diff options
Diffstat (limited to 'dom/svg/SVGContentUtils.cpp')
-rw-r--r-- | dom/svg/SVGContentUtils.cpp | 85 |
1 files changed, 58 insertions, 27 deletions
diff --git a/dom/svg/SVGContentUtils.cpp b/dom/svg/SVGContentUtils.cpp index 0913ae48c5..72534c12e8 100644 --- a/dom/svg/SVGContentUtils.cpp +++ b/dom/svg/SVGContentUtils.cpp @@ -493,6 +493,14 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM, return ret; }; + auto postTranslateFrameOffset = [](nsIFrame* aFrame, nsIFrame* aAncestorFrame, + gfx::Matrix& aMatrix) { + auto point = aFrame->GetOffsetTo(aAncestorFrame); + aMatrix = + aMatrix.PostTranslate(nsPresContext::AppUnitsToFloatCSSPixels(point.x), + nsPresContext::AppUnitsToFloatCSSPixels(point.y)); + }; + gfxMatrix matrix = getLocalTransformHelper(aElement, aHaveRecursed); SVGElement* element = aElement; @@ -530,39 +538,62 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM, matrix = getLocalTransformHelper(aElement, true); } - if (auto* f = element->GetPrimaryFrame()) { - if (f->IsSVGOuterSVGFrame()) { - nsMargin bp = f->GetUsedBorderAndPadding(); - matrix.PostTranslate( - NSAppUnitsToFloatPixels(bp.left, AppUnitsPerCSSPixel()), - NSAppUnitsToFloatPixels(bp.top, AppUnitsPerCSSPixel())); - } + gfx::Matrix tm = gfx::ToMatrix(matrix); + nsIFrame* frame = element->GetPrimaryFrame(); + if (!frame) { + return tm; + } + if (frame->IsSVGOuterSVGFrame()) { + nsMargin bp = frame->GetUsedBorderAndPadding(); + int32_t appUnitsPerCSSPixel = AppUnitsPerCSSPixel(); + tm.PostTranslate(NSAppUnitsToFloatPixels(bp.left, appUnitsPerCSSPixel), + NSAppUnitsToFloatPixels(bp.top, appUnitsPerCSSPixel)); } if (!ancestor || !ancestor->IsElement()) { - return gfx::ToMatrix(matrix); + return tm; } if (auto* ancestorSVG = SVGElement::FromNode(ancestor)) { - return gfx::ToMatrix(matrix) * GetCTMInternal(ancestorSVG, true, true); - } - - // XXX this does not take into account CSS transform, or that the non-SVG - // content that we've hit may itself be inside an SVG foreignObject higher up - Document* currentDoc = aElement->GetComposedDoc(); - float x = 0.0f, y = 0.0f; - if (currentDoc && element->IsSVGElement(nsGkAtoms::svg)) { - PresShell* presShell = currentDoc->GetPresShell(); - if (presShell) { - nsIFrame* frame = element->GetPrimaryFrame(); - nsIFrame* ancestorFrame = presShell->GetRootFrame(); - if (frame && ancestorFrame) { - nsPoint point = frame->GetOffsetTo(ancestorFrame); - x = nsPresContext::AppUnitsToFloatCSSPixels(point.x); - y = nsPresContext::AppUnitsToFloatCSSPixels(point.y); - } - } + return tm * GetCTMInternal(ancestorSVG, true, true); } - return ToMatrix(matrix).PostTranslate(x, y); + nsIFrame* parentFrame = frame->GetParent(); + if (!parentFrame) { + return tm; + } + postTranslateFrameOffset(frame, parentFrame, tm); + + nsIContent* nearestSVGAncestor = ancestor; + while (nearestSVGAncestor && !nearestSVGAncestor->IsSVGElement()) { + nearestSVGAncestor = nearestSVGAncestor->GetFlattenedTreeParent(); + } + + nsIFrame* ancestorFrame; + if (nearestSVGAncestor) { + ancestorFrame = nearestSVGAncestor->GetPrimaryFrame(); + } else { + Document* currentDoc = aElement->GetComposedDoc(); + PresShell* presShell = currentDoc ? currentDoc->GetPresShell() : nullptr; + ancestorFrame = presShell ? presShell->GetRootFrame() : nullptr; + } + if (!ancestorFrame) { + return tm; + } + auto transformToAncestor = nsLayoutUtils::GetTransformToAncestor( + RelativeTo{parentFrame, ViewportType::Layout}, + RelativeTo{ancestorFrame, ViewportType::Layout}, nsIFrame::IN_CSS_UNITS); + gfx::Matrix result2d; + if (transformToAncestor.CanDraw2D(&result2d)) { + tm = tm * result2d; + } else { + // The transform from our outer SVG matrix to the root is a 3D + // transform. We can't really process that so give up and just + // return the overall translation from the outer SVG to the root. + postTranslateFrameOffset(parentFrame, ancestorFrame, tm); + } + return nearestSVGAncestor + ? tm * GetCTMInternal(static_cast<SVGElement*>(nearestSVGAncestor), + true, true) + : tm; } gfx::Matrix SVGContentUtils::GetCTM(SVGElement* aElement, bool aScreenCTM) { |