Skip to content

Commit

Permalink
Auto merge of #13860 - canaltinova:text-emphasis-style, r=Manishearth…
Browse files Browse the repository at this point in the history
…,emilio

Implement parsing/serialization and gecko glue for text-emphasis-style

<!-- 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. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13860)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Oct 23, 2016
2 parents 62689ba + 6dc2c36 commit bfd966f
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 2 deletions.
51 changes: 50 additions & 1 deletion components/style/properties/gecko.mako.rs
Expand Up @@ -1646,7 +1646,7 @@ fn static_assert() {


<%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 " +
"-moz-right match-parent") %>
Expand Down Expand Up @@ -1744,6 +1744,55 @@ fn static_assert() {

<%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 style_struct_name="Text"
Expand Down
198 changes: 198 additions & 0 deletions components/style/properties/longhand/inherited_text.mako.rs
Expand Up @@ -737,7 +737,205 @@ ${helpers.single_keyword("text-align-last",
}
</%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`
${helpers.single_keyword("text-transform",
Expand Down
3 changes: 2 additions & 1 deletion components/style/properties/properties.mako.rs
Expand Up @@ -1639,7 +1639,8 @@ pub fn cascade(viewport_size: Size2D<Au>,
PropertyDeclaration::Color(_) |
PropertyDeclaration::Position(_) |
PropertyDeclaration::Float(_) |
PropertyDeclaration::TextDecoration${'' if product == 'servo' else 'Line'}(_)
PropertyDeclaration::TextDecoration${'' if product == 'servo' else 'Line'}(_) |
PropertyDeclaration::WritingMode(_)
);
if
% if category_to_cascade_now == "early":
Expand Down
46 changes: 46 additions & 0 deletions tests/unit/style/parsing/inherited_text.rs
@@ -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);
}
1 change: 1 addition & 0 deletions tests/unit/style/parsing/mod.rs
Expand Up @@ -63,6 +63,7 @@ macro_rules! parse_longhand {

mod basic_shape;
mod image;
mod inherited_text;
mod mask;
mod position;
mod selectors;

0 comments on commit bfd966f

Please sign in to comment.