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
|
||||
//! low-level drawing primitives.
|
||||
|
||||
use euclid::{Transform3D, Vector2D, TypedRect, SideOffsets2D};
|
||||
use euclid::{Vector2D, TypedRect, SideOffsets2D};
|
||||
use euclid::num::{One, Zero};
|
||||
use gfx_traits::{self, StackingContextId};
|
||||
use gfx_traits::print_tree::PrintTree;
|
||||
use ipc_channel::ipc::IpcSharedMemory;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use net_traits::image::base::{Image, PixelFormat};
|
||||
use range::Range;
|
||||
use servo_geometry::MaxRect;
|
||||
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, 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::{LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D, LineStyle};
|
||||
use webrender_api::{LocalClip, MixBlendMode, NormalBorder, ScrollPolicy, ScrollSensitivity};
|
||||
use webrender_api::{StickyOffsetBounds, TransformStyle};
|
||||
|
||||
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) {
|
||||
let mut print_tree = PrintTree::new("Display List".to_owned());
|
||||
self.print_with_tree(&mut print_tree);
|
||||
|
@ -209,13 +185,13 @@ pub struct StackingContext {
|
|||
pub mix_blend_mode: MixBlendMode,
|
||||
|
||||
/// 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.
|
||||
pub transform_style: TransformStyle,
|
||||
|
||||
/// The perspective matrix to be applied to children.
|
||||
pub perspective: Option<Transform3D<f32>>,
|
||||
pub perspective: Option<LayoutTransform>,
|
||||
|
||||
/// The scroll policy of this layer.
|
||||
pub scroll_policy: ScrollPolicy,
|
||||
|
@ -234,9 +210,9 @@ impl StackingContext {
|
|||
z_index: i32,
|
||||
filters: Vec<FilterOp>,
|
||||
mix_blend_mode: MixBlendMode,
|
||||
transform: Option<Transform3D<f32>>,
|
||||
transform: Option<LayoutTransform>,
|
||||
transform_style: TransformStyle,
|
||||
perspective: Option<Transform3D<f32>>,
|
||||
perspective: Option<LayoutTransform>,
|
||||
scroll_policy: ScrollPolicy,
|
||||
parent_clipping_and_scrolling: ClippingAndScrolling)
|
||||
-> StackingContext {
|
||||
|
@ -651,16 +627,6 @@ pub struct SolidColorDisplayItem {
|
|||
pub struct TextDisplayItem {
|
||||
/// Fields common to all display items.
|
||||
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.
|
||||
pub glyphs: Vec<GlyphInstance>,
|
||||
/// Reference to the font to be used.
|
||||
|
@ -683,9 +649,6 @@ pub struct ImageDisplayItem {
|
|||
|
||||
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 bounds of this display item, then the image will be repeated in the appropriate
|
||||
/// direction to tile the entire bounds.
|
||||
|
@ -1028,7 +991,7 @@ pub trait SimpleMatrixDetection {
|
|||
fn is_identity_or_simple_translation(&self) -> bool;
|
||||
}
|
||||
|
||||
impl SimpleMatrixDetection for Transform3D<f32> {
|
||||
impl SimpleMatrixDetection for LayoutTransform {
|
||||
#[inline]
|
||||
fn is_identity_or_simple_translation(&self) -> bool {
|
||||
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
|
||||
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 #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)
|
||||
.map(|slice| {
|
||||
let (slice_index, slice_advance) =
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
* 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/. */
|
||||
|
||||
//! 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)]
|
||||
|
||||
|
@ -10,12 +13,16 @@
|
|||
|
||||
use app_units::Au;
|
||||
use display_list::ToLayout;
|
||||
use euclid::{Point2D, Size2D, Vector2D};
|
||||
use gfx::display_list;
|
||||
use model::MaybeAuto;
|
||||
use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Vector2D};
|
||||
use gfx::display_list::{self, BorderDetails, WebRenderImageInfo};
|
||||
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::{LengthOrPercentage, LengthOrPercentageOrAuto, Percentage};
|
||||
use style::values::computed::Position;
|
||||
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||
use style::values::computed::{NumberOrPercentage, Percentage, Position};
|
||||
use style::values::computed::image::{EndingShape, LineDirection};
|
||||
use style::values::generics::background::BackgroundSize;
|
||||
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::specified::background::BackgroundRepeatKeyword;
|
||||
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.
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -34,9 +42,51 @@ struct StopRun {
|
|||
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
|
||||
/// image should be displayed on the background.
|
||||
pub fn compute_background_image_size(
|
||||
fn compute_background_image_size(
|
||||
bg_size: BackgroundSize<LengthOrPercentageOrAuto>,
|
||||
bounds_size: 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(
|
||||
position: &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.
|
||||
///
|
||||
/// This is done separately for both axes because the repeat keywords may differ.
|
||||
pub fn tile_image_axis(
|
||||
fn tile_image_axis(
|
||||
repeat: BackgroundRepeatKeyword,
|
||||
position: &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.
|
||||
// Note: Remove the + 2 if fix_gradient_stops is changed.
|
||||
let mut stops = Vec::with_capacity(stop_items.len() + 2);
|
||||
let mut stops = Vec::with_capacity(stop_items.len());
|
||||
let mut stop_run = None;
|
||||
for (i, stop) in stop_items.iter().enumerate() {
|
||||
let offset = match stop.position {
|
||||
|
@ -427,14 +552,7 @@ pub fn convert_linear_gradient(
|
|||
// 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 mut 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 stops = convert_gradient_stops(stops, length);
|
||||
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
let stops = convert_gradient_stops(stops, radius.width);
|
||||
|
||||
display_list::RadialGradient {
|
||||
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.
|
||||
fn get_distance_to_corner<F>(size: &Size2D<Au>, center: &Point2D<Au>, cmp: F) -> Au
|
||||
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 context::LayoutContext;
|
||||
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 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 flow::{BaseFlow, Flow, FlowFlags};
|
||||
use flow_ref::FlowRef;
|
||||
|
@ -41,7 +43,7 @@ use gfx_traits::{combine_id_with_fragment_type, FragmentType, StackingContextId}
|
|||
use inline::{InlineFlow, InlineFragmentNodeFlags};
|
||||
use ipc_channel::ipc;
|
||||
use list_item::ListItemFlow;
|
||||
use model::{self, MaybeAuto};
|
||||
use model::MaybeAuto;
|
||||
use msg::constellation_msg::{BrowsingContextId, PipelineId};
|
||||
use net_traits::image::base::PixelFormat;
|
||||
use net_traits::image_cache::UsePlaceholder;
|
||||
|
@ -52,20 +54,17 @@ 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;
|
||||
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::overflow_x::T as StyleOverflow;
|
||||
use style::computed_values::pointer_events::T as PointerEvents;
|
||||
use style::computed_values::position::T as StylePosition;
|
||||
use style::computed_values::visibility::T as Visibility;
|
||||
use style::logical_geometry::{LogicalMargin, LogicalPoint, LogicalRect};
|
||||
use style::properties::ComputedValues;
|
||||
use style::properties::style_structs;
|
||||
use style::properties::{ComputedValues, style_structs};
|
||||
use style::servo::restyle_damage::ServoRestyleDamage;
|
||||
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::pointing::Cursor;
|
||||
use style::values::generics::background::BackgroundSize;
|
||||
|
@ -75,23 +74,10 @@ use style_traits::ToCss;
|
|||
use style_traits::cursor::CursorKind;
|
||||
use table_cell::CollapsedBordersForCell;
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
use webrender_api::{ComplexClipRegion, ExternalScrollId, FilterOp, GlyphInstance};
|
||||
use webrender_api::{ImageRendering, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
|
||||
use webrender_api::{LineStyle, LocalClip, NormalBorder, ScrollPolicy};
|
||||
use webrender_api::{ScrollSensitivity, StickyOffsetBounds};
|
||||
|
||||
fn establishes_containing_block_for_absolute(
|
||||
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 {
|
||||
is_first_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
|
||||
/// new iframe sizes
|
||||
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> {
|
||||
|
@ -350,6 +335,7 @@ impl<'a> DisplayListBuildState<'a> {
|
|||
current_stacking_context_id: StackingContextId::root(),
|
||||
current_clipping_and_scrolling: root_clip_indices,
|
||||
iframe_sizes: Vec::new(),
|
||||
indexable_text: IndexableText::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,19 +529,6 @@ pub trait FragmentDisplayListBuilding {
|
|||
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
|
||||
/// appropriate section of the display list.
|
||||
fn build_display_list_for_webrender_image(
|
||||
|
@ -728,82 +701,6 @@ pub trait FragmentDisplayListBuilding {
|
|||
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
|
||||
/// for building the clip for the content inside the border.
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
fn collect_stacking_contexts_for_blocklike_fragment(
|
||||
&mut self,
|
||||
|
@ -975,15 +781,13 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
let mut bounds = *absolute_bounds;
|
||||
|
||||
// This is the clip for the color (which is the last element in the bg array)
|
||||
let color_clip = get_cyclic(
|
||||
&background.background_clip.0,
|
||||
background.background_image.0.len() - 1,
|
||||
);
|
||||
// Background clips are never empty.
|
||||
let color_clip = &background.background_clip.0.last().unwrap();
|
||||
|
||||
// Adjust the clipping region as necessary to account for `border-radius`.
|
||||
let mut border_radii = build_border_radius(absolute_bounds, style.get_border());
|
||||
|
||||
match *color_clip {
|
||||
match **color_clip {
|
||||
BackgroundClip::BorderBox => {},
|
||||
BackgroundClip::PaddingBox => {
|
||||
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(
|
||||
&self,
|
||||
state: &mut DisplayListBuildState,
|
||||
|
@ -1187,8 +914,15 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
Au::from_px(webrender_image.width as i32),
|
||||
Au::from_px(webrender_image.height as i32),
|
||||
);
|
||||
let placement =
|
||||
self.compute_background_placement(state, style, absolute_bounds, Some(image), index);
|
||||
let placement = compute_background_placement(
|
||||
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.
|
||||
let base = state.create_base_display_item(
|
||||
|
@ -1203,7 +937,6 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
state.add_display_item(DisplayItem::Image(Box::new(ImageDisplayItem {
|
||||
base: base,
|
||||
webrender_image: webrender_image,
|
||||
image_data: None,
|
||||
stretch_size: placement.tile_size.to_layout(),
|
||||
tile_spacing: placement.tile_spacing.to_layout(),
|
||||
image_rendering: style.get_inheritedbox().image_rendering.to_layout(),
|
||||
|
@ -1280,8 +1013,15 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
style: &ComputedValues,
|
||||
index: usize,
|
||||
) {
|
||||
let placement =
|
||||
self.compute_background_placement(state, style, absolute_bounds, None, index);
|
||||
let placement = compute_background_placement(
|
||||
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(
|
||||
&placement.bounds,
|
||||
|
@ -2000,7 +1740,6 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
state.add_display_item(DisplayItem::Image(Box::new(ImageDisplayItem {
|
||||
base: base,
|
||||
webrender_image: WebRenderImageInfo::from_image(image),
|
||||
image_data: Some(Arc::new(image.bytes.clone())),
|
||||
stretch_size: stacking_relative_content_box.size.to_layout(),
|
||||
tile_spacing: LayoutSize::zero(),
|
||||
image_rendering: self.style.get_inheritedbox().image_rendering.to_layout(),
|
||||
|
@ -2041,7 +1780,6 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
format: format,
|
||||
key: Some(image_key),
|
||||
},
|
||||
image_data: None,
|
||||
stretch_size: stacking_relative_content_box.size.to_layout(),
|
||||
tile_spacing: LayoutSize::zero(),
|
||||
image_rendering: ImageRendering::Auto,
|
||||
|
@ -2178,7 +1916,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
// Create display items for text decorations.
|
||||
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,
|
||||
*stacking_relative_content_box,
|
||||
container_size,
|
||||
|
@ -2186,9 +1924,10 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
|
||||
// Underline
|
||||
if text_decorations.underline {
|
||||
let mut stacking_relative_box = stacking_relative_content_box;
|
||||
stacking_relative_box.start.b =
|
||||
stacking_relative_content_box.start.b + metrics.ascent - metrics.underline_offset;
|
||||
let mut stacking_relative_box = logical_stacking_relative_content_box;
|
||||
stacking_relative_box.start.b = logical_stacking_relative_content_box.start.b +
|
||||
metrics.ascent -
|
||||
metrics.underline_offset;
|
||||
stacking_relative_box.size.block = metrics.underline_size;
|
||||
self.build_display_list_for_text_decoration(
|
||||
state,
|
||||
|
@ -2200,7 +1939,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
|
||||
// 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;
|
||||
self.build_display_list_for_text_decoration(
|
||||
state,
|
||||
|
@ -2217,11 +1956,16 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
baseline_origin,
|
||||
);
|
||||
if !glyphs.is_empty() {
|
||||
state.add_display_item(DisplayItem::Text(Box::new(TextDisplayItem {
|
||||
base: base.clone(),
|
||||
let indexable_text = IndexableTextItem {
|
||||
origin: stacking_relative_content_box.origin,
|
||||
text_run: text_fragment.run.clone(),
|
||||
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,
|
||||
font_key: text_fragment.run.font_key,
|
||||
text_color: text_color.to_layout(),
|
||||
|
@ -2233,7 +1977,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
|
||||
// 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 + metrics.ascent - metrics.strikeout_offset;
|
||||
stacking_relative_box.size.block = metrics.strikeout_size;
|
||||
|
@ -2464,7 +2208,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
|
||||
let perspective = self.fragment
|
||||
.perspective_matrix(&border_box)
|
||||
.unwrap_or_else(Transform3D::identity);
|
||||
.unwrap_or(LayoutTransform::identity());
|
||||
let transform = transform.pre_mul(&perspective).inverse();
|
||||
|
||||
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 = Size2D::new(content_size.x, content_size.y);
|
||||
|
||||
let external_id = ExternalScrollId(
|
||||
self.fragment.unique_id(),
|
||||
state.pipeline_id.to_webrender()
|
||||
);
|
||||
let external_id =
|
||||
ExternalScrollId(self.fragment.unique_id(), state.pipeline_id.to_webrender());
|
||||
let new_clip_scroll_index = state.add_clip_scroll_node(ClipScrollNode {
|
||||
parent_index: self.clipping_and_scrolling().scrolling,
|
||||
clip: clip,
|
||||
|
@ -3228,18 +2970,67 @@ pub enum BorderPaintingMode<'a> {
|
|||
Hidden,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct BackgroundPlacement {
|
||||
/// Rendering bounds. The background will start in the uppper-left corner
|
||||
/// and fill the whole area.
|
||||
bounds: Rect<Au>,
|
||||
/// Background tile size. Some backgrounds are repeated. These are the
|
||||
/// dimensions of a single image of the background.
|
||||
tile_size: Size2D<Au>,
|
||||
/// Spacing between tiles. Some backgrounds are not repeated seamless
|
||||
/// but have seams between them like tiles in real life.
|
||||
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.
|
||||
css_clip: Rect<Au>,
|
||||
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;
|
||||
}
|
||||
|
||||
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::DisplayListBuildState;
|
||||
pub use self::builder::FlexFlowDisplayListBuilding;
|
||||
pub use self::builder::IndexableText;
|
||||
pub use self::builder::InlineFlowDisplayListBuilding;
|
||||
pub use self::builder::ListItemFlowDisplayListBuilding;
|
||||
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::{DisplayList, StackingContextType};
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use webrender_api::{self, ClipAndScrollInfo, ClipId};
|
||||
use webrender_api::{DisplayListBuilder, LayoutTransform};
|
||||
use webrender_api::{self, ClipAndScrollInfo, ClipId, DisplayListBuilder};
|
||||
|
||||
pub trait WebRenderDisplayListConverter {
|
||||
fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder;
|
||||
|
@ -224,19 +223,12 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
|||
let stacking_context = &item.stacking_context;
|
||||
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(
|
||||
&webrender_api::LayoutPrimitiveInfo::new(stacking_context.bounds),
|
||||
stacking_context.scroll_policy,
|
||||
transform,
|
||||
stacking_context.transform.map(Into::into),
|
||||
stacking_context.transform_style,
|
||||
perspective,
|
||||
stacking_context.perspective,
|
||||
stacking_context.mix_blend_mode,
|
||||
stacking_context.filters.clone(),
|
||||
);
|
||||
|
|
|
@ -29,7 +29,7 @@ use app_units::Au;
|
|||
use block::{BlockFlow, FormattingContextType};
|
||||
use context::LayoutContext;
|
||||
use display_list::{DisplayListBuildState, StackingContextCollectionState};
|
||||
use euclid::{Transform3D, Point2D, Vector2D, Rect, Size2D};
|
||||
use euclid::{Point2D, Vector2D, Rect, Size2D};
|
||||
use flex::FlexFlow;
|
||||
use floats::{Floats, SpeculatedFloatPlacement};
|
||||
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
|
||||
|
@ -67,6 +67,7 @@ use table_colgroup::TableColGroupFlow;
|
|||
use table_row::TableRowFlow;
|
||||
use table_rowgroup::TableRowGroupFlow;
|
||||
use table_wrapper::TableWrapperFlow;
|
||||
use webrender_api::LayoutTransform;
|
||||
|
||||
/// 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.
|
||||
|
@ -335,8 +336,8 @@ pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {
|
|||
let transform_2d = self.as_block()
|
||||
.fragment
|
||||
.transform_matrix(&position)
|
||||
.unwrap_or(Transform3D::identity())
|
||||
.to_2d();
|
||||
.unwrap_or(LayoutTransform::identity())
|
||||
.to_2d().to_untyped();
|
||||
let transformed_overflow = Overflow {
|
||||
paint: f32_rect_to_au_rect(transform_2d.transform_rect(
|
||||
&au_rect_to_f32_rect(overflow.paint))),
|
||||
|
|
|
@ -10,7 +10,8 @@ use ServoArc;
|
|||
use app_units::Au;
|
||||
use canvas_traits::canvas::CanvasMsg;
|
||||
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 flow::{GetBaseFlow, ImmutableFlowUtils};
|
||||
use flow_ref::FlowRef;
|
||||
|
@ -65,7 +66,7 @@ use style::values::generics::box_::VerticalAlign;
|
|||
use style::values::generics::transform;
|
||||
use text;
|
||||
use text::TextRunScanner;
|
||||
use webrender_api;
|
||||
use webrender_api::{self, LayoutTransform};
|
||||
use wrapper::ThreadSafeLayoutNodeHelpers;
|
||||
|
||||
// From gfxFontConstants.h in Firefox.
|
||||
|
@ -2867,9 +2868,10 @@ impl Fragment {
|
|||
}
|
||||
|
||||
/// 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 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_x =
|
||||
|
@ -2882,38 +2884,42 @@ impl Fragment {
|
|||
.to_f32_px();
|
||||
let transform_origin_z = transform_origin.depth.px();
|
||||
|
||||
let pre_transform = Transform3D::create_translation(transform_origin_x,
|
||||
transform_origin_y,
|
||||
transform_origin_z);
|
||||
let post_transform = Transform3D::create_translation(-transform_origin_x,
|
||||
-transform_origin_y,
|
||||
-transform_origin_z);
|
||||
let pre_transform = LayoutTransform::create_translation(
|
||||
transform_origin_x,
|
||||
transform_origin_y,
|
||||
transform_origin_z);
|
||||
let post_transform = LayoutTransform::create_translation(
|
||||
-transform_origin_x,
|
||||
-transform_origin_y,
|
||||
-transform_origin_z);
|
||||
|
||||
Some(pre_transform.pre_mul(&transform).pre_mul(&post_transform))
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
Either::First(length) => {
|
||||
let perspective_origin = self.style().get_box().perspective_origin;
|
||||
let perspective_origin =
|
||||
Point2D::new(
|
||||
perspective_origin.horizontal
|
||||
.to_used_value(stacking_relative_border_box.size.width)
|
||||
.to_f32_px(),
|
||||
.to_used_value(stacking_relative_border_box.size.width),
|
||||
perspective_origin.vertical
|
||||
.to_used_value(stacking_relative_border_box.size.height)
|
||||
.to_f32_px());
|
||||
).to_layout();
|
||||
|
||||
let pre_transform = Transform3D::create_translation(perspective_origin.x,
|
||||
perspective_origin.y,
|
||||
0.0);
|
||||
let post_transform = Transform3D::create_translation(-perspective_origin.x,
|
||||
-perspective_origin.y,
|
||||
0.0);
|
||||
let pre_transform = LayoutTransform::create_translation(
|
||||
perspective_origin.x,
|
||||
perspective_origin.y,
|
||||
0.0);
|
||||
let post_transform = LayoutTransform::create_translation(
|
||||
-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))
|
||||
}
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
use app_units::Au;
|
||||
use construct::ConstructionResult;
|
||||
use context::LayoutContext;
|
||||
use display_list::IndexableText;
|
||||
use euclid::{Point2D, Vector2D, Rect, Size2D};
|
||||
use flow::{Flow, GetBaseFlow};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
||||
use gfx::display_list::{DisplayItem, DisplayList, OpaqueNode, ScrollOffsetMap};
|
||||
use gfx::display_list::{DisplayList, OpaqueNode, ScrollOffsetMap};
|
||||
use inline::InlineFragmentNodeFlags;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
|
@ -26,7 +27,6 @@ use script_traits::LayoutMsg as ConstellationMsg;
|
|||
use script_traits::UntrustedNodeAddress;
|
||||
use sequential;
|
||||
use std::cmp::{min, max};
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use style::computed_values::display::T as Display;
|
||||
|
@ -51,6 +51,8 @@ pub struct LayoutThreadData {
|
|||
/// The root stacking context.
|
||||
pub display_list: Option<Arc<DisplayList>>,
|
||||
|
||||
pub indexable_text: IndexableText,
|
||||
|
||||
/// A queued response for the union of the content boxes of a node.
|
||||
pub content_box_response: Option<Rect<Au>>,
|
||||
|
||||
|
@ -885,16 +887,11 @@ enum InnerTextItem {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#the-innertext-idl-attribute
|
||||
pub fn process_element_inner_text_query<N: LayoutNode>(node: N,
|
||||
display_list: &Option<Arc<DisplayList>>) -> String {
|
||||
if !display_list.is_some() {
|
||||
warn!("We should have a display list at this point. Cannot get inner text");
|
||||
return String::new();
|
||||
}
|
||||
|
||||
indexable_text: &IndexableText) -> String {
|
||||
// Step 1.
|
||||
let mut results = Vec::new();
|
||||
// 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 inner_text = Vec::new();
|
||||
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
|
||||
#[allow(unsafe_code)]
|
||||
fn inner_text_collection_steps<N: LayoutNode>(node: N,
|
||||
display_list: &Arc<DisplayList>,
|
||||
indexable_text: &IndexableText,
|
||||
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();
|
||||
for child in node.traverse_preorder() {
|
||||
let node = match child.type_id() {
|
||||
|
@ -983,9 +970,9 @@ fn inner_text_collection_steps<N: LayoutNode>(node: N,
|
|||
match child.type_id() {
|
||||
LayoutNodeType::Text => {
|
||||
// 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 {
|
||||
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 traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList};
|
||||
use traversal::{InorderFlowTraversal, PostorderFlowTraversal, PreorderFlowTraversal};
|
||||
use webrender_api::LayoutPoint;
|
||||
|
||||
pub fn resolve_generated_content(root: &mut Flow, layout_context: &LayoutContext) {
|
||||
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()
|
||||
.fragment
|
||||
.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 +
|
||||
Vector2D::new(Au::from_f32_px(transform_matrix.x),
|
||||
Au::from_f32_px(transform_matrix.y))
|
||||
|
|
|
@ -68,7 +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::{IndexableText, ToLayout};
|
||||
use layout::display_list::WebRenderDisplayListConverter;
|
||||
use layout::flow::{Flow, GetBaseFlow, ImmutableFlowUtils, MutableOwnedFlowUtils};
|
||||
use layout::flow_ref::FlowRef;
|
||||
|
@ -515,6 +515,7 @@ impl LayoutThread {
|
|||
LayoutThreadData {
|
||||
constellation_chan: constellation_chan,
|
||||
display_list: None,
|
||||
indexable_text: IndexableText::default(),
|
||||
content_box_response: None,
|
||||
content_boxes_response: Vec::new(),
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
@ -1366,10 +1370,7 @@ impl LayoutThread {
|
|||
Au::from_f32_px(point_in_node.y)
|
||||
);
|
||||
rw_data.text_index_response = TextIndexResponse(
|
||||
rw_data.display_list
|
||||
.as_ref()
|
||||
.expect("Tried to hit test with no display list")
|
||||
.text_index(opaque_node, point_in_node.to_layout())
|
||||
rw_data.indexable_text.text_index(opaque_node, point_in_node)
|
||||
);
|
||||
},
|
||||
ReflowGoal::NodeGeometryQuery(node) => {
|
||||
|
@ -1426,7 +1427,7 @@ impl LayoutThread {
|
|||
ReflowGoal::ElementInnerTextQuery(node) => {
|
||||
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||
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 => {}
|
||||
}
|
||||
|
|
|
@ -126,7 +126,6 @@ fn test_first_contentful_paint_setter() {
|
|||
format: PixelFormat::RGB8,
|
||||
key: None,
|
||||
},
|
||||
image_data: None,
|
||||
stretch_size: LayoutSize::zero(),
|
||||
tile_spacing: LayoutSize::zero(),
|
||||
image_rendering: ImageRendering::Auto,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue