diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index f4267c6fbc2..6c001ab310f 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -15,7 +15,7 @@ //! low-level drawing primitives. use azure::azure::AzFloat; -use azure::azure_hl::Color; +use azure::azure_hl::{Color, DrawTarget}; use display_list::optimizer::DisplayListOptimizer; use euclid::approxeq::ApproxEq; use euclid::num::Zero; @@ -97,7 +97,7 @@ pub struct DisplayList { /// Child stacking contexts. pub children: LinkedList>, /// Child PaintLayers that will be rendered on top of everything else. - pub layered_children: LinkedList, + pub layered_children: LinkedList>, } impl DisplayList { @@ -116,27 +116,6 @@ impl DisplayList { } } - /// Sort all children by their z-index and split layered children into their own - /// section of the display list. - /// TODO(mrobinson): This should properly handle unlayered children that are on - /// top of layered children. - #[inline] - pub fn sort_and_layerize_children(&mut self) { - let mut children: SmallVec<[Arc; 8]> = SmallVec::new(); - while let Some(stacking_context) = self.children.pop_front() { - children.push(stacking_context); - } - children.sort_by(|this, other| this.z_index.cmp(&other.z_index)); - - for stacking_context in children.into_iter() { - match stacking_context.layer_id { - Some(layer_id) => self.layered_children.push_back( - PaintLayer::new(layer_id, color::transparent(), stacking_context)), - None => self.children.push_back(stacking_context), - } - } - } - /// Appends all display items from `other` into `self`, preserving stacking order and emptying /// `other` in the process. #[inline] @@ -237,6 +216,113 @@ impl DisplayList { paint_layer.stacking_context.print_with_tree(print_tree); } } + + /// Draws the DisplayList in stacking context order according to the steps in CSS 2.1 ยง E.2. + fn draw_into_context(&self, + draw_target: &DrawTarget, + paint_context: &mut PaintContext, + transform: &Matrix4, + clip_rect: Option<&Rect>) { + let mut paint_subcontext = PaintContext { + draw_target: draw_target.clone(), + font_context: &mut *paint_context.font_context, + page_rect: paint_context.page_rect, + screen_rect: paint_context.screen_rect, + clip_rect: clip_rect.map(|clip_rect| *clip_rect), + transient_clip: None, + layer_kind: paint_context.layer_kind, + }; + + if opts::get().dump_display_list_optimized { + self.print(format!("Optimized display list. Tile bounds: {:?}", + paint_context.page_rect)); + } + + // Set up our clip rect and transform. + let old_transform = paint_subcontext.draw_target.get_transform(); + let xform_2d = Matrix2D::new(transform.m11, transform.m12, + transform.m21, transform.m22, + transform.m41, transform.m42); + paint_subcontext.draw_target.set_transform(&xform_2d); + paint_subcontext.push_clip_if_applicable(); + + // Steps 1 and 2: Borders and background for the root. + for display_item in &self.background_and_borders { + display_item.draw_into_context(&mut paint_subcontext) + } + + // Step 3: Positioned descendants with negative z-indices. + for positioned_kid in &self.children { + if positioned_kid.z_index >= 0 { + break + } + 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. + for display_item in &self.block_backgrounds_and_borders { + display_item.draw_into_context(&mut paint_subcontext) + } + + // Step 5: Floats. + for display_item in &self.floats { + display_item.draw_into_context(&mut paint_subcontext) + } + + // TODO(pcwalton): Step 6: Inlines that generate stacking contexts. + + // Step 7: Content. + for display_item in &self.content { + display_item.draw_into_context(&mut paint_subcontext) + } + + // Step 8: Positioned descendants with `z-index: auto`. + for display_item in &self.positioned_content { + display_item.draw_into_context(&mut paint_subcontext) + } + + // Step 9: Positioned descendants with nonnegative, numeric z-indices. + for positioned_kid in &self.children { + if positioned_kid.z_index < 0 { + continue + } + 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. + for display_item in &self.outlines { + display_item.draw_into_context(&mut paint_subcontext) + } + + // Undo our clipping and transform. + paint_subcontext.remove_transient_clip_if_applicable(); + paint_subcontext.pop_clip_if_applicable(); + paint_subcontext.draw_target.set_transform(&old_transform) + } } #[derive(HeapSizeOf, Deserialize, Serialize)] @@ -341,107 +427,11 @@ impl StackingContext { clip_rect: Option<&Rect>) { 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: paint_context.page_rect, - screen_rect: paint_context.screen_rect, - clip_rect: clip_rect.map(|clip_rect| *clip_rect), - transient_clip: None, - layer_kind: paint_context.layer_kind, - }; - if opts::get().dump_display_list_optimized { - display_list.print(format!("Optimized display list. Tile bounds: {:?}", - paint_context.page_rect)); - } - - // Set up our clip rect and transform. - let old_transform = paint_subcontext.draw_target.get_transform(); - let xform_2d = Matrix2D::new(transform.m11, transform.m12, - transform.m21, transform.m22, - transform.m41, transform.m42); - paint_subcontext.draw_target.set_transform(&xform_2d); - paint_subcontext.push_clip_if_applicable(); - - // Steps 1 and 2: Borders and background for the root. - for display_item in &display_list.background_and_borders { - display_item.draw_into_context(&mut paint_subcontext) - } - - // Step 3: Positioned descendants with negative z-indices. - for positioned_kid in &display_list.children { - if positioned_kid.z_index >= 0 { - break - } - 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. - for display_item in &display_list.block_backgrounds_and_borders { - display_item.draw_into_context(&mut paint_subcontext) - } - - // Step 5: Floats. - for display_item in &display_list.floats { - display_item.draw_into_context(&mut paint_subcontext) - } - - // TODO(pcwalton): Step 6: Inlines that generate stacking contexts. - - // Step 7: Content. - for display_item in &display_list.content { - display_item.draw_into_context(&mut paint_subcontext) - } - - // Step 8: Positioned descendants with `z-index: auto`. - for display_item in &display_list.positioned_content { - display_item.draw_into_context(&mut paint_subcontext) - } - - // Step 9: Positioned descendants with nonnegative, numeric z-indices. - for positioned_kid in &self.display_list.children { - if positioned_kid.z_index < 0 { - continue - } - 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. - for display_item in &display_list.outlines { - display_item.draw_into_context(&mut paint_subcontext) - } - - // Undo our clipping and transform. - paint_subcontext.remove_transient_clip_if_applicable(); - paint_subcontext.pop_clip_if_applicable(); - paint_subcontext.draw_target.set_transform(&old_transform) - } + display_list.draw_into_context(&temporary_draw_target, + paint_context, + transform, + clip_rect); paint_context.draw_temporary_draw_target_if_necessary(&temporary_draw_target, &self.filters, @@ -692,8 +682,8 @@ impl StackingContextLayerCreator { stacking_context.display_list.layered_children.back().unwrap().id.companion_layer_id(); let child_stacking_context = Arc::new(stacking_context.create_layered_child(next_layer_id, display_list)); - stacking_context.display_list.layered_children.push_back( - PaintLayer::new(next_layer_id, color::transparent(), child_stacking_context)); + stacking_context.display_list.layered_children.push_back(Arc::new( + PaintLayer::new(next_layer_id, color::transparent(), child_stacking_context))); self.all_following_children_need_layers = true; } } @@ -704,7 +694,7 @@ impl StackingContextLayerCreator { if let Some(layer_id) = stacking_context.layer_id { self.finish_building_current_layer(parent_stacking_context); parent_stacking_context.display_list.layered_children.push_back( - PaintLayer::new(layer_id, color::transparent(), stacking_context)); + Arc::new(PaintLayer::new(layer_id, color::transparent(), stacking_context))); // We have started processing layered stacking contexts, so any stacking context that // we process from now on needs its own layer to ensure proper rendering order. @@ -722,17 +712,18 @@ impl StackingContextLayerCreator { } /// Returns the stacking context in the given tree of stacking contexts with a specific layer ID. -pub fn find_stacking_context_with_layer_id(this: &Arc, layer_id: LayerId) - -> Option> { +pub fn find_layer_with_layer_id(this: &Arc, + layer_id: LayerId) + -> Option> { for kid in &this.display_list.layered_children { - if let Some(stacking_context) = kid.find_stacking_context_with_layer_id(layer_id) { - return Some(stacking_context); + if let Some(paint_layer) = PaintLayer::find_layer_with_layer_id(&kid, layer_id) { + return Some(paint_layer); } } for kid in &this.display_list.children { - if let Some(stacking_context) = find_stacking_context_with_layer_id(kid, layer_id) { - return Some(stacking_context); + if let Some(paint_layer) = find_layer_with_layer_id(kid, layer_id) { + return Some(paint_layer); } } diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs index b729d311e4e..3c139fafaaa 100644 --- a/components/gfx/paint_task.rs +++ b/components/gfx/paint_task.rs @@ -60,14 +60,14 @@ impl PaintLayer { } } - pub fn find_stacking_context_with_layer_id(&self, - layer_id: LayerId) - -> Option> { - if self.id == layer_id { - return Some(self.stacking_context.clone()); + pub fn find_layer_with_layer_id(this: &Arc, + layer_id: LayerId) + -> Option> { + if this.id == layer_id { + return Some(this.clone()); } - display_list::find_stacking_context_with_layer_id(&self.stacking_context, layer_id) + display_list::find_layer_with_layer_id(&this.stacking_context, layer_id) } } @@ -111,7 +111,7 @@ pub struct PaintTask { time_profiler_chan: time::ProfilerChan, /// The root paint layer sent to us by the layout thread. - root_paint_layer: Option, + root_paint_layer: Option>, /// Permission to send paint messages to the compositor paint_permission: bool, @@ -216,7 +216,7 @@ impl PaintTask where C: PaintListener + Send + 'static { match message { Msg::FromLayout(LayoutToPaintMsg::PaintInit(epoch, paint_layer)) => { self.current_epoch = Some(epoch); - self.root_paint_layer = Some(paint_layer); + self.root_paint_layer = Some(Arc::new(paint_layer)); if !self.paint_permission { debug!("PaintTask: paint ready msg"); @@ -296,9 +296,9 @@ impl PaintTask where C: PaintListener + Send + 'static { layer_kind: LayerKind) { time::profile(time::ProfilerCategory::Painting, None, self.time_profiler_chan.clone(), || { // Bail out if there is no appropriate layer. - let stacking_context = if let Some(ref paint_layer) = self.root_paint_layer { - match paint_layer.find_stacking_context_with_layer_id(layer_id) { - Some(stacking_context) => stacking_context, + let paint_layer = if let Some(ref root_paint_layer) = self.root_paint_layer { + match PaintLayer::find_layer_with_layer_id(root_paint_layer, layer_id) { + Some(paint_layer) => paint_layer, None => return, } } else { @@ -313,7 +313,7 @@ impl PaintTask where C: PaintListener + Send + 'static { let thread_id = i % self.worker_threads.len(); self.worker_threads[thread_id].paint_tile(thread_id, tile, - stacking_context.clone(), + paint_layer.clone(), scale, layer_kind); } @@ -347,7 +347,7 @@ impl PaintTask where C: PaintListener + Send + 'static { self.current_epoch.unwrap()); fn build_from_paint_layer(properties: &mut Vec, - paint_layer: &PaintLayer, + paint_layer: &Arc, page_position: &Point2D, transform: &Matrix4, perspective: &Matrix4, @@ -470,12 +470,12 @@ impl WorkerThreadProxy { fn paint_tile(&mut self, thread_id: usize, tile: BufferRequest, - stacking_context: Arc, + paint_layer: Arc, scale: f32, layer_kind: LayerKind) { let msg = MsgToWorkerThread::PaintTile(thread_id, tile, - stacking_context, + paint_layer, scale, layer_kind); self.sender.send(msg).unwrap() @@ -540,10 +540,10 @@ impl WorkerThread { loop { match self.receiver.recv().unwrap() { MsgToWorkerThread::Exit => break, - MsgToWorkerThread::PaintTile(thread_id, tile, stacking_context, scale, layer_kind) => { + MsgToWorkerThread::PaintTile(thread_id, tile, paint_layer, scale, layer_kind) => { let buffer = self.optimize_and_paint_tile(thread_id, tile, - stacking_context, + paint_layer, scale, layer_kind); self.sender.send(MsgFromWorkerThread::PaintedTile(buffer)).unwrap() @@ -576,10 +576,11 @@ impl WorkerThread { fn optimize_and_paint_tile(&mut self, thread_id: usize, mut tile: BufferRequest, - stacking_context: Arc, + paint_layer: Arc, scale: f32, layer_kind: LayerKind) -> Box { + let stacking_context = &paint_layer.stacking_context; let size = Size2D::new(tile.screen_rect.size.width as i32, tile.screen_rect.size.height as i32); let mut buffer = self.create_layer_buffer(&mut tile, scale); @@ -683,7 +684,7 @@ impl WorkerThread { enum MsgToWorkerThread { Exit, - PaintTile(usize, BufferRequest, Arc, f32, LayerKind), + PaintTile(usize, BufferRequest, Arc, f32, LayerKind), } enum MsgFromWorkerThread {