diff options
-rw-r--r-- | Cargo.lock | 4 | ||||
-rw-r--r-- | components/layout_2020/Cargo.toml | 4 | ||||
-rw-r--r-- | components/layout_2020/display_list.rs | 55 | ||||
-rw-r--r-- | components/layout_2020/flow/inline.rs | 140 | ||||
-rw-r--r-- | components/layout_2020/fragments.rs | 14 | ||||
-rw-r--r-- | components/layout_2020/lib.rs | 1 | ||||
-rw-r--r-- | components/style/properties/longhands/font.mako.rs | 5 | ||||
-rw-r--r-- | components/style/properties/longhands/inherited_text.mako.rs | 7 | ||||
-rw-r--r-- | components/style/properties/shorthands/font.mako.rs | 1 |
9 files changed, 210 insertions, 21 deletions
diff --git a/Cargo.lock b/Cargo.lock index c216acf7031..a501e46e194 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", ] diff --git a/components/layout_2020/Cargo.toml b/components/layout_2020/Cargo.toml index 69b0bea014e..f7167b638d5 100644 --- a/components/layout_2020/Cargo.toml +++ b/components/layout_2020/Cargo.toml @@ -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"]} diff --git a/components/layout_2020/display_list.rs b/components/layout_2020/display_list.rs index c153b04294c..5dc5ecb96ad 100644 --- a/components/layout_2020/display_list.rs +++ b/components/layout_2020/display_list.rs @@ -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 +} diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 11bb82eef8e..8ff10b24aec 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -5,7 +5,9 @@ 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; @@ -286,7 +288,139 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> { } impl TextRun { - fn layout(&self, _layout_context: &LayoutContext, _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; + + 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; + } + } + // 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 = font_size * 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: 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(); + } + } } } diff --git a/components/layout_2020/fragments.rs b/components/layout_2020/fragments.rs index ceb2fdf7971..a0ea097abb6 100644 --- a/components/layout_2020/fragments.rs +++ b/components/layout_2020/fragments.rs @@ -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 { diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index b25d8837581..c0892553f35 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -7,6 +7,7 @@ #![allow(unused_imports)] #![allow(unused_variables)] #![deny(unsafe_code)] +#![feature(exact_size_is_empty)] #[macro_use] extern crate serde; diff --git a/components/style/properties/longhands/font.mako.rs b/components/style/properties/longhands/font.mako.rs index b4b2ab0598c..7e0bff6fbbe 100644 --- a/components/style/properties/longhands/font.mako.rs +++ b/components/style/properties/longhands/font.mako.rs @@ -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", diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs index 18f5c466d1a..428b40a101f 100644 --- a/components/style/properties/longhands/inherited_text.mako.rs +++ b/components/style/properties/longhands/inherited_text.mako.rs @@ -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", diff --git a/components/style/properties/shorthands/font.mako.rs b/components/style/properties/shorthands/font.mako.rs index e3b44d86a36..1feed113875 100644 --- a/components/style/properties/shorthands/font.mako.rs +++ b/components/style/properties/shorthands/font.mako.rs @@ -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 |