Bug 770780 - Add support for parsing of the CSS text-underline-position property. r=emilio

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jonathan Kew 2019-12-04 11:39:15 +00:00
parent 03dfefdf7e
commit 3b87f01682
20 changed files with 190 additions and 46 deletions

View File

@ -153,6 +153,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"-moz-text-size-adjust",
"-webkit-text-stroke-width",
"text-transform",
"text-underline-position",
"touch-action",
"transform-box",
"transform-style",

View File

@ -3206,6 +3206,7 @@ exports.CSS_PROPERTIES = {
"text-rendering",
"-moz-control-character-visibility",
"text-underline-offset",
"text-underline-position",
"text-decoration-skip-ink",
"cursor",
"pointer-events",
@ -10865,6 +10866,10 @@ exports.PREFERENCES = [
"text-justify",
"layout.css.text-justify.enabled"
],
[
"text-underline-position",
"layout.css.text-underline-position.enabled"
],
[
"touch-action",
"layout.css.touch_action.enabled"

View File

@ -56,6 +56,7 @@ hide-types = [
bitfield-enums = [
"nsChangeHint",
"mozilla::OriginFlags",
"mozilla::StyleTextUnderlinePosition",
]
rusty-enums = [
"nsCompatibility",
@ -479,6 +480,7 @@ cbindgen-types = [
{ gecko = "StyleWillChange", servo = "values::specified::box_::WillChange" },
{ gecko = "StyleTextDecorationLine", servo = "values::computed::TextDecorationLine" },
{ gecko = "StyleTextTransform", servo = "values::computed::TextTransform" },
{ gecko = "StyleTextUnderlinePosition", servo = "values::computed::TextUnderlinePosition" },
{ gecko = "StyleMozListReversed", servo = "values::computed::MozListReversed" },
{ gecko = "StyleOwned", servo = "gecko_bindings::sugar::ownership::Owned" },
{ gecko = "StyleOwnedOrNull", servo = "gecko_bindings::sugar::ownership::OwnedOrNull" },

View File

@ -3426,6 +3426,7 @@ nsStyleText::nsStyleText(const Document& aDocument)
mTextIndent(LengthPercentage::Zero()),
mTextUnderlineOffset(StyleTextDecorationLength::Auto()),
mTextDecorationSkipInk(StyleTextDecorationSkipInk::Auto),
mTextUnderlinePosition(StyleTextUnderlinePosition::Auto()),
mWebkitTextStrokeWidth(0),
mTextEmphasisStyle(StyleTextEmphasisStyle::None()) {
MOZ_COUNT_CTOR(nsStyleText);
@ -3464,6 +3465,7 @@ nsStyleText::nsStyleText(const nsStyleText& aSource)
mTextIndent(aSource.mTextIndent),
mTextUnderlineOffset(aSource.mTextUnderlineOffset),
mTextDecorationSkipInk(aSource.mTextDecorationSkipInk),
mTextUnderlinePosition(aSource.mTextUnderlinePosition),
mWebkitTextStrokeWidth(aSource.mWebkitTextStrokeWidth),
mTextShadow(aSource.mTextShadow),
mTextEmphasisStyle(aSource.mTextEmphasisStyle) {
@ -3524,7 +3526,8 @@ nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aNewData) const {
if (mTextShadow != aNewData.mTextShadow ||
mTextEmphasisStyle != aNewData.mTextEmphasisStyle ||
mWebkitTextStrokeWidth != aNewData.mWebkitTextStrokeWidth) {
mWebkitTextStrokeWidth != aNewData.mWebkitTextStrokeWidth ||
mTextUnderlinePosition != aNewData.mTextUnderlinePosition) {
hint |= nsChangeHint_UpdateSubtreeOverflow | nsChangeHint_SchedulePaint |
nsChangeHint_RepaintFrame;

View File

@ -1166,6 +1166,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
mozilla::StyleTextDecorationLength mTextUnderlineOffset;
mozilla::StyleTextDecorationSkipInk mTextDecorationSkipInk;
mozilla::StyleTextUnderlinePosition mTextUnderlinePosition;
nscoord mWebkitTextStrokeWidth; // coord
@ -1290,6 +1291,22 @@ inline StyleTextTransform StyleTextTransform::None() {
inline bool StyleTextTransform::IsNone() const { return *this == None(); }
inline StyleTextUnderlinePosition StyleTextUnderlinePosition::Auto() {
return StyleTextUnderlinePosition_AUTO;
}
inline bool StyleTextUnderlinePosition::IsAuto() const {
return *this == Auto();
}
inline bool StyleTextUnderlinePosition::IsUnder() const {
return bool(*this & StyleTextUnderlinePosition_UNDER);
}
inline bool StyleTextUnderlinePosition::IsLeft() const {
return bool(*this & StyleTextUnderlinePosition_LEFT);
}
inline bool StyleTextUnderlinePosition::IsRight() const {
return bool(*this & StyleTextUnderlinePosition_RIGHT);
}
struct StyleTransition {
StyleTransition() { /* leaves uninitialized; see also SetInitialValues */
}

View File

@ -12,6 +12,7 @@ prefs =
layout.css.overflow-logical.enabled=true
layout.css.step-position-jump.enabled=true
layout.css.text-underline-offset.enabled=true
layout.css.text-underline-position.enabled=true
layout.css.text-decoration-thickness.enabled=true
layout.css.backdrop-filter.enabled=true
layout.css.text-decoration-skip-ink.enabled=true

View File

@ -7757,6 +7757,34 @@ var gCSSProperties = {
"from font",
],
},
"text-underline-position": {
domProp: "textUnderlinePosition",
inherited: true,
type: CSS_TYPE_LONGHAND,
applies_to_first_letter: true,
applies_to_first_line: true,
applies_to_placeholder: true,
initial_values: ["auto"],
other_values: [
"under",
"left",
"right",
"left under",
"under left",
"right under",
"under right",
],
invalid_values: [
"none",
"auto under",
"left right",
"right auto",
"0",
"1px",
"10%",
"from-font",
],
},
"text-emphasis": {
domProp: "textEmphasis",
inherited: true,

View File

@ -4853,6 +4853,12 @@
value: true
mirror: always
# text underline position
- name: layout.css.text-underline-position.enabled
type: bool
value: false
mirror: always
# text decoration thickness
- name: layout.css.text-decoration-thickness.enabled
type: bool

View File

@ -10,7 +10,8 @@
# "offset-distance",
# "offset-path",
# "offset-rotate",
# "offset"
# "offset",
# "text-underline-position",
COUNTED_UNKNOWN_PROPERTIES = [
"-webkit-font-smoothing",
"-webkit-tap-highlight-color",
@ -40,7 +41,6 @@ COUNTED_UNKNOWN_PROPERTIES = [
"baseline-shift",
"-webkit-hyphenate-character",
"page",
"text-underline-position",
"-webkit-highlight",
"background-repeat-x",
"-webkit-padding-end",

View File

@ -385,6 +385,7 @@ class Longhand(object):
"TextDecorationLine",
"TextEmphasisPosition",
"TextTransform",
"TextUnderlinePosition",
"TouchAction",
"TransformStyle",
"UserSelect",

View File

@ -392,6 +392,18 @@ ${helpers.predefined_type(
spec="https://drafts.csswg.org/css-text-decor-4/#underline-offset",
)}
// text underline position
${helpers.predefined_type(
"text-underline-position",
"TextUnderlinePosition",
"computed::TextUnderlinePosition::AUTO",
engines="gecko",
animation_value_type="discrete",
gecko_pref="layout.css.text-underline-position.enabled",
has_effect_on_gecko_scrollbars=False,
spec="https://drafts.csswg.org/css-text-decor-3/#text-underline-position-property",
)}
// text decoration skip ink
${helpers.predefined_type(
"text-decoration-skip-ink",

View File

@ -79,6 +79,7 @@ pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight};
pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing};
pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle};
pub use self::text::{TextDecorationLength, TextDecorationSkipInk};
pub use self::text::TextUnderlinePosition;
pub use self::time::Time;
pub use self::transform::{Rotate, Scale, Transform, TransformOperation};
pub use self::transform::{TransformOrigin, TransformStyle, Translate};

View File

@ -22,6 +22,7 @@ pub use crate::values::specified::TextAlignKeyword as TextAlign;
pub use crate::values::specified::{LineBreak, OverflowWrap, WordBreak};
pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition};
pub use crate::values::specified::{TextDecorationSkipInk, TextTransform};
pub use crate::values::specified::TextUnderlinePosition;
/// A computed value for the `initial-letter` property.
pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;

View File

@ -84,6 +84,7 @@ pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAl
pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak};
pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};
pub use self::text::{TextDecorationLength, TextDecorationSkipInk, TextTransform};
pub use self::text::TextUnderlinePosition;
pub use self::time::Time;
pub use self::transform::{Rotate, Scale, Transform};
pub use self::transform::{TransformOrigin, TransformStyle, Translate};

View File

@ -1053,3 +1053,98 @@ impl TextDecorationLength {
matches!(*self, GenericTextDecorationLength::Auto)
}
}
bitflags! {
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
#[value_info(other_values = "auto,under,left,right")]
#[repr(C)]
/// Specified keyword values for the text-underline-position property.
/// (Non-exclusive, but not all combinations are allowed: only `under` may occur
/// together with either `left` or `right`.)
/// https://drafts.csswg.org/css-text-decor-3/#text-underline-position-property
pub struct TextUnderlinePosition: u8 {
/// Use automatic positioning below the alphabetic baseline.
const AUTO = 0;
/// Below the glyph box.
const UNDER = 1 << 0;
/// In vertical mode, place to the left of the text.
const LEFT = 1 << 1;
/// In vertical mode, place to the right of the text.
const RIGHT = 1 << 2;
}
}
impl Parse for TextUnderlinePosition {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<TextUnderlinePosition, ParseError<'i>> {
let mut result = TextUnderlinePosition::empty();
loop {
let location = input.current_source_location();
let ident = match input.next() {
Ok(&Token::Ident(ref ident)) => ident,
Ok(other) => return Err(location.new_unexpected_token_error(other.clone())),
Err(..) => break,
};
match_ignore_ascii_case! { ident,
"auto" if result.is_empty() => {
return Ok(result);
},
"under" if !result.intersects(TextUnderlinePosition::UNDER) => {
result.insert(TextUnderlinePosition::UNDER);
},
"left" if !result.intersects(TextUnderlinePosition::LEFT |
TextUnderlinePosition::RIGHT) => {
result.insert(TextUnderlinePosition::LEFT);
},
"right" if !result.intersects(TextUnderlinePosition::LEFT |
TextUnderlinePosition::RIGHT) => {
result.insert(TextUnderlinePosition::RIGHT);
},
_ => return Err(location.new_custom_error(
SelectorParseErrorKind::UnexpectedIdent(ident.clone())
)),
}
}
if !result.is_empty() {
Ok(result)
} else {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
}
}
impl ToCss for TextUnderlinePosition {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
if self.is_empty() {
return dest.write_str("auto");
}
let mut writer = SequenceWriter::new(dest, " ");
let mut any = false;
macro_rules! maybe_write {
($ident:ident => $str:expr) => {
if self.contains(TextUnderlinePosition::$ident) {
any = true;
writer.raw_item($str)?;
}
};
}
maybe_write!(UNDER => "under");
maybe_write!(LEFT => "left");
maybe_write!(RIGHT => "right");
debug_assert!(any);
Ok(())
}
}

View File

@ -130,6 +130,7 @@ include = [
"TouchAction",
"WillChange",
"TextDecorationLine",
"TextUnderlinePosition",
"TextTransform",
"TextOverflow",
"MozListReversed",
@ -338,6 +339,14 @@ renaming_overrides_prefixing = true
inline bool IsNone() const;
"""
"TextUnderlinePosition" = """
static inline StyleTextUnderlinePosition Auto();
inline bool IsAuto() const;
inline bool IsUnder() const;
inline bool IsLeft() const;
inline bool IsRight() const;
"""
# TODO(emilio): Add hooks to cbindgen to be able to generate MOZ_MUST_USE_TYPE
# or MOZ_MUST_USE on the functions.
"Owned" = """

View File

@ -1,4 +1,5 @@
[first-letter-property-whitelist.html]
prefs: [layout.css.text-underline-position.enabled:true]
[Whitelisted property backgroundPosition should be applied to first-letter pseudo elements.]
expected: FAIL
@ -31,6 +32,3 @@
[Whitelisted property textJustify should be applied to first-letter pseudo elements.]
expected: FAIL
[Whitelisted property textUnderlinePosition should be applied to first-letter pseudo elements.]
expected: FAIL

View File

@ -1,8 +1,2 @@
[inheritance.html]
prefs: [layout.css.text-decoration-skip-ink.enabled:true]
[Property text-underline-position has initial value auto]
expected: FAIL
[Property text-underline-position inherits]
expected: FAIL
prefs: [layout.css.text-decoration-skip-ink.enabled:true, layout.css.text-underline-position.enabled:true]

View File

@ -1,16 +1,2 @@
[text-underline-position-computed.html]
[Property text-underline-position value 'under left' computes to 'under left']
expected: FAIL
[Property text-underline-position value 'under' computes to 'under']
expected: FAIL
[Property text-underline-position value 'right' computes to 'right']
expected: FAIL
[Property text-underline-position value 'left' computes to 'left']
expected: FAIL
[Property text-underline-position value 'auto' computes to 'auto']
expected: FAIL
prefs: [layout.css.text-underline-position.enabled:true]

View File

@ -1,19 +1,2 @@
[text-underline-position-valid.html]
[e.style['text-underline-position'\] = "right under" should set the property value]
expected: FAIL
[e.style['text-underline-position'\] = "under left" should set the property value]
expected: FAIL
[e.style['text-underline-position'\] = "auto" should set the property value]
expected: FAIL
[e.style['text-underline-position'\] = "left" should set the property value]
expected: FAIL
[e.style['text-underline-position'\] = "right" should set the property value]
expected: FAIL
[e.style['text-underline-position'\] = "under" should set the property value]
expected: FAIL
prefs: [layout.css.text-underline-position.enabled:true]