aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorCristian Brinza <cristianb@gmail.com>2024-08-19 13:47:09 +0300
committerGitHub <noreply@github.com>2024-08-19 10:47:09 +0000
commit2a31fddc0b6f3ae89bd36cff3be1062e54c4a64c (patch)
treed4cb341b0a1f6c563b1128a63fbf1b02436ed7f3 /components
parentd59a7f62f8f49c810a6d42b154d39bb8440eb11e (diff)
downloadservo-2a31fddc0b6f3ae89bd36cff3be1062e54c4a64c.tar.gz
servo-2a31fddc0b6f3ae89bd36cff3be1062e54c4a64c.zip
Refactor `GlyphStore::iter_glyphs_for_byte_range` without recursion (#33074)
* Implement DoubleEndedIterator for EachIndex Signed-off-by: crbrz <cristianb@gmail.com> * Refactor GlyphStore::iter_glyphs_for_byte_range without recursion Signed-off-by: crbrz <cristianb@gmail.com> * Update WPT result Signed-off-by: crbrz <cristianb@gmail.com> * Update WPT legacy result Signed-off-by: crbrz <cristianb@gmail.com> --------- Signed-off-by: crbrz <cristianb@gmail.com>
Diffstat (limited to 'components')
-rw-r--r--components/fonts/Cargo.toml1
-rw-r--r--components/fonts/glyph.rs123
-rw-r--r--components/range/lib.rs13
3 files changed, 45 insertions, 92 deletions
diff --git a/components/fonts/Cargo.toml b/components/fonts/Cargo.toml
index 8b976b4f9b8..78e4453ea13 100644
--- a/components/fonts/Cargo.toml
+++ b/components/fonts/Cargo.toml
@@ -25,6 +25,7 @@ fontsan = { git = "https://github.com/servo/fontsan" }
fonts_traits = { workspace = true }
harfbuzz-sys = "0.6.1"
ipc-channel = { workspace = true }
+itertools = { workspace = true }
libc = { workspace = true }
log = { workspace = true }
malloc_size_of = { workspace = true }
diff --git a/components/fonts/glyph.rs b/components/fonts/glyph.rs
index 450478ea5ae..517afebfc64 100644
--- a/components/fonts/glyph.rs
+++ b/components/fonts/glyph.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cmp::{Ordering, PartialOrd};
+use std::iter::once;
use std::sync::Arc;
use std::vec::Vec;
use std::{fmt, mem};
@@ -10,9 +11,10 @@ use std::{fmt, mem};
use app_units::Au;
use euclid::default::Point2D;
pub use fonts_traits::ByteIndex;
+use itertools::Either;
use log::debug;
use malloc_size_of_derive::MallocSizeOf;
-use range::{self, EachIndex, Range, RangeIndex};
+use range::{self, Range, RangeIndex};
use serde::{Deserialize, Serialize};
/// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
@@ -588,7 +590,10 @@ impl<'a> GlyphStore {
}
#[inline]
- pub fn iter_glyphs_for_byte_range(&'a self, range: &Range<ByteIndex>) -> GlyphIterator<'a> {
+ pub fn iter_glyphs_for_byte_range(
+ &self,
+ range: &Range<ByteIndex>,
+ ) -> impl Iterator<Item = GlyphInfo> {
if range.begin() >= self.len() {
panic!("iter_glyphs_for_range: range.begin beyond length!");
}
@@ -596,16 +601,31 @@ impl<'a> GlyphStore {
panic!("iter_glyphs_for_range: range.end beyond length!");
}
- GlyphIterator {
- store: self,
- byte_index: if self.is_rtl {
- range.end()
+ let range_it = if self.is_rtl {
+ Either::Left(range.each_index().rev())
+ } else {
+ Either::Right(range.each_index())
+ };
+ range_it.into_iter().flat_map(move |range_idx| {
+ let entry = self.entry_buffer[range_idx.to_usize()];
+ let result = if entry.is_simple() {
+ Either::Left(once(GlyphInfo::Simple(self, range_idx)))
} else {
- range.begin() - ByteIndex(1)
- },
- byte_range: *range,
- glyph_range: None,
- }
+ // Slow path for complex glyphs
+ let glyphs = self.detail_store.detailed_glyphs_for_entry(
+ range_idx,
+ self.entry_buffer[range_idx.to_usize()].glyph_count(),
+ );
+
+ let complex_glyph_range =
+ range::each_index(ByteIndex(0), ByteIndex(glyphs.len() as isize));
+ Either::Right(complex_glyph_range.map(move |i| {
+ GlyphInfo::Detail(self, range_idx, i.get() as u16 /* ??? */)
+ }))
+ };
+
+ result.into_iter()
+ })
}
// Scan the glyphs for a given range until we reach a given advance. Returns the index
@@ -707,87 +727,6 @@ impl fmt::Debug for GlyphStore {
}
}
-/// An iterator over the glyphs in a byte range in a `GlyphStore`.
-pub struct GlyphIterator<'a> {
- store: &'a GlyphStore,
- byte_index: ByteIndex,
- byte_range: Range<ByteIndex>,
- glyph_range: Option<EachIndex<ByteIndex>>,
-}
-
-impl<'a> GlyphIterator<'a> {
- // Slow path when there is a glyph range.
- #[inline(never)]
- fn next_glyph_range(&mut self) -> Option<GlyphInfo<'a>> {
- match self.glyph_range.as_mut().unwrap().next() {
- Some(j) => {
- Some(GlyphInfo::Detail(
- self.store,
- self.byte_index,
- j.get() as u16, /* ??? */
- ))
- },
- None => {
- // No more glyphs for current character. Try to get another.
- self.glyph_range = None;
- self.next()
- },
- }
- }
-
- // Slow path when there is a complex glyph.
- #[inline(never)]
- fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: ByteIndex) -> Option<GlyphInfo<'a>> {
- let glyphs = self
- .store
- .detail_store
- .detailed_glyphs_for_entry(i, entry.glyph_count());
- self.glyph_range = Some(range::each_index(
- ByteIndex(0),
- ByteIndex(glyphs.len() as isize),
- ));
- self.next()
- }
-}
-
-impl<'a> Iterator for GlyphIterator<'a> {
- type Item = GlyphInfo<'a>;
-
- // I tried to start with something simpler and apply FlatMap, but the
- // inability to store free variables in the FlatMap struct was problematic.
- //
- // This function consists of the fast path and is designed to be inlined into its caller. The
- // slow paths, which should not be inlined, are `next_glyph_range()` and
- // `next_complex_glyph()`.
- #[inline(always)]
- fn next(&mut self) -> Option<GlyphInfo<'a>> {
- // Would use 'match' here but it borrows contents in a way that interferes with mutation.
- if self.glyph_range.is_some() {
- return self.next_glyph_range();
- }
-
- // No glyph range. Look at next byte.
- self.byte_index = self.byte_index +
- if self.store.is_rtl {
- ByteIndex(-1)
- } else {
- ByteIndex(1)
- };
- let i = self.byte_index;
- if !self.byte_range.contains(i) {
- return None;
- }
- debug_assert!(i < self.store.len());
- let entry = self.store.entry_buffer[i.to_usize()];
- if entry.is_simple() {
- Some(GlyphInfo::Simple(self.store, i))
- } else {
- // Fall back to the slow path.
- self.next_complex_glyph(&entry, i)
- }
- }
-}
-
/// A single series of glyphs within a text run.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GlyphRun {
diff --git a/components/range/lib.rs b/components/range/lib.rs
index 8c5ca095f53..24c7231946c 100644
--- a/components/range/lib.rs
+++ b/components/range/lib.rs
@@ -193,6 +193,19 @@ impl<I: RangeIndex> Iterator for EachIndex<I> {
}
}
+impl<I: RangeIndex> DoubleEndedIterator for EachIndex<I> {
+ #[inline]
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.start < self.stop {
+ let next = self.stop - I::one();
+ self.stop = next;
+ Some(next)
+ } else {
+ None
+ }
+ }
+}
+
impl<I: RangeIndex> Range<I> {
/// Create a new range from beginning and length offsets. This could be
/// denoted as `[begin, begin + length)`.