mirror of
https://github.com/servo/servo.git
synced 2025-08-02 20:20:14 +01:00
Use new webrender rounded clip API.
This commit is contained in:
parent
eb2f7f7f0a
commit
af05da574b
5 changed files with 61 additions and 106 deletions
|
@ -14,7 +14,9 @@ use crate::display_list::background::{self, get_cyclic};
|
||||||
use crate::display_list::border;
|
use crate::display_list::border;
|
||||||
use crate::display_list::gradient;
|
use crate::display_list::gradient;
|
||||||
use crate::display_list::items::{self, BaseDisplayItem, ClipScrollNode};
|
use crate::display_list::items::{self, BaseDisplayItem, ClipScrollNode};
|
||||||
use crate::display_list::items::{ClipScrollNodeIndex, ClipScrollNodeType, ClippingAndScrolling};
|
use crate::display_list::items::{
|
||||||
|
ClipScrollNodeIndex, ClipScrollNodeType, ClipType, ClippingAndScrolling,
|
||||||
|
};
|
||||||
use crate::display_list::items::{ClippingRegion, DisplayItem, DisplayItemMetadata, DisplayList};
|
use crate::display_list::items::{ClippingRegion, DisplayItem, DisplayItemMetadata, DisplayList};
|
||||||
use crate::display_list::items::{CommonDisplayItem, DisplayListSection};
|
use crate::display_list::items::{CommonDisplayItem, DisplayListSection};
|
||||||
use crate::display_list::items::{IframeDisplayItem, OpaqueNode};
|
use crate::display_list::items::{IframeDisplayItem, OpaqueNode};
|
||||||
|
@ -424,15 +426,8 @@ impl<'a> DisplayListBuildState<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_late_clip_node(&mut self, rect: LayoutRect, radii: BorderRadius) -> ClipScrollNodeIndex {
|
fn add_late_clip_node(&mut self, rect: LayoutRect, radii: BorderRadius) -> ClipScrollNodeIndex {
|
||||||
let mut clip = ClippingRegion::from_rect(rect);
|
let node =
|
||||||
clip.intersect_with_rounded_rect(rect, radii);
|
ClipScrollNode::rounded(rect, radii, self.current_clipping_and_scrolling.scrolling);
|
||||||
|
|
||||||
let node = ClipScrollNode {
|
|
||||||
parent_index: self.current_clipping_and_scrolling.scrolling,
|
|
||||||
clip,
|
|
||||||
content_rect: LayoutRect::zero(), // content_rect isn't important for clips.
|
|
||||||
node_type: ClipScrollNodeType::Clip,
|
|
||||||
};
|
|
||||||
|
|
||||||
// We want the scroll root to be defined before any possible item that could use it,
|
// We want the scroll root to be defined before any possible item that could use it,
|
||||||
// so we make sure that it is added to the beginning of the parent "real" (non-pseudo)
|
// so we make sure that it is added to the beginning of the parent "real" (non-pseudo)
|
||||||
|
@ -2643,10 +2638,18 @@ impl BlockFlow {
|
||||||
.to_physical(self.fragment.style.writing_mode);
|
.to_physical(self.fragment.style.writing_mode);
|
||||||
let clip_rect = border_box.inner_rect(border_widths);
|
let clip_rect = border_box.inner_rect(border_widths);
|
||||||
|
|
||||||
let mut clip = ClippingRegion::from_rect(clip_rect.to_layout());
|
let clip = ClippingRegion::from_rect(clip_rect.to_layout());
|
||||||
let radii = build_border_radius_for_inner_rect(border_box, &self.fragment.style);
|
let radii = build_border_radius_for_inner_rect(border_box, &self.fragment.style);
|
||||||
if !radii.is_zero() {
|
if !radii.is_zero() {
|
||||||
clip.intersect_with_rounded_rect(clip_rect.to_layout(), radii)
|
let node = ClipScrollNode::rounded(
|
||||||
|
clip_rect.to_layout(),
|
||||||
|
radii,
|
||||||
|
state.current_clipping_and_scrolling.scrolling,
|
||||||
|
);
|
||||||
|
let clip_id = state.add_clip_scroll_node(node);
|
||||||
|
let new_clipping_and_scrolling = ClippingAndScrolling::simple(clip_id);
|
||||||
|
self.base.clipping_and_scrolling = Some(new_clipping_and_scrolling);
|
||||||
|
state.current_clipping_and_scrolling = new_clipping_and_scrolling;
|
||||||
}
|
}
|
||||||
|
|
||||||
let content_size = self.base.overflow.scroll.origin + self.base.overflow.scroll.size;
|
let content_size = self.base.overflow.scroll.origin + self.base.overflow.scroll.size;
|
||||||
|
@ -2713,7 +2716,7 @@ impl BlockFlow {
|
||||||
parent_index: self.clipping_and_scrolling().scrolling,
|
parent_index: self.clipping_and_scrolling().scrolling,
|
||||||
clip: ClippingRegion::from_rect(clip_rect.to_layout()),
|
clip: ClippingRegion::from_rect(clip_rect.to_layout()),
|
||||||
content_rect: LayoutRect::zero(), // content_rect isn't important for clips.
|
content_rect: LayoutRect::zero(), // content_rect isn't important for clips.
|
||||||
node_type: ClipScrollNodeType::Clip,
|
node_type: ClipScrollNodeType::Clip(ClipType::Rect),
|
||||||
});
|
});
|
||||||
|
|
||||||
let new_indices = ClippingAndScrolling::new(new_index, new_index);
|
let new_indices = ClippingAndScrolling::new(new_index, new_index);
|
||||||
|
|
|
@ -24,7 +24,7 @@ use std::f32;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style::computed_values::_servo_top_layer::T as InTopLayer;
|
use style::computed_values::_servo_top_layer::T as InTopLayer;
|
||||||
use webrender_api as wr;
|
use webrender_api as wr;
|
||||||
use webrender_api::units::{LayoutPixel, LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
|
use webrender_api::units::{LayoutPixel, LayoutRect, LayoutTransform};
|
||||||
use webrender_api::{
|
use webrender_api::{
|
||||||
BorderRadius, ClipId, ClipMode, CommonItemProperties, ComplexClipRegion, ExternalScrollId,
|
BorderRadius, ClipId, ClipMode, CommonItemProperties, ComplexClipRegion, ExternalScrollId,
|
||||||
FilterOp, GlyphInstance, GradientStop, ImageKey, MixBlendMode, PrimitiveFlags,
|
FilterOp, GlyphInstance, GradientStop, ImageKey, MixBlendMode, PrimitiveFlags,
|
||||||
|
@ -334,12 +334,18 @@ pub struct StickyFrameData {
|
||||||
pub horizontal_offset_bounds: StickyOffsetBounds,
|
pub horizontal_offset_bounds: StickyOffsetBounds,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
|
||||||
|
pub enum ClipType {
|
||||||
|
Rounded(ComplexClipRegion),
|
||||||
|
Rect,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||||
pub enum ClipScrollNodeType {
|
pub enum ClipScrollNodeType {
|
||||||
Placeholder,
|
Placeholder,
|
||||||
ScrollFrame(ScrollSensitivity, ExternalScrollId),
|
ScrollFrame(ScrollSensitivity, ExternalScrollId),
|
||||||
StickyFrame(StickyFrameData),
|
StickyFrame(StickyFrameData),
|
||||||
Clip,
|
Clip(ClipType),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines a clip scroll node.
|
/// Defines a clip scroll node.
|
||||||
|
@ -371,6 +377,24 @@ impl ClipScrollNode {
|
||||||
pub fn is_placeholder(&self) -> bool {
|
pub fn is_placeholder(&self) -> bool {
|
||||||
self.node_type == ClipScrollNodeType::Placeholder
|
self.node_type == ClipScrollNodeType::Placeholder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rounded(
|
||||||
|
clip_rect: LayoutRect,
|
||||||
|
radii: BorderRadius,
|
||||||
|
parent_index: ClipScrollNodeIndex,
|
||||||
|
) -> ClipScrollNode {
|
||||||
|
let complex_region = ComplexClipRegion {
|
||||||
|
rect: clip_rect,
|
||||||
|
radii,
|
||||||
|
mode: ClipMode::Clip,
|
||||||
|
};
|
||||||
|
ClipScrollNode {
|
||||||
|
parent_index,
|
||||||
|
clip: ClippingRegion::from_rect(clip_rect),
|
||||||
|
content_rect: LayoutRect::zero(), // content_rect isn't important for clips.
|
||||||
|
node_type: ClipScrollNodeType::Clip(ClipType::Rounded(complex_region)),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// One drawing command in the list.
|
/// One drawing command in the list.
|
||||||
|
@ -465,11 +489,6 @@ pub fn empty_common_item_properties() -> CommonItemProperties {
|
||||||
pub struct ClippingRegion {
|
pub struct ClippingRegion {
|
||||||
/// The main rectangular region. This does not include any corners.
|
/// The main rectangular region. This does not include any corners.
|
||||||
pub main: LayoutRect,
|
pub main: LayoutRect,
|
||||||
/// Any complex regions.
|
|
||||||
///
|
|
||||||
/// TODO(pcwalton): Atomically reference count these? Not sure if it's worth the trouble.
|
|
||||||
/// Measure and follow up.
|
|
||||||
pub complex: Vec<ComplexClipRegion>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClippingRegion {
|
impl ClippingRegion {
|
||||||
|
@ -478,7 +497,6 @@ impl ClippingRegion {
|
||||||
pub fn empty() -> ClippingRegion {
|
pub fn empty() -> ClippingRegion {
|
||||||
ClippingRegion {
|
ClippingRegion {
|
||||||
main: LayoutRect::zero(),
|
main: LayoutRect::zero(),
|
||||||
complex: Vec::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,45 +505,13 @@ impl ClippingRegion {
|
||||||
pub fn max() -> ClippingRegion {
|
pub fn max() -> ClippingRegion {
|
||||||
ClippingRegion {
|
ClippingRegion {
|
||||||
main: LayoutRect::max_rect(),
|
main: LayoutRect::max_rect(),
|
||||||
complex: Vec::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a clipping region that represents the given rectangle.
|
/// Returns a clipping region that represents the given rectangle.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_rect(rect: LayoutRect) -> ClippingRegion {
|
pub fn from_rect(rect: LayoutRect) -> ClippingRegion {
|
||||||
ClippingRegion {
|
ClippingRegion { main: rect }
|
||||||
main: rect,
|
|
||||||
complex: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Intersects this clipping region with the given rounded rectangle.
|
|
||||||
#[inline]
|
|
||||||
pub fn intersect_with_rounded_rect(&mut self, rect: LayoutRect, radii: BorderRadius) {
|
|
||||||
let new_complex_region = ComplexClipRegion {
|
|
||||||
rect,
|
|
||||||
radii,
|
|
||||||
mode: ClipMode::Clip,
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME(pcwalton): This is O(n²) worst case for disjoint clipping regions. Is that OK?
|
|
||||||
// They're slow anyway…
|
|
||||||
//
|
|
||||||
// Possibly relevant if we want to do better:
|
|
||||||
//
|
|
||||||
// http://www.inrg.csie.ntu.edu.tw/algorithm2014/presentation/D&C%20Lee-84.pdf
|
|
||||||
for existing_complex_region in &mut self.complex {
|
|
||||||
if completely_encloses(&existing_complex_region, &new_complex_region) {
|
|
||||||
*existing_complex_region = new_complex_region;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if completely_encloses(&new_complex_region, &existing_complex_region) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.complex.push(new_complex_region);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,46 +521,12 @@ impl fmt::Debug for ClippingRegion {
|
||||||
write!(f, "ClippingRegion::Max")
|
write!(f, "ClippingRegion::Max")
|
||||||
} else if *self == ClippingRegion::empty() {
|
} else if *self == ClippingRegion::empty() {
|
||||||
write!(f, "ClippingRegion::Empty")
|
write!(f, "ClippingRegion::Empty")
|
||||||
} else if self.main == LayoutRect::max_rect() {
|
|
||||||
write!(f, "ClippingRegion(Complex={:?})", self.complex)
|
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(f, "ClippingRegion(Rect={:?})", self.main,)
|
||||||
f,
|
|
||||||
"ClippingRegion(Rect={:?}, Complex={:?})",
|
|
||||||
self.main, self.complex
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): This could be more aggressive by considering points that touch the inside of
|
|
||||||
// the border radius ellipse.
|
|
||||||
fn completely_encloses(this: &ComplexClipRegion, other: &ComplexClipRegion) -> bool {
|
|
||||||
let left = this.radii.top_left.width.max(this.radii.bottom_left.width);
|
|
||||||
let top = this.radii.top_left.height.max(this.radii.top_right.height);
|
|
||||||
let right = this
|
|
||||||
.radii
|
|
||||||
.top_right
|
|
||||||
.width
|
|
||||||
.max(this.radii.bottom_right.width);
|
|
||||||
let bottom = this
|
|
||||||
.radii
|
|
||||||
.bottom_left
|
|
||||||
.height
|
|
||||||
.max(this.radii.bottom_right.height);
|
|
||||||
let interior = LayoutRect::new(
|
|
||||||
LayoutPoint::new(this.rect.origin.x + left, this.rect.origin.y + top),
|
|
||||||
LayoutSize::new(
|
|
||||||
this.rect.size.width - left - right,
|
|
||||||
this.rect.size.height - top - bottom,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
interior.origin.x <= other.rect.origin.x &&
|
|
||||||
interior.origin.y <= other.rect.origin.y &&
|
|
||||||
interior.max_x() >= other.rect.max_x() &&
|
|
||||||
interior.max_y() >= other.rect.max_y()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Metadata attached to each display item. This is useful for performing auxiliary threads with
|
/// Metadata attached to each display item. This is useful for performing auxiliary threads with
|
||||||
/// the display list involving hit testing: finding the originating DOM node and determining the
|
/// the display list involving hit testing: finding the originating DOM node and determining the
|
||||||
/// cursor to use when the element is hovered over.
|
/// cursor to use when the element is hovered over.
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
// This might be achieved by sharing types between WR and Servo display lists, or
|
// 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.
|
// completely converting layout to directly generate WebRender display lists, for example.
|
||||||
|
|
||||||
use crate::display_list::items::{BaseDisplayItem, ClipScrollNode, ClipScrollNodeType};
|
use crate::display_list::items::{BaseDisplayItem, ClipScrollNode, ClipScrollNodeType, ClipType};
|
||||||
use crate::display_list::items::{DisplayItem, DisplayList, StackingContextType};
|
use crate::display_list::items::{DisplayItem, DisplayList, StackingContextType};
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use webrender_api::units::LayoutPoint;
|
use webrender_api::units::LayoutPoint;
|
||||||
|
@ -269,15 +269,19 @@ impl DisplayItem {
|
||||||
.expect("Tried to use WebRender parent ClipId before it was defined.");
|
.expect("Tried to use WebRender parent ClipId before it was defined.");
|
||||||
|
|
||||||
match node.node_type {
|
match node.node_type {
|
||||||
ClipScrollNodeType::Clip => {
|
ClipScrollNodeType::Clip(clip_type) => {
|
||||||
let id = builder.define_clip(
|
let space_and_clip_info = SpaceAndClipInfo {
|
||||||
&SpaceAndClipInfo {
|
clip_id: parent_clip_id,
|
||||||
clip_id: parent_clip_id,
|
spatial_id: parent_spatial_id,
|
||||||
spatial_id: parent_spatial_id,
|
};
|
||||||
|
let id = match clip_type {
|
||||||
|
ClipType::Rect => {
|
||||||
|
builder.define_clip_rect(&space_and_clip_info, item_rect)
|
||||||
},
|
},
|
||||||
item_rect,
|
ClipType::Rounded(complex) => {
|
||||||
node.clip.complex.clone(),
|
builder.define_clip_rounded_rect(&space_and_clip_info, complex)
|
||||||
);
|
},
|
||||||
|
};
|
||||||
|
|
||||||
state.spatial_ids[item.node_index.to_index()] = Some(parent_spatial_id);
|
state.spatial_ids[item.node_index.to_index()] = Some(parent_spatial_id);
|
||||||
state.clip_ids[item.node_index.to_index()] = Some(id);
|
state.clip_ids[item.node_index.to_index()] = Some(id);
|
||||||
|
@ -291,7 +295,6 @@ impl DisplayItem {
|
||||||
Some(external_id),
|
Some(external_id),
|
||||||
node.content_rect,
|
node.content_rect,
|
||||||
node.clip.main,
|
node.clip.main,
|
||||||
node.clip.complex.clone(),
|
|
||||||
scroll_sensitivity,
|
scroll_sensitivity,
|
||||||
webrender_api::units::LayoutVector2D::zero(),
|
webrender_api::units::LayoutVector2D::zero(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -344,7 +344,7 @@ impl<'a> BuilderForBoxFragment<'a> {
|
||||||
let (bounds, common) = background::painting_area(self, builder, layer_index);
|
let (bounds, common) = background::painting_area(self, builder, layer_index);
|
||||||
builder
|
builder
|
||||||
.wr
|
.wr
|
||||||
.push_rect(&common, bounds, rgba(background_color))
|
.push_rect(&common, *bounds, rgba(background_color))
|
||||||
}
|
}
|
||||||
// Reverse because the property is top layer first, we want to paint bottom layer first.
|
// Reverse because the property is top layer first, we want to paint bottom layer first.
|
||||||
for (index, image) in b.background_image.0.iter().enumerate().rev() {
|
for (index, image) in b.background_image.0.iter().enumerate().rev() {
|
||||||
|
@ -589,14 +589,13 @@ fn clip_for_radii(
|
||||||
if radii.is_zero() {
|
if radii.is_zero() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(builder.wr.define_clip(
|
Some(builder.wr.define_clip_rounded_rect(
|
||||||
&builder.current_space_and_clip,
|
&builder.current_space_and_clip,
|
||||||
rect,
|
wr::ComplexClipRegion {
|
||||||
Some(wr::ComplexClipRegion {
|
|
||||||
rect,
|
rect,
|
||||||
radii,
|
radii,
|
||||||
mode: wr::ClipMode::Clip,
|
mode: wr::ClipMode::Clip,
|
||||||
}),
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -605,8 +605,6 @@ impl BoxFragment {
|
||||||
self.scrollable_overflow(&containing_block_info.rect)
|
self.scrollable_overflow(&containing_block_info.rect)
|
||||||
.to_webrender(),
|
.to_webrender(),
|
||||||
padding_rect,
|
padding_rect,
|
||||||
vec![], // complex_clips
|
|
||||||
None, // image_mask
|
|
||||||
sensitivity,
|
sensitivity,
|
||||||
LayoutVector2D::zero(),
|
LayoutVector2D::zero(),
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue