Auto merge of #15331 - Manishearth:stylo-presattr, r=emilio,bz

Basic handling framework for presentation attributes in Stylo, with handling for font-size and color

https://bugzilla.mozilla.org/show_bug.cgi?id=1330041

r=emilio,bz

<!-- 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/15331)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-02-03 17:36:04 -08:00 committed by GitHub
commit 57fb07e9c0
6 changed files with 126 additions and 24 deletions

View file

@ -123,7 +123,7 @@ impl HTMLFontElementLayoutHelpers for LayoutJS<HTMLFontElement> {
}
/// https://html.spec.whatwg.org/multipage/#rules-for-parsing-a-legacy-font-size
pub fn parse_legacy_font_size(mut input: &str) -> Option<&'static str> {
fn parse_length(mut input: &str) -> Option<specified::Length> {
// Steps 1 & 2 are not relevant
// Step 3
@ -153,8 +153,8 @@ pub fn parse_legacy_font_size(mut input: &str) -> Option<&'static str> {
// Steps 6, 7, 8
let mut value = match read_numbers(input_chars) {
(Some(v), _) => v,
(None, _) => return None,
(Some(v), _) if v >= 0 => v,
_ => return None,
};
// Step 9
@ -165,18 +165,5 @@ pub fn parse_legacy_font_size(mut input: &str) -> Option<&'static str> {
}
// Steps 10, 11, 12
Some(match value {
n if n >= 7 => "xxx-large",
6 => "xx-large",
5 => "x-large",
4 => "large",
3 => "medium",
2 => "small",
n if n <= 1 => "x-small",
_ => unreachable!(),
})
}
fn parse_length(value: &str) -> Option<specified::Length> {
parse_legacy_font_size(&value).and_then(|parsed| specified::Length::from_str(&parsed))
Some(specified::Length::from_font_size_int(value as u8))
}

View file

@ -30,7 +30,8 @@ use gecko_bindings::bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink, Gecko
use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
use gecko_bindings::bindings::Gecko_ClassOrClassList;
use gecko_bindings::bindings::Gecko_GetAnimationRule;
use gecko_bindings::bindings::Gecko_GetServoDeclarationBlock;
use gecko_bindings::bindings::Gecko_GetHTMLPresentationAttrDeclarationBlock;
use gecko_bindings::bindings::Gecko_GetStyleAttrDeclarationBlock;
use gecko_bindings::bindings::Gecko_GetStyleContext;
use gecko_bindings::structs;
use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode};
@ -42,6 +43,7 @@ use parking_lot::RwLock;
use parser::ParserContextExtraData;
use properties::{ComputedValues, parse_style_attribute};
use properties::PropertyDeclarationBlock;
use rule_tree::CascadeLevel as ServoCascadeLevel;
use selector_parser::{ElementExt, Snapshot};
use selectors::Element;
use selectors::parser::{AttrSelector, NamespaceConstraint};
@ -385,7 +387,7 @@ impl<'le> TElement for GeckoElement<'le> {
}
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>> {
let declarations = unsafe { Gecko_GetServoDeclarationBlock(self.0) };
let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) };
declarations.map(|s| s.as_arc_opt()).unwrap_or(None)
}
@ -483,10 +485,16 @@ impl<'le> PartialEq for GeckoElement<'le> {
}
impl<'le> PresentationalHintsSynthetizer for GeckoElement<'le> {
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, _hints: &mut V)
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
where V: Push<ApplicableDeclarationBlock>,
{
// FIXME(bholley) - Need to implement this.
let declarations = unsafe { Gecko_GetHTMLPresentationAttrDeclarationBlock(self.0) };
let declarations = declarations.and_then(|s| s.as_arc_opt());
if let Some(decl) = declarations {
hints.push(
ApplicableDeclarationBlock::from_declarations(Clone::clone(decl), ServoCascadeLevel::PresHints)
);
}
}
}

View file

@ -499,7 +499,11 @@ extern "C" {
-> u32;
}
extern "C" {
pub fn Gecko_GetServoDeclarationBlock(element: RawGeckoElementBorrowed)
pub fn Gecko_GetStyleAttrDeclarationBlock(element: RawGeckoElementBorrowed)
-> RawServoDeclarationBlockStrongBorrowedOrNull;
}
extern "C" {
pub fn Gecko_GetHTMLPresentationAttrDeclarationBlock(element: RawGeckoElementBorrowed)
-> RawServoDeclarationBlockStrongBorrowedOrNull;
}
extern "C" {
@ -1391,6 +1395,13 @@ extern "C" {
property:
nsCSSPropertyID);
}
extern "C" {
pub fn Servo_DeclarationBlock_AddPresValue(declarations:
RawServoDeclarationBlockBorrowed,
property: nsCSSPropertyID,
css_value:
nsCSSValueBorrowedMut);
}
extern "C" {
pub fn Servo_CSSSupports2(name: *const nsACString_internal,
value: *const nsACString_internal) -> bool;

View file

@ -12,7 +12,7 @@ use gecko_bindings::bindings::Gecko_CSSValue_GetPercentage;
use gecko_bindings::bindings::Gecko_CSSValue_SetAbsoluteLength;
use gecko_bindings::bindings::Gecko_CSSValue_SetCalc;
use gecko_bindings::bindings::Gecko_CSSValue_SetPercentage;
use gecko_bindings::structs::{nsCSSValue, nsCSSUnit, nsCSSValue_Array};
use gecko_bindings::structs::{nsCSSValue, nsCSSUnit, nsCSSValue_Array, nscolor};
use std::mem;
use std::ops::Index;
use std::slice;
@ -34,6 +34,28 @@ impl nsCSSValue {
unsafe { *self.mValue.mInt.as_ref() }
}
/// Checks if it is an integer and returns it if so
pub fn integer(&self) -> Option<i32> {
if self.mUnit == nsCSSUnit::eCSSUnit_Integer ||
self.mUnit == nsCSSUnit::eCSSUnit_Enumerated ||
self.mUnit == nsCSSUnit::eCSSUnit_EnumColor {
Some(unsafe { *self.mValue.mInt.as_ref() })
} else {
None
}
}
/// Checks if it is an RGBA color, returning it if so
/// Only use it with colors set by SetColorValue(),
/// which always sets RGBA colors
pub fn color_value(&self) -> Option<nscolor> {
if self.mUnit == nsCSSUnit::eCSSUnit_RGBAColor {
Some(unsafe { *self.mValue.mColor.as_ref() })
} else {
None
}
}
/// Returns this nsCSSValue value as a floating point value, unchecked in
/// release builds.
pub fn float_unchecked(&self) -> f32 {

View file

@ -293,6 +293,20 @@ impl NoCalcLength {
})
}
/// https://drafts.csswg.org/css-fonts-3/#font-size-prop
pub fn from_font_size_int(i: u8) -> Self {
let au = match i {
0 | 1 => Au::from_px(FONT_MEDIUM_PX) * 3 / 4,
2 => Au::from_px(FONT_MEDIUM_PX) * 8 / 9,
3 => Au::from_px(FONT_MEDIUM_PX),
4 => Au::from_px(FONT_MEDIUM_PX) * 6 / 5,
5 => Au::from_px(FONT_MEDIUM_PX) * 3 / 2,
6 => Au::from_px(FONT_MEDIUM_PX) * 2,
_ => Au::from_px(FONT_MEDIUM_PX) * 3,
};
NoCalcLength::Absolute(au)
}
/// Parse a given absolute or relative dimension.
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<NoCalcLength, ()> {
match_ignore_ascii_case! { unit,
@ -429,6 +443,11 @@ impl Length {
NoCalcLength::parse_dimension(value, unit).map(Length::NoCalc)
}
/// https://drafts.csswg.org/css-fonts-3/#font-size-prop
pub fn from_font_size_int(i: u8) -> Self {
Length::NoCalc(NoCalcLength::from_font_size_int(i))
}
#[inline]
fn parse_internal(input: &mut Parser, context: AllowedNumericType) -> Result<Length, ()> {
match try!(input.next()) {

View file

@ -34,7 +34,7 @@ use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSet
use style::gecko_bindings::bindings::{RawServoStyleSheetBorrowed, ServoComputedValuesBorrowed};
use style::gecko_bindings::bindings::{RawServoStyleSheetStrong, ServoComputedValuesStrong};
use style::gecko_bindings::bindings::{ServoCssRulesBorrowed, ServoCssRulesStrong};
use style::gecko_bindings::bindings::{nsACString, nsAString};
use style::gecko_bindings::bindings::{nsACString, nsCSSValueBorrowedMut, nsAString};
use style::gecko_bindings::bindings::Gecko_AnimationAppendKeyframe;
use style::gecko_bindings::bindings::RawGeckoAnimationValueListBorrowedMut;
use style::gecko_bindings::bindings::RawGeckoElementBorrowed;
@ -946,6 +946,61 @@ pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(declarations: RawSer
remove_property(declarations, get_property_id_from_nscsspropertyid!(property, ()))
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_AddPresValue(declarations: RawServoDeclarationBlockBorrowed,
property: nsCSSPropertyID,
css_value: nsCSSValueBorrowedMut) {
use style::gecko::values::convert_nscolor_to_rgba;
use style::properties::{DeclaredValue, LonghandId, PropertyDeclaration, PropertyId, longhands};
use style::values::specified;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let prop = PropertyId::from_nscsspropertyid(property);
let long = match prop {
Ok(PropertyId::Longhand(long)) => long,
_ => {
error!("stylo: unknown presentation property with id {:?}", property);
return
}
};
let decl = match long {
LonghandId::FontSize => {
if let Some(int) = css_value.integer() {
PropertyDeclaration::FontSize(DeclaredValue::Value(
longhands::font_size::SpecifiedValue(
specified::LengthOrPercentage::Length(
specified::NoCalcLength::from_font_size_int(int as u8)
)
)
))
} else {
error!("stylo: got unexpected non-integer value for font-size presentation attribute");
return
}
}
LonghandId::Color => {
if let Some(color) = css_value.color_value() {
PropertyDeclaration::Color(DeclaredValue::Value(
specified::CSSRGBA {
parsed: convert_nscolor_to_rgba(color),
authored: None
}
))
} else {
error!("stylo: got unexpected non-integer value for color presentation attribute");
return
}
}
_ => {
error!("stylo: cannot handle longhand {:?} from presentation attribute", long);
return
}
};
declarations.write().declarations.push((decl, Importance::Normal));
}
#[no_mangle]
pub extern "C" fn Servo_CSSSupports2(property: *const nsACString, value: *const nsACString) -> bool {
let property = unsafe { property.as_ref().unwrap().as_str_unchecked() };