Changeset 142215 in webkit


Ignore:
Timestamp:
Feb 7, 2013 5:40:30 PM (11 years ago)
Author:
esprehn@chromium.org
Message:

getComputedStyle() doesn't report intermediate values during a transition of a pseudo element
https://bugs.webkit.org/show_bug.cgi?id=106535

Reviewed by Ojan Vafai.

Source/WebCore:

Element::computedStyle and CSSComputedStyleDeclaration::getPropertyCSSValue
should use the PseudoElement and it's renderer if they exist so that
querying the computed style while an animation is running returns
the intermediate values.

No new tests, updated existing tests.

  • css/CSSComputedStyleDeclaration.cpp:

(WebCore::CSSComputedStyleDeclaration::styledNode): Added, returns either the PseudoElement or the Node.
(WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue): Updated to use styledNode.

  • css/CSSComputedStyleDeclaration.h:

(CSSComputedStyleDeclaration):

  • dom/Element.cpp:

(WebCore::Element::computedStyle): Check the PseudoElement, not just the cached pseudo style.

  • dom/ElementRareData.h:

(WebCore::ElementRareData::pseudoElement): Remove ASSERT_NOT_REACHED so passing other pseudos returns 0.

LayoutTests:

Update tests to also check getComputedStyle during animations and transitions.

  • fast/css-generated-content/pseudo-animation-expected.txt:
  • fast/css-generated-content/pseudo-animation.html:
  • fast/css-generated-content/pseudo-transition-expected.txt:
  • fast/css-generated-content/pseudo-transition.html:
Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r142214 r142215  
     12013-02-07  Elliott Sprehn  <esprehn@chromium.org>
     2
     3        getComputedStyle() doesn't report intermediate values during a transition of a pseudo element
     4        https://bugs.webkit.org/show_bug.cgi?id=106535
     5
     6        Reviewed by Ojan Vafai.
     7
     8        Update tests to also check getComputedStyle during animations and transitions.
     9
     10        * fast/css-generated-content/pseudo-animation-expected.txt:
     11        * fast/css-generated-content/pseudo-animation.html:
     12        * fast/css-generated-content/pseudo-transition-expected.txt:
     13        * fast/css-generated-content/pseudo-transition.html:
     14
    1152013-02-07  Kent Tamura  <tkent@chromium.org>
    216
  • trunk/LayoutTests/fast/css-generated-content/pseudo-animation-expected.txt

    r138632 r142215  
    55
    66PASS div.offsetWidth is 52
    7 PASS div.offsetWidth is 20
    8 PASS div.offsetWidth is 12
     7PASS div.offsetWidth is within 1 of 20
     8PASS computedTop is within 1 of 170
     9PASS div.offsetWidth is within 1 of 12
     10PASS computedTop is within 1 of 200
    911PASS div.offsetWidth is 52
    10 PASS div.offsetWidth is 20
    11 PASS div.offsetWidth is 12
     12PASS div.offsetWidth is within 1 of 20
     13PASS computedTop is within 1 of 170
     14PASS div.offsetWidth is within 1 of 12
     15PASS computedTop is within 1 of 200
    1216PASS successfullyParsed is true
    1317
  • trunk/LayoutTests/fast/css-generated-content/pseudo-animation.html

    r138632 r142215  
    88    width: 50px;
    99    height: 50px;
     10    top: 50px;
    1011  }
    1112  to {
    1213    width: 10px;
    1314    height: 10px;
     15    top: 200px;
    1416  }
    1517}
     
    1921    width: 50px;
    2022    height: 50px;
     23    top: 50px;
    2124  }
    2225  to {
    2326    width: 10px;
    2427    height: 10px;
     28    top: 200px;
    2529  }
    2630}
     
    3236    height: 50px;
    3337    width: 50px;
     38    position: relative;
    3439}
    3540
    3641#after.animate:after,
    3742#before.animate:before {
     43    top: 200px;
    3844    width: 10px;
    3945    height: 10px;
     
    6571    testRunner.dumpAsText();
    6672
     73function getPseudoComputedTop(id)
     74{
     75    return Math.round(parseFloat(getComputedStyle(document.getElementById(id), ':' + id).top));
     76}
     77
     78// FIXME: This test should be modified so subpixel doesn't cause off by one
     79// below and it no longer needs shouldBeCloseTo.
     80
    6781function testAnimation(id)
    6882{
     
    7387    if (window.internals) {
    7488        internals.pauseAnimationAtTimeOnPseudoElement('example', 1.0, div, id);
    75         shouldBe('div.offsetWidth', '20');
     89        shouldBeCloseTo('div.offsetWidth', 20, 1);
     90        computedTop = getPseudoComputedTop(id);
     91        shouldBeCloseTo('computedTop', 170, 1);
    7692        internals.pauseAnimationAtTimeOnPseudoElement('example', 2.0, div, id);
    77         shouldBe('div.offsetWidth', '12');
     93        shouldBeCloseTo('div.offsetWidth', 12, 1);
     94        computedTop = getPseudoComputedTop(id);
     95        shouldBeCloseTo('computedTop', 200, 1);
    7896    } else {
    7997        // This will be flaky, but it's a reasonable approximation for testing
     
    8199        setTimeout(function() {
    82100            window.div = div;
    83             shouldBe('div.offsetWidth', '20');
     101            shouldBeCloseTo('div.offsetWidth', 20, 1);
     102            computedTop = getPseudoComputedTop(id);
     103            shouldBeCloseTo('computedTop', 170, 1);
    84104        }, 1000);
    85105        setTimeout(function() {
    86106            window.div = div;
    87             shouldBe('div.offsetWidth', '12');
     107            shouldBeCloseTo('div.offsetWidth', 12, 1);
     108            computedTop = getPseudoComputedTop(id);
     109            shouldBeCloseTo('computedTop', 200, 1);
    88110        }, 2000);
    89111    }
  • trunk/LayoutTests/fast/css-generated-content/pseudo-transition-expected.txt

    r138632 r142215  
    55
    66PASS div.offsetWidth is 52
    7 PASS div.offsetWidth is 20
    8 PASS div.offsetWidth is 12
     7PASS div.offsetWidth is within 1 of 20
     8PASS computedTop is within 1 of 170
     9PASS div.offsetWidth is within 1 of 12
     10PASS computedTop is within 1 of 200
    911PASS div.offsetWidth is 52
    10 PASS div.offsetWidth is 20
    11 PASS div.offsetWidth is 12
     12PASS div.offsetWidth is within 1 of 20
     13PASS computedTop is within 1 of 170
     14PASS div.offsetWidth is within 1 of 12
     15PASS computedTop is within 1 of 200
    1216PASS successfullyParsed is true
    1317
  • trunk/LayoutTests/fast/css-generated-content/pseudo-transition.html

    r138632 r142215  
    1010    height: 50px;
    1111    width: 50px;
    12     -webkit-transition: width 2s;
    13     -moz-transition: width 2s;
    14     transition: width 2s;
     12    top: 50px;
     13    position: relative;
     14    -webkit-transition: width 2s, top 2s;
     15    -moz-transition: width 2s, top 2s;
     16    transition: width 2s, top 2s;
    1517}
    1618
    1719#before.transition:before,
    1820#after.transition:after {
     21    top: 200px;
    1922    height: 10px;
    2023    width: 10px;
     
    4346    testRunner.dumpAsText();
    4447
     48function getPseudoComputedTop(id)
     49{
     50    return Math.round(parseFloat(getComputedStyle(document.getElementById(id), ':' + id).top));
     51}
     52
     53// FIXME: This test should be modified so subpixel doesn't cause off by one
     54// below and it no longer needs shouldBeCloseTo.
     55
    4556function testTransition(id)
    4657{
     
    5162    if (window.internals) {
    5263        internals.pauseTransitionAtTimeOnPseudoElement('width', 1.0, div, id);
    53         shouldBe('div.offsetWidth', '20');
     64        shouldBeCloseTo('div.offsetWidth', 20, 1);
     65        internals.pauseTransitionAtTimeOnPseudoElement('top', 1.0, div, id);
     66        computedTop = getPseudoComputedTop(id);
     67        shouldBeCloseTo('computedTop', 170, 1);
    5468        internals.pauseTransitionAtTimeOnPseudoElement('width', 2.0, div, id);
    55         shouldBe('div.offsetWidth', '12');
     69        shouldBeCloseTo('div.offsetWidth', 12, 1);
     70        internals.pauseTransitionAtTimeOnPseudoElement('top', 2.0, div, id);
     71        computedTop = getPseudoComputedTop(id);
     72        shouldBeCloseTo('computedTop', 200, 1);
    5673    } else {
    5774        // This will be flaky, but it's a reasonable approximation for testing
     
    5976        setTimeout(function() {
    6077            window.div = div;
    61             shouldBe('div.offsetWidth', '20');
     78            shouldBeCloseTo('div.offsetWidth', 20, 1);
     79            computedTop = getPseudoComputedTop(id);
     80            shouldBeCloseTo('computedTop', 170, 1);
    6281        }, 1000);
    6382        setTimeout(function() {
    6483            window.div = div;
    65             shouldBe('div.offsetWidth', '12');
     84            shouldBeCloseTo('div.offsetWidth', 12, 1);
     85            computedTop = getPseudoComputedTop(id);
     86            shouldBeCloseTo('computedTop', 200, 1);
    6687        }, 2000);
    6788    }
  • trunk/Source/WebCore/ChangeLog

    r142213 r142215  
     12013-02-07  Elliott Sprehn  <esprehn@chromium.org>
     2
     3        getComputedStyle() doesn't report intermediate values during a transition of a pseudo element
     4        https://bugs.webkit.org/show_bug.cgi?id=106535
     5
     6        Reviewed by Ojan Vafai.
     7
     8        Element::computedStyle and CSSComputedStyleDeclaration::getPropertyCSSValue
     9        should use the PseudoElement and it's renderer if they exist so that
     10        querying the computed style while an animation is running returns
     11        the intermediate values.
     12
     13        No new tests, updated existing tests.
     14
     15        * css/CSSComputedStyleDeclaration.cpp:
     16        (WebCore::CSSComputedStyleDeclaration::styledNode): Added, returns either the PseudoElement or the Node.
     17        (WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue): Updated to use styledNode.
     18        * css/CSSComputedStyleDeclaration.h:
     19        (CSSComputedStyleDeclaration):
     20        * dom/Element.cpp:
     21        (WebCore::Element::computedStyle): Check the PseudoElement, not just the cached pseudo style.
     22        * dom/ElementRareData.h:
     23        (WebCore::ElementRareData::pseudoElement): Remove ASSERT_NOT_REACHED so passing other pseudos returns 0.
     24
    1252013-02-07  Mark Lam  <mark.lam@apple.com>
    226
  • trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp

    r142168 r142215  
    5252#include "HTMLFrameOwnerElement.h"
    5353#include "Pair.h"
     54#include "PseudoElement.h"
    5455#include "Rect.h"
    5556#include "RenderBox.h"
     
    15111512}
    15121513
     1514Node* CSSComputedStyleDeclaration::styledNode() const
     1515{
     1516    if (!m_node)
     1517        return 0;
     1518    if (m_node->isElementNode()) {
     1519        if (PseudoElement* element = toElement(m_node.get())->pseudoElement(m_pseudoElementSpecifier))
     1520            return element;
     1521    }
     1522    return m_node.get();
     1523}
     1524
    15131525PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(CSSPropertyID propertyID, EUpdateLayout updateLayout) const
    15141526{
    1515     Node* node = m_node.get();
    1516     if (!node)
     1527    Node* styledNode = this->styledNode();
     1528    if (!styledNode)
    15171529        return 0;
    15181530
    15191531    if (updateLayout) {
    1520         Document* document = m_node->document();
     1532        Document* document = styledNode->document();
    15211533        // FIXME: Some of these cases could be narrowed down or optimized better.
    15221534        bool forceFullLayout = isLayoutDependentProperty(propertyID)
    1523             || node->isInShadowTree()
     1535            || styledNode->isInShadowTree()
    15241536            || (document->styleResolverIfExists() && document->styleResolverIfExists()->hasViewportDependentMediaQueries() && document->ownerElement())
    15251537            || document->seamlessParentIFrame();
     
    15291541        else {
    15301542            bool needsStyleRecalc = document->hasPendingForcedStyleRecalc();
    1531             for (Node* n = m_node.get(); n && !needsStyleRecalc; n = n->parentNode())
     1543            for (Node* n = styledNode; n && !needsStyleRecalc; n = n->parentNode())
    15321544                needsStyleRecalc = n->needsStyleRecalc();
    15331545            if (needsStyleRecalc)
    15341546                document->updateStyleIfNeeded();
    15351547        }
    1536     }
    1537 
    1538     RenderObject* renderer = node->renderer();
     1548
     1549        // The style recalc could have caused the styled node to be discarded or replaced
     1550        // if it was a PseudoElement so we need to update it.
     1551        styledNode = this->styledNode();
     1552    }
     1553
     1554    RenderObject* renderer = styledNode->renderer();
    15391555
    15401556    RefPtr<RenderStyle> style;
     
    15421558        AnimationUpdateBlock animationUpdateBlock(renderer->animation());
    15431559        style = renderer->animation()->getAnimatedStyleForRenderer(renderer);
    1544         if (m_pseudoElementSpecifier) {
     1560        if (m_pseudoElementSpecifier && !styledNode->isPseudoElement()) {
    15451561            // FIXME: This cached pseudo style will only exist if the animation has been run at least once.
    15461562            style = style->getCachedPseudoStyle(m_pseudoElementSpecifier);
    15471563        }
    15481564    } else
    1549         style = node->computedStyle(m_pseudoElementSpecifier);
     1565        style = styledNode->computedStyle(styledNode->isPseudoElement() ? NOPSEUDO : m_pseudoElementSpecifier);
    15501566
    15511567    if (!style)
    15521568        return 0;
    1553 
    1554     if (node->isElementNode() && (m_pseudoElementSpecifier == BEFORE || m_pseudoElementSpecifier == AFTER))
    1555         renderer = toElement(node)->pseudoElementRenderer(m_pseudoElementSpecifier);
    15561569
    15571570    propertyID = CSSProperty::resolveDirectionAwareProperty(propertyID, style->direction(), style->writingMode());
     
    18391852        case CSSPropertyWebkitAlignSelf:
    18401853            if (style->alignSelf() == AlignAuto) {
    1841                 if (m_node && m_node->parentNode() && m_node->parentNode()->computedStyle())
    1842                     return cssValuePool().createValue(m_node->parentNode()->computedStyle()->alignItems());
     1854                Node* parent = styledNode->parentNode();
     1855                if (parent && parent->computedStyle())
     1856                    return cssValuePool().createValue(parent->computedStyle()->alignItems());
    18431857                return cssValuePool().createValue(AlignStretch);
    18441858            }
  • trunk/Source/WebCore/css/CSSComputedStyleDeclaration.h

    r132952 r142215  
    7979    CSSComputedStyleDeclaration(PassRefPtr<Node>, bool allowVisitedStyle, const String&);
    8080
     81    // The styled node is either the node passed into getComputedStyle, or the
     82    // PseudoElement for :before and :after if they exist.
     83    // FIXME: This should be styledElement since in JS getComputedStyle only works
     84    // on Elements, but right now editing creates these for text nodes. We should fix
     85    // that.
     86    Node* styledNode() const;
     87
    8188    // CSSOM functions. Don't make these public.
    8289    virtual CSSRule* parentRule() const;
  • trunk/Source/WebCore/dom/Element.cpp

    r141816 r142215  
    19921992RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
    19931993{
     1994    if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
     1995        return element->computedStyle();
     1996
    19941997    // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
    19951998    // properties, which are only known by the renderer because it did the layout, will be correct and so that the
  • trunk/Source/WebCore/dom/ElementRareData.h

    r141524 r142215  
    241241        return m_generatedAfter.get();
    242242    default:
    243         ASSERT_NOT_REACHED();
    244243        return 0;
    245244    }
Note: See TracChangeset for help on using the changeset viewer.