LayoutRect RenderNamedFlowThread::decorationsClipRectForBoxInNamedFlowFragment(const RenderBox& box, RenderNamedFlowFragment& fragment) const
{
    LayoutRect visualOverflowRect = fragment.visualOverflowRectForBox(&box);
    LayoutUnit initialLogicalX = style().isHorizontalWritingMode() ? visualOverflowRect.x() : visualOverflowRect.y();

    // The visual overflow rect returned by visualOverflowRectForBox is already flipped but the
    // RenderRegion::rectFlowPortionForBox method expects it unflipped.
    flipForWritingModeLocalCoordinates(visualOverflowRect);
    visualOverflowRect = fragment.rectFlowPortionForBox(&box, visualOverflowRect);
    
    // Now flip it again.
    flipForWritingModeLocalCoordinates(visualOverflowRect);

    // Take the scrolled offset of this object's parents into consideration.
    IntSize scrolledContentOffset;
    RenderBlock* containingBlock = box.containingBlock();
    while (containingBlock) {
        if (containingBlock->isRenderNamedFlowThread()) {
            // We've reached the flow thread, take the scrolled offset of the region into consideration.
            ASSERT(containingBlock == this);
            scrolledContentOffset += fragment.fragmentContainer().scrolledContentOffset();
            break;
        }
        
        scrolledContentOffset += containingBlock->scrolledContentOffset();
        containingBlock = containingBlock->containingBlock();
    }

    if (!scrolledContentOffset.isZero()) {
        if (style().isFlippedBlocksWritingMode())
            scrolledContentOffset = -scrolledContentOffset;
        
        visualOverflowRect.inflateX(scrolledContentOffset.width());
        visualOverflowRect.inflateY(scrolledContentOffset.height());
    }
    
    // Layers are in physical coordinates so the origin must be moved to the physical top-left of the flowthread.
    if (style().isFlippedBlocksWritingMode()) {
        if (style().isHorizontalWritingMode())
            visualOverflowRect.moveBy(LayoutPoint(0, height()));
        else
            visualOverflowRect.moveBy(LayoutPoint(width(), 0));
    }

    const RenderBox* iterBox = &box;
    while (iterBox && iterBox != this) {
        RenderBlock* containerBlock = iterBox->containingBlock();

        // FIXME: This doesn't work properly with flipped writing modes.
        // https://bugs.webkit.org/show_bug.cgi?id=125149
        if (iterBox->isPositioned()) {
            // For positioned elements, just use the layer's absolute bounding box.
            visualOverflowRect.moveBy(iterBox->layer()->absoluteBoundingBox().location());
            break;
        }

        LayoutRect currentBoxRect = iterBox->frameRect();
        if (iterBox->style().isFlippedBlocksWritingMode()) {
            if (iterBox->style().isHorizontalWritingMode())
                currentBoxRect.setY(currentBoxRect.height() - currentBoxRect.maxY());
            else
                currentBoxRect.setX(currentBoxRect.width() - currentBoxRect.maxX());
        }

        if (containerBlock->style().writingMode() != iterBox->style().writingMode())
            iterBox->flipForWritingMode(currentBoxRect);

        visualOverflowRect.moveBy(currentBoxRect.location());
        iterBox = containerBlock;
    }

    // Since the purpose of this method is to make sure the borders of a fragmented
    // element don't overflow the region in the fragmentation direction, there's no
    // point in restricting the clipping rect on the logical X axis. 
    // This also saves us the trouble of handling percent-based widths and margins
    // since the absolute bounding box of a positioned element would not contain
    // the correct coordinates relative to the region we're interested in, but rather
    // relative to the actual flow thread.
    if (style().isHorizontalWritingMode()) {
        if (initialLogicalX < visualOverflowRect.x())
            visualOverflowRect.shiftXEdgeTo(initialLogicalX);
        if (visualOverflowRect.width() < frameRect().width())
            visualOverflowRect.setWidth(frameRect().width());
    } else {
        if (initialLogicalX < visualOverflowRect.y())
            visualOverflowRect.shiftYEdgeTo(initialLogicalX);
        if (visualOverflowRect.height() < frameRect().height())
            visualOverflowRect.setHeight(frameRect().height());
    }

    return visualOverflowRect;
}