void RenderFlowThread::repaintRectangleInRegions(const LayoutRect& repaintRect, bool immediate) { if (!shouldRepaint(repaintRect) || !hasValidRegionInfo()) return; for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; if (!region->isValid()) continue; // We only have to issue a repaint in this region if the region rect intersects the repaint rect. LayoutRect flippedRegionRect(region->regionRect()); LayoutRect flippedRegionOverflowRect(region->regionOverflowRect()); flipForWritingMode(flippedRegionRect); // Put the region rects into physical coordinates. flipForWritingMode(flippedRegionOverflowRect); LayoutRect clippedRect(repaintRect); clippedRect.intersect(flippedRegionOverflowRect); if (clippedRect.isEmpty()) continue; // Put the region rect into the region's physical coordinate space. clippedRect.setLocation(region->contentBoxRect().location() + (clippedRect.location() - flippedRegionRect.location())); // Now switch to the region's writing mode coordinate space and let it repaint itself. region->flipForWritingMode(clippedRect); LayoutStateDisabler layoutStateDisabler(view()); // We can't use layout state to repaint, since the region is somewhere else. // Can't use currentFlowThread as it possible to have imbricated flow threads and the wrong one could be used, // so, we let each region figure out the proper enclosing flow thread CurrentRenderFlowThreadDisabler disabler(view()); region->repaintRectangle(clippedRect, immediate); } }
LayoutSize RenderMultiColumnSet::flowThreadTranslationAtOffset(LayoutUnit blockOffset) const { unsigned columnIndex = columnIndexAtOffset(blockOffset); LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); flipForWritingMode(portionRect); LayoutRect columnRect(columnRectAt(columnIndex)); flipForWritingMode(columnRect); return contentBoxRect().location() + columnRect.location() - portionRect.location(); }
void LayoutFlowThread::mapRectToPaintInvalidationBacking(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const { ASSERT(paintInvalidationContainer != this); // A flow thread should never be an invalidation container. // |rect| is a layout rectangle, where the block direction coordinate is flipped for writing // mode. fragmentsBoundingBox(), on the other hand, works on physical rectangles, so we need to // flip the rectangle before and after calling it. flipForWritingMode(rect); rect = fragmentsBoundingBox(rect); flipForWritingMode(rect); LayoutBlockFlow::mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, paintInvalidationState); }
bool RenderFlowThread::hitTestRegion(RenderRegion* region, const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset) { LayoutRect regionRect(region->regionRect()); LayoutRect regionOverflowRect = region->regionOverflowRect(); LayoutRect regionClippingRect(accumulatedOffset + (regionOverflowRect.location() - regionRect.location()), regionOverflowRect.size()); if (!regionClippingRect.contains(pointInContainer)) return false; LayoutPoint renderFlowThreadOffset; if (style()->isFlippedBlocksWritingMode()) { LayoutRect flippedRegionRect(regionRect); flipForWritingMode(flippedRegionRect); renderFlowThreadOffset = LayoutPoint(accumulatedOffset - flippedRegionRect.location()); } else renderFlowThreadOffset = LayoutPoint(accumulatedOffset - regionRect.location()); LayoutPoint transformedPoint(pointInContainer.x() - renderFlowThreadOffset.x(), pointInContainer.y() - renderFlowThreadOffset.y()); // Always ignore clipping, since the RenderFlowThread has nothing to do with the bounds of the FrameView. HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping); RenderRegion* oldRegion = result.region(); result.setRegion(region); LayoutPoint oldPoint = result.point(); result.setPoint(transformedPoint); bool isPointInsideFlowThread = layer()->hitTest(newRequest, result); result.setPoint(oldPoint); result.setRegion(oldRegion); // FIXME: Should we set result.m_localPoint back to the RenderRegion's coordinate space or leave it in the RenderFlowThread's coordinate // space? Right now it's staying in the RenderFlowThread's coordinate space, which may end up being ok. We will know more when we get around to // patching positionForPoint. return isPointInsideFlowThread; }
void RenderRegion::repaintFlowThreadContentRectangle(const LayoutRect& repaintRect, const LayoutRect& flowThreadPortionRect, const LayoutPoint& regionLocation, const LayoutRect* flowThreadPortionClipRect) { ASSERT(isValid()); // We only have to issue a repaint in this region if the region rect intersects the repaint rect. LayoutRect clippedRect(repaintRect); if (flowThreadPortionClipRect) { LayoutRect flippedFlowThreadPortionClipRect(*flowThreadPortionClipRect); flowThread()->flipForWritingMode(flippedFlowThreadPortionClipRect); clippedRect.intersect(flippedFlowThreadPortionClipRect); } if (clippedRect.isEmpty()) return; LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); flowThread()->flipForWritingMode(flippedFlowThreadPortionRect); // Put the region rects into physical coordinates. // Put the region rect into the region's physical coordinate space. clippedRect.setLocation(regionLocation + (clippedRect.location() - flippedFlowThreadPortionRect.location())); // Now switch to the region's writing mode coordinate space and let it repaint itself. flipForWritingMode(clippedRect); // Issue the repaint. repaintRectangle(clippedRect); }
bool RenderFlowThread::hitTestFlowThreadPortionInRegion(RenderRegion* region, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const { LayoutRect regionClippingRect = computeRegionClippingRect(accumulatedOffset, flowThreadPortionRect, flowThreadPortionOverflowRect); if (!regionClippingRect.contains(locationInContainer.point())) return false; LayoutSize renderFlowThreadOffset; if (style()->isFlippedBlocksWritingMode()) { LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); flipForWritingMode(flippedFlowThreadPortionRect); renderFlowThreadOffset = accumulatedOffset - flippedFlowThreadPortionRect.location(); } else renderFlowThreadOffset = accumulatedOffset - flowThreadPortionRect.location(); // Always ignore clipping, since the RenderFlowThread has nothing to do with the bounds of the FrameView. HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping); // Make a new temporary HitTestLocation in the new region. HitTestLocation newHitTestLocation(locationInContainer, -renderFlowThreadOffset, region); bool isPointInsideFlowThread = layer()->hitTest(newRequest, newHitTestLocation, result); // FIXME: Should we set result.m_localPoint back to the RenderRegion's coordinate space or leave it in the RenderFlowThread's coordinate // space? Right now it's staying in the RenderFlowThread's coordinate space, which may end up being ok. We will know more when we get around to // patching positionForPoint. return isPointInsideFlowThread; }
void RenderMultiColumnSet::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // For each rectangle, set it as the region rectangle and then let flow thread painting do the rest. // We make multiple calls to paintFlowThreadPortionInRegion, changing the rectangles each time. unsigned colCount = columnCount(); if (!colCount) return; LayoutUnit colGap = columnGap(); for (unsigned i = 0; i < colCount; i++) { // First we get the column rect, which is in our local coordinate space, and we make it physical and apply // the paint offset to it. That gives us the physical location that we want to paint the column at. LayoutRect colRect = columnRectAt(i); flipForWritingMode(colRect); colRect.moveBy(paintOffset); // Next we 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); // Do the paint with the computed rects. flowThread()->paintFlowThreadPortionInRegion(paintInfo, this, flowThreadPortion, flowThreadOverflowPortion, colRect.location()); } }
int RenderView::docRight() const { IntRect overflowRect(layoutOverflowRect()); flipForWritingMode(overflowRect); if (hasTransform()) overflowRect = layer()->currentTransform().mapRect(overflowRect); return overflowRect.maxX(); }
int RenderView::docTop() const { IntRect overflowRect(0, minYLayoutOverflow(), 0, maxYLayoutOverflow() - minYLayoutOverflow()); flipForWritingMode(overflowRect); if (hasTransform()) overflowRect = layer()->currentTransform().mapRect(overflowRect); return overflowRect.y(); }
LayoutSize LayoutMultiColumnFlowThread::columnOffset(const LayoutPoint& point) const { if (!hasValidColumnSetInfo()) return LayoutSize(0, 0); LayoutPoint flowThreadPoint = flipForWritingMode(point); LayoutUnit blockOffset = isHorizontalWritingMode() ? flowThreadPoint.y() : flowThreadPoint.x(); return flowThreadTranslationAtOffset(blockOffset); }
RenderRegion* RenderMultiColumnFlowThread::mapFromFlowToRegion(TransformState& transformState) const { if (!hasValidRegionInfo()) return nullptr; // Get back into our local flow thread space. LayoutRect boxRect = transformState.mappedQuad().enclosingBoundingBox(); flipForWritingMode(boxRect); // FIXME: We need to refactor RenderObject::absoluteQuads to be able to split the quads across regions, // for now we just take the center of the mapped enclosing box and map it to a column. LayoutPoint center = boxRect.center(); LayoutUnit centerOffset = isHorizontalWritingMode() ? center.y() : center.x(); RenderRegion* renderRegion = const_cast<RenderMultiColumnFlowThread*>(this)->regionAtBlockOffset(this, centerOffset, true, DisallowRegionAutoGeneration); if (!renderRegion) return nullptr; // Now that we know which multicolumn set we hit, we need to get the appropriate translation offset for the column. RenderMultiColumnSet* columnSet = toRenderMultiColumnSet(renderRegion); LayoutPoint translationOffset = columnSet->columnTranslationForOffset(centerOffset); // Now we know how we want the rect to be translated into the region. LayoutRect flippedRegionRect(renderRegion->flowThreadPortionRect()); if (isHorizontalWritingMode()) flippedRegionRect.setHeight(columnSet->computedColumnHeight()); else flippedRegionRect.setWidth(columnSet->computedColumnHeight()); flipForWritingMode(flippedRegionRect); flippedRegionRect.moveBy(-translationOffset); // There is an additional offset to apply, which is the offset of the region within the multi-column space. transformState.move(renderRegion->contentBoxRect().location() - flippedRegionRect.location()); return renderRegion; }
RenderRegion* RenderFlowThread::mapFromFlowToRegion(TransformState& transformState) const { if (!hasValidRegionInfo()) return 0; LayoutRect boxRect = transformState.mappedQuad().enclosingBoundingBox(); flipForWritingMode(boxRect); // FIXME: We need to refactor RenderObject::absoluteQuads to be able to split the quads across regions, // for now we just take the center of the mapped enclosing box and map it to a region. // Note: Using the center in order to avoid rounding errors. LayoutPoint center = boxRect.center(); RenderRegion* renderRegion = regionAtBlockOffset(isHorizontalWritingMode() ? center.y() : center.x(), true); if (!renderRegion) return 0; LayoutRect flippedRegionRect(renderRegion->flowThreadPortionRect()); flipForWritingMode(flippedRegionRect); transformState.move(renderRegion->contentBoxRect().location() - flippedRegionRect.location()); return renderRegion; }
bool InlineTextBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) { if (isLineBreak() || m_truncation == cFullTruncation) return false; LayoutPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(accumulatedOffset); LayoutRect rect(boxOrigin, size()); if (visibleToHitTestRequest(result.hitTestRequest()) && locationInContainer.intersects(rect)) { getLineLayoutItem().updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); if (result.addNodeToListBasedTestResult(getLineLayoutItem().node(), locationInContainer, rect) == StopHitTesting) return true; } return false; }
bool InlineTextBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) { if (isLineBreak()) return false; LayoutPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(accumulatedOffset); LayoutRect rect(boxOrigin, size()); // FIXME: both calls to rawValue() below is temporary and should be removed once the transition // to LayoutUnit-based types is complete (crbug.com/321237) if (m_truncation != cFullTruncation && visibleToHitTestRequest(result.hitTestRequest()) && locationInContainer.intersects(rect)) { lineLayoutItem().updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); if (!result.addNodeToListBasedTestResult(lineLayoutItem().node(), locationInContainer, rect)) return true; } return false; }
void RenderFlowThread::paintFlowThreadPortionInRegion(PaintInfo& paintInfo, RenderRegion* region, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const LayoutPoint& paintOffset) const { GraphicsContext* context = paintInfo.context; if (!context) return; // RenderFlowThread should start painting its content in a position that is offset // from the region rect's current position. The amount of offset is equal to the location of // the flow thread portion in the flow thread's local coordinates. // Note that we have to pixel snap the location at which we're going to paint, since this is necessary // to minimize the amount of incorrect snapping that would otherwise occur. // If we tried to paint by applying a non-integral translation, then all the // layout code that attempted to pixel snap would be incorrect. IntPoint adjustedPaintOffset; LayoutPoint portionLocation; if (style()->isFlippedBlocksWritingMode()) { LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); flipForWritingMode(flippedFlowThreadPortionRect); portionLocation = flippedFlowThreadPortionRect.location(); } else portionLocation = flowThreadPortionRect.location(); adjustedPaintOffset = roundedIntPoint(paintOffset - portionLocation); // The clipping rect for the region is set up by assuming the flowThreadPortionRect is going to paint offset from adjustedPaintOffset. // Remember that we pixel snapped and moved the paintOffset and stored the snapped result in adjustedPaintOffset. Now we add back in // the flowThreadPortionRect's location to get the spot where we expect the portion to actually paint. This can be non-integral and // that's ok. We then pixel snap the resulting clipping rect to account for snapping that will occur when the flow thread paints. IntRect regionClippingRect = pixelSnappedIntRect(computeRegionClippingRect(adjustedPaintOffset + portionLocation, flowThreadPortionRect, flowThreadPortionOverflowRect)); PaintInfo info(paintInfo); info.rect.intersect(regionClippingRect); if (!info.rect.isEmpty()) { context->save(); context->clip(regionClippingRect); context->translate(adjustedPaintOffset.x(), adjustedPaintOffset.y()); info.rect.moveBy(-adjustedPaintOffset); layer()->paint(context, info.rect, 0, 0, region, RenderLayer::PaintLayerTemporaryClipRects); context->restore(); } }
RenderRegion* RenderMultiColumnFlowThread::mapFromFlowToRegion(TransformState& transformState) const { if (!hasValidRegionInfo()) return nullptr; // Get back into our local flow thread space. LayoutRect boxRect = transformState.mappedQuad().enclosingBoundingBox(); flipForWritingMode(boxRect); // FIXME: We need to refactor RenderObject::absoluteQuads to be able to split the quads across regions, // for now we just take the center of the mapped enclosing box and map it to a column. LayoutPoint centerPoint = boxRect.center(); LayoutUnit centerLogicalOffset = isHorizontalWritingMode() ? centerPoint.y() : centerPoint.x(); RenderRegion* renderRegion = const_cast<RenderMultiColumnFlowThread*>(this)->regionAtBlockOffset(this, centerLogicalOffset, true, DisallowRegionAutoGeneration); if (!renderRegion) return nullptr; transformState.move(physicalTranslationOffsetFromFlowToRegion(renderRegion, centerLogicalOffset)); return renderRegion; }
bool RenderMultiColumnSet::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { LayoutPoint adjustedLocation = accumulatedOffset + location(); // Check our bounds next. For this purpose always assume that we can only be hit in the // foreground phase (which is true for replaced elements like images). // FIXME: Once we support overflow, we need to intersect with that and not with the bounds rect. LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region()); boundsRect.moveBy(adjustedLocation); if (!visibleToHitTesting() || action != HitTestForeground || !locationInContainer.intersects(boundsRect)) return false; // The point is in one specific column. Since columns can't overlap, we don't ever have to test // multiple columns. Put the // FIXME: It would be nice to jump right to the specific column by just doing math on the point. Since columns // can't overlap, we shouldn't have to walk every column like this. The old column code walked all the columns, though, // so this is no worse. We'd have to watch out for rect-based hit testing, though, which actually could overlap // multiple columns. LayoutUnit colGap = columnGap(); unsigned colCount = columnCount(); for (unsigned i = 0; i < colCount; i++) { // First we get the column rect, which is in our local coordinate space, and we make it physical and apply // the hit test offset to it. That gives us the physical location that we want to paint the column at. LayoutRect colRect = columnRectAt(i); flipForWritingMode(colRect); colRect.moveBy(adjustedLocation); // Next we 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); // Do the hit test with the computed rects. if (flowThread()->hitTestFlowThreadPortionInRegion(this, flowThreadPortion, flowThreadOverflowPortion, request, result, locationInContainer, colRect.location())) return true; } updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); return !result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect); }
void RenderFlowThread::paintIntoRegion(PaintInfo& paintInfo, RenderRegion* region, const LayoutPoint& paintOffset) { GraphicsContext* context = paintInfo.context; if (!context) return; // Adjust the clipping rect for the region. // paintOffset contains the offset where the painting should occur // adjusted with the region padding and border. LayoutRect regionRect(region->regionRect()); LayoutRect regionOverflowRect(region->regionOverflowRect()); LayoutRect regionClippingRect(paintOffset + (regionOverflowRect.location() - regionRect.location()), regionOverflowRect.size()); PaintInfo info(paintInfo); info.rect.intersect(pixelSnappedIntRect(regionClippingRect)); if (!info.rect.isEmpty()) { context->save(); context->clip(regionClippingRect); // RenderFlowThread should start painting its content in a position that is offset // from the region rect's current position. The amount of offset is equal to the location of // region in flow coordinates. LayoutPoint renderFlowThreadOffset; if (style()->isFlippedBlocksWritingMode()) { LayoutRect flippedRegionRect(regionRect); flipForWritingMode(flippedRegionRect); renderFlowThreadOffset = LayoutPoint(paintOffset - flippedRegionRect.location()); } else renderFlowThreadOffset = LayoutPoint(paintOffset - regionRect.location()); context->translate(renderFlowThreadOffset.x(), renderFlowThreadOffset.y()); info.rect.moveBy(-roundedIntPoint(renderFlowThreadOffset)); layer()->paint(context, info.rect, 0, 0, region, RenderLayer::PaintLayerTemporaryClipRects); context->restore(); } }
RenderRegion* RenderMultiColumnFlowThread::physicalTranslationFromFlowToRegion(LayoutPoint& physicalPoint) const { if (!hasValidRegionInfo()) return nullptr; // Put the physical point into the flow thread's coordinate space. LayoutPoint logicalPoint = flipForWritingMode(physicalPoint); // Now get the region that we are in. LayoutUnit logicalOffset = isHorizontalWritingMode() ? logicalPoint.y() : logicalPoint.x(); RenderRegion* renderRegion = const_cast<RenderMultiColumnFlowThread*>(this)->regionAtBlockOffset(this, logicalOffset, true, DisallowRegionAutoGeneration); if (!renderRegion) return nullptr; // Translate to the coordinate space of the region. LayoutSize translationOffset = physicalTranslationOffsetFromFlowToRegion(renderRegion, logicalOffset); // Now shift the physical point into the region's coordinate space. physicalPoint += translationOffset; return renderRegion; }
IntRect RenderView::unscaledDocumentRect() const { IntRect overflowRect(layoutOverflowRect()); flipForWritingMode(overflowRect); return overflowRect; }
IntRect RenderView::unscaledDocumentRect() const { LayoutRect overflowRect(layoutOverflowRect()); flipForWritingMode(overflowRect); return pixelSnappedIntRect(overflowRect); }
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); } }