tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 7eaee8e028d96a9fd2b3e29c2e50421a03e04597
parent 8b39e2f000103df4f00897d660291d019993b423
Author: longsonr <longsonr@gmail.com>
Date:   Fri, 21 Nov 2025 08:28:25 +0000

Bug 2000531 - Fix getBBox when content has padding and scale r=dholbert,firefox-svg-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D273465

Diffstat:
Mdom/svg/SVGContentUtils.cpp | 27++++++++++++++++-----------
Mtesting/web-platform/tests/svg/types/scripted/SVGGraphicsElement-padding.svg | 33+++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+), 11 deletions(-)

diff --git a/dom/svg/SVGContentUtils.cpp b/dom/svg/SVGContentUtils.cpp @@ -438,9 +438,8 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, CTMType aCTMType, 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)); + aMatrix.PostTranslate(nsPresContext::AppUnitsToFloatCSSPixels(point.x), + nsPresContext::AppUnitsToFloatCSSPixels(point.y)); }; gfxMatrix matrix = getLocalTransformHelper(aElement, aHaveRecursed); @@ -502,8 +501,7 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, CTMType aCTMType, if (frame->IsSVGOuterSVGFrame()) { nsMargin bp = frame->GetUsedBorderAndPadding(); int32_t appUnitsPerCSSPixel = AppUnitsPerCSSPixel(); - float xOffset = NSAppUnitsToFloatPixels(bp.left, appUnitsPerCSSPixel); - float yOffset = NSAppUnitsToFloatPixels(bp.top, appUnitsPerCSSPixel); + nscoord xOffset, yOffset; // See // https://drafts.csswg.org/css-transforms/#valdef-transform-box-fill-box // For elements with associated CSS layout box, the used value for fill-box @@ -511,17 +509,24 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, CTMType aCTMType, switch (frame->StyleDisplay()->mTransformBox) { case StyleTransformBox::FillBox: case StyleTransformBox::ContentBox: - // Apply border/padding separate from the rest of the transform. - // i.e. after it's been transformed - tm.PostTranslate(xOffset, yOffset); + xOffset = bp.left; + yOffset = bp.top; break; case StyleTransformBox::StrokeBox: case StyleTransformBox::ViewBox: - case StyleTransformBox::BorderBox: - // Apply border/padding before we transform the surface. - tm.PreTranslate(xOffset, yOffset); + case StyleTransformBox::BorderBox: { + // Extract the rotation component of the matrix. + float angle = std::atan2(tm._12, tm._11); + float cosAngle = std::cos(angle); + float sinAngle = std::sin(angle); + // Apply that rotation to bp.left and bp.top. + xOffset = bp.left * cosAngle - bp.top * sinAngle; + yOffset = bp.top * cosAngle + bp.left * sinAngle; break; + } } + tm.PostTranslate(NSAppUnitsToFloatPixels(xOffset, appUnitsPerCSSPixel), + NSAppUnitsToFloatPixels(yOffset, appUnitsPerCSSPixel)); } if (!ancestor || !ancestor->IsElement()) { diff --git a/testing/web-platform/tests/svg/types/scripted/SVGGraphicsElement-padding.svg b/testing/web-platform/tests/svg/types/scripted/SVGGraphicsElement-padding.svg @@ -51,6 +51,17 @@ test(function() { let svg = document.getElementById("svg"); + svg.setAttribute("style", "padding-left: 12px; padding-bottom: 10px; padding-top: 12px; padding-right: 24px; transform: rotate(180deg);"); + let ctm = svg.getScreenCTM(); + let pt = DOMPoint.fromPoint({x: 50, y: 50}); + let transformedPoint = pt.matrixTransform(ctm.inverse()); + svg.removeAttribute("style"); + assert_approx_equals(transformedPoint.x, pt.x + 24, 0.1); + assert_approx_equals(transformedPoint.y, pt.y + 10, 0.1); + }, 'getScreenCTM with padding and rotation'); + + test(function() { + let svg = document.getElementById("svg"); svg.setAttribute("style", "padding-left: 12px; transform: rotate(180deg); transform-box: content-box"); let ctm = svg.getScreenCTM(); let pt = DOMPoint.fromPoint({x: 50, y: 50}); @@ -60,5 +71,27 @@ assert_equals(transformedPoint.y, pt.y); }, 'getScreenCTM with padding-left, rotation and content-box'); + test(function() { + let svg = document.getElementById("svg"); + svg.setAttribute("style", "padding-left: 12px; transform: scale(2)"); + let ctm = svg.getScreenCTM(); + let pt = DOMPoint.fromPoint({x: 50, y: 50}); + let transformedPoint = pt.matrixTransform(ctm.inverse()); + svg.removeAttribute("style"); + assert_equals(transformedPoint.x, pt.x - 3); + assert_equals(transformedPoint.y, pt.y); + }, 'getScreenCTM with padding-left, scale'); + + test(function() { + let svg = document.getElementById("svg"); + svg.setAttribute("style", "border-width: 12px; transform: rotate(180deg);"); + let ctm = svg.getScreenCTM(); + let pt = DOMPoint.fromPoint({x: 50, y: 50}); + let transformedPoint = pt.matrixTransform(ctm.inverse()); + svg.removeAttribute("style"); + assert_equals(transformedPoint.x, pt.x); + assert_equals(transformedPoint.y, pt.y); + }, 'getScreenCTM with border-width and rotation'); + ]]></script> </svg>