Apply animations and transitions for first-letter element
authorigor.o@sisa.samsung.com <igor.o@sisa.samsung.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 12 Jun 2012 21:08:18 +0000 (21:08 +0000)
committerigor.o@sisa.samsung.com <igor.o@sisa.samsung.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 12 Jun 2012 21:08:18 +0000 (21:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=85253

Source/WebCore:

Add animations and transitions support for the first-letter
pseudo element.
Instead of calling RenderOject::node() in the animations code,
now we need to call RenderObject::styledGeneratingNode() because
pseudo elements does not have a Node associated with the
RenderObject.

Initial patch by Simon Fraser

Reviewed by Simon Fraser.

Tests: animations/first-letter-animation.html
       animations/first-letter-play-state.html
       transitions/first-letter-color-transition.html
       transitions/first-letter-transition.html

* page/animation/AnimationBase.cpp:
(WebCore::AnimationBase::updateStateMachine):
* page/animation/AnimationController.cpp:
(WebCore::AnimationControllerPrivate::updateAnimations):
(WebCore::AnimationControllerPrivate::pauseAnimationAtTime):
(WebCore::AnimationControllerPrivate::pauseTransitionAtTime):
(WebCore::AnimationController::cancelAnimations):
(WebCore::AnimationController::updateAnimations):
* page/animation/ImplicitAnimation.cpp:
(WebCore::ImplicitAnimation::pauseAnimation):
(WebCore::ImplicitAnimation::sendTransitionEvent):
* page/animation/KeyframeAnimation.cpp:
(WebCore::KeyframeAnimation::KeyframeAnimation):
(WebCore::KeyframeAnimation::pauseAnimation):
(WebCore::KeyframeAnimation::endAnimation):
(WebCore::KeyframeAnimation::sendAnimationEvent):
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::updateFirstLetterStyle):
(WebCore::RenderBlock::createFirstLetterRenderer):
* rendering/RenderInline.cpp:
(WebCore::RenderInline::clippedOverflowRectForRepaint):
* rendering/RenderObject.cpp:
(WebCore::RenderObject::setAnimatableStyle):
(WebCore::RenderObject::styledGeneratingNode):
(WebCore):
* rendering/RenderObject.h:
(RenderObject):

LayoutTests:

Reviewed by Simon Fraser.

* animations/first-letter-animation-expected.txt: Added.
* animations/first-letter-animation.html: Added.
* animations/first-letter-play-state-expected.txt: Added.
* animations/first-letter-play-state.html: Added.
* transitions/first-letter-color-transition-expected.txt: Added.
* transitions/first-letter-color-transition.html: Added.
* transitions/first-letter-transition-expected.txt: Added.
* transitions/first-letter-transition.html: Added.

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

18 files changed:
LayoutTests/ChangeLog
LayoutTests/animations/first-letter-animation-expected.txt [new file with mode: 0644]
LayoutTests/animations/first-letter-animation.html [new file with mode: 0644]
LayoutTests/animations/first-letter-play-state-expected.txt [new file with mode: 0644]
LayoutTests/animations/first-letter-play-state.html [new file with mode: 0644]
LayoutTests/transitions/first-letter-color-transition-expected.txt [new file with mode: 0644]
LayoutTests/transitions/first-letter-color-transition.html [new file with mode: 0644]
LayoutTests/transitions/first-letter-transition-expected.txt [new file with mode: 0644]
LayoutTests/transitions/first-letter-transition.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/page/animation/AnimationBase.cpp
Source/WebCore/page/animation/AnimationController.cpp
Source/WebCore/page/animation/ImplicitAnimation.cpp
Source/WebCore/page/animation/KeyframeAnimation.cpp
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderInline.cpp
Source/WebCore/rendering/RenderObject.cpp
Source/WebCore/rendering/RenderObject.h

index bad4f5f..101d96b 100644 (file)
@@ -1,3 +1,19 @@
+2012-06-12  Igor Oliveira  <igor.o@sisa.samsung.com>
+
+        Apply animations and transitions for first-letter element
+        https://bugs.webkit.org/show_bug.cgi?id=85253
+
+        Reviewed by Simon Fraser.
+
+        * animations/first-letter-animation-expected.txt: Added.
+        * animations/first-letter-animation.html: Added.
+        * animations/first-letter-play-state-expected.txt: Added.
+        * animations/first-letter-play-state.html: Added.
+        * transitions/first-letter-color-transition-expected.txt: Added.
+        * transitions/first-letter-color-transition.html: Added.
+        * transitions/first-letter-transition-expected.txt: Added.
+        * transitions/first-letter-transition.html: Added.
+
 2012-06-12  Kent Tamura  <tkent@chromium.org>
 
         Checking a radio button doesn't uncheck other buttons in the same group in some cases.
diff --git a/LayoutTests/animations/first-letter-animation-expected.txt b/LayoutTests/animations/first-letter-animation-expected.txt
new file mode 100644 (file)
index 0000000..9b8a006
--- /dev/null
@@ -0,0 +1,6 @@
+Lorem ipsum dolor sit amet.
+Animations test result: 
+
+PASS
+PASS
+
diff --git a/LayoutTests/animations/first-letter-animation.html b/LayoutTests/animations/first-letter-animation.html
new file mode 100644 (file)
index 0000000..a6970d0
--- /dev/null
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style type="text/css" media="screen">
+    .box {
+      position: relative;
+      width: 100px;
+      height: 100px;
+      background: blue;
+      -webkit-animation: boxAnimation 0.1s 0.1s linear;
+    }
+
+    .box::first-letter {
+      color: black;
+      -webkit-animation: firstLetterAnimation 0.1s 0.2s forwards ease-out;
+    }
+
+    @-webkit-keyframes firstLetterAnimation {
+      from { font-size: 24pt;}
+      to { font-size: 40pt;}
+    }
+
+    @-webkit-keyframes boxAnimation {
+      from { 
+             font-size: 40pt;
+             -webkit-transform: rotate(0deg);
+      }
+      to {
+           font-size: 2pt;
+           -webkit-transform: rotate(360deg);
+      }
+    }
+
+</style>
+<script type="text/javascript" charset="utf-8">
+   if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+
+    var result = "Animations test result: <br><br>";
+    var animations = 0;
+    function animationEnded(event)
+    {
+        if ((event.animationName == "firstLetterAnimation" || event.animationName == "boxAnimation") &&
+            parseFloat(event.elapsedTime).toFixed(2) == 0.1)
+           result += "PASS<br>";
+        else
+           result += "FAIL<br>";
+
+        ++animations;
+        if (animations == 2) {
+            document.getElementById('result').innerHTML = result;
+            if (window.layoutTestController)
+                layoutTestController.notifyDone();
+        }
+    }
+
+    window.addEventListener("webkitAnimationEnd", animationEnded, false );
+</script>
+</head>
+<body>
+  <div class="box">
+    Lorem ipsum dolor sit amet.
+  </div>
+  <div id="result" style="position:absolute; top:150px">
+  </div>
+</body>
+</html>
diff --git a/LayoutTests/animations/first-letter-play-state-expected.txt b/LayoutTests/animations/first-letter-play-state-expected.txt
new file mode 100644 (file)
index 0000000..122c56c
--- /dev/null
@@ -0,0 +1,6 @@
+This tests the operation of -webkit-animation-play-state. After 100 milliseconds the box should stop and after 150 milliseconds it should start again. We test it both while in motion and when stopped.
+
+Lorem ipsum dolor sit amet.
+PASS - "left" property for "box1" element at 0.1s saw something close to: 200
+PASS - "left" property for "box1" element at 0.13s saw something close to: 200
+
diff --git a/LayoutTests/animations/first-letter-play-state.html b/LayoutTests/animations/first-letter-play-state.html
new file mode 100644 (file)
index 0000000..22e9f46
--- /dev/null
@@ -0,0 +1,92 @@
+<html>
+<head>
+  <title>Test of -webkit-animation-play-state with first-letter pseudo element</title>
+  <style type="text/css" media="screen">
+    #box1 {
+      position: absolute;
+      height: 100px;
+      width: 100px;
+      background-color: blue;
+      color: red;
+      -webkit-animation: move1 0.2s linear;
+    }
+    #box1::first-letter {
+      color: white;
+      -webkit-animation: firstLetterAnimation 0.21s linear;
+    }
+    #box1.paused::first-letter {
+      -webkit-animation-play-state: paused;
+    }
+    #box1.running::first-letter {
+      -webkit-animation-play-state: running;
+    }
+    @-webkit-keyframes move1 {
+        from { left: 0px ; color: red;}
+        to   { left: 400px; color: black;}
+    }
+    @-webkit-keyframes firstLetterAnimation {
+        from { color: white; }
+        to { color: green; }
+    }
+  </style>
+  <script src="resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script type="text/javascript" charset="utf-8">
+    
+    const expectedValues = [
+      // [animation-name, time, element-id, property, expected-value, tolerance]
+      ["move1", 0.1, "box1", "left", 200, 20],
+      ["move1", 0.13, "box1", "left", 200, 20]
+    ];
+    
+    function stop()
+    {
+        box1Element = document.getElementById("box1");
+        box1Element.className = "paused";
+        box1Element.style.webkitAnimationPlayState = "paused";
+    }
+
+    function start()
+    {
+        box1Element = document.getElementById("box1");
+        box1Element.className = "running";
+        box1Element.style.webkitAnimationPlayState = "running";
+    }
+
+    function setTimers()
+    {
+        setTimeout(stop, 100);
+        setTimeout(start, 150);
+    }
+
+    var move1AnimationEnded = false;
+    function animationEnded(event)
+    {
+        if (event.animationName == "move1")
+            move1AnimationEnded = true;
+
+        if (event.animationName == "firstLetterAnimation" && move1AnimationEnded) {
+            document.getElementById('resultFirstLetter').innerHTML = "Test Failed: firstLetterAnimation should end before move1 animation<br>";
+        }
+    }
+
+    window.addEventListener("webkitAnimationEnd", animationEnded, false );
+    
+    runAnimationTest(expectedValues, setTimers, null, true);
+    
+  </script>
+</head>
+<body>
+<p>
+This tests the operation of -webkit-animation-play-state. After 100 milliseconds the box should stop and after 150 milliseconds
+it should start again. We test it both while in motion and when stopped.
+<div id="box1">
+    Lorem ipsum dolor sit amet.
+</div>
+<div id="box2">
+</div>
+<div id="result">
+</div>
+<div id="resultFirstLetter">
+</div>
+</body>
+</html>
diff --git a/LayoutTests/transitions/first-letter-color-transition-expected.txt b/LayoutTests/transitions/first-letter-color-transition-expected.txt
new file mode 100644 (file)
index 0000000..b057b0d
--- /dev/null
@@ -0,0 +1,2 @@
+Lorem ipsum dolor sit amet.
+PASS
diff --git a/LayoutTests/transitions/first-letter-color-transition.html b/LayoutTests/transitions/first-letter-color-transition.html
new file mode 100644 (file)
index 0000000..f0c595c
--- /dev/null
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style type="text/css" media="screen">
+    .box {
+      width: 100px;
+      height: 100px;
+      background-color: blue;
+    }
+    
+    .box::first-letter {
+      font-size: 24pt;
+      color: black;
+      -webkit-transition: color 0.1s;
+    }
+
+    body.go .box::first-letter {
+      color: white;
+    }
+
+</style>
+<script  type="text/javascript" charset="utf-8">
+   if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+
+    var result = "";
+    function transitionEnded(event)
+    {   
+        if (event.propertyName == "color")
+           result += "PASS";
+        else
+           result += "FAIL";
+
+        document.getElementById('result').innerHTML = result;
+        if (window.layoutTestController)
+            layoutTestController.notifyDone();
+    }
+
+    window.addEventListener('webkitTransitionEnd', transitionEnded, false);
+
+    window.addEventListener('load', function () {
+        document.body.className = "go";
+    }, false);
+</script>
+</head>
+<body>
+  <div class="box">
+    Lorem ipsum dolor sit amet.
+  </div>
+  <div id="result">
+  </div>
+</body>
+</html>
diff --git a/LayoutTests/transitions/first-letter-transition-expected.txt b/LayoutTests/transitions/first-letter-transition-expected.txt
new file mode 100644 (file)
index 0000000..5d448be
--- /dev/null
@@ -0,0 +1,10 @@
+Box One
+Box two
+Transtions test result: 
+
+PASS 
+PASS 
+PASS 
+PASS 
+PASS 
+
diff --git a/LayoutTests/transitions/first-letter-transition.html b/LayoutTests/transitions/first-letter-transition.html
new file mode 100644 (file)
index 0000000..becee08
--- /dev/null
@@ -0,0 +1,85 @@
+<html>
+<head>
+<style type="text/css" media="screen">
+    .box {
+      position: relative;
+      width: 100px;
+      height: 100px;
+      left: 100px;
+      background-color: blue;
+    }
+
+    .box::first-letter {
+      font-size: 24pt;
+      color: black;
+      -webkit-transition: color 0.1s 0.1s;
+    }
+
+    #first {
+      -webkit-transition: left 0.1s 0.15s;
+    }
+
+    #second {
+      -webkit-transition: all 0.1s 0.2s;
+    }
+
+    .animating #first {
+      left: 400px;
+    }
+
+    .animating #second {
+      -webkit-transform: rotate(360deg);
+      color: purple;
+    }
+
+    .animating *::first-letter {
+      color: white;
+    }
+
+
+</style>
+<script src="resources/transition-test-helpers.js"></script>
+<script  type="text/javascript" charset="utf-8">
+   if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+
+    var result = "Transtions test result: <br><br>";
+    var transitions = 0;
+    function transitionEnded(event)
+    {
+        if ((event.propertyName == "color") || (event.propertyName == "left") || (event.propertyName == "-webkit-transform"))
+           result += "PASS <br>";
+        else
+           result += "FAIL <br>";
+
+        ++transitions;
+
+        if (transitions == 5) {
+            document.getElementById('result').innerHTML = result;
+            if (window.layoutTestController)
+                layoutTestController.notifyDone();
+        }
+    }
+
+    window.addEventListener( 'webkitTransitionEnd', transitionEnded, false );
+
+    window.addEventListener("load", function () {
+        document.getElementById('container').className = 'animating';
+    }, false);
+</script>
+</head>
+<body>
+<div id="container">
+  <div id="first" class="box">
+      Box One
+  </div>
+  <div id="second" class="box">
+      Box two
+  </div>
+</div>
+  <div id="result">
+  </div>
+</body>
+</html>
index d75d459..9ab23c0 100644 (file)
@@ -1,3 +1,52 @@
+2012-06-12  Igor Oliveira  <igor.o@sisa.samsung.com>
+
+        Apply animations and transitions for first-letter element
+        https://bugs.webkit.org/show_bug.cgi?id=85253
+
+        Add animations and transitions support for the first-letter
+        pseudo element.
+        Instead of calling RenderOject::node() in the animations code,
+        now we need to call RenderObject::styledGeneratingNode() because
+        pseudo elements does not have a Node associated with the
+        RenderObject.
+
+        Initial patch by Simon Fraser
+
+        Reviewed by Simon Fraser.
+
+        Tests: animations/first-letter-animation.html
+               animations/first-letter-play-state.html
+               transitions/first-letter-color-transition.html
+               transitions/first-letter-transition.html
+
+        * page/animation/AnimationBase.cpp:
+        (WebCore::AnimationBase::updateStateMachine):
+        * page/animation/AnimationController.cpp:
+        (WebCore::AnimationControllerPrivate::updateAnimations):
+        (WebCore::AnimationControllerPrivate::pauseAnimationAtTime):
+        (WebCore::AnimationControllerPrivate::pauseTransitionAtTime):
+        (WebCore::AnimationController::cancelAnimations):
+        (WebCore::AnimationController::updateAnimations):
+        * page/animation/ImplicitAnimation.cpp:
+        (WebCore::ImplicitAnimation::pauseAnimation):
+        (WebCore::ImplicitAnimation::sendTransitionEvent):
+        * page/animation/KeyframeAnimation.cpp:
+        (WebCore::KeyframeAnimation::KeyframeAnimation):
+        (WebCore::KeyframeAnimation::pauseAnimation):
+        (WebCore::KeyframeAnimation::endAnimation):
+        (WebCore::KeyframeAnimation::sendAnimationEvent):
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::updateFirstLetterStyle):
+        (WebCore::RenderBlock::createFirstLetterRenderer):
+        * rendering/RenderInline.cpp:
+        (WebCore::RenderInline::clippedOverflowRectForRepaint):
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::setAnimatableStyle):
+        (WebCore::RenderObject::styledGeneratingNode):
+        (WebCore):
+        * rendering/RenderObject.h:
+        (RenderObject):
+
 2012-06-12  Kent Tamura  <tkent@chromium.org>
 
         Checking a radio button doesn't uncheck other buttons in the same group in some cases.
index 33d6326..9e80d89 100644 (file)
@@ -191,7 +191,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
 
                 // Trigger a render so we can start the animation
                 if (m_object)
-                    m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
+                    m_compAnim->animationController()->addNodeChangeToDispatch(m_object->styledGeneratingNode());
             } else {
                 ASSERT(!paused());
                 // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait
@@ -252,7 +252,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
 
                 // Dispatch updateStyleIfNeeded so we can start the animation
                 if (m_object)
-                    m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
+                    m_compAnim->animationController()->addNodeChangeToDispatch(m_object->styledGeneratingNode());
             } else {
                 // We are pausing while waiting for a start response. Cancel the animation and wait. When 
                 // we unpause, we will act as though the start timer just fired
@@ -298,7 +298,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
                         resumeOverriddenAnimations();
 
                     // Fire off another style change so we can set the final value
-                    m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
+                    m_compAnim->animationController()->addNodeChangeToDispatch(m_object->styledGeneratingNode());
                 }
             } else {
                 // We are pausing while running. Cancel the animation and wait
index c49119e..98858ff 100644 (file)
@@ -100,7 +100,7 @@ double AnimationControllerPrivate::updateAnimations(SetChanged callSetChanged/*
                 timeToNextService = t;
             if (!timeToNextService) {
                 if (callSetChanged == CallSetChanged) {
-                    Node* node = it->first->node();
+                    Node* node = it->first->styledGeneratingNode();
                     ASSERT(!node || (node->document() && !node->document()->inPageCache()));
                     node->setNeedsStyleRecalc(SyntheticStyleChange);
                     calledSetChanged = true;
@@ -328,7 +328,7 @@ bool AnimationControllerPrivate::pauseAnimationAtTime(RenderObject* renderer, co
         return false;
 
     if (compAnim->pauseAnimationAtTime(name, t)) {
-        renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
+        renderer->styledGeneratingNode()->setNeedsStyleRecalc(SyntheticStyleChange);
         startUpdateStyleIfNeededDispatcher();
         return true;
     }
@@ -346,7 +346,7 @@ bool AnimationControllerPrivate::pauseTransitionAtTime(RenderObject* renderer, c
         return false;
 
     if (compAnim->pauseTransitionAtTime(cssPropertyID(property), t)) {
-        renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
+        renderer->styledGeneratingNode()->setNeedsStyleRecalc(SyntheticStyleChange);
         startUpdateStyleIfNeededDispatcher();
         return true;
     }
@@ -508,7 +508,7 @@ void AnimationController::cancelAnimations(RenderObject* renderer)
         return;
 
     if (m_data->clear(renderer)) {
-        Node* node = renderer->node();
+        Node* node = renderer->styledGeneratingNode();
         ASSERT(!node || (node->document() && !node->document()->inPageCache()));
         node->setNeedsStyleRecalc(SyntheticStyleChange);
     }
@@ -533,7 +533,6 @@ PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* rend
     // against the animations in the style and make sure we're in sync.  If destination values
     // have changed, we reset the animation.  We then do a blend to get new values and we return
     // a new style.
-    ASSERT(renderer->node()); // FIXME: We do not animate generated content yet.
 
     RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer);
     RefPtr<RenderStyle> blendedStyle = rendererAnimations->animate(renderer, oldStyle, newStyle);
index f71a153..9789762 100644 (file)
@@ -129,7 +129,7 @@ void ImplicitAnimation::pauseAnimation(double timeOffset)
 #endif
     // Restore the original (unanimated) style
     if (!paused())
-        setNeedsStyleRecalc(m_object->node());
+        setNeedsStyleRecalc(m_object->styledGeneratingNode());
 }
 
 void ImplicitAnimation::endAnimation()
@@ -165,8 +165,8 @@ bool ImplicitAnimation::sendTransitionEvent(const AtomicString& eventType, doubl
                 
             // Dispatch the event
             RefPtr<Element> element = 0;
-            if (m_object->node() && m_object->node()->isElementNode())
-                element = static_cast<Element*>(m_object->node());
+            if (m_object->styledGeneratingNode() && m_object->styledGeneratingNode()->isElementNode())
+                element = static_cast<Element*>(m_object->styledGeneratingNode());
 
             ASSERT(!element || (element->document() && !element->document()->inPageCache()));
             if (!element)
index da2915d..53f246d 100644 (file)
@@ -51,8 +51,8 @@ KeyframeAnimation::KeyframeAnimation(const Animation* animation, RenderObject* r
     , m_unanimatedStyle(unanimatedStyle)
 {
     // Get the keyframe RenderStyles
-    if (m_object && m_object->node() && m_object->node()->isElementNode())
-        m_object->document()->styleResolver()->keyframeStylesForAnimation(static_cast<Element*>(m_object->node()), unanimatedStyle, m_keyframes);
+    if (m_object && m_object->styledGeneratingNode() && m_object->styledGeneratingNode()->isElementNode())
+        m_object->document()->styleResolver()->keyframeStylesForAnimation(static_cast<Element*>(m_object->styledGeneratingNode()), unanimatedStyle, m_keyframes);
 
     // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
     validateTransformFunctionList();
@@ -255,7 +255,7 @@ void KeyframeAnimation::pauseAnimation(double timeOffset)
 #endif
     // Restore the original (unanimated) style
     if (!paused())
-        setNeedsStyleRecalc(m_object->node());
+        setNeedsStyleRecalc(m_object->styledGeneratingNode());
 }
 
 void KeyframeAnimation::endAnimation()
@@ -269,7 +269,7 @@ void KeyframeAnimation::endAnimation()
 #endif
     // Restore the original (unanimated) style
     if (!paused())
-        setNeedsStyleRecalc(m_object->node());
+        setNeedsStyleRecalc(m_object->styledGeneratingNode());
 }
 
 bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) const
@@ -314,8 +314,8 @@ bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double
     if (shouldSendEventForListener(listenerType)) {
         // Dispatch the event
         RefPtr<Element> element;
-        if (m_object->node() && m_object->node()->isElementNode())
-            element = static_cast<Element*>(m_object->node());
+        if (m_object->styledGeneratingNode() && m_object->styledGeneratingNode()->isElementNode())
+            element = static_cast<Element*>(m_object->styledGeneratingNode());
 
         ASSERT(!element || (element->document() && !element->document()->inPageCache()));
         if (!element)
index 99a2493..1ea90c7 100755 (executable)
@@ -6051,12 +6051,13 @@ void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderO
         firstLetter->destroy();
         firstLetter = newFirstLetter;
         firstLetterContainer->addChild(firstLetter, nextSibling);
-    } else
-        firstLetter->setStyle(pseudoStyle);
+    }
+
+    firstLetter->setAnimatableStyle(pseudoStyle);
 
     for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) {
         if (genChild->isText())
-            genChild->setStyle(pseudoStyle);
+            genChild->setStyle(firstLetter->style());
     }
 }
 
@@ -6069,8 +6070,13 @@ void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, Rend
         firstLetter = new (renderArena()) RenderInline(document());
     else
         firstLetter = new (renderArena()) RenderBlock(document());
-    firstLetter->setStyle(pseudoStyle);
+
+    RefPtr<RenderStyle> temporaryStyle = RenderStyle::create();
+    temporaryStyle->inheritFrom(firstLetterBlock->style());
+    firstLetter->setStyle(temporaryStyle);  
     firstLetterContainer->addChild(firstLetter, currentChild);
+    
+    firstLetter->setAnimatableStyle(pseudoStyle);
 
     RenderText* textObj = toRenderText(currentChild);
 
@@ -6118,7 +6124,7 @@ void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, Rend
         // construct text fragment for the first letter
         RenderTextFragment* letter = 
             new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length);
-        letter->setStyle(pseudoStyle);
+        letter->setStyle(firstLetter->style());
         firstLetter->addChild(letter);
 
         textObj->destroy();
index 0e0b453..91a05ad 100644 (file)
@@ -953,8 +953,8 @@ LayoutRect RenderInline::linesVisualOverflowBoundingBox() const
 
 LayoutRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const
 {
-    // Only run-ins are allowed in here during layout.
-    ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
+    // Only run-ins and first-letter elements are allowed in here during layout.
+    ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn() || style()->styleType() == FIRST_LETTER);
 
     if (!firstLineBoxIncludingCulling() && !continuation())
         return LayoutRect();
index 797e5bf..563e594 100755 (executable)
@@ -2134,6 +2134,21 @@ bool RenderObject::isRooted(RenderView** view)
     return true;
 }
 
+Node* RenderObject::styledGeneratingNode() const
+{
+    Node* node = generatingNode();
+    if (node)
+        return node;
+
+    for (RenderObject* object = parent(); object; object = object->parent()) {
+        if (Node* node = object->generatingNode())
+            return node;
+    }
+
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
 RenderObject* RenderObject::rendererForRootBackground()
 {
     ASSERT(isRoot());
index 8d37445..523de2f 100644 (file)
@@ -563,10 +563,16 @@ public:
 
     Node* node() const { return isAnonymous() ? 0 : m_node; }
 
-    // Returns the styled node that caused the generation of this renderer.
-    // This is the same as node() except for renderers of :before and :after
+    // This is the same as node() except for renderers of :before. :after and first-letter
     // pseudo elements for which their parent node is returned.
     Node* generatingNode() const { return m_node == document() ? 0 : m_node; }
+
+    // Returns the styled node that caused the generation of this renderer.
+    // This is the same as node() except for anonymous renderers, for which
+    // it returns the node whose style caused the generation of this renderer.
+    // FIXME: merge with generatingNode()
+    Node* styledGeneratingNode() const;
+
     void setNode(Node* node) { m_node = node; }
 
     Document* document() const { return m_node->document(); }
@@ -648,8 +654,6 @@ public:
     virtual void dirtyLinesFromChangedChild(RenderObject*);
 
     // Called to update a style that is allowed to trigger animations.
-    // FIXME: Right now this will typically be called only when updating happens from the DOM on explicit elements.
-    // We don't yet handle generated content animation such as first-letter or before/after (we'll worry about this later).
     void setAnimatableStyle(PassRefPtr<RenderStyle>);
 
     // Set the style of the object and update the state of the object accordingly.