void RenderVideo::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { MediaPlayer* mediaPlayer = mediaElement()->player(); bool displayingPoster = videoElement()->shouldDisplayPosterImage(); Page* page = 0; if (Frame* frame = this->frame()) page = frame->page(); if (!displayingPoster && !mediaPlayer) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } LayoutRect rect = videoBox(); if (rect.isEmpty()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } rect.moveBy(paintOffset); if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantRepaintedObject(this, rect); if (displayingPoster) paintIntoRect(paintInfo.context, rect); else if (document()->view() && document()->view()->paintBehavior() & PaintBehaviorFlattenCompositingLayers) mediaPlayer->paintCurrentFrameInContext(paintInfo.context, pixelSnappedIntRect(rect)); else mediaPlayer->paint(paintInfo.context, pixelSnappedIntRect(rect)); }
bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseOutline && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseMask) return false; if (!paintInfo.shouldPaintWithinRoot(this)) return false; // if we're invisible or haven't received a layout yet, then just bail. if (style()->visibility() != VISIBLE) return false; LayoutPoint adjustedPaintOffset = paintOffset + location(); // Early exit if the element touches the edges. LayoutUnit top = adjustedPaintOffset.y() + visualOverflowRect().y(); LayoutUnit bottom = adjustedPaintOffset.y() + visualOverflowRect().maxY(); if (isSelected() && m_inlineBoxWrapper) { LayoutUnit selTop = paintOffset.y() + m_inlineBoxWrapper->root()->selectionTop(); LayoutUnit selBottom = paintOffset.y() + selTop + m_inlineBoxWrapper->root()->selectionHeight(); top = min(selTop, top); bottom = max(selBottom, bottom); } LayoutRect localRepaintRect = paintInfo.rect; localRepaintRect.inflate(maximalOutlineSize(paintInfo.phase)); if (adjustedPaintOffset.x() + visualOverflowRect().x() >= localRepaintRect.maxX() || adjustedPaintOffset.x() + visualOverflowRect().maxX() <= localRepaintRect.x()) return false; if (top >= localRepaintRect.maxY() || bottom <= localRepaintRect.y()) return false; return true; }
void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterEdge) { LayoutUnit height = oldClientAfterEdge; LayoutUnit offsetBreakAdjustment = 0; // Simulate a region break at height. If it points inside an auto logical height region, // then it may determine the region override logical content height. addForcedRegionBreak(height, this, false, &offsetBreakAdjustment); // During the normal layout phase of the flow thread all the auto-height regions have the overrideLogicalContentHeight set to max height. // We need to clear the overrideLogicalContentHeight for all the regions that didn't receive any content, starting with firstEmptyRegion. RenderRegion* firstEmptyRegion = 0; if (view()->normalLayoutPhase()) firstEmptyRegion = regionAtBlockOffset(height + offsetBreakAdjustment); // FIXME: the visual overflow of middle region (if it is the last one to contain any content in a render flow thread) // might not be taken into account because the render flow thread height is greater that that regions height + its visual overflow // because of how computeLogicalHeight is implemented for RenderFlowThread (as a sum of all regions height). // This means that the middle region will be marked as fit (even if it has visual overflow flowing into the next region) if (hasRenderOverflow() && ( (isHorizontalWritingMode() && visualOverflowRect().maxY() > clientBoxRect().maxY()) || (!isHorizontalWritingMode() && visualOverflowRect().maxX() > clientBoxRect().maxX()))) height = isHorizontalWritingMode() ? visualOverflowRect().maxY() : visualOverflowRect().maxX(); bool inEmptyRegionsSection = false; RenderRegion* lastReg = lastRegion(); for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().y() : region->flowThreadPortionRect().x()); LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().maxY() : region->flowThreadPortionRect().maxX()); RenderRegion::RegionState previousState = region->regionState(); RenderRegion::RegionState state = RenderRegion::RegionFit; if (flowMin <= 0) state = RenderRegion::RegionEmpty; if (flowMax > 0 && region == lastReg) state = RenderRegion::RegionOverset; region->setRegionState(state); // determine whether the NamedFlow object should dispatch a regionLayoutUpdate event // FIXME: currently it cannot determine whether a region whose regionOverset state remained either "fit" or "overset" has actually // changed, so it just assumes that the NamedFlow should dispatch the event if (previousState != state || state == RenderRegion::RegionFit || state == RenderRegion::RegionOverset) setDispatchRegionLayoutUpdateEvent(true); if (region == firstEmptyRegion) inEmptyRegionsSection = true; // Clear the overrideLogicalContentHeight value for autoheight regions that didn't receive any content. if (inEmptyRegionsSection && region->hasAutoLogicalHeight()) region->clearOverrideLogicalContentHeight(); } // With the regions overflow state computed we can also set the overset flag for the named flow. // If there are no valid regions in the chain, overset is true. m_overset = lastReg ? lastReg->regionState() == RenderRegion::RegionOverset : true; }
void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. if (pixelSnappedBorderBoxRect().isEmpty()) return; // Don't paint, if the context explicitely disabled it. if (paintInfo.context->paintingDisabled()) return; Page* page = 0; if (Frame* frame = this->frame()) page = frame->page(); // Don't paint if we don't have kids, except if we have filters we should paint those. if (!firstChild()) { SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); if (!resources || !resources->filter()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } } if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantRepaintedObject(this, visualOverflowRect()); // Make a copy of the PaintInfo because applyTransform will modify the damage rect. PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); // Apply initial viewport clip - not affected by overflow handling childPaintInfo.context->clip(pixelSnappedIntRect(overflowClipRect(paintOffset, paintInfo.renderRegion))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset); childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()) * localToBorderBoxTransform()); // SVGRenderingContext must be destroyed before we restore the childPaintInfo.context, because a filter may have // changed the context and it is only reverted when the SVGRenderingContext destructor finishes applying the filter. { SVGRenderingContext renderingContext; bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) { renderingContext.prepareToRenderSVGContent(this, childPaintInfo); continueRendering = renderingContext.isRenderingPrepared(); } if (continueRendering) RenderBox::paint(childPaintInfo, LayoutPoint()); } childPaintInfo.context->restore(); }
void TableSectionPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { ANNOTATE_GRAPHICS_CONTEXT(paintInfo, &m_layoutTableSection); ASSERT(!m_layoutTableSection.needsLayout()); // avoid crashing on bugs that cause us to paint with dirty layout if (m_layoutTableSection.needsLayout()) return; unsigned totalRows = m_layoutTableSection.numRows(); unsigned totalCols = m_layoutTableSection.table()->columns().size(); if (!totalRows || !totalCols) return; LayoutPoint adjustedPaintOffset = paintOffset + m_layoutTableSection.location(); { BoxClipper boxClipper(m_layoutTableSection, paintInfo, adjustedPaintOffset, ForceContentsClip); paintObject(paintInfo, adjustedPaintOffset); } if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && m_layoutTableSection.style()->visibility() == VISIBLE) { LayoutRect visualOverflowRect(m_layoutTableSection.visualOverflowRect()); visualOverflowRect.moveBy(adjustedPaintOffset); ObjectPainter(m_layoutTableSection).paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, m_layoutTableSection.size()), visualOverflowRect); } }
IntRect RenderReplaced::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) return IntRect(); // The selectionRect can project outside of the overflowRect, so take their union // for repainting to avoid selection painting glitches. IntRect r = unionRect(localSelectionRect(false), visualOverflowRect()); RenderView* v = view(); if (v) { // FIXME: layoutDelta needs to be applied in parts before/after transforms and // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 r.move(v->layoutDelta()); } if (style()) { if (style()->hasAppearance()) // The theme may wish to inflate the rect used when repainting. theme()->adjustRepaintRect(this, r); if (v) r.inflate(style()->outlineSize()); } computeRectForRepaint(repaintContainer, r); return r; }
void RenderSVGRoot::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const { // Apply our local transforms (except for x/y translation), then our shadow, // and then call RenderBox's method to handle all the normal CSS Box model bits repaintRect = m_localToBorderBoxTransform.mapRect(repaintRect); const SVGRenderStyle& svgStyle = style().svgStyle(); if (const ShadowData* shadow = svgStyle.shadow()) shadow->adjustRectForShadow(repaintRect); // Apply initial viewport clip if (shouldApplyViewportClip()) repaintRect.intersect(pixelSnappedBorderBoxRect()); if (m_hasBoxDecorations || hasRenderOverflow()) { // The selectionRect can project outside of the overflowRect, so take their union // for repainting to avoid selection painting glitches. LayoutRect decoratedRepaintRect = unionRect(localSelectionRect(false), visualOverflowRect()); repaintRect.unite(decoratedRepaintRect); } LayoutRect rect = enclosingIntRect(repaintRect); RenderReplaced::computeRectForRepaint(repaintContainer, rect, fixed); repaintRect = rect; }
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; }
void RenderNamedFlowThread::computeOversetStateForRegions(LayoutUnit oldClientAfterEdge) { LayoutUnit height = oldClientAfterEdge; // FIXME: the visual overflow of middle region (if it is the last one to contain any content in a render flow thread) // might not be taken into account because the render flow thread height is greater that that regions height + its visual overflow // because of how computeLogicalHeight is implemented for RenderNamedFlowThread (as a sum of all regions height). // This means that the middle region will be marked as fit (even if it has visual overflow flowing into the next region) if (hasRenderOverflow() && ( (isHorizontalWritingMode() && visualOverflowRect().maxY() > clientBoxRect().maxY()) || (!isHorizontalWritingMode() && visualOverflowRect().maxX() > clientBoxRect().maxX()))) height = isHorizontalWritingMode() ? visualOverflowRect().maxY() : visualOverflowRect().maxX(); RenderRegion* lastReg = lastRegion(); for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().y() : region->flowThreadPortionRect().x()); LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().maxY() : region->flowThreadPortionRect().maxX()); RegionOversetState previousState = region->regionOversetState(); RegionOversetState state = RegionFit; if (flowMin <= 0) state = RegionEmpty; if (flowMax > 0 && region == lastReg) state = RegionOverset; region->setRegionOversetState(state); // determine whether the NamedFlow object should dispatch a regionLayoutUpdate event // FIXME: currently it cannot determine whether a region whose regionOverset state remained either "fit" or "overset" has actually // changed, so it just assumes that the NamedFlow should dispatch the event if (previousState != state || state == RegionFit || state == RegionOverset) setDispatchRegionLayoutUpdateEvent(true); if (previousState != state) setDispatchRegionOversetChangeEvent(true); } // If the number of regions has changed since we last computed the overset property, schedule the regionOversetChange event. if (previousRegionCountChanged()) { setDispatchRegionOversetChangeEvent(true); updatePreviousRegionCount(); } // With the regions overflow state computed we can also set the overset flag for the named flow. // If there are no valid regions in the chain, overset is true. m_overset = lastReg ? lastReg->regionOversetState() == RegionOverset : true; }
LayoutRect RenderReplaced::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const { if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) return LayoutRect(); // The selectionRect can project outside of the overflowRect, so take their union // for paint invalidation to avoid selection painting glitches. LayoutRect r = isSelected() ? localSelectionRect() : visualOverflowRect(); mapRectToPaintInvalidationBacking(paintInvalidationContainer, r, paintInvalidationState); return r; }
bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseOutline && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseMask) return false; if (!paintInfo.shouldPaintWithinRoot(*this)) return false; // if we're invisible or haven't received a layout yet, then just bail. if (style().visibility() != VISIBLE) return false; RenderNamedFlowFragment* namedFlowFragment = currentRenderNamedFlowFragment(); // Check our region range to make sure we need to be painting in this region. if (namedFlowFragment && !namedFlowFragment->flowThread()->objectShouldFragmentInFlowRegion(this, namedFlowFragment)) return false; LayoutPoint adjustedPaintOffset = paintOffset + location(); // Early exit if the element touches the edges. LayoutUnit top = adjustedPaintOffset.y() + visualOverflowRect().y(); LayoutUnit bottom = adjustedPaintOffset.y() + visualOverflowRect().maxY(); if (isSelected() && m_inlineBoxWrapper) { const RootInlineBox& rootBox = m_inlineBoxWrapper->root(); LayoutUnit selTop = paintOffset.y() + rootBox.selectionTop(); LayoutUnit selBottom = paintOffset.y() + selTop + rootBox.selectionHeight(); top = std::min(selTop, top); bottom = std::max(selBottom, bottom); } LayoutRect localRepaintRect = paintInfo.rect; adjustRectWithMaximumOutline(paintInfo.phase, localRepaintRect); if (adjustedPaintOffset.x() + visualOverflowRect().x() >= localRepaintRect.maxX() || adjustedPaintOffset.x() + visualOverflowRect().maxX() <= localRepaintRect.x()) return false; if (top >= localRepaintRect.maxY() || bottom <= localRepaintRect.y()) return false; return true; }
LayoutRect RenderReplaced::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const { if (style().visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) return LayoutRect(); // The selectionRect can project outside of the overflowRect, so take their union // for repainting to avoid selection painting glitches. LayoutRect r = unionRect(localSelectionRect(false), visualOverflowRect()); // FIXME: layoutDelta needs to be applied in parts before/after transforms and // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 r.move(view().layoutDelta()); return computeRectForRepaint(r, repaintContainer); }
bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutPoint adjustedPaintOffset = paintOffset + location(); // Early exit if the element touches the edges. LayoutUnit top = adjustedPaintOffset.y() + visualOverflowRect().y(); LayoutUnit bottom = adjustedPaintOffset.y() + visualOverflowRect().maxY(); if (isSelected() && inlineBoxWrapper()) { LayoutUnit selTop = paintOffset.y() + inlineBoxWrapper()->root().selectionTop(); LayoutUnit selBottom = paintOffset.y() + selTop + inlineBoxWrapper()->root().selectionHeight(); top = std::min(selTop, top); bottom = std::max(selBottom, bottom); } if (adjustedPaintOffset.x() + visualOverflowRect().x() >= paintInfo.rect.maxX() || adjustedPaintOffset.x() + visualOverflowRect().maxX() <= paintInfo.rect.x()) return false; if (top >= paintInfo.rect.maxY() || bottom <= paintInfo.rect.y()) return false; return true; }
void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterEdge) { LayoutUnit height = oldClientAfterEdge; // FIXME: the visual overflow of middle region (if it is the last one to contain any content in a render flow thread) // might not be taken into account because the render flow thread height is greater that that regions height + its visual overflow // because of how computeLogicalHeight is implemented for RenderFlowThread (as a sum of all regions height). // This means that the middle region will be marked as fit (even if it has visual overflow flowing into the next region) if (hasRenderOverflow()) height = isHorizontalWritingMode() ? visualOverflowRect().maxY() : visualOverflowRect().maxX(); for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; if (!region->isValid()) { region->setRegionState(RenderRegion::RegionUndefined); continue; } LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->regionRect().y() : region->regionRect().x()); LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->regionRect().maxY() : region->regionRect().maxX()); RenderRegion::RegionState previousState = region->regionState(); RenderRegion::RegionState state = RenderRegion::RegionFit; if (flowMin <= 0) state = RenderRegion::RegionEmpty; if (flowMax > 0) state = RenderRegion::RegionOverflow; region->setRegionState(state); // determine whether this region should dispatch a regionLayoutUpdate event // FIXME: currently it cannot determine whether a region whose regionOverflow state remained either "fit" or "overflow" has actually // changed, so it just assumes that those region should dispatch the event if (previousState != state || state == RenderRegion::RegionFit || state == RenderRegion::RegionOverflow) region->setDispatchRegionLayoutUpdateEvent(true); } // With the regions overflow state computed we can also set the overflow for the named flow. RenderRegion* lastReg = lastRegion(); m_overflow = lastReg && (lastReg->regionState() == RenderRegion::RegionOverflow); }
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); }
bool LayoutReplaced::shouldPaint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const { if (paintInfo.phase != PaintPhaseForeground && !shouldPaintSelfOutline(paintInfo.phase) && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseMask && paintInfo.phase != PaintPhaseClippingMask) return false; if (!paintInfo.shouldPaintWithinRoot(this)) return false; // if we're invisible or haven't received a layout yet, then just bail. if (style()->visibility() != VISIBLE) return false; LayoutRect paintRect(visualOverflowRect()); paintRect.unite(localSelectionRect()); paintRect.moveBy(paintOffset + location()); if (!paintInfo.cullRect().intersectsCullRect(paintRect)) return false; return true; }
LayoutRect RenderReplaced::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const { if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) return LayoutRect(); // The selectionRect can project outside of the overflowRect, so take their union // for repainting to avoid selection painting glitches. LayoutRect r = unionRect(localSelectionRect(false), visualOverflowRect()); RenderView* v = view(); if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && v) { // FIXME: layoutDelta needs to be applied in parts before/after transforms and // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 r.move(v->layoutDelta()); } if (style()) { if (v) r.inflate(style()->outlineSize()); } computeRectForRepaint(repaintContainer, r); return r; }
bool LayoutSVGRoot::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { LayoutPoint pointInParent = locationInContainer.point() - toLayoutSize(accumulatedOffset); LayoutPoint pointInBorderBox = pointInParent - toLayoutSize(location()); // Only test SVG content if the point is in our content box, or in case we // don't clip to the viewport, the visual overflow rect. // FIXME: This should be an intersection when rect-based hit tests are supported by nodeAtFloatPoint. if (contentBoxRect().contains(pointInBorderBox) || (!shouldApplyViewportClip() && visualOverflowRect().contains(pointInBorderBox))) { const AffineTransform& localToParentTransform = this->localToParentTransform(); if (localToParentTransform.isInvertible()) { FloatPoint localPoint = localToParentTransform.inverse().mapPoint(FloatPoint(pointInParent)); for (LayoutObject* child = lastChild(); child; child = child->previousSibling()) { // FIXME: nodeAtFloatPoint() doesn't handle rect-based hit tests yet. if (child->nodeAtFloatPoint(result, localPoint, hitTestAction)) { updateHitTestResult(result, pointInBorderBox); if (result.addNodeToListBasedTestResult(child->node(), locationInContainer) == StopHitTesting) return true; } } } } // If we didn't early exit above, we've just hit the container <svg> element. Unlike SVG 1.1, 2nd Edition allows container elements to be hit. if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && visibleToHitTestRequest(result.hitTestRequest())) { // Only return true here, if the last hit testing phase 'BlockBackground' (or 'ChildBlockBackground' - depending on context) is executed. // If we'd return true in the 'Foreground' phase, hit testing would stop immediately. For SVG only trees this doesn't matter. // Though when we have a <foreignObject> subtree we need to be able to detect hits on the background of a <div> element. // If we'd return true here in the 'Foreground' phase, we are not able to detect these hits anymore. LayoutRect boundsRect(accumulatedOffset + location(), size()); if (locationInContainer.intersects(boundsRect)) { updateHitTestResult(result, pointInBorderBox); if (result.addNodeToListBasedTestResult(node(), locationInContainer, boundsRect) == StopHitTesting) return true; } } return false; }
void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. if (pixelSnappedBorderBoxRect().isEmpty()) return; // Don't paint, if the context explicitly disabled it. if (paintInfo.context->paintingDisabled()) return; // SVG outlines are painted during PaintPhaseForeground. if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) return; // An empty viewBox also disables rendering. // (http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute) if (svgSVGElement().hasEmptyViewBox()) return; Page* page = frame().page(); // Don't paint if we don't have kids, except if we have filters we should paint those. if (!firstChild()) { auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this); if (!resources || !resources->filter()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } } if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantRepaintedObject(this, visualOverflowRect()); // Make a copy of the PaintInfo because applyTransform will modify the damage rect. PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); // Apply initial viewport clip if (shouldApplyViewportClip()) childPaintInfo.context->clip(snappedIntRect(overflowClipRect(paintOffset, currentRenderNamedFlowFragment()))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset); childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()) * localToBorderBoxTransform()); // SVGRenderingContext must be destroyed before we restore the childPaintInfo.context, because a filter may have // changed the context and it is only reverted when the SVGRenderingContext destructor finishes applying the filter. { SVGRenderingContext renderingContext; bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) { renderingContext.prepareToRenderSVGContent(*this, childPaintInfo); continueRendering = renderingContext.isRenderingPrepared(); } if (continueRendering) { childPaintInfo.updateSubtreePaintRootForChildren(this); for (auto& child : childrenOfType<RenderElement>(*this)) child.paint(childPaintInfo, location()); } } childPaintInfo.context->restore(); }