Beispiel #1
0
LayoutState::LayoutState(RenderBox& renderer, const LayoutSize& offset, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged, ColumnInfo* columnInfo, bool containingBlockLogicalWidthChanged)
    : m_containingBlockLogicalWidthChanged(containingBlockLogicalWidthChanged)
    , m_columnInfo(columnInfo)
    , m_next(renderer.view()->layoutState())
    , m_renderer(renderer)
{
    m_flowThread = renderer.isRenderFlowThread() ? toRenderFlowThread(&renderer) : m_next->flowThread();
    renderer.view()->pushLayoutState(*this);
    bool fixed = renderer.isOutOfFlowPositioned() && renderer.style()->position() == FixedPosition;
    if (fixed) {
        // FIXME: This doesn't work correctly with transforms.
        FloatPoint fixedOffset = renderer.view()->localToAbsolute(FloatPoint(), IsFixed);
        m_layoutOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()) + offset;
    } else {
        m_layoutOffset = m_next->m_layoutOffset + offset;
    }

    if (renderer.isOutOfFlowPositioned() && !fixed) {
        if (RenderObject* container = renderer.container()) {
            if (container->style()->hasInFlowPosition() && container->isRenderInline())
                m_layoutOffset += toRenderInline(container)->offsetForInFlowPositionedInline(renderer);
        }
    }
    // If we establish a new page height, then cache the offset to the top of the first page.
    // We can compare this later on to figure out what part of the page we're actually on,
    if (pageLogicalHeight || m_columnInfo || renderer.isRenderFlowThread()) {
        m_pageLogicalHeight = pageLogicalHeight;
        bool isFlipped = renderer.style()->isFlippedBlocksWritingMode();
        m_pageOffset = LayoutSize(m_layoutOffset.width() + (!isFlipped ? renderer.borderLeft() + renderer.paddingLeft() : renderer.borderRight() + renderer.paddingRight()),
            m_layoutOffset.height() + (!isFlipped ? renderer.borderTop() + renderer.paddingTop() : renderer.borderBottom() + renderer.paddingBottom()));
        m_pageLogicalHeightChanged = pageLogicalHeightChanged;
        m_isPaginated = true;
    } else {
        // If we don't establish a new page height, then propagate the old page height and offset down.
        m_pageLogicalHeight = m_next->m_pageLogicalHeight;
        m_pageLogicalHeightChanged = m_next->m_pageLogicalHeightChanged;
        m_pageOffset = m_next->m_pageOffset;

        // Disable pagination for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and
        // writing mode roots.
        if (renderer.isUnsplittableForPagination()) {
            m_pageLogicalHeight = 0;
            m_isPaginated = false;
        } else {
            m_isPaginated = m_pageLogicalHeight || m_next->m_columnInfo || renderer.flowThreadContainingBlock();
        }
    }

    if (!m_columnInfo)
        m_columnInfo = m_next->m_columnInfo;

    // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present.
}
static void adjustGridPositionsFromStyle(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction, GridPosition& initialPosition, GridPosition& finalPosition)
{
    bool isForColumns = direction == ForColumns;
    initialPosition = isForColumns ? gridItem.style().gridItemColumnStart() : gridItem.style().gridItemRowStart();
    finalPosition = isForColumns ? gridItem.style().gridItemColumnEnd() : gridItem.style().gridItemRowEnd();

    // We must handle the placement error handling code here instead of in the StyleAdjuster because we don't want to
    // overwrite the specified values.
    if (initialPosition.isSpan() && finalPosition.isSpan())
        finalPosition.setAutoPosition();

    if (gridItem.isOutOfFlowPositioned()) {
        // Early detect the case of non existing named grid lines for positioned items.
        if (initialPosition.isNamedGridArea() && !NamedLineCollection::isValidNamedLineOrArea(initialPosition.namedGridLine(), gridContainerStyle, initialPositionSide(direction)))
            initialPosition.setAutoPosition();

        if (finalPosition.isNamedGridArea() && !NamedLineCollection::isValidNamedLineOrArea(finalPosition.namedGridLine(), gridContainerStyle, finalPositionSide(direction)))
            finalPosition.setAutoPosition();
    }

    // If the grid item has an automatic position and a grid span for a named line in a given dimension, instead treat the grid span as one.
    if (initialPosition.isAuto() && finalPosition.isSpan() && !finalPosition.namedGridLine().isNull())
        finalPosition.setSpanPosition(1, String());
    if (finalPosition.isAuto() && initialPosition.isSpan() && !initialPosition.namedGridLine().isNull())
        initialPosition.setSpanPosition(1, String());
}
Beispiel #3
0
void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, SubtreeLayoutScope& layoutScope, LayoutUnit beforeEdge, LayoutUnit afterEdge)
{
    dirtyForLayoutFromPercentageHeightDescendants(layoutScope);

    RenderBox* next = firstChildBox();
    RenderBox* lastNormalFlowChild = 0;

    while (next) {
        RenderBox* child = next;
        next = child->nextSiblingBox();

        // FIXME: this should only be set from clearNeedsLayout crbug.com/361250
        child->setLayoutDidGetCalled(true);

        updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);

        if (child->isOutOfFlowPositioned()) {
            child->containingBlock()->insertPositionedObject(child);
            adjustPositionedBlock(child);
            continue;
        }

        // Lay out the child.
        layoutBlockChild(child);
        lastNormalFlowChild = child;
    }

    // Negative margins can cause our height to shrink below our minimal height (border/padding).
    // If this happens, ensure that the computed height is increased to the minimal height.
    setLogicalHeight(std::max(logicalHeight() + afterEdge, beforeEdge + afterEdge));
}
Beispiel #4
0
static void buildRendererHighlight(RenderObject* renderer, RenderRegion* region, const HighlightConfig& highlightConfig, Highlight* highlight, InspectorOverlay::CoordinateSystem coordinateSystem)
{
    Frame* containingFrame = renderer->document().frame();
    if (!containingFrame)
        return;

    highlight->setDataFromConfig(highlightConfig);
    FrameView* containingView = containingFrame->view();
    FrameView* mainView = containingFrame->page()->mainFrame().view();

    // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
    bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot();

    if (isSVGRenderer) {
        highlight->type = HighlightTypeRects;
        renderer->absoluteQuads(highlight->quads);
        for (size_t i = 0; i < highlight->quads.size(); ++i)
            contentsQuadToCoordinateSystem(mainView, containingView, highlight->quads[i], coordinateSystem);
    } else if (renderer->isBox() || renderer->isRenderInline()) {
        LayoutRect contentBox;
        LayoutRect paddingBox;
        LayoutRect borderBox;
        LayoutRect marginBox;

        if (renderer->isBox()) {
            RenderBox* renderBox = toRenderBox(renderer);

            LayoutBoxExtent margins(renderBox->marginTop(), renderBox->marginRight(), renderBox->marginBottom(), renderBox->marginLeft());

            if (!renderBox->isOutOfFlowPositioned() && region) {
                RenderBox::LogicalExtentComputedValues computedValues;
                renderBox->computeLogicalWidthInRegion(computedValues, region);
                margins.mutableLogicalLeft(renderBox->style().writingMode()) = computedValues.m_margins.m_start;
                margins.mutableLogicalRight(renderBox->style().writingMode()) = computedValues.m_margins.m_end;
            }

            paddingBox = renderBox->clientBoxRectInRegion(region);
            contentBox = LayoutRect(paddingBox.x() + renderBox->paddingLeft(), paddingBox.y() + renderBox->paddingTop(),
                paddingBox.width() - renderBox->paddingLeft() - renderBox->paddingRight(), paddingBox.height() - renderBox->paddingTop() - renderBox->paddingBottom());
            borderBox = LayoutRect(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
                paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
            marginBox = LayoutRect(borderBox.x() - margins.left(), borderBox.y() - margins.top(),
                borderBox.width() + margins.left() + margins.right(), borderBox.height() + margins.top() + margins.bottom());
        } else {
            RenderInline* renderInline = toRenderInline(renderer);

            // RenderInline's bounding box includes paddings and borders, excludes margins.
            borderBox = renderInline->linesBoundingBox();
            paddingBox = LayoutRect(borderBox.x() + renderInline->borderLeft(), borderBox.y() + renderInline->borderTop(),
                borderBox.width() - renderInline->borderLeft() - renderInline->borderRight(), borderBox.height() - renderInline->borderTop() - renderInline->borderBottom());
            contentBox = LayoutRect(paddingBox.x() + renderInline->paddingLeft(), paddingBox.y() + renderInline->paddingTop(),
                paddingBox.width() - renderInline->paddingLeft() - renderInline->paddingRight(), paddingBox.height() - renderInline->paddingTop() - renderInline->paddingBottom());
            // Ignore marginTop and marginBottom for inlines.
            marginBox = LayoutRect(borderBox.x() - renderInline->marginLeft(), borderBox.y(),
                borderBox.width() + renderInline->horizontalMarginExtent(), borderBox.height());
        }

        FloatQuad absContentQuad;
        FloatQuad absPaddingQuad;
        FloatQuad absBorderQuad;
        FloatQuad absMarginQuad;

        if (region) {
            RenderFlowThread* flowThread = region->flowThread();

            // Figure out the quads in the space of the RenderFlowThread.
            absContentQuad = renderer->localToContainerQuad(FloatRect(contentBox), flowThread);
            absPaddingQuad = renderer->localToContainerQuad(FloatRect(paddingBox), flowThread);
            absBorderQuad = renderer->localToContainerQuad(FloatRect(borderBox), flowThread);
            absMarginQuad = renderer->localToContainerQuad(FloatRect(marginBox), flowThread);

            // Move the quad relative to the space of the current region.
            LayoutRect flippedRegionRect(region->flowThreadPortionRect());
            flowThread->flipForWritingMode(flippedRegionRect);

            FloatSize delta = region->contentBoxRect().location() - flippedRegionRect.location();
            absContentQuad.move(delta);
            absPaddingQuad.move(delta);
            absBorderQuad.move(delta);
            absMarginQuad.move(delta);

            // Resolve the absolute quads starting from the current region.
            absContentQuad = region->localToAbsoluteQuad(absContentQuad);
            absPaddingQuad = region->localToAbsoluteQuad(absPaddingQuad);
            absBorderQuad = region->localToAbsoluteQuad(absBorderQuad);
            absMarginQuad = region->localToAbsoluteQuad(absMarginQuad);
        } else {
            absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox));
            absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox));
            absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox));
            absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox));
        }

        contentsQuadToCoordinateSystem(mainView, containingView, absContentQuad, coordinateSystem);
        contentsQuadToCoordinateSystem(mainView, containingView, absPaddingQuad, coordinateSystem);
        contentsQuadToCoordinateSystem(mainView, containingView, absBorderQuad, coordinateSystem);
        contentsQuadToCoordinateSystem(mainView, containingView, absMarginQuad, coordinateSystem);

        highlight->type = HighlightTypeNode;
        highlight->quads.append(absMarginQuad);
        highlight->quads.append(absBorderQuad);
        highlight->quads.append(absPaddingQuad);
        highlight->quads.append(absContentQuad);
    }
}
Beispiel #5
0
void RenderMathMLRow::layoutRowItems(LayoutUnit& ascent, LayoutUnit& descent)
{
    // We first stretch the vertical operators.
    // For inline formulas, we can then calculate the logical width.
    LayoutUnit width = borderAndPaddingStart();
    for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
        if (child->isOutOfFlowPositioned())
            continue;

        if (is<RenderMathMLBlock>(child)) {
            auto renderOperator = downcast<RenderMathMLBlock>(child)->unembellishedOperator();
            if (renderOperator && renderOperator->hasOperatorFlag(MathMLOperatorDictionary::Stretchy) && renderOperator->isVertical())
                renderOperator->stretchTo(ascent, descent);
        }

        child->layoutIfNeeded();

        width += child->marginStart() + child->logicalWidth() + child->marginEnd();
    }

    width += borderEnd() + paddingEnd();
    // FIXME: RenderMathMLRoot classes should also recalculate the exact logical width instead of using the preferred width.
    // See http://webkit.org/b/153987
    if ((!isRenderMathMLMath() || style().display() == INLINE) && !isRenderMathMLRoot())
        setLogicalWidth(width);

    LayoutUnit verticalOffset = borderTop() + paddingTop();
    LayoutUnit maxAscent = 0, maxDescent = 0; // Used baseline alignment.
    LayoutUnit horizontalOffset = borderAndPaddingStart();
    bool shouldFlipHorizontal = !style().isLeftToRightDirection();
    for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
        if (child->isOutOfFlowPositioned()) {
            child->containingBlock()->insertPositionedObject(*child);
            continue;
        }
        LayoutUnit childHorizontalExtent = child->logicalWidth();
        LayoutUnit ascent = ascentForChild(*child);
        LayoutUnit descent = child->verticalMarginExtent() + child->logicalHeight() - ascent;
        maxAscent = std::max(maxAscent, ascent);
        maxDescent = std::max(maxDescent, descent);
        LayoutUnit childVerticalMarginBoxExtent = maxAscent + maxDescent;

        horizontalOffset += child->marginStart();

        setLogicalHeight(std::max(logicalHeight(), verticalOffset + borderBottom() + paddingBottom() + childVerticalMarginBoxExtent + horizontalScrollbarHeight()));

        LayoutPoint childLocation(shouldFlipHorizontal ? logicalWidth() - horizontalOffset - childHorizontalExtent : horizontalOffset, verticalOffset + child->marginTop());
        child->setLocation(childLocation);

        horizontalOffset += childHorizontalExtent + child->marginEnd();
    }

    LayoutUnit centerBlockOffset = 0;
    // FIXME: Remove the FLEX when it is not required by the css.
    if (style().display() == BLOCK || style().display() == FLEX)
        centerBlockOffset = std::max<LayoutUnit>(0, (logicalWidth() - (horizontalOffset + borderEnd() + paddingEnd())) / 2);

    if (shouldFlipHorizontal && centerBlockOffset > 0)
        centerBlockOffset = -centerBlockOffset;

    for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
        LayoutUnit ascent = ascentForChild(*child);
        LayoutUnit startOffset = maxAscent - ascent;
        child->setLocation(child->location() + LayoutPoint(centerBlockOffset, startOffset));
    }

    ascent = maxAscent;
    descent = maxDescent;
}
Beispiel #6
0
static bool isDeletableElement(const Node* node)
{
    if (!node || !node->isHTMLElement() || !node->inDocument() || !node->rendererIsEditable())
        return false;

    // In general we want to only draw the UI around object of a certain area, but we still keep the min width/height to
    // make sure we don't end up with very thin or very short elements getting the UI.
    const int minimumArea = 2500;
    const int minimumWidth = 48;
    const int minimumHeight = 16;
    const unsigned minimumVisibleBorders = 1;

    RenderObject* renderer = node->renderer();
    if (!renderer || !renderer->isBox())
        return false;

    // Disallow the body element since it isn't practical to delete, and the deletion UI would be clipped.
    if (node->hasTagName(bodyTag))
        return false;

    // Disallow elements with any overflow clip, since the deletion UI would be clipped as well. <rdar://problem/6840161>
    if (renderer->hasOverflowClip())
        return false;

    // Disallow Mail blockquotes since the deletion UI would get in the way of editing for these.
    if (isMailBlockquote(node))
        return false;

    RenderBox* box = toRenderBox(renderer);
    IntRect borderBoundingBox = box->borderBoundingBox();
    if (borderBoundingBox.width() < minimumWidth || borderBoundingBox.height() < minimumHeight)
        return false;

    if ((borderBoundingBox.width() * borderBoundingBox.height()) < minimumArea)
        return false;

    if (box->isTable())
        return true;

    if (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(iframeTag))
        return true;

    if (box->isOutOfFlowPositioned())
        return true;

    if (box->isRenderBlock() && !box->isTableCell()) {
        const RenderStyle& style = box->style();

        // Allow blocks that have background images
        if (style.hasBackgroundImage()) {
            for (const FillLayer* background = style.backgroundLayers(); background; background = background->next()) {
                if (background->image() && background->image()->canRender(box, 1))
                    return true;
            }
        }

        // Allow blocks with a minimum number of non-transparent borders
        unsigned visibleBorders = style.borderTop().isVisible() + style.borderBottom().isVisible() + style.borderLeft().isVisible() + style.borderRight().isVisible();
        if (visibleBorders >= minimumVisibleBorders)
            return true;

        // Allow blocks that have a different background from it's parent
        ContainerNode* parentNode = node->parentNode();
        if (!parentNode)
            return false;

        RenderObject* parentRenderer = parentNode->renderer();
        if (!parentRenderer)
            return false;

        const RenderStyle& parentStyle = parentRenderer->style();

        if (box->hasBackground() && (!parentRenderer->hasBackground() || style.visitedDependentColor(CSSPropertyBackgroundColor) != parentStyle.visitedDependentColor(CSSPropertyBackgroundColor)))
            return true;
    }

    return false;
}