LayoutSize LayoutMultiColumnFlowThread::flowThreadTranslationAtOffset(LayoutUnit offsetInFlowThread) const
{
    LayoutMultiColumnSet* columnSet = columnSetAtBlockOffset(offsetInFlowThread);
    if (!columnSet)
        return LayoutSize(0, 0);
    return columnSet->flowThreadTranslationAtOffset(offsetInFlowThread);
}
void LayoutMultiColumnFlowThread::appendNewFragmentainerGroupIfNeeded(LayoutUnit offsetInFlowThread)
{
    if (!isPageLogicalHeightKnown()) {
        // If we have no clue about the height of the multicol container, bail. This situation
        // occurs initially when an auto-height multicol container is nested inside another
        // auto-height multicol container. We need at least an estimated height of the outer
        // multicol container before we can check what an inner fragmentainer group has room for.
        // Its height is indefinite for now.
        return;
    }
    LayoutMultiColumnSet* columnSet = columnSetAtBlockOffset(offsetInFlowThread);
    if (columnSet->isInitialHeightCalculated()) {
        // We only insert additional fragmentainer groups in the initial layout pass. We only want
        // to balance columns in the last fragmentainer group (if we need to balance at all), so we
        // want that last fragmentainer group to be the same one in all layout passes that follow.
        return;
    }

    if (!columnSet->hasFragmentainerGroupForColumnAt(offsetInFlowThread)) {
        FragmentationContext* enclosingFragmentationContext = this->enclosingFragmentationContext();
        if (!enclosingFragmentationContext)
            return; // Not nested. We'll never need more rows than the one we already have then.
        ASSERT(!isLayoutPagedFlowThread());
        // We have run out of columns here, so we add another row to hold more columns. When we add
        // a new row, it implicitly means that we're inserting another column in our enclosing
        // multicol container. That in turn may mean that we've run out of columns there too.
        const MultiColumnFragmentainerGroup& newRow = columnSet->appendNewFragmentainerGroup();
        if (LayoutMultiColumnFlowThread* enclosingFlowThread = enclosingFragmentationContext->associatedFlowThread())
            enclosingFlowThread->appendNewFragmentainerGroupIfNeeded(newRow.blockOffsetInEnclosingFragmentationContext());
    }
}
void LayoutMultiColumnFlowThread::appendNewFragmentainerGroupIfNeeded(LayoutUnit bottomOffsetInFlowThread)
{
    if (!isPageLogicalHeightKnown()) {
        // If we have no clue about the height of the multicol container, bail. This situation
        // occurs initially when an auto-height multicol container is nested inside another
        // auto-height multicol container. We need at least an estimated height of the outer
        // multicol container before we can check what an inner fragmentainer group has room for.
        // Its height is indefinite for now.
        return;
    }
    // TODO(mstensho): bottomOffsetInFlowThread is an endpoint-exclusive offset, i.e. the offset
    // just after the bottom of some object. So, ideally, columnSetAtBlockOffset() should be
    // informed about this (i.e. take a PageBoundaryRule argument). This is not the only place with
    // this issue; see also pageRemainingLogicalHeightForOffset().
    LayoutMultiColumnSet* columnSet = columnSetAtBlockOffset(bottomOffsetInFlowThread);
    if (columnSet->isInitialHeightCalculated()) {
        // We only insert additional fragmentainer groups in the initial layout pass. We only want
        // to balance columns in the last fragmentainer group (if we need to balance at all), so we
        // want that last fragmentainer group to be the same one in all layout passes that follow.
        return;
    }

    if (!columnSet->hasFragmentainerGroupForColumnAt(bottomOffsetInFlowThread)) {
        FragmentationContext* enclosingFragmentationContext = this->enclosingFragmentationContext();
        if (!enclosingFragmentationContext)
            return; // Not nested. We'll never need more rows than the one we already have then.
        ASSERT(!isLayoutPagedFlowThread());
        // We have run out of columns here, so we add another row to hold more columns. When we add
        // a new row, it implicitly means that we're inserting another column in our enclosing
        // multicol container. That in turn may mean that we've run out of columns there too.
        const MultiColumnFragmentainerGroup& newRow = columnSet->appendNewFragmentainerGroup();
        if (LayoutMultiColumnFlowThread* enclosingFlowThread = enclosingFragmentationContext->associatedFlowThread())
            enclosingFlowThread->appendNewFragmentainerGroupIfNeeded(newRow.blockOffsetInEnclosingFragmentationContext() + newRow.logicalHeight());
    }
}
Пример #4
0
LayoutUnit RenderFlowThread::pageLogicalHeightForOffset(LayoutUnit offset)
{
    RenderMultiColumnSet* columnSet = columnSetAtBlockOffset(offset);
    if (!columnSet)
        return 0;

    return columnSet->pageLogicalHeight();
}
Пример #5
0
void RenderFlowThread::setRegionRangeForBox(const RenderBox* box, LayoutUnit offsetFromLogicalTopOfFirstPage)
{
    if (!hasRegions())
        return;

    // FIXME: Not right for differing writing-modes.
    RenderMultiColumnSet* startColumnSet = columnSetAtBlockOffset(offsetFromLogicalTopOfFirstPage);
    RenderMultiColumnSet* endColumnSet = columnSetAtBlockOffset(offsetFromLogicalTopOfFirstPage + box->logicalHeight());
    RenderMultiColumnSetRangeMap::iterator it = m_multiColumnSetRangeMap.find(box);
    if (it == m_multiColumnSetRangeMap.end()) {
        m_multiColumnSetRangeMap.set(box, RenderMultiColumnSetRange(startColumnSet, endColumnSet));
        return;
    }

    // If nothing changed, just bail.
    RenderMultiColumnSetRange& range = it->value;
    if (range.startColumnSet() == startColumnSet && range.endColumnSet() == endColumnSet)
        return;

    range.setRange(startColumnSet, endColumnSet);
}
Пример #6
0
LayoutUnit RenderFlowThread::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule)
{
    RenderMultiColumnSet* columnSet = columnSetAtBlockOffset(offset);
    if (!columnSet)
        return 0;

    LayoutUnit pageLogicalTop = columnSet->pageLogicalTopForOffset(offset);
    LayoutUnit pageLogicalHeight = columnSet->pageLogicalHeight();
    LayoutUnit pageLogicalBottom = pageLogicalTop + pageLogicalHeight;
    LayoutUnit remainingHeight = pageLogicalBottom - offset;
    if (pageBoundaryRule == IncludePageBoundary) {
        // If IncludePageBoundary is set, the line exactly on the top edge of a
        // columnSet will act as being part of the previous columnSet.
        remainingHeight = intMod(remainingHeight, pageLogicalHeight);
    }
    return remainingHeight;
}
LayoutUnit LayoutMultiColumnFlowThread::tallestUnbreakableLogicalHeight(LayoutUnit offsetInFlowThread) const
{
    if (LayoutMultiColumnSet* multicolSet = columnSetAtBlockOffset(offsetInFlowThread))
        return multicolSet->tallestUnbreakableLogicalHeight();
    return LayoutUnit();
}
Пример #8
0
LayoutUnit RenderFlowThread::pageLogicalTopForOffset(LayoutUnit offset)
{
    RenderMultiColumnSet* columnSet = columnSetAtBlockOffset(offset);
    return columnSet ? columnSet->pageLogicalTopForOffset(offset) : LayoutUnit();
}
Пример #9
0
LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject& boxModelObject, const LayoutPoint& startPoint)
{
    LayoutPoint referencePoint = startPoint;

    // FIXME: This needs to be adapted for different writing modes inside the flow thread.
    RenderMultiColumnSet* startColumnSet = columnSetAtBlockOffset(referencePoint.y());
    if (startColumnSet) {
        // Take into account the offset coordinates of the columnSet.
        RenderObject* currObject = startColumnSet;
        RenderObject* currOffsetParentRenderer;
        Element* currOffsetParentElement;
        while ((currOffsetParentElement = currObject->offsetParent()) && (currOffsetParentRenderer = currOffsetParentElement->renderer())) {
            if (currObject->isBoxModelObject())
                referencePoint.move(toRenderBoxModelObject(currObject)->offsetLeft(), toRenderBoxModelObject(currObject)->offsetTop());

            // Since we're looking for the offset relative to the body, we must also
            // take into consideration the borders of the columnSet's offsetParent.
            if (currOffsetParentRenderer->isBox() && !currOffsetParentRenderer->isBody())
                referencePoint.move(toRenderBox(currOffsetParentRenderer)->borderLeft(), toRenderBox(currOffsetParentRenderer)->borderTop());

            currObject = currOffsetParentRenderer;
        }

        // We need to check if any of this box's containing blocks start in a different columnSet
        // and if so, drop the object's top position (which was computed relative to its containing block
        // and is no longer valid) and recompute it using the columnSet in which it flows as reference.
        bool wasComputedRelativeToOtherRegion = false;
        const RenderBlock* objContainingBlock = boxModelObject.containingBlock();
        while (objContainingBlock) {
            // Check if this object is in a different columnSet.
            RenderMultiColumnSet* parentStartRegion = 0;
            RenderMultiColumnSet* parentEndRegion = 0;
            getRegionRangeForBox(objContainingBlock, parentStartRegion, parentEndRegion);
            if (parentStartRegion && parentStartRegion != startColumnSet) {
                wasComputedRelativeToOtherRegion = true;
                break;
            }
            objContainingBlock = objContainingBlock->containingBlock();
        }

        if (wasComputedRelativeToOtherRegion) {
            // Get the logical top coordinate of the current object.
            LayoutUnit top = 0;
            if (boxModelObject.isRenderBlock()) {
                top = toRenderBlock(&boxModelObject)->offsetFromLogicalTopOfFirstPage();
            } else {
                if (boxModelObject.containingBlock())
                    top = boxModelObject.containingBlock()->offsetFromLogicalTopOfFirstPage();

                if (boxModelObject.isBox())
                    top += toRenderBox(&boxModelObject)->topLeftLocation().y();
                else if (boxModelObject.isRenderInline())
                    top -= toRenderInline(&boxModelObject)->borderTop();
            }

            // Get the logical top of the columnSet this object starts in
            // and compute the object's top, relative to the columnSet's top.
            LayoutUnit regionLogicalTop = startColumnSet->pageLogicalTopForOffset(top);
            LayoutUnit topRelativeToRegion = top - regionLogicalTop;
            referencePoint.setY(startColumnSet->offsetTop() + topRelativeToRegion);

            // Since the top has been overriden, check if the
            // relative positioning must be reconsidered.
            if (boxModelObject.isRelPositioned())
                referencePoint.move(0, boxModelObject.relativePositionOffset().height());
        }

        // Since we're looking for the offset relative to the body, we must also
        // take into consideration the borders of the columnSet.
        referencePoint.move(startColumnSet->borderLeft(), startColumnSet->borderTop());
    }

    return referencePoint;
}