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 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); }
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); }
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); }
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()); }
// 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); }
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(); }
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; }
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); }
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); }
void FontCascade::adjustSelectionRectForComplexText(const TextRun& run, LayoutRect& selectionRect, int from, int to) const { UniscribeController it(this, run); it.advance(from); float beforeWidth = it.runWidthSoFar(); it.advance(to); float afterWidth = it.runWidthSoFar(); if (run.rtl()) { it.advance(run.length()); selectionRect.move(it.runWidthSoFar() - afterWidth, 0); } else selectionRect.move(beforeWidth, 0); selectionRect.setWidth(afterWidth - beforeWidth); }
// 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; }
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; }
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; }
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; }
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(); }
void RenderListItem::positionListMarker() { if (!m_marker || !m_marker->parent() || !m_marker->parent()->isBox()) return; if (m_marker->isInside() || !m_marker->inlineBoxWrapper()) return; 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; bool hitSelfPaintingLayer = false; const RootInlineBox& rootBox = m_marker->inlineBoxWrapper()->root(); LayoutUnit lineTop = rootBox.lineTop(); LayoutUnit lineBottom = rootBox.lineBottom(); // FIXME: Need to account for relative positioning in the layout overflow. if (style().isLeftToRightDirection()) { markerLogicalLeft = m_marker->lineOffsetForListItem() - lineOffset - paddingStart() - borderStart() + m_marker->marginStart(); m_marker->inlineBoxWrapper()->adjustLineDirectionPosition(markerLogicalLeft - markerOldLogicalLeft); 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 == &rootBox) adjustOverflow = true; } if (markerLogicalLeft < newLogicalLayoutOverflowRect.x()) { newLogicalLayoutOverflowRect.setWidth(newLogicalLayoutOverflowRect.maxX() - markerLogicalLeft); newLogicalLayoutOverflowRect.setX(markerLogicalLeft); if (box == &rootBox) adjustOverflow = true; } box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect, lineTop, lineBottom); if (box->renderer().hasSelfPaintingLayer()) hitSelfPaintingLayer = true; } } else { markerLogicalLeft = m_marker->lineOffsetForListItem() - lineOffset + paddingStart() + borderStart() + m_marker->marginEnd(); m_marker->inlineBoxWrapper()->adjustLineDirectionPosition(markerLogicalLeft - markerOldLogicalLeft); 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 == &rootBox) adjustOverflow = true; } if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalLayoutOverflowRect.maxX()) { newLogicalLayoutOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - newLogicalLayoutOverflowRect.x()); if (box == &rootBox) adjustOverflow = true; } box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect, lineTop, lineBottom); if (box->renderer().hasSelfPaintingLayer()) hitSelfPaintingLayer = true; } } if (adjustOverflow) { LayoutRect markerRect(markerLogicalLeft + lineOffset, blockOffset, m_marker->width(), m_marker->height()); if (!style().isHorizontalWritingMode()) markerRect = markerRect.transposedRect(); RenderBox* o = m_marker; bool propagateVisualOverflow = true; bool propagateLayoutOverflow = true; do { o = o->parentBox(); if (o->hasOverflowClip()) propagateVisualOverflow = false; if (is<RenderBlock>(*o)) { if (propagateVisualOverflow) downcast<RenderBlock>(*o).addVisualOverflow(markerRect); if (propagateLayoutOverflow) downcast<RenderBlock>(*o).addLayoutOverflow(markerRect); } if (o->hasOverflowClip()) propagateLayoutOverflow = false; if (o->hasSelfPaintingLayer()) propagateVisualOverflow = false; markerRect.moveBy(-o->location()); } while (o != this && propagateVisualOverflow && propagateLayoutOverflow); } }
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); } }
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; }
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); } } }
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; }