Auto merge of #25033 - servo:intrinsic, r=nox

Add support for inline-block and for computing min/max-content
This commit is contained in:
bors-servo 2019-12-04 16:23:33 -05:00 committed by GitHub
commit e70397d90a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 823 additions and 272 deletions

View file

@ -2,6 +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/. */
use crate::context::LayoutContext;
use crate::dom_traversal::{BoxSlot, Contents, NodeExt, NonReplacedContents, TraversalHandler};
use crate::element_data::LayoutBox;
use crate::flow::float::FloatBox;
@ -9,26 +10,31 @@ use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, Te
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::positioned::AbsolutelyPositionedBox;
use crate::style_ext::{DisplayGeneratingBox, DisplayInside, DisplayOutside};
use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest};
use crate::style_ext::{ComputedValuesExt, DisplayGeneratingBox, DisplayInside, DisplayOutside};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use rayon_croissant::ParallelIteratorExt;
use servo_arc::Arc;
use std::convert::TryInto;
use style::context::SharedStyleContext;
use std::convert::{TryFrom, TryInto};
use style::properties::ComputedValues;
use style::selector_parser::PseudoElement;
impl BlockFormattingContext {
pub fn construct<'dom>(
context: &SharedStyleContext<'_>,
context: &LayoutContext,
style: &Arc<ComputedValues>,
contents: NonReplacedContents<impl NodeExt<'dom>>,
) -> Self {
let (contents, contains_floats) = BlockContainer::construct(context, style, contents);
Self {
content_sizes: ContentSizesRequest,
) -> (Self, BoxContentSizes) {
let (contents, contains_floats, inline_content_sizes) =
BlockContainer::construct(context, style, contents, content_sizes);
// FIXME: add contribution to `inline_content_sizes` of floats in this formatting context
// https://dbaron.org/css/intrinsic/#intrinsic
let bfc = Self {
contents,
contains_floats: contains_floats == ContainsFloats::Yes,
}
};
(bfc, inline_content_sizes)
}
}
@ -71,7 +77,7 @@ enum IntermediateBlockContainer<Node> {
/// This builder starts from the first child of a given DOM node
/// and does a preorder traversal of all of its inclusive siblings.
struct BlockContainerBuilder<'dom, 'style, Node> {
context: &'style SharedStyleContext<'style>,
context: &'style LayoutContext<'style>,
block_container_style: &'style Arc<ComputedValues>,
@ -123,19 +129,20 @@ struct BlockContainerBuilder<'dom, 'style, Node> {
}
impl BlockContainer {
pub fn construct<'dom, 'style>(
context: &SharedStyleContext<'style>,
pub fn construct<'dom>(
context: &LayoutContext,
block_container_style: &Arc<ComputedValues>,
contents: NonReplacedContents<impl NodeExt<'dom>>,
) -> (BlockContainer, ContainsFloats) {
content_sizes: ContentSizesRequest,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
let mut builder = BlockContainerBuilder {
context,
block_container_style,
block_level_boxes: Default::default(),
ongoing_inline_formatting_context: Default::default(),
ongoing_inline_boxes_stack: Default::default(),
anonymous_style: Default::default(),
contains_floats: Default::default(),
block_level_boxes: Vec::new(),
ongoing_inline_formatting_context: InlineFormattingContext::default(),
ongoing_inline_boxes_stack: Vec::new(),
anonymous_style: None,
contains_floats: ContainsFloats::No,
};
contents.traverse(block_container_style, context, &mut builder);
@ -148,32 +155,65 @@ impl BlockContainer {
.is_empty()
{
if builder.block_level_boxes.is_empty() {
let content_sizes = content_sizes.compute(|| {
builder
.ongoing_inline_formatting_context
.inline_content_sizes(context)
});
let container = BlockContainer::InlineFormattingContext(
builder.ongoing_inline_formatting_context,
);
return (container, builder.contains_floats);
return (container, builder.contains_floats, content_sizes);
}
builder.end_ongoing_inline_formatting_context();
}
let mut contains_floats = builder.contains_floats;
let container = BlockContainer::BlockLevelBoxes(
builder
.block_level_boxes
.into_par_iter()
.mapfold_reduce_into(
&mut contains_floats,
|contains_floats, (intermediate, box_slot): (IntermediateBlockLevelBox<_>, BoxSlot<'_>)| {
let (block_level_box, box_contains_floats) = intermediate.finish(context);
*contains_floats |= box_contains_floats;
box_slot.set(LayoutBox::BlockLevel(block_level_box.clone()));
block_level_box
},
|left, right| *left |= right,
)
.collect(),
type Intermediate<Node> = IntermediateBlockLevelBox<Node>;
struct Target {
contains_floats: ContainsFloats,
outer_content_sizes_of_children: ContentSizes,
}
impl Default for Target {
fn default() -> Self {
Self {
contains_floats: ContainsFloats::No,
outer_content_sizes_of_children: ContentSizes::zero(),
}
}
}
let mut target = Target {
contains_floats: builder.contains_floats,
outer_content_sizes_of_children: ContentSizes::zero(),
};
let iter = builder.block_level_boxes.into_par_iter();
let iter = iter.mapfold_reduce_into(
&mut target,
|target, (intermediate, box_slot): (Intermediate<_>, BoxSlot<'_>)| {
let (block_level_box, box_contains_floats) = intermediate.finish(
context,
content_sizes
.if_requests_inline(|| &mut target.outer_content_sizes_of_children),
);
target.contains_floats |= box_contains_floats;
box_slot.set(LayoutBox::BlockLevel(block_level_box.clone()));
block_level_box
},
|left, right| {
left.contains_floats |= right.contains_floats;
if content_sizes.requests_inline() {
left.outer_content_sizes_of_children
.max_assign(&right.outer_content_sizes_of_children)
}
},
);
(container, contains_floats)
let container = BlockContainer::BlockLevelBoxes(iter.collect());
let Target {
contains_floats,
outer_content_sizes_of_children,
} = target;
let content_sizes = content_sizes.compute(|| outer_content_sizes_of_children);
(container, contains_floats, content_sizes)
}
}
@ -324,38 +364,38 @@ where
display_inside: DisplayInside,
contents: Contents<Node>,
) -> Arc<InlineLevelBox> {
let box_ = match contents.try_into() {
Err(replaced) => Arc::new(InlineLevelBox::Atomic(
let box_ = if display_inside == DisplayInside::Flow && !contents.is_replaced() {
// We found un inline box.
// Whatever happened before, all we need to do before recurring
// is to remember this ongoing inline level box.
self.ongoing_inline_boxes_stack.push(InlineBox {
style: style.clone(),
first_fragment: true,
last_fragment: false,
children: vec![],
});
// `unwrap` doesnt panic here because `is_replaced` returned `false`.
NonReplacedContents::try_from(contents)
.unwrap()
.traverse(&style, self.context, self);
let mut inline_box = self
.ongoing_inline_boxes_stack
.pop()
.expect("no ongoing inline level box found");
inline_box.last_fragment = true;
Arc::new(InlineLevelBox::InlineBox(inline_box))
} else {
Arc::new(InlineLevelBox::Atomic(
IndependentFormattingContext::construct(
self.context,
style.clone(),
display_inside,
<Contents<Node>>::Replaced(replaced),
contents,
ContentSizesRequest::inline_if(style.inline_size_is_auto()),
),
)),
Ok(non_replaced) => match display_inside {
DisplayInside::Flow |
// TODO: Properly implement display: inline-block.
DisplayInside::FlowRoot => {
// Whatever happened before, we just found an inline level element, so
// all we need to do is to remember this ongoing inline level box.
self.ongoing_inline_boxes_stack.push(InlineBox {
style: style.clone(),
first_fragment: true,
last_fragment: false,
children: vec![],
});
NonReplacedContents::traverse(non_replaced, &style, self.context, self);
let mut inline_box = self
.ongoing_inline_boxes_stack
.pop()
.expect("no ongoing inline level box found");
inline_box.last_fragment = true;
Arc::new(InlineLevelBox::InlineBox(inline_box))
},
},
))
};
self.current_inline_level_boxes().push(box_.clone());
box_
@ -451,14 +491,7 @@ where
self.block_level_boxes.push((box_, box_slot));
} else {
let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(
AbsolutelyPositionedBox {
contents: IndependentFormattingContext::construct(
self.context,
style,
display_inside,
contents,
),
},
AbsolutelyPositionedBox::construct(self.context, style, display_inside, contents),
));
self.current_inline_level_boxes().push(box_.clone());
box_slot.set(LayoutBox::InlineLevel(box_))
@ -482,14 +515,12 @@ where
};
self.block_level_boxes.push((box_, box_slot));
} else {
let box_ = Arc::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox {
contents: IndependentFormattingContext::construct(
self.context,
style,
display_inside,
contents,
),
}));
let box_ = Arc::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox::construct(
self.context,
style,
display_inside,
contents,
)));
self.current_inline_level_boxes().push(box_.clone());
box_slot.set(LayoutBox::InlineLevel(box_))
}
@ -509,9 +540,10 @@ where
let block_container_style = self.block_container_style;
let anonymous_style = self.anonymous_style.get_or_insert_with(|| {
context
.shared_context()
.stylist
.style_for_anonymous::<Node::ConcreteElement>(
&context.guards,
&context.shared_context().guards,
&PseudoElement::ServoText,
&block_container_style,
)
@ -546,13 +578,24 @@ impl<'dom, Node> IntermediateBlockLevelBox<Node>
where
Node: NodeExt<'dom>,
{
fn finish<'style>(
fn finish(
self,
context: &SharedStyleContext<'style>,
context: &LayoutContext,
max_assign_in_flow_outer_content_sizes_to: Option<&mut ContentSizes>,
) -> (Arc<BlockLevelBox>, ContainsFloats) {
match self {
IntermediateBlockLevelBox::SameFormattingContextBlock { style, contents } => {
let (contents, contains_floats) = contents.finish(context, &style);
let (contents, contains_floats, box_content_sizes) = contents.finish(
context,
&style,
ContentSizesRequest::inline_if(
max_assign_in_flow_outer_content_sizes_to.is_some() &&
style.inline_size_is_auto(),
),
);
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
to.max_assign(&box_content_sizes.outer_inline(&style))
}
let block_level_box =
Arc::new(BlockLevelBox::SameFormattingContextBlock { contents, style });
(block_level_box, contains_floats)
@ -562,12 +605,20 @@ where
display_inside,
contents,
} => {
let content_sizes = ContentSizesRequest::inline_if(
max_assign_in_flow_outer_content_sizes_to.is_some() &&
style.inline_size_is_auto(),
);
let contents = IndependentFormattingContext::construct(
context,
style,
display_inside,
contents,
content_sizes,
);
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
to.max_assign(&contents.content_sizes.outer_inline(&contents.style))
}
(
Arc::new(BlockLevelBox::Independent(contents)),
ContainsFloats::No,
@ -579,14 +630,7 @@ where
contents,
} => {
let block_level_box = Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
AbsolutelyPositionedBox {
contents: IndependentFormattingContext::construct(
context,
style,
display_inside,
contents,
),
},
AbsolutelyPositionedBox::construct(context, style, display_inside, contents),
));
(block_level_box, ContainsFloats::No)
},
@ -595,14 +639,9 @@ where
display_inside,
contents,
} => {
let contents = IndependentFormattingContext::construct(
context,
style,
display_inside,
contents,
);
let block_level_box =
Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox { contents }));
let block_level_box = Arc::new(BlockLevelBox::OutOfFlowFloatBox(
FloatBox::construct(context, style, display_inside, contents),
));
(block_level_box, ContainsFloats::Yes)
},
}
@ -613,22 +652,25 @@ impl<'dom, Node> IntermediateBlockContainer<Node>
where
Node: NodeExt<'dom>,
{
fn finish<'style>(
fn finish(
self,
context: &SharedStyleContext<'style>,
context: &LayoutContext,
style: &Arc<ComputedValues>,
) -> (BlockContainer, ContainsFloats) {
content_sizes: ContentSizesRequest,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
match self {
IntermediateBlockContainer::Deferred { contents } => {
BlockContainer::construct(context, style, contents)
BlockContainer::construct(context, style, contents, content_sizes)
},
IntermediateBlockContainer::InlineFormattingContext(ifc) => {
let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context));
// If that inline formatting context contained any float, those
// were already taken into account during the first phase of
// box construction.
(
BlockContainer::InlineFormattingContext(ifc),
ContainsFloats::No,
content_sizes,
)
},
}
@ -648,9 +690,3 @@ impl std::ops::BitOrAssign for ContainsFloats {
}
}
}
impl Default for ContainsFloats {
fn default() -> Self {
ContainsFloats::No
}
}

View file

@ -2,7 +2,13 @@
* 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::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeExt};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{ComputedValuesExt, DisplayInside};
use servo_arc::Arc;
use style::properties::ComputedValues;
#[derive(Debug)]
pub(crate) struct FloatBox {
@ -19,3 +25,23 @@ impl FloatContext {
FloatContext {}
}
}
impl FloatBox {
pub fn construct<'dom>(
context: &LayoutContext,
style: Arc<ComputedValues>,
display_inside: DisplayInside,
contents: Contents<impl NodeExt<'dom>>,
) -> Self {
let content_sizes = ContentSizesRequest::inline_if(style.inline_size_is_auto());
Self {
contents: IndependentFormattingContext::construct(
context,
style,
display_inside,
contents,
content_sizes,
),
}
}
}

View file

@ -10,12 +10,16 @@ use crate::fragments::CollapsedBlockMargins;
use crate::fragments::{AnonymousFragment, BoxFragment, Fragment, TextFragment};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment};
use crate::sizing::ContentSizes;
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
use crate::{relative_adjustement, ContainingBlock};
use app_units::Au;
use gfx::text::text_run::GlyphRun;
use servo_arc::Arc;
use style::properties::ComputedValues;
use style::values::computed::Length;
use style::values::computed::{Length, LengthPercentage, Percentage};
use style::Zero;
use webrender_api::FontInstanceKey;
#[derive(Debug, Default)]
pub(crate) struct InlineFormattingContext {
@ -63,8 +67,9 @@ struct PartialInlineBoxFragment<'box_tree> {
parent_nesting_level: InlineNestingLevelState<'box_tree>,
}
struct InlineFormattingContextState<'box_tree, 'cb> {
containing_block: &'cb ContainingBlock,
struct InlineFormattingContextState<'box_tree, 'a> {
absolutely_positioned_fragments: &'a mut Vec<AbsolutelyPositionedFragment<'box_tree>>,
containing_block: &'a ContainingBlock,
line_boxes: LinesBoxes,
inline_position: Length,
partial_inline_boxes_stack: Vec<PartialInlineBoxFragment<'box_tree>>,
@ -77,6 +82,114 @@ struct LinesBoxes {
}
impl InlineFormattingContext {
// This works on an already-constructed `InlineFormattingContext`,
// Which would have to change if/when
// `BlockContainer::construct` parallelize their construction.
pub(super) fn inline_content_sizes(&self, layout_context: &LayoutContext) -> ContentSizes {
struct Computation {
paragraph: ContentSizes,
current_line: ContentSizes,
current_line_percentages: Percentage,
}
impl Computation {
fn traverse(
&mut self,
layout_context: &LayoutContext,
inline_level_boxes: &[Arc<InlineLevelBox>],
) {
for inline_level_box in inline_level_boxes {
match &**inline_level_box {
InlineLevelBox::InlineBox(inline_box) => {
let padding = inline_box.style.padding();
let border = inline_box.style.border_width();
let margin = inline_box.style.margin();
macro_rules! add {
($condition: ident, $side: ident) => {
if inline_box.$condition {
self.add_lengthpercentage(padding.$side);
self.add_length(border.$side);
if let Some(lp) = margin.$side.non_auto() {
self.add_lengthpercentage(lp)
}
}
};
}
add!(first_fragment, inline_start);
self.traverse(layout_context, &inline_box.children);
add!(last_fragment, inline_end);
},
InlineLevelBox::TextRun(text_run) => {
let BreakAndShapeResult {
runs,
break_at_start,
..
} = text_run.break_and_shape(layout_context);
if break_at_start {
self.line_break_opportunity()
}
for run in &runs {
let advance = Length::from(run.glyph_store.total_advance());
if run.glyph_store.is_whitespace() {
self.line_break_opportunity()
} else {
self.current_line.min_content += advance
}
self.current_line.max_content += advance
}
},
InlineLevelBox::Atomic(atomic) => {
let (outer, pc) = atomic
.content_sizes
.outer_inline_and_percentages(&atomic.style);
self.current_line.min_content += outer.min_content;
self.current_line.max_content += outer.max_content;
self.current_line_percentages += pc;
},
InlineLevelBox::OutOfFlowFloatBox(_) |
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(_) => {},
}
}
}
fn add_lengthpercentage(&mut self, lp: LengthPercentage) {
self.add_length(lp.length_component());
self.current_line_percentages += lp.percentage_component();
}
fn add_length(&mut self, l: Length) {
self.current_line.min_content += l;
self.current_line.max_content += l;
}
fn line_break_opportunity(&mut self) {
self.paragraph
.min_content
.max_assign(take(&mut self.current_line.min_content));
}
fn forced_line_break(&mut self) {
self.line_break_opportunity();
self.current_line
.adjust_for_pbm_percentages(take(&mut self.current_line_percentages));
self.paragraph
.max_content
.max_assign(take(&mut self.current_line.max_content));
}
}
fn take<T: Zero>(x: &mut T) -> T {
std::mem::replace(x, T::zero())
}
let mut computation = Computation {
paragraph: ContentSizes::zero(),
current_line: ContentSizes::zero(),
current_line_percentages: Percentage::zero(),
};
computation.traverse(layout_context, &self.inline_level_boxes);
computation.forced_line_break();
computation.paragraph
}
pub(super) fn layout<'a>(
&'a self,
layout_context: &LayoutContext,
@ -85,6 +198,7 @@ impl InlineFormattingContext {
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
) -> FlowLayout {
let mut ifc = InlineFormattingContextState {
absolutely_positioned_fragments,
containing_block,
partial_inline_boxes_stack: Vec::new(),
line_boxes: LinesBoxes {
@ -107,10 +221,7 @@ impl InlineFormattingContext {
ifc.partial_inline_boxes_stack.push(partial)
},
InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc),
InlineLevelBox::Atomic(_independent) => {
// TODO
continue;
},
InlineLevelBox::Atomic(a) => layout_atomic(layout_context, &mut ifc, a),
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
let initial_start_corner =
match Display::from(box_.contents.style.get_box().original_display) {
@ -131,12 +242,11 @@ impl InlineFormattingContext {
panic!("display:none does not generate an abspos box")
},
};
absolutely_positioned_fragments
ifc.absolutely_positioned_fragments
.push(box_.layout(initial_start_corner, tree_rank));
},
InlineLevelBox::OutOfFlowFloatBox(_box_) => {
// TODO
continue;
},
}
} else
@ -282,12 +392,114 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
}
}
fn layout_atomic<'box_tree>(
layout_context: &LayoutContext,
ifc: &mut InlineFormattingContextState<'box_tree, '_>,
atomic: &'box_tree IndependentFormattingContext,
) {
let cbis = ifc.containing_block.inline_size;
let padding = atomic.style.padding().percentages_relative_to(cbis);
let border = atomic.style.border_width();
let margin = atomic
.style
.margin()
.percentages_relative_to(cbis)
.auto_is(Length::zero);
let pbm = &(&padding + &border) + &margin;
ifc.inline_position += pbm.inline_start;
let mut start_corner = Vec2 {
block: pbm.block_start,
inline: ifc.inline_position - ifc.current_nesting_level.inline_start,
};
start_corner += &relative_adjustement(
&atomic.style,
ifc.containing_block.inline_size,
ifc.containing_block.block_size,
);
let fragment = match atomic.as_replaced() {
Ok(replaced) => {
// FIXME: implement https://drafts.csswg.org/css2/visudet.html#inline-replaced-width
// and https://drafts.csswg.org/css2/visudet.html#inline-replaced-height
let size = Vec2::zero();
let fragments = replaced.make_fragments(&atomic.style, size.clone());
let content_rect = Rect { start_corner, size };
BoxFragment {
style: atomic.style.clone(),
children: fragments,
content_rect,
padding,
border,
margin,
block_margins_collapsed_with_children: CollapsedBlockMargins::zero(),
}
},
Err(non_replaced) => {
let box_size = atomic.style.box_size();
let inline_size = box_size.inline.percentage_relative_to(cbis).auto_is(|| {
let available_size = cbis - pbm.inline_sum();
atomic.content_sizes.shrink_to_fit(available_size)
});
let block_size = box_size
.block
.maybe_percentage_relative_to(ifc.containing_block.block_size.non_auto());
let containing_block_for_children = ContainingBlock {
inline_size,
block_size,
mode: atomic.style.writing_mode(),
};
assert_eq!(
ifc.containing_block.mode, containing_block_for_children.mode,
"Mixed writing modes are not supported yet"
);
// FIXME is this correct?
let dummy_tree_rank = 0;
// FIXME: Do we need to call `adjust_static_positions` somewhere near here?
let independent_layout = non_replaced.layout(
layout_context,
&containing_block_for_children,
dummy_tree_rank,
ifc.absolutely_positioned_fragments,
);
let block_size = block_size.auto_is(|| independent_layout.content_block_size);
let content_rect = Rect {
start_corner,
size: Vec2 {
block: block_size,
inline: inline_size,
},
};
BoxFragment {
style: atomic.style.clone(),
children: independent_layout.fragments,
content_rect,
padding,
border,
margin,
block_margins_collapsed_with_children: CollapsedBlockMargins::zero(),
}
},
};
ifc.inline_position += pbm.inline_end;
ifc.current_nesting_level
.fragments_so_far
.push(Fragment::Box(fragment));
}
struct BreakAndShapeResult {
font_ascent: Au,
font_line_gap: Au,
font_key: FontInstanceKey,
runs: Vec<GlyphRun>,
break_at_start: bool,
}
impl TextRun {
fn layout(&self, layout_context: &LayoutContext, ifc: &mut InlineFormattingContextState) {
fn break_and_shape(&self, layout_context: &LayoutContext) -> BreakAndShapeResult {
use gfx::font::ShapingFlags;
use style::computed_values::text_rendering::T as TextRendering;
use style::computed_values::word_break::T as WordBreak;
use style::values::generics::text::LineHeight;
let font_style = self.parent_style.clone_font();
let inherited_text_style = self.parent_style.get_inherited_text();
@ -316,30 +528,41 @@ impl TextRun {
flags,
};
let (font_ascent, font_line_gap, font_key, runs) =
crate::context::with_thread_local_font_context(layout_context, |font_context| {
let font_group = font_context.font_group(font_style);
let font = font_group
.borrow_mut()
.first(font_context)
.expect("could not find font");
let mut font = font.borrow_mut();
crate::context::with_thread_local_font_context(layout_context, |font_context| {
let font_group = font_context.font_group(font_style);
let font = font_group
.borrow_mut()
.first(font_context)
.expect("could not find font");
let mut font = font.borrow_mut();
let (runs, _break_at_start) = gfx::text::text_run::TextRun::break_and_shape(
&mut font,
&self.text,
&shaping_options,
&mut None,
);
let (runs, break_at_start) = gfx::text::text_run::TextRun::break_and_shape(
&mut font,
&self.text,
&shaping_options,
&mut None,
);
(
font.metrics.ascent,
font.metrics.line_gap,
font.font_key,
runs,
)
});
BreakAndShapeResult {
font_ascent: font.metrics.ascent,
font_line_gap: font.metrics.line_gap,
font_key: font.font_key,
runs,
break_at_start,
}
})
}
fn layout(&self, layout_context: &LayoutContext, ifc: &mut InlineFormattingContextState) {
use style::values::generics::text::LineHeight;
let BreakAndShapeResult {
font_ascent,
font_line_gap,
font_key,
runs,
break_at_start: _,
} = self.break_and_shape(layout_context);
let font_size = self.parent_style.get_font().font_size.size.0;
let mut runs = runs.iter();
loop {

View file

@ -656,17 +656,11 @@ fn layout_in_flow_replaced_block_level<'a>(
block_start: computed_margin.block_start.auto_is(Length::zero),
block_end: computed_margin.block_end.auto_is(Length::zero),
};
let containing_block_for_children = ContainingBlock {
inline_size,
block_size: LengthOrAuto::LengthPercentage(block_size),
mode,
let size = Vec2 {
block: block_size,
inline: inline_size,
};
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
assert_eq!(
containing_block.mode, containing_block_for_children.mode,
"Mixed writing modes are not supported yet"
);
let independent_layout = replaced.layout(style, &containing_block_for_children);
let fragments = replaced.make_fragments(style, size.clone());
let relative_adjustement = relative_adjustement(
style,
inline_size,
@ -677,14 +671,11 @@ fn layout_in_flow_replaced_block_level<'a>(
block: pb.block_start + relative_adjustement.block,
inline: pb.inline_start + relative_adjustement.inline + margin.inline_start,
},
size: Vec2 {
block: block_size,
inline: inline_size,
},
size,
};
BoxFragment {
style: style.clone(),
children: independent_layout.fragments,
children: fragments,
content_rect,
padding,
border,

View file

@ -14,12 +14,12 @@ use crate::geom;
use crate::geom::flow_relative::Vec2;
use crate::positioned::AbsolutelyPositionedBox;
use crate::replaced::ReplacedContent;
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{Direction, Display, DisplayGeneratingBox, DisplayInside, WritingMode};
use crate::{ContainingBlock, DefiniteContainingBlock};
use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator};
use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc;
use style::context::SharedStyleContext;
use style::values::computed::{Length, LengthOrAuto};
use style::Zero;
use style_traits::CSSPixel;
@ -28,7 +28,7 @@ pub struct BoxTreeRoot(BlockFormattingContext);
pub struct FragmentTreeRoot(Vec<Fragment>);
impl BoxTreeRoot {
pub fn construct<'dom, Node>(context: &SharedStyleContext<'_>, root_element: Node) -> Self
pub fn construct<'dom, Node>(context: &LayoutContext, root_element: Node) -> Self
where
Node: 'dom + Copy + LayoutNode + Send + Sync,
{
@ -41,7 +41,7 @@ impl BoxTreeRoot {
}
fn construct_for_root_element<'dom>(
context: &SharedStyleContext<'_>,
context: &LayoutContext,
root_element: impl NodeExt<'dom>,
) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) {
let style = root_element.style(context);
@ -60,32 +60,33 @@ fn construct_for_root_element<'dom>(
Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
};
let position = box_style.position;
let float = box_style.float;
let contents = IndependentFormattingContext::construct(
context,
style,
display_inside,
replaced.map_or(Contents::OfElement(root_element), Contents::Replaced),
);
if position.is_absolutely_positioned() {
let contents = replaced.map_or(Contents::OfElement(root_element), Contents::Replaced);
if box_style.position.is_absolutely_positioned() {
(
ContainsFloats::No,
vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
AbsolutelyPositionedBox { contents },
AbsolutelyPositionedBox::construct(context, style, display_inside, contents),
))],
)
} else if float.is_floating() {
} else if box_style.float.is_floating() {
(
ContainsFloats::Yes,
vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox {
contents,
}))],
vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(
FloatBox::construct(context, style, display_inside, contents),
))],
)
} else {
(
ContainsFloats::No,
vec![Arc::new(BlockLevelBox::Independent(contents))],
vec![Arc::new(BlockLevelBox::Independent(
IndependentFormattingContext::construct(
context,
style,
display_inside,
contents,
ContentSizesRequest::None,
),
))],
)
}
}