mirror of
https://github.com/servo/servo.git
synced 2025-07-07 23:43:39 +01:00
layout: Add a ReflowPhases
bitflags (#37696)
This is used to capture information about what layout phases are necessary for a given `ReflowGoal`. It's moved closer to where these decisions are made and it should be easier to understand what the values mean. They had gotten a bit out of sync with how queries and layout were implemented. Testing: This shouldn't change observable behavior and thus should be covered by existing WPT tests. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
03dbf9b6f7
commit
3cda9f2fb2
2 changed files with 65 additions and 60 deletions
|
@ -14,6 +14,7 @@ use std::sync::{Arc, LazyLock};
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use base::Epoch;
|
use base::Epoch;
|
||||||
use base::id::{PipelineId, WebViewId};
|
use base::id::{PipelineId, WebViewId};
|
||||||
|
use bitflags::bitflags;
|
||||||
use compositing_traits::CrossProcessCompositorApi;
|
use compositing_traits::CrossProcessCompositorApi;
|
||||||
use compositing_traits::display_list::ScrollType;
|
use compositing_traits::display_list::ScrollType;
|
||||||
use embedder_traits::{Theme, UntrustedNodeAddress, ViewportDetails};
|
use embedder_traits::{Theme, UntrustedNodeAddress, ViewportDetails};
|
||||||
|
@ -25,8 +26,8 @@ use fonts_traits::StylesheetWebFontLoadFinishedCallback;
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use layout_api::{
|
use layout_api::{
|
||||||
Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, OffsetParentResponse, ReflowGoal,
|
Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, OffsetParentResponse, QueryMsg,
|
||||||
ReflowRequest, ReflowResult, TrustedNodeAddress,
|
ReflowGoal, ReflowRequest, ReflowResult, TrustedNodeAddress,
|
||||||
};
|
};
|
||||||
use log::{debug, error, warn};
|
use log::{debug, error, warn};
|
||||||
use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf, MallocSizeOfOps};
|
use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf, MallocSizeOfOps};
|
||||||
|
@ -588,21 +589,31 @@ impl LayoutThread {
|
||||||
if reflow_request.restyle_reason.needs_restyle() {
|
if reflow_request.restyle_reason.needs_restyle() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// We always need to at least build a fragment tree.
|
||||||
|
if !self.fragment_tree.borrow().is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// If only the fragment tree is required, and it's up-to-date, layout is unnecessary.
|
// If we have a fragment tree and it's up-to-date and this reflow
|
||||||
if !reflow_request.reflow_goal.needs_display() && self.fragment_tree.borrow().is_some() {
|
// doesn't need more reflow results, we can skip the rest of layout.
|
||||||
|
let necessary_phases = ReflowPhases::necessary(&reflow_request.reflow_goal);
|
||||||
|
if necessary_phases.is_empty() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If only the stacking context tree is required, and it's up-to-date, layout is unnecessary.
|
// If only the stacking context tree is required, and it's up-to-date,
|
||||||
if !reflow_request.reflow_goal.needs_display_list() &&
|
// layout is unnecessary, otherwise a layout is necessary.
|
||||||
self.stacking_context_tree.borrow().is_some() &&
|
if necessary_phases == ReflowPhases::StackingContextTreeConstruction {
|
||||||
!self.need_new_stacking_context_tree.get()
|
return self.stacking_context_tree.borrow().is_some() &&
|
||||||
{
|
!self.need_new_stacking_context_tree.get();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, the only interesting thing is whether the current display list is up-to-date.
|
// Otherwise, the only interesting thing is whether the current display
|
||||||
|
// list is up-to-date.
|
||||||
|
assert_eq!(
|
||||||
|
necessary_phases,
|
||||||
|
ReflowPhases::StackingContextTreeConstruction | ReflowPhases::DisplayListConstruction
|
||||||
|
);
|
||||||
!self.need_new_display_list.get()
|
!self.need_new_display_list.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -910,8 +921,8 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_stacking_context_tree(&self, reflow_request: &ReflowRequest, damage: RestyleDamage) {
|
fn build_stacking_context_tree(&self, reflow_request: &ReflowRequest, damage: RestyleDamage) {
|
||||||
if !reflow_request.reflow_goal.needs_display_list() &&
|
if !ReflowPhases::necessary(&reflow_request.reflow_goal)
|
||||||
!reflow_request.reflow_goal.needs_display()
|
.contains(ReflowPhases::StackingContextTreeConstruction)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -973,7 +984,9 @@ impl LayoutThread {
|
||||||
damage: RestyleDamage,
|
damage: RestyleDamage,
|
||||||
layout_context: &mut LayoutContext<'_>,
|
layout_context: &mut LayoutContext<'_>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if !reflow_request.reflow_goal.needs_display() {
|
if !ReflowPhases::necessary(&reflow_request.reflow_goal)
|
||||||
|
.contains(ReflowPhases::DisplayListConstruction)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let Some(fragment_tree) = &*self.fragment_tree.borrow() else {
|
let Some(fragment_tree) = &*self.fragment_tree.borrow() else {
|
||||||
|
@ -1363,3 +1376,41 @@ impl Drop for SnapshotSetter<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub struct ReflowPhases: u8 {
|
||||||
|
const StackingContextTreeConstruction = 1 << 0;
|
||||||
|
const DisplayListConstruction = 1 << 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReflowPhases {
|
||||||
|
/// Return the necessary phases of layout for the given [`ReflowGoal`]. Note that all
|
||||||
|
/// [`ReflowGoals`] need the basic restyle + box tree layout + fragment tree layout,
|
||||||
|
/// so [`ReflowPhases::empty()`] implies that.
|
||||||
|
fn necessary(reflow_goal: &ReflowGoal) -> Self {
|
||||||
|
match reflow_goal {
|
||||||
|
ReflowGoal::UpdateTheRendering | ReflowGoal::UpdateScrollNode(..) => {
|
||||||
|
Self::StackingContextTreeConstruction | Self::DisplayListConstruction
|
||||||
|
},
|
||||||
|
ReflowGoal::LayoutQuery(query) => match query {
|
||||||
|
QueryMsg::NodesFromPointQuery => {
|
||||||
|
Self::StackingContextTreeConstruction | Self::DisplayListConstruction
|
||||||
|
},
|
||||||
|
QueryMsg::ResolvedStyleQuery | QueryMsg::ScrollingAreaOrOffsetQuery => {
|
||||||
|
Self::StackingContextTreeConstruction
|
||||||
|
},
|
||||||
|
QueryMsg::ClientRectQuery |
|
||||||
|
QueryMsg::ContentBox |
|
||||||
|
QueryMsg::ContentBoxes |
|
||||||
|
QueryMsg::ElementInnerOuterTextQuery |
|
||||||
|
QueryMsg::InnerWindowDimensionsQuery |
|
||||||
|
QueryMsg::OffsetParentQuery |
|
||||||
|
QueryMsg::ResolvedFontStyleQuery |
|
||||||
|
QueryMsg::TextIndexQuery |
|
||||||
|
QueryMsg::StyleQuery => Self::empty(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -346,52 +346,6 @@ pub enum ReflowGoal {
|
||||||
UpdateScrollNode(ExternalScrollId, LayoutVector2D),
|
UpdateScrollNode(ExternalScrollId, LayoutVector2D),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReflowGoal {
|
|
||||||
/// Returns true if the given ReflowQuery needs a full, up-to-date display list to
|
|
||||||
/// be present or false if it only needs stacking-relative positions.
|
|
||||||
pub fn needs_display_list(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
ReflowGoal::UpdateTheRendering | ReflowGoal::UpdateScrollNode(..) => true,
|
|
||||||
ReflowGoal::LayoutQuery(ref querymsg) => match *querymsg {
|
|
||||||
QueryMsg::ElementInnerOuterTextQuery |
|
|
||||||
QueryMsg::InnerWindowDimensionsQuery |
|
|
||||||
QueryMsg::NodesFromPointQuery |
|
|
||||||
QueryMsg::ResolvedStyleQuery |
|
|
||||||
QueryMsg::ScrollingAreaOrOffsetQuery |
|
|
||||||
QueryMsg::TextIndexQuery => true,
|
|
||||||
QueryMsg::ClientRectQuery |
|
|
||||||
QueryMsg::ContentBox |
|
|
||||||
QueryMsg::ContentBoxes |
|
|
||||||
QueryMsg::OffsetParentQuery |
|
|
||||||
QueryMsg::ResolvedFontStyleQuery |
|
|
||||||
QueryMsg::StyleQuery => false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the given ReflowQuery needs its display list send to WebRender or
|
|
||||||
/// false if a layout_thread display list is sufficient.
|
|
||||||
pub fn needs_display(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
ReflowGoal::UpdateTheRendering | ReflowGoal::UpdateScrollNode(..) => true,
|
|
||||||
ReflowGoal::LayoutQuery(ref querymsg) => match *querymsg {
|
|
||||||
QueryMsg::NodesFromPointQuery |
|
|
||||||
QueryMsg::TextIndexQuery |
|
|
||||||
QueryMsg::ElementInnerOuterTextQuery => true,
|
|
||||||
QueryMsg::ContentBox |
|
|
||||||
QueryMsg::ContentBoxes |
|
|
||||||
QueryMsg::ClientRectQuery |
|
|
||||||
QueryMsg::ScrollingAreaOrOffsetQuery |
|
|
||||||
QueryMsg::ResolvedStyleQuery |
|
|
||||||
QueryMsg::ResolvedFontStyleQuery |
|
|
||||||
QueryMsg::OffsetParentQuery |
|
|
||||||
QueryMsg::InnerWindowDimensionsQuery |
|
|
||||||
QueryMsg::StyleQuery => false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, MallocSizeOf)]
|
#[derive(Clone, Debug, MallocSizeOf)]
|
||||||
pub struct IFrameSize {
|
pub struct IFrameSize {
|
||||||
pub browsing_context_id: BrowsingContextId,
|
pub browsing_context_id: BrowsingContextId,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue