Пример #1
0
// The algorithm below assumes this is a full layout. In case there are previously computed values for regions, supplemental steps are taken
// to ensure the results are the same as those obtained from a full layout (i.e. the auto-height regions from all the flows are marked as needing
// layout).
// 1. The flows are laid out from the outer flow to the inner flow. This successfully computes the outer non-auto-height regions size so the 
// inner flows have the necessary information to correctly fragment the content.
// 2. The flows are laid out from the inner flow to the outer flow. After an inner flow is laid out it goes into the constrained layout phase
// and marks the auto-height regions they need layout. This means the outer flows will relayout if they depend on regions with auto-height regions
// belonging to inner flows. This step will correctly set the computedAutoHeight for the auto-height regions. It's possible for non-auto-height
// regions to relayout if they depend on auto-height regions. This will invalidate the inner flow threads and mark them as needing layout.
// 3. The last step is to do one last layout if there are pathological dependencies between non-auto-height regions and auto-height regions
// as detected in the previous step.
void RenderView::layoutContentInAutoLogicalHeightRegions(const LayoutState& state)
{
    // We need to invalidate all the flows with auto-height regions if one such flow needs layout.
    // If none is found we do a layout a check back again afterwards.
    if (!flowThreadController().updateFlowThreadsNeedingLayout()) {
        // Do a first layout of the content. In some cases more layouts are not needed (e.g. only flows with non-auto-height regions have changed).
        layoutContent(state);

        // If we find no named flow needing a two step layout after the first layout, exit early.
        // Otherwise, initiate the two step layout algorithm and recompute all the flows.
        if (!flowThreadController().updateFlowThreadsNeedingTwoStepLayout())
            return;
    }

    // Layout to recompute all the named flows with auto-height regions.
    layoutContent(state);

    // Propagate the computed auto-height values upwards.
    // Non-auto-height regions may invalidate the flow thread because they depended on auto-height regions, but that's ok.
    flowThreadController().updateFlowThreadsIntoConstrainedPhase();

    // Do one last layout that should update the auto-height regions found in the main flow
    // and solve pathological dependencies between regions (e.g. a non-auto-height region depending
    // on an auto-height one).
    if (needsLayout())
        layoutContent(state);
}
Пример #2
0
void RenderView::layout()
{
    StackStats::LayoutCheckPoint layoutCheckPoint;
    if (!document()->paginated())
        setPageLogicalHeight(0);

    if (shouldUsePrintingLayout())
        m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = logicalWidth();

    // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account.
    bool relayoutChildren = !shouldUsePrintingLayout() && (!m_frameView || width() != viewWidth() || height() != viewHeight());
    if (relayoutChildren) {
        setChildNeedsLayout(true, MarkOnlyThis);
        for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
            if ((child->isBox() && toRenderBox(child)->hasRelativeLogicalHeight())
                    || child->style()->logicalHeight().isPercent()
                    || child->style()->logicalMinHeight().isPercent()
                    || child->style()->logicalMaxHeight().isPercent())
                child->setChildNeedsLayout(true, MarkOnlyThis);
        }
    }

    ASSERT(!m_layoutState);
    if (!needsLayout())
        return;

    LayoutState state;
    // FIXME: May be better to push a clip and avoid issuing offscreen repaints.
    state.m_clipped = false;
    state.m_pageLogicalHeight = m_pageLogicalHeight;
    state.m_pageLogicalHeightChanged = m_pageLogicalHeightChanged;
    state.m_isPaginated = state.m_pageLogicalHeight;
    m_pageLogicalHeightChanged = false;
    m_layoutState = &state;

    m_layoutPhase = RenderViewNormalLayout;
    bool needsTwoPassLayoutForAutoLogicalHeightRegions = hasRenderNamedFlowThreads()
        && flowThreadController()->hasAutoLogicalHeightRegions()
        && flowThreadController()->hasRenderNamedFlowThreadsNeedingLayout();

    if (needsTwoPassLayoutForAutoLogicalHeightRegions)
        flowThreadController()->resetRegionsOverrideLogicalContentHeight();

    layoutContent(state);

    if (needsTwoPassLayoutForAutoLogicalHeightRegions) {
        m_layoutPhase = ConstrainedFlowThreadsLayoutInAutoLogicalHeightRegions;
        flowThreadController()->markAutoLogicalHeightRegionsForLayout();
        layoutContent(state);
    }

#ifndef NDEBUG
    checkLayoutState(state);
#endif
    m_layoutState = 0;
    setNeedsLayout(false);
}
Пример #3
0
void RenderView::layout()
{
    StackStats::LayoutCheckPoint layoutCheckPoint;
    if (!document().paginated())
        setPageLogicalHeight(0);

    if (shouldUsePrintingLayout())
        m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = logicalWidth();

    // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account.
    bool relayoutChildren = !shouldUsePrintingLayout() && (width() != viewWidth() || height() != viewHeight());
    if (relayoutChildren) {
        setChildNeedsLayout(MarkOnlyThis);
        for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
            if (!child->isBox())
                continue;
            RenderBox& box = toRenderBox(*child);
            if (box.hasRelativeLogicalHeight()
                || box.hasViewportPercentageLogicalHeight()
                || box.style()->logicalHeight().isPercent()
                || box.style()->logicalMinHeight().isPercent()
                || box.style()->logicalMaxHeight().isPercent()
                || box.style()->logicalHeight().isViewportPercentage()
                || box.style()->logicalMinHeight().isViewportPercentage()
                || box.style()->logicalMaxHeight().isViewportPercentage()
#if ENABLE(SVG)
                || box.isSVGRoot()
#endif
                )
                box.setChildNeedsLayout(MarkOnlyThis);
        }
    }

    ASSERT(!m_layoutState);
    if (!needsLayout())
        return;

    m_layoutState = std::make_unique<LayoutState>();
    bool isSeamlessAncestorInFlowThread = initializeLayoutState(*m_layoutState);

    m_pageLogicalHeightChanged = false;

    if (checkTwoPassLayoutForAutoHeightRegions())
        layoutContentInAutoLogicalHeightRegions(*m_layoutState);
    else
        layoutContent(*m_layoutState);

    layoutContentToComputeOverflowInRegions(*m_layoutState);

#ifndef NDEBUG
    checkLayoutState(*m_layoutState);
#endif
    m_layoutState = nullptr;
    clearNeedsLayout();
    
    if (isSeamlessAncestorInFlowThread)
        flowThreadController().setCurrentRenderFlowThread(0);
}
Пример #4
0
void RenderView::layoutContent(const LayoutState& state)
{
    UNUSED_PARAM(state);
    ASSERT(needsLayout());

    RenderBlock::layout();
    if (hasRenderNamedFlowThreads())
        flowThreadController()->layoutRenderNamedFlowThreads();
#ifndef NDEBUG
    checkLayoutState(state);
#endif
}
Пример #5
0
void RenderView::layoutContentToComputeOverflowInRegions(const LayoutState& state)
{
    if (!hasRenderNamedFlowThreads())
        return;

    // First pass through the flow threads and mark the regions as needing a simple layout.
    // The regions extract the overflow from the flow thread and pass it to their containg
    // block chain.
    flowThreadController().updateFlowThreadsIntoOverflowPhase();
    if (needsLayout())
        layoutContent(state);

    // In case scrollbars resized the regions a new pass is necessary to update the flow threads
    // and recompute the overflow on regions. This is the final state of the flow threads.
    flowThreadController().updateFlowThreadsIntoFinalPhase();
    if (needsLayout())
        layoutContent(state);

    // Finally reset the layout state of the flow threads.
    flowThreadController().updateFlowThreadsIntoMeasureContentPhase();
}
Пример #6
0
void RenderView::layout()
{
    if (!document()->paginated())
        setPageLogicalHeight(0);

    if (shouldUsePrintingLayout())
        m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = logicalWidth();

    // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account.
    bool relayoutChildren = !shouldUsePrintingLayout() && (!m_frameView || width() != viewWidth() || height() != viewHeight());
    if (relayoutChildren) {
        setChildNeedsLayout(true, MarkOnlyThis);
        for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
            if ((child->isBox() && toRenderBox(child)->hasRelativeLogicalHeight())
                    || child->style()->logicalHeight().isPercent()
                    || child->style()->logicalMinHeight().isPercent()
                    || child->style()->logicalMaxHeight().isPercent())
                child->setChildNeedsLayout(true, MarkOnlyThis);
        }
    }

    ASSERT(!m_layoutState);
    LayoutState state;
    // FIXME: May be better to push a clip and avoid issuing offscreen repaints.
    state.m_clipped = false;
    state.m_pageLogicalHeight = m_pageLogicalHeight;
    state.m_pageLogicalHeightChanged = m_pageLogicalHeightChanged;
    state.m_isPaginated = state.m_pageLogicalHeight;
    m_pageLogicalHeightChanged = false;
    m_layoutState = &state;

    if (needsLayout()) {
        RenderBlock::layout();
        if (hasRenderNamedFlowThreads())
            flowThreadController()->layoutRenderNamedFlowThreads();
    }

    ASSERT(layoutDelta() == LayoutSize());
    ASSERT(m_layoutStateDisableCount == 0);
    ASSERT(m_layoutState == &state);
    m_layoutState = 0;
    setNeedsLayout(false);
}
Пример #7
0
bool RenderView::initializeLayoutState(LayoutState& state)
{
    bool isSeamlessAncestorInFlowThread = false;

    // FIXME: May be better to push a clip and avoid issuing offscreen repaints.
    state.m_clipped = false;
    
    // Check the writing mode of the seamless ancestor. It has to match our document's writing mode, or we won't inherit any
    // pagination information.
    RenderBox* seamlessAncestor = enclosingSeamlessRenderer(document());
    LayoutState* seamlessLayoutState = seamlessAncestor ? seamlessAncestor->view().layoutState() : 0;
    bool shouldInheritPagination = seamlessLayoutState && !m_pageLogicalHeight && seamlessAncestor->style()->writingMode() == style()->writingMode();
    
    state.m_pageLogicalHeight = shouldInheritPagination ? seamlessLayoutState->m_pageLogicalHeight : m_pageLogicalHeight;
    state.m_pageLogicalHeightChanged = shouldInheritPagination ? seamlessLayoutState->m_pageLogicalHeightChanged : m_pageLogicalHeightChanged;
    state.m_isPaginated = state.m_pageLogicalHeight;
    if (state.m_isPaginated && shouldInheritPagination) {
        // Set up the correct pagination offset. We can use a negative offset in order to push the top of the RenderView into its correct place
        // on a page. We can take the iframe's offset from the logical top of the first page and make the negative into the pagination offset within the child
        // view.
        bool isFlipped = seamlessAncestor->style()->isFlippedBlocksWritingMode();
        LayoutSize layoutOffset = seamlessLayoutState->layoutOffset();
        LayoutSize iFrameOffset(layoutOffset.width() + seamlessAncestor->x() + (!isFlipped ? seamlessAncestor->borderLeft() + seamlessAncestor->paddingLeft() :
            seamlessAncestor->borderRight() + seamlessAncestor->paddingRight()),
            layoutOffset.height() + seamlessAncestor->y() + (!isFlipped ? seamlessAncestor->borderTop() + seamlessAncestor->paddingTop() :
            seamlessAncestor->borderBottom() + seamlessAncestor->paddingBottom()));
        
        LayoutSize offsetDelta = seamlessLayoutState->m_pageOffset - iFrameOffset;
        state.m_pageOffset = offsetDelta;
        
        // Set the current render flow thread to point to our ancestor. This will allow the seamless document to locate the correct
        // regions when doing a layout.
        if (seamlessAncestor->flowThreadContainingBlock()) {
            flowThreadController().setCurrentRenderFlowThread(seamlessAncestor->view().flowThreadController().currentRenderFlowThread());
            isSeamlessAncestorInFlowThread = true;
        }
    }

    // FIXME: We need to make line grids and exclusions work with seamless iframes as well here. Basically all layout state information needs
    // to propagate here and not just pagination information.
    return isSeamlessAncestorInFlowThread;
}
Пример #8
0
void RenderView::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
    RenderBlock::styleDidChange(diff, oldStyle);
    if (hasRenderNamedFlowThreads())
        flowThreadController()->styleDidChange();
}