mirror of
https://github.com/servo/servo.git
synced 2025-06-14 11:24:33 +00:00
Remove the concept of nested stacking contexts from display list builder <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [x] These changes do not require tests because they should not change behavior. <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> With the removal of the legacy rendering path, we don't need to worry about nested stacking contexts. This change just pushes the complication to the WebRender conversion step, but a later change will remove the concept from WebRender as well. This also helps to prepare for the introduction of ids for particular scrolling regions, an integral part of multiple ScrollLayers per block. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13820) <!-- Reviewable:end -->
625 lines
29 KiB
Rust
625 lines
29 KiB
Rust
/* 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::{Matrix4D, Point2D, Rect, Size2D};
|
|
use gfx::display_list::{BorderRadii, BoxShadowClipMode, ClippingRegion};
|
|
use gfx::display_list::{DisplayItem, DisplayList, DisplayListTraversal};
|
|
use gfx::display_list::{GradientStop, StackingContext, StackingContextType};
|
|
use gfx_traits::{FragmentType, ScrollPolicy, StackingContextId};
|
|
use style::computed_values::{image_rendering, mix_blend_mode};
|
|
use style::computed_values::filter::{self, Filter};
|
|
use style::values::computed::BorderStyle;
|
|
use webrender_traits::{self, AuxiliaryListsBuilder, DisplayListId, PipelineId};
|
|
|
|
trait WebRenderStackingContextConverter {
|
|
fn convert_to_webrender<'a>(&self,
|
|
traversal: &mut DisplayListTraversal<'a>,
|
|
api: &mut webrender_traits::RenderApi,
|
|
pipeline_id: webrender_traits::PipelineId,
|
|
epoch: webrender_traits::Epoch,
|
|
scroll_layer_id: Option<webrender_traits::ScrollLayerId>,
|
|
scroll_policy: ScrollPolicy,
|
|
frame_builder: &mut WebRenderFrameBuilder)
|
|
-> webrender_traits::StackingContextId;
|
|
|
|
fn convert_children_to_webrender<'a>(&self,
|
|
traversal: &mut DisplayListTraversal<'a>,
|
|
api: &mut webrender_traits::RenderApi,
|
|
pipeline_id: webrender_traits::PipelineId,
|
|
epoch: webrender_traits::Epoch,
|
|
scroll_layer_id: Option<webrender_traits::ScrollLayerId>,
|
|
scroll_policy: ScrollPolicy,
|
|
builder: &mut webrender_traits::DisplayListBuilder,
|
|
frame_builder: &mut WebRenderFrameBuilder,
|
|
force_positioned_stacking_level: bool);
|
|
}
|
|
|
|
pub trait WebRenderDisplayListConverter {
|
|
fn convert_to_webrender(&self,
|
|
api: &mut webrender_traits::RenderApi,
|
|
pipeline_id: webrender_traits::PipelineId,
|
|
epoch: webrender_traits::Epoch,
|
|
scroll_layer_id: Option<webrender_traits::ScrollLayerId>,
|
|
frame_builder: &mut WebRenderFrameBuilder)
|
|
-> webrender_traits::StackingContextId;
|
|
}
|
|
|
|
trait WebRenderDisplayItemConverter {
|
|
fn convert_to_webrender(&self,
|
|
builder: &mut webrender_traits::DisplayListBuilder,
|
|
frame_builder: &mut WebRenderFrameBuilder);
|
|
}
|
|
|
|
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, frame_builder: &mut WebRenderFrameBuilder)
|
|
-> webrender_traits::ClipRegion;
|
|
}
|
|
|
|
impl ToClipRegion for ClippingRegion {
|
|
fn to_clip_region(&self, frame_builder: &mut WebRenderFrameBuilder)
|
|
-> 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(),
|
|
&mut frame_builder.auxiliary_lists_builder)
|
|
}
|
|
}
|
|
|
|
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_children_to_webrender<'a>(&self,
|
|
traversal: &mut DisplayListTraversal<'a>,
|
|
api: &mut webrender_traits::RenderApi,
|
|
pipeline_id: webrender_traits::PipelineId,
|
|
epoch: webrender_traits::Epoch,
|
|
scroll_layer_id: Option<webrender_traits::ScrollLayerId>,
|
|
scroll_policy: ScrollPolicy,
|
|
builder: &mut webrender_traits::DisplayListBuilder,
|
|
frame_builder: &mut WebRenderFrameBuilder,
|
|
_force_positioned_stacking_level: bool) {
|
|
while let Some(item) = traversal.next() {
|
|
match item {
|
|
&DisplayItem::PushStackingContext(ref stacking_context_item) => {
|
|
let stacking_context = &stacking_context_item.stacking_context;
|
|
debug_assert!(stacking_context.context_type == StackingContextType::Real);
|
|
|
|
let scroll_layer_id_for_children = if self.overflow_scroll_id.is_some() {
|
|
scroll_layer_id
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let stacking_context_id =
|
|
stacking_context.convert_to_webrender(traversal,
|
|
api,
|
|
pipeline_id,
|
|
epoch,
|
|
scroll_layer_id_for_children,
|
|
scroll_policy,
|
|
frame_builder);
|
|
builder.push_stacking_context(stacking_context_id);
|
|
|
|
}
|
|
&DisplayItem::PopStackingContext(_) => return,
|
|
_ => item.convert_to_webrender(builder, frame_builder),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn convert_to_webrender<'a>(&self,
|
|
traversal: &mut DisplayListTraversal<'a>,
|
|
api: &mut webrender_traits::RenderApi,
|
|
pipeline_id: webrender_traits::PipelineId,
|
|
epoch: webrender_traits::Epoch,
|
|
scroll_layer_id: Option<webrender_traits::ScrollLayerId>,
|
|
mut scroll_policy: ScrollPolicy,
|
|
frame_builder: &mut WebRenderFrameBuilder)
|
|
-> webrender_traits::StackingContextId {
|
|
if let Some(ref layer_info) = self.layer_info {
|
|
scroll_policy = layer_info.scroll_policy
|
|
}
|
|
|
|
let webrender_scroll_policy = match scroll_policy {
|
|
ScrollPolicy::Scrollable => webrender_traits::ScrollPolicy::Scrollable,
|
|
ScrollPolicy::FixedPosition => webrender_traits::ScrollPolicy::Fixed,
|
|
};
|
|
|
|
let webrender_stacking_context_id = self.id.convert_to_webrender();
|
|
|
|
let outer_overflow = if self.overflow_scroll_id.is_none() {
|
|
self.overflow.to_rectf()
|
|
} else {
|
|
Rect::new(Point2D::zero(), self.bounds.size).to_rectf()
|
|
};
|
|
|
|
let mut sc =
|
|
webrender_traits::StackingContext::new(webrender_stacking_context_id,
|
|
scroll_layer_id,
|
|
webrender_scroll_policy,
|
|
self.bounds.to_rectf(),
|
|
outer_overflow,
|
|
self.z_index,
|
|
&self.transform,
|
|
&self.perspective,
|
|
self.establishes_3d_context,
|
|
self.blend_mode.to_blend_mode(),
|
|
self.filters.to_filter_ops(),
|
|
&mut frame_builder.auxiliary_lists_builder);
|
|
|
|
let mut builder = webrender_traits::DisplayListBuilder::new();
|
|
|
|
if let Some(inner_stacking_context_id) = self.overflow_scroll_id {
|
|
let inner_webrender_stacking_context_id =
|
|
inner_stacking_context_id.convert_to_webrender();
|
|
let mut inner_sc =
|
|
webrender_traits::StackingContext::new(inner_webrender_stacking_context_id,
|
|
Some(frame_builder.next_scroll_layer_id()),
|
|
webrender_scroll_policy,
|
|
self.overflow.to_rectf(),
|
|
self.overflow.to_rectf(),
|
|
self.z_index,
|
|
&Matrix4D::identity(),
|
|
&Matrix4D::identity(),
|
|
false,
|
|
webrender_traits::MixBlendMode::Normal,
|
|
Vec::new(),
|
|
&mut frame_builder.auxiliary_lists_builder);
|
|
let mut inner_builder = webrender_traits::DisplayListBuilder::new();
|
|
self.convert_children_to_webrender(traversal,
|
|
api,
|
|
pipeline_id,
|
|
epoch,
|
|
None,
|
|
scroll_policy,
|
|
&mut inner_builder,
|
|
frame_builder,
|
|
false);
|
|
|
|
frame_builder.add_display_list(api, inner_builder.finalize(), &mut inner_sc);
|
|
let new_id = frame_builder.add_stacking_context(api, pipeline_id, inner_sc);
|
|
builder.push_stacking_context(new_id);
|
|
} else {
|
|
self.convert_children_to_webrender(traversal,
|
|
api,
|
|
pipeline_id,
|
|
epoch,
|
|
scroll_layer_id,
|
|
scroll_policy,
|
|
&mut builder,
|
|
frame_builder,
|
|
false);
|
|
}
|
|
|
|
|
|
frame_builder.add_display_list(api, builder.finalize(), &mut sc);
|
|
frame_builder.add_stacking_context(api, pipeline_id, sc)
|
|
}
|
|
}
|
|
|
|
impl WebRenderDisplayListConverter for DisplayList {
|
|
fn convert_to_webrender(&self,
|
|
api: &mut webrender_traits::RenderApi,
|
|
pipeline_id: webrender_traits::PipelineId,
|
|
epoch: webrender_traits::Epoch,
|
|
scroll_layer_id: Option<webrender_traits::ScrollLayerId>,
|
|
frame_builder: &mut WebRenderFrameBuilder)
|
|
-> webrender_traits::StackingContextId {
|
|
let mut traversal = DisplayListTraversal::new(self);
|
|
let item = traversal.next();
|
|
match item {
|
|
Some(&DisplayItem::PushStackingContext(ref stacking_context_item)) => {
|
|
let stacking_context = &stacking_context_item.stacking_context;
|
|
stacking_context.convert_to_webrender(&mut traversal,
|
|
api,
|
|
pipeline_id,
|
|
epoch,
|
|
scroll_layer_id,
|
|
ScrollPolicy::Scrollable,
|
|
frame_builder)
|
|
}
|
|
_ => unreachable!("DisplayList did not start with StackingContext."),
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
impl WebRenderDisplayItemConverter for DisplayItem {
|
|
fn convert_to_webrender(&self,
|
|
builder: &mut webrender_traits::DisplayListBuilder,
|
|
frame_builder: &mut WebRenderFrameBuilder) {
|
|
match *self {
|
|
DisplayItem::SolidColor(ref item) => {
|
|
let color = item.color.to_colorf();
|
|
if color.a > 0.0 {
|
|
builder.push_rect(item.base.bounds.to_rectf(),
|
|
item.base.clip.to_clip_region(frame_builder),
|
|
color);
|
|
}
|
|
}
|
|
DisplayItem::Text(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_byte_range(&slice.range) {
|
|
let glyph_advance = if glyph.char_is_space() {
|
|
glyph.advance() + item.text_run.extra_word_spacing
|
|
} else {
|
|
glyph.advance()
|
|
};
|
|
if !slice.glyphs.is_whitespace() {
|
|
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(),
|
|
};
|
|
glyphs.push(glyph);
|
|
}
|
|
origin.x = origin.x + glyph_advance;
|
|
};
|
|
}
|
|
|
|
if glyphs.len() > 0 {
|
|
builder.push_text(item.base.bounds.to_rectf(),
|
|
item.base.clip.to_clip_region(frame_builder),
|
|
glyphs,
|
|
item.text_run.font_key,
|
|
item.text_color.to_colorf(),
|
|
item.text_run.actual_pt_size,
|
|
item.blur_radius,
|
|
&mut frame_builder.auxiliary_lists_builder);
|
|
}
|
|
}
|
|
DisplayItem::Image(ref item) => {
|
|
if let Some(id) = item.webrender_image.key {
|
|
if item.stretch_size.width > Au(0) &&
|
|
item.stretch_size.height > Au(0) {
|
|
builder.push_image(item.base.bounds.to_rectf(),
|
|
item.base.clip.to_clip_region(frame_builder),
|
|
item.stretch_size.to_sizef(),
|
|
item.tile_spacing.to_sizef(),
|
|
item.image_rendering.to_image_rendering(),
|
|
id);
|
|
}
|
|
}
|
|
}
|
|
DisplayItem::WebGL(ref item) => {
|
|
builder.push_webgl_canvas(item.base.bounds.to_rectf(),
|
|
item.base.clip.to_clip_region(frame_builder),
|
|
item.context_id);
|
|
}
|
|
DisplayItem::Border(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(rect,
|
|
item.base.clip.to_clip_region(frame_builder),
|
|
left,
|
|
top,
|
|
right,
|
|
bottom,
|
|
radius);
|
|
}
|
|
DisplayItem::Gradient(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(rect,
|
|
item.base.clip.to_clip_region(frame_builder),
|
|
start_point,
|
|
end_point,
|
|
stops,
|
|
&mut frame_builder.auxiliary_lists_builder);
|
|
}
|
|
DisplayItem::Line(..) => {
|
|
println!("TODO DisplayItem::Line");
|
|
}
|
|
DisplayItem::BoxShadow(ref item) => {
|
|
let rect = item.base.bounds.to_rectf();
|
|
let box_bounds = item.box_bounds.to_rectf();
|
|
builder.push_box_shadow(rect,
|
|
item.base.clip.to_clip_region(frame_builder),
|
|
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::Iframe(ref item) => {
|
|
let rect = item.base.bounds.to_rectf();
|
|
let pipeline_id = item.iframe.to_webrender();
|
|
builder.push_iframe(rect,
|
|
item.base.clip.to_clip_region(frame_builder),
|
|
pipeline_id);
|
|
}
|
|
DisplayItem::PushStackingContext(_) | DisplayItem::PopStackingContext(_) => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct WebRenderFrameBuilder {
|
|
pub stacking_contexts: Vec<(webrender_traits::StackingContextId,
|
|
webrender_traits::StackingContext)>,
|
|
pub display_lists: Vec<(DisplayListId, webrender_traits::BuiltDisplayList)>,
|
|
pub auxiliary_lists_builder: AuxiliaryListsBuilder,
|
|
pub root_pipeline_id: PipelineId,
|
|
pub next_scroll_layer_id: usize,
|
|
}
|
|
|
|
impl WebRenderFrameBuilder {
|
|
pub fn new(root_pipeline_id: PipelineId) -> WebRenderFrameBuilder {
|
|
WebRenderFrameBuilder {
|
|
stacking_contexts: vec![],
|
|
display_lists: vec![],
|
|
auxiliary_lists_builder: AuxiliaryListsBuilder::new(),
|
|
root_pipeline_id: root_pipeline_id,
|
|
next_scroll_layer_id: 0,
|
|
}
|
|
}
|
|
|
|
pub fn add_stacking_context(&mut self,
|
|
api: &mut webrender_traits::RenderApi,
|
|
pipeline_id: PipelineId,
|
|
stacking_context: webrender_traits::StackingContext)
|
|
-> webrender_traits::StackingContextId {
|
|
assert!(pipeline_id == self.root_pipeline_id);
|
|
let id = api.next_stacking_context_id();
|
|
self.stacking_contexts.push((id, stacking_context));
|
|
id
|
|
}
|
|
|
|
pub fn add_display_list(&mut self,
|
|
api: &mut webrender_traits::RenderApi,
|
|
display_list: webrender_traits::BuiltDisplayList,
|
|
stacking_context: &mut webrender_traits::StackingContext)
|
|
-> DisplayListId {
|
|
let id = api.next_display_list_id();
|
|
stacking_context.has_stacking_contexts = stacking_context.has_stacking_contexts ||
|
|
display_list.descriptor().has_stacking_contexts;
|
|
stacking_context.display_lists.push(id);
|
|
self.display_lists.push((id, display_list));
|
|
id
|
|
}
|
|
|
|
pub fn next_scroll_layer_id(&mut self) -> webrender_traits::ScrollLayerId {
|
|
let scroll_layer_id = self.next_scroll_layer_id;
|
|
self.next_scroll_layer_id += 1;
|
|
webrender_traits::ScrollLayerId::new(self.root_pipeline_id, scroll_layer_id)
|
|
}
|
|
}
|
|
|
|
trait WebRenderStackingContextIdConverter {
|
|
fn convert_to_webrender(&self) -> webrender_traits::ServoStackingContextId;
|
|
}
|
|
|
|
impl WebRenderStackingContextIdConverter for StackingContextId {
|
|
fn convert_to_webrender(&self) -> webrender_traits::ServoStackingContextId {
|
|
webrender_traits::ServoStackingContextId(self.fragment_type().convert_to_webrender(),
|
|
self.id())
|
|
}
|
|
}
|
|
|
|
trait WebRenderFragmentTypeConverter {
|
|
fn convert_to_webrender(&self) -> webrender_traits::FragmentType;
|
|
}
|
|
|
|
impl WebRenderFragmentTypeConverter for FragmentType {
|
|
fn convert_to_webrender(&self) -> webrender_traits::FragmentType {
|
|
match *self {
|
|
FragmentType::FragmentBody => webrender_traits::FragmentType::FragmentBody,
|
|
FragmentType::BeforePseudoContent => {
|
|
webrender_traits::FragmentType::BeforePseudoContent
|
|
}
|
|
FragmentType::AfterPseudoContent => webrender_traits::FragmentType::AfterPseudoContent,
|
|
}
|
|
}
|
|
}
|