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

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

Issue 143323014: *** DO NOT LAND *** Attempt to understand Regions complexity Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 11 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2012 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "core/rendering/RenderMultiColumnSet.h"
28
29 #include "core/rendering/PaintInfo.h"
30 #include "core/rendering/RenderLayer.h"
31 #include "core/rendering/RenderMultiColumnBlock.h"
32 #include "core/rendering/RenderMultiColumnFlowThread.h"
33
34 using namespace std;
35
36 namespace WebCore {
37
38 RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread* flowThread)
39 : RenderRegionSet(0, flowThread)
40 , m_computedColumnCount(1)
41 , m_computedColumnWidth(0)
42 , m_computedColumnHeight(0)
43 , m_maxColumnHeight(LayoutUnit::max())
44 , m_minSpaceShortage(LayoutUnit::max())
45 , m_minimumColumnHeight(0)
46 , m_forcedBreaksCount(0)
47 , m_maximumDistanceBetweenForcedBreaks(0)
48 , m_forcedBreakOffset(0)
49 {
50 }
51
52 RenderMultiColumnSet* RenderMultiColumnSet::createAnonymous(RenderFlowThread* fl owThread)
53 {
54 Document& document = flowThread->document();
55 RenderMultiColumnSet* renderer = new RenderMultiColumnSet(flowThread);
56 renderer->setDocumentForAnonymous(&document);
57 return renderer;
58 }
59
60 LayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) c onst
61 {
62 RenderMultiColumnBlock* multicolBlock = toRenderMultiColumnBlock(parent());
63 LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderBefore() - multicolBlock->paddingBefore();
64
65 height -= contentLogicalTop;
66 return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created.
67 }
68
69 LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) cons t
70 {
71 LayoutUnit portionLogicalTop = (isHorizontalWritingMode() ? flowThreadPortio nRect().y() : flowThreadPortionRect().x());
72 unsigned columnIndex = columnIndexAtOffset(offset, AssumeNewColumns);
73 return portionLogicalTop + columnIndex * computedColumnHeight();
74 }
75
76 void RenderMultiColumnSet::setAndConstrainColumnHeight(LayoutUnit newHeight)
77 {
78 m_computedColumnHeight = newHeight;
79 if (m_computedColumnHeight > m_maxColumnHeight)
80 m_computedColumnHeight = m_maxColumnHeight;
81 // FIXME: the height may also be affected by the enclosing pagination contex t, if any.
82 }
83
84 bool RenderMultiColumnSet::calculateBalancedHeight(bool initial)
85 {
86 ASSERT(toRenderMultiColumnBlock(parent())->requiresBalancing());
87 LayoutUnit oldColumnHeight = m_computedColumnHeight;
88 LayoutUnit currentMinSpaceShortage = m_minSpaceShortage;
89 m_minSpaceShortage = LayoutUnit::max();
90
91 if (initial) {
92 // Start with the lowest imaginable column height.
93 LayoutUnit logicalHeightGuess = ceilf(float(flowThread()->logicalHeight( )) / float(m_computedColumnCount));
94 logicalHeightGuess = max(logicalHeightGuess, m_minimumColumnHeight);
95 setAndConstrainColumnHeight(logicalHeightGuess);
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 }
104
105 if (columnCount() <= computedColumnCount()) {
106 // With the current column height, the content fits without creating ove rflowing columns. We're done.
107 return false;
108 }
109
110 // 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.
112
113 ASSERT(currentMinSpaceShortage != LayoutUnit::max()); // If this can actuall y happen, we probably have a bug.
114 if (currentMinSpaceShortage == LayoutUnit::max())
115 return false; // So bail out rather than looping infinitely.
116
117 setAndConstrainColumnHeight(m_computedColumnHeight + currentMinSpaceShortage );
118
119 // If we reach the maximum column height (typically set by the height or max -height property),
120 // we may not be allowed to stretch further. Return true only if stretching
121 // succeeded. Otherwise, we're done.
122 ASSERT(m_computedColumnHeight >= oldColumnHeight); // We shouldn't be able t o shrink the height!
123 return m_computedColumnHeight > oldColumnHeight;
124 }
125
126 void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage)
127 {
128 if (spaceShortage >= m_minSpaceShortage)
129 return;
130
131 // The space shortage is what we use as our stretch amount. We need a positi ve number here in
132 // order to get anywhere.
133 ASSERT(spaceShortage > 0);
134
135 m_minSpaceShortage = spaceShortage;
136 }
137
138 void RenderMultiColumnSet::updateLogicalWidth()
139 {
140 RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent());
141 setComputedColumnWidthAndCount(parentBlock->columnWidth(), parentBlock->colu mnCount()); // FIXME: This will eventually vary if we are contained inside regio ns.
142
143 // FIXME: When we add regions support, we'll start it off at the width of th e multi-column
144 // block in that particular region.
145 setLogicalWidth(parentBox()->contentLogicalWidth());
146
147 // If we overflow, increase our logical width.
148 unsigned colCount = columnCount();
149 LayoutUnit colGap = columnGap();
150 LayoutUnit minimumContentLogicalWidth = colCount * computedColumnWidth() + ( colCount - 1) * colGap;
151 LayoutUnit currentContentLogicalWidth = contentLogicalWidth();
152 LayoutUnit delta = max(LayoutUnit(), minimumContentLogicalWidth - currentCon tentLogicalWidth);
153 if (!delta)
154 return;
155
156 // Increase our logical width by the delta.
157 setLogicalWidth(logicalWidth() + delta);
158 }
159
160 void RenderMultiColumnSet::prepareForLayout()
161 {
162 RenderMultiColumnBlock* multicolBlock = toRenderMultiColumnBlock(parent());
163 RenderStyle* multicolStyle = multicolBlock->style();
164
165 // Set box logical top.
166 ASSERT(!previousSiblingBox() || !previousSiblingBox()->isRenderMultiColumnSe t()); // FIXME: multiple set not implemented; need to examine previous set to ca lculate the correct logical top.
167 setLogicalTop(multicolBlock->borderBefore() + multicolBlock->paddingBefore() );
168
169 // Set box width.
170 updateLogicalWidth();
171
172 if (multicolBlock->requiresBalancing()) {
173 // Set maximum column height. We will not stretch beyond this.
174 m_maxColumnHeight = LayoutUnit::max();
175 if (!multicolStyle->logicalHeight().isAuto())
176 m_maxColumnHeight = multicolBlock->computeContentLogicalHeight(multi colStyle->logicalHeight(), -1);
177 if (!multicolStyle->logicalMaxHeight().isUndefined()) {
178 LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHe ight(multicolStyle->logicalMaxHeight(), -1);
179 if (m_maxColumnHeight > logicalMaxHeight)
180 m_maxColumnHeight = logicalMaxHeight;
181 }
182 m_maxColumnHeight = heightAdjustedForSetOffset(m_maxColumnHeight);
183 m_computedColumnHeight = 0; // Restart balancing.
184 } else {
185 setAndConstrainColumnHeight(heightAdjustedForSetOffset(multicolBlock->co lumnHeightAvailable()));
186 }
187
188 // Nuke previously stored minimum column height. Contents may have changed f or all we know.
189 m_minimumColumnHeight = 0;
190 }
191
192 void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTo p, LogicalExtentComputedValues& computedValues) const
193 {
194 computedValues.m_extent = m_computedColumnHeight;
195 computedValues.m_position = logicalTop;
196 }
197
198 LayoutUnit RenderMultiColumnSet::columnGap() const
199 {
200 // FIXME: Eventually we will cache the column gap when the widths of columns start varying, but for now we just
201 // go to the parent block to get the gap.
202 RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent());
203 if (parentBlock->style()->hasNormalColumnGap())
204 return parentBlock->style()->fontDescription().computedPixelSize(); // " 1em" is recommended as the normal gap setting. Matches <p> margins.
205 return parentBlock->style()->columnGap();
206 }
207
208 unsigned RenderMultiColumnSet::columnCount() const
209 {
210 // We must always return a value of 1 or greater. Column count = 0 is a mean ingless situation,
211 // and will confuse and cause problems in other parts of the code.
212 if (!computedColumnHeight())
213 return 1;
214
215 // Our portion rect determines our column count. We have as many columns as needed to fit all the content.
216 LayoutUnit logicalHeightInColumns = flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().height() : flowThreadPortionRect().width();
217 unsigned count = ceil(static_cast<float>(logicalHeightInColumns) / computedC olumnHeight());
218 ASSERT(count >= 1);
219 return count;
220 }
221
222 LayoutRect RenderMultiColumnSet::columnRectAt(unsigned index) const
223 {
224 LayoutUnit colLogicalWidth = computedColumnWidth();
225 LayoutUnit colLogicalHeight = computedColumnHeight();
226 LayoutUnit colLogicalTop = borderBefore() + paddingBefore();
227 LayoutUnit colLogicalLeft = borderAndPaddingLogicalLeft();
228 LayoutUnit colGap = columnGap();
229 if (style()->isLeftToRightDirection())
230 colLogicalLeft += index * (colLogicalWidth + colGap);
231 else
232 colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * (col LogicalWidth + colGap);
233
234 if (isHorizontalWritingMode())
235 return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLog icalHeight);
236 return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogica lWidth);
237 }
238
239 unsigned RenderMultiColumnSet::columnIndexAtOffset(LayoutUnit offset, ColumnInde xCalculationMode mode) const
240 {
241 LayoutRect portionRect(flowThreadPortionRect());
242
243 // Handle the offset being out of range.
244 LayoutUnit flowThreadLogicalTop = isHorizontalWritingMode() ? portionRect.y( ) : portionRect.x();
245 if (offset < flowThreadLogicalTop)
246 return 0;
247 // If we're laying out right now, we cannot constrain against some logical b ottom, since it
248 // isn't known yet. Otherwise, just return the last column if we're past the logical bottom.
249 if (mode == ClampToExistingColumns) {
250 LayoutUnit flowThreadLogicalBottom = isHorizontalWritingMode() ? portion Rect.maxY() : portionRect.maxX();
251 if (offset >= flowThreadLogicalBottom)
252 return columnCount() - 1;
253 }
254
255 // Just divide by the column height to determine the correct column.
256 return static_cast<float>(offset - flowThreadLogicalTop) / computedColumnHei ght();
257 }
258
259 LayoutRect RenderMultiColumnSet::flowThreadPortionRectAt(unsigned index) const
260 {
261 LayoutRect portionRect = flowThreadPortionRect();
262 if (isHorizontalWritingMode())
263 portionRect = LayoutRect(portionRect.x(), portionRect.y() + index * comp utedColumnHeight(), portionRect.width(), computedColumnHeight());
264 else
265 portionRect = LayoutRect(portionRect.x() + index * computedColumnHeight( ), portionRect.y(), computedColumnHeight(), portionRect.height());
266 return portionRect;
267 }
268
269 LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect& portionRect, unsigned index, unsigned colCount, LayoutUnit colGap) const
270 {
271 // This function determines the portion of the flow thread that paints for t he column. Along the inline axis, columns are
272 // unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column
273 // gap along interior edges.
274 //
275 // In the block direction, we will not clip overflow out of the top of the f irst column, or out of the bottom of
276 // the last column. This applies only to the true first column and last colu mn across all column sets.
277 //
278 // FIXME: Eventually we will know overflow on a per-column basis, but we can 't do this until we have a painting
279 // mode that understands not to paint contents from a previous column in the overflow area of a following column.
280 // This problem applies to regions and pages as well and is not unique to co lumns.
281 bool isFirstColumn = !index;
282 bool isLastColumn = index == colCount - 1;
283 bool isLeftmostColumn = style()->isLeftToRightDirection() ? isFirstColumn : isLastColumn;
284 bool isRightmostColumn = style()->isLeftToRightDirection() ? isLastColumn : isFirstColumn;
285
286 // Calculate the overflow rectangle, based on the flow thread's, clipped at column logical
287 // top/bottom unless it's the first/last column.
288 LayoutRect overflowRect = overflowRectForFlowThreadPortion(portionRect, isFi rstColumn && isFirstRegion(), isLastColumn && isLastRegion());
289
290 // Avoid overflowing into neighboring columns, by clipping in the middle of adjacent column
291 // gaps. Also make sure that we avoid rounding errors.
292 if (isHorizontalWritingMode()) {
293 if (!isLeftmostColumn)
294 overflowRect.shiftXEdgeTo(portionRect.x() - colGap / 2);
295 if (!isRightmostColumn)
296 overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + colGap - colGap / 2);
297 } else {
298 if (!isLeftmostColumn)
299 overflowRect.shiftYEdgeTo(portionRect.y() - colGap / 2);
300 if (!isRightmostColumn)
301 overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + colGap - colGap / 2);
302 }
303 return overflowRect;
304 }
305
306 void RenderMultiColumnSet::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
307 {
308 if (style()->visibility() != VISIBLE)
309 return;
310
311 RenderBlock::paintObject(paintInfo, paintOffset);
312
313 // FIXME: Right now we're only painting in the foreground phase.
314 // Columns should technically respect phases and allow for background/float/ foreground overlap etc., just like
315 // RenderBlocks do. Note this is a pretty minor issue, since the old column implementation clipped columns
316 // anyway, thus making it impossible for them to overlap one another. It's a lso really unlikely that the columns
317 // would overlap another block.
318 if (!m_flowThread || !isValid() || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
319 return;
320
321 paintColumnRules(paintInfo, paintOffset);
322 }
323
324 void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPo int& paintOffset)
325 {
326 if (paintInfo.context->paintingDisabled())
327 return;
328
329 RenderStyle* blockStyle = toRenderMultiColumnBlock(parent())->style();
330 const Color& ruleColor = resolveColor(blockStyle, CSSPropertyWebkitColumnRul eColor);
331 bool ruleTransparent = blockStyle->columnRuleIsTransparent();
332 EBorderStyle ruleStyle = blockStyle->columnRuleStyle();
333 LayoutUnit ruleThickness = blockStyle->columnRuleWidth();
334 LayoutUnit colGap = columnGap();
335 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
336 if (!renderRule)
337 return;
338
339 unsigned colCount = columnCount();
340 if (colCount <= 1)
341 return;
342
343 bool antialias = shouldAntialiasLines(paintInfo.context);
344
345 bool leftToRight = style()->isLeftToRightDirection();
346 LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogic alWidth();
347 LayoutUnit ruleAdd = borderAndPaddingLogicalLeft();
348 LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidt h();
349 LayoutUnit inlineDirectionSize = computedColumnWidth();
350 BoxSide boxSide = isHorizontalWritingMode()
351 ? leftToRight ? BSLeft : BSRight
352 : leftToRight ? BSTop : BSBottom;
353
354 for (unsigned i = 0; i < colCount; i++) {
355 // Move to the next position.
356 if (leftToRight) {
357 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
358 currLogicalLeftOffset += inlineDirectionSize + colGap;
359 } else {
360 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
361 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
362 }
363
364 // Now paint the column rule.
365 if (i < colCount - 1) {
366 LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft();
367 LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleTh ickness : ruleLeft + contentWidth();
368 LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + b orderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
369 LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + conten tHeight() : ruleTop + ruleThickness;
370 IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft , ruleTop, ruleRight, ruleBottom);
371 drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixe lSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
372 }
373
374 ruleLogicalLeft = currLogicalLeftOffset;
375 }
376 }
377
378 void RenderMultiColumnSet::repaintFlowThreadContent(const LayoutRect& repaintRec t) const
379 {
380 // Figure out the start and end columns and only check within that range so that we don't walk the
381 // entire column set. Put the repaint rect into flow thread coordinates by f lipping it first.
382 LayoutRect flowThreadRepaintRect(repaintRect);
383 flowThread()->flipForWritingMode(flowThreadRepaintRect);
384
385 // Now we can compare this rect with the flow thread portions owned by each column. First let's
386 // just see if the repaint rect intersects our flow thread portion at all.
387 LayoutRect clippedRect(flowThreadRepaintRect);
388 clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect());
389 if (clippedRect.isEmpty())
390 return;
391
392 // Now we know we intersect at least one column. Let's figure out the logica l top and logical
393 // bottom of the area we're repainting.
394 LayoutUnit repaintLogicalTop = isHorizontalWritingMode() ? flowThreadRepaint Rect.y() : flowThreadRepaintRect.x();
395 LayoutUnit repaintLogicalBottom = (isHorizontalWritingMode() ? flowThreadRep aintRect.maxY() : flowThreadRepaintRect.maxX()) - 1;
396
397 unsigned startColumn = columnIndexAtOffset(repaintLogicalTop);
398 unsigned endColumn = columnIndexAtOffset(repaintLogicalBottom);
399
400 LayoutUnit colGap = columnGap();
401 unsigned colCount = columnCount();
402 for (unsigned i = startColumn; i <= endColumn; i++) {
403 LayoutRect colRect = columnRectAt(i);
404
405 // Get the portion of the flow thread that corresponds to this column.
406 LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);
407
408 // Now get the overflow rect that corresponds to the column.
409 LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flo wThreadPortion, i, colCount, colGap);
410
411 // Do a repaint for this specific column.
412 repaintFlowThreadContentRectangle(repaintRect, flowThreadPortion, flowTh readOverflowPortion, colRect.location());
413 }
414 }
415
416 void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, cons t LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect)
417 {
418 // The two rectangles passed to this method are physical, except that we pre tend that there's
419 // only one long column (that's how a flow thread works).
420 //
421 // Then there's the output from this method - the stuff we put into the list of fragments. The
422 // fragment.paginationOffset point is the actual physical translation requir ed to get from a
423 // location in the flow thread to a location in a given column. The fragment .paginationClip
424 // rectangle, on the other hand, is in the same coordinate system as the two rectangles passed
425 // to this method (flow thread coordinates).
426 //
427 // All other rectangles in this method are sized physically, and the inline direction coordinate
428 // is physical too, but the block direction coordinate is "logical top". Thi s is the same as
429 // e.g. RenderBox::frameRect(). These rectangles also pretend that there's o nly one long column,
430 // i.e. they are for the flow thread.
431
432 // Put the layer bounds into flow thread-local coordinates by flipping it fi rst. Since we're in
433 // a renderer, most rectangles are represented this way.
434 LayoutRect layerBoundsInFlowThread(layerBoundingBox);
435 flowThread()->flipForWritingMode(layerBoundsInFlowThread);
436
437 // Now we can compare with the flow thread portions owned by each column. Fi rst let's
438 // see if the rect intersects our flow thread portion at all.
439 LayoutRect clippedRect(layerBoundsInFlowThread);
440 clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect());
441 if (clippedRect.isEmpty())
442 return;
443
444 // Now we know we intersect at least one column. Let's figure out the logica l top and logical
445 // bottom of the area we're checking.
446 LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowTh read.y() : layerBoundsInFlowThread.x();
447 LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFl owThread.maxY() : layerBoundsInFlowThread.maxX()) - 1;
448
449 // Figure out the start and end columns and only check within that range so that we don't walk the
450 // entire column set.
451 unsigned startColumn = columnIndexAtOffset(layerLogicalTop);
452 unsigned endColumn = columnIndexAtOffset(layerLogicalBottom);
453
454 LayoutUnit colLogicalWidth = computedColumnWidth();
455 LayoutUnit colGap = columnGap();
456 unsigned colCount = columnCount();
457
458 for (unsigned i = startColumn; i <= endColumn; i++) {
459 // Get the portion of the flow thread that corresponds to this column.
460 LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);
461
462 // Now get the overflow rect that corresponds to the column.
463 LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flo wThreadPortion, i, colCount, colGap);
464
465 // In order to create a fragment we must intersect the portion painted b y this column.
466 LayoutRect clippedRect(layerBoundsInFlowThread);
467 clippedRect.intersect(flowThreadOverflowPortion);
468 if (clippedRect.isEmpty())
469 continue;
470
471 // We also need to intersect the dirty rect. We have to apply a translat ion and shift based off
472 // our column index.
473 LayoutPoint translationOffset;
474 LayoutUnit inlineOffset = i * (colLogicalWidth + colGap);
475 if (!style()->isLeftToRightDirection())
476 inlineOffset = -inlineOffset;
477 translationOffset.setX(inlineOffset);
478 LayoutUnit blockOffset = isHorizontalWritingMode() ? -flowThreadPortion. y() : -flowThreadPortion.x();
479 if (isFlippedBlocksWritingMode(style()->writingMode()))
480 blockOffset = -blockOffset;
481 translationOffset.setY(blockOffset);
482 if (!isHorizontalWritingMode())
483 translationOffset = translationOffset.transposedPoint();
484 // FIXME: The translation needs to include the multicolumn set's content offset within the
485 // multicolumn block as well. This won't be an issue until we start crea ting multiple multicolumn sets.
486
487 // Shift the dirty rect to be in flow thread coordinates with this trans lation applied.
488 LayoutRect translatedDirtyRect(dirtyRect);
489 translatedDirtyRect.moveBy(-translationOffset);
490
491 // See if we intersect the dirty rect.
492 clippedRect = layerBoundingBox;
493 clippedRect.intersect(translatedDirtyRect);
494 if (clippedRect.isEmpty())
495 continue;
496
497 // Something does need to paint in this column. Make a fragment now and supply the physical translation
498 // offset and the clip rect for the column with that offset applied.
499 LayerFragment fragment;
500 fragment.paginationOffset = translationOffset;
501
502 LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion);
503 // Flip it into more a physical (RenderLayer-style) rectangle.
504 flowThread()->flipForWritingMode(flippedFlowThreadOverflowPortion);
505 fragment.paginationClip = flippedFlowThreadOverflowPortion;
506 fragments.append(fragment);
507 }
508 }
509
510 const char* RenderMultiColumnSet::renderName() const
511 {
512 return "RenderMultiColumnSet";
513 }
514
515 }
OLDNEW
« no previous file with comments | « Source/core/rendering/RenderMultiColumnSet.h ('k') | Source/core/rendering/RenderNamedFlowFragment.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698