aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/compositing/constellation.rs9
-rw-r--r--components/gfx/font_cache_task.rs67
-rw-r--r--components/gfx/font_context.rs37
-rw-r--r--components/gfx/paint_context.rs6
-rw-r--r--components/gfx/platform/macos/font.rs30
-rw-r--r--components/layout/animation.rs4
-rw-r--r--components/layout/layout_task.rs118
-rw-r--r--components/script/dom/window.rs2
-rw-r--r--components/script/layout_interface.rs7
-rw-r--r--components/script/script_task.rs11
-rw-r--r--components/script_traits/lib.rs8
-rw-r--r--components/util/geometry.rs40
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.