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()); }
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)) 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); LayoutTheme::theme().painter().paintCapsLockIndicator(*this, paintInfo, snappedRect); } }
void RenderView::computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect& rect, bool fixed) const { // If a container was specified, and was not 0 or the RenderView, // then we should have found it by now. ASSERT_ARG(repaintContainer, !repaintContainer || repaintContainer == this); if (printing()) return; if (style()->isFlippedBlocksWritingMode()) { // We have to flip by hand since the view's logical height has not been determined. We // can use the viewport width and height. if (style()->isHorizontalWritingMode()) rect.setY(viewHeight() - rect.maxY()); else rect.setX(viewWidth() - rect.maxX()); } if (fixed && m_frameView) rect.move(m_frameView->scrollOffsetForFixedPosition()); // Apply our transform if we have one (because of full page zooming). if (!repaintContainer && m_layer && m_layer->transform()) rect = m_layer->transform()->mapRect(rect); }
LayoutRect ShapeOutsideInfo::computedShapePhysicalBoundingBox() const { LayoutRect physicalBoundingBox = computedShape().shapeMarginLogicalBoundingBox(); physicalBoundingBox.setX(physicalBoundingBox.x() + logicalLeftOffset()); physicalBoundingBox.setY(physicalBoundingBox.y() + logicalTopOffset()); if (m_renderer.style().isFlippedBlocksWritingMode()) physicalBoundingBox.setY(m_renderer.logicalHeight() - physicalBoundingBox.maxY()); if (!m_renderer.style().isHorizontalWritingMode()) physicalBoundingBox = physicalBoundingBox.transposedRect(); return physicalBoundingBox; }
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); }
static LayoutRect relevantViewRect(RenderView* view) { // DidHitRelevantRepaintedObjectsAreaThreshold is a LayoutMilestone intended to indicate that // a certain relevant amount of content has been drawn to the screen. This is the rect that // has been determined to be relevant in the context of this goal. We may choose to tweak // the rect over time, much like we may choose to tweak gMinimumPaintedAreaRatio and // gMaximumUnpaintedAreaRatio. But this seems to work well right now. LayoutRect relevantViewRect = LayoutRect(0, 0, 980, 1300); LayoutRect viewRect = view->viewRect(); // If the viewRect is wider than the relevantViewRect, center the relevantViewRect. if (viewRect.width() > relevantViewRect.width()) relevantViewRect.setX((viewRect.width() - relevantViewRect.width()) / 2); return relevantViewRect; }
// 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 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)); } }
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; }
void RenderView::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, ViewportConstrainedPosition viewportConstraint, const PaintInvalidationState* state) const { if (document().printing()) return; if (style()->slowIsFlippedBlocksWritingMode()) { // We have to flip by hand since the view's logical height has not been determined. We // can use the viewport width and height. if (style()->isHorizontalWritingMode()) rect.setY(viewHeight() - rect.maxY()); else rect.setX(viewWidth() - rect.maxX()); } adjustViewportConstrainedOffset(rect, viewportConstraint); // Apply our transform if we have one (because of full page zooming). if (!paintInvalidationContainer && layer() && layer()->transform()) rect = layer()->transform()->mapRect(rect); ASSERT(paintInvalidationContainer); if (paintInvalidationContainer == this) return; Element* owner = document().ownerElement(); if (!owner) return; if (RenderBox* obj = owner->renderBox()) { // Intersect the viewport with the paint invalidation rect. LayoutRect viewRectangle = viewRect(); rect.intersect(viewRectangle); // Adjust for scroll offset of the view. rect.moveBy(-viewRectangle.location()); // Adjust for frame border. rect.moveBy(obj->contentBoxRect().location()); obj->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, 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; }
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; }
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); } }
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); } }