зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #13860 - Implement parsing/serialization and gecko glue for text-emphasis-style (from canaltinova:text-emphasis-style); r=Manishearth,emilio
<!-- Please describe your changes on the following line: --> Implementation of parsing/serialization and gecko glue for text-emphasis-style. r? @Manishearth --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #13853 (github issue number if applicable). <!-- Either: --> - [X] There are tests for these changes <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bfd966f81998cc13f067a31182115577ba9346ca
This commit is contained in:
Родитель
42c549806a
Коммит
aa6bea5f24
|
@ -1646,7 +1646,7 @@ fn static_assert() {
|
||||||
|
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="InheritedText"
|
<%self:impl_trait style_struct_name="InheritedText"
|
||||||
skip_longhands="text-align text-shadow line-height letter-spacing word-spacing">
|
skip_longhands="text-align text-emphasis-style text-shadow line-height letter-spacing word-spacing">
|
||||||
|
|
||||||
<% text_align_keyword = Keyword("text-align", "start end left right center justify -moz-center -moz-left " +
|
<% text_align_keyword = Keyword("text-align", "start end left right center justify -moz-center -moz-left " +
|
||||||
"-moz-right match-parent") %>
|
"-moz-right match-parent") %>
|
||||||
|
@ -1744,6 +1744,55 @@ fn static_assert() {
|
||||||
|
|
||||||
<%call expr="impl_coord_copy('word_spacing', 'mWordSpacing')"></%call>
|
<%call expr="impl_coord_copy('word_spacing', 'mWordSpacing')"></%call>
|
||||||
|
|
||||||
|
fn clear_text_emphasis_style_if_string(&mut self) {
|
||||||
|
use nsstring::nsString;
|
||||||
|
if self.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 {
|
||||||
|
self.gecko.mTextEmphasisStyleString.assign(&nsString::new());
|
||||||
|
self.gecko.mTextEmphasisStyle = structs::NS_STYLE_TEXT_EMPHASIS_STYLE_NONE as u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_text_emphasis_style(&mut self, v: longhands::text_emphasis_style::computed_value::T) {
|
||||||
|
use nsstring::nsCString;
|
||||||
|
use properties::longhands::text_emphasis_style::computed_value::T;
|
||||||
|
use properties::longhands::text_emphasis_style::ShapeKeyword;
|
||||||
|
|
||||||
|
self.clear_text_emphasis_style_if_string();
|
||||||
|
let (te, s) = match v {
|
||||||
|
T::None => (structs::NS_STYLE_TEXT_EMPHASIS_STYLE_NONE, ""),
|
||||||
|
T::Keyword(ref keyword) => {
|
||||||
|
let fill = if keyword.fill {
|
||||||
|
structs::NS_STYLE_TEXT_EMPHASIS_STYLE_FILLED
|
||||||
|
} else {
|
||||||
|
structs::NS_STYLE_TEXT_EMPHASIS_STYLE_OPEN
|
||||||
|
};
|
||||||
|
let shape = match keyword.shape {
|
||||||
|
ShapeKeyword::Dot => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_DOT,
|
||||||
|
ShapeKeyword::Circle => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_CIRCLE,
|
||||||
|
ShapeKeyword::DoubleCircle => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_DOUBLE_CIRCLE,
|
||||||
|
ShapeKeyword::Triangle => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_TRIANGLE,
|
||||||
|
ShapeKeyword::Sesame => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_SESAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
(shape | fill, keyword.shape.char(keyword.fill))
|
||||||
|
},
|
||||||
|
T::String(ref s) => {
|
||||||
|
(structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING, &**s)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
self.gecko.mTextEmphasisStyleString.assign_utf8(&nsCString::from(s));
|
||||||
|
self.gecko.mTextEmphasisStyle = te as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_text_emphasis_style_from(&mut self, other: &Self) {
|
||||||
|
self.clear_text_emphasis_style_if_string();
|
||||||
|
if other.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 {
|
||||||
|
self.gecko.mTextEmphasisStyleString
|
||||||
|
.assign(&other.gecko.mTextEmphasisStyleString)
|
||||||
|
}
|
||||||
|
self.gecko.mTextEmphasisStyle = other.gecko.mTextEmphasisStyle;
|
||||||
|
}
|
||||||
|
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="Text"
|
<%self:impl_trait style_struct_name="Text"
|
||||||
|
|
|
@ -737,7 +737,205 @@ ${helpers.single_keyword("text-align-last",
|
||||||
}
|
}
|
||||||
</%helpers:longhand>
|
</%helpers:longhand>
|
||||||
|
|
||||||
|
<%helpers:longhand name="text-emphasis-style" products="gecko" need_clone="True" animatable="False">
|
||||||
|
use computed_values::writing_mode::T as writing_mode;
|
||||||
|
use cssparser::ToCss;
|
||||||
|
use std::fmt;
|
||||||
|
use values::LocalToCss;
|
||||||
|
use values::NoViewportPercentage;
|
||||||
|
|
||||||
|
impl NoViewportPercentage for SpecifiedValue {}
|
||||||
|
|
||||||
|
pub mod computed_value {
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub enum T {
|
||||||
|
Keyword(KeywordValue),
|
||||||
|
None,
|
||||||
|
String(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub struct KeywordValue {
|
||||||
|
pub fill: bool,
|
||||||
|
pub shape: super::ShapeKeyword,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub enum SpecifiedValue {
|
||||||
|
Keyword(KeywordValue),
|
||||||
|
None,
|
||||||
|
String(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for computed_value::T {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
match *self {
|
||||||
|
computed_value::T::Keyword(ref keyword) => keyword.to_css(dest),
|
||||||
|
computed_value::T::None => dest.write_str("none"),
|
||||||
|
computed_value::T::String(ref string) => write!(dest, "\"{}\"", string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ToCss for SpecifiedValue {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
match *self {
|
||||||
|
SpecifiedValue::Keyword(ref keyword) => keyword.to_css(dest),
|
||||||
|
SpecifiedValue::None => dest.write_str("none"),
|
||||||
|
SpecifiedValue::String(ref string) => write!(dest, "\"{}\"", string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub enum KeywordValue {
|
||||||
|
Fill(bool),
|
||||||
|
Shape(ShapeKeyword),
|
||||||
|
FillAndShape(bool, ShapeKeyword),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for KeywordValue {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
if let Some(fill) = self.fill() {
|
||||||
|
if fill {
|
||||||
|
try!(dest.write_str("filled"));
|
||||||
|
} else {
|
||||||
|
try!(dest.write_str("open"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(shape) = self.shape() {
|
||||||
|
if self.fill().is_some() {
|
||||||
|
try!(dest.write_str(" "));
|
||||||
|
}
|
||||||
|
try!(shape.to_css(dest));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ToCss for computed_value::KeywordValue {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
if self.fill {
|
||||||
|
try!(dest.write_str("filled"));
|
||||||
|
} else {
|
||||||
|
try!(dest.write_str("open"));
|
||||||
|
}
|
||||||
|
try!(dest.write_str(" "));
|
||||||
|
self.shape.to_css(dest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeywordValue {
|
||||||
|
fn fill(&self) -> Option<bool> {
|
||||||
|
match *self {
|
||||||
|
KeywordValue::Fill(fill) |
|
||||||
|
KeywordValue::FillAndShape(fill,_) => Some(fill),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn shape(&self) -> Option<ShapeKeyword> {
|
||||||
|
match *self {
|
||||||
|
KeywordValue::Shape(shape) |
|
||||||
|
KeywordValue::FillAndShape(_, shape) => Some(shape),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define_css_keyword_enum!(ShapeKeyword:
|
||||||
|
"dot" => Dot,
|
||||||
|
"circle" => Circle,
|
||||||
|
"double-circle" => DoubleCircle,
|
||||||
|
"triangle" => Triangle,
|
||||||
|
"sesame" => Sesame);
|
||||||
|
|
||||||
|
impl ShapeKeyword {
|
||||||
|
pub fn char(&self, fill: bool) -> &str {
|
||||||
|
match *self {
|
||||||
|
ShapeKeyword::Dot => if fill { "\u{2022}" } else { "\u{25e6}" },
|
||||||
|
ShapeKeyword::Circle => if fill { "\u{25cf}" } else { "\u{25cb}" },
|
||||||
|
ShapeKeyword::DoubleCircle => if fill { "\u{25c9}" } else { "\u{25ce}" },
|
||||||
|
ShapeKeyword::Triangle => if fill { "\u{25b2}" } else { "\u{25b3}" },
|
||||||
|
ShapeKeyword::Sesame => if fill { "\u{fe45}" } else { "\u{fe46}" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
|
computed_value::T::None
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToComputedValue for SpecifiedValue {
|
||||||
|
type ComputedValue = computed_value::T;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||||
|
match *self {
|
||||||
|
SpecifiedValue::Keyword(ref keyword) => {
|
||||||
|
let default_shape = if context.style().get_inheritedbox()
|
||||||
|
.clone_writing_mode() == writing_mode::horizontal_tb {
|
||||||
|
ShapeKeyword::Circle
|
||||||
|
} else {
|
||||||
|
ShapeKeyword::Sesame
|
||||||
|
};
|
||||||
|
computed_value::T::Keyword(computed_value::KeywordValue {
|
||||||
|
fill: keyword.fill().unwrap_or(true),
|
||||||
|
shape: keyword.shape().unwrap_or(default_shape),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
SpecifiedValue::None => computed_value::T::None,
|
||||||
|
SpecifiedValue::String(ref s) => {
|
||||||
|
let string = s.chars().next().as_ref().map(ToString::to_string).unwrap_or_default();
|
||||||
|
computed_value::T::String(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn from_computed_value(computed: &computed_value::T) -> Self {
|
||||||
|
match *computed {
|
||||||
|
computed_value::T::Keyword(ref keyword) =>
|
||||||
|
SpecifiedValue::Keyword(KeywordValue::FillAndShape(keyword.fill,keyword.shape)),
|
||||||
|
computed_value::T::None => SpecifiedValue::None,
|
||||||
|
computed_value::T::String(ref string) => SpecifiedValue::String(string.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
||||||
|
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||||
|
return Ok(SpecifiedValue::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(s) = input.try(|input| input.expect_string()) {
|
||||||
|
// Handle <string>
|
||||||
|
return Ok(SpecifiedValue::String(s.into_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle a pair of keywords
|
||||||
|
let mut shape = input.try(ShapeKeyword::parse);
|
||||||
|
let fill = if input.try(|input| input.expect_ident_matching("filled")).is_ok() {
|
||||||
|
Some(true)
|
||||||
|
} else if input.try(|input| input.expect_ident_matching("open")).is_ok() {
|
||||||
|
Some(false)
|
||||||
|
} else { None };
|
||||||
|
if shape.is_err() {
|
||||||
|
shape = input.try(ShapeKeyword::parse);
|
||||||
|
}
|
||||||
|
|
||||||
|
// At least one of shape or fill must be handled
|
||||||
|
let keyword_value = match (fill, shape) {
|
||||||
|
(Some(fill), Ok(shape)) => KeywordValue::FillAndShape(fill,shape),
|
||||||
|
(Some(fill), Err(_)) => KeywordValue::Fill(fill),
|
||||||
|
(None, Ok(shape)) => KeywordValue::Shape(shape),
|
||||||
|
_ => return Err(()),
|
||||||
|
};
|
||||||
|
Ok(SpecifiedValue::Keyword(keyword_value))
|
||||||
|
}
|
||||||
|
</%helpers:longhand>
|
||||||
|
|
||||||
// TODO(pcwalton): `full-width`
|
// TODO(pcwalton): `full-width`
|
||||||
${helpers.single_keyword("text-transform",
|
${helpers.single_keyword("text-transform",
|
||||||
|
|
|
@ -1639,7 +1639,8 @@ pub fn cascade(viewport_size: Size2D<Au>,
|
||||||
PropertyDeclaration::Color(_) |
|
PropertyDeclaration::Color(_) |
|
||||||
PropertyDeclaration::Position(_) |
|
PropertyDeclaration::Position(_) |
|
||||||
PropertyDeclaration::Float(_) |
|
PropertyDeclaration::Float(_) |
|
||||||
PropertyDeclaration::TextDecoration${'' if product == 'servo' else 'Line'}(_)
|
PropertyDeclaration::TextDecoration${'' if product == 'servo' else 'Line'}(_) |
|
||||||
|
PropertyDeclaration::WritingMode(_)
|
||||||
);
|
);
|
||||||
if
|
if
|
||||||
% if category_to_cascade_now == "early":
|
% if category_to_cascade_now == "early":
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use cssparser::Parser;
|
||||||
|
use media_queries::CSSErrorReporterTest;
|
||||||
|
use style::parser::ParserContext;
|
||||||
|
use style::stylesheets::Origin;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn text_emphasis_style_longhand_should_parse_properly() {
|
||||||
|
use style::properties::longhands::text_emphasis_style;
|
||||||
|
use style::properties::longhands::text_emphasis_style::{ShapeKeyword, SpecifiedValue, KeywordValue};
|
||||||
|
|
||||||
|
let none = parse_longhand!(text_emphasis_style, "none");
|
||||||
|
assert_eq!(none, SpecifiedValue::None);
|
||||||
|
|
||||||
|
let fill = parse_longhand!(text_emphasis_style, "open");
|
||||||
|
let fill_struct = SpecifiedValue::Keyword(KeywordValue::Fill(false));
|
||||||
|
assert_eq!(fill, fill_struct);
|
||||||
|
|
||||||
|
let shape = parse_longhand!(text_emphasis_style, "triangle");
|
||||||
|
let shape_struct = SpecifiedValue::Keyword(KeywordValue::Shape(ShapeKeyword::Triangle));
|
||||||
|
assert_eq!(shape, shape_struct);
|
||||||
|
|
||||||
|
let fill_shape = parse_longhand!(text_emphasis_style, "filled dot");
|
||||||
|
let fill_shape_struct = SpecifiedValue::Keyword(KeywordValue::FillAndShape(true, ShapeKeyword::Dot));
|
||||||
|
assert_eq!(fill_shape, fill_shape_struct);
|
||||||
|
|
||||||
|
let shape_fill = parse_longhand!(text_emphasis_style, "dot filled");
|
||||||
|
let shape_fill_struct = SpecifiedValue::Keyword(KeywordValue::FillAndShape(true, ShapeKeyword::Dot));
|
||||||
|
assert_eq!(shape_fill, shape_fill_struct);
|
||||||
|
|
||||||
|
let a_string = parse_longhand!(text_emphasis_style, "\"a\"");
|
||||||
|
let a_string_struct = SpecifiedValue::String("a".to_string());
|
||||||
|
assert_eq!(a_string, a_string_struct);
|
||||||
|
|
||||||
|
let chinese_string = parse_longhand!(text_emphasis_style, "\"点\"");
|
||||||
|
let chinese_string_struct = SpecifiedValue::String("点".to_string());
|
||||||
|
assert_eq!(chinese_string, chinese_string_struct);
|
||||||
|
|
||||||
|
let unicode_string = parse_longhand!(text_emphasis_style, "\"\\25B2\"");
|
||||||
|
let unicode_string_struct = SpecifiedValue::String("▲".to_string());
|
||||||
|
assert_eq!(unicode_string, unicode_string_struct);
|
||||||
|
}
|
|
@ -63,6 +63,7 @@ macro_rules! parse_longhand {
|
||||||
|
|
||||||
mod basic_shape;
|
mod basic_shape;
|
||||||
mod image;
|
mod image;
|
||||||
|
mod inherited_text;
|
||||||
mod mask;
|
mod mask;
|
||||||
mod position;
|
mod position;
|
||||||
mod selectors;
|
mod selectors;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче