mirror of
https://github.com/servo/servo.git
synced 2025-07-29 10:10:34 +01:00
layout: Load Web fonts asynchronously.
Improves page load times significantly. Closes #7343.
This commit is contained in:
parent
9523283c14
commit
9bb6acd690
8 changed files with 216 additions and 35 deletions
|
@ -1219,6 +1219,15 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Synchronously query the layout task for this pipeline
|
||||||
|
// to see if it is idle.
|
||||||
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
let msg = LayoutControlMsg::GetWebFontLoadState(sender);
|
||||||
|
pipeline.layout_chan.0.send(msg).unwrap();
|
||||||
|
if receiver.recv().unwrap() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Check the visible rectangle for this pipeline. If the constellation
|
// Check the visible rectangle for this pipeline. If the constellation
|
||||||
// hasn't received a rectangle for this pipeline yet, then assume
|
// hasn't received a rectangle for this pipeline yet, then assume
|
||||||
// that the output image isn't stable yet.
|
// that the output image isn't stable yet.
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use font_template::{FontTemplate, FontTemplateDescriptor};
|
use font_template::{FontTemplate, FontTemplateDescriptor};
|
||||||
use net_traits::{ResourceTask, load_whole_resource};
|
use ipc_channel::ipc;
|
||||||
|
use ipc_channel::router::ROUTER;
|
||||||
|
use net_traits::{AsyncResponseTarget, PendingAsyncLoad, ResourceTask, ResponseAction};
|
||||||
use platform::font_context::FontContextHandle;
|
use platform::font_context::FontContextHandle;
|
||||||
use platform::font_list::for_each_available_family;
|
use platform::font_list::for_each_available_family;
|
||||||
use platform::font_list::for_each_variation;
|
use platform::font_list::for_each_variation;
|
||||||
|
@ -12,10 +14,12 @@ use platform::font_list::system_default_family;
|
||||||
use platform::font_template::FontTemplateData;
|
use platform::font_template::FontTemplateData;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::mem;
|
||||||
use std::sync::mpsc::{Receiver, Sender, channel};
|
use std::sync::mpsc::{Sender, Receiver, channel};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use style::font_face::Source;
|
use style::font_face::Source;
|
||||||
|
use url::Url;
|
||||||
use util::str::LowercaseString;
|
use util::str::LowercaseString;
|
||||||
use util::task::spawn_named;
|
use util::task::spawn_named;
|
||||||
|
|
||||||
|
@ -77,6 +81,7 @@ pub enum Command {
|
||||||
GetFontTemplate(String, FontTemplateDescriptor, Sender<Reply>),
|
GetFontTemplate(String, FontTemplateDescriptor, Sender<Reply>),
|
||||||
GetLastResortFontTemplate(FontTemplateDescriptor, Sender<Reply>),
|
GetLastResortFontTemplate(FontTemplateDescriptor, Sender<Reply>),
|
||||||
AddWebFont(Atom, Source, Sender<()>),
|
AddWebFont(Atom, Source, Sender<()>),
|
||||||
|
AddDownloadedWebFont(LowercaseString, Url, Vec<u8>, Sender<()>),
|
||||||
Exit(Sender<()>),
|
Exit(Sender<()>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +94,7 @@ pub enum Reply {
|
||||||
/// font templates that are currently in use.
|
/// font templates that are currently in use.
|
||||||
struct FontCache {
|
struct FontCache {
|
||||||
port: Receiver<Command>,
|
port: Receiver<Command>,
|
||||||
|
channel_to_self: Sender<Command>,
|
||||||
generic_fonts: HashMap<LowercaseString, LowercaseString>,
|
generic_fonts: HashMap<LowercaseString, LowercaseString>,
|
||||||
local_families: HashMap<LowercaseString, FontFamily>,
|
local_families: HashMap<LowercaseString, FontFamily>,
|
||||||
web_families: HashMap<LowercaseString, FontFamily>,
|
web_families: HashMap<LowercaseString, FontFamily>,
|
||||||
|
@ -131,25 +137,51 @@ impl FontCache {
|
||||||
match src {
|
match src {
|
||||||
Source::Url(ref url_source) => {
|
Source::Url(ref url_source) => {
|
||||||
let url = &url_source.url;
|
let url = &url_source.url;
|
||||||
let maybe_resource = load_whole_resource(&self.resource_task, url.clone());
|
let load = PendingAsyncLoad::new(self.resource_task.clone(),
|
||||||
match maybe_resource {
|
url.clone(),
|
||||||
Ok((_, bytes)) => {
|
None);
|
||||||
let family = &mut self.web_families.get_mut(&family_name).unwrap();
|
let (data_sender, data_receiver) = ipc::channel().unwrap();
|
||||||
family.add_template(Atom::from_slice(&url.to_string()), Some(bytes));
|
let data_target = AsyncResponseTarget {
|
||||||
},
|
sender: data_sender,
|
||||||
Err(_) => {
|
};
|
||||||
debug!("Failed to load web font: family={:?} url={}", family_name, url);
|
load.load_async(data_target);
|
||||||
|
let channel_to_self = self.channel_to_self.clone();
|
||||||
|
let url = (*url).clone();
|
||||||
|
let bytes = Mutex::new(Vec::new());
|
||||||
|
ROUTER.add_route(data_receiver.to_opaque(), box move |message| {
|
||||||
|
let response: ResponseAction = message.to().unwrap();
|
||||||
|
match response {
|
||||||
|
ResponseAction::HeadersAvailable(_) |
|
||||||
|
ResponseAction::ResponseComplete(Err(_)) => {}
|
||||||
|
ResponseAction::DataAvailable(new_bytes) => {
|
||||||
|
bytes.lock().unwrap().extend(new_bytes.into_iter())
|
||||||
|
}
|
||||||
|
ResponseAction::ResponseComplete(Ok(_)) => {
|
||||||
|
let mut bytes = bytes.lock().unwrap();
|
||||||
|
let bytes = mem::replace(&mut *bytes, Vec::new());
|
||||||
|
let command =
|
||||||
|
Command::AddDownloadedWebFont(family_name.clone(),
|
||||||
|
url.clone(),
|
||||||
|
bytes,
|
||||||
|
result.clone());
|
||||||
|
channel_to_self.send(command).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
Source::Local(ref local_family_name) => {
|
Source::Local(ref local_family_name) => {
|
||||||
let family = &mut self.web_families.get_mut(&family_name).unwrap();
|
let family = &mut self.web_families.get_mut(&family_name).unwrap();
|
||||||
for_each_variation(&local_family_name, |path| {
|
for_each_variation(&local_family_name, |path| {
|
||||||
family.add_template(Atom::from_slice(&path), None);
|
family.add_template(Atom::from_slice(&path), None);
|
||||||
});
|
});
|
||||||
|
result.send(()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.send(()).unwrap();
|
}
|
||||||
|
Command::AddDownloadedWebFont(family_name, url, bytes, result) => {
|
||||||
|
let family = &mut self.web_families.get_mut(&family_name).unwrap();
|
||||||
|
family.add_template(Atom::from_slice(&url.to_string()), Some(bytes));
|
||||||
|
drop(result.send(()));
|
||||||
}
|
}
|
||||||
Command::Exit(result) => {
|
Command::Exit(result) => {
|
||||||
result.send(()).unwrap();
|
result.send(()).unwrap();
|
||||||
|
@ -253,6 +285,7 @@ impl FontCacheTask {
|
||||||
pub fn new(resource_task: ResourceTask) -> FontCacheTask {
|
pub fn new(resource_task: ResourceTask) -> FontCacheTask {
|
||||||
let (chan, port) = channel();
|
let (chan, port) = channel();
|
||||||
|
|
||||||
|
let channel_to_self = chan.clone();
|
||||||
spawn_named("FontCacheTask".to_owned(), move || {
|
spawn_named("FontCacheTask".to_owned(), move || {
|
||||||
// TODO: Allow users to specify these.
|
// TODO: Allow users to specify these.
|
||||||
let mut generic_fonts = HashMap::with_capacity(5);
|
let mut generic_fonts = HashMap::with_capacity(5);
|
||||||
|
@ -264,6 +297,7 @@ impl FontCacheTask {
|
||||||
|
|
||||||
let mut cache = FontCache {
|
let mut cache = FontCache {
|
||||||
port: port,
|
port: port,
|
||||||
|
channel_to_self: channel_to_self,
|
||||||
generic_fonts: generic_fonts,
|
generic_fonts: generic_fonts,
|
||||||
local_families: HashMap::new(),
|
local_families: HashMap::new(),
|
||||||
web_families: HashMap::new(),
|
web_families: HashMap::new(),
|
||||||
|
@ -310,10 +344,8 @@ impl FontCacheTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_web_font(&self, family: Atom, src: Source) {
|
pub fn add_web_font(&self, family: Atom, src: Source, sender: Sender<()>) {
|
||||||
let (response_chan, response_port) = channel();
|
self.chan.send(Command::AddWebFont(family, src, sender)).unwrap();
|
||||||
self.chan.send(Command::AddWebFont(family, src, response_chan)).unwrap();
|
|
||||||
response_port.recv().unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit(&self) {
|
pub fn exit(&self) {
|
||||||
|
@ -322,3 +354,4 @@ impl FontCacheTask {
|
||||||
response_port.recv().unwrap();
|
response_port.recv().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ use std::default::Default;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use style::computed_values::{font_style, font_variant};
|
use style::computed_values::{font_style, font_variant};
|
||||||
use util::cache::HashCache;
|
use util::cache::HashCache;
|
||||||
|
@ -61,6 +62,10 @@ struct PaintFontCacheEntry {
|
||||||
font: Rc<RefCell<ScaledFont>>,
|
font: Rc<RefCell<ScaledFont>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An epoch for the font context cache. The cache is flushed if the current epoch does not match
|
||||||
|
/// this one.
|
||||||
|
static FONT_CACHE_EPOCH: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||||
|
|
||||||
/// The FontContext represents the per-thread/task state necessary for
|
/// The FontContext represents the per-thread/task state necessary for
|
||||||
/// working with fonts. It is the public API used by the layout and
|
/// working with fonts. It is the public API used by the layout and
|
||||||
/// paint code. It talks directly to the font cache task where
|
/// paint code. It talks directly to the font cache task where
|
||||||
|
@ -79,6 +84,8 @@ pub struct FontContext {
|
||||||
|
|
||||||
layout_font_group_cache:
|
layout_font_group_cache:
|
||||||
HashMap<LayoutFontGroupCacheKey, Rc<FontGroup>, DefaultState<FnvHasher>>,
|
HashMap<LayoutFontGroupCacheKey, Rc<FontGroup>, DefaultState<FnvHasher>>,
|
||||||
|
|
||||||
|
epoch: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontContext {
|
impl FontContext {
|
||||||
|
@ -91,6 +98,7 @@ impl FontContext {
|
||||||
fallback_font_cache: vec!(),
|
fallback_font_cache: vec!(),
|
||||||
paint_font_cache: vec!(),
|
paint_font_cache: vec!(),
|
||||||
layout_font_group_cache: HashMap::with_hash_state(Default::default()),
|
layout_font_group_cache: HashMap::with_hash_state(Default::default()),
|
||||||
|
epoch: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,11 +135,26 @@ impl FontContext {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expire_font_caches_if_necessary(&mut self) {
|
||||||
|
let current_epoch = FONT_CACHE_EPOCH.load(Ordering::SeqCst);
|
||||||
|
if current_epoch == self.epoch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.layout_font_cache.clear();
|
||||||
|
self.fallback_font_cache.clear();
|
||||||
|
self.paint_font_cache.clear();
|
||||||
|
self.layout_font_group_cache.clear();
|
||||||
|
self.epoch = current_epoch
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a group of fonts for use in layout calculations. May return
|
/// Create a group of fonts for use in layout calculations. May return
|
||||||
/// a cached font if this font instance has already been used by
|
/// a cached font if this font instance has already been used by
|
||||||
/// this context.
|
/// this context.
|
||||||
pub fn layout_font_group_for_style(&mut self, style: Arc<SpecifiedFontStyle>)
|
pub fn layout_font_group_for_style(&mut self, style: Arc<SpecifiedFontStyle>)
|
||||||
-> Rc<FontGroup> {
|
-> Rc<FontGroup> {
|
||||||
|
self.expire_font_caches_if_necessary();
|
||||||
|
|
||||||
let address = &*style as *const SpecifiedFontStyle as usize;
|
let address = &*style as *const SpecifiedFontStyle as usize;
|
||||||
if let Some(ref cached_font_group) = self.layout_font_group_cache.get(&address) {
|
if let Some(ref cached_font_group) = self.layout_font_group_cache.get(&address) {
|
||||||
return (*cached_font_group).clone()
|
return (*cached_font_group).clone()
|
||||||
|
@ -319,3 +342,9 @@ impl borrow::Borrow<usize> for LayoutFontGroupCacheKey {
|
||||||
&self.address
|
&self.address
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn invalidate_font_caches() {
|
||||||
|
FONT_CACHE_EPOCH.fetch_add(1, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
||||||
use gfx::display_list::StackingContext;
|
use gfx::display_list::StackingContext;
|
||||||
use gfx::display_list::{ClippingRegion, DisplayList, OpaqueNode};
|
use gfx::display_list::{ClippingRegion, DisplayList, OpaqueNode};
|
||||||
use gfx::font_cache_task::FontCacheTask;
|
use gfx::font_cache_task::FontCacheTask;
|
||||||
|
use gfx::font_context;
|
||||||
use gfx::paint_task::{LayoutToPaintMsg, PaintLayer};
|
use gfx::paint_task::{LayoutToPaintMsg, PaintLayer};
|
||||||
use gfx_traits::color;
|
use gfx_traits::color;
|
||||||
use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT};
|
use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT};
|
||||||
|
@ -67,7 +68,8 @@ use std::collections::HashMap;
|
||||||
use std::collections::hash_state::DefaultState;
|
use std::collections::hash_state::DefaultState;
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::sync::mpsc::{Receiver, Select, Sender, channel};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::sync::mpsc::{channel, Sender, Receiver, Select};
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use style::computed_values::{self, filter, mix_blend_mode};
|
use style::computed_values::{self, filter, mix_blend_mode};
|
||||||
|
@ -151,6 +153,9 @@ pub struct LayoutTaskData {
|
||||||
/// A counter for epoch messages
|
/// A counter for epoch messages
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
|
|
||||||
|
/// The number of Web fonts that have been requested but not yet loaded.
|
||||||
|
pub outstanding_web_fonts: Arc<AtomicUsize>,
|
||||||
|
|
||||||
/// The position and size of the visible rect for each layer. We do not build display lists
|
/// The position and size of the visible rect for each layer. We do not build display lists
|
||||||
/// for any areas more than `DISPLAY_PORT_SIZE_FACTOR` screens away from this area.
|
/// for any areas more than `DISPLAY_PORT_SIZE_FACTOR` screens away from this area.
|
||||||
pub visible_rects: Arc<HashMap<LayerId, Rect<Au>, DefaultState<FnvHasher>>>,
|
pub visible_rects: Arc<HashMap<LayerId, Rect<Au>, DefaultState<FnvHasher>>>,
|
||||||
|
@ -187,6 +192,12 @@ pub struct LayoutTask {
|
||||||
/// The channel on which the image cache can send messages to ourself.
|
/// The channel on which the image cache can send messages to ourself.
|
||||||
image_cache_sender: ImageCacheChan,
|
image_cache_sender: ImageCacheChan,
|
||||||
|
|
||||||
|
/// The port on which we receive messages from the font cache task.
|
||||||
|
font_cache_receiver: Receiver<()>,
|
||||||
|
|
||||||
|
/// The channel on which the font cache can send messages to us.
|
||||||
|
font_cache_sender: Sender<()>,
|
||||||
|
|
||||||
/// The channel on which we or others can send messages to ourselves.
|
/// The channel on which we or others can send messages to ourselves.
|
||||||
pub chan: LayoutChan,
|
pub chan: LayoutChan,
|
||||||
|
|
||||||
|
@ -304,10 +315,18 @@ impl<'a> DerefMut for RWGuard<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_font_face_rules(stylesheet: &Stylesheet, device: &Device, font_cache_task: &FontCacheTask) {
|
fn add_font_face_rules(stylesheet: &Stylesheet,
|
||||||
|
device: &Device,
|
||||||
|
font_cache_task: &FontCacheTask,
|
||||||
|
font_cache_sender: &Sender<()>,
|
||||||
|
outstanding_web_fonts_counter: &Arc<AtomicUsize>) {
|
||||||
for font_face in stylesheet.effective_rules(&device).font_face() {
|
for font_face in stylesheet.effective_rules(&device).font_face() {
|
||||||
for source in &font_face.sources {
|
for source in &font_face.sources {
|
||||||
font_cache_task.add_web_font(font_face.family.clone(), source.clone());
|
let font_cache_task = (*font_cache_task).clone();
|
||||||
|
outstanding_web_fonts_counter.fetch_add(1, Ordering::SeqCst);
|
||||||
|
font_cache_task.add_web_font(font_face.family.clone(),
|
||||||
|
(*source).clone(),
|
||||||
|
(*font_cache_sender).clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,9 +370,16 @@ impl LayoutTask {
|
||||||
let image_cache_receiver =
|
let image_cache_receiver =
|
||||||
ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_image_cache_receiver);
|
ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_image_cache_receiver);
|
||||||
|
|
||||||
|
let (font_cache_sender, font_cache_receiver) = channel();
|
||||||
|
|
||||||
let stylist = box Stylist::new(device);
|
let stylist = box Stylist::new(device);
|
||||||
|
let outstanding_web_fonts_counter = Arc::new(AtomicUsize::new(0));
|
||||||
for user_or_user_agent_stylesheet in stylist.stylesheets() {
|
for user_or_user_agent_stylesheet in stylist.stylesheets() {
|
||||||
add_font_face_rules(user_or_user_agent_stylesheet, &stylist.device, &font_cache_task);
|
add_font_face_rules(user_or_user_agent_stylesheet,
|
||||||
|
&stylist.device,
|
||||||
|
&font_cache_task,
|
||||||
|
&font_cache_sender,
|
||||||
|
&outstanding_web_fonts_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutTask {
|
LayoutTask {
|
||||||
|
@ -373,6 +399,8 @@ impl LayoutTask {
|
||||||
first_reflow: Cell::new(true),
|
first_reflow: Cell::new(true),
|
||||||
image_cache_receiver: image_cache_receiver,
|
image_cache_receiver: image_cache_receiver,
|
||||||
image_cache_sender: ImageCacheChan(ipc_image_cache_sender),
|
image_cache_sender: ImageCacheChan(ipc_image_cache_sender),
|
||||||
|
font_cache_receiver: font_cache_receiver,
|
||||||
|
font_cache_sender: font_cache_sender,
|
||||||
canvas_layers_receiver: canvas_layers_receiver,
|
canvas_layers_receiver: canvas_layers_receiver,
|
||||||
canvas_layers_sender: canvas_layers_sender,
|
canvas_layers_sender: canvas_layers_sender,
|
||||||
rw_data: Arc::new(Mutex::new(
|
rw_data: Arc::new(Mutex::new(
|
||||||
|
@ -395,6 +423,7 @@ impl LayoutTask {
|
||||||
new_animations_receiver: new_animations_receiver,
|
new_animations_receiver: new_animations_receiver,
|
||||||
new_animations_sender: new_animations_sender,
|
new_animations_sender: new_animations_sender,
|
||||||
epoch: Epoch(0),
|
epoch: Epoch(0),
|
||||||
|
outstanding_web_fonts: outstanding_web_fonts_counter,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,25 +472,30 @@ impl LayoutTask {
|
||||||
Pipeline,
|
Pipeline,
|
||||||
Script,
|
Script,
|
||||||
ImageCache,
|
ImageCache,
|
||||||
|
FontCache,
|
||||||
}
|
}
|
||||||
|
|
||||||
let port_to_read = {
|
let port_to_read = {
|
||||||
let sel = Select::new();
|
let select = Select::new();
|
||||||
let mut port1 = sel.handle(&self.port);
|
let mut port_from_script = select.handle(&self.port);
|
||||||
let mut port2 = sel.handle(&self.pipeline_port);
|
let mut port_from_pipeline = select.handle(&self.pipeline_port);
|
||||||
let mut port3 = sel.handle(&self.image_cache_receiver);
|
let mut port_from_image_cache = select.handle(&self.image_cache_receiver);
|
||||||
|
let mut port_from_font_cache = select.handle(&self.font_cache_receiver);
|
||||||
unsafe {
|
unsafe {
|
||||||
port1.add();
|
port_from_script.add();
|
||||||
port2.add();
|
port_from_pipeline.add();
|
||||||
port3.add();
|
port_from_image_cache.add();
|
||||||
|
port_from_font_cache.add();
|
||||||
}
|
}
|
||||||
let ret = sel.wait();
|
let ret = select.wait();
|
||||||
if ret == port1.id() {
|
if ret == port_from_script.id() {
|
||||||
PortToRead::Script
|
PortToRead::Script
|
||||||
} else if ret == port2.id() {
|
} else if ret == port_from_pipeline.id() {
|
||||||
PortToRead::Pipeline
|
PortToRead::Pipeline
|
||||||
} else if ret == port3.id() {
|
} else if ret == port_from_image_cache.id() {
|
||||||
PortToRead::ImageCache
|
PortToRead::ImageCache
|
||||||
|
} else if ret == port_from_font_cache.id() {
|
||||||
|
PortToRead::FontCache
|
||||||
} else {
|
} else {
|
||||||
panic!("invalid select result");
|
panic!("invalid select result");
|
||||||
}
|
}
|
||||||
|
@ -481,6 +515,10 @@ impl LayoutTask {
|
||||||
self.handle_request_helper(Msg::GetCurrentEpoch(sender),
|
self.handle_request_helper(Msg::GetCurrentEpoch(sender),
|
||||||
possibly_locked_rw_data)
|
possibly_locked_rw_data)
|
||||||
}
|
}
|
||||||
|
LayoutControlMsg::GetWebFontLoadState(sender) => {
|
||||||
|
self.handle_request_helper(Msg::GetWebFontLoadState(sender),
|
||||||
|
possibly_locked_rw_data)
|
||||||
|
}
|
||||||
LayoutControlMsg::ExitNow(exit_type) => {
|
LayoutControlMsg::ExitNow(exit_type) => {
|
||||||
self.handle_request_helper(Msg::ExitNow(exit_type),
|
self.handle_request_helper(Msg::ExitNow(exit_type),
|
||||||
possibly_locked_rw_data)
|
possibly_locked_rw_data)
|
||||||
|
@ -495,6 +533,14 @@ impl LayoutTask {
|
||||||
let _ = self.image_cache_receiver.recv().unwrap();
|
let _ = self.image_cache_receiver.recv().unwrap();
|
||||||
self.repaint(possibly_locked_rw_data)
|
self.repaint(possibly_locked_rw_data)
|
||||||
}
|
}
|
||||||
|
PortToRead::FontCache => {
|
||||||
|
let _ = self.font_cache_receiver.recv().unwrap();
|
||||||
|
let rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
||||||
|
rw_data.outstanding_web_fonts.fetch_sub(1, Ordering::SeqCst);
|
||||||
|
font_context::invalidate_font_caches();
|
||||||
|
self.script_chan.send(ConstellationControlMsg::WebFontLoaded(self.id)).unwrap();
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,6 +627,9 @@ impl LayoutTask {
|
||||||
|| self.handle_reflow(&*data, possibly_locked_rw_data));
|
|| self.handle_reflow(&*data, possibly_locked_rw_data));
|
||||||
},
|
},
|
||||||
Msg::TickAnimations => self.tick_all_animations(possibly_locked_rw_data),
|
Msg::TickAnimations => self.tick_all_animations(possibly_locked_rw_data),
|
||||||
|
Msg::ReflowWithNewlyLoadedWebFont => {
|
||||||
|
self.reflow_with_newly_loaded_web_font(possibly_locked_rw_data)
|
||||||
|
}
|
||||||
Msg::SetVisibleRects(new_visible_rects) => {
|
Msg::SetVisibleRects(new_visible_rects) => {
|
||||||
self.set_visible_rects(new_visible_rects, possibly_locked_rw_data);
|
self.set_visible_rects(new_visible_rects, possibly_locked_rw_data);
|
||||||
}
|
}
|
||||||
|
@ -596,6 +645,11 @@ impl LayoutTask {
|
||||||
let rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
let rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
||||||
sender.send(rw_data.epoch).unwrap();
|
sender.send(rw_data.epoch).unwrap();
|
||||||
},
|
},
|
||||||
|
Msg::GetWebFontLoadState(sender) => {
|
||||||
|
let rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
||||||
|
let outstanding_web_fonts = rw_data.outstanding_web_fonts.load(Ordering::SeqCst);
|
||||||
|
sender.send(outstanding_web_fonts != 0).unwrap();
|
||||||
|
},
|
||||||
Msg::CreateLayoutTask(info) => {
|
Msg::CreateLayoutTask(info) => {
|
||||||
self.create_layout_task(info)
|
self.create_layout_task(info)
|
||||||
}
|
}
|
||||||
|
@ -756,9 +810,12 @@ impl LayoutTask {
|
||||||
// GWTODO: Need to handle unloading web fonts (when we handle unloading stylesheets!)
|
// GWTODO: Need to handle unloading web fonts (when we handle unloading stylesheets!)
|
||||||
|
|
||||||
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
||||||
|
|
||||||
if mq.evaluate(&rw_data.stylist.device) {
|
if mq.evaluate(&rw_data.stylist.device) {
|
||||||
add_font_face_rules(&sheet, &rw_data.stylist.device, &self.font_cache_task);
|
add_font_face_rules(&sheet,
|
||||||
|
&rw_data.stylist.device,
|
||||||
|
&self.font_cache_task,
|
||||||
|
&self.font_cache_sender,
|
||||||
|
&rw_data.outstanding_web_fonts);
|
||||||
rw_data.stylist.add_stylesheet(sheet);
|
rw_data.stylist.add_stylesheet(sheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1306,6 +1363,32 @@ impl LayoutTask {
|
||||||
&mut layout_context);
|
&mut layout_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reflow_with_newly_loaded_web_font<'a>(
|
||||||
|
&'a self,
|
||||||
|
possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>) {
|
||||||
|
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
|
||||||
|
font_context::invalidate_font_caches();
|
||||||
|
|
||||||
|
let reflow_info = Reflow {
|
||||||
|
goal: ReflowGoal::ForDisplay,
|
||||||
|
page_clip_rect: MAX_RECT,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut layout_context = self.build_shared_layout_context(&*rw_data,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
&self.url,
|
||||||
|
reflow_info.goal);
|
||||||
|
|
||||||
|
// No need to do a style recalc here.
|
||||||
|
if rw_data.root_flow.as_ref().is_none() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.perform_post_style_recalc_layout_passes(&reflow_info,
|
||||||
|
&mut *rw_data,
|
||||||
|
&mut layout_context);
|
||||||
|
}
|
||||||
|
|
||||||
fn perform_post_style_recalc_layout_passes<'a>(&'a self,
|
fn perform_post_style_recalc_layout_passes<'a>(&'a self,
|
||||||
data: &Reflow,
|
data: &Reflow,
|
||||||
rw_data: &mut LayoutTaskData,
|
rw_data: &mut LayoutTaskData,
|
||||||
|
@ -1571,3 +1654,4 @@ fn get_root_flow_background_color(flow: &mut Flow) -> AzColor {
|
||||||
.resolve_color(kid_block_flow.fragment.style.get_background().background_color)
|
.resolve_color(kid_block_flow.fragment.style.get_background().background_color)
|
||||||
.to_gfx_color()
|
.to_gfx_color()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,7 @@ pub enum ReflowReason {
|
||||||
DocumentLoaded,
|
DocumentLoaded,
|
||||||
ImageLoaded,
|
ImageLoaded,
|
||||||
RequestAnimationFrame,
|
RequestAnimationFrame,
|
||||||
|
WebFontLoaded,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ScrollPoint = Point2D<Au>;
|
pub type ScrollPoint = Point2D<Au>;
|
||||||
|
@ -1378,6 +1379,7 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason:
|
||||||
ReflowReason::DocumentLoaded => "\tDocumentLoaded",
|
ReflowReason::DocumentLoaded => "\tDocumentLoaded",
|
||||||
ReflowReason::ImageLoaded => "\tImageLoaded",
|
ReflowReason::ImageLoaded => "\tImageLoaded",
|
||||||
ReflowReason::RequestAnimationFrame => "\tRequestAnimationFrame",
|
ReflowReason::RequestAnimationFrame => "\tRequestAnimationFrame",
|
||||||
|
ReflowReason::WebFontLoaded => "\tWebFontLoaded",
|
||||||
});
|
});
|
||||||
|
|
||||||
println!("{}", debug_msg);
|
println!("{}", debug_msg);
|
||||||
|
|
|
@ -51,6 +51,9 @@ pub enum Msg {
|
||||||
/// Requests that the layout task render the next frame of all animations.
|
/// Requests that the layout task render the next frame of all animations.
|
||||||
TickAnimations,
|
TickAnimations,
|
||||||
|
|
||||||
|
/// Requests that the layout task reflow with a newly-loaded Web font.
|
||||||
|
ReflowWithNewlyLoadedWebFont,
|
||||||
|
|
||||||
/// Updates the layout visible rects, affecting the area that display lists will be constructed
|
/// Updates the layout visible rects, affecting the area that display lists will be constructed
|
||||||
/// for.
|
/// for.
|
||||||
SetVisibleRects(Vec<(LayerId, Rect<Au>)>),
|
SetVisibleRects(Vec<(LayerId, Rect<Au>)>),
|
||||||
|
@ -76,6 +79,10 @@ pub enum Msg {
|
||||||
/// Get the last epoch counter for this layout task.
|
/// Get the last epoch counter for this layout task.
|
||||||
GetCurrentEpoch(IpcSender<Epoch>),
|
GetCurrentEpoch(IpcSender<Epoch>),
|
||||||
|
|
||||||
|
/// Asks the layout task whether any Web fonts have yet to load (if true, loads are pending;
|
||||||
|
/// false otherwise).
|
||||||
|
GetWebFontLoadState(IpcSender<bool>),
|
||||||
|
|
||||||
/// Creates a new layout task.
|
/// Creates a new layout task.
|
||||||
///
|
///
|
||||||
/// This basically exists to keep the script-layout dependency one-way.
|
/// This basically exists to keep the script-layout dependency one-way.
|
||||||
|
|
|
@ -942,6 +942,8 @@ impl ScriptTask {
|
||||||
self.handle_webdriver_msg(pipeline_id, msg),
|
self.handle_webdriver_msg(pipeline_id, msg),
|
||||||
ConstellationControlMsg::TickAllAnimations(pipeline_id) =>
|
ConstellationControlMsg::TickAllAnimations(pipeline_id) =>
|
||||||
self.handle_tick_all_animations(pipeline_id),
|
self.handle_tick_all_animations(pipeline_id),
|
||||||
|
ConstellationControlMsg::WebFontLoaded(pipeline_id) =>
|
||||||
|
self.handle_web_font_loaded(pipeline_id),
|
||||||
ConstellationControlMsg::StylesheetLoadComplete(id, url, responder) => {
|
ConstellationControlMsg::StylesheetLoadComplete(id, url, responder) => {
|
||||||
responder.respond();
|
responder.respond();
|
||||||
self.handle_resource_loaded(id, LoadType::Stylesheet(url));
|
self.handle_resource_loaded(id, LoadType::Stylesheet(url));
|
||||||
|
@ -1478,6 +1480,15 @@ impl ScriptTask {
|
||||||
document.r().run_the_animation_frame_callbacks();
|
document.r().run_the_animation_frame_callbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles a Web font being loaded. Does nothing if the page no longer exists.
|
||||||
|
fn handle_web_font_loaded(&self, pipeline_id: PipelineId) {
|
||||||
|
if let Some(page) = self.page.borrow().as_ref() {
|
||||||
|
if let Some(page) = page.find(pipeline_id) {
|
||||||
|
self.rebuild_and_force_reflow(&*page, ReflowReason::WebFontLoaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The entry point to document loading. Defines bindings, sets up the window and document
|
/// The entry point to document loading. Defines bindings, sets up the window and document
|
||||||
/// objects, parses HTML and CSS, and kicks off initial layout.
|
/// objects, parses HTML and CSS, and kicks off initial layout.
|
||||||
fn load(&self, metadata: Metadata, incomplete: InProgressLoad) -> Root<ServoHTMLParser> {
|
fn load(&self, metadata: Metadata, incomplete: InProgressLoad) -> Root<ServoHTMLParser> {
|
||||||
|
|
|
@ -58,6 +58,9 @@ pub enum LayoutControlMsg {
|
||||||
TickAnimations,
|
TickAnimations,
|
||||||
/// Informs layout as to which regions of the page are visible.
|
/// Informs layout as to which regions of the page are visible.
|
||||||
SetVisibleRects(Vec<(LayerId, Rect<Au>)>),
|
SetVisibleRects(Vec<(LayerId, Rect<Au>)>),
|
||||||
|
/// Requests the current load state of Web fonts. `true` is returned if fonts are still loading
|
||||||
|
/// and `false` is returned if all fonts have loaded.
|
||||||
|
GetWebFontLoadState(IpcSender<bool>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The initial data associated with a newly-created framed pipeline.
|
/// The initial data associated with a newly-created framed pipeline.
|
||||||
|
@ -99,7 +102,7 @@ pub enum ScriptState {
|
||||||
DocumentLoading,
|
DocumentLoading,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Messages sent from the constellation to the script task
|
/// Messages sent from the constellation or layout to the script task.
|
||||||
pub enum ConstellationControlMsg {
|
pub enum ConstellationControlMsg {
|
||||||
/// Gives a channel and ID to a layout task, as well as the ID of that layout's parent
|
/// Gives a channel and ID to a layout task, as well as the ID of that layout's parent
|
||||||
AttachLayout(NewLayoutInfo),
|
AttachLayout(NewLayoutInfo),
|
||||||
|
@ -133,6 +136,9 @@ pub enum ConstellationControlMsg {
|
||||||
WebDriverScriptCommand(PipelineId, WebDriverScriptCommand),
|
WebDriverScriptCommand(PipelineId, WebDriverScriptCommand),
|
||||||
/// Notifies script task that all animations are done
|
/// Notifies script task that all animations are done
|
||||||
TickAllAnimations(PipelineId),
|
TickAllAnimations(PipelineId),
|
||||||
|
/// Notifies the script task that a new Web font has been loaded, and thus the page should be
|
||||||
|
/// reflowed.
|
||||||
|
WebFontLoaded(PipelineId),
|
||||||
/// Notifies script that a stylesheet has finished loading.
|
/// Notifies script that a stylesheet has finished loading.
|
||||||
StylesheetLoadComplete(PipelineId, Url, Box<StylesheetLoadResponder + Send>),
|
StylesheetLoadComplete(PipelineId, Url, Box<StylesheetLoadResponder + Send>),
|
||||||
/// Get the current state of the script task for a given pipeline.
|
/// Get the current state of the script task for a given pipeline.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue