mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-26 02:17:34 +09:00
Support percentage-and-pixel calc() values in SVG length attributes
This commit is contained in:
parent
d636b76284
commit
5e93ebd7f1
2 changed files with 115 additions and 13 deletions
|
|
@ -115,6 +115,62 @@ GetValueFromString(const nsAString& aString,
|
||||||
return IsValidUnitType(*aUnitType);
|
return IsValidUnitType(*aUnitType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SVG geometry attributes can contain a percentage with a pixel adjustment.
|
||||||
|
// Keep the two terms separate so the percentage follows viewport changes.
|
||||||
|
static bool
|
||||||
|
GetPercentageCalcFromString(const nsAString& aString,
|
||||||
|
float& aPercentage, float& aPixelOffset)
|
||||||
|
{
|
||||||
|
nsAutoString value(aString);
|
||||||
|
value.Trim(" \t\r\n\f");
|
||||||
|
if (value.Length() < 6 ||
|
||||||
|
!Substring(value, 0, 5).LowerCaseEqualsLiteral("calc(") ||
|
||||||
|
value.Last() != ')') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(value) + 5;
|
||||||
|
const RangedPtr<const char16_t> end =
|
||||||
|
SVGContentUtils::GetEndRangedPtr(value) - 1;
|
||||||
|
while (iter < end && IsSVGWhitespace(*iter)) {
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
if (!SVGContentUtils::ParseNumber(iter, end, aPercentage) ||
|
||||||
|
iter == end || *iter++ != '%') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (iter == end || !IsSVGWhitespace(*iter)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (iter < end && IsSVGWhitespace(*iter)) {
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
if (iter == end || (*iter != '+' && *iter != '-')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool subtract = *iter++ == '-';
|
||||||
|
if (iter == end || !IsSVGWhitespace(*iter)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (iter < end && IsSVGWhitespace(*iter)) {
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
if (!SVGContentUtils::ParseNumber(iter, end, aPixelOffset) ||
|
||||||
|
end - iter < 2 || *iter++ != 'p' || *iter++ != 'x') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (iter < end && IsSVGWhitespace(*iter)) {
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
if (iter != end) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (subtract) {
|
||||||
|
aPixelOffset = -aPixelOffset;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static float GetMMPerPixel() { return MM_PER_INCH_FLOAT / 96; }
|
static float GetMMPerPixel() { return MM_PER_INCH_FLOAT / 96; }
|
||||||
|
|
||||||
static float
|
static float
|
||||||
|
|
@ -272,7 +328,7 @@ nsSVGLength2::SetBaseValueInSpecifiedUnits(float aValue,
|
||||||
nsSVGElement *aSVGElement,
|
nsSVGElement *aSVGElement,
|
||||||
bool aDoSetAttr)
|
bool aDoSetAttr)
|
||||||
{
|
{
|
||||||
if (mIsBaseSet && mBaseVal == aValue) {
|
if (mIsBaseSet && mBaseVal == aValue && !mHasBaseCalc) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -282,6 +338,8 @@ nsSVGLength2::SetBaseValueInSpecifiedUnits(float aValue,
|
||||||
}
|
}
|
||||||
mBaseVal = aValue;
|
mBaseVal = aValue;
|
||||||
mIsBaseSet = true;
|
mIsBaseSet = true;
|
||||||
|
mBaseCalcOffset = 0;
|
||||||
|
mHasBaseCalc = false;
|
||||||
if (!mIsAnimated) {
|
if (!mIsAnimated) {
|
||||||
mAnimVal = mBaseVal;
|
mAnimVal = mBaseVal;
|
||||||
}
|
}
|
||||||
|
|
@ -300,7 +358,8 @@ nsSVGLength2::ConvertToSpecifiedUnits(uint16_t unitType,
|
||||||
if (!IsValidUnitType(unitType))
|
if (!IsValidUnitType(unitType))
|
||||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||||
|
|
||||||
if (mIsBaseSet && mSpecifiedUnitType == uint8_t(unitType))
|
if (mIsBaseSet && mSpecifiedUnitType == uint8_t(unitType) &&
|
||||||
|
!mHasBaseCalc)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
// Even though we're not changing the visual effect this length will have
|
// Even though we're not changing the visual effect this length will have
|
||||||
|
|
@ -309,9 +368,10 @@ nsSVGLength2::ConvertToSpecifiedUnits(uint16_t unitType,
|
||||||
// change.
|
// change.
|
||||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
|
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
|
||||||
|
|
||||||
float valueInUserUnits =
|
float valueInUserUnits = GetBaseValue(aSVGElement);
|
||||||
mBaseVal / GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType);
|
|
||||||
mSpecifiedUnitType = uint8_t(unitType);
|
mSpecifiedUnitType = uint8_t(unitType);
|
||||||
|
mHasBaseCalc = false;
|
||||||
|
mBaseCalcOffset = 0;
|
||||||
// Setting aDoSetAttr to false here will ensure we don't call
|
// Setting aDoSetAttr to false here will ensure we don't call
|
||||||
// Will/DidChangeAngle a second time (and dispatch duplicate notifications).
|
// Will/DidChangeAngle a second time (and dispatch duplicate notifications).
|
||||||
SetBaseValue(valueInUserUnits, aSVGElement, false);
|
SetBaseValue(valueInUserUnits, aSVGElement, false);
|
||||||
|
|
@ -331,7 +391,7 @@ nsSVGLength2::NewValueSpecifiedUnits(uint16_t unitType,
|
||||||
if (!IsValidUnitType(unitType))
|
if (!IsValidUnitType(unitType))
|
||||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||||
|
|
||||||
if (mIsBaseSet && mBaseVal == valueInSpecifiedUnits &&
|
if (mIsBaseSet && mBaseVal == valueInSpecifiedUnits && !mHasBaseCalc &&
|
||||||
mSpecifiedUnitType == uint8_t(unitType)) {
|
mSpecifiedUnitType == uint8_t(unitType)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -339,6 +399,8 @@ nsSVGLength2::NewValueSpecifiedUnits(uint16_t unitType,
|
||||||
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
|
nsAttrValue emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
|
||||||
mBaseVal = valueInSpecifiedUnits;
|
mBaseVal = valueInSpecifiedUnits;
|
||||||
mIsBaseSet = true;
|
mIsBaseSet = true;
|
||||||
|
mBaseCalcOffset = 0;
|
||||||
|
mHasBaseCalc = false;
|
||||||
mSpecifiedUnitType = uint8_t(unitType);
|
mSpecifiedUnitType = uint8_t(unitType);
|
||||||
if (!mIsAnimated) {
|
if (!mIsAnimated) {
|
||||||
mAnimVal = mBaseVal;
|
mAnimVal = mBaseVal;
|
||||||
|
|
@ -379,13 +441,20 @@ nsSVGLength2::SetBaseValueString(const nsAString &aValueAsString,
|
||||||
{
|
{
|
||||||
float value;
|
float value;
|
||||||
uint16_t unitType;
|
uint16_t unitType;
|
||||||
|
float pixelOffset = 0;
|
||||||
|
bool isCalc = false;
|
||||||
|
|
||||||
if (!GetValueFromString(aValueAsString, value, &unitType)) {
|
if (!GetValueFromString(aValueAsString, value, &unitType)) {
|
||||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
if (!GetPercentageCalcFromString(aValueAsString, value, pixelOffset)) {
|
||||||
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||||
|
}
|
||||||
|
unitType = nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE;
|
||||||
|
isCalc = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIsBaseSet && mBaseVal == float(value) &&
|
if (mIsBaseSet && mBaseVal == float(value) &&
|
||||||
mSpecifiedUnitType == uint8_t(unitType)) {
|
mSpecifiedUnitType == uint8_t(unitType) &&
|
||||||
|
mBaseCalcOffset == pixelOffset && mHasBaseCalc == isCalc) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -396,6 +465,8 @@ nsSVGLength2::SetBaseValueString(const nsAString &aValueAsString,
|
||||||
mBaseVal = value;
|
mBaseVal = value;
|
||||||
mIsBaseSet = true;
|
mIsBaseSet = true;
|
||||||
mSpecifiedUnitType = uint8_t(unitType);
|
mSpecifiedUnitType = uint8_t(unitType);
|
||||||
|
mBaseCalcOffset = pixelOffset;
|
||||||
|
mHasBaseCalc = isCalc;
|
||||||
if (!mIsAnimated) {
|
if (!mIsAnimated) {
|
||||||
mAnimVal = mBaseVal;
|
mAnimVal = mBaseVal;
|
||||||
}
|
}
|
||||||
|
|
@ -413,18 +484,36 @@ void
|
||||||
nsSVGLength2::GetBaseValueString(nsAString & aValueAsString) const
|
nsSVGLength2::GetBaseValueString(nsAString & aValueAsString) const
|
||||||
{
|
{
|
||||||
GetValueString(aValueAsString, mBaseVal, mSpecifiedUnitType);
|
GetValueString(aValueAsString, mBaseVal, mSpecifiedUnitType);
|
||||||
|
if (mHasBaseCalc) {
|
||||||
|
nsAutoString percentage(aValueAsString);
|
||||||
|
nsAutoString pixels;
|
||||||
|
GetValueString(pixels, std::abs(mBaseCalcOffset),
|
||||||
|
nsIDOMSVGLength::SVG_LENGTHTYPE_PX);
|
||||||
|
aValueAsString.AssignLiteral("calc(");
|
||||||
|
aValueAsString.Append(percentage);
|
||||||
|
aValueAsString.Append(mBaseCalcOffset < 0 ? NS_LITERAL_STRING(" - ")
|
||||||
|
: NS_LITERAL_STRING(" + "));
|
||||||
|
aValueAsString.Append(pixels);
|
||||||
|
aValueAsString.Append(')');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsSVGLength2::GetAnimValueString(nsAString & aValueAsString) const
|
nsSVGLength2::GetAnimValueString(nsAString & aValueAsString) const
|
||||||
{
|
{
|
||||||
GetValueString(aValueAsString, mAnimVal, mSpecifiedUnitType);
|
GetValueString(aValueAsString, mAnimVal, mSpecifiedUnitType);
|
||||||
|
if (mHasBaseCalc && !mIsAnimated) {
|
||||||
|
GetBaseValueString(aValueAsString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsSVGLength2::SetBaseValue(float aValue, nsSVGElement *aSVGElement,
|
nsSVGLength2::SetBaseValue(float aValue, nsSVGElement *aSVGElement,
|
||||||
bool aDoSetAttr)
|
bool aDoSetAttr)
|
||||||
{
|
{
|
||||||
|
if (mHasBaseCalc) {
|
||||||
|
mSpecifiedUnitType = nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER;
|
||||||
|
}
|
||||||
SetBaseValueInSpecifiedUnits(aValue * GetUnitScaleFactor(aSVGElement,
|
SetBaseValueInSpecifiedUnits(aValue * GetUnitScaleFactor(aSVGElement,
|
||||||
mSpecifiedUnitType),
|
mSpecifiedUnitType),
|
||||||
aSVGElement, aDoSetAttr);
|
aSVGElement, aDoSetAttr);
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,8 @@ public:
|
||||||
mCtxType = aCtxType;
|
mCtxType = aCtxType;
|
||||||
mIsAnimated = false;
|
mIsAnimated = false;
|
||||||
mIsBaseSet = false;
|
mIsBaseSet = false;
|
||||||
|
mBaseCalcOffset = 0;
|
||||||
|
mHasBaseCalc = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsSVGLength2& operator=(const nsSVGLength2& aLength) {
|
nsSVGLength2& operator=(const nsSVGLength2& aLength) {
|
||||||
|
|
@ -106,6 +108,8 @@ public:
|
||||||
mSpecifiedUnitType = aLength.mSpecifiedUnitType;
|
mSpecifiedUnitType = aLength.mSpecifiedUnitType;
|
||||||
mIsAnimated = aLength.mIsAnimated;
|
mIsAnimated = aLength.mIsAnimated;
|
||||||
mIsBaseSet = aLength.mIsBaseSet;
|
mIsBaseSet = aLength.mIsBaseSet;
|
||||||
|
mBaseCalcOffset = aLength.mBaseCalcOffset;
|
||||||
|
mHasBaseCalc = aLength.mHasBaseCalc;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,16 +120,21 @@ public:
|
||||||
void GetAnimValueString(nsAString& aValue) const;
|
void GetAnimValueString(nsAString& aValue) const;
|
||||||
|
|
||||||
float GetBaseValue(nsSVGElement* aSVGElement) const
|
float GetBaseValue(nsSVGElement* aSVGElement) const
|
||||||
{ return mBaseVal / GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType); }
|
{ return mBaseVal / GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType) +
|
||||||
|
mBaseCalcOffset; }
|
||||||
|
|
||||||
float GetAnimValue(nsSVGElement* aSVGElement) const
|
float GetAnimValue(nsSVGElement* aSVGElement) const
|
||||||
{ return mAnimVal / GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType); }
|
{ return mAnimVal / GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType) +
|
||||||
|
(mIsAnimated ? 0 : mBaseCalcOffset); }
|
||||||
float GetAnimValue(nsIFrame* aFrame) const
|
float GetAnimValue(nsIFrame* aFrame) const
|
||||||
{ return mAnimVal / GetUnitScaleFactor(aFrame, mSpecifiedUnitType); }
|
{ return mAnimVal / GetUnitScaleFactor(aFrame, mSpecifiedUnitType) +
|
||||||
|
(mIsAnimated ? 0 : mBaseCalcOffset); }
|
||||||
float GetAnimValue(mozilla::dom::SVGSVGElement* aCtx) const
|
float GetAnimValue(mozilla::dom::SVGSVGElement* aCtx) const
|
||||||
{ return mAnimVal / GetUnitScaleFactor(aCtx, mSpecifiedUnitType); }
|
{ return mAnimVal / GetUnitScaleFactor(aCtx, mSpecifiedUnitType) +
|
||||||
|
(mIsAnimated ? 0 : mBaseCalcOffset); }
|
||||||
float GetAnimValue(const UserSpaceMetrics& aMetrics) const
|
float GetAnimValue(const UserSpaceMetrics& aMetrics) const
|
||||||
{ return mAnimVal / GetUnitScaleFactor(aMetrics, mSpecifiedUnitType); }
|
{ return mAnimVal / GetUnitScaleFactor(aMetrics, mSpecifiedUnitType) +
|
||||||
|
(mIsAnimated ? 0 : mBaseCalcOffset); }
|
||||||
|
|
||||||
uint8_t GetCtxType() const { return mCtxType; }
|
uint8_t GetCtxType() const { return mCtxType; }
|
||||||
uint8_t GetSpecifiedUnitType() const { return mSpecifiedUnitType; }
|
uint8_t GetSpecifiedUnitType() const { return mSpecifiedUnitType; }
|
||||||
|
|
@ -135,7 +144,8 @@ public:
|
||||||
float GetBaseValInSpecifiedUnits() const { return mBaseVal; }
|
float GetBaseValInSpecifiedUnits() const { return mBaseVal; }
|
||||||
|
|
||||||
float GetBaseValue(mozilla::dom::SVGSVGElement* aCtx) const
|
float GetBaseValue(mozilla::dom::SVGSVGElement* aCtx) const
|
||||||
{ return mBaseVal / GetUnitScaleFactor(aCtx, mSpecifiedUnitType); }
|
{ return mBaseVal / GetUnitScaleFactor(aCtx, mSpecifiedUnitType) +
|
||||||
|
mBaseCalcOffset; }
|
||||||
|
|
||||||
bool HasBaseVal() const {
|
bool HasBaseVal() const {
|
||||||
return mIsBaseSet;
|
return mIsBaseSet;
|
||||||
|
|
@ -158,11 +168,14 @@ private:
|
||||||
|
|
||||||
float mAnimVal;
|
float mAnimVal;
|
||||||
float mBaseVal;
|
float mBaseVal;
|
||||||
|
// The px term of a calc(<percentage> +/- <px>) base value.
|
||||||
|
float mBaseCalcOffset;
|
||||||
uint8_t mSpecifiedUnitType;
|
uint8_t mSpecifiedUnitType;
|
||||||
uint8_t mAttrEnum; // element specified tracking for attribute
|
uint8_t mAttrEnum; // element specified tracking for attribute
|
||||||
uint8_t mCtxType; // X, Y or Unspecified
|
uint8_t mCtxType; // X, Y or Unspecified
|
||||||
bool mIsAnimated:1;
|
bool mIsAnimated:1;
|
||||||
bool mIsBaseSet:1;
|
bool mIsBaseSet:1;
|
||||||
|
bool mHasBaseCalc:1;
|
||||||
|
|
||||||
float GetUnitScaleFactor(nsIFrame *aFrame, uint8_t aUnitType) const;
|
float GetUnitScaleFactor(nsIFrame *aFrame, uint8_t aUnitType) const;
|
||||||
float GetUnitScaleFactor(const UserSpaceMetrics& aMetrics, uint8_t aUnitType) const;
|
float GetUnitScaleFactor(const UserSpaceMetrics& aMetrics, uint8_t aUnitType) const;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue