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

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 1106 matching lines...) Expand 10 before | Expand all | Expand 10 after
2301 LayoutRect LayoutBox::localVisualRect() const { 2305 LayoutRect LayoutBox::localVisualRect() const {
2302 if (style()->visibility() != EVisibility::kVisible) 2306 if (style()->visibility() != EVisibility::kVisible)
2303 return LayoutRect(); 2307 return LayoutRect();
2304 2308
2305 if (hasMask() && !RuntimeEnabledFeatures::slimmingPaintV2Enabled()) 2309 if (hasMask() && !RuntimeEnabledFeatures::slimmingPaintV2Enabled())
2306 return LayoutRect(layer()->boxForFilterOrMask()); 2310 return LayoutRect(layer()->boxForFilterOrMask());
2307 return selfVisualOverflowRect(); 2311 return selfVisualOverflowRect();
2308 } 2312 }
2309 2313
2310 void LayoutBox::inflateVisualRectForFilterUnderContainer( 2314 void LayoutBox::inflateVisualRectForFilterUnderContainer(
2311 LayoutRect& rect, 2315 TransformState& transformState,
2312 const LayoutObject& container, 2316 const LayoutObject& container,
2313 const LayoutBoxModelObject* ancestorToStopAt) const { 2317 const LayoutBoxModelObject* ancestorToStopAt) const {
2318 transformState.flatten();
2314 // Apply visual overflow caused by reflections and filters defined on objects 2319 // Apply visual overflow caused by reflections and filters defined on objects
2315 // between this object and container (not included) or ancestorToStopAt 2320 // between this object and container (not included) or ancestorToStopAt
2316 // (included). 2321 // (included).
2317 LayoutSize offsetFromContainer = this->offsetFromContainer(&container); 2322 LayoutSize offsetFromContainer = this->offsetFromContainer(&container);
2318 rect.move(offsetFromContainer); 2323 transformState.move(offsetFromContainer);
2319 for (LayoutObject* parent = this->parent(); parent && parent != container; 2324 for (LayoutObject* parent = this->parent(); parent && parent != container;
2320 parent = parent->parent()) { 2325 parent = parent->parent()) {
2321 if (parent->isBox()) { 2326 if (parent->isBox()) {
2322 // Convert rect into coordinate space of parent to apply parent's 2327 // Convert rect into coordinate space of parent to apply parent's
2323 // reflection and filter. 2328 // reflection and filter.
2324 LayoutSize parentOffset = parent->offsetFromAncestorContainer(&container); 2329 LayoutSize parentOffset = parent->offsetFromAncestorContainer(&container);
2325 rect.move(-parentOffset); 2330 transformState.move(-parentOffset);
2326 toLayoutBox(parent)->inflateVisualRectForFilter(rect); 2331 toLayoutBox(parent)->inflateVisualRectForFilter(transformState);
2327 rect.move(parentOffset); 2332 transformState.move(parentOffset);
2328 } 2333 }
2329 if (parent == ancestorToStopAt) 2334 if (parent == ancestorToStopAt)
2330 break; 2335 break;
2331 } 2336 }
2332 rect.move(-offsetFromContainer); 2337 transformState.move(-offsetFromContainer);
2333 } 2338 }
2334 2339
2335 bool LayoutBox::mapToVisualRectInAncestorSpace( 2340 bool LayoutBox::mapToVisualRectInAncestorSpaceInternal(
2336 const LayoutBoxModelObject* ancestor, 2341 const LayoutBoxModelObject* ancestor,
2337 LayoutRect& rect, 2342 TransformState& transformState,
2338 VisualRectFlags visualRectFlags) const { 2343 VisualRectFlags visualRectFlags) const {
2339 inflateVisualRectForFilter(rect); 2344 inflateVisualRectForFilter(transformState);
2340 2345
2341 if (ancestor == this) 2346 if (ancestor == this)
2342 return true; 2347 return true;
2343 2348
2344 AncestorSkipInfo skipInfo(ancestor, true); 2349 AncestorSkipInfo skipInfo(ancestor, true);
2345 LayoutObject* container = this->container(&skipInfo); 2350 LayoutObject* container = this->container(&skipInfo);
2346 LayoutBox* tableRowContainer = nullptr; 2351 LayoutBox* tableRowContainer = nullptr;
2347 // Skip table row because cells and rows are in the same coordinate space (see 2352 // Skip table row because cells and rows are in the same coordinate space (see
2348 // below, however for more comments about when |ancestor| is the table row). 2353 // below, however for more comments about when |ancestor| is the table row).
2349 if (isTableCell()) { 2354 if (isTableCell()) {
2350 DCHECK(container->isTableRow() && parentBox() == container); 2355 DCHECK(container->isTableRow() && parentBox() == container);
2351 if (container != ancestor) 2356 if (container != ancestor)
2352 container = container->parent(); 2357 container = container->parent();
2353 else 2358 else
2354 tableRowContainer = toLayoutBox(container); 2359 tableRowContainer = toLayoutBox(container);
2355 } 2360 }
2356 if (!container) 2361 if (!container)
2357 return true; 2362 return true;
2358 2363
2359 if (skipInfo.filterSkipped()) 2364 LayoutPoint containerOffset;
2360 inflateVisualRectForFilterUnderContainer(rect, *container, ancestor); 2365 if (container->isBox()) {
2366 containerOffset.moveBy(physicalLocation(toLayoutBox(container)));
2361 2367
2362 // We are now in our parent container's coordinate space. Apply our transform
2363 // to obtain a bounding box in the parent's coordinate space that encloses us.
2364 if (hasLayer() && layer()->transform()) {
2365 // Use enclosingIntRect because we cannot properly compute pixel snapping
2366 // for painted elements within the transform since we don't know the desired
2367 // subpixel accumulation at this point, and the transform may include a
2368 // scale.
2369 rect = LayoutRect(layer()->transform()->mapRect(enclosingIntRect(rect)));
2370 }
2371 LayoutPoint topLeft = rect.location();
2372 if (container->isBox()) {
2373 topLeft.moveBy(physicalLocation(toLayoutBox(container)));
2374 // If the row is the ancestor, however, add its offset back in. In effect, 2368 // If the row is the ancestor, however, add its offset back in. In effect,
2375 // this passes from the joint <td> / <tr> coordinate space to the parent 2369 // this passes from the joint <td> / <tr> coordinate space to the parent
2376 // space, then back to <tr> / <td>. 2370 // space, then back to <tr> / <td>.
2377 if (tableRowContainer) { 2371 if (tableRowContainer) {
2378 topLeft.moveBy( 2372 containerOffset.moveBy(
2379 -tableRowContainer->physicalLocation(toLayoutBox(container))); 2373 -tableRowContainer->physicalLocation(toLayoutBox(container)));
2380 } 2374 }
2381 } else if (container->isRuby()) { 2375 } else if (container->isRuby()) {
2382 // TODO(wkorman): Generalize Ruby specialization and/or document more 2376 // TODO(wkorman): Generalize Ruby specialization and/or document more
2383 // clearly. See the accompanying specialization in 2377 // clearly. See the accompanying specialization in
2384 // LayoutInline::mapToVisualRectInAncestorSpace. 2378 // LayoutInline::mapToVisualRectInAncestorSpaceInternal.
2385 topLeft.moveBy(physicalLocation()); 2379 containerOffset.moveBy(physicalLocation());
2386 } else { 2380 } else {
2387 topLeft.moveBy(location()); 2381 containerOffset.moveBy(location());
2388 } 2382 }
2389 2383
2390 const ComputedStyle& styleToUse = styleRef(); 2384 const ComputedStyle& styleToUse = styleRef();
2391 EPosition position = styleToUse.position(); 2385 EPosition position = styleToUse.position();
2392 if (position == EPosition::kAbsolute && container->isInFlowPositioned() && 2386 if (position == EPosition::kAbsolute && container->isInFlowPositioned() &&
2393 container->isLayoutInline()) { 2387 container->isLayoutInline()) {
2394 topLeft += 2388 containerOffset.move(
2395 toLayoutInline(container)->offsetForInFlowPositionedInline(*this); 2389 toLayoutInline(container)->offsetForInFlowPositionedInline(*this));
2396 } else if (styleToUse.hasInFlowPosition() && layer()) { 2390 } else if (styleToUse.hasInFlowPosition() && layer()) {
2397 // Apply the relative position offset when invalidating a rectangle. The 2391 // Apply the relative position offset when invalidating a rectangle. The
2398 // layer is translated, but the layout box isn't, so we need to do this to 2392 // layer is translated, but the layout box isn't, so we need to do this to
2399 // get the right dirty rect. Since this is called from 2393 // get the right dirty rect. Since this is called from
2400 // LayoutObject::setStyle, the relative position flag on the LayoutObject 2394 // LayoutObject::setStyle, the relative position flag on the LayoutObject
2401 // has been cleared, so use the one on the style(). 2395 // has been cleared, so use the one on the style().
2402 topLeft += layer()->offsetForInFlowPosition(); 2396 containerOffset.move(layer()->offsetForInFlowPosition());
2397 }
2398
2399 bool preserve3D = container->style()->preserves3D() || style()->preserves3D();
2400
2401 TransformState::TransformAccumulation accumulation =
2402 preserve3D ? TransformState::AccumulateTransform
2403 : TransformState::FlattenTransform;
2404
2405 if (skipInfo.filterSkipped()) {
2406 inflateVisualRectForFilterUnderContainer(transformState, *container,
2407 ancestor);
2408 }
2409
2410 // We are now in our parent container's coordinate space. Apply our transform
2411 // to obtain a bounding box in the parent's coordinate space that encloses us.
2412 if (shouldUseTransformFromContainer(container)) {
2413 TransformationMatrix t;
2414 getTransformFromContainer(container, toLayoutSize(containerOffset), t);
2415 transformState.applyTransform(t, accumulation);
2416
2417 // Use enclosingBoundingBox because we cannot properly compute pixel
2418 // snapping for painted elements within the transform since we don't know
2419 // the desired subpixel accumulation at this point, and the transform may
2420 // include a scale.
2421 if (!preserve3D) {
2422 transformState.flatten();
2423 transformState.setQuad(
2424 FloatQuad(transformState.lastPlanarQuad().enclosingBoundingBox()));
2425 }
2426 } else {
2427 transformState.move(toLayoutSize(containerOffset), accumulation);
2403 } 2428 }
2404 2429
2405 // FIXME: We ignore the lightweight clipping rect that controls use, since if 2430 // FIXME: We ignore the lightweight clipping rect that controls use, since if
2406 // |o| is in mid-layout, its controlClipRect will be wrong. For overflow clip 2431 // |o| is in mid-layout, its controlClipRect will be wrong. For overflow clip
2407 // we use the values cached by the layer. 2432 // we use the values cached by the layer.
2408 rect.setLocation(topLeft);
2409
2410 if (container->isBox() && container != ancestor && 2433 if (container->isBox() && container != ancestor &&
2411 !toLayoutBox(container)->mapScrollingContentsRectToBoxSpace( 2434 !toLayoutBox(container)->mapScrollingContentsRectToBoxSpace(
2412 rect, visualRectFlags)) 2435 transformState, accumulation, visualRectFlags))
2413 return false; 2436 return false;
2414 2437
2415 if (skipInfo.ancestorSkipped()) { 2438 if (skipInfo.ancestorSkipped()) {
2416 // If the ancestor is below the container, then we need to map the rect into 2439 // If the ancestor is below the container, then we need to map the rect into
2417 // ancestor's coordinates. 2440 // ancestor's coordinates.
2418 LayoutSize containerOffset = 2441 LayoutSize containerOffset =
2419 ancestor->offsetFromAncestorContainer(container); 2442 ancestor->offsetFromAncestorContainer(container);
2420 rect.move(-containerOffset); 2443 transformState.move(-containerOffset, accumulation);
2421 // If the ancestor is fixed, then the rect is already in its coordinates so 2444 // If the ancestor is fixed, then the rect is already in its coordinates so
2422 // doesn't need viewport-adjusting. 2445 // doesn't need viewport-adjusting.
2423 if (ancestor->style()->position() != EPosition::kFixed && 2446 if (ancestor->style()->position() != EPosition::kFixed &&
2424 container->isLayoutView() && position == EPosition::kFixed) 2447 container->isLayoutView() && position == EPosition::kFixed) {
2425 rect.move(toLayoutView(container)->offsetForFixedPosition(true)); 2448 transformState.move(toLayoutView(container)->offsetForFixedPosition(true),
2449 accumulation);
2450 }
2426 return true; 2451 return true;
2427 } 2452 }
2428 2453
2429 if (container->isLayoutView()) 2454 if (container->isLayoutView())
2430 return toLayoutView(container)->mapToVisualRectInAncestorSpace( 2455 return toLayoutView(container)->mapToVisualRectInAncestorSpaceInternal(
2431 ancestor, rect, position == EPosition::kFixed ? IsFixed : 0, 2456 ancestor, transformState, position == EPosition::kFixed ? IsFixed : 0,
2432 visualRectFlags); 2457 visualRectFlags);
2433 else 2458 else
2434 return container->mapToVisualRectInAncestorSpace(ancestor, rect, 2459 return container->mapToVisualRectInAncestorSpaceInternal(
2435 visualRectFlags); 2460 ancestor, transformState, visualRectFlags);
2436 } 2461 }
2437 2462
2438 void LayoutBox::inflateVisualRectForFilter(LayoutRect& visualRect) const { 2463 void LayoutBox::inflateVisualRectForFilter(
2439 if (layer() && layer()->hasFilterInducingProperty()) 2464 TransformState& transformState) const {
2440 visualRect = layer()->mapLayoutRectForFilter(visualRect); 2465 if (!layer() || !layer()->hasFilterInducingProperty())
2466 return;
2467
2468 transformState.flatten();
2469 LayoutRect rect(transformState.lastPlanarQuad().boundingBox());
2470 transformState.setQuad(
2471 FloatQuad(FloatRect(layer()->mapLayoutRectForFilter(rect))));
2441 } 2472 }
2442 2473
2443 void LayoutBox::updateLogicalWidth() { 2474 void LayoutBox::updateLogicalWidth() {
2444 LogicalExtentComputedValues computedValues; 2475 LogicalExtentComputedValues computedValues;
2445 computeLogicalWidth(computedValues); 2476 computeLogicalWidth(computedValues);
2446 2477
2447 setLogicalWidth(computedValues.m_extent); 2478 setLogicalWidth(computedValues.m_extent);
2448 setLogicalLeft(computedValues.m_position); 2479 setLogicalLeft(computedValues.m_position);
2449 setMarginStart(computedValues.m_margins.m_start); 2480 setMarginStart(computedValues.m_margins.m_start);
2450 setMarginEnd(computedValues.m_margins.m_end); 2481 setMarginEnd(computedValues.m_margins.m_end);
(...skipping 3263 matching lines...) Expand 10 before | Expand all | Expand 10 after
5714 5745
5715 void LayoutBox::MutableForPainting:: 5746 void LayoutBox::MutableForPainting::
5716 savePreviousContentBoxSizeAndLayoutOverflowRect() { 5747 savePreviousContentBoxSizeAndLayoutOverflowRect() {
5717 auto& rareData = layoutBox().ensureRareData(); 5748 auto& rareData = layoutBox().ensureRareData();
5718 rareData.m_hasPreviousContentBoxSizeAndLayoutOverflowRect = true; 5749 rareData.m_hasPreviousContentBoxSizeAndLayoutOverflowRect = true;
5719 rareData.m_previousContentBoxSize = layoutBox().contentBoxRect().size(); 5750 rareData.m_previousContentBoxSize = layoutBox().contentBoxRect().size();
5720 rareData.m_previousLayoutOverflowRect = layoutBox().layoutOverflowRect(); 5751 rareData.m_previousLayoutOverflowRect = layoutBox().layoutOverflowRect();
5721 } 5752 }
5722 5753
5723 } // namespace blink 5754 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/layout/LayoutBox.h ('k') | third_party/WebKit/Source/core/layout/LayoutFlowThread.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698