Changeset 147426 in webkit
- Timestamp:
- Apr 2, 2013 6:48:53 AM (11 years ago)
- Location:
- trunk
- Files:
-
- 8 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r147424 r147426 1 2013-04-02 Andrei Bucur <abucur@adobe.com> 2 3 [CSS Regions] Nested auto-height regions don't layout correctly 4 https://bugs.webkit.org/show_bug.cgi?id=111969 5 6 Reviewed by David Hyatt. 7 8 These tests cover various combinations of dependencies between flows and regions with 9 or without auto-height. 10 11 * fast/regions/autoheight-mixed-nested-complex-regions-expected.txt: Added. 12 * fast/regions/autoheight-mixed-nested-complex-regions.html: Added. 13 * fast/regions/autoheight-mixed-nested-regions-expected.txt: Added. 14 * fast/regions/autoheight-mixed-nested-regions.html: Added. 15 * fast/regions/autoheight-mixed-parallel-regions-expected.txt: Added. 16 * fast/regions/autoheight-mixed-parallel-regions.html: Added. 17 * fast/regions/autoheight-nested-regions-expected.txt: Added. 18 * fast/regions/autoheight-nested-regions.html: Added. 19 1 20 2013-04-02 Dmitry Zvorygin <zvorygin@chromium.org> 2 21 -
trunk/Source/WebCore/ChangeLog
r147425 r147426 1 2013-04-02 Andrei Bucur <abucur@adobe.com> 2 3 [CSS Regions] Nested auto-height regions don't layout correctly 4 https://bugs.webkit.org/show_bug.cgi?id=111969 5 6 Reviewed by David Hyatt. 7 8 The patch fixes the auto-height regions processing model to work with nested named flows. Currently 9 this use case doesn't work correctly because the order in which the computed height value is propagated 10 to the regions is incorrect. For example, in the case of two flows (f1 and f2) and two auto-height 11 regions (r1 and r2) with r2 a member of f1: 12 1. the normal layout phase starts 13 2. r1 is laid out with height = 0 14 3. f1 is laid out including r2 with height = 0; overrideLogicalHeight for r1 is computed 15 4. f2 is laid out; overrideLogicalHeight for r2 is computed 16 5. the constrained layout phase starts 17 6. r1 is laid out using the overrideLogicalHeight computed in the normal phase 18 7. f1 is laid out including r2 with its overrideLogicalHeight 19 8. f2 is laid out 20 21 The problem appears at step 6 because the overrideLogicalheight computed during step 3 assumes r2 22 has a height of 0. The patch changes the algorithm to update the auto-height regions in the reverse 23 order of their flow threads dependecies. Here is a high level overview of the new algorithm, 24 considering the named flows are sorted in the order of their dependencies: 25 1. The flows are laid out from the outer flow to the inner flow. This successfully computes the outer 26 non-auto-height regions size so the inner flows have the necessary information to correctly fragment 27 the content. 28 2. The flows are laid out from the inner flow to the outer flow. After an inner flow is laid out it 29 goes into the constrained layout phase and marks the auto-height regions they need layout. This 30 means the outer flows will relayout if they depend on regions with auto-height regions belonging to 31 inner flows. This step will correctly compute the overrideLogicalHeights for the auto-height regions. 32 It's possible for non-auto-height regions to relayout if they depend on auto-height regions. This 33 will invalidate the inner flow threads and mark them as needing layout. 34 3. The last step is to do one last layout if there are pahtological dependencies between non-auto-height 35 regions and auto-height regions as detected in the previous step. 36 37 The patch also removes the layout phase flag from RenderView and moves it to the flow threads. This 38 happens because a flow needs to update its auto-height regions overrideLogicalHeight while updating 39 the logical height of the regions belonging to the inner flows that are laid out by the flow (i.e. the 40 outer flow is in the normal phase while the inner flows are in the constrained layout phase). 41 42 There's also a new flag on the RenderFlowThread that is set when the flow needs the constrained layout 43 phase. This could have been placed on the flow thread controller but I think it will be useful when doing 44 content balancing for the new multi-column implementation. 45 46 Another change is the moment we clear the overrideLogicalHeight value on empty auto-height regions because 47 we don't have to relayout a flow thread once it's in the constrained phase. We need to have the correct 48 flow thread portions correctly computed after the artificial forced break is applied at the end of the content. 49 50 Tests: fast/regions/autoheight-mixed-nested-complex-regions.html 51 fast/regions/autoheight-mixed-nested-regions.html 52 fast/regions/autoheight-mixed-parallel-regions.html 53 fast/regions/autoheight-nested-regions.html 54 55 * rendering/FlowThreadController.cpp: 56 (WebCore::FlowThreadController::FlowThreadController): 57 (WebCore::FlowThreadController::layoutRenderNamedFlowThreads): 58 (WebCore): 59 (WebCore::FlowThreadController::registerNamedFlowContentNode): 60 (WebCore::FlowThreadController::unregisterNamedFlowContentNode): 61 (WebCore::FlowThreadController::updateFlowThreadsChainIfNecessary): 62 (WebCore::FlowThreadController::updateFlowThreadsNeedingLayout): 63 (WebCore::FlowThreadController::updateFlowThreadsNeedingTwoStepLayout): 64 (WebCore::FlowThreadController::resetFlowThreadsWithAutoHeightRegions): 65 (WebCore::FlowThreadController::updateFlowThreadsIntoConstrainedPhase): 66 * rendering/FlowThreadController.h: 67 (FlowThreadController): 68 * rendering/RenderBlock.cpp: 69 (WebCore::RenderBlock::layoutBlock): 70 * rendering/RenderFlowThread.cpp: 71 (WebCore::RenderFlowThread::RenderFlowThread): 72 (WebCore::RenderFlowThread::validateRegions): 73 (WebCore::RenderFlowThread::layout): 74 (WebCore::RenderFlowThread::regionAtBlockOffset): 75 (WebCore::RenderFlowThread::applyBreakAfterContent): Apply an artificial break at the end of the content. 76 This way we can detect when the content ends and clear the overrideLogicalHeight on the empty auto-height regions. 77 (WebCore::RenderFlowThread::computeOverflowStateForRegions): 78 (WebCore): 79 (WebCore::RenderFlowThread::initializeRegionsOverrideLogicalContentHeight): 80 (WebCore::RenderFlowThread::markAutoLogicalHeightRegionsForLayout): 81 (WebCore::RenderFlowThread::updateRegionsFlowThreadPortionRect): 82 (WebCore::RenderFlowThread::addForcedRegionBreak): 83 * rendering/RenderFlowThread.h: 84 * rendering/RenderRegion.cpp: 85 (WebCore::RenderRegion::pageLogicalWidth): 86 (WebCore::RenderRegion::pageLogicalHeight): 87 (WebCore::RenderRegion::maxPageLogicalHeight): 88 (WebCore::RenderRegion::logicalHeightOfAllFlowThreadContent): 89 (WebCore::RenderRegion::layoutBlock): 90 (WebCore::RenderRegion::updateLogicalHeight): 91 * rendering/RenderView.cpp: 92 (WebCore::RenderView::RenderView): 93 (WebCore): 94 (WebCore::RenderView::layoutContentInAutoLogicalHeightRegions): 95 (WebCore::RenderView::layout): 96 * rendering/RenderView.h: 97 (WebCore): 98 (RenderView): 99 1 100 2013-04-02 Andrey Kosyakov <caseq@chromium.org> 2 101 -
trunk/Source/WebCore/rendering/FlowThreadController.cpp
r147414 r147426 50 50 , m_currentRenderFlowThread(0) 51 51 , m_isRenderNamedFlowThreadOrderDirty(false) 52 , m_needsTwoPassLayoutForAutoHeightRegions(false)53 52 , m_flowThreadsWithAutoLogicalHeightRegions(0) 54 53 { … … 98 97 99 98 void FlowThreadController::layoutRenderNamedFlowThreads() 99 { 100 updateFlowThreadsChainIfNecessary(); 101 102 for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { 103 RenderNamedFlowThread* flowRenderer = *iter; 104 flowRenderer->layoutIfNeeded(); 105 } 106 } 107 108 void FlowThreadController::registerNamedFlowContentNode(Node* contentNode, RenderNamedFlowThread* namedFlow) 109 { 110 ASSERT(contentNode && contentNode->isElementNode()); 111 ASSERT(namedFlow); 112 ASSERT(!m_mapNamedFlowContentNodes.contains(contentNode)); 113 ASSERT(!namedFlow->hasContentNode(contentNode)); 114 m_mapNamedFlowContentNodes.add(contentNode, namedFlow); 115 namedFlow->registerNamedFlowContentNode(contentNode); 116 } 117 118 void FlowThreadController::unregisterNamedFlowContentNode(Node* contentNode) 119 { 120 ASSERT(contentNode && contentNode->isElementNode()); 121 HashMap<Node*, RenderNamedFlowThread*>::iterator it = m_mapNamedFlowContentNodes.find(contentNode); 122 ASSERT(it != m_mapNamedFlowContentNodes.end()); 123 ASSERT(it->value); 124 ASSERT(it->value->hasContentNode(contentNode)); 125 it->value->unregisterNamedFlowContentNode(contentNode); 126 m_mapNamedFlowContentNodes.remove(contentNode); 127 } 128 129 void FlowThreadController::updateFlowThreadsChainIfNecessary() 100 130 { 101 131 ASSERT(m_renderNamedFlowThreadList); … … 132 162 setIsRenderNamedFlowThreadOrderDirty(false); 133 163 } 134 135 for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { 136 RenderNamedFlowThread* flowRenderer = *iter; 164 } 165 166 bool FlowThreadController::updateFlowThreadsNeedingLayout() 167 { 168 bool needsTwoPassLayout = false; 169 170 for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { 171 RenderNamedFlowThread* flowRenderer = *iter; 172 ASSERT(!flowRenderer->needsTwoPhasesLayout()); 173 flowRenderer->setInConstrainedLayoutPhase(false); 174 if (flowRenderer->needsLayout() && flowRenderer->hasAutoLogicalHeightRegions()) 175 needsTwoPassLayout = true; 176 } 177 178 if (needsTwoPassLayout) 179 resetFlowThreadsWithAutoHeightRegions(); 180 181 return needsTwoPassLayout; 182 } 183 184 bool FlowThreadController::updateFlowThreadsNeedingTwoStepLayout() 185 { 186 bool needsTwoPassLayout = false; 187 188 for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { 189 RenderNamedFlowThread* flowRenderer = *iter; 190 if (flowRenderer->needsTwoPhasesLayout()) { 191 needsTwoPassLayout = true; 192 break; 193 } 194 } 195 196 if (needsTwoPassLayout) 197 resetFlowThreadsWithAutoHeightRegions(); 198 199 return needsTwoPassLayout; 200 } 201 202 void FlowThreadController::resetFlowThreadsWithAutoHeightRegions() 203 { 204 for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { 205 RenderNamedFlowThread* flowRenderer = *iter; 206 if (flowRenderer->hasAutoLogicalHeightRegions()) { 207 flowRenderer->markAutoLogicalHeightRegionsForLayout(); 208 flowRenderer->invalidateRegions(); 209 } 210 } 211 } 212 213 void FlowThreadController::updateFlowThreadsIntoConstrainedPhase() 214 { 215 // Walk the flow chain in reverse order to update the auto-height regions and compute correct sizes for the containing regions. Only after this we can 216 // set the flow in the constrained layout phase. 217 for (RenderNamedFlowThreadList::reverse_iterator iter = m_renderNamedFlowThreadList->rbegin(); iter != m_renderNamedFlowThreadList->rend(); ++iter) { 218 RenderNamedFlowThread* flowRenderer = *iter; 219 ASSERT(!flowRenderer->hasRegions() || flowRenderer->hasValidRegionInfo()); 137 220 flowRenderer->layoutIfNeeded(); 138 } 139 } 140 141 void FlowThreadController::registerNamedFlowContentNode(Node* contentNode, RenderNamedFlowThread* namedFlow) 142 { 143 ASSERT(contentNode && contentNode->isElementNode()); 144 ASSERT(namedFlow); 145 ASSERT(!m_mapNamedFlowContentNodes.contains(contentNode)); 146 ASSERT(!namedFlow->hasContentNode(contentNode)); 147 m_mapNamedFlowContentNodes.add(contentNode, namedFlow); 148 namedFlow->registerNamedFlowContentNode(contentNode); 149 } 150 151 void FlowThreadController::unregisterNamedFlowContentNode(Node* contentNode) 152 { 153 ASSERT(contentNode && contentNode->isElementNode()); 154 HashMap<Node*, RenderNamedFlowThread*>::iterator it = m_mapNamedFlowContentNodes.find(contentNode); 155 ASSERT(it != m_mapNamedFlowContentNodes.end()); 156 ASSERT(it->value); 157 ASSERT(it->value->hasContentNode(contentNode)); 158 it->value->unregisterNamedFlowContentNode(contentNode); 159 m_mapNamedFlowContentNodes.remove(contentNode); 221 if (flowRenderer->hasAutoLogicalHeightRegions()) { 222 ASSERT(flowRenderer->needsTwoPhasesLayout()); 223 flowRenderer->markAutoLogicalHeightRegionsForLayout(); 224 } 225 flowRenderer->setInConstrainedLayoutPhase(true); 226 flowRenderer->clearNeedsTwoPhasesLayout(); 227 } 160 228 } 161 229 … … 175 243 #endif 176 244 177 bool FlowThreadController::hasRenderNamedFlowThreadsNeedingLayout() const178 {179 ASSERT(m_view->normalLayoutPhase());180 for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter)181 if ((*iter)->needsLayout())182 return true;183 return false;184 }185 186 void FlowThreadController::resetRegionsOverrideLogicalContentHeight()187 {188 ASSERT(m_view->normalLayoutPhase());189 ASSERT(hasFlowThreadsWithAutoLogicalHeightRegions());190 191 for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter)192 (*iter)->resetRegionsOverrideLogicalContentHeight();193 }194 195 void FlowThreadController::markAutoLogicalHeightRegionsForLayout()196 {197 ASSERT(m_view->constrainedFlowThreadsLayoutPhase());198 ASSERT(hasFlowThreadsWithAutoLogicalHeightRegions());199 200 for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter)201 (*iter)->markAutoLogicalHeightRegionsForLayout();202 }203 204 245 } // namespace WebCore -
trunk/Source/WebCore/rendering/FlowThreadController.h
r140948 r147426 72 72 void decrementFlowThreadsWithAutoLogicalHeightRegions() { ASSERT(m_flowThreadsWithAutoLogicalHeightRegions > 0); --m_flowThreadsWithAutoLogicalHeightRegions; } 73 73 74 bool hasRenderNamedFlowThreadsNeedingLayout() const; 74 bool updateFlowThreadsNeedingLayout(); 75 bool updateFlowThreadsNeedingTwoStepLayout(); 76 void updateFlowThreadsIntoConstrainedPhase(); 75 77 76 78 #ifndef NDEBUG … … 78 80 #endif 79 81 80 void resetRegionsOverrideLogicalContentHeight();81 void markAutoLogicalHeightRegionsForLayout();82 83 bool needsTwoPassLayoutForAutoHeightRegions() const { return m_needsTwoPassLayoutForAutoHeightRegions; }84 void setNeedsTwoPassLayoutForAutoHeightRegions(bool needsTwoPassLayout) { m_needsTwoPassLayoutForAutoHeightRegions = needsTwoPassLayout; }85 86 82 protected: 87 83 FlowThreadController(RenderView*); 84 void updateFlowThreadsChainIfNecessary(); 85 void resetFlowThreadsWithAutoHeightRegions(); 88 86 89 87 private: … … 91 89 RenderFlowThread* m_currentRenderFlowThread; 92 90 bool m_isRenderNamedFlowThreadOrderDirty; 93 bool m_needsTwoPassLayoutForAutoHeightRegions;94 91 unsigned m_flowThreadsWithAutoLogicalHeightRegions; 95 92 OwnPtr<RenderNamedFlowThreadList> m_renderNamedFlowThreadList; -
trunk/Source/WebCore/rendering/RenderBlock.cpp
r147250 r147426 1590 1590 if (relayoutForPagination(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher)) 1591 1591 return; 1592 1592 1593 1593 // Calculate our new height. 1594 1594 LayoutUnit oldHeight = logicalHeight(); 1595 1595 LayoutUnit oldClientAfterEdge = clientLogicalBottom(); 1596 1597 // Before updating the final size of the flow thread make sure a forced break is applied after the content. 1598 // This ensures the size information is correctly computed for the last auto-height region receiving content. 1599 if (isRenderFlowThread()) 1600 toRenderFlowThread(this)->applyBreakAfterContent(oldClientAfterEdge); 1601 1596 1602 updateLogicalHeight(); 1597 1603 LayoutUnit newHeight = logicalHeight(); -
trunk/Source/WebCore/rendering/RenderFlowThread.cpp
r147414 r147426 56 56 , m_dispatchRegionLayoutUpdateEvent(false) 57 57 , m_pageLogicalSizeChanged(false) 58 , m_inConstrainedLayoutPhase(false) 59 , m_needsTwoPhasesLayout(false) 58 60 { 59 61 setFlowThreadState(InsideOutOfFlowThread); … … 162 164 // Also, if we have auto-height regions we can't assume m_regionsHaveUniformLogicalHeight to be true in the first phase 163 165 // because the auto-height regions don't have their height computed yet. 164 if ( view()->normalLayoutPhase() && region->hasAutoLogicalHeight()) {166 if (!inConstrainedLayoutPhase() && region->hasAutoLogicalHeight()) { 165 167 region->setOverrideLogicalContentHeight(region->maxPageLogicalHeight()); 166 168 m_regionsHaveUniformLogicalHeight = false; … … 193 195 194 196 m_pageLogicalSizeChanged = m_regionsInvalidated && everHadLayout(); 197 198 // In case this is the second pass of the normal phase we need to update the auto-height regions to their initial value. 199 // If the region chain was invalidated this will happen anyway. 200 if (!m_regionsInvalidated && !inConstrainedLayoutPhase()) 201 initializeRegionsOverrideLogicalContentHeight(); 202 195 203 validateRegions(); 204 205 // This is the first phase of the layout and because we have auto-height regions we'll need a second 206 // pass to update the flow with the computed auto-height regions. 207 m_needsTwoPhasesLayout = !inConstrainedLayoutPhase() && hasAutoLogicalHeightRegions(); 196 208 197 209 CurrentRenderFlowThreadMaintainer currentFlowThreadSetter(this); … … 380 392 lastValidRegion = region; 381 393 382 if (region->hasOverrideHeight() && view()->normalLayoutPhase()) {394 if (region->hasOverrideHeight() && !inConstrainedLayoutPhase()) { 383 395 accumulatedLogicalHeight += region->overrideLogicalContentHeight(); 384 396 if (offset < accumulatedLogicalHeight) … … 646 658 } 647 659 648 void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterEdge) 649 { 650 LayoutUnit height = oldClientAfterEdge; 651 652 LayoutUnit offsetBreakAdjustment = 0; 660 void RenderFlowThread::applyBreakAfterContent(LayoutUnit clientHeight) 661 { 653 662 // Simulate a region break at height. If it points inside an auto logical height region, 654 663 // then it may determine the region override logical content height. 655 addForcedRegionBreak(height, this, false, &offsetBreakAdjustment); 656 657 // During the normal layout phase of the flow thread all the auto-height regions have the overrideLogicalContentHeight set to max height. 658 // We need to clear the overrideLogicalContentHeight for all the regions that didn't receive any content, starting with firstEmptyRegion. 659 RenderRegion* firstEmptyRegion = 0; 660 if (view()->normalLayoutPhase()) 661 firstEmptyRegion = regionAtBlockOffset(height + offsetBreakAdjustment); 664 addForcedRegionBreak(clientHeight, this, false); 665 } 666 667 void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterEdge) 668 { 669 LayoutUnit height = oldClientAfterEdge; 662 670 663 671 // FIXME: the visual overflow of middle region (if it is the last one to contain any content in a render flow thread) … … 670 678 height = isHorizontalWritingMode() ? visualOverflowRect().maxY() : visualOverflowRect().maxX(); 671 679 672 bool inEmptyRegionsSection = false;673 680 RenderRegion* lastReg = lastRegion(); 674 681 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { … … 690 697 || state == RenderRegion::RegionOverset) 691 698 setDispatchRegionLayoutUpdateEvent(true); 692 693 if (region == firstEmptyRegion)694 inEmptyRegionsSection = true;695 696 // Clear the overrideLogicalContentHeight value for autoheight regions that didn't receive any content.697 if (inEmptyRegionsSection && region->hasAutoLogicalHeight())698 region->clearOverrideLogicalContentHeight();699 699 } 700 700 … … 792 792 #endif 793 793 794 void RenderFlowThread::resetRegionsOverrideLogicalContentHeight()795 {796 ASSERT(view()->layoutState());797 ASSERT(view()->normalLayoutPhase());798 799 if (!hasAutoLogicalHeightRegions())800 return;801 802 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {803 RenderRegion* region = *iter;804 if (!region->hasAutoLogicalHeight())805 continue;806 807 region->clearOverrideLogicalContentHeight();808 // FIXME: We need to find a way to avoid marking all the regions ancestors for layout809 // as we are already inside layout.810 region->setNeedsLayout(true);811 }812 // Make sure we don't skip any region breaks when we do the layout again.813 // Using m_regionsInvalidated to force all the RenderFlowThread children do the layout again.814 invalidateRegions();815 }816 817 794 // During the normal layout phase of the named flow the regions are initialized with a height equal to their max-height. 818 795 // This way unforced breaks are automatically placed when a region is full and the content height/position correctly estimated. … … 820 797 void RenderFlowThread::initializeRegionsOverrideLogicalContentHeight(RenderRegion* startRegion) 821 798 { 822 ASSERT( view()->normalLayoutPhase());799 ASSERT(!inConstrainedLayoutPhase()); 823 800 if (!hasAutoLogicalHeightRegions()) 824 801 return; … … 834 811 void RenderFlowThread::markAutoLogicalHeightRegionsForLayout() 835 812 { 836 ASSERT(view()->layoutState()); 837 ASSERT(view()->constrainedFlowThreadsLayoutPhase()); 838 839 if (!hasAutoLogicalHeightRegions()) 840 return; 813 ASSERT(hasAutoLogicalHeightRegions()); 841 814 842 815 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { … … 849 822 region->setNeedsLayout(true); 850 823 } 851 852 invalidateRegions(); 853 } 854 855 void RenderFlowThread::updateRegionsFlowThreadPortionRect() 856 { 824 } 825 826 void RenderFlowThread::updateRegionsFlowThreadPortionRect(const RenderRegion* lastRegionWithContent) 827 { 828 ASSERT(!lastRegionWithContent || (!inConstrainedLayoutPhase() && hasAutoLogicalHeightRegions())); 857 829 LayoutUnit logicalHeight = 0; 830 bool emptyRegionsSegment = false; 858 831 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { 859 832 RenderRegion* region = *iter; 833 834 // If we find an empty auto-height region, clear the overrideLogicalContentHeight value. 835 if (emptyRegionsSegment && region->hasAutoLogicalHeight()) 836 region->clearOverrideLogicalContentHeight(); 860 837 861 838 LayoutUnit regionLogicalWidth = region->pageLogicalWidth(); … … 866 843 region->setFlowThreadPortionRect(isHorizontalWritingMode() ? regionRect : regionRect.transposedRect()); 867 844 logicalHeight += regionLogicalHeight; 868 } 845 846 // Once we find the last region with content the next regions are considered empty. 847 if (lastRegionWithContent == region) 848 emptyRegionsSegment = true; 849 } 850 851 ASSERT(!lastRegionWithContent || emptyRegionsSegment); 869 852 } 870 853 … … 878 861 // and we use the content breaks to determine the overrideContentLogicalHeight for 879 862 // auto logical height regions. 880 if ( view()->constrainedFlowThreadsLayoutPhase())863 if (inConstrainedLayoutPhase()) 881 864 return false; 882 865 … … 903 886 return false; 904 887 888 bool lastBreakAfterContent = breakChild == this; 905 889 bool overrideLogicalContentHeightComputed = false; 906 890 … … 931 915 932 916 // If the break was found inside an auto-height region its size changed so we need to recompute the flow thread portion rectangles. 933 if (overrideLogicalContentHeightComputed) 917 // Also, if this is the last break after the content we need to clear the overrideLogicalContentHeight value on the last empty regions. 918 if (hasAutoLogicalHeightRegions() && lastBreakAfterContent) 919 updateRegionsFlowThreadPortionRect(region); 920 else if (overrideLogicalContentHeightComputed) 934 921 updateRegionsFlowThreadPortionRect(); 935 922 -
trunk/Source/WebCore/rendering/RenderFlowThread.h
r147414 r147426 137 137 bool objectInFlowRegion(const RenderObject*, const RenderRegion*) const; 138 138 139 void resetRegionsOverrideLogicalContentHeight();140 139 void markAutoLogicalHeightRegionsForLayout(); 141 140 142 141 bool addForcedRegionBreak(LayoutUnit, RenderObject* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0); 142 void applyBreakAfterContent(LayoutUnit); 143 143 144 144 bool pageLogicalSizeChanged() const { return m_pageLogicalSizeChanged; } … … 155 155 LayoutRect fragmentsBoundingBox(const LayoutRect& layerBoundingBox); 156 156 157 void setInConstrainedLayoutPhase(bool value) { m_inConstrainedLayoutPhase = value; } 158 bool inConstrainedLayoutPhase() const { return m_inConstrainedLayoutPhase; } 159 160 bool needsTwoPhasesLayout() const { return m_needsTwoPhasesLayout; } 161 void clearNeedsTwoPhasesLayout() { m_needsTwoPhasesLayout = false; } 162 157 163 protected: 158 164 virtual const char* renderName() const = 0; … … 162 168 virtual LayoutUnit initialLogicalWidth() const { return 0; }; 163 169 164 void updateRegionsFlowThreadPortionRect( );170 void updateRegionsFlowThreadPortionRect(const RenderRegion* = 0); 165 171 bool shouldRepaint(const LayoutRect&) const; 166 172 bool regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const; … … 223 229 bool m_dispatchRegionLayoutUpdateEvent : 1; 224 230 bool m_pageLogicalSizeChanged : 1; 231 bool m_inConstrainedLayoutPhase : 1; 232 bool m_needsTwoPhasesLayout : 1; 225 233 }; 226 234 -
trunk/Source/WebCore/rendering/RenderRegion.cpp
r147411 r147426 60 60 LayoutUnit RenderRegion::pageLogicalWidth() const 61 61 { 62 ASSERT(m_flowThread); 62 63 return m_flowThread->isHorizontalWritingMode() ? contentWidth() : contentHeight(); 63 64 } … … 65 66 LayoutUnit RenderRegion::pageLogicalHeight() const 66 67 { 67 if (hasOverrideHeight() && view()->normalLayoutPhase()) { 68 ASSERT(m_flowThread); 69 if (hasOverrideHeight() && !m_flowThread->inConstrainedLayoutPhase()) { 68 70 ASSERT(hasAutoLogicalHeight()); 69 71 return overrideLogicalContentHeight(); … … 76 78 LayoutUnit RenderRegion::maxPageLogicalHeight() const 77 79 { 78 ASSERT(hasAutoLogicalHeight() && view()->normalLayoutPhase()); 80 ASSERT(m_flowThread); 81 ASSERT(hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase()); 79 82 return style()->logicalMaxHeight().isUndefined() ? LayoutUnit::max() / 2 : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight()); 80 83 } … … 82 85 LayoutUnit RenderRegion::logicalHeightOfAllFlowThreadContent() const 83 86 { 84 if (hasOverrideHeight() && view()->normalLayoutPhase()) { 87 ASSERT(m_flowThread); 88 if (hasOverrideHeight() && !m_flowThread->inConstrainedLayoutPhase()) { 85 89 ASSERT(hasAutoLogicalHeight()); 86 90 return overrideLogicalContentHeight(); … … 272 276 oldRegionRect = oldRegionRect.transposedRect(); 273 277 274 if (view()->checkTwoPassLayoutForAutoHeightRegions() && hasAutoLogicalHeight()) 275 view()->flowThreadController()->setNeedsTwoPassLayoutForAutoHeightRegions(true); 276 277 if (!isRenderRegionSet() && (oldRegionRect.width() != pageLogicalWidth() || oldRegionRect.height() != pageLogicalHeight())) { 278 if (hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase()) { 278 279 m_flowThread->invalidateRegions(); 279 if (view()->checkTwoPassLayoutForAutoHeightRegions())280 view()->flowThreadController()->setNeedsTwoPassLayoutForAutoHeightRegions(true);280 clearOverrideLogicalContentHeight(); 281 return; 281 282 } 283 284 if (!isRenderRegionSet() && (oldRegionRect.width() != pageLogicalWidth() || oldRegionRect.height() != pageLogicalHeight())) 285 // This can happen even if we are in the inConstrainedLayoutPhase and it will trigger a pathological layout of the flow thread. 286 m_flowThread->invalidateRegions(); 282 287 } 283 288 … … 634 639 // content height only if the view is in the layout phase 635 640 // in which all the auto logical height regions have their override logical height set. 636 if ( view()->normalLayoutPhase())641 if (!m_flowThread->inConstrainedLayoutPhase()) 637 642 return; 638 643 -
trunk/Source/WebCore/rendering/RenderView.cpp
r145126 r147426 69 69 , m_renderQuoteHead(0) 70 70 , m_renderCounterCount(0) 71 , m_layoutPhase(RenderViewNormalLayout)72 71 { 73 72 // init RenderObject attributes … … 207 206 } 208 207 209 // The algorithm to layout the flow thread content in auto height regions has to make sure 210 // that when a two-pass layout is needed, the auto height regions always start the first 211 // pass without a computed override logical content height (from previous layouts). 212 // This way, the layout algorithm gives the same result in all situations. 213 // If the flow thread content does not need layout, the decision of whether we need a full 214 // two pass layout cannot be made up-front. Therefore, we do a first layout, and if an auto 215 // height region needs layout or a non-auto height region changes its box dimensions, 216 // we need to perform a full two pass layout. 208 // The algorithm below assumes this is a full layout. In case there are previously computed values for regions, supplemental steps are taken 209 // to ensure the results are the same as those obtained from a full layout (i.e. the auto-height regions from all the flows are marked as needing 210 // layout). 211 // 1. The flows are laid out from the outer flow to the inner flow. This successfully computes the outer non-auto-height regions size so the 212 // inner flows have the necessary information to correctly fragment the content. 213 // 2. The flows are laid out from the inner flow to the outer flow. After an inner flow is laid out it goes into the constrained layout phase 214 // and marks the auto-height regions they need layout. This means the outer flows will relayout if they depend on regions with auto-height regions 215 // belonging to inner flows. This step will correctly compute the overrideLogicalHeights for the auto-height regions. It's possible for non-auto-height 216 // regions to relayout if they depend on auto-height regions. This will invalidate the inner flow threads and mark them as needing layout. 217 // 3. The last step is to do one last layout if there are pathological dependencies between non-auto-height regions and auto-height regions 218 // as detected in the previous step. 217 219 void RenderView::layoutContentInAutoLogicalHeightRegions(const LayoutState& state) 218 220 { 219 ASSERT(!flowThreadController()->needsTwoPassLayoutForAutoHeightRegions()); 220 221 if (!flowThreadController()->hasRenderNamedFlowThreadsNeedingLayout()) { 221 // We need to invalidate all the flows with auto-height regions if one such flow needs layout. 222 // If none is found we do a layout a check back again afterwards. 223 if (!flowThreadController()->updateFlowThreadsNeedingLayout()) { 224 // Do a first layout of the content. In some cases more layouts are not needed (e.g. only flows with non-auto-height regions have changed). 222 225 layoutContent(state); 223 if (!flowThreadController()->needsTwoPassLayoutForAutoHeightRegions()) 226 227 // If we find no named flow needing a two step layout after the first layout, exit early. 228 // Otherwise, initiate the two step layout algorithm and recompute all the flows. 229 if (!flowThreadController()->updateFlowThreadsNeedingTwoStepLayout()) 224 230 return; 225 231 } 226 232 227 // Start a full two phase layout for regions with auto logical height. 228 flowThreadController()->resetRegionsOverrideLogicalContentHeight(); 233 // Layout to recompute all the named flows with auto-height regions. 229 234 layoutContent(state); 230 235 231 m_layoutPhase = ConstrainedFlowThreadsLayoutInAutoLogicalHeightRegions; 232 flowThreadController()->markAutoLogicalHeightRegionsForLayout(); 233 layoutContent(state); 234 flowThreadController()->setNeedsTwoPassLayoutForAutoHeightRegions(false); 236 // Propagate the computed auto-height values upwards. 237 // Non-auto-height regions may invalidate the flow thread because they depended on auto-height regions, but that's ok. 238 flowThreadController()->updateFlowThreadsIntoConstrainedPhase(); 239 240 // Do one last layout that should update the auto-height regions found in the main flow 241 // and solve pathological dependencies between regions (e.g. a non-auto-height region depending 242 // on an auto-height one). 243 if (needsLayout()) 244 layoutContent(state); 235 245 } 236 246 … … 270 280 m_layoutState = &state; 271 281 272 m_layoutPhase = RenderViewNormalLayout;273 282 if (checkTwoPassLayoutForAutoHeightRegions()) 274 283 layoutContentInAutoLogicalHeightRegions(state); -
trunk/Source/WebCore/rendering/RenderView.h
r146642 r147426 32 32 33 33 class FlowThreadController; 34 class RenderQuote; 34 35 class RenderWidget; 35 class RenderQuote;36 36 37 37 #if USE(ACCELERATED_COMPOSITING) … … 208 208 FlowThreadController* flowThreadController(); 209 209 210 enum RenderViewLayoutPhase { RenderViewNormalLayout, ConstrainedFlowThreadsLayoutInAutoLogicalHeightRegions };211 bool normalLayoutPhase() const { return m_layoutPhase == RenderViewNormalLayout; }212 bool constrainedFlowThreadsLayoutPhase() const { return m_layoutPhase == ConstrainedFlowThreadsLayoutInAutoLogicalHeightRegions; }213 214 210 void styleDidChange(StyleDifference, const RenderStyle* oldStyle); 215 211 … … 340 336 RenderQuote* m_renderQuoteHead; 341 337 unsigned m_renderCounterCount; 342 RenderViewLayoutPhase m_layoutPhase;343 338 }; 344 339
Note: See TracChangeset
for help on using the changeset viewer.