--- a/servo/components/layout/animation.rs
+++ b/servo/components/layout/animation.rs
@@ -8,16 +8,17 @@ use context::LayoutContext;
use flow::{self, Flow};
use gfx::display_list::OpaqueNode;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId;
use script_traits::{AnimationState, ConstellationControlMsg, LayoutMsg as ConstellationMsg};
use std::collections::HashMap;
use std::sync::mpsc::Receiver;
use style::animation::{Animation, update_style_for_animation};
+use style::font_metrics::ServoMetricsProvider;
use style::selector_parser::RestyleDamage;
use style::timer::Timer;
/// Processes any new animations that were discovered after style recalculation.
/// Also expire any old animations that have completed, inserting them into
/// `expired_animations`.
pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
script_chan: &IpcSender<ConstellationControlMsg>,
@@ -138,17 +139,18 @@ pub fn recalc_style_for_animations(conte
Vec<Animation>>) {
let mut damage = RestyleDamage::empty();
flow.mutate_fragments(&mut |fragment| {
if let Some(ref animations) = animations.get(&fragment.node) {
for animation in animations.iter() {
let old_style = fragment.style.clone();
update_style_for_animation(&context.style_context,
animation,
- &mut fragment.style);
+ &mut fragment.style,
+ &ServoMetricsProvider);
damage |= RestyleDamage::compute(&old_style, &fragment.style);
}
}
});
let base = flow::mut_base(flow);
base.restyle_damage.insert(damage);
for kid in base.children.iter_mut() {
--- a/servo/components/script/layout_wrapper.rs
+++ b/servo/components/script/layout_wrapper.rs
@@ -62,16 +62,17 @@ use std::sync::atomic::Ordering;
use style;
use style::attr::AttrValue;
use style::computed_values::display;
use style::context::{QuirksMode, SharedStyleContext};
use style::data::ElementData;
use style::dom::{DescendantsBit, DirtyDescendants, LayoutIterator, NodeInfo, OpaqueNode};
use style::dom::{PresentationalHintsSynthetizer, TElement, TNode, UnsafeNode};
use style::element_state::*;
+use style::font_metrics::ServoMetricsProvider;
use style::properties::{ComputedValues, PropertyDeclarationBlock};
use style::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl};
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
use style::sink::Push;
use style::str::is_whitespace;
use style::stylist::ApplicableDeclarationBlock;
#[derive(Copy, Clone)]
@@ -368,16 +369,18 @@ impl<'le> PresentationalHintsSynthetizer
self.element.synthesize_presentational_hints_for_legacy_attributes(hints);
}
}
}
impl<'le> TElement for ServoLayoutElement<'le> {
type ConcreteNode = ServoLayoutNode<'le>;
+ type FontMetricsProvider = ServoMetricsProvider;
+
fn as_node(&self) -> ServoLayoutNode<'le> {
ServoLayoutNode::from_layout_js(self.element.upcast())
}
fn style_attribute(&self) -> Option<&Arc<StyleLocked<PropertyDeclarationBlock>>> {
unsafe {
(*self.element.style_attribute()).as_ref()
}
--- a/servo/components/script_layout_interface/wrapper_traits.rs
+++ b/servo/components/script_layout_interface/wrapper_traits.rs
@@ -16,16 +16,17 @@ use range::Range;
use servo_url::ServoUrl;
use std::fmt::Debug;
use std::sync::Arc;
use style::computed_values::display;
use style::context::SharedStyleContext;
use style::data::ElementData;
use style::dom::{LayoutIterator, NodeInfo, PresentationalHintsSynthetizer, TNode};
use style::dom::OpaqueNode;
+use style::font_metrics::ServoMetricsProvider;
use style::properties::{CascadeFlags, ServoComputedValues};
use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl};
#[derive(Copy, PartialEq, Clone, Debug)]
pub enum PseudoElementType<T> {
Normal,
Before(T),
After(T),
@@ -406,34 +407,36 @@ pub trait ThreadSafeLayoutElement: Clone
.borrow()
.styles().pseudos.contains_key(&style_pseudo) {
let mut data = self.get_style_data().unwrap().borrow_mut();
let new_style =
context.stylist.precomputed_values_for_pseudo(
&context.guards,
&style_pseudo,
Some(data.styles().primary.values()),
- CascadeFlags::empty());
+ CascadeFlags::empty(),
+ &ServoMetricsProvider);
data.styles_mut().pseudos
.insert(style_pseudo.clone(), new_style);
}
}
PseudoElementCascadeType::Lazy => {
if !self.get_style_data()
.unwrap()
.borrow()
.styles().pseudos.contains_key(&style_pseudo) {
let mut data = self.get_style_data().unwrap().borrow_mut();
let new_style =
context.stylist
.lazily_compute_pseudo_element_style(
&context.guards,
unsafe { &self.unsafe_get() },
&style_pseudo,
- data.styles().primary.values());
+ data.styles().primary.values(),
+ &ServoMetricsProvider);
data.styles_mut().pseudos
.insert(style_pseudo.clone(), new_style.unwrap());
}
}
}
self.get_style_data().unwrap().borrow()
.styles().pseudos.get(&style_pseudo)
--- a/servo/components/style/animation.rs
+++ b/servo/components/style/animation.rs
@@ -5,16 +5,17 @@
//! CSS transitions and animations.
#![deny(missing_docs)]
use Atom;
use bezier::Bezier;
use context::SharedStyleContext;
use dom::{OpaqueNode, UnsafeNode};
use euclid::point::Point2D;
+use font_metrics::FontMetricsProvider;
use keyframes::{KeyframesStep, KeyframesStepValue};
use properties::{self, CascadeFlags, ComputedValues, Importance};
use properties::animated_properties::{AnimatedProperty, TransitionProperty};
use properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
use properties::longhands::animation_iteration_count::single_value::computed_value::T as AnimationIterationCount;
use properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
use properties::longhands::transition_timing_function::single_value::computed_value::StartEnd;
use properties::longhands::transition_timing_function::single_value::computed_value::T as TransitionTimingFunction;
@@ -405,17 +406,18 @@ pub fn start_transitions_if_applicable(n
}
had_animations
}
fn compute_style_for_animation_step(context: &SharedStyleContext,
step: &KeyframesStep,
previous_style: &ComputedValues,
- style_from_cascade: &ComputedValues)
+ style_from_cascade: &ComputedValues,
+ font_metrics_provider: &FontMetricsProvider)
-> ComputedValues {
match step.value {
KeyframesStepValue::ComputedValues => style_from_cascade.clone(),
KeyframesStepValue::Declarations { block: ref declarations } => {
let guard = declarations.read_with(context.guards.author);
// No !important in keyframes.
debug_assert!(guard.declarations().iter()
@@ -428,17 +430,17 @@ fn compute_style_for_animation_step(cont
let computed =
properties::apply_declarations(&context.stylist.device,
/* is_root = */ false,
iter,
previous_style,
previous_style,
/* cascade_info = */ None,
&*context.error_reporter,
- /* Metrics provider */ None,
+ font_metrics_provider,
CascadeFlags::empty());
computed
}
}
}
/// Triggers animations for a given node looking at the animation property
/// values.
@@ -529,17 +531,18 @@ pub fn update_style_for_animation_frame(
frame.property_animation.update(Arc::make_mut(&mut new_style), progress);
true
}
/// Updates a single animation and associated style based on the current time.
/// If `damage` is provided, inserts the appropriate restyle damage.
pub fn update_style_for_animation(context: &SharedStyleContext,
animation: &Animation,
- style: &mut Arc<ComputedValues>) {
+ style: &mut Arc<ComputedValues>,
+ font_metrics_provider: &FontMetricsProvider) {
debug!("update_style_for_animation: entering");
debug_assert!(!animation.is_expired());
match *animation {
Animation::Transition(_, _, start_time, ref frame, _) => {
debug!("update_style_for_animation: transition found");
let now = context.timer.seconds();
let mut new_style = (*style).clone();
@@ -653,31 +656,33 @@ pub fn update_style_for_animation(contex
_ => unreachable!(),
};
let relative_progress = (now - last_keyframe_ended_at) / relative_duration;
// TODO: How could we optimise it? Is it such a big deal?
let from_style = compute_style_for_animation_step(context,
last_keyframe,
&**style,
- &state.cascade_style);
+ &state.cascade_style,
+ font_metrics_provider);
// NB: The spec says that the timing function can be overwritten
// from the keyframe style.
let mut timing_function = style.get_box().animation_timing_function_mod(index);
if last_keyframe.declared_timing_function {
// NB: animation_timing_function can never be empty, always has
// at least the default value (`ease`).
timing_function = from_style.get_box().animation_timing_function_at(0);
}
let target_style = compute_style_for_animation_step(context,
target_keyframe,
&from_style,
- &state.cascade_style);
+ &state.cascade_style,
+ font_metrics_provider);
let mut new_style = (*style).clone();
for transition_property in &animation.properties_changed {
debug!("update_style_for_animation: scanning prop {:?} for animation \"{}\"",
transition_property, name);
match PropertyAnimation::from_transition_property(*transition_property,
timing_function,
--- a/servo/components/style/context.rs
+++ b/servo/components/style/context.rs
@@ -7,16 +7,17 @@
use animation::Animation;
use app_units::Au;
use bloom::StyleBloom;
use data::ElementData;
use dom::{OpaqueNode, TNode, TElement, SendElement};
use error_reporting::ParseErrorReporter;
use euclid::Size2D;
+use font_metrics::FontMetricsProvider;
#[cfg(feature = "gecko")] use gecko_bindings::structs;
use matching::StyleSharingCandidateCache;
use parking_lot::RwLock;
#[cfg(feature = "gecko")] use selector_parser::PseudoElement;
use selectors::matching::ElementSelectorFlags;
use servo_config::opts;
use shared_lock::StylesheetGuards;
use std::collections::HashMap;
@@ -272,28 +273,32 @@ pub struct ThreadLocalStyleContext<E: TE
/// A set of tasks to be run (on the parent thread) in sequential mode after
/// the rest of the styling is complete. This is useful for infrequently-needed
/// non-threadsafe operations.
pub tasks: Vec<SequentialTask<E>>,
/// Statistics about the traversal.
pub statistics: TraversalStatistics,
/// Information related to the current element, non-None during processing.
current_element_info: Option<CurrentElementInfo>,
+ /// The struct used to compute and cache font metrics from style
+ /// for evaluation of the font-relative em/ch units and font-size
+ font_metrics_provider: E::FontMetricsProvider,
}
impl<E: TElement> ThreadLocalStyleContext<E> {
/// Creates a new `ThreadLocalStyleContext` from a shared one.
pub fn new(shared: &SharedStyleContext) -> Self {
ThreadLocalStyleContext {
style_sharing_candidate_cache: StyleSharingCandidateCache::new(),
bloom_filter: StyleBloom::new(),
new_animations_sender: shared.local_context_creation_data.lock().unwrap().new_animations_sender.clone(),
tasks: Vec::new(),
statistics: TraversalStatistics::default(),
current_element_info: None,
+ font_metrics_provider: E::FontMetricsProvider::create_from(shared),
}
}
/// Notes when the style system starts traversing an element.
pub fn begin_element(&mut self, element: E, data: &ElementData) {
debug_assert!(self.current_element_info.is_none());
self.current_element_info = Some(CurrentElementInfo {
element: element.as_node().opaque(),
@@ -311,16 +316,21 @@ impl<E: TElement> ThreadLocalStyleContex
/// Returns true if the current element being traversed is being styled for
/// the first time.
///
/// Panics if called while no element is being traversed.
pub fn is_initial_style(&self) -> bool {
self.current_element_info.as_ref().unwrap().is_initial_style
}
+
+ /// Get the contained font metrics provider
+ pub fn font_metrics_provider(&self) -> &FontMetricsProvider {
+ &self.font_metrics_provider
+ }
}
impl<E: TElement> Drop for ThreadLocalStyleContext<E> {
fn drop(&mut self) {
debug_assert!(self.current_element_info.is_none());
// Execute any enqueued sequential tasks.
debug_assert!(thread_state::get() == thread_state::LAYOUT);
--- a/servo/components/style/dom.rs
+++ b/servo/components/style/dom.rs
@@ -7,16 +7,17 @@
#![allow(unsafe_code)]
#![deny(missing_docs)]
use {Atom, Namespace, LocalName};
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
#[cfg(feature = "gecko")] use context::UpdateAnimationsTasks;
use data::ElementData;
use element_state::ElementState;
+use font_metrics::FontMetricsProvider;
use properties::{ComputedValues, PropertyDeclarationBlock};
use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement};
use selectors::matching::ElementSelectorFlags;
use shared_lock::Locked;
use sink::Push;
use std::fmt;
use std::fmt::Debug;
use std::ops::Deref;
@@ -273,16 +274,22 @@ pub trait PresentationalHintsSynthetizer
pub struct AnimationRules(pub Option<Arc<Locked<PropertyDeclarationBlock>>>,
pub Option<Arc<Locked<PropertyDeclarationBlock>>>);
/// The element trait, the main abstraction the style crate acts over.
pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer {
/// The concrete node type.
type ConcreteNode: TNode<ConcreteElement = Self>;
+ /// Type of the font metrics provider
+ ///
+ /// XXXManishearth It would be better to make this a type parameter on
+ /// ThreadLocalStyleContext and StyleContext
+ type FontMetricsProvider: FontMetricsProvider;
+
/// Get this element as a node.
fn as_node(&self) -> Self::ConcreteNode;
/// While doing a reflow, the element at the root has no parent, as far as we're
/// concerned. This method returns `None` at the reflow root.
fn layout_parent_element(self, reflow_root: OpaqueNode) -> Option<Self> {
if self.as_node().opaque() == reflow_root {
None
--- a/servo/components/style/font_metrics.rs
+++ b/servo/components/style/font_metrics.rs
@@ -3,16 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Access to font metrics from the style system.
#![deny(missing_docs)]
use Atom;
use app_units::Au;
+use context::SharedStyleContext;
use euclid::Size2D;
use std::fmt;
/// Represents the font metrics that style needs from a font to compute the
/// value of certain CSS units like `ex`.
#[derive(Debug, PartialEq, Clone)]
pub struct FontMetrics {
/// The x-height of the font.
@@ -26,19 +27,56 @@ pub struct FontMetrics {
pub enum FontMetricsQueryResult {
/// The font is available, but we may or may not have found any font metrics
/// for it.
Available(Option<FontMetrics>),
/// The font is not available.
NotAvailable,
}
+// TODO: Servo's font metrics provider will probably not live in this crate, so this will
+// have to be replaced with something else (perhaps a trait method on TElement)
+// when we get there
+#[derive(Debug)]
+#[cfg(feature = "servo")]
+/// Dummy metrics provider for Servo. Knows nothing about fonts and does not provide
+/// any metrics.
+pub struct ServoMetricsProvider;
+
+#[cfg(feature = "servo")]
+impl FontMetricsProvider for ServoMetricsProvider {
+ fn create_from(_: &SharedStyleContext) -> Self {
+ ServoMetricsProvider
+ }
+}
+
+#[cfg(feature = "gecko")]
+/// Construct a font metrics provider for the current product
+pub fn get_metrics_provider_for_product() -> ::gecko::wrapper::GeckoFontMetricsProvider {
+ ::gecko::wrapper::GeckoFontMetricsProvider::new()
+}
+
+#[cfg(feature = "servo")]
+/// Construct a font metrics provider for the current product
+pub fn get_metrics_provider_for_product() -> ServoMetricsProvider {
+ ServoMetricsProvider
+}
+
/// A trait used to represent something capable of providing us font metrics.
-pub trait FontMetricsProvider: Send + Sync + fmt::Debug {
+pub trait FontMetricsProvider: Send + fmt::Debug {
/// Obtain the metrics for given font family.
///
/// TODO: We could make this take the full list, I guess, and save a few
/// virtual calls in the case we are repeatedly unable to find font metrics?
/// That is not too common in practice though.
fn query(&self, _font_name: &Atom) -> FontMetricsQueryResult {
FontMetricsQueryResult::NotAvailable
}
+
+ /// Get default size of a given language and generic family
+ fn get_size(&self, _font_name: &Atom, _font_family: u8) -> Au {
+ unimplemented!()
+ }
+
+ /// Construct from a shared style context
+ fn create_from(context: &SharedStyleContext) -> Self where Self: Sized;
}
+
--- a/servo/components/style/gecko/media_queries.rs
+++ b/servo/components/style/gecko/media_queries.rs
@@ -2,16 +2,17 @@
* 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/. */
//! Gecko's media-query device and expression representation.
use app_units::Au;
use cssparser::{CssStringWriter, Parser, Token};
use euclid::Size2D;
+use font_metrics::get_metrics_provider_for_product;
use gecko_bindings::bindings;
use gecko_bindings::structs::{nsCSSValue, nsCSSUnit, nsStringBuffer};
use gecko_bindings::structs::{nsMediaExpression_Range, nsMediaFeature};
use gecko_bindings::structs::{nsMediaFeature_ValueType, nsMediaFeature_RangeType, nsMediaFeature_RequirementFlags};
use gecko_bindings::structs::RawGeckoPresContextOwned;
use media_queries::MediaType;
use properties::ComputedValues;
use std::ascii::AsciiExt;
@@ -494,27 +495,29 @@ impl Expression {
use std::cmp::Ordering;
debug_assert!(self.range == nsMediaExpression_Range::eEqual ||
self.feature.mRangeType == nsMediaFeature_RangeType::eMinMaxAllowed,
"Whoops, wrong range");
let default_values = device.default_computed_values();
+ let provider = get_metrics_provider_for_product();
+
// http://dev.w3.org/csswg/mediaqueries3/#units
// em units are relative to the initial font-size.
let context = computed::Context {
is_root_element: false,
device: device,
inherited_style: default_values,
layout_parent_style: default_values,
// This cloning business is kind of dumb.... It's because Context
// insists on having an actual ComputedValues inside itself.
style: default_values.clone(),
- font_metrics_provider: None,
+ font_metrics_provider: &provider,
};
let required_value = match self.value {
Some(ref v) => v,
None => {
// If there's no value, always match unless it's a zero length
// or a zero integer or boolean.
return match *actual_value {
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -10,17 +10,17 @@
//! This really follows the Servo pattern in
//! `components/script/layout_wrapper.rs`.
//!
//! This theoretically should live in its own crate, but now it lives in the
//! style system it's kind of pointless in the Stylo case, and only Servo forces
//! the separation between the style system implementation and everything else.
use atomic_refcell::AtomicRefCell;
-use context::UpdateAnimationsTasks;
+use context::{SharedStyleContext, UpdateAnimationsTasks};
use data::ElementData;
use dom::{self, AnimationRules, DescendantsBit, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode};
use dom::{OpaqueNode, PresentationalHintsSynthetizer};
use element_state::ElementState;
use error_reporting::StdoutErrorReporter;
use gecko::global_style_data::GLOBAL_STYLE_DATA;
use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement};
use gecko::snapshot_helpers;
@@ -55,16 +55,17 @@ use properties::PropertyDeclarationBlock
use properties::animated_properties::AnimationValueMap;
use rule_tree::CascadeLevel as ServoCascadeLevel;
use selector_parser::{ElementExt, Snapshot};
use selectors::Element;
use selectors::matching::{ElementSelectorFlags, StyleRelations};
use selectors::parser::{AttrSelector, NamespaceConstraint};
use shared_lock::Locked;
use sink::Push;
+use std::cell::RefCell;
use std::fmt;
use std::ptr;
use std::sync::Arc;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use stylesheets::UrlExtraData;
use stylist::ApplicableDeclarationBlock;
/// A simple wrapper over a non-null Gecko node (`nsINode`) pointer.
@@ -421,18 +422,44 @@ fn get_animation_rule(element: &GeckoEle
let shared_lock = &GLOBAL_STYLE_DATA.shared_lock;
Some(Arc::new(shared_lock.wrap(
PropertyDeclarationBlock::from_animation_value_map(&animation_values.read()))))
} else {
None
}
}
+#[derive(Debug)]
+/// Gecko font metrics provider
+pub struct GeckoFontMetricsProvider {
+ /// Cache of base font sizes for each language
+ ///
+ /// Should have at most 31 elements (the number of language groups). Usually
+ /// will have 1.
+ pub font_size_cache: RefCell<Vec<(Atom, ::gecko_bindings::structs::FontSizePrefs)>>,
+}
+
+impl GeckoFontMetricsProvider {
+ /// Construct
+ pub fn new() -> Self {
+ GeckoFontMetricsProvider {
+ font_size_cache: RefCell::new(Vec::new()),
+ }
+ }
+}
+
+impl ::font_metrics::FontMetricsProvider for GeckoFontMetricsProvider {
+ fn create_from(_: &SharedStyleContext) -> Self {
+ GeckoFontMetricsProvider::new()
+ }
+}
+
impl<'le> TElement for GeckoElement<'le> {
type ConcreteNode = GeckoNode<'le>;
+ type FontMetricsProvider = GeckoFontMetricsProvider;
fn as_node(&self) -> Self::ConcreteNode {
unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
}
fn style_attribute(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>> {
let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) };
declarations.map(|s| s.as_arc_opt()).unwrap_or(None)
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -10,16 +10,17 @@
use {Atom, LocalName};
use animation::{self, Animation, PropertyAnimation};
use atomic_refcell::AtomicRefMut;
use cache::{LRUCache, LRUCacheMutIterator};
use cascade_info::CascadeInfo;
use context::{SequentialTask, SharedStyleContext, StyleContext};
use data::{ComputedStyle, ElementData, ElementStyles, RestyleData};
use dom::{AnimationRules, SendElement, TElement, TNode};
+use font_metrics::FontMetricsProvider;
use properties::{CascadeFlags, ComputedValues, SHAREABLE, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade};
use properties::longhands::display::computed_value as display;
use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_CSS_ANIMATIONS, RestyleHint};
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode};
use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl};
use selectors::MatchAttr;
use selectors::bloom::BloomFilter;
use selectors::matching::{ElementSelectorFlags, StyleRelations};
@@ -532,16 +533,17 @@ trait PrivateMatchMethods: TElement {
let values =
Arc::new(cascade(&shared_context.stylist.device,
rule_node,
&shared_context.guards,
inherited_values,
layout_parent_style,
Some(&mut cascade_info),
&*shared_context.error_reporter,
+ context.thread_local.font_metrics_provider(),
cascade_flags));
cascade_info.finish(&self.as_node());
values
}
fn cascade_internal(&self,
context: &StyleContext<Self>,
@@ -680,17 +682,18 @@ trait PrivateMatchMethods: TElement {
context: &mut StyleContext<Self>,
old_values: &mut Option<Arc<ComputedValues>>,
new_values: &mut Arc<ComputedValues>,
_pseudo: Option<&PseudoElement>,
possibly_expired_animations: &mut Vec<PropertyAnimation>) {
let shared_context = context.shared;
if let Some(ref mut old) = *old_values {
self.update_animations_for_cascade(shared_context, old,
- possibly_expired_animations);
+ possibly_expired_animations,
+ context.thread_local.font_metrics_provider());
}
let new_animations_sender = &context.thread_local.new_animations_sender;
let this_opaque = self.as_node().opaque();
// Trigger any present animations if necessary.
animation::maybe_start_animations(&shared_context,
new_animations_sender,
this_opaque, &new_values);
@@ -748,17 +751,18 @@ trait PrivateMatchMethods: TElement {
let d = self.compute_restyle_damage(&old_values, &new_values, pseudo);
restyle.damage |= d;
}
}
fn update_animations_for_cascade(&self,
context: &SharedStyleContext,
style: &mut Arc<ComputedValues>,
- possibly_expired_animations: &mut Vec<PropertyAnimation>) {
+ possibly_expired_animations: &mut Vec<PropertyAnimation>,
+ font_metrics: &FontMetricsProvider) {
// Finish any expired transitions.
let this_opaque = self.as_node().opaque();
animation::complete_expired_transitions(this_opaque, style, context);
// Merge any running transitions into the current style, and cancel them.
let had_running_animations = context.running_animations
.read()
.get(&this_opaque)
@@ -775,17 +779,18 @@ trait PrivateMatchMethods: TElement {
// updated by layout, because other restyle due to script might
// be triggered by layout before the animation tick.
//
// See #12171 and the associated PR for an example where this
// happened while debugging other release panic.
if !running_animation.is_expired() {
animation::update_style_for_animation(context,
running_animation,
- style);
+ style,
+ font_metrics);
if let Animation::Transition(_, _, _, ref frame, _) = *running_animation {
possibly_expired_animations.push(frame.property_animation.clone())
}
}
}
}
}
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -1946,16 +1946,17 @@ bitflags! {
///
pub fn cascade(device: &Device,
rule_node: &StrongRuleNode,
guards: &StylesheetGuards,
parent_style: Option<<&ComputedValues>,
layout_parent_style: Option<<&ComputedValues>,
cascade_info: Option<<&mut CascadeInfo>,
error_reporter: &ParseErrorReporter,
+ font_metrics_provider: &FontMetricsProvider,
flags: CascadeFlags)
-> ComputedValues {
debug_assert_eq!(parent_style.is_some(), layout_parent_style.is_some());
let (is_root_element, inherited_style, layout_parent_style) = match parent_style {
Some(parent_style) => {
(false,
parent_style,
layout_parent_style.unwrap())
@@ -1990,31 +1991,31 @@ pub fn cascade(device: &Device,
};
apply_declarations(device,
is_root_element,
iter_declarations,
inherited_style,
layout_parent_style,
cascade_info,
error_reporter,
- None,
+ font_metrics_provider,
flags)
}
/// NOTE: This function expects the declaration with more priority to appear
/// first.
#[allow(unused_mut)] // conditionally compiled code for "position"
pub fn apply_declarations<'a, F, I>(device: &Device,
is_root_element: bool,
iter_declarations: F,
inherited_style: &ComputedValues,
layout_parent_style: &ComputedValues,
mut cascade_info: Option<<&mut CascadeInfo>,
error_reporter: &ParseErrorReporter,
- font_metrics_provider: Option<<&FontMetricsProvider>,
+ font_metrics_provider: &FontMetricsProvider,
flags: CascadeFlags)
-> ComputedValues
where F: Fn() -> I,
I: Iterator<Item = &'a PropertyDeclaration>,
{
let default_style = device.default_computed_values();
let inherited_custom_properties = inherited_style.custom_properties();
let mut custom_properties = None;
--- a/servo/components/style/servo/media_queries.rs
+++ b/servo/components/style/servo/media_queries.rs
@@ -2,16 +2,17 @@
* 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/. */
//! Servo's media-query device and expression representation.
use app_units::Au;
use cssparser::Parser;
use euclid::{Size2D, TypedSize2D};
+use font_metrics::ServoMetricsProvider;
use media_queries::MediaType;
use properties::ComputedValues;
use std::fmt;
use style_traits::{CSSPixel, ToCss};
use style_traits::viewport::ViewportConstraints;
use values::computed::{self, ToComputedValue};
use values::specified;
@@ -180,17 +181,20 @@ impl Range<specified::Length> {
let context = computed::Context {
is_root_element: false,
device: device,
inherited_style: default_values,
layout_parent_style: default_values,
// This cloning business is kind of dumb.... It's because Context
// insists on having an actual ComputedValues inside itself.
style: default_values.clone(),
- font_metrics_provider: None
+ // Servo doesn't support font metrics
+ // A real provider will be needed here once we do; since
+ // ch units can exist in media queries.
+ font_metrics_provider: &ServoMetricsProvider,
};
match *self {
Range::Min(ref width) => Range::Min(width.to_computed_value(&context)),
Range::Max(ref width) => Range::Max(width.to_computed_value(&context)),
Range::Eq(ref width) => Range::Eq(width.to_computed_value(&context))
}
}
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -5,16 +5,17 @@
//! Selector matching.
#![deny(missing_docs)]
use {Atom, LocalName};
use data::ComputedStyle;
use dom::{AnimationRules, PresentationalHintsSynthetizer, TElement};
use error_reporting::StdoutErrorReporter;
+use font_metrics::FontMetricsProvider;
use keyframes::KeyframesAnimation;
use media_queries::Device;
use pdqsort::sort_by;
use properties::{self, CascadeFlags, ComputedValues};
#[cfg(feature = "servo")]
use properties::INHERIT_ALL;
use properties::PropertyDeclarationBlock;
use restyle_hints::{RestyleHint, DependencySet};
@@ -338,17 +339,18 @@ impl Stylist {
/// If `inherit_all` is true, then all properties are inherited from the
/// parent; otherwise, non-inherited properties are reset to their initial
/// values. The flow constructor uses this flag when constructing anonymous
/// flows.
pub fn precomputed_values_for_pseudo(&self,
guards: &StylesheetGuards,
pseudo: &PseudoElement,
parent: Option<&Arc<ComputedValues>>,
- cascade_flags: CascadeFlags)
+ cascade_flags: CascadeFlags,
+ font_metrics: &FontMetricsProvider)
-> ComputedStyle {
debug_assert!(SelectorImpl::pseudo_element_cascade_type(pseudo).is_precomputed());
let rule_node = match self.precomputed_pseudo_element_decls.get(pseudo) {
Some(declarations) => {
// FIXME(emilio): When we've taken rid of the cascade we can just
// use into_iter.
self.rule_tree.insert_ordered_rules(
@@ -374,27 +376,30 @@ impl Stylist {
let computed =
properties::cascade(&self.device,
&rule_node,
guards,
parent.map(|p| &**p),
parent.map(|p| &**p),
None,
&StdoutErrorReporter,
+ font_metrics,
cascade_flags);
ComputedStyle::new(rule_node, Arc::new(computed))
}
/// Returns the style for an anonymous box of the given type.
#[cfg(feature = "servo")]
pub fn style_for_anonymous(&self,
guards: &StylesheetGuards,
pseudo: &PseudoElement,
parent_style: &Arc<ComputedValues>)
-> Arc<ComputedValues> {
+ use font_metrics::ServoMetricsProvider;
+
// For most (but not all) pseudo-elements, we inherit all values from the parent.
let inherit_all = match *pseudo {
PseudoElement::ServoText |
PseudoElement::ServoInputText => false,
PseudoElement::ServoAnonymousBlock |
PseudoElement::ServoAnonymousTable |
PseudoElement::ServoAnonymousTableCell |
PseudoElement::ServoAnonymousTableRow |
@@ -409,32 +414,34 @@ impl Stylist {
PseudoElement::DetailsContent => {
unreachable!("That pseudo doesn't represent an anonymous box!")
}
};
let mut cascade_flags = CascadeFlags::empty();
if inherit_all {
cascade_flags.insert(INHERIT_ALL);
}
- self.precomputed_values_for_pseudo(guards, &pseudo, Some(parent_style), cascade_flags)
+ self.precomputed_values_for_pseudo(guards, &pseudo, Some(parent_style), cascade_flags,
+ &ServoMetricsProvider)
.values.unwrap()
}
/// Computes a pseudo-element style lazily during layout.
///
/// This can only be done for a certain set of pseudo-elements, like
/// :selection.
///
/// Check the documentation on lazy pseudo-elements in
/// docs/components/style.md
pub fn lazily_compute_pseudo_element_style<E>(&self,
guards: &StylesheetGuards,
element: &E,
pseudo: &PseudoElement,
- parent: &Arc<ComputedValues>)
+ parent: &Arc<ComputedValues>,
+ font_metrics: &FontMetricsProvider)
-> Option<ComputedStyle>
where E: TElement +
fmt::Debug +
PresentationalHintsSynthetizer
{
debug_assert!(SelectorImpl::pseudo_element_cascade_type(pseudo).is_lazy());
if self.pseudos_map.get(pseudo).is_none() {
return None;
@@ -487,16 +494,17 @@ impl Stylist {
let computed =
properties::cascade(&self.device,
&rule_node,
guards,
Some(&**parent),
Some(&**parent),
None,
&StdoutErrorReporter,
+ font_metrics,
CascadeFlags::empty());
Some(ComputedStyle::new(rule_node, Arc::new(computed)))
}
/// Set a given device, which may change the styles that apply to the
/// document.
///
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -52,19 +52,17 @@ pub struct Context<'a> {
/// Values access through this need to be in the properties "computed
/// early": color, text-decoration, font-size, display, position, float,
/// border-*-style, outline-style, font-family, writing-mode...
pub style: ComputedValues,
/// A font metrics provider, used to access font metrics to implement
/// font-relative units.
- ///
- /// TODO(emilio): This should be required, see #14079.
- pub font_metrics_provider: Option<&'a FontMetricsProvider>,
+ pub font_metrics_provider: &'a FontMetricsProvider,
}
impl<'a> Context<'a> {
/// Whether the current element is the root element.
pub fn is_root_element(&self) -> bool { self.is_root_element }
/// The current viewport size.
pub fn viewport_size(&self) -> Size2D<Au> { self.device.au_viewport_size() }
/// The style we're inheriting from.
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -68,21 +68,19 @@ impl ToCss for FontRelativeLength {
}
}
impl FontRelativeLength {
/// Gets the first available font metrics from the current context's
/// font-family list.
pub fn find_first_available_font_metrics(context: &Context) -> Option<FontMetrics> {
use font_metrics::FontMetricsQueryResult::*;
- if let Some(ref metrics_provider) = context.font_metrics_provider {
- for family in context.style().get_font().font_family_iter() {
- if let Available(metrics) = metrics_provider.query(family.atom()) {
- return metrics;
- }
+ for family in context.style().get_font().font_family_iter() {
+ if let Available(metrics) = context.font_metrics_provider.query(family.atom()) {
+ return metrics;
}
}
None
}
/// Computes the font-relative length. We use the use_inherited flag to
/// special-case the computation of font-size.
--- a/servo/components/style/viewport.rs
+++ b/servo/components/style/viewport.rs
@@ -8,16 +8,17 @@
//! [meta]: https://drafts.csswg.org/css-device-adapt/#viewport-meta
#![deny(missing_docs)]
use app_units::Au;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important};
use cssparser::ToCss as ParserToCss;
use euclid::size::TypedSize2D;
+use font_metrics::get_metrics_provider_for_product;
use media_queries::Device;
use parser::{ParserContext, log_css_error};
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::fmt;
use std::iter::Enumerate;
use std::str::Chars;
@@ -682,24 +683,26 @@ impl MaybeNew for ViewportConstraints {
}
// DEVICE-ADAPT § 6.2.3 Resolve non-auto lengths to pixel lengths
//
// Note: DEVICE-ADAPT § 5. states that relative length values are
// resolved against initial values
let initial_viewport = device.au_viewport_size();
+ let provider = get_metrics_provider_for_product();
+
// TODO(emilio): Stop cloning `ComputedValues` around!
let context = Context {
is_root_element: false,
device: device,
inherited_style: device.default_computed_values(),
layout_parent_style: device.default_computed_values(),
style: device.default_computed_values().clone(),
- font_metrics_provider: None, // TODO: Should have!
+ font_metrics_provider: &provider,
};
// DEVICE-ADAPT § 9.3 Resolving 'extend-to-zoom'
let extend_width;
let extend_height;
if let Some(extend_zoom) = max!(initial_zoom, max_zoom) {
let scale_factor = 1. / extend_zoom;
extend_width = Some(initial_viewport.width.scale_by(scale_factor));
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -15,16 +15,17 @@ use std::ptr;
use std::sync::{Arc, Mutex};
use style::arc_ptr_eq;
use style::context::{QuirksMode, SharedStyleContext, StyleContext};
use style::context::{ThreadLocalStyleContext, ThreadLocalStyleContextCreationInfo};
use style::data::{ElementData, ElementStyles, RestyleData};
use style::dom::{AnimationOnlyDirtyDescendants, DirtyDescendants};
use style::dom::{ShowSubtreeData, TElement, TNode};
use style::error_reporting::StdoutErrorReporter;
+use style::font_metrics::get_metrics_provider_for_product;
use style::gecko::data::{PerDocumentStyleData, PerDocumentStyleDataImpl};
use style::gecko::global_style_data::GLOBAL_STYLE_DATA;
use style::gecko::restyle_damage::GeckoRestyleDamage;
use style::gecko::selector_parser::{SelectorImpl, PseudoElement};
use style::gecko::traversal::RecalcStyleOnly;
use style::gecko::wrapper::GeckoElement;
use style::gecko_bindings::bindings;
use style::gecko_bindings::bindings::{RawGeckoKeyframeListBorrowed, RawGeckoKeyframeListBorrowedMut};
@@ -686,18 +687,19 @@ pub extern "C" fn Servo_ComputedValues_G
let pseudo = PseudoElement::from_atom_unchecked(atom, /* anon_box = */ true);
let maybe_parent = ComputedValues::arc_from_borrowed(&parent_style_or_null);
let mut cascade_flags = CascadeFlags::empty();
if skip_display_fixup {
cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP);
}
+ let metrics = get_metrics_provider_for_product();
data.stylist.precomputed_values_for_pseudo(&guards, &pseudo, maybe_parent,
- cascade_flags)
+ cascade_flags, &metrics)
.values.unwrap()
.into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
pseudo_tag: *mut nsIAtom, is_probe: bool,
raw_data: RawServoStyleSetBorrowed)
@@ -733,20 +735,22 @@ fn get_pseudo_style(guard: &SharedRwLock
let pseudo = PseudoElement::from_atom_unchecked(Atom::from(pseudo_tag), false);
match SelectorImpl::pseudo_element_cascade_type(&pseudo) {
PseudoElementCascadeType::Eager => styles.pseudos.get(&pseudo).map(|s| s.values().clone()),
PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"),
PseudoElementCascadeType::Lazy => {
let d = doc_data.borrow_mut();
let base = styles.primary.values();
let guards = StylesheetGuards::same(guard);
+ let metrics = get_metrics_provider_for_product();
d.stylist.lazily_compute_pseudo_element_style(&guards,
&element,
&pseudo,
- base)
+ base,
+ &metrics)
.map(|s| s.values().clone())
},
}
}
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_Inherit(
raw_data: RawServoStyleSetBorrowed,
@@ -1546,24 +1550,25 @@ pub extern "C" fn Servo_GetComputedKeyfr
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let style = ComputedValues::as_arc(&style);
let parent_style = parent_style.as_ref().map(|r| &**ComputedValues::as_arc(&r));
let default_values = data.default_computed_values();
+ let metrics = get_metrics_provider_for_product();
let context = Context {
is_root_element: false,
device: &data.stylist.device,
inherited_style: parent_style.unwrap_or(default_values),
layout_parent_style: parent_style.unwrap_or(default_values),
style: (**style).clone(),
- font_metrics_provider: None,
+ font_metrics_provider: &metrics,
};
for (index, keyframe) in keyframes.iter().enumerate() {
let ref mut animation_values = computed_keyframes[index];
let mut seen = LonghandIdSet::new();
// mServoDeclarationBlock is null in the case where we have an invalid css property.