mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Import victor's layout system 🍷
This commit is contained in:
parent
86904757e6
commit
4444c5a2ad
25 changed files with 1270 additions and 712 deletions
|
@ -1,14 +1,27 @@
|
|||
use super::*;
|
||||
use crate::fonts::BITSTREAM_VERA_SANS;
|
||||
use crate::text::ShapedSegment;
|
||||
/* 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::float::FloatBox;
|
||||
use crate::flow::FlowChildren;
|
||||
use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment};
|
||||
use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
||||
use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment};
|
||||
use crate::replaced::ReplacedContent;
|
||||
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
|
||||
use crate::{relative_adjustement, take, ContainingBlock};
|
||||
use servo_arc::Arc;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::Length;
|
||||
use style::Zero;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(in crate::layout) struct InlineFormattingContext {
|
||||
pub(crate) struct InlineFormattingContext {
|
||||
pub(super) inline_level_boxes: Vec<Arc<InlineLevelBox>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(in crate::layout) enum InlineLevelBox {
|
||||
pub(crate) enum InlineLevelBox {
|
||||
InlineBox(InlineBox),
|
||||
TextRun(TextRun),
|
||||
OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox),
|
||||
|
@ -21,7 +34,7 @@ pub(in crate::layout) enum InlineLevelBox {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(in crate::layout) struct InlineBox {
|
||||
pub(crate) struct InlineBox {
|
||||
pub style: Arc<ComputedValues>,
|
||||
pub first_fragment: bool,
|
||||
pub last_fragment: bool,
|
||||
|
@ -30,7 +43,7 @@ pub(in crate::layout) struct InlineBox {
|
|||
|
||||
/// https://www.w3.org/TR/css-display-3/#css-text-run
|
||||
#[derive(Debug)]
|
||||
pub(in crate::layout) struct TextRun {
|
||||
pub(crate) struct TextRun {
|
||||
pub parent_style: Arc<ComputedValues>,
|
||||
pub text: String,
|
||||
}
|
||||
|
@ -93,36 +106,40 @@ impl InlineFormattingContext {
|
|||
InlineLevelBox::InlineBox(inline) => {
|
||||
let partial = inline.start_layout(&mut ifc);
|
||||
ifc.partial_inline_boxes_stack.push(partial)
|
||||
}
|
||||
},
|
||||
InlineLevelBox::TextRun(run) => run.layout(&mut ifc),
|
||||
InlineLevelBox::Atomic { style: _, contents } => {
|
||||
// FIXME
|
||||
match *contents {}
|
||||
}
|
||||
},
|
||||
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
|
||||
let initial_start_corner = match box_.style.specified_display {
|
||||
Display::GeneratingBox(DisplayGeneratingBox::OutsideInside {
|
||||
outside,
|
||||
inside: _,
|
||||
}) => Vec2 {
|
||||
inline: match outside {
|
||||
DisplayOutside::Inline => ifc.inline_position,
|
||||
DisplayOutside::Block => Length::zero(),
|
||||
let initial_start_corner =
|
||||
match Display::from(box_.style.get_box().original_display) {
|
||||
Display::GeneratingBox(DisplayGeneratingBox::OutsideInside {
|
||||
outside,
|
||||
inside: _,
|
||||
}) => Vec2 {
|
||||
inline: match outside {
|
||||
DisplayOutside::Inline => ifc.inline_position,
|
||||
DisplayOutside::Block => Length::zero(),
|
||||
DisplayOutside::None => unreachable!(":("),
|
||||
},
|
||||
block: ifc.line_boxes.next_line_block_position,
|
||||
},
|
||||
block: ifc.line_boxes.next_line_block_position,
|
||||
},
|
||||
Display::Contents => {
|
||||
panic!("display:contents does not generate an abspos box")
|
||||
}
|
||||
Display::None => panic!("display:none does not generate an abspos box"),
|
||||
};
|
||||
Display::Contents => {
|
||||
panic!("display:contents does not generate an abspos box")
|
||||
},
|
||||
Display::None => {
|
||||
panic!("display:none does not generate an abspos box")
|
||||
},
|
||||
};
|
||||
absolutely_positioned_fragments
|
||||
.push(box_.layout(initial_start_corner, tree_rank));
|
||||
}
|
||||
},
|
||||
InlineLevelBox::OutOfFlowFloatBox(_box_) => {
|
||||
// TODO
|
||||
continue;
|
||||
}
|
||||
},
|
||||
}
|
||||
} else
|
||||
// Reached the end of ifc.remaining_boxes
|
||||
|
@ -180,7 +197,7 @@ impl InlineBox {
|
|||
let style = self.style.clone();
|
||||
let cbis = ifc.containing_block.inline_size;
|
||||
let mut padding = style.padding().percentages_relative_to(cbis);
|
||||
let mut border = style.border_width().percentages_relative_to(cbis);
|
||||
let mut border = style.border_width();
|
||||
let mut margin = style
|
||||
.margin()
|
||||
.percentages_relative_to(cbis)
|
||||
|
@ -245,9 +262,9 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
|
|||
};
|
||||
let last_fragment = self.last_box_tree_fragment && !at_line_break;
|
||||
if last_fragment {
|
||||
*inline_position += fragment.padding.inline_end
|
||||
+ fragment.border.inline_end
|
||||
+ fragment.margin.inline_end;
|
||||
*inline_position += fragment.padding.inline_end +
|
||||
fragment.border.inline_end +
|
||||
fragment.margin.inline_end;
|
||||
} else {
|
||||
fragment.padding.inline_end = Length::zero();
|
||||
fragment.border.inline_end = Length::zero();
|
||||
|
@ -256,10 +273,10 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
|
|||
self.parent_nesting_level
|
||||
.max_block_size_of_fragments_so_far
|
||||
.max_assign(
|
||||
fragment.content_rect.size.block
|
||||
+ fragment.padding.block_sum()
|
||||
+ fragment.border.block_sum()
|
||||
+ fragment.margin.block_sum(),
|
||||
fragment.content_rect.size.block +
|
||||
fragment.padding.block_sum() +
|
||||
fragment.border.block_sum() +
|
||||
fragment.margin.block_sum(),
|
||||
);
|
||||
self.parent_nesting_level
|
||||
.fragments_so_far
|
||||
|
@ -268,78 +285,7 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
|
|||
}
|
||||
|
||||
impl TextRun {
|
||||
fn layout(&self, ifc: &mut InlineFormattingContextState) {
|
||||
let available = ifc.containing_block.inline_size - ifc.inline_position;
|
||||
let mut chars = self.text.chars();
|
||||
loop {
|
||||
let mut shaped = ShapedSegment::new_with_naive_shaping(BITSTREAM_VERA_SANS.clone());
|
||||
let mut last_break_opportunity = None;
|
||||
loop {
|
||||
let next = chars.next();
|
||||
if matches!(next, Some(' ') | None) {
|
||||
let inline_size = self.parent_style.font.font_size * shaped.advance_width;
|
||||
if inline_size > available {
|
||||
if let Some((state, iter)) = last_break_opportunity.take() {
|
||||
shaped.restore(&state);
|
||||
chars = iter;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(ch) = next {
|
||||
if ch == ' ' {
|
||||
last_break_opportunity = Some((shaped.save(), chars.clone()))
|
||||
}
|
||||
shaped.append_char(ch).unwrap()
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let inline_size = self.parent_style.font.font_size * shaped.advance_width;
|
||||
// https://www.w3.org/TR/CSS2/visudet.html#propdef-line-height
|
||||
// 'normal':
|
||||
// “set the used value to a "reasonable" value based on the font of the element.”
|
||||
let line_height = self.parent_style.font.font_size.0 * 1.2;
|
||||
let content_rect = Rect {
|
||||
start_corner: Vec2 {
|
||||
block: Length::zero(),
|
||||
inline: ifc.inline_position - ifc.current_nesting_level.inline_start,
|
||||
},
|
||||
size: Vec2 {
|
||||
block: line_height,
|
||||
inline: inline_size,
|
||||
},
|
||||
};
|
||||
ifc.inline_position += inline_size;
|
||||
ifc.current_nesting_level
|
||||
.max_block_size_of_fragments_so_far
|
||||
.max_assign(line_height);
|
||||
ifc.current_nesting_level
|
||||
.fragments_so_far
|
||||
.push(Fragment::Text(TextFragment {
|
||||
parent_style: self.parent_style.clone(),
|
||||
content_rect,
|
||||
text: shaped,
|
||||
}));
|
||||
if chars.as_str().is_empty() {
|
||||
break;
|
||||
} else {
|
||||
// New line
|
||||
ifc.current_nesting_level.inline_start = Length::zero();
|
||||
let mut nesting_level = &mut ifc.current_nesting_level;
|
||||
for partial in ifc.partial_inline_boxes_stack.iter_mut().rev() {
|
||||
partial.finish_layout(nesting_level, &mut ifc.inline_position, true);
|
||||
partial.start_corner.inline = Length::zero();
|
||||
partial.padding.inline_start = Length::zero();
|
||||
partial.border.inline_start = Length::zero();
|
||||
partial.margin.inline_start = Length::zero();
|
||||
partial.parent_nesting_level.inline_start = Length::zero();
|
||||
nesting_level = &mut partial.parent_nesting_level;
|
||||
}
|
||||
ifc.line_boxes
|
||||
.finish_line(nesting_level, ifc.containing_block);
|
||||
ifc.inline_position = Length::zero();
|
||||
}
|
||||
}
|
||||
fn layout(&self, _ifc: &mut InlineFormattingContextState) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue