mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Layerize canvas
Note that this keeps using readback right now, `NativeSurface` painting will be implemented soon. Also see https://github.com/servo/servo/issues/6142
This commit is contained in:
parent
6481058309
commit
3350522306
35 changed files with 769 additions and 500 deletions
|
@ -13,9 +13,15 @@ git = "https://github.com/servo/rust-azure"
|
|||
[dependencies.canvas]
|
||||
path = "../canvas"
|
||||
|
||||
[dependencies.canvas_traits]
|
||||
path = "../canvas_traits"
|
||||
|
||||
[dependencies.gfx]
|
||||
path = "../gfx"
|
||||
|
||||
[dependencies.gfx_traits]
|
||||
path = "../gfx_traits"
|
||||
|
||||
[dependencies.msg]
|
||||
path = "../msg"
|
||||
|
||||
|
|
|
@ -8,11 +8,12 @@
|
|||
|
||||
use css::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache};
|
||||
|
||||
use canvas_traits::CanvasMsg;
|
||||
use msg::compositor_msg::LayerId;
|
||||
use geom::{Rect, Size2D};
|
||||
use gfx::display_list::OpaqueNode;
|
||||
use gfx::font_cache_task::FontCacheTask;
|
||||
use gfx::font_context::FontContext;
|
||||
use msg::compositor_msg::LayerId;
|
||||
use msg::constellation_msg::ConstellationChan;
|
||||
use net_traits::image::base::Image;
|
||||
use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageState};
|
||||
|
@ -22,7 +23,7 @@ use std::cell::Cell;
|
|||
use std::collections::HashMap;
|
||||
use std::collections::hash_state::DefaultState;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::{channel, Sender};
|
||||
use style::selector_matching::Stylist;
|
||||
use url::Url;
|
||||
|
@ -103,6 +104,9 @@ pub struct SharedLayoutContext {
|
|||
/// sent.
|
||||
pub new_animations_sender: Sender<Animation>,
|
||||
|
||||
/// A channel to send canvas renderers to paint task, in order to correctly paint the layers
|
||||
pub canvas_layers_sender: Sender<(LayerId, Option<Arc<Mutex<Sender<CanvasMsg>>>>)>,
|
||||
|
||||
/// The visible rects for each layer, as reported to us by the compositor.
|
||||
pub visible_rects: Arc<HashMap<LayerId, Rect<Au>, DefaultState<FnvHasher>>>,
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
use azure::azure_hl::Color;
|
||||
use block::BlockFlow;
|
||||
use canvas::canvas_msg::{CanvasMsg, CanvasCommonMsg};
|
||||
use context::LayoutContext;
|
||||
use flow::{self, BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED, NEEDS_LAYER};
|
||||
use fragment::{CoordinateSystem, Fragment, IframeFragmentInfo, ImageFragmentInfo};
|
||||
|
@ -23,7 +22,7 @@ use model::{self, MaybeAuto, ToGfxMatrix};
|
|||
use table_cell::CollapsedBordersForCell;
|
||||
|
||||
use geom::{Matrix2D, Point2D, Rect, Size2D, SideOffsets2D};
|
||||
use gfx::color;
|
||||
use gfx_traits::color;
|
||||
use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayItem};
|
||||
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
|
||||
use gfx::display_list::{DisplayItem, DisplayList, DisplayItemMetadata};
|
||||
|
@ -32,7 +31,7 @@ use gfx::display_list::{GradientStop, ImageDisplayItem, LineDisplayItem};
|
|||
use gfx::display_list::{OpaqueNode, SolidColorDisplayItem};
|
||||
use gfx::display_list::{StackingContext, TextDisplayItem, TextOrientation};
|
||||
use gfx::paint_task::{PaintLayer, THREAD_TINT_COLORS};
|
||||
use msg::compositor_msg::ScrollPolicy;
|
||||
use msg::compositor_msg::{ScrollPolicy, LayerId};
|
||||
use msg::constellation_msg::ConstellationChan;
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use png::{self, PixelsByColorType};
|
||||
|
@ -40,7 +39,6 @@ use std::cmp;
|
|||
use std::default::Default;
|
||||
use std::iter::repeat;
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::channel;
|
||||
use style::computed_values::filter::Filter;
|
||||
use style::computed_values::transform::ComputedMatrix;
|
||||
use style::computed_values::{background_attachment, background_clip, background_origin, background_repeat, background_size};
|
||||
|
@ -56,6 +54,15 @@ use util::geometry::{Au, ZERO_POINT};
|
|||
use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
|
||||
use util::opts;
|
||||
|
||||
use canvas_traits::{CanvasMsg, CanvasCommonMsg};
|
||||
use std::sync::mpsc::channel;
|
||||
|
||||
/// A possible `PaintLayer` for an stacking context
|
||||
pub enum StackingContextLayer {
|
||||
Existing(PaintLayer),
|
||||
IfCanvas(LayerId),
|
||||
}
|
||||
|
||||
/// The results of display list building for a single flow.
|
||||
pub enum DisplayListBuildingResult {
|
||||
None,
|
||||
|
@ -240,7 +247,8 @@ pub trait FragmentDisplayListBuilding {
|
|||
fn create_stacking_context(&self,
|
||||
base_flow: &BaseFlow,
|
||||
display_list: Box<DisplayList>,
|
||||
layer: Option<Arc<PaintLayer>>)
|
||||
layout_context: &LayoutContext,
|
||||
layer: StackingContextLayer)
|
||||
-> Arc<StackingContext>;
|
||||
|
||||
}
|
||||
|
@ -1077,11 +1085,11 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}
|
||||
}
|
||||
SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
|
||||
// TODO(ecoal95): make the canvas with a renderer use the custom layer
|
||||
let width = canvas_fragment_info.replaced_image_fragment_info
|
||||
.computed_inline_size.map_or(0, |w| w.to_px() as usize);
|
||||
let height = canvas_fragment_info.replaced_image_fragment_info
|
||||
.computed_block_size.map_or(0, |h| h.to_px() as usize);
|
||||
|
||||
let (sender, receiver) = channel::<Vec<u8>>();
|
||||
let canvas_data = match canvas_fragment_info.renderer {
|
||||
Some(ref renderer) => {
|
||||
|
@ -1091,12 +1099,11 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
},
|
||||
None => repeat(0xFFu8).take(width * height * 4).collect(),
|
||||
};
|
||||
|
||||
let canvas_display_item = box ImageDisplayItem {
|
||||
display_list.content.push_back(DisplayItem::ImageClass(box ImageDisplayItem{
|
||||
base: BaseDisplayItem::new(stacking_relative_content_box,
|
||||
DisplayItemMetadata::new(self.node,
|
||||
&*self.style,
|
||||
Cursor::DefaultCursor),
|
||||
&*self.style,
|
||||
Cursor::DefaultCursor),
|
||||
(*clip).clone()),
|
||||
image: Arc::new(png::Image {
|
||||
width: width as u32,
|
||||
|
@ -1105,9 +1112,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}),
|
||||
stretch_size: stacking_relative_content_box.size,
|
||||
image_rendering: image_rendering::T::Auto,
|
||||
};
|
||||
|
||||
display_list.content.push_back(DisplayItem::ImageClass(canvas_display_item));
|
||||
}));
|
||||
}
|
||||
SpecificFragmentInfo::UnscannedText(_) => {
|
||||
panic!("Shouldn't see unscanned fragments here.")
|
||||
|
@ -1121,7 +1126,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
fn create_stacking_context(&self,
|
||||
base_flow: &BaseFlow,
|
||||
display_list: Box<DisplayList>,
|
||||
layer: Option<Arc<PaintLayer>>)
|
||||
layout_context: &LayoutContext,
|
||||
layer: StackingContextLayer)
|
||||
-> Arc<StackingContext> {
|
||||
let border_box = self.stacking_relative_border_box(&base_flow.stacking_relative_position,
|
||||
&base_flow.absolute_position_info
|
||||
|
@ -1153,6 +1159,28 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
filters.push(Filter::Opacity(effects.opacity))
|
||||
}
|
||||
|
||||
// Ensure every canvas has a layer
|
||||
let layer = match layer {
|
||||
StackingContextLayer::Existing(existing_layer) => Some(existing_layer),
|
||||
StackingContextLayer::IfCanvas(layer_id) => {
|
||||
if let SpecificFragmentInfo::Canvas(_) = self.specific {
|
||||
Some(PaintLayer::new(layer_id, color::transparent(), ScrollPolicy::Scrollable))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// If it's a canvas we must propagate the layer and the renderer to the paint
|
||||
// task
|
||||
if let SpecificFragmentInfo::Canvas(ref fragment_info) = self.specific {
|
||||
let layer_id = layer.as_ref().unwrap().id;
|
||||
layout_context.shared.canvas_layers_sender
|
||||
.send((layer_id, fragment_info.renderer.clone())).unwrap();
|
||||
}
|
||||
|
||||
let layer = layer.map(|l| Arc::new(l));
|
||||
|
||||
Arc::new(StackingContext::new(display_list,
|
||||
&border_box,
|
||||
&overflow,
|
||||
|
@ -1419,10 +1447,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
background_border_level);
|
||||
|
||||
self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
|
||||
DisplayListBuildingResult::StackingContext(self.fragment.create_stacking_context(
|
||||
&self.base,
|
||||
display_list,
|
||||
None))
|
||||
DisplayListBuildingResult::StackingContext(
|
||||
self.fragment.create_stacking_context(&self.base,
|
||||
display_list,
|
||||
layout_context,
|
||||
StackingContextLayer::IfCanvas(self.layer_id(0))))
|
||||
} else {
|
||||
match self.fragment.style.get_box().position {
|
||||
position::T::static_ => {}
|
||||
|
@ -1452,10 +1481,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
if !self.will_get_layer() {
|
||||
// We didn't need a layer.
|
||||
self.base.display_list_building_result =
|
||||
DisplayListBuildingResult::StackingContext(self.fragment.create_stacking_context(
|
||||
&self.base,
|
||||
display_list,
|
||||
None));
|
||||
DisplayListBuildingResult::StackingContext(
|
||||
self.fragment.create_stacking_context(&self.base,
|
||||
display_list,
|
||||
layout_context,
|
||||
StackingContextLayer::IfCanvas(self.layer_id(0))));
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1466,11 +1496,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
ScrollPolicy::Scrollable
|
||||
};
|
||||
|
||||
let transparent = color::transparent();
|
||||
let stacking_context = self.fragment.create_stacking_context(
|
||||
&self.base,
|
||||
display_list,
|
||||
Some(Arc::new(PaintLayer::new(self.layer_id(0), transparent, scroll_policy))));
|
||||
let paint_layer = PaintLayer::new(self.layer_id(0), color::transparent(), scroll_policy);
|
||||
let stacking_context = self.fragment.create_stacking_context(&self.base,
|
||||
display_list,
|
||||
layout_context,
|
||||
StackingContextLayer::Existing(paint_layer));
|
||||
self.base.display_list_building_result =
|
||||
DisplayListBuildingResult::StackingContext(stacking_context)
|
||||
}
|
||||
|
@ -1487,7 +1517,10 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
|
||||
self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
|
||||
DisplayListBuildingResult::StackingContext(
|
||||
self.fragment.create_stacking_context(&self.base, display_list, None))
|
||||
self.fragment.create_stacking_context(&self.base,
|
||||
display_list,
|
||||
layout_context,
|
||||
StackingContextLayer::IfCanvas(self.layer_id(0))))
|
||||
} else {
|
||||
DisplayListBuildingResult::Normal(display_list)
|
||||
}
|
||||
|
@ -1544,6 +1577,7 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
|
|||
&self.base.stacking_relative_position_of_display_port);
|
||||
|
||||
has_stacking_context = fragment.establishes_stacking_context();
|
||||
|
||||
match fragment.specific {
|
||||
SpecificFragmentInfo::InlineBlock(ref mut block_flow) => {
|
||||
let block_flow = &mut *block_flow.flow_ref;
|
||||
|
@ -1571,17 +1605,23 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
|
|||
|
||||
// FIXME(Savago): fix Fragment::establishes_stacking_context() for absolute positioned item
|
||||
// and remove the check for filter presence. Further details on #5812.
|
||||
if has_stacking_context &&
|
||||
!self.fragments.fragments[0].style().get_effects().filter.is_empty() {
|
||||
self.base.display_list_building_result =
|
||||
DisplayListBuildingResult::StackingContext(
|
||||
self.fragments.fragments[0].create_stacking_context(&self.base,
|
||||
display_list,
|
||||
None));
|
||||
has_stacking_context = has_stacking_context && {
|
||||
if let SpecificFragmentInfo::Canvas(_) = self.fragments.fragments[0].specific {
|
||||
true
|
||||
} else {
|
||||
!self.fragments.fragments[0].style().get_effects().filter.is_empty()
|
||||
}
|
||||
};
|
||||
|
||||
self.base.display_list_building_result = if has_stacking_context {
|
||||
DisplayListBuildingResult::StackingContext(
|
||||
self.fragments.fragments[0].create_stacking_context(&self.base,
|
||||
display_list,
|
||||
layout_context,
|
||||
StackingContextLayer::IfCanvas(self.layer_id(0))))
|
||||
} else {
|
||||
self.base.display_list_building_result =
|
||||
DisplayListBuildingResult::Normal(display_list);
|
||||
}
|
||||
DisplayListBuildingResult::Normal(display_list)
|
||||
};
|
||||
|
||||
if opts::get().validate_display_list_geometry {
|
||||
self.base.validate_display_list_geometry();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
use canvas::canvas_msg::CanvasMsg;
|
||||
use canvas_traits::CanvasMsg;
|
||||
use css::node_style::StyledNode;
|
||||
use context::LayoutContext;
|
||||
use floats::ClearType;
|
||||
|
@ -195,9 +195,7 @@ impl SpecificFragmentInfo {
|
|||
SpecificFragmentInfo::Iframe(_) => "SpecificFragmentInfo::Iframe",
|
||||
SpecificFragmentInfo::Image(_) => "SpecificFragmentInfo::Image",
|
||||
SpecificFragmentInfo::InlineAbsolute(_) => "SpecificFragmentInfo::InlineAbsolute",
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {
|
||||
"SpecificFragmentInfo::InlineAbsoluteHypothetical"
|
||||
}
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => "SpecificFragmentInfo::InlineAbsoluteHypothetical",
|
||||
SpecificFragmentInfo::InlineBlock(_) => "SpecificFragmentInfo::InlineBlock",
|
||||
SpecificFragmentInfo::ScannedText(_) => "SpecificFragmentInfo::ScannedText",
|
||||
SpecificFragmentInfo::Table => "SpecificFragmentInfo::Table",
|
||||
|
@ -1993,6 +1991,13 @@ impl Fragment {
|
|||
if self.style().get_effects().transform.is_some() {
|
||||
return true
|
||||
}
|
||||
|
||||
// Canvas always layerizes, as an special case
|
||||
// FIXME(pcwalton): Don't unconditionally form stacking contexts for each canvas.
|
||||
if let SpecificFragmentInfo::Canvas(_) = self.specific {
|
||||
return true
|
||||
}
|
||||
|
||||
match self.style().get_box().position {
|
||||
position::T::absolute | position::T::fixed => {
|
||||
// FIXME(pcwalton): This should only establish a new stacking context when
|
||||
|
|
|
@ -24,6 +24,7 @@ use sequential;
|
|||
use wrapper::{LayoutNode, TLayoutNode};
|
||||
|
||||
use azure::azure::AzColor;
|
||||
use canvas_traits::CanvasMsg;
|
||||
use encoding::EncodingRef;
|
||||
use encoding::all::UTF_8;
|
||||
use geom::matrix2d::Matrix2D;
|
||||
|
@ -31,7 +32,7 @@ use geom::point::Point2D;
|
|||
use geom::rect::Rect;
|
||||
use geom::scale_factor::ScaleFactor;
|
||||
use geom::size::Size2D;
|
||||
use gfx::color;
|
||||
use gfx_traits::color;
|
||||
use gfx::display_list::{ClippingRegion, DisplayItemMetadata, DisplayList, OpaqueNode};
|
||||
use gfx::display_list::{StackingContext};
|
||||
use gfx::font_cache_task::FontCacheTask;
|
||||
|
@ -39,7 +40,7 @@ use gfx::paint_task::Msg as PaintMsg;
|
|||
use gfx::paint_task::{PaintChan, PaintLayer};
|
||||
use layout_traits::{LayoutControlMsg, LayoutTaskFactory};
|
||||
use log;
|
||||
use msg::compositor_msg::{Epoch, LayerId, ScrollPolicy};
|
||||
use msg::compositor_msg::{Epoch, ScrollPolicy, LayerId};
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use msg::constellation_msg::{ConstellationChan, Failure, PipelineExitType, PipelineId};
|
||||
use profile_traits::mem::{self, Report, ReportsChan};
|
||||
|
@ -134,7 +135,7 @@ pub struct LayoutTaskData {
|
|||
/// sent.
|
||||
pub new_animations_sender: Sender<Animation>,
|
||||
|
||||
/// A counter for epoch messages.
|
||||
/// A counter for epoch messages
|
||||
epoch: Epoch,
|
||||
|
||||
/// The position and size of the visible rect for each layer. We do not build display lists
|
||||
|
@ -195,6 +196,11 @@ pub struct LayoutTask {
|
|||
/// Is this the first reflow in this LayoutTask?
|
||||
pub first_reflow: Cell<bool>,
|
||||
|
||||
/// To receive a canvas renderer associated to a layer, this message is propagated
|
||||
/// to the paint chan
|
||||
pub canvas_layers_receiver: Receiver<(LayerId, Option<Arc<Mutex<Sender<CanvasMsg>>>>)>,
|
||||
pub canvas_layers_sender: Sender<(LayerId, Option<Arc<Mutex<Sender<CanvasMsg>>>>)>,
|
||||
|
||||
/// A mutex to allow for fast, read-only RPC of layout's internal data
|
||||
/// structures, while still letting the LayoutTask modify them.
|
||||
///
|
||||
|
@ -310,6 +316,7 @@ impl LayoutTask {
|
|||
// Create the channel on which new animations can be sent.
|
||||
let (new_animations_sender, new_animations_receiver) = channel();
|
||||
let (image_cache_sender, image_cache_receiver) = channel();
|
||||
let (canvas_layers_sender, canvas_layers_receiver) = channel();
|
||||
|
||||
LayoutTask {
|
||||
id: id,
|
||||
|
@ -329,6 +336,8 @@ impl LayoutTask {
|
|||
first_reflow: Cell::new(true),
|
||||
image_cache_receiver: image_cache_receiver,
|
||||
image_cache_sender: ImageCacheChan(image_cache_sender),
|
||||
canvas_layers_receiver: canvas_layers_receiver,
|
||||
canvas_layers_sender: canvas_layers_sender,
|
||||
rw_data: Arc::new(Mutex::new(
|
||||
LayoutTaskData {
|
||||
root_flow: None,
|
||||
|
@ -375,6 +384,7 @@ impl LayoutTask {
|
|||
constellation_chan: rw_data.constellation_chan.clone(),
|
||||
layout_chan: self.chan.clone(),
|
||||
font_cache_task: self.font_cache_task.clone(),
|
||||
canvas_layers_sender: self.canvas_layers_sender.clone(),
|
||||
stylist: &*rw_data.stylist,
|
||||
url: (*url).clone(),
|
||||
reflow_root: reflow_root.map(|node| OpaqueNodeMethods::from_layout_node(node)),
|
||||
|
@ -960,6 +970,14 @@ impl LayoutTask {
|
|||
animation::process_new_animations(&mut *rw_data, self.id);
|
||||
}
|
||||
|
||||
// Send new canvas renderers to the paint task
|
||||
while let Ok((layer_id, renderer)) = self.canvas_layers_receiver.try_recv() {
|
||||
// Just send if there's an actual renderer
|
||||
if let Some(renderer) = renderer {
|
||||
self.paint_chan.send(PaintMsg::CanvasLayer(layer_id, renderer));
|
||||
}
|
||||
}
|
||||
|
||||
// Perform post-style recalculation layout passes.
|
||||
self.perform_post_style_recalc_layout_passes(&data.reflow_info,
|
||||
&mut rw_data,
|
||||
|
|
|
@ -39,13 +39,14 @@ extern crate util;
|
|||
extern crate rustc_serialize;
|
||||
extern crate alloc;
|
||||
extern crate azure;
|
||||
extern crate canvas;
|
||||
extern crate canvas_traits;
|
||||
extern crate clock_ticks;
|
||||
extern crate collections;
|
||||
extern crate cssparser;
|
||||
extern crate encoding;
|
||||
extern crate geom;
|
||||
extern crate gfx;
|
||||
extern crate gfx_traits;
|
||||
extern crate layout_traits;
|
||||
extern crate libc;
|
||||
extern crate msg;
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use canvas::canvas_msg::CanvasMsg;
|
||||
use canvas_traits::CanvasMsg;
|
||||
use context::SharedLayoutContext;
|
||||
use css::node_style::StyledNode;
|
||||
use incremental::RestyleDamage;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue