layout: Shape text only once (#31146)

Shape text during InlineFormattingContext construction rather than doing
it twice during fragment tree construction. This is a step on the way
toward proper font fallback.

This also moves all `TextRun` related code into `text_run.rs` to try to
trim down the size of `inline.rs`.
<!-- Please describe your changes on the following line: -->


---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by
`[X]` when the step is complete, and replace `___` with appropriate
data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes do not require tests because this should only have
performance impacts.

<!-- Also, please make sure that "Allow edits from maintainers" checkbox
is checked, so that we can help you if you get stuck somewhere along the
way.-->

<!-- Pull requests that do not address these steps are welcome, but they
will require additional verification as part of the review process. -->
This commit is contained in:
Martin Robinson 2024-01-25 15:33:47 +01:00 committed by GitHub
parent bb04c97f15
commit 094f7845b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 289 additions and 268 deletions

View file

@ -19,7 +19,8 @@ use crate::context::LayoutContext;
use crate::dom::{BoxSlot, LayoutBox, NodeExt};
use crate::dom_traversal::{Contents, NodeAndStyleInfo, NonReplacedContents, TraversalHandler};
use crate::flow::float::FloatBox;
use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, TextRun};
use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox};
use crate::flow::text_run::TextRun;
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::positioned::AbsolutelyPositionedBox;
@ -56,6 +57,7 @@ impl BlockFormattingContext {
pub fn construct_for_text_runs<'dom>(
runs: impl Iterator<Item = TextRun>,
layout_context: &LayoutContext,
text_decoration_line: TextDecorationLine,
) -> Self {
// FIXME: do white space collapsing
@ -70,10 +72,8 @@ impl BlockFormattingContext {
contains_floats: false,
ends_with_whitespace: false,
};
let contents = BlockContainer::InlineFormattingContext(ifc);
Self {
contents,
contents: BlockContainer::construct_inline_formatting_context(layout_context, ifc),
contains_floats: false,
}
}
@ -216,6 +216,16 @@ impl BlockContainer {
contents.traverse(context, info, &mut builder);
builder.finish()
}
pub(super) fn construct_inline_formatting_context(
layout_context: &LayoutContext,
mut ifc: InlineFormattingContext,
) -> Self {
// TODO(mrobinson): Perhaps it would be better to iteratively break and shape the contents
// of the IFC, and not wait until it is completely built.
ifc.break_and_shape_text(layout_context);
BlockContainer::InlineFormattingContext(ifc)
}
}
impl<'dom, 'style, Node> BlockContainerBuilder<'dom, 'style, Node>
@ -251,7 +261,8 @@ where
if !self.ongoing_inline_formatting_context.is_empty() {
if self.block_level_boxes.is_empty() {
return BlockContainer::InlineFormattingContext(
return BlockContainer::construct_inline_formatting_context(
self.context,
self.ongoing_inline_formatting_context,
);
}
@ -427,6 +438,7 @@ where
parent_style: Arc::clone(&info.style),
text: output,
has_uncollapsible_content,
shaped_text: None,
})));
}
}
@ -811,15 +823,15 @@ where
/* ends_with_whitespace */ false,
);
std::mem::swap(&mut self.ongoing_inline_formatting_context, &mut ifc);
let kind = BlockLevelCreator::SameFormattingContextBlock(
IntermediateBlockContainer::InlineFormattingContext(ifc),
);
let info = self.info.new_replacing_style(anonymous_style.clone());
self.block_level_boxes.push(BlockLevelJob {
info,
// FIXME(nox): We should be storing this somewhere.
box_slot: BoxSlot::dummy(),
kind,
kind: BlockLevelCreator::SameFormattingContextBlock(
IntermediateBlockContainer::InlineFormattingContext(ifc),
),
});
}
@ -919,7 +931,7 @@ impl IntermediateBlockContainer {
is_list_item,
),
IntermediateBlockContainer::InlineFormattingContext(ifc) => {
BlockContainer::InlineFormattingContext(ifc)
BlockContainer::construct_inline_formatting_context(context, ifc)
},
}
}