bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) { IntPoint pointInContainer(_x, _y); IntSize containerToParentOffset(_tx, _ty); IntPoint pointInParent = pointInContainer - containerToParentOffset; IntPoint pointInBorderBox = pointInParent - parentOriginToBorderBox(); // Note: For now, we're ignoring hits to border and padding for <svg> IntPoint pointInContentBox = pointInBorderBox - borderOriginToContentBox(); if (!contentBoxRect().contains(pointInContentBox)) return false; IntPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { // FIXME: CSS/HTML assumes the local point is relative to the border box, right? updateHitTestResult(result, pointInBorderBox); return true; } } // Spec: Only graphical elements can be targeted by the mouse, so we don't check self here. // 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched." return false; }
bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const IntPoint& pointInContainer, const IntPoint& accumulatedOffset, HitTestAction hitTestAction) { IntPoint pointInParent = pointInContainer - toSize(accumulatedOffset); IntPoint pointInBorderBox = pointInParent - parentOriginToBorderBox(); // Note: For now, we're ignoring hits to border and padding for <svg> IntPoint pointInContentBox = pointInBorderBox - borderOriginToContentBox(); if (!contentBoxRect().contains(pointInContentBox)) return false; IntPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { // FIXME: CSS/HTML assumes the local point is relative to the border box, right? updateHitTestResult(result, pointInBorderBox); // FIXME: nodeAtFloatPoint() doesn't handle rect-based hit tests yet. result.addNodeToRectBasedTestResult(child->node(), pointInContainer); 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 && style()->pointerEvents() != PE_NONE) { // Only return true here, if the last hit testing phase 'BlockBackground' 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. updateHitTestResult(result, roundedIntPoint(localPoint)); return true; } return false; }
const AffineTransform& RenderSVGRoot::localToParentTransform() const { IntSize parentToBorderBoxOffset = parentOriginToBorderBox(); m_localToParentTransform = AffineTransform::translation(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height()) * localToBorderBoxTransform(); return m_localToParentTransform; }
const AffineTransform& RenderSVGRoot::localToParentTransform() const { IntSize parentToBorderBoxOffset = parentOriginToBorderBox(); AffineTransform borderBoxOriginToParentOrigin(localToBorderBoxTransform()); borderBoxOriginToParentOrigin.translateRight(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height()); m_localToParentTransform = borderBoxOriginToParentOrigin; return m_localToParentTransform; }
void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY) { if (paintInfo.context->paintingDisabled()) return; bool isVisible = style()->visibility() == VISIBLE; IntPoint parentOriginInContainer(parentX, parentY); IntPoint borderBoxOriginInContainer = parentOriginInContainer + parentOriginToBorderBox(); if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackground) && isVisible) paintBoxDecorations(paintInfo, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y()); if (paintInfo.phase == PaintPhaseBlockBackground) return; // An empty viewport disables rendering. FIXME: Should we still render filters? if (m_viewportSize.isEmpty()) return; // Don't paint if we don't have kids, except if we have filters we should paint those. if (!firstChild() && !selfWillPaint()) return; // 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(overflowClipRect(borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y())); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. childPaintInfo.applyTransform(localToRepaintContainerTransform(parentOriginInContainer)); bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) continueRendering = SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo); if (continueRendering) RenderBox::paint(childPaintInfo, 0, 0); if (childPaintInfo.phase == PaintPhaseForeground) SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, paintInfo.context); childPaintInfo.context->restore(); if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && isVisible) paintOutline(paintInfo.context, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y(), width(), height()); }