Bug 1903352 - SVG attribute values should not be zoomed r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D214286
This commit is contained in:
longsonr 2024-06-20 10:41:02 +00:00
Родитель e729cdd153
Коммит 51a0a02f4b
15 изменённых файлов: 118 добавлений и 69 удалений

Просмотреть файл

@ -376,31 +376,37 @@ float UserSpaceMetricsWithSize::GetAxisLength(uint8_t aCtxType) const {
float SVGAnimatedLength::GetPixelsPerUnit(const SVGElement* aSVGElement,
uint8_t aUnitType) const {
return SVGLength::GetPixelsPerUnit(SVGElementMetrics(aSVGElement), aUnitType,
mCtxType);
mCtxType, false);
}
float SVGAnimatedLength::GetPixelsPerUnit(const SVGViewportElement* aCtx,
uint8_t aUnitType) const {
float SVGAnimatedLength::GetPixelsPerUnitWithZoom(const SVGElement* aSVGElement,
uint8_t aUnitType) const {
return SVGLength::GetPixelsPerUnit(SVGElementMetrics(aSVGElement), aUnitType,
mCtxType, true);
}
float SVGAnimatedLength::GetPixelsPerUnitWithZoom(
const SVGViewportElement* aCtx, uint8_t aUnitType) const {
return SVGLength::GetPixelsPerUnit(SVGElementMetrics(aCtx, aCtx), aUnitType,
mCtxType);
mCtxType, true);
}
float SVGAnimatedLength::GetPixelsPerUnit(nsIFrame* aFrame,
uint8_t aUnitType) const {
float SVGAnimatedLength::GetPixelsPerUnitWithZoom(nsIFrame* aFrame,
uint8_t aUnitType) const {
const nsIContent* content = aFrame->GetContent();
MOZ_ASSERT(!content->IsText(), "Not expecting text content");
if (content->IsSVGElement()) {
return SVGLength::GetPixelsPerUnit(
SVGElementMetrics(static_cast<const SVGElement*>(content)), aUnitType,
mCtxType);
mCtxType, true);
}
return SVGLength::GetPixelsPerUnit(NonSVGFrameUserSpaceMetrics(aFrame),
aUnitType, mCtxType);
aUnitType, mCtxType, true);
}
float SVGAnimatedLength::GetPixelsPerUnit(const UserSpaceMetrics& aMetrics,
uint8_t aUnitType) const {
return SVGLength::GetPixelsPerUnit(aMetrics, aUnitType, mCtxType);
float SVGAnimatedLength::GetPixelsPerUnitWithZoom(
const UserSpaceMetrics& aMetrics, uint8_t aUnitType) const {
return SVGLength::GetPixelsPerUnit(aMetrics, aUnitType, mCtxType, true);
}
void SVGAnimatedLength::SetBaseValueInSpecifiedUnits(float aValue,
@ -653,7 +659,7 @@ float SVGLengthAndInfo::ConvertUnits(const SVGLengthAndInfo& aTo) const {
float SVGLengthAndInfo::ValueInPixels(const UserSpaceMetrics& aMetrics) const {
return mValue == 0.0f ? 0.0f
: mValue * SVGLength::GetPixelsPerUnit(
aMetrics, mUnitType, mCtxType);
aMetrics, mUnitType, mCtxType, false);
}
void SVGLengthAndInfo::Add(const SVGLengthAndInfo& aValueToAdd,
@ -673,7 +679,7 @@ void SVGLengthAndInfo::Add(const SVGLengthAndInfo& aValueToAdd,
mUnitType = aValueToAdd.mUnitType;
mCtxType = aValueToAdd.mCtxType;
mValue = (currentLength + lengthToAdd) /
SVGLength::GetPixelsPerUnit(metrics, mUnitType, mCtxType);
SVGLength::GetPixelsPerUnit(metrics, mUnitType, mCtxType, false);
}
void SVGLengthAndInfo::Interpolate(const SVGLengthAndInfo& aStart,

Просмотреть файл

@ -151,14 +151,17 @@ class SVGAnimatedLength {
float GetAnimValue(const SVGElement* aSVGElement) const {
return mAnimVal * GetPixelsPerUnit(aSVGElement, mAnimUnitType);
}
float GetAnimValue(nsIFrame* aFrame) const {
return mAnimVal * GetPixelsPerUnit(aFrame, mAnimUnitType);
float GetAnimValueWithZoom(const SVGElement* aSVGElement) const {
return mAnimVal * GetPixelsPerUnitWithZoom(aSVGElement, mAnimUnitType);
}
float GetAnimValue(const SVGViewportElement* aCtx) const {
return mAnimVal * GetPixelsPerUnit(aCtx, mAnimUnitType);
float GetAnimValueWithZoom(nsIFrame* aFrame) const {
return mAnimVal * GetPixelsPerUnitWithZoom(aFrame, mAnimUnitType);
}
float GetAnimValue(const UserSpaceMetrics& aMetrics) const {
return mAnimVal * GetPixelsPerUnit(aMetrics, mAnimUnitType);
float GetAnimValueWithZoom(const SVGViewportElement* aCtx) const {
return mAnimVal * GetPixelsPerUnitWithZoom(aCtx, mAnimUnitType);
}
float GetAnimValueWithZoom(const UserSpaceMetrics& aMetrics) const {
return mAnimVal * GetPixelsPerUnitWithZoom(aMetrics, mAnimUnitType);
}
uint8_t GetCtxType() const { return mCtxType; }
@ -197,13 +200,15 @@ class SVGAnimatedLength {
// These APIs returns the number of user-unit pixels per unit of the
// given type, in a given context (frame/element/etc).
float GetPixelsPerUnit(nsIFrame* aFrame, uint8_t aUnitType) const;
float GetPixelsPerUnit(const UserSpaceMetrics& aMetrics,
uint8_t aUnitType) const;
float GetPixelsPerUnit(const SVGElement* aSVGElement,
uint8_t aUnitType) const;
float GetPixelsPerUnit(const SVGViewportElement* aCtx,
uint8_t aUnitType) const;
float GetPixelsPerUnitWithZoom(nsIFrame* aFrame, uint8_t aUnitType) const;
float GetPixelsPerUnitWithZoom(const UserSpaceMetrics& aMetrics,
uint8_t aUnitType) const;
float GetPixelsPerUnitWithZoom(const SVGElement* aSVGElement,
uint8_t aUnitType) const;
float GetPixelsPerUnitWithZoom(const SVGViewportElement* aCtx,
uint8_t aUnitType) const;
// SetBaseValue and SetAnimValue set the value in user units. This may fail
// if unit conversion fails e.g. conversion to ex or em units where the

Просмотреть файл

@ -1559,7 +1559,7 @@ void SVGElement::GetAnimatedLengthValues(float* aFirst, ...) {
va_start(args, aFirst);
while (f && i < info.mCount) {
*f = info.mValues[i++].GetAnimValue(metrics);
*f = info.mValues[i++].GetAnimValueWithZoom(metrics);
f = va_arg(args, float*);
}

Просмотреть файл

@ -165,7 +165,8 @@ enum class ZoomType { Self, SelfFromRoot, None };
/*static*/
float SVGLength::GetPixelsPerUnit(const UserSpaceMetrics& aMetrics,
uint8_t aUnitType, uint8_t aAxis) {
uint8_t aUnitType, uint8_t aAxis,
bool aApplyZoom) {
auto zoomType = ZoomType::Self;
float value = [&]() -> float {
switch (aUnitType) {
@ -216,15 +217,17 @@ float SVGLength::GetPixelsPerUnit(const UserSpaceMetrics& aMetrics,
return GetAbsUnitsPerAbsUnit(SVG_LENGTHTYPE_PX, aUnitType);
}
}();
switch (zoomType) {
case ZoomType::None:
break;
case ZoomType::Self:
value *= aMetrics.GetZoom();
break;
case ZoomType::SelfFromRoot:
value *= aMetrics.GetZoom() / aMetrics.GetRootZoom();
break;
if (aApplyZoom) {
switch (zoomType) {
case ZoomType::None:
break;
case ZoomType::Self:
value *= aMetrics.GetZoom();
break;
case ZoomType::SelfFromRoot:
value *= aMetrics.GetZoom() / aMetrics.GetRootZoom();
break;
}
}
return value;
}

Просмотреть файл

@ -93,9 +93,14 @@ class SVGLength {
bool IsPercentage() const { return IsPercentageUnit(mUnit); }
float GetPixelsPerUnitWithZoom(const dom::UserSpaceMetrics& aMetrics,
uint8_t aAxis) const {
return GetPixelsPerUnit(aMetrics, mUnit, aAxis, true);
}
float GetPixelsPerUnit(const dom::UserSpaceMetrics& aMetrics,
uint8_t aAxis) const {
return GetPixelsPerUnit(aMetrics, mUnit, aAxis);
return GetPixelsPerUnit(aMetrics, mUnit, aAxis, false);
}
static bool IsValidUnitType(uint16_t aUnitType) {
@ -123,7 +128,8 @@ class SVGLength {
* Returns the number of pixels per given unit.
*/
static float GetPixelsPerUnit(const dom::UserSpaceMetrics& aMetrics,
uint8_t aUnitType, uint8_t aAxis);
uint8_t aUnitType, uint8_t aAxis,
bool aApplyZoom);
private:
float mValue;

Просмотреть файл

@ -180,17 +180,17 @@ SVGViewBox SVGMarkerElement::GetViewBox() {
if (mViewBox.HasRect()) {
return mViewBox.GetAnimValue();
}
return SVGViewBox(0, 0,
mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx),
mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx));
return SVGViewBox(
0, 0, mLengthAttributes[MARKERWIDTH].GetAnimValueWithZoom(mCoordCtx),
mLengthAttributes[MARKERHEIGHT].GetAnimValueWithZoom(mCoordCtx));
}
gfx::Matrix SVGMarkerElement::GetViewBoxTransform() {
if (!mViewBoxToViewportTransform) {
float viewportWidth =
mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx);
mLengthAttributes[MARKERWIDTH].GetAnimValueWithZoom(mCoordCtx);
float viewportHeight =
mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx);
mLengthAttributes[MARKERHEIGHT].GetAnimValueWithZoom(mCoordCtx);
SVGViewBox viewbox = GetViewBox();
@ -201,8 +201,8 @@ gfx::Matrix SVGMarkerElement::GetViewBoxTransform() {
viewportWidth, viewportHeight, viewbox.x, viewbox.y, viewbox.width,
viewbox.height, mPreserveAspectRatio);
float refX = mLengthAttributes[REFX].GetAnimValue(mCoordCtx);
float refY = mLengthAttributes[REFY].GetAnimValue(mCoordCtx);
float refX = mLengthAttributes[REFX].GetAnimValueWithZoom(mCoordCtx);
float refY = mLengthAttributes[REFY].GetAnimValueWithZoom(mCoordCtx);
gfx::Point ref = viewBoxTM.TransformPoint(gfx::Point(refX, refY));

Просмотреть файл

@ -396,7 +396,7 @@ LengthPercentage SVGSVGElement::GetIntrinsicWidthOrHeight(int aAttr) {
// that uses the passed argument as the context, but that's fine since we
// know the length isn't a percentage so the context won't be used (and we
// need to pass the element to be able to resolve em/ex units).
float rawSize = mLengthAttributes[aAttr].GetAnimValue(this);
float rawSize = mLengthAttributes[aAttr].GetAnimValueWithZoom(this);
return LengthPercentage::FromPixels(rawSize);
}

Просмотреть файл

@ -105,7 +105,7 @@ inline float ComputeSynthesizedViewBoxDimension(
return aViewportLength * aLength.GetAnimValInSpecifiedUnits() / 100.0f;
}
return aLength.GetAnimValue(aSelf);
return aLength.GetAnimValueWithZoom(aSelf);
}
//----------------------------------------------------------------------
@ -155,8 +155,9 @@ gfx::Matrix SVGViewportElement::GetViewBoxTransform() const {
float viewportWidth, viewportHeight;
if (IsInner()) {
SVGElementMetrics metrics(this);
viewportWidth = mLengthAttributes[ATTR_WIDTH].GetAnimValue(metrics);
viewportHeight = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(metrics);
viewportWidth = mLengthAttributes[ATTR_WIDTH].GetAnimValueWithZoom(metrics);
viewportHeight =
mLengthAttributes[ATTR_HEIGHT].GetAnimValueWithZoom(metrics);
} else {
viewportWidth = mViewportSize.width;
viewportHeight = mViewportSize.height;
@ -201,10 +202,10 @@ float SVGViewportElement::GetLength(uint8_t aCtxType) const {
// of GetAnimValue().
SVGElementMetrics metrics(this);
if (shouldComputeWidth) {
w = mLengthAttributes[ATTR_WIDTH].GetAnimValue(metrics);
w = mLengthAttributes[ATTR_WIDTH].GetAnimValueWithZoom(metrics);
}
if (shouldComputeHeight) {
h = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(metrics);
h = mLengthAttributes[ATTR_HEIGHT].GetAnimValueWithZoom(metrics);
}
} else if (ShouldSynthesizeViewBox()) {
if (shouldComputeWidth) {

Просмотреть файл

@ -20,6 +20,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=342513
<svg font-size="10" width="20em" height="20em">
<rect id="r1" x="5em" y="6em" width="20%" height="30%" />
</svg>
<div style="zoom: 2;">
<svg width="40" height="40">
<rect id="r2" width="25" height="20" />
</svg>
</div>
</svg>
</div>
@ -46,6 +51,10 @@ function run() {
is(r1.width.baseVal.value, 40, "width in em for elements inside inner <svg> should be resolved against the inner <svg>");
is(r1.height.baseVal.value, 60, "height in em for elements inside inner <svg> should be resolved against the inner <svg>");
let r2 = document.getElementById("r2");
is(r2.width.baseVal.value, 25, "width in px for elements in zoomed div should be the same as unzoomed");
is(r2.height.baseVal.value, 20, "height in px for elements inside zoomed div should be the same as unzoomed");
SimpleTest.finish();
}

Просмотреть файл

@ -455,7 +455,7 @@ float SVGLinearGradientFrame::GetLengthValue(uint32_t aIndex) {
NS_ASSERTION(gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
"Unknown gradientUnits type");
return length.GetAnimValue(static_cast<SVGViewportElement*>(nullptr));
return length.GetAnimValueWithZoom(static_cast<SVGViewportElement*>(nullptr));
}
dom::SVGLinearGradientElement*
@ -557,7 +557,7 @@ float SVGRadialGradientFrame::GetLengthValueFromElement(
NS_ASSERTION(gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
"Unknown gradientUnits type");
return length.GetAnimValue(static_cast<SVGViewportElement*>(nullptr));
return length.GetAnimValueWithZoom(static_cast<SVGViewportElement*>(nullptr));
}
dom::SVGRadialGradientElement*

Просмотреть файл

@ -158,7 +158,8 @@ nscoord SVGOuterSVGFrame::GetPrefISize(gfxContext* aRenderingContext) {
result = nscoord(0);
}
} else {
result = nsPresContext::CSSPixelsToAppUnits(isize.GetAnimValue(svg));
result =
nsPresContext::CSSPixelsToAppUnits(isize.GetAnimValueWithZoom(svg));
if (result < 0) {
result = nscoord(0);
}
@ -189,13 +190,13 @@ IntrinsicSize SVGOuterSVGFrame::GetIntrinsicSize() {
if (!width.IsPercentage()) {
nscoord val =
nsPresContext::CSSPixelsToAppUnits(width.GetAnimValue(content));
nsPresContext::CSSPixelsToAppUnits(width.GetAnimValueWithZoom(content));
intrinsicSize.width.emplace(std::max(val, 0));
}
if (!height.IsPercentage()) {
nscoord val =
nsPresContext::CSSPixelsToAppUnits(height.GetAnimValue(content));
nscoord val = nsPresContext::CSSPixelsToAppUnits(
height.GetAnimValueWithZoom(content));
intrinsicSize.height.emplace(std::max(val, 0));
}

Просмотреть файл

@ -644,16 +644,16 @@ gfxMatrix SVGPatternFrame::ConstructCTM(const SVGAnimatedViewBox& aViewBox,
// If we're dealing with an SVG target only retrieve the context once.
// Calling the nsIFrame* variant of GetAnimValue would look it up on
// every call.
viewportWidth =
GetLengthValue(SVGPatternElement::ATTR_WIDTH)->GetAnimValue(ctx);
viewportHeight =
GetLengthValue(SVGPatternElement::ATTR_HEIGHT)->GetAnimValue(ctx);
viewportWidth = GetLengthValue(SVGPatternElement::ATTR_WIDTH)
->GetAnimValueWithZoom(ctx);
viewportHeight = GetLengthValue(SVGPatternElement::ATTR_HEIGHT)
->GetAnimValueWithZoom(ctx);
} else {
// No SVG target, call the nsIFrame* variant of GetAnimValue.
viewportWidth =
GetLengthValue(SVGPatternElement::ATTR_WIDTH)->GetAnimValue(aTarget);
viewportHeight =
GetLengthValue(SVGPatternElement::ATTR_HEIGHT)->GetAnimValue(aTarget);
viewportWidth = GetLengthValue(SVGPatternElement::ATTR_WIDTH)
->GetAnimValueWithZoom(aTarget);
viewportHeight = GetLengthValue(SVGPatternElement::ATTR_HEIGHT)
->GetAnimValueWithZoom(aTarget);
}
if (viewportWidth <= 0.0f || viewportHeight <= 0.0f) {

Просмотреть файл

@ -4564,7 +4564,7 @@ gfxFloat SVGTextFrame::GetStartOffset(nsIFrame* aTextPathFrame) {
100.0
: 0.0;
}
float lengthValue = length->GetAnimValue(tp);
float lengthValue = length->GetAnimValueWithZoom(tp);
// If offsetScale is infinity we want to return 0 not NaN
return lengthValue == 0 ? 0.0 : lengthValue * GetOffsetScale(aTextPathFrame);
}
@ -4802,7 +4802,7 @@ void SVGTextFrame::DoGlyphPositioning() {
element->EnumAttributes()[SVGTextContentElement::LENGTHADJUST]
.GetAnimValue();
bool adjustingTextLength = textLengthAttr->IsExplicitlySet();
float expectedTextLength = textLengthAttr->GetAnimValue(element);
float expectedTextLength = textLengthAttr->GetAnimValueWithZoom(element);
if (adjustingTextLength &&
(expectedTextLength < 0.0f || lengthAdjust == LENGTHADJUST_UNKNOWN)) {

Просмотреть файл

@ -254,19 +254,20 @@ float SVGUtils::ObjectSpace(const gfxRect& aRect,
// Multiply first to avoid precision errors:
return axis * aLength->GetAnimValInSpecifiedUnits() / 100;
}
return aLength->GetAnimValue(static_cast<SVGViewportElement*>(nullptr)) *
return aLength->GetAnimValueWithZoom(
static_cast<SVGViewportElement*>(nullptr)) *
axis;
}
float SVGUtils::UserSpace(nsIFrame* aNonSVGContext,
const SVGAnimatedLength* aLength) {
MOZ_ASSERT(!aNonSVGContext->IsTextFrame(), "Not expecting text content");
return aLength->GetAnimValue(aNonSVGContext);
return aLength->GetAnimValueWithZoom(aNonSVGContext);
}
float SVGUtils::UserSpace(const UserSpaceMetrics& aMetrics,
const SVGAnimatedLength* aLength) {
return aLength->GetAnimValue(aMetrics);
return aLength->GetAnimValueWithZoom(aMetrics);
}
SVGOuterSVGFrame* SVGUtils::GetOuterSVGFrame(nsIFrame* aFrame) {

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE HTML>
<title>SVGLength in zoomed div</title>
<link rel="help" href="https://www.w3.org/TR/SVG/types.html#InterfaceSVGLength">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div style="zoom: 2;">
<svg>
<rect id="rect" width="100" height="100"/>
</svg>
</div>
<script>
const rect = document.getElementById("rect");
test(() => {
assert_approx_equals(rect.width.baseVal.value, 100, 0.1);
}, "SVGLength in zoomed div should be unchanged");
</script>