Node* TreeScope::nodeFromPoint(const LayoutPoint& clientPoint, LayoutPoint* localPoint) { auto* frame = documentScope().frame(); auto* view = documentScope().view(); if (!frame || !view) return nullptr; float scaleFactor = frame->pageZoomFactor() * frame->frameScaleFactor(); LayoutPoint contentsPoint = clientPoint; contentsPoint.scale(scaleFactor); contentsPoint.moveBy(view->contentsScrollPosition()); LayoutRect visibleRect; #if PLATFORM(IOS) visibleRect = view->unobscuredContentRect(); #else visibleRect = view->visibleContentRect(); #endif if (!visibleRect.contains(contentsPoint)) return nullptr; HitTestResult result(contentsPoint); documentScope().renderView()->hitTest(HitTestRequest(), result); if (localPoint) *localPoint = result.localPoint(); return result.innerNode(); }
LayoutRect TableCellPainter::paintBounds(const LayoutPoint& paintOffset, PaintBoundOffsetBehavior paintBoundOffsetBehavior) { LayoutPoint adjustedPaintOffset = paintOffset; if (paintBoundOffsetBehavior == AddOffsetFromParent) adjustedPaintOffset.moveBy(m_layoutTableCell.location()); return LayoutRect(adjustedPaintOffset, LayoutSize(m_layoutTableCell.pixelSnappedSize())); }
void ImagePainter::paintAreaElementFocusRing(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { Document& document = m_layoutImage.document(); if (paintInfo.isPrinting() || !document.frame()->selection().isFocusedAndActive()) return; Element* focusedElement = document.focusedElement(); if (!isHTMLAreaElement(focusedElement)) return; HTMLAreaElement& areaElement = toHTMLAreaElement(*focusedElement); if (areaElement.imageElement() != m_layoutImage.node()) return; // Even if the theme handles focus ring drawing for entire elements, it won't // do it for an area within an image, so we don't call // LayoutTheme::themeDrawsFocusRing here. const ComputedStyle& areaElementStyle = *areaElement.ensureComputedStyle(); // If the outline width is 0 we want to avoid drawing anything even if we // don't use the value directly. if (!areaElementStyle.outlineWidth()) return; Path path = areaElement.getPath(&m_layoutImage); if (path.isEmpty()) return; LayoutPoint adjustedPaintOffset = paintOffset; adjustedPaintOffset.moveBy(m_layoutImage.location()); path.translate(FloatSize(adjustedPaintOffset.x(), adjustedPaintOffset.y())); if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( paintInfo.context, m_layoutImage, DisplayItem::kImageAreaFocusRing)) return; LayoutRect focusRect = m_layoutImage.contentBoxRect(); focusRect.moveBy(adjustedPaintOffset); LayoutObjectDrawingRecorder drawingRecorder(paintInfo.context, m_layoutImage, DisplayItem::kImageAreaFocusRing, focusRect); // FIXME: Clip path instead of context when Skia pathops is ready. // https://crbug.com/251206 paintInfo.context.save(); paintInfo.context.clip(pixelSnappedIntRect(focusRect)); paintInfo.context.drawFocusRing( path, areaElementStyle.getOutlineStrokeWidthForFocusRing(), areaElementStyle.outlineOffset(), m_layoutImage.resolveColor(areaElementStyle, CSSPropertyOutlineColor)); paintInfo.context.restore(); }
LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const LayoutPoint& startPoint) const { // If the element is the HTML body element or doesn't have a parent // return 0 and stop this algorithm. if (isBody() || !parent()) return LayoutPoint(); LayoutPoint referencePoint = startPoint; referencePoint.move(parent()->columnOffset(referencePoint)); // If the offsetParent of the element is null, or is the HTML body element, // return the distance between the canvas origin and the left border edge // of the element and stop this algorithm. Element* element = offsetParent(); if (!element) return referencePoint; if (const RenderBoxModelObject* offsetParent = element->renderBoxModelObject()) { if (offsetParent->isBox() && !offsetParent->isBody()) referencePoint.move(-toRenderBox(offsetParent)->borderLeft(), -toRenderBox(offsetParent)->borderTop()); if (!isOutOfFlowPositioned() || flowThreadContainingBlock()) { if (isRelPositioned()) referencePoint.move(relativePositionOffset()); RenderObject* current; for (current = parent(); current != offsetParent && current->parent(); current = current->parent()) { // FIXME: What are we supposed to do inside SVG content? if (!isOutOfFlowPositioned()) { if (current->isBox() && !current->isTableRow()) referencePoint.moveBy(toRenderBox(current)->topLeftLocation()); referencePoint.move(current->parent()->columnOffset(referencePoint)); } } if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent->isPositioned()) referencePoint.moveBy(toRenderBox(offsetParent)->topLeftLocation()); } } return referencePoint; }
bool InlineTextBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) { if (isLineBreak() || m_truncation == cFullTruncation) return false; LayoutPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(accumulatedOffset); LayoutRect rect(boxOrigin, size()); if (visibleToHitTestRequest(result.hitTestRequest()) && locationInContainer.intersects(rect)) { getLineLayoutItem().updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); if (result.addNodeToListBasedTestResult(getLineLayoutItem().node(), locationInContainer, rect) == StopHitTesting) return true; } return false; }
void BlockPainter::paintContinuationOutlines(const PaintInfo& info, const LayoutPoint& paintOffset) { LayoutInline* inlineCont = m_layoutBlock.inlineElementContinuation(); if (inlineCont && inlineCont->style()->hasOutline() && inlineCont->style()->visibility() == VISIBLE) { LayoutInline* inlineLayoutObject = toLayoutInline(inlineCont->node()->layoutObject()); LayoutBlock* cb = m_layoutBlock.containingBlock(); bool inlineEnclosedInSelfPaintingLayer = false; for (LayoutBoxModelObject* box = inlineLayoutObject; box != cb; box = box->parent()->enclosingBoxModelObject()) { if (box->hasSelfPaintingLayer()) { inlineEnclosedInSelfPaintingLayer = true; break; } } // Do not add continuations for outline painting by our containing block if we are a relative positioned // anonymous block (i.e. have our own layer), paint them straightaway instead. This is because a block depends on layoutObjects in its continuation table being // in the same layer. if (!inlineEnclosedInSelfPaintingLayer && !m_layoutBlock.hasLayer()) { cb->addContinuationWithOutline(inlineLayoutObject); } else if (!inlineLayoutObject->firstLineBox() || (!inlineEnclosedInSelfPaintingLayer && m_layoutBlock.hasLayer())) { // The outline might be painted multiple times if multiple blocks have the same inline element continuation, and the inline has a self-painting layer. ScopeRecorder scopeRecorder(*info.context); InlinePainter(*inlineLayoutObject).paintOutline(info, paintOffset - m_layoutBlock.locationOffset() + inlineLayoutObject->containingBlock()->location()); } } ContinuationOutlineTableMap* table = continuationOutlineTable(); if (table->isEmpty()) return; OwnPtr<ListHashSet<LayoutInline*>> continuations = table->take(&m_layoutBlock); if (!continuations) return; LayoutPoint accumulatedPaintOffset = paintOffset; // Paint each continuation outline. ListHashSet<LayoutInline*>::iterator end = continuations->end(); for (ListHashSet<LayoutInline*>::iterator it = continuations->begin(); it != end; ++it) { // Need to add in the coordinates of the intervening blocks. LayoutInline* flow = *it; LayoutBlock* block = flow->containingBlock(); for ( ; block && block != &m_layoutBlock; block = block->containingBlock()) accumulatedPaintOffset.moveBy(block->location()); ASSERT(block); InlinePainter(*flow).paintOutline(info, accumulatedPaintOffset); } }
bool EllipsisBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { // FIXME: the call to roundedLayoutPoint() below is temporary and should be removed once // the transition to LayoutUnit-based types is complete (crbug.com/321237) LayoutPoint adjustedLocation = accumulatedOffset + topLeft(); LayoutPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(accumulatedOffset); LayoutRect boundsRect(boxOrigin, size()); if (visibleToHitTestRequest(result.hitTestRequest()) && boundsRect.intersects(LayoutRect(HitTestLocation::rectForPoint(locationInContainer.point(), 0, 0, 0, 0)))) { lineLayoutItem().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); if (result.addNodeToListBasedTestResult(lineLayoutItem().node(), locationInContainer, boundsRect) == StopHitTesting) return true; } return false; }
bool InlineTextBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) { if (isLineBreak()) return false; LayoutPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(accumulatedOffset); LayoutRect rect(boxOrigin, size()); // FIXME: both calls to rawValue() below is temporary and should be removed once the transition // to LayoutUnit-based types is complete (crbug.com/321237) if (m_truncation != cFullTruncation && visibleToHitTestRequest(result.hitTestRequest()) && locationInContainer.intersects(rect)) { lineLayoutItem().updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); if (!result.addNodeToListBasedTestResult(lineLayoutItem().node(), locationInContainer, rect)) return true; } return false; }
void DeprecatedPaintLayerPainter::paintFragmentByApplyingTransform(GraphicsContext* context, const DeprecatedPaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutPoint& fragmentTranslation) { // This involves subtracting out the position of the layer in our current coordinate space, but preserving // the accumulated error for sub-pixel layout. LayoutPoint delta; m_paintLayer.convertToLayerCoords(paintingInfo.rootLayer, delta); delta.moveBy(fragmentTranslation); TransformationMatrix transform(m_paintLayer.renderableTransform(paintingInfo.globalPaintFlags())); IntPoint roundedDelta = roundedIntPoint(delta); transform.translateRight(roundedDelta.x(), roundedDelta.y()); LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta); Transform3DRecorder transform3DRecorder(*context, *m_paintLayer.layoutObject(), DisplayItem::Transform3DElementTransform, transform); // Now do a paint with the root layer shifted to be us. DeprecatedPaintLayerPaintingInfo transformedPaintingInfo(&m_paintLayer, LayoutRect(enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect))), paintingInfo.globalPaintFlags(), adjustedSubPixelAccumulation, paintingInfo.paintingRoot); paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags, ForceSingleFragment); }
void EllipsisBoxPainter::paintEllipsis(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom, const ComputedStyle& style) { bool haveSelection = !paintInfo.isPrinting() && paintInfo.phase != PaintPhaseTextClip && m_ellipsisBox.getSelectionState() != SelectionNone; LayoutRect paintRect(m_ellipsisBox.logicalFrameRect()); if (haveSelection) paintRect.unite(LayoutRect(m_ellipsisBox.selectionRect())); m_ellipsisBox.logicalRectToPhysicalRect(paintRect); paintRect.moveBy(paintOffset); GraphicsContext& context = paintInfo.context; DisplayItem::Type displayItemType = DisplayItem::paintPhaseToDrawingType(paintInfo.phase); if (DrawingRecorder::useCachedDrawingIfPossible(context, m_ellipsisBox, displayItemType)) return; DrawingRecorder recorder(context, m_ellipsisBox, displayItemType, FloatRect(paintRect)); LayoutPoint boxOrigin = m_ellipsisBox.locationIncludingFlipping(); boxOrigin.moveBy(paintOffset); LayoutRect boxRect(boxOrigin, LayoutSize(m_ellipsisBox.logicalWidth(), m_ellipsisBox.virtualLogicalHeight())); GraphicsContextStateSaver stateSaver(context); if (!m_ellipsisBox.isHorizontal()) context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockwise)); const Font& font = style.font(); if (haveSelection) paintSelection(context, boxOrigin, style, font); else if (paintInfo.phase == PaintPhaseSelection) return; TextPainter::Style textStyle = TextPainter::textPaintingStyle(m_ellipsisBox.getLineLayoutItem(), style, paintInfo); if (haveSelection) textStyle = TextPainter::selectionPaintingStyle(m_ellipsisBox.getLineLayoutItem(), true, paintInfo, textStyle); TextRun textRun = constructTextRun(font, m_ellipsisBox.ellipsisStr(), style, TextRun::AllowTrailingExpansion); LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.getFontMetrics().ascent()); TextPainter textPainter(context, font, textRun, textOrigin, boxRect, m_ellipsisBox.isHorizontal()); textPainter.paint(0, m_ellipsisBox.ellipsisStr().length(), m_ellipsisBox.ellipsisStr().length(), textStyle); }
PaintLayerPainter::PaintResult PaintLayerPainter::paintFragmentByApplyingTransform(GraphicsContext& context, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutPoint& fragmentTranslation) { // This involves subtracting out the position of the layer in our current coordinate space, but preserving // the accumulated error for sub-pixel layout. LayoutPoint delta; m_paintLayer.convertToLayerCoords(paintingInfo.rootLayer, delta); delta.moveBy(fragmentTranslation); TransformationMatrix transform(m_paintLayer.renderableTransform(paintingInfo.globalPaintFlags())); IntPoint roundedDelta = roundedIntPoint(delta); transform.translateRight(roundedDelta.x(), roundedDelta.y()); LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + (delta - roundedDelta); // TODO(jbroman): Put the real transform origin here, instead of using a // matrix with the origin baked in. FloatPoint3D transformOrigin; Transform3DRecorder transform3DRecorder(context, *m_paintLayer.layoutObject(), DisplayItem::Transform3DElementTransform, transform, transformOrigin); // Now do a paint with the root layer shifted to be us. PaintLayerPaintingInfo transformedPaintingInfo(&m_paintLayer, LayoutRect(enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect))), paintingInfo.globalPaintFlags(), adjustedSubPixelAccumulation); transformedPaintingInfo.ancestorHasClipPathClipping = paintingInfo.ancestorHasClipPathClipping; return paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags, ForceSingleFragment); }