mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Auto merge of #23956 - nox:trim-layout, r=Manishearth
Remove more stuff from layout_2020 <!-- 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/23956) <!-- Reviewable:end -->
This commit is contained in:
commit
3aa55904d1
8 changed files with 47 additions and 1079 deletions
|
@ -1,53 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Builds display lists from flows and fragments.
|
||||
//!
|
||||
//! Other browser engines sometimes call this "painting", but it is more accurately called display
|
||||
//! list building, as the actual painting does not happen here—only deciding *what* we're going to
|
||||
//! paint.
|
||||
|
||||
use crate::display_list::items::OpaqueNode;
|
||||
use app_units::Au;
|
||||
use euclid::default::Point2D;
|
||||
use fnv::FnvHashMap;
|
||||
use gfx::text::glyph::ByteIndex;
|
||||
use gfx::text::TextRun;
|
||||
use range::Range;
|
||||
use std::sync::Arc;
|
||||
|
||||
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 {
|
||||
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),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -2,9 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
pub use self::builder::IndexableText;
|
||||
pub use self::webrender_helpers::WebRenderDisplayListConverter;
|
||||
|
||||
mod builder;
|
||||
pub mod items;
|
||||
mod webrender_helpers;
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::fmt;
|
||||
use style::selector_parser::RestyleDamage;
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub unsafe trait HasBaseFlow {}
|
||||
|
||||
pub trait GetBaseFlow {
|
||||
fn base(&self) -> &BaseFlow;
|
||||
fn mut_base(&mut self) -> &mut BaseFlow;
|
||||
}
|
||||
|
||||
impl<T: HasBaseFlow + ?Sized> GetBaseFlow for T {
|
||||
#[inline(always)]
|
||||
#[allow(unsafe_code)]
|
||||
fn base(&self) -> &BaseFlow {
|
||||
let ptr: *const Self = self;
|
||||
let ptr = ptr as *const BaseFlow;
|
||||
unsafe { &*ptr }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(unsafe_code)]
|
||||
fn mut_base(&mut self) -> &mut BaseFlow {
|
||||
let ptr: *mut Self = self;
|
||||
let ptr = ptr as *mut BaseFlow;
|
||||
unsafe { &mut *ptr }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Flow: HasBaseFlow + fmt::Debug + Sync + Send + 'static {}
|
||||
|
||||
pub struct BaseFlow {
|
||||
pub restyle_damage: RestyleDamage,
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::flow::Flow;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FlowRef(Arc<dyn Flow>);
|
||||
|
||||
impl Deref for FlowRef {
|
||||
type Target = dyn Flow;
|
||||
fn deref(&self) -> &dyn Flow {
|
||||
self.0.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl FlowRef {
|
||||
pub fn new(mut r: Arc<dyn Flow>) -> Self {
|
||||
assert!(Arc::get_mut(&mut r).is_some());
|
||||
FlowRef(r)
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn deref_mut(this: &mut FlowRef) -> &mut dyn Flow {
|
||||
let ptr: *const dyn Flow = &*this.0;
|
||||
unsafe { &mut *(ptr as *mut dyn Flow) }
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ use crate::context::LayoutContext;
|
|||
use crate::display_list::items::OpaqueNode;
|
||||
use crate::ServoArc;
|
||||
use app_units::Au;
|
||||
use euclid::default::Rect;
|
||||
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutNode};
|
||||
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
||||
use style::logical_geometry::{LogicalMargin, LogicalRect};
|
||||
|
@ -98,13 +97,3 @@ impl Fragment {
|
|||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// A top-down fragment border box iteration handler.
|
||||
pub trait FragmentBorderBoxIterator {
|
||||
/// The operation to perform.
|
||||
fn process(&mut self, fragment: &Fragment, level: i32, overflow: &Rect<Au>);
|
||||
|
||||
/// Returns true if this fragment must be processed in-order. If this returns false,
|
||||
/// we skip the operation for this fragment, but continue processing siblings.
|
||||
fn should_process(&mut self, fragment: &Fragment) -> bool;
|
||||
}
|
||||
|
|
|
@ -10,8 +10,6 @@ extern crate serde;
|
|||
pub mod context;
|
||||
pub mod data;
|
||||
pub mod display_list;
|
||||
pub mod flow;
|
||||
pub mod flow_ref;
|
||||
mod fragment;
|
||||
pub mod opaque_node;
|
||||
pub mod query;
|
||||
|
@ -21,6 +19,4 @@ pub mod wrapper;
|
|||
// For unit tests:
|
||||
pub use crate::fragment::Fragment;
|
||||
|
||||
// We can't use servo_arc for everything in layout, because the Flow stuff uses
|
||||
// weak references.
|
||||
use servo_arc::Arc as ServoArc;
|
||||
|
|
|
@ -6,35 +6,20 @@
|
|||
|
||||
use crate::context::LayoutContext;
|
||||
use crate::display_list::items::{DisplayList, OpaqueNode, ScrollOffsetMap};
|
||||
use crate::display_list::IndexableText;
|
||||
use crate::fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use crate::opaque_node::OpaqueNodeMethods;
|
||||
use app_units::Au;
|
||||
use euclid::default::{Point2D, Rect, Size2D, Vector2D};
|
||||
use euclid::default::{Point2D, Rect};
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use script_layout_interface::rpc::TextIndexResponse;
|
||||
use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC};
|
||||
use script_layout_interface::rpc::{NodeGeometryResponse, NodeScrollIdResponse};
|
||||
use script_layout_interface::rpc::{OffsetParentResponse, ResolvedStyleResponse, StyleResponse};
|
||||
use script_layout_interface::wrapper_traits::{
|
||||
LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
|
||||
};
|
||||
use script_layout_interface::StyleData;
|
||||
use script_layout_interface::{LayoutElementType, LayoutNodeType};
|
||||
use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
|
||||
use script_traits::LayoutMsg as ConstellationMsg;
|
||||
use script_traits::UntrustedNodeAddress;
|
||||
use std::cmp::{max, min};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use style::computed_values::display::T as Display;
|
||||
use style::computed_values::position::T as Position;
|
||||
use style::computed_values::visibility::T as Visibility;
|
||||
use style::context::{StyleContext, ThreadLocalStyleContext};
|
||||
use style::dom::TElement;
|
||||
use style::logical_geometry::{BlockFlowDirection, InlineBaseDirection, WritingMode};
|
||||
use style::properties::{style_structs, LonghandId, PropertyDeclarationId, PropertyId};
|
||||
use style::properties::PropertyId;
|
||||
use style::selector_parser::PseudoElement;
|
||||
use style_traits::ToCss;
|
||||
use webrender_api::ExternalScrollId;
|
||||
|
||||
/// Mutable data belonging to the LayoutThread.
|
||||
|
@ -47,8 +32,6 @@ pub struct LayoutThreadData {
|
|||
/// The root stacking context.
|
||||
pub display_list: Option<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>>,
|
||||
|
||||
|
@ -88,29 +71,6 @@ pub struct LayoutThreadData {
|
|||
|
||||
pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutThreadData>>);
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#overflow-directions
|
||||
fn overflow_direction(writing_mode: &WritingMode) -> OverflowDirection {
|
||||
match (
|
||||
writing_mode.block_flow_direction(),
|
||||
writing_mode.inline_base_direction(),
|
||||
) {
|
||||
(BlockFlowDirection::TopToBottom, InlineBaseDirection::LeftToRight) |
|
||||
(BlockFlowDirection::LeftToRight, InlineBaseDirection::LeftToRight) => {
|
||||
OverflowDirection::RightAndDown
|
||||
},
|
||||
(BlockFlowDirection::TopToBottom, InlineBaseDirection::RightToLeft) |
|
||||
(BlockFlowDirection::RightToLeft, InlineBaseDirection::LeftToRight) => {
|
||||
OverflowDirection::LeftAndDown
|
||||
},
|
||||
(BlockFlowDirection::RightToLeft, InlineBaseDirection::RightToLeft) => {
|
||||
OverflowDirection::LeftAndUp
|
||||
},
|
||||
(BlockFlowDirection::LeftToRight, InlineBaseDirection::RightToLeft) => {
|
||||
OverflowDirection::RightAndUp
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl LayoutRPC for LayoutRPCImpl {
|
||||
// The neat thing here is that in order to answer the following two queries we only
|
||||
// need to compare nodes for equality. Thus we can safely work only with `OpaqueNode`.
|
||||
|
@ -189,428 +149,16 @@ impl LayoutRPC for LayoutRPCImpl {
|
|||
}
|
||||
}
|
||||
|
||||
struct UnioningFragmentBorderBoxIterator {
|
||||
node_address: OpaqueNode,
|
||||
rect: Option<Rect<Au>>,
|
||||
pub fn process_content_box_request(_requested_node: OpaqueNode) -> Option<Rect<Au>> {
|
||||
None
|
||||
}
|
||||
|
||||
impl UnioningFragmentBorderBoxIterator {
|
||||
fn new(node_address: OpaqueNode) -> UnioningFragmentBorderBoxIterator {
|
||||
UnioningFragmentBorderBoxIterator {
|
||||
node_address: node_address,
|
||||
rect: None,
|
||||
}
|
||||
}
|
||||
pub fn process_content_boxes_request(_requested_node: OpaqueNode) -> Vec<Rect<Au>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
impl FragmentBorderBoxIterator for UnioningFragmentBorderBoxIterator {
|
||||
fn process(&mut self, _: &Fragment, _: i32, border_box: &Rect<Au>) {
|
||||
self.rect = match self.rect {
|
||||
Some(rect) => Some(rect.union(border_box)),
|
||||
None => Some(*border_box),
|
||||
};
|
||||
}
|
||||
|
||||
fn should_process(&mut self, fragment: &Fragment) -> bool {
|
||||
fragment.contains_node(self.node_address)
|
||||
}
|
||||
}
|
||||
|
||||
struct CollectingFragmentBorderBoxIterator {
|
||||
node_address: OpaqueNode,
|
||||
rects: Vec<Rect<Au>>,
|
||||
}
|
||||
|
||||
impl CollectingFragmentBorderBoxIterator {
|
||||
fn new(node_address: OpaqueNode) -> CollectingFragmentBorderBoxIterator {
|
||||
CollectingFragmentBorderBoxIterator {
|
||||
node_address: node_address,
|
||||
rects: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FragmentBorderBoxIterator for CollectingFragmentBorderBoxIterator {
|
||||
fn process(&mut self, _: &Fragment, _: i32, border_box: &Rect<Au>) {
|
||||
self.rects.push(*border_box);
|
||||
}
|
||||
|
||||
fn should_process(&mut self, fragment: &Fragment) -> bool {
|
||||
fragment.contains_node(self.node_address)
|
||||
}
|
||||
}
|
||||
|
||||
enum Side {
|
||||
Left,
|
||||
Right,
|
||||
Bottom,
|
||||
Top,
|
||||
}
|
||||
|
||||
enum MarginPadding {
|
||||
Margin,
|
||||
Padding,
|
||||
}
|
||||
|
||||
enum PositionProperty {
|
||||
Left,
|
||||
Right,
|
||||
Top,
|
||||
Bottom,
|
||||
Width,
|
||||
Height,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum OverflowDirection {
|
||||
RightAndDown,
|
||||
LeftAndDown,
|
||||
LeftAndUp,
|
||||
RightAndUp,
|
||||
}
|
||||
|
||||
struct PositionRetrievingFragmentBorderBoxIterator {
|
||||
node_address: OpaqueNode,
|
||||
result: Option<Au>,
|
||||
position: Point2D<Au>,
|
||||
property: PositionProperty,
|
||||
}
|
||||
|
||||
impl PositionRetrievingFragmentBorderBoxIterator {
|
||||
fn new(
|
||||
node_address: OpaqueNode,
|
||||
property: PositionProperty,
|
||||
position: Point2D<Au>,
|
||||
) -> PositionRetrievingFragmentBorderBoxIterator {
|
||||
PositionRetrievingFragmentBorderBoxIterator {
|
||||
node_address: node_address,
|
||||
position: position,
|
||||
property: property,
|
||||
result: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FragmentBorderBoxIterator for PositionRetrievingFragmentBorderBoxIterator {
|
||||
fn process(&mut self, fragment: &Fragment, _: i32, border_box: &Rect<Au>) {
|
||||
let border_padding = fragment
|
||||
.border_padding
|
||||
.to_physical(fragment.style.writing_mode);
|
||||
self.result = Some(match self.property {
|
||||
PositionProperty::Left => self.position.x,
|
||||
PositionProperty::Top => self.position.y,
|
||||
PositionProperty::Width => border_box.size.width - border_padding.horizontal(),
|
||||
PositionProperty::Height => border_box.size.height - border_padding.vertical(),
|
||||
// TODO: the following 2 calculations are completely wrong.
|
||||
// They should return the difference between the parent's and this
|
||||
// fragment's border boxes.
|
||||
PositionProperty::Right => border_box.max_x() + self.position.x,
|
||||
PositionProperty::Bottom => border_box.max_y() + self.position.y,
|
||||
});
|
||||
}
|
||||
|
||||
fn should_process(&mut self, fragment: &Fragment) -> bool {
|
||||
fragment.contains_node(self.node_address)
|
||||
}
|
||||
}
|
||||
|
||||
struct MarginRetrievingFragmentBorderBoxIterator {
|
||||
node_address: OpaqueNode,
|
||||
result: Option<Au>,
|
||||
writing_mode: WritingMode,
|
||||
margin_padding: MarginPadding,
|
||||
side: Side,
|
||||
}
|
||||
|
||||
impl MarginRetrievingFragmentBorderBoxIterator {
|
||||
fn new(
|
||||
node_address: OpaqueNode,
|
||||
side: Side,
|
||||
margin_padding: MarginPadding,
|
||||
writing_mode: WritingMode,
|
||||
) -> MarginRetrievingFragmentBorderBoxIterator {
|
||||
MarginRetrievingFragmentBorderBoxIterator {
|
||||
node_address: node_address,
|
||||
side: side,
|
||||
margin_padding: margin_padding,
|
||||
result: None,
|
||||
writing_mode: writing_mode,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FragmentBorderBoxIterator for MarginRetrievingFragmentBorderBoxIterator {
|
||||
fn process(&mut self, fragment: &Fragment, _: i32, _: &Rect<Au>) {
|
||||
let rect = match self.margin_padding {
|
||||
MarginPadding::Margin => &fragment.margin,
|
||||
MarginPadding::Padding => &fragment.border_padding,
|
||||
};
|
||||
self.result = Some(match self.side {
|
||||
Side::Left => rect.left(self.writing_mode),
|
||||
Side::Right => rect.right(self.writing_mode),
|
||||
Side::Bottom => rect.bottom(self.writing_mode),
|
||||
Side::Top => rect.top(self.writing_mode),
|
||||
});
|
||||
}
|
||||
|
||||
fn should_process(&mut self, fragment: &Fragment) -> bool {
|
||||
fragment.contains_node(self.node_address)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_content_box_request(requested_node: OpaqueNode) -> Option<Rect<Au>> {
|
||||
UnioningFragmentBorderBoxIterator::new(requested_node).rect
|
||||
}
|
||||
|
||||
pub fn process_content_boxes_request(requested_node: OpaqueNode) -> Vec<Rect<Au>> {
|
||||
// FIXME(pcwalton): This has not been updated to handle the stacking context relative
|
||||
// stuff. So the position is wrong in most cases.
|
||||
CollectingFragmentBorderBoxIterator::new(requested_node).rects
|
||||
}
|
||||
|
||||
struct FragmentLocatingFragmentIterator {
|
||||
node_address: OpaqueNode,
|
||||
client_rect: Rect<i32>,
|
||||
}
|
||||
|
||||
impl FragmentLocatingFragmentIterator {
|
||||
fn new(node_address: OpaqueNode) -> FragmentLocatingFragmentIterator {
|
||||
FragmentLocatingFragmentIterator {
|
||||
node_address: node_address,
|
||||
client_rect: Rect::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct UnioningFragmentScrollAreaIterator {
|
||||
node_address: OpaqueNode,
|
||||
union_rect: Rect<i32>,
|
||||
origin_rect: Rect<i32>,
|
||||
level: Option<i32>,
|
||||
is_child: bool,
|
||||
overflow_direction: OverflowDirection,
|
||||
}
|
||||
|
||||
impl UnioningFragmentScrollAreaIterator {
|
||||
fn new(node_address: OpaqueNode) -> UnioningFragmentScrollAreaIterator {
|
||||
UnioningFragmentScrollAreaIterator {
|
||||
node_address: node_address,
|
||||
union_rect: Rect::zero(),
|
||||
origin_rect: Rect::zero(),
|
||||
level: None,
|
||||
is_child: false,
|
||||
// FIXME(#20867)
|
||||
overflow_direction: OverflowDirection::RightAndDown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NodeOffsetBoxInfo {
|
||||
offset: Point2D<Au>,
|
||||
rectangle: Rect<Au>,
|
||||
}
|
||||
|
||||
struct ParentBorderBoxInfo {
|
||||
node_address: OpaqueNode,
|
||||
origin: Point2D<Au>,
|
||||
}
|
||||
|
||||
struct ParentOffsetBorderBoxIterator {
|
||||
node_address: OpaqueNode,
|
||||
has_processed_node: bool,
|
||||
node_offset_box: Option<NodeOffsetBoxInfo>,
|
||||
parent_nodes: Vec<Option<ParentBorderBoxInfo>>,
|
||||
}
|
||||
|
||||
impl ParentOffsetBorderBoxIterator {
|
||||
fn new(node_address: OpaqueNode) -> ParentOffsetBorderBoxIterator {
|
||||
ParentOffsetBorderBoxIterator {
|
||||
node_address: node_address,
|
||||
has_processed_node: false,
|
||||
node_offset_box: None,
|
||||
parent_nodes: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FragmentBorderBoxIterator for FragmentLocatingFragmentIterator {
|
||||
fn process(&mut self, fragment: &Fragment, _: i32, border_box: &Rect<Au>) {
|
||||
let style_structs::Border {
|
||||
border_top_width: top_width,
|
||||
border_right_width: right_width,
|
||||
border_bottom_width: bottom_width,
|
||||
border_left_width: left_width,
|
||||
..
|
||||
} = *fragment.style.get_border();
|
||||
let (left_width, right_width) = (left_width.px(), right_width.px());
|
||||
let (top_width, bottom_width) = (top_width.px(), bottom_width.px());
|
||||
self.client_rect.origin.y = top_width as i32;
|
||||
self.client_rect.origin.x = left_width as i32;
|
||||
self.client_rect.size.width =
|
||||
(border_box.size.width.to_f32_px() - left_width - right_width) as i32;
|
||||
self.client_rect.size.height =
|
||||
(border_box.size.height.to_f32_px() - top_width - bottom_width) as i32;
|
||||
}
|
||||
|
||||
fn should_process(&mut self, fragment: &Fragment) -> bool {
|
||||
fragment.node == self.node_address
|
||||
}
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#scrolling-area
|
||||
impl FragmentBorderBoxIterator for UnioningFragmentScrollAreaIterator {
|
||||
fn process(&mut self, fragment: &Fragment, level: i32, border_box: &Rect<Au>) {
|
||||
// In cases in which smaller child elements contain less padding than the parent
|
||||
// the a union of the two elements padding rectangles could result in an unwanted
|
||||
// increase in size. To work around this, we store the original elements padding
|
||||
// rectangle as `origin_rect` and the union of all child elements padding and
|
||||
// margin rectangles as `union_rect`.
|
||||
let style_structs::Border {
|
||||
border_top_width: top_border,
|
||||
border_right_width: right_border,
|
||||
border_bottom_width: bottom_border,
|
||||
border_left_width: left_border,
|
||||
..
|
||||
} = *fragment.style.get_border();
|
||||
let (left_border, right_border) = (left_border.px(), right_border.px());
|
||||
let (top_border, bottom_border) = (top_border.px(), bottom_border.px());
|
||||
let right_padding = (border_box.size.width.to_f32_px() - right_border - left_border) as i32;
|
||||
let bottom_padding =
|
||||
(border_box.size.height.to_f32_px() - bottom_border - top_border) as i32;
|
||||
let top_padding = top_border as i32;
|
||||
let left_padding = left_border as i32;
|
||||
|
||||
match self.level {
|
||||
Some(start_level) if level <= start_level => {
|
||||
self.is_child = false;
|
||||
},
|
||||
Some(_) => {
|
||||
let padding = Rect::new(
|
||||
Point2D::new(left_padding, top_padding),
|
||||
Size2D::new(right_padding, bottom_padding),
|
||||
);
|
||||
let top_margin = fragment.margin.top(fragment.style.writing_mode).to_px();
|
||||
let left_margin = fragment.margin.left(fragment.style.writing_mode).to_px();
|
||||
let bottom_margin = fragment.margin.bottom(fragment.style.writing_mode).to_px();
|
||||
let right_margin = fragment.margin.right(fragment.style.writing_mode).to_px();
|
||||
let margin = Rect::new(
|
||||
Point2D::new(left_margin, top_margin),
|
||||
Size2D::new(right_margin, bottom_margin),
|
||||
);
|
||||
self.union_rect = self.union_rect.union(&margin).union(&padding);
|
||||
},
|
||||
None => {
|
||||
self.level = Some(level);
|
||||
self.is_child = true;
|
||||
self.overflow_direction = overflow_direction(&fragment.style.writing_mode);
|
||||
self.origin_rect = Rect::new(
|
||||
Point2D::new(left_padding, top_padding),
|
||||
Size2D::new(right_padding, bottom_padding),
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn should_process(&mut self, fragment: &Fragment) -> bool {
|
||||
fragment.contains_node(self.node_address) || self.is_child
|
||||
}
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
|
||||
impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator {
|
||||
fn process(&mut self, fragment: &Fragment, level: i32, border_box: &Rect<Au>) {
|
||||
if self.node_offset_box.is_none() {
|
||||
// We haven't found the node yet, so we're still looking
|
||||
// for its parent. Remove all nodes at this level or
|
||||
// higher, as they can't be parents of this node.
|
||||
self.parent_nodes.truncate(level as usize);
|
||||
assert_eq!(
|
||||
self.parent_nodes.len(),
|
||||
level as usize,
|
||||
"Skipped at least one level in the flow tree!"
|
||||
);
|
||||
}
|
||||
|
||||
if !fragment.is_primary_fragment() {
|
||||
// This fragment doesn't correspond to anything worth
|
||||
// taking measurements from.
|
||||
|
||||
if self.node_offset_box.is_none() {
|
||||
// If this is the only fragment in the flow, we need to
|
||||
// do this to avoid failing the above assertion.
|
||||
self.parent_nodes.push(None);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if fragment.node == self.node_address {
|
||||
// Found the fragment in the flow tree that matches the
|
||||
// DOM node being looked for.
|
||||
|
||||
assert!(
|
||||
self.node_offset_box.is_none(),
|
||||
"Node was being treated as inline, but it has an associated fragment!"
|
||||
);
|
||||
|
||||
self.has_processed_node = true;
|
||||
self.node_offset_box = Some(NodeOffsetBoxInfo {
|
||||
offset: border_box.origin,
|
||||
rectangle: *border_box,
|
||||
});
|
||||
|
||||
// offsetParent returns null if the node is fixed.
|
||||
if fragment.style.get_box().position == Position::Fixed {
|
||||
self.parent_nodes.clear();
|
||||
}
|
||||
} else if self.node_offset_box.is_none() {
|
||||
// TODO(gw): Is there a less fragile way of checking whether this
|
||||
// fragment is the body element, rather than just checking that
|
||||
// it's at level 1 (below the root node)?
|
||||
let is_body_element = level == 1;
|
||||
|
||||
let is_valid_parent = match (
|
||||
is_body_element,
|
||||
fragment.style.get_box().position,
|
||||
&fragment.specific,
|
||||
) {
|
||||
// Spec says it's valid if any of these are true:
|
||||
// 1) Is the body element
|
||||
// 2) Is static position *and* is a table or table cell
|
||||
// 3) Is not static position
|
||||
(true, _, _) |
|
||||
(false, Position::Absolute, _) |
|
||||
(false, Position::Relative, _) |
|
||||
(false, Position::Fixed, _) => true,
|
||||
|
||||
// Otherwise, it's not a valid parent
|
||||
(false, Position::Static, _) => false,
|
||||
};
|
||||
|
||||
let parent_info = if is_valid_parent {
|
||||
let border_width = fragment
|
||||
.border_width()
|
||||
.to_physical(fragment.style.writing_mode);
|
||||
|
||||
Some(ParentBorderBoxInfo {
|
||||
node_address: fragment.node,
|
||||
origin: border_box.origin + Vector2D::new(border_width.left, border_width.top),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.parent_nodes.push(parent_info);
|
||||
}
|
||||
}
|
||||
|
||||
fn should_process(&mut self, _: &Fragment) -> bool {
|
||||
!self.has_processed_node
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_node_geometry_request(requested_node: OpaqueNode) -> Rect<i32> {
|
||||
FragmentLocatingFragmentIterator::new(requested_node).client_rect
|
||||
pub fn process_node_geometry_request(_requested_node: OpaqueNode) -> Rect<i32> {
|
||||
Rect::zero()
|
||||
}
|
||||
|
||||
pub fn process_node_scroll_id_request<N: LayoutNode>(
|
||||
|
@ -622,380 +170,37 @@ pub fn process_node_scroll_id_request<N: LayoutNode>(
|
|||
}
|
||||
|
||||
/// https://drafts.csswg.org/cssom-view/#scrolling-area
|
||||
pub fn process_node_scroll_area_request(requested_node: OpaqueNode) -> Rect<i32> {
|
||||
let iterator = UnioningFragmentScrollAreaIterator::new(requested_node);
|
||||
match iterator.overflow_direction {
|
||||
OverflowDirection::RightAndDown => {
|
||||
let right = max(
|
||||
iterator.union_rect.size.width,
|
||||
iterator.origin_rect.size.width,
|
||||
);
|
||||
let bottom = max(
|
||||
iterator.union_rect.size.height,
|
||||
iterator.origin_rect.size.height,
|
||||
);
|
||||
Rect::new(iterator.origin_rect.origin, Size2D::new(right, bottom))
|
||||
},
|
||||
OverflowDirection::LeftAndDown => {
|
||||
let bottom = max(
|
||||
iterator.union_rect.size.height,
|
||||
iterator.origin_rect.size.height,
|
||||
);
|
||||
let left = min(iterator.union_rect.origin.x, iterator.origin_rect.origin.x);
|
||||
Rect::new(
|
||||
Point2D::new(left, iterator.origin_rect.origin.y),
|
||||
Size2D::new(iterator.origin_rect.size.width, bottom),
|
||||
)
|
||||
},
|
||||
OverflowDirection::LeftAndUp => {
|
||||
let top = min(iterator.union_rect.origin.y, iterator.origin_rect.origin.y);
|
||||
let left = min(iterator.union_rect.origin.x, iterator.origin_rect.origin.x);
|
||||
Rect::new(Point2D::new(left, top), iterator.origin_rect.size)
|
||||
},
|
||||
OverflowDirection::RightAndUp => {
|
||||
let top = min(iterator.union_rect.origin.y, iterator.origin_rect.origin.y);
|
||||
let right = max(
|
||||
iterator.union_rect.size.width,
|
||||
iterator.origin_rect.size.width,
|
||||
);
|
||||
Rect::new(
|
||||
Point2D::new(iterator.origin_rect.origin.x, top),
|
||||
Size2D::new(right, iterator.origin_rect.size.height),
|
||||
)
|
||||
},
|
||||
}
|
||||
pub fn process_node_scroll_area_request(_requested_node: OpaqueNode) -> Rect<i32> {
|
||||
Rect::zero()
|
||||
}
|
||||
|
||||
/// Return the resolved value of property for a given (pseudo)element.
|
||||
/// <https://drafts.csswg.org/cssom/#resolved-value>
|
||||
pub fn process_resolved_style_request<'a, N>(
|
||||
context: &LayoutContext,
|
||||
node: N,
|
||||
pseudo: &Option<PseudoElement>,
|
||||
property: &PropertyId,
|
||||
_context: &LayoutContext,
|
||||
_node: N,
|
||||
_pseudo: &Option<PseudoElement>,
|
||||
_property: &PropertyId,
|
||||
) -> String
|
||||
where
|
||||
N: LayoutNode,
|
||||
{
|
||||
use style::stylist::RuleInclusion;
|
||||
use style::traversal::resolve_style;
|
||||
|
||||
let element = node.as_element().unwrap();
|
||||
|
||||
// We call process_resolved_style_request after performing a whole-document
|
||||
// traversal, so in the common case, the element is styled.
|
||||
if element.get_data().is_some() {
|
||||
return process_resolved_style_request_internal(node, pseudo, property);
|
||||
}
|
||||
|
||||
// In a display: none subtree. No pseudo-element exists.
|
||||
if pseudo.is_some() {
|
||||
return String::new();
|
||||
}
|
||||
|
||||
let mut tlc = ThreadLocalStyleContext::new(&context.style_context);
|
||||
let mut context = StyleContext {
|
||||
shared: &context.style_context,
|
||||
thread_local: &mut tlc,
|
||||
};
|
||||
|
||||
let styles = resolve_style(&mut context, element, RuleInclusion::All, pseudo.as_ref());
|
||||
let style = styles.primary();
|
||||
let longhand_id = match *property {
|
||||
PropertyId::LonghandAlias(id, _) | PropertyId::Longhand(id) => id,
|
||||
// Firefox returns blank strings for the computed value of shorthands,
|
||||
// so this should be web-compatible.
|
||||
PropertyId::ShorthandAlias(..) | PropertyId::Shorthand(_) => return String::new(),
|
||||
PropertyId::Custom(ref name) => {
|
||||
return style.computed_value_to_string(PropertyDeclarationId::Custom(name));
|
||||
},
|
||||
};
|
||||
|
||||
// No need to care about used values here, since we're on a display: none
|
||||
// subtree, use the resolved value.
|
||||
style.computed_value_to_string(PropertyDeclarationId::Longhand(longhand_id))
|
||||
"".to_owned()
|
||||
}
|
||||
|
||||
/// The primary resolution logic, which assumes that the element is styled.
|
||||
fn process_resolved_style_request_internal<'a, N>(
|
||||
requested_node: N,
|
||||
pseudo: &Option<PseudoElement>,
|
||||
property: &PropertyId,
|
||||
) -> String
|
||||
where
|
||||
N: LayoutNode,
|
||||
{
|
||||
let layout_el = requested_node.to_threadsafe().as_element().unwrap();
|
||||
let layout_el = match *pseudo {
|
||||
Some(PseudoElement::Before) => layout_el.get_before_pseudo(),
|
||||
Some(PseudoElement::After) => layout_el.get_after_pseudo(),
|
||||
Some(PseudoElement::DetailsSummary) |
|
||||
Some(PseudoElement::DetailsContent) |
|
||||
Some(PseudoElement::Selection) => None,
|
||||
// FIXME(emilio): What about the other pseudos? Probably they shouldn't
|
||||
// just return the element's style!
|
||||
_ => Some(layout_el),
|
||||
};
|
||||
|
||||
let layout_el = match layout_el {
|
||||
None => {
|
||||
// The pseudo doesn't exist, return nothing. Chrome seems to query
|
||||
// the element itself in this case, Firefox uses the resolved value.
|
||||
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=29006
|
||||
return String::new();
|
||||
},
|
||||
Some(layout_el) => layout_el,
|
||||
};
|
||||
|
||||
let style = &*layout_el.resolved_style();
|
||||
let longhand_id = match *property {
|
||||
PropertyId::LonghandAlias(id, _) | PropertyId::Longhand(id) => id,
|
||||
// Firefox returns blank strings for the computed value of shorthands,
|
||||
// so this should be web-compatible.
|
||||
PropertyId::ShorthandAlias(..) | PropertyId::Shorthand(_) => return String::new(),
|
||||
PropertyId::Custom(ref name) => {
|
||||
return style.computed_value_to_string(PropertyDeclarationId::Custom(name));
|
||||
},
|
||||
};
|
||||
|
||||
let positioned = match style.get_box().position {
|
||||
Position::Relative | Position::Fixed | Position::Absolute => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
//TODO: determine whether requested property applies to the element.
|
||||
// eg. width does not apply to non-replaced inline elements.
|
||||
// Existing browsers disagree about when left/top/right/bottom apply
|
||||
// (Chrome seems to think they never apply and always returns resolved values).
|
||||
// There are probably other quirks.
|
||||
let applies = true;
|
||||
|
||||
fn used_value_for_position_property<N: LayoutNode>(
|
||||
_layout_el: <N::ConcreteThreadSafeLayoutNode as ThreadSafeLayoutNode>::ConcreteThreadSafeLayoutElement,
|
||||
requested_node: N,
|
||||
longhand_id: LonghandId,
|
||||
) -> String {
|
||||
let position = Point2D::zero();
|
||||
let property = match longhand_id {
|
||||
LonghandId::Bottom => PositionProperty::Bottom,
|
||||
LonghandId::Top => PositionProperty::Top,
|
||||
LonghandId::Left => PositionProperty::Left,
|
||||
LonghandId::Right => PositionProperty::Right,
|
||||
LonghandId::Width => PositionProperty::Width,
|
||||
LonghandId::Height => PositionProperty::Height,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let iterator = PositionRetrievingFragmentBorderBoxIterator::new(
|
||||
requested_node.opaque(),
|
||||
property,
|
||||
position,
|
||||
);
|
||||
iterator
|
||||
.result
|
||||
.map(|r| r.to_css_string())
|
||||
.unwrap_or(String::new())
|
||||
}
|
||||
|
||||
// TODO: we will return neither the computed nor used value for margin and padding.
|
||||
match longhand_id {
|
||||
LonghandId::MarginBottom |
|
||||
LonghandId::MarginTop |
|
||||
LonghandId::MarginLeft |
|
||||
LonghandId::MarginRight |
|
||||
LonghandId::PaddingBottom |
|
||||
LonghandId::PaddingTop |
|
||||
LonghandId::PaddingLeft |
|
||||
LonghandId::PaddingRight
|
||||
if applies && style.get_box().display != Display::None =>
|
||||
{
|
||||
let (margin_padding, side) = match longhand_id {
|
||||
LonghandId::MarginBottom => (MarginPadding::Margin, Side::Bottom),
|
||||
LonghandId::MarginTop => (MarginPadding::Margin, Side::Top),
|
||||
LonghandId::MarginLeft => (MarginPadding::Margin, Side::Left),
|
||||
LonghandId::MarginRight => (MarginPadding::Margin, Side::Right),
|
||||
LonghandId::PaddingBottom => (MarginPadding::Padding, Side::Bottom),
|
||||
LonghandId::PaddingTop => (MarginPadding::Padding, Side::Top),
|
||||
LonghandId::PaddingLeft => (MarginPadding::Padding, Side::Left),
|
||||
LonghandId::PaddingRight => (MarginPadding::Padding, Side::Right),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let iterator = MarginRetrievingFragmentBorderBoxIterator::new(
|
||||
requested_node.opaque(),
|
||||
side,
|
||||
margin_padding,
|
||||
style.writing_mode,
|
||||
);
|
||||
iterator
|
||||
.result
|
||||
.map(|r| r.to_css_string())
|
||||
.unwrap_or(String::new())
|
||||
}
|
||||
|
||||
LonghandId::Bottom | LonghandId::Top | LonghandId::Right | LonghandId::Left
|
||||
if applies && positioned && style.get_box().display != Display::None =>
|
||||
{
|
||||
used_value_for_position_property(layout_el, requested_node, longhand_id)
|
||||
},
|
||||
LonghandId::Width | LonghandId::Height
|
||||
if applies && style.get_box().display != Display::None =>
|
||||
{
|
||||
used_value_for_position_property(layout_el, requested_node, longhand_id)
|
||||
},
|
||||
// FIXME: implement used value computation for line-height
|
||||
_ => style.computed_value_to_string(PropertyDeclarationId::Longhand(longhand_id)),
|
||||
}
|
||||
pub fn process_offset_parent_query(_requested_node: OpaqueNode) -> OffsetParentResponse {
|
||||
OffsetParentResponse::empty()
|
||||
}
|
||||
|
||||
pub fn process_offset_parent_query(requested_node: OpaqueNode) -> OffsetParentResponse {
|
||||
let iterator = ParentOffsetBorderBoxIterator::new(requested_node);
|
||||
|
||||
let node_offset_box = iterator.node_offset_box;
|
||||
let parent_info = iterator
|
||||
.parent_nodes
|
||||
.into_iter()
|
||||
.rev()
|
||||
.filter_map(|info| info)
|
||||
.next();
|
||||
match (node_offset_box, parent_info) {
|
||||
(Some(node_offset_box), Some(parent_info)) => {
|
||||
let origin = node_offset_box.offset - parent_info.origin.to_vector();
|
||||
let size = node_offset_box.rectangle.size;
|
||||
OffsetParentResponse {
|
||||
node_address: Some(parent_info.node_address.to_untrusted_node_address()),
|
||||
rect: Rect::new(origin, size),
|
||||
}
|
||||
},
|
||||
_ => OffsetParentResponse::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_style_query<N: LayoutNode>(requested_node: N) -> StyleResponse {
|
||||
let element = requested_node.as_element().unwrap();
|
||||
let data = element.borrow_data();
|
||||
|
||||
StyleResponse(data.map(|d| d.styles.primary().clone()))
|
||||
}
|
||||
|
||||
enum InnerTextItem {
|
||||
Text(String),
|
||||
RequiredLineBreakCount(u32),
|
||||
pub fn process_style_query<N: LayoutNode>(_requested_node: N) -> StyleResponse {
|
||||
StyleResponse(None)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#the-innertext-idl-attribute
|
||||
pub fn process_element_inner_text_query<N: LayoutNode>(
|
||||
node: N,
|
||||
indexable_text: &IndexableText,
|
||||
) -> String {
|
||||
// Step 1.
|
||||
let mut results = Vec::new();
|
||||
// Step 2.
|
||||
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 {
|
||||
match item {
|
||||
InnerTextItem::Text(s) => {
|
||||
if max_req_line_break_count > 0 {
|
||||
// Step 5.
|
||||
for _ in 0..max_req_line_break_count {
|
||||
inner_text.push("\u{000A}".to_owned());
|
||||
}
|
||||
max_req_line_break_count = 0;
|
||||
}
|
||||
// Step 3.
|
||||
if !s.is_empty() {
|
||||
inner_text.push(s.to_owned());
|
||||
}
|
||||
},
|
||||
InnerTextItem::RequiredLineBreakCount(count) => {
|
||||
// Step 4.
|
||||
if inner_text.len() == 0 {
|
||||
// Remove required line break count at the start.
|
||||
continue;
|
||||
}
|
||||
// Store the count if it's the max of this run,
|
||||
// but it may be ignored if no text item is found afterwards,
|
||||
// which means that these are consecutive line breaks at the end.
|
||||
if count > max_req_line_break_count {
|
||||
max_req_line_break_count = count;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
inner_text.into_iter().collect()
|
||||
pub fn process_element_inner_text_query<N: LayoutNode>(_node: N) -> String {
|
||||
"".to_owned()
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#inner-text-collection-steps
|
||||
#[allow(unsafe_code)]
|
||||
fn inner_text_collection_steps<N: LayoutNode>(
|
||||
node: N,
|
||||
indexable_text: &IndexableText,
|
||||
results: &mut Vec<InnerTextItem>,
|
||||
) {
|
||||
let mut items = Vec::new();
|
||||
for child in node.traverse_preorder() {
|
||||
let node = match child.type_id() {
|
||||
LayoutNodeType::Text => child.parent_node().unwrap(),
|
||||
_ => child,
|
||||
};
|
||||
|
||||
let element_data = unsafe {
|
||||
node.get_style_and_layout_data()
|
||||
.map(|d| &(*(d.ptr.as_ptr() as *mut StyleData)).element_data)
|
||||
};
|
||||
|
||||
if element_data.is_none() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let style = match element_data.unwrap().borrow().styles.get_primary() {
|
||||
None => continue,
|
||||
Some(style) => style.clone(),
|
||||
};
|
||||
|
||||
// Step 2.
|
||||
if style.get_inherited_box().visibility != Visibility::Visible {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Step 3.
|
||||
let display = style.get_box().display;
|
||||
if !child.is_connected() || display == Display::None {
|
||||
continue;
|
||||
}
|
||||
|
||||
match child.type_id() {
|
||||
LayoutNodeType::Text => {
|
||||
// Step 4.
|
||||
if let Some(text_content) = indexable_text.get(child.opaque()) {
|
||||
for content in text_content {
|
||||
items.push(InnerTextItem::Text(content.text_run.text.to_string()));
|
||||
}
|
||||
}
|
||||
},
|
||||
LayoutNodeType::Element(LayoutElementType::HTMLBRElement) => {
|
||||
// Step 5.
|
||||
items.push(InnerTextItem::Text(String::from(
|
||||
"\u{000A}", /* line feed */
|
||||
)));
|
||||
},
|
||||
LayoutNodeType::Element(LayoutElementType::HTMLParagraphElement) => {
|
||||
// Step 8.
|
||||
items.insert(0, InnerTextItem::RequiredLineBreakCount(2));
|
||||
items.push(InnerTextItem::RequiredLineBreakCount(2));
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
match display {
|
||||
Display::Block => {
|
||||
// Step 9.
|
||||
items.insert(0, InnerTextItem::RequiredLineBreakCount(1));
|
||||
items.push(InnerTextItem::RequiredLineBreakCount(1));
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
results.append(&mut items);
|
||||
pub fn process_text_index_request(_node: OpaqueNode, _point: Point2D<Au>) -> TextIndexResponse {
|
||||
TextIndexResponse(None)
|
||||
}
|
||||
|
|
|
@ -37,10 +37,8 @@ use histogram::Histogram;
|
|||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use layout::context::LayoutContext;
|
||||
use layout::display_list::items::{DisplayList, OpaqueNode};
|
||||
use layout::display_list::{IndexableText, WebRenderDisplayListConverter};
|
||||
use layout::flow::{Flow, GetBaseFlow};
|
||||
use layout::flow_ref::FlowRef;
|
||||
use layout::display_list::items::DisplayList;
|
||||
use layout::display_list::WebRenderDisplayListConverter;
|
||||
use layout::query::{
|
||||
process_content_box_request, process_content_boxes_request, LayoutRPCImpl, LayoutThreadData,
|
||||
};
|
||||
|
@ -48,6 +46,7 @@ use layout::query::{process_element_inner_text_query, process_node_geometry_requ
|
|||
use layout::query::{process_node_scroll_area_request, process_node_scroll_id_request};
|
||||
use layout::query::{
|
||||
process_offset_parent_query, process_resolved_style_request, process_style_query,
|
||||
process_text_index_request,
|
||||
};
|
||||
use layout::traversal::RecalcStyleAndConstructFlows;
|
||||
use layout_traits::LayoutThreadFactory;
|
||||
|
@ -60,7 +59,6 @@ use msg::constellation_msg::{
|
|||
use msg::constellation_msg::{LayoutHangAnnotation, MonitoredComponentType, PipelineId};
|
||||
use msg::constellation_msg::{MonitoredComponentId, TopLevelBrowsingContextId};
|
||||
use net_traits::image_cache::ImageCache;
|
||||
use parking_lot::RwLock;
|
||||
use profile_traits::mem::{self as profile_mem, Report, ReportKind, ReportsChan};
|
||||
use profile_traits::time::{self as profile_time, profile, TimerMetadata};
|
||||
use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
|
||||
|
@ -68,7 +66,6 @@ use script_layout_interface::message::{LayoutThreadInit, Msg, NodesFromPointQuer
|
|||
use script_layout_interface::message::{QueryMsg, ReflowComplete, ReflowGoal, ScriptReflow};
|
||||
use script_layout_interface::rpc::TextIndexResponse;
|
||||
use script_layout_interface::rpc::{LayoutRPC, OffsetParentResponse, StyleResponse};
|
||||
use script_layout_interface::wrapper_traits::LayoutNode;
|
||||
use script_traits::Painter;
|
||||
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
|
||||
use script_traits::{DrawAPaintImageResult, PaintWorkletError};
|
||||
|
@ -91,7 +88,7 @@ use std::time::Duration;
|
|||
use style::animation::Animation;
|
||||
use style::context::{QuirksMode, RegisteredSpeculativePainter, RegisteredSpeculativePainters};
|
||||
use style::context::{SharedStyleContext, ThreadLocalStyleContextCreationInfo};
|
||||
use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TDocument, TElement, TNode};
|
||||
use style::dom::{ShowSubtree, TDocument, TElement, TNode};
|
||||
use style::driver;
|
||||
use style::error_reporting::RustLogReporter;
|
||||
use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL};
|
||||
|
@ -99,7 +96,6 @@ use style::invalidation::element::restyle_hints::RestyleHint;
|
|||
use style::media_queries::{Device, MediaList, MediaType};
|
||||
use style::properties::PropertyId;
|
||||
use style::selector_parser::SnapshotMap;
|
||||
use style::servo::restyle_damage::ServoRestyleDamage;
|
||||
use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards};
|
||||
use style::stylesheets::{
|
||||
DocumentStyleSheet, Origin, Stylesheet, StylesheetInDocument, UserAgentStylesheets,
|
||||
|
@ -177,18 +173,9 @@ pub struct LayoutThread {
|
|||
/// The number of Web fonts that have been requested but not yet loaded.
|
||||
outstanding_web_fonts: Arc<AtomicUsize>,
|
||||
|
||||
/// The root of the flow tree.
|
||||
root_flow: RefCell<Option<FlowRef>>,
|
||||
|
||||
/// The document-specific shared lock used for author-origin stylesheets
|
||||
document_shared_lock: Option<SharedRwLock>,
|
||||
|
||||
/// The list of currently-running animations.
|
||||
running_animations: ServoArc<RwLock<FxHashMap<OpaqueNode, Vec<Animation>>>>,
|
||||
|
||||
/// The list of animations that have expired since the last style recalculation.
|
||||
expired_animations: ServoArc<RwLock<FxHashMap<OpaqueNode, Vec<Animation>>>>,
|
||||
|
||||
/// A counter for epoch messages
|
||||
epoch: Cell<Epoch>,
|
||||
|
||||
|
@ -234,31 +221,8 @@ pub struct LayoutThread {
|
|||
/// If unspecified, will use the platform default setting.
|
||||
device_pixels_per_px: Option<f32>,
|
||||
|
||||
/// Dumps the display list form after a layout.
|
||||
dump_display_list: bool,
|
||||
|
||||
/// Dumps the display list in JSON form after a layout.
|
||||
dump_display_list_json: bool,
|
||||
|
||||
/// Dumps the DOM after restyle.
|
||||
dump_style_tree: bool,
|
||||
|
||||
/// Dumps the flow tree after a layout.
|
||||
dump_rule_tree: bool,
|
||||
|
||||
/// Emits notifications when there is a relayout.
|
||||
relayout_event: bool,
|
||||
|
||||
/// True to turn off incremental layout.
|
||||
nonincremental_layout: bool,
|
||||
|
||||
/// True if each step of layout is traced to an external JSON file
|
||||
/// for debugging purposes. Setting this implies sequential layout
|
||||
/// and paint.
|
||||
trace_layout: bool,
|
||||
|
||||
/// Dumps the flow tree after a layout.
|
||||
dump_flow_tree: bool,
|
||||
}
|
||||
|
||||
impl LayoutThreadFactory for LayoutThread {
|
||||
|
@ -287,14 +251,14 @@ impl LayoutThreadFactory for LayoutThread {
|
|||
load_webfonts_synchronously: bool,
|
||||
initial_window_size: Size2D<u32, DeviceIndependentPixel>,
|
||||
device_pixels_per_px: Option<f32>,
|
||||
dump_display_list: bool,
|
||||
dump_display_list_json: bool,
|
||||
dump_style_tree: bool,
|
||||
dump_rule_tree: bool,
|
||||
_dump_display_list: bool,
|
||||
_dump_display_list_json: bool,
|
||||
_dump_style_tree: bool,
|
||||
_dump_rule_tree: bool,
|
||||
relayout_event: bool,
|
||||
nonincremental_layout: bool,
|
||||
trace_layout: bool,
|
||||
dump_flow_tree: bool,
|
||||
_nonincremental_layout: bool,
|
||||
_trace_layout: bool,
|
||||
_dump_flow_tree: bool,
|
||||
) {
|
||||
thread::Builder::new()
|
||||
.name(format!("LayoutThread {:?}", id))
|
||||
|
@ -335,14 +299,7 @@ impl LayoutThreadFactory for LayoutThread {
|
|||
load_webfonts_synchronously,
|
||||
initial_window_size,
|
||||
device_pixels_per_px,
|
||||
dump_display_list,
|
||||
dump_display_list_json,
|
||||
dump_style_tree,
|
||||
dump_rule_tree,
|
||||
relayout_event,
|
||||
nonincremental_layout,
|
||||
trace_layout,
|
||||
dump_flow_tree,
|
||||
);
|
||||
|
||||
let reporter_name = format!("layout-reporter-{}", id);
|
||||
|
@ -508,14 +465,7 @@ impl LayoutThread {
|
|||
load_webfonts_synchronously: bool,
|
||||
initial_window_size: Size2D<u32, DeviceIndependentPixel>,
|
||||
device_pixels_per_px: Option<f32>,
|
||||
dump_display_list: bool,
|
||||
dump_display_list_json: bool,
|
||||
dump_style_tree: bool,
|
||||
dump_rule_tree: bool,
|
||||
relayout_event: bool,
|
||||
nonincremental_layout: bool,
|
||||
trace_layout: bool,
|
||||
dump_flow_tree: bool,
|
||||
) -> LayoutThread {
|
||||
// The device pixel ratio is incorrect (it does not have the hidpi value),
|
||||
// but it will be set correctly when the initial reflow takes place.
|
||||
|
@ -557,10 +507,7 @@ impl LayoutThread {
|
|||
new_animations_sender: new_animations_sender,
|
||||
_new_animations_receiver: new_animations_receiver,
|
||||
outstanding_web_fonts: Arc::new(AtomicUsize::new(0)),
|
||||
root_flow: RefCell::new(None),
|
||||
document_shared_lock: None,
|
||||
running_animations: ServoArc::new(RwLock::new(Default::default())),
|
||||
expired_animations: ServoArc::new(RwLock::new(Default::default())),
|
||||
epoch: Cell::new(Epoch(0)),
|
||||
viewport_size: Size2D::new(Au(0), Au(0)),
|
||||
webrender_api: webrender_api_sender.create_api(),
|
||||
|
@ -569,7 +516,6 @@ impl LayoutThread {
|
|||
rw_data: Arc::new(Mutex::new(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(),
|
||||
|
@ -594,14 +540,7 @@ impl LayoutThread {
|
|||
load_webfonts_synchronously,
|
||||
initial_window_size,
|
||||
device_pixels_per_px,
|
||||
dump_display_list,
|
||||
dump_display_list_json,
|
||||
dump_style_tree,
|
||||
dump_rule_tree,
|
||||
relayout_event,
|
||||
nonincremental_layout,
|
||||
trace_layout,
|
||||
dump_flow_tree,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -634,8 +573,8 @@ impl LayoutThread {
|
|||
options: GLOBAL_STYLE_DATA.options.clone(),
|
||||
guards,
|
||||
visited_styles_enabled: false,
|
||||
running_animations: self.running_animations.clone(),
|
||||
expired_animations: self.expired_animations.clone(),
|
||||
running_animations: Default::default(),
|
||||
expired_animations: Default::default(),
|
||||
registered_speculative_painters: &self.registered_painters,
|
||||
local_context_creation_data: Mutex::new(thread_local_style_context_creation_data),
|
||||
timer: self.timer.clone(),
|
||||
|
@ -829,7 +768,7 @@ impl LayoutThread {
|
|||
self.paint_time_metrics.set_navigation_start(time);
|
||||
},
|
||||
Msg::GetRunningAnimations(sender) => {
|
||||
let _ = sender.send(self.running_animations.read().len());
|
||||
let _ = sender.send(0);
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -888,14 +827,14 @@ impl LayoutThread {
|
|||
self.load_webfonts_synchronously,
|
||||
self.initial_window_size,
|
||||
self.device_pixels_per_px,
|
||||
self.dump_display_list,
|
||||
self.dump_display_list_json,
|
||||
self.dump_style_tree,
|
||||
self.dump_rule_tree,
|
||||
false, // dump_display_list
|
||||
false, // dump_display_list_json
|
||||
false, // dump_style_tree
|
||||
false, // dump_rule_tree
|
||||
self.relayout_event,
|
||||
self.nonincremental_layout,
|
||||
self.trace_layout,
|
||||
self.dump_flow_tree,
|
||||
true, // nonincremental_layout
|
||||
false, // trace_layout
|
||||
false, // dump_flow_tree
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -936,7 +875,6 @@ impl LayoutThread {
|
|||
waiting_time_min, waiting_time_max, waiting_time_mean, waiting_time_stddev
|
||||
);
|
||||
|
||||
self.root_flow.borrow_mut().take();
|
||||
self.background_hang_monitor.unregister();
|
||||
}
|
||||
|
||||
|
@ -969,10 +907,6 @@ impl LayoutThread {
|
|||
self.stylist.set_quirks_mode(quirks_mode);
|
||||
}
|
||||
|
||||
fn try_get_layout_root<N: LayoutNode>(&self, _node: N) -> Option<FlowRef> {
|
||||
None
|
||||
}
|
||||
|
||||
/// The high-level routine that performs layout threads.
|
||||
fn handle_reflow<'a, 'b>(
|
||||
&mut self,
|
||||
|
@ -1139,12 +1073,6 @@ impl LayoutThread {
|
|||
}
|
||||
}
|
||||
|
||||
if viewport_size_changed {
|
||||
if let Some(mut flow) = self.try_get_layout_root(element.as_node()) {
|
||||
LayoutThread::reflow_all_nodes(FlowRef::deref_mut(&mut flow));
|
||||
}
|
||||
}
|
||||
|
||||
debug!(
|
||||
"Shadow roots in document {:?}",
|
||||
document.shadow_roots().len()
|
||||
|
@ -1248,9 +1176,6 @@ impl LayoutThread {
|
|||
0,
|
||||
0,
|
||||
);
|
||||
|
||||
// Retrieve the (possibly rebuilt) root flow.
|
||||
*self.root_flow.borrow_mut() = self.try_get_layout_root(element.as_node());
|
||||
}
|
||||
|
||||
for element in elements_with_snapshot {
|
||||
|
@ -1259,18 +1184,6 @@ impl LayoutThread {
|
|||
|
||||
layout_context = traversal.destroy();
|
||||
|
||||
if self.dump_style_tree {
|
||||
println!("{:?}", ShowSubtreeDataAndPrimaryValues(element.as_node()));
|
||||
}
|
||||
|
||||
if self.dump_rule_tree {
|
||||
layout_context
|
||||
.style_context
|
||||
.stylist
|
||||
.rule_tree()
|
||||
.dump_stdout(&guards);
|
||||
}
|
||||
|
||||
// GC the rule tree if some heuristics are met.
|
||||
unsafe {
|
||||
layout_context.style_context.stylist.rule_tree().maybe_gc();
|
||||
|
@ -1302,8 +1215,7 @@ impl LayoutThread {
|
|||
Au::from_f32_px(point_in_node.x),
|
||||
Au::from_f32_px(point_in_node.y),
|
||||
);
|
||||
rw_data.text_index_response =
|
||||
TextIndexResponse(rw_data.indexable_text.text_index(node, point_in_node));
|
||||
rw_data.text_index_response = process_text_index_request(node, point_in_node);
|
||||
},
|
||||
&QueryMsg::NodeGeometryQuery(node) => {
|
||||
rw_data.client_rect_response = process_node_geometry_request(node);
|
||||
|
@ -1354,8 +1266,7 @@ impl LayoutThread {
|
|||
},
|
||||
&QueryMsg::ElementInnerTextQuery(node) => {
|
||||
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||
rw_data.element_inner_text_response =
|
||||
process_element_inner_text_query(node, &rw_data.indexable_text);
|
||||
rw_data.element_inner_text_response = process_element_inner_text_query(node);
|
||||
},
|
||||
},
|
||||
ReflowGoal::Full | ReflowGoal::TickAnimations => {},
|
||||
|
@ -1471,16 +1382,6 @@ impl LayoutThread {
|
|||
self.generation.set(self.generation.get() + 1);
|
||||
}
|
||||
|
||||
fn reflow_all_nodes(flow: &mut dyn Flow) {
|
||||
debug!("reflowing all nodes!");
|
||||
flow.mut_base().restyle_damage.insert(
|
||||
ServoRestyleDamage::REPAINT |
|
||||
ServoRestyleDamage::STORE_OVERFLOW |
|
||||
ServoRestyleDamage::REFLOW |
|
||||
ServoRestyleDamage::REPOSITION,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns profiling information which is passed to the time profiler.
|
||||
fn profiler_metadata(&self) -> Option<TimerMetadata> {
|
||||
Some(TimerMetadata {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue