Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Side by Side Diff: third_party/WebKit/Source/core/layout/LayoutBox.cpp

Issue 2727093002: Account for perspective and preserve-3d in mapToVisualRectInAncestorSpace (Closed)
Patch Set: none Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) 4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com) 5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. 6 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc.
7 * All rights reserved. 7 * All rights reserved.
8 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. 8 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
9 * 9 *
10 * This library is free software; you can redistribute it and/or 10 * This library is free software; you can redistribute it and/or
(...skipping 1142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1153 if (hasOverflowClip() || style()->containsPaint()) 1153 if (hasOverflowClip() || style()->containsPaint())
1154 result = overflowClipRect(LayoutPoint()); 1154 result = overflowClipRect(LayoutPoint());
1155 1155
1156 if (hasClip()) 1156 if (hasClip())
1157 result.intersect(clipRect(LayoutPoint())); 1157 result.intersect(clipRect(LayoutPoint()));
1158 1158
1159 return result; 1159 return result;
1160 } 1160 }
1161 1161
1162 bool LayoutBox::mapScrollingContentsRectToBoxSpace( 1162 bool LayoutBox::mapScrollingContentsRectToBoxSpace(
1163 LayoutRect& rect, 1163 TransformState& transformState,
1164 TransformState::TransformAccumulation accumulation,
1164 VisualRectFlags visualRectFlags) const { 1165 VisualRectFlags visualRectFlags) const {
1165 if (!hasClipRelatedProperty()) 1166 if (!hasClipRelatedProperty())
1166 return true; 1167 return true;
1167 1168
1168 if (hasOverflowClip()) { 1169 if (hasOverflowClip()) {
1169 LayoutSize offset = LayoutSize(-scrolledContentOffset()); 1170 LayoutSize offset = LayoutSize(-scrolledContentOffset());
1170 rect.move(offset); 1171 transformState.move(offset, accumulation);
1171 } 1172 }
1172 1173
1173 // This won't work fully correctly for fixed-position elements, who should 1174 // This won't work fully correctly for fixed-position elements, who should
1174 // receive CSS clip but for whom the current object is not in the containing 1175 // receive CSS clip but for whom the current object is not in the containing
1175 // block chain. 1176 // block chain.
1176 LayoutRect clipRect = clippingRect(); 1177 LayoutRect clipRect = clippingRect();
1177 1178
1179 transformState.flatten();
1180 LayoutRect rect(transformState.lastPlanarQuad().enclosingBoundingBox());
1178 bool doesIntersect; 1181 bool doesIntersect;
1179 if (visualRectFlags & EdgeInclusive) { 1182 if (visualRectFlags & EdgeInclusive) {
1180 doesIntersect = rect.inclusiveIntersect(clipRect); 1183 doesIntersect = rect.inclusiveIntersect(clipRect);
1181 } else { 1184 } else {
1182 rect.intersect(clipRect); 1185 rect.intersect(clipRect);
1183 doesIntersect = !rect.isEmpty(); 1186 doesIntersect = !rect.isEmpty();
1184 } 1187 }
1188 transformState.setQuad(FloatQuad(FloatRect(rect)));
1185 1189
1186 return doesIntersect; 1190 return doesIntersect;
1187 } 1191 }
1188 1192
1189 void LayoutBox::computeIntrinsicLogicalWidths( 1193 void LayoutBox::computeIntrinsicLogicalWidths(
1190 LayoutUnit& minLogicalWidth, 1194 LayoutUnit& minLogicalWidth,
1191 LayoutUnit& maxLogicalWidth) const { 1195 LayoutUnit& maxLogicalWidth) const {
1192 minLogicalWidth = minPreferredLogicalWidth() - borderAndPaddingLogicalWidth(); 1196 minLogicalWidth = minPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
1193 maxLogicalWidth = maxPreferredLogicalWidth() - borderAndPaddingLogicalWidth(); 1197 maxLogicalWidth = maxPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
1194 } 1198 }
(...skipping 1126 matching lines...) Expand 10 before | Expand all | Expand 10 after
2321 LayoutRect LayoutBox::localVisualRect() const { 2325 LayoutRect LayoutBox::localVisualRect() const {
2322 if (style()->visibility() != EVisibility::kVisible) 2326 if (style()->visibility() != EVisibility::kVisible)
2323 return LayoutRect(); 2327 return LayoutRect();
2324 2328
2325 if (hasMask() && !RuntimeEnabledFeatures::slimmingPaintV2Enabled()) 2329 if (hasMask() && !RuntimeEnabledFeatures::slimmingPaintV2Enabled())
2326 return LayoutRect(layer()->boxForFilterOrMask()); 2330 return LayoutRect(layer()->boxForFilterOrMask());
2327 return selfVisualOverflowRect(); 2331 return selfVisualOverflowRect();
2328 } 2332 }
2329 2333
2330 void LayoutBox::inflateVisualRectForFilterUnderContainer( 2334 void LayoutBox::inflateVisualRectForFilterUnderContainer(
2331 LayoutRect& rect, 2335 TransformState& transformState,
2332 const LayoutObject& container, 2336 const LayoutObject& container,
2333 const LayoutBoxModelObject* ancestorToStopAt) const { 2337 const LayoutBoxModelObject* ancestorToStopAt) const {
2338 transformState.flatten();
2334 // Apply visual overflow caused by reflections and filters defined on objects 2339 // Apply visual overflow caused by reflections and filters defined on objects
2335 // between this object and container (not included) or ancestorToStopAt 2340 // between this object and container (not included) or ancestorToStopAt
2336 // (included). 2341 // (included).
2337 LayoutSize offsetFromContainer = this->offsetFromContainer(&container); 2342 LayoutSize offsetFromContainer = this->offsetFromContainer(&container);
2338 rect.move(offsetFromContainer); 2343 transformState.move(offsetFromContainer);
2339 for (LayoutObject* parent = this->parent(); parent && parent != container; 2344 for (LayoutObject* parent = this->parent(); parent && parent != container;
2340 parent = parent->parent()) { 2345 parent = parent->parent()) {
2341 if (parent->isBox()) { 2346 if (parent->isBox()) {
2342 // Convert rect into coordinate space of parent to apply parent's 2347 // Convert rect into coordinate space of parent to apply parent's
2343 // reflection and filter. 2348 // reflection and filter.
2344 LayoutSize parentOffset = parent->offsetFromAncestorContainer(&container); 2349 LayoutSize parentOffset = parent->offsetFromAncestorContainer(&container);
2345 rect.move(-parentOffset); 2350 transformState.move(-parentOffset);
2346 toLayoutBox(parent)->inflateVisualRectForFilter(rect); 2351 toLayoutBox(parent)->inflateVisualRectForFilter(transformState);
2347 rect.move(parentOffset); 2352 transformState.move(parentOffset);
2348 } 2353 }
2349 if (parent == ancestorToStopAt) 2354 if (parent == ancestorToStopAt)
2350 break; 2355 break;
2351 } 2356 }
2352 rect.move(-offsetFromContainer); 2357 transformState.move(-offsetFromContainer);
2353 } 2358 }
2354 2359
2355 bool LayoutBox::mapToVisualRectInAncestorSpace( 2360 bool LayoutBox::mapToVisualRectInAncestorSpaceInternal(
2356 const LayoutBoxModelObject* ancestor, 2361 const LayoutBoxModelObject* ancestor,
2357 LayoutRect& rect, 2362 TransformState& transformState,
2358 VisualRectFlags visualRectFlags) const { 2363 VisualRectFlags visualRectFlags) const {
2359 inflateVisualRectForFilter(rect); 2364 inflateVisualRectForFilter(transformState);
2360 2365
2361 if (ancestor == this) 2366 if (ancestor == this)
2362 return true; 2367 return true;
2363 2368
2364 AncestorSkipInfo skipInfo(ancestor, true); 2369 AncestorSkipInfo skipInfo(ancestor, true);
2365 LayoutObject* container = this->container(&skipInfo); 2370 LayoutObject* container = this->container(&skipInfo);
2366 LayoutBox* tableRowContainer = nullptr; 2371 LayoutBox* tableRowContainer = nullptr;
2367 // Skip table row because cells and rows are in the same coordinate space (see 2372 // Skip table row because cells and rows are in the same coordinate space (see
2368 // below, however for more comments about when |ancestor| is the table row). 2373 // below, however for more comments about when |ancestor| is the table row).
2369 if (isTableCell()) { 2374 if (isTableCell()) {
2370 DCHECK(container->isTableRow() && parentBox() == container); 2375 DCHECK(container->isTableRow() && parentBox() == container);
2371 if (container != ancestor) 2376 if (container != ancestor)
2372 container = container->parent(); 2377 container = container->parent();
2373 else 2378 else
2374 tableRowContainer = toLayoutBox(container); 2379 tableRowContainer = toLayoutBox(container);
2375 } 2380 }
2376 if (!container) 2381 if (!container)
2377 return true; 2382 return true;
2378 2383
2379 if (skipInfo.filterSkipped()) 2384 LayoutPoint containerOffset;
2380 inflateVisualRectForFilterUnderContainer(rect, *container, ancestor); 2385 if (container->isBox()) {
2386 containerOffset.moveBy(physicalLocation(toLayoutBox(container)));
2381 2387
2382 // We are now in our parent container's coordinate space. Apply our transform
2383 // to obtain a bounding box in the parent's coordinate space that encloses us.
2384 if (hasLayer() && layer()->transform()) {
2385 // Use enclosingIntRect because we cannot properly compute pixel snapping
2386 // for painted elements within the transform since we don't know the desired
2387 // subpixel accumulation at this point, and the transform may include a
2388 // scale.
2389 rect = LayoutRect(layer()->transform()->mapRect(enclosingIntRect(rect)));
2390 }
2391 LayoutPoint topLeft = rect.location();
2392 if (container->isBox()) {
2393 topLeft.moveBy(physicalLocation(toLayoutBox(container)));
2394 // If the row is the ancestor, however, add its offset back in. In effect, 2388 // If the row is the ancestor, however, add its offset back in. In effect,
2395 // this passes from the joint <td> / <tr> coordinate space to the parent 2389 // this passes from the joint <td> / <tr> coordinate space to the parent
2396 // space, then back to <tr> / <td>. 2390 // space, then back to <tr> / <td>.
2397 if (tableRowContainer) { 2391 if (tableRowContainer) {
2398 topLeft.moveBy( 2392 containerOffset.moveBy(
2399 -tableRowContainer->physicalLocation(toLayoutBox(container))); 2393 -tableRowContainer->physicalLocation(toLayoutBox(container)));
2400 } 2394 }
2401 } else if (container->isRuby()) { 2395 } else if (container->isRuby()) {
2402 // TODO(wkorman): Generalize Ruby specialization and/or document more 2396 // TODO(wkorman): Generalize Ruby specialization and/or document more
2403 // clearly. See the accompanying specialization in 2397 // clearly. See the accompanying specialization in
2404 // LayoutInline::mapToVisualRectInAncestorSpace. 2398 // LayoutInline::mapToVisualRectInAncestorSpaceInternal.
2405 topLeft.moveBy(physicalLocation()); 2399 containerOffset.moveBy(physicalLocation());
2406 } else { 2400 } else {
2407 topLeft.moveBy(location()); 2401 containerOffset.moveBy(location());
2408 } 2402 }
2409 2403
2410 const ComputedStyle& styleToUse = styleRef(); 2404 const ComputedStyle& styleToUse = styleRef();
2411 EPosition position = styleToUse.position(); 2405 EPosition position = styleToUse.position();
2412 if (position == EPosition::kAbsolute && container->isInFlowPositioned() && 2406 if (position == EPosition::kAbsolute && container->isInFlowPositioned() &&
2413 container->isLayoutInline()) { 2407 container->isLayoutInline()) {
2414 topLeft += 2408 containerOffset.move(
2415 toLayoutInline(container)->offsetForInFlowPositionedInline(*this); 2409 toLayoutInline(container)->offsetForInFlowPositionedInline(*this));
2416 } else if (styleToUse.hasInFlowPosition() && layer()) { 2410 } else if (styleToUse.hasInFlowPosition() && layer()) {
2417 // Apply the relative position offset when invalidating a rectangle. The 2411 // Apply the relative position offset when invalidating a rectangle. The
2418 // layer is translated, but the layout box isn't, so we need to do this to 2412 // layer is translated, but the layout box isn't, so we need to do this to
2419 // get the right dirty rect. Since this is called from 2413 // get the right dirty rect. Since this is called from
2420 // LayoutObject::setStyle, the relative position flag on the LayoutObject 2414 // LayoutObject::setStyle, the relative position flag on the LayoutObject
2421 // has been cleared, so use the one on the style(). 2415 // has been cleared, so use the one on the style().
2422 topLeft += layer()->offsetForInFlowPosition(); 2416 containerOffset.move(layer()->offsetForInFlowPosition());
2417 }
2418
2419 bool preserve3D =
2420 ((container->style()->preserves3D() && !container->isText()) ||
2421 (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.
2422
2423 TransformState::TransformAccumulation accumulation =
2424 preserve3D ? TransformState::AccumulateTransform
2425 : TransformState::FlattenTransform;
2426
2427 if (skipInfo.filterSkipped()) {
2428 inflateVisualRectForFilterUnderContainer(transformState, *container,
2429 ancestor);
2430 }
2431
2432 // We are now in our parent container's coordinate space. Apply our transform
2433 // to obtain a bounding box in the parent's coordinate space that encloses us.
2434 if (shouldUseTransformFromContainer(container)) {
2435 TransformationMatrix t;
2436 getTransformFromContainer(container, toLayoutSize(containerOffset), t);
2437 transformState.applyTransform(t, accumulation);
2438
2439 // 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.
2440 // for painted elements within the transform since we don't know the desired
2441 // subpixel accumulation at this point, and the transform may include a
2442 // scale.
2443 if (!preserve3D) {
2444 transformState.flatten();
2445 transformState.setQuad(
2446 FloatQuad(transformState.lastPlanarQuad().enclosingBoundingBox()));
2447 }
2448 } else {
2449 transformState.move(toLayoutSize(containerOffset), accumulation);
2423 } 2450 }
2424 2451
2425 // FIXME: We ignore the lightweight clipping rect that controls use, since if 2452 // FIXME: We ignore the lightweight clipping rect that controls use, since if
2426 // |o| is in mid-layout, its controlClipRect will be wrong. For overflow clip 2453 // |o| is in mid-layout, its controlClipRect will be wrong. For overflow clip
2427 // we use the values cached by the layer. 2454 // we use the values cached by the layer.
2428 rect.setLocation(topLeft);
2429
2430 if (container->isBox() && container != ancestor && 2455 if (container->isBox() && container != ancestor &&
2431 !toLayoutBox(container)->mapScrollingContentsRectToBoxSpace( 2456 !toLayoutBox(container)->mapScrollingContentsRectToBoxSpace(
2432 rect, visualRectFlags)) 2457 transformState, accumulation, visualRectFlags))
2433 return false; 2458 return false;
2434 2459
2435 if (skipInfo.ancestorSkipped()) { 2460 if (skipInfo.ancestorSkipped()) {
2436 // If the ancestor is below the container, then we need to map the rect into 2461 // If the ancestor is below the container, then we need to map the rect into
2437 // ancestor's coordinates. 2462 // ancestor's coordinates.
2438 LayoutSize containerOffset = 2463 LayoutSize containerOffset =
2439 ancestor->offsetFromAncestorContainer(container); 2464 ancestor->offsetFromAncestorContainer(container);
2440 rect.move(-containerOffset); 2465 transformState.move(-containerOffset, accumulation);
2441 // If the ancestor is fixed, then the rect is already in its coordinates so 2466 // If the ancestor is fixed, then the rect is already in its coordinates so
2442 // doesn't need viewport-adjusting. 2467 // doesn't need viewport-adjusting.
2443 if (ancestor->style()->position() != EPosition::kFixed && 2468 if (ancestor->style()->position() != EPosition::kFixed &&
2444 container->isLayoutView() && position == EPosition::kFixed) 2469 container->isLayoutView() && position == EPosition::kFixed) {
2445 rect.move(toLayoutView(container)->offsetForFixedPosition(true)); 2470 transformState.move(toLayoutView(container)->offsetForFixedPosition(true),
2471 accumulation);
2472 }
2446 return true; 2473 return true;
2447 } 2474 }
2448 2475
2449 if (container->isLayoutView()) 2476 if (container->isLayoutView())
2450 return toLayoutView(container)->mapToVisualRectInAncestorSpace( 2477 return toLayoutView(container)->mapToVisualRectInAncestorSpaceInternal(
2451 ancestor, rect, position == EPosition::kFixed ? IsFixed : 0, 2478 ancestor, transformState, position == EPosition::kFixed ? IsFixed : 0,
2452 visualRectFlags); 2479 visualRectFlags);
2453 else 2480 else
2454 return container->mapToVisualRectInAncestorSpace(ancestor, rect, 2481 return container->mapToVisualRectInAncestorSpaceInternal(
2455 visualRectFlags); 2482 ancestor, transformState, visualRectFlags);
2456 } 2483 }
2457 2484
2458 void LayoutBox::inflateVisualRectForFilter(LayoutRect& visualRect) const { 2485 void LayoutBox::inflateVisualRectForFilter(
2459 if (layer() && layer()->hasFilterInducingProperty()) 2486 TransformState& transformState) const {
2460 visualRect = layer()->mapLayoutRectForFilter(visualRect); 2487 if (!layer() || !layer()->hasFilterInducingProperty())
2488 return;
2489
2490 transformState.flatten();
2491 LayoutRect rect(transformState.lastPlanarQuad().boundingBox());
2492 transformState.setQuad(
2493 FloatQuad(FloatRect(layer()->mapLayoutRectForFilter(rect))));
2461 } 2494 }
2462 2495
2463 void LayoutBox::updateLogicalWidth() { 2496 void LayoutBox::updateLogicalWidth() {
2464 LogicalExtentComputedValues computedValues; 2497 LogicalExtentComputedValues computedValues;
2465 computeLogicalWidth(computedValues); 2498 computeLogicalWidth(computedValues);
2466 2499
2467 setLogicalWidth(computedValues.m_extent); 2500 setLogicalWidth(computedValues.m_extent);
2468 setLogicalLeft(computedValues.m_position); 2501 setLogicalLeft(computedValues.m_position);
2469 setMarginStart(computedValues.m_margins.m_start); 2502 setMarginStart(computedValues.m_margins.m_start);
2470 setMarginEnd(computedValues.m_margins.m_end); 2503 setMarginEnd(computedValues.m_margins.m_end);
(...skipping 3263 matching lines...) Expand 10 before | Expand all | Expand 10 after
5734 5767
5735 void LayoutBox::MutableForPainting:: 5768 void LayoutBox::MutableForPainting::
5736 savePreviousContentBoxSizeAndLayoutOverflowRect() { 5769 savePreviousContentBoxSizeAndLayoutOverflowRect() {
5737 auto& rareData = layoutBox().ensureRareData(); 5770 auto& rareData = layoutBox().ensureRareData();
5738 rareData.m_hasPreviousContentBoxSizeAndLayoutOverflowRect = true; 5771 rareData.m_hasPreviousContentBoxSizeAndLayoutOverflowRect = true;
5739 rareData.m_previousContentBoxSize = layoutBox().contentBoxRect().size(); 5772 rareData.m_previousContentBoxSize = layoutBox().contentBoxRect().size();
5740 rareData.m_previousLayoutOverflowRect = layoutBox().layoutOverflowRect(); 5773 rareData.m_previousLayoutOverflowRect = layoutBox().layoutOverflowRect();
5741 } 5774 }
5742 5775
5743 } // namespace blink 5776 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698