From f01bea301b5d87ae84162b6784dc0f0c4cb42ec0 Mon Sep 17 00:00:00 2001 From: Ojan Vafai Date: Fri, 27 Feb 2015 17:18:07 -0800 Subject: [PATCH] Move transforms from RenderLayer to RenderBox. This is more member data on RenderLayer that is now only used by RenderBox. R=eseidel@chromium.org Review URL: https://codereview.chromium.org/965013003 --- engine/core/rendering/RenderBox.cpp | 79 ++++++++++++++----- engine/core/rendering/RenderBox.h | 9 +++ .../core/rendering/RenderBoxModelObject.cpp | 2 +- engine/core/rendering/RenderLayer.cpp | 58 ++------------ engine/core/rendering/RenderLayer.h | 21 +---- engine/core/rendering/RenderLayerClipper.cpp | 2 +- engine/core/rendering/RenderObject.cpp | 8 +- engine/core/rendering/RenderView.cpp | 2 +- 8 files changed, 84 insertions(+), 97 deletions(-) diff --git a/engine/core/rendering/RenderBox.cpp b/engine/core/rendering/RenderBox.cpp index 4bea821698a..5148cd28ab5 100644 --- a/engine/core/rendering/RenderBox.cpp +++ b/engine/core/rendering/RenderBox.cpp @@ -149,10 +149,52 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle layer()->styleChanged(diff, oldStyle); } + updateTransform(oldStyle); + if (needsLayout() && oldStyle) RenderBlock::removePercentHeightDescendantIfNeeded(this); } +void RenderBox::updateTransformationMatrix() +{ + if (m_transform) { + m_transform->makeIdentity(); + style()->applyTransform(*m_transform, pixelSnappedBorderBoxRect().size(), RenderStyle::IncludeTransformOrigin); + // FIXME(sky): We shouldn't need to do this once Skia has 4x4 matrix support. + // Until then, 3d transforms don't work right. + m_transform->makeAffine(); + } +} + +void RenderBox::updateTransform(const RenderStyle* oldStyle) +{ + if (oldStyle && style()->transformDataEquivalent(*oldStyle)) + return; + + // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set, + // so check style too. + bool localHasTransform = hasTransform() && style()->hasTransform(); + bool had3DTransform = has3DTransform(); + + bool hadTransform = m_transform; + if (localHasTransform != hadTransform) { + if (localHasTransform) + m_transform = adoptPtr(new TransformationMatrix); + else + m_transform.clear(); + + // Layers with transforms act as clip rects roots, so clear the cached clip rects here. + layer()->clipper().clearClipRectsIncludingDescendants(); + } else if (localHasTransform) { + layer()->clipper().clearClipRectsIncludingDescendants(AbsoluteClipRects); + } + + updateTransformationMatrix(); + + if (had3DTransform != has3DTransform()) + layer()->dirty3DTransformedDescendantStatus(); +} + // TODO(ojan): Inline this into styleDidChange, void RenderBox::updateFromStyle() { @@ -246,9 +288,8 @@ void RenderBox::absoluteQuads(Vector& quads) const void RenderBox::updateLayerTransformAfterLayout() { - // Transform-origin depends on box size, so we need to update the layer transform after layout. - if (hasLayer()) - layer()->updateTransformationMatrix(); + // Transform-origin depends on box size, so we need to update the transform after layout. + updateTransformationMatrix(); } LayoutUnit RenderBox::constrainLogicalWidthByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb) const @@ -548,11 +589,11 @@ bool RenderBox::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer HitTestLocation localHitTestLocation = hitTestLocation; // We need transform state for the first time, or to offset the container state, or to accumulate the new transform. - if (layer()->transform() || transformState || layer()->has3DTransformedDescendant() || layer()->preserves3D()) + if (transform() || transformState || layer()->has3DTransformedDescendant() || style()->preserves3D()) localTransformState = createLocalTransformState(rootLayer, containerLayer, localHitTestRect, localHitTestLocation, transformState); // Apply a transform if we have one. - if (layer()->transform()) { + if (transform()) { // The RenderView cannot have transforms. ASSERT(parent()); // Make sure the parent's clip rects have been calculated. @@ -596,7 +637,7 @@ bool RenderBox::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer } RefPtr unflattenedTransformState = localTransformState; - if (localTransformState && !layer()->preserves3D()) { + if (localTransformState && !style()->preserves3D()) { // Keep a copy of the pre-flattening state, for computing z-offsets for the container unflattenedTransformState = HitTestingTransformState::create(*localTransformState); // This layer is flattening, so flatten the state passed to descendants. @@ -610,7 +651,7 @@ bool RenderBox::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer double* zOffsetForContentsPtr = 0; bool depthSortDescendants = false; - if (layer()->preserves3D()) { + if (style()->preserves3D()) { depthSortDescendants = true; // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down. zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset; @@ -720,9 +761,7 @@ void RenderBox::paintLayer(GraphicsContext* context, const LayerPaintingInfo& pa if (!opacity()) return; - TransformationMatrix* layerTransform = layer()->transform(); - - if (!layerTransform) { + if (!transform()) { paintLayerContents(context, paintingInfo); return; } @@ -731,7 +770,7 @@ void RenderBox::paintLayer(GraphicsContext* context, const LayerPaintingInfo& pa ASSERT(layer()->parent()); // If the transform can't be inverted, then don't paint anything. - if (!layerTransform->isInvertible()) + if (!transform()->isInvertible()) return; // Make sure the parent's clip rects have been calculated. @@ -746,20 +785,20 @@ void RenderBox::paintLayer(GraphicsContext* context, const LayerPaintingInfo& pa // the accumulated error for sub-pixel layout. LayoutPoint delta; layer()->convertToLayerCoords(paintingInfo.rootLayer, delta); - TransformationMatrix transform(*layerTransform); + TransformationMatrix localTransform(*transform()); IntPoint roundedDelta = roundedIntPoint(delta); - transform.translateRight(roundedDelta.x(), roundedDelta.y()); + localTransform.translateRight(roundedDelta.x(), roundedDelta.y()); LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta); // Apply the transform. GraphicsContextStateSaver stateSaver(*context, false); - if (!transform.isIdentity()) { + if (!localTransform.isIdentity()) { stateSaver.save(); - context->concatCTM(transform.toAffineTransform()); + context->concatCTM(localTransform.toAffineTransform()); } // Now do a paint with the root layer shifted to be us. - LayerPaintingInfo transformedPaintingInfo(layer(), enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect)), + LayerPaintingInfo transformedPaintingInfo(layer(), enclosingIntRect(localTransform.inverse().mapRect(paintingInfo.paintDirtyRect)), adjustedSubPixelAccumulation); paintLayerContents(context, transformedPaintingInfo); @@ -785,7 +824,7 @@ static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLaye // paintDirtyRect, and that should cut down on the amount we have to paint. Still it // would be better to respect clips. - if (rootLayer != layer && layer->transform()) { + if (rootLayer != layer && layer->renderer()->transform()) { // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass // the transformed layer and all of its children. const RenderLayer* rootLayerForTransform = rootLayer; @@ -796,7 +835,7 @@ static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLaye IntPoint pixelSnappedDelta = roundedIntPoint(delta); TransformationMatrix transform; transform.translate(pixelSnappedDelta.x(), pixelSnappedDelta.y()); - transform = transform * *layer->transform(); + transform = transform * *layer->renderer()->transform(); // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always // paints unfragmented.y @@ -3013,8 +3052,8 @@ LayoutRect RenderBox::layoutOverflowRectForPropagation() const if (!hasOverflowClip()) rect.unite(layoutOverflowRect()); - if (hasLayer() && layer()->transform()) - rect = layer()->transform()->mapRect(rect); + if (transform()) + rect = transform()->mapRect(rect); return rect; } diff --git a/engine/core/rendering/RenderBox.h b/engine/core/rendering/RenderBox.h index 0948df5d05e..f83578c0309 100644 --- a/engine/core/rendering/RenderBox.h +++ b/engine/core/rendering/RenderBox.h @@ -33,6 +33,7 @@ struct LayerPaintingInfo; struct PaintInfo; class HitTestingTransformState; class RenderBlockFlow; +class TransformationMatrix; enum SizeType { MainOrPreferredSize, MinSize, MaxSize }; enum AvailableLogicalHeightType { ExcludeMarginBorderPadding, IncludeMarginBorderPadding }; @@ -217,6 +218,10 @@ public: void updateLayerTransformAfterLayout(); + // This transform has the transform-origin baked in. + TransformationMatrix* transform() const { return m_transform.get(); } + bool has3DTransform() const { return m_transform && !m_transform->isAffine(); } + LayoutUnit contentWidth() const { return clientWidth() - paddingLeft() - paddingRight(); } LayoutUnit contentHeight() const { return clientHeight() - paddingTop() - paddingBottom(); } LayoutUnit contentLogicalWidth() const { return contentWidth(); } @@ -485,6 +490,8 @@ protected: void updateIntrinsicContentLogicalHeight(LayoutUnit intrinsicContentLogicalHeight) const { m_intrinsicContentLogicalHeight = intrinsicContentLogicalHeight; } private: + void updateTransformationMatrix(); + void updateTransform(const RenderStyle* oldStyle); void updateFromStyle(); void updateFilters(); @@ -557,7 +564,9 @@ protected: // Our overflow information. OwnPtr m_overflow; + // TODO(ojan): Move these two into RenderBoxRareData. OwnPtr m_filterRenderer; + OwnPtr m_transform; private: OwnPtr m_layer; diff --git a/engine/core/rendering/RenderBoxModelObject.cpp b/engine/core/rendering/RenderBoxModelObject.cpp index 2335c6ea922..b6179ac1649 100644 --- a/engine/core/rendering/RenderBoxModelObject.cpp +++ b/engine/core/rendering/RenderBoxModelObject.cpp @@ -2324,7 +2324,7 @@ const RenderObject* RenderBoxModelObject::pushMappingToContainer(const RenderBox return 0; bool isInline = isRenderInline(); - bool hasTransform = !isInline && hasLayer() && toRenderBox(this)->layer()->transform(); + bool hasTransform = !isInline && isBox() && toRenderBox(this)->transform(); LayoutSize adjustmentForSkippedAncestor; if (ancestorSkipped) { diff --git a/engine/core/rendering/RenderLayer.cpp b/engine/core/rendering/RenderLayer.cpp index c94a575d355..db2feecc9dd 100644 --- a/engine/core/rendering/RenderLayer.cpp +++ b/engine/core/rendering/RenderLayer.cpp @@ -102,46 +102,6 @@ void RenderLayer::updateLayerPositionsAfterLayout() m_clipper.clearClipRectsIncludingDescendants(); } -void RenderLayer::updateTransformationMatrix() -{ - if (m_transform) { - RenderBox* box = renderer(); - m_transform->makeIdentity(); - box->style()->applyTransform(*m_transform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::IncludeTransformOrigin); - // FIXME(sky): We shouldn't need to do this once Skia has 4x4 matrix support. - // Until then, 3d transforms don't work right. - m_transform->makeAffine(); - } -} - -void RenderLayer::updateTransform(const RenderStyle* oldStyle, RenderStyle* newStyle) -{ - if (oldStyle && newStyle->transformDataEquivalent(*oldStyle)) - return; - - // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set, - // so check style too. - bool hasTransform = renderer()->hasTransform() && newStyle->hasTransform(); - bool had3DTransform = has3DTransform(); - - bool hadTransform = m_transform; - if (hasTransform != hadTransform) { - if (hasTransform) - m_transform = adoptPtr(new TransformationMatrix); - else - m_transform.clear(); - - // Layers with transforms act as clip rects roots, so clear the cached clip rects here. - m_clipper.clearClipRectsIncludingDescendants(); - } else if (hasTransform) { - m_clipper.clearClipRectsIncludingDescendants(AbsoluteClipRects); - } - - updateTransformationMatrix(); - - if (had3DTransform != has3DTransform()) - dirty3DTransformedDescendantStatus(); -} void RenderLayer::dirty3DTransformedDescendantStatus() { @@ -153,7 +113,7 @@ void RenderLayer::dirty3DTransformedDescendantStatus() // This propagates up through preserve-3d hierarchies to the enclosing flattening layer. // Note that preserves3D() creates stacking context, so we can just run up the stacking containers. - while (stackingNode && stackingNode->layer()->preserves3D()) { + while (stackingNode && stackingNode->layer()->renderer()->style()->preserves3D()) { stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true; stackingNode = stackingNode->ancestorStackingContextNode(); } @@ -178,10 +138,10 @@ bool RenderLayer::update3DTransformedDescendantStatus() // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs // the m_has3DTransformedDescendant set. - if (preserves3D()) - return has3DTransform() || m_has3DTransformedDescendant; + if (renderer()->style()->preserves3D()) + return renderer()->has3DTransform() || m_has3DTransformedDescendant; - return has3DTransform(); + return renderer()->has3DTransform(); } IntSize RenderLayer::size() const @@ -571,8 +531,8 @@ LayoutRect RenderLayer::boundingBoxForCompositing(const RenderLayer* ancestorLay LayoutRect localClipRect = clipper().localClipRect(); if (localClipRect != PaintInfo::infiniteRect()) { - if (transform()) - localClipRect = transform()->mapRect(localClipRect); + if (renderer()->transform()) + localClipRect = renderer()->transform()->mapRect(localClipRect); LayoutPoint delta; convertToLayerCoords(ancestorLayer, delta); @@ -592,8 +552,8 @@ LayoutRect RenderLayer::boundingBoxForCompositing(const RenderLayer* ancestorLay // https://bugs.webkit.org/show_bug.cgi?id=81239 m_renderer->style()->filterOutsets().expandRect(result); - if (transform()) - result = transform()->mapRect(result); + if (renderer()->transform()) + result = renderer()->transform()->mapRect(result); LayoutPoint delta; convertToLayerCoords(ancestorLayer, delta); @@ -614,8 +574,6 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle // Overlay scrollbars can make this layer self-painting so we need // to recompute the bit once scrollbars have been updated. m_isSelfPaintingLayer = shouldBeSelfPaintingLayer(); - - updateTransform(oldStyle, renderer()->style()); } } // namespace blink diff --git a/engine/core/rendering/RenderLayer.h b/engine/core/rendering/RenderLayer.h index a0834aea8e0..80a393c81d0 100644 --- a/engine/core/rendering/RenderLayer.h +++ b/engine/core/rendering/RenderLayer.h @@ -55,12 +55,7 @@ namespace blink { -class FilterOperations; -class HitTestRequest; -class HitTestResult; -class HitTestingTransformState; class RenderStyle; -class TransformationMatrix; enum BorderRadiusClippingRule { IncludeSelfForBorderRadius, DoNotIncludeSelfForBorderRadius }; enum IncludeSelfOrNot { IncludeSelf, ExcludeSelf }; @@ -103,7 +98,6 @@ public: bool isRootLayer() const { return m_isRootLayer; } void updateLayerPositionsAfterLayout(); - void updateTransformationMatrix(); RenderLayerStackingNode* stackingNode() { return m_stackingNode.get(); } const RenderLayerStackingNode* stackingNode() const { return m_stackingNode.get(); } @@ -125,19 +119,10 @@ public: LayoutRect physicalBoundingBoxIncludingReflectionAndStackingChildren(const RenderLayer* ancestorLayer, const LayoutPoint& offsetFromRoot) const; LayoutRect boundingBoxForCompositing(const RenderLayer* ancestorLayer = 0) const; - // This transform has the transform-origin baked in. - TransformationMatrix* transform() const { return m_transform.get(); } - - bool preserves3D() const { return renderer()->style()->transformStyle3D() == TransformStyle3DPreserve3D; } - bool has3DTransform() const { return m_transform && !m_transform->isAffine(); } - bool has3DTransformedDescendant() const { return m_has3DTransformedDescendant; } // Both updates the status, and returns true if descendants of this have 3d. bool update3DTransformedDescendantStatus(); - // FIXME: reflections should force transform-style to be flat in the style: https://bugs.webkit.org/show_bug.cgi?id=106959 - bool shouldPreserve3D() const { return renderer()->style()->transformStyle3D() == TransformStyle3DPreserve3D; } - void* operator new(size_t); // Only safe to call from RenderBox::destroyLayer() void operator delete(void*); @@ -154,7 +139,6 @@ public: void clipToRect(const LayerPaintingInfo&, GraphicsContext*, const ClipRect&, BorderRadiusClippingRule = IncludeSelfForBorderRadius); void restoreClip(GraphicsContext*, const LayoutRect& paintDirtyRect, const ClipRect&); -private: // Bounding box in the coordinates of this layer. LayoutRect logicalBoundingBox() const; @@ -165,10 +149,9 @@ private: bool shouldBeSelfPaintingLayer() const; - void updateTransform(const RenderStyle* oldStyle, RenderStyle* newStyle); - void dirty3DTransformedDescendantStatus(); +private: LayerType m_layerType; // Self-painting layer is an optimization where we avoid the heavy RenderLayer painting @@ -191,8 +174,6 @@ private: RenderLayer* m_first; RenderLayer* m_last; - OwnPtr m_transform; - RenderLayerClipper m_clipper; // FIXME: Lazily allocate? OwnPtr m_stackingNode; }; diff --git a/engine/core/rendering/RenderLayerClipper.cpp b/engine/core/rendering/RenderLayerClipper.cpp index e3daa0da860..ecbaa77bddf 100644 --- a/engine/core/rendering/RenderLayerClipper.cpp +++ b/engine/core/rendering/RenderLayerClipper.cpp @@ -317,7 +317,7 @@ RenderLayer* RenderLayerClipper::clippingRootForPainting() const current = current->compositingContainer(); ASSERT(current); - if (current->transform()) + if (current->renderer()->transform()) return const_cast(current); } diff --git a/engine/core/rendering/RenderObject.cpp b/engine/core/rendering/RenderObject.cpp index 59d41ff06d6..638e3e8b4a1 100644 --- a/engine/core/rendering/RenderObject.cpp +++ b/engine/core/rendering/RenderObject.cpp @@ -1418,16 +1418,16 @@ bool RenderObject::shouldUseTransformFromContainer(const RenderObject* container { // hasTransform() indicates whether the object has transform, transform-style or perspective. We just care about transform, // so check the layer's transform directly. - return (hasLayer() && toRenderBox(this)->layer()->transform()) || (containerObject && containerObject->style()->hasPerspective()); + return (isBox() && toRenderBox(this)->transform()) || (containerObject && containerObject->style()->hasPerspective()); } void RenderObject::getTransformFromContainer(const RenderObject* containerObject, const LayoutSize& offsetInContainer, TransformationMatrix& transform) const { transform.makeIdentity(); transform.translate(offsetInContainer.width().toFloat(), offsetInContainer.height().toFloat()); - RenderLayer* layer = hasLayer() ? toRenderBox(this)->layer() : 0; - if (layer && layer->transform()) - transform.multiply(*layer->transform()); + TransformationMatrix* localTransform = isBox() ? toRenderBox(this)->transform() : 0; + if (localTransform) + transform.multiply(*localTransform); if (containerObject && containerObject->hasLayer() && containerObject->style()->hasPerspective()) { // Perpsective on the container affects us, so we have to factor it in here. diff --git a/engine/core/rendering/RenderView.cpp b/engine/core/rendering/RenderView.cpp index ee4f6e1e7b0..a171ec4513c 100644 --- a/engine/core/rendering/RenderView.cpp +++ b/engine/core/rendering/RenderView.cpp @@ -353,7 +353,7 @@ IntRect RenderView::documentRect() const { FloatRect overflowRect(unscaledDocumentRect()); if (hasTransform()) - overflowRect = layer()->transform()->mapRect(overflowRect); + overflowRect = transform()->mapRect(overflowRect); return IntRect(overflowRect); }