зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1532122 - Make word-spacing, letter-spacing, and line-height use Rust lengths. r=boris
This also adopts the resolution from [1] while at it, making letter-spacing compute to a length, serializing 0 to normal rather than keeping normal in the computed value, which matches every other engine. This removes the SMIL tests for percentages from letter-spacing since letter-spacing does in fact not support percentages, so they were passing just by chance. [1]: https://github.com/w3c/csswg-drafts/issues/1484 Differential Revision: https://phabricator.services.mozilla.com/D21850 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
2a809aa796
Коммит
25098daaaa
|
@ -149,6 +149,16 @@ var _fromToTestLists = {
|
|||
],
|
||||
};
|
||||
|
||||
function _tweakForLetterSpacing(testcases) {
|
||||
return testcases.map(function(t) {
|
||||
let valMap = Object.assign({}, t.computedValMap);
|
||||
for (let prop of Object.keys(valMap))
|
||||
if (valMap[prop] == "0px")
|
||||
valMap[prop] = "normal";
|
||||
return new AnimTestcaseFromTo(t.from, t.to, valMap)
|
||||
});
|
||||
}
|
||||
|
||||
// List of attribute/testcase-list bundles to be tested
|
||||
var gFromToBundles = [
|
||||
new TestcaseBundle(gPropList.clip, [
|
||||
|
@ -341,13 +351,9 @@ var gFromToBundles = [
|
|||
toComp: "optimizespeed" }),
|
||||
]),
|
||||
new TestcaseBundle(gPropList.letter_spacing,
|
||||
[].concat(_fromToTestLists.lengthNoUnits,
|
||||
_fromToTestLists.lengthPx,
|
||||
_fromToTestLists.lengthPxPctSVG)),
|
||||
new TestcaseBundle(gPropList.letter_spacing,
|
||||
_fromToTestLists.lengthPctSVG,
|
||||
"pct->pct animations don't currently work for " +
|
||||
"*-spacing properties"),
|
||||
_tweakForLetterSpacing(
|
||||
[].concat(_fromToTestLists.lengthNoUnits,
|
||||
_fromToTestLists.lengthPx))),
|
||||
new TestcaseBundle(gPropList.lighting_color,
|
||||
[].concat(_fromToTestLists.color,
|
||||
_fromToTestLists.colorFromInheritWhite)),
|
||||
|
|
|
@ -201,12 +201,9 @@ LogicalSize nsTextControlFrame::CalcIntrinsicSize(
|
|||
|
||||
// Increment width with cols * letter-spacing.
|
||||
{
|
||||
const nsStyleCoord& lsCoord = StyleText()->mLetterSpacing;
|
||||
if (eStyleUnit_Coord == lsCoord.GetUnit()) {
|
||||
nscoord letterSpacing = lsCoord.GetCoordValue();
|
||||
if (letterSpacing != 0) {
|
||||
intrinsicSize.ISize(aWM) += cols * letterSpacing;
|
||||
}
|
||||
const StyleLength& letterSpacing = StyleText()->mLetterSpacing;
|
||||
if (!letterSpacing.IsZero()) {
|
||||
intrinsicSize.ISize(aWM) += cols * letterSpacing.ToAppUnits();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -734,11 +734,7 @@ void ReflowInput::InitResizeFlags(nsPresContext* aPresContext,
|
|||
mStylePosition->OffsetHasPercent(wm.PhysicalSide(eLogicalSideBStart)) ||
|
||||
!mStylePosition->mOffset.GetBEnd(wm).IsAuto() || mFrame->IsXULBoxFrame();
|
||||
|
||||
if (mStyleText->mLineHeight.GetUnit() == eStyleUnit_Enumerated) {
|
||||
NS_ASSERTION(mStyleText->mLineHeight.GetIntValue() ==
|
||||
NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT,
|
||||
"bad line-height value");
|
||||
|
||||
if (mStyleText->mLineHeight.IsMozBlockHeight()) {
|
||||
// line-height depends on block bsize
|
||||
mFrame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
|
||||
// but only on containing blocks if this frame is not a suitable block
|
||||
|
@ -2849,33 +2845,26 @@ static inline nscoord ComputeLineHeight(ComputedStyle* aComputedStyle,
|
|||
nsPresContext* aPresContext,
|
||||
nscoord aBlockBSize,
|
||||
float aFontSizeInflation) {
|
||||
const nsStyleCoord& lhCoord = aComputedStyle->StyleText()->mLineHeight;
|
||||
|
||||
if (lhCoord.GetUnit() == eStyleUnit_Coord) {
|
||||
nscoord result = lhCoord.GetCoordValue();
|
||||
const StyleLineHeight& lineHeight = aComputedStyle->StyleText()->mLineHeight;
|
||||
if (lineHeight.IsLength()) {
|
||||
nscoord result = lineHeight.length._0.ToAppUnits();
|
||||
if (aFontSizeInflation != 1.0f) {
|
||||
result = NSToCoordRound(result * aFontSizeInflation);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (lhCoord.GetUnit() == eStyleUnit_Factor)
|
||||
if (lineHeight.IsNumber()) {
|
||||
// For factor units the computed value of the line-height property
|
||||
// is found by multiplying the factor by the font's computed size
|
||||
// (adjusted for min-size prefs and text zoom).
|
||||
return NSToCoordRound(lhCoord.GetFactorValue() * aFontSizeInflation *
|
||||
return NSToCoordRound(lineHeight.number._0 * aFontSizeInflation *
|
||||
aComputedStyle->StyleFont()->mFont.size);
|
||||
}
|
||||
|
||||
NS_ASSERTION(lhCoord.GetUnit() == eStyleUnit_Normal ||
|
||||
lhCoord.GetUnit() == eStyleUnit_Enumerated,
|
||||
"bad line-height unit");
|
||||
|
||||
if (lhCoord.GetUnit() == eStyleUnit_Enumerated) {
|
||||
NS_ASSERTION(lhCoord.GetIntValue() == NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT,
|
||||
"bad line-height value");
|
||||
if (aBlockBSize != NS_AUTOHEIGHT) {
|
||||
return aBlockBSize;
|
||||
}
|
||||
MOZ_ASSERT(lineHeight.IsNormal() || lineHeight.IsMozBlockHeight());
|
||||
if (lineHeight.IsMozBlockHeight() && aBlockBSize != NS_AUTOHEIGHT) {
|
||||
return aBlockBSize;
|
||||
}
|
||||
|
||||
RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForComputedStyle(
|
||||
|
|
|
@ -1877,7 +1877,7 @@ void nsLineLayout::VerticalAlignFrames(PerSpanData* psd) {
|
|||
// the frame block size if the user has left line-height == normal
|
||||
const nsStyleText* styleText = spanFrame->StyleText();
|
||||
if (spanFramePFD->mIsLetterFrame && !spanFrame->GetPrevInFlow() &&
|
||||
styleText->mLineHeight.GetUnit() == eStyleUnit_Normal) {
|
||||
styleText->mLineHeight.IsNormal()) {
|
||||
logicalBSize = spanFramePFD->mBounds.BSize(lineWM);
|
||||
}
|
||||
|
||||
|
@ -2191,7 +2191,7 @@ void nsLineLayout::VerticalAlignFrames(PerSpanData* psd) {
|
|||
// line-height=normal.
|
||||
canUpdate =
|
||||
pfd->mIsNonWhitespaceTextFrame &&
|
||||
frame->StyleText()->mLineHeight.GetUnit() == eStyleUnit_Normal;
|
||||
frame->StyleText()->mLineHeight.IsNormal();
|
||||
} else {
|
||||
canUpdate = !pfd->mIsPlaceholder;
|
||||
}
|
||||
|
|
|
@ -1729,7 +1729,7 @@ static gfxFont::Metrics GetFirstFontMetrics(gfxFontGroup* aFontGroup,
|
|||
: gfxFont::eHorizontal);
|
||||
}
|
||||
|
||||
static gfxFloat GetSpaceWidthAppUnits(const gfxTextRun* aTextRun) {
|
||||
static nscoord GetSpaceWidthAppUnits(const gfxTextRun* aTextRun) {
|
||||
// Round the space width when converting to appunits the same way textruns
|
||||
// do.
|
||||
gfxFloat spaceWidthAppUnits =
|
||||
|
@ -1757,12 +1757,7 @@ static nscoord LetterSpacing(nsIFrame* aFrame,
|
|||
if (!aStyleText) {
|
||||
aStyleText = aFrame->StyleText();
|
||||
}
|
||||
|
||||
const nsStyleCoord& coord = aStyleText->mLetterSpacing;
|
||||
if (eStyleUnit_Coord == coord.GetUnit()) {
|
||||
return coord.GetCoordValue();
|
||||
}
|
||||
return 0;
|
||||
return aStyleText->mLetterSpacing.ToAppUnits();
|
||||
}
|
||||
|
||||
// This function converts non-coord values (e.g. percentages) to nscoord.
|
||||
|
@ -1775,12 +1770,9 @@ static nscoord WordSpacing(nsIFrame* aFrame, const gfxTextRun* aTextRun,
|
|||
aStyleText = aFrame->StyleText();
|
||||
}
|
||||
|
||||
const nsStyleCoord& coord = aStyleText->mWordSpacing;
|
||||
if (coord.IsCoordPercentCalcUnit()) {
|
||||
nscoord pctBasis = coord.HasPercent() ? GetSpaceWidthAppUnits(aTextRun) : 0;
|
||||
return coord.ComputeCoordPercentCalc(pctBasis);
|
||||
}
|
||||
return 0;
|
||||
return aStyleText->mWordSpacing.Resolve([&] {
|
||||
return GetSpaceWidthAppUnits(aTextRun);
|
||||
});
|
||||
}
|
||||
|
||||
// Returns gfxTextRunFactory::TEXT_ENABLE_SPACING if non-standard
|
||||
|
@ -1792,20 +1784,14 @@ static gfx::ShapedTextFlags GetSpacingFlags(
|
|||
}
|
||||
|
||||
const nsStyleText* styleText = aFrame->StyleText();
|
||||
const nsStyleCoord& ls = styleText->mLetterSpacing;
|
||||
const nsStyleCoord& ws = styleText->mWordSpacing;
|
||||
const auto& ls = styleText->mLetterSpacing;
|
||||
const auto& ws = styleText->mWordSpacing;
|
||||
|
||||
// It's possible to have a calc() value that computes to zero but for which
|
||||
// IsDefinitelyZero() is false, in which case we'll return
|
||||
// TEXT_ENABLE_SPACING unnecessarily. That's ok because such cases are likely
|
||||
// to be rare, and avoiding TEXT_ENABLE_SPACING is just an optimization.
|
||||
bool nonStandardSpacing =
|
||||
(eStyleUnit_Coord == ls.GetUnit() && ls.GetCoordValue() != 0) ||
|
||||
(eStyleUnit_Coord == ws.GetUnit() && ws.GetCoordValue() != 0) ||
|
||||
(eStyleUnit_Percent == ws.GetUnit() && ws.GetPercentValue() != 0) ||
|
||||
(eStyleUnit_Calc == ws.GetUnit() &&
|
||||
!ws.GetCalcValue()->IsDefinitelyZero());
|
||||
|
||||
bool nonStandardSpacing = !ls.IsZero() || !ws.IsDefinitelyZero();
|
||||
return nonStandardSpacing ? gfx::ShapedTextFlags::TEXT_ENABLE_SPACING
|
||||
: gfx::ShapedTextFlags();
|
||||
}
|
||||
|
|
|
@ -446,6 +446,8 @@ cbindgen-types = [
|
|||
{ gecko = "StyleGenericZIndex", servo = "values::generics::position::ZIndex" },
|
||||
{ gecko = "StyleTransformOrigin", servo = "values::computed::TransformOrigin" },
|
||||
{ gecko = "StyleGenericBorderRadius", servo = "values::generics::border::BorderRadius" },
|
||||
{ gecko = "StyleLetterSpacing", servo = "values::computed::text::LetterSpacing" },
|
||||
{ gecko = "StyleGenericLineHeight", servo = "values::generics::text::LineHeight" },
|
||||
]
|
||||
|
||||
mapped-generic-types = [
|
||||
|
|
|
@ -101,7 +101,6 @@ LONGHANDS_NOT_SERIALIZED_WITH_SERVO = [
|
|||
"grid-row-start",
|
||||
"grid-template-areas",
|
||||
"initial-letter",
|
||||
"letter-spacing",
|
||||
"marker-end",
|
||||
"marker-mid",
|
||||
"marker-start",
|
||||
|
@ -140,7 +139,6 @@ LONGHANDS_NOT_SERIALIZED_WITH_SERVO = [
|
|||
"vertical-align",
|
||||
"-webkit-text-stroke-width",
|
||||
"will-change",
|
||||
"word-spacing",
|
||||
]
|
||||
|
||||
def serialized_by_servo(prop):
|
||||
|
|
|
@ -2012,14 +2012,25 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetInitialLetter() {
|
|||
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetLineHeight() {
|
||||
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
|
||||
|
||||
nscoord lineHeight;
|
||||
if (GetLineHeightCoord(lineHeight)) {
|
||||
val->SetAppUnits(lineHeight);
|
||||
} else {
|
||||
SetValueToCoord(val, StyleText()->mLineHeight, true, nullptr,
|
||||
nsCSSProps::kLineHeightKTable);
|
||||
{
|
||||
nscoord lineHeight;
|
||||
if (GetLineHeightCoord(lineHeight)) {
|
||||
val->SetAppUnits(lineHeight);
|
||||
return val.forget();
|
||||
}
|
||||
}
|
||||
|
||||
auto& lh = StyleText()->mLineHeight;
|
||||
if (lh.IsLength()) {
|
||||
val->SetAppUnits(lh.length._0.ToAppUnits());
|
||||
} else if (lh.IsNumber()) {
|
||||
val->SetNumber(lh.number._0);
|
||||
} else if (lh.IsMozBlockHeight()) {
|
||||
val->SetIdent(eCSSKeyword__moz_block_height);
|
||||
} else {
|
||||
MOZ_ASSERT(lh.IsNormal());
|
||||
val->SetIdent(eCSSKeyword_normal);
|
||||
}
|
||||
return val.forget();
|
||||
}
|
||||
|
||||
|
@ -2188,18 +2199,6 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetTextShadow() {
|
|||
return GetCSSShadowArray(StyleText()->mTextShadow, false);
|
||||
}
|
||||
|
||||
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetLetterSpacing() {
|
||||
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
|
||||
SetValueToCoord(val, StyleText()->mLetterSpacing, false);
|
||||
return val.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetWordSpacing() {
|
||||
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
|
||||
SetValueToCoord(val, StyleText()->mWordSpacing, false);
|
||||
return val.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetWebkitTextStrokeWidth() {
|
||||
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
|
||||
val->SetAppUnits(StyleText()->mWebkitTextStrokeWidth);
|
||||
|
@ -2674,7 +2673,7 @@ bool nsComputedDOMStyle::GetLineHeightCoord(nscoord& aCoord) {
|
|||
AssertFlushedPendingReflows();
|
||||
|
||||
nscoord blockHeight = NS_AUTOHEIGHT;
|
||||
if (StyleText()->mLineHeight.GetUnit() == eStyleUnit_Enumerated) {
|
||||
if (StyleText()->mLineHeight.IsMozBlockHeight()) {
|
||||
if (!mInnerFrame) return false;
|
||||
|
||||
if (nsLayoutUtils::IsNonWrapperBlock(mInnerFrame)) {
|
||||
|
|
|
@ -294,7 +294,6 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration,
|
|||
already_AddRefed<CSSValue> DoGetBorderTopLeftRadius();
|
||||
already_AddRefed<CSSValue> DoGetBorderTopRightRadius();
|
||||
|
||||
|
||||
/* Border Image */
|
||||
already_AddRefed<CSSValue> DoGetBorderImageWidth();
|
||||
|
||||
|
@ -314,7 +313,6 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration,
|
|||
already_AddRefed<CSSValue> DoGetOutlineRadiusTopLeft();
|
||||
already_AddRefed<CSSValue> DoGetOutlineRadiusTopRight();
|
||||
|
||||
|
||||
/* Text Properties */
|
||||
already_AddRefed<CSSValue> DoGetInitialLetter();
|
||||
already_AddRefed<CSSValue> DoGetLineHeight();
|
||||
|
@ -326,8 +324,6 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration,
|
|||
already_AddRefed<CSSValue> DoGetTextEmphasisStyle();
|
||||
already_AddRefed<CSSValue> DoGetTextOverflow();
|
||||
already_AddRefed<CSSValue> DoGetTextShadow();
|
||||
already_AddRefed<CSSValue> DoGetLetterSpacing();
|
||||
already_AddRefed<CSSValue> DoGetWordSpacing();
|
||||
already_AddRefed<CSSValue> DoGetWebkitTextStrokeWidth();
|
||||
|
||||
/* Display properties */
|
||||
|
@ -379,8 +375,6 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration,
|
|||
already_AddRefed<CSSValue> DoGetMarkerMid();
|
||||
already_AddRefed<CSSValue> DoGetMarkerStart();
|
||||
|
||||
|
||||
|
||||
already_AddRefed<CSSValue> DoGetFilter();
|
||||
already_AddRefed<CSSValue> DoGetPaintOrder();
|
||||
|
||||
|
|
|
@ -46,6 +46,10 @@ using NonNegativeLengthPercentageOrAuto =
|
|||
StyleNonNegativeLengthPercentageOrAuto;
|
||||
using BorderRadius = StyleBorderRadius;
|
||||
|
||||
bool StyleCSSPixelLength::IsZero() const {
|
||||
return _0 == 0.0f;
|
||||
}
|
||||
|
||||
nscoord StyleCSSPixelLength::ToAppUnits() const {
|
||||
// We want to resolve the length part of the calc() expression rounding 0.5
|
||||
// away from zero, instead of the default behavior of NSToCoordRoundWithClamp
|
||||
|
@ -95,7 +99,7 @@ nscoord LengthPercentage::ToLength() const {
|
|||
}
|
||||
|
||||
bool LengthPercentage::ConvertsToPercentage() const {
|
||||
return has_percentage && length._0 == 0.0f;
|
||||
return has_percentage && length.IsZero();
|
||||
}
|
||||
|
||||
float LengthPercentage::ToPercentage() const {
|
||||
|
@ -107,6 +111,10 @@ bool LengthPercentage::HasLengthAndPercentage() const {
|
|||
return !ConvertsToLength() && !ConvertsToPercentage();
|
||||
}
|
||||
|
||||
bool LengthPercentage::IsDefinitelyZero() const {
|
||||
return length.IsZero() && Percentage() == 0.0f;
|
||||
}
|
||||
|
||||
CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const {
|
||||
return LengthInCSSPixels() + Percentage() * aPercentageBasis;
|
||||
}
|
||||
|
|
|
@ -3711,9 +3711,9 @@ nsStyleText::nsStyleText(const Document& aDocument)
|
|||
mWebkitTextStrokeColor(StyleComplexColor::CurrentColor()),
|
||||
mMozTabSize(
|
||||
StyleNonNegativeLengthOrNumber::Number(NS_STYLE_TABSIZE_INITIAL)),
|
||||
mWordSpacing(0, nsStyleCoord::CoordConstructor),
|
||||
mLetterSpacing(eStyleUnit_Normal),
|
||||
mLineHeight(eStyleUnit_Normal),
|
||||
mWordSpacing(LengthPercentage::Zero()),
|
||||
mLetterSpacing({0.}),
|
||||
mLineHeight(StyleLineHeight::Normal()),
|
||||
mTextIndent(LengthPercentage::Zero()),
|
||||
mWebkitTextStrokeWidth(0),
|
||||
mTextShadow(nullptr) {
|
||||
|
|
|
@ -1476,9 +1476,9 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
|
|||
mozilla::StyleComplexColor mWebkitTextStrokeColor;
|
||||
|
||||
mozilla::StyleNonNegativeLengthOrNumber mMozTabSize;
|
||||
nsStyleCoord mWordSpacing; // coord, percent, calc
|
||||
nsStyleCoord mLetterSpacing; // coord, normal
|
||||
nsStyleCoord mLineHeight; // coord, factor, normal
|
||||
mozilla::LengthPercentage mWordSpacing;
|
||||
mozilla::StyleLetterSpacing mLetterSpacing;
|
||||
mozilla::StyleLineHeight mLineHeight;
|
||||
mozilla::LengthPercentage mTextIndent;
|
||||
nscoord mWebkitTextStrokeWidth; // coord
|
||||
|
||||
|
|
|
@ -3962,11 +3962,9 @@ var gCSSProperties = {
|
|||
applies_to_first_letter: true,
|
||||
applies_to_first_line: true,
|
||||
applies_to_placeholder: true,
|
||||
initial_values: [ "normal" ],
|
||||
other_values: [ "0", "0px", "1em", "2px", "-3px",
|
||||
"calc(0px)", "calc(1em)", "calc(1em + 3px)",
|
||||
"calc(15px / 2)", "calc(15px/2)", "calc(-3px)"
|
||||
],
|
||||
initial_values: [ "normal", "0", "0px", "calc(0px)" ],
|
||||
other_values: [ "1em", "2px", "-3px", "calc(1em)", "calc(1em + 3px)",
|
||||
"calc(15px / 2)", "calc(15px/2)", "calc(-3px)" ],
|
||||
invalid_values: [],
|
||||
quirks_values: { "5": "5px" },
|
||||
},
|
||||
|
|
|
@ -1284,11 +1284,10 @@ function test_length_clamped_or_unclamped(prop, is_clamped) {
|
|||
div.style.setProperty("transition-timing-function", FUNC_NEGATIVE, "");
|
||||
div.style.setProperty("transition-property", "none", "");
|
||||
div.style.setProperty(prop, "0px", "");
|
||||
is(cs.getPropertyValue(prop), "0px",
|
||||
"length-valued property " + prop + ": flush before clamping test");
|
||||
let zero_val = cs.getPropertyValue(prop); // Flushes
|
||||
div.style.setProperty("transition-property", prop, "");
|
||||
div.style.setProperty(prop, "100px", "");
|
||||
(is_clamped ? is : isnot)(cs.getPropertyValue(prop), "0px",
|
||||
(is_clamped ? is : isnot)(cs.getPropertyValue(prop), zero_val,
|
||||
"length-valued property " + prop + ": clamping of negatives");
|
||||
div.style.setProperty("transition-timing-function", "linear", "");
|
||||
}
|
||||
|
|
|
@ -78,8 +78,10 @@ include = [
|
|||
"Resize",
|
||||
"Overflow",
|
||||
"LengthPercentage",
|
||||
"LetterSpacing",
|
||||
"NonNegativeLengthPercentage",
|
||||
"LengthPercentageOrAuto",
|
||||
"LineHeight",
|
||||
"NonNegativeLengthPercentageOrAuto",
|
||||
"Rect",
|
||||
"IntersectionObserverRootMargin",
|
||||
|
@ -102,6 +104,7 @@ item_types = ["enums", "structs", "typedefs"]
|
|||
[export.body]
|
||||
"CSSPixelLength" = """
|
||||
inline nscoord ToAppUnits() const;
|
||||
inline bool IsZero() const;
|
||||
"""
|
||||
|
||||
"LengthPercentage" = """
|
||||
|
@ -118,6 +121,7 @@ item_types = ["enums", "structs", "typedefs"]
|
|||
inline bool ConvertsToPercentage() const;
|
||||
inline bool HasLengthAndPercentage() const;
|
||||
inline float ToPercentage() const;
|
||||
inline bool IsDefinitelyZero() const;
|
||||
inline CSSCoord ResolveToCSSPixels(CSSCoord aPercentageBasisInCSSPixels) const;
|
||||
template<typename T> inline CSSCoord ResolveToCSSPixelsWith(T aPercentageGetter) const;
|
||||
template<typename T, typename U>
|
||||
|
|
|
@ -1227,56 +1227,23 @@ impl Clone for ${style_struct.gecko_struct_name} {
|
|||
|
||||
# Types used with predefined_type()-defined properties that we can auto-generate.
|
||||
predefined_types = {
|
||||
"Appearance": impl_simple,
|
||||
"OverscrollBehavior": impl_simple,
|
||||
"OverflowClipBox": impl_simple,
|
||||
"ScrollSnapAlign": impl_simple,
|
||||
"ScrollSnapType": impl_simple,
|
||||
"Float": impl_simple,
|
||||
"Overflow": impl_simple,
|
||||
"BreakBetween": impl_simple,
|
||||
"BreakWithin": impl_simple,
|
||||
"Resize": impl_simple,
|
||||
"Color": impl_color,
|
||||
"ColorOrAuto": impl_color,
|
||||
"GreaterThanOrEqualToOneNumber": impl_simple,
|
||||
"Integer": impl_simple,
|
||||
"length::LengthOrAuto": impl_style_coord,
|
||||
"length::LengthOrNormal": impl_style_coord,
|
||||
"length::NonNegativeLengthOrAuto": impl_style_coord,
|
||||
"length::NonNegativeLengthPercentageOrNormal": impl_style_coord,
|
||||
"FillRule": impl_simple,
|
||||
"FlexBasis": impl_simple,
|
||||
"Length": impl_absolute_length,
|
||||
"LengthOrNormal": impl_style_coord,
|
||||
"LengthPercentage": impl_simple,
|
||||
"LengthPercentageOrAuto": impl_style_coord,
|
||||
"MaxSize": impl_simple,
|
||||
"Size": impl_simple,
|
||||
"MozScriptMinSize": impl_absolute_length,
|
||||
"MozScriptSizeMultiplier": impl_simple,
|
||||
"NonNegativeLengthPercentage": impl_simple,
|
||||
"NonNegativeLengthOrNumber": impl_simple,
|
||||
"NonNegativeLengthOrNumberRect": impl_simple,
|
||||
"BorderImageSlice": impl_simple,
|
||||
"NonNegativeNumber": impl_simple,
|
||||
"Number": impl_simple,
|
||||
"Opacity": impl_simple,
|
||||
"OverflowWrap": impl_simple,
|
||||
"OverflowAnchor": impl_simple,
|
||||
"Perspective": impl_simple,
|
||||
"Position": impl_simple,
|
||||
"RGBAColor": impl_rgba_color,
|
||||
"SVGLength": impl_svg_length,
|
||||
"SVGOpacity": impl_svg_opacity,
|
||||
"SVGPaint": impl_svg_paint,
|
||||
"SVGWidth": impl_svg_length,
|
||||
"Transform": impl_transform,
|
||||
"TransformOrigin": impl_simple,
|
||||
"UserSelect": impl_simple,
|
||||
"url::UrlOrNone": impl_css_url,
|
||||
"WordBreak": impl_simple,
|
||||
"ZIndex": impl_simple,
|
||||
}
|
||||
|
||||
def longhand_method(longhand):
|
||||
|
@ -1291,15 +1258,12 @@ impl Clone for ${style_struct.gecko_struct_name} {
|
|||
args.update(keyword=longhand.keyword)
|
||||
if "font" in longhand.ident:
|
||||
args.update(cast_type=longhand.cast_type)
|
||||
else:
|
||||
elif longhand.predefined_type in predefined_types:
|
||||
method = predefined_types[longhand.predefined_type]
|
||||
else:
|
||||
method = impl_simple
|
||||
|
||||
method(**args)
|
||||
|
||||
picked_longhands = []
|
||||
for x in longhands:
|
||||
if x.keyword or x.predefined_type in predefined_types or x.logical:
|
||||
picked_longhands.append(x)
|
||||
%>
|
||||
impl ${style_struct.gecko_struct_name} {
|
||||
/*
|
||||
|
@ -1311,7 +1275,7 @@ impl ${style_struct.gecko_struct_name} {
|
|||
* Auto-Generated Methods.
|
||||
*/
|
||||
<%
|
||||
for longhand in picked_longhands:
|
||||
for longhand in longhands:
|
||||
longhand_method(longhand)
|
||||
%>
|
||||
}
|
||||
|
@ -1992,6 +1956,7 @@ fn static_assert() {
|
|||
|
||||
<%
|
||||
skip_font_longhands = """font-family font-size font-size-adjust font-weight
|
||||
font-style font-stretch -moz-script-level
|
||||
font-synthesis -x-lang font-variant-alternates
|
||||
font-variant-east-asian font-variant-ligatures
|
||||
font-variant-numeric font-language-override
|
||||
|
@ -2783,6 +2748,7 @@ fn static_assert() {
|
|||
animation-iteration-count animation-timing-function
|
||||
clear transition-duration transition-delay
|
||||
transition-timing-function transition-property
|
||||
transform-style
|
||||
rotate scroll-snap-points-x scroll-snap-points-y
|
||||
scroll-snap-coordinate -moz-binding will-change
|
||||
offset-path shape-outside contain touch-action
|
||||
|
@ -4158,7 +4124,7 @@ fn static_assert() {
|
|||
|
||||
|
||||
<%self:impl_trait style_struct_name="InheritedText"
|
||||
skip_longhands="text-align text-emphasis-style text-shadow line-height letter-spacing word-spacing
|
||||
skip_longhands="text-align text-emphasis-style text-shadow
|
||||
-webkit-text-stroke-width text-emphasis-position">
|
||||
|
||||
<% text_align_keyword = Keyword("text-align",
|
||||
|
@ -4190,78 +4156,6 @@ fn static_assert() {
|
|||
longhands::text_shadow::computed_value::List(buf)
|
||||
}
|
||||
|
||||
pub fn set_line_height(&mut self, v: longhands::line_height::computed_value::T) {
|
||||
use crate::values::generics::text::LineHeight;
|
||||
// FIXME: Align binary representations and ditch |match| for cast + static_asserts
|
||||
let en = match v {
|
||||
LineHeight::Normal => CoordDataValue::Normal,
|
||||
LineHeight::Length(val) => CoordDataValue::Coord(val.0.to_i32_au()),
|
||||
LineHeight::Number(val) => CoordDataValue::Factor(val.0),
|
||||
LineHeight::MozBlockHeight =>
|
||||
CoordDataValue::Enumerated(structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT),
|
||||
};
|
||||
self.gecko.mLineHeight.set_value(en);
|
||||
}
|
||||
|
||||
pub fn clone_line_height(&self) -> longhands::line_height::computed_value::T {
|
||||
use crate::values::generics::text::LineHeight;
|
||||
return match self.gecko.mLineHeight.as_value() {
|
||||
CoordDataValue::Normal => LineHeight::Normal,
|
||||
CoordDataValue::Coord(coord) => LineHeight::Length(Au(coord).into()),
|
||||
CoordDataValue::Factor(n) => LineHeight::Number(n.into()),
|
||||
CoordDataValue::Enumerated(val) if val == structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT =>
|
||||
LineHeight::MozBlockHeight,
|
||||
_ => panic!("this should not happen"),
|
||||
}
|
||||
}
|
||||
|
||||
<%call expr="impl_coord_copy('line_height', 'mLineHeight')"></%call>
|
||||
|
||||
pub fn set_letter_spacing(&mut self, v: longhands::letter_spacing::computed_value::T) {
|
||||
use crate::values::generics::text::Spacing;
|
||||
match v {
|
||||
Spacing::Value(value) => self.gecko.mLetterSpacing.set(value),
|
||||
Spacing::Normal => self.gecko.mLetterSpacing.set_value(CoordDataValue::Normal)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone_letter_spacing(&self) -> longhands::letter_spacing::computed_value::T {
|
||||
use crate::values::computed::Length;
|
||||
use crate::values::generics::text::Spacing;
|
||||
debug_assert!(
|
||||
matches!(self.gecko.mLetterSpacing.as_value(),
|
||||
CoordDataValue::Normal |
|
||||
CoordDataValue::Coord(_)),
|
||||
"Unexpected computed value for letter-spacing");
|
||||
Length::from_gecko_style_coord(&self.gecko.mLetterSpacing).map_or(Spacing::Normal, Spacing::Value)
|
||||
}
|
||||
|
||||
<%call expr="impl_coord_copy('letter_spacing', 'mLetterSpacing')"></%call>
|
||||
|
||||
pub fn set_word_spacing(&mut self, v: longhands::word_spacing::computed_value::T) {
|
||||
use crate::values::generics::text::Spacing;
|
||||
match v {
|
||||
Spacing::Value(lp) => self.gecko.mWordSpacing.set(lp),
|
||||
// https://drafts.csswg.org/css-text-3/#valdef-word-spacing-normal
|
||||
Spacing::Normal => self.gecko.mWordSpacing.set_value(CoordDataValue::Coord(0)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone_word_spacing(&self) -> longhands::word_spacing::computed_value::T {
|
||||
use crate::values::computed::LengthPercentage;
|
||||
use crate::values::generics::text::Spacing;
|
||||
debug_assert!(
|
||||
matches!(self.gecko.mWordSpacing.as_value(),
|
||||
CoordDataValue::Normal |
|
||||
CoordDataValue::Coord(_) |
|
||||
CoordDataValue::Percent(_) |
|
||||
CoordDataValue::Calc(_)),
|
||||
"Unexpected computed value for word-spacing");
|
||||
LengthPercentage::from_gecko_style_coord(&self.gecko.mWordSpacing).map_or(Spacing::Normal, Spacing::Value)
|
||||
}
|
||||
|
||||
<%call expr="impl_coord_copy('word_spacing', 'mWordSpacing')"></%call>
|
||||
|
||||
fn clear_text_emphasis_style_if_string(&mut self) {
|
||||
if self.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 {
|
||||
self.gecko.mTextEmphasisStyleString.truncate();
|
||||
|
|
|
@ -157,7 +157,7 @@ ${helpers.predefined_type(
|
|||
${helpers.predefined_type(
|
||||
"word-spacing",
|
||||
"WordSpacing",
|
||||
"computed::WordSpacing::normal()",
|
||||
"computed::WordSpacing::zero()",
|
||||
animation_value_type="ComputedValue",
|
||||
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
|
||||
spec="https://drafts.csswg.org/css-text/#propdef-word-spacing",
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
#[cfg(feature = "servo")]
|
||||
use crate::properties::StyleBuilder;
|
||||
use crate::values::computed::length::{Length, LengthPercentage};
|
||||
use crate::values::computed::{NonNegativeLength, NonNegativeNumber};
|
||||
use crate::values::computed::{Context, NonNegativeLength, NonNegativeNumber, ToComputedValue};
|
||||
use crate::values::generics::text::InitialLetter as GenericInitialLetter;
|
||||
use crate::values::generics::text::LineHeight as GenericLineHeight;
|
||||
use crate::values::generics::text::Spacing;
|
||||
use crate::values::specified::text::TextOverflowSide;
|
||||
use crate::values::specified::text::{self as specified, TextOverflowSide};
|
||||
use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword};
|
||||
use crate::values::{CSSFloat, CSSInteger};
|
||||
use crate::Zero;
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ToCss};
|
||||
|
||||
|
@ -25,10 +26,78 @@ pub use crate::values::specified::TextEmphasisPosition;
|
|||
pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
|
||||
|
||||
/// A computed value for the `letter-spacing` property.
|
||||
pub type LetterSpacing = Spacing<Length>;
|
||||
#[repr(transparent)]
|
||||
#[derive(
|
||||
Animate,
|
||||
Clone,
|
||||
ComputeSquaredDistance,
|
||||
Copy,
|
||||
Debug,
|
||||
MallocSizeOf,
|
||||
PartialEq,
|
||||
ToAnimatedValue,
|
||||
ToAnimatedZero,
|
||||
)]
|
||||
pub struct LetterSpacing(Length);
|
||||
|
||||
impl LetterSpacing {
|
||||
/// Return the `normal` computed value, which is just zero.
|
||||
#[inline]
|
||||
pub fn normal() -> Self {
|
||||
LetterSpacing(Length::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for LetterSpacing {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
// https://drafts.csswg.org/css-text/#propdef-letter-spacing
|
||||
//
|
||||
// For legacy reasons, a computed letter-spacing of zero yields a
|
||||
// resolved value (getComputedStyle() return value) of normal.
|
||||
if self.0.is_zero() {
|
||||
return dest.write_str("normal");
|
||||
}
|
||||
self.0.to_css(dest)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for specified::LetterSpacing {
|
||||
type ComputedValue = LetterSpacing;
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
match *self {
|
||||
Spacing::Normal => LetterSpacing(Length::zero()),
|
||||
Spacing::Value(ref v) => LetterSpacing(v.to_computed_value(context)),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
if computed.0.is_zero() {
|
||||
return Spacing::Normal;
|
||||
}
|
||||
Spacing::Value(ToComputedValue::from_computed_value(&computed.0))
|
||||
}
|
||||
}
|
||||
|
||||
/// A computed value for the `word-spacing` property.
|
||||
pub type WordSpacing = Spacing<LengthPercentage>;
|
||||
pub type WordSpacing = LengthPercentage;
|
||||
|
||||
impl ToComputedValue for specified::WordSpacing {
|
||||
type ComputedValue = WordSpacing;
|
||||
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
match *self {
|
||||
Spacing::Normal => LengthPercentage::zero(),
|
||||
Spacing::Value(ref v) => v.to_computed_value(context),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
Spacing::Value(ToComputedValue::from_computed_value(computed))
|
||||
}
|
||||
}
|
||||
|
||||
/// A computed value for the `line-height` property.
|
||||
pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeLength>;
|
||||
|
|
|
@ -5,9 +5,7 @@
|
|||
//! Generic types for text properties.
|
||||
|
||||
use crate::parser::ParserContext;
|
||||
use crate::values::animated::{Animate, Procedure, ToAnimatedZero};
|
||||
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||
use app_units::Au;
|
||||
use crate::values::animated::ToAnimatedZero;
|
||||
use cssparser::Parser;
|
||||
use style_traits::ParseError;
|
||||
|
||||
|
@ -32,7 +30,7 @@ impl<N, I> InitialLetter<N, I> {
|
|||
|
||||
/// A generic spacing value for the `letter-spacing` and `word-spacing` properties.
|
||||
#[derive(
|
||||
Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
|
||||
Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss,
|
||||
)]
|
||||
pub enum Spacing<Value> {
|
||||
/// `normal`
|
||||
|
@ -63,51 +61,6 @@ impl<Value> Spacing<Value> {
|
|||
}
|
||||
parse(context, input).map(Spacing::Value)
|
||||
}
|
||||
|
||||
/// Returns the spacing value, if not `normal`.
|
||||
#[inline]
|
||||
pub fn value(&self) -> Option<&Value> {
|
||||
match *self {
|
||||
Spacing::Normal => None,
|
||||
Spacing::Value(ref value) => Some(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Value> Animate for Spacing<Value>
|
||||
where
|
||||
Value: Animate + From<Au>,
|
||||
{
|
||||
#[inline]
|
||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||
if let (&Spacing::Normal, &Spacing::Normal) = (self, other) {
|
||||
return Ok(Spacing::Normal);
|
||||
}
|
||||
let zero = Value::from(Au(0));
|
||||
let this = self.value().unwrap_or(&zero);
|
||||
let other = other.value().unwrap_or(&zero);
|
||||
Ok(Spacing::Value(this.animate(other, procedure)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> ComputeSquaredDistance for Spacing<V>
|
||||
where
|
||||
V: ComputeSquaredDistance + From<Au>,
|
||||
{
|
||||
#[inline]
|
||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||
let zero = V::from(Au(0));
|
||||
let this = self.value().unwrap_or(&zero);
|
||||
let other = other.value().unwrap_or(&zero);
|
||||
this.compute_squared_distance(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> ToAnimatedZero for Spacing<V> {
|
||||
#[inline]
|
||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A generic value for the `line-height` property.
|
||||
|
@ -123,18 +76,21 @@ impl<V> ToAnimatedZero for Spacing<V> {
|
|||
ToAnimatedValue,
|
||||
ToCss,
|
||||
)]
|
||||
pub enum LineHeight<Number, LengthPercentage> {
|
||||
#[repr(C, u8)]
|
||||
pub enum GenericLineHeight<N, L> {
|
||||
/// `normal`
|
||||
Normal,
|
||||
/// `-moz-block-height`
|
||||
#[cfg(feature = "gecko")]
|
||||
MozBlockHeight,
|
||||
/// `<number>`
|
||||
Number(Number),
|
||||
/// `<length-or-percentage>`
|
||||
Length(LengthPercentage),
|
||||
Number(N),
|
||||
/// `<length-percentage>`
|
||||
Length(L),
|
||||
}
|
||||
|
||||
pub use self::GenericLineHeight as LineHeight;
|
||||
|
||||
impl<N, L> ToAnimatedZero for LineHeight<N, L> {
|
||||
#[inline]
|
||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
||||
|
|
|
@ -1,16 +1,5 @@
|
|||
prefs: [layout.css.font-variations.enabled:true, layout.css.overflow-clip-box.enabled:true, layout.css.individual-transform.enabled:true]
|
||||
[accumulation-per-property.html]
|
||||
[word-spacing: calc]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing: units "calc" onto "px"]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing: units "rem" onto "%"]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing: units "px" onto "%"]
|
||||
expected: FAIL
|
||||
|
||||
[flex-basis: units "%" onto "px"]
|
||||
expected: FAIL
|
||||
|
@ -18,9 +7,6 @@ prefs: [layout.css.font-variations.enabled:true, layout.css.overflow-clip-box.en
|
|||
[flex-basis: units "%" onto "rem"]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing: units "%" onto "px"]
|
||||
expected: FAIL
|
||||
|
||||
[flex-basis: units "px" onto "%"]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -30,9 +16,6 @@ prefs: [layout.css.font-variations.enabled:true, layout.css.overflow-clip-box.en
|
|||
[flex-basis: units "rem" onto "%"]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing: units "%" onto "rem"]
|
||||
expected: FAIL
|
||||
|
||||
[flex-basis: units "calc" onto "px"]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
prefs: [layout.css.font-variations.enabled:true, layout.css.overflow-clip-box.enabled:true, layout.css.individual-transform.enabled:true]
|
||||
[addition-per-property.html]
|
||||
[word-spacing: calc]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing: units "rem" onto "%"]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing: units "px" onto "%"]
|
||||
expected: FAIL
|
||||
|
||||
[flex-basis: units "px" onto "%"]
|
||||
expected: FAIL
|
||||
|
@ -15,12 +7,6 @@ prefs: [layout.css.font-variations.enabled:true, layout.css.overflow-clip-box.en
|
|||
[flex-basis: units "%" onto "rem"]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing: units "calc" onto "px"]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing: units "%" onto "px"]
|
||||
expected: FAIL
|
||||
|
||||
[flex-basis: calc]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -30,9 +16,6 @@ prefs: [layout.css.font-variations.enabled:true, layout.css.overflow-clip-box.en
|
|||
[flex-basis: units "%" onto "px"]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing: units "%" onto "rem"]
|
||||
expected: FAIL
|
||||
|
||||
[flex-basis: units "calc" onto "px"]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -7,24 +7,12 @@ prefs: [layout.css.font-variations.enabled:true, layout.css.overflow-clip-box.en
|
|||
[flex-basis supports animating as combination units "px" and "%"]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing supports animating as combination units "px" and "%"]
|
||||
expected: FAIL
|
||||
|
||||
[flex-basis supports animating as combination units "px" and "calc"]
|
||||
expected: FAIL
|
||||
|
||||
[flex-basis supports animating as a calc]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing supports animating as combination units "px" and "calc"]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing supports animating as a calc]
|
||||
expected: FAIL
|
||||
|
||||
[word-spacing supports animating as combination units "%" and "em"]
|
||||
expected: FAIL
|
||||
|
||||
[flex-basis supports animating as combination units "%" and "em"]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче