bool BlockPainter::intersectsPaintRect( const PaintInfo& paintInfo, const LayoutPoint& adjustedPaintOffset) const { LayoutRect overflowRect; if (paintInfo.isPrinting() && m_layoutBlock.isAnonymousBlock() && m_layoutBlock.childrenInline()) { // For case <a href="..."><div>...</div></a>, when m_layoutBlock is the // anonymous container of <a>, the anonymous container's visual overflow is // empty, but we need to continue painting to output <a>'s PDF URL rect // which covers the continuations, as if we included <a>'s PDF URL rect into // m_layoutBlock's visual overflow. Vector<LayoutRect> rects; m_layoutBlock.addElementVisualOverflowRects(rects, LayoutPoint()); overflowRect = unionRect(rects); } overflowRect.unite(m_layoutBlock.visualOverflowRect()); bool usesCompositedScrolling = m_layoutBlock.hasOverflowModel() && m_layoutBlock.usesCompositedScrolling(); if (usesCompositedScrolling) { LayoutRect layoutOverflowRect = m_layoutBlock.layoutOverflowRect(); overflowRect.unite(layoutOverflowRect); } m_layoutBlock.flipForWritingMode(overflowRect); // Scrolling is applied in physical space, which is why it is after the flip // above. if (usesCompositedScrolling) { overflowRect.move(-m_layoutBlock.scrolledContentOffset()); } overflowRect.moveBy(adjustedPaintOffset); return paintInfo.cullRect().intersectsCullRect(overflowRect); }
LayoutRect RenderTextLineBoxes::selectionRectForRange(unsigned start, unsigned end) { LayoutRect rect; for (auto box = m_first; box; box = box->nextTextBox()) { rect.unite(box->localSelectionRect(start, end)); rect.unite(ellipsisRectForBox(*box, start, end)); } return rect; }
void RenderTextLineBoxes::collectSelectionRectsForRange(unsigned start, unsigned end, Vector<LayoutRect>& rects) { for (auto box = m_first; box; box = box->nextTextBox()) { LayoutRect rect; rect.unite(box->localSelectionRect(start, end)); rect.unite(ellipsisRectForBox(*box, start, end)); if (!rect.size().isEmpty()) rects.append(rect); } }
IntRect RenderView::selectionBounds() const { typedef WillBeHeapHashMap<RawPtrWillBeMember<RenderObject>, OwnPtrWillBeMember<RenderSelectionInfo> > SelectionMap; SelectionMap selectedObjects; RenderObject* os = m_selectionStart; RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos); while (os && os != stop) { if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. selectedObjects.set(os, adoptPtrWillBeNoop(new RenderSelectionInfo(os))); RenderBlock* cb = os->containingBlock(); while (cb && !cb->isRenderView()) { OwnPtrWillBeMember<RenderSelectionInfo>& blockInfo = selectedObjects.add(cb, nullptr).storedValue->value; if (blockInfo) break; blockInfo = adoptPtrWillBeNoop(new RenderSelectionInfo(cb)); cb = cb->containingBlock(); } } os = os->nextInPreOrder(); } // Now create a single bounding box rect that encloses the whole selection. LayoutRect selRect; SelectionMap::iterator end = selectedObjects.end(); for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) selRect.unite(i->value->absoluteSelectionRect()); return pixelSnappedIntRect(selRect); }
LayoutRect LayoutSVGRoot::clippedOverflowRectForPaintInvalidation(const LayoutBoxModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const { // This is an open-coded aggregate of SVGLayoutSupport::clippedOverflowRectForPaintInvalidation, // LayoutSVGRoot::mapToVisibleRectInContainerSpace and LayoutReplaced::clippedOverflowRectForPaintInvalidation. // The reason for this is to optimize/minimize the paint invalidation rect when the box is not "decorated" // (does not have background/border/etc.) // Return early for any cases where we don't actually paint. if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) return LayoutRect(); // Compute the paint invalidation rect of the content of the SVG in the border-box coordinate space. FloatRect contentPaintInvalidationRect = paintInvalidationRectInLocalCoordinates(); contentPaintInvalidationRect = m_localToBorderBoxTransform.mapRect(contentPaintInvalidationRect); // Apply initial viewport clip, overflow:visible content is added to visualOverflow // but the most common case is that overflow is hidden, so always intersect. contentPaintInvalidationRect.intersect(pixelSnappedBorderBoxRect()); LayoutRect paintInvalidationRect = enclosingLayoutRect(contentPaintInvalidationRect); // If the box is decorated or is overflowing, extend it to include the border-box and overflow. if (m_hasBoxDecorationBackground || hasOverflowModel()) { // The selectionRect can project outside of the overflowRect, so take their union // for paint invalidation to avoid selection painting glitches. LayoutRect decoratedPaintInvalidationRect = unionRect(localSelectionRect(), visualOverflowRect()); paintInvalidationRect.unite(decoratedPaintInvalidationRect); } // Compute the paint invalidation rect in the parent coordinate space. LayoutRect rect(enclosingIntRect(paintInvalidationRect)); LayoutReplaced::mapToVisibleRectInAncestorSpace(paintInvalidationContainer, rect, paintInvalidationState); return rect; }
LayoutRect LayoutMultiColumnSet::fragmentsBoundingBox(const LayoutRect& boundingBoxInFlowThread) const { LayoutRect result; for (const auto& group : m_fragmentainerGroups) result.unite(group.fragmentsBoundingBox(boundingBoxInFlowThread)); return result; }
LayoutRect unionRect(const Vector<LayoutRect>& rects) { LayoutRect result; size_t count = rects.size(); for (size_t i = 0; i < count; ++i) result.unite(rects[i]); return result; }
LayoutRect SVGInlineFlowBox::calculateBoundaries() const { LayoutRect childRect; for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { if (!child->isSVGInlineTextBox() && !child->isSVGInlineFlowBox()) continue; childRect.unite(child->calculateBoundaries()); } return childRect; }
LayoutRect BlockPainter::overflowRectForPaintRejection() const { LayoutRect overflowRect = m_layoutBlock.visualOverflowRect(); if (!m_layoutBlock.hasOverflowModel() || !m_layoutBlock.usesCompositedScrolling()) return overflowRect; overflowRect.unite(m_layoutBlock.layoutOverflowRect()); overflowRect.move(-m_layoutBlock.scrolledContentOffset()); return overflowRect; }
bool BlockPainter::intersectsPaintRect(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const { LayoutRect overflowRect = m_layoutBlock.visualOverflowRect(); if (m_layoutBlock.hasOverflowModel() && m_layoutBlock.usesCompositedScrolling()) { overflowRect.unite(m_layoutBlock.layoutOverflowRect()); overflowRect.move(-m_layoutBlock.scrolledContentOffset()); } m_layoutBlock.flipForWritingMode(overflowRect); overflowRect.moveBy(paintOffset + m_layoutBlock.location()); return paintInfo.cullRect().intersectsCullRect(overflowRect); }
void LayoutMultiColumnSet::addOverflowFromChildren() { LayoutRect overflowRect; for (const auto& group : m_fragmentainerGroups) { LayoutRect rect = group.calculateOverflow(); rect.move(group.offsetFromColumnSet()); overflowRect.unite(rect); } addLayoutOverflow(overflowRect); addContentsVisualOverflow(overflowRect); }
LayoutRect SVGInlineTextBox::calculateBoundaries() const { LineLayoutSVGInlineText lineLayoutItem = LineLayoutSVGInlineText(this->lineLayoutItem()); float scalingFactor = lineLayoutItem.scalingFactor(); ASSERT(scalingFactor); LayoutUnit baseline = lineLayoutItem.scaledFont().fontMetrics().floatAscent() / scalingFactor; LayoutRect textBoundingRect; for (const SVGTextFragment& fragment : m_textFragments) textBoundingRect.unite(LayoutRect(fragment.overflowBoundingBox(baseline))); return textBoundingRect; }
LayoutRect InlinePainter::outlinePaintRect(const Vector<LayoutRect>& outlineRects, const LayoutPoint& paintOffset) const { int outlineOutset = m_layoutInline.styleRef().outlineOutsetExtent(); LayoutRect outlineRect; for (const LayoutRect& rect : outlineRects) { LayoutRect inflatedRect(rect); // Inflate the individual rects instead of the union, to avoid losing // rects which have degenerate width/height (== isEmpty() true.) inflatedRect.inflate(outlineOutset); outlineRect.unite(inflatedRect); } outlineRect.moveBy(paintOffset); return outlineRect; }
LayoutRect RenderSVGRoot::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const { if (style().visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) return LayoutRect(); FloatRect contentRepaintRect = m_localToBorderBoxTransform.mapRect(repaintRectInLocalCoordinates()); contentRepaintRect.intersect(snappedIntRect(borderBoxRect())); LayoutRect repaintRect = enclosingLayoutRect(contentRepaintRect); if (m_hasBoxDecorations || hasRenderOverflow()) repaintRect.unite(unionRect(localSelectionRect(false), visualOverflowRect())); return RenderReplaced::computeRectForRepaint(enclosingIntRect(repaintRect), repaintContainer); }
LayoutRect LayoutFlowThread::fragmentsBoundingBox(const LayoutRect& layerBoundingBox) const { ASSERT(!m_columnSetsInvalidated); LayoutRect result; for (auto* columnSet : m_multiColumnSetList) { DeprecatedPaintLayerFragments fragments; columnSet->collectLayerFragments(fragments, layerBoundingBox, LayoutRect(LayoutRect::infiniteIntRect())); for (const auto& fragment : fragments) { LayoutRect fragmentRect(layerBoundingBox); fragmentRect.intersect(fragment.paginationClip); fragmentRect.moveBy(fragment.paginationOffset); result.unite(fragmentRect); } } return result; }
LayoutRect SVGInlineTextBox::calculateBoundaries() const { LineLayoutSVGInlineText lineLayoutItem = LineLayoutSVGInlineText(this->getLineLayoutItem()); const SimpleFontData* fontData = lineLayoutItem.scaledFont().primaryFont(); DCHECK(fontData); if (!fontData) return LayoutRect(); float scalingFactor = lineLayoutItem.scalingFactor(); ASSERT(scalingFactor); LayoutUnit baseline(fontData->getFontMetrics().floatAscent() / scalingFactor); LayoutRect textBoundingRect; for (const SVGTextFragment& fragment : m_textFragments) textBoundingRect.unite(LayoutRect(fragment.overflowBoundingBox(baseline))); return textBoundingRect; }
// FIXME: This doesn't work for writing modes. LayoutRect RenderRegion::layoutOverflowRectForBoxForPropagation(const RenderBox* box) { // Only propagate interior layout overflow if we don't clip it. LayoutRect rect = box->borderBoxRectInRegion(this); rect = rectFlowPortionForBox(box, rect); if (!box->hasOverflowClip()) rect.unite(layoutOverflowRectForBox(box)); bool hasTransform = box->hasLayer() && box->layer()->transform(); if (box->isInFlowPositioned() || hasTransform) { if (hasTransform) rect = box->layer()->currentTransform().mapRect(rect); if (box->isInFlowPositioned()) rect.move(box->offsetForInFlowPosition()); } return rect; }
IntRect RenderView::selectionBounds(bool clipToVisibleContent) const { document()->updateStyleIfNeeded(); typedef HashMap<RenderObject*, RenderSelectionInfo*> SelectionMap; SelectionMap selectedObjects; RenderObject* os = m_selectionStart; RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos); while (os && os != stop) { if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. selectedObjects.set(os, new RenderSelectionInfo(os, clipToVisibleContent)); RenderBlock* cb = os->containingBlock(); while (cb && !cb->isRenderView()) { RenderSelectionInfo* blockInfo = selectedObjects.get(cb); if (blockInfo) break; selectedObjects.set(cb, new RenderSelectionInfo(cb, clipToVisibleContent)); cb = cb->containingBlock(); } } os = os->nextInPreOrder(); } // Now create a single bounding box rect that encloses the whole selection. LayoutRect selRect; SelectionMap::iterator end = selectedObjects.end(); for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) { RenderSelectionInfo* info = i->second; // RenderSelectionInfo::rect() is in the coordinates of the repaintContainer, so map to page coordinates. LayoutRect currRect = info->rect(); if (RenderBoxModelObject* repaintContainer = info->repaintContainer()) { FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currRect)); currRect = absQuad.enclosingBoundingBox(); } selRect.unite(currRect); delete info; } return pixelSnappedIntRect(selRect); }
LayoutRect RenderFlowThread::fragmentsBoundingBox(const LayoutRect& layerBoundingBox) { ASSERT(!m_regionsInvalidated); LayoutRect result; for (RenderMultiColumnSetList::const_iterator iter = m_multiColumnSetList.begin(); iter != m_multiColumnSetList.end(); ++iter) { RenderMultiColumnSet* columnSet = *iter; LayerFragments fragments; columnSet->collectLayerFragments(fragments, layerBoundingBox, PaintInfo::infiniteRect()); for (size_t i = 0; i < fragments.size(); ++i) { const LayerFragment& fragment = fragments.at(i); LayoutRect fragmentRect(layerBoundingBox); fragmentRect.intersect(fragment.paginationClip); fragmentRect.moveBy(fragment.paginationOffset); result.unite(fragmentRect); } } return result; }
LayoutRect AccessibilityObject::boundingBoxForQuads(RenderObject* obj, const Vector<FloatQuad>& quads) { ASSERT(obj); if (!obj) return LayoutRect(); size_t count = quads.size(); if (!count) return LayoutRect(); LayoutRect result; for (size_t i = 0; i < count; ++i) { LayoutRect r = quads[i].enclosingBoundingBox(); if (!r.isEmpty()) { if (obj->style()->hasAppearance()) obj->theme()->adjustRepaintRect(obj, r); result.unite(r); } } return result; }
IntRect RenderView::selectionBounds(bool clipToVisibleContent) const { typedef HashMap<RawPtr<RenderObject>, OwnPtr<RenderSelectionInfo> > SelectionMap; SelectionMap selectedObjects; RenderObject* os = m_selectionStart; RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos); while (os && os != stop) { if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. selectedObjects.set(os, adoptPtr(new RenderSelectionInfo(os, clipToVisibleContent))); RenderBlock* cb = os->containingBlock(); while (cb && !cb->isRenderView()) { OwnPtr<RenderSelectionInfo>& blockInfo = selectedObjects.add(cb, nullptr).storedValue->value; if (blockInfo) break; blockInfo = adoptPtr(new RenderSelectionInfo(cb, clipToVisibleContent)); cb = cb->containingBlock(); } } os = os->nextInPreOrder(); } // Now create a single bounding box rect that encloses the whole selection. LayoutRect selRect; SelectionMap::iterator end = selectedObjects.end(); for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) { RenderSelectionInfo* info = i->value.get(); // RenderSelectionInfo::rect() is in the coordinates of the paintInvalidationContainer, so map to page coordinates. LayoutRect currRect = info->rect(); if (const RenderLayerModelObject* paintInvalidationContainer = info->paintInvalidationContainer()) { FloatQuad absQuad = paintInvalidationContainer->localToAbsoluteQuad(FloatRect(currRect)); currRect = absQuad.enclosingBoundingBox(); } selRect.unite(currRect); } return pixelSnappedIntRect(selRect); }
LayoutRect SVGInlineTextBox::calculateBoundaries() const { LayoutRect textRect; LayoutSVGInlineText& textLayoutObject = toLayoutSVGInlineText(this->layoutObject()); float scalingFactor = textLayoutObject.scalingFactor(); ASSERT(scalingFactor); LayoutUnit baseline = textLayoutObject.scaledFont().fontMetrics().floatAscent() / scalingFactor; AffineTransform fragmentTransform; unsigned textFragmentsSize = m_textFragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = m_textFragments.at(i); FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); fragment.buildFragmentTransform(fragmentTransform); fragmentRect = fragmentTransform.mapRect(fragmentRect); textRect.unite(LayoutRect(fragmentRect)); } return textRect; }
// 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; }
void InlinePainter::paintOutline(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { const ComputedStyle& styleToUse = m_layoutInline.styleRef(); if (!styleToUse.hasOutline()) return; if (styleToUse.outlineStyleIsAuto()) { if (LayoutTheme::theme().shouldDrawDefaultFocusRing(&m_layoutInline)) { Vector<LayoutRect> focusRingRects; m_layoutInline.addFocusRingRects(focusRingRects, paintOffset); LayoutRect focusRingBoundingRect; for (const auto& rect : focusRingRects) focusRingBoundingRect.unite(rect); LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutInline, paintInfo.phase, focusRingBoundingRect); if (recorder.canUseCachedDrawing()) return; // Only paint the focus ring by hand if the theme isn't able to draw the focus ring. ObjectPainter(m_layoutInline).paintFocusRing(paintInfo, styleToUse, focusRingRects); } return; } if (styleToUse.outlineStyle() == BNONE) return; Vector<LayoutRect> rects; rects.append(LayoutRect()); for (InlineFlowBox* curr = m_layoutInline.firstLineBox(); curr; curr = curr->nextLineBox()) { RootInlineBox& root = curr->root(); LayoutUnit top = std::max<LayoutUnit>(root.lineTop(), curr->logicalTop()); LayoutUnit bottom = std::min<LayoutUnit>(root.lineBottom(), curr->logicalBottom()); rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top)); } rects.append(LayoutRect()); Color outlineColor = m_layoutInline.resolveColor(styleToUse, CSSPropertyOutlineColor); bool useTransparencyLayer = outlineColor.hasAlpha(); int outlineWidth = styleToUse.outlineWidth(); LayoutRect bounds; for (const auto& rect : rects) { LayoutRect rectCopy(rect); rectCopy.expand(LayoutSize(outlineWidth, outlineWidth)); bounds.unite(rectCopy); } bounds.moveBy(paintOffset); LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutInline, paintInfo.phase, bounds); if (recorder.canUseCachedDrawing()) return; GraphicsContext* graphicsContext = paintInfo.context; if (useTransparencyLayer) { graphicsContext->beginLayer(static_cast<float>(outlineColor.alpha()) / 255); outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue()); } for (unsigned i = 1; i < rects.size() - 1; i++) paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor); if (useTransparencyLayer) graphicsContext->endLayer(); }