Closed
Bug 1256562
Opened 9 years ago
Closed 8 years ago
Convert native event times to TimeStamps for Mac
Categories
(Core :: Widget: Cocoa, defect, P3)
Tracking
()
RESOLVED
FIXED
mozilla53
People
(Reporter: birtles, Assigned: masayuki)
References
(Blocks 1 open bug)
Details
(Whiteboard: tpi:+)
Attachments
(3 files)
As with bug 1026803 and bug 77992, we need to convert events times provided by the OS to corresponding TimeStamp values.
Reporter | ||
Updated•9 years ago
|
Flags: needinfo?(ajones)
Comment 1•9 years ago
|
||
I know bug 1026803 was in DOM: Events but it seems like it should be in Widget: Cocoa. Feel free to disagree, of course :)
Component: DOM: Events → Widget: Cocoa
Updated•9 years ago
|
Whiteboard: tpi:?
Updated•9 years ago
|
Whiteboard: tpi:? → tpi:-
Updated•9 years ago
|
Priority: -- → P1
Whiteboard: tpi:- → tpi:+
Updated•9 years ago
|
Priority: P1 → P3
Removing ni? because I'm no longer involved in this bug in any way.
Flags: needinfo?(ajones)
Assignee | ||
Updated•8 years ago
|
Assignee: nobody → masayuki
Assignee | ||
Comment 3•8 years ago
|
||
Assignee | ||
Comment 4•8 years ago
|
||
Are there good testcases for Event.timeStamp? I briefly tested for keydown, keypress, keyup, mousedown, mouseup, click, dblclick, compositionstart, compositionupdate and compositionend.
Assignee | ||
Updated•8 years ago
|
status-firefox50:
--- → wontfix
status-firefox51:
--- → wontfix
status-firefox52:
--- → wontfix
status-firefox53:
--- → affected
status-firefox-esr45:
--- → wontfix
Assignee | ||
Updated•8 years ago
|
Status: NEW → ASSIGNED
Hardware: Unspecified → All
Assignee | ||
Comment 5•8 years ago
|
||
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Assignee | ||
Comment 9•8 years ago
|
||
Brian, could you check if I implement CurrentCocoaTimeGetter as you expected first? After your r+, I'll request to review to mstange and smaug.
Reporter | ||
Comment 10•8 years ago
|
||
mozreview-review |
Comment on attachment 8820295 [details]
Bug 1256562 part.1 Implement nsCocoaUtils::GetEventTimeStamp() to convert from timeStamp of NSEvent to TimeStamp
https://reviewboard.mozilla.org/r/99824/#review100444
I've only done a very rough review. The general flow seems correct although I'm not sure the check for inflight requests is correct but perhaps I'm missing something. I think karlt should check this though.
::: widget/cocoa/nsCocoaUtils.mm:51
(Diff revision 1)
> using std::ceil;
>
> +// The type of [NSEvent timestamp] is NSTimeInterval which is an alias of
> +// double. However, SystemTimeConverter allows only unsigned type and
> +// we don't need such big range (NSTimeInterval supports over a range of
> +// 10,000 years!). So, let's use uint32_t here (Note that SystemTimeConver
SystemTimeConverter
::: widget/cocoa/nsCocoaUtils.mm:92
(Diff revision 1)
> + NSTimeInterval currentTime = GetCurrentTimeNative();
> + if (mBackwardsSkewStamp && currentTime == mLastPostTime) {
Does this ever evaluate true? Doesn't the value of GetCurrentTimeNative() always return a different value?
(Also, with CurrentX11TimeGetter we avoid calling get synchronous time getter in this method because it's expensive but is that not the case for OSX?)
::: widget/cocoa/nsCocoaUtils.mm:130
(Diff revision 1)
> + }
> +
> +private:
> + static CurrentCocoaTimeGetter* sInstance;
> +
> + Maybe<TimeStamp> mBackwardsSkewStamp;
TimeStamp has a null value so I don't think we need Maybe?
::: widget/cocoa/nsCocoaUtils.mm:1141
(Diff revision 1)
> +
> +TimeStamp
> +nsCocoaUtils::GetEventTimeStamp(NSTimeInterval aEventTime)
> +{
> + if (!aEventTime) {
> + // If the event is generaged by 3rd party's apps or something, its timestamp
generated
Reporter | ||
Comment 11•8 years ago
|
||
Hmm, looks like karlt is away until Dec 29.
Reporter | ||
Comment 12•8 years ago
|
||
mozreview-review |
Comment on attachment 8820295 [details]
Bug 1256562 part.1 Implement nsCocoaUtils::GetEventTimeStamp() to convert from timeStamp of NSEvent to TimeStamp
https://reviewboard.mozilla.org/r/99824/#review100448
I'm inclined to give say r=me but I think I'd like to know first:
* Is the check for currentTime == mLastPostTime in GetTimeAsyncForPossibleBackwardsSkew needed? If not, can we drop it?
* Is GetCurrentTimeNative() expensive? If so, can we avoid it? For that matter, why is the approach used by CurrentX11TimeGetter not suitable here?
* Is it possible to use more similar names to CurrentX11TimeGetter? e.g. s/mBackwardsSkewStamp/mAsyncUpdateStart/ ?
::: widget/cocoa/nsCocoaUtils.mm:1141
(Diff revision 1)
> +
> +TimeStamp
> +nsCocoaUtils::GetEventTimeStamp(NSTimeInterval aEventTime)
> +{
> + if (!aEventTime) {
> + // If the event is generaged by 3rd party's apps or something, its timestamp
("or something" seems a bit vague. Perhaps, "If the event is generated by a 3rd party application, its timestamp...")
Reporter | ||
Comment 13•8 years ago
|
||
mozreview-review |
Comment on attachment 8820295 [details]
Bug 1256562 part.1 Implement nsCocoaUtils::GetEventTimeStamp() to convert from timeStamp of NSEvent to TimeStamp
https://reviewboard.mozilla.org/r/99824/#review100546
As discussed in person, this looks good but:
* We should drop the check for currentTime == mLastPostTime in GetTimeAsyncForPossibleBackwardsSkew and file a bug for doing the same thing for the Windows version
* We *don't* need to use more similar names to CurrentX11TimeGetter since the names here match the Windows version
* We can drop the use of Maybe<> since TimeStamp has a null value
* We should make the comment tweaks in comment 10 and comment 12
Other than that r=me
I'd like to get karlt to review but since he's away I think this is fine. If he finds issues once he returns we can problem uplift the necessary fixes.
Attachment #8820295 -
Flags: review?(bbirtles) → review+
Assignee | ||
Comment 14•8 years ago
|
||
Assignee | ||
Comment 15•8 years ago
|
||
Oh, I misunderstood about the limitation of SystemTimeConverter. It uses int64_t in it, but it's used for storing the difference between 2 TimeStamp instances difference. So, my patch should be able to use uint64_t.
Assignee | ||
Comment 16•8 years ago
|
||
Assignee | ||
Comment 17•8 years ago
|
||
https://jsfiddle.net/d_toybox/kp2beobg/3/
Hmm, at dispatching eKeyPress event, TextInputHandler uses NSKeyDown event at initializing the mTimeStamp of eKeyPress event. However, the Event.timeStamp values of "keydown" and "keypress" are different and it sometimes causes setting older timestamp to keypress event. I've not understood about Event.TimeStamp yet...
Anyway, we should fix it later. There are other issues of timeStamp of keyboard/composition event vs. input event. So, might be caused by same issue.
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Assignee | ||
Updated•8 years ago
|
Attachment #8820296 -
Flags: review?(mstange)
Comment 21•8 years ago
|
||
mozreview-review |
Comment on attachment 8820296 [details]
Bug 1256562 part.2 All event dispatchers under widget/cocoa should initialize WidgetEventTime::mTimeStamp with nsCocoaUtils::GetEventTimeStamp()
https://reviewboard.mozilla.org/r/99826/#review101044
::: widget/cocoa/SwipeTracker.mm:204
(Diff revision 2)
> /* static */ WidgetSimpleGestureEvent
> SwipeTracker::CreateSwipeGestureEvent(EventMessage aMsg, nsIWidget* aWidget,
> - const LayoutDeviceIntPoint& aPosition)
> + const LayoutDeviceIntPoint& aPosition,
> + const TimeStamp& aTimeStamp)
> {
> + // XXX Why isn't this initialized with nsCocoaUtils::InitInputEvent()?
Not sure, probably because we don't need modifiers information on the event. And now with this patch, you'd have to overwrite the mTimeStamp field afterwards anyway because we don't have an NSEvent to pull it from.
::: widget/cocoa/nsChildView.mm:3546
(Diff revision 2)
> - (BOOL)isOpaque
> {
> return [[self window] isOpaque];
> }
>
> +// XXX Is this really used?
Looks like it's unused.
Attachment #8820296 -
Flags: review?(mstange) → review+
Comment 22•8 years ago
|
||
mozreview-review |
Comment on attachment 8820295 [details]
Bug 1256562 part.1 Implement nsCocoaUtils::GetEventTimeStamp() to convert from timeStamp of NSEvent to TimeStamp
https://reviewboard.mozilla.org/r/99824/#review101048
::: widget/cocoa/nsCocoaUtils.mm:80
(Diff revision 2)
> + static_assert(sizeof(unsigned long) == sizeof(uint64_t),
> + "Assuming that unsignedLongValue returns uint64_t value");
> + return [[NSNumber numberWithDouble:aTime * 1000] unsignedLongValue];
Why did you choose this way of converting the value, instead of just `return uint64_t(aTime * 1000.0);`?
Also, using 1000 only gives you millisecond resolution. Why not go higher? We might as well use 1000000 and go for microsecond resolution (and rename this function to ToMicroseconds).
::: widget/cocoa/nsCocoaUtils.mm:101
(Diff revision 2)
> + mBackwardsSkewStamp = aNow;
> + NSEvent* event =
> + [NSEvent otherEventWithType:NSApplicationDefined
> + location:NSMakePoint(0, 0)
> + modifierFlags:0
> + timestamp:GetCurrentTimeNative()
So here you're setting the timestamp that will be on the event. This makes me think that it doesn't make sense to go through the event loop for this because you have all the information you need to correct time skew already.
I can see how it would be useful to post an event on platforms where events are the only way to receive a new timestamp in "native event time". But that's not the case here on Mac.
We can correct for time skew synchronously on Mac by just querying the new time. I think the ideal implementation of GetTimeAsyncForPossibleBackwardsSkew would be:
```
void GetTimeAsyncForPossibleBackwardsSkew(const TimeStamp& aNow)
{
TimeConverter().CompensateForBackwardsSkew(GetCurrentTime(), aNow);
}
```
But the caller of GetTimeAsyncForPossibleBackwardsSkew would probably need to be adjusted to be able to deal with synchronous responses.
::: widget/cocoa/nsCocoaUtils.mm:130
(Diff revision 2)
> + {
> + }
> +
> + NSTimeInterval GetCurrentTimeNative() const
> + {
> + return [[NSProcessInfo processInfo] systemUptime];
Please add a comment that says that, since we care about NSEvent timestamps here, we need a reference timestamp that is in the same "space" as NSEvent timestamps. And `[[NSProcessInfo processInfo] systemUptime]` is how you get the current time in the same space as `-[NSEvent timestamp]`.
You could also mention that CurrentCocoaTimeGetter does not let us express timestamps before the system startup, and that that's ok because we only care about event timestamps.
Attachment #8820295 -
Flags: review?(mstange)
Comment 23•8 years ago
|
||
mozreview-review |
Comment on attachment 8820295 [details]
Bug 1256562 part.1 Implement nsCocoaUtils::GetEventTimeStamp() to convert from timeStamp of NSEvent to TimeStamp
https://reviewboard.mozilla.org/r/99824/#review101058
::: widget/cocoa/nsCocoaUtils.mm:1128
(Diff revision 2)
> + uint32_t milliseconds = CurrentCocoaTimeGetter::ToMilliseconds(aPostedTime);
> + TimeConverter().CompensateForBackwardsSkew(milliseconds, skewStamp);
> +}
> +
> +TimeStamp
> +nsCocoaUtils::GetEventTimeStamp(NSTimeInterval aEventTime)
Actually, I think we don't need any of the SystemTimeConverter mechanisms on Mac. TimeStamp::mValue is in nanoseconds since boot, and `mach_absolute_time() == [[NSProcessInfo processInfo] systemUptime] * 1000000000.0`, so I think all you need is:
```
nsCocoaUtils::GetEventTimeStamp(NSTimeInterval aEventTime)
{
return TimeStamp::FromSystemTime(uint64_t(aEventTime * 1000000000.0));
}
```
Comment 24•8 years ago
|
||
mozreview-review-reply |
Comment on attachment 8820295 [details]
Bug 1256562 part.1 Implement nsCocoaUtils::GetEventTimeStamp() to convert from timeStamp of NSEvent to TimeStamp
https://reviewboard.mozilla.org/r/99824/#review101058
> Actually, I think we don't need any of the SystemTimeConverter mechanisms on Mac. TimeStamp::mValue is in nanoseconds since boot, and `mach_absolute_time() == [[NSProcessInfo processInfo] systemUptime] * 1000000000.0`, so I think all you need is:
>
> ```
> nsCocoaUtils::GetEventTimeStamp(NSTimeInterval aEventTime)
> {
> return TimeStamp::FromSystemTime(uint64_t(aEventTime * 1000000000.0));
> }
> ```
Oh, let me correct that:
```
return TimeStamp::FromSystemTime(BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aEventTime * 1000.0));
```
mach_absolute_time is not necessarily in milliseconds (though on my system it is, because timebase.numer and timebase.denom are both 1).
Comment 25•8 years ago
|
||
mozreview-review |
Comment on attachment 8820297 [details]
Bug 1256562 part.3 Enable high resolution timestamp on macOS
https://reviewboard.mozilla.org/r/99828/#review101094
::: modules/libpref/init/all.js:1225
(Diff revision 2)
> // Annotate channels based on the tracking protection list in all modes
> pref("privacy.trackingprotection.annotate_channels", false);
>
> pref("dom.event.contextmenu.enabled", true);
> pref("dom.event.clipboardevents.enabled", true);
> -#if defined(XP_WIN) && !defined(RELEASE_OR_BETA) || defined(MOZ_WIDGET_GTK) && !defined(RELEASE_OR_BETA)
> +#if defined(XP_WIN) && !defined(RELEASE_OR_BETA) || defined(MOZ_WIDGET_GTK) && !defined(RELEASE_OR_BETA) || defined(XP_MACOSX) && !defined(RELEASE_OR_BETA)
Ok, so we need still support for Android.
Looks like that is bug 1256565.
Attachment #8820297 -
Flags: review?(bugs) → review+
Comment 26•8 years ago
|
||
mozreview-review |
Comment on attachment 8820296 [details]
Bug 1256562 part.2 All event dispatchers under widget/cocoa should initialize WidgetEventTime::mTimeStamp with nsCocoaUtils::GetEventTimeStamp()
https://reviewboard.mozilla.org/r/99826/#review101104
::: widget/cocoa/nsCocoaUtils.mm:707
(Diff revision 2)
> {
> NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
>
> aInputEvent.mModifiers = ModifiersForEvent(aNativeEvent);
> aInputEvent.mTime = PR_IntervalNow();
> + aInputEvent.mTimeStamp = GetEventTimeStamp([aNativeEvent timestamp]);
Ok, I trust that GetEventTimeStamp does the right thing.
Attachment #8820296 -
Flags: review?(bugs) → review+
Assignee | ||
Comment 27•8 years ago
|
||
mozreview-review |
Comment on attachment 8820296 [details]
Bug 1256562 part.2 All event dispatchers under widget/cocoa should initialize WidgetEventTime::mTimeStamp with nsCocoaUtils::GetEventTimeStamp()
https://reviewboard.mozilla.org/r/99826/#review101152
::: widget/cocoa/SwipeTracker.mm:204
(Diff revision 2)
> /* static */ WidgetSimpleGestureEvent
> SwipeTracker::CreateSwipeGestureEvent(EventMessage aMsg, nsIWidget* aWidget,
> - const LayoutDeviceIntPoint& aPosition)
> + const LayoutDeviceIntPoint& aPosition,
> + const TimeStamp& aTimeStamp)
> {
> + // XXX Why isn't this initialized with nsCocoaUtils::InitInputEvent()?
Hmm, even if current event listeners don't need the modifiers, it may be referred by others. Perhaps, we need to improve here in another bug.
::: widget/cocoa/nsChildView.mm:3546
(Diff revision 2)
> - (BOOL)isOpaque
> {
> return [[self window] isOpaque];
> }
>
> +// XXX Is this really used?
Okay, I'll file a bug to remove this.
::: widget/cocoa/nsCocoaUtils.mm:707
(Diff revision 2)
> {
> NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
>
> aInputEvent.mModifiers = ModifiersForEvent(aNativeEvent);
> aInputEvent.mTime = PR_IntervalNow();
> + aInputEvent.mTimeStamp = GetEventTimeStamp([aNativeEvent timestamp]);
Me too :-)
We should wrap the whole things to compute mTimeStamp with a utility method.
Assignee | ||
Comment 28•8 years ago
|
||
mozreview-review-reply |
Comment on attachment 8820295 [details]
Bug 1256562 part.1 Implement nsCocoaUtils::GetEventTimeStamp() to convert from timeStamp of NSEvent to TimeStamp
https://reviewboard.mozilla.org/r/99824/#review101058
> Oh, let me correct that:
>
> ```
> return TimeStamp::FromSystemTime(BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aEventTime * 1000.0));
> ```
>
> mach_absolute_time is not necessarily in milliseconds (though on my system it is, because timebase.numer and timebase.denom are both 1).
Oh, really? If we don't need SystemTimeConverter nor CurrentCocoaTimeGetter, we do this much simpler!
Assignee | ||
Comment 29•8 years ago
|
||
mozreview-review-reply |
Comment on attachment 8820295 [details]
Bug 1256562 part.1 Implement nsCocoaUtils::GetEventTimeStamp() to convert from timeStamp of NSEvent to TimeStamp
https://reviewboard.mozilla.org/r/99824/#review101048
> Why did you choose this way of converting the value, instead of just `return uint64_t(aTime * 1000.0);`?
>
> Also, using 1000 only gives you millisecond resolution. Why not go higher? We might as well use 1000000 and go for microsecond resolution (and rename this function to ToMicroseconds).
> Why did you choose this way of converting the value, instead of just return uint64_t(aTime * 1000.0);?
I'm not familiar with cast with too big double value. So, I was thinking that using such API is safer.
> Also, using 1000 only gives you millisecond resolution. Why not go higher? We might as well
> use 1000000 and go for microsecond resolution (and rename this function to ToMicroseconds).
Because of SystemTimeConverter's limitation. It doesn't allow to use |double| and if we use microsecond with unsigned integer type, the range becomes narrower.
> So here you're setting the timestamp that will be on the event. This makes me think that it doesn't make sense to go through the event loop for this because you have all the information you need to correct time skew already.
> I can see how it would be useful to post an event on platforms where events are the only way to receive a new timestamp in "native event time". But that's not the case here on Mac.
>
> We can correct for time skew synchronously on Mac by just querying the new time. I think the ideal implementation of GetTimeAsyncForPossibleBackwardsSkew would be:
>
> ```
> void GetTimeAsyncForPossibleBackwardsSkew(const TimeStamp& aNow)
> {
> TimeConverter().CompensateForBackwardsSkew(GetCurrentTime(), aNow);
> }
> ```
>
> But the caller of GetTimeAsyncForPossibleBackwardsSkew would probably need to be adjusted to be able to deal with synchronous responses.
Okay, I'll retry to understand deeper what we should do.
Comment 30•8 years ago
|
||
Yeah I changed my mind a bit during the review. Comment 24 has the code I think we should use.
Assignee | ||
Comment 31•8 years ago
|
||
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment 35•8 years ago
|
||
mozreview-review |
Comment on attachment 8820295 [details]
Bug 1256562 part.1 Implement nsCocoaUtils::GetEventTimeStamp() to convert from timeStamp of NSEvent to TimeStamp
https://reviewboard.mozilla.org/r/99824/#review101414
::: widget/cocoa/nsCocoaUtils.mm:1033
(Diff revision 3)
> + // If the event is generated by a 3rd party application, its timestamp
> + // may be 0. In this case, just return current timestamp.
> + // XXX Should we cache last event time?
> + return TimeStamp::Now();
> + }
> + int64_t tick =
Let's add a comment:
// The internal value of the macOS implementation of TimeStamp is based on
// mach_absolute_time(), which measures "ticks" since boot.
// Event timestamps are NSTimeIntervals (seconds) since boot. So the two time
// representations already have the same base; we only need to convert
// seconds into ticks.
And you can use the same explanation in the commit message.
Attachment #8820295 -
Flags: review?(mstange) → review+
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment 39•8 years ago
|
||
Pushed by masayuki@d-toybox.com:
https://hg.mozilla.org/integration/autoland/rev/5e87a3190b95
part.1 Implement nsCocoaUtils::GetEventTimeStamp() to convert from timeStamp of NSEvent to TimeStamp r=birtles,mstange
https://hg.mozilla.org/integration/autoland/rev/725f7a643301
part.2 All event dispatchers under widget/cocoa should initialize WidgetEventTime::mTimeStamp with nsCocoaUtils::GetEventTimeStamp() r=mstange,smaug
https://hg.mozilla.org/integration/autoland/rev/d3343e6ab57e
part.3 Enable high resolution timestamp on macOS r=smaug
Comment 40•8 years ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/5e87a3190b95
https://hg.mozilla.org/mozilla-central/rev/725f7a643301
https://hg.mozilla.org/mozilla-central/rev/d3343e6ab57e
Status: ASSIGNED → RESOLVED
Closed: 8 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla53
You need to log in
before you can comment on or make changes to this bug.
Description
•