mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
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!
This commit is contained in:
parent
f7f0eea470
commit
c0531c312f
75 changed files with 2869 additions and 888 deletions
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
@ -50,8 +50,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
|
||||
}));
|
||||
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)));
|
||||
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,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
display_list.layer_info.push_back(
|
||||
LayerInfo::new(layer_id, ScrollPolicy::Scrollable, None));
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
SpecificFragmentInfo::UnscannedText(_) => {
|
||||
|
@ -1993,4 +2028,3 @@ pub enum StackingContextCreationMode {
|
|||
OuterScrollWrapper,
|
||||
InnerScrollWrapper,
|
||||
}
|
||||
|
||||
|
|
|
@ -1928,9 +1928,14 @@ impl InlineMetrics {
|
|||
#[inline]
|
||||
pub fn from_font_metrics(font_metrics: &FontMetrics, line_height: Au) -> InlineMetrics {
|
||||
let leading = line_height - (font_metrics.ascent + font_metrics.descent);
|
||||
// Calculating the half leading here and then using leading - half_leading
|
||||
// below ensure that we don't introduce any rounding accuracy issues here.
|
||||
// The invariant is that the resulting total line height must exactly
|
||||
// equal the requested line_height.
|
||||
let half_leading = leading.scale_by(0.5);
|
||||
InlineMetrics {
|
||||
block_size_above_baseline: font_metrics.ascent + leading.scale_by(0.5),
|
||||
depth_below_baseline: font_metrics.descent + leading.scale_by(0.5),
|
||||
block_size_above_baseline: font_metrics.ascent + half_leading,
|
||||
depth_below_baseline: font_metrics.descent + leading - half_leading,
|
||||
ascent: font_metrics.ascent,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
481
components/layout/webrender_helpers.rs
Normal file
481
components/layout/webrender_helpers.rs
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue