mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Auto merge of #24822 - servo:fontcontext, r=SimonSapin
Start implementing text in layout 2020
This commit is contained in:
commit
a562808ebb
16 changed files with 311 additions and 42 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -2694,17 +2694,21 @@ dependencies = [
|
|||
"cssparser",
|
||||
"euclid",
|
||||
"gfx",
|
||||
"gfx_traits",
|
||||
"ipc-channel",
|
||||
"libc",
|
||||
"msg",
|
||||
"range",
|
||||
"rayon",
|
||||
"rayon_croissant",
|
||||
"script_layout_interface",
|
||||
"script_traits",
|
||||
"serde",
|
||||
"servo_arc",
|
||||
"servo_geometry",
|
||||
"style",
|
||||
"style_traits",
|
||||
"unicode-script",
|
||||
"webrender_api",
|
||||
]
|
||||
|
||||
|
|
|
@ -452,6 +452,11 @@ impl<'a> GlyphStore {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn total_advance(&self) -> Au {
|
||||
self.total_advance
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> ByteIndex {
|
||||
ByteIndex(self.entry_buffer.len() as isize)
|
||||
|
|
|
@ -18,15 +18,19 @@ atomic_refcell = "0.1"
|
|||
cssparser = "0.27"
|
||||
euclid = "0.20"
|
||||
gfx = {path = "../gfx"}
|
||||
gfx_traits = {path = "../gfx_traits"}
|
||||
ipc-channel = "0.12"
|
||||
libc = "0.2"
|
||||
msg = {path = "../msg"}
|
||||
range = {path = "../range"}
|
||||
rayon = "1"
|
||||
rayon_croissant = "0.1.1"
|
||||
script_layout_interface = {path = "../script_layout_interface"}
|
||||
script_traits = {path = "../script_traits"}
|
||||
serde = "1.0"
|
||||
servo_arc = { path = "../servo_arc" }
|
||||
servo_geometry = {path = "../geometry"}
|
||||
style = {path = "../style", features = ["servo", "servo-layout-2020"]}
|
||||
style_traits = {path = "../style_traits"}
|
||||
unicode-script = {version = "0.3", features = ["harfbuzz"]}
|
||||
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use gfx::font_cache_thread::FontCacheThread;
|
||||
use gfx::font_context::FontContext;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::sync::Mutex;
|
||||
use style::context::SharedStyleContext;
|
||||
|
||||
|
@ -19,3 +21,18 @@ impl<'a> LayoutContext<'a> {
|
|||
&self.style_context
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type LayoutFontContext = FontContext<FontCacheThread>;
|
||||
|
||||
thread_local!(static FONT_CONTEXT: RefCell<Option<LayoutFontContext>> = RefCell::new(None));
|
||||
|
||||
pub(crate) fn with_thread_local_font_context<F, R>(layout_context: &LayoutContext, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut LayoutFontContext) -> R,
|
||||
{
|
||||
FONT_CONTEXT.with(|font_context| {
|
||||
f(font_context.borrow_mut().get_or_insert_with(|| {
|
||||
FontContext::new(layout_context.font_cache_thread.lock().unwrap().clone())
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -6,7 +6,10 @@ use crate::fragments::{BoxFragment, Fragment};
|
|||
use crate::geom::physical::{Rect, Vec2};
|
||||
use crate::style_ext::ComputedValuesExt;
|
||||
use app_units::Au;
|
||||
use euclid::{self, SideOffsets2D};
|
||||
use euclid::{Point2D, SideOffsets2D};
|
||||
use gfx::text::glyph::GlyphStore;
|
||||
use servo_geometry::MaxRect;
|
||||
use std::sync::Arc;
|
||||
use style::values::computed::{BorderStyle, Length};
|
||||
use webrender_api::{self as wr, units, CommonItemProperties, PrimitiveFlags};
|
||||
|
||||
|
@ -50,9 +53,30 @@ impl Fragment {
|
|||
child.build_display_list(builder, is_contentful, &rect)
|
||||
}
|
||||
},
|
||||
Fragment::Text(_) => {
|
||||
Fragment::Text(t) => {
|
||||
is_contentful.0 = true;
|
||||
// FIXME
|
||||
let rect = t
|
||||
.content_rect
|
||||
.to_physical(t.parent_style.writing_mode(), containing_block)
|
||||
.translate(&containing_block.top_left);
|
||||
let mut baseline_origin = rect.top_left.clone();
|
||||
baseline_origin.y += t.ascent;
|
||||
let common = CommonItemProperties {
|
||||
clip_rect: rect.clone().into(),
|
||||
clip_id: wr::ClipId::root(builder.pipeline_id),
|
||||
spatial_id: wr::SpatialId::root_scroll_node(builder.pipeline_id),
|
||||
hit_info: None,
|
||||
// TODO(gw): Make use of the WR backface visibility functionality.
|
||||
flags: PrimitiveFlags::default(),
|
||||
};
|
||||
let glyphs = glyphs(&t.glyphs, baseline_origin);
|
||||
if glyphs.is_empty() {
|
||||
return;
|
||||
}
|
||||
let color = t.parent_style.clone_color();
|
||||
builder
|
||||
.wr
|
||||
.push_text(&common, rect.into(), &glyphs, t.font_key, rgba(color), None);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -154,3 +178,28 @@ fn rgba(rgba: cssparser::RGBA) -> wr::ColorF {
|
|||
rgba.alpha_f32(),
|
||||
)
|
||||
}
|
||||
|
||||
fn glyphs(glyph_runs: &[Arc<GlyphStore>], mut origin: Vec2<Length>) -> Vec<wr::GlyphInstance> {
|
||||
use gfx_traits::ByteIndex;
|
||||
use range::Range;
|
||||
|
||||
let mut glyphs = vec![];
|
||||
for run in glyph_runs {
|
||||
for glyph in run.iter_glyphs_for_byte_range(&Range::new(ByteIndex(0), run.len())) {
|
||||
if !run.is_whitespace() {
|
||||
let glyph_offset = glyph.offset().unwrap_or(Point2D::zero());
|
||||
let point = units::LayoutPoint::new(
|
||||
origin.x.px() + glyph_offset.x.to_f32_px(),
|
||||
origin.y.px() + glyph_offset.y.to_f32_px(),
|
||||
);
|
||||
let glyph = wr::GlyphInstance {
|
||||
index: glyph.id(),
|
||||
point,
|
||||
};
|
||||
glyphs.push(glyph);
|
||||
}
|
||||
origin.x += Length::from(glyph.advance());
|
||||
}
|
||||
}
|
||||
glyphs
|
||||
}
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
* 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::flow::float::FloatBox;
|
||||
use crate::flow::FlowChildren;
|
||||
use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment};
|
||||
use crate::fragments::{
|
||||
AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment, TextFragment,
|
||||
};
|
||||
use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
||||
use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment};
|
||||
use crate::replaced::ReplacedContent;
|
||||
|
@ -81,6 +84,7 @@ struct LinesBoxes {
|
|||
impl InlineFormattingContext {
|
||||
pub(super) fn layout<'a>(
|
||||
&'a self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
|
||||
|
@ -107,7 +111,7 @@ impl InlineFormattingContext {
|
|||
let partial = inline.start_layout(&mut ifc);
|
||||
ifc.partial_inline_boxes_stack.push(partial)
|
||||
},
|
||||
InlineLevelBox::TextRun(run) => run.layout(&mut ifc),
|
||||
InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc),
|
||||
InlineLevelBox::Atomic { style: _, contents } => {
|
||||
// FIXME
|
||||
match *contents {}
|
||||
|
@ -284,7 +288,141 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
|
|||
}
|
||||
|
||||
impl TextRun {
|
||||
fn layout(&self, _ifc: &mut InlineFormattingContextState) {
|
||||
// TODO
|
||||
fn layout(&self, layout_context: &LayoutContext, ifc: &mut InlineFormattingContextState) {
|
||||
use gfx::font::{ShapingFlags, ShapingOptions};
|
||||
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();
|
||||
let letter_spacing = if inherited_text_style.letter_spacing.0.px() != 0. {
|
||||
Some(app_units::Au::from(inherited_text_style.letter_spacing.0))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut flags = ShapingFlags::empty();
|
||||
if letter_spacing.is_some() {
|
||||
flags.insert(ShapingFlags::IGNORE_LIGATURES_SHAPING_FLAG);
|
||||
}
|
||||
if inherited_text_style.text_rendering == TextRendering::Optimizespeed {
|
||||
flags.insert(ShapingFlags::IGNORE_LIGATURES_SHAPING_FLAG);
|
||||
flags.insert(ShapingFlags::DISABLE_KERNING_SHAPING_FLAG)
|
||||
}
|
||||
if inherited_text_style.word_break == WordBreak::KeepAll {
|
||||
flags.insert(ShapingFlags::KEEP_ALL_FLAG);
|
||||
}
|
||||
|
||||
let shaping_options = gfx::font::ShapingOptions {
|
||||
letter_spacing,
|
||||
word_spacing: inherited_text_style.word_spacing.to_hash_key(),
|
||||
script: unicode_script::Script::Common,
|
||||
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();
|
||||
|
||||
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,
|
||||
)
|
||||
});
|
||||
|
||||
let font_size = self.parent_style.get_font().font_size.size.0;
|
||||
let mut runs = runs.iter();
|
||||
loop {
|
||||
let mut glyphs = vec![];
|
||||
let mut advance_width = Length::zero();
|
||||
let mut last_break_opportunity = None;
|
||||
loop {
|
||||
let next = runs.next();
|
||||
if next
|
||||
.as_ref()
|
||||
.map_or(true, |run| run.glyph_store.is_whitespace())
|
||||
{
|
||||
if advance_width > ifc.containing_block.inline_size - ifc.inline_position {
|
||||
if let Some((len, width, iter)) = last_break_opportunity.take() {
|
||||
glyphs.truncate(len);
|
||||
advance_width = width;
|
||||
runs = iter;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(run) = next {
|
||||
if run.glyph_store.is_whitespace() {
|
||||
last_break_opportunity = Some((glyphs.len(), advance_width, runs.clone()));
|
||||
}
|
||||
glyphs.push(run.glyph_store.clone());
|
||||
advance_width += Length::from(run.glyph_store.total_advance());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let line_height = match self.parent_style.get_inherited_text().line_height {
|
||||
LineHeight::Normal => font_line_gap.into(),
|
||||
LineHeight::Number(n) => font_size * n.0,
|
||||
LineHeight::Length(l) => l.0,
|
||||
};
|
||||
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: advance_width,
|
||||
},
|
||||
};
|
||||
ifc.inline_position += advance_width;
|
||||
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,
|
||||
ascent: font_ascent.into(),
|
||||
font_key,
|
||||
glyphs,
|
||||
}));
|
||||
if runs.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
//! Flow layout, also known as block-and-inline layout.
|
||||
|
||||
use crate::context::LayoutContext;
|
||||
use crate::flow::float::{FloatBox, FloatContext};
|
||||
use crate::flow::inline::InlineFormattingContext;
|
||||
use crate::fragments::{
|
||||
|
@ -67,6 +68,7 @@ struct CollapsibleWithParentStartMargin(bool);
|
|||
impl BlockFormattingContext {
|
||||
pub(super) fn layout<'a>(
|
||||
&'a self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
|
||||
|
@ -79,6 +81,7 @@ impl BlockFormattingContext {
|
|||
None
|
||||
};
|
||||
let mut flow_children = self.contents.layout(
|
||||
layout_context,
|
||||
containing_block,
|
||||
tree_rank,
|
||||
absolutely_positioned_fragments,
|
||||
|
@ -97,6 +100,7 @@ impl BlockFormattingContext {
|
|||
impl BlockContainer {
|
||||
fn layout<'a>(
|
||||
&'a self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
|
||||
|
@ -105,6 +109,7 @@ impl BlockContainer {
|
|||
) -> FlowChildren {
|
||||
match self {
|
||||
BlockContainer::BlockLevelBoxes(child_boxes) => layout_block_level_children(
|
||||
layout_context,
|
||||
child_boxes,
|
||||
containing_block,
|
||||
tree_rank,
|
||||
|
@ -112,14 +117,18 @@ impl BlockContainer {
|
|||
float_context,
|
||||
collapsible_with_parent_start_margin,
|
||||
),
|
||||
BlockContainer::InlineFormattingContext(ifc) => {
|
||||
ifc.layout(containing_block, tree_rank, absolutely_positioned_fragments)
|
||||
},
|
||||
BlockContainer::InlineFormattingContext(ifc) => ifc.layout(
|
||||
layout_context,
|
||||
containing_block,
|
||||
tree_rank,
|
||||
absolutely_positioned_fragments,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_block_level_children<'a>(
|
||||
layout_context: &LayoutContext,
|
||||
child_boxes: &'a [Arc<BlockLevelBox>],
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
|
@ -201,6 +210,7 @@ fn layout_block_level_children<'a>(
|
|||
.enumerate()
|
||||
.map(|(tree_rank, box_)| {
|
||||
let mut fragment = box_.layout(
|
||||
layout_context,
|
||||
containing_block,
|
||||
tree_rank,
|
||||
absolutely_positioned_fragments,
|
||||
|
@ -218,6 +228,7 @@ fn layout_block_level_children<'a>(
|
|||
absolutely_positioned_fragments,
|
||||
|abspos_fragments, (tree_rank, box_)| {
|
||||
box_.layout(
|
||||
layout_context,
|
||||
containing_block,
|
||||
tree_rank,
|
||||
abspos_fragments,
|
||||
|
@ -255,6 +266,7 @@ fn layout_block_level_children<'a>(
|
|||
impl BlockLevelBox {
|
||||
fn layout<'a>(
|
||||
&'a self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
|
||||
|
@ -263,12 +275,14 @@ impl BlockLevelBox {
|
|||
match self {
|
||||
BlockLevelBox::SameFormattingContextBlock { style, contents } => {
|
||||
Fragment::Box(layout_in_flow_non_replaced_block_level(
|
||||
layout_context,
|
||||
containing_block,
|
||||
absolutely_positioned_fragments,
|
||||
style,
|
||||
BlockLevelKind::SameFormattingContextBlock,
|
||||
|containing_block, nested_abspos, collapsible_with_parent_start_margin| {
|
||||
contents.layout(
|
||||
layout_context,
|
||||
containing_block,
|
||||
tree_rank,
|
||||
nested_abspos,
|
||||
|
@ -284,12 +298,13 @@ impl BlockLevelBox {
|
|||
match *replaced {}
|
||||
},
|
||||
Err(contents) => Fragment::Box(layout_in_flow_non_replaced_block_level(
|
||||
layout_context,
|
||||
containing_block,
|
||||
absolutely_positioned_fragments,
|
||||
style,
|
||||
BlockLevelKind::EstablishesAnIndependentFormattingContext,
|
||||
|containing_block, nested_abspos, _| {
|
||||
contents.layout(containing_block, tree_rank, nested_abspos)
|
||||
contents.layout(layout_context, containing_block, tree_rank, nested_abspos)
|
||||
},
|
||||
)),
|
||||
},
|
||||
|
@ -314,6 +329,7 @@ enum BlockLevelKind {
|
|||
/// https://drafts.csswg.org/css2/visudet.html#blockwidth
|
||||
/// https://drafts.csswg.org/css2/visudet.html#normal-block
|
||||
fn layout_in_flow_non_replaced_block_level<'a>(
|
||||
layout_context: &LayoutContext,
|
||||
containing_block: &ContainingBlock,
|
||||
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
|
||||
style: &Arc<ComputedValues>,
|
||||
|
@ -433,6 +449,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
|
|||
};
|
||||
if style.get_box().position == Position::Relative {
|
||||
AbsolutelyPositionedFragment::in_positioned_containing_block(
|
||||
layout_context,
|
||||
&nested_abspos,
|
||||
&mut flow_children.fragments,
|
||||
&content_rect.size,
|
||||
|
|
|
@ -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::display_list::IsContentful;
|
||||
use crate::dom_traversal::{Contents, NodeExt};
|
||||
use crate::flow::construct::ContainsFloats;
|
||||
|
@ -98,7 +99,11 @@ fn construct_for_root_element<'dom>(
|
|||
}
|
||||
|
||||
impl BoxTreeRoot {
|
||||
pub fn layout(&self, viewport: geom::Size<CSSPixel>) -> FragmentTreeRoot {
|
||||
pub fn layout(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
viewport: geom::Size<CSSPixel>,
|
||||
) -> FragmentTreeRoot {
|
||||
let initial_containing_block_size = Vec2 {
|
||||
inline: Length::new(viewport.width),
|
||||
block: Length::new(viewport.height),
|
||||
|
@ -114,6 +119,7 @@ impl BoxTreeRoot {
|
|||
let dummy_tree_rank = 0;
|
||||
let mut absolutely_positioned_fragments = vec![];
|
||||
let mut flow_children = self.0.layout(
|
||||
layout_context,
|
||||
&initial_containing_block,
|
||||
dummy_tree_rank,
|
||||
&mut absolutely_positioned_fragments,
|
||||
|
@ -126,7 +132,7 @@ impl BoxTreeRoot {
|
|||
flow_children.fragments.par_extend(
|
||||
absolutely_positioned_fragments
|
||||
.par_iter()
|
||||
.map(|a| a.layout(&initial_containing_block)),
|
||||
.map(|a| a.layout(layout_context, &initial_containing_block)),
|
||||
);
|
||||
FragmentTreeRoot(flow_children.fragments)
|
||||
}
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
|
||||
use crate::geom::flow_relative::{Rect, Sides};
|
||||
use crate::style_ext::{Direction, WritingMode};
|
||||
// use crate::text::ShapedSegment;
|
||||
use servo_arc::Arc;
|
||||
use gfx::text::glyph::GlyphStore;
|
||||
use servo_arc::Arc as ServoArc;
|
||||
use std::sync::Arc;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::Length;
|
||||
use style::Zero;
|
||||
use webrender_api::FontInstanceKey;
|
||||
|
||||
pub(crate) enum Fragment {
|
||||
Box(BoxFragment),
|
||||
|
@ -17,7 +19,7 @@ pub(crate) enum Fragment {
|
|||
}
|
||||
|
||||
pub(crate) struct BoxFragment {
|
||||
pub style: Arc<ComputedValues>,
|
||||
pub style: ServoArc<ComputedValues>,
|
||||
pub children: Vec<Fragment>,
|
||||
|
||||
/// From the containing block’s start corner…?
|
||||
|
@ -52,9 +54,11 @@ pub(crate) struct AnonymousFragment {
|
|||
}
|
||||
|
||||
pub(crate) struct TextFragment {
|
||||
pub parent_style: Arc<ComputedValues>,
|
||||
pub parent_style: ServoArc<ComputedValues>,
|
||||
pub content_rect: Rect<Length>,
|
||||
// pub text: ShapedSegment,
|
||||
pub ascent: Length,
|
||||
pub font_key: FontInstanceKey,
|
||||
pub glyphs: Vec<Arc<GlyphStore>>,
|
||||
}
|
||||
|
||||
impl AnonymousFragment {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#![allow(unused_imports)]
|
||||
#![allow(unused_variables)]
|
||||
#![deny(unsafe_code)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
|
@ -33,6 +34,7 @@ pub mod wrapper;
|
|||
|
||||
pub use flow::{BoxTreeRoot, FragmentTreeRoot};
|
||||
|
||||
use crate::context::LayoutContext;
|
||||
use crate::dom_traversal::{Contents, NodeExt};
|
||||
use crate::flow::{BlockFormattingContext, FlowChildren};
|
||||
use crate::geom::flow_relative::Vec2;
|
||||
|
@ -87,13 +89,19 @@ impl IndependentFormattingContext {
|
|||
|
||||
fn layout<'a>(
|
||||
&'a self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
|
||||
) -> FlowChildren {
|
||||
match self.as_replaced() {
|
||||
Ok(replaced) => match *replaced {},
|
||||
Err(ifc) => ifc.layout(containing_block, tree_rank, absolutely_positioned_fragments),
|
||||
Err(ifc) => ifc.layout(
|
||||
layout_context,
|
||||
containing_block,
|
||||
tree_rank,
|
||||
absolutely_positioned_fragments,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,14 +109,18 @@ impl IndependentFormattingContext {
|
|||
impl<'a> NonReplacedIFC<'a> {
|
||||
fn layout(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block: &ContainingBlock,
|
||||
tree_rank: usize,
|
||||
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
|
||||
) -> FlowChildren {
|
||||
match self {
|
||||
NonReplacedIFC::Flow(bfc) => {
|
||||
bfc.layout(containing_block, tree_rank, absolutely_positioned_fragments)
|
||||
},
|
||||
NonReplacedIFC::Flow(bfc) => bfc.layout(
|
||||
layout_context,
|
||||
containing_block,
|
||||
tree_rank,
|
||||
absolutely_positioned_fragments,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment};
|
||||
use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
||||
use crate::style_ext::{ComputedValuesExt, Direction, WritingMode};
|
||||
|
@ -94,6 +95,7 @@ impl AbsolutelyPositionedBox {
|
|||
|
||||
impl<'a> AbsolutelyPositionedFragment<'a> {
|
||||
pub(crate) fn in_positioned_containing_block(
|
||||
layout_context: &LayoutContext,
|
||||
absolute: &[Self],
|
||||
fragments: &mut Vec<Fragment>,
|
||||
content_rect_size: &Vec2<Length>,
|
||||
|
@ -116,14 +118,18 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
|
|||
fragments.push(Fragment::Anonymous(AnonymousFragment {
|
||||
children: absolute
|
||||
.par_iter()
|
||||
.map(|a| a.layout(&containing_block))
|
||||
.map(|a| a.layout(layout_context, &containing_block))
|
||||
.collect(),
|
||||
rect: padding_rect,
|
||||
mode,
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn layout(&self, containing_block: &DefiniteContainingBlock) -> Fragment {
|
||||
pub(crate) fn layout(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block: &DefiniteContainingBlock,
|
||||
) -> Fragment {
|
||||
let style = &self.absolutely_positioned_box.style;
|
||||
let cbis = containing_block.size.inline;
|
||||
let cbbs = containing_block.size.block;
|
||||
|
@ -269,6 +275,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
|
|||
let dummy_tree_rank = 0;
|
||||
let mut absolutely_positioned_fragments = vec![];
|
||||
let mut flow_children = self.absolutely_positioned_box.contents.layout(
|
||||
layout_context,
|
||||
&containing_block_for_children,
|
||||
dummy_tree_rank,
|
||||
&mut absolutely_positioned_fragments,
|
||||
|
@ -297,6 +304,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
|
|||
};
|
||||
|
||||
AbsolutelyPositionedFragment::in_positioned_containing_block(
|
||||
layout_context,
|
||||
&absolutely_positioned_fragments,
|
||||
&mut flow_children.fragments,
|
||||
&content_rect.size,
|
||||
|
|
|
@ -88,7 +88,7 @@ use style::context::{SharedStyleContext, ThreadLocalStyleContextCreationInfo};
|
|||
use style::dom::{TDocument, TElement, TNode};
|
||||
use style::driver;
|
||||
use style::error_reporting::RustLogReporter;
|
||||
use style::global_style_data::GLOBAL_STYLE_DATA;
|
||||
use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL};
|
||||
use style::invalidation::element::restyle_hints::RestyleHint;
|
||||
use style::media_queries::{Device, MediaList, MediaType};
|
||||
use style::properties::PropertyId;
|
||||
|
@ -1087,16 +1087,29 @@ impl LayoutThread {
|
|||
RecalcStyle::pre_traverse(element, shared)
|
||||
};
|
||||
|
||||
if token.should_traverse() {
|
||||
let rayon_pool = STYLE_THREAD_POOL.pool();
|
||||
let rayon_pool = rayon_pool.as_ref().unwrap();
|
||||
|
||||
let box_tree = if token.should_traverse() {
|
||||
driver::traverse_dom(&traversal, token, None);
|
||||
|
||||
let shared = DomTraversal::<ServoLayoutElement>::shared_context(&traversal);
|
||||
let box_tree =
|
||||
BoxTreeRoot::construct(shared, document.root_element().unwrap().as_node());
|
||||
let fragment_tree = box_tree.layout(Size2D::new(
|
||||
let root_node = document.root_element().unwrap().as_node();
|
||||
let box_tree = rayon_pool.install(|| BoxTreeRoot::construct(shared, root_node));
|
||||
Some(box_tree)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
layout_context = traversal.destroy();
|
||||
|
||||
if let Some(box_tree) = box_tree {
|
||||
let viewport_size = Size2D::new(
|
||||
self.viewport_size.width.to_f32_px(),
|
||||
self.viewport_size.height.to_f32_px(),
|
||||
));
|
||||
);
|
||||
let fragment_tree =
|
||||
rayon_pool.install(|| box_tree.layout(&layout_context, viewport_size));
|
||||
*self.box_tree_root.borrow_mut() = Some(box_tree);
|
||||
*self.fragment_tree_root.borrow_mut() = Some(fragment_tree);
|
||||
}
|
||||
|
@ -1105,8 +1118,6 @@ impl LayoutThread {
|
|||
unsafe { element.unset_snapshot_flags() }
|
||||
}
|
||||
|
||||
layout_context = traversal.destroy();
|
||||
|
||||
// GC the rule tree if some heuristics are met.
|
||||
unsafe {
|
||||
layout_context.style_context.stylist.rule_tree().maybe_gc();
|
||||
|
|
|
@ -63,6 +63,7 @@ ${helpers.predefined_type(
|
|||
"Float",
|
||||
"computed::Float::None",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
servo_2020_pref="layout.2020.unimplemented",
|
||||
initial_specified_value="specified::Float::None",
|
||||
spec="https://drafts.csswg.org/css-box/#propdef-float",
|
||||
animation_value_type="discrete",
|
||||
|
|
|
@ -11,7 +11,6 @@ ${helpers.predefined_type(
|
|||
"font-family",
|
||||
"FontFamily",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
servo_2020_pref="layout.2020.unimplemented",
|
||||
initial_value="computed::FontFamily::serif()",
|
||||
animation_value_type="discrete",
|
||||
spec="https://drafts.csswg.org/css-fonts/#propdef-font-family",
|
||||
|
@ -22,7 +21,6 @@ ${helpers.predefined_type(
|
|||
"font-style",
|
||||
"FontStyle",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
servo_2020_pref="layout.2020.unimplemented",
|
||||
initial_value="computed::FontStyle::normal()",
|
||||
initial_specified_value="specified::FontStyle::normal()",
|
||||
animation_value_type="FontStyle",
|
||||
|
@ -40,7 +38,6 @@ ${helpers.single_keyword_system(
|
|||
"font-variant-caps",
|
||||
"normal small-caps",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
servo_2020_pref="layout.2020.unimplemented",
|
||||
extra_gecko_values="all-small-caps petite-caps all-petite-caps unicase titling-caps",
|
||||
gecko_constant_prefix="NS_FONT_VARIANT_CAPS",
|
||||
gecko_ffi_name="mFont.variantCaps",
|
||||
|
@ -54,7 +51,6 @@ ${helpers.predefined_type(
|
|||
"font-weight",
|
||||
"FontWeight",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
servo_2020_pref="layout.2020.unimplemented",
|
||||
initial_value="computed::FontWeight::normal()",
|
||||
initial_specified_value="specified::FontWeight::normal()",
|
||||
animation_value_type="Number",
|
||||
|
@ -97,7 +93,6 @@ ${helpers.predefined_type(
|
|||
"font-stretch",
|
||||
"FontStretch",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
servo_2020_pref="layout.2020.unimplemented",
|
||||
initial_value="computed::FontStretch::hundred()",
|
||||
initial_specified_value="specified::FontStretch::normal()",
|
||||
animation_value_type="Percentage",
|
||||
|
|
|
@ -21,7 +21,6 @@ ${helpers.predefined_type(
|
|||
"LineHeight",
|
||||
"computed::LineHeight::normal()",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
servo_2020_pref="layout.2020.unimplemented",
|
||||
animation_value_type="LineHeight",
|
||||
spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height",
|
||||
servo_restyle_damage="reflow"
|
||||
|
@ -167,7 +166,7 @@ ${helpers.predefined_type(
|
|||
"letter-spacing",
|
||||
"LetterSpacing",
|
||||
"computed::LetterSpacing::normal()",
|
||||
engines="gecko servo-2013",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
animation_value_type="ComputedValue",
|
||||
spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing",
|
||||
servo_restyle_damage="rebuild_and_reflow",
|
||||
|
@ -177,7 +176,7 @@ ${helpers.predefined_type(
|
|||
"word-spacing",
|
||||
"WordSpacing",
|
||||
"computed::WordSpacing::zero()",
|
||||
engines="gecko servo-2013",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
animation_value_type="ComputedValue",
|
||||
spec="https://drafts.csswg.org/css-text/#propdef-word-spacing",
|
||||
servo_restyle_damage="rebuild_and_reflow",
|
||||
|
@ -360,7 +359,7 @@ ${helpers.single_keyword(
|
|||
${helpers.single_keyword(
|
||||
"text-rendering",
|
||||
"auto optimizespeed optimizelegibility geometricprecision",
|
||||
engines="gecko servo-2013",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
gecko_enum_prefix="StyleTextRendering",
|
||||
animation_value_type="discrete",
|
||||
spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty",
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
<%helpers:shorthand
|
||||
name="font"
|
||||
engines="gecko servo-2013 servo-2020"
|
||||
servo_2020_pref="layout.2020.unimplemented"
|
||||
sub_properties="
|
||||
font-style
|
||||
font-variant-caps
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue