Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stylo: Make font base size computation threadsafe #16316

Merged
merged 3 commits into from Apr 9, 2017
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

stylo: Store font metrics provider in thread local style context

  • Loading branch information
Manishearth committed Apr 9, 2017
commit e402c72d0eb0726c612bfe384b97903b2e3888f7
@@ -13,6 +13,7 @@ use script_traits::{AnimationState, ConstellationControlMsg, LayoutMsg as Conste
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;

@@ -143,7 +144,8 @@ pub fn recalc_style_for_animations(context: &LayoutContext,
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);
}
}
@@ -53,6 +53,7 @@ impl<'a> RecalcStyleAndConstructFlows<'a> {
impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a>
where E: TElement,
E::ConcreteNode: LayoutNode,
E::FontMetricsProvider: Send,
{
type ThreadLocalContext = ScopedThreadLocalLayoutContext<E>;

@@ -67,6 +67,7 @@ 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};
@@ -373,6 +374,8 @@ impl<'le> PresentationalHintsSynthetizer for ServoLayoutElement<'le> {
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())
}
@@ -21,6 +21,7 @@ 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};

@@ -411,7 +412,8 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
&context.guards,
&style_pseudo,
Some(data.styles().primary.values()),
CascadeFlags::empty());
CascadeFlags::empty(),
&ServoMetricsProvider);
data.styles_mut().cached_pseudos
.insert(style_pseudo.clone(), new_style);
}
@@ -426,7 +428,8 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
&context.guards,
unsafe { &self.unsafe_get() },
&style_pseudo,
data.styles().primary.values());
data.styles().primary.values(),
&ServoMetricsProvider);
data.styles_mut().cached_pseudos
.insert(style_pseudo.clone(), new_style.unwrap());
}
@@ -10,6 +10,7 @@ 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};
@@ -410,7 +411,8 @@ pub fn start_transitions_if_applicable(new_animations_sender: &Sender<Animation>
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(),
@@ -433,7 +435,7 @@ fn compute_style_for_animation_step(context: &SharedStyleContext,
previous_style,
/* cascade_info = */ None,
&*context.error_reporter,
/* Metrics provider */ None,
font_metrics_provider,
CascadeFlags::empty());
computed
}
@@ -534,7 +536,8 @@ pub fn update_style_for_animation_frame(mut new_style: &mut Arc<ComputedValues>,
/// 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());

@@ -658,7 +661,8 @@ pub fn update_style_for_animation(context: &SharedStyleContext,
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.
@@ -672,7 +676,8 @@ pub fn update_style_for_animation(context: &SharedStyleContext,
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();

@@ -12,6 +12,7 @@ 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;
@@ -291,6 +292,9 @@ pub struct ThreadLocalStyleContext<E: TElement> {
pub statistics: TraversalStatistics,
/// Information related to the current element, non-None during processing.
pub 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
pub font_metrics_provider: E::FontMetricsProvider,
}

impl<E: TElement> ThreadLocalStyleContext<E> {
@@ -303,6 +307,7 @@ impl<E: TElement> ThreadLocalStyleContext<E> {
tasks: Vec::new(),
statistics: TraversalStatistics::default(),
current_element_info: None,
font_metrics_provider: E::FontMetricsProvider::create_from(shared),
}
}

@@ -12,6 +12,7 @@ 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;
@@ -278,6 +279,12 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
/// 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;

@@ -8,6 +8,7 @@

use Atom;
use app_units::Au;
use context::SharedStyleContext;
use euclid::Size2D;
use std::fmt;

@@ -31,8 +32,36 @@ pub enum FontMetricsQueryResult {
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
@@ -41,4 +70,13 @@ pub trait FontMetricsProvider: Send + Sync + fmt::Debug {
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;
}

@@ -7,6 +7,7 @@
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};
@@ -499,6 +500,8 @@ impl Expression {

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 {
@@ -509,7 +512,7 @@ impl Expression {
// 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 {
@@ -15,7 +15,7 @@
//! 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};
@@ -60,6 +60,7 @@ 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;
@@ -426,8 +427,34 @@ fn get_animation_rule(element: &GeckoElement,
}
}

#[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)) }
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.