diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 5d41ffa8a03b..86da27a0e2d6 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -14,8 +14,7 @@ //! They are therefore not exactly analogous to constructs like Skia pictures, which consist of //! low-level drawing primitives. -use app_units::Au; -use euclid::{Transform3D, Point2D, Vector2D, Rect, Size2D, TypedRect, SideOffsets2D}; +use euclid::{Transform3D, Vector2D, TypedRect, SideOffsets2D}; use euclid::num::{One, Zero}; use gfx_traits::{self, StackingContextId}; use gfx_traits::print_tree::PrintTree; @@ -24,18 +23,19 @@ use msg::constellation_msg::PipelineId; use net_traits::image::base::{Image, PixelFormat}; use range::Range; use servo_geometry::MaxRect; -use std::cmp::{self, Ordering}; +use std::cmp::Ordering; use std::collections::HashMap; use std::f32; use std::fmt; use std::sync::Arc; use text::TextRun; use text::glyph::ByteIndex; -use webrender_api::{BorderRadius, BorderWidths, BoxShadowClipMode, ColorF, ExtendMode}; -use webrender_api::{ExternalScrollId, FilterOp, GradientStop, ImageBorder, ImageKey}; -use webrender_api::{ImageRendering, LayoutPoint, LayoutRect, LayoutSize, LayoutVector2D}; -use webrender_api::{LineStyle, LocalClip, MixBlendMode, NormalBorder, ScrollPolicy}; -use webrender_api::{ScrollSensitivity, StickyOffsetBounds, TransformStyle}; +use webrender_api::{BorderRadius, BorderWidths, BoxShadowClipMode, ClipMode, ColorF}; +use webrender_api::{ComplexClipRegion, ExtendMode, ExternalScrollId, FilterOp, FontInstanceKey}; +use webrender_api::{GlyphInstance, GradientStop, ImageBorder, ImageKey, ImageRendering}; +use webrender_api::{LayoutPoint, LayoutRect, LayoutSize, LayoutVector2D, LineStyle, LocalClip}; +use webrender_api::{MixBlendMode, NormalBorder, ScrollPolicy, ScrollSensitivity}; +use webrender_api::{StickyOffsetBounds, TransformStyle}; pub use style::dom::OpaqueNode; @@ -96,22 +96,22 @@ pub struct DisplayList { impl DisplayList { /// Return the bounds of this display list based on the dimensions of the root /// stacking context. - pub fn bounds(&self) -> Rect { + pub fn bounds(&self) -> LayoutRect { match self.list.get(0) { Some(&DisplayItem::PushStackingContext(ref item)) => item.stacking_context.bounds, Some(_) => unreachable!("Root element of display list not stacking context."), - None => Rect::zero(), + None => LayoutRect::zero(), } } // Returns the text index within a node for the point of interest. - pub fn text_index(&self, node: OpaqueNode, point_in_item: &Point2D) -> Option { + pub fn text_index(&self, node: OpaqueNode, point_in_item: LayoutPoint) -> Option { for item in &self.list { match item { &DisplayItem::Text(ref text) => { let base = item.base(); if base.metadata.node == node { - let point = *point_in_item + item.base().bounds.origin.to_vector(); + let point = point_in_item + item.base().bounds.origin.to_vector(); let offset = point - text.baseline_origin; return Some(text.text_run.range_index_of_advance(&text.range, offset.x)); } @@ -194,10 +194,10 @@ pub struct StackingContext { pub context_type: StackingContextType, /// The position and size of this stacking context. - pub bounds: Rect, + pub bounds: LayoutRect, /// The overflow rect for this stacking context in its coordinate system. - pub overflow: Rect, + pub overflow: LayoutRect, /// The `z-index` for this stacking context. pub z_index: i32, @@ -229,8 +229,8 @@ impl StackingContext { #[inline] pub fn new(id: StackingContextId, context_type: StackingContextType, - bounds: &Rect, - overflow: &Rect, + bounds: LayoutRect, + overflow: LayoutRect, z_index: i32, filters: Vec, mix_blend_mode: MixBlendMode, @@ -243,8 +243,8 @@ impl StackingContext { StackingContext { id, context_type, - bounds: *bounds, - overflow: *overflow, + bounds, + overflow, z_index, filters, mix_blend_mode, @@ -261,8 +261,8 @@ impl StackingContext { StackingContext::new( StackingContextId::root(), StackingContextType::Real, - &Rect::zero(), - &Rect::zero(), + LayoutRect::zero(), + LayoutRect::zero(), 0, vec![], MixBlendMode::Normal, @@ -394,7 +394,7 @@ pub enum DisplayItem { #[derive(Clone, Deserialize, MallocSizeOf, Serialize)] pub struct BaseDisplayItem { /// The boundaries of the display item, in layer coordinates. - pub bounds: Rect, + pub bounds: LayoutRect, /// Metadata attached to this display item. pub metadata: DisplayItemMetadata, @@ -414,7 +414,7 @@ pub struct BaseDisplayItem { impl BaseDisplayItem { #[inline(always)] - pub fn new(bounds: Rect, + pub fn new(bounds: LayoutRect, metadata: DisplayItemMetadata, local_clip: LocalClip, section: DisplayListSection, @@ -454,23 +454,12 @@ impl BaseDisplayItem { #[derive(Clone, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub struct ClippingRegion { /// The main rectangular region. This does not include any corners. - pub main: Rect, + 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, -} - -/// A complex clipping region. These don't as easily admit arbitrary intersection operations, so -/// they're stored in a list over to the side. Currently a complex clipping region is just a -/// rounded rectangle, but the CSS WGs will probably make us throw more stuff in here eventually. -#[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] -pub struct ComplexClippingRegion { - /// The boundaries of the rectangle. - pub rect: Rect, - /// Border radii of this rectangle. - pub radii: BorderRadii, + pub complex: Vec, } impl ClippingRegion { @@ -478,7 +467,7 @@ impl ClippingRegion { #[inline] pub fn empty() -> ClippingRegion { ClippingRegion { - main: Rect::zero(), + main: LayoutRect::zero(), complex: Vec::new(), } } @@ -487,16 +476,16 @@ impl ClippingRegion { #[inline] pub fn max() -> ClippingRegion { ClippingRegion { - main: Rect::max_rect(), + main: LayoutRect::max_rect(), complex: Vec::new(), } } /// Returns a clipping region that represents the given rectangle. #[inline] - pub fn from_rect(rect: &Rect) -> ClippingRegion { + pub fn from_rect(rect: LayoutRect) -> ClippingRegion { ClippingRegion { - main: *rect, + main: rect, complex: Vec::new(), } } @@ -506,8 +495,8 @@ impl ClippingRegion { /// TODO(pcwalton): This could more eagerly eliminate complex clipping regions, at the cost of /// complexity. #[inline] - pub fn intersect_rect(&mut self, rect: &Rect) { - self.main = self.main.intersection(rect).unwrap_or(Rect::zero()) + pub fn intersect_rect(&mut self, rect: &LayoutRect) { + self.main = self.main.intersection(rect).unwrap_or(LayoutRect::zero()) } /// Returns true if this clipping region might be nonempty. This can return false positives, @@ -520,7 +509,7 @@ impl ClippingRegion { /// Returns true if this clipping region might contain the given point and false otherwise. /// This is a quick, not a precise, test; it can yield false positives. #[inline] - pub fn might_intersect_point(&self, point: &Point2D) -> bool { + pub fn might_intersect_point(&self, point: &LayoutPoint) -> bool { self.main.contains(point) && self.complex.iter().all(|complex| complex.rect.contains(point)) } @@ -528,14 +517,14 @@ impl ClippingRegion { /// Returns true if this clipping region might intersect the given rectangle and false /// otherwise. This is a quick, not a precise, test; it can yield false positives. #[inline] - pub fn might_intersect_rect(&self, rect: &Rect) -> bool { + pub fn might_intersect_rect(&self, rect: &LayoutRect) -> bool { self.main.intersects(rect) && self.complex.iter().all(|complex| complex.rect.intersects(rect)) } /// Returns true if this clipping region completely surrounds the given rect. #[inline] - pub fn does_not_clip_rect(&self, rect: &Rect) -> bool { + pub fn does_not_clip_rect(&self, rect: &LayoutRect) -> bool { self.main.contains(&rect.origin) && self.main.contains(&rect.bottom_right()) && self.complex.iter().all(|complex| { complex.rect.contains(&rect.origin) && complex.rect.contains(&rect.bottom_right()) @@ -544,7 +533,7 @@ impl ClippingRegion { /// Returns a bounding rect that surrounds this entire clipping region. #[inline] - pub fn bounding_rect(&self) -> Rect { + pub fn bounding_rect(&self) -> LayoutRect { let mut rect = self.main; for complex in &*self.complex { rect = rect.union(&complex.rect) @@ -554,10 +543,11 @@ impl ClippingRegion { /// Intersects this clipping region with the given rounded rectangle. #[inline] - pub fn intersect_with_rounded_rect(&mut self, rect: &Rect, radii: &BorderRadii) { - let new_complex_region = ComplexClippingRegion { - rect: *rect, - radii: *radii, + 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? @@ -576,21 +566,19 @@ impl ClippingRegion { } } - self.complex.push(ComplexClippingRegion { - rect: *rect, - radii: *radii, - }); + self.complex.push(new_complex_region); } /// Translates this clipping region by the given vector. #[inline] - pub fn translate(&self, delta: &Vector2D) -> ClippingRegion { + pub fn translate(&self, delta: &LayoutVector2D) -> ClippingRegion { ClippingRegion { main: self.main.translate(delta), complex: self.complex.iter().map(|complex| { - ComplexClippingRegion { + ComplexClipRegion { rect: complex.rect.translate(delta), radii: complex.radii, + mode: complex.mode, } }).collect(), } @@ -598,7 +586,7 @@ impl ClippingRegion { #[inline] pub fn is_max(&self) -> bool { - self.main == Rect::max_rect() && self.complex.is_empty() + self.main == LayoutRect::max_rect() && self.complex.is_empty() } } @@ -608,7 +596,7 @@ impl fmt::Debug for ClippingRegion { write!(f, "ClippingRegion::Max") } else if *self == ClippingRegion::empty() { write!(f, "ClippingRegion::Empty") - } else if self.main == Rect::max_rect() { + } else if self.main == LayoutRect::max_rect() { write!(f, "ClippingRegion(Complex={:?})", self.complex) } else { write!(f, "ClippingRegion(Rect={:?}, Complex={:?})", self.main, self.complex) @@ -616,17 +604,21 @@ impl fmt::Debug for ClippingRegion { } } -impl ComplexClippingRegion { +pub trait CompletelyEncloses { + fn completely_encloses(&self, other: &Self) -> bool; +} + +impl CompletelyEncloses for ComplexClipRegion { // TODO(pcwalton): This could be more aggressive by considering points that touch the inside of // the border radius ellipse. - fn completely_encloses(&self, other: &ComplexClippingRegion) -> bool { - let left = cmp::max(self.radii.top_left.width, self.radii.bottom_left.width); - let top = cmp::max(self.radii.top_left.height, self.radii.top_right.height); - let right = cmp::max(self.radii.top_right.width, self.radii.bottom_right.width); - let bottom = cmp::max(self.radii.bottom_left.height, self.radii.bottom_right.height); - let interior = Rect::new(Point2D::new(self.rect.origin.x + left, self.rect.origin.y + top), - Size2D::new(self.rect.size.width - left - right, - self.rect.size.height - top - bottom)); + fn completely_encloses(&self, other: &Self) -> bool { + let left = self.radii.top_left.width.max(self.radii.bottom_left.width); + let top = self.radii.top_left.height.max(self.radii.top_right.height); + let right = self.radii.top_right.width.max(self.radii.bottom_right.width); + let bottom = self.radii.bottom_left.height.max(self.radii.bottom_right.height); + let interior = LayoutRect::new(LayoutPoint::new(self.rect.origin.x + left, self.rect.origin.y + top), + LayoutSize::new(self.rect.size.width - left - right, + self.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() } @@ -667,14 +659,14 @@ pub struct TextDisplayItem { /// The range of text within the text run. pub range: Range, + /// The position of the start of the baseline of this text. + pub baseline_origin: LayoutPoint, + /// A collection of (non-whitespace) glyphs to be displayed. + pub glyphs: Vec, + /// Reference to the font to be used. + pub font_key: FontInstanceKey, /// The color of the text. pub text_color: ColorF, - - /// The position of the start of the baseline of this text. - pub baseline_origin: Point2D, - - /// The orientation of the text: upright or sideways left/right. - pub orientation: TextOrientation, } #[derive(Clone, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)] @@ -826,68 +818,6 @@ pub struct BorderDisplayItem { pub details: BorderDetails, } -/// Information about the border radii. -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] -pub struct BorderRadii { - pub top_left: Size2D, - pub top_right: Size2D, - pub bottom_right: Size2D, - pub bottom_left: Size2D, -} - -impl Default for BorderRadii where T: Default, T: Clone { - fn default() -> Self { - let top_left = Size2D::new(Default::default(), - Default::default()); - let top_right = Size2D::new(Default::default(), - Default::default()); - let bottom_left = Size2D::new(Default::default(), - Default::default()); - let bottom_right = Size2D::new(Default::default(), - Default::default()); - BorderRadii { top_left: top_left, - top_right: top_right, - bottom_left: bottom_left, - bottom_right: bottom_right } - } -} - -impl BorderRadii { - // Scale the border radii by the specified factor - pub fn scale_by(&self, s: f32) -> BorderRadii { - BorderRadii { top_left: BorderRadii::scale_corner_by(self.top_left, s), - top_right: BorderRadii::scale_corner_by(self.top_right, s), - bottom_left: BorderRadii::scale_corner_by(self.bottom_left, s), - bottom_right: BorderRadii::scale_corner_by(self.bottom_right, s) } - } - - // Scale the border corner radius by the specified factor - pub fn scale_corner_by(corner: Size2D, s: f32) -> Size2D { - Size2D::new(corner.width.scale_by(s), corner.height.scale_by(s)) - } -} - -impl BorderRadii where T: PartialEq + Zero { - /// Returns true if all the radii are zero. - pub fn is_square(&self) -> bool { - let zero = Zero::zero(); - self.top_left == zero && self.top_right == zero && self.bottom_right == zero && - self.bottom_left == zero - } -} - -impl BorderRadii where T: PartialEq + Zero + Clone { - /// Returns a set of border radii that all have the given value. - pub fn all_same(value: T) -> BorderRadii { - BorderRadii { - top_left: Size2D::new(value.clone(), value.clone()), - top_right: Size2D::new(value.clone(), value.clone()), - bottom_right: Size2D::new(value.clone(), value.clone()), - bottom_left: Size2D::new(value.clone(), value.clone()), - } - } -} - /// Paints a line segment. #[derive(Clone, Deserialize, MallocSizeOf, Serialize)] pub struct LineDisplayItem { @@ -1015,7 +945,7 @@ impl DisplayItem { self.base().section } - pub fn bounds(&self) -> Rect { + pub fn bounds(&self) -> LayoutRect { self.base().bounds } @@ -1050,11 +980,7 @@ impl fmt::Debug for DisplayItem { solid_color.color.g, solid_color.color.b, solid_color.color.a), - DisplayItem::Text(ref text) => { - format!("Text ({:?})", - &text.text_run.text[ - text.range.begin().0 as usize..(text.range.begin().0 + text.range.length().0) as usize]) - } + DisplayItem::Text(_) => "Text".to_owned(), DisplayItem::Image(_) => "Image".to_owned(), DisplayItem::Border(_) => "Border".to_owned(), DisplayItem::Gradient(_) => "Gradient".to_owned(), diff --git a/components/gfx/text/text_run.rs b/components/gfx/text/text_run.rs index 62126ab838a7..a85c8aababdb 100644 --- a/components/gfx/text/text_run.rs +++ b/components/gfx/text/text_run.rs @@ -333,10 +333,10 @@ impl<'a> TextRun { } /// Returns the index in the range of the first glyph advancing over given advance - pub fn range_index_of_advance(&self, range: &Range, advance: Au) -> usize { + pub fn range_index_of_advance(&self, range: &Range, advance: f32) -> usize { // TODO(Issue #199): alter advance direction for RTL // TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text - let mut remaining = advance; + let mut remaining = Au::from_f32_px(advance); self.natural_word_slices_in_range(range) .map(|slice| { let (slice_index, slice_advance) = diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index 347d180c89d4..30219c9da494 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -17,8 +17,7 @@ use context::LayoutContext; use display_list::ToLayout; use display_list::background::{compute_background_image_size, tile_image_axis}; use display_list::background::{convert_linear_gradient, convert_radial_gradient}; -use display_list::webrender_helpers::ToBorderRadius; -use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Transform3D, TypedRect, TypedSize2D, Vector2D}; +use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Transform3D, TypedSize2D, Vector2D, rect}; use flex::FlexFlow; use flow::{BaseFlow, Flow, FlowFlags}; use flow_ref::FlowRef; @@ -27,7 +26,7 @@ use fragment::{CanvasFragmentSource, CoordinateSystem, Fragment, ScannedTextFrag use fragment::SpecificFragmentInfo; use gfx::display_list; use gfx::display_list::{BaseDisplayItem, BorderDetails, BorderDisplayItem, BLUR_INFLATION_FACTOR}; -use gfx::display_list::{BorderRadii, BoxShadowDisplayItem, ClipScrollNode}; +use gfx::display_list::{BoxShadowDisplayItem, ClipScrollNode}; use gfx::display_list::{ClipScrollNodeIndex, ClipScrollNodeType, ClippingAndScrolling}; use gfx::display_list::{ClippingRegion, DisplayItem, DisplayItemMetadata, DisplayList}; use gfx::display_list::{DisplayListSection, GradientDisplayItem, IframeDisplayItem}; @@ -36,6 +35,8 @@ use gfx::display_list::{PopAllTextShadowsDisplayItem, PushTextShadowDisplayItem} use gfx::display_list::{RadialGradientDisplayItem, SolidColorDisplayItem, StackingContext}; use gfx::display_list::{StackingContextType, StickyFrameData, TextDisplayItem, TextOrientation}; use gfx::display_list::WebRenderImageInfo; +use gfx::text::TextRun; +use gfx::text::glyph::ByteIndex; use gfx_traits::{combine_id_with_fragment_type, FragmentType, StackingContextId}; use inline::{InlineFlow, InlineFragmentNodeFlags}; use ipc_channel::ipc; @@ -47,8 +48,8 @@ use net_traits::image_cache::UsePlaceholder; use range::Range; use servo_config::opts; use servo_geometry::MaxRect; -use std::{cmp, f32}; use std::default::Default; +use std::f32; use std::mem; use std::sync::Arc; use style::computed_values::background_attachment::single_value::T as BackgroundAttachment; @@ -73,10 +74,11 @@ use style_traits::CSSPixel; use style_traits::ToCss; use style_traits::cursor::CursorKind; use table_cell::CollapsedBordersForCell; -use webrender_api::{self, BorderSide, BoxShadowClipMode, ClipMode, ColorF, ComplexClipRegion}; -use webrender_api::{ExternalScrollId, FilterOp, ImageBorder, ImageRendering, LayoutRect}; -use webrender_api::{LayoutSize, LayoutVector2D, LineStyle, LocalClip, NinePatchDescriptor}; -use webrender_api::{NormalBorder, ScrollPolicy, ScrollSensitivity, StickyOffsetBounds}; +use webrender_api::{self, BorderRadius, BorderSide, BoxShadowClipMode, ClipMode, ColorF}; +use webrender_api::{ComplexClipRegion, ExternalScrollId, FilterOp, GlyphInstance, ImageBorder}; +use webrender_api::{ImageRendering, LayoutRect, LayoutSize, LayoutVector2D, LineStyle, LocalClip}; +use webrender_api::{NinePatchDescriptor, NormalBorder, ScrollPolicy, ScrollSensitivity}; +use webrender_api::StickyOffsetBounds; trait ResolvePercentage { fn resolve(&self, length: u32) -> u32; @@ -244,7 +246,7 @@ impl StackingContextCollectionState { // takes care of adding this root node and it can be ignored during DL conversion. let root_node = ClipScrollNode { parent_index: ClipScrollNodeIndex(0), - clip: ClippingRegion::from_rect(&TypedRect::zero()), + clip: ClippingRegion::from_rect(LayoutRect::zero()), content_rect: LayoutRect::zero(), node_type: ClipScrollNodeType::ScrollFrame( ScrollSensitivity::ScriptAndInputEvents, @@ -389,7 +391,7 @@ impl<'a> DisplayListBuildState<'a> { }; BaseDisplayItem::new( - *bounds, + bounds.to_layout(), DisplayItemMetadata { node, // Store cursor id in display list. @@ -708,16 +710,25 @@ pub trait FragmentDisplayListBuilding { fn fragment_type(&self) -> FragmentType; } -fn handle_overlapping_radii(size: &Size2D, radii: &BorderRadii) -> BorderRadii { +fn scale_border_radii(radii: BorderRadius, factor: f32) -> BorderRadius { + BorderRadius { + top_left: radii.top_left * factor, + top_right: radii.top_right * factor, + bottom_left: radii.bottom_left * factor, + bottom_right: radii.bottom_right * factor, + } +} + +fn handle_overlapping_radii(size: LayoutSize, radii: BorderRadius) -> BorderRadius { // No two corners' border radii may add up to more than the length of the edge // between them. To prevent that, all radii are scaled down uniformly. - fn scale_factor(radius_a: Au, radius_b: Au, edge_length: Au) -> f32 { + fn scale_factor(radius_a: f32, radius_b: f32, edge_length: f32) -> f32 { let required = radius_a + radius_b; if required <= edge_length { 1.0 } else { - edge_length.to_f32_px() / required.to_f32_px() + edge_length / required } } @@ -738,39 +749,39 @@ fn handle_overlapping_radii(size: &Size2D, radii: &BorderRadii) -> Borde .min(left_factor) .min(right_factor); if min_factor < 1.0 { - radii.scale_by(min_factor) + scale_border_radii(radii, min_factor) } else { - *radii + radii } } fn build_border_radius( abs_bounds: &Rect, border_style: &style_structs::Border, -) -> BorderRadii { +) -> BorderRadius { // TODO(cgaebel): Support border radii even in the case of multiple border widths. // This is an extension of supporting elliptical radii. For now, all percentage // radii will be relative to the width. handle_overlapping_radii( - &abs_bounds.size, - &BorderRadii { + abs_bounds.size.to_layout(), + BorderRadius { top_left: model::specified_border_radius( border_style.border_top_left_radius, abs_bounds.size, - ), + ).to_layout(), top_right: model::specified_border_radius( border_style.border_top_right_radius, abs_bounds.size, - ), + ).to_layout(), bottom_right: model::specified_border_radius( border_style.border_bottom_right_radius, abs_bounds.size, - ), + ).to_layout(), bottom_left: model::specified_border_radius( border_style.border_bottom_left_radius, abs_bounds.size, - ), + ).to_layout(), }, ) } @@ -780,9 +791,9 @@ fn build_border_radius( fn build_border_radius_for_inner_rect( outer_rect: &Rect, style: &ComputedValues, -) -> BorderRadii { +) -> BorderRadius { let radii = build_border_radius(&outer_rect, style.get_border()); - if radii.is_square() { + if radii.is_zero() { return radii; } @@ -830,20 +841,23 @@ fn simple_normal_border(color: ColorF, style: webrender_api::BorderStyle) -> Nor } fn calculate_inner_border_radii( - mut radii: BorderRadii, + mut radii: BorderRadius, offsets: SideOffsets2D, -) -> BorderRadii { - radii.top_left.width = cmp::max(Au(0), radii.top_left.width - offsets.left); - radii.bottom_left.width = cmp::max(Au(0), radii.bottom_left.width - offsets.left); +) -> BorderRadius { + fn inner_length(x: f32, offset: Au) -> f32 { + 0.0_f32.max(x - offset.to_f32_px()) + } + radii.top_left.width = inner_length(radii.top_left.width, offsets.left); + radii.bottom_left.width = inner_length(radii.bottom_left.width, offsets.left); - radii.top_right.width = cmp::max(Au(0), radii.top_right.width - offsets.right); - radii.bottom_right.width = cmp::max(Au(0), radii.bottom_right.width - offsets.right); + radii.top_right.width = inner_length(radii.top_right.width, offsets.right); + radii.bottom_right.width = inner_length(radii.bottom_right.width, offsets.right); - radii.top_left.height = cmp::max(Au(0), radii.top_left.height - offsets.top); - radii.top_right.height = cmp::max(Au(0), radii.top_right.height - offsets.top); + radii.top_left.height = inner_length(radii.top_left.height, offsets.top); + radii.top_right.height = inner_length(radii.top_right.height, offsets.top); - radii.bottom_left.height = cmp::max(Au(0), radii.bottom_left.height - offsets.bottom); - radii.bottom_right.height = cmp::max(Au(0), radii.bottom_right.height - offsets.bottom); + radii.bottom_left.height = inner_length(radii.bottom_left.height, offsets.bottom); + radii.bottom_right.height = inner_length(radii.bottom_right.height, offsets.bottom); radii } @@ -877,6 +891,35 @@ fn build_image_border_details( } } +fn convert_text_run_to_glyphs( + text_run: Arc, + range: Range, + mut origin: Point2D, +) -> Vec { + let mut glyphs = vec![]; + + for slice in text_run.natural_word_slices_in_visual_order(&range) { + for glyph in slice.glyphs.iter_glyphs_for_byte_range(&slice.range) { + let glyph_advance = if glyph.char_is_space() { + glyph.advance() + text_run.extra_word_spacing + } else { + glyph.advance() + }; + if !slice.glyphs.is_whitespace() { + let glyph_offset = glyph.offset().unwrap_or(Point2D::zero()); + let point = origin + glyph_offset.to_vector(); + let glyph = GlyphInstance { + index: glyph.id(), + point: point.to_layout(), + }; + glyphs.push(glyph); + } + origin.x += glyph_advance; + } + } + return glyphs; +} + impl FragmentDisplayListBuilding for Fragment { fn collect_stacking_contexts_for_blocklike_fragment( &mut self, @@ -946,14 +989,10 @@ impl FragmentDisplayListBuilding for Fragment { }, } - let clip = if !border_radii.is_square() { + let clip = if !border_radii.is_zero() { LocalClip::RoundedRect( bounds.to_layout(), - ComplexClipRegion::new( - bounds.to_layout(), - border_radii.to_border_radius(), - ClipMode::Clip, - ), + ComplexClipRegion::new(bounds.to_layout(), border_radii, ClipMode::Clip), ) } else { LocalClip::Rect(bounds.to_layout()) @@ -1325,7 +1364,7 @@ impl FragmentDisplayListBuilding for Fragment { ), blur_radius: box_shadow.base.blur.px(), spread_radius: box_shadow.spread.px(), - border_radius: border_radius.to_border_radius(), + border_radius: border_radius, clip_mode: if box_shadow.inset { BoxShadowClipMode::Inset } else { @@ -1420,7 +1459,7 @@ impl FragmentDisplayListBuilding for Fragment { color: style.resolve_color(colors.bottom).to_layout(), style: border_style.bottom.to_layout(), }, - radius: border_radius.to_border_radius(), + radius: border_radius, })), Either::Second(Image::Gradient(ref gradient)) => { Some(match gradient.kind { @@ -1653,27 +1692,19 @@ impl FragmentDisplayListBuilding for Fragment { let insertion_point_bounds; let cursor; if !self.style.writing_mode.is_vertical() { - insertion_point_bounds = Rect::new( - Point2D::new( - stacking_relative_border_box.origin.x + advance, - stacking_relative_border_box.origin.y, - ), - Size2D::new( - INSERTION_POINT_LOGICAL_WIDTH, - stacking_relative_border_box.size.height, - ), + insertion_point_bounds = rect( + stacking_relative_border_box.origin.x + advance, + stacking_relative_border_box.origin.y, + INSERTION_POINT_LOGICAL_WIDTH, + stacking_relative_border_box.size.height, ); cursor = CursorKind::Text; } else { - insertion_point_bounds = Rect::new( - Point2D::new( - stacking_relative_border_box.origin.x, - stacking_relative_border_box.origin.y + advance, - ), - Size2D::new( - stacking_relative_border_box.size.width, - INSERTION_POINT_LOGICAL_WIDTH, - ), + insertion_point_bounds = rect( + stacking_relative_border_box.origin.x, + stacking_relative_border_box.origin.y + advance, + stacking_relative_border_box.size.width, + INSERTION_POINT_LOGICAL_WIDTH, ); cursor = CursorKind::VerticalText; }; @@ -1842,12 +1873,12 @@ impl FragmentDisplayListBuilding for Fragment { // Adjust the clipping region as necessary to account for `border-radius`. let build_local_clip = |style: &ComputedValues| { let radii = build_border_radius_for_inner_rect(&stacking_relative_border_box, style); - if !radii.is_square() { + if !radii.is_zero() { LocalClip::RoundedRect( stacking_relative_border_box.to_layout(), ComplexClipRegion::new( stacking_relative_content_box.to_layout(), - radii.to_border_radius(), + radii, ClipMode::Clip, ), ) @@ -1946,10 +1977,7 @@ impl FragmentDisplayListBuilding for Fragment { iframe: pipeline_id, })); - let size = Size2D::new( - item.bounds().size.width.to_f32_px(), - item.bounds().size.height.to_f32_px(), - ); + let size = Size2D::new(item.bounds().size.width, item.bounds().size.height); state .iframe_sizes .push((browsing_context_id, TypedSize2D::from_untyped(&size))); @@ -2067,8 +2095,8 @@ impl FragmentDisplayListBuilding for Fragment { StackingContext::new( id, context_type, - &border_box, - &overflow, + border_box.to_layout(), + overflow.to_layout(), self.effective_z_index(), filters, self.style().get_effects().mix_blend_mode.to_layout(), @@ -2100,7 +2128,7 @@ impl FragmentDisplayListBuilding for Fragment { }; // Determine the orientation and cursor to use. - let (orientation, cursor) = if self.style.writing_mode.is_vertical() { + let (_orientation, cursor) = if self.style.writing_mode.is_vertical() { // TODO: Distinguish between 'sideways-lr' and 'sideways-rl' writing modes in CSS // Writing Modes Level 4. (TextOrientation::SidewaysRight, CursorKind::VerticalText) @@ -2181,14 +2209,22 @@ impl FragmentDisplayListBuilding for Fragment { } // Text - state.add_display_item(DisplayItem::Text(Box::new(TextDisplayItem { - base: base.clone(), - text_run: text_fragment.run.clone(), - range: text_fragment.range, - text_color: text_color.to_layout(), - orientation: orientation, - baseline_origin: baseline_origin, - }))); + let glyphs = convert_text_run_to_glyphs( + text_fragment.run.clone(), + text_fragment.range, + baseline_origin, + ); + if !glyphs.is_empty() { + state.add_display_item(DisplayItem::Text(Box::new(TextDisplayItem { + base: base.clone(), + text_run: text_fragment.run.clone(), + range: text_fragment.range, + baseline_origin: baseline_origin.to_layout(), + glyphs: glyphs, + font_key: text_fragment.run.font_key, + text_color: text_color.to_layout(), + }))); + } // TODO(#17715): emit text-emphasis marks here. // (just push another TextDisplayItem?) @@ -2435,25 +2471,20 @@ impl BlockFlowDisplayListBuilding for BlockFlow { Rect::max_rect() }, Some(transform) => { - let clip = Rect::new( - Point2D::new( - (clip.origin.x - origin.x).to_f32_px(), - (clip.origin.y - origin.y).to_f32_px(), - ), - Size2D::new(clip.size.width.to_f32_px(), clip.size.height.to_f32_px()), + let clip = rect( + (clip.origin.x - origin.x).to_f32_px(), + (clip.origin.y - origin.y).to_f32_px(), + clip.size.width.to_f32_px(), + clip.size.height.to_f32_px(), ); let clip = transform.transform_rect(&clip); - Rect::new( - Point2D::new( - Au::from_f32_px(clip.origin.x), - Au::from_f32_px(clip.origin.y), - ), - Size2D::new( - Au::from_f32_px(clip.size.width), - Au::from_f32_px(clip.size.height), - ), + rect( + Au::from_f32_px(clip.origin.x), + Au::from_f32_px(clip.origin.y), + Au::from_f32_px(clip.size.width), + Au::from_f32_px(clip.size.height), ) }, None => Rect::zero(), @@ -2669,7 +2700,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { let new_clip_scroll_index = state.add_clip_scroll_node(ClipScrollNode { parent_index: self.clipping_and_scrolling().scrolling, - clip: ClippingRegion::from_rect(border_box), + clip: ClippingRegion::from_rect(border_box.to_layout()), content_rect: LayoutRect::zero(), node_type: ClipScrollNodeType::StickyFrame(sticky_frame_data), }); @@ -2709,10 +2740,10 @@ impl BlockFlowDisplayListBuilding for BlockFlow { }; let clip_rect = build_inner_border_box_for_border_rect(&border_box, &self.fragment.style); - let mut clip = ClippingRegion::from_rect(&clip_rect); + let mut clip = ClippingRegion::from_rect(clip_rect.to_layout()); let radii = build_border_radius_for_inner_rect(&border_box, &self.fragment.style); - if !radii.is_square() { - clip.intersect_with_rounded_rect(&clip_rect, &radii) + if !radii.is_zero() { + clip.intersect_with_rounded_rect(clip_rect.to_layout(), radii) } let content_size = self.base.overflow.scroll.origin + self.base.overflow.scroll.size; @@ -2776,7 +2807,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { let new_index = state.add_clip_scroll_node(ClipScrollNode { parent_index: self.clipping_and_scrolling().scrolling, - clip: ClippingRegion::from_rect(&clip_rect), + clip: ClippingRegion::from_rect(clip_rect.to_layout()), content_rect: LayoutRect::zero(), // content_rect isn't important for clips. node_type: ClipScrollNodeType::Clip, }); diff --git a/components/layout/display_list/webrender_helpers.rs b/components/layout/display_list/webrender_helpers.rs index 3fa80190a9eb..3c9a4b5dd3bc 100644 --- a/components/layout/display_list/webrender_helpers.rs +++ b/components/layout/display_list/webrender_helpers.rs @@ -7,14 +7,11 @@ // 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 display_list::ToLayout; -use euclid::Point2D; -use gfx::display_list::{BorderDetails, BorderRadii, ClipScrollNode}; -use gfx::display_list::{ClipScrollNodeIndex, ClipScrollNodeType, ClippingRegion, DisplayItem}; +use gfx::display_list::{BorderDetails, ClipScrollNode}; +use gfx::display_list::{ClipScrollNodeIndex, ClipScrollNodeType, DisplayItem}; use gfx::display_list::{DisplayList, StackingContextType}; use msg::constellation_msg::PipelineId; -use webrender_api::{self, ClipAndScrollInfo, ClipId, ClipMode, ComplexClipRegion}; +use webrender_api::{self, ClipAndScrollInfo, ClipId}; use webrender_api::{DisplayListBuilder, LayoutTransform}; pub trait WebRenderDisplayListConverter { @@ -32,26 +29,11 @@ trait WebRenderDisplayItemConverter { ); } -pub trait ToBorderRadius { - fn to_border_radius(&self) -> webrender_api::BorderRadius; -} - -impl ToBorderRadius for BorderRadii { - fn to_border_radius(&self) -> webrender_api::BorderRadius { - webrender_api::BorderRadius { - top_left: self.top_left.to_layout(), - top_right: self.top_right.to_layout(), - bottom_left: self.bottom_left.to_layout(), - bottom_right: self.bottom_right.to_layout(), - } - } -} - impl WebRenderDisplayListConverter for DisplayList { fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder { let mut builder = DisplayListBuilder::with_capacity( pipeline_id.to_webrender(), - self.bounds().size.to_layout(), + self.bounds().size, 1024 * 1024, ); // 1 MB of space @@ -81,7 +63,7 @@ impl WebRenderDisplayItemConverter for DisplayItem { None => None, }; webrender_api::LayoutPrimitiveInfo { - rect: self.base().bounds.to_layout(), + rect: self.base().bounds, local_clip: self.base().local_clip, // TODO(gw): Make use of the WR backface visibility functionality. is_backface_visible: true, @@ -121,42 +103,13 @@ impl WebRenderDisplayItemConverter for DisplayItem { builder.push_rect(&self.prim_info(), item.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 x = (origin.x + glyph_offset.x).to_f32_px(); - let y = (origin.y + glyph_offset.y).to_f32_px(); - let point = webrender_api::LayoutPoint::new(x, y); - let glyph = webrender_api::GlyphInstance { - index: glyph.id(), - point: point, - }; - glyphs.push(glyph); - } - origin.x = origin.x + glyph_advance; - } - } - - if glyphs.len() > 0 { - builder.push_text( - &self.prim_info(), - &glyphs, - item.text_run.font_key, - item.text_color, - None, - ); - } + builder.push_text( + &self.prim_info(), + &item.glyphs, + item.font_key, + item.text_color, + None, + ); }, DisplayItem::Image(ref item) => { if let Some(id) = item.webrender_image.key { @@ -233,7 +186,7 @@ impl WebRenderDisplayItemConverter for DisplayItem { builder.push_line( &self.prim_info(), // TODO(gw): Use a better estimate for wavy line thickness. - (0.33 * item.base.bounds.size.height.to_f32_px()).ceil(), + (0.33 * item.base.bounds.size.height).ceil(), webrender_api::LineOrientation::Horizontal, &item.color, item.style, @@ -279,7 +232,7 @@ impl WebRenderDisplayItemConverter for DisplayItem { .map(|perspective| LayoutTransform::from_untyped(&perspective)); builder.push_stacking_context( - &webrender_api::LayoutPrimitiveInfo::new(stacking_context.bounds.to_layout()), + &webrender_api::LayoutPrimitiveInfo::new(stacking_context.bounds), stacking_context.scroll_policy, transform, stacking_context.transform_style, @@ -292,13 +245,13 @@ impl WebRenderDisplayItemConverter for DisplayItem { DisplayItem::DefineClipScrollNode(ref item) => { let node = &clip_scroll_nodes[item.node_index.0]; let parent_id = get_id(clip_ids, node.parent_index); - let item_rect = node.clip.main.to_layout(); + let item_rect = node.clip.main; let webrender_id = match node.node_type { ClipScrollNodeType::Clip => builder.define_clip_with_parent( parent_id, item_rect, - node.clip.get_complex_clips(), + node.clip.complex.clone(), None, ), ClipScrollNodeType::ScrollFrame(scroll_sensitivity, external_id) => builder @@ -306,8 +259,8 @@ impl WebRenderDisplayItemConverter for DisplayItem { parent_id, Some(external_id), node.content_rect, - node.clip.main.to_layout(), - node.clip.get_complex_clips(), + node.clip.main, + node.clip.complex.clone(), None, scroll_sensitivity, ), @@ -331,22 +284,3 @@ impl WebRenderDisplayItemConverter for DisplayItem { } } } - -trait ToWebRenderClip { - fn get_complex_clips(&self) -> Vec; -} - -impl ToWebRenderClip for ClippingRegion { - fn get_complex_clips(&self) -> Vec { - self.complex - .iter() - .map(|complex_clipping_region| { - ComplexClipRegion::new( - complex_clipping_region.rect.to_layout(), - complex_clipping_region.radii.to_border_radius(), - ClipMode::Clip, - ) - }) - .collect() - } -} diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index efc1489eae31..d3a77d1e6523 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -68,6 +68,7 @@ use layout::context::LayoutContext; use layout::context::RegisteredPainter; use layout::context::RegisteredPainters; use layout::context::malloc_size_of_persistent_local_context; +use layout::display_list::ToLayout; use layout::display_list::WebRenderDisplayListConverter; use layout::flow::{Flow, GetBaseFlow, ImmutableFlowUtils, MutableOwnedFlowUtils}; use layout::flow_ref::FlowRef; @@ -986,7 +987,7 @@ impl LayoutThread { } }; - let origin = Rect::new(Point2D::new(Au(0), Au(0)), root_size); + let origin = Rect::new(Point2D::new(Au(0), Au(0)), root_size).to_layout(); build_state.root_stacking_context.bounds = origin; build_state.root_stacking_context.overflow = origin; @@ -1364,7 +1365,7 @@ impl LayoutThread { rw_data.display_list .as_ref() .expect("Tried to hit test with no display list") - .text_index(opaque_node, &point_in_node) + .text_index(opaque_node, point_in_node.to_layout()) ); }, ReflowGoal::NodeGeometryQuery(node) => { diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs index bb6eddb628c2..074ebd6b675a 100644 --- a/components/malloc_size_of/lib.rs +++ b/components/malloc_size_of/lib.rs @@ -825,14 +825,20 @@ malloc_size_of_is_0!(webrender_api::ClipAndScrollInfo); #[cfg(feature = "webrender_api")] malloc_size_of_is_0!(webrender_api::ColorF); #[cfg(feature = "webrender_api")] +malloc_size_of_is_0!(webrender_api::ComplexClipRegion); +#[cfg(feature = "webrender_api")] malloc_size_of_is_0!(webrender_api::ExtendMode); #[cfg(feature = "webrender_api")] malloc_size_of_is_0!(webrender_api::FilterOp); #[cfg(feature = "webrender_api")] malloc_size_of_is_0!(webrender_api::ExternalScrollId); #[cfg(feature = "webrender_api")] +malloc_size_of_is_0!(webrender_api::FontInstanceKey); +#[cfg(feature = "webrender_api")] malloc_size_of_is_0!(webrender_api::GradientStop); #[cfg(feature = "webrender_api")] +malloc_size_of_is_0!(webrender_api::GlyphInstance); +#[cfg(feature = "webrender_api")] malloc_size_of_is_0!(webrender_api::ImageBorder); #[cfg(feature = "webrender_api")] malloc_size_of_is_0!(webrender_api::ImageKey);