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

Side by Side Diff: Source/core/rendering/RenderMultiColumnSet.cpp

Issue 143383002: Region based multicol: support explicit column breaks (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Code review. Created 6 years, 10 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
« no previous file with comments | « Source/core/rendering/RenderMultiColumnSet.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2012 Apple Inc. All rights reserved. 2 * Copyright (C) 2012 Apple Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 25 matching lines...) Expand all
36 namespace WebCore { 36 namespace WebCore {
37 37
38 RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread) 38 RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread)
39 : RenderRegionSet(0, flowThread) 39 : RenderRegionSet(0, flowThread)
40 , m_computedColumnCount(1) 40 , m_computedColumnCount(1)
41 , m_computedColumnWidth(0) 41 , m_computedColumnWidth(0)
42 , m_computedColumnHeight(0) 42 , m_computedColumnHeight(0)
43 , m_maxColumnHeight(LayoutUnit::max()) 43 , m_maxColumnHeight(LayoutUnit::max())
44 , m_minSpaceShortage(LayoutUnit::max()) 44 , m_minSpaceShortage(LayoutUnit::max())
45 , m_minimumColumnHeight(0) 45 , m_minimumColumnHeight(0)
46 , m_forcedBreaksCount(0)
47 , m_maximumDistanceBetweenForcedBreaks(0)
48 , m_forcedBreakOffset(0)
49 { 46 {
50 } 47 }
51 48
52 RenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread* fl owThread) 49 RenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread* fl owThread)
53 { 50 {
54 Document& document = flowThread->document(); 51 Document& document = flowThread->document();
55 RenderMultiColumnSet* renderer = new RenderMultiColumnSet(flowThread); 52 RenderMultiColumnSet* renderer = new RenderMultiColumnSet(flowThread);
56 renderer->setDocumentForAnonymous(&document); 53 renderer->setDocumentForAnonymous(&document);
57 return renderer; 54 return renderer;
58 } 55 }
(...skipping 15 matching lines...) Expand all
74 } 71 }
75 72
76 void RenderMultiColumnSet::setAndConstrainColumnHeight(LayoutUnit newHeight) 73 void RenderMultiColumnSet::setAndConstrainColumnHeight(LayoutUnit newHeight)
77 { 74 {
78 m_computedColumnHeight = newHeight; 75 m_computedColumnHeight = newHeight;
79 if (m_computedColumnHeight > m_maxColumnHeight) 76 if (m_computedColumnHeight > m_maxColumnHeight)
80 m_computedColumnHeight = m_maxColumnHeight; 77 m_computedColumnHeight = m_maxColumnHeight;
81 // FIXME: the height may also be affected by the enclosing pagination contex t, if any. 78 // FIXME: the height may also be affected by the enclosing pagination contex t, if any.
82 } 79 }
83 80
84 bool RenderMultiColumnSet::calculateBalancedHeight(bool initial) 81 unsigned RenderMultiColumnSet::findRunWithTallestColumns() const
85 { 82 {
86 ASSERT(toRenderMultiColumnBlock(parent())->requiresBalancing()); 83 unsigned indexWithLargestHeight = 0;
87 LayoutUnit oldColumnHeight = m_computedColumnHeight; 84 LayoutUnit largestHeight;
88 LayoutUnit currentMinSpaceShortage = m_minSpaceShortage; 85 LayoutUnit previousOffset;
89 m_minSpaceShortage = LayoutUnit::max(); 86 size_t runCount = m_contentRuns.size();
87 ASSERT(runCount);
88 for (size_t i = 0; i < runCount; i++) {
89 const ContentRun& run = m_contentRuns[i];
90 LayoutUnit height = run.columnLogicalHeight(previousOffset);
91 if (largestHeight < height) {
92 largestHeight = height;
93 indexWithLargestHeight = i;
94 }
95 previousOffset = run.breakOffset();
96 }
97 return indexWithLargestHeight;
98 }
90 99
100 void RenderMultiColumnSet::distributeImplicitBreaks()
101 {
102 unsigned breakCount = forcedBreaksCount();
103
104 #ifndef NDEBUG
105 // There should be no implicit breaks assumed at this point.
106 for (unsigned i = 0; i < breakCount; i++)
107 ASSERT(!m_contentRuns[i].assumedImplicitBreaks());
108 #endif // NDEBUG
109
110 // There will always be at least one break, since the flow thread reports a "forced break" at
111 // end of content.
112 ASSERT(breakCount >= 1);
113
114 // If there is room for more breaks (to reach the used value of column-count ), imagine that we
115 // insert implicit breaks at suitable locations. At any given time, the cont ent run with the
116 // currently tallest columns will get another implicit break "inserted", whi ch will increase its
117 // column count by one and shrink its columns' height. Repeat until we have the desired total
118 // number of breaks. The largest column height among the runs will then be t he initial column
119 // height for the balancer to use.
120 while (breakCount < m_computedColumnCount) {
121 unsigned index = findRunWithTallestColumns();
122 m_contentRuns[index].assumeAnotherImplicitBreak();
123 breakCount++;
124 }
125 }
126
127 LayoutUnit RenderMultiColumnSet::calculateBalancedHeight(bool initial) const
128 {
91 if (initial) { 129 if (initial) {
92 // Start with the lowest imaginable column height. 130 // Start with the lowest imaginable column height.
93 LayoutUnit logicalHeightGuess = ceilf(float(flowThread()->logicalHeight( )) / float(m_computedColumnCount)); 131 unsigned index = findRunWithTallestColumns();
94 logicalHeightGuess = max(logicalHeightGuess, m_minimumColumnHeight); 132 LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffse t() : LayoutUnit();
95 setAndConstrainColumnHeight(logicalHeightGuess); 133 return std::max<LayoutUnit>(m_contentRuns[index].columnLogicalHeight(sta rtOffset), m_minimumColumnHeight);
96
97 // The multicol container now typically needs at least one more layout p ass with a new
98 // column height, but if height was specified, we only need to do this i f we found that we
99 // might need less space than that. On the other hand, if we determined that the columns
100 // need to be as tall as the specified height of the container, we have already laid it out
101 // correctly, and there's no need for another pass.
102 return m_computedColumnHeight != oldColumnHeight;
103 } 134 }
104 135
105 if (columnCount() <= computedColumnCount()) { 136 if (columnCount() <= computedColumnCount()) {
106 // With the current column height, the content fits without creating ove rflowing columns. We're done. 137 // With the current column height, the content fits without creating ove rflowing columns. We're done.
107 return false; 138 return m_computedColumnHeight;
139 }
140
141 if (forcedBreaksCount() > 1 && forcedBreaksCount() >= computedColumnCount()) {
142 // Too many forced breaks to allow any implicit breaks. Initial balancin g should already
143 // have set a good height. There's nothing more we should do.
144 return m_computedColumnHeight;
108 } 145 }
109 146
110 // If the initial guessed column height wasn't enough, stretch it now. Stret ch by the lowest 147 // If the initial guessed column height wasn't enough, stretch it now. Stret ch by the lowest
111 // amount of space shortage found during layout. 148 // amount of space shortage found during layout.
112 149
113 ASSERT(currentMinSpaceShortage != LayoutUnit::max()); // If this can actuall y happen, we probably have a bug. 150 ASSERT(m_minSpaceShortage > 0); // We should never _shrink_ the height!
114 if (currentMinSpaceShortage == LayoutUnit::max()) 151 ASSERT(m_minSpaceShortage != LayoutUnit::max()); // If this happens, we prob ably have a bug.
115 return false; // So bail out rather than looping infinitely. 152 if (m_minSpaceShortage == LayoutUnit::max())
153 return m_computedColumnHeight; // So bail out rather than looping infini tely.
116 154
117 setAndConstrainColumnHeight(m_computedColumnHeight + currentMinSpaceShortage ); 155 return m_computedColumnHeight + m_minSpaceShortage;
156 }
118 157
119 // If we reach the maximum column height (typically set by the height or max -height property), 158 void RenderMultiColumnSet::clearForcedBreaks()
120 // we may not be allowed to stretch further. Return true only if stretching 159 {
121 // succeeded. Otherwise, we're done. 160 m_contentRuns.clear();
122 ASSERT(m_computedColumnHeight >= oldColumnHeight); // We shouldn't be able t o shrink the height! 161 }
123 return m_computedColumnHeight > oldColumnHeight; 162
163 void RenderMultiColumnSet::addForcedBreak(LayoutUnit offsetFromFirstPage)
164 {
165 if (!toRenderMultiColumnBlock(parent())->requiresBalancing())
166 return;
167 if (!m_contentRuns.isEmpty() && offsetFromFirstPage <= m_contentRuns.last(). breakOffset())
168 return;
169 // Append another item as long as we haven't exceeded used column count. Wha t ends up in the
170 // overflow area shouldn't affect column balancing.
171 if (m_contentRuns.size() < m_computedColumnCount)
172 m_contentRuns.append(ContentRun(offsetFromFirstPage));
173 }
174
175 bool RenderMultiColumnSet::recalculateBalancedHeight(bool initial)
176 {
177 ASSERT(toRenderMultiColumnBlock(parent())->requiresBalancing());
178
179 LayoutUnit oldColumnHeight = m_computedColumnHeight;
180 if (initial)
181 distributeImplicitBreaks();
182 LayoutUnit newColumnHeight = calculateBalancedHeight(initial);
183 setAndConstrainColumnHeight(newColumnHeight);
184
185 // After having calculated an initial column height, the multicol container typically needs at
186 // least one more layout pass with a new column height, but if a height was specified, we only
187 // need to do this if we think that we need less space than specified. Conve rsely, if we
188 // determined that the columns need to be as tall as the specified height of the container, we
189 // have already laid it out correctly, and there's no need for another pass.
190
191 if (m_computedColumnHeight == oldColumnHeight)
192 return false; // No change. We're done.
193
194 m_minSpaceShortage = LayoutUnit::max();
195 clearForcedBreaks();
196 return true; // Need another pass.
124 } 197 }
125 198
126 void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage) 199 void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage)
127 { 200 {
128 if (spaceShortage >= m_minSpaceShortage) 201 if (spaceShortage >= m_minSpaceShortage)
129 return; 202 return;
130 203
131 // The space shortage is what we use as our stretch amount. We need a positi ve number here in 204 // The space shortage is what we use as our stretch amount. We need a positi ve number here in
132 // order to get anywhere. 205 // order to get anywhere.
133 ASSERT(spaceShortage > 0); 206 ASSERT(spaceShortage > 0);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHe ight(multicolStyle->logicalMaxHeight(), -1); 251 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHe ight(multicolStyle->logicalMaxHeight(), -1);
179 if (m_maxColumnHeight > logicalMaxHeight) 252 if (m_maxColumnHeight > logicalMaxHeight)
180 m_maxColumnHeight = logicalMaxHeight; 253 m_maxColumnHeight = logicalMaxHeight;
181 } 254 }
182 m_maxColumnHeight = heightAdjustedForSetOffset(m_maxColumnHeight); 255 m_maxColumnHeight = heightAdjustedForSetOffset(m_maxColumnHeight);
183 m_computedColumnHeight = 0; // Restart balancing. 256 m_computedColumnHeight = 0; // Restart balancing.
184 } else { 257 } else {
185 setAndConstrainColumnHeight(heightAdjustedForSetOffset(multicolBlock->co lumnHeightAvailable())); 258 setAndConstrainColumnHeight(heightAdjustedForSetOffset(multicolBlock->co lumnHeightAvailable()));
186 } 259 }
187 260
261 clearForcedBreaks();
262
188 // Nuke previously stored minimum column height. Contents may have changed f or all we know. 263 // Nuke previously stored minimum column height. Contents may have changed f or all we know.
189 m_minimumColumnHeight = 0; 264 m_minimumColumnHeight = 0;
190 } 265 }
191 266
192 void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTo p, LogicalExtentComputedValues& computedValues) const 267 void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTo p, LogicalExtentComputedValues& computedValues) const
193 { 268 {
194 computedValues.m_extent = m_computedColumnHeight; 269 computedValues.m_extent = m_computedColumnHeight;
195 computedValues.m_position = logicalTop; 270 computedValues.m_position = logicalTop;
196 } 271 }
197 272
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 fragments.append(fragment); 581 fragments.append(fragment);
507 } 582 }
508 } 583 }
509 584
510 const char* RenderMultiColumnSet::renderName() const 585 const char* RenderMultiColumnSet::renderName() const
511 { 586 {
512 return "RenderMultiColumnSet"; 587 return "RenderMultiColumnSet";
513 } 588 }
514 589
515 } 590 }
OLDNEW
« no previous file with comments | « Source/core/rendering/RenderMultiColumnSet.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698