diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2016-02-19 00:54:06 +0530 |
---|---|---|
committer | bors-servo <lbergstrom+bors@mozilla.com> | 2016-02-19 00:54:06 +0530 |
commit | ab07b06823ea9748a6091aee2281495f86f00bce (patch) | |
tree | 2dd06ac4834d5bc4bcba6e4ada3aab12bb2c12d9 /components/layout | |
parent | fe70efe07f6d72665f10c752884e5705d5bdc600 (diff) | |
parent | c0531c312fdb0783e4d121b4c2d7f15d4f5cdc1f (diff) | |
download | servo-ab07b06823ea9748a6091aee2281495f86f00bce.tar.gz servo-ab07b06823ea9748a6091aee2281495f86f00bce.zip |
Auto merge of #9589 - glennw:webrender, r=pcwalton
Add WebRender integration to Servo.
WebRender is an experimental GPU accelerated rendering backend for Servo.
The WebRender backend can be specified by running Servo with the -w option (otherwise the default rendering backend will be used).
WebRender has many bugs, and missing features - but it is usable to browse most websites - please report any WebRender specific rendering bugs you encounter!
<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.svg" height="40" alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/9589)
<!-- Reviewable:end -->
Diffstat (limited to 'components/layout')
-rw-r--r-- | components/layout/Cargo.toml | 3 | ||||
-rw-r--r-- | components/layout/display_list_builder.rs | 126 | ||||
-rw-r--r-- | components/layout/layout_thread.rs | 56 | ||||
-rw-r--r-- | components/layout/lib.rs | 2 | ||||
-rw-r--r-- | components/layout/webrender_helpers.rs | 481 |
5 files changed, 614 insertions, 54 deletions
diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml index d549967e753..99bf99cd47a 100644 --- a/components/layout/Cargo.toml +++ b/components/layout/Cargo.toml @@ -56,6 +56,9 @@ path = "../util" [dependencies.ipc-channel] git = "https://github.com/servo/ipc-channel" +[dependencies.webrender_traits] +git = "https://github.com/glennw/webrender_traits" + [dependencies] app_units = {version = "0.2.1", features = ["plugins"]} bitflags = "0.3" diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index d49f4f4813b..efd7b0a2394 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -13,7 +13,7 @@ use app_units::{Au, AU_PER_PX}; use azure::azure_hl::Color; use block::BlockFlow; -use canvas_traits::{CanvasMsg, FromLayoutMsg}; +use canvas_traits::{CanvasMsg, CanvasPixelData, CanvasData, FromLayoutMsg}; use context::LayoutContext; use euclid::num::Zero; use euclid::{Matrix4, Point2D, Point3D, Rect, SideOffsets2D, Size2D}; @@ -26,7 +26,7 @@ use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayIte use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion}; use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList, DisplayListSection}; use gfx::display_list::{GradientDisplayItem}; -use gfx::display_list::{GradientStop, ImageDisplayItem, LayeredItem, LayerInfo}; +use gfx::display_list::{GradientStop, IframeDisplayItem, ImageDisplayItem, WebGLDisplayItem, LayeredItem, LayerInfo}; use gfx::display_list::{LineDisplayItem, OpaqueNode, SolidColorDisplayItem}; use gfx::display_list::{StackingContext, TextDisplayItem, TextOrientation}; use gfx::paint_thread::THREAD_TINT_COLORS; @@ -51,8 +51,7 @@ use style::properties::style_structs::Border; use style::properties::{self, ComputedValues}; use style::values::RGBA; use style::values::computed; -use style::values::computed::LinearGradient; -use style::values::computed::{LengthOrNone, LengthOrPercentage, LengthOrPercentageOrAuto}; +use style::values::computed::{LengthOrNone, LengthOrPercentage, LengthOrPercentageOrAuto, LinearGradient}; use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirection}; use style_traits::cursor::Cursor; use table_cell::CollapsedBordersForCell; @@ -948,9 +947,12 @@ impl FragmentDisplayListBuilding for Fragment { stacking_relative_flow_origin, self); - if !stacking_relative_border_box.intersects(stacking_relative_display_port) { - debug!("Fragment::build_display_list: outside display port"); - return + // webrender deals with all culling via aabb + if !opts::get().use_webrender { + if !stacking_relative_border_box.intersects(stacking_relative_display_port) { + debug!("Fragment::build_display_list: outside display port"); + return + } } // Calculate the clip rect. If there's nothing to render at all, don't even construct @@ -1112,20 +1114,31 @@ impl FragmentDisplayListBuilding for Fragment { } SpecificFragmentInfo::Iframe(ref fragment_info) => { if !stacking_relative_content_box.is_empty() { - let layer_id = self.layer_id(); - display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem { - item: DisplayItem::NoopClass( - box BaseDisplayItem::new(&stacking_relative_content_box, - DisplayItemMetadata::new(self.node, - &*self.style, - Cursor::DefaultCursor), - clip)), - layer_id: layer_id - })); - - display_list.layer_info.push_back(LayerInfo::new(layer_id, - ScrollPolicy::Scrollable, - Some(fragment_info.pipeline_id))); + if opts::get().use_webrender { + display_list.content.push_back(DisplayItem::IframeClass(box IframeDisplayItem { + base: BaseDisplayItem::new(&stacking_relative_content_box, + DisplayItemMetadata::new(self.node, + &*self.style, + Cursor::DefaultCursor), + clip), + iframe: fragment_info.pipeline_id, + })); + } else { + let layer_id = self.layer_id(); + display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem { + item: DisplayItem::NoopClass( + box BaseDisplayItem::new(&stacking_relative_content_box, + DisplayItemMetadata::new(self.node, + &*self.style, + Cursor::DefaultCursor), + clip)), + layer_id: layer_id + })); + + display_list.layer_info.push_back(LayerInfo::new(layer_id, + ScrollPolicy::Scrollable, + Some(fragment_info.pipeline_id))); + } } } SpecificFragmentInfo::Image(ref mut image_fragment) => { @@ -1144,7 +1157,6 @@ 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 @@ -1156,7 +1168,7 @@ impl FragmentDisplayListBuilding for Fragment { let ipc_renderer = ipc_renderer.lock().unwrap(); let (sender, receiver) = ipc::channel().unwrap(); ipc_renderer.send(CanvasMsg::FromLayout( - FromLayoutMsg::SendPixelContents(sender))).unwrap(); + FromLayoutMsg::SendData(sender))).unwrap(); let data = receiver.recv().unwrap(); // Propagate the layer and the renderer to the paint thread. @@ -1165,31 +1177,54 @@ impl FragmentDisplayListBuilding for Fragment { data }, - None => IpcSharedMemory::from_byte(0xFFu8, width * height * 4), - }; - let display_item = DisplayItem::ImageClass(box ImageDisplayItem { - base: BaseDisplayItem::new(&stacking_relative_content_box, - DisplayItemMetadata::new(self.node, - &*self.style, - Cursor::DefaultCursor), - clip), - image: Arc::new(Image { - width: width as u32, - height: height as u32, - format: PixelFormat::RGBA8, - bytes: canvas_data, + None => CanvasData::Pixels(CanvasPixelData { + image_data: IpcSharedMemory::from_byte(0xFFu8, width * height * 4), + image_key: None, }), - stretch_size: stacking_relative_content_box.size, - image_rendering: image_rendering::T::Auto, - }); + }; - display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem { - item: display_item, - layer_id: layer_id - })); + let display_item = match canvas_data { + CanvasData::Pixels(canvas_data) => { + DisplayItem::ImageClass(box ImageDisplayItem { + base: BaseDisplayItem::new(&stacking_relative_content_box, + DisplayItemMetadata::new(self.node, + &*self.style, + Cursor::DefaultCursor), + clip), + image: Arc::new(Image { + width: width as u32, + height: height as u32, + format: PixelFormat::RGBA8, + bytes: canvas_data.image_data, + id: canvas_data.image_key, + }), + stretch_size: stacking_relative_content_box.size, + image_rendering: image_rendering::T::Auto, + }) + } + CanvasData::WebGL(context_id) => { + DisplayItem::WebGLClass(box WebGLDisplayItem { + base: BaseDisplayItem::new(&stacking_relative_content_box, + DisplayItemMetadata::new(self.node, + &*self.style, + Cursor::DefaultCursor), + clip), + context_id: context_id, + }) + } + }; + + if opts::get().use_webrender { + display_list.content.push_back(display_item); + } else { + display_list.content.push_back(DisplayItem::LayeredItemClass(box LayeredItem { + item: display_item, + layer_id: layer_id + })); - display_list.layer_info.push_back( - LayerInfo::new(layer_id, ScrollPolicy::Scrollable, None)); + display_list.layer_info.push_back( + LayerInfo::new(layer_id, ScrollPolicy::Scrollable, None)); + } } } SpecificFragmentInfo::UnscannedText(_) => { @@ -1993,4 +2028,3 @@ pub enum StackingContextCreationMode { OuterScrollWrapper, InnerScrollWrapper, } - diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index e5f72a395e4..fbc1cd26daf 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -35,7 +35,7 @@ use ipc_channel::router::ROUTER; use layout_debug; use layout_traits::LayoutThreadFactory; use log; -use msg::constellation_msg::{ConstellationChan, Failure, PipelineId}; +use msg::constellation_msg::{ConstellationChan, ConvertPipelineIdToWebRender, Failure, PipelineId}; use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread}; use parallel; use profile_traits::mem::{self, Report, ReportKind, ReportsChan}; @@ -80,6 +80,8 @@ use util::opts; use util::thread; use util::thread_state; use util::workqueue::WorkQueue; +use webrender_helpers::WebRenderStackingContextConverter; +use webrender_traits; use wrapper::{LayoutNode, NonOpaqueStyleAndLayoutData, ServoLayoutNode, ThreadSafeLayoutNode}; /// The number of screens of data we're allowed to generate display lists for in each direction. @@ -221,6 +223,8 @@ pub struct LayoutThread { /// The CSS error reporter for all CSS loaded in this layout thread error_reporter: CSSErrorReporter, + // Webrender interface, if enabled. + webrender_api: Option<webrender_traits::RenderApi>, } impl LayoutThreadFactory for LayoutThread { @@ -240,7 +244,8 @@ impl LayoutThreadFactory for LayoutThread { time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, shutdown_chan: IpcSender<()>, - content_process_shutdown_chan: IpcSender<()>) { + content_process_shutdown_chan: IpcSender<()>, + webrender_api_sender: Option<webrender_traits::RenderApiSender>) { let ConstellationChan(con_chan) = constellation_chan.clone(); thread::spawn_named_with_send_on_failure(format!("LayoutThread {:?}", id), thread_state::LAYOUT, @@ -258,7 +263,8 @@ impl LayoutThreadFactory for LayoutThread { image_cache_thread, font_cache_thread, time_profiler_chan, - mem_profiler_chan.clone()); + mem_profiler_chan.clone(), + webrender_api_sender); let reporter_name = format!("layout-reporter-{}", id); mem_profiler_chan.run_with_memory_reporting(|| { @@ -367,7 +373,8 @@ impl LayoutThread { image_cache_thread: ImageCacheThread, font_cache_thread: FontCacheThread, time_profiler_chan: time::ProfilerChan, - mem_profiler_chan: mem::ProfilerChan) + mem_profiler_chan: mem::ProfilerChan, + webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> LayoutThread { let device = Device::new( MediaType::Screen, @@ -437,6 +444,7 @@ impl LayoutThread { expired_animations: Arc::new(RwLock::new(HashMap::new())), epoch: Epoch(0), viewport_size: Size2D::new(Au(0), Au(0)), + webrender_api: webrender_api_sender.map(|wr| wr.create_api()), rw_data: Arc::new(Mutex::new( LayoutThreadData { constellation_chan: constellation_chan, @@ -705,7 +713,8 @@ impl LayoutThread { self.time_profiler_chan.clone(), self.mem_profiler_chan.clone(), info.layout_shutdown_chan, - info.content_process_shutdown_chan); + info.content_process_shutdown_chan, + self.webrender_api.as_ref().map(|wr| wr.clone_sender())); } /// Enters a quiescent state in which no new messages will be processed until an `ExitNow` is @@ -908,9 +917,40 @@ impl LayoutThread { debug!("Layout done!"); self.epoch.next(); - self.paint_chan - .send(LayoutToPaintMsg::PaintInit(self.epoch, paint_layer)) - .unwrap(); + + if opts::get().use_webrender { + let api = self.webrender_api.as_ref().unwrap(); + // TODO: Avoid the temporary conversion and build webrender sc/dl directly! + let Epoch(epoch_number) = self.epoch; + let epoch = webrender_traits::Epoch(epoch_number); + let pipeline_id = self.id.to_webrender(); + + // TODO(gw) For now only create a root scrolling layer! + let root_scroll_layer_id = webrender_traits::ScrollLayerId::new(pipeline_id, 0); + let sc_id = rw_data.stacking_context.as_ref() + .unwrap() + .convert_to_webrender(&self.webrender_api.as_ref().unwrap(), + pipeline_id, + epoch, + Some(root_scroll_layer_id)); + let root_background_color = webrender_traits::ColorF::new(root_background_color.r, + root_background_color.g, + root_background_color.b, + root_background_color.a); + + let viewport_size = Size2D::new(self.viewport_size.width.to_f32_px(), + self.viewport_size.height.to_f32_px()); + + api.set_root_stacking_context(sc_id, + root_background_color, + epoch, + pipeline_id, + viewport_size); + } else { + self.paint_chan + .send(LayoutToPaintMsg::PaintInit(self.epoch, paint_layer)) + .unwrap(); + } } }); } diff --git a/components/layout/lib.rs b/components/layout/lib.rs index 498e91fb206..431f576ca78 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -59,6 +59,7 @@ extern crate unicode_script; extern crate url; #[macro_use] extern crate util; +extern crate webrender_traits; #[macro_use] mod layout_debug; @@ -95,4 +96,5 @@ mod table_rowgroup; mod table_wrapper; mod text; mod traversal; +mod webrender_helpers; mod wrapper; diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs new file mode 100644 index 00000000000..a1ab8fac3fe --- /dev/null +++ b/components/layout/webrender_helpers.rs @@ -0,0 +1,481 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// TODO(gw): This contains helper traits and implementations for converting Servo display lists +// into WebRender display lists. In the future, this step should be completely removed. +// This might be achieved by sharing types between WR and Servo display lists, or +// completely converting layout to directly generate WebRender display lists, for example. + +use app_units::Au; +use azure::azure_hl::Color; +use euclid::num::Zero; +use euclid::{Point2D, Rect, Size2D}; +use gfx::display_list::{BorderRadii, BoxShadowClipMode, ClippingRegion}; +use gfx::display_list::{DisplayItem, DisplayList}; +use gfx::display_list::{GradientStop, StackingContext}; +use gfx_traits::ScrollPolicy; +use msg::constellation_msg::ConvertPipelineIdToWebRender; +use style::computed_values::filter::{self, Filter}; +use style::computed_values::{image_rendering, mix_blend_mode}; +use style::values::computed::BorderStyle; +use webrender_traits; + +pub trait WebRenderStackingContextConverter { + fn convert_to_webrender(&self, + api: &webrender_traits::RenderApi, + pipeline_id: webrender_traits::PipelineId, + epoch: webrender_traits::Epoch, + scroll_layer_id: Option<webrender_traits::ScrollLayerId>) + -> webrender_traits::StackingContextId; +} + +trait WebRenderDisplayListConverter { + fn convert_to_webrender(&self, + api: &webrender_traits::RenderApi, + pipeline_id: webrender_traits::PipelineId, + epoch: webrender_traits::Epoch) -> webrender_traits::DisplayListBuilder; +} + +trait WebRenderDisplayItemConverter { + fn convert_to_webrender(&self, + api: &webrender_traits::RenderApi, + pipeline_id: webrender_traits::PipelineId, + epoch: webrender_traits::Epoch, + level: webrender_traits::StackingLevel, + builder: &mut webrender_traits::DisplayListBuilder); +} + +trait ToBorderStyle { + fn to_border_style(&self) -> webrender_traits::BorderStyle; +} + +impl ToBorderStyle for BorderStyle { + fn to_border_style(&self) -> webrender_traits::BorderStyle { + match *self { + BorderStyle::none => webrender_traits::BorderStyle::None, + BorderStyle::solid => webrender_traits::BorderStyle::Solid, + BorderStyle::double => webrender_traits::BorderStyle::Double, + BorderStyle::dotted => webrender_traits::BorderStyle::Dotted, + BorderStyle::dashed => webrender_traits::BorderStyle::Dashed, + BorderStyle::hidden => webrender_traits::BorderStyle::Hidden, + BorderStyle::groove => webrender_traits::BorderStyle::Groove, + BorderStyle::ridge => webrender_traits::BorderStyle::Ridge, + BorderStyle::inset => webrender_traits::BorderStyle::Inset, + BorderStyle::outset => webrender_traits::BorderStyle::Outset, + } + } +} + +trait ToBoxShadowClipMode { + fn to_clip_mode(&self) -> webrender_traits::BoxShadowClipMode; +} + +impl ToBoxShadowClipMode for BoxShadowClipMode { + fn to_clip_mode(&self) -> webrender_traits::BoxShadowClipMode { + match *self { + BoxShadowClipMode::None => webrender_traits::BoxShadowClipMode::None, + BoxShadowClipMode::Inset => webrender_traits::BoxShadowClipMode::Inset, + BoxShadowClipMode::Outset => webrender_traits::BoxShadowClipMode::Outset, + } + } +} + +trait ToSizeF { + fn to_sizef(&self) -> Size2D<f32>; +} + +trait ToPointF { + fn to_pointf(&self) -> Point2D<f32>; +} + +impl ToPointF for Point2D<Au> { + fn to_pointf(&self) -> Point2D<f32> { + Point2D::new(self.x.to_f32_px(), self.y.to_f32_px()) + } +} + +impl ToSizeF for Size2D<Au> { + fn to_sizef(&self) -> Size2D<f32> { + Size2D::new(self.width.to_f32_px(), self.height.to_f32_px()) + } +} + +trait ToRectF { + fn to_rectf(&self) -> Rect<f32>; +} + +impl ToRectF for Rect<Au> { + fn to_rectf(&self) -> Rect<f32> { + let x = self.origin.x.to_f32_px(); + let y = self.origin.y.to_f32_px(); + let w = self.size.width.to_f32_px(); + let h = self.size.height.to_f32_px(); + Rect::new(Point2D::new(x, y), Size2D::new(w, h)) + } +} + +trait ToColorF { + fn to_colorf(&self) -> webrender_traits::ColorF; +} + +impl ToColorF for Color { + fn to_colorf(&self) -> webrender_traits::ColorF { + webrender_traits::ColorF::new(self.r, self.g, self.b, self.a) + } +} + +trait ToGradientStop { + fn to_gradient_stop(&self) -> webrender_traits::GradientStop; +} + +impl ToGradientStop for GradientStop { + fn to_gradient_stop(&self) -> webrender_traits::GradientStop { + webrender_traits::GradientStop { + offset: self.offset, + color: self.color.to_colorf(), + } + } +} + +trait ToClipRegion { + fn to_clip_region(&self) -> webrender_traits::ClipRegion; +} + +impl ToClipRegion for ClippingRegion { + fn to_clip_region(&self) -> webrender_traits::ClipRegion { + webrender_traits::ClipRegion::new(self.main.to_rectf(), + self.complex.iter().map(|complex_clipping_region| { + webrender_traits::ComplexClipRegion::new( + complex_clipping_region.rect.to_rectf(), + complex_clipping_region.radii.to_border_radius(), + ) + }).collect()) + } +} + +trait ToBorderRadius { + fn to_border_radius(&self) -> webrender_traits::BorderRadius; +} + +impl ToBorderRadius for BorderRadii<Au> { + fn to_border_radius(&self) -> webrender_traits::BorderRadius { + webrender_traits::BorderRadius { + top_left: self.top_left.to_sizef(), + top_right: self.top_right.to_sizef(), + bottom_left: self.bottom_left.to_sizef(), + bottom_right: self.bottom_right.to_sizef(), + } + } +} + +trait ToBlendMode { + fn to_blend_mode(&self) -> webrender_traits::MixBlendMode; +} + +impl ToBlendMode for mix_blend_mode::T { + fn to_blend_mode(&self) -> webrender_traits::MixBlendMode { + match *self { + mix_blend_mode::T::normal => webrender_traits::MixBlendMode::Normal, + mix_blend_mode::T::multiply => webrender_traits::MixBlendMode::Multiply, + mix_blend_mode::T::screen => webrender_traits::MixBlendMode::Screen, + mix_blend_mode::T::overlay => webrender_traits::MixBlendMode::Overlay, + mix_blend_mode::T::darken => webrender_traits::MixBlendMode::Darken, + mix_blend_mode::T::lighten => webrender_traits::MixBlendMode::Lighten, + mix_blend_mode::T::color_dodge => webrender_traits::MixBlendMode::ColorDodge, + mix_blend_mode::T::color_burn => webrender_traits::MixBlendMode::ColorBurn, + mix_blend_mode::T::hard_light => webrender_traits::MixBlendMode::HardLight, + mix_blend_mode::T::soft_light => webrender_traits::MixBlendMode::SoftLight, + mix_blend_mode::T::difference => webrender_traits::MixBlendMode::Difference, + mix_blend_mode::T::exclusion => webrender_traits::MixBlendMode::Exclusion, + mix_blend_mode::T::hue => webrender_traits::MixBlendMode::Hue, + mix_blend_mode::T::saturation => webrender_traits::MixBlendMode::Saturation, + mix_blend_mode::T::color => webrender_traits::MixBlendMode::Color, + mix_blend_mode::T::luminosity => webrender_traits::MixBlendMode::Luminosity, + } + } +} + +trait ToImageRendering { + fn to_image_rendering(&self) -> webrender_traits::ImageRendering; +} + +impl ToImageRendering for image_rendering::T { + fn to_image_rendering(&self) -> webrender_traits::ImageRendering { + match *self { + image_rendering::T::CrispEdges => webrender_traits::ImageRendering::CrispEdges, + image_rendering::T::Auto => webrender_traits::ImageRendering::Auto, + image_rendering::T::Pixelated => webrender_traits::ImageRendering::Pixelated, + } + } +} + +trait ToFilterOps { + fn to_filter_ops(&self) -> Vec<webrender_traits::FilterOp>; +} + +impl ToFilterOps for filter::T { + fn to_filter_ops(&self) -> Vec<webrender_traits::FilterOp> { + let mut result = Vec::with_capacity(self.filters.len()); + for filter in self.filters.iter() { + match *filter { + Filter::Blur(radius) => result.push(webrender_traits::FilterOp::Blur(radius)), + Filter::Brightness(amount) => result.push(webrender_traits::FilterOp::Brightness(amount)), + Filter::Contrast(amount) => result.push(webrender_traits::FilterOp::Contrast(amount)), + Filter::Grayscale(amount) => result.push(webrender_traits::FilterOp::Grayscale(amount)), + Filter::HueRotate(angle) => result.push(webrender_traits::FilterOp::HueRotate(angle.0)), + Filter::Invert(amount) => result.push(webrender_traits::FilterOp::Invert(amount)), + Filter::Opacity(amount) => result.push(webrender_traits::FilterOp::Opacity(amount)), + Filter::Saturate(amount) => result.push(webrender_traits::FilterOp::Saturate(amount)), + Filter::Sepia(amount) => result.push(webrender_traits::FilterOp::Sepia(amount)), + } + } + result + } +} + +impl WebRenderStackingContextConverter for StackingContext { + fn convert_to_webrender(&self, + api: &webrender_traits::RenderApi, + pipeline_id: webrender_traits::PipelineId, + epoch: webrender_traits::Epoch, + scroll_layer_id: Option<webrender_traits::ScrollLayerId>) + -> webrender_traits::StackingContextId { + let scroll_policy = self.layer_info + .map_or(webrender_traits::ScrollPolicy::Scrollable, |info| { + match info.scroll_policy { + ScrollPolicy::Scrollable => webrender_traits::ScrollPolicy::Scrollable, + ScrollPolicy::FixedPosition => webrender_traits::ScrollPolicy::Fixed, + } + }); + + let mut sc = webrender_traits::StackingContext::new(scroll_layer_id, + scroll_policy, + self.bounds.to_rectf(), + self.overflow.to_rectf(), + self.z_index, + &self.transform, + &self.perspective, + self.establishes_3d_context, + self.blend_mode.to_blend_mode(), + self.filters.to_filter_ops()); + + let dl_builder = self.display_list.convert_to_webrender(api, + pipeline_id, + epoch); + api.add_display_list(dl_builder, &mut sc, pipeline_id, epoch); + + api.add_stacking_context(sc, pipeline_id, epoch) + } +} + +impl WebRenderDisplayListConverter for Box<DisplayList> { + fn convert_to_webrender(&self, + api: &webrender_traits::RenderApi, + pipeline_id: webrender_traits::PipelineId, + epoch: webrender_traits::Epoch) -> webrender_traits::DisplayListBuilder { + let mut builder = webrender_traits::DisplayListBuilder::new(); + + for item in &self.background_and_borders { + item.convert_to_webrender(api, + pipeline_id, + epoch, + webrender_traits::StackingLevel::BackgroundAndBorders, + &mut builder); + } + + for item in &self.block_backgrounds_and_borders { + item.convert_to_webrender(api, + pipeline_id, + epoch, + webrender_traits::StackingLevel::BlockBackgroundAndBorders, + &mut builder); + } + + for item in &self.floats { + item.convert_to_webrender(api, + pipeline_id, + epoch, + webrender_traits::StackingLevel::Floats, + &mut builder); + } + + for item in &self.content { + item.convert_to_webrender(api, + pipeline_id, + epoch, + webrender_traits::StackingLevel::Content, + &mut builder); + } + + for item in &self.positioned_content { + item.convert_to_webrender(api, + pipeline_id, + epoch, + webrender_traits::StackingLevel::PositionedContent, + &mut builder); + } + + for item in &self.outlines { + item.convert_to_webrender(api, + pipeline_id, + epoch, + webrender_traits::StackingLevel::Outlines, + &mut builder); + } + + builder + } +} + +impl WebRenderDisplayItemConverter for DisplayItem { + fn convert_to_webrender(&self, + api: &webrender_traits::RenderApi, + pipeline_id: webrender_traits::PipelineId, + epoch: webrender_traits::Epoch, + level: webrender_traits::StackingLevel, + builder: &mut webrender_traits::DisplayListBuilder) { + match *self { + DisplayItem::SolidColorClass(ref item) => { + let color = item.color.to_colorf(); + if color.a > 0.0 { + builder.push_rect(level, + item.base.bounds.to_rectf(), + item.base.clip.to_clip_region(), + color); + } + } + DisplayItem::TextClass(ref item) => { + let mut origin = item.baseline_origin.clone(); + let mut glyphs = vec!(); + + for slice in item.text_run.natural_word_slices_in_visual_order(&item.range) { + for glyph in slice.glyphs.iter_glyphs_for_char_range(&slice.range) { + let glyph_advance = glyph.advance(); + let glyph_offset = glyph.offset().unwrap_or(Point2D::zero()); + let glyph = webrender_traits::GlyphInstance { + index: glyph.id(), + x: (origin.x + glyph_offset.x).to_f32_px(), + y: (origin.y + glyph_offset.y).to_f32_px(), + }; + origin = Point2D::new(origin.x + glyph_advance, origin.y); + glyphs.push(glyph); + }; + } + + if glyphs.len() > 0 { + builder.push_text(level, + item.base.bounds.to_rectf(), + item.base.clip.to_clip_region(), + glyphs, + item.text_run.font_key.expect("Font not added to webrender!"), + item.text_color.to_colorf(), + item.text_run.actual_pt_size, + item.blur_radius); + } + } + DisplayItem::ImageClass(ref item) => { + if let Some(id) = item.image.id { + if item.stretch_size.width > Au(0) && + item.stretch_size.height > Au(0) { + builder.push_image(level, + item.base.bounds.to_rectf(), + item.base.clip.to_clip_region(), + item.stretch_size.to_sizef(), + item.image_rendering.to_image_rendering(), + id); + } + } + } + DisplayItem::WebGLClass(ref item) => { + builder.push_webgl_canvas(level, + item.base.bounds.to_rectf(), + item.base.clip.to_clip_region(), + item.context_id); + } + DisplayItem::BorderClass(ref item) => { + let rect = item.base.bounds.to_rectf(); + let left = webrender_traits::BorderSide { + width: item.border_widths.left.to_f32_px(), + color: item.color.left.to_colorf(), + style: item.style.left.to_border_style(), + }; + let top = webrender_traits::BorderSide { + width: item.border_widths.top.to_f32_px(), + color: item.color.top.to_colorf(), + style: item.style.top.to_border_style(), + }; + let right = webrender_traits::BorderSide { + width: item.border_widths.right.to_f32_px(), + color: item.color.right.to_colorf(), + style: item.style.right.to_border_style(), + }; + let bottom = webrender_traits::BorderSide { + width: item.border_widths.bottom.to_f32_px(), + color: item.color.bottom.to_colorf(), + style: item.style.bottom.to_border_style(), + }; + let radius = item.radius.to_border_radius(); + builder.push_border(level, + rect, + item.base.clip.to_clip_region(), + left, + top, + right, + bottom, + radius); + } + DisplayItem::GradientClass(ref item) => { + let rect = item.base.bounds.to_rectf(); + let start_point = item.start_point.to_pointf(); + let end_point = item.end_point.to_pointf(); + let mut stops = Vec::new(); + for stop in &item.stops { + stops.push(stop.to_gradient_stop()); + } + builder.push_gradient(level, + rect, + item.base.clip.to_clip_region(), + start_point, + end_point, + stops); + } + DisplayItem::LineClass(..) => { + println!("TODO DisplayItem::LineClass"); + } + DisplayItem::LayeredItemClass(..) | + DisplayItem::NoopClass(..) => { + panic!("Unexpected in webrender!"); + } + DisplayItem::BoxShadowClass(ref item) => { + let rect = item.base.bounds.to_rectf(); + let box_bounds = item.box_bounds.to_rectf(); + builder.push_box_shadow(level, + rect, + item.base.clip.to_clip_region(), + box_bounds, + item.offset.to_pointf(), + item.color.to_colorf(), + item.blur_radius.to_f32_px(), + item.spread_radius.to_f32_px(), + item.border_radius.to_f32_px(), + item.clip_mode.to_clip_mode()); + } + DisplayItem::IframeClass(ref item) => { + let rect = item.base.bounds.to_rectf(); + let pipeline_id = item.iframe.to_webrender(); + builder.push_iframe(level, + rect, + item.base.clip.to_clip_region(), + pipeline_id); + } + DisplayItem::StackingContextClass(ref item) => { + let stacking_context_id = item.convert_to_webrender(api, + pipeline_id, + epoch, + None); + builder.push_stacking_context(level, stacking_context_id); + } + } + } +} |