Beispiel #1
0
void RenderFlowThread::paintFlowThreadPortionInRegion(PaintInfo& paintInfo, RenderRegion* region, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const LayoutPoint& paintOffset) const
{
    GraphicsContext* context = paintInfo.context;
    if (!context)
        return;

    // Adjust the clipping rect for the region.
    // paintOffset contains the offset where the painting should occur
    // adjusted with the region padding and border.
    LayoutRect regionClippingRect = computeRegionClippingRect(paintOffset, flowThreadPortionRect, flowThreadPortionOverflowRect);

    PaintInfo info(paintInfo);
    info.rect.intersect(pixelSnappedIntRect(regionClippingRect));

    if (!info.rect.isEmpty()) {
        context->save();

        context->clip(regionClippingRect);

        // RenderFlowThread should start painting its content in a position that is offset
        // from the region rect's current position. The amount of offset is equal to the location of
        // the flow thread portion in the flow thread's local coordinates.
        IntPoint renderFlowThreadOffset;
        if (style()->isFlippedBlocksWritingMode()) {
            LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect);
            flipForWritingMode(flippedFlowThreadPortionRect);
            renderFlowThreadOffset = roundedIntPoint(paintOffset - flippedFlowThreadPortionRect.location());
        } else
            renderFlowThreadOffset = roundedIntPoint(paintOffset - flowThreadPortionRect.location());

        context->translate(renderFlowThreadOffset.x(), renderFlowThreadOffset.y());
        info.rect.moveBy(-renderFlowThreadOffset);
        
        layer()->paint(context, info.rect, 0, 0, region, RenderLayer::PaintLayerTemporaryClipRects);

        context->restore();
    }
}
Beispiel #2
0
static void mapCaretRectToCaretPainter(LayoutItem caretLayoutItem,
                                       LayoutBlockItem caretPainterItem,
                                       LayoutRect& caretRect) {
    // FIXME: This shouldn't be called on un-rooted subtrees.
    // FIXME: This should probably just use mapLocalToAncestor.
    // Compute an offset between the caretLayoutItem and the caretPainterItem.

    DCHECK(caretLayoutItem.isDescendantOf(caretPainterItem));

    bool unrooted = false;
    while (caretLayoutItem != caretPainterItem) {
        LayoutItem containerItem = caretLayoutItem.container();
        if (containerItem.isNull()) {
            unrooted = true;
            break;
        }
        caretRect.move(caretLayoutItem.offsetFromContainer(containerItem));
        caretLayoutItem = containerItem;
    }

    if (unrooted)
        caretRect = LayoutRect();
}
void RenderMultiColumnSet::repaintFlowThreadContent(const LayoutRect& repaintRect, bool immediate) const
{
    // Figure out the start and end columns and only check within that range so that we don't walk the
    // entire column set. Put the repaint rect into flow thread coordinates by flipping it first.
    LayoutRect flowThreadRepaintRect(repaintRect);
    flowThread()->flipForWritingMode(flowThreadRepaintRect);
    
    // Now we can compare this rect with the flow thread portions owned by each column. First let's
    // just see if the repaint rect intersects our flow thread portion at all.
    LayoutRect clippedRect(flowThreadRepaintRect);
    clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect());
    if (clippedRect.isEmpty())
        return;
    
    // Now we know we intersect at least one column. Let's figure out the logical top and logical
    // bottom of the area we're repainting.
    LayoutUnit repaintLogicalTop = isHorizontalWritingMode() ? flowThreadRepaintRect.y() : flowThreadRepaintRect.x();
    LayoutUnit repaintLogicalBottom = (isHorizontalWritingMode() ? flowThreadRepaintRect.maxY() : flowThreadRepaintRect.maxX()) - 1;
    
    unsigned startColumn = columnIndexAtOffset(repaintLogicalTop);
    unsigned endColumn = columnIndexAtOffset(repaintLogicalBottom);
    
    LayoutUnit colGap = columnGap();
    unsigned colCount = columnCount();
    for (unsigned i = startColumn; i <= endColumn; i++) {
        LayoutRect colRect = columnRectAt(i);
        
        // Get the portion of the flow thread that corresponds to this column.
        LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);
        
        // Now get the overflow rect that corresponds to the column.
        LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap);

        // Do a repaint for this specific column.
        repaintFlowThreadContentRectangle(repaintRect, immediate, flowThreadPortion, flowThreadOverflowPortion, colRect.location());
    }
}
void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    RenderTextControl::paint(paintInfo, paintOffset);

    if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) {
        LayoutRect contentsRect = contentBoxRect();

        // Center in the block progression direction.
        if (isHorizontalWritingMode())
            contentsRect.setY((height() - contentsRect.height()) / 2);
        else
            contentsRect.setX((width() - contentsRect.width()) / 2);

        // Convert the rect into the coords used for painting the content
        contentsRect.moveBy(paintOffset + location());
        theme().paintCapsLockIndicator(*this, paintInfo, snappedIntRect(contentsRect));
    }
}
Beispiel #5
0
static FloatRect localQuadForTextBox(const InlineTextBox& box, unsigned start, unsigned end, bool useSelectionHeight)
{
    unsigned realEnd = std::min(box.end() + 1, end);
    LayoutRect boxSelectionRect = box.localSelectionRect(start, realEnd);
    if (!boxSelectionRect.height())
        return FloatRect();
    if (useSelectionHeight)
        return boxSelectionRect;
    // Change the height and y position (or width and x for vertical text)
    // because selectionRect uses selection-specific values.
    if (box.isHorizontal()) {
        boxSelectionRect.setHeight(box.height());
        boxSelectionRect.setY(box.y());
    } else {
        boxSelectionRect.setWidth(box.width());
        boxSelectionRect.setX(box.x());
    }
    return boxSelectionRect;
}
LayoutRect RootFrameViewport::scrollIntoView(const LayoutRect& rectInContent, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
{
    // We want to move the rect into the viewport that excludes the scrollbars so we intersect
    // the visual viewport with the scrollbar-excluded frameView content rect. However, we don't
    // use visibleContentRect directly since it floors the scroll position. Instead, we use
    // FrameView::scrollPositionDouble and construct a LayoutRect from that (the FrameView size
    // is always integer sized.

    LayoutRect frameRectInContent = LayoutRect(
        layoutViewport().scrollPositionDouble(),
        layoutViewport().visibleContentRect().size());
    LayoutRect visualRectInContent = LayoutRect(
        layoutViewport().scrollPositionDouble() + toDoubleSize(visualViewport().scrollPositionDouble()),
        visualViewport().visibleContentRect().size());

    LayoutRect viewRectInContent = intersection(visualRectInContent, frameRectInContent);
    LayoutRect targetViewport =
        ScrollAlignment::getRectToExpose(viewRectInContent, rectInContent, alignX, alignY);

    // visualViewport.scrollIntoView will attempt to center the given rect within the viewport
    // so to prevent it from adjusting r's coordinates the rect must match the viewport's size
    // i.e. add the subtracted scrollbars from above back in.
    // FIXME: This is hacky and required because getRectToExpose doesn't naturally account
    // for the two viewports. crbug.com/449340.
    targetViewport.setSize(LayoutSize(visualViewport().visibleContentRect().size()));

    // Snap the visible rect to layout units to match the calculated target viewport rect.
    FloatRect visible =
        LayoutRect(visualViewport().scrollPositionDouble(), visualViewport().visibleContentRect().size());

    float centeringOffsetX = (visible.width() - targetViewport.width()) / 2;
    float centeringOffsetY = (visible.height() - targetViewport.height()) / 2;

    DoublePoint targetOffset(
        targetViewport.x() - centeringOffsetX,
        targetViewport.y() - centeringOffsetY);

    setScrollPosition(targetOffset, ProgrammaticScroll);

    // RootFrameViewport only changes the viewport relative to the document so we can't change the input
    // rect's location relative to the document origin.
    return rectInContent;
}
static void adjustBubblePosition(const LayoutRect& hostRect, HTMLElement* bubble)
{
    ASSERT(bubble);
    if (hostRect.isEmpty())
        return;
    double hostX = hostRect.x();
    double hostY = hostRect.y();
    if (RenderBox* container = bubble->renderer()->containingBlock()) {
        FloatPoint containerLocation = container->localToAbsolute();
        hostX -= containerLocation.x() + container->borderLeft();
        hostY -= containerLocation.y() + container->borderTop();
    }
    bubble->getInlineStyleDecl()->setProperty(CSSPropertyTop, hostY + hostRect.height(), CSSPrimitiveValue::CSS_PX);
    // The 'left' value of ::-webkit-validation-bubble-arrow.
    const int bubbleArrowTopOffset = 32;
    double bubbleX = hostX;
    if (hostRect.width() / 2 < bubbleArrowTopOffset)
        bubbleX = max(hostX + hostRect.width() / 2 - bubbleArrowTopOffset, 0.0);
    bubble->getInlineStyleDecl()->setProperty(CSSPropertyLeft, bubbleX, CSSPrimitiveValue::CSS_PX);
}
void RenderVideo::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    MediaPlayer* mediaPlayer = videoElement().player();
    bool displayingPoster = videoElement().shouldDisplayPosterImage();

    Page* page = frame().page();

    if (!displayingPoster && !mediaPlayer) {
        if (page && paintInfo.phase == PaintPhaseForeground)
            page->addRelevantUnpaintedObject(this, visualOverflowRect());
        return;
    }

    LayoutRect rect = videoBox();
    if (rect.isEmpty()) {
        if (page && paintInfo.phase == PaintPhaseForeground)
            page->addRelevantUnpaintedObject(this, visualOverflowRect());
        return;
    }
    rect.moveBy(paintOffset);

    if (page && paintInfo.phase == PaintPhaseForeground)
        page->addRelevantRepaintedObject(this, rect);

    LayoutRect contentRect = contentBoxRect();
    contentRect.moveBy(paintOffset);
    GraphicsContext& context = paintInfo.context();
    bool clip = !contentRect.contains(rect);
    GraphicsContextStateSaver stateSaver(context, clip);
    if (clip)
        context.clip(contentRect);

    if (displayingPoster)
        paintIntoRect(context, rect);
    else if (!videoElement().isFullscreen() || !mediaPlayer->supportsAcceleratedRendering()) {
        if (view().frameView().paintBehavior() & PaintBehaviorFlattenCompositingLayers)
            mediaPlayer->paintCurrentFrameInContext(context, rect);
        else
            mediaPlayer->paint(context, rect);
    }
}
void BlockFlowPainter::paintSelection(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    ASSERT(paintInfo.phase == PaintPhaseForeground);
    if (!m_layoutBlockFlow.shouldPaintSelectionGaps())
        return;

    LayoutUnit lastTop = 0;
    LayoutUnit lastLeft = m_layoutBlockFlow.logicalLeftSelectionOffset(&m_layoutBlockFlow, lastTop);
    LayoutUnit lastRight = m_layoutBlockFlow.logicalRightSelectionOffset(&m_layoutBlockFlow, lastTop);

    LayoutRect bounds = m_layoutBlockFlow.visualOverflowRect();
    bounds.moveBy(paintOffset);

    // Only create a DrawingRecorder and ClipScope if skipRecording is false. This logic is needed
    // because selectionGaps(...) needs to be called even when we do not record.
    bool skipRecording = LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutBlockFlow, DisplayItem::SelectionGap, paintOffset);
    Optional<LayoutObjectDrawingRecorder> drawingRecorder;
    Optional<ClipScope> clipScope;
    if (!skipRecording) {
        drawingRecorder.emplace(paintInfo.context, m_layoutBlockFlow, DisplayItem::SelectionGap, FloatRect(bounds), paintOffset);
        clipScope.emplace(paintInfo.context);
    }

    LayoutRect gapRectsBounds = m_layoutBlockFlow.selectionGaps(&m_layoutBlockFlow, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight,
        skipRecording ? nullptr : &paintInfo,
        skipRecording ? nullptr : &(*clipScope));
    // TODO(wkorman): Rework below to process paint invalidation rects during layout rather than paint.
    if (!gapRectsBounds.isEmpty()) {
        PaintLayer* layer = m_layoutBlockFlow.enclosingLayer();
        gapRectsBounds.moveBy(-paintOffset);
        if (!m_layoutBlockFlow.hasLayer()) {
            LayoutRect localBounds(gapRectsBounds);
            m_layoutBlockFlow.flipForWritingMode(localBounds);
            gapRectsBounds = LayoutRect(m_layoutBlockFlow.localToAncestorQuad(FloatRect(localBounds), layer->layoutObject()).enclosingBoundingBox());
            if (layer->layoutObject()->hasOverflowClip())
                gapRectsBounds.move(layer->layoutBox()->scrolledContentOffset());
        }
        layer->addBlockSelectionGapsBounds(gapRectsBounds);
    }
}
Beispiel #10
0
LayoutRect InlineTextBox::localSelectionRect(int startPos, int endPos)
{
    int sPos = max(startPos - m_start, 0);
    int ePos = min(endPos - m_start, (int)m_len);

    if (sPos > ePos)
        return LayoutRect();

    FontCachePurgePreventer fontCachePurgePreventer;

    LayoutUnit selTop = selectionTop();
    LayoutUnit selHeight = selectionHeight();
    RenderStyle* styleToUse = textRenderer().style(isFirstLineStyle());
    const Font& font = styleToUse->font();

    StringBuilder charactersWithHyphen;
    bool respectHyphen = ePos == m_len && hasHyphen();
    TextRun textRun = constructTextRun(styleToUse, font, respectHyphen ? &charactersWithHyphen : 0);

    FloatPoint startingPoint = FloatPoint(logicalLeft(), selTop.toFloat());
    LayoutRect r;
    if (sPos || ePos != static_cast<int>(m_len))
        r = enclosingIntRect(font.selectionRectForText(textRun, startingPoint, selHeight, sPos, ePos));
    else // Avoid computing the font width when the entire line box is selected as an optimization.
        r = enclosingIntRect(FloatRect(startingPoint, FloatSize(m_logicalWidth, selHeight.toFloat())));

    LayoutUnit logicalWidth = r.width();
    if (r.x() > logicalRight())
        logicalWidth  = 0;
    else if (r.maxX() > logicalRight())
        logicalWidth = logicalRight() - r.x();

    LayoutPoint topPoint = isHorizontal() ? LayoutPoint(r.x(), selTop) : LayoutPoint(selTop, r.x());
    LayoutUnit width = isHorizontal() ? logicalWidth : selHeight;
    LayoutUnit height = isHorizontal() ? selHeight : logicalWidth;

    return LayoutRect(topPoint, LayoutSize(width, height));
}
void LayoutTextControlSingleLine::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const
{
    LayoutTextControl::paint(paintInfo, paintOffset);

    if (shouldPaintSelfBlockBackground(paintInfo.phase) && m_shouldDrawCapsLockIndicator) {
        if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, *this, paintInfo.phase, paintOffset))
            return;

        LayoutRect contentsRect = contentBoxRect();

        // Center in the block progression direction.
        if (isHorizontalWritingMode())
            contentsRect.setY((size().height() - contentsRect.height()) / 2);
        else
            contentsRect.setX((size().width() - contentsRect.width()) / 2);

        // Convert the rect into the coords used for painting the content
        contentsRect.moveBy(paintOffset + location());
        IntRect snappedRect = pixelSnappedIntRect(contentsRect);
        LayoutObjectDrawingRecorder recorder(paintInfo.context, *this, paintInfo.phase, snappedRect, paintOffset);
        LayoutTheme::theme().painter().paintCapsLockIndicator(*this, paintInfo, snappedRect);
    }
}
Beispiel #12
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 #13
0
static PassRefPtr<InspectorObject> buildObjectForRegionHighlight(FrameView* mainView, RenderRegion* region)
{
    FrameView* containingView = region->frame().view();
    if (!containingView)
        return nullptr;

    RenderBlockFlow* regionContainer = toRenderBlockFlow(region->parent());
    LayoutRect borderBox = regionContainer->borderBoxRect();
    borderBox.setWidth(borderBox.width() + regionContainer->verticalScrollbarWidth());
    borderBox.setHeight(borderBox.height() + regionContainer->horizontalScrollbarHeight());

    // Create incoming and outgoing boxes that we use to chain the regions toghether.
    const LayoutSize linkBoxSize(10, 10);
    const LayoutSize linkBoxMidpoint(linkBoxSize.width() / 2, linkBoxSize.height() / 2);
    
    LayoutRect incomingRectBox = LayoutRect(borderBox.location() - linkBoxMidpoint, linkBoxSize);
    LayoutRect outgoingRectBox = LayoutRect(borderBox.location() - linkBoxMidpoint + borderBox.size(), linkBoxSize);

    // Move the link boxes slightly inside the region border box.
    LayoutUnit maxUsableHeight = std::max(LayoutUnit(), borderBox.height() - linkBoxMidpoint.height());
    LayoutUnit linkBoxVerticalOffset = std::min(LayoutUnit::fromPixel(15), maxUsableHeight);
    incomingRectBox.move(0, linkBoxVerticalOffset);
    outgoingRectBox.move(0, -linkBoxVerticalOffset);

    FloatQuad borderRectQuad = regionContainer->localToAbsoluteQuad(FloatRect(borderBox));
    FloatQuad incomingRectQuad = regionContainer->localToAbsoluteQuad(FloatRect(incomingRectBox));
    FloatQuad outgoingRectQuad = regionContainer->localToAbsoluteQuad(FloatRect(outgoingRectBox));

    contentsQuadToPage(mainView, containingView, borderRectQuad);
    contentsQuadToPage(mainView, containingView, incomingRectQuad);
    contentsQuadToPage(mainView, containingView, outgoingRectQuad);

    RefPtr<InspectorObject> regionObject = InspectorObject::create();

    regionObject->setArray("borderQuad", buildArrayForQuad(borderRectQuad));
    regionObject->setArray("incomingQuad", buildArrayForQuad(incomingRectQuad));
    regionObject->setArray("outgoingQuad", buildArrayForQuad(outgoingRectQuad));

    return regionObject.release();
}
LayoutRect LayoutMultiColumnSet::overflowRectForFlowThreadPortion(const LayoutRect& flowThreadPortionRect, bool isFirstPortion, bool isLastPortion) const
{
    if (hasOverflowClip())
        return flowThreadPortionRect;

    LayoutRect flowThreadOverflow = m_flowThread->visualOverflowRect();

    // Only clip along the flow thread axis.
    LayoutRect clipRect;
    if (m_flowThread->isHorizontalWritingMode()) {
        LayoutUnit minY = isFirstPortion ? flowThreadOverflow.y() : flowThreadPortionRect.y();
        LayoutUnit maxY = isLastPortion ? std::max(flowThreadPortionRect.maxY(), flowThreadOverflow.maxY()) : flowThreadPortionRect.maxY();
        LayoutUnit minX = std::min(flowThreadPortionRect.x(), flowThreadOverflow.x());
        LayoutUnit maxX = std::max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX());
        clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY);
    } else {
        LayoutUnit minX = isFirstPortion ? flowThreadOverflow.x() : flowThreadPortionRect.x();
        LayoutUnit maxX = isLastPortion ? std::max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX()) : flowThreadPortionRect.maxX();
        LayoutUnit minY = std::min(flowThreadPortionRect.y(), (flowThreadOverflow.y()));
        LayoutUnit maxY = std::max(flowThreadPortionRect.y(), (flowThreadOverflow.maxY()));
        clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY);
    }

    return clipRect;
}
Beispiel #15
0
LayoutRect RenderReplaced::replacedContentRect(const LayoutSize& intrinsicSize) const
{
    LayoutRect contentRect = contentBoxRect();
    ObjectFit objectFit = style().objectFit();
    if (objectFit == ObjectFitFill)
        return contentRect;

    if (!intrinsicSize.width() || !intrinsicSize.height())
        return contentRect;

    LayoutRect finalRect = contentRect;
    switch (objectFit) {
    case ObjectFitContain:
    case ObjectFitScaleDown:
    case ObjectFitCover:
        finalRect.setSize(finalRect.size().fitToAspectRatio(intrinsicSize, objectFit == ObjectFitCover ? AspectRatioFitGrow : AspectRatioFitShrink));
        if (objectFit != ObjectFitScaleDown || finalRect.width() <= intrinsicSize.width())
            break;
        // fall through
    case ObjectFitNone:
        finalRect.setSize(intrinsicSize);
        break;
    case ObjectFitFill:
        ASSERT_NOT_REACHED();
    }

    // FIXME: This is where object-position should be taken into account, but since it's not
    // implemented yet, assume the initial value of "50% 50%".
    LayoutUnit xOffset = (contentRect.width() - finalRect.width()) / 2;
    LayoutUnit yOffset = (contentRect.height() - finalRect.height()) / 2;
    finalRect.move(xOffset, yOffset);

    return finalRect;
}
Beispiel #16
0
IntRect::IntRect(const LayoutRect& r)
    : m_location(r.x(), r.y())
    , m_size(r.width(), r.height())
{
}
void IntersectionObserver::applyRootMargin(LayoutRect& rect) const
{
    // TODO(szager): Make sure the spec is clear that left/right margins are resolved against
    // width and not height.
    LayoutUnit topMargin = computeMargin(m_topMargin, rect.height());
    LayoutUnit rightMargin = computeMargin(m_rightMargin, rect.width());
    LayoutUnit bottomMargin = computeMargin(m_bottomMargin, rect.height());
    LayoutUnit leftMargin = computeMargin(m_leftMargin, rect.width());

    rect.setX(rect.x() - leftMargin);
    rect.setWidth(rect.width() + leftMargin + rightMargin);
    rect.setY(rect.y() - topMargin);
    rect.setHeight(rect.height() + topMargin + bottomMargin);
}
LayoutRect RenderNamedFlowFragment::flowThreadPortionRectForClipping(bool isFirstRegionInRange, bool isLastRegionInRange) const
{
    // Elements flowed into a region should not be painted past the region's content box
    // if they continue to flow into another region in that direction.
    // If they do not continue into another region in that direction, they should be
    // painted all the way to the region's border box.
    // Regions with overflow:hidden will apply clip at the border box, not the content box.
    
    LayoutRect clippingRect = flowThreadPortionRect();
    RenderBlockFlow& container = fragmentContainer();
    if (container.style().hasPadding()) {
        if (isFirstRegionInRange) {
            if (flowThread()->isHorizontalWritingMode()) {
                clippingRect.move(0, -container.paddingBefore());
                clippingRect.expand(0, container.paddingBefore());
            } else {
                clippingRect.move(-container.paddingBefore(), 0);
                clippingRect.expand(container.paddingBefore(), 0);
            }
        }
        
        if (isLastRegionInRange) {
            if (flowThread()->isHorizontalWritingMode())
                clippingRect.expand(0, container.paddingAfter());
            else
                clippingRect.expand(container.paddingAfter(), 0);
        }
        
        if (flowThread()->isHorizontalWritingMode()) {
            clippingRect.move(-container.paddingStart(), 0);
            clippingRect.expand(container.paddingStart() + container.paddingEnd(), 0);
        } else {
            clippingRect.move(0, -container.paddingStart());
            clippingRect.expand(0, container.paddingStart() + container.paddingEnd());
        }
    }
    
    return clippingRect;
}
Beispiel #19
0
void RenderListItem::positionListMarker()
{
    if (m_marker && m_marker->parent()->isBox() && !m_marker->isInside() && m_marker->inlineBoxWrapper()) {
        LayoutUnit markerOldLogicalLeft = m_marker->logicalLeft();
        LayoutUnit blockOffset = 0;
        LayoutUnit lineOffset = 0;
        for (RenderBox* o = m_marker->parentBox(); o != this; o = o->parentBox()) {
            blockOffset += o->logicalTop();
            lineOffset += o->logicalLeft();
        }

        bool adjustOverflow = false;
        LayoutUnit markerLogicalLeft;
        RootInlineBox& root = m_marker->inlineBoxWrapper()->root();
        bool hitSelfPaintingLayer = false;

        LayoutUnit lineTop = root.lineTop();
        LayoutUnit lineBottom = root.lineBottom();

        // FIXME: Need to account for relative positioning in the layout overflow.
        if (style()->isLeftToRightDirection()) {
            LayoutUnit leftLineOffset = logicalLeftOffsetForLine(blockOffset, logicalLeftOffsetForLine(blockOffset, false), false);
            markerLogicalLeft = leftLineOffset - lineOffset - paddingStart() - borderStart() + m_marker->marginStart();
            m_marker->inlineBoxWrapper()->adjustLineDirectionPosition((markerLogicalLeft - markerOldLogicalLeft).toFloat());
            for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) {
                LayoutRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(lineTop, lineBottom);
                LayoutRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(lineTop, lineBottom);
                if (markerLogicalLeft < newLogicalVisualOverflowRect.x() && !hitSelfPaintingLayer) {
                    newLogicalVisualOverflowRect.setWidth(newLogicalVisualOverflowRect.maxX() - markerLogicalLeft);
                    newLogicalVisualOverflowRect.setX(markerLogicalLeft);
                    if (box == root)
                        adjustOverflow = true;
                }
                if (markerLogicalLeft < newLogicalLayoutOverflowRect.x()) {
                    newLogicalLayoutOverflowRect.setWidth(newLogicalLayoutOverflowRect.maxX() - markerLogicalLeft);
                    newLogicalLayoutOverflowRect.setX(markerLogicalLeft);
                    if (box == root)
                        adjustOverflow = true;
                }
                box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect, lineTop, lineBottom);
                if (box->boxModelObject()->hasSelfPaintingLayer())
                    hitSelfPaintingLayer = true;
            }
        } else {
            LayoutUnit rightLineOffset = logicalRightOffsetForLine(blockOffset, logicalRightOffsetForLine(blockOffset, false), false);
            markerLogicalLeft = rightLineOffset - lineOffset + paddingStart() + borderStart() + m_marker->marginEnd();
            m_marker->inlineBoxWrapper()->adjustLineDirectionPosition((markerLogicalLeft - markerOldLogicalLeft).toFloat());
            for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) {
                LayoutRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(lineTop, lineBottom);
                LayoutRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(lineTop, lineBottom);
                if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalVisualOverflowRect.maxX() && !hitSelfPaintingLayer) {
                    newLogicalVisualOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - newLogicalVisualOverflowRect.x());
                    if (box == root)
                        adjustOverflow = true;
                }
                if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalLayoutOverflowRect.maxX()) {
                    newLogicalLayoutOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - newLogicalLayoutOverflowRect.x());
                    if (box == root)
                        adjustOverflow = true;
                }
                box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect, lineTop, lineBottom);

                if (box->boxModelObject()->hasSelfPaintingLayer())
                    hitSelfPaintingLayer = true;
            }
        }

        if (adjustOverflow) {
            LayoutRect markerRect(LayoutPoint(markerLogicalLeft + lineOffset, blockOffset), m_marker->size());
            if (!style()->isHorizontalWritingMode())
                markerRect = markerRect.transposedRect();
            RenderBox* o = m_marker;
            bool propagateVisualOverflow = true;
            bool propagateLayoutOverflow = true;
            do {
                o = o->parentBox();
                if (o->isRenderBlock()) {
                    if (propagateVisualOverflow)
                        toRenderBlock(o)->addContentsVisualOverflow(markerRect);
                    if (propagateLayoutOverflow)
                        toRenderBlock(o)->addLayoutOverflow(markerRect);
                }
                if (o->hasOverflowClip()) {
                    propagateLayoutOverflow = false;
                    propagateVisualOverflow = false;
                }
                if (o->hasSelfPaintingLayer())
                    propagateVisualOverflow = false;
                markerRect.moveBy(-o->location());
            } while (o != this && propagateVisualOverflow && propagateLayoutOverflow);
        }
    }
}
Beispiel #20
0
// Widgets are always placed on integer boundaries, so rounding the size is actually
// the desired behavior. This function is here because it's otherwise seldom what we
// want to do with a LayoutRect.
static inline IntRect roundedIntRect(const LayoutRect& rect)
{
    return IntRect(roundedIntPoint(rect.location()), roundedIntSize(rect.size()));
}
Beispiel #21
0
TEST_F(VisualRectMappingTest, ContainerFlippedWritingModeAndOverflowScroll) {
  setBodyInnerHTML(
      "<div id='container' style='writing-mode: vertical-rl; position: "
      "absolute; top: 111px; left: 222px;"
      "    border: solid red; border-width: 10px 20px 30px 40px;"
      "    overflow: scroll; width: 50px; height: 80px'>"
      "    <div id='target' style='box-shadow: 40px 20px black; width: 100px; "
      "height: 90px'></div>"
      "    <div style='width: 100px; height: 100px'></div>"
      "</div>");

  LayoutBlock* container =
      toLayoutBlock(getLayoutObjectByElementId("container"));
  EXPECT_EQ(LayoutUnit(), container->scrollTop());
  // The initial scroll offset is to the left-most because of flipped blocks
  // writing mode.
  // 150 = total_layout_overflow(100 + 100) - width(50)
  EXPECT_EQ(LayoutUnit(150), container->scrollLeft());
  container->setScrollTop(LayoutUnit(7));
  container->setScrollLeft(
      LayoutUnit(142));  // Scroll to the right by 8 pixels.
  document().view()->updateAllLifecyclePhases();

  LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target"));
  LayoutRect targetVisualRect = target->localVisualRect();
  // -40 = -box_shadow_offset_x(40) (with target's top-right corner as the
  // origin)
  // 140 = width(100) + box_shadow_offset_x(40)
  // 110 = height(90) + box_shadow_offset_y(20)
  EXPECT_EQ(LayoutRect(-40, 0, 140, 110), targetVisualRect);

  LayoutRect rect = targetVisualRect;
  target->flipForWritingMode(rect);
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect));
  // This rect is in physical coordinates of target.
  EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect);

  rect = targetVisualRect;
  target->flipForWritingMode(rect);
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect));
  rect.move(-container->scrolledContentOffset());
  // -2 = target_physical_x(100) + container_border_left(40) - scroll_left(142)
  // 3 = target_y(0) + container_border_top(10) - scroll_top(7)
  // Rect is clipped by container's overflow clip because of overflow:scroll.
  EXPECT_EQ(LayoutRect(-2, 3, 140, 110), rect);

  rect = targetVisualRect;
  target->flipForWritingMode(rect);
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect));
  // (-2, 3, 140, 100) is first clipped by container's overflow clip, to
  // (40, 10, 50, 80), then is added by container's offset in LayoutView
  // (111, 222).
  // TODO(crbug.com/600039): rect.x() should be 262 (left + border-left), but is
  // offset
  // by extra horizontal border-widths because of layout error.
  EXPECT_EQ(LayoutRect(322, 121, 50, 80), rect);
  checkPaintInvalidationStateRectMapping(rect, targetVisualRect, *target,
                                         layoutView(), layoutView());

  LayoutRect containerVisualRect = container->localVisualRect();
  // Because container has overflow clip, its visual overflow doesn't include
  // overflow from children.
  // 110 = width(50) + border_left_width(40) + border_right_width(20)
  // 120 = height(80) + border_top_width(10) + border_bottom_width(30)
  EXPECT_EQ(LayoutRect(0, 0, 110, 120), containerVisualRect);

  rect = containerVisualRect;
  container->flipForWritingMode(rect);
  EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(container, rect));
  EXPECT_EQ(LayoutRect(0, 0, 110, 120), rect);

  rect = containerVisualRect;
  container->flipForWritingMode(rect);
  EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(&layoutView(), rect));
  // TODO(crbug.com/600039): rect.x() should be 222 (left), but is offset by
  // extra horizontal
  // border-widths because of layout error.
  EXPECT_EQ(LayoutRect(282, 111, 110, 120), rect);
  checkPaintInvalidationStateRectMapping(rect, containerVisualRect, *container,
                                         layoutView(), layoutView());
}
Beispiel #22
0
TEST_F(VisualRectMappingTest, ContainerOverflowScroll) {
  setBodyInnerHTML(
      "<div id='container' style='position: absolute; top: 111px; left: 222px;"
      "    border: 10px solid red; overflow: scroll; width: 50px; height: "
      "80px;'>"
      "    <div id='target' style='box-shadow: 40px 20px black; width: 100px; "
      "height: 90px'></div>"
      "</div>");

  LayoutBlock* container =
      toLayoutBlock(getLayoutObjectByElementId("container"));
  EXPECT_EQ(LayoutUnit(), container->scrollTop());
  EXPECT_EQ(LayoutUnit(), container->scrollLeft());
  container->setScrollTop(LayoutUnit(7));
  container->setScrollLeft(LayoutUnit(8));
  document().view()->updateAllLifecyclePhases();

  LayoutBlock* target = toLayoutBlock(getLayoutObjectByElementId("target"));
  LayoutRect targetVisualRect = target->localVisualRect();
  // 140 = width(100) + box_shadow_offset_x(40)
  // 110 = height(90) + box_shadow_offset_y(20)
  EXPECT_EQ(LayoutRect(0, 0, 140, 110), targetVisualRect);
  LayoutRect rect = targetVisualRect;
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(target, rect));
  EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect);

  rect = targetVisualRect;
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(container, rect));
  rect.move(-container->scrolledContentOffset());
  // 2 = target_x(0) + container_border_left(10) - scroll_left(8)
  // 3 = target_y(0) + container_border_top(10) - scroll_top(7)
  // Rect is not clipped by container's overflow clip because of
  // overflow:scroll.
  EXPECT_EQ(LayoutRect(2, 3, 140, 110), rect);

  rect = targetVisualRect;
  EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect));
  // (2, 3, 140, 100) is first clipped by container's overflow clip, to
  // (10, 10, 50, 80), then is by added container's offset in LayoutView
  // (111, 222).
  EXPECT_EQ(LayoutRect(232, 121, 50, 80), rect);
  checkPaintInvalidationStateRectMapping(rect, targetVisualRect, *target,
                                         layoutView(), layoutView());

  LayoutRect containerVisualRect = container->localVisualRect();
  // Because container has overflow clip, its visual overflow doesn't include
  // overflow from children.
  // 70 = width(50) + border_left_width(10) + border_right_width(10)
  // 100 = height(80) + border_top_width(10) + border_bottom_width(10)
  EXPECT_EQ(LayoutRect(0, 0, 70, 100), containerVisualRect);
  rect = containerVisualRect;
  EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(container, rect));
  // Container should not apply overflow clip on its own overflow rect.
  EXPECT_EQ(LayoutRect(0, 0, 70, 100), rect);

  rect = containerVisualRect;
  EXPECT_TRUE(container->mapToVisualRectInAncestorSpace(&layoutView(), rect));
  EXPECT_EQ(LayoutRect(222, 111, 70, 100), rect);
  checkPaintInvalidationStateRectMapping(rect, containerVisualRect, *container,
                                         layoutView(), layoutView());
}
IntPoint AccessibilityObject::clickPoint()
{
    LayoutRect rect = elementRect();
    return roundedIntPoint(LayoutPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2));
}
Beispiel #24
0
LayoutRect LayoutTextControlSingleLine::controlClipRect(
    const LayoutPoint& additionalOffset) const {
  LayoutRect clipRect = paddingBoxRect();
  clipRect.moveBy(additionalOffset);
  return clipRect;
}
Beispiel #25
0
void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    if (!shouldPaint(paintInfo, paintOffset))
        return;

#ifndef NDEBUG
    SetLayoutNeededForbiddenScope scope(this);
#endif
    LayoutPoint adjustedPaintOffset = paintOffset + location();
    
    if (hasVisibleBoxDecorations() && paintInfo.phase == PaintPhaseForeground)
        paintBoxDecorations(paintInfo, adjustedPaintOffset);
    
    if (paintInfo.phase == PaintPhaseMask) {
        paintMask(paintInfo, adjustedPaintOffset);
        return;
    }

    LayoutRect paintRect = LayoutRect(adjustedPaintOffset, size());
    if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style().outlineWidth())
        paintOutline(paintInfo, paintRect);
    
    if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && !canHaveChildren())
        return;
    
    if (!paintInfo.shouldPaintWithinRoot(*this))
        return;
    
    bool drawSelectionTint = shouldDrawSelectionTint();
    if (paintInfo.phase == PaintPhaseSelection) {
        if (selectionState() == SelectionNone)
            return;
        drawSelectionTint = false;
    }

    bool completelyClippedOut = false;
    if (style().hasBorderRadius()) {
        LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size());

        if (borderRect.isEmpty())
            completelyClippedOut = true;
        else {
            // Push a clip if we have a border radius, since we want to round the foreground content that gets painted.
            paintInfo.context().save();
            FloatRoundedRect roundedInnerRect = FloatRoundedRect(style().getRoundedInnerBorderFor(paintRect,
                paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), true, true));
            clipRoundedInnerRect(paintInfo.context(), paintRect, roundedInnerRect);
        }
    }

    if (!completelyClippedOut) {
        paintReplaced(paintInfo, adjustedPaintOffset);

        if (style().hasBorderRadius())
            paintInfo.context().restore();
    }
        
    // The selection tint never gets clipped by border-radius rounding, since we want it to run right up to the edges of
    // surrounding content.
    if (drawSelectionTint) {
        LayoutRect selectionPaintingRect = localSelectionRect();
        selectionPaintingRect.moveBy(adjustedPaintOffset);
        paintInfo.context().fillRect(snappedIntRect(selectionPaintingRect), selectionBackgroundColor());
    }
}
LayoutUnit RenderRegion::logicalBottomOfFlowThreadContentRect(const LayoutRect& rect) const
{
    ASSERT(isValid());
    return flowThread()->isHorizontalWritingMode() ? rect.maxY() : rect.maxX();
}
void ImagePainter::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    LayoutUnit cWidth = m_renderImage.contentWidth();
    LayoutUnit cHeight = m_renderImage.contentHeight();

    GraphicsContext* context = paintInfo.context;

    if (!m_renderImage.imageResource()->hasImage() || m_renderImage.imageResource()->errorOccurred()) {
        if (paintInfo.phase == PaintPhaseSelection)
            return;

        if (cWidth > 2 && cHeight > 2) {
            const int borderWidth = 1;

            LayoutUnit leftBorder = m_renderImage.borderLeft();
            LayoutUnit topBorder = m_renderImage.borderTop();
            LayoutUnit leftPad = m_renderImage.paddingLeft();
            LayoutUnit topPad = m_renderImage.paddingTop();

            // Draw an outline rect where the image should be.
            IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset.x() + leftBorder + leftPad, paintOffset.y() + topBorder + topPad, cWidth, cHeight));
            DrawingRecorder recorder(context, &m_renderImage, paintInfo.phase, paintRect);
            context->setStrokeStyle(SolidStroke);
            context->setStrokeColor(Color::lightGray);
            context->setFillColor(Color::transparent);
            context->drawRect(paintRect);

            bool errorPictureDrawn = false;
            LayoutSize imageOffset;
            // When calculating the usable dimensions, exclude the pixels of
            // the ouline rect so the error image/alt text doesn't draw on it.
            LayoutUnit usableWidth = cWidth - 2 * borderWidth;
            LayoutUnit usableHeight = cHeight - 2 * borderWidth;

            RefPtr<Image> image = m_renderImage.imageResource()->image();

            if (m_renderImage.imageResource()->errorOccurred() && !image->isNull() && usableWidth >= image->width() && usableHeight >= image->height()) {
                float deviceScaleFactor = blink::deviceScaleFactor(m_renderImage.frame());
                // Call brokenImage() explicitly to ensure we get the broken image icon at the appropriate resolution.
                pair<Image*, float> brokenImageAndImageScaleFactor = ImageResource::brokenImage(deviceScaleFactor);
                image = brokenImageAndImageScaleFactor.first;
                IntSize imageSize = image->size();
                imageSize.scale(1 / brokenImageAndImageScaleFactor.second);
                // Center the error image, accounting for border and padding.
                LayoutUnit centerX = (usableWidth - imageSize.width()) / 2;
                if (centerX < 0)
                    centerX = 0;
                LayoutUnit centerY = (usableHeight - imageSize.height()) / 2;
                if (centerY < 0)
                    centerY = 0;
                imageOffset = LayoutSize(leftBorder + leftPad + centerX + borderWidth, topBorder + topPad + centerY + borderWidth);
                context->drawImage(image.get(), pixelSnappedIntRect(LayoutRect(paintOffset + imageOffset, imageSize)), CompositeSourceOver, m_renderImage.shouldRespectImageOrientation());
                errorPictureDrawn = true;
            }

            if (!m_renderImage.altText().isEmpty()) {
                const Font& font = m_renderImage.style()->font();
                const FontMetrics& fontMetrics = font.fontMetrics();
                LayoutUnit ascent = fontMetrics.ascent();
                LayoutPoint textRectOrigin = paintOffset;
                textRectOrigin.move(leftBorder + leftPad + (RenderImage::paddingWidth / 2) - borderWidth, topBorder + topPad + (RenderImage::paddingHeight / 2) - borderWidth);
                LayoutPoint textOrigin(textRectOrigin.x(), textRectOrigin.y() + ascent);

                // Only draw the alt text if it'll fit within the content box,
                // and only if it fits above the error image.
                TextRun textRun = constructTextRun(&m_renderImage, font, m_renderImage.altText(), m_renderImage.style(), TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion, DefaultTextRunFlags | RespectDirection);
                float textWidth = font.width(textRun);
                TextRunPaintInfo textRunPaintInfo(textRun);
                textRunPaintInfo.bounds = FloatRect(textRectOrigin, FloatSize(textWidth, fontMetrics.height()));
                context->setFillColor(m_renderImage.resolveColor(CSSPropertyColor));
                if (textRun.direction() == RTL) {
                    int availableWidth = cWidth - static_cast<int>(RenderImage::paddingWidth);
                    textOrigin.move(availableWidth - ceilf(textWidth), 0);
                }
                if (errorPictureDrawn) {
                    if (usableWidth >= textWidth && fontMetrics.height() <= imageOffset.height())
                        context->drawBidiText(font, textRunPaintInfo, textOrigin);
                } else if (usableWidth >= textWidth && usableHeight >= fontMetrics.height()) {
                    context->drawBidiText(font, textRunPaintInfo, textOrigin);
                }
            }
        }
    } else if (m_renderImage.imageResource()->hasImage() && cWidth > 0 && cHeight > 0) {
        LayoutRect contentRect = m_renderImage.contentBoxRect();
        contentRect.moveBy(paintOffset);
        LayoutRect paintRect = m_renderImage.replacedContentRect();
        paintRect.moveBy(paintOffset);
        DrawingRecorder recorder(context, &m_renderImage, paintInfo.phase, contentRect);
        bool clip = !contentRect.contains(paintRect);
        if (clip) {
            context->save();
            context->clip(contentRect);
        }

        paintIntoRect(context, paintRect);

        if (clip)
            context->restore();
    }
}
LayoutRect RenderRegion::overflowRectForFlowThreadPortion(LayoutRect flowThreadPortionRect, bool isFirstPortion, bool isLastPortion) const
{
    ASSERT(isValid());

    // FIXME: Would like to just use hasOverflowClip() but we aren't a block yet. When RenderRegion is eliminated and
    // folded into RenderBlock, switch to hasOverflowClip().
    bool clipX = style()->overflowX() != OVISIBLE;
    bool clipY = style()->overflowY() != OVISIBLE;
    bool isLastRegionWithRegionOverflowBreak = (isLastPortion && (style()->regionOverflow() == BreakRegionOverflow));
    if ((clipX && clipY) || isLastRegionWithRegionOverflowBreak)
        return flowThreadPortionRect;

    LayoutRect flowThreadOverflow = m_flowThread->visualOverflowRect();

    // Only clip along the flow thread axis.
    LayoutUnit outlineSize = maximalOutlineSize(PaintPhaseOutline);
    LayoutRect clipRect;
    if (m_flowThread->isHorizontalWritingMode()) {
        LayoutUnit minY = isFirstPortion ? (flowThreadOverflow.y() - outlineSize) : flowThreadPortionRect.y();
        LayoutUnit maxY = isLastPortion ? max(flowThreadPortionRect.maxY(), flowThreadOverflow.maxY()) + outlineSize : flowThreadPortionRect.maxY();
        LayoutUnit minX = clipX ? flowThreadPortionRect.x() : min(flowThreadPortionRect.x(), flowThreadOverflow.x() - outlineSize);
        LayoutUnit maxX = clipX ? flowThreadPortionRect.maxX() : max(flowThreadPortionRect.maxX(), (flowThreadOverflow.maxX() + outlineSize));
        clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY);
    } else {
        LayoutUnit minX = isFirstPortion ? (flowThreadOverflow.x() - outlineSize) : flowThreadPortionRect.x();
        LayoutUnit maxX = isLastPortion ? max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX()) + outlineSize : flowThreadPortionRect.maxX();
        LayoutUnit minY = clipY ? flowThreadPortionRect.y() : min(flowThreadPortionRect.y(), (flowThreadOverflow.y() - outlineSize));
        LayoutUnit maxY = clipY ? flowThreadPortionRect.maxY() : max(flowThreadPortionRect.y(), (flowThreadOverflow.maxY() + outlineSize));
        clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY);
    }

    return clipRect;
}
Beispiel #29
0
void LayoutMedia::layout() {
  LayoutSize oldSize = contentBoxRect().size();

  LayoutImage::layout();

  LayoutRect newRect = contentBoxRect();

  LayoutState state(*this);

  Optional<LayoutUnit> newPanelWidth;

// Iterate the children in reverse order so that the media controls are laid
// out before the text track container. This is to ensure that the text
// track rendering has an up-to-date position of the media controls for
// overlap checking, see LayoutVTTCue.
#if ENABLE(ASSERT)
  bool seenTextTrackContainer = false;
#endif
  for (LayoutObject* child = m_children.lastChild(); child;
       child = child->previousSibling()) {
#if ENABLE(ASSERT)
    if (child->node()->isMediaControls())
      ASSERT(!seenTextTrackContainer);
    else if (child->node()->isTextTrackContainer())
      seenTextTrackContainer = true;
    else
      ASSERT_NOT_REACHED();
#endif

    // TODO(mlamouri): we miss some layouts because needsLayout returns false in
    // some cases where we want to change the width of the controls because the
    // visible viewport has changed for example.
    if (newRect.size() == oldSize && !child->needsLayout())
      continue;

    LayoutUnit width = newRect.width();
    if (child->node()->isMediaControls()) {
      width = computePanelWidth(newRect);
      if (width != oldSize.width())
        newPanelWidth = width;
    }

    LayoutBox* layoutBox = toLayoutBox(child);
    layoutBox->setLocation(newRect.location());
    // TODO(foolip): Remove the mutableStyleRef() and depend on CSS
    // width/height: inherit to match the media element size.
    layoutBox->mutableStyleRef().setHeight(Length(newRect.height(), Fixed));
    layoutBox->mutableStyleRef().setWidth(Length(width, Fixed));

    layoutBox->forceLayout();
  }

  clearNeedsLayout();

  // Notify our MediaControls that a layout has happened.
  if (mediaElement() && mediaElement()->mediaControls() &&
      newPanelWidth.has_value()) {
    mediaElement()->mediaControls()->notifyPanelWidthChanged(
        newPanelWidth.value());
  }
}
Beispiel #30
0
bool LayoutRect::contains(const LayoutRect& other) const
{
    return x() <= other.x() && maxX() >= other.maxX()
        && y() <= other.y() && maxY() >= other.maxY();
}