Exemplo n.º 1
0
void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    if (!paintInfo.shouldPaintWithinRoot(*this))
        return;

    LayoutRect paintRect(paintOffset, size());
    RenderBox* legend = findLegend();
    if (!legend)
        return RenderBlockFlow::paintBoxDecorations(paintInfo, paintOffset);

    // FIXME: We need to work with "rl" and "bt" block flow directions.  In those
    // cases the legend is embedded in the right and bottom borders respectively.
    // https://bugs.webkit.org/show_bug.cgi?id=47236
    if (style().isHorizontalWritingMode()) {
        LayoutUnit yOff = (legend->y() > 0) ? LayoutUnit() : (legend->height() - borderTop()) / 2;
        paintRect.setHeight(paintRect.height() - yOff);
        paintRect.setY(paintRect.y() + yOff);
    } else {
        LayoutUnit xOff = (legend->x() > 0) ? LayoutUnit() : (legend->width() - borderLeft()) / 2;
        paintRect.setWidth(paintRect.width() - xOff);
        paintRect.setX(paintRect.x() + xOff);
    }

    if (!boxShadowShouldBeAppliedToBackground(determineBackgroundBleedAvoidance(paintInfo.context)))
        paintBoxShadow(paintInfo, paintRect, style(), Normal);
    paintFillLayers(paintInfo, style().visitedDependentColor(CSSPropertyBackgroundColor), style().backgroundLayers(), paintRect);
    paintBoxShadow(paintInfo, paintRect, style(), Inset);

    if (!style().hasBorder())
        return;
    
    // Create a clipping region around the legend and paint the border as normal
    GraphicsContext* graphicsContext = paintInfo.context;
    GraphicsContextStateSaver stateSaver(*graphicsContext);

    // FIXME: We need to work with "rl" and "bt" block flow directions.  In those
    // cases the legend is embedded in the right and bottom borders respectively.
    // https://bugs.webkit.org/show_bug.cgi?id=47236
    LayoutRect clipRect;
    if (style().isHorizontalWritingMode()) {
        clipRect.setX(paintRect.x() + legend->x());
        clipRect.setY(paintRect.y());
        clipRect.setWidth(legend->width());
        clipRect.setHeight(std::max<LayoutUnit>(style().borderTopWidth(), legend->height() - ((legend->height() - borderTop()) / 2)));
    } else {
        clipRect.setX(paintRect.x());
        clipRect.setY(paintRect.y() + legend->y());
        clipRect.setWidth(std::max<LayoutUnit>(style().borderLeftWidth(), legend->width()));
        clipRect.setHeight(legend->height());
    }
    graphicsContext->clipOut(snapRectToDevicePixels(clipRect, document().deviceScaleFactor()));

    paintBorder(paintInfo, paintRect, style());
}
LayoutRect AccessibilitySpinButtonPart::elementRect() const
{
    // FIXME: This logic should exist in the render tree or elsewhere, but there is no
    // relationship that exists that can be queried.
    
    LayoutRect parentRect = parentObject()->elementRect();
    if (m_isIncrementor)
        parentRect.setHeight(parentRect.height() / 2);
    else {
        parentRect.setY(parentRect.y() + parentRect.height() / 2);        
        parentRect.setHeight(parentRect.height() / 2);        
    }
        
    return parentRect;
}
Exemplo n.º 3
0
IntRect RenderVideo::videoBox() const
{
    if (m_cachedImageSize.isEmpty() && videoElement()->shouldDisplayPosterImage())
        return IntRect();

    LayoutSize elementSize;
    if (videoElement()->shouldDisplayPosterImage())
        elementSize = m_cachedImageSize;
    else
        elementSize = intrinsicSize();

    IntRect contentRect = pixelSnappedIntRect(contentBoxRect());
    if (elementSize.isEmpty() || contentRect.isEmpty())
        return IntRect();

    LayoutRect renderBox = contentRect;
    LayoutUnit ratio = renderBox.width() * elementSize.height() - renderBox.height() * elementSize.width();
    if (ratio > 0) {
        LayoutUnit newWidth = renderBox.height() * elementSize.width() / elementSize.height();
        // Just fill the whole area if the difference is one pixel or less (in both sides)
        if (renderBox.width() - newWidth > 2)
            renderBox.setWidth(newWidth);
        renderBox.move((contentRect.width() - renderBox.width()) / 2, 0);
    } else if (ratio < 0) {
        LayoutUnit newHeight = renderBox.width() * elementSize.height() / elementSize.width();
        if (renderBox.height() - newHeight > 2)
            renderBox.setHeight(newHeight);
        renderBox.move(0, (contentRect.height() - renderBox.height()) / 2);
    }

    return pixelSnappedIntRect(renderBox);
}
Exemplo n.º 4
0
LayoutRect RenderRegion::rectFlowPortionForBox(const RenderBox* box, const LayoutRect& rect) const
{
    RenderRegion* startRegion = 0;
    RenderRegion* endRegion = 0;
    m_flowThread->getRegionRangeForBox(box, startRegion, endRegion);

    LayoutRect mappedRect = m_flowThread->mapFromLocalToFlowThread(box, rect);
    if (flowThread()->isHorizontalWritingMode()) {
        if (this != startRegion)
            mappedRect.shiftYEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.y()));

        if (this != endRegion)
            mappedRect.setHeight(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.y(), mappedRect.height())));
    } else {
        if (this != startRegion)
            mappedRect.shiftXEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.x()));
            
        if (this != endRegion)
            mappedRect.setWidth(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.x(), mappedRect.width())));
    }

    if (shouldClipFlowThreadContent()) {
        LayoutRect portionRect;
        if (isRenderNamedFlowFragment())
            portionRect = toRenderNamedFlowFragment(this)->flowThreadPortionRectForClipping(this == startRegion, this == endRegion);
        else
            portionRect = flowThreadPortionRect();
        
        mappedRect.intersect(portionRect);
    }

    return mappedRect.isEmpty() ? mappedRect : m_flowThread->mapFromFlowThreadToLocal(box, mappedRect);
}
Exemplo n.º 5
0
LayoutRect RenderRegion::rectFlowPortionForBox(const RenderBox* box, const LayoutRect& rect) const
{
    RenderRegion* startRegion = 0;
    RenderRegion* endRegion = 0;
    m_flowThread->getRegionRangeForBox(box, startRegion, endRegion);

    LayoutRect mappedRect = m_flowThread->mapFromLocalToFlowThread(box, rect);
    if (flowThread()->isHorizontalWritingMode()) {
        if (this != startRegion)
            mappedRect.shiftYEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.y()));

        if (this != endRegion)
            mappedRect.setHeight(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.y(), mappedRect.height())));
    } else {
        if (this != startRegion)
            mappedRect.shiftXEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.x()));
            
        if (this != endRegion)
            mappedRect.setWidth(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.x(), mappedRect.width())));
    }

    bool isLastRegionWithRegionFragmentBreak = (isLastRegion() && (style().regionFragment() == BreakRegionFragment));
    if (hasOverflowClip() || isLastRegionWithRegionFragmentBreak)
        mappedRect.intersect(flowThreadPortionRect());

    return mappedRect.isEmpty() ? mappedRect : m_flowThread->mapFromFlowThreadToLocal(box, mappedRect);
}
LayoutSize RenderMultiColumnFlowThread::physicalTranslationOffsetFromFlowToRegion(const RenderRegion* renderRegion, const LayoutUnit logicalOffset) const
{
    // Now that we know which multicolumn set we hit, we need to get the appropriate translation offset for the column.
    const RenderMultiColumnSet* columnSet = toRenderMultiColumnSet(renderRegion);
    LayoutPoint translationOffset = columnSet->columnTranslationForOffset(logicalOffset);

    // Now we know how we want the rect to be translated into the region. At this point we're converting
    // back to physical coordinates.
    if (style().isFlippedBlocksWritingMode()) {
        LayoutRect portionRect(columnSet->flowThreadPortionRect());
        LayoutRect columnRect = columnSet->columnRectAt(0);
        LayoutUnit physicalDeltaFromPortionBottom = logicalHeight() - columnSet->logicalBottomInFlowThread();
        if (isHorizontalWritingMode())
            columnRect.setHeight(portionRect.height());
        else
            columnRect.setWidth(portionRect.width());
        columnSet->flipForWritingMode(columnRect);
        if (isHorizontalWritingMode())
            translationOffset.move(0, columnRect.y() - portionRect.y() - physicalDeltaFromPortionBottom);
        else
            translationOffset.move(columnRect.x() - portionRect.x() - physicalDeltaFromPortionBottom, 0);
    }

    return LayoutSize(translationOffset.x(), translationOffset.y());
}
Exemplo n.º 7
0
// Checks if |node| is offscreen the visible area (viewport) of its container
// document. In case it is, one can scroll in direction or take any different
// desired action later on.
bool hasOffscreenRect(Node* node, FocusType type)
{
    // Get the FrameView in which |node| is (which means the current viewport if |node|
    // is not in an inner document), so we can check if its content rect is visible
    // before we actually move the focus to it.
    FrameView* frameView = node->document().view();
    if (!frameView)
        return true;

    ASSERT(!frameView->needsLayout());

    LayoutRect containerViewportRect = frameView->visibleContentRect();
    // We want to select a node if it is currently off screen, but will be
    // exposed after we scroll. Adjust the viewport to post-scrolling position.
    // If the container has overflow:hidden, we cannot scroll, so we do not pass direction
    // and we do not adjust for scrolling.
    switch (type) {
    case FocusTypeLeft:
        containerViewportRect.setX(containerViewportRect.x() - ScrollableArea::pixelsPerLineStep());
        containerViewportRect.setWidth(containerViewportRect.width() + ScrollableArea::pixelsPerLineStep());
        break;
    case FocusTypeRight:
        containerViewportRect.setWidth(containerViewportRect.width() + ScrollableArea::pixelsPerLineStep());
        break;
    case FocusTypeUp:
        containerViewportRect.setY(containerViewportRect.y() - ScrollableArea::pixelsPerLineStep());
        containerViewportRect.setHeight(containerViewportRect.height() + ScrollableArea::pixelsPerLineStep());
        break;
    case FocusTypeDown:
        containerViewportRect.setHeight(containerViewportRect.height() + ScrollableArea::pixelsPerLineStep());
        break;
    default:
        break;
    }

    RenderObject* render = node->renderer();
    if (!render)
        return true;

    LayoutRect rect(render->absoluteClippedOverflowRect());
    if (rect.isEmpty())
        return true;

    return !containerViewportRect.intersects(rect);
}
Exemplo n.º 8
0
RenderBox::LogicalExtentComputedValues RenderProgress::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop) const
{
    auto computedValues = RenderBox::computeLogicalHeight(logicalHeight, logicalTop);
    LayoutRect frame = frameRect();
    if (isHorizontalWritingMode())
        frame.setHeight(computedValues.m_extent);
    else
        frame.setWidth(computedValues.m_extent);
    IntSize frameSize = theme().progressBarRectForBounds(*this, snappedIntRect(frame)).size();
    computedValues.m_extent = isHorizontalWritingMode() ? frameSize.height() : frameSize.width();
    return computedValues;
}
Exemplo n.º 9
0
void RenderMeter::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
{
    RenderBox::computeLogicalHeight(logicalHeight, logicalTop, computedValues);

    LayoutRect frame = frameRect();
    if (isHorizontalWritingMode())
        frame.setHeight(computedValues.m_extent);
    else
        frame.setWidth(computedValues.m_extent);
    IntSize frameSize = theme().meterSizeForBounds(*this, pixelSnappedIntRect(frame));
    computedValues.m_extent = isHorizontalWritingMode() ? frameSize.height() : frameSize.width();
}
Exemplo n.º 10
0
void ShadowData::adjustRectForShadow(LayoutRect& rect, int additionalOutlineSize) const
{
    int shadowLeft = 0;
    int shadowRight = 0;
    int shadowTop = 0;
    int shadowBottom = 0;
    calculateShadowExtent(this, additionalOutlineSize, shadowLeft, shadowRight, shadowTop, shadowBottom);

    rect.move(shadowLeft, shadowTop);
    rect.setWidth(rect.width() - shadowLeft + shadowRight);
    rect.setHeight(rect.height() - shadowTop + shadowBottom);
}
Exemplo n.º 11
0
void RenderLineBreak::collectSelectionRects(Vector<SelectionRect>& rects, unsigned, unsigned)
{
    ensureLineBoxes(*this);
    InlineElementBox* box = m_inlineBoxWrapper;
    if (!box)
        return;
    const RootInlineBox& rootBox = box->root();
    LayoutRect rect = rootBox.computeCaretRect(box->logicalLeft(), 0, nullptr);
    if (rootBox.isFirstAfterPageBreak()) {
        if (box->isHorizontal())
            rect.shiftYEdgeTo(rootBox.lineTopWithLeading());
        else
            rect.shiftXEdgeTo(rootBox.lineTopWithLeading());
    }

    RenderBlock* containingBlock = this->containingBlock();
    // Map rect, extended left to leftOffset, and right to rightOffset, through transforms to get minX and maxX.
    LogicalSelectionOffsetCaches cache(*containingBlock);
    LayoutUnit leftOffset = containingBlock->logicalLeftSelectionOffset(*containingBlock, box->logicalTop(), cache);
    LayoutUnit rightOffset = containingBlock->logicalRightSelectionOffset(*containingBlock, box->logicalTop(), cache);
    LayoutRect extentsRect = rect;
    if (box->isHorizontal()) {
        extentsRect.setX(leftOffset);
        extentsRect.setWidth(rightOffset - leftOffset);
    } else {
        extentsRect.setY(leftOffset);
        extentsRect.setHeight(rightOffset - leftOffset);
    }
    extentsRect = localToAbsoluteQuad(FloatRect(extentsRect)).enclosingBoundingBox();
    if (!box->isHorizontal())
        extentsRect = extentsRect.transposedRect();
    bool isFirstOnLine = !box->previousOnLineExists();
    bool isLastOnLine = !box->nextOnLineExists();
    if (containingBlock->isRubyBase() || containingBlock->isRubyText())
        isLastOnLine = !containingBlock->containingBlock()->inlineBoxWrapper()->nextOnLineExists();

    bool isFixed = false;
    IntRect absRect = localToAbsoluteQuad(FloatRect(rect), UseTransforms, &isFixed).enclosingBoundingBox();
    bool boxIsHorizontal = !box->isSVGInlineTextBox() ? box->isHorizontal() : !style().svgStyle().isVerticalWritingMode();
    // If the containing block is an inline element, we want to check the inlineBoxWrapper orientation
    // to determine the orientation of the block. In this case we also use the inlineBoxWrapper to
    // determine if the element is the last on the line.
    if (containingBlock->inlineBoxWrapper()) {
        if (containingBlock->inlineBoxWrapper()->isHorizontal() != boxIsHorizontal) {
            boxIsHorizontal = containingBlock->inlineBoxWrapper()->isHorizontal();
            isLastOnLine = !containingBlock->inlineBoxWrapper()->nextOnLineExists();
        }
    }

    rects.append(SelectionRect(absRect, box->direction(), extentsRect.x(), extentsRect.maxX(), extentsRect.maxY(), 0, box->isLineBreak(), isFirstOnLine, isLastOnLine, false, false, boxIsHorizontal, isFixed, containingBlock->isRubyText(), view().pageNumberForBlockProgressionOffset(absRect.x())));
}
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);
}
Exemplo n.º 13
0
// The starting rect is the rect of the focused node, in document coordinates.
// Compose a virtual starting rect if there is no focused node or if it is off screen.
// The virtual rect is the edge of the container or frame. We select which
// edge depending on the direction of the navigation.
LayoutRect virtualRectForDirection(FocusType type, const LayoutRect& startingRect, LayoutUnit width)
{
    LayoutRect virtualStartingRect = startingRect;
    switch (type) {
    case FocusTypeLeft:
        virtualStartingRect.setX(virtualStartingRect.maxX() - width);
        virtualStartingRect.setWidth(width);
        break;
    case FocusTypeUp:
        virtualStartingRect.setY(virtualStartingRect.maxY() - width);
        virtualStartingRect.setHeight(width);
        break;
    case FocusTypeRight:
        virtualStartingRect.setWidth(width);
        break;
    case FocusTypeDown:
        virtualStartingRect.setHeight(width);
        break;
    default:
        ASSERT_NOT_REACHED();
    }

    return virtualStartingRect;
}
Exemplo n.º 14
0
bool RenderFlowThread::objectInFlowRegion(const RenderObject* object, const RenderRegion* region) const
{
    ASSERT(object);
    ASSERT(region);

    if (!object->inRenderFlowThread())
        return false;
    if (object->enclosingRenderFlowThread() != this)
        return false;
    if (!m_regionList.contains(const_cast<RenderRegion*>(region)))
        return false;

    RenderBox* enclosingBox = object->enclosingBox();
    RenderRegion* enclosingBoxStartRegion = 0;
    RenderRegion* enclosingBoxEndRegion = 0;
    getRegionRangeForBox(enclosingBox, enclosingBoxStartRegion, enclosingBoxEndRegion);
    if (!regionInRange(region, enclosingBoxStartRegion, enclosingBoxEndRegion))
       return false;

    if (object->isBox())
        return true;

    LayoutRect objectABBRect = object->absoluteBoundingBoxRect(true);
    if (!objectABBRect.width())
        objectABBRect.setWidth(1);
    if (!objectABBRect.height())
        objectABBRect.setHeight(1); 
    if (objectABBRect.intersects(region->absoluteBoundingBoxRect(true)))
        return true;

    if (region == lastRegion()) {
        // If the object does not intersect any of the enclosing box regions
        // then the object is in last region.
        for (RenderRegionList::const_iterator it = m_regionList.find(enclosingBoxStartRegion); it != m_regionList.end(); ++it) {
            const RenderRegion* currRegion = *it;
            if (!region->isValid())
                continue;
            if (currRegion == region)
                break;
            if (objectABBRect.intersects(currRegion->absoluteBoundingBoxRect(true)))
                return false;
        }
        return true;
    }

    return false;
}
Exemplo n.º 15
0
LayoutRect nodeRectInAbsoluteCoordinates(Node* node, bool ignoreBorder)
{
    ASSERT(node && node->renderer() && !node->document().view()->needsLayout());

    if (node->isDocumentNode())
        return frameRectInAbsoluteCoordinates(toDocument(node)->frame());
    LayoutRect rect = rectToAbsoluteCoordinates(node->document().frame(), node->boundingBox());

    // For authors that use border instead of outline in their CSS, we compensate by ignoring the border when calculating
    // the rect of the focused element.
    if (ignoreBorder) {
        rect.move(node->renderer()->style()->borderLeftWidth(), node->renderer()->style()->borderTopWidth());
        rect.setWidth(rect.width() - node->renderer()->style()->borderLeftWidth() - node->renderer()->style()->borderRightWidth());
        rect.setHeight(rect.height() - node->renderer()->style()->borderTopWidth() - node->renderer()->style()->borderBottomWidth());
    }
    return rect;
}
Exemplo n.º 16
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;
}
Exemplo n.º 17
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();
}
Exemplo n.º 18
0
// Bounds of the LayoutObject relative to the scroller's visible content rect.
static LayoutRect relativeBounds(const LayoutObject* layoutObject,
                                 const ScrollableArea* scroller) {
  LayoutRect localBounds;
  if (layoutObject->isBox()) {
    localBounds = toLayoutBox(layoutObject)->borderBoxRect();
    if (!layoutObject->hasOverflowClip()) {
      // borderBoxRect doesn't include overflow content and floats.
      LayoutUnit maxHeight =
          std::max(localBounds.height(),
                   toLayoutBox(layoutObject)->layoutOverflowRect().height());
      if (layoutObject->isLayoutBlockFlow() &&
          toLayoutBlockFlow(layoutObject)->containsFloats()) {
        // Note that lowestFloatLogicalBottom doesn't include floating
        // grandchildren.
        maxHeight = std::max(
            maxHeight,
            toLayoutBlockFlow(layoutObject)->lowestFloatLogicalBottom());
      }
      localBounds.setHeight(maxHeight);
    }
  } else if (layoutObject->isText()) {
    // TODO(skobes): Use first and last InlineTextBox only?
    for (InlineTextBox* box = toLayoutText(layoutObject)->firstTextBox(); box;
         box = box->nextTextBox())
      localBounds.unite(box->frameRect());
  } else {
    // Only LayoutBox and LayoutText are supported.
    ASSERT_NOT_REACHED();
  }

  LayoutRect relativeBounds = LayoutRect(
      scroller->localToVisibleContentQuad(FloatRect(localBounds), layoutObject)
          .boundingBox());

  return relativeBounds;
}
LayoutRect RenderNamedFlowThread::decorationsClipRectForBoxInNamedFlowFragment(const RenderBox& box, RenderNamedFlowFragment& fragment) const
{
    LayoutRect visualOverflowRect = fragment.visualOverflowRectForBox(&box);
    LayoutUnit initialLogicalX = style().isHorizontalWritingMode() ? visualOverflowRect.x() : visualOverflowRect.y();

    // The visual overflow rect returned by visualOverflowRectForBox is already flipped but the
    // RenderRegion::rectFlowPortionForBox method expects it unflipped.
    flipForWritingModeLocalCoordinates(visualOverflowRect);
    visualOverflowRect = fragment.rectFlowPortionForBox(&box, visualOverflowRect);
    
    // Now flip it again.
    flipForWritingModeLocalCoordinates(visualOverflowRect);

    // Take the scrolled offset of this object's parents into consideration.
    IntSize scrolledContentOffset;
    RenderBlock* containingBlock = box.containingBlock();
    while (containingBlock) {
        if (containingBlock->isRenderNamedFlowThread()) {
            // We've reached the flow thread, take the scrolled offset of the region into consideration.
            ASSERT(containingBlock == this);
            scrolledContentOffset += fragment.fragmentContainer().scrolledContentOffset();
            break;
        }
        
        scrolledContentOffset += containingBlock->scrolledContentOffset();
        containingBlock = containingBlock->containingBlock();
    }

    if (!scrolledContentOffset.isZero()) {
        if (style().isFlippedBlocksWritingMode())
            scrolledContentOffset = -scrolledContentOffset;
        
        visualOverflowRect.inflateX(scrolledContentOffset.width());
        visualOverflowRect.inflateY(scrolledContentOffset.height());
    }
    
    // Layers are in physical coordinates so the origin must be moved to the physical top-left of the flowthread.
    if (style().isFlippedBlocksWritingMode()) {
        if (style().isHorizontalWritingMode())
            visualOverflowRect.moveBy(LayoutPoint(0, height()));
        else
            visualOverflowRect.moveBy(LayoutPoint(width(), 0));
    }

    const RenderBox* iterBox = &box;
    while (iterBox && iterBox != this) {
        RenderBlock* containerBlock = iterBox->containingBlock();

        // FIXME: This doesn't work properly with flipped writing modes.
        // https://bugs.webkit.org/show_bug.cgi?id=125149
        if (iterBox->isPositioned()) {
            // For positioned elements, just use the layer's absolute bounding box.
            visualOverflowRect.moveBy(iterBox->layer()->absoluteBoundingBox().location());
            break;
        }

        LayoutRect currentBoxRect = iterBox->frameRect();
        if (iterBox->style().isFlippedBlocksWritingMode()) {
            if (iterBox->style().isHorizontalWritingMode())
                currentBoxRect.setY(currentBoxRect.height() - currentBoxRect.maxY());
            else
                currentBoxRect.setX(currentBoxRect.width() - currentBoxRect.maxX());
        }

        if (containerBlock->style().writingMode() != iterBox->style().writingMode())
            iterBox->flipForWritingMode(currentBoxRect);

        visualOverflowRect.moveBy(currentBoxRect.location());
        iterBox = containerBlock;
    }

    // Since the purpose of this method is to make sure the borders of a fragmented
    // element don't overflow the region in the fragmentation direction, there's no
    // point in restricting the clipping rect on the logical X axis. 
    // This also saves us the trouble of handling percent-based widths and margins
    // since the absolute bounding box of a positioned element would not contain
    // the correct coordinates relative to the region we're interested in, but rather
    // relative to the actual flow thread.
    if (style().isHorizontalWritingMode()) {
        if (initialLogicalX < visualOverflowRect.x())
            visualOverflowRect.shiftXEdgeTo(initialLogicalX);
        if (visualOverflowRect.width() < frameRect().width())
            visualOverflowRect.setWidth(frameRect().width());
    } else {
        if (initialLogicalX < visualOverflowRect.y())
            visualOverflowRect.shiftYEdgeTo(initialLogicalX);
        if (visualOverflowRect.height() < frameRect().height())
            visualOverflowRect.setHeight(frameRect().height());
    }

    return visualOverflowRect;
}
Exemplo n.º 20
0
void RenderMathMLMenclose::paint(PaintInfo& info, const LayoutPoint& paintOffset)
{
    RenderMathMLRow::paint(info, paintOffset);

    if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE)
        return;

    LayoutUnit thickness = ruleThickness();

    // Make a copy of the PaintInfo because applyTransform will modify its rect.
    PaintInfo paintInfo(info);
    GraphicsContextStateSaver stateSaver(paintInfo.context());

    paintInfo.context().setStrokeThickness(thickness);
    paintInfo.context().setStrokeStyle(SolidStroke);
    paintInfo.context().setStrokeColor(style().visitedDependentColor(CSSPropertyColor));
    paintInfo.context().setFillColor(Color::transparent);
    paintInfo.applyTransform(AffineTransform().translate(paintOffset + location()));

    // In the MathML in HTML5 implementation note, the "left" notation is described as follows:
    // - center of the left vertical bar is at 3\xi_8 padding + \xi_8 border/2 = 7\xi_8/2
    // - top space is Overbar Vertical Gap + Overbar Rule Thickness = 3\xi_8 + \xi_8 = 4\xi_8
    // - bottom space is Underbar Vertical Gap + Underbar Rule Thickness = 3\xi_8 + \xi_8 = 4\xi_8
    if (hasNotation(MathMLMencloseElement::Left)) {
        LayoutUnit x = m_contentRect.x() - 7 * thickness / 2;
        LayoutUnit yStart = m_contentRect.y() - 4 * thickness;
        LayoutUnit yEnd = m_contentRect.maxY() + 4 * thickness;
        drawLine(info, x, yStart, x, yEnd);
    }

    // In the MathML in HTML5 implementation note, the "right" notation is described as follows:
    // - center of the right vertical bar is at 3\xi_8 padding + \xi_8 border/2 = 7\xi_8/2
    // - top space is Overbar Vertical Gap + Overbar Rule Thickness = 3\xi_8 + \xi_8 = 4\xi_8
    // - bottom space is Underbar Vertical Gap + Underbar Rule Thickness = 3\xi_8 + \xi_8 = 4\xi_8
    if (hasNotation(MathMLMencloseElement::Right)) {
        LayoutUnit x = m_contentRect.maxX() + 7 * thickness / 2;
        LayoutUnit yStart = m_contentRect.y() - 4 * thickness;
        LayoutUnit yEnd = m_contentRect.maxY() + 4 * thickness;
        drawLine(info, x, yStart, x, yEnd);
    }

    // In the MathML in HTML5 implementation note, the "vertical" notation is horizontally centered.
    if (hasNotation(MathMLMencloseElement::VerticalStrike)) {
        LayoutUnit x = m_contentRect.x() + (m_contentRect.width() - thickness) / 2;
        LayoutUnit yStart = m_contentRect.y();
        LayoutUnit yEnd = m_contentRect.maxY();
        drawLine(info, x, yStart, x, yEnd);
    }

    // In the MathML in HTML5 implementation note, the "top" notation is described as follows:
    // - middle of the top horizontal bar is at Vertical Gap + Rule Thickness / 2 = 7\xi_8/2
    // - left and right spaces have size 4\xi_8
    if (hasNotation(MathMLMencloseElement::Top)) {
        LayoutUnit y = m_contentRect.y() - 7 * thickness / 2;
        LayoutUnit xStart = m_contentRect.x() - 4 * thickness;
        LayoutUnit xEnd = m_contentRect.maxX() + 4 * thickness;
        drawLine(info, xStart, y, xEnd, y);
    }

    // In the MathML in HTML5 implementation note, the "bottom" notation is described as follows:
    // - middle of the bottom horizontal bar is at Vertical Gap + Rule Thickness / 2 = 7\xi_8/2
    // - left and right spaces have size 4\xi_8
    if (hasNotation(MathMLMencloseElement::Bottom)) {
        LayoutUnit y = m_contentRect.maxY() + 7 * thickness / 2;
        LayoutUnit xStart = m_contentRect.x() - 4 * thickness;
        LayoutUnit xEnd = m_contentRect.maxX() + 4 * thickness;
        drawLine(info, xStart, y, xEnd, y);
    }

    // In the MathML in HTML5 implementation note, the "vertical" notation is vertically centered.
    if (hasNotation(MathMLMencloseElement::HorizontalStrike)) {
        LayoutUnit y = m_contentRect.y() + (m_contentRect.height() - thickness) / 2;
        LayoutUnit xStart = m_contentRect.x();
        LayoutUnit xEnd = m_contentRect.maxX();
        drawLine(info, xStart, y, xEnd, y);
    }

    // In the MathML in HTML5 implementation note, the "updiagonalstrike" goes from the bottom left corner
    // to the top right corner.
    if (hasNotation(MathMLMencloseElement::UpDiagonalStrike))
        drawLine(info, m_contentRect.x(), m_contentRect.maxY(), m_contentRect.maxX(), m_contentRect.y());

    // In the MathML in HTML5 implementation note, the "downdiagonalstrike" goes from the top left corner
    // to the bottom right corner.
    if (hasNotation(MathMLMencloseElement::DownDiagonalStrike))
        drawLine(info, m_contentRect.x(), m_contentRect.y(), m_contentRect.maxX(), m_contentRect.maxY());

    // In the MathML in HTML5 implementation note, the "roundedbox" has radii size 3\xi_8 and is obtained
    // by inflating the content box by 3\xi_8 + \xi_8/2 = 7\xi_8/2
    if (hasNotation(MathMLMencloseElement::RoundedBox)) {
        LayoutSize radiiSize(3 * thickness, 3 * thickness);
        RoundedRect::Radii radii(radiiSize, radiiSize, radiiSize, radiiSize);
        RoundedRect roundedRect(m_contentRect, radii);
        roundedRect.inflate(7 * thickness / 2);
        Path path;
        path.addRoundedRect(roundedRect);
        paintInfo.context().strokePath(path);
    }

    // For longdiv, we use our own rules for now:
    // - top space is like "top" notation
    // - bottom space is like "bottom" notation
    // - right space is like "right" notation
    // - left space is longDivLeftSpace * \xi_8
    // - We subtract half of the thickness from these spaces to obtain "top", "bottom", "left"
    //   and "right" coordinates.
    // - The top bar is drawn from "right" to "left" and positioned at vertical offset "top".
    // - The left part is draw as a quadratic Bezier curve with end points going from "top" to
    //   "bottom" and positioned at horizontal offset "left".
    // - In order to force the curvature of the left part, we use a middle point that is vertically
    //   centered and shifted towards the right by longDivLeftSpace * \xi_8
    if (hasNotation(MathMLMencloseElement::LongDiv)) {
        LayoutUnit top = m_contentRect.y() - 7 * thickness / 2;
        LayoutUnit bottom = m_contentRect.maxY() + 7 * thickness / 2;
        LayoutUnit left = m_contentRect.x() - longDivLeftSpace * thickness + thickness / 2;
        LayoutUnit right = m_contentRect.maxX() + 4 * thickness;
        LayoutUnit midX = left + longDivLeftSpace * thickness;
        LayoutUnit midY = (top + bottom) / 2;
        Path path;
        path.moveTo(LayoutPoint(right, top));
        path.addLineTo(LayoutPoint(left, top));
        path.addQuadCurveTo(LayoutPoint(midX, midY), FloatPoint(left, bottom));
        paintInfo.context().strokePath(path);
    }

    // In the MathML in HTML5 implementation note, the "circle" notation is described as follows:
    // - The center and axes are the same as the content bounding box.
    // - The width of the bounding box is \xi_8/2 + contentWidth * \sqrt{2} + \xi_8/2
    // - The height is \xi_8/2 + contentHeight * \sqrt{2} + \xi_8/2
    if (hasNotation(MathMLMencloseElement::Circle)) {
        LayoutRect ellipseRect;
        ellipseRect.setWidth(m_contentRect.width() * sqrtOfTwoFloat + thickness);
        ellipseRect.setHeight(m_contentRect.height() * sqrtOfTwoFloat + thickness);
        ellipseRect.setX(m_contentRect.x() - (ellipseRect.width() - m_contentRect.width()) / 2);
        ellipseRect.setY(m_contentRect.y() - (ellipseRect.height() - m_contentRect.height()) / 2);
        Path path;
        path.addEllipse(ellipseRect);
        paintInfo.context().strokePath(path);
    }
}
Exemplo n.º 21
0
bool InspectorHighlight::buildNodeQuads(Node* node, FloatQuad* content, FloatQuad* padding, FloatQuad* border, FloatQuad* margin)
{
    LayoutObject* layoutObject = node->layoutObject();
    if (!layoutObject)
        return false;

    FrameView* containingView = layoutObject->frameView();
    if (!containingView)
        return false;
    if (!layoutObject->isBox() && !layoutObject->isLayoutInline())
        return false;

    LayoutRect contentBox;
    LayoutRect paddingBox;
    LayoutRect borderBox;
    LayoutRect marginBox;

    if (layoutObject->isBox()) {
        LayoutBox* layoutBox = toLayoutBox(layoutObject);

        // LayoutBox returns the "pure" content area box, exclusive of the scrollbars (if present), which also count towards the content area in CSS.
        const int verticalScrollbarWidth = layoutBox->verticalScrollbarWidth();
        const int horizontalScrollbarHeight = layoutBox->horizontalScrollbarHeight();
        contentBox = layoutBox->contentBoxRect();
        contentBox.setWidth(contentBox.width() + verticalScrollbarWidth);
        contentBox.setHeight(contentBox.height() + horizontalScrollbarHeight);

        paddingBox = layoutBox->paddingBoxRect();
        paddingBox.setWidth(paddingBox.width() + verticalScrollbarWidth);
        paddingBox.setHeight(paddingBox.height() + horizontalScrollbarHeight);

        borderBox = layoutBox->borderBoxRect();

        marginBox = LayoutRect(borderBox.x() - layoutBox->marginLeft(), borderBox.y() - layoutBox->marginTop(),
            borderBox.width() + layoutBox->marginWidth(), borderBox.height() + layoutBox->marginHeight());
    } else {
        LayoutInline* layoutInline = toLayoutInline(layoutObject);

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

    *content = layoutObject->localToAbsoluteQuad(FloatRect(contentBox));
    *padding = layoutObject->localToAbsoluteQuad(FloatRect(paddingBox));
    *border = layoutObject->localToAbsoluteQuad(FloatRect(borderBox));
    *margin = layoutObject->localToAbsoluteQuad(FloatRect(marginBox));

    contentsQuadToViewport(containingView, *content);
    contentsQuadToViewport(containingView, *padding);
    contentsQuadToViewport(containingView, *border);
    contentsQuadToViewport(containingView, *margin);

    return true;
}