mirror of
https://github.com/servo/servo.git
synced 2025-10-02 09:39:14 +01:00
Motivation: The font cache currently has to store a cache of Keys which need to be given by the webrender instance. Having a cache for every WebViewId in the future when we have every webview have the different webrender::DocumentId might be too wasteful to store this key cache per DocumentId. This proposes to include in the WebViewId another id, the RenderingGroupId. This id can be easily changed to be equivalent to the DocumentId when we support multiple DocumentIds for a unique Webrender instance. Additionally this will keep it easier to integrate the currently out of tree patches for multiple rendering contexts with different webrenders. Change: We introduce the RenderingGroupId in the WebViewId and allow a method to extract it. The font key cache uses this cache and forwards it to the Compositor when requesting new changes. The compositor currently ignores this id. Additionally, the WebView can return the RenderingGroupId. The WebViewId also has an appropiate constructor for specifying a RenderingGroupId. Because there currently will be only one RenderingGroupId the performance will be minimal. Signed-off-by: Narfinger <Narfinger@users.noreply.github.com> Testing: This should be covered by WPT tests and normal browsing behavior works fine. --------- Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
252 lines
8.8 KiB
Rust
252 lines
8.8 KiB
Rust
/* 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/. */
|
|
|
|
//! Layout construction code that is shared between modern layout modes (Flexbox and CSS Grid)
|
|
|
|
use std::borrow::Cow;
|
|
use std::sync::LazyLock;
|
|
|
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
|
use style::selector_parser::PseudoElement;
|
|
|
|
use crate::PropagatedBoxTreeData;
|
|
use crate::context::LayoutContext;
|
|
use crate::dom::{BoxSlot, LayoutBox};
|
|
use crate::dom_traversal::{Contents, NodeAndStyleInfo, TraversalHandler};
|
|
use crate::flow::inline::construct::InlineFormattingContextBuilder;
|
|
use crate::flow::{BlockContainer, BlockFormattingContext};
|
|
use crate::formatting_contexts::{
|
|
IndependentFormattingContext, IndependentFormattingContextContents,
|
|
};
|
|
use crate::layout_box_base::LayoutBoxBase;
|
|
use crate::style_ext::{ComputedValuesExt, DisplayGeneratingBox};
|
|
|
|
/// A builder used for both flex and grid containers.
|
|
pub(crate) struct ModernContainerBuilder<'a, 'dom> {
|
|
context: &'a LayoutContext<'a>,
|
|
info: &'a NodeAndStyleInfo<'dom>,
|
|
propagated_data: PropagatedBoxTreeData,
|
|
contiguous_text_runs: Vec<ModernContainerTextRun<'dom>>,
|
|
/// To be run in parallel with rayon in `finish`
|
|
jobs: Vec<ModernContainerJob<'dom>>,
|
|
has_text_runs: bool,
|
|
}
|
|
|
|
enum ModernContainerJob<'dom> {
|
|
ElementOrPseudoElement {
|
|
info: NodeAndStyleInfo<'dom>,
|
|
display: DisplayGeneratingBox,
|
|
contents: Contents,
|
|
box_slot: BoxSlot<'dom>,
|
|
},
|
|
TextRuns(Vec<ModernContainerTextRun<'dom>>),
|
|
}
|
|
|
|
impl<'dom> ModernContainerJob<'dom> {
|
|
fn finish(
|
|
self,
|
|
builder: &ModernContainerBuilder,
|
|
anonymous_info: &LazyLock<NodeAndStyleInfo<'dom>, impl FnOnce() -> NodeAndStyleInfo<'dom>>,
|
|
) -> Option<ModernItem<'dom>> {
|
|
match self {
|
|
ModernContainerJob::TextRuns(runs) => {
|
|
let mut inline_formatting_context_builder =
|
|
InlineFormattingContextBuilder::new(builder.info);
|
|
for flex_text_run in runs.into_iter() {
|
|
inline_formatting_context_builder
|
|
.push_text(flex_text_run.text, &flex_text_run.info);
|
|
}
|
|
|
|
let inline_formatting_context = inline_formatting_context_builder.finish(
|
|
builder.context,
|
|
true, /* has_first_formatted_line */
|
|
false, /* is_single_line_text_box */
|
|
builder.info.style.to_bidi_level(),
|
|
builder.context.rendering_group_id,
|
|
)?;
|
|
|
|
let block_formatting_context = BlockFormattingContext::from_block_container(
|
|
BlockContainer::InlineFormattingContext(inline_formatting_context),
|
|
);
|
|
let info: &NodeAndStyleInfo = anonymous_info;
|
|
let formatting_context = IndependentFormattingContext::new(
|
|
LayoutBoxBase::new(info.into(), info.style.clone()),
|
|
IndependentFormattingContextContents::Flow(block_formatting_context),
|
|
);
|
|
|
|
Some(ModernItem {
|
|
kind: ModernItemKind::InFlow(formatting_context),
|
|
order: 0,
|
|
box_slot: None,
|
|
})
|
|
},
|
|
ModernContainerJob::ElementOrPseudoElement {
|
|
info,
|
|
display,
|
|
contents,
|
|
box_slot,
|
|
} => {
|
|
let is_abspos = info.style.get_box().position.is_absolutely_positioned();
|
|
let order = if is_abspos {
|
|
0
|
|
} else {
|
|
info.style.clone_order()
|
|
};
|
|
|
|
if let Some(layout_box) = box_slot
|
|
.take_layout_box_if_undamaged(info.damage)
|
|
.and_then(|layout_box| match &layout_box {
|
|
LayoutBox::FlexLevel(_) | LayoutBox::TaffyItemBox(_) => Some(layout_box),
|
|
_ => None,
|
|
})
|
|
{
|
|
return Some(ModernItem {
|
|
kind: ModernItemKind::ReusedBox(layout_box),
|
|
order,
|
|
box_slot: Some(box_slot),
|
|
});
|
|
}
|
|
|
|
// Text decorations are not propagated to any out-of-flow descendants. In addition,
|
|
// absolutes don't affect the size of ancestors so it is fine to allow descendent
|
|
// tables to resolve percentage columns.
|
|
let propagated_data = match is_abspos {
|
|
false => builder.propagated_data,
|
|
true => PropagatedBoxTreeData::default(),
|
|
};
|
|
|
|
let formatting_context = IndependentFormattingContext::construct(
|
|
builder.context,
|
|
&info,
|
|
display.display_inside(),
|
|
contents,
|
|
propagated_data,
|
|
);
|
|
|
|
let kind = if is_abspos {
|
|
ModernItemKind::OutOfFlow(formatting_context)
|
|
} else {
|
|
ModernItemKind::InFlow(formatting_context)
|
|
};
|
|
Some(ModernItem {
|
|
kind,
|
|
order,
|
|
box_slot: Some(box_slot),
|
|
})
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
struct ModernContainerTextRun<'dom> {
|
|
info: NodeAndStyleInfo<'dom>,
|
|
text: Cow<'dom, str>,
|
|
}
|
|
|
|
impl ModernContainerTextRun<'_> {
|
|
/// <https://drafts.csswg.org/css-text/#white-space>
|
|
fn is_only_document_white_space(&self) -> bool {
|
|
// FIXME: is this the right definition? See
|
|
// https://github.com/w3c/csswg-drafts/issues/5146
|
|
// https://github.com/w3c/csswg-drafts/issues/5147
|
|
self.text
|
|
.bytes()
|
|
.all(|byte| matches!(byte, b' ' | b'\n' | b'\t'))
|
|
}
|
|
}
|
|
|
|
pub(crate) enum ModernItemKind {
|
|
InFlow(IndependentFormattingContext),
|
|
OutOfFlow(IndependentFormattingContext),
|
|
ReusedBox(LayoutBox),
|
|
}
|
|
|
|
pub(crate) struct ModernItem<'dom> {
|
|
pub kind: ModernItemKind,
|
|
pub order: i32,
|
|
pub box_slot: Option<BoxSlot<'dom>>,
|
|
}
|
|
|
|
impl<'dom> TraversalHandler<'dom> for ModernContainerBuilder<'_, 'dom> {
|
|
fn handle_text(&mut self, info: &NodeAndStyleInfo<'dom>, text: Cow<'dom, str>) {
|
|
self.contiguous_text_runs.push(ModernContainerTextRun {
|
|
info: info.clone(),
|
|
text,
|
|
})
|
|
}
|
|
|
|
/// Or pseudo-element
|
|
fn handle_element(
|
|
&mut self,
|
|
info: &NodeAndStyleInfo<'dom>,
|
|
display: DisplayGeneratingBox,
|
|
contents: Contents,
|
|
box_slot: BoxSlot<'dom>,
|
|
) {
|
|
self.wrap_any_text_in_anonymous_block_container();
|
|
|
|
self.jobs.push(ModernContainerJob::ElementOrPseudoElement {
|
|
info: info.clone(),
|
|
display,
|
|
contents,
|
|
box_slot,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<'a, 'dom> ModernContainerBuilder<'a, 'dom> {
|
|
pub fn new(
|
|
context: &'a LayoutContext<'a>,
|
|
info: &'a NodeAndStyleInfo<'dom>,
|
|
propagated_data: PropagatedBoxTreeData,
|
|
) -> Self {
|
|
ModernContainerBuilder {
|
|
context,
|
|
info,
|
|
propagated_data: propagated_data.disallowing_percentage_table_columns(),
|
|
contiguous_text_runs: Vec::new(),
|
|
jobs: Vec::new(),
|
|
has_text_runs: false,
|
|
}
|
|
}
|
|
|
|
fn wrap_any_text_in_anonymous_block_container(&mut self) {
|
|
let runs = std::mem::take(&mut self.contiguous_text_runs);
|
|
if runs
|
|
.iter()
|
|
.all(ModernContainerTextRun::is_only_document_white_space)
|
|
{
|
|
// There is no text run, or they all only contain document white space characters
|
|
} else {
|
|
self.jobs.push(ModernContainerJob::TextRuns(runs));
|
|
self.has_text_runs = true;
|
|
}
|
|
}
|
|
|
|
pub(crate) fn finish(mut self) -> Vec<ModernItem<'dom>> {
|
|
self.wrap_any_text_in_anonymous_block_container();
|
|
|
|
let anonymous_info = LazyLock::new(|| {
|
|
self.info
|
|
.with_pseudo_element(self.context, PseudoElement::ServoAnonymousBox)
|
|
.expect("Should always be able to construct info for anonymous boxes.")
|
|
});
|
|
|
|
let jobs = std::mem::take(&mut self.jobs);
|
|
let mut children: Vec<_> = if self.context.use_rayon {
|
|
jobs.into_par_iter()
|
|
.filter_map(|job| job.finish(&self, &anonymous_info))
|
|
.collect()
|
|
} else {
|
|
jobs.into_iter()
|
|
.filter_map(|job| job.finish(&self, &anonymous_info))
|
|
.collect()
|
|
};
|
|
|
|
// https://drafts.csswg.org/css-flexbox/#order-modified-document-order
|
|
children.sort_by_key(|child| child.order);
|
|
|
|
children
|
|
}
|
|
}
|