Bug 1287054 part 2 - support vw, vh, vmin and vmax units for non-CSS lengths r=emilio,jgilbert

Differential Revision: https://phabricator.services.mozilla.com/D180619
This commit is contained in:
Robert Longson 2023-09-12 11:45:27 +00:00
Родитель 2c9fa6fab2
Коммит 7b6c56870c
7 изменённых файлов: 140 добавлений и 13 удалений

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

@ -2820,6 +2820,10 @@ class CanvasUserSpaceMetrics : public UserSpaceMetricsWithSize {
}
gfx::Size GetSize() const override { return Size(mSize); }
CSSSize GetCSSViewportSize() const override {
return GetCSSViewportSizeFromContext(mPresContext);
}
private:
GeckoFontMetrics GetFontMetricsForType(Type aType) const override {
switch (aType) {

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

@ -178,6 +178,11 @@ float UserSpaceMetrics::GetCapHeight(Type aType) const {
return GetEmLength(aType);
}
CSSSize UserSpaceMetrics::GetCSSViewportSizeFromContext(
const nsPresContext* aContext) {
return CSSPixel::FromAppUnits(aContext->GetSizeForViewportUnits());
}
SVGElementMetrics::SVGElementMetrics(const SVGElement* aSVGElement,
const SVGViewportElement* aCtx)
: mSVGElement(aSVGElement), mCtx(aCtx) {}
@ -210,6 +215,17 @@ float SVGElementMetrics::GetAxisLength(uint8_t aCtxType) const {
return FixAxisLength(mCtx->GetLength(aCtxType));
}
CSSSize SVGElementMetrics::GetCSSViewportSize() const {
if (!mSVGElement) {
return {0.0f, 0.0f};
}
nsPresContext* context = nsContentUtils::GetContextForContent(mSVGElement);
if (!context) {
return {0.0f, 0.0f};
}
return GetCSSViewportSizeFromContext(context);
}
bool SVGElementMetrics::EnsureCtx() const {
if (!mCtx && mSVGElement) {
mCtx = mSVGElement->GetCtx();
@ -279,6 +295,10 @@ gfx::Size NonSVGFrameUserSpaceMetrics::GetSize() const {
return SVGIntegrationUtils::GetSVGCoordContextForNonSVGFrame(mFrame);
}
CSSSize NonSVGFrameUserSpaceMetrics::GetCSSViewportSize() const {
return GetCSSViewportSizeFromContext(mFrame->PresContext());
}
float UserSpaceMetricsWithSize::GetAxisLength(uint8_t aCtxType) const {
gfx::Size size = GetSize();
float length;

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

@ -42,6 +42,7 @@ class UserSpaceMetrics {
static GeckoFontMetrics DefaultFontMetrics();
static GeckoFontMetrics GetFontMetrics(const Element* aElement);
static WritingMode GetWritingMode(const Element* aElement);
static CSSSize GetCSSViewportSizeFromContext(const nsPresContext* aContext);
virtual ~UserSpaceMetrics() = default;
@ -51,6 +52,7 @@ class UserSpaceMetrics {
float GetIcWidth(Type aType) const;
float GetCapHeight(Type aType) const;
virtual float GetAxisLength(uint8_t aCtxType) const = 0;
virtual CSSSize GetCSSViewportSize() const = 0;
protected:
virtual GeckoFontMetrics GetFontMetricsForType(Type aType) const = 0;
@ -72,6 +74,7 @@ class SVGElementMetrics : public UserSpaceMetrics {
return SVGContentUtils::GetFontSize(GetElementForType(aType));
}
float GetAxisLength(uint8_t aCtxType) const override;
CSSSize GetCSSViewportSize() const override;
private:
bool EnsureCtx() const;
@ -89,6 +92,7 @@ class NonSVGFrameUserSpaceMetrics : public UserSpaceMetricsWithSize {
float GetEmLength(Type aType) const override;
gfx::Size GetSize() const override;
CSSSize GetCSSViewportSize() const override;
private:
GeckoFontMetrics GetFontMetricsForType(Type aType) const override;

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

@ -25,6 +25,10 @@ const unsigned short SVG_LENGTHTYPE_CH = 12;
const unsigned short SVG_LENGTHTYPE_REM = 13;
const unsigned short SVG_LENGTHTYPE_IC = 14;
const unsigned short SVG_LENGTHTYPE_CAP = 15;
const unsigned short SVG_LENGTHTYPE_VW = 16;
const unsigned short SVG_LENGTHTYPE_VH = 17;
const unsigned short SVG_LENGTHTYPE_VMIN = 18;
const unsigned short SVG_LENGTHTYPE_VMAX = 19;
void SVGLength::GetValueAsString(nsAString& aValue) const {
nsTextFormatter::ssprintf(aValue, u"%g", (double)mValue);
@ -143,12 +147,6 @@ float SVGLength::GetValueInSpecifiedUnit(uint8_t aUnit,
float userUnitsPerNewUnit =
SVGLength(0.0f, aUnit).GetPixelsPerUnit(userSpaceMetrics, aAxis);
NS_ASSERTION(
userUnitsPerCurrentUnit >= 0 || !std::isfinite(userUnitsPerCurrentUnit),
"bad userUnitsPerCurrentUnit");
NS_ASSERTION(userUnitsPerNewUnit >= 0 || !std::isfinite(userUnitsPerNewUnit),
"bad userUnitsPerNewUnit");
float value = mValue * userUnitsPerCurrentUnit / userUnitsPerNewUnit;
// userUnitsPerCurrentUnit could be infinity, or userUnitsPerNewUnit could
@ -182,6 +180,18 @@ float SVGLength::GetPixelsPerUnit(const UserSpaceMetrics& aMetrics,
return aMetrics.GetIcWidth(UserSpaceMetrics::Type::This);
case SVG_LENGTHTYPE_CAP:
return aMetrics.GetCapHeight(UserSpaceMetrics::Type::This);
case SVG_LENGTHTYPE_VW:
return aMetrics.GetCSSViewportSize().width / 100.f;
case SVG_LENGTHTYPE_VH:
return aMetrics.GetCSSViewportSize().height / 100.f;
case SVG_LENGTHTYPE_VMIN: {
auto sz = aMetrics.GetCSSViewportSize();
return std::min(sz.width, sz.height) / 100.f;
}
case SVG_LENGTHTYPE_VMAX: {
auto sz = aMetrics.GetCSSViewportSize();
return std::max(sz.width, sz.height) / 100.f;
}
default:
MOZ_ASSERT(IsAbsoluteUnit(aUnitType));
return GetAbsUnitsPerAbsUnit(SVG_LENGTHTYPE_PX, aUnitType);
@ -234,6 +244,18 @@ nsCSSUnit SVGLength::SpecifiedUnitTypeToCSSUnit(uint8_t aSpecifiedUnit) {
case SVG_LENGTHTYPE_CAP:
return nsCSSUnit::eCSSUnit_CapHeight;
case SVG_LENGTHTYPE_VW:
return nsCSSUnit::eCSSUnit_VW;
case SVG_LENGTHTYPE_VH:
return nsCSSUnit::eCSSUnit_VH;
case SVG_LENGTHTYPE_VMIN:
return nsCSSUnit::eCSSUnit_VMin;
case SVG_LENGTHTYPE_VMAX:
return nsCSSUnit::eCSSUnit_VMax;
default:
MOZ_ASSERT_UNREACHABLE("Unknown unit type");
return nsCSSUnit::eCSSUnit_Pixel;
@ -288,6 +310,18 @@ void SVGLength::GetUnitString(nsAString& aUnit, uint16_t aUnitType) {
case SVG_LENGTHTYPE_CAP:
aUnit.AssignLiteral("cap");
return;
case SVG_LENGTHTYPE_VW:
aUnit.AssignLiteral("vw");
return;
case SVG_LENGTHTYPE_VH:
aUnit.AssignLiteral("vh");
return;
case SVG_LENGTHTYPE_VMIN:
aUnit.AssignLiteral("vmin");
return;
case SVG_LENGTHTYPE_VMAX:
aUnit.AssignLiteral("vmax");
return;
}
MOZ_ASSERT_UNREACHABLE(
"Unknown unit type! Someone's using an SVGLength "
@ -341,6 +375,18 @@ uint16_t SVGLength::GetUnitTypeForString(const nsAString& aUnit) {
if (aUnit.LowerCaseEqualsLiteral("cap")) {
return SVG_LENGTHTYPE_CAP;
}
if (aUnit.LowerCaseEqualsLiteral("vw")) {
return SVG_LENGTHTYPE_VW;
}
if (aUnit.LowerCaseEqualsLiteral("vh")) {
return SVG_LENGTHTYPE_VH;
}
if (aUnit.LowerCaseEqualsLiteral("vmin")) {
return SVG_LENGTHTYPE_VMIN;
}
if (aUnit.LowerCaseEqualsLiteral("vmax")) {
return SVG_LENGTHTYPE_VMAX;
}
return SVG_LENGTHTYPE_UNKNOWN;
}

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

@ -55,12 +55,12 @@ enum nsCSSUnit : uint32_t {
// different behavior than percent)
// Font relative measure
eCSSUnit_EM = 800, // == current font size
eCSSUnit_XHeight = 801, // distance from top of lower case x to
// baseline
eCSSUnit_Char = 802, // number of characters, used for width with
// monospace font
eCSSUnit_RootEM = 803, // == root element font size
eCSSUnit_EM = 800, // == current font size
eCSSUnit_XHeight = 801, // distance from top of lower case x to
// baseline
eCSSUnit_Char = 802, // number of characters, used for width with
// monospace font
eCSSUnit_RootEM = 803, // == root element font size
eCSSUnit_Ideographic = 804, // == CJK water ideograph width
eCSSUnit_CapHeight = 805, // == Capital letter height
@ -72,6 +72,12 @@ enum nsCSSUnit : uint32_t {
eCSSUnit_Pica = 904, // 12 points == 16 CSS pixls
eCSSUnit_Quarter = 905, // 96/101.6 CSS pixels
eCSSUnit_Pixel = 906, // CSS pixel unit
// Viewport percentage lengths
eCSSUnit_VW = 950,
eCSSUnit_VH = 951,
eCSSUnit_VMin = 952,
eCSSUnit_VMax = 953,
};
struct nsCSSValuePair;

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

@ -5341,7 +5341,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
use style::properties::PropertyDeclaration;
use style::values::generics::length::{LengthPercentageOrAuto, Size};
use style::values::generics::NonNegative;
use style::values::specified::length::{FontRelativeLength, LengthPercentage};
use style::values::specified::length::{FontRelativeLength, LengthPercentage, ViewportPercentageLength};
use style::values::specified::FontSize;
let long = get_longhand_from_id!(property);
@ -5375,6 +5375,18 @@ pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
structs::nsCSSUnit::eCSSUnit_Point => NoCalcLength::Absolute(AbsoluteLength::Pt(value)),
structs::nsCSSUnit::eCSSUnit_Pica => NoCalcLength::Absolute(AbsoluteLength::Pc(value)),
structs::nsCSSUnit::eCSSUnit_Quarter => NoCalcLength::Absolute(AbsoluteLength::Q(value)),
structs::nsCSSUnit::eCSSUnit_VW => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(value))
},
structs::nsCSSUnit::eCSSUnit_VH => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vh(value))
},
structs::nsCSSUnit::eCSSUnit_VMin => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vmin(value))
},
structs::nsCSSUnit::eCSSUnit_VMax => {
NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vmax(value))
},
_ => unreachable!("Unknown unit passed to SetLengthValue"),
};

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

@ -0,0 +1,35 @@
<!DOCTYPE HTML>
<title>SVGLength with 'viewport' units</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 id="ref"></div>
<svg>
<rect id="rect"/>
</svg>
<script>
const units = ['vw', 'vh', 'vmin', 'vmax'];
for (const unit of units) {
const ref = document.getElementById("ref");
ref.style.width=`10${unit}`;
const rect = document.getElementById("rect");
rect.setAttribute("x", `10${unit}`);
const ref_width = ref.offsetWidth;
let length = rect.x.baseVal;
test(() => {
assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_UNKNOWN);
assert_approx_equals(length.value, ref_width, 0.5);
}, `${unit} unit in SVGLength`);
test(() => {
const old_value = length.value
length.value = ref_width * 2;
assert_approx_equals(length.valueInSpecifiedUnits, 20, 0.2);
length.value = old_value;
}, `Convert back to ${unit} from new user unit value`);
}
</script>