<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[245020] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/245020">245020</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2019-05-07 11:43:27 -0700 (Tue, 07 May 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>[Pointer Events] isPrimary property of pointercancel events should match previous events for that pointer
https://bugs.webkit.org/show_bug.cgi?id=197665

Patch by Antoine Quint <graouts@apple.com> on 2019-05-07
Reviewed by Dean Jackson.

LayoutTests/imported/w3c:

Record WPT progressions.

* web-platform-tests/pointerevents/pointerevent_pointercancel_touch-expected.txt:

Source/WebCore:

The test at web-platform-tests/pointerevents/pointerevent_pointercancel_touch.html would fail early because one of the first assertions
would check that isPrimary for a pointercancel event would match the isPrimary property of the previous pointer event dispatched for that
pointer id. This prevented many further assertions from passing and also was the cause of flakiness for the next test since this test was
ended early and the state of touches created using UIScriptController were not in a clean state.

We now track the isPrimary state for a given pointer using the CapturingData and use that value when dispatching a pointercancel event.

* dom/PointerEvent.cpp:
(WebCore::PointerEvent::create):
(WebCore::PointerEvent::PointerEvent):
* dom/PointerEvent.h:
* page/PointerCaptureController.cpp:
(WebCore::PointerCaptureController::pointerEventWasDispatched):
(WebCore::PointerCaptureController::cancelPointer):
* page/PointerCaptureController.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsimportedw3cChangeLog">trunk/LayoutTests/imported/w3c/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsimportedw3cwebplatformtestspointereventspointerevent_pointercancel_touchexpectedtxt">trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_pointercancel_touch-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoredomPointerEventcpp">trunk/Source/WebCore/dom/PointerEvent.cpp</a></li>
<li><a href="#trunkSourceWebCoredomPointerEventh">trunk/Source/WebCore/dom/PointerEvent.h</a></li>
<li><a href="#trunkSourceWebCorepagePointerCaptureControllercpp">trunk/Source/WebCore/page/PointerCaptureController.cpp</a></li>
<li><a href="#trunkSourceWebCorepagePointerCaptureControllerh">trunk/Source/WebCore/page/PointerCaptureController.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsimportedw3cChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/imported/w3c/ChangeLog (245019 => 245020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/imported/w3c/ChangeLog 2019-05-07 18:42:16 UTC (rev 245019)
+++ trunk/LayoutTests/imported/w3c/ChangeLog    2019-05-07 18:43:27 UTC (rev 245020)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2019-05-07  Antoine Quint  <graouts@apple.com>
+
+        [Pointer Events] isPrimary property of pointercancel events should match previous events for that pointer
+        https://bugs.webkit.org/show_bug.cgi?id=197665
+
+        Reviewed by Dean Jackson.
+
+        Record WPT progressions.
+
+        * web-platform-tests/pointerevents/pointerevent_pointercancel_touch-expected.txt:
+
</ins><span class="cx"> 2019-05-07  Youenn Fablet  <youenn@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Import WPT referrer-policy tests
</span></span></pre></div>
<a id="trunkLayoutTestsimportedw3cwebplatformtestspointereventspointerevent_pointercancel_touchexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_pointercancel_touch-expected.txt (245019 => 245020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_pointercancel_touch-expected.txt    2019-05-07 18:42:16 UTC (rev 245019)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_pointercancel_touch-expected.txt       2019-05-07 18:43:27 UTC (rev 245020)
</span><span class="lines">@@ -11,5 +11,43 @@
</span><span class="cx"> The following pointer types were detected: touch.
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-FAIL pointercancel event received assert_equals: isPrimary should be the same for pointerdown and pointercancel expected true but got false
</del><ins>+FAIL pointercancel event received assert_true: pointerleave should be received before the test finished expected true got false
+PASS  touch pointercancel event is a PointerEvent event 
+PASS  touch pointercancel.pointerId attribute exists 
+PASS  touch pointercancel.pointerId is readonly 
+PASS  touch pointercancel.pointerId IDL type long (JS type was number) 
+PASS  touch pointercancel.width attribute exists 
+PASS  touch pointercancel.width is readonly 
+PASS  touch pointercancel.width IDL type float (JS type was number) 
+PASS  touch pointercancel.height attribute exists 
+PASS  touch pointercancel.height is readonly 
+PASS  touch pointercancel.height IDL type float (JS type was number) 
+PASS  touch pointercancel.pressure attribute exists 
+PASS  touch pointercancel.pressure is readonly 
+PASS  touch pointercancel.pressure IDL type float (JS type was number) 
+PASS  touch pointercancel.tiltX attribute exists 
+PASS  touch pointercancel.tiltX is readonly 
+PASS  touch pointercancel.tiltX IDL type long (JS type was number) 
+PASS  touch pointercancel.tiltY attribute exists 
+PASS  touch pointercancel.tiltY is readonly 
+PASS  touch pointercancel.tiltY IDL type long (JS type was number) 
+PASS  touch pointercancel.pointerType attribute exists 
+PASS  touch pointercancel.pointerType is readonly 
+PASS  touch pointercancel.pointerType IDL type string (JS type was string) 
+PASS  touch pointercancel.isPrimary attribute exists 
+PASS  touch pointercancel.isPrimary is readonly 
+PASS  touch pointercancel.isPrimary IDL type boolean (JS type was boolean) 
+PASS  touch pointercancel.detail attribute exists 
+PASS  touch pointercancel.detail is readonly 
+PASS  touch pointercancel.detail IDL type long (JS type was number) 
+PASS  touch pointercancel.detail value is 0. 
+PASS  touch pointercancel.fromElement attribute exists 
+PASS  touch pointercancel.fromElement is readonly 
+PASS  touch pointercancel.fromElement IDL type object (JS type was object) 
+PASS  touch pointercancel.fromElement value is null. 
+PASS  touch pointercancel.toElement attribute exists 
+PASS  touch pointercancel.toElement is readonly 
+PASS  touch pointercancel.toElement IDL type object (JS type was object) 
+FAIL  touch pointercancel.toElement value is null. assert_equals: toElement attribute value expected null but got Element node <div id="target0" style="background: black"></div>
+PASS  touch pointercancel.pressure value is valid 
</ins><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (245019 => 245020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2019-05-07 18:42:16 UTC (rev 245019)
+++ trunk/Source/WebCore/ChangeLog      2019-05-07 18:43:27 UTC (rev 245020)
</span><span class="lines">@@ -1,3 +1,26 @@
</span><ins>+2019-05-07  Antoine Quint  <graouts@apple.com>
+
+        [Pointer Events] isPrimary property of pointercancel events should match previous events for that pointer
+        https://bugs.webkit.org/show_bug.cgi?id=197665
+
+        Reviewed by Dean Jackson.
+
+        The test at web-platform-tests/pointerevents/pointerevent_pointercancel_touch.html would fail early because one of the first assertions
+        would check that isPrimary for a pointercancel event would match the isPrimary property of the previous pointer event dispatched for that
+        pointer id. This prevented many further assertions from passing and also was the cause of flakiness for the next test since this test was
+        ended early and the state of touches created using UIScriptController were not in a clean state.
+
+        We now track the isPrimary state for a given pointer using the CapturingData and use that value when dispatching a pointercancel event.
+
+        * dom/PointerEvent.cpp:
+        (WebCore::PointerEvent::create):
+        (WebCore::PointerEvent::PointerEvent):
+        * dom/PointerEvent.h:
+        * page/PointerCaptureController.cpp:
+        (WebCore::PointerCaptureController::pointerEventWasDispatched):
+        (WebCore::PointerCaptureController::cancelPointer):
+        * page/PointerCaptureController.h:
+
</ins><span class="cx"> 2019-05-07  Ryan Haddad  <ryanhaddad@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, rolling out r244900.
</span></span></pre></div>
<a id="trunkSourceWebCoredomPointerEventcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/PointerEvent.cpp (245019 => 245020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/PointerEvent.cpp        2019-05-07 18:42:16 UTC (rev 245019)
+++ trunk/Source/WebCore/dom/PointerEvent.cpp   2019-05-07 18:43:27 UTC (rev 245020)
</span><span class="lines">@@ -84,9 +84,9 @@
</span><span class="cx">     return adoptRef(*new PointerEvent(type, canBubble, isCancelable, isComposed, mouseEvent));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Ref<PointerEvent> PointerEvent::create(const String& type, PointerID pointerId, const String& pointerType)
</del><ins>+Ref<PointerEvent> PointerEvent::create(const String& type, PointerID pointerId, const String& pointerType, IsPrimary isPrimary)
</ins><span class="cx"> {
</span><del>-    return adoptRef(*new PointerEvent(type, CanBubble::Yes, IsCancelable::No, IsComposed::Yes, pointerId, pointerType));
</del><ins>+    return adoptRef(*new PointerEvent(type, CanBubble::Yes, IsCancelable::No, IsComposed::Yes, pointerId, pointerType, isPrimary));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PointerEvent::PointerEvent() = default;
</span><span class="lines">@@ -112,10 +112,11 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-PointerEvent::PointerEvent(const AtomicString& type, CanBubble canBubble, IsCancelable isCancelable, IsComposed isComposed, PointerID pointerId, const String& pointerType)
</del><ins>+PointerEvent::PointerEvent(const AtomicString& type, CanBubble canBubble, IsCancelable isCancelable, IsComposed isComposed, PointerID pointerId, const String& pointerType, IsPrimary isPrimary)
</ins><span class="cx">     : MouseEvent(type, canBubble, isCancelable, isComposed, nullptr, 0, { }, { }, { }, 0, 0, 0, nullptr)
</span><span class="cx">     , m_pointerId(pointerId)
</span><span class="cx">     , m_pointerType(pointerType)
</span><ins>+    , m_isPrimary(isPrimary == IsPrimary::Yes)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoredomPointerEventh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/PointerEvent.h (245019 => 245020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/PointerEvent.h  2019-05-07 18:42:16 UTC (rev 245019)
+++ trunk/Source/WebCore/dom/PointerEvent.h     2019-05-07 18:43:27 UTC (rev 245020)
</span><span class="lines">@@ -52,6 +52,8 @@
</span><span class="cx">         bool isPrimary { false };
</span><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    enum class IsPrimary : uint8_t { No, Yes };
+
</ins><span class="cx">     static Ref<PointerEvent> create(const AtomicString& type, Init&& initializer)
</span><span class="cx">     {
</span><span class="cx">         return adoptRef(*new PointerEvent(type, WTFMove(initializer)));
</span><span class="lines">@@ -73,7 +75,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static RefPtr<PointerEvent> create(const MouseEvent&);
</span><del>-    static Ref<PointerEvent> create(const String& type, PointerID, const String& pointerType);
</del><ins>+    static Ref<PointerEvent> create(const String& type, PointerID, const String& pointerType, IsPrimary = IsPrimary::No);
</ins><span class="cx"> 
</span><span class="cx"> #if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
</span><span class="cx">     static Ref<PointerEvent> create(const PlatformTouchEvent&, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&&);
</span><span class="lines">@@ -106,7 +108,7 @@
</span><span class="cx">     PointerEvent();
</span><span class="cx">     PointerEvent(const AtomicString&, Init&&);
</span><span class="cx">     PointerEvent(const AtomicString& type, CanBubble, IsCancelable, IsComposed, const MouseEvent&);
</span><del>-    PointerEvent(const AtomicString& type, CanBubble, IsCancelable, IsComposed, PointerID, const String& pointerType);
</del><ins>+    PointerEvent(const AtomicString& type, CanBubble, IsCancelable, IsComposed, PointerID, const String& pointerType, IsPrimary);
</ins><span class="cx"> #if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
</span><span class="cx">     PointerEvent(const AtomicString& type, const PlatformTouchEvent&, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&&);
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCorepagePointerCaptureControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/PointerCaptureController.cpp (245019 => 245020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/PointerCaptureController.cpp   2019-05-07 18:42:16 UTC (rev 245019)
+++ trunk/Source/WebCore/page/PointerCaptureController.cpp      2019-05-07 18:43:27 UTC (rev 245020)
</span><span class="lines">@@ -234,6 +234,8 @@
</span><span class="cx">     auto iterator = m_activePointerIdsToCapturingData.find(event.pointerId());
</span><span class="cx">     if (iterator != m_activePointerIdsToCapturingData.end()) {
</span><span class="cx">         auto& capturingData = iterator->value;
</span><ins>+        capturingData.isPrimary = event.isPrimary();
+
</ins><span class="cx">         // Immediately after firing the pointerup or pointercancel events, a user agent MUST clear the pending pointer capture target
</span><span class="cx">         // override for the pointerId of the pointerup or pointercancel event that was just dispatched, and then run Process Pending
</span><span class="cx">         // Pointer Capture steps to fire lostpointercapture if necessary.
</span><span class="lines">@@ -281,7 +283,7 @@
</span><span class="cx">     if (!target)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    auto event = PointerEvent::create(eventNames().pointercancelEvent, pointerId, capturingData.pointerType);
</del><ins>+    auto event = PointerEvent::create(eventNames().pointercancelEvent, pointerId, capturingData.pointerType, capturingData.isPrimary ? PointerEvent::IsPrimary::Yes : PointerEvent::IsPrimary::No);
</ins><span class="cx">     target->dispatchEvent(event);
</span><span class="cx">     processPendingPointerCapture(WTFMove(event));
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCorepagePointerCaptureControllerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/PointerCaptureController.h (245019 => 245020)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/PointerCaptureController.h     2019-05-07 18:42:16 UTC (rev 245019)
+++ trunk/Source/WebCore/page/PointerCaptureController.h        2019-05-07 18:43:27 UTC (rev 245020)
</span><span class="lines">@@ -63,6 +63,7 @@
</span><span class="cx">         RefPtr<Element> targetOverride;
</span><span class="cx">         String pointerType;
</span><span class="cx">         bool cancelled { false };
</span><ins>+        bool isPrimary { false };
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     void pointerEventWillBeDispatched(const PointerEvent&, EventTarget*);
</span></span></pre>
</div>
</div>

</body>
</html>