mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +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::gradient;
|
||||
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::{CommonDisplayItem, DisplayListSection};
|
||||
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 {
|
||||
let mut clip = ClippingRegion::from_rect(rect);
|
||||
clip.intersect_with_rounded_rect(rect, radii);
|
||||
|
||||
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,
|
||||
};
|
||||
let node =
|
||||
ClipScrollNode::rounded(rect, radii, self.current_clipping_and_scrolling.scrolling);
|
||||
|
||||
// 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)
|
||||
|
@ -2643,10 +2638,18 @@ impl BlockFlow {
|
|||
.to_physical(self.fragment.style.writing_mode);
|
||||
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);
|
||||
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;
|
||||
|
@ -2713,7 +2716,7 @@ impl BlockFlow {
|
|||
parent_index: self.clipping_and_scrolling().scrolling,
|
||||
clip: ClippingRegion::from_rect(clip_rect.to_layout()),
|
||||
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);
|
||||
|
|
|
@ -24,7 +24,7 @@ use std::f32;
|
|||
use std::fmt;
|
||||
use style::computed_values::_servo_top_layer::T as InTopLayer;
|
||||
use webrender_api as wr;
|
||||
use webrender_api::units::{LayoutPixel, LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
|
||||
use webrender_api::units::{LayoutPixel, LayoutRect, LayoutTransform};
|
||||
use webrender_api::{
|
||||
BorderRadius, ClipId, ClipMode, CommonItemProperties, ComplexClipRegion, ExternalScrollId,
|
||||
FilterOp, GlyphInstance, GradientStop, ImageKey, MixBlendMode, PrimitiveFlags,
|
||||
|
@ -334,12 +334,18 @@ pub struct StickyFrameData {
|
|||
pub horizontal_offset_bounds: StickyOffsetBounds,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
|
||||
pub enum ClipType {
|
||||
Rounded(ComplexClipRegion),
|
||||
Rect,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||
pub enum ClipScrollNodeType {
|
||||
Placeholder,
|
||||
ScrollFrame(ScrollSensitivity, ExternalScrollId),
|
||||
StickyFrame(StickyFrameData),
|
||||
Clip,
|
||||
Clip(ClipType),
|
||||
}
|
||||
|
||||
/// Defines a clip scroll node.
|
||||
|
@ -371,6 +377,24 @@ impl ClipScrollNode {
|
|||
pub fn is_placeholder(&self) -> bool {
|
||||
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.
|
||||
|
@ -465,11 +489,6 @@ pub fn empty_common_item_properties() -> CommonItemProperties {
|
|||
pub struct ClippingRegion {
|
||||
/// The main rectangular region. This does not include any corners.
|
||||
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 {
|
||||
|
@ -478,7 +497,6 @@ impl ClippingRegion {
|
|||
pub fn empty() -> ClippingRegion {
|
||||
ClippingRegion {
|
||||
main: LayoutRect::zero(),
|
||||
complex: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,45 +505,13 @@ impl ClippingRegion {
|
|||
pub fn max() -> ClippingRegion {
|
||||
ClippingRegion {
|
||||
main: LayoutRect::max_rect(),
|
||||
complex: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a clipping region that represents the given rectangle.
|
||||
#[inline]
|
||||
pub fn from_rect(rect: LayoutRect) -> ClippingRegion {
|
||||
ClippingRegion {
|
||||
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);
|
||||
ClippingRegion { main: rect }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,46 +521,12 @@ impl fmt::Debug for ClippingRegion {
|
|||
write!(f, "ClippingRegion::Max")
|
||||
} else if *self == ClippingRegion::empty() {
|
||||
write!(f, "ClippingRegion::Empty")
|
||||
} else if self.main == LayoutRect::max_rect() {
|
||||
write!(f, "ClippingRegion(Complex={:?})", self.complex)
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"ClippingRegion(Rect={:?}, Complex={:?})",
|
||||
self.main, self.complex
|
||||
)
|
||||
write!(f, "ClippingRegion(Rect={:?})", self.main,)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
/// the display list involving hit testing: finding the originating DOM node and determining the
|
||||
/// 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
|
||||
// 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 msg::constellation_msg::PipelineId;
|
||||
use webrender_api::units::LayoutPoint;
|
||||
|
@ -269,15 +269,19 @@ impl DisplayItem {
|
|||
.expect("Tried to use WebRender parent ClipId before it was defined.");
|
||||
|
||||
match node.node_type {
|
||||
ClipScrollNodeType::Clip => {
|
||||
let id = builder.define_clip(
|
||||
&SpaceAndClipInfo {
|
||||
clip_id: parent_clip_id,
|
||||
spatial_id: parent_spatial_id,
|
||||
ClipScrollNodeType::Clip(clip_type) => {
|
||||
let space_and_clip_info = SpaceAndClipInfo {
|
||||
clip_id: parent_clip_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,
|
||||
node.clip.complex.clone(),
|
||||
);
|
||||
ClipType::Rounded(complex) => {
|
||||
builder.define_clip_rounded_rect(&space_and_clip_info, complex)
|
||||
},
|
||||
};
|
||||
|
||||
state.spatial_ids[item.node_index.to_index()] = Some(parent_spatial_id);
|
||||
state.clip_ids[item.node_index.to_index()] = Some(id);
|
||||
|
@ -291,7 +295,6 @@ impl DisplayItem {
|
|||
Some(external_id),
|
||||
node.content_rect,
|
||||
node.clip.main,
|
||||
node.clip.complex.clone(),
|
||||
scroll_sensitivity,
|
||||
webrender_api::units::LayoutVector2D::zero(),
|
||||
);
|
||||
|
|
|
@ -344,7 +344,7 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
let (bounds, common) = background::painting_area(self, builder, layer_index);
|
||||
builder
|
||||
.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.
|
||||
for (index, image) in b.background_image.0.iter().enumerate().rev() {
|
||||
|
@ -589,14 +589,13 @@ fn clip_for_radii(
|
|||
if radii.is_zero() {
|
||||
None
|
||||
} else {
|
||||
Some(builder.wr.define_clip(
|
||||
Some(builder.wr.define_clip_rounded_rect(
|
||||
&builder.current_space_and_clip,
|
||||
rect,
|
||||
Some(wr::ComplexClipRegion {
|
||||
wr::ComplexClipRegion {
|
||||
rect,
|
||||
radii,
|
||||
mode: wr::ClipMode::Clip,
|
||||
}),
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -605,8 +605,6 @@ impl BoxFragment {
|
|||
self.scrollable_overflow(&containing_block_info.rect)
|
||||
.to_webrender(),
|
||||
padding_rect,
|
||||
vec![], // complex_clips
|
||||
None, // image_mask
|
||||
sensitivity,
|
||||
LayoutVector2D::zero(),
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue