diff options
Diffstat (limited to 'components/script/page.rs')
-rw-r--r-- | components/script/page.rs | 55 |
1 files changed, 53 insertions, 2 deletions
diff --git a/components/script/page.rs b/components/script/page.rs index 4e87ebe9050..b150804b5d3 100644 --- a/components/script/page.rs +++ b/components/script/page.rs @@ -19,19 +19,21 @@ use layout_interface::{ }; use script_traits::{UntrustedNodeAddress, ScriptControlChan}; -use geom::{Point2D, Rect}; +use geom::{Point2D, Rect, Size2D}; use js::rust::Cx; use servo_msg::compositor_msg::PerformingLayout; use servo_msg::compositor_msg::ScriptListener; use servo_msg::constellation_msg::{ConstellationChan, WindowSizeData}; use servo_msg::constellation_msg::{PipelineId, SubpageId}; use servo_net::resource_task::ResourceTask; -use servo_util::geometry::Au; +use servo_util::geometry::{Au, MAX_RECT}; +use servo_util::geometry; use servo_util::str::DOMString; use servo_util::smallvec::{SmallVec1, SmallVec}; use std::cell::Cell; use std::comm::{channel, Receiver, Empty, Disconnected}; use std::mem::replace; +use std::num::abs; use std::rc::Rc; use url::Url; @@ -98,6 +100,10 @@ pub struct Page { /// Number of unnecessary potential reflows that were skipped since the last reflow pub avoided_reflows: Cell<int>, + + /// An enlarged rectangle around the page contents visible in the viewport, used + /// to prevent creating display list items for content that is far away from the viewport. + pub page_clip_rect: Cell<Rect<Au>>, } pub struct PageIterator { @@ -164,6 +170,7 @@ impl Page { damaged: Cell::new(false), pending_reflows: Cell::new(0), avoided_reflows: Cell::new(0), + page_clip_rect: Cell::new(MAX_RECT), } } @@ -236,6 +243,49 @@ impl Page { } None } + + fn should_move_clip_rect(&self, clip_rect: Rect<Au>, new_viewport: Rect<f32>) -> bool{ + let clip_rect = Rect(Point2D(geometry::to_frac_px(clip_rect.origin.x) as f32, + geometry::to_frac_px(clip_rect.origin.y) as f32), + Size2D(geometry::to_frac_px(clip_rect.size.width) as f32, + geometry::to_frac_px(clip_rect.size.height) as f32)); + + // We only need to move the clip rect if the viewport is getting near the edge of + // our preexisting clip rect. We use half of the size of the viewport as a heuristic + // for "close." + static VIEWPORT_SCROLL_MARGIN_SIZE: f32 = 0.5; + let viewport_scroll_margin = new_viewport.size * VIEWPORT_SCROLL_MARGIN_SIZE; + + abs(clip_rect.origin.x - new_viewport.origin.x) <= viewport_scroll_margin.width || + abs(clip_rect.max_x() - new_viewport.max_x()) <= viewport_scroll_margin.width || + abs(clip_rect.origin.y - new_viewport.origin.y) <= viewport_scroll_margin.height || + abs(clip_rect.max_y() - new_viewport.max_y()) <= viewport_scroll_margin.height + } + + pub fn set_page_clip_rect_with_new_viewport(&self, viewport: Rect<f32>) -> bool { + // We use a clipping rectangle that is five times the size of the of the viewport, + // so that we don't collect display list items for areas too far outside the viewport, + // but also don't trigger reflows every time the viewport changes. + static VIEWPORT_EXPANSION: f32 = 2.0; // 2 lengths on each side plus original length is 5 total. + let proposed_clip_rect = geometry::f32_rect_to_au_rect( + viewport.inflate(viewport.size.width * VIEWPORT_EXPANSION, + viewport.size.height * VIEWPORT_EXPANSION)); + let clip_rect = self.page_clip_rect.get(); + if proposed_clip_rect == clip_rect { + return false; + } + + let had_clip_rect = clip_rect != MAX_RECT; + if had_clip_rect && !self.should_move_clip_rect(clip_rect, viewport) { + return false; + } + + self.page_clip_rect.set(proposed_clip_rect); + + // If we didn't have a clip rect, the previous display doesn't need rebuilding + // because it was built for infinite clip (MAX_RECT). + had_clip_rect + } } impl Iterator<Rc<Page>> for PageIterator { @@ -375,6 +425,7 @@ impl Page { script_join_chan: join_chan, id: last_reflow_id.get(), query_type: query_type, + page_clip_rect: self.page_clip_rect.get(), }; let LayoutChan(ref chan) = self.layout_chan; |