Changeset 181515 in webkit


Ignore:
Timestamp:
Mar 15, 2015, 4:07:37 PM (10 years ago)
Author:
Simon Fraser
Message:

Reduce the side-effects of animations turning off overlap testing
https://bugs.webkit.org/show_bug.cgi?id=92791

Reviewed by Dean Jackson.

Source/WebCore:

When a layer is running a transition or animation of the transform property,
we would simply disable overlap testing for later layers, which had the side-effect
of promoting lots of unrelated elements into layers temporarily.

Fix by maintaining overlap, but computing an overlap extent that takes the animation
into account.

Rotations are currently treated as full rotations. If an extent for the overlap is
hard to compute (e.g. 3d transforms, or matrix animations with a rotation component),
then we fall back to the current behavior.

Tests: compositing/layer-creation/mismatched-rotated-transform-animation-overlap.html

compositing/layer-creation/mismatched-rotated-transform-transition-overlap.html
compositing/layer-creation/mismatched-transform-transition-overlap.html
compositing/layer-creation/multiple-keyframes-animation-overlap.html
compositing/layer-creation/scale-rotation-animation-overlap.html
compositing/layer-creation/scale-rotation-transition-overlap.html
compositing/layer-creation/translate-animation-overlap.html
compositing/layer-creation/translate-scale-animation-overlap.html
compositing/layer-creation/translate-scale-transition-overlap.html
compositing/layer-creation/translate-transition-overlap.html

  • page/animation/AnimationBase.cpp:

(WebCore::containsRotation):
(WebCore::AnimationBase::computeTransformedExtentViaTransformList): When we have matched
transform lists, we can map a rectangle through the various operations. Transform-origin
is used to shift the origin of the box first, and then unshift after. If we encounter
a rotation, for now assume it's a full rotation (a future patch could tighten this up).
(WebCore::AnimationBase::computeTransformedExtentViaMatrix): If we're using matrix
interpolation, we have to decompose the matrix to see if there's any rotation component,
and, if there is, fall back to current behavior.

  • page/animation/AnimationBase.h:
  • page/animation/AnimationController.cpp:

(WebCore::AnimationControllerPrivate::computeExtentOfAnimation):
(WebCore::AnimationController::computeExtentOfAnimation):

  • page/animation/AnimationController.h:
  • page/animation/AnimationControllerPrivate.h:
  • page/animation/CompositeAnimation.cpp:

(WebCore::CompositeAnimation::computeExtentOfTransformAnimation): Ask active keyframe
animations and transitions to compute the bounds extent.

  • page/animation/CompositeAnimation.h:
  • page/animation/ImplicitAnimation.cpp:

(WebCore::ImplicitAnimation::computeExtentOfTransformAnimation): Compute the extent
of the start and end transforms, and union them.

  • page/animation/ImplicitAnimation.h:
  • page/animation/KeyframeAnimation.cpp:

(WebCore::KeyframeAnimation::animate):
(WebCore::KeyframeAnimation::getAnimatedStyle): Some nullptr goodness.
(WebCore::KeyframeAnimation::computeExtentOfTransformAnimation): Compute an extent
for each keyframe, and take their union.

  • page/animation/KeyframeAnimation.h:
  • platform/graphics/GeometryUtilities.cpp:

(WebCore::euclidianDistance): Use Pythagoras to compute a distance.
(WebCore::boundsOfRotatingRect): Given a rect whose location is relative
to the rotation origin, compute a bounds for the rotated rect by computing
the furthest corner from the origin, and sweeping out a circle.

  • platform/graphics/GeometryUtilities.h:
  • platform/graphics/transforms/Matrix3DTransformOperation.h:
  • platform/graphics/transforms/MatrixTransformOperation.h:
  • platform/graphics/transforms/PerspectiveTransformOperation.h:
  • platform/graphics/transforms/RotateTransformOperation.h:
  • platform/graphics/transforms/ScaleTransformOperation.h:
  • platform/graphics/transforms/SkewTransformOperation.h:
  • platform/graphics/transforms/TransformOperation.h:

(WebCore::TransformOperation::isAffectedByTransformOrigin):

  • platform/graphics/transforms/TransformOperations.cpp:

(WebCore::TransformOperations::affectedByTransformOrigin): Ask all the operations if
they are affected by transform-origin.
(WebCore::TransformOperations::blendByMatchingOperations): nullptr.

  • platform/graphics/transforms/TransformOperations.h:
  • rendering/RenderBox.cpp:

(WebCore::RenderBox::pushMappingToContainer): Comment fix. Only take transforms into account
if the geometry map says so (which is most of the time).

  • rendering/RenderGeometryMap.cpp:

(WebCore::RenderGeometryMap::mapToContainer): RenderLayerCompositor is now using the
geometry map in a way that is incompatible with this assertion; it deliberately ignores
transforms sometimes, so we can't easily verify that the mapping matches mapping through
renderers.
(WebCore::RenderGeometryMap::pushMappingsToAncestor): Save and restore the UseTransforms
bit.

  • rendering/RenderGeometryMap.h:
  • rendering/RenderLayer.cpp:

(WebCore::RenderLayer::boundingBox): Whitespace.
(WebCore::RenderLayer::getOverlapBoundsIncludingChildrenAccountingForTransformAnimations): Helper
function to get the bounds of a layer, including descendants, when a transform animation is running.

  • rendering/RenderLayer.h:
  • rendering/RenderLayerCompositor.cpp:

(WebCore::RenderLayerCompositor::CompositingState::CompositingState): Add a ancestorHasTransformAnimation
flag to detect nested animated transforms.
(WebCore::RenderLayerCompositor::OverlapExtent::knownToBeHaveExtentUncertainty): This returns true when
the layer is animating transform, and the transition/animation is such that we can't easily compute the
bounds of the animation.
(WebCore::RenderLayerCompositor::computeExtent): const RenderLayer&.
Compute the animated bounds if there's a transform animation running.
(WebCore::RenderLayerCompositor::addToOverlapMap): const RenderLayer&
(WebCore::RenderLayerCompositor::addToOverlapMapRecursive): const RenderLayer&
(WebCore::RenderLayerCompositor::computeCompositingRequirements):
Delay the call to pushMappingsToAncestor() until knowing if there's a transform animation running, and
if there is, push the mapping while ignoring transforms (since the transform is implicitly taken into account
for overlap via the computed animated bounds).
If this layer is running a transform animation, set the childState.ancestorHasTransformAnimation flag so
that descendants will know (nested transform animations fall back to current behavior).
The if (.... && isRunningAcceleratedTransformAnimation()) is what previously caused us to turn off overlap
testing in the face of animations. That now only happens if we were unable to easily compute the animation bounds.
(WebCore::RenderLayerCompositor::isRunningTransformAnimation): This previously tested whether an accelerated animation
was running, but that's timing sensitive; AnimationController can start the transform animation, but it's not yet
considered accelerated until we get an async callback from GraphicsLayer, yet this code needed to know if the
animation was running.
Since transform animations are always accelerated, we can just test for a running transform animation.
(WebCore::RenderLayerCompositor::isRunningAcceleratedTransformAnimation): Deleted.

  • rendering/RenderLayerCompositor.h:
  • rendering/style/RenderStyle.cpp:

(WebCore::requireTransformOrigin): Some FIXME comments.

LayoutTests:

These test overlay an animated element with a grid of position: relative squares.
These reveal the overlap area by selectively getting composited.

  • compositing/layer-creation/animation-overlap-with-children-expected.txt:
  • compositing/layer-creation/mismatched-rotated-transform-animation-overlap-expected.txt: Added.
  • compositing/layer-creation/mismatched-rotated-transform-animation-overlap.html: Added.
  • compositing/layer-creation/mismatched-rotated-transform-transition-overlap-expected.txt: Added.
  • compositing/layer-creation/mismatched-rotated-transform-transition-overlap.html: Added.
  • compositing/layer-creation/mismatched-transform-transition-overlap-expected.txt: Added.
  • compositing/layer-creation/mismatched-transform-transition-overlap.html: Added.
  • compositing/layer-creation/multiple-keyframes-animation-overlap-expected.txt: Added.
  • compositing/layer-creation/multiple-keyframes-animation-overlap.html: Added.
  • compositing/layer-creation/scale-rotation-animation-overlap-expected.txt: Added.
  • compositing/layer-creation/scale-rotation-animation-overlap.html: Added.
  • compositing/layer-creation/scale-rotation-transition-overlap-expected.txt: Added.
  • compositing/layer-creation/scale-rotation-transition-overlap.html: Added.
  • compositing/layer-creation/translate-animation-overlap-expected.txt: Added.
  • compositing/layer-creation/translate-animation-overlap.html: Added.
  • compositing/layer-creation/translate-scale-animation-overlap-expected.txt: Added.
  • compositing/layer-creation/translate-scale-animation-overlap.html: Added.
  • compositing/layer-creation/translate-scale-transition-overlap-expected.txt: Added.
  • compositing/layer-creation/translate-scale-transition-overlap.html: Added.
  • compositing/layer-creation/translate-transition-overlap-expected.txt: Added.
  • compositing/layer-creation/translate-transition-overlap.html: Added.
Location:
trunk
Files:
20 added
33 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r181512 r181515  
     12015-03-15  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Reduce the side-effects of animations turning off overlap testing
     4        https://bugs.webkit.org/show_bug.cgi?id=92791
     5
     6        Reviewed by Dean Jackson.
     7       
     8        These test overlay an animated element with a grid of position: relative squares.
     9        These reveal the overlap area by selectively getting composited.
     10
     11        * compositing/layer-creation/animation-overlap-with-children-expected.txt:
     12        * compositing/layer-creation/mismatched-rotated-transform-animation-overlap-expected.txt: Added.
     13        * compositing/layer-creation/mismatched-rotated-transform-animation-overlap.html: Added.
     14        * compositing/layer-creation/mismatched-rotated-transform-transition-overlap-expected.txt: Added.
     15        * compositing/layer-creation/mismatched-rotated-transform-transition-overlap.html: Added.
     16        * compositing/layer-creation/mismatched-transform-transition-overlap-expected.txt: Added.
     17        * compositing/layer-creation/mismatched-transform-transition-overlap.html: Added.
     18        * compositing/layer-creation/multiple-keyframes-animation-overlap-expected.txt: Added.
     19        * compositing/layer-creation/multiple-keyframes-animation-overlap.html: Added.
     20        * compositing/layer-creation/scale-rotation-animation-overlap-expected.txt: Added.
     21        * compositing/layer-creation/scale-rotation-animation-overlap.html: Added.
     22        * compositing/layer-creation/scale-rotation-transition-overlap-expected.txt: Added.
     23        * compositing/layer-creation/scale-rotation-transition-overlap.html: Added.
     24        * compositing/layer-creation/translate-animation-overlap-expected.txt: Added.
     25        * compositing/layer-creation/translate-animation-overlap.html: Added.
     26        * compositing/layer-creation/translate-scale-animation-overlap-expected.txt: Added.
     27        * compositing/layer-creation/translate-scale-animation-overlap.html: Added.
     28        * compositing/layer-creation/translate-scale-transition-overlap-expected.txt: Added.
     29        * compositing/layer-creation/translate-scale-transition-overlap.html: Added.
     30        * compositing/layer-creation/translate-transition-overlap-expected.txt: Added.
     31        * compositing/layer-creation/translate-transition-overlap.html: Added.
     32
    1332015-03-15  Benjamin Poulain  <bpoulain@apple.com>
    234
  • trunk/LayoutTests/compositing/layer-creation/animation-overlap-with-children-expected.txt

    r180441 r181515  
    88      (bounds 800.00 600.00)
    99      (contentsOpaque 1)
    10       (children 2
     10      (children 1
    1111        (GraphicsLayer
    1212          (position 8.00 8.00)
     
    2727          )
    2828        )
    29         (GraphicsLayer
    30           (position 18.00 230.00)
    31           (bounds 100.00 100.00)
    32           (contentsOpaque 1)
    33           (drawsContent 1)
    34         )
    3529      )
    3630    )
  • trunk/Source/WebCore/ChangeLog

    r181514 r181515  
     12015-03-15  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Reduce the side-effects of animations turning off overlap testing
     4        https://bugs.webkit.org/show_bug.cgi?id=92791
     5
     6        Reviewed by Dean Jackson.
     7       
     8        When a layer is running a transition or animation of the transform property,
     9        we would simply disable overlap testing for later layers, which had the side-effect
     10        of promoting lots of unrelated elements into layers temporarily.
     11       
     12        Fix by maintaining overlap, but computing an overlap extent that takes the animation
     13        into account.
     14       
     15        Rotations are currently treated as full rotations. If an extent for the overlap is
     16        hard to compute (e.g. 3d transforms, or matrix animations with a rotation component),
     17        then we fall back to the current behavior.
     18
     19        Tests: compositing/layer-creation/mismatched-rotated-transform-animation-overlap.html
     20               compositing/layer-creation/mismatched-rotated-transform-transition-overlap.html
     21               compositing/layer-creation/mismatched-transform-transition-overlap.html
     22               compositing/layer-creation/multiple-keyframes-animation-overlap.html
     23               compositing/layer-creation/scale-rotation-animation-overlap.html
     24               compositing/layer-creation/scale-rotation-transition-overlap.html
     25               compositing/layer-creation/translate-animation-overlap.html
     26               compositing/layer-creation/translate-scale-animation-overlap.html
     27               compositing/layer-creation/translate-scale-transition-overlap.html
     28               compositing/layer-creation/translate-transition-overlap.html
     29
     30        * page/animation/AnimationBase.cpp:
     31        (WebCore::containsRotation):
     32        (WebCore::AnimationBase::computeTransformedExtentViaTransformList): When we have matched
     33        transform lists, we can map a rectangle through the various operations. Transform-origin
     34        is used to shift the origin of the box first, and then unshift after. If we encounter
     35        a rotation, for now assume it's a full rotation (a future patch could tighten this up).
     36        (WebCore::AnimationBase::computeTransformedExtentViaMatrix): If we're using matrix
     37        interpolation, we have to decompose the matrix to see if there's any rotation component,
     38        and, if there is, fall back to current behavior.
     39        * page/animation/AnimationBase.h:
     40        * page/animation/AnimationController.cpp:
     41        (WebCore::AnimationControllerPrivate::computeExtentOfAnimation):
     42        (WebCore::AnimationController::computeExtentOfAnimation):
     43        * page/animation/AnimationController.h:
     44        * page/animation/AnimationControllerPrivate.h:
     45        * page/animation/CompositeAnimation.cpp:
     46        (WebCore::CompositeAnimation::computeExtentOfTransformAnimation): Ask active keyframe
     47        animations and transitions to compute the bounds extent.
     48        * page/animation/CompositeAnimation.h:
     49        * page/animation/ImplicitAnimation.cpp:
     50        (WebCore::ImplicitAnimation::computeExtentOfTransformAnimation): Compute the extent
     51        of the start and end transforms, and union them.
     52        * page/animation/ImplicitAnimation.h:
     53        * page/animation/KeyframeAnimation.cpp:
     54        (WebCore::KeyframeAnimation::animate):
     55        (WebCore::KeyframeAnimation::getAnimatedStyle): Some nullptr goodness.
     56        (WebCore::KeyframeAnimation::computeExtentOfTransformAnimation): Compute an extent
     57        for each keyframe, and take their union.
     58        * page/animation/KeyframeAnimation.h:
     59        * platform/graphics/GeometryUtilities.cpp:
     60        (WebCore::euclidianDistance): Use Pythagoras to compute a distance.
     61        (WebCore::boundsOfRotatingRect): Given a rect whose location is relative
     62        to the rotation origin, compute a bounds for the rotated rect by computing
     63        the furthest corner from the origin, and sweeping out a circle.
     64        * platform/graphics/GeometryUtilities.h:
     65        * platform/graphics/transforms/Matrix3DTransformOperation.h:
     66        * platform/graphics/transforms/MatrixTransformOperation.h:
     67        * platform/graphics/transforms/PerspectiveTransformOperation.h:
     68        * platform/graphics/transforms/RotateTransformOperation.h:
     69        * platform/graphics/transforms/ScaleTransformOperation.h:
     70        * platform/graphics/transforms/SkewTransformOperation.h:
     71        * platform/graphics/transforms/TransformOperation.h:
     72        (WebCore::TransformOperation::isAffectedByTransformOrigin):
     73        * platform/graphics/transforms/TransformOperations.cpp:
     74        (WebCore::TransformOperations::affectedByTransformOrigin): Ask all the operations if
     75        they are affected by transform-origin.
     76        (WebCore::TransformOperations::blendByMatchingOperations): nullptr.
     77        * platform/graphics/transforms/TransformOperations.h:
     78        * rendering/RenderBox.cpp:
     79        (WebCore::RenderBox::pushMappingToContainer): Comment fix. Only take transforms into account
     80        if the geometry map says so (which is most of the time).
     81        * rendering/RenderGeometryMap.cpp:
     82        (WebCore::RenderGeometryMap::mapToContainer): RenderLayerCompositor is now using the
     83        geometry map in a way that is incompatible with this assertion; it deliberately ignores
     84        transforms sometimes, so we can't easily verify that the mapping matches mapping through
     85        renderers.
     86        (WebCore::RenderGeometryMap::pushMappingsToAncestor): Save and restore the UseTransforms
     87        bit.
     88        * rendering/RenderGeometryMap.h:
     89        * rendering/RenderLayer.cpp:
     90        (WebCore::RenderLayer::boundingBox): Whitespace.
     91        (WebCore::RenderLayer::getOverlapBoundsIncludingChildrenAccountingForTransformAnimations): Helper
     92        function to get the bounds of a layer, including descendants, when a transform animation is running.
     93        * rendering/RenderLayer.h:
     94        * rendering/RenderLayerCompositor.cpp:
     95        (WebCore::RenderLayerCompositor::CompositingState::CompositingState): Add a ancestorHasTransformAnimation
     96        flag to detect nested animated transforms.
     97        (WebCore::RenderLayerCompositor::OverlapExtent::knownToBeHaveExtentUncertainty): This returns true when
     98        the layer is animating transform, and the transition/animation is such that we can't easily compute the
     99        bounds of the animation.
     100        (WebCore::RenderLayerCompositor::computeExtent): const RenderLayer&.
     101        Compute the animated bounds if there's a transform animation running.
     102        (WebCore::RenderLayerCompositor::addToOverlapMap): const RenderLayer&
     103        (WebCore::RenderLayerCompositor::addToOverlapMapRecursive): const RenderLayer&
     104        (WebCore::RenderLayerCompositor::computeCompositingRequirements):
     105        Delay the call to pushMappingsToAncestor() until knowing if there's a transform animation running, and
     106        if there is, push the mapping while ignoring transforms (since the transform is implicitly taken into account
     107        for overlap via the computed animated bounds).
     108        If this layer is running a transform animation, set the childState.ancestorHasTransformAnimation flag so
     109        that descendants will know (nested transform animations fall back to current behavior).
     110        The if (.... && isRunningAcceleratedTransformAnimation()) is what previously caused us to turn off overlap
     111        testing in the face of animations. That now only happens if we were unable to easily compute the animation bounds.
     112        (WebCore::RenderLayerCompositor::isRunningTransformAnimation): This previously tested whether an accelerated animation
     113        was running, but that's timing sensitive; AnimationController can start the transform animation, but it's not yet
     114        considered accelerated until we get an async callback from GraphicsLayer, yet this code needed to know if the
     115        animation was running.
     116        Since transform animations are always accelerated, we can just test for a running transform animation.
     117        (WebCore::RenderLayerCompositor::isRunningAcceleratedTransformAnimation): Deleted.
     118        * rendering/RenderLayerCompositor.h:
     119        * rendering/style/RenderStyle.cpp:
     120        (WebCore::requireTransformOrigin): Some FIXME comments.
     121
    11222015-03-15  Simon Fraser  <simon.fraser@apple.com>
    2123
  • trunk/Source/WebCore/page/animation/AnimationBase.cpp

    r174587 r181515  
    3737#include "EventNames.h"
    3838#include "FloatConversion.h"
     39#include "GeometryUtilities.h"
    3940#include "Logging.h"
    4041#include "RenderBox.h"
     
    698699}
    699700
     701static bool containsRotation(const Vector<RefPtr<TransformOperation>>& operations)
     702{
     703    for (const auto& operation : operations) {
     704        if (operation->type() == TransformOperation::ROTATE)
     705            return true;
     706    }
     707    return false;
     708}
     709
     710bool AnimationBase::computeTransformedExtentViaTransformList(const FloatRect& rendererBox, const RenderStyle& style, LayoutRect& bounds) const
     711{
     712    FloatRect floatBounds = bounds;
     713    FloatPoint transformOrigin;
     714   
     715    bool applyTransformOrigin = containsRotation(style.transform().operations()) || style.transform().affectedByTransformOrigin();
     716    if (applyTransformOrigin) {
     717        float offsetX = style.transformOriginX().isPercentNotCalculated() ? rendererBox.x() : 0;
     718        float offsetY = style.transformOriginY().isPercentNotCalculated() ? rendererBox.y() : 0;
     719
     720        transformOrigin.setX(floatValueForLength(style.transformOriginX(), rendererBox.width()) + offsetX);
     721        transformOrigin.setY(floatValueForLength(style.transformOriginY(), rendererBox.height()) + offsetY);
     722        // Ignore transformOriginZ because we'll bail if we encounter any 3D transforms.
     723       
     724        floatBounds.moveBy(-transformOrigin);
     725    }
     726
     727    for (const auto& operation : style.transform().operations()) {
     728        if (operation->type() == TransformOperation::ROTATE) {
     729            // For now, just treat this as a full rotation. This could take angle into account to reduce inflation.
     730            floatBounds = boundsOfRotatingRect(floatBounds);
     731        } else {
     732            TransformationMatrix transform;
     733            operation->apply(transform, rendererBox.size());
     734            if (!transform.isAffine())
     735                return false;
     736
     737            if (operation->type() == TransformOperation::MATRIX || operation->type() == TransformOperation::MATRIX_3D) {
     738                TransformationMatrix::Decomposed2Type toDecomp;
     739                transform.decompose2(toDecomp);
     740                // Any rotation prevents us from using a simple start/end rect union.
     741                if (toDecomp.angle)
     742                    return false;
     743            }
     744
     745            floatBounds = transform.mapRect(floatBounds);
     746        }
     747    }
     748
     749    if (applyTransformOrigin)
     750        floatBounds.moveBy(transformOrigin);
     751
     752    bounds = LayoutRect(floatBounds);
     753    return true;
     754}
     755
     756bool AnimationBase::computeTransformedExtentViaMatrix(const FloatRect& rendererBox, const RenderStyle& style, LayoutRect& bounds) const
     757{
     758    TransformationMatrix transform;
     759    style.applyTransform(transform, rendererBox, RenderStyle::IncludeTransformOrigin);
     760    if (!transform.isAffine())
     761        return false;
     762
     763    TransformationMatrix::Decomposed2Type fromDecomp;
     764    transform.decompose2(fromDecomp);
     765    // Any rotation prevents us from using a simple start/end rect union.
     766    if (fromDecomp.angle)
     767        return false;
     768
     769    bounds = LayoutRect(transform.mapRect(bounds));
     770    return true;
     771
     772}
     773
    700774} // namespace WebCore
  • trunk/Source/WebCore/page/animation/AnimationBase.h

    r173268 r181515  
    4040namespace WebCore {
    4141
    42 class AnimationController;
    4342class CompositeAnimation;
    4443class Element;
     44class FloatRect;
     45class LayoutRect;
    4546class RenderElement;
    4647class RenderStyle;
    4748class TimingFunction;
     49
    4850class AnimationBase : public RefCounted<AnimationBase> {
    4951    friend class CompositeAnimation;
     
    137139    virtual void getAnimatedStyle(RefPtr<RenderStyle>& /*animatedStyle*/) = 0;
    138140
     141    virtual bool computeExtentOfTransformAnimation(LayoutRect&) const = 0;
     142
    139143    virtual bool shouldFireEvents() const { return false; }
    140144
     
    237241    double fractionalTime(double scale, double elapsedTime, double offset) const;
    238242
     243    // These return true if we can easily compute a bounding box by applying the style's transform to the bounds rect.
     244    bool computeTransformedExtentViaTransformList(const FloatRect& rendererBox, const RenderStyle&, LayoutRect& bounds) const;
     245    bool computeTransformedExtentViaMatrix(const FloatRect& rendererBox, const RenderStyle&, LayoutRect& bounds) const;
     246
    239247    AnimationState m_animationState;
    240248
  • trunk/Source/WebCore/page/animation/AnimationController.cpp

    r177302 r181515  
    418418}
    419419
     420bool AnimationControllerPrivate::computeExtentOfAnimation(RenderElement& renderer, LayoutRect& bounds) const
     421{
     422    ASSERT(renderer.isCSSAnimating());
     423    ASSERT(m_compositeAnimations.contains(&renderer));
     424
     425    const CompositeAnimation& rendererAnimations = *m_compositeAnimations.get(&renderer);
     426    if (!rendererAnimations.isAnimatingProperty(CSSPropertyWebkitTransform, false, AnimationBase::Running | AnimationBase::Paused))
     427        return true;
     428
     429    return rendererAnimations.computeExtentOfTransformAnimation(bounds);
     430}
     431
    420432unsigned AnimationControllerPrivate::numberOfActiveAnimations(Document* document) const
    421433{
     
    578590}
    579591
     592bool AnimationController::computeExtentOfAnimation(RenderElement& renderer, LayoutRect& bounds) const
     593{
     594    if (!renderer.isCSSAnimating())
     595        return true;
     596
     597    return m_data->computeExtentOfAnimation(renderer, bounds);
     598}
     599
    580600void AnimationController::notifyAnimationStarted(RenderElement&, double startTime)
    581601{
  • trunk/Source/WebCore/page/animation/AnimationController.h

    r177302 r181515  
    4040class Element;
    4141class Frame;
     42class LayoutRect;
    4243class RenderElement;
    4344class RenderStyle;
     
    5152    Ref<RenderStyle> updateAnimations(RenderElement&, Ref<RenderStyle>&& newStyle);
    5253    PassRefPtr<RenderStyle> getAnimatedStyleForRenderer(RenderElement&);
     54
     55    // If possible, compute the visual extent of any transform animation on the given renderer
     56    // using the given rect, returning the result in the rect. Return false if there is some
     57    // transform animation but we were unable to cheaply compute its affect on the extent.
     58    bool computeExtentOfAnimation(RenderElement&, LayoutRect&) const;
    5359
    5460    // This is called when an accelerated animation or transition has actually started to animate.
  • trunk/Source/WebCore/page/animation/AnimationControllerPrivate.h

    r177302 r181515  
    9696    PassRefPtr<RenderStyle> getAnimatedStyleForRenderer(RenderElement&);
    9797
     98    bool computeExtentOfAnimation(RenderElement&, LayoutRect&) const;
     99
    98100    double beginAnimationUpdateTime();
    99101    void setBeginAnimationUpdateTime(double t) { m_beginAnimationUpdateTime = t; }
  • trunk/Source/WebCore/page/animation/CompositeAnimation.cpp

    r177259 r181515  
    400400}
    401401
     402bool CompositeAnimation::computeExtentOfTransformAnimation(LayoutRect& bounds) const
     403{
     404    // If more than one transition and animation affect transform, give up.
     405    bool seenTransformAnimation = false;
     406   
     407    for (auto& it : m_keyframeAnimations) {
     408        if (KeyframeAnimation* anim = it.value.get()) {
     409            if (!anim->hasAnimationForProperty(CSSPropertyWebkitTransform))
     410                continue;
     411
     412            if (seenTransformAnimation)
     413                return false;
     414
     415            seenTransformAnimation = true;
     416
     417            if (!anim->computeExtentOfTransformAnimation(bounds))
     418                return false;
     419        }
     420    }
     421
     422    for (auto& it : m_transitions) {
     423        if (ImplicitAnimation* anim = it.value.get()) {
     424            if (anim->animatingProperty() != CSSPropertyWebkitTransform || !anim->hasStyle())
     425                continue;
     426
     427            if (seenTransformAnimation)
     428                return false;
     429
     430            if (!anim->computeExtentOfTransformAnimation(bounds))
     431                return false;
     432        }
     433    }
     434   
     435    return true;
     436}
     437
    402438void CompositeAnimation::suspendAnimations()
    403439{
  • trunk/Source/WebCore/page/animation/CompositeAnimation.h

    r177733 r181515  
    5858    Ref<RenderStyle> animate(RenderElement&, RenderStyle* currentStyle, RenderStyle& targetStyle);
    5959    PassRefPtr<RenderStyle> getAnimatedStyle() const;
     60    bool computeExtentOfTransformAnimation(LayoutRect&) const;
    6061
    6162    double timeToNextService() const;
  • trunk/Source/WebCore/page/animation/ImplicitAnimation.cpp

    r174587 r181515  
    3333#include "CompositeAnimation.h"
    3434#include "EventNames.h"
     35#include "GeometryUtilities.h"
    3536#include "ImplicitAnimation.h"
    3637#include "KeyframeAnimation.h"
    37 #include "RenderBoxModelObject.h"
     38#include "RenderBox.h"
    3839
    3940namespace WebCore {
     
    9899
    99100    CSSPropertyAnimation::blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0));
     101}
     102
     103bool ImplicitAnimation::computeExtentOfTransformAnimation(LayoutRect& bounds) const
     104{
     105    ASSERT(hasStyle());
     106
     107    if (!m_object->isBox())
     108        return false;
     109
     110    ASSERT(m_animatingProperty == CSSPropertyWebkitTransform);
     111
     112    RenderBox& box = downcast<RenderBox>(*m_object);
     113    FloatRect rendererBox = snapRectToDevicePixels(box.borderBoxRect(), box.document().deviceScaleFactor());
     114
     115    LayoutRect startBounds = bounds;
     116    LayoutRect endBounds = bounds;
     117
     118    if (isTransformFunctionListValid()) {
     119        if (!computeTransformedExtentViaTransformList(rendererBox, *m_fromStyle, startBounds))
     120            return false;
     121
     122        if (!computeTransformedExtentViaTransformList(rendererBox, *m_toStyle, endBounds))
     123            return false;
     124    } else {
     125        if (!computeTransformedExtentViaMatrix(rendererBox, *m_fromStyle, startBounds))
     126            return false;
     127
     128        if (!computeTransformedExtentViaMatrix(rendererBox, *m_toStyle, endBounds))
     129            return false;
     130    }
     131
     132    bounds = unionRect(startBounds, endBounds);
     133    return true;
    100134}
    101135
  • trunk/Source/WebCore/page/animation/ImplicitAnimation.h

    r173268 r181515  
    5959    virtual void reset(RenderStyle* to);
    6060
     61    bool computeExtentOfTransformAnimation(LayoutRect&) const override;
     62
    6163    void setOverridden(bool);
    6264    virtual bool overridden() const override { return m_overridden; }
  • trunk/Source/WebCore/page/animation/KeyframeAnimation.cpp

    r176423 r181515  
    3535#include "CompositeAnimation.h"
    3636#include "EventNames.h"
    37 #include "RenderBoxModelObject.h"
     37#include "GeometryUtilities.h"
     38#include "RenderBox.h"
    3839#include "RenderStyle.h"
    3940#include "StyleResolver.h"
     
    160161    for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
    161162        // Get the from/to styles and progress between
    162         const RenderStyle* fromStyle = 0;
    163         const RenderStyle* toStyle = 0;
    164         double progress = 0.0;
     163        const RenderStyle* fromStyle = nullptr;
     164        const RenderStyle* toStyle = nullptr;
     165        double progress = 0;
    165166        fetchIntervalEndpointsForProperty(*it, fromStyle, toStyle, progress);
    166167
     
    190191    for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
    191192        // Get the from/to styles and progress between
    192         const RenderStyle* fromStyle = 0;
    193         const RenderStyle* toStyle = 0;
    194         double progress = 0.0;
     193        const RenderStyle* fromStyle = nullptr;
     194        const RenderStyle* toStyle = nullptr;
     195        double progress = 0;
    195196        fetchIntervalEndpointsForProperty(*it, fromStyle, toStyle, progress);
    196197
    197198        CSSPropertyAnimation::blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress);
    198199    }
     200}
     201
     202bool KeyframeAnimation::computeExtentOfTransformAnimation(LayoutRect& bounds) const
     203{
     204    ASSERT(m_keyframes.containsProperty(CSSPropertyWebkitTransform));
     205
     206    RenderBox& box = downcast<RenderBox>(*m_object);
     207    FloatRect rendererBox = snapRectToDevicePixels(box.borderBoxRect(), box.document().deviceScaleFactor());
     208
     209    FloatRect cumulativeBounds = bounds;
     210
     211    size_t numKeyframes = m_keyframes.size();
     212    for (size_t i = 0; i < numKeyframes; ++i) {
     213        const KeyframeValue& currKeyFrame = m_keyframes[i];
     214
     215        if (!currKeyFrame.containsProperty(CSSPropertyWebkitTransform))
     216            continue;
     217
     218        LayoutRect keyframeBounds = bounds;
     219       
     220        bool canCompute;
     221        if (isTransformFunctionListValid())
     222            canCompute = computeTransformedExtentViaTransformList(rendererBox, *currKeyFrame.style(), keyframeBounds);
     223        else
     224            canCompute = computeTransformedExtentViaMatrix(rendererBox, *currKeyFrame.style(), keyframeBounds);
     225       
     226        if (!canCompute)
     227            return false;
     228       
     229        cumulativeBounds.unite(keyframeBounds);
     230    }
     231
     232    bounds = LayoutRect(cumulativeBounds);
     233    return true;
    199234}
    200235
  • trunk/Source/WebCore/page/animation/KeyframeAnimation.h

    r173268 r181515  
    4949    virtual void getAnimatedStyle(RefPtr<RenderStyle>&) override;
    5050
     51    bool computeExtentOfTransformAnimation(LayoutRect&) const override;
     52
    5153    const KeyframeList& keyframes() const { return m_keyframes; }
    5254
     
    7880    virtual bool affectsProperty(CSSPropertyID) const override;
    7981
     82    bool computeExtentOfAnimationForMatrixAnimation(const FloatRect& rendererBox, LayoutRect&) const;
     83
     84    bool computeExtentOfAnimationForMatchingTransformLists(const FloatRect& rendererBox, LayoutRect&) const;
     85
    8086    void validateTransformFunctionList();
    8187    void checkForMatchingFilterFunctionLists();
  • trunk/Source/WebCore/platform/graphics/GeometryUtilities.cpp

    r168392 r181515  
    2828
    2929namespace WebCore {
     30
     31float euclidianDistance(const FloatPoint& p1, const FloatPoint& p2)
     32{
     33    FloatSize delta = p1 - p2;
     34    return sqrt(delta.width() * delta.width() + delta.height() * delta.height());
     35}
    3036
    3137float findSlope(const FloatPoint& p1, const FloatPoint& p2, float& c)
     
    116122}
    117123
     124FloatRect boundsOfRotatingRect(const FloatRect& r)
     125{
     126    // Compute the furthest corner from the origin.
     127    float maxCornerDistance = euclidianDistance(FloatPoint(), r.minXMinYCorner());
     128    maxCornerDistance = std::max(maxCornerDistance, euclidianDistance(FloatPoint(), r.maxXMinYCorner()));
     129    maxCornerDistance = std::max(maxCornerDistance, euclidianDistance(FloatPoint(), r.minXMaxYCorner()));
     130    maxCornerDistance = std::max(maxCornerDistance, euclidianDistance(FloatPoint(), r.maxXMaxYCorner()));
     131   
     132    return FloatRect(-maxCornerDistance, -maxCornerDistance, 2 * maxCornerDistance, 2 * maxCornerDistance);
    118133}
     134
     135}
  • trunk/Source/WebCore/platform/graphics/GeometryUtilities.h

    r179861 r181515  
    3333namespace WebCore {
    3434
     35float euclidianDistance(const FloatPoint&, const FloatPoint&);
     36
    3537float findSlope(const FloatPoint& p1, const FloatPoint& p2, float& c);
    3638
     
    4648WEBCORE_EXPORT FloatRect largestRectWithAspectRatioInsideRect(float aspectRatio, const FloatRect&);
    4749
     50// Compute a rect that encloses all points covered by the given rect if it were rotated a full turn around (0,0).
     51FloatRect boundsOfRotatingRect(const FloatRect&);
     52
    4853}
    4954
  • trunk/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h

    r174739 r181515  
    4242private:   
    4343    virtual bool isIdentity() const override { return m_matrix.isIdentity(); }
     44    virtual bool isAffectedByTransformOrigin() const { return !isIdentity(); }
    4445
    4546    virtual OperationType type() const override { return MATRIX_3D; }
  • trunk/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.h

    r174739 r181515  
    4747private:
    4848    virtual bool isIdentity() const override { return m_a == 1 && m_b == 0 && m_c == 0 && m_d == 1 && m_e == 0 && m_f == 0; }
     49    virtual bool isAffectedByTransformOrigin() const { return !isIdentity(); }
    4950
    5051    virtual OperationType type() const override { return MATRIX; }
  • trunk/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h

    r174739 r181515  
    4444private:
    4545    virtual bool isIdentity() const override { return !floatValueForLength(m_p, 1); }
     46    virtual bool isAffectedByTransformOrigin() const { return !isIdentity(); }
     47
    4648    virtual OperationType type() const override { return PERSPECTIVE; }
    4749    virtual bool isSameType(const TransformOperation& o) const override { return o.type() == PERSPECTIVE; }
  • trunk/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h

    r174739 r181515  
    4949private:
    5050    virtual bool isIdentity() const override { return m_angle == 0; }
     51    virtual bool isAffectedByTransformOrigin() const { return !isIdentity(); }
    5152
    5253    virtual OperationType type() const override { return m_type; }
  • trunk/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h

    r174739 r181515  
    4848private:
    4949    virtual bool isIdentity() const override { return m_x == 1 &&  m_y == 1 &&  m_z == 1; }
     50    virtual bool isAffectedByTransformOrigin() const { return !isIdentity(); }
    5051
    5152    virtual OperationType type() const override { return m_type; }
  • trunk/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.h

    r174739 r181515  
    4242private:
    4343    virtual bool isIdentity() const override { return m_angleX == 0 && m_angleY == 0; }
     44    virtual bool isAffectedByTransformOrigin() const { return !isIdentity(); }
     45
    4446    virtual OperationType type() const override { return m_type; }
    4547    virtual bool isSameType(const TransformOperation& o) const override { return o.type() == m_type; }
  • trunk/Source/WebCore/platform/graphics/transforms/TransformOperation.h

    r174739 r181515  
    6767    virtual OperationType type() const = 0;
    6868    virtual bool isSameType(const TransformOperation&) const { return false; }
     69
     70    virtual bool isAffectedByTransformOrigin() const { return false; }
    6971   
    7072    bool is3DOperation() const
  • trunk/Source/WebCore/platform/graphics/transforms/TransformOperations.cpp

    r159027 r181515  
    6464}
    6565
     66bool TransformOperations::affectedByTransformOrigin() const
     67{
     68    for (const auto& operation : m_operations) {
     69        if (operation->isAffectedByTransformOrigin())
     70            return true;
     71    }
     72    return false;
     73}
     74
    6675TransformOperations TransformOperations::blendByMatchingOperations(const TransformOperations& from, const double& progress) const
    6776{
     
    7281    unsigned size = std::max(fromSize, toSize);
    7382    for (unsigned i = 0; i < size; i++) {
    74         RefPtr<TransformOperation> fromOperation = (i < fromSize) ? from.operations()[i].get() : 0;
    75         RefPtr<TransformOperation> toOperation = (i < toSize) ? operations()[i].get() : 0;
    76         RefPtr<TransformOperation> blendedOperation = toOperation ? toOperation->blend(fromOperation.get(), progress) : (fromOperation ? fromOperation->blend(0, progress, true) : 0);
     83        RefPtr<TransformOperation> fromOperation = (i < fromSize) ? from.operations()[i].get() : nullptr;
     84        RefPtr<TransformOperation> toOperation = (i < toSize) ? operations()[i].get() : nullptr;
     85        RefPtr<TransformOperation> blendedOperation = toOperation ? toOperation->blend(fromOperation.get(), progress) : (fromOperation ? fromOperation->blend(nullptr, progress, true) : nullptr);
    7786        if (blendedOperation)
    7887            result.operations().append(blendedOperation);
  • trunk/Source/WebCore/platform/graphics/transforms/TransformOperations.h

    r157653 r181515  
    6666        m_operations.clear();
    6767    }
     68
     69    bool affectedByTransformOrigin() const;
    6870   
    6971    Vector<RefPtr<TransformOperation>>& operations() { return m_operations; }
  • trunk/Source/WebCore/rendering/RenderBox.cpp

    r181505 r181515  
    19951995    LayoutSize adjustmentForSkippedAncestor;
    19961996    if (ancestorSkipped) {
    1997         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
    1998         // to just subtract the delta between the ancestor and o.
     1997        // There can't be a transform between repaintContainer and container, because transforms create containers, so it should be safe
     1998        // to just subtract the delta between the ancestor and container.
    19991999        adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(*container);
    20002000    }
     
    20042004
    20052005    bool preserve3D = container->style().preserves3D() || style().preserves3D();
    2006     if (shouldUseTransformFromContainer(container)) {
     2006    if (shouldUseTransformFromContainer(container) && (geometryMap.mapCoordinatesFlags() & UseTransforms)) {
    20072007        TransformationMatrix t;
    20082008        getTransformFromContainer(container, containerOffset, t);
  • trunk/Source/WebCore/rendering/RenderGeometryMap.cpp

    r180441 r181515  
    135135    }
    136136
    137 #if !ASSERT_DISABLED
    138     FloatRect rendererMappedResult = m_mapping.last().m_renderer->localToContainerQuad(rect, container, m_mapCoordinatesFlags).boundingBox();
    139     // Inspector creates renderers with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>.
    140     // Taking FloatQuad bounds avoids spurious assertions because of that.
    141     ASSERT(enclosingIntRect(rendererMappedResult) == enclosingIntRect(result.boundingBox()));
    142 #endif
    143 
    144137    return result;
    145138}
     
    179172}
    180173
    181 void RenderGeometryMap::pushMappingsToAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer)
    182 {
     174void RenderGeometryMap::pushMappingsToAncestor(const RenderLayer* layer, const RenderLayer* ancestorLayer, bool respectTransforms)
     175{
     176    MapCoordinatesFlags newFlags = respectTransforms ? m_mapCoordinatesFlags : m_mapCoordinatesFlags & ~UseTransforms;
     177    TemporaryChange<MapCoordinatesFlags> flagsChange(m_mapCoordinatesFlags, newFlags);
     178
    183179    const RenderLayerModelObject& renderer = layer->renderer();
    184180
  • trunk/Source/WebCore/rendering/RenderGeometryMap.h

    r181505 r181515  
    9898   
    9999    // Called by code walking the renderer or layer trees.
    100     void pushMappingsToAncestor(const RenderLayer*, const RenderLayer* ancestorLayer);
     100    void pushMappingsToAncestor(const RenderLayer*, const RenderLayer* ancestorLayer, bool respectTransforms = true);
    101101    void popMappingsToAncestor(const RenderLayer*);
    102102    void pushMappingsToAncestor(const RenderObject*, const RenderLayerModelObject* ancestorRenderer);
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r181505 r181515  
    58315831    if (flags & UseFragmentBoxesIncludingCompositing)
    58325832        inclusionMode = IncludeCompositedPaginatedLayers;
     5833
    58335834    const RenderLayer* paginationLayer = nullptr;
    58345835    if (flags & UseFragmentBoxesExcludingCompositing || flags & UseFragmentBoxesIncludingCompositing)
     
    58565857    result.move(offsetFromRoot);
    58575858    return result;
     5859}
     5860
     5861bool RenderLayer::getOverlapBoundsIncludingChildrenAccountingForTransformAnimations(LayoutRect& bounds) const
     5862{
     5863    // The animation will override the display transform, so don't include it.
     5864    CalculateLayerBoundsFlags boundsFlags = DefaultCalculateLayerBoundsFlags & ~IncludeSelfTransform;
     5865   
     5866    bounds = calculateLayerBounds(this, LayoutSize(), boundsFlags);
     5867   
     5868    LayoutRect animatedBounds = bounds;
     5869    if (renderer().animation().computeExtentOfAnimation(renderer(), animatedBounds)) {
     5870        bounds = animatedBounds;
     5871        return true;
     5872    }
     5873   
     5874    return false;
    58585875}
    58595876
  • trunk/Source/WebCore/rendering/RenderLayer.h

    r181166 r181515  
    488488
    489489    enum CalculateLayerBoundsFlag {
    490         IncludeSelfTransform = 1 << 0,
    491         UseLocalClipRectIfPossible = 1 << 1,
    492         IncludeLayerFilterOutsets = 1 << 2,
    493         ExcludeHiddenDescendants = 1 << 3,
    494         DontConstrainForMask = 1 << 4,
    495         IncludeCompositedDescendants = 1 << 5,
    496         UseFragmentBoxesExcludingCompositing = 1 << 6,
    497         UseFragmentBoxesIncludingCompositing = 1 << 7,
    498         DefaultCalculateLayerBoundsFlags = IncludeSelfTransform | UseLocalClipRectIfPossible | IncludeLayerFilterOutsets | UseFragmentBoxesExcludingCompositing
     490        IncludeSelfTransform                    = 1 << 0,
     491        UseLocalClipRectIfPossible              = 1 << 1,
     492        IncludeLayerFilterOutsets               = 1 << 2,
     493        ExcludeHiddenDescendants                = 1 << 3,
     494        DontConstrainForMask                    = 1 << 4,
     495        IncludeCompositedDescendants            = 1 << 5,
     496        UseFragmentBoxesExcludingCompositing    = 1 << 6,
     497        UseFragmentBoxesIncludingCompositing    = 1 << 7,
     498        DefaultCalculateLayerBoundsFlags        = IncludeSelfTransform | UseLocalClipRectIfPossible | IncludeLayerFilterOutsets | UseFragmentBoxesExcludingCompositing
    499499    };
    500500    typedef unsigned CalculateLayerBoundsFlags;
     
    511511    // Bounds used for layer overlap testing in RenderLayerCompositor.
    512512    LayoutRect overlapBounds() const { return overlapBoundsIncludeChildren() ? calculateLayerBounds(this, LayoutSize()) : localBoundingBox(); }
     513   
     514    // Takes transform animations into account, returning true if they could be cheaply computed.
     515    // Unlike overlapBounds, these bounds include descendant layers.
     516    bool getOverlapBoundsIncludingChildrenAccountingForTransformAnimations(LayoutRect&) const;
    513517
    514518    // If true, this layer's children are included in its bounds for overlap testing.
  • trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp

    r181513 r181515  
    224224        , subtreeIsCompositing(false)
    225225        , testingOverlap(testOverlap)
     226        , ancestorHasTransformAnimation(false)
    226227#if ENABLE(CSS_COMPOSITING)
    227228        , hasNotIsolatedCompositedBlendingDescendants(false)
     
    237238        , subtreeIsCompositing(other.subtreeIsCompositing)
    238239        , testingOverlap(other.testingOverlap)
     240        , ancestorHasTransformAnimation(other.ancestorHasTransformAnimation)
    239241#if ENABLE(CSS_COMPOSITING)
    240242        , hasNotIsolatedCompositedBlendingDescendants(other.hasNotIsolatedCompositedBlendingDescendants)
     
    249251    bool subtreeIsCompositing;
    250252    bool testingOverlap;
     253    bool ancestorHasTransformAnimation;
    251254#if ENABLE(CSS_COMPOSITING)
    252255    bool hasNotIsolatedCompositedBlendingDescendants;
     
    260263    LayoutRect bounds;
    261264    bool extentComputed { false };
     265    bool hasTransformAnimation { false };
     266    bool animationCausesExtentUncertainty { false };
     267
     268    bool knownToBeHaveExtentUncertainty() const { return extentComputed && animationCausesExtentUncertainty; }
    262269};
    263270
     
    11421149}
    11431150
    1144 void RenderLayerCompositor::computeExtent(const OverlapMap& overlapMap, RenderLayer& layer, OverlapExtent& extent) const
     1151void RenderLayerCompositor::computeExtent(const OverlapMap& overlapMap, const RenderLayer& layer, OverlapExtent& extent) const
    11451152{
    11461153    if (extent.extentComputed)
    11471154        return;
    11481155
    1149     // FIXME: If this layer's overlap bounds include its children, we don't need to add its
    1150     // children's bounds to the overlap map.
    1151     extent.bounds = enclosingLayoutRect(overlapMap.geometryMap().absoluteRect(layer.overlapBounds()));
     1156    LayoutRect layerBounds;
     1157    if (extent.hasTransformAnimation)
     1158        extent.animationCausesExtentUncertainty = !layer.getOverlapBoundsIncludingChildrenAccountingForTransformAnimations(layerBounds);
     1159    else
     1160        layerBounds = layer.overlapBounds();
     1161   
     1162    // In the animating transform case, we avoid double-accounting for the transform because
     1163    // we told pushMappingsToAncestor() to ignore transforms earlier.
     1164    extent.bounds = enclosingLayoutRect(overlapMap.geometryMap().absoluteRect(layerBounds));
     1165
    11521166    // Empty rects never intersect, but we need them to for the purposes of overlap testing.
    11531167    if (extent.bounds.isEmpty())
     
    11571171}
    11581172
    1159 void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer& layer, OverlapExtent& extent)
     1173void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, const RenderLayer& layer, OverlapExtent& extent)
    11601174{
    11611175    if (layer.isRootLayer())
     
    11771191}
    11781192
    1179 void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, RenderLayer& layer, RenderLayer* ancestorLayer)
     1193void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, const RenderLayer& layer, const RenderLayer* ancestorLayer)
    11801194{
    11811195    if (!canBeComposited(layer) || overlapMap.contains(&layer))
     
    11901204
    11911205#if !ASSERT_DISABLED
    1192     LayerListMutationDetector mutationChecker(&layer);
     1206    LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(&layer));
    11931207#endif
    11941208
     
    12561270    }
    12571271
    1258     overlapMap.geometryMap().pushMappingsToAncestor(&layer, ancestorLayer);
    1259    
    12601272    // Clear the flag
    12611273    layer.setHasCompositingDescendant(false);
     
    12631275
    12641276    // Check if the layer needs to be composited for direct reasons (e.g. 3D transform).
    1265     // We use this value to avoid checking the overlap map, if we know for sure the layer
    1266     // is already going to be composited for other reasons.
    12671277    bool willBeComposited = needsToBeComposited(layer);
    1268     bool mayHaveAnimatedTransform = willBeComposited && !layer.isRootLayer();
     1278
     1279    OverlapExtent layerExtent;
     1280    // Use the fact that we're composited as a hint to check for an animating transform.
     1281    // FIXME: Maybe needsToBeComposited() should return a bitmask of reasons, to avoid the need to recompute things.
     1282    if (willBeComposited && !layer.isRootLayer())
     1283        layerExtent.hasTransformAnimation = isRunningTransformAnimation(layer.renderer());
     1284
     1285    bool respectTransforms = !layerExtent.hasTransformAnimation;
     1286    overlapMap.geometryMap().pushMappingsToAncestor(&layer, ancestorLayer, respectTransforms);
    12691287
    12701288    RenderLayer::IndirectCompositingReason compositingReason = compositingState.subtreeIsCompositing ? RenderLayer::IndirectCompositingReason::Stacking : RenderLayer::IndirectCompositingReason::None;
    1271 
    1272     OverlapExtent layerExtent;
    12731289
    12741290    // If we know for sure the layer is going to be composited, don't bother looking it up in the overlap map
     
    13141330        // animation running behind this layer, meaning they can rely on the overlap map testing again.
    13151331        childState.testingOverlap = true;
     1332
     1333        computeExtent(overlapMap, layer, layerExtent);
     1334        childState.ancestorHasTransformAnimation |= layerExtent.hasTransformAnimation;
     1335        // Too hard to compute animated bounds if both us and some ancestor is animating transform.
     1336        layerExtent.animationCausesExtentUncertainty |= layerExtent.hasTransformAnimation && compositingState.ancestorHasTransformAnimation;
    13161337    }
    13171338
     
    13781399    // the overlap map. Layers that do not composite will draw into their
    13791400    // compositing ancestor's backing, and so are still considered for overlap.
     1401    // FIXME: When layerExtent has taken animation bounds into account, we also know that the bounds
     1402    // include descendants, so we don't need to add them all to the overlap map.
    13801403    if (childState.compositingAncestor && !childState.compositingAncestor->isRootLayer())
    13811404        addToOverlapMap(overlapMap, layer, layerExtent);
     
    14061429        compositingState.subtreeIsCompositing = true;
    14071430
    1408     // Set the flag to say that this SC has compositing children.
     1431    // Set the flag to say that this layer has compositing children.
    14091432    layer.setHasCompositingDescendant(childState.subtreeIsCompositing);
    14101433
    1411     // setHasCompositingDescendant() may have changed the answer to needsToBeComposited() when clipping,
    1412     // so test that again.
     1434    // setHasCompositingDescendant() may have changed the answer to needsToBeComposited() when clipping, so test that again.
    14131435    bool isCompositedClippingLayer = canBeComposited(layer) && clipsCompositingDescendants(layer);
    14141436
     
    14161438    // Note that if the layer clips its descendants, there's no reason to propagate the child animation to the parent layers. That's because
    14171439    // we know for sure the animation is contained inside the clipping rectangle, which is already added to the overlap map.
    1418     if ((!childState.testingOverlap && !isCompositedClippingLayer) || (mayHaveAnimatedTransform && isRunningAcceleratedTransformAnimation(layer.renderer())))
     1440    if ((!childState.testingOverlap && !isCompositedClippingLayer) || layerExtent.knownToBeHaveExtentUncertainty())
    14191441        compositingState.testingOverlap = false;
    14201442   
     
    27842806#endif
    27852807
    2786 bool RenderLayerCompositor::isRunningAcceleratedTransformAnimation(RenderLayerModelObject& renderer) const
     2808bool RenderLayerCompositor::isRunningTransformAnimation(RenderLayerModelObject& renderer) const
    27872809{
    27882810    if (!(m_compositingTriggers & ChromeClient::AnimationTrigger))
    27892811        return false;
    27902812
    2791     return renderer.animation().isRunningAcceleratedAnimationOnRenderer(renderer, CSSPropertyWebkitTransform, AnimationBase::Running | AnimationBase::Paused);
     2813    return renderer.animation().isRunningAnimationOnRenderer(renderer, CSSPropertyWebkitTransform, AnimationBase::Running | AnimationBase::Paused);
    27922814}
    27932815
  • trunk/Source/WebCore/rendering/RenderLayerCompositor.h

    r181247 r181515  
    339339    void recursiveRepaintLayer(RenderLayer&);
    340340
    341     void computeExtent(const OverlapMap&, RenderLayer&, OverlapExtent&) const;
    342     void addToOverlapMap(OverlapMap&, RenderLayer&, OverlapExtent&);
    343     void addToOverlapMapRecursive(OverlapMap&, RenderLayer&, RenderLayer* ancestorLayer = nullptr);
     341    void computeExtent(const OverlapMap&, const RenderLayer&, OverlapExtent&) const;
     342    void addToOverlapMap(OverlapMap&, const RenderLayer&, OverlapExtent&);
     343    void addToOverlapMapRecursive(OverlapMap&, const RenderLayer&, const RenderLayer* ancestorLayer = nullptr);
    344344
    345345    void updateCompositingLayersTimerFired();
     
    369369
    370370    bool layerHas3DContent(const RenderLayer&) const;
    371     bool isRunningAcceleratedTransformAnimation(RenderLayerModelObject&) const;
     371    bool isRunningTransformAnimation(RenderLayerModelObject&) const;
    372372
    373373    void appendDocumentOverlayLayers(Vector<GraphicsLayer*>&);
  • trunk/Source/WebCore/rendering/style/RenderStyle.cpp

    r181189 r181515  
    989989}
    990990
     991// FIXME: use affectedByTransformOrigin().
    991992static inline bool requireTransformOrigin(const Vector<RefPtr<TransformOperation>>& transformOperations, RenderStyle::ApplyTransformOrigin applyOrigin)
    992993{
     
    10021003            && type != TransformOperation::TRANSLATE_Y
    10031004            && type != TransformOperation::TRANSLATE
    1004             && type != TransformOperation::TRANSLATE_Z
     1005            && type != TransformOperation::TRANSLATE_Z // FIXME: doesn't this depend on transform origin?
    10051006            && type != TransformOperation::TRANSLATE_3D)
    10061007            return true;
Note: See TracChangeset for help on using the changeset viewer.