diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 621068824c4..5865b36a20a 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -17,7 +17,7 @@ #![deny(unsafe_code)] use display_list::optimizer::DisplayListOptimizer; -use paint_context::{PaintContext, ToAzureRect}; +use paint_context::PaintContext; use self::DisplayItem::*; use self::DisplayItemIterator::*; use text::glyph::CharIndex; @@ -286,22 +286,15 @@ impl StackingContext { pub fn draw_into_context(&self, display_list: &DisplayList, paint_context: &mut PaintContext, - tile_bounds: &Rect, transform: &Matrix4, clip_rect: Option<&Rect>) { - // If a layer is being used, the transform for this layer - // will be handled by the compositor. - let transform = match self.layer { - Some(..) => *transform, - None => transform.mul(&self.transform), - }; let temporary_draw_target = paint_context.get_or_create_temporary_draw_target(&self.filters, self.blend_mode); { let mut paint_subcontext = PaintContext { draw_target: temporary_draw_target.clone(), font_context: &mut *paint_context.font_context, - page_rect: *tile_bounds, + page_rect: paint_context.page_rect, screen_rect: paint_context.screen_rect, clip_rect: clip_rect.map(|clip_rect| *clip_rect), transient_clip: None, @@ -309,14 +302,16 @@ impl StackingContext { }; if opts::get().dump_display_list_optimized { - println!("**** optimized display list. Tile bounds: {:?}", tile_bounds); + println!("**** optimized display list. Tile bounds: {:?}", paint_context.page_rect); display_list.print_items("*".to_owned()); } // Sort positioned children according to z-index. let mut positioned_children: SmallVec<[Arc; 8]> = SmallVec::new(); for kid in display_list.children.iter() { - positioned_children.push((*kid).clone()); + if kid.layer.is_none() { + positioned_children.push((*kid).clone()); + } } positioned_children.sort_by(|this, other| this.z_index.cmp(&other.z_index)); @@ -338,25 +333,19 @@ impl StackingContext { if positioned_kid.z_index >= 0 { break } - if positioned_kid.layer.is_none() { - let new_transform = - transform.translate(positioned_kid.bounds - .origin - .x - .to_nearest_px() as AzFloat, - positioned_kid.bounds - .origin - .y - .to_nearest_px() as AzFloat, - 0.0); - let new_tile_rect = - self.compute_tile_rect_for_child_stacking_context(tile_bounds, - &**positioned_kid); - positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext, - &new_tile_rect, - &new_transform, - Some(&positioned_kid.overflow)) - } + let new_transform = + transform.translate(positioned_kid.bounds + .origin + .x + .to_nearest_px() as AzFloat, + positioned_kid.bounds + .origin + .y + .to_nearest_px() as AzFloat, + 0.0); + positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext, + &new_transform, + Some(&positioned_kid.overflow)) } // Step 4: Block backgrounds and borders. @@ -386,26 +375,19 @@ impl StackingContext { if positioned_kid.z_index < 0 { continue } - - if positioned_kid.layer.is_none() { - let new_transform = - transform.translate(positioned_kid.bounds - .origin - .x - .to_nearest_px() as AzFloat, - positioned_kid.bounds - .origin - .y - .to_nearest_px() as AzFloat, - 0.0); - let new_tile_rect = - self.compute_tile_rect_for_child_stacking_context(tile_bounds, - &**positioned_kid); - positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext, - &new_tile_rect, - &new_transform, - Some(&positioned_kid.overflow)) - } + let new_transform = + transform.translate(positioned_kid.bounds + .origin + .x + .to_nearest_px() as AzFloat, + positioned_kid.bounds + .origin + .y + .to_nearest_px() as AzFloat, + 0.0); + positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext, + &new_transform, + Some(&positioned_kid.overflow)) } // Step 10: Outlines. @@ -428,62 +410,47 @@ impl StackingContext { /// Optionally optimize and then draws the stacking context. pub fn optimize_and_draw_into_context(&self, paint_context: &mut PaintContext, - tile_bounds: &Rect, transform: &Matrix4, clip_rect: Option<&Rect>) { + + // If a layer is being used, the transform for this layer + // will be handled by the compositor. + let transform = match self.layer { + Some(..) => *transform, + None => transform.mul(&self.transform), + }; + // TODO(gw): This is a hack to avoid running the DL optimizer // on 3d transformed tiles. We should have a better solution // than just disabling the opts here. if paint_context.layer_kind == LayerKind::Layer3D { self.draw_into_context(&self.display_list, paint_context, - tile_bounds, - transform, + &transform, clip_rect); } else { + // Invert the current transform, then use this to back transform + // the tile rect (placed at the origin) into the space of this + // stacking context. + let inverse_transform = transform.invert(); + let inverse_transform_2d = Matrix2D::new(inverse_transform.m11, inverse_transform.m12, + inverse_transform.m21, inverse_transform.m22, + inverse_transform.m41, inverse_transform.m42); + + let tile_rect = Rect::new(Point2D::zero(), paint_context.page_rect.size); + 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. - let display_list = - DisplayListOptimizer::new(tile_bounds).optimize(&*self.display_list); + let display_list = DisplayListOptimizer::new(&tile_rect).optimize(&*self.display_list); self.draw_into_context(&display_list, paint_context, - tile_bounds, - transform, + &transform, clip_rect); } } - /// Translate the given tile rect into the coordinate system of a child stacking context. - fn compute_tile_rect_for_child_stacking_context(&self, - tile_bounds: &Rect, - child_stacking_context: &StackingContext) - -> Rect { - static ZERO_AZURE_RECT: Rect = Rect { - origin: Point2D { - x: 0.0, - y: 0.0, - }, - size: Size2D { - width: 0.0, - height: 0.0 - } - }; - - // Translate the child's overflow region into our coordinate system. - let child_stacking_context_overflow = - child_stacking_context.overflow.translate(&child_stacking_context.bounds.origin) - .to_nearest_azure_rect(); - - // Intersect that with the current tile boundaries to find the tile boundaries that the - // child covers. - let tile_subrect = tile_bounds.intersection(&child_stacking_context_overflow) - .unwrap_or(ZERO_AZURE_RECT); - - // Translate the resulting rect into the child's coordinate system. - tile_subrect.translate(&-child_stacking_context.bounds.to_nearest_azure_rect().origin) - } - /// Places all nodes containing the point of interest into `result`, topmost first. Respects /// the `pointer-events` CSS property If `topmost_only` is true, stops after placing one node /// into the list. `result` must be empty upon entry to this function. diff --git a/components/gfx/display_list/optimizer.rs b/components/gfx/display_list/optimizer.rs index e6788d3642c..37661ce6402 100644 --- a/components/gfx/display_list/optimizer.rs +++ b/components/gfx/display_list/optimizer.rs @@ -8,6 +8,7 @@ use display_list::{DisplayItem, DisplayList, StackingContext}; use std::collections::linked_list::LinkedList; use euclid::rect::Rect; +use euclid::{Matrix2D, Matrix4}; use util::geometry::{self, Au}; use std::sync::Arc; @@ -62,9 +63,27 @@ impl DisplayListOptimizer { stacking_contexts: I) where I: Iterator> { for stacking_context in stacking_contexts { - let overflow = stacking_context.overflow.translate(&stacking_context.bounds.origin); - if self.visible_rect.intersects(&overflow) { - result_list.push_back((*stacking_context).clone()) + if stacking_context.layer.is_none() { + // Transform this stacking context to get it into the same space as + // the parent stacking context. + let origin_x = stacking_context.bounds.origin.x.to_f32_px(); + let origin_y = stacking_context.bounds.origin.y.to_f32_px(); + + let transform = Matrix4::identity().translate(origin_x, + origin_y, + 0.0) + .mul(&stacking_context.transform); + let transform_2d = Matrix2D::new(transform.m11, transform.m12, + transform.m21, transform.m22, + transform.m41, transform.m42); + + let overflow = geometry::au_rect_to_f32_rect(stacking_context.overflow); + let overflow = transform_2d.transform_rect(&overflow); + let overflow = geometry::f32_rect_to_au_rect(overflow); + + if self.visible_rect.intersects(&overflow) { + result_list.push_back((*stacking_context).clone()) + } } } } diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs index 39f0ace7155..75b93a081c9 100644 --- a/components/gfx/paint_task.rs +++ b/components/gfx/paint_task.rs @@ -602,7 +602,6 @@ impl WorkerThread { self.time_profiler_sender.clone(), || { stacking_context.optimize_and_draw_into_context(&mut paint_context, - &tile_bounds, &matrix, None); paint_context.draw_target.flush(); diff --git a/components/util/geometry.rs b/components/util/geometry.rs index 8af8dce27ab..cefc82e53d6 100644 --- a/components/util/geometry.rs +++ b/components/util/geometry.rs @@ -290,3 +290,8 @@ pub fn f32_rect_to_au_rect(rect: Rect) -> Rect { Size2D::new(Au::from_f32_px(rect.size.width), Au::from_f32_px(rect.size.height))) } +/// A helper function to convert a rect of `Au` pixels to a rect of f32 units. +pub fn au_rect_to_f32_rect(rect: Rect) -> Rect { + Rect::new(Point2D::new(rect.origin.x.to_f32_px(), rect.origin.y.to_f32_px()), + Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px())) +} diff --git a/tests/ref/basic.list b/tests/ref/basic.list index 1318c9d6f4d..b8ec45640c5 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -320,6 +320,7 @@ flaky_cpu == linebreak_simple_a.html linebreak_simple_b.html == text_transform_none_a.html text_transform_none_ref.html == text_transform_uppercase_a.html text_transform_uppercase_ref.html == transform_3d.html transform_3d_ref.html +== transform_optimization.html transform_optimization_ref.html == transform_simple_a.html transform_simple_ref.html == transform_stacking_context_a.html transform_stacking_context_ref.html == upper_id_attr.html upper_id_attr_ref.html diff --git a/tests/ref/transform_optimization.html b/tests/ref/transform_optimization.html new file mode 100644 index 00000000000..db2c1ad4181 --- /dev/null +++ b/tests/ref/transform_optimization.html @@ -0,0 +1,29 @@ + + + + + + +
+
+
+
+ + diff --git a/tests/ref/transform_optimization_ref.html b/tests/ref/transform_optimization_ref.html new file mode 100644 index 00000000000..a20d5a1478c --- /dev/null +++ b/tests/ref/transform_optimization_ref.html @@ -0,0 +1,23 @@ + + + + + + +
+
+
+
+ +