static inline FloatPoint physicalPointToLogical(const FloatPoint& point, float logicalBoxHeight, WritingMode writingMode) { if (isHorizontalWritingMode(writingMode)) return point; if (isFlippedBlocksWritingMode(writingMode)) return FloatPoint(point.y(), logicalBoxHeight - point.x()); return point.transposedPoint(); }
static inline FloatRect physicalRectToLogical(const FloatRect& rect, float logicalBoxHeight, WritingMode writingMode) { if (isHorizontalWritingMode(writingMode)) return rect; if (isFlippedBlocksWritingMode(writingMode)) return FloatRect(rect.y(), logicalBoxHeight - rect.maxX(), rect.height(), rect.width()); return rect.transposedRect(); }
void RenderMultiColumnSet::adjustRegionBoundsFromFlowThreadPortionRect(const LayoutPoint& layerOffset, LayoutRect& regionBounds) { LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerOffset.y() : layerOffset.x(); unsigned startColumn = columnIndexAtOffset(layerLogicalTop); LayoutUnit colGap = columnGap(); LayoutUnit colLogicalWidth = computedColumnWidth(); LayoutRect flowThreadPortion = flowThreadPortionRectAt(startColumn); LayoutPoint translationOffset; RenderBlockFlow* parentFlow = toRenderBlockFlow(parent()); bool progressionReversed = parentFlow->multiColumnFlowThread()->progressionIsReversed(); bool progressionIsInline = parentFlow->multiColumnFlowThread()->progressionIsInline(); LayoutUnit initialBlockOffset = initialBlockOffsetForPainting(); LayoutUnit inlineOffset = progressionIsInline ? startColumn * (colLogicalWidth + colGap) : LayoutUnit(); bool leftToRight = style().isLeftToRightDirection() ^ progressionReversed; if (!leftToRight) { inlineOffset = -inlineOffset; if (progressionReversed) inlineOffset += contentLogicalWidth() - colLogicalWidth; } translationOffset.setX(inlineOffset); LayoutUnit blockOffset = initialBlockOffset + (isHorizontalWritingMode() ? -flowThreadPortion.y() : -flowThreadPortion.x()); if (!progressionIsInline) { if (!progressionReversed) blockOffset = startColumn * colGap; else blockOffset -= startColumn * (computedColumnHeight() + colGap); } if (isFlippedBlocksWritingMode(style().writingMode())) blockOffset = -blockOffset; translationOffset.setY(blockOffset); if (!isHorizontalWritingMode()) translationOffset = translationOffset.transposedPoint(); // FIXME: The translation needs to include the multicolumn set's content offset within the // multicolumn block as well. This won't be an issue until we start creating multiple multicolumn sets. regionBounds.moveBy(roundedIntPoint(-translationOffset)); }
void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) { // The two rectangles passed to this method are physical, except that we pretend that there's // only one long column (that's how a flow thread works). // // Then there's the output from this method - the stuff we put into the list of fragments. The // fragment.paginationOffset point is the actual physical translation required to get from a // location in the flow thread to a location in a given column. The fragment.paginationClip // rectangle, on the other hand, is in the same coordinate system as the two rectangles passed // to this method (flow thread coordinates). // // All other rectangles in this method are sized physically, and the inline direction coordinate // is physical too, but the block direction coordinate is "logical top". This is the same as // e.g. RenderBox::frameRect(). These rectangles also pretend that there's only one long column, // i.e. they are for the flow thread. // Put the layer bounds into flow thread-local coordinates by flipping it first. Since we're in // a renderer, most rectangles are represented this way. LayoutRect layerBoundsInFlowThread(layerBoundingBox); flowThread()->flipForWritingMode(layerBoundsInFlowThread); // Now we can compare with the flow thread portions owned by each column. First let's // see if the rect intersects our flow thread portion at all. LayoutRect clippedRect(layerBoundsInFlowThread); clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect()); if (clippedRect.isEmpty()) return; // Now we know we intersect at least one column. Let's figure out the logical top and logical // bottom of the area we're checking. LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowThread.y() : layerBoundsInFlowThread.x(); LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFlowThread.maxY() : layerBoundsInFlowThread.maxX()) - 1; // Figure out the start and end columns and only check within that range so that we don't walk the // entire column set. unsigned startColumn = columnIndexAtOffset(layerLogicalTop); unsigned endColumn = columnIndexAtOffset(layerLogicalBottom); LayoutUnit colLogicalWidth = computedColumnWidth(); LayoutUnit colGap = columnGap(); unsigned colCount = columnCount(); for (unsigned i = startColumn; i <= endColumn; i++) { // Get the portion of the flow thread that corresponds to this column. LayoutRect flowThreadPortion = flowThreadPortionRectAt(i); // Now get the overflow rect that corresponds to the column. LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap); // In order to create a fragment we must intersect the portion painted by this column. LayoutRect clippedRect(layerBoundsInFlowThread); clippedRect.intersect(flowThreadOverflowPortion); if (clippedRect.isEmpty()) continue; // We also need to intersect the dirty rect. We have to apply a translation and shift based off // our column index. LayoutPoint translationOffset; LayoutUnit inlineOffset = i * (colLogicalWidth + colGap); if (!style()->isLeftToRightDirection()) inlineOffset = -inlineOffset; translationOffset.setX(inlineOffset); LayoutUnit blockOffset = isHorizontalWritingMode() ? -flowThreadPortion.y() : -flowThreadPortion.x(); if (isFlippedBlocksWritingMode(style()->writingMode())) blockOffset = -blockOffset; translationOffset.setY(blockOffset); if (!isHorizontalWritingMode()) translationOffset = translationOffset.transposedPoint(); // FIXME: The translation needs to include the multicolumn set's content offset within the // multicolumn block as well. This won't be an issue until we start creating multiple multicolumn sets. // Shift the dirty rect to be in flow thread coordinates with this translation applied. LayoutRect translatedDirtyRect(dirtyRect); translatedDirtyRect.moveBy(-translationOffset); // See if we intersect the dirty rect. clippedRect = layerBoundingBox; clippedRect.intersect(translatedDirtyRect); if (clippedRect.isEmpty()) continue; // Something does need to paint in this column. Make a fragment now and supply the physical translation // offset and the clip rect for the column with that offset applied. LayerFragment fragment; fragment.paginationOffset = translationOffset; LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion); // Flip it into more a physical (RenderLayer-style) rectangle. flowThread()->flipForWritingMode(flippedFlowThreadOverflowPortion); fragment.paginationClip = flippedFlowThreadOverflowPortion; fragments.append(fragment); } }
void MultiColumnFragmentainerGroup::collectLayerFragments(DeprecatedPaintLayerFragments& fragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) const { // |layerBoundingBox| is in the flow thread coordinate space, relative to the top/left edge of // the flow thread, but note that it has been converted with respect to writing mode (so that // it's visual/physical in that sense). // // |dirtyRect| is visual, relative to the multicol container. // // Then there's the output from this method - the stuff we put into the list of fragments. The // fragment.paginationOffset point is the actual visual translation required to get from a // location in the flow thread to a location in a given column. The fragment.paginationClip // rectangle, on the other hand, is in flow thread coordinates, but otherwise completely // physical in terms of writing mode. // // All other rectangles in this method are sized physically, and the inline direction coordinate // is physical too, but the block direction coordinate is "logical top". This is the same as // e.g. LayoutBox::frameRect(). These rectangles also pretend that there's only one long column, // i.e. they are for the flow thread. LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread(); bool isHorizontalWritingMode = m_columnSet.isHorizontalWritingMode(); // Put the layer bounds into flow thread-local coordinates by flipping it first. Since we're in // a layoutObject, most rectangles are represented this way. LayoutRect layerBoundsInFlowThread(layerBoundingBox); flowThread->flipForWritingMode(layerBoundsInFlowThread); // Now we can compare with the flow thread portions owned by each column. First let's // see if the rect intersects our flow thread portion at all. LayoutRect clippedRect(layerBoundsInFlowThread); clippedRect.intersect(m_columnSet.flowThreadPortionOverflowRect()); if (clippedRect.isEmpty()) return; // Now we know we intersect at least one column. Let's figure out the logical top and logical // bottom of the area we're checking. LayoutUnit layerLogicalTop = isHorizontalWritingMode ? layerBoundsInFlowThread.y() : layerBoundsInFlowThread.x(); LayoutUnit layerLogicalBottom = (isHorizontalWritingMode ? layerBoundsInFlowThread.maxY() : layerBoundsInFlowThread.maxX()) - 1; // Figure out the start and end columns and only check within that range so that we don't walk the // entire column row. unsigned startColumn = columnIndexAtOffset(layerLogicalTop); unsigned endColumn = columnIndexAtOffset(layerLogicalBottom); LayoutUnit colLogicalWidth = m_columnSet.pageLogicalWidth(); LayoutUnit colGap = m_columnSet.columnGap(); unsigned colCount = actualColumnCount(); bool progressionIsInline = flowThread->progressionIsInline(); bool leftToRight = m_columnSet.style()->isLeftToRightDirection(); LayoutUnit initialBlockOffset = m_columnSet.logicalTop() + logicalTop() - flowThread->logicalTop(); for (unsigned i = startColumn; i <= endColumn; i++) { // Get the portion of the flow thread that corresponds to this column. LayoutRect flowThreadPortion = flowThreadPortionRectAt(i); // Now get the overflow rect that corresponds to the column. LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap); // In order to create a fragment we must intersect the portion painted by this column. LayoutRect clippedRect(layerBoundsInFlowThread); clippedRect.intersect(flowThreadOverflowPortion); if (clippedRect.isEmpty()) continue; // We also need to intersect the dirty rect. We have to apply a translation and shift based off // our column index. LayoutPoint translationOffset; LayoutUnit inlineOffset = progressionIsInline ? i * (colLogicalWidth + colGap) : LayoutUnit(); if (!leftToRight) inlineOffset = -inlineOffset; translationOffset.setX(inlineOffset); LayoutUnit blockOffset; if (progressionIsInline) { blockOffset = initialBlockOffset + (isHorizontalWritingMode ? -flowThreadPortion.y() : -flowThreadPortion.x()); } else { // Column gap can apply in the block direction for page fragmentainers. // There is currently no spec which calls for column-gap to apply // for page fragmentainers at all, but it's applied here for compatibility // with the old multicolumn implementation. blockOffset = i * colGap; } if (isFlippedBlocksWritingMode(m_columnSet.style()->writingMode())) blockOffset = -blockOffset; translationOffset.setY(blockOffset); if (!isHorizontalWritingMode) translationOffset = translationOffset.transposedPoint(); // Shift the dirty rect to be in flow thread coordinates with this translation applied. LayoutRect translatedDirtyRect(dirtyRect); translatedDirtyRect.moveBy(-translationOffset); // See if we intersect the dirty rect. clippedRect = layerBoundingBox; clippedRect.intersect(translatedDirtyRect); if (clippedRect.isEmpty()) continue; // Something does need to paint in this column. Make a fragment now and supply the physical translation // offset and the clip rect for the column with that offset applied. DeprecatedPaintLayerFragment fragment; fragment.paginationOffset = translationOffset; LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion); // Flip it into more a physical (DeprecatedPaintLayer-style) rectangle. flowThread->flipForWritingMode(flippedFlowThreadOverflowPortion); fragment.paginationClip = flippedFlowThreadOverflowPortion; fragments.append(fragment); } }
void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) { // Let's start by introducing the different coordinate systems involved here. They are different // in how they deal with writing modes and columns. RenderLayer rectangles tend to be more // physical than the rectangles used in RenderObject & co. // // The two rectangles passed to this method are physical, except that we pretend that there's // only one long column (that's the flow thread). They are relative to the top left corner of // the flow thread. All rectangles being compared to the dirty rect also need to be in this // coordinate system. // // Then there's the output from this method - the stuff we put into the list of fragments. The // translationOffset point is the actual physical translation required to get from a location in // the flow thread to a location in some column. The paginationClip rectangle is in the same // coordinate system as the two rectangles passed to this method (i.e. physical, in flow thread // coordinates, pretending that there's only one long column). // // All other rectangles in this method are slightly less physical, when it comes to how they are // used with different writing modes, but they aren't really logical either. They are just like // RenderBox::frameRect(). More precisely, the sizes are physical, and the inline direction // coordinate is too, but the block direction coordinate is always "logical top". These // rectangles also pretend that there's only one long column, i.e. they are for the flow thread. // // To sum up: input and output from this method are "physical" RenderLayer-style rectangles and // points, while inside this method we mostly use the RenderObject-style rectangles (with the // block direction coordinate always being logical top). // Put the layer bounds into flow thread-local coordinates by flipping it first. Since we're in // a renderer, most rectangles are represented this way. LayoutRect layerBoundsInFlowThread(layerBoundingBox); flowThread()->flipForWritingMode(layerBoundsInFlowThread); // Now we can compare with the flow thread portions owned by each column. First let's // see if the rect intersects our flow thread portion at all. LayoutRect clippedRect(layerBoundsInFlowThread); clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect()); if (clippedRect.isEmpty()) return; // Now we know we intersect at least one column. Let's figure out the logical top and logical // bottom of the area we're checking. LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowThread.y() : layerBoundsInFlowThread.x(); LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFlowThread.maxY() : layerBoundsInFlowThread.maxX()) - 1; // Figure out the start and end columns and only check within that range so that we don't walk the // entire column set. unsigned startColumn = columnIndexAtOffset(layerLogicalTop); unsigned endColumn = columnIndexAtOffset(layerLogicalBottom); LayoutUnit colLogicalWidth = computedColumnWidth(); LayoutUnit colGap = columnGap(); unsigned colCount = columnCount(); RenderBlockFlow* parentFlow = toRenderBlockFlow(parent()); bool progressionReversed = parentFlow->multiColumnFlowThread()->progressionIsReversed(); bool progressionIsInline = parentFlow->multiColumnFlowThread()->progressionIsInline(); LayoutUnit initialBlockOffset = initialBlockOffsetForPainting(); for (unsigned i = startColumn; i <= endColumn; i++) { // Get the portion of the flow thread that corresponds to this column. LayoutRect flowThreadPortion = flowThreadPortionRectAt(i); // Now get the overflow rect that corresponds to the column. LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap); // In order to create a fragment we must intersect the portion painted by this column. LayoutRect clippedRect(layerBoundsInFlowThread); clippedRect.intersect(flowThreadOverflowPortion); if (clippedRect.isEmpty()) continue; // We also need to intersect the dirty rect. We have to apply a translation and shift based off // our column index. LayoutPoint translationOffset; LayoutUnit inlineOffset = progressionIsInline ? i * (colLogicalWidth + colGap) : LayoutUnit(); bool leftToRight = style().isLeftToRightDirection() ^ progressionReversed; if (!leftToRight) { inlineOffset = -inlineOffset; if (progressionReversed) inlineOffset += contentLogicalWidth() - colLogicalWidth; } translationOffset.setX(inlineOffset); LayoutUnit blockOffset = initialBlockOffset + (isHorizontalWritingMode() ? -flowThreadPortion.y() : -flowThreadPortion.x()); if (!progressionIsInline) { if (!progressionReversed) blockOffset = i * colGap; else blockOffset -= i * (computedColumnHeight() + colGap); } if (isFlippedBlocksWritingMode(style().writingMode())) blockOffset = -blockOffset; translationOffset.setY(blockOffset); if (!isHorizontalWritingMode()) translationOffset = translationOffset.transposedPoint(); // FIXME: The translation needs to include the multicolumn set's content offset within the // multicolumn block as well. This won't be an issue until we start creating multiple multicolumn sets. // Shift the dirty rect to be in flow thread coordinates with this translation applied. LayoutRect translatedDirtyRect(dirtyRect); translatedDirtyRect.moveBy(-translationOffset); // See if we intersect the dirty rect. clippedRect = layerBoundingBox; clippedRect.intersect(translatedDirtyRect); if (clippedRect.isEmpty()) continue; // Something does need to paint in this column. Make a fragment now and supply the physical translation // offset and the clip rect for the column with that offset applied. LayerFragment fragment; fragment.paginationOffset = translationOffset; LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion); // Flip it into more a physical (RenderLayer-style) rectangle. flowThread()->flipForWritingMode(flippedFlowThreadOverflowPortion); fragment.paginationClip = flippedFlowThreadOverflowPortion; fragments.append(fragment); } }
void RenderMultiColumnSet::collectLayerFragments(Vector<LayerFragment>& fragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) { // Put the layer bounds into flow thread-local coordinates by flipping it first. LayoutRect layerBoundsInFlowThread(layerBoundingBox); flowThread()->flipForWritingMode(layerBoundsInFlowThread); // Do the same for the dirty rect. LayoutRect dirtyRectInFlowThread(dirtyRect); flowThread()->flipForWritingMode(dirtyRectInFlowThread); // Now we can compare with the flow thread portions owned by each column. First let's // see if the rect intersects our flow thread portion at all. LayoutRect clippedRect(layerBoundsInFlowThread); clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect()); if (clippedRect.isEmpty()) return; // Now we know we intersect at least one column. Let's figure out the logical top and logical // bottom of the area we're checking. LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowThread.y() : layerBoundsInFlowThread.x(); LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFlowThread.maxY() : layerBoundsInFlowThread.maxX()) - 1; // Figure out the start and end columns and only check within that range so that we don't walk the // entire column set. unsigned startColumn = columnIndexAtOffset(layerLogicalTop); unsigned endColumn = columnIndexAtOffset(layerLogicalBottom); LayoutUnit colLogicalWidth = computedColumnWidth(); LayoutUnit colGap = columnGap(); unsigned colCount = columnCount(); for (unsigned i = startColumn; i <= endColumn; i++) { // Get the portion of the flow thread that corresponds to this column. LayoutRect flowThreadPortion = flowThreadPortionRectAt(i); // Now get the overflow rect that corresponds to the column. LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap); // In order to create a fragment we must intersect the portion painted by this column. LayoutRect clippedRect(layerBoundsInFlowThread); clippedRect.intersect(flowThreadOverflowPortion); if (clippedRect.isEmpty()) continue; // We also need to intersect the dirty rect. We have to apply a translation and shift based off // our column index. LayoutPoint translationOffset; LayoutUnit inlineOffset = i * (colLogicalWidth + colGap); if (!style()->isLeftToRightDirection()) inlineOffset = -inlineOffset; translationOffset.setX(inlineOffset); LayoutUnit blockOffset = isHorizontalWritingMode() ? -flowThreadPortion.y() : -flowThreadPortion.x(); if (isFlippedBlocksWritingMode(style()->writingMode())) blockOffset = -blockOffset; translationOffset.setY(blockOffset); if (!isHorizontalWritingMode()) translationOffset = translationOffset.transposedPoint(); // FIXME: The translation needs to include the multicolumn set's content offset within the // multicolumn block as well. This won't be an issue until we start creating multiple multicolumn sets. // Shift the dirty rect to be in flow thread coordinates with this translation applied. LayoutRect translatedDirtyRect(dirtyRectInFlowThread); translatedDirtyRect.moveBy(-translationOffset); // See if we intersect the dirty rect. clippedRect = layerBoundsInFlowThread; clippedRect.intersect(translatedDirtyRect); if (clippedRect.isEmpty()) continue; // Something does need to paint in this column. Make a fragment now and supply the physical translation // offset and the clip rect for the column with that offset applied. LayerFragment fragment; fragment.paginationOffset = translationOffset; LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion); flipForWritingMode(flippedFlowThreadOverflowPortion); fragment.paginationClip = flippedFlowThreadOverflowPortion; fragments.append(fragment); } }
FractionalLayoutUnit& FractionalLayoutBoxExtent::mutableAfter(WritingMode writingMode) { return isHorizontalWritingMode(writingMode) ? (isFlippedBlocksWritingMode(writingMode) ? m_top : m_bottom) : (isFlippedBlocksWritingMode(writingMode) ? m_left: m_right); }