Changeset 167714 in webkit
- Timestamp:
- Apr 23, 2014 11:05:33 AM (10 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r167713 r167714 1 2014-04-22 David Hyatt <hyatt@apple.com> 2 3 [New Multicolumn] Nested columns not working at all. 4 https://bugs.webkit.org/show_bug.cgi?id=131805 5 6 Reviewed by Dean Jackson. 7 8 Add support for nested pagination contexts, allowing for an arbitrary level 9 of nesting of multicolumn layouts. There were a number of things that had to 10 be patched in order for this to work. 11 12 * rendering/RenderBlock.cpp: 13 (WebCore::RenderBlock::regionAtBlockOffset): 14 Make sure RenderMultiColumnFlowThreads just return null for regions at any 15 block offset. Individual region sets will be created as you cross ancestor 16 regions eventually, so this is just getting in the way. 17 18 * rendering/RenderLayer.cpp: 19 (WebCore::RenderLayer::enclosingPaginationLayerInSubtree): 20 Add a new helper method for obtaining an enclosingPaginationLayer when 21 constrained by some root. This function ensures you don't accidentally 22 cross your subtree root when looking for enclosing pagination layers. 23 24 (WebCore::RenderLayer::collectFragments): 25 Patch collectFragments to know how to recur to collect ancestor fragments 26 in order to apply nested splitting as you cross pagination boundaries. 27 28 (WebCore::RenderLayer::updatePaintingInfoForFragments): 29 (WebCore::RenderLayer::calculateClipRects): 30 * rendering/RenderLayer.h: 31 (WebCore::LayerFragment::LayerFragment): 32 (WebCore::LayerFragment::setRects): 33 (WebCore::LayerFragment::moveBy): 34 (WebCore::LayerFragment::intersect): 35 Improve the LayerFragment so that it caches transformed bounding boxes as 36 well. This is needed to fix intersectsDamageRect so that it doesn't grab 37 the wrong bounding box when checking inline layers that are paginated. 38 39 * rendering/RenderMultiColumnFlowThread.cpp: 40 (WebCore::RenderMultiColumnFlowThread::flowThreadDescendantInserted): 41 Ignore inserted flow threads inside an ancestor flow thread, since we only 42 care about what the sets do. 43 44 * rendering/RenderObject.cpp: 45 (WebCore::RenderObject::insertedIntoTree): 46 Make sure that nested flow thread layers return themselves when a child 47 is inserted directly under them. 48 1 49 2014-04-22 Myles C. Maxfield <mmaxfield@apple.com> 2 50 -
trunk/Source/WebCore/rendering/RenderBlock.cpp
r167706 r167714 4829 4829 RenderRegion* RenderBlock::regionAtBlockOffset(LayoutUnit blockOffset) const 4830 4830 { 4831 if (isInFlowRenderFlowThread()) 4832 return 0; 4833 4831 4834 RenderFlowThread* flowThread = flowThreadContainingBlock(); 4832 4835 if (!flowThread || !flowThread->hasValidRegionInfo()) -
trunk/Source/WebCore/rendering/RenderLayer.cpp
r167562 r167714 4241 4241 } 4242 4242 4243 RenderLayer* RenderLayer::enclosingPaginationLayerInSubtree(const RenderLayer* rootLayer) const 4244 { 4245 // If we don't have an enclosing layer, or if the root layer is the same as the enclosing layer, 4246 // then just return the enclosing pagination layer (it will be 0 in the former case and the rootLayer in the latter case). 4247 if (!m_enclosingPaginationLayer || rootLayer == m_enclosingPaginationLayer) 4248 return m_enclosingPaginationLayer; 4249 4250 // Walk up the layer tree and see which layer we hit first. If it's the root, then the enclosing pagination 4251 // layer isn't in our subtree and we return 0. If we hit the enclosing pagination layer first, then 4252 // we can return it. 4253 for (const RenderLayer* layer = this; layer; layer = layer->parent()) { 4254 if (layer == rootLayer) 4255 return 0; 4256 if (layer == m_enclosingPaginationLayer) 4257 return m_enclosingPaginationLayer; 4258 } 4259 4260 // This should never be reached, since an enclosing layer should always either be the rootLayer or be 4261 // our enclosing pagination layer. 4262 ASSERT_NOT_REACHED(); 4263 return 0; 4264 } 4265 4243 4266 void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, RenderRegion* region, const LayoutRect& dirtyRect, 4244 4267 ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutPoint* offsetFromRoot, 4245 const LayoutRect* layerBoundingBox) 4246 { 4247 if (!enclosingPaginationLayer() || hasTransform()) { 4268 const LayoutRect* layerBoundingBox, ShouldApplyRootOffsetToFragments applyRootOffsetToFragments) 4269 { 4270 RenderLayer* paginationLayer = enclosingPaginationLayerInSubtree(rootLayer); 4271 if (!paginationLayer || hasTransform()) { 4248 4272 // For unpaginated layers, there is only one fragment. 4249 4273 LayerFragment fragment; … … 4256 4280 // Compute our offset within the enclosing pagination layer. 4257 4281 LayoutPoint offsetWithinPaginatedLayer; 4258 convertToLayerCoords( enclosingPaginationLayer(), offsetWithinPaginatedLayer);4282 convertToLayerCoords(paginationLayer, offsetWithinPaginatedLayer); 4259 4283 4260 4284 // Calculate clip rects relative to the enclosingPaginationLayer. The purpose of this call is to determine our bounds clipped to intermediate 4261 4285 // layers between us and the pagination context. It's important to minimize the number of fragments we need to create and this helps with that. 4262 ClipRectsContext paginationClipRectsContext( enclosingPaginationLayer(), region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip);4286 ClipRectsContext paginationClipRectsContext(paginationLayer, region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip); 4263 4287 LayoutRect layerBoundsInFlowThread; 4264 4288 ClipRect backgroundRectInFlowThread; … … 4269 4293 4270 4294 // Take our bounding box within the flow thread and clip it. 4271 LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : boundingBox( enclosingPaginationLayer(), 0, &offsetWithinPaginatedLayer);4295 LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : boundingBox(paginationLayer, 0, &offsetWithinPaginatedLayer); 4272 4296 layerBoundingBoxInFlowThread.intersect(backgroundRectInFlowThread.rect()); 4273 4297 4298 RenderFlowThread& enclosingFlowThread = toRenderFlowThread(paginationLayer->renderer()); 4299 RenderLayer* parentPaginationLayer = paginationLayer->parent()->enclosingPaginationLayerInSubtree(rootLayer); 4300 LayerFragments ancestorFragments; 4301 if (parentPaginationLayer) { 4302 // Compute a bounding box accounting for fragments. 4303 LayoutRect layerFragmentBoundingBoxInParentPaginationLayer = enclosingFlowThread.fragmentsBoundingBox(layerBoundingBoxInFlowThread); 4304 4305 // Convert to be in the ancestor pagination context's coordinate space. 4306 LayoutPoint offsetWithinParentPaginatedLayer; 4307 paginationLayer->convertToLayerCoords(parentPaginationLayer, offsetWithinParentPaginatedLayer); 4308 layerFragmentBoundingBoxInParentPaginationLayer.moveBy(offsetWithinParentPaginatedLayer); 4309 4310 // Now collect ancestor fragments. 4311 parentPaginationLayer->collectFragments(ancestorFragments, rootLayer, region, dirtyRect, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip, nullptr, &layerFragmentBoundingBoxInParentPaginationLayer, ApplyRootOffsetToFragments); 4312 4313 if (ancestorFragments.isEmpty()) 4314 return; 4315 4316 for (auto& ancestorFragment : ancestorFragments) { 4317 // Shift the dirty rect into flow thread coordinates. 4318 LayoutRect dirtyRectInFlowThread(dirtyRect); 4319 dirtyRectInFlowThread.moveBy(-offsetWithinParentPaginatedLayer + -ancestorFragment.paginationOffset); 4320 4321 size_t oldSize = fragments.size(); 4322 4323 // Tell the flow thread to collect the fragments. We pass enough information to create a minimal number of fragments based off the pages/columns 4324 // that intersect the actual dirtyRect as well as the pages/columns that intersect our layer's bounding box. 4325 enclosingFlowThread.collectLayerFragments(fragments, layerBoundingBoxInFlowThread, dirtyRectInFlowThread); 4326 4327 size_t newSize = fragments.size(); 4328 4329 if (oldSize == newSize) 4330 continue; 4331 4332 for (size_t i = oldSize; i < newSize; ++i) { 4333 LayerFragment& fragment = fragments.at(i); 4334 4335 // Set our four rects with all clipping applied that was internal to the flow thread. 4336 fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, outlineRectInFlowThread, &layerBoundingBoxInFlowThread); 4337 4338 // Shift to the root-relative physical position used when painting the flow thread in this fragment. 4339 fragment.moveBy(ancestorFragment.paginationOffset + fragment.paginationOffset + offsetWithinParentPaginatedLayer); 4340 4341 // Intersect the fragment with our ancestor's background clip so that e.g., columns in an overflow:hidden block are 4342 // properly clipped by the overflow. 4343 fragment.intersect(ancestorFragment.paginationClip); 4344 4345 // Now intersect with our pagination clip. This will typically mean we're just intersecting the dirty rect with the column 4346 // clip, so the column clip ends up being all we apply. 4347 fragment.intersect(fragment.paginationClip); 4348 4349 if (applyRootOffsetToFragments == ApplyRootOffsetToFragments) 4350 fragment.paginationOffset = fragment.paginationOffset + offsetWithinParentPaginatedLayer; 4351 } 4352 } 4353 4354 return; 4355 } 4356 4274 4357 // Shift the dirty rect into flow thread coordinates. 4275 4358 LayoutPoint offsetOfPaginationLayerFromRoot; … … 4280 4363 // Tell the flow thread to collect the fragments. We pass enough information to create a minimal number of fragments based off the pages/columns 4281 4364 // that intersect the actual dirtyRect as well as the pages/columns that intersect our layer's bounding box. 4282 RenderFlowThread& enclosingFlowThread = toRenderFlowThread(enclosingPaginationLayer()->renderer());4283 4365 enclosingFlowThread.collectLayerFragments(fragments, layerBoundingBoxInFlowThread, dirtyRectInFlowThread); 4284 4366 … … 4288 4370 // Get the parent clip rects of the pagination layer, since we need to intersect with that when painting column contents. 4289 4371 ClipRect ancestorClipRect = dirtyRect; 4290 if ( enclosingPaginationLayer()->parent()) {4372 if (paginationLayer->parent()) { 4291 4373 ClipRectsContext clipRectsContext(rootLayer, region, clipRectsType, inOverlayScrollbarSizeRelevancy, respectOverflowClip); 4292 ancestorClipRect = enclosingPaginationLayer()->backgroundClipRect(clipRectsContext);4374 ancestorClipRect = paginationLayer->backgroundClipRect(clipRectsContext); 4293 4375 ancestorClipRect.intersect(dirtyRect); 4294 4376 } … … 4298 4380 4299 4381 // Set our four rects with all clipping applied that was internal to the flow thread. 4300 fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, outlineRectInFlowThread );4382 fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlowThread, outlineRectInFlowThread, &layerBoundingBoxInFlowThread); 4301 4383 4302 4384 // Shift to the root-relative physical position used when painting the flow thread in this fragment. … … 4310 4392 // clip, so the column clip ends up being all we apply. 4311 4393 fragment.intersect(fragment.paginationClip); 4394 4395 if (applyRootOffsetToFragments == ApplyRootOffsetToFragments) 4396 fragment.paginationOffset = fragment.paginationOffset + offsetOfPaginationLayerFromRoot; 4312 4397 } 4313 4398 } … … 4322 4407 if (this != localPaintingInfo.rootLayer || !(localPaintFlags & PaintLayerPaintingOverflowContents)) { 4323 4408 LayoutPoint newOffsetFromRoot = *offsetFromRoot + fragment.paginationOffset; 4324 fragment.shouldPaintContent &= intersectsDamageRect(fragment.layerBounds, fragment.backgroundRect.rect(), localPaintingInfo.rootLayer, &newOffsetFromRoot, localPaintingInfo.renderNamedFlowFragment );4409 fragment.shouldPaintContent &= intersectsDamageRect(fragment.layerBounds, fragment.backgroundRect.rect(), localPaintingInfo.rootLayer, &newOffsetFromRoot, localPaintingInfo.renderNamedFlowFragment, fragment.hasBoundingBox ? &fragment.boundingBox : 0); 4325 4410 } 4326 4411 } … … 5651 5736 } 5652 5737 5653 bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot, RenderRegion* region ) const5738 bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot, RenderRegion* region, const LayoutRect* cachedBoundingBox) const 5654 5739 { 5655 5740 // Always examine the canvas and the root. … … 5679 5764 return true; 5680 5765 } 5681 5766 5682 5767 // Otherwise we need to compute the bounding box of this single layer and see if it intersects 5683 // the damage rect. 5768 // the damage rect. It's possible the fragment computed the bounding box already, in which case we 5769 // can use the cached value. 5770 if (cachedBoundingBox) 5771 return cachedBoundingBox->intersects(damageRect); 5772 5684 5773 return boundingBox(rootLayer, 0, offsetFromRoot).intersects(damageRect); 5685 5774 } … … 5735 5824 else 5736 5825 renderer().containingBlock()->flipForWritingMode(result); 5737 5738 if (enclosingPaginationLayer() && (flags & UseFragmentBoxes)) { 5826 5827 const RenderLayer* paginationLayer = (flags & UseFragmentBoxes) ? enclosingPaginationLayerInSubtree(ancestorLayer) : 0; 5828 const RenderLayer* childLayer = this; 5829 bool isPaginated = paginationLayer; 5830 5831 while (paginationLayer) { 5739 5832 // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to 5740 5833 // get our true bounding box. 5741 5834 LayoutPoint offsetWithinPaginationLayer; 5742 c onvertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginationLayer);5835 childLayer->convertToLayerCoords(paginationLayer, offsetWithinPaginationLayer); 5743 5836 result.moveBy(offsetWithinPaginationLayer); 5744 5837 5745 RenderFlowThread& enclosingFlowThread = toRenderFlowThread( enclosingPaginationLayer()->renderer());5838 RenderFlowThread& enclosingFlowThread = toRenderFlowThread(paginationLayer->renderer()); 5746 5839 result = enclosingFlowThread.fragmentsBoundingBox(result); 5747 5840 5841 childLayer = paginationLayer; 5842 paginationLayer = paginationLayer->parent()->enclosingPaginationLayerInSubtree(ancestorLayer); 5843 } 5844 5845 if (isPaginated) { 5748 5846 LayoutPoint delta; 5749 if (offsetFromRoot) 5750 delta = *offsetFromRoot; 5751 else 5752 enclosingPaginationLayer()->convertToLayerCoords(ancestorLayer, delta); 5847 childLayer->convertToLayerCoords(ancestorLayer, delta); 5753 5848 result.moveBy(delta); 5754 5849 return result; 5755 5850 } 5756 5851 5757 5852 LayoutPoint delta; 5758 5853 if (offsetFromRoot) -
trunk/Source/WebCore/rendering/RenderLayer.h
r167424 r167714 237 237 }; 238 238 239 enum ShouldApplyRootOffsetToFragments { 240 ApplyRootOffsetToFragments, 241 IgnoreRootOffsetForFragments 242 }; 243 239 244 struct ClipRectsCache { 240 245 WTF_MAKE_FAST_ALLOCATED; … … 274 279 LayerFragment() 275 280 : shouldPaintContent(false) 281 , hasBoundingBox(false) 276 282 { } 277 283 278 void setRects(const LayoutRect& bounds, const ClipRect& background, const ClipRect& foreground, const ClipRect& outline )284 void setRects(const LayoutRect& bounds, const ClipRect& background, const ClipRect& foreground, const ClipRect& outline, const LayoutRect* bbox) 279 285 { 280 286 layerBounds = bounds; … … 282 288 foregroundRect = foreground; 283 289 outlineRect = outline; 290 if (bbox) { 291 boundingBox = *bbox; 292 hasBoundingBox = true; 293 } 284 294 } 285 295 … … 291 301 outlineRect.moveBy(offset); 292 302 paginationClip.moveBy(offset); 303 boundingBox.moveBy(offset); 293 304 } 294 305 … … 298 309 foregroundRect.intersect(rect); 299 310 outlineRect.intersect(rect); 311 boundingBox.intersect(rect); 300 312 } 301 313 302 314 bool shouldPaintContent; 315 bool hasBoundingBox; 303 316 LayoutRect layerBounds; 304 317 ClipRect backgroundRect; 305 318 ClipRect foregroundRect; 306 319 ClipRect outlineRect; 320 LayoutRect boundingBox; 307 321 308 322 // Unique to paginated fragments. The physical translation to apply to shift the layer when painting/hit-testing. … … 697 711 698 712 // Pass offsetFromRoot if known. 699 bool intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot = 0, RenderRegion* = 0 ) const;713 bool intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot = 0, RenderRegion* = 0, const LayoutRect* cachedBoundingBox = 0) const; 700 714 701 715 enum CalculateLayerBoundsFlag { … … 933 947 934 948 IntSize clampScrollOffset(const IntSize&) const; 949 950 RenderLayer* enclosingPaginationLayerInSubtree(const RenderLayer* rootLayer) const; 935 951 936 952 void setNextSibling(RenderLayer* next) { m_next = next; } … … 985 1001 void collectFragments(LayerFragments&, const RenderLayer* rootLayer, RenderRegion*, const LayoutRect& dirtyRect, 986 1002 ClipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, 987 ShouldRespectOverflowClip = RespectOverflowClip, const LayoutPoint* offsetFromRoot = 0, const LayoutRect* layerBoundingBox = 0 );1003 ShouldRespectOverflowClip = RespectOverflowClip, const LayoutPoint* offsetFromRoot = 0, const LayoutRect* layerBoundingBox = 0, ShouldApplyRootOffsetToFragments = IgnoreRootOffsetForFragments); 988 1004 void updatePaintingInfoForFragments(LayerFragments&, const LayerPaintingInfo&, PaintLayerFlags, bool shouldPaintContent, const LayoutPoint* offsetFromRoot); 989 1005 void paintBackgroundForFragments(const LayerFragments&, GraphicsContext*, GraphicsContext* transparencyLayerContext, -
trunk/Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp
r167404 r167714 267 267 void RenderMultiColumnFlowThread::flowThreadDescendantInserted(RenderObject* descendant) 268 268 { 269 if (m_beingEvacuated )269 if (m_beingEvacuated || descendant->isInFlowRenderFlowThread()) 270 270 return; 271 271 RenderObject* subtreeRoot = descendant; -
trunk/Source/WebCore/rendering/RenderObject.cpp
r167705 r167714 1925 1925 if (!isFloating() && parent()->childrenInline()) 1926 1926 parent()->dirtyLinesFromChangedChild(this); 1927 1928 if (RenderFlowThread* flowThread = parent()->flowThreadContainingBlock()) 1927 1928 if (parent()->isRenderFlowThread()) 1929 toRenderFlowThread(parent())->flowThreadDescendantInserted(this); 1930 else if (RenderFlowThread* flowThread = parent()->flowThreadContainingBlock()) 1929 1931 flowThread->flowThreadDescendantInserted(this); 1930 1932 }
Note: See TracChangeset
for help on using the changeset viewer.