mirror of
https://github.com/servo/servo
synced 2026-04-25 17:15:48 +02:00
Run both shapers at once
Signed-off-by: Nico Burns <nico@nicoburns.com>
This commit is contained in:
@@ -14,7 +14,7 @@ test = true
|
||||
doctest = false
|
||||
|
||||
[features]
|
||||
default = ["harfrust"]
|
||||
default = ["harfrust", "harfbuzz"]
|
||||
harfbuzz = ["dep:harfbuzz-sys"]
|
||||
harfrust = ["dep:harfrust"]
|
||||
tracing = ["dep:tracing"]
|
||||
|
||||
@@ -881,12 +881,23 @@ impl FontFamilyDescriptor {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct FontBaseline {
|
||||
pub ideographic_baseline: f32,
|
||||
pub alphabetic_baseline: f32,
|
||||
pub hanging_baseline: f32,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for FontBaseline {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{} {} {}",
|
||||
self.ideographic_baseline, self.alphabetic_baseline, self.hanging_baseline
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a mapping array `mapping` and a value, map that value onto
|
||||
/// the value specified by the array. For instance, for FontConfig
|
||||
/// values of weights, we would map these onto the CSS [0..1000] range
|
||||
|
||||
113
components/fonts/shapers/both.rs
Normal file
113
components/fonts/shapers/both.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
use std::io::Write as _;
|
||||
|
||||
use app_units::Au;
|
||||
|
||||
use super::harfbuzz::ShapedGlyphData as HarfBuzzShapedGlyphData;
|
||||
use super::harfrust::ShapedGlyphData as HarfRustShapedGlyphData;
|
||||
use super::{HarfBuzzShapedGlyphData as THarfBuzzShapedGlyphData, HarfBuzzShaper, HarfRustShaper};
|
||||
use crate::{Font, FontBaseline, GlyphStore, ShapingOptions};
|
||||
|
||||
pub(crate) struct ShapedGlyphData {
|
||||
buzz: HarfBuzzShapedGlyphData,
|
||||
rust: HarfRustShapedGlyphData,
|
||||
}
|
||||
|
||||
pub(crate) struct Shaper {
|
||||
buzz: HarfBuzzShaper,
|
||||
rust: HarfRustShaper,
|
||||
}
|
||||
|
||||
impl Shaper {
|
||||
pub(crate) fn new(font: &Font) -> Self {
|
||||
Self {
|
||||
buzz: HarfBuzzShaper::new(font),
|
||||
rust: HarfRustShaper::new(font),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn shaped_glyph_data(
|
||||
&self,
|
||||
text: &str,
|
||||
options: &ShapingOptions,
|
||||
) -> ShapedGlyphData {
|
||||
ShapedGlyphData {
|
||||
buzz: self.buzz.shaped_glyph_data(text, options),
|
||||
rust: self.rust.shaped_glyph_data(text, options),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shape_text(&self, text: &str, options: &ShapingOptions, glyphs: &mut GlyphStore) {
|
||||
let glyph_data = self.shaped_glyph_data(text, options);
|
||||
let font = self.buzz.font();
|
||||
|
||||
let equal = shape_data_eq(&glyph_data.buzz, &glyph_data.rust);
|
||||
if !equal {
|
||||
println!("SHAPING DATA DIFFERENT:");
|
||||
println!("Input text:");
|
||||
println!("{text}");
|
||||
println!("Buzz:");
|
||||
log_shape_data(&glyph_data.buzz);
|
||||
println!("Rust:");
|
||||
log_shape_data(&glyph_data.rust);
|
||||
println!("========================");
|
||||
}
|
||||
|
||||
super::shape_text_harfbuzz(&glyph_data.rust, font, text, options, glyphs);
|
||||
}
|
||||
|
||||
pub fn baseline(&self) -> Option<FontBaseline> {
|
||||
let buzz_baseline = self.buzz.baseline();
|
||||
let rust_baseline = self.rust.baseline();
|
||||
|
||||
// Debug log
|
||||
let equal = buzz_baseline == rust_baseline;
|
||||
let eq_word = if equal { "same" } else { "diff" };
|
||||
println!(
|
||||
"BL ({eq_word}) C: {:?} | R: {:?}",
|
||||
buzz_baseline, rust_baseline
|
||||
);
|
||||
|
||||
rust_baseline
|
||||
}
|
||||
}
|
||||
|
||||
fn shape_data_eq(a: &impl THarfBuzzShapedGlyphData, b: &impl THarfBuzzShapedGlyphData) -> bool {
|
||||
if a.len() != b.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut a_y_pos = Au::new(0);
|
||||
let mut b_y_pos = Au::new(0);
|
||||
for i in 0..a.len() {
|
||||
if a.byte_offset_of_glyph(i) != b.byte_offset_of_glyph(i) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if a.entry_for_glyph(i, &mut a_y_pos) != b.entry_for_glyph(i, &mut b_y_pos) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn log_shape_data(data: &impl THarfBuzzShapedGlyphData) {
|
||||
let mut out = std::io::stdout().lock();
|
||||
writeln!(&mut out, "len: {}", data.len()).unwrap();
|
||||
writeln!(&mut out, "offsets:").unwrap();
|
||||
for i in 0..data.len() {
|
||||
write!(&mut out, "{} ", data.byte_offset_of_glyph(i)).unwrap();
|
||||
}
|
||||
writeln!(&mut out).unwrap();
|
||||
writeln!(&mut out, "entries:").unwrap();
|
||||
let mut y_pos = Au::new(0);
|
||||
for i in 0..data.len() {
|
||||
let entry = data.entry_for_glyph(i, &mut y_pos);
|
||||
write!(&mut out, "cp: {} ad: {} ", entry.codepoint, entry.advance.0).unwrap();
|
||||
match entry.offset {
|
||||
Some(offset) => write!(&mut out, "Some(x:{}, y:{})", offset.x.0, offset.y.0).unwrap(),
|
||||
None => write!(&mut out, "None").unwrap(),
|
||||
};
|
||||
writeln!(&mut out).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,11 @@ impl Shaper {
|
||||
}
|
||||
|
||||
/// Calculate the layout metrics associated with the given text with the [`Shaper`]s font.
|
||||
fn shaped_glyph_data(&self, text: &str, options: &ShapingOptions) -> ShapedGlyphData {
|
||||
pub(crate) fn shaped_glyph_data(
|
||||
&self,
|
||||
text: &str,
|
||||
options: &ShapingOptions,
|
||||
) -> ShapedGlyphData {
|
||||
unsafe {
|
||||
let hb_buffer: *mut hb_buffer_t = hb_buffer_create();
|
||||
hb_buffer_set_direction(
|
||||
@@ -268,7 +272,7 @@ impl Shaper {
|
||||
}
|
||||
}
|
||||
|
||||
fn font(&self) -> &Font {
|
||||
pub(crate) fn font(&self) -> &Font {
|
||||
unsafe { &(*self.font) }
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,11 @@ impl Shaper {
|
||||
}
|
||||
|
||||
impl Shaper {
|
||||
fn shaped_glyph_data(&self, text: &str, options: &crate::ShapingOptions) -> ShapedGlyphData {
|
||||
pub(crate) fn shaped_glyph_data(
|
||||
&self,
|
||||
text: &str,
|
||||
options: &crate::ShapingOptions,
|
||||
) -> ShapedGlyphData {
|
||||
let mut buffer = UnicodeBuffer::new();
|
||||
|
||||
// Set direction
|
||||
@@ -179,7 +183,7 @@ impl Shaper {
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
fn font(&self) -> &Font {
|
||||
pub(crate) fn font(&self) -> &Font {
|
||||
// SAFETY: the font actually owns this shaper so it cannot have been dropped
|
||||
unsafe { &(*self.font) }
|
||||
}
|
||||
|
||||
@@ -16,12 +16,24 @@ use crate::{Font, GlyphData, GlyphId, GlyphStore, ShapingOptions, advance_for_sh
|
||||
#[cfg(feature = "harfbuzz")]
|
||||
mod harfbuzz;
|
||||
#[cfg(feature = "harfbuzz")]
|
||||
pub(crate) use harfbuzz::Shaper;
|
||||
pub(crate) use harfbuzz::Shaper as HarfBuzzShaper;
|
||||
|
||||
#[cfg(feature = "harfrust")]
|
||||
mod harfrust;
|
||||
#[cfg(all(feature = "harfrust", not(feature = "harfbuzz")))]
|
||||
pub(crate) use harfrust::Shaper;
|
||||
#[cfg(feature = "harfrust")]
|
||||
pub(crate) use harfrust::Shaper as HarfRustShaper;
|
||||
|
||||
#[cfg(all(feature = "harfbuzz", feature = "harfrust"))]
|
||||
mod both;
|
||||
#[cfg(all(feature = "harfbuzz", feature = "harfrust"))]
|
||||
pub(crate) use BothShaper as Shaper;
|
||||
// Configure default shaper (actually used)
|
||||
#[cfg(all(feature = "harfbuzz", not(feature = "harfrust")))]
|
||||
pub(crate) use HarfBuzzShaper as Shaper;
|
||||
#[cfg(all(not(feature = "harfbuzz"), feature = "harfrust"))]
|
||||
pub(crate) use HarfRustShaper as Shaper;
|
||||
#[cfg(all(feature = "harfbuzz", feature = "harfrust"))]
|
||||
pub(crate) use both::Shaper as BothShaper;
|
||||
|
||||
const NO_GLYPH: i32 = -1;
|
||||
|
||||
@@ -39,6 +51,7 @@ fn unicode_script_to_iso15924_tag(script: unicode_script::Script) -> u32 {
|
||||
u32::from_be_bytes(bytes)
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct ShapedGlyphEntry {
|
||||
codepoint: GlyphId,
|
||||
advance: Au,
|
||||
|
||||
Reference in New Issue
Block a user