Implement pseudoElement attribute on transition DOM events.
authoralexis@webkit.org <alexis@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 29 Jan 2013 16:55:32 +0000 (16:55 +0000)
committeralexis@webkit.org <alexis@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 29 Jan 2013 16:55:32 +0000 (16:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=107986

Reviewed by Julien Chaffraix.

Source/WebCore:

Implement the pseudoElement attribute documented here :
http://dev.w3.org/csswg/css3-transitions/#transition-events.
This add a new attribute to the transition DOM event useful when
animating pseudo elements. As they are not accessible in JS, it's
very useful to get on which pseudo element the transition just ended.
This patch adds the new attribute on the IDLs of DOM transition events as well
as adding it to the C++ classes representing them. The event
dispatching code have been patched to change the target of the event
(we can't send the current target as it is the actual DOM
representation of the pseudo element).

Test: fast/css-generated-content/pseudo-transition-event.html

* dom/EventDispatcher.cpp:
(WebCore::eventTargetRespectingTargetRules): Change the target of the
event in the case of a pseudo element. We can't expose them through the
public interface so the target is the node they belong to.
(WebCore::EventDispatcher::ensureEventAncestors):
(WebCore::EventDispatcher::dispatchScopedEvent):
(WebCore::EventDispatcher::dispatchEvent):
(WebCore::EventDispatcher::dispatchEventPostProcess):
* dom/EventTarget.cpp:
(WebCore::createMatchingPrefixedEvent):
* dom/PseudoElement.cpp:
(WebCore::PseudoElement::pseudoElementNameForEvents):
(WebCore):
* dom/PseudoElement.h:
* dom/TransitionEvent.cpp:
(WebCore::TransitionEventInit::TransitionEventInit):
(WebCore::TransitionEvent::TransitionEvent):
(WebCore::TransitionEvent::pseudoElement):
(WebCore):
* dom/TransitionEvent.h:
(TransitionEventInit):
(WebCore::TransitionEvent::create):
(TransitionEvent):
* dom/TransitionEvent.idl:
* dom/WebKitTransitionEvent.cpp:
(WebCore::WebKitTransitionEventInit::WebKitTransitionEventInit):
(WebCore::WebKitTransitionEvent::WebKitTransitionEvent):
(WebCore::WebKitTransitionEvent::pseudoElement):
(WebCore):
* dom/WebKitTransitionEvent.h:
(WebKitTransitionEventInit):
(WebCore::WebKitTransitionEvent::create):
(WebKitTransitionEvent):
* dom/WebKitTransitionEvent.idl:
* page/animation/AnimationController.cpp:
(WebCore::AnimationControllerPrivate::fireEventsAndUpdateStyle): Pass
the pseudo element name when creating the Event objects. If the element
is not a pseudo element then the name will be empty which is what the
spec is telling to do. If the element is a pseudo element then the name
will be the pseudo element's name with "::" as a prefix.

LayoutTests:

Add new tests to cover the feature.

* fast/css-generated-content/pseudo-transition-event-expected.txt: Added.
* fast/css-generated-content/pseudo-transition-event.html: Added.
* fast/events/constructors/transition-event-constructor-expected.txt:
* fast/events/constructors/transition-event-constructor.html:
* fast/events/constructors/webkit-transition-event-constructor-expected.txt:
* fast/events/constructors/webkit-transition-event-constructor.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@141119 268f45cc-cd09-0410-ab3c-d52691b4dbfc

19 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css-generated-content/pseudo-transition-event-expected.txt [new file with mode: 0644]
LayoutTests/fast/css-generated-content/pseudo-transition-event.html [new file with mode: 0644]
LayoutTests/fast/events/constructors/transition-event-constructor-expected.txt
LayoutTests/fast/events/constructors/transition-event-constructor.html
LayoutTests/fast/events/constructors/webkit-transition-event-constructor-expected.txt
LayoutTests/fast/events/constructors/webkit-transition-event-constructor.html
Source/WebCore/ChangeLog
Source/WebCore/dom/EventDispatcher.cpp
Source/WebCore/dom/EventTarget.cpp
Source/WebCore/dom/PseudoElement.cpp
Source/WebCore/dom/PseudoElement.h
Source/WebCore/dom/TransitionEvent.cpp
Source/WebCore/dom/TransitionEvent.h
Source/WebCore/dom/TransitionEvent.idl
Source/WebCore/dom/WebKitTransitionEvent.cpp
Source/WebCore/dom/WebKitTransitionEvent.h
Source/WebCore/dom/WebKitTransitionEvent.idl
Source/WebCore/page/animation/AnimationController.cpp

index cd93b8c..fdcedad 100644 (file)
@@ -1,3 +1,19 @@
+2013-01-29  Alexis Menard  <alexis@webkit.org>
+
+        Implement pseudoElement attribute on transition DOM events.
+        https://bugs.webkit.org/show_bug.cgi?id=107986
+
+        Reviewed by Julien Chaffraix.
+
+        Add new tests to cover the feature.
+
+        * fast/css-generated-content/pseudo-transition-event-expected.txt: Added.
+        * fast/css-generated-content/pseudo-transition-event.html: Added.
+        * fast/events/constructors/transition-event-constructor-expected.txt:
+        * fast/events/constructors/transition-event-constructor.html:
+        * fast/events/constructors/webkit-transition-event-constructor-expected.txt:
+        * fast/events/constructors/webkit-transition-event-constructor.html:
+
 2013-01-29  Zan Dobersek  <zdobersek@igalia.com>
 
         Unreviewed GTK gardening.
diff --git a/LayoutTests/fast/css-generated-content/pseudo-transition-event-expected.txt b/LayoutTests/fast/css-generated-content/pseudo-transition-event-expected.txt
new file mode 100644 (file)
index 0000000..5fa597c
--- /dev/null
@@ -0,0 +1,15 @@
+Transitions on :before and :after pseudo elements should run and fire DOM events
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS event.propertyName is expectedEvents[currentEvent][0]
+PASS event.target.id is expectedEvents[currentEvent][1]
+PASS event.pseudoElement is expectedEvents[currentEvent][2]
+PASS event.propertyName is expectedEvents[currentEvent][0]
+PASS event.target.id is expectedEvents[currentEvent][1]
+PASS event.pseudoElement is expectedEvents[currentEvent][2]
+PASS successfullyParsed is true
+
+TEST COMPLETE
diff --git a/LayoutTests/fast/css-generated-content/pseudo-transition-event.html b/LayoutTests/fast/css-generated-content/pseudo-transition-event.html
new file mode 100644 (file)
index 0000000..e4f8a4f
--- /dev/null
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+
+<script src="../js/resources/js-test-pre.js"></script>
+
+<style>
+#before:before,
+#after:after {
+    content: "";
+    display: block;
+    height: 50px;
+    width: 50px;
+    -webkit-transition: width 1ms;
+    transition: width 1ms;
+}
+
+#before.transition:before,
+#after.transition:after {
+    height: 10px;
+    width: 10px;
+}
+
+#before,
+#after {
+    display: inline-block;
+    border: 1px solid black;
+    background: red;
+}
+
+#after.transition,
+#before.transition {
+    background: green;
+}
+</style>
+
+<div id="before"></div>
+<div id="after"></div>
+
+<script>
+description('Transitions on :before and :after pseudo elements should run and fire DOM events');
+
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+var expectedEvents = [ ["width", "before", "::before"] , ["width", "after", "::after"] ];
+var currentEvent = 0;
+
+function recordTransitionEvent()
+{
+    shouldBe("event.propertyName", "expectedEvents[currentEvent][0]");
+    shouldBe("event.target.id", "expectedEvents[currentEvent][1]");
+    shouldBe("event.pseudoElement", "expectedEvents[currentEvent][2]");
+    if (currentEvent == 1) {
+        isSuccessfullyParsed();
+        if (window.testRunner)
+            testRunner.notifyDone();
+    } else {
+        currentEvent++;
+        testTransition('after');
+    }
+}
+
+function testTransition(id)
+{
+    var div = document.getElementById(id);
+    div.className = 'transition';
+}
+
+onload = function() {
+    document.addEventListener( 'transitionend', recordTransitionEvent);
+    testTransition('before');
+};
+</script>
index eef8f7c..3cb1e31 100644 (file)
@@ -7,6 +7,7 @@ PASS new TransitionEvent('eventType').bubbles is false
 PASS new TransitionEvent('eventType').cancelable is false
 PASS new TransitionEvent('eventType').propertyName is ""
 PASS new TransitionEvent('eventType').elapsedTime is 0
+PASS new TransitionEvent('eventType').pseudoElement is ""
 PASS new TransitionEvent('eventType', { bubbles: false }).bubbles is false
 PASS new TransitionEvent('eventType', { bubbles: true }).bubbles is true
 PASS new TransitionEvent('eventType', { cancelable: false }).cancelable is false
@@ -31,6 +32,8 @@ PASS new TransitionEvent('eventType', { elapsedTime: 18446744073709551615 }).ela
 PASS new TransitionEvent('eventType', { elapsedTime: NaN }).elapsedTime is NaN
 PASS new TransitionEvent('eventType', { elapsedTime: Infinity }).elapsedTime is Infinity
 PASS new TransitionEvent('eventType', { elapsedTime: -Infinity }).elapsedTime is -Infinity
+PASS new TransitionEvent('eventType', { pseudoElement: '::before' }).pseudoElement is "::before"
+PASS new TransitionEvent('eventType', { pseudoElement: '' }).pseudoElement is ""
 PASS new TransitionEvent('eventType', { elapsedTime: undefined }).elapsedTime is NaN
 PASS new TransitionEvent('eventType', { elapsedTime: null }).elapsedTime is 0
 PASS new TransitionEvent('eventType', { elapsedTime: false }).elapsedTime is 0
@@ -42,10 +45,11 @@ PASS new TransitionEvent('eventType', { elapsedTime: [123.45] }).elapsedTime is
 PASS new TransitionEvent('eventType', { elapsedTime: [123.45, 678.90] }).elapsedTime is NaN
 PASS new TransitionEvent('eventType', { elapsedTime: {doremi: 123.45} }).elapsedTime is NaN
 PASS new TransitionEvent('eventType', { elapsedTime: {valueOf: function () { return 123.45 } } }).elapsedTime is 123.45
-PASS new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).bubbles is true
-PASS new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).cancelable is true
-PASS new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).propertyName is 'doremi'
-PASS new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).elapsedTime is 123.45
+PASS new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).bubbles is true
+PASS new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).cancelable is true
+PASS new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).propertyName is 'doremi'
+PASS new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).elapsedTime is 123.45
+PASS new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).pseudoElement is '::after'
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 8aef039..8aafcdd 100644 (file)
@@ -13,6 +13,7 @@ shouldBe("new TransitionEvent('eventType').bubbles", "false");
 shouldBe("new TransitionEvent('eventType').cancelable", "false");
 shouldBeEqualToString("new TransitionEvent('eventType').propertyName", "");
 shouldBe("new TransitionEvent('eventType').elapsedTime", "0");
+shouldBeEqualToString("new TransitionEvent('eventType').pseudoElement", "");
 
 // bubbles is passed.
 shouldBe("new TransitionEvent('eventType', { bubbles: false }).bubbles", "false");
@@ -50,6 +51,11 @@ shouldBe("new TransitionEvent('eventType', { elapsedTime: NaN }).elapsedTime", "
 shouldBe("new TransitionEvent('eventType', { elapsedTime: Infinity }).elapsedTime", "Infinity");
 shouldBe("new TransitionEvent('eventType', { elapsedTime: -Infinity }).elapsedTime", "-Infinity");
 
+// pseudoElement is passed.
+// Strings.
+shouldBeEqualToString("new TransitionEvent('eventType', { pseudoElement: '::before' }).pseudoElement", "::before");
+shouldBeEqualToString("new TransitionEvent('eventType', { pseudoElement: '' }).pseudoElement", "");
+
 // Non-numeric values.
 shouldBe("new TransitionEvent('eventType', { elapsedTime: undefined }).elapsedTime", "NaN");
 shouldBe("new TransitionEvent('eventType', { elapsedTime: null }).elapsedTime", "0");
@@ -64,10 +70,11 @@ shouldBe("new TransitionEvent('eventType', { elapsedTime: {doremi: 123.45} }).el
 shouldBe("new TransitionEvent('eventType', { elapsedTime: {valueOf: function () { return 123.45 } } }).elapsedTime", "123.45");
 
 // All initializers are passed.
-shouldBe("new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).bubbles", "true");
-shouldBe("new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).cancelable", "true");
-shouldBe("new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).propertyName", "'doremi'");
-shouldBe("new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).elapsedTime", "123.45");
+shouldBe("new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).bubbles", "true");
+shouldBe("new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).cancelable", "true");
+shouldBe("new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).propertyName", "'doremi'");
+shouldBe("new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).elapsedTime", "123.45");
+shouldBe("new TransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).pseudoElement", "'::after'");
 </script>
 <script src="../../js/resources/js-test-post.js"></script>
 </body>
index b128b24..934284a 100644 (file)
@@ -7,6 +7,7 @@ PASS new WebKitTransitionEvent('eventType').bubbles is false
 PASS new WebKitTransitionEvent('eventType').cancelable is false
 PASS new WebKitTransitionEvent('eventType').propertyName is ""
 PASS new WebKitTransitionEvent('eventType').elapsedTime is 0
+PASS new WebKitTransitionEvent('eventType').pseudoElement is ""
 PASS new WebKitTransitionEvent('eventType', { bubbles: false }).bubbles is false
 PASS new WebKitTransitionEvent('eventType', { bubbles: true }).bubbles is true
 PASS new WebKitTransitionEvent('eventType', { cancelable: false }).cancelable is false
@@ -31,6 +32,8 @@ PASS new WebKitTransitionEvent('eventType', { elapsedTime: 18446744073709551615
 PASS new WebKitTransitionEvent('eventType', { elapsedTime: NaN }).elapsedTime is NaN
 PASS new WebKitTransitionEvent('eventType', { elapsedTime: Infinity }).elapsedTime is Infinity
 PASS new WebKitTransitionEvent('eventType', { elapsedTime: -Infinity }).elapsedTime is -Infinity
+PASS new WebKitTransitionEvent('eventType', { pseudoElement: '::before' }).pseudoElement is "::before"
+PASS new WebKitTransitionEvent('eventType', { pseudoElement: '' }).pseudoElement is ""
 PASS new WebKitTransitionEvent('eventType', { elapsedTime: undefined }).elapsedTime is NaN
 PASS new WebKitTransitionEvent('eventType', { elapsedTime: null }).elapsedTime is 0
 PASS new WebKitTransitionEvent('eventType', { elapsedTime: false }).elapsedTime is 0
@@ -42,10 +45,11 @@ PASS new WebKitTransitionEvent('eventType', { elapsedTime: [123.45] }).elapsedTi
 PASS new WebKitTransitionEvent('eventType', { elapsedTime: [123.45, 678.90] }).elapsedTime is NaN
 PASS new WebKitTransitionEvent('eventType', { elapsedTime: {doremi: 123.45} }).elapsedTime is NaN
 PASS new WebKitTransitionEvent('eventType', { elapsedTime: {valueOf: function () { return 123.45 } } }).elapsedTime is 123.45
-PASS new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).bubbles is true
-PASS new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).cancelable is true
-PASS new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).propertyName is 'doremi'
-PASS new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).elapsedTime is 123.45
+PASS new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).bubbles is true
+PASS new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).cancelable is true
+PASS new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).propertyName is 'doremi'
+PASS new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).elapsedTime is 123.45
+PASS new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).pseudoElement is '::after'
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 85b0007..b2b7eeb 100644 (file)
@@ -13,6 +13,7 @@ shouldBe("new WebKitTransitionEvent('eventType').bubbles", "false");
 shouldBe("new WebKitTransitionEvent('eventType').cancelable", "false");
 shouldBeEqualToString("new WebKitTransitionEvent('eventType').propertyName", "");
 shouldBe("new WebKitTransitionEvent('eventType').elapsedTime", "0");
+shouldBeEqualToString("new WebKitTransitionEvent('eventType').pseudoElement", "");
 
 // bubbles is passed.
 shouldBe("new WebKitTransitionEvent('eventType', { bubbles: false }).bubbles", "false");
@@ -50,6 +51,11 @@ shouldBe("new WebKitTransitionEvent('eventType', { elapsedTime: NaN }).elapsedTi
 shouldBe("new WebKitTransitionEvent('eventType', { elapsedTime: Infinity }).elapsedTime", "Infinity");
 shouldBe("new WebKitTransitionEvent('eventType', { elapsedTime: -Infinity }).elapsedTime", "-Infinity");
 
+// pseudoElement is passed.
+// Strings.
+shouldBeEqualToString("new WebKitTransitionEvent('eventType', { pseudoElement: '::before' }).pseudoElement", "::before");
+shouldBeEqualToString("new WebKitTransitionEvent('eventType', { pseudoElement: '' }).pseudoElement", "");
+
 // Non-numeric values.
 shouldBe("new WebKitTransitionEvent('eventType', { elapsedTime: undefined }).elapsedTime", "NaN");
 shouldBe("new WebKitTransitionEvent('eventType', { elapsedTime: null }).elapsedTime", "0");
@@ -64,10 +70,11 @@ shouldBe("new WebKitTransitionEvent('eventType', { elapsedTime: {doremi: 123.45}
 shouldBe("new WebKitTransitionEvent('eventType', { elapsedTime: {valueOf: function () { return 123.45 } } }).elapsedTime", "123.45");
 
 // All initializers are passed.
-shouldBe("new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).bubbles", "true");
-shouldBe("new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).cancelable", "true");
-shouldBe("new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).propertyName", "'doremi'");
-shouldBe("new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45 }).elapsedTime", "123.45");
+shouldBe("new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).bubbles", "true");
+shouldBe("new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).cancelable", "true");
+shouldBe("new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).propertyName", "'doremi'");
+shouldBe("new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).elapsedTime", "123.45");
+shouldBe("new WebKitTransitionEvent('eventType', { bubbles: true, cancelable: true, propertyName: 'doremi', elapsedTime: 123.45, pseudoElement: '::after' }).pseudoElement", "'::after'");
 </script>
 <script src="../../js/resources/js-test-post.js"></script>
 </body>
index 1788961..2ab642d 100644 (file)
@@ -1,3 +1,64 @@
+2013-01-29  Alexis Menard  <alexis@webkit.org>
+
+        Implement pseudoElement attribute on transition DOM events.
+        https://bugs.webkit.org/show_bug.cgi?id=107986
+
+        Reviewed by Julien Chaffraix.
+
+        Implement the pseudoElement attribute documented here :
+        http://dev.w3.org/csswg/css3-transitions/#transition-events.
+        This add a new attribute to the transition DOM event useful when
+        animating pseudo elements. As they are not accessible in JS, it's
+        very useful to get on which pseudo element the transition just ended.
+        This patch adds the new attribute on the IDLs of DOM transition events as well
+        as adding it to the C++ classes representing them. The event
+        dispatching code have been patched to change the target of the event
+        (we can't send the current target as it is the actual DOM
+        representation of the pseudo element).
+
+        Test: fast/css-generated-content/pseudo-transition-event.html
+
+        * dom/EventDispatcher.cpp:
+        (WebCore::eventTargetRespectingTargetRules): Change the target of the
+        event in the case of a pseudo element. We can't expose them through the
+        public interface so the target is the node they belong to.
+        (WebCore::EventDispatcher::ensureEventAncestors):
+        (WebCore::EventDispatcher::dispatchScopedEvent):
+        (WebCore::EventDispatcher::dispatchEvent):
+        (WebCore::EventDispatcher::dispatchEventPostProcess):
+        * dom/EventTarget.cpp:
+        (WebCore::createMatchingPrefixedEvent):
+        * dom/PseudoElement.cpp:
+        (WebCore::PseudoElement::pseudoElementNameForEvents):
+        (WebCore):
+        * dom/PseudoElement.h:
+        * dom/TransitionEvent.cpp:
+        (WebCore::TransitionEventInit::TransitionEventInit):
+        (WebCore::TransitionEvent::TransitionEvent):
+        (WebCore::TransitionEvent::pseudoElement):
+        (WebCore):
+        * dom/TransitionEvent.h:
+        (TransitionEventInit):
+        (WebCore::TransitionEvent::create):
+        (TransitionEvent):
+        * dom/TransitionEvent.idl:
+        * dom/WebKitTransitionEvent.cpp:
+        (WebCore::WebKitTransitionEventInit::WebKitTransitionEventInit):
+        (WebCore::WebKitTransitionEvent::WebKitTransitionEvent):
+        (WebCore::WebKitTransitionEvent::pseudoElement):
+        (WebCore):
+        * dom/WebKitTransitionEvent.h:
+        (WebKitTransitionEventInit):
+        (WebCore::WebKitTransitionEvent::create):
+        (WebKitTransitionEvent):
+        * dom/WebKitTransitionEvent.idl:
+        * page/animation/AnimationController.cpp:
+        (WebCore::AnimationControllerPrivate::fireEventsAndUpdateStyle): Pass
+        the pseudo element name when creating the Event objects. If the element
+        is not a pseudo element then the name will be empty which is what the
+        spec is telling to do. If the element is a pseudo element then the name
+        will be the pseudo element's name with "::" as a prefix.
+
 2013-01-29  Allan Sandfeld Jensen  <allan.jensen@digia.com>
 
         [Qt] Implement GCActivityCallback
index 3ca938f..d409a83 100644 (file)
@@ -135,10 +135,13 @@ bool EventDispatcher::dispatchEvent(Node* node, PassRefPtr<EventDispatchMediator
     return mediator->dispatchEvent(&dispatcher);
 }
 
-inline static EventTarget* eventTargetRespectingSVGTargetRules(Node* referenceNode)
+inline static EventTarget* eventTargetRespectingTargetRules(Node* referenceNode)
 {
     ASSERT(referenceNode);
 
+    if (referenceNode->isPseudoElement())
+        return referenceNode->parentNode();
+
 #if ENABLE(SVG)
     if (!referenceNode->isSVGElement() || !referenceNode->isInShadowTree())
         return referenceNode;
@@ -192,10 +195,10 @@ void EventDispatcher::ensureEventAncestors(Event* event)
     for (AncestorChainWalker walker(m_node.get()); walker.get(); walker.parent()) {
         Node* node = walker.get();
         if (targetStack.isEmpty())
-            targetStack.append(eventTargetRespectingSVGTargetRules(node));
+            targetStack.append(eventTargetRespectingTargetRules(node));
         else if (walker.crossingInsertionPoint())
             targetStack.append(targetStack.last());
-        m_ancestors.append(EventContext(node, eventTargetRespectingSVGTargetRules(node), targetStack.last()));
+        m_ancestors.append(EventContext(node, eventTargetRespectingTargetRules(node), targetStack.last()));
         if (!inDocument)
             return;
         if (!node->isShadowRoot())
@@ -212,7 +215,7 @@ void EventDispatcher::ensureEventAncestors(Event* event)
 void EventDispatcher::dispatchScopedEvent(Node* node, PassRefPtr<EventDispatchMediator> mediator)
 {
     // We need to set the target here because it can go away by the time we actually fire the event.
-    mediator->event()->setTarget(eventTargetRespectingSVGTargetRules(node));
+    mediator->event()->setTarget(eventTargetRespectingTargetRules(node));
     ScopedEventQueue::instance()->enqueueEventDispatchMediator(mediator);
 }
 
@@ -253,7 +256,7 @@ bool EventDispatcher::dispatchEvent(PassRefPtr<Event> prpEvent)
     RefPtr<Event> event = prpEvent;
     ChildNodesLazySnapshot::takeChildNodesLazySnapshot();
 
-    event->setTarget(eventTargetRespectingSVGTargetRules(m_node.get()));
+    event->setTarget(eventTargetRespectingTargetRules(m_node.get()));
     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
     ASSERT(event->target());
     ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null.
@@ -339,7 +342,7 @@ inline EventDispatchContinuation EventDispatcher::dispatchEventAtBubbling(PassRe
 
 inline void EventDispatcher::dispatchEventPostProcess(PassRefPtr<Event> event, void* preDispatchEventHandlerResult)
 {
-    event->setTarget(eventTargetRespectingSVGTargetRules(m_node.get()));
+    event->setTarget(eventTargetRespectingTargetRules(m_node.get()));
     event->setCurrentTarget(0);
     event->setEventPhase(0);
 
index 924a32c..d0ad520 100644 (file)
@@ -165,7 +165,7 @@ static PassRefPtr<Event> createMatchingPrefixedEvent(const Event* event)
 {
     if (event->type() == eventNames().transitionendEvent) {
         const WebKitTransitionEvent* transitionEvent = static_cast<const WebKitTransitionEvent*>(event);
-        RefPtr<Event> prefixedEvent = WebKitTransitionEvent::create(eventNames().webkitTransitionEndEvent, transitionEvent->propertyName(), transitionEvent->elapsedTime());
+        RefPtr<Event> prefixedEvent = WebKitTransitionEvent::create(eventNames().webkitTransitionEndEvent, transitionEvent->propertyName(), transitionEvent->elapsedTime(), transitionEvent->pseudoElement());
         prefixedEvent->setTarget(event->target());
         prefixedEvent->setCurrentTarget(event->currentTarget());
         prefixedEvent->setEventPhase(event->eventPhase());
index d6caf86..761ec6f 100644 (file)
@@ -39,6 +39,20 @@ const QualifiedName& pseudoElementTagName()
     return name;
 }
 
+String PseudoElement::pseudoElementNameForEvents(PseudoId pseudoId)
+{
+    DEFINE_STATIC_LOCAL(const String, after, (ASCIILiteral("::after")));
+    DEFINE_STATIC_LOCAL(const String, before, (ASCIILiteral("::before")));
+    switch (pseudoId) {
+    case AFTER:
+        return after;
+    case BEFORE:
+        return before;
+    default:
+        return emptyString();
+    }
+}
+
 PseudoElement::PseudoElement(Element* parent, PseudoId pseudoId)
     : Element(pseudoElementTagName(), parent->document(), CreatePseudoElement)
     , m_pseudoId(pseudoId)
index 5599202..939c8f9 100644 (file)
@@ -48,12 +48,11 @@ public:
     virtual bool canStartSelection() const OVERRIDE { return false; }
     virtual bool canContainRangeEndPoint() const OVERRIDE { return false; }
 
+    static String pseudoElementNameForEvents(PseudoId);
+
 private:
     PseudoElement(Element*, PseudoId);
 
-    using EventTarget::dispatchEvent;
-    virtual bool dispatchEvent(PassRefPtr<Event>) OVERRIDE { return false; }
-
     virtual void didRecalcStyle(StyleChange) OVERRIDE;
     virtual PseudoId customPseudoId() const OVERRIDE { return m_pseudoId; }
 
index b3fe20f..a89e94a 100644 (file)
 namespace WebCore {
 
 TransitionEventInit::TransitionEventInit()
-    : propertyName()
-    , elapsedTime(0)
+    : elapsedTime(0)
 {
 }
 
 TransitionEvent::TransitionEvent()
-    : m_propertyName()
-    , m_elapsedTime(0)
+    : m_elapsedTime(0)
 {
 }
 
-TransitionEvent::TransitionEvent(const AtomicString& type, const String& propertyName, double elapsedTime)
+TransitionEvent::TransitionEvent(const AtomicString& type, const String& propertyName, double elapsedTime, const String& pseudoElement)
     : Event(type, true, true)
     , m_propertyName(propertyName)
     , m_elapsedTime(elapsedTime)
+    , m_pseudoElement(pseudoElement)
 {
 }
 
@@ -56,6 +55,7 @@ TransitionEvent::TransitionEvent(const AtomicString& type, const TransitionEvent
     : Event(type, initializer)
     , m_propertyName(initializer.propertyName)
     , m_elapsedTime(initializer.elapsedTime)
+    , m_pseudoElement(initializer.pseudoElement)
 {
 }
 
@@ -73,6 +73,11 @@ double TransitionEvent::elapsedTime() const
     return m_elapsedTime;
 }
 
+const String& TransitionEvent::pseudoElement() const
+{
+    return m_pseudoElement;
+}
+
 const AtomicString& TransitionEvent::interfaceName() const
 {
     return eventNames().interfaceForTransitionEvent;
index b173860..32226ed 100644 (file)
@@ -38,6 +38,7 @@ struct TransitionEventInit : public EventInit {
 
     String propertyName;
     double elapsedTime;
+    String pseudoElement;
 };
 
 class TransitionEvent : public Event {
@@ -46,9 +47,9 @@ public:
     {
         return adoptRef(new TransitionEvent);
     }
-    static PassRefPtr<TransitionEvent> create(const AtomicString& type, const String& propertyName, double elapsedTime)
+    static PassRefPtr<TransitionEvent> create(const AtomicString& type, const String& propertyName, double elapsedTime, const String& pseudoElement)
     {
-        return adoptRef(new TransitionEvent(type, propertyName, elapsedTime));
+        return adoptRef(new TransitionEvent(type, propertyName, elapsedTime, pseudoElement));
     }
     static PassRefPtr<TransitionEvent> create(const AtomicString& type, const TransitionEventInit& initializer)
     {
@@ -59,16 +60,18 @@ public:
 
     const String& propertyName() const;
     double elapsedTime() const;
+    const String& pseudoElement() const;
 
     virtual const AtomicString& interfaceName() const;
 
 private:
     TransitionEvent();
-    TransitionEvent(const AtomicString& type, const String& propertyName, double elapsedTime);
+    TransitionEvent(const AtomicString& type, const String& propertyName, double elapsedTime, const String& pseudoElement);
     TransitionEvent(const AtomicString& type, const TransitionEventInit& initializer);
 
     String m_propertyName;
     double m_elapsedTime;
+    String m_pseudoElement;
 };
 
 } // namespace WebCore
index cc06de6..a07237f 100644 (file)
@@ -30,5 +30,6 @@
 ] interface TransitionEvent : Event {
     [InitializedByEventConstructor] readonly attribute DOMString propertyName;
     [InitializedByEventConstructor] readonly attribute double elapsedTime;
+    [InitializedByEventConstructor] readonly attribute DOMString pseudoElement;
 };
 
index 45c2b47..1091758 100644 (file)
 namespace WebCore {
 
 WebKitTransitionEventInit::WebKitTransitionEventInit()
-    : propertyName()
-    , elapsedTime(0)
+    : elapsedTime(0)
 {
 }
 
 WebKitTransitionEvent::WebKitTransitionEvent()
-    : m_propertyName()
-    , m_elapsedTime(0)
+    : m_elapsedTime(0)
 {
 }
 
-WebKitTransitionEvent::WebKitTransitionEvent(const AtomicString& type, const String& propertyName, double elapsedTime)
+WebKitTransitionEvent::WebKitTransitionEvent(const AtomicString& type, const String& propertyName, double elapsedTime, const String& pseudoElement)
     : Event(type, true, true)
     , m_propertyName(propertyName)
     , m_elapsedTime(elapsedTime)
+    , m_pseudoElement(pseudoElement)
 {
 }
 
@@ -53,6 +52,7 @@ WebKitTransitionEvent::WebKitTransitionEvent(const AtomicString& type, const Web
     : Event(type, initializer)
     , m_propertyName(initializer.propertyName)
     , m_elapsedTime(initializer.elapsedTime)
+    , m_pseudoElement(initializer.pseudoElement)
 {
 }
 
@@ -70,6 +70,11 @@ double WebKitTransitionEvent::elapsedTime() const
     return m_elapsedTime;
 }
 
+const String& WebKitTransitionEvent::pseudoElement() const
+{
+    return m_pseudoElement;
+}
+
 const AtomicString& WebKitTransitionEvent::interfaceName() const
 {
     return eventNames().interfaceForWebKitTransitionEvent;
index 232c105..c45ab74 100644 (file)
@@ -35,6 +35,7 @@ struct WebKitTransitionEventInit : public EventInit {
 
     String propertyName;
     double elapsedTime;
+    String pseudoElement;
 };
 
 class WebKitTransitionEvent : public Event {
@@ -43,9 +44,9 @@ public:
     {
         return adoptRef(new WebKitTransitionEvent);
     }
-    static PassRefPtr<WebKitTransitionEvent> create(const AtomicString& type, const String& propertyName, double elapsedTime)
+    static PassRefPtr<WebKitTransitionEvent> create(const AtomicString& type, const String& propertyName, double elapsedTime, const String& pseudoElement)
     {
-        return adoptRef(new WebKitTransitionEvent(type, propertyName, elapsedTime));
+        return adoptRef(new WebKitTransitionEvent(type, propertyName, elapsedTime, pseudoElement));
     }
     static PassRefPtr<WebKitTransitionEvent> create(const AtomicString& type, const WebKitTransitionEventInit& initializer)
     {
@@ -56,16 +57,18 @@ public:
 
     const String& propertyName() const;
     double elapsedTime() const;
+    const String& pseudoElement() const;
 
     virtual const AtomicString& interfaceName() const;
 
 private:
     WebKitTransitionEvent();
-    WebKitTransitionEvent(const AtomicString& type, const String& propertyName, double elapsedTime);
+    WebKitTransitionEvent(const AtomicString& type, const String& propertyName, double elapsedTime, const String& pseudoElement);
     WebKitTransitionEvent(const AtomicString& type, const WebKitTransitionEventInit& initializer);
 
     String m_propertyName;
     double m_elapsedTime;
+    String m_pseudoElement;
 };
 
 } // namespace WebCore
index 218ccab..4e21030 100644 (file)
@@ -28,5 +28,6 @@
 ] interface WebKitTransitionEvent : Event {
     [InitializedByEventConstructor] readonly attribute DOMString propertyName;
     [InitializedByEventConstructor] readonly attribute double elapsedTime;
+    [InitializedByEventConstructor] readonly attribute DOMString pseudoElement;
 };
 
index 7a936b8..f97c92b 100644 (file)
@@ -37,6 +37,7 @@
 #include "EventNames.h"
 #include "Frame.h"
 #include "FrameView.h"
+#include "PseudoElement.h"
 #include "RenderView.h"
 #include "TransitionEvent.h"
 #include "WebKitAnimationEvent.h"
@@ -180,14 +181,15 @@ void AnimationControllerPrivate::fireEventsAndUpdateStyle()
     m_eventsToDispatch.clear();
     Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = eventsToDispatch.end();
     for (Vector<EventToDispatch>::const_iterator it = eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) {
-        if (it->eventType == eventNames().transitionendEvent)
+        Element* element = it->element.get();
+        if (it->eventType == eventNames().transitionendEvent) {
 #if ENABLE(CSS_TRANSFORMS_ANIMATIONS_TRANSITIONS_UNPREFIXED)
-            it->element->dispatchEvent(TransitionEvent::create(it->eventType, it->name, it->elapsedTime));
+            element->dispatchEvent(TransitionEvent::create(it->eventType, it->name, it->elapsedTime, PseudoElement::pseudoElementNameForEvents(element->pseudoId())));
 #else
-            it->element->dispatchEvent(WebKitTransitionEvent::create(it->eventType, it->name, it->elapsedTime));
+            element->dispatchEvent(WebKitTransitionEvent::create(it->eventType, it->name, it->elapsedTime, PseudoElement::pseudoElementNameForEvents(element->pseudoId())));
 #endif
-        else
-            it->element->dispatchEvent(WebKitAnimationEvent::create(it->eventType, it->name, it->elapsedTime));
+        else
+            element->dispatchEvent(WebKitAnimationEvent::create(it->eventType, it->name, it->elapsedTime));
     }
 
     // call setChanged on all the elements