| 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 85e242f342eff412113a0fca91f4dfa3ec93e381..b5a5cd99d2179e28add1be0e9df42ee540b04314 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;
|
| }
|
| @@ -2308,35 +2312,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;
|
| @@ -2356,60 +2361,78 @@ 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() || style()->preserves3D();
|
| +
|
| + 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 enclosingBoundingBox 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.
|
| + 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()) {
|
| @@ -2417,27 +2440,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() {
|
|
|