mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Auto merge of #20031 - pyfisch:transform, r=mbrubeck
Reorganise display list builder Description in the individual commits. <!-- 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/20031) <!-- Reviewable:end -->
This commit is contained in:
commit
6a2feb3c1b
12 changed files with 466 additions and 495 deletions
|
@ -14,27 +14,22 @@
|
||||||
//! They are therefore not exactly analogous to constructs like Skia pictures, which consist of
|
//! They are therefore not exactly analogous to constructs like Skia pictures, which consist of
|
||||||
//! low-level drawing primitives.
|
//! low-level drawing primitives.
|
||||||
|
|
||||||
use euclid::{Transform3D, Vector2D, TypedRect, SideOffsets2D};
|
use euclid::{Vector2D, TypedRect, SideOffsets2D};
|
||||||
use euclid::num::{One, Zero};
|
use euclid::num::{One, Zero};
|
||||||
use gfx_traits::{self, StackingContextId};
|
use gfx_traits::{self, StackingContextId};
|
||||||
use gfx_traits::print_tree::PrintTree;
|
use gfx_traits::print_tree::PrintTree;
|
||||||
use ipc_channel::ipc::IpcSharedMemory;
|
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use net_traits::image::base::{Image, PixelFormat};
|
use net_traits::image::base::{Image, PixelFormat};
|
||||||
use range::Range;
|
|
||||||
use servo_geometry::MaxRect;
|
use servo_geometry::MaxRect;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
|
||||||
use text::TextRun;
|
|
||||||
use text::glyph::ByteIndex;
|
|
||||||
use webrender_api::{BorderRadius, BorderWidths, BoxShadowClipMode, ClipMode, ColorF};
|
use webrender_api::{BorderRadius, BorderWidths, BoxShadowClipMode, ClipMode, ColorF};
|
||||||
use webrender_api::{ComplexClipRegion, ExtendMode, ExternalScrollId, FilterOp, FontInstanceKey};
|
use webrender_api::{ComplexClipRegion, ExtendMode, ExternalScrollId, FilterOp, FontInstanceKey};
|
||||||
use webrender_api::{GlyphInstance, GradientStop, ImageBorder, ImageKey, ImageRendering};
|
use webrender_api::{GlyphInstance, GradientStop, ImageBorder, ImageKey, ImageRendering};
|
||||||
use webrender_api::{LayoutPoint, LayoutRect, LayoutSize, LayoutVector2D, LineStyle, LocalClip};
|
use webrender_api::{LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D, LineStyle};
|
||||||
use webrender_api::{MixBlendMode, NormalBorder, ScrollPolicy, ScrollSensitivity};
|
use webrender_api::{LocalClip, MixBlendMode, NormalBorder, ScrollPolicy, ScrollSensitivity};
|
||||||
use webrender_api::{StickyOffsetBounds, TransformStyle};
|
use webrender_api::{StickyOffsetBounds, TransformStyle};
|
||||||
|
|
||||||
pub use style::dom::OpaqueNode;
|
pub use style::dom::OpaqueNode;
|
||||||
|
@ -104,25 +99,6 @@ impl DisplayList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the text index within a node for the point of interest.
|
|
||||||
pub fn text_index(&self, node: OpaqueNode, point_in_item: LayoutPoint) -> Option<usize> {
|
|
||||||
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 offset = point - text.baseline_origin;
|
|
||||||
return Some(text.text_run.range_index_of_advance(&text.range, offset.x));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print(&self) {
|
pub fn print(&self) {
|
||||||
let mut print_tree = PrintTree::new("Display List".to_owned());
|
let mut print_tree = PrintTree::new("Display List".to_owned());
|
||||||
self.print_with_tree(&mut print_tree);
|
self.print_with_tree(&mut print_tree);
|
||||||
|
@ -209,13 +185,13 @@ pub struct StackingContext {
|
||||||
pub mix_blend_mode: MixBlendMode,
|
pub mix_blend_mode: MixBlendMode,
|
||||||
|
|
||||||
/// A transform to be applied to this stacking context.
|
/// A transform to be applied to this stacking context.
|
||||||
pub transform: Option<Transform3D<f32>>,
|
pub transform: Option<LayoutTransform>,
|
||||||
|
|
||||||
/// The transform style of this stacking context.
|
/// The transform style of this stacking context.
|
||||||
pub transform_style: TransformStyle,
|
pub transform_style: TransformStyle,
|
||||||
|
|
||||||
/// The perspective matrix to be applied to children.
|
/// The perspective matrix to be applied to children.
|
||||||
pub perspective: Option<Transform3D<f32>>,
|
pub perspective: Option<LayoutTransform>,
|
||||||
|
|
||||||
/// The scroll policy of this layer.
|
/// The scroll policy of this layer.
|
||||||
pub scroll_policy: ScrollPolicy,
|
pub scroll_policy: ScrollPolicy,
|
||||||
|
@ -234,9 +210,9 @@ impl StackingContext {
|
||||||
z_index: i32,
|
z_index: i32,
|
||||||
filters: Vec<FilterOp>,
|
filters: Vec<FilterOp>,
|
||||||
mix_blend_mode: MixBlendMode,
|
mix_blend_mode: MixBlendMode,
|
||||||
transform: Option<Transform3D<f32>>,
|
transform: Option<LayoutTransform>,
|
||||||
transform_style: TransformStyle,
|
transform_style: TransformStyle,
|
||||||
perspective: Option<Transform3D<f32>>,
|
perspective: Option<LayoutTransform>,
|
||||||
scroll_policy: ScrollPolicy,
|
scroll_policy: ScrollPolicy,
|
||||||
parent_clipping_and_scrolling: ClippingAndScrolling)
|
parent_clipping_and_scrolling: ClippingAndScrolling)
|
||||||
-> StackingContext {
|
-> StackingContext {
|
||||||
|
@ -651,16 +627,6 @@ pub struct SolidColorDisplayItem {
|
||||||
pub struct TextDisplayItem {
|
pub struct TextDisplayItem {
|
||||||
/// Fields common to all display items.
|
/// Fields common to all display items.
|
||||||
pub base: BaseDisplayItem,
|
pub base: BaseDisplayItem,
|
||||||
|
|
||||||
/// The text run.
|
|
||||||
#[ignore_malloc_size_of = "Because it is non-owning"]
|
|
||||||
pub text_run: Arc<TextRun>,
|
|
||||||
|
|
||||||
/// The range of text within the text run.
|
|
||||||
pub range: Range<ByteIndex>,
|
|
||||||
|
|
||||||
/// The position of the start of the baseline of this text.
|
|
||||||
pub baseline_origin: LayoutPoint,
|
|
||||||
/// A collection of (non-whitespace) glyphs to be displayed.
|
/// A collection of (non-whitespace) glyphs to be displayed.
|
||||||
pub glyphs: Vec<GlyphInstance>,
|
pub glyphs: Vec<GlyphInstance>,
|
||||||
/// Reference to the font to be used.
|
/// Reference to the font to be used.
|
||||||
|
@ -683,9 +649,6 @@ pub struct ImageDisplayItem {
|
||||||
|
|
||||||
pub webrender_image: WebRenderImageInfo,
|
pub webrender_image: WebRenderImageInfo,
|
||||||
|
|
||||||
#[ignore_malloc_size_of = "Because it is non-owning"]
|
|
||||||
pub image_data: Option<Arc<IpcSharedMemory>>,
|
|
||||||
|
|
||||||
/// The dimensions to which the image display item should be stretched. If this is smaller than
|
/// The dimensions to which the image display item should be stretched. If this is smaller than
|
||||||
/// the bounds of this display item, then the image will be repeated in the appropriate
|
/// the bounds of this display item, then the image will be repeated in the appropriate
|
||||||
/// direction to tile the entire bounds.
|
/// direction to tile the entire bounds.
|
||||||
|
@ -1028,7 +991,7 @@ pub trait SimpleMatrixDetection {
|
||||||
fn is_identity_or_simple_translation(&self) -> bool;
|
fn is_identity_or_simple_translation(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleMatrixDetection for Transform3D<f32> {
|
impl SimpleMatrixDetection for LayoutTransform {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_identity_or_simple_translation(&self) -> bool {
|
fn is_identity_or_simple_translation(&self) -> bool {
|
||||||
let (_0, _1) = (Zero::zero(), One::one());
|
let (_0, _1) = (Zero::zero(), One::one());
|
||||||
|
|
|
@ -333,10 +333,10 @@ impl<'a> TextRun {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the index in the range of the first glyph advancing over given advance
|
/// Returns the index in the range of the first glyph advancing over given advance
|
||||||
pub fn range_index_of_advance(&self, range: &Range<ByteIndex>, advance: f32) -> usize {
|
pub fn range_index_of_advance(&self, range: &Range<ByteIndex>, advance: Au) -> usize {
|
||||||
// TODO(Issue #199): alter advance direction for RTL
|
// TODO(Issue #199): alter advance direction for RTL
|
||||||
// TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text
|
// TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text
|
||||||
let mut remaining = Au::from_f32_px(advance);
|
let mut remaining = advance;
|
||||||
self.natural_word_slices_in_range(range)
|
self.natural_word_slices_in_range(range)
|
||||||
.map(|slice| {
|
.map(|slice| {
|
||||||
let (slice_index, slice_advance) =
|
let (slice_index, slice_advance) =
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
//! Calculations for CSS images and CSS backgrounds.
|
//! Calculations for CSS images, backgrounds and borders.
|
||||||
|
//!
|
||||||
|
//! * [CSS Images Module Level 3](https://drafts.csswg.org/css-images-3/)
|
||||||
|
//! * [CSS Backgrounds and Borders Module Level 3](https://drafts.csswg.org/css-backgrounds-3/)
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
|
||||||
|
@ -10,12 +13,16 @@
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use display_list::ToLayout;
|
use display_list::ToLayout;
|
||||||
use euclid::{Point2D, Size2D, Vector2D};
|
use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Vector2D};
|
||||||
use gfx::display_list;
|
use gfx::display_list::{self, BorderDetails, WebRenderImageInfo};
|
||||||
use model::MaybeAuto;
|
use model::{self, MaybeAuto};
|
||||||
|
use style::computed_values::background_attachment::single_value::T as BackgroundAttachment;
|
||||||
|
use style::computed_values::background_clip::single_value::T as BackgroundClip;
|
||||||
|
use style::computed_values::background_origin::single_value::T as BackgroundOrigin;
|
||||||
|
use style::properties::style_structs::{self, Background};
|
||||||
use style::values::computed::{Angle, GradientItem};
|
use style::values::computed::{Angle, GradientItem};
|
||||||
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto, Percentage};
|
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
use style::values::computed::Position;
|
use style::values::computed::{NumberOrPercentage, Percentage, Position};
|
||||||
use style::values::computed::image::{EndingShape, LineDirection};
|
use style::values::computed::image::{EndingShape, LineDirection};
|
||||||
use style::values::generics::background::BackgroundSize;
|
use style::values::generics::background::BackgroundSize;
|
||||||
use style::values::generics::image::{Circle, Ellipse, ShapeExtent};
|
use style::values::generics::image::{Circle, Ellipse, ShapeExtent};
|
||||||
|
@ -23,7 +30,8 @@ use style::values::generics::image::EndingShape as GenericEndingShape;
|
||||||
use style::values::generics::image::GradientItem as GenericGradientItem;
|
use style::values::generics::image::GradientItem as GenericGradientItem;
|
||||||
use style::values::specified::background::BackgroundRepeatKeyword;
|
use style::values::specified::background::BackgroundRepeatKeyword;
|
||||||
use style::values::specified::position::{X, Y};
|
use style::values::specified::position::{X, Y};
|
||||||
use webrender_api::{ExtendMode, GradientStop};
|
use webrender_api::{BorderRadius, BorderSide, BorderStyle, ColorF, ExtendMode, ImageBorder};
|
||||||
|
use webrender_api::{GradientStop, LayoutSize, NinePatchDescriptor, NormalBorder};
|
||||||
|
|
||||||
/// A helper data structure for gradients.
|
/// A helper data structure for gradients.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -34,9 +42,51 @@ struct StopRun {
|
||||||
stop_count: usize,
|
stop_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Placment information for both image and gradient backgrounds.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct BackgroundPlacement {
|
||||||
|
/// Rendering bounds. The background will start in the uppper-left corner
|
||||||
|
/// and fill the whole area.
|
||||||
|
pub bounds: Rect<Au>,
|
||||||
|
/// Background tile size. Some backgrounds are repeated. These are the
|
||||||
|
/// dimensions of a single image of the background.
|
||||||
|
pub tile_size: Size2D<Au>,
|
||||||
|
/// Spacing between tiles. Some backgrounds are not repeated seamless
|
||||||
|
/// but have seams between them like tiles in real life.
|
||||||
|
pub tile_spacing: Size2D<Au>,
|
||||||
|
/// A clip area. While the background is rendered according to all the
|
||||||
|
/// measures above it is only shown within these bounds.
|
||||||
|
pub css_clip: Rect<Au>,
|
||||||
|
/// Whether or not the background is fixed to the viewport.
|
||||||
|
pub fixed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ResolvePercentage {
|
||||||
|
fn resolve(&self, length: u32) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResolvePercentage for NumberOrPercentage {
|
||||||
|
fn resolve(&self, length: u32) -> u32 {
|
||||||
|
match *self {
|
||||||
|
NumberOrPercentage::Percentage(p) => (p.0 * length as f32).round() as u32,
|
||||||
|
NumberOrPercentage::Number(n) => n.round() as u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access element at index modulo the array length.
|
||||||
|
///
|
||||||
|
/// Obviously it does not work with empty arrays.
|
||||||
|
///
|
||||||
|
/// This is used for multiple layered background images.
|
||||||
|
/// See: https://drafts.csswg.org/css-backgrounds-3/#layering
|
||||||
|
pub fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
|
||||||
|
&arr[index % arr.len()]
|
||||||
|
}
|
||||||
|
|
||||||
/// For a given area and an image compute how big the
|
/// For a given area and an image compute how big the
|
||||||
/// image should be displayed on the background.
|
/// image should be displayed on the background.
|
||||||
pub fn compute_background_image_size(
|
fn compute_background_image_size(
|
||||||
bg_size: BackgroundSize<LengthOrPercentageOrAuto>,
|
bg_size: BackgroundSize<LengthOrPercentageOrAuto>,
|
||||||
bounds_size: Size2D<Au>,
|
bounds_size: Size2D<Au>,
|
||||||
intrinsic_size: Option<Size2D<Au>>,
|
intrinsic_size: Option<Size2D<Au>>,
|
||||||
|
@ -99,6 +149,82 @@ pub fn compute_background_image_size(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determines where to place an element background image or gradient.
|
||||||
|
///
|
||||||
|
/// Photos have their resolution as intrinsic size while gradients have
|
||||||
|
/// no intrinsic size.
|
||||||
|
pub fn compute_background_placement(
|
||||||
|
bg: &Background,
|
||||||
|
viewport_size: Size2D<Au>,
|
||||||
|
absolute_bounds: Rect<Au>,
|
||||||
|
intrinsic_size: Option<Size2D<Au>>,
|
||||||
|
border: SideOffsets2D<Au>,
|
||||||
|
border_padding: SideOffsets2D<Au>,
|
||||||
|
index: usize,
|
||||||
|
) -> BackgroundPlacement {
|
||||||
|
let bg_attachment = *get_cyclic(&bg.background_attachment.0, index);
|
||||||
|
let bg_clip = *get_cyclic(&bg.background_clip.0, index);
|
||||||
|
let bg_origin = *get_cyclic(&bg.background_origin.0, index);
|
||||||
|
let bg_position_x = get_cyclic(&bg.background_position_x.0, index);
|
||||||
|
let bg_position_y = get_cyclic(&bg.background_position_y.0, index);
|
||||||
|
let bg_repeat = get_cyclic(&bg.background_repeat.0, index);
|
||||||
|
let bg_size = *get_cyclic(&bg.background_size.0, index);
|
||||||
|
|
||||||
|
let css_clip = match bg_clip {
|
||||||
|
BackgroundClip::BorderBox => absolute_bounds,
|
||||||
|
BackgroundClip::PaddingBox => absolute_bounds.inner_rect(border),
|
||||||
|
BackgroundClip::ContentBox => absolute_bounds.inner_rect(border_padding),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut fixed = false;
|
||||||
|
let mut bounds = match bg_attachment {
|
||||||
|
BackgroundAttachment::Scroll => match bg_origin {
|
||||||
|
BackgroundOrigin::BorderBox => absolute_bounds,
|
||||||
|
BackgroundOrigin::PaddingBox => absolute_bounds.inner_rect(border),
|
||||||
|
BackgroundOrigin::ContentBox => absolute_bounds.inner_rect(border_padding),
|
||||||
|
},
|
||||||
|
BackgroundAttachment::Fixed => {
|
||||||
|
fixed = true;
|
||||||
|
Rect::new(Point2D::origin(), viewport_size)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut tile_size = compute_background_image_size(bg_size, bounds.size, intrinsic_size);
|
||||||
|
|
||||||
|
let mut tile_spacing = Size2D::zero();
|
||||||
|
let own_position = bounds.size - tile_size;
|
||||||
|
let pos_x = bg_position_x.to_used_value(own_position.width);
|
||||||
|
let pos_y = bg_position_y.to_used_value(own_position.height);
|
||||||
|
tile_image_axis(
|
||||||
|
bg_repeat.0,
|
||||||
|
&mut bounds.origin.x,
|
||||||
|
&mut bounds.size.width,
|
||||||
|
&mut tile_size.width,
|
||||||
|
&mut tile_spacing.width,
|
||||||
|
pos_x,
|
||||||
|
css_clip.origin.x,
|
||||||
|
css_clip.size.width,
|
||||||
|
);
|
||||||
|
tile_image_axis(
|
||||||
|
bg_repeat.1,
|
||||||
|
&mut bounds.origin.y,
|
||||||
|
&mut bounds.size.height,
|
||||||
|
&mut tile_size.height,
|
||||||
|
&mut tile_spacing.height,
|
||||||
|
pos_y,
|
||||||
|
css_clip.origin.y,
|
||||||
|
css_clip.size.height,
|
||||||
|
);
|
||||||
|
|
||||||
|
BackgroundPlacement {
|
||||||
|
bounds,
|
||||||
|
tile_size,
|
||||||
|
tile_spacing,
|
||||||
|
css_clip,
|
||||||
|
fixed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn tile_image_round(
|
fn tile_image_round(
|
||||||
position: &mut Au,
|
position: &mut Au,
|
||||||
size: &mut Au,
|
size: &mut Au,
|
||||||
|
@ -175,7 +301,7 @@ fn tile_image(position: &mut Au, size: &mut Au, absolute_anchor_origin: Au, imag
|
||||||
/// For either the x or the y axis ajust various values to account for tiling.
|
/// For either the x or the y axis ajust various values to account for tiling.
|
||||||
///
|
///
|
||||||
/// This is done separately for both axes because the repeat keywords may differ.
|
/// This is done separately for both axes because the repeat keywords may differ.
|
||||||
pub fn tile_image_axis(
|
fn tile_image_axis(
|
||||||
repeat: BackgroundRepeatKeyword,
|
repeat: BackgroundRepeatKeyword,
|
||||||
position: &mut Au,
|
position: &mut Au,
|
||||||
size: &mut Au,
|
size: &mut Au,
|
||||||
|
@ -322,8 +448,7 @@ fn convert_gradient_stops(gradient_items: &[GradientItem], total_length: Au) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Evenly space stops without position.
|
// Step 3: Evenly space stops without position.
|
||||||
// Note: Remove the + 2 if fix_gradient_stops is changed.
|
let mut stops = Vec::with_capacity(stop_items.len());
|
||||||
let mut stops = Vec::with_capacity(stop_items.len() + 2);
|
|
||||||
let mut stop_run = None;
|
let mut stop_run = None;
|
||||||
for (i, stop) in stop_items.iter().enumerate() {
|
for (i, stop) in stop_items.iter().enumerate() {
|
||||||
let offset = match stop.position {
|
let offset = match stop.position {
|
||||||
|
@ -427,14 +552,7 @@ pub fn convert_linear_gradient(
|
||||||
// This is the length of the gradient line.
|
// This is the length of the gradient line.
|
||||||
let length = Au::from_f32_px((delta.x.to_f32_px() * 2.0).hypot(delta.y.to_f32_px() * 2.0));
|
let length = Au::from_f32_px((delta.x.to_f32_px() * 2.0).hypot(delta.y.to_f32_px() * 2.0));
|
||||||
|
|
||||||
let mut stops = convert_gradient_stops(stops, length);
|
let stops = convert_gradient_stops(stops, length);
|
||||||
|
|
||||||
// Only clamped gradients need to be fixed because in repeating gradients
|
|
||||||
// there is no "first" or "last" stop because they repeat infinitly in
|
|
||||||
// both directions, so the rendering is always correct.
|
|
||||||
if !repeating {
|
|
||||||
fix_gradient_stops(&mut stops);
|
|
||||||
}
|
|
||||||
|
|
||||||
let center = Point2D::new(size.width / 2, size.height / 2);
|
let center = Point2D::new(size.width / 2, size.height / 2);
|
||||||
|
|
||||||
|
@ -473,12 +591,7 @@ pub fn convert_radial_gradient(
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut stops = convert_gradient_stops(stops, radius.width);
|
let stops = convert_gradient_stops(stops, radius.width);
|
||||||
// Repeating gradients have no last stops that can be ignored. So
|
|
||||||
// fixup is not necessary but may actually break the gradient.
|
|
||||||
if !repeating {
|
|
||||||
fix_gradient_stops(&mut stops);
|
|
||||||
}
|
|
||||||
|
|
||||||
display_list::RadialGradient {
|
display_list::RadialGradient {
|
||||||
center: center.to_layout(),
|
center: center.to_layout(),
|
||||||
|
@ -488,38 +601,6 @@ pub fn convert_radial_gradient(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Duplicate the first and last stops if necessary.
|
|
||||||
///
|
|
||||||
/// Explanation by pyfisch:
|
|
||||||
/// If the last stop is at the same position as the previous stop the
|
|
||||||
/// last color is ignored by webrender. This differs from the spec
|
|
||||||
/// (I think so). The implementations of Chrome and Firefox seem
|
|
||||||
/// to have the same problem but work fine if the position of the last
|
|
||||||
/// stop is smaller than 100%. (Otherwise they ignore the last stop.)
|
|
||||||
///
|
|
||||||
/// Similarly the first stop is duplicated if it is not placed
|
|
||||||
/// at the start of the virtual gradient ray.
|
|
||||||
fn fix_gradient_stops(stops: &mut Vec<GradientStop>) {
|
|
||||||
if stops.first().unwrap().offset > 0.0 {
|
|
||||||
let color = stops.first().unwrap().color;
|
|
||||||
stops.insert(
|
|
||||||
0,
|
|
||||||
GradientStop {
|
|
||||||
offset: 0.0,
|
|
||||||
color: color,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if stops.last().unwrap().offset < 1.0 {
|
|
||||||
let color = stops.last().unwrap().color;
|
|
||||||
stops.push(GradientStop {
|
|
||||||
offset: 1.0,
|
|
||||||
color: color,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the the distance to the nearest or farthest corner depending on the comperator.
|
/// Returns the the distance to the nearest or farthest corner depending on the comperator.
|
||||||
fn get_distance_to_corner<F>(size: &Size2D<Au>, center: &Point2D<Au>, cmp: F) -> Au
|
fn get_distance_to_corner<F>(size: &Size2D<Au>, center: &Point2D<Au>, cmp: F) -> Au
|
||||||
where
|
where
|
||||||
|
@ -555,3 +636,151 @@ fn position_to_offset(position: LengthOrPercentage, total_length: Au) -> f32 {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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: f32, radius_b: f32, edge_length: f32) -> f32 {
|
||||||
|
let required = radius_a + radius_b;
|
||||||
|
|
||||||
|
if required <= edge_length {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
edge_length / required
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let top_factor = scale_factor(radii.top_left.width, radii.top_right.width, size.width);
|
||||||
|
let bottom_factor = scale_factor(
|
||||||
|
radii.bottom_left.width,
|
||||||
|
radii.bottom_right.width,
|
||||||
|
size.width,
|
||||||
|
);
|
||||||
|
let left_factor = scale_factor(radii.top_left.height, radii.bottom_left.height, size.height);
|
||||||
|
let right_factor = scale_factor(
|
||||||
|
radii.top_right.height,
|
||||||
|
radii.bottom_right.height,
|
||||||
|
size.height,
|
||||||
|
);
|
||||||
|
let min_factor = top_factor
|
||||||
|
.min(bottom_factor)
|
||||||
|
.min(left_factor)
|
||||||
|
.min(right_factor);
|
||||||
|
if min_factor < 1.0 {
|
||||||
|
scale_border_radii(radii, min_factor)
|
||||||
|
} else {
|
||||||
|
radii
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_border_radius(
|
||||||
|
abs_bounds: &Rect<Au>,
|
||||||
|
border_style: &style_structs::Border,
|
||||||
|
) -> 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.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(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a four-sided border with uniform color, width and corner radius.
|
||||||
|
pub fn simple_normal_border(color: ColorF, style: BorderStyle) -> NormalBorder {
|
||||||
|
let side = BorderSide { color, style };
|
||||||
|
NormalBorder {
|
||||||
|
left: side,
|
||||||
|
right: side,
|
||||||
|
top: side,
|
||||||
|
bottom: side,
|
||||||
|
radius: BorderRadius::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates radii for the inner side.
|
||||||
|
///
|
||||||
|
/// Radii usually describe the outer side of a border but for the lines to look nice
|
||||||
|
/// the inner radii need to be smaller depending on the line width.
|
||||||
|
///
|
||||||
|
/// This is used to determine clipping areas.
|
||||||
|
pub fn calculate_inner_border_radii(
|
||||||
|
mut radii: BorderRadius,
|
||||||
|
offsets: SideOffsets2D<Au>,
|
||||||
|
) -> 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 = inner_length(radii.top_right.width, offsets.right);
|
||||||
|
radii.bottom_right.width = inner_length(radii.bottom_right.width, offsets.right);
|
||||||
|
|
||||||
|
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 = inner_length(radii.bottom_left.height, offsets.bottom);
|
||||||
|
radii.bottom_right.height = inner_length(radii.bottom_right.height, offsets.bottom);
|
||||||
|
radii
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given an image and a border style constructs a border image.
|
||||||
|
///
|
||||||
|
/// See: https://drafts.csswg.org/css-backgrounds-3/#border-images
|
||||||
|
pub fn build_image_border_details(
|
||||||
|
webrender_image: WebRenderImageInfo,
|
||||||
|
border_style_struct: &style_structs::Border,
|
||||||
|
) -> Option<BorderDetails> {
|
||||||
|
let corners = &border_style_struct.border_image_slice.offsets;
|
||||||
|
let border_image_repeat = &border_style_struct.border_image_repeat;
|
||||||
|
if let Some(image_key) = webrender_image.key {
|
||||||
|
Some(BorderDetails::Image(ImageBorder {
|
||||||
|
image_key: image_key,
|
||||||
|
patch: NinePatchDescriptor {
|
||||||
|
width: webrender_image.width,
|
||||||
|
height: webrender_image.height,
|
||||||
|
slice: SideOffsets2D::new(
|
||||||
|
corners.0.resolve(webrender_image.height),
|
||||||
|
corners.1.resolve(webrender_image.width),
|
||||||
|
corners.2.resolve(webrender_image.height),
|
||||||
|
corners.3.resolve(webrender_image.width),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
fill: border_style_struct.border_image_slice.fill,
|
||||||
|
// TODO(gw): Support border-image-outset
|
||||||
|
outset: SideOffsets2D::zero(),
|
||||||
|
repeat_horizontal: border_image_repeat.0.to_layout(),
|
||||||
|
repeat_vertical: border_image_repeat.1.to_layout(),
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,9 +15,11 @@ use block::{BlockFlow, BlockStackingContextType};
|
||||||
use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg};
|
use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg};
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use display_list::ToLayout;
|
use display_list::ToLayout;
|
||||||
use display_list::background::{compute_background_image_size, tile_image_axis};
|
use display_list::background::{build_border_radius, build_image_border_details};
|
||||||
|
use display_list::background::{calculate_inner_border_radii, compute_background_placement};
|
||||||
use display_list::background::{convert_linear_gradient, convert_radial_gradient};
|
use display_list::background::{convert_linear_gradient, convert_radial_gradient};
|
||||||
use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Transform3D, TypedSize2D, Vector2D, rect};
|
use display_list::background::{get_cyclic, simple_normal_border};
|
||||||
|
use euclid::{rect, Point2D, Rect, SideOffsets2D, Size2D, TypedSize2D, Vector2D};
|
||||||
use flex::FlexFlow;
|
use flex::FlexFlow;
|
||||||
use flow::{BaseFlow, Flow, FlowFlags};
|
use flow::{BaseFlow, Flow, FlowFlags};
|
||||||
use flow_ref::FlowRef;
|
use flow_ref::FlowRef;
|
||||||
|
@ -41,7 +43,7 @@ use gfx_traits::{combine_id_with_fragment_type, FragmentType, StackingContextId}
|
||||||
use inline::{InlineFlow, InlineFragmentNodeFlags};
|
use inline::{InlineFlow, InlineFragmentNodeFlags};
|
||||||
use ipc_channel::ipc;
|
use ipc_channel::ipc;
|
||||||
use list_item::ListItemFlow;
|
use list_item::ListItemFlow;
|
||||||
use model::{self, MaybeAuto};
|
use model::MaybeAuto;
|
||||||
use msg::constellation_msg::{BrowsingContextId, PipelineId};
|
use msg::constellation_msg::{BrowsingContextId, PipelineId};
|
||||||
use net_traits::image::base::PixelFormat;
|
use net_traits::image::base::PixelFormat;
|
||||||
use net_traits::image_cache::UsePlaceholder;
|
use net_traits::image_cache::UsePlaceholder;
|
||||||
|
@ -52,20 +54,17 @@ use std::default::Default;
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use style::computed_values::background_attachment::single_value::T as BackgroundAttachment;
|
|
||||||
use style::computed_values::background_clip::single_value::T as BackgroundClip;
|
use style::computed_values::background_clip::single_value::T as BackgroundClip;
|
||||||
use style::computed_values::background_origin::single_value::T as BackgroundOrigin;
|
|
||||||
use style::computed_values::border_style::T as BorderStyle;
|
use style::computed_values::border_style::T as BorderStyle;
|
||||||
use style::computed_values::overflow_x::T as StyleOverflow;
|
use style::computed_values::overflow_x::T as StyleOverflow;
|
||||||
use style::computed_values::pointer_events::T as PointerEvents;
|
use style::computed_values::pointer_events::T as PointerEvents;
|
||||||
use style::computed_values::position::T as StylePosition;
|
use style::computed_values::position::T as StylePosition;
|
||||||
use style::computed_values::visibility::T as Visibility;
|
use style::computed_values::visibility::T as Visibility;
|
||||||
use style::logical_geometry::{LogicalMargin, LogicalPoint, LogicalRect};
|
use style::logical_geometry::{LogicalMargin, LogicalPoint, LogicalRect};
|
||||||
use style::properties::ComputedValues;
|
use style::properties::{ComputedValues, style_structs};
|
||||||
use style::properties::style_structs;
|
|
||||||
use style::servo::restyle_damage::ServoRestyleDamage;
|
use style::servo::restyle_damage::ServoRestyleDamage;
|
||||||
use style::values::{Either, RGBA};
|
use style::values::{Either, RGBA};
|
||||||
use style::values::computed::{Gradient, NumberOrPercentage};
|
use style::values::computed::Gradient;
|
||||||
use style::values::computed::effects::SimpleShadow;
|
use style::values::computed::effects::SimpleShadow;
|
||||||
use style::values::computed::pointing::Cursor;
|
use style::values::computed::pointing::Cursor;
|
||||||
use style::values::generics::background::BackgroundSize;
|
use style::values::generics::background::BackgroundSize;
|
||||||
|
@ -75,23 +74,10 @@ use style_traits::ToCss;
|
||||||
use style_traits::cursor::CursorKind;
|
use style_traits::cursor::CursorKind;
|
||||||
use table_cell::CollapsedBordersForCell;
|
use table_cell::CollapsedBordersForCell;
|
||||||
use webrender_api::{self, BorderRadius, BorderSide, BoxShadowClipMode, ClipMode, ColorF};
|
use webrender_api::{self, BorderRadius, BorderSide, BoxShadowClipMode, ClipMode, ColorF};
|
||||||
use webrender_api::{ComplexClipRegion, ExternalScrollId, FilterOp, GlyphInstance, ImageBorder};
|
use webrender_api::{ComplexClipRegion, ExternalScrollId, FilterOp, GlyphInstance};
|
||||||
use webrender_api::{ImageRendering, LayoutRect, LayoutSize, LayoutVector2D, LineStyle, LocalClip};
|
use webrender_api::{ImageRendering, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
|
||||||
use webrender_api::{NinePatchDescriptor, NormalBorder, ScrollPolicy, ScrollSensitivity};
|
use webrender_api::{LineStyle, LocalClip, NormalBorder, ScrollPolicy};
|
||||||
use webrender_api::StickyOffsetBounds;
|
use webrender_api::{ScrollSensitivity, StickyOffsetBounds};
|
||||||
|
|
||||||
trait ResolvePercentage {
|
|
||||||
fn resolve(&self, length: u32) -> u32;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResolvePercentage for NumberOrPercentage {
|
|
||||||
fn resolve(&self, length: u32) -> u32 {
|
|
||||||
match *self {
|
|
||||||
NumberOrPercentage::Percentage(p) => (p.0 * length as f32).round() as u32,
|
|
||||||
NumberOrPercentage::Number(n) => n.round() as u32,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn establishes_containing_block_for_absolute(
|
fn establishes_containing_block_for_absolute(
|
||||||
flags: StackingContextCollectionFlags,
|
flags: StackingContextCollectionFlags,
|
||||||
|
@ -167,10 +153,6 @@ static THREAD_TINT_COLORS: [ColorF; 8] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
|
|
||||||
&arr[index % arr.len()]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InlineNodeBorderInfo {
|
pub struct InlineNodeBorderInfo {
|
||||||
is_first_fragment_of_element: bool,
|
is_first_fragment_of_element: bool,
|
||||||
is_last_fragment_of_element: bool,
|
is_last_fragment_of_element: bool,
|
||||||
|
@ -332,6 +314,9 @@ pub struct DisplayListBuildState<'a> {
|
||||||
/// Vector containing iframe sizes, used to inform the constellation about
|
/// Vector containing iframe sizes, used to inform the constellation about
|
||||||
/// new iframe sizes
|
/// new iframe sizes
|
||||||
pub iframe_sizes: Vec<(BrowsingContextId, TypedSize2D<f32, CSSPixel>)>,
|
pub iframe_sizes: Vec<(BrowsingContextId, TypedSize2D<f32, CSSPixel>)>,
|
||||||
|
|
||||||
|
/// Stores text runs to answer text queries used to place a cursor inside text.
|
||||||
|
pub indexable_text: IndexableText,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DisplayListBuildState<'a> {
|
impl<'a> DisplayListBuildState<'a> {
|
||||||
|
@ -350,6 +335,7 @@ impl<'a> DisplayListBuildState<'a> {
|
||||||
current_stacking_context_id: StackingContextId::root(),
|
current_stacking_context_id: StackingContextId::root(),
|
||||||
current_clipping_and_scrolling: root_clip_indices,
|
current_clipping_and_scrolling: root_clip_indices,
|
||||||
iframe_sizes: Vec::new(),
|
iframe_sizes: Vec::new(),
|
||||||
|
indexable_text: IndexableText::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,19 +529,6 @@ pub trait FragmentDisplayListBuilding {
|
||||||
absolute_bounds: &Rect<Au>,
|
absolute_bounds: &Rect<Au>,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Determines where to place an element background image or gradient.
|
|
||||||
///
|
|
||||||
/// Photos have their resolution as intrinsic size while gradients have
|
|
||||||
/// no intrinsic size.
|
|
||||||
fn compute_background_placement(
|
|
||||||
&self,
|
|
||||||
state: &mut DisplayListBuildState,
|
|
||||||
style: &ComputedValues,
|
|
||||||
absolute_bounds: Rect<Au>,
|
|
||||||
intrinsic_size: Option<Size2D<Au>>,
|
|
||||||
index: usize,
|
|
||||||
) -> BackgroundPlacement;
|
|
||||||
|
|
||||||
/// Adds the display items necessary to paint a webrender image of this fragment to the
|
/// Adds the display items necessary to paint a webrender image of this fragment to the
|
||||||
/// appropriate section of the display list.
|
/// appropriate section of the display list.
|
||||||
fn build_display_list_for_webrender_image(
|
fn build_display_list_for_webrender_image(
|
||||||
|
@ -728,82 +701,6 @@ pub trait FragmentDisplayListBuilding {
|
||||||
fn fragment_type(&self) -> FragmentType;
|
fn fragment_type(&self) -> FragmentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
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: f32, radius_b: f32, edge_length: f32) -> f32 {
|
|
||||||
let required = radius_a + radius_b;
|
|
||||||
|
|
||||||
if required <= edge_length {
|
|
||||||
1.0
|
|
||||||
} else {
|
|
||||||
edge_length / required
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let top_factor = scale_factor(radii.top_left.width, radii.top_right.width, size.width);
|
|
||||||
let bottom_factor = scale_factor(
|
|
||||||
radii.bottom_left.width,
|
|
||||||
radii.bottom_right.width,
|
|
||||||
size.width,
|
|
||||||
);
|
|
||||||
let left_factor = scale_factor(radii.top_left.height, radii.bottom_left.height, size.height);
|
|
||||||
let right_factor = scale_factor(
|
|
||||||
radii.top_right.height,
|
|
||||||
radii.bottom_right.height,
|
|
||||||
size.height,
|
|
||||||
);
|
|
||||||
let min_factor = top_factor
|
|
||||||
.min(bottom_factor)
|
|
||||||
.min(left_factor)
|
|
||||||
.min(right_factor);
|
|
||||||
if min_factor < 1.0 {
|
|
||||||
scale_border_radii(radii, min_factor)
|
|
||||||
} else {
|
|
||||||
radii
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_border_radius(
|
|
||||||
abs_bounds: &Rect<Au>,
|
|
||||||
border_style: &style_structs::Border,
|
|
||||||
) -> 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.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(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the border radius for the rectangle inside of a rounded border. This is useful
|
/// Get the border radius for the rectangle inside of a rounded border. This is useful
|
||||||
/// for building the clip for the content inside the border.
|
/// for building the clip for the content inside the border.
|
||||||
fn build_border_radius_for_inner_rect(
|
fn build_border_radius_for_inner_rect(
|
||||||
|
@ -822,97 +719,6 @@ fn build_border_radius_for_inner_rect(
|
||||||
calculate_inner_border_radii(radii, border_widths)
|
calculate_inner_border_radii(radii, border_widths)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn simple_normal_border(color: ColorF, style: webrender_api::BorderStyle) -> NormalBorder {
|
|
||||||
let side = BorderSide { color, style };
|
|
||||||
NormalBorder {
|
|
||||||
left: side,
|
|
||||||
right: side,
|
|
||||||
top: side,
|
|
||||||
bottom: side,
|
|
||||||
radius: webrender_api::BorderRadius::zero(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn calculate_inner_border_radii(
|
|
||||||
mut radii: BorderRadius,
|
|
||||||
offsets: SideOffsets2D<Au>,
|
|
||||||
) -> 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 = inner_length(radii.top_right.width, offsets.right);
|
|
||||||
radii.bottom_right.width = inner_length(radii.bottom_right.width, offsets.right);
|
|
||||||
|
|
||||||
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 = inner_length(radii.bottom_left.height, offsets.bottom);
|
|
||||||
radii.bottom_right.height = inner_length(radii.bottom_right.height, offsets.bottom);
|
|
||||||
radii
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_image_border_details(
|
|
||||||
webrender_image: WebRenderImageInfo,
|
|
||||||
border_style_struct: &style_structs::Border,
|
|
||||||
) -> Option<BorderDetails> {
|
|
||||||
let corners = &border_style_struct.border_image_slice.offsets;
|
|
||||||
let border_image_repeat = &border_style_struct.border_image_repeat;
|
|
||||||
if let Some(image_key) = webrender_image.key {
|
|
||||||
Some(BorderDetails::Image(ImageBorder {
|
|
||||||
image_key: image_key,
|
|
||||||
patch: NinePatchDescriptor {
|
|
||||||
width: webrender_image.width,
|
|
||||||
height: webrender_image.height,
|
|
||||||
slice: SideOffsets2D::new(
|
|
||||||
corners.0.resolve(webrender_image.height),
|
|
||||||
corners.1.resolve(webrender_image.width),
|
|
||||||
corners.2.resolve(webrender_image.height),
|
|
||||||
corners.3.resolve(webrender_image.width),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
fill: border_style_struct.border_image_slice.fill,
|
|
||||||
// TODO(gw): Support border-image-outset
|
|
||||||
outset: SideOffsets2D::zero(),
|
|
||||||
repeat_horizontal: border_image_repeat.0.to_layout(),
|
|
||||||
repeat_vertical: border_image_repeat.1.to_layout(),
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_text_run_to_glyphs(
|
|
||||||
text_run: Arc<TextRun>,
|
|
||||||
range: Range<ByteIndex>,
|
|
||||||
mut origin: Point2D<Au>,
|
|
||||||
) -> Vec<GlyphInstance> {
|
|
||||||
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 {
|
impl FragmentDisplayListBuilding for Fragment {
|
||||||
fn collect_stacking_contexts_for_blocklike_fragment(
|
fn collect_stacking_contexts_for_blocklike_fragment(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -975,15 +781,13 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
let mut bounds = *absolute_bounds;
|
let mut bounds = *absolute_bounds;
|
||||||
|
|
||||||
// This is the clip for the color (which is the last element in the bg array)
|
// This is the clip for the color (which is the last element in the bg array)
|
||||||
let color_clip = get_cyclic(
|
// Background clips are never empty.
|
||||||
&background.background_clip.0,
|
let color_clip = &background.background_clip.0.last().unwrap();
|
||||||
background.background_image.0.len() - 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Adjust the clipping region as necessary to account for `border-radius`.
|
// Adjust the clipping region as necessary to account for `border-radius`.
|
||||||
let mut border_radii = build_border_radius(absolute_bounds, style.get_border());
|
let mut border_radii = build_border_radius(absolute_bounds, style.get_border());
|
||||||
|
|
||||||
match *color_clip {
|
match **color_clip {
|
||||||
BackgroundClip::BorderBox => {},
|
BackgroundClip::BorderBox => {},
|
||||||
BackgroundClip::PaddingBox => {
|
BackgroundClip::PaddingBox => {
|
||||||
let border = style.logical_border_width().to_physical(style.writing_mode);
|
let border = style.logical_border_width().to_physical(style.writing_mode);
|
||||||
|
@ -1095,83 +899,6 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_background_placement(
|
|
||||||
&self,
|
|
||||||
state: &mut DisplayListBuildState,
|
|
||||||
style: &ComputedValues,
|
|
||||||
absolute_bounds: Rect<Au>,
|
|
||||||
intrinsic_size: Option<Size2D<Au>>,
|
|
||||||
index: usize,
|
|
||||||
) -> BackgroundPlacement {
|
|
||||||
let bg = style.get_background();
|
|
||||||
let bg_attachment = *get_cyclic(&bg.background_attachment.0, index);
|
|
||||||
let bg_clip = *get_cyclic(&bg.background_clip.0, index);
|
|
||||||
let bg_origin = *get_cyclic(&bg.background_origin.0, index);
|
|
||||||
let bg_position_x = get_cyclic(&bg.background_position_x.0, index);
|
|
||||||
let bg_position_y = get_cyclic(&bg.background_position_y.0, index);
|
|
||||||
let bg_repeat = get_cyclic(&bg.background_repeat.0, index);
|
|
||||||
let bg_size = *get_cyclic(&bg.background_size.0, index);
|
|
||||||
|
|
||||||
let css_clip = match bg_clip {
|
|
||||||
BackgroundClip::BorderBox => absolute_bounds,
|
|
||||||
BackgroundClip::PaddingBox => absolute_bounds
|
|
||||||
.inner_rect(style.logical_border_width().to_physical(style.writing_mode)),
|
|
||||||
BackgroundClip::ContentBox => {
|
|
||||||
absolute_bounds.inner_rect(self.border_padding.to_physical(style.writing_mode))
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut bounds = match bg_attachment {
|
|
||||||
BackgroundAttachment::Scroll => match bg_origin {
|
|
||||||
BackgroundOrigin::BorderBox => absolute_bounds,
|
|
||||||
BackgroundOrigin::PaddingBox => absolute_bounds
|
|
||||||
.inner_rect(style.logical_border_width().to_physical(style.writing_mode)),
|
|
||||||
BackgroundOrigin::ContentBox => {
|
|
||||||
absolute_bounds.inner_rect(self.border_padding.to_physical(style.writing_mode))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
BackgroundAttachment::Fixed => Rect::new(
|
|
||||||
Point2D::origin(),
|
|
||||||
// Get current viewport
|
|
||||||
state.layout_context.shared_context().viewport_size(),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut tile_size = compute_background_image_size(bg_size, bounds.size, intrinsic_size);
|
|
||||||
|
|
||||||
let mut tile_spacing = Size2D::zero();
|
|
||||||
let own_position = bounds.size - tile_size;
|
|
||||||
let pos_x = bg_position_x.to_used_value(own_position.width);
|
|
||||||
let pos_y = bg_position_y.to_used_value(own_position.height);
|
|
||||||
tile_image_axis(
|
|
||||||
bg_repeat.0,
|
|
||||||
&mut bounds.origin.x,
|
|
||||||
&mut bounds.size.width,
|
|
||||||
&mut tile_size.width,
|
|
||||||
&mut tile_spacing.width,
|
|
||||||
pos_x,
|
|
||||||
css_clip.origin.x,
|
|
||||||
css_clip.size.width,
|
|
||||||
);
|
|
||||||
tile_image_axis(
|
|
||||||
bg_repeat.1,
|
|
||||||
&mut bounds.origin.y,
|
|
||||||
&mut bounds.size.height,
|
|
||||||
&mut tile_size.height,
|
|
||||||
&mut tile_spacing.height,
|
|
||||||
pos_y,
|
|
||||||
css_clip.origin.y,
|
|
||||||
css_clip.size.height,
|
|
||||||
);
|
|
||||||
|
|
||||||
BackgroundPlacement {
|
|
||||||
bounds,
|
|
||||||
tile_size,
|
|
||||||
tile_spacing,
|
|
||||||
css_clip,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_display_list_for_webrender_image(
|
fn build_display_list_for_webrender_image(
|
||||||
&self,
|
&self,
|
||||||
state: &mut DisplayListBuildState,
|
state: &mut DisplayListBuildState,
|
||||||
|
@ -1187,8 +914,15 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
Au::from_px(webrender_image.width as i32),
|
Au::from_px(webrender_image.width as i32),
|
||||||
Au::from_px(webrender_image.height as i32),
|
Au::from_px(webrender_image.height as i32),
|
||||||
);
|
);
|
||||||
let placement =
|
let placement = compute_background_placement(
|
||||||
self.compute_background_placement(state, style, absolute_bounds, Some(image), index);
|
style.get_background(),
|
||||||
|
state.layout_context.shared_context().viewport_size(),
|
||||||
|
absolute_bounds,
|
||||||
|
Some(image),
|
||||||
|
style.logical_border_width().to_physical(style.writing_mode),
|
||||||
|
self.border_padding.to_physical(style.writing_mode),
|
||||||
|
index,
|
||||||
|
);
|
||||||
|
|
||||||
// Create the image display item.
|
// Create the image display item.
|
||||||
let base = state.create_base_display_item(
|
let base = state.create_base_display_item(
|
||||||
|
@ -1203,7 +937,6 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
state.add_display_item(DisplayItem::Image(Box::new(ImageDisplayItem {
|
state.add_display_item(DisplayItem::Image(Box::new(ImageDisplayItem {
|
||||||
base: base,
|
base: base,
|
||||||
webrender_image: webrender_image,
|
webrender_image: webrender_image,
|
||||||
image_data: None,
|
|
||||||
stretch_size: placement.tile_size.to_layout(),
|
stretch_size: placement.tile_size.to_layout(),
|
||||||
tile_spacing: placement.tile_spacing.to_layout(),
|
tile_spacing: placement.tile_spacing.to_layout(),
|
||||||
image_rendering: style.get_inheritedbox().image_rendering.to_layout(),
|
image_rendering: style.get_inheritedbox().image_rendering.to_layout(),
|
||||||
|
@ -1280,8 +1013,15 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
style: &ComputedValues,
|
style: &ComputedValues,
|
||||||
index: usize,
|
index: usize,
|
||||||
) {
|
) {
|
||||||
let placement =
|
let placement = compute_background_placement(
|
||||||
self.compute_background_placement(state, style, absolute_bounds, None, index);
|
style.get_background(),
|
||||||
|
state.layout_context.shared_context().viewport_size(),
|
||||||
|
absolute_bounds,
|
||||||
|
None,
|
||||||
|
style.logical_border_width().to_physical(style.writing_mode),
|
||||||
|
self.border_padding.to_physical(style.writing_mode),
|
||||||
|
index,
|
||||||
|
);
|
||||||
|
|
||||||
let base = state.create_base_display_item(
|
let base = state.create_base_display_item(
|
||||||
&placement.bounds,
|
&placement.bounds,
|
||||||
|
@ -2000,7 +1740,6 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
state.add_display_item(DisplayItem::Image(Box::new(ImageDisplayItem {
|
state.add_display_item(DisplayItem::Image(Box::new(ImageDisplayItem {
|
||||||
base: base,
|
base: base,
|
||||||
webrender_image: WebRenderImageInfo::from_image(image),
|
webrender_image: WebRenderImageInfo::from_image(image),
|
||||||
image_data: Some(Arc::new(image.bytes.clone())),
|
|
||||||
stretch_size: stacking_relative_content_box.size.to_layout(),
|
stretch_size: stacking_relative_content_box.size.to_layout(),
|
||||||
tile_spacing: LayoutSize::zero(),
|
tile_spacing: LayoutSize::zero(),
|
||||||
image_rendering: self.style.get_inheritedbox().image_rendering.to_layout(),
|
image_rendering: self.style.get_inheritedbox().image_rendering.to_layout(),
|
||||||
|
@ -2041,7 +1780,6 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
format: format,
|
format: format,
|
||||||
key: Some(image_key),
|
key: Some(image_key),
|
||||||
},
|
},
|
||||||
image_data: None,
|
|
||||||
stretch_size: stacking_relative_content_box.size.to_layout(),
|
stretch_size: stacking_relative_content_box.size.to_layout(),
|
||||||
tile_spacing: LayoutSize::zero(),
|
tile_spacing: LayoutSize::zero(),
|
||||||
image_rendering: ImageRendering::Auto,
|
image_rendering: ImageRendering::Auto,
|
||||||
|
@ -2178,7 +1916,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
// Create display items for text decorations.
|
// Create display items for text decorations.
|
||||||
let text_decorations = self.style().get_inheritedtext().text_decorations_in_effect;
|
let text_decorations = self.style().get_inheritedtext().text_decorations_in_effect;
|
||||||
|
|
||||||
let stacking_relative_content_box = LogicalRect::from_physical(
|
let logical_stacking_relative_content_box = LogicalRect::from_physical(
|
||||||
self.style.writing_mode,
|
self.style.writing_mode,
|
||||||
*stacking_relative_content_box,
|
*stacking_relative_content_box,
|
||||||
container_size,
|
container_size,
|
||||||
|
@ -2186,9 +1924,10 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
|
|
||||||
// Underline
|
// Underline
|
||||||
if text_decorations.underline {
|
if text_decorations.underline {
|
||||||
let mut stacking_relative_box = stacking_relative_content_box;
|
let mut stacking_relative_box = logical_stacking_relative_content_box;
|
||||||
stacking_relative_box.start.b =
|
stacking_relative_box.start.b = logical_stacking_relative_content_box.start.b +
|
||||||
stacking_relative_content_box.start.b + metrics.ascent - metrics.underline_offset;
|
metrics.ascent -
|
||||||
|
metrics.underline_offset;
|
||||||
stacking_relative_box.size.block = metrics.underline_size;
|
stacking_relative_box.size.block = metrics.underline_size;
|
||||||
self.build_display_list_for_text_decoration(
|
self.build_display_list_for_text_decoration(
|
||||||
state,
|
state,
|
||||||
|
@ -2200,7 +1939,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
|
|
||||||
// Overline
|
// Overline
|
||||||
if text_decorations.overline {
|
if text_decorations.overline {
|
||||||
let mut stacking_relative_box = stacking_relative_content_box;
|
let mut stacking_relative_box = logical_stacking_relative_content_box;
|
||||||
stacking_relative_box.size.block = metrics.underline_size;
|
stacking_relative_box.size.block = metrics.underline_size;
|
||||||
self.build_display_list_for_text_decoration(
|
self.build_display_list_for_text_decoration(
|
||||||
state,
|
state,
|
||||||
|
@ -2217,11 +1956,16 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
baseline_origin,
|
baseline_origin,
|
||||||
);
|
);
|
||||||
if !glyphs.is_empty() {
|
if !glyphs.is_empty() {
|
||||||
state.add_display_item(DisplayItem::Text(Box::new(TextDisplayItem {
|
let indexable_text = IndexableTextItem {
|
||||||
base: base.clone(),
|
origin: stacking_relative_content_box.origin,
|
||||||
text_run: text_fragment.run.clone(),
|
text_run: text_fragment.run.clone(),
|
||||||
range: text_fragment.range,
|
range: text_fragment.range,
|
||||||
baseline_origin: baseline_origin.to_layout(),
|
baseline_origin,
|
||||||
|
};
|
||||||
|
state.indexable_text.insert(self.node, indexable_text);
|
||||||
|
|
||||||
|
state.add_display_item(DisplayItem::Text(Box::new(TextDisplayItem {
|
||||||
|
base: base.clone(),
|
||||||
glyphs: glyphs,
|
glyphs: glyphs,
|
||||||
font_key: text_fragment.run.font_key,
|
font_key: text_fragment.run.font_key,
|
||||||
text_color: text_color.to_layout(),
|
text_color: text_color.to_layout(),
|
||||||
|
@ -2233,7 +1977,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
|
|
||||||
// Line-Through
|
// Line-Through
|
||||||
if text_decorations.line_through {
|
if text_decorations.line_through {
|
||||||
let mut stacking_relative_box = stacking_relative_content_box;
|
let mut stacking_relative_box = logical_stacking_relative_content_box;
|
||||||
stacking_relative_box.start.b =
|
stacking_relative_box.start.b =
|
||||||
stacking_relative_box.start.b + metrics.ascent - metrics.strikeout_offset;
|
stacking_relative_box.start.b + metrics.ascent - metrics.strikeout_offset;
|
||||||
stacking_relative_box.size.block = metrics.strikeout_size;
|
stacking_relative_box.size.block = metrics.strikeout_size;
|
||||||
|
@ -2464,7 +2208,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
|
|
||||||
let perspective = self.fragment
|
let perspective = self.fragment
|
||||||
.perspective_matrix(&border_box)
|
.perspective_matrix(&border_box)
|
||||||
.unwrap_or_else(Transform3D::identity);
|
.unwrap_or(LayoutTransform::identity());
|
||||||
let transform = transform.pre_mul(&perspective).inverse();
|
let transform = transform.pre_mul(&perspective).inverse();
|
||||||
|
|
||||||
let origin = &border_box.origin;
|
let origin = &border_box.origin;
|
||||||
|
@ -2766,10 +2510,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
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;
|
||||||
let content_size = Size2D::new(content_size.x, content_size.y);
|
let content_size = Size2D::new(content_size.x, content_size.y);
|
||||||
|
|
||||||
let external_id = ExternalScrollId(
|
let external_id =
|
||||||
self.fragment.unique_id(),
|
ExternalScrollId(self.fragment.unique_id(), state.pipeline_id.to_webrender());
|
||||||
state.pipeline_id.to_webrender()
|
|
||||||
);
|
|
||||||
let new_clip_scroll_index = state.add_clip_scroll_node(ClipScrollNode {
|
let new_clip_scroll_index = state.add_clip_scroll_node(ClipScrollNode {
|
||||||
parent_index: self.clipping_and_scrolling().scrolling,
|
parent_index: self.clipping_and_scrolling().scrolling,
|
||||||
clip: clip,
|
clip: clip,
|
||||||
|
@ -3228,18 +2970,67 @@ pub enum BorderPaintingMode<'a> {
|
||||||
Hidden,
|
Hidden,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
fn convert_text_run_to_glyphs(
|
||||||
pub struct BackgroundPlacement {
|
text_run: Arc<TextRun>,
|
||||||
/// Rendering bounds. The background will start in the uppper-left corner
|
range: Range<ByteIndex>,
|
||||||
/// and fill the whole area.
|
mut origin: Point2D<Au>,
|
||||||
bounds: Rect<Au>,
|
) -> Vec<GlyphInstance> {
|
||||||
/// Background tile size. Some backgrounds are repeated. These are the
|
let mut glyphs = vec![];
|
||||||
/// dimensions of a single image of the background.
|
|
||||||
tile_size: Size2D<Au>,
|
for slice in text_run.natural_word_slices_in_visual_order(&range) {
|
||||||
/// Spacing between tiles. Some backgrounds are not repeated seamless
|
for glyph in slice.glyphs.iter_glyphs_for_byte_range(&slice.range) {
|
||||||
/// but have seams between them like tiles in real life.
|
let glyph_advance = if glyph.char_is_space() {
|
||||||
tile_spacing: Size2D<Au>,
|
glyph.advance() + text_run.extra_word_spacing
|
||||||
/// A clip area. While the background is rendered according to all the
|
} else {
|
||||||
/// measures above it is only shown within these bounds.
|
glyph.advance()
|
||||||
css_clip: Rect<Au>,
|
};
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IndexableTextItem {
|
||||||
|
/// The placement of the text item on the plane.
|
||||||
|
pub origin: Point2D<Au>,
|
||||||
|
/// The text run.
|
||||||
|
pub text_run: Arc<TextRun>,
|
||||||
|
/// The range of text within the text run.
|
||||||
|
pub range: Range<ByteIndex>,
|
||||||
|
/// The position of the start of the baseline of this text.
|
||||||
|
pub baseline_origin: Point2D<Au>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct IndexableText {
|
||||||
|
inner: FnvHashMap<OpaqueNode, Vec<IndexableTextItem>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexableText {
|
||||||
|
fn insert(&mut self, node: OpaqueNode, item: IndexableTextItem) {
|
||||||
|
let entries = self.inner.entry(node).or_insert(Vec::new());
|
||||||
|
entries.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, node: OpaqueNode) -> Option<&[IndexableTextItem]> {
|
||||||
|
self.inner.get(&node).map(|x| x.as_slice())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the text index within a node for the point of interest.
|
||||||
|
pub fn text_index(&self, node: OpaqueNode, point_in_item: Point2D<Au>) -> Option<usize> {
|
||||||
|
let item = self.inner.get(&node)?;
|
||||||
|
// TODO(#20020): access all elements
|
||||||
|
let point = point_in_item + item[0].origin.to_vector();
|
||||||
|
let offset = point - item[0].baseline_origin;
|
||||||
|
Some(item[0].text_run.range_index_of_advance(&item[0].range, offset.x))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ pub use self::builder::BlockFlowDisplayListBuilding;
|
||||||
pub use self::builder::BorderPaintingMode;
|
pub use self::builder::BorderPaintingMode;
|
||||||
pub use self::builder::DisplayListBuildState;
|
pub use self::builder::DisplayListBuildState;
|
||||||
pub use self::builder::FlexFlowDisplayListBuilding;
|
pub use self::builder::FlexFlowDisplayListBuilding;
|
||||||
|
pub use self::builder::IndexableText;
|
||||||
pub use self::builder::InlineFlowDisplayListBuilding;
|
pub use self::builder::InlineFlowDisplayListBuilding;
|
||||||
pub use self::builder::ListItemFlowDisplayListBuilding;
|
pub use self::builder::ListItemFlowDisplayListBuilding;
|
||||||
pub use self::builder::StackingContextCollectionFlags;
|
pub use self::builder::StackingContextCollectionFlags;
|
||||||
|
|
|
@ -11,8 +11,7 @@ use gfx::display_list::{BorderDetails, ClipScrollNode};
|
||||||
use gfx::display_list::{ClipScrollNodeIndex, ClipScrollNodeType, DisplayItem};
|
use gfx::display_list::{ClipScrollNodeIndex, ClipScrollNodeType, DisplayItem};
|
||||||
use gfx::display_list::{DisplayList, StackingContextType};
|
use gfx::display_list::{DisplayList, StackingContextType};
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use webrender_api::{self, ClipAndScrollInfo, ClipId};
|
use webrender_api::{self, ClipAndScrollInfo, ClipId, DisplayListBuilder};
|
||||||
use webrender_api::{DisplayListBuilder, LayoutTransform};
|
|
||||||
|
|
||||||
pub trait WebRenderDisplayListConverter {
|
pub trait WebRenderDisplayListConverter {
|
||||||
fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder;
|
fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder;
|
||||||
|
@ -224,19 +223,12 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
||||||
let stacking_context = &item.stacking_context;
|
let stacking_context = &item.stacking_context;
|
||||||
debug_assert_eq!(stacking_context.context_type, StackingContextType::Real);
|
debug_assert_eq!(stacking_context.context_type, StackingContextType::Real);
|
||||||
|
|
||||||
let transform = stacking_context
|
|
||||||
.transform
|
|
||||||
.map(|transform| LayoutTransform::from_untyped(&transform).into());
|
|
||||||
let perspective = stacking_context
|
|
||||||
.perspective
|
|
||||||
.map(|perspective| LayoutTransform::from_untyped(&perspective));
|
|
||||||
|
|
||||||
builder.push_stacking_context(
|
builder.push_stacking_context(
|
||||||
&webrender_api::LayoutPrimitiveInfo::new(stacking_context.bounds),
|
&webrender_api::LayoutPrimitiveInfo::new(stacking_context.bounds),
|
||||||
stacking_context.scroll_policy,
|
stacking_context.scroll_policy,
|
||||||
transform,
|
stacking_context.transform.map(Into::into),
|
||||||
stacking_context.transform_style,
|
stacking_context.transform_style,
|
||||||
perspective,
|
stacking_context.perspective,
|
||||||
stacking_context.mix_blend_mode,
|
stacking_context.mix_blend_mode,
|
||||||
stacking_context.filters.clone(),
|
stacking_context.filters.clone(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -29,7 +29,7 @@ use app_units::Au;
|
||||||
use block::{BlockFlow, FormattingContextType};
|
use block::{BlockFlow, FormattingContextType};
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use display_list::{DisplayListBuildState, StackingContextCollectionState};
|
use display_list::{DisplayListBuildState, StackingContextCollectionState};
|
||||||
use euclid::{Transform3D, Point2D, Vector2D, Rect, Size2D};
|
use euclid::{Point2D, Vector2D, Rect, Size2D};
|
||||||
use flex::FlexFlow;
|
use flex::FlexFlow;
|
||||||
use floats::{Floats, SpeculatedFloatPlacement};
|
use floats::{Floats, SpeculatedFloatPlacement};
|
||||||
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
|
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
|
||||||
|
@ -67,6 +67,7 @@ use table_colgroup::TableColGroupFlow;
|
||||||
use table_row::TableRowFlow;
|
use table_row::TableRowFlow;
|
||||||
use table_rowgroup::TableRowGroupFlow;
|
use table_rowgroup::TableRowGroupFlow;
|
||||||
use table_wrapper::TableWrapperFlow;
|
use table_wrapper::TableWrapperFlow;
|
||||||
|
use webrender_api::LayoutTransform;
|
||||||
|
|
||||||
/// This marker trait indicates that a type is a struct with `#[repr(C)]` whose first field
|
/// This marker trait indicates that a type is a struct with `#[repr(C)]` whose first field
|
||||||
/// is of type `BaseFlow` or some type that also implements this trait.
|
/// is of type `BaseFlow` or some type that also implements this trait.
|
||||||
|
@ -335,8 +336,8 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
|
||||||
let transform_2d = self.as_block()
|
let transform_2d = self.as_block()
|
||||||
.fragment
|
.fragment
|
||||||
.transform_matrix(&position)
|
.transform_matrix(&position)
|
||||||
.unwrap_or(Transform3D::identity())
|
.unwrap_or(LayoutTransform::identity())
|
||||||
.to_2d();
|
.to_2d().to_untyped();
|
||||||
let transformed_overflow = Overflow {
|
let transformed_overflow = Overflow {
|
||||||
paint: f32_rect_to_au_rect(transform_2d.transform_rect(
|
paint: f32_rect_to_au_rect(transform_2d.transform_rect(
|
||||||
&au_rect_to_f32_rect(overflow.paint))),
|
&au_rect_to_f32_rect(overflow.paint))),
|
||||||
|
|
|
@ -10,7 +10,8 @@ use ServoArc;
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use canvas_traits::canvas::CanvasMsg;
|
use canvas_traits::canvas::CanvasMsg;
|
||||||
use context::{LayoutContext, with_thread_local_font_context};
|
use context::{LayoutContext, with_thread_local_font_context};
|
||||||
use euclid::{Transform3D, Point2D, Vector2D, Rect, Size2D};
|
use display_list::ToLayout;
|
||||||
|
use euclid::{Point2D, Vector2D, Rect, Size2D};
|
||||||
use floats::ClearType;
|
use floats::ClearType;
|
||||||
use flow::{GetBaseFlow, ImmutableFlowUtils};
|
use flow::{GetBaseFlow, ImmutableFlowUtils};
|
||||||
use flow_ref::FlowRef;
|
use flow_ref::FlowRef;
|
||||||
|
@ -65,7 +66,7 @@ use style::values::generics::box_::VerticalAlign;
|
||||||
use style::values::generics::transform;
|
use style::values::generics::transform;
|
||||||
use text;
|
use text;
|
||||||
use text::TextRunScanner;
|
use text::TextRunScanner;
|
||||||
use webrender_api;
|
use webrender_api::{self, LayoutTransform};
|
||||||
use wrapper::ThreadSafeLayoutNodeHelpers;
|
use wrapper::ThreadSafeLayoutNodeHelpers;
|
||||||
|
|
||||||
// From gfxFontConstants.h in Firefox.
|
// From gfxFontConstants.h in Firefox.
|
||||||
|
@ -2867,9 +2868,10 @@ impl Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the 4D matrix representing this fragment's transform.
|
/// Returns the 4D matrix representing this fragment's transform.
|
||||||
pub fn transform_matrix(&self, stacking_relative_border_box: &Rect<Au>) -> Option<Transform3D<f32>> {
|
pub fn transform_matrix(&self, stacking_relative_border_box: &Rect<Au>) -> Option<LayoutTransform> {
|
||||||
let list = &self.style.get_box().transform;
|
let list = &self.style.get_box().transform;
|
||||||
let transform = list.to_transform_3d_matrix(Some(stacking_relative_border_box)).ok()?.0;
|
let transform = LayoutTransform::from_untyped(
|
||||||
|
&list.to_transform_3d_matrix(Some(stacking_relative_border_box)).ok()?.0);
|
||||||
|
|
||||||
let transform_origin = &self.style.get_box().transform_origin;
|
let transform_origin = &self.style.get_box().transform_origin;
|
||||||
let transform_origin_x =
|
let transform_origin_x =
|
||||||
|
@ -2882,38 +2884,42 @@ impl Fragment {
|
||||||
.to_f32_px();
|
.to_f32_px();
|
||||||
let transform_origin_z = transform_origin.depth.px();
|
let transform_origin_z = transform_origin.depth.px();
|
||||||
|
|
||||||
let pre_transform = Transform3D::create_translation(transform_origin_x,
|
let pre_transform = LayoutTransform::create_translation(
|
||||||
transform_origin_y,
|
transform_origin_x,
|
||||||
transform_origin_z);
|
transform_origin_y,
|
||||||
let post_transform = Transform3D::create_translation(-transform_origin_x,
|
transform_origin_z);
|
||||||
-transform_origin_y,
|
let post_transform = LayoutTransform::create_translation(
|
||||||
-transform_origin_z);
|
-transform_origin_x,
|
||||||
|
-transform_origin_y,
|
||||||
|
-transform_origin_z);
|
||||||
|
|
||||||
Some(pre_transform.pre_mul(&transform).pre_mul(&post_transform))
|
Some(pre_transform.pre_mul(&transform).pre_mul(&post_transform))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the 4D matrix representing this fragment's perspective.
|
/// Returns the 4D matrix representing this fragment's perspective.
|
||||||
pub fn perspective_matrix(&self, stacking_relative_border_box: &Rect<Au>) -> Option<Transform3D<f32>> {
|
pub fn perspective_matrix(&self, stacking_relative_border_box: &Rect<Au>) -> Option<LayoutTransform> {
|
||||||
match self.style().get_box().perspective {
|
match self.style().get_box().perspective {
|
||||||
Either::First(length) => {
|
Either::First(length) => {
|
||||||
let perspective_origin = self.style().get_box().perspective_origin;
|
let perspective_origin = self.style().get_box().perspective_origin;
|
||||||
let perspective_origin =
|
let perspective_origin =
|
||||||
Point2D::new(
|
Point2D::new(
|
||||||
perspective_origin.horizontal
|
perspective_origin.horizontal
|
||||||
.to_used_value(stacking_relative_border_box.size.width)
|
.to_used_value(stacking_relative_border_box.size.width),
|
||||||
.to_f32_px(),
|
|
||||||
perspective_origin.vertical
|
perspective_origin.vertical
|
||||||
.to_used_value(stacking_relative_border_box.size.height)
|
.to_used_value(stacking_relative_border_box.size.height)
|
||||||
.to_f32_px());
|
).to_layout();
|
||||||
|
|
||||||
let pre_transform = Transform3D::create_translation(perspective_origin.x,
|
let pre_transform = LayoutTransform::create_translation(
|
||||||
perspective_origin.y,
|
perspective_origin.x,
|
||||||
0.0);
|
perspective_origin.y,
|
||||||
let post_transform = Transform3D::create_translation(-perspective_origin.x,
|
0.0);
|
||||||
-perspective_origin.y,
|
let post_transform = LayoutTransform::create_translation(
|
||||||
0.0);
|
-perspective_origin.x,
|
||||||
|
-perspective_origin.y,
|
||||||
|
0.0);
|
||||||
|
|
||||||
let perspective_matrix = transform::create_perspective_matrix(length.px());
|
let perspective_matrix = LayoutTransform::from_untyped(
|
||||||
|
&transform::create_perspective_matrix(length.px()));
|
||||||
|
|
||||||
Some(pre_transform.pre_mul(&perspective_matrix).pre_mul(&post_transform))
|
Some(pre_transform.pre_mul(&perspective_matrix).pre_mul(&post_transform))
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,11 @@
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use construct::ConstructionResult;
|
use construct::ConstructionResult;
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
|
use display_list::IndexableText;
|
||||||
use euclid::{Point2D, Vector2D, Rect, Size2D};
|
use euclid::{Point2D, Vector2D, Rect, Size2D};
|
||||||
use flow::{Flow, GetBaseFlow};
|
use flow::{Flow, GetBaseFlow};
|
||||||
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
||||||
use gfx::display_list::{DisplayItem, DisplayList, OpaqueNode, ScrollOffsetMap};
|
use gfx::display_list::{DisplayList, OpaqueNode, ScrollOffsetMap};
|
||||||
use inline::InlineFragmentNodeFlags;
|
use inline::InlineFragmentNodeFlags;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
|
@ -26,7 +27,6 @@ use script_traits::LayoutMsg as ConstellationMsg;
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_traits::UntrustedNodeAddress;
|
||||||
use sequential;
|
use sequential;
|
||||||
use std::cmp::{min, max};
|
use std::cmp::{min, max};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use style::computed_values::display::T as Display;
|
use style::computed_values::display::T as Display;
|
||||||
|
@ -51,6 +51,8 @@ pub struct LayoutThreadData {
|
||||||
/// The root stacking context.
|
/// The root stacking context.
|
||||||
pub display_list: Option<Arc<DisplayList>>,
|
pub display_list: Option<Arc<DisplayList>>,
|
||||||
|
|
||||||
|
pub indexable_text: IndexableText,
|
||||||
|
|
||||||
/// A queued response for the union of the content boxes of a node.
|
/// A queued response for the union of the content boxes of a node.
|
||||||
pub content_box_response: Option<Rect<Au>>,
|
pub content_box_response: Option<Rect<Au>>,
|
||||||
|
|
||||||
|
@ -885,16 +887,11 @@ enum InnerTextItem {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#the-innertext-idl-attribute
|
// https://html.spec.whatwg.org/multipage/#the-innertext-idl-attribute
|
||||||
pub fn process_element_inner_text_query<N: LayoutNode>(node: N,
|
pub fn process_element_inner_text_query<N: LayoutNode>(node: N,
|
||||||
display_list: &Option<Arc<DisplayList>>) -> String {
|
indexable_text: &IndexableText) -> String {
|
||||||
if !display_list.is_some() {
|
|
||||||
warn!("We should have a display list at this point. Cannot get inner text");
|
|
||||||
return String::new();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 1.
|
// Step 1.
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
// Step 2.
|
// Step 2.
|
||||||
inner_text_collection_steps(node, display_list.as_ref().unwrap(), &mut results);
|
inner_text_collection_steps(node, indexable_text, &mut results);
|
||||||
let mut max_req_line_break_count = 0;
|
let mut max_req_line_break_count = 0;
|
||||||
let mut inner_text = Vec::new();
|
let mut inner_text = Vec::new();
|
||||||
for item in results {
|
for item in results {
|
||||||
|
@ -933,18 +930,8 @@ pub fn process_element_inner_text_query<N: LayoutNode>(node: N,
|
||||||
// https://html.spec.whatwg.org/multipage/#inner-text-collection-steps
|
// https://html.spec.whatwg.org/multipage/#inner-text-collection-steps
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn inner_text_collection_steps<N: LayoutNode>(node: N,
|
fn inner_text_collection_steps<N: LayoutNode>(node: N,
|
||||||
display_list: &Arc<DisplayList>,
|
indexable_text: &IndexableText,
|
||||||
results: &mut Vec<InnerTextItem>) {
|
results: &mut Vec<InnerTextItem>) {
|
||||||
// Extracts the text nodes from the display list to avoid traversing it
|
|
||||||
// for each child node.
|
|
||||||
let mut text = HashMap::new();
|
|
||||||
for item in &display_list.as_ref().list {
|
|
||||||
if let &DisplayItem::Text(ref text_content) = item {
|
|
||||||
let entries = text.entry(&item.base().metadata.node).or_insert(Vec::new());
|
|
||||||
entries.push(&text_content.text_run.text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
for child in node.traverse_preorder() {
|
for child in node.traverse_preorder() {
|
||||||
let node = match child.type_id() {
|
let node = match child.type_id() {
|
||||||
|
@ -983,9 +970,9 @@ fn inner_text_collection_steps<N: LayoutNode>(node: N,
|
||||||
match child.type_id() {
|
match child.type_id() {
|
||||||
LayoutNodeType::Text => {
|
LayoutNodeType::Text => {
|
||||||
// Step 4.
|
// Step 4.
|
||||||
if let Some(text_content) = text.get(&child.opaque()) {
|
if let Some(text_content) = indexable_text.get(child.opaque()) {
|
||||||
for content in text_content {
|
for content in text_content {
|
||||||
items.push(InnerTextItem::Text(content.to_string()));
|
items.push(InnerTextItem::Text(content.text_run.text.to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,6 +17,7 @@ use servo_config::opts;
|
||||||
use style::servo::restyle_damage::ServoRestyleDamage;
|
use style::servo::restyle_damage::ServoRestyleDamage;
|
||||||
use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList};
|
use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList};
|
||||||
use traversal::{InorderFlowTraversal, PostorderFlowTraversal, PreorderFlowTraversal};
|
use traversal::{InorderFlowTraversal, PostorderFlowTraversal, PreorderFlowTraversal};
|
||||||
|
use webrender_api::LayoutPoint;
|
||||||
|
|
||||||
pub fn resolve_generated_content(root: &mut Flow, layout_context: &LayoutContext) {
|
pub fn resolve_generated_content(root: &mut Flow, layout_context: &LayoutContext) {
|
||||||
ResolveGeneratedContent::new(&layout_context).traverse(root, 0);
|
ResolveGeneratedContent::new(&layout_context).traverse(root, 0);
|
||||||
|
@ -98,7 +99,7 @@ pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut Flow, iterator
|
||||||
if let Some(matrix) = kid.as_block()
|
if let Some(matrix) = kid.as_block()
|
||||||
.fragment
|
.fragment
|
||||||
.transform_matrix(&relative_position) {
|
.transform_matrix(&relative_position) {
|
||||||
let transform_matrix = matrix.transform_point2d(&Point2D::zero());
|
let transform_matrix = matrix.transform_point2d(&LayoutPoint::zero());
|
||||||
stacking_context_position = stacking_context_position +
|
stacking_context_position = stacking_context_position +
|
||||||
Vector2D::new(Au::from_f32_px(transform_matrix.x),
|
Vector2D::new(Au::from_f32_px(transform_matrix.x),
|
||||||
Au::from_f32_px(transform_matrix.y))
|
Au::from_f32_px(transform_matrix.y))
|
||||||
|
|
|
@ -68,7 +68,7 @@ use layout::context::LayoutContext;
|
||||||
use layout::context::RegisteredPainter;
|
use layout::context::RegisteredPainter;
|
||||||
use layout::context::RegisteredPainters;
|
use layout::context::RegisteredPainters;
|
||||||
use layout::context::malloc_size_of_persistent_local_context;
|
use layout::context::malloc_size_of_persistent_local_context;
|
||||||
use layout::display_list::ToLayout;
|
use layout::display_list::{IndexableText, ToLayout};
|
||||||
use layout::display_list::WebRenderDisplayListConverter;
|
use layout::display_list::WebRenderDisplayListConverter;
|
||||||
use layout::flow::{Flow, GetBaseFlow, ImmutableFlowUtils, MutableOwnedFlowUtils};
|
use layout::flow::{Flow, GetBaseFlow, ImmutableFlowUtils, MutableOwnedFlowUtils};
|
||||||
use layout::flow_ref::FlowRef;
|
use layout::flow_ref::FlowRef;
|
||||||
|
@ -515,6 +515,7 @@ impl LayoutThread {
|
||||||
LayoutThreadData {
|
LayoutThreadData {
|
||||||
constellation_chan: constellation_chan,
|
constellation_chan: constellation_chan,
|
||||||
display_list: None,
|
display_list: None,
|
||||||
|
indexable_text: IndexableText::default(),
|
||||||
content_box_response: None,
|
content_box_response: None,
|
||||||
content_boxes_response: Vec::new(),
|
content_boxes_response: Vec::new(),
|
||||||
client_rect_response: Rect::zero(),
|
client_rect_response: Rect::zero(),
|
||||||
|
@ -1002,6 +1003,9 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rw_data.indexable_text = std::mem::replace(
|
||||||
|
&mut build_state.indexable_text,
|
||||||
|
IndexableText::default());
|
||||||
rw_data.display_list = Some(Arc::new(build_state.to_display_list()));
|
rw_data.display_list = Some(Arc::new(build_state.to_display_list()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1366,10 +1370,7 @@ impl LayoutThread {
|
||||||
Au::from_f32_px(point_in_node.y)
|
Au::from_f32_px(point_in_node.y)
|
||||||
);
|
);
|
||||||
rw_data.text_index_response = TextIndexResponse(
|
rw_data.text_index_response = TextIndexResponse(
|
||||||
rw_data.display_list
|
rw_data.indexable_text.text_index(opaque_node, point_in_node)
|
||||||
.as_ref()
|
|
||||||
.expect("Tried to hit test with no display list")
|
|
||||||
.text_index(opaque_node, point_in_node.to_layout())
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
ReflowGoal::NodeGeometryQuery(node) => {
|
ReflowGoal::NodeGeometryQuery(node) => {
|
||||||
|
@ -1426,7 +1427,7 @@ impl LayoutThread {
|
||||||
ReflowGoal::ElementInnerTextQuery(node) => {
|
ReflowGoal::ElementInnerTextQuery(node) => {
|
||||||
let node = unsafe { ServoLayoutNode::new(&node) };
|
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||||
rw_data.element_inner_text_response =
|
rw_data.element_inner_text_response =
|
||||||
process_element_inner_text_query(node, &rw_data.display_list);
|
process_element_inner_text_query(node, &rw_data.indexable_text);
|
||||||
},
|
},
|
||||||
ReflowGoal::Full | ReflowGoal::TickAnimations => {}
|
ReflowGoal::Full | ReflowGoal::TickAnimations => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,6 @@ fn test_first_contentful_paint_setter() {
|
||||||
format: PixelFormat::RGB8,
|
format: PixelFormat::RGB8,
|
||||||
key: None,
|
key: None,
|
||||||
},
|
},
|
||||||
image_data: None,
|
|
||||||
stretch_size: LayoutSize::zero(),
|
stretch_size: LayoutSize::zero(),
|
||||||
tile_spacing: LayoutSize::zero(),
|
tile_spacing: LayoutSize::zero(),
|
||||||
image_rendering: ImageRendering::Auto,
|
image_rendering: ImageRendering::Auto,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue