void RenderFrameSet::computeEdgeInfo()
{
    m_rows.m_preventResize.fill(frameSetElement().noResize());
    m_rows.m_allowBorder.fill(false);
    m_cols.m_preventResize.fill(frameSetElement().noResize());
    m_cols.m_allowBorder.fill(false);
    
    RenderObject* child = firstChild();
    if (!child)
        return;

    size_t rows = m_rows.m_sizes.size();
    size_t cols = m_cols.m_sizes.size();
    for (size_t r = 0; r < rows; ++r) {
        for (size_t c = 0; c < cols; ++c) {
            FrameEdgeInfo edgeInfo;
            if (child->isFrameSet())
                edgeInfo = toRenderFrameSet(child)->edgeInfo();
            else
                edgeInfo = toRenderFrame(child)->edgeInfo();
            fillFromEdgeInfo(edgeInfo, r, c);
            child = child->nextSibling();
            if (!child)
                return;
        }
    }
}
void RenderFrameSet::layout()
{
    StackStats::LayoutCheckPoint layoutCheckPoint;
    ASSERT(needsLayout());

    bool doFullRepaint = selfNeedsLayout() && checkForRepaintDuringLayout();
    LayoutRect oldBounds;
    RenderLayerModelObject* repaintContainer = 0;
    if (doFullRepaint) {
        repaintContainer = containerForRepaint();
        oldBounds = clippedOverflowRectForRepaint(repaintContainer);
    }

    if (!parent()->isFrameSet() && !document().printing()) {
        setWidth(view().viewWidth());
        setHeight(view().viewHeight());
    }

    unsigned cols = frameSetElement().totalCols();
    unsigned rows = frameSetElement().totalRows();

    if (m_rows.m_sizes.size() != rows || m_cols.m_sizes.size() != cols) {
        m_rows.resize(rows);
        m_cols.resize(cols);
    }

    LayoutUnit borderThickness = frameSetElement().border();
    layOutAxis(m_rows, frameSetElement().rowLengths(), height() - (rows - 1) * borderThickness);
    layOutAxis(m_cols, frameSetElement().colLengths(), width() - (cols - 1) * borderThickness);

    if (flattenFrameSet())
        positionFramesWithFlattening();
    else
        positionFrames();

    RenderBox::layout();

    computeEdgeInfo();

    updateLayerTransform();

    if (doFullRepaint) {
        repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds));
        LayoutRect newBounds = clippedOverflowRectForRepaint(repaintContainer);
        if (newBounds != oldBounds)
            repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds));
    }

    clearNeedsLayout();
}
void RenderFrameSet::setIsResizing(bool isResizing)
{
    m_isResizing = isResizing;
    for (auto& ancestor : ancestorsOfType<RenderFrameSet>(*this))
        ancestor.m_isChildResizing = isResizing;
    frame().eventHandler().setResizingFrameSet(isResizing ? &frameSetElement() : nullptr);
}
void RenderFrameSet::positionFrames()
{
    RenderBox* child = firstChildBox();
    if (!child)
        return;

    int rows = frameSetElement().totalRows();
    int cols = frameSetElement().totalCols();

    int yPos = 0;
    int borderThickness = frameSetElement().border();
    for (int r = 0; r < rows; r++) {
        int xPos = 0;
        int height = m_rows.m_sizes[r];
        for (int c = 0; c < cols; c++) {
            child->setLocation(IntPoint(xPos, yPos));
            int width = m_cols.m_sizes[c];

            // has to be resized and itself resize its contents
            if (width != child->width() || height != child->height()) {
                child->setWidth(width);
                child->setHeight(height);
#if PLATFORM(IOS)
                // FIXME: Is this iOS-specific?
                child->setNeedsLayout(MarkOnlyThis);
#else
                child->setNeedsLayout();
#endif
                child->layout();
            }

            xPos += width + borderThickness;

            child = child->nextSiblingBox();
            if (!child)
                return;
        }
        yPos += height + borderThickness;
    }

    // all the remaining frames are hidden to avoid ugly spurious unflowed frames
    for (; child; child = child->nextSiblingBox()) {
        child->setWidth(0);
        child->setHeight(0);
        child->clearNeedsLayout();
    }
}
Exemple #5
0
void RenderFrameSet::setIsResizing(bool isResizing)
{
    m_isResizing = isResizing;
    for (auto ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
        if (ancestor->isFrameSet())
            toRenderFrameSet(ancestor)->m_isChildResizing = isResizing;
    }
    frame().eventHandler().setResizingFrameSet(isResizing ? &frameSetElement() : 0);
}
FrameEdgeInfo RenderFrameSet::edgeInfo() const
{
    FrameEdgeInfo result(frameSetElement().noResize(), true);
    
    int rows = frameSetElement().totalRows();
    int cols = frameSetElement().totalCols();
    if (rows && cols) {
        result.setPreventResize(LeftFrameEdge, m_cols.m_preventResize[0]);
        result.setAllowBorder(LeftFrameEdge, m_cols.m_allowBorder[0]);
        result.setPreventResize(RightFrameEdge, m_cols.m_preventResize[cols]);
        result.setAllowBorder(RightFrameEdge, m_cols.m_allowBorder[cols]);
        result.setPreventResize(TopFrameEdge, m_rows.m_preventResize[0]);
        result.setAllowBorder(TopFrameEdge, m_rows.m_allowBorder[0]);
        result.setPreventResize(BottomFrameEdge, m_rows.m_preventResize[rows]);
        result.setAllowBorder(BottomFrameEdge, m_rows.m_allowBorder[rows]);
    }
    
    return result;
}
int RenderFrameSet::splitPosition(const GridAxis& axis, int split) const
{
    if (needsLayout())
        return 0;

    int borderThickness = frameSetElement().border();

    int size = axis.m_sizes.size();
    if (!size)
        return 0;

    int position = 0;
    for (int i = 0; i < split && i < size; ++i)
        position += axis.m_sizes[i] + borderThickness;
    return position - borderThickness;
}
void RenderFrameSet::paintColumnBorder(const PaintInfo& paintInfo, const IntRect& borderRect)
{
    if (!paintInfo.rect.intersects(borderRect))
        return;
        
    // FIXME: We should do something clever when borders from distinct framesets meet at a join.
    
    // Fill first.
    GraphicsContext* context = paintInfo.context;
    ColorSpace colorSpace = style().colorSpace();
    context->fillRect(borderRect, frameSetElement().hasBorderColor() ? style().visitedDependentColor(CSSPropertyBorderLeftColor) : borderFillColor(), colorSpace);
    
    // Now stroke the edges but only if we have enough room to paint both edges with a little
    // bit of the fill color showing through.
    if (borderRect.width() >= 3) {
        context->fillRect(IntRect(borderRect.location(), IntSize(1, height())), borderStartEdgeColor(), colorSpace);
        context->fillRect(IntRect(IntPoint(borderRect.maxX() - 1, borderRect.y()), IntSize(1, height())), borderEndEdgeColor(), colorSpace);
    }
}
int RenderFrameSet::hitTestSplit(const GridAxis& axis, int position) const
{
    if (needsLayout())
        return noSplit;

    int borderThickness = frameSetElement().border();
    if (borderThickness <= 0)
        return noSplit;

    size_t size = axis.m_sizes.size();
    if (!size)
        return noSplit;

    int splitPosition = axis.m_sizes[0];
    for (size_t i = 1; i < size; ++i) {
        if (position >= splitPosition && position < splitPosition + borderThickness)
            return i;
        splitPosition += borderThickness + axis.m_sizes[i];
    }
    return noSplit;
}
void RenderFrameSet::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    if (paintInfo.phase != PaintPhaseForeground)
        return;
    
    RenderObject* child = firstChild();
    if (!child)
        return;

    LayoutPoint adjustedPaintOffset = paintOffset + location();

    size_t rows = m_rows.m_sizes.size();
    size_t cols = m_cols.m_sizes.size();
    LayoutUnit borderThickness = frameSetElement().border();
    
    LayoutUnit yPos = 0;
    for (size_t r = 0; r < rows; r++) {
        LayoutUnit xPos = 0;
        for (size_t c = 0; c < cols; c++) {
            toRenderElement(child)->paint(paintInfo, adjustedPaintOffset);
            xPos += m_cols.m_sizes[c];
            if (borderThickness && m_cols.m_allowBorder[c + 1]) {
                paintColumnBorder(paintInfo, pixelSnappedIntRect(LayoutRect(adjustedPaintOffset.x() + xPos, adjustedPaintOffset.y() + yPos, borderThickness, height())));
                xPos += borderThickness;
            }
            child = child->nextSibling();
            if (!child)
                return;
        }
        yPos += m_rows.m_sizes[r];
        if (borderThickness && m_rows.m_allowBorder[r + 1]) {
            paintRowBorder(paintInfo, pixelSnappedIntRect(LayoutRect(adjustedPaintOffset.x(), adjustedPaintOffset.y() + yPos, width(), borderThickness)));
            yPos += borderThickness;
        }
    }
}
void RenderFrameSet::positionFramesWithFlattening()
{
    RenderBox* child = firstChildBox();
    if (!child)
        return;

    int rows = frameSetElement().totalRows();
    int cols = frameSetElement().totalCols();

    int borderThickness = frameSetElement().border();
    bool repaintNeeded = false;

    // calculate frameset height based on actual content height to eliminate scrolling
    bool out = false;
    for (int r = 0; r < rows && !out; r++) {
        int extra = 0;
        int height = m_rows.m_sizes[r];

        for (int c = 0; c < cols; c++) {
            IntRect oldFrameRect = pixelSnappedIntRect(child->frameRect());

            int width = m_cols.m_sizes[c];

            bool fixedWidth = frameSetElement().colLengths() && frameSetElement().colLengths()[c].isFixed();
            bool fixedHeight = frameSetElement().rowLengths() && frameSetElement().rowLengths()[r].isFixed();

            // has to be resized and itself resize its contents
            if (!fixedWidth)
                child->setWidth(width ? width + extra / (cols - c) : 0);
            else
                child->setWidth(width);
            child->setHeight(height);

            child->setNeedsLayout();

            if (child->isFrameSet())
                toRenderFrameSet(child)->layout();
            else
                toRenderFrame(child)->layoutWithFlattening(fixedWidth, fixedHeight);

            if (child->height() > m_rows.m_sizes[r])
                m_rows.m_sizes[r] = child->height();
            if (child->width() > m_cols.m_sizes[c])
                m_cols.m_sizes[c] = child->width();

            if (child->frameRect() != oldFrameRect)
                repaintNeeded = true;

            // difference between calculated frame width and the width it actually decides to have
            extra += width - m_cols.m_sizes[c];

            child = child->nextSiblingBox();
            if (!child) {
                out = true;
                break;
            }
        }
    }

    int xPos = 0;
    int yPos = 0;
    out = false;
    child = firstChildBox();
    for (int r = 0; r < rows && !out; r++) {
        xPos = 0;
        for (int c = 0; c < cols; c++) {
            // ensure the rows and columns are filled
            IntRect oldRect = pixelSnappedIntRect(child->frameRect());

            child->setLocation(IntPoint(xPos, yPos));
            child->setHeight(m_rows.m_sizes[r]);
            child->setWidth(m_cols.m_sizes[c]);

            if (child->frameRect() != oldRect) {
                repaintNeeded = true;

                // update to final size
                child->setNeedsLayout();
                if (child->isFrameSet())
                    toRenderFrameSet(child)->layout();
                else
                    toRenderFrame(child)->layoutWithFlattening(true, true);
            }

            xPos += m_cols.m_sizes[c] + borderThickness;
            child = child->nextSiblingBox();
            if (!child) {
                out = true;
                break;
            }
        }
        yPos += m_rows.m_sizes[r] + borderThickness;
    }

    setWidth(xPos - borderThickness);
    setHeight(yPos - borderThickness);

    if (repaintNeeded)
        repaint();

    // all the remaining frames are hidden to avoid ugly spurious unflowed frames
    for (; child; child = child->nextSiblingBox()) {
        child->setWidth(0);
        child->setHeight(0);
        child->clearNeedsLayout();
    }
}