aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/gfx/display_list/mod.rs10
-rw-r--r--components/gfx/paint_context.rs75
-rw-r--r--components/gfx/paint_task.rs4
-rw-r--r--components/script/dom/bindings/trace.rs3
-rw-r--r--components/script/dom/htmlimageelement.rs9
-rw-r--r--components/script/dom/window.rs19
-rw-r--r--components/script/script_task.rs39
7 files changed, 108 insertions, 51 deletions
diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs
index 7273c73d254..3f03ecf88ef 100644
--- a/components/gfx/display_list/mod.rs
+++ b/components/gfx/display_list/mod.rs
@@ -705,9 +705,9 @@ impl StackingContext {
inverse_transform.m21, inverse_transform.m22,
inverse_transform.m41, inverse_transform.m42);
- let tile_size = Size2D::new(paint_context.screen_rect.size.width as f32,
- paint_context.screen_rect.size.height as f32);
- let tile_rect = Rect::new(Point2D::zero(), tile_size);
+ let tile_size = Size2D::new(paint_context.screen_rect.as_f32().size.width,
+ paint_context.screen_rect.as_f32().size.height);
+ let tile_rect = Rect::new(Point2D::zero(), tile_size).to_untyped();
let tile_rect = inverse_transform_2d.transform_rect(&tile_rect);
// Optimize the display list to throw out out-of-bounds display items and so forth.
@@ -1493,11 +1493,11 @@ impl DisplayItem {
transform.translate(stacking_context.bounds
.origin
.x
- .to_nearest_pixel(pixels_per_px) as AzFloat,
+ .to_nearest_pixel(pixels_per_px.get()) as AzFloat,
stacking_context.bounds
.origin
.y
- .to_nearest_pixel(pixels_per_px) as AzFloat,
+ .to_nearest_pixel(pixels_per_px.get()) as AzFloat,
0.0);
stacking_context.optimize_and_draw_into_context(paint_context,
&new_transform,
diff --git a/components/gfx/paint_context.rs b/components/gfx/paint_context.rs
index 039ffa15918..b579688e33f 100644
--- a/components/gfx/paint_context.rs
+++ b/components/gfx/paint_context.rs
@@ -20,7 +20,8 @@ use display_list::{BLUR_INFLATION_FACTOR, BorderRadii, BoxShadowClipMode, Clippi
use display_list::{TextDisplayItem};
use euclid::matrix2d::Matrix2D;
use euclid::point::Point2D;
-use euclid::rect::Rect;
+use euclid::rect::{Rect, TypedRect};
+use euclid::scale_factor::ScaleFactor;
use euclid::side_offsets::SideOffsets2D;
use euclid::size::Size2D;
use filters;
@@ -35,7 +36,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, MAX_RECT, ZERO_POINT, ZERO_RECT};
+use util::geometry::{self, MAX_RECT, PagePx, ScreenPx, ZERO_POINT, ZERO_RECT};
use util::opts;
use util::range::Range;
@@ -43,9 +44,9 @@ pub struct PaintContext<'a> {
pub draw_target: DrawTarget,
pub font_context: &'a mut Box<FontContext>,
/// The rectangle that this context encompasses in page coordinates.
- pub page_rect: Rect<f32>,
+ pub page_rect: TypedRect<PagePx, f32>,
/// The rectangle that this context encompasses in screen coordinates (pixels).
- pub screen_rect: Rect<usize>,
+ pub screen_rect: TypedRect<ScreenPx, usize>,
/// The clipping rect for the stacking context as a whole.
pub clip_rect: Option<Rect<Au>>,
/// The current transient clipping region, if any. A "transient clipping region" is the
@@ -119,8 +120,8 @@ struct CornerOrigin {
}
impl<'a> PaintContext<'a> {
- pub fn screen_pixels_per_px(&self) -> f32 {
- self.screen_rect.size.width as f32 / self.page_rect.size.width
+ pub fn screen_pixels_per_px(&self) -> ScaleFactor<PagePx, ScreenPx, f32> {
+ self.screen_rect.as_f32().size.width / self.page_rect.size.width
}
pub fn draw_target(&self) -> &DrawTarget {
@@ -269,10 +270,12 @@ impl<'a> PaintContext<'a> {
pub fn clear(&self) {
let pattern = ColorPattern::new(color::transparent());
- let rect = Rect::new(Point2D::new(self.page_rect.origin.x as AzFloat,
- self.page_rect.origin.y as AzFloat),
- Size2D::new(self.screen_rect.size.width as AzFloat,
- self.screen_rect.size.height as AzFloat));
+ let page_rect = self.page_rect.to_untyped();
+ let screen_rect = self.screen_rect.to_untyped();
+ let rect = Rect::new(Point2D::new(page_rect.origin.x as AzFloat,
+ page_rect.origin.y as AzFloat),
+ Size2D::new(screen_rect.size.width as AzFloat,
+ screen_rect.size.height as AzFloat));
let mut draw_options = DrawOptions::new(1.0, CompositionOp::Over, AntialiasMode::None);
draw_options.set_composition_op(CompositionOp::Source);
self.draw_target.make_current();
@@ -1577,7 +1580,7 @@ impl<'a> PaintContext<'a> {
// smallest possible rectangle that encompasses all the paint.
let side_inflation = blur_radius * BLUR_INFLATION_FACTOR;
let tile_box_bounds =
- geometry::f32_rect_to_au_rect(self.page_rect).intersection(box_bounds)
+ geometry::f32_rect_to_au_rect(self.page_rect.to_untyped()).intersection(box_bounds)
.unwrap_or(ZERO_RECT)
.inflate(side_inflation, side_inflation);
TemporaryDrawTarget::from_bounds(&self.draw_target, &tile_box_bounds)
@@ -1635,14 +1638,14 @@ impl<'a> PaintContext<'a> {
}
pub trait ToAzurePoint {
- fn to_nearest_azure_point(&self, pixels_per_px: f32) -> Point2D<AzFloat>;
+ fn to_nearest_azure_point(&self, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> Point2D<AzFloat>;
fn to_azure_point(&self) -> Point2D<AzFloat>;
}
impl ToAzurePoint for Point2D<Au> {
- fn to_nearest_azure_point(&self, pixels_per_px: f32) -> Point2D<AzFloat> {
- Point2D::new(self.x.to_nearest_pixel(pixels_per_px) as AzFloat,
- self.y.to_nearest_pixel(pixels_per_px) as AzFloat)
+ fn to_nearest_azure_point(&self, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> Point2D<AzFloat> {
+ Point2D::new(self.x.to_nearest_pixel(pixels_per_px.get()) as AzFloat,
+ self.y.to_nearest_pixel(pixels_per_px.get()) as AzFloat)
}
fn to_azure_point(&self) -> Point2D<AzFloat> {
Point2D::new(self.x.to_f32_px(), self.y.to_f32_px())
@@ -1650,8 +1653,8 @@ impl ToAzurePoint for Point2D<Au> {
}
pub trait ToAzureRect {
- fn to_nearest_azure_rect(&self, pixels_per_px: f32) -> Rect<AzFloat>;
- fn to_nearest_non_empty_azure_rect(&self, pixels_per_px: f32) -> Rect<AzFloat>;
+ fn to_nearest_azure_rect(&self, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> Rect<AzFloat>;
+ fn to_nearest_non_empty_azure_rect(&self, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> Rect<AzFloat>;
fn to_azure_rect(&self) -> Rect<AzFloat>;
}
@@ -1659,7 +1662,7 @@ impl ToAzureRect for Rect<Au> {
/// Round rects to pixel coordinates, maintaining the invariant of non-overlap,
/// assuming that before rounding rects don't overlap.
- fn to_nearest_azure_rect(&self, pixels_per_px: f32) -> Rect<AzFloat> {
+ fn to_nearest_azure_rect(&self, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> Rect<AzFloat> {
// Rounding the top left corner to the nearest pixel with the size rounded
// to the nearest pixel multiple would violate the non-overlap condition,
// e.g.
@@ -1679,7 +1682,7 @@ impl ToAzureRect for Rect<Au> {
/// 10px×0.6px at 0px,28.56px -> 10px×0px at 0px,29px
/// Instead round the top left to the nearest pixel and the size to the nearest pixel
/// multiple. It's possible for non-overlapping rects after this rounding to overlap.
- fn to_nearest_non_empty_azure_rect(&self, pixels_per_px: f32) -> Rect<AzFloat> {
+ fn to_nearest_non_empty_azure_rect(&self, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> Rect<AzFloat> {
Rect::new(self.origin.to_nearest_azure_point(pixels_per_px),
self.size.to_nearest_azure_size(pixels_per_px))
}
@@ -1690,13 +1693,13 @@ impl ToAzureRect for Rect<Au> {
}
pub trait ToNearestAzureSize {
- fn to_nearest_azure_size(&self, pixels_per_px: f32) -> Size2D<AzFloat>;
+ fn to_nearest_azure_size(&self, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> Size2D<AzFloat>;
}
impl ToNearestAzureSize for Size2D<Au> {
- fn to_nearest_azure_size(&self, pixels_per_px: f32) -> Size2D<AzFloat> {
- Size2D::new(self.width.to_nearest_pixel(pixels_per_px) as AzFloat,
- self.height.to_nearest_pixel(pixels_per_px) as AzFloat)
+ fn to_nearest_azure_size(&self, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> Size2D<AzFloat> {
+ Size2D::new(self.width.to_nearest_pixel(pixels_per_px.get()) as AzFloat,
+ self.height.to_nearest_pixel(pixels_per_px.get()) as AzFloat)
}
}
@@ -1727,26 +1730,26 @@ impl ToAzureIntSize for Size2D<AzFloat> {
}
trait ToSideOffsetsPixels {
- fn to_float_pixels(&self, pixels_per_px: f32) -> SideOffsets2D<AzFloat>;
+ fn to_float_pixels(&self, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> SideOffsets2D<AzFloat>;
}
impl ToSideOffsetsPixels for SideOffsets2D<Au> {
- fn to_float_pixels(&self, pixels_per_px: f32) -> SideOffsets2D<AzFloat> {
- SideOffsets2D::new(self.top.to_nearest_pixel(pixels_per_px) as AzFloat,
- self.right.to_nearest_pixel(pixels_per_px) as AzFloat,
- self.bottom.to_nearest_pixel(pixels_per_px) as AzFloat,
- self.left.to_nearest_pixel(pixels_per_px) as AzFloat)
+ fn to_float_pixels(&self, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> SideOffsets2D<AzFloat> {
+ SideOffsets2D::new(self.top.to_nearest_pixel(pixels_per_px.get()) as AzFloat,
+ self.right.to_nearest_pixel(pixels_per_px.get()) as AzFloat,
+ self.bottom.to_nearest_pixel(pixels_per_px.get()) as AzFloat,
+ self.left.to_nearest_pixel(pixels_per_px.get()) as AzFloat)
}
}
trait ToRadiiPixels {
- fn to_radii_pixels(&self, pixels_per_px: f32) -> BorderRadii<AzFloat>;
+ fn to_radii_pixels(&self, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> BorderRadii<AzFloat>;
}
impl ToRadiiPixels for BorderRadii<Au> {
- fn to_radii_pixels(&self, pixels_per_px: f32) -> BorderRadii<AzFloat> {
+ fn to_radii_pixels(&self, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> BorderRadii<AzFloat> {
let to_nearest_px = |x: Au| -> AzFloat {
- x.to_nearest_pixel(pixels_per_px) as AzFloat
+ x.to_nearest_pixel(pixels_per_px.get()) as AzFloat
};
BorderRadii {
@@ -1846,17 +1849,17 @@ trait DrawTargetExtensions {
fn create_rectangular_border_path(&self,
outer_rect: &Rect<Au>,
inner_rect: &Rect<Au>,
- pixels_per_px: f32) -> Path;
+ pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> Path;
/// Creates and returns a path that represents a rectangle.
- fn create_rectangular_path(&self, rect: &Rect<Au>, pixels_per_px: f32) -> Path;
+ fn create_rectangular_path(&self, rect: &Rect<Au>, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> Path;
}
impl DrawTargetExtensions for DrawTarget {
fn create_rectangular_border_path(&self,
outer_rect: &Rect<Au>,
inner_rect: &Rect<Au>,
- pixels_per_px: f32) -> Path {
+ pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> Path {
// +-----------+
// |2 |1
// | |
@@ -1885,7 +1888,7 @@ impl DrawTargetExtensions for DrawTarget {
path_builder.finish()
}
- fn create_rectangular_path(&self, rect: &Rect<Au>, pixels_per_px: f32) -> Path {
+ fn create_rectangular_path(&self, rect: &Rect<Au>, pixels_per_px: ScaleFactor<PagePx, ScreenPx, f32>) -> Path {
// Explicitly round to the nearest non-empty rect because when drawing
// box-shadow the rect height can be between 0.5px & 1px and could
// otherwise round to an empty rect.
diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs
index 331c25a0be2..cd996c5b8f2 100644
--- a/components/gfx/paint_task.rs
+++ b/components/gfx/paint_task.rs
@@ -681,8 +681,8 @@ impl WorkerThread {
let mut paint_context = PaintContext {
draw_target: draw_target.clone(),
font_context: &mut self.font_context,
- page_rect: tile.page_rect,
- screen_rect: tile.screen_rect,
+ page_rect: Rect::from_untyped(&tile.page_rect),
+ screen_rect: Rect::from_untyped(&tile.screen_rect),
clip_rect: None,
transient_clip: None,
layer_kind: layer_kind,
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index df5c84d3778..48f6ed39032 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -79,6 +79,7 @@ use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
use std::sync::mpsc::{Receiver, Sender};
use string_cache::{Atom, Namespace};
use style::properties::PropertyDeclarationBlock;
@@ -246,7 +247,7 @@ impl<A: JSTraceable, B: JSTraceable> JSTraceable for (A, B) {
}
-no_jsmanaged_fields!(bool, f32, f64, String, Url);
+no_jsmanaged_fields!(bool, f32, f64, String, Url, AtomicBool);
no_jsmanaged_fields!(usize, u8, u16, u32, u64);
no_jsmanaged_fields!(isize, i8, i16, i32, i64);
no_jsmanaged_fields!(Sender<T>);
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index 098938c8285..e05a50e6027 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -110,13 +110,16 @@ impl HTMLImageElement {
let trusted_node = Trusted::new(window.get_cx(), self, window.script_chan());
let (responder_sender, responder_receiver) = ipc::channel().unwrap();
let script_chan = window.script_chan();
+ let wrapper = window.get_runnable_wrapper();
ROUTER.add_route(responder_receiver.to_opaque(), box move |message| {
// Return the image via a message to the script task, which marks the element
// as dirty and triggers a reflow.
let image_response = message.to().unwrap();
- script_chan.send(CommonScriptMsg::RunnableMsg(UpdateReplacedElement,
- box ImageResponseHandlerRunnable::new(
- trusted_node.clone(), image_response))).unwrap();
+ let runnable = ImageResponseHandlerRunnable::new(
+ trusted_node.clone(), image_response);
+ let runnable = wrapper.wrap_runnable(runnable);
+ script_chan.send(CommonScriptMsg::RunnableMsg(
+ UpdateReplacedElement, runnable)).unwrap();
});
image_cache.request_image(img_url,
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 93b8741f243..e296cea77d5 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -53,7 +53,7 @@ use num::traits::ToPrimitive;
use page::Page;
use profile_traits::mem;
use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64};
-use script_task::{ScriptChan, ScriptPort, MainThreadScriptMsg};
+use script_task::{ScriptChan, ScriptPort, MainThreadScriptMsg, RunnableWrapper};
use script_task::{SendableMainThreadScriptChan, MainThreadScriptChan, MainThreadTimerEventChan};
use script_traits::{TimerEventChan, TimerEventId, TimerEventRequest, TimerSource};
use selectors::parser::PseudoElement;
@@ -66,6 +66,7 @@ use std::ffi::CString;
use std::io::{Write, stderr, stdout};
use std::rc::Rc;
use std::sync::Arc;
+use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::TryRecvError::{Disconnected, Empty};
use std::sync::mpsc::{Sender, channel};
use string_cache::Atom;
@@ -209,7 +210,11 @@ pub struct Window {
/// The current state of the window object
current_state: Cell<WindowState>,
- current_viewport: Cell<Rect<Au>>
+ current_viewport: Cell<Rect<Au>>,
+
+ /// A flag to prevent async events from attempting to interact with this window.
+ #[ignore_heap_size_of = "defined in std"]
+ ignore_further_async_events: Arc<AtomicBool>,
}
impl Window {
@@ -219,6 +224,7 @@ impl Window {
*self.js_runtime.borrow_for_script_deallocation() = None;
self.browsing_context.set(None);
self.current_state.set(WindowState::Zombie);
+ self.ignore_further_async_events.store(true, Ordering::Relaxed);
}
}
@@ -781,6 +787,12 @@ impl<'a, T: Reflectable> ScriptHelpers for &'a T {
}
impl Window {
+ pub fn get_runnable_wrapper(&self) -> RunnableWrapper {
+ RunnableWrapper {
+ cancelled: self.ignore_further_async_events.clone()
+ }
+ }
+
pub fn clear_js_runtime(&self) {
self.Document().upcast::<Node>().teardown();
@@ -798,6 +810,7 @@ impl Window {
self.current_state.set(WindowState::Zombie);
*self.js_runtime.borrow_mut() = None;
self.browsing_context.set(None);
+ self.ignore_further_async_events.store(true, Ordering::Relaxed);
}
/// https://drafts.csswg.org/cssom-view/#dom-window-scroll
@@ -1258,6 +1271,8 @@ impl Window {
devtools_markers: DOMRefCell::new(HashSet::new()),
devtools_wants_updates: Cell::new(false),
webdriver_script_chan: DOMRefCell::new(None),
+
+ ignore_further_async_events: Arc::new(AtomicBool::new(false)),
};
WindowBinding::Wrap(runtime.cx(), win)
diff --git a/components/script/script_task.rs b/components/script/script_task.rs
index ac67e4a5996..dda6faaa85b 100644
--- a/components/script/script_task.rs
+++ b/components/script/script_task.rs
@@ -95,6 +95,7 @@ use std::option::Option;
use std::ptr;
use std::rc::Rc;
use std::result::Result;
+use std::sync::atomic::{Ordering, AtomicBool};
use std::sync::mpsc::{Receiver, Select, Sender, channel};
use std::sync::{Arc, Mutex};
use string_cache::Atom;
@@ -158,7 +159,38 @@ impl InProgressLoad {
}
}
+/// Encapsulated state required to create cancellable runnables from non-script threads.
+pub struct RunnableWrapper {
+ pub cancelled: Arc<AtomicBool>,
+}
+
+impl RunnableWrapper {
+ pub fn wrap_runnable<T: Runnable + Send + 'static>(&self, runnable: T) -> Box<Runnable + Send> {
+ box CancellableRunnable {
+ cancelled: self.cancelled.clone(),
+ inner: box runnable,
+ }
+ }
+}
+
+/// A runnable that can be discarded by toggling a shared flag.
+pub struct CancellableRunnable<T: Runnable + Send> {
+ cancelled: Arc<AtomicBool>,
+ inner: Box<T>,
+}
+
+impl<T: Runnable + Send> Runnable for CancellableRunnable<T> {
+ fn is_cancelled(&self) -> bool {
+ self.cancelled.load(Ordering::Relaxed)
+ }
+
+ fn handler(self: Box<CancellableRunnable<T>>) {
+ self.inner.handler()
+ }
+}
+
pub trait Runnable {
+ fn is_cancelled(&self) -> bool { false }
fn handler(self: Box<Self>);
}
@@ -990,10 +1022,13 @@ impl ScriptTask {
runnable.handler(self),
MainThreadScriptMsg::DocumentLoadsComplete(id) =>
self.handle_loads_complete(id),
- MainThreadScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable)) =>
+ MainThreadScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable)) => {
// The category of the runnable is ignored by the pattern, however
// it is still respected by profiling (see categorize_msg).
- runnable.handler(),
+ if !runnable.is_cancelled() {
+ runnable.handler()
+ }
+ }
MainThreadScriptMsg::Common(CommonScriptMsg::RefcountCleanup(addr)) =>
LiveDOMReferences::cleanup(addr),
MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan)) =>