diff options
-rw-r--r-- | components/compositing/constellation.rs | 9 | ||||
-rw-r--r-- | components/gfx/font_cache_task.rs | 67 | ||||
-rw-r--r-- | components/gfx/font_context.rs | 37 | ||||
-rw-r--r-- | components/gfx/paint_context.rs | 6 | ||||
-rw-r--r-- | components/gfx/platform/macos/font.rs | 30 | ||||
-rw-r--r-- | components/layout/animation.rs | 4 | ||||
-rw-r--r-- | components/layout/layout_task.rs | 118 | ||||
-rw-r--r-- | components/script/dom/window.rs | 2 | ||||
-rw-r--r-- | components/script/layout_interface.rs | 7 | ||||
-rw-r--r-- | components/script/script_task.rs | 11 | ||||
-rw-r--r-- | components/script_traits/lib.rs | 8 | ||||
-rw-r--r-- | components/util/geometry.rs | 40 |
12 files changed, 248 insertions, 91 deletions
diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index 81a35241b80..656a254d40e 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -1219,6 +1219,15 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { 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 // hasn't received a rectangle for this pipeline yet, then assume // that the output image isn't stable yet. diff --git a/components/gfx/font_cache_task.rs b/components/gfx/font_cache_task.rs index 08e0b636c36..a568af35840 100644 --- a/components/gfx/font_cache_task.rs +++ b/components/gfx/font_cache_task.rs @@ -3,7 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 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_list::for_each_available_family; use platform::font_list::for_each_variation; @@ -12,10 +14,12 @@ use platform::font_list::system_default_family; use platform::font_template::FontTemplateData; use std::borrow::ToOwned; use std::collections::HashMap; -use std::sync::Arc; -use std::sync::mpsc::{Receiver, Sender, channel}; +use std::mem; +use std::sync::mpsc::{Sender, Receiver, channel}; +use std::sync::{Arc, Mutex}; use string_cache::Atom; use style::font_face::Source; +use url::Url; use util::str::LowercaseString; use util::task::spawn_named; @@ -77,6 +81,7 @@ pub enum Command { GetFontTemplate(String, FontTemplateDescriptor, Sender<Reply>), GetLastResortFontTemplate(FontTemplateDescriptor, Sender<Reply>), AddWebFont(Atom, Source, Sender<()>), + AddDownloadedWebFont(LowercaseString, Url, Vec<u8>, Sender<()>), Exit(Sender<()>), } @@ -89,6 +94,7 @@ pub enum Reply { /// font templates that are currently in use. struct FontCache { port: Receiver<Command>, + channel_to_self: Sender<Command>, generic_fonts: HashMap<LowercaseString, LowercaseString>, local_families: HashMap<LowercaseString, FontFamily>, web_families: HashMap<LowercaseString, FontFamily>, @@ -131,25 +137,51 @@ impl FontCache { match src { Source::Url(ref url_source) => { let url = &url_source.url; - let maybe_resource = load_whole_resource(&self.resource_task, url.clone()); - match maybe_resource { - Ok((_, bytes)) => { - let family = &mut self.web_families.get_mut(&family_name).unwrap(); - family.add_template(Atom::from_slice(&url.to_string()), Some(bytes)); - }, - Err(_) => { - debug!("Failed to load web font: family={:?} url={}", family_name, url); + let load = PendingAsyncLoad::new(self.resource_task.clone(), + url.clone(), + None); + let (data_sender, data_receiver) = ipc::channel().unwrap(); + let data_target = AsyncResponseTarget { + sender: data_sender, + }; + 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) => { let family = &mut self.web_families.get_mut(&family_name).unwrap(); for_each_variation(&local_family_name, |path| { 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) => { result.send(()).unwrap(); @@ -253,6 +285,7 @@ impl FontCacheTask { pub fn new(resource_task: ResourceTask) -> FontCacheTask { let (chan, port) = channel(); + let channel_to_self = chan.clone(); spawn_named("FontCacheTask".to_owned(), move || { // TODO: Allow users to specify these. let mut generic_fonts = HashMap::with_capacity(5); @@ -264,6 +297,7 @@ impl FontCacheTask { let mut cache = FontCache { port: port, + channel_to_self: channel_to_self, generic_fonts: generic_fonts, local_families: HashMap::new(), web_families: HashMap::new(), @@ -310,10 +344,8 @@ impl FontCacheTask { } } - pub fn add_web_font(&self, family: Atom, src: Source) { - let (response_chan, response_port) = channel(); - self.chan.send(Command::AddWebFont(family, src, response_chan)).unwrap(); - response_port.recv().unwrap(); + pub fn add_web_font(&self, family: Atom, src: Source, sender: Sender<()>) { + self.chan.send(Command::AddWebFont(family, src, sender)).unwrap(); } pub fn exit(&self) { @@ -322,3 +354,4 @@ impl FontCacheTask { response_port.recv().unwrap(); } } + diff --git a/components/gfx/font_context.rs b/components/gfx/font_context.rs index e0fa69800e1..ff2ba9fc256 100644 --- a/components/gfx/font_context.rs +++ b/components/gfx/font_context.rs @@ -24,6 +24,7 @@ use std::default::Default; use std::hash::{Hash, Hasher}; use std::rc::Rc; use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; use string_cache::Atom; use style::computed_values::{font_style, font_variant}; use util::cache::HashCache; @@ -61,6 +62,10 @@ struct PaintFontCacheEntry { 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 /// working with fonts. It is the public API used by the layout and /// paint code. It talks directly to the font cache task where @@ -79,6 +84,8 @@ pub struct FontContext { layout_font_group_cache: HashMap<LayoutFontGroupCacheKey, Rc<FontGroup>, DefaultState<FnvHasher>>, + + epoch: usize, } impl FontContext { @@ -91,6 +98,7 @@ impl FontContext { fallback_font_cache: vec!(), paint_font_cache: vec!(), 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 /// a cached font if this font instance has already been used by /// this context. pub fn layout_font_group_for_style(&mut self, style: Arc<SpecifiedFontStyle>) -> Rc<FontGroup> { + self.expire_font_caches_if_necessary(); + let address = &*style as *const SpecifiedFontStyle as usize; if let Some(ref cached_font_group) = self.layout_font_group_cache.get(&address) { return (*cached_font_group).clone() @@ -142,10 +165,10 @@ impl FontContext { size: style.font_size, address: address, }; - if let Some(ref cached_font_group) = - self.layout_font_group_cache.get(&layout_font_group_cache_key) { - return (*cached_font_group).clone() - } + if let Some(ref cached_font_group) = self.layout_font_group_cache.get( + &layout_font_group_cache_key) { + return (*cached_font_group).clone() + } // TODO: The font context holds a strong ref to the cached fonts // so they will never be released. Find out a good time to drop them. @@ -319,3 +342,9 @@ impl borrow::Borrow<usize> for LayoutFontGroupCacheKey { &self.address } } + +#[inline] +pub fn invalidate_font_caches() { + FONT_CACHE_EPOCH.fetch_add(1, Ordering::SeqCst); +} + diff --git a/components/gfx/paint_context.rs b/components/gfx/paint_context.rs index 4981f4f8856..87463981aa8 100644 --- a/components/gfx/paint_context.rs +++ b/components/gfx/paint_context.rs @@ -34,7 +34,7 @@ use std::{f32, mem, ptr}; use style::computed_values::{border_style, filter, image_rendering, mix_blend_mode}; use text::TextRun; use text::glyph::CharIndex; -use util::geometry::{self, Au, MAX_RECT, ZERO_RECT}; +use util::geometry::{self, Au, MAX_RECT, ZERO_POINT, ZERO_RECT}; use util::opts; use util::range::Range; @@ -1344,7 +1344,7 @@ impl<'a> PaintContext<'a> { self.draw_target.set_transform(&draw_target_transform.mul(&Matrix2D::new(0., -1., 1., 0., x, y))); - Point2D::zero() + ZERO_POINT } SidewaysRight => { let x = text.baseline_origin.x.to_f32_px(); @@ -1352,7 +1352,7 @@ impl<'a> PaintContext<'a> { self.draw_target.set_transform(&draw_target_transform.mul(&Matrix2D::new(0., 1., -1., 0., x, y))); - Point2D::zero() + ZERO_POINT } }; diff --git a/components/gfx/platform/macos/font.rs b/components/gfx/platform/macos/font.rs index fa29592d184..0cf95aa6c3f 100644 --- a/components/gfx/platform/macos/font.rs +++ b/components/gfx/platform/macos/font.rs @@ -25,12 +25,26 @@ use std::ptr; use std::sync::Arc; use style::computed_values::{font_stretch, font_weight}; use text::glyph::GlyphId; -use util::geometry::{Au, px_to_pt}; +use util::geometry::Au; pub struct FontTable { data: CFData, } +// assumes 72 points per inch, and 96 px per inch +fn px_to_pt(px: f64) -> f64 { + px / 96. * 72. +} + +// assumes 72 points per inch, and 96 px per inch +fn pt_to_px(pt: f64) -> f64 { + pt / 72. * 96. +} + +fn au_from_pt(pt: f64) -> Au { + Au::from_f64_px(pt_to_px(pt)) +} + impl FontTable { pub fn wrap(data: CFData) -> FontTable { FontTable { data: data } @@ -161,27 +175,27 @@ impl FontHandleMethods for FontHandle { let scale = px_to_pt(self.ctfont.pt_size() as f64) / (ascent + descent); let line_gap = (ascent + descent + leading + 0.5).floor(); - let max_advance_width = Au::from_pt(bounding_rect.size.width as f64); + let max_advance_width = au_from_pt(bounding_rect.size.width as f64); let average_advance = self.glyph_index('0') .and_then(|idx| self.glyph_h_advance(idx)) .map(|advance| Au::from_f64_px(advance)) .unwrap_or(max_advance_width); let metrics = FontMetrics { - underline_size: Au::from_pt(self.ctfont.underline_thickness() as f64), + underline_size: au_from_pt(self.ctfont.underline_thickness() as f64), // TODO(Issue #201): underline metrics are not reliable. Have to pull out of font table // directly. // // see also: https://bugs.webkit.org/show_bug.cgi?id=16768 // see also: https://bugreports.qt-project.org/browse/QTBUG-13364 - underline_offset: Au::from_pt(self.ctfont.underline_position() as f64), + underline_offset: au_from_pt(self.ctfont.underline_position() as f64), strikeout_size: Au(0), // FIXME(Issue #942) strikeout_offset: Au(0), // FIXME(Issue #942) - leading: Au::from_pt(leading), - x_height: Au::from_pt(self.ctfont.x_height() as f64), + leading: au_from_pt(leading), + x_height: au_from_pt(self.ctfont.x_height() as f64), em_size: em_size, - ascent: Au::from_pt(ascent * scale), - descent: Au::from_pt(descent * scale), + ascent: au_from_pt(ascent * scale), + descent: au_from_pt(descent * scale), max_advance: max_advance_width, average_advance: average_advance, line_gap: Au::from_f64_px(line_gap), diff --git a/components/layout/animation.rs b/components/layout/animation.rs index 863b1eb325a..99d257f38a4 100644 --- a/components/layout/animation.rs +++ b/components/layout/animation.rs @@ -136,5 +136,7 @@ pub fn recalc_style_for_animations(flow: &mut Flow, pub fn tick_all_animations(layout_task: &LayoutTask, rw_data: &mut LayoutTaskData) { layout_task.tick_animations(rw_data); - layout_task.script_chan.send(ConstellationControlMsg::TickAllAnimations(layout_task.id)).unwrap(); + layout_task.script_chan + .send(ConstellationControlMsg::TickAllAnimations(layout_task.id)) + .unwrap(); } diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index f0aba98b393..c5f9c371035 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -29,6 +29,7 @@ use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use gfx::display_list::StackingContext; use gfx::display_list::{ClippingRegion, DisplayList, OpaqueNode}; use gfx::font_cache_task::FontCacheTask; +use gfx::font_context; use gfx::paint_task::{LayoutToPaintMsg, PaintLayer}; use gfx_traits::color; use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT}; @@ -67,7 +68,8 @@ use std::collections::HashMap; use std::collections::hash_state::DefaultState; use std::mem::transmute; 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 string_cache::Atom; use style::computed_values::{self, filter, mix_blend_mode}; @@ -151,6 +153,9 @@ pub struct LayoutTaskData { /// A counter for epoch messages 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 /// for any areas more than `DISPLAY_PORT_SIZE_FACTOR` screens away from this area. 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. 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. 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 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 = 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 outstanding_web_fonts_counter = Arc::new(AtomicUsize::new(0)); 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 { @@ -373,6 +399,8 @@ impl LayoutTask { first_reflow: Cell::new(true), image_cache_receiver: image_cache_receiver, 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_sender: canvas_layers_sender, rw_data: Arc::new(Mutex::new( @@ -395,6 +423,7 @@ impl LayoutTask { new_animations_receiver: new_animations_receiver, new_animations_sender: new_animations_sender, epoch: Epoch(0), + outstanding_web_fonts: outstanding_web_fonts_counter, })), } } @@ -443,25 +472,30 @@ impl LayoutTask { Pipeline, Script, ImageCache, + FontCache, } let port_to_read = { - let sel = Select::new(); - let mut port1 = sel.handle(&self.port); - let mut port2 = sel.handle(&self.pipeline_port); - let mut port3 = sel.handle(&self.image_cache_receiver); + let select = Select::new(); + let mut port_from_script = select.handle(&self.port); + let mut port_from_pipeline = select.handle(&self.pipeline_port); + 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 { - port1.add(); - port2.add(); - port3.add(); + port_from_script.add(); + port_from_pipeline.add(); + port_from_image_cache.add(); + port_from_font_cache.add(); } - let ret = sel.wait(); - if ret == port1.id() { + let ret = select.wait(); + if ret == port_from_script.id() { PortToRead::Script - } else if ret == port2.id() { + } else if ret == port_from_pipeline.id() { PortToRead::Pipeline - } else if ret == port3.id() { + } else if ret == port_from_image_cache.id() { PortToRead::ImageCache + } else if ret == port_from_font_cache.id() { + PortToRead::FontCache } else { panic!("invalid select result"); } @@ -481,6 +515,10 @@ impl LayoutTask { self.handle_request_helper(Msg::GetCurrentEpoch(sender), possibly_locked_rw_data) } + LayoutControlMsg::GetWebFontLoadState(sender) => { + self.handle_request_helper(Msg::GetWebFontLoadState(sender), + possibly_locked_rw_data) + } LayoutControlMsg::ExitNow(exit_type) => { self.handle_request_helper(Msg::ExitNow(exit_type), possibly_locked_rw_data) @@ -495,6 +533,14 @@ impl LayoutTask { let _ = self.image_cache_receiver.recv().unwrap(); 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)); }, 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) => { 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); 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) => { self.create_layout_task(info) } @@ -756,9 +810,12 @@ impl LayoutTask { // GWTODO: Need to handle unloading web fonts (when we handle unloading stylesheets!) let mut rw_data = self.lock_rw_data(possibly_locked_rw_data); - 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); } @@ -1306,6 +1363,32 @@ impl LayoutTask { &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, data: &Reflow, 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) .to_gfx_color() } + diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index a510dd544cf..4cec46c7814 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -100,6 +100,7 @@ pub enum ReflowReason { DocumentLoaded, ImageLoaded, RequestAnimationFrame, + WebFontLoaded, } pub type ScrollPoint = Point2D<Au>; @@ -1378,6 +1379,7 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason: ReflowReason::DocumentLoaded => "\tDocumentLoaded", ReflowReason::ImageLoaded => "\tImageLoaded", ReflowReason::RequestAnimationFrame => "\tRequestAnimationFrame", + ReflowReason::WebFontLoaded => "\tWebFontLoaded", }); println!("{}", debug_msg); diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index 9a461a4b1b0..702cce2d0b0 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -51,6 +51,9 @@ pub enum Msg { /// Requests that the layout task render the next frame of all animations. 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 /// for. SetVisibleRects(Vec<(LayerId, Rect<Au>)>), @@ -76,6 +79,10 @@ pub enum Msg { /// Get the last epoch counter for this layout task. 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. /// /// This basically exists to keep the script-layout dependency one-way. diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 30684e0ee00..a935e4b91f5 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -942,6 +942,8 @@ impl ScriptTask { self.handle_webdriver_msg(pipeline_id, msg), ConstellationControlMsg::TickAllAnimations(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) => { responder.respond(); self.handle_resource_loaded(id, LoadType::Stylesheet(url)); @@ -1478,6 +1480,15 @@ impl ScriptTask { 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 /// objects, parses HTML and CSS, and kicks off initial layout. fn load(&self, metadata: Metadata, incomplete: InProgressLoad) -> Root<ServoHTMLParser> { diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 8bea026d706..ba0f25d42e0 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -58,6 +58,9 @@ pub enum LayoutControlMsg { TickAnimations, /// Informs layout as to which regions of the page are visible. 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. @@ -99,7 +102,7 @@ pub enum ScriptState { DocumentLoading, } -/// Messages sent from the constellation to the script task +/// Messages sent from the constellation or layout to the script task. pub enum ConstellationControlMsg { /// Gives a channel and ID to a layout task, as well as the ID of that layout's parent AttachLayout(NewLayoutInfo), @@ -133,6 +136,9 @@ pub enum ConstellationControlMsg { WebDriverScriptCommand(PipelineId, WebDriverScriptCommand), /// Notifies script task that all animations are done 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. StylesheetLoadComplete(PipelineId, Url, Box<StylesheetLoadResponder + Send>), /// Get the current state of the script task for a given pipeline. diff --git a/components/util/geometry.rs b/components/util/geometry.rs index fb39cfd9919..d14b1808f83 100644 --- a/components/util/geometry.rs +++ b/components/util/geometry.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cssparser::ToCss; -use euclid::length::Length; use euclid::num::Zero; use euclid::point::Point2D; use euclid::rect::Rect; @@ -205,29 +204,12 @@ impl Au { Au((px * AU_PER_PX) as i32) } - #[inline] - pub fn from_page_px(px: Length<PagePx, f32>) -> Au { - Au((px.get() * (AU_PER_PX as f32)) as i32) - } - /// Rounds this app unit down to the pixel towards zero and returns it. #[inline] pub fn to_px(self) -> i32 { self.0 / AU_PER_PX } - /// Rounds this app unit down to the previous (left or top) pixel and returns it. - #[inline] - pub fn to_prev_px(self) -> i32 { - ((self.0 as f64) / (AU_PER_PX as f64)).floor() as i32 - } - - /// Rounds this app unit up to the next (right or bottom) pixel and returns it. - #[inline] - pub fn to_next_px(self) -> i32 { - ((self.0 as f64) / (AU_PER_PX as f64)).ceil() as i32 - } - #[inline] pub fn to_nearest_px(self) -> i32 { ((self.0 as f64) / (AU_PER_PX as f64)).round() as i32 @@ -249,38 +231,16 @@ impl Au { } #[inline] - pub fn to_snapped(self) -> Au { - let res = self.0 % AU_PER_PX; - return if res >= 30i32 { return Au(self.0 - res + AU_PER_PX) } - else { return Au(self.0 - res) }; - } - - #[inline] pub fn from_f32_px(px: f32) -> Au { Au((px * (AU_PER_PX as f32)) as i32) } #[inline] - pub fn from_pt(pt: f64) -> Au { - Au::from_f64_px(pt_to_px(pt)) - } - - #[inline] pub fn from_f64_px(px: f64) -> Au { Au((px * (AU_PER_PX as f64)) as i32) } } -// assumes 72 points per inch, and 96 px per inch -pub fn pt_to_px(pt: f64) -> f64 { - pt / 72. * 96. -} - -// assumes 72 points per inch, and 96 px per inch -pub fn px_to_pt(px: f64) -> f64 { - px / 96. * 72. -} - /// Returns true if the rect contains the given point. Points on the top or left sides of the rect /// are considered inside the rectangle, while points on the right or bottom sides of the rect are /// not considered inside the rectangle. |