Chromium Code Reviews| Index: third_party/WebKit/Source/core/layout/LayoutBox.cpp |
| diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp |
| index 456e411cbfb3a0d7b3ddef0e74bf1e6bd0209937..d770f5baea9cf6161fbc3af16bde409a5996484d 100644 |
| --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp |
| +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp |
| @@ -1160,14 +1160,15 @@ LayoutRect LayoutBox::clippingRect() const { |
| } |
| bool LayoutBox::mapScrollingContentsRectToBoxSpace( |
| - LayoutRect& rect, |
| + TransformState& transformState, |
| + TransformState::TransformAccumulation accumulation, |
| VisualRectFlags visualRectFlags) const { |
| if (!hasClipRelatedProperty()) |
| return true; |
| if (hasOverflowClip()) { |
| LayoutSize offset = LayoutSize(-scrolledContentOffset()); |
| - rect.move(offset); |
| + transformState.move(offset, accumulation); |
| } |
| // This won't work fully correctly for fixed-position elements, who should |
| @@ -1175,6 +1176,8 @@ bool LayoutBox::mapScrollingContentsRectToBoxSpace( |
| // block chain. |
| LayoutRect clipRect = clippingRect(); |
| + transformState.flatten(); |
| + LayoutRect rect(transformState.lastPlanarQuad().enclosingBoundingBox()); |
| bool doesIntersect; |
| if (visualRectFlags & EdgeInclusive) { |
| doesIntersect = rect.inclusiveIntersect(clipRect); |
| @@ -1182,6 +1185,7 @@ bool LayoutBox::mapScrollingContentsRectToBoxSpace( |
| rect.intersect(clipRect); |
| doesIntersect = !rect.isEmpty(); |
| } |
| + transformState.setQuad(FloatQuad(FloatRect(rect))); |
| return doesIntersect; |
| } |
| @@ -2328,35 +2332,36 @@ LayoutRect LayoutBox::localVisualRect() const { |
| } |
| void LayoutBox::inflateVisualRectForFilterUnderContainer( |
| - LayoutRect& rect, |
| + TransformState& transformState, |
| const LayoutObject& container, |
| const LayoutBoxModelObject* ancestorToStopAt) const { |
| + transformState.flatten(); |
| // Apply visual overflow caused by reflections and filters defined on objects |
| // between this object and container (not included) or ancestorToStopAt |
| // (included). |
| LayoutSize offsetFromContainer = this->offsetFromContainer(&container); |
| - rect.move(offsetFromContainer); |
| + transformState.move(offsetFromContainer); |
| for (LayoutObject* parent = this->parent(); parent && parent != container; |
| parent = parent->parent()) { |
| if (parent->isBox()) { |
| // Convert rect into coordinate space of parent to apply parent's |
| // reflection and filter. |
| LayoutSize parentOffset = parent->offsetFromAncestorContainer(&container); |
| - rect.move(-parentOffset); |
| - toLayoutBox(parent)->inflateVisualRectForFilter(rect); |
| - rect.move(parentOffset); |
| + transformState.move(-parentOffset); |
| + toLayoutBox(parent)->inflateVisualRectForFilter(transformState); |
| + transformState.move(parentOffset); |
| } |
| if (parent == ancestorToStopAt) |
| break; |
| } |
| - rect.move(-offsetFromContainer); |
| + transformState.move(-offsetFromContainer); |
| } |
| -bool LayoutBox::mapToVisualRectInAncestorSpace( |
| +bool LayoutBox::mapToVisualRectInAncestorSpaceInternal( |
| const LayoutBoxModelObject* ancestor, |
| - LayoutRect& rect, |
| + TransformState& transformState, |
| VisualRectFlags visualRectFlags) const { |
| - inflateVisualRectForFilter(rect); |
| + inflateVisualRectForFilter(transformState); |
| if (ancestor == this) |
| return true; |
| @@ -2376,60 +2381,80 @@ bool LayoutBox::mapToVisualRectInAncestorSpace( |
| if (!container) |
| return true; |
| - if (skipInfo.filterSkipped()) |
| - inflateVisualRectForFilterUnderContainer(rect, *container, ancestor); |
| - |
| - // We are now in our parent container's coordinate space. Apply our transform |
| - // to obtain a bounding box in the parent's coordinate space that encloses us. |
| - if (hasLayer() && layer()->transform()) { |
| - // Use enclosingIntRect because we cannot properly compute pixel snapping |
| - // for painted elements within the transform since we don't know the desired |
| - // subpixel accumulation at this point, and the transform may include a |
| - // scale. |
| - rect = LayoutRect(layer()->transform()->mapRect(enclosingIntRect(rect))); |
| - } |
| - LayoutPoint topLeft = rect.location(); |
| + LayoutPoint containerOffset; |
| if (container->isBox()) { |
| - topLeft.moveBy(physicalLocation(toLayoutBox(container))); |
| + containerOffset.moveBy(physicalLocation(toLayoutBox(container))); |
| + |
| // If the row is the ancestor, however, add its offset back in. In effect, |
| // this passes from the joint <td> / <tr> coordinate space to the parent |
| // space, then back to <tr> / <td>. |
| if (tableRowContainer) { |
| - topLeft.moveBy( |
| + containerOffset.moveBy( |
| -tableRowContainer->physicalLocation(toLayoutBox(container))); |
| } |
| } else if (container->isRuby()) { |
| // TODO(wkorman): Generalize Ruby specialization and/or document more |
| // clearly. See the accompanying specialization in |
| - // LayoutInline::mapToVisualRectInAncestorSpace. |
| - topLeft.moveBy(physicalLocation()); |
| + // LayoutInline::mapToVisualRectInAncestorSpaceInternal. |
| + containerOffset.moveBy(physicalLocation()); |
| } else { |
| - topLeft.moveBy(location()); |
| + containerOffset.moveBy(location()); |
| } |
| const ComputedStyle& styleToUse = styleRef(); |
| EPosition position = styleToUse.position(); |
| if (position == EPosition::kAbsolute && container->isInFlowPositioned() && |
| container->isLayoutInline()) { |
| - topLeft += |
| - toLayoutInline(container)->offsetForInFlowPositionedInline(*this); |
| + containerOffset.move( |
| + toLayoutInline(container)->offsetForInFlowPositionedInline(*this)); |
| } else if (styleToUse.hasInFlowPosition() && layer()) { |
| // Apply the relative position offset when invalidating a rectangle. The |
| // layer is translated, but the layout box isn't, so we need to do this to |
| // get the right dirty rect. Since this is called from |
| // LayoutObject::setStyle, the relative position flag on the LayoutObject |
| // has been cleared, so use the one on the style(). |
| - topLeft += layer()->offsetForInFlowPosition(); |
| + containerOffset.move(layer()->offsetForInFlowPosition()); |
| + } |
| + |
| + bool preserve3D = |
| + ((container->style()->preserves3D() && !container->isText()) || |
| + (style()->preserves3D() && !isText())); |
|
Xianzhu
2017/03/03 01:24:42
I think !container->isText() and !isText() are bot
chrishtr
2017/03/03 02:45:11
Done.
|
| + |
| + TransformState::TransformAccumulation accumulation = |
| + preserve3D ? TransformState::AccumulateTransform |
| + : TransformState::FlattenTransform; |
| + |
| + if (skipInfo.filterSkipped()) { |
| + inflateVisualRectForFilterUnderContainer(transformState, *container, |
| + ancestor); |
| + } |
| + |
| + // We are now in our parent container's coordinate space. Apply our transform |
| + // to obtain a bounding box in the parent's coordinate space that encloses us. |
| + if (shouldUseTransformFromContainer(container)) { |
| + TransformationMatrix t; |
| + getTransformFromContainer(container, toLayoutSize(containerOffset), t); |
| + transformState.applyTransform(t, accumulation); |
| + |
| + // Use enclosingIntRect because we cannot properly compute pixel snapping |
|
Xianzhu
2017/03/03 01:24:42
enclosingIntRect -> enclosingBoundingBox().
Not a
chrishtr
2017/03/03 02:45:11
Will fix in a followup. Changed comment.
|
| + // for painted elements within the transform since we don't know the desired |
| + // subpixel accumulation at this point, and the transform may include a |
| + // scale. |
| + if (!preserve3D) { |
| + transformState.flatten(); |
| + transformState.setQuad( |
| + FloatQuad(transformState.lastPlanarQuad().enclosingBoundingBox())); |
| + } |
| + } else { |
| + transformState.move(toLayoutSize(containerOffset), accumulation); |
| } |
| // FIXME: We ignore the lightweight clipping rect that controls use, since if |
| // |o| is in mid-layout, its controlClipRect will be wrong. For overflow clip |
| // we use the values cached by the layer. |
| - rect.setLocation(topLeft); |
| - |
| if (container->isBox() && container != ancestor && |
| !toLayoutBox(container)->mapScrollingContentsRectToBoxSpace( |
| - rect, visualRectFlags)) |
| + transformState, accumulation, visualRectFlags)) |
| return false; |
| if (skipInfo.ancestorSkipped()) { |
| @@ -2437,27 +2462,35 @@ bool LayoutBox::mapToVisualRectInAncestorSpace( |
| // ancestor's coordinates. |
| LayoutSize containerOffset = |
| ancestor->offsetFromAncestorContainer(container); |
| - rect.move(-containerOffset); |
| + transformState.move(-containerOffset, accumulation); |
| // If the ancestor is fixed, then the rect is already in its coordinates so |
| // doesn't need viewport-adjusting. |
| if (ancestor->style()->position() != EPosition::kFixed && |
| - container->isLayoutView() && position == EPosition::kFixed) |
| - rect.move(toLayoutView(container)->offsetForFixedPosition(true)); |
| + container->isLayoutView() && position == EPosition::kFixed) { |
| + transformState.move(toLayoutView(container)->offsetForFixedPosition(true), |
| + accumulation); |
| + } |
| return true; |
| } |
| if (container->isLayoutView()) |
| - return toLayoutView(container)->mapToVisualRectInAncestorSpace( |
| - ancestor, rect, position == EPosition::kFixed ? IsFixed : 0, |
| + return toLayoutView(container)->mapToVisualRectInAncestorSpaceInternal( |
| + ancestor, transformState, position == EPosition::kFixed ? IsFixed : 0, |
| visualRectFlags); |
| else |
| - return container->mapToVisualRectInAncestorSpace(ancestor, rect, |
| - visualRectFlags); |
| + return container->mapToVisualRectInAncestorSpaceInternal( |
| + ancestor, transformState, visualRectFlags); |
| } |
| -void LayoutBox::inflateVisualRectForFilter(LayoutRect& visualRect) const { |
| - if (layer() && layer()->hasFilterInducingProperty()) |
| - visualRect = layer()->mapLayoutRectForFilter(visualRect); |
| +void LayoutBox::inflateVisualRectForFilter( |
| + TransformState& transformState) const { |
| + if (!layer() || !layer()->hasFilterInducingProperty()) |
| + return; |
| + |
| + transformState.flatten(); |
| + LayoutRect rect(transformState.lastPlanarQuad().boundingBox()); |
| + transformState.setQuad( |
| + FloatQuad(FloatRect(layer()->mapLayoutRectForFilter(rect)))); |
| } |
| void LayoutBox::updateLogicalWidth() { |