aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2016-02-19 00:54:06 +0530
committerbors-servo <lbergstrom+bors@mozilla.com>2016-02-19 00:54:06 +0530
commitab07b06823ea9748a6091aee2281495f86f00bce (patch)
tree2dd06ac4834d5bc4bcba6e4ada3aab12bb2c12d9 /components/layout
parentfe70efe07f6d72665f10c752884e5705d5bdc600 (diff)
parentc0531c312fdb0783e4d121b4c2d7f15d4f5cdc1f (diff)
downloadservo-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.toml3
-rw-r--r--components/layout/display_list_builder.rs126
-rw-r--r--components/layout/layout_thread.rs56
-rw-r--r--components/layout/lib.rs2
-rw-r--r--components/layout/webrender_helpers.rs481
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);
+ }
+ }
+ }
+}