enhance: Implement CanvasRenderingContext2D.measureText (#32704)

Signed-off-by: Chocolate Pie <106949016+chocolate-pie@users.noreply.github.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Chocolate Pie 2024-07-18 04:20:18 +09:00 committed by GitHub
parent d82232d549
commit 1223335547
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 325 additions and 51 deletions

View file

@ -7,13 +7,14 @@ use std::sync::Arc;
use std::{mem, ptr};
use app_units::Au;
use euclid::default::{Point2D, Rect, Size2D};
use freetype_sys::{
ft_sfnt_head, ft_sfnt_os2, FT_Byte, FT_Done_Face, FT_Error, FT_F26Dot6, FT_Face, FT_Fixed,
FT_Get_Char_Index, FT_Get_Kerning, FT_Get_Sfnt_Table, FT_GlyphSlot, FT_Int32, FT_Load_Glyph,
FT_Long, FT_MulFix, FT_New_Memory_Face, FT_Pos, FT_Select_Size, FT_Set_Char_Size, FT_Short,
FT_SizeRec, FT_Size_Metrics, FT_UInt, FT_ULong, FT_UShort, FT_Vector, FT_FACE_FLAG_COLOR,
FT_FACE_FLAG_FIXED_SIZES, FT_FACE_FLAG_SCALABLE, FT_KERNING_DEFAULT, FT_LOAD_COLOR,
FT_LOAD_DEFAULT, FT_STYLE_FLAG_ITALIC, TT_OS2,
FT_LOAD_DEFAULT, FT_LOAD_NO_HINTING, FT_STYLE_FLAG_ITALIC, TT_OS2,
};
use log::debug;
use parking_lot::ReentrantMutex;
@ -388,6 +389,28 @@ impl PlatformFontMethods for PlatformFont {
}
}
fn typographic_bounds(&self, glyph_id: GlyphId) -> Rect<f32> {
let face = self.face.lock();
assert!(!face.is_null());
let load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
let result = unsafe { FT_Load_Glyph(*face, glyph_id as FT_UInt, load_flags) };
if 0 != result {
debug!("Unable to load glyph {}. reason: {:?}", glyph_id, result);
return Rect::default();
}
let metrics = unsafe { &(*(**face).glyph).metrics };
Rect::new(
Point2D::new(
metrics.horiBearingX as f32,
(metrics.horiBearingY - metrics.height) as f32,
),
Size2D::new(metrics.width as f32, metrics.height as f32),
) * (1. / 64.)
}
fn webrender_font_instance_flags(&self) -> FontInstanceFlags {
// On other platforms, we only pass this when we know that we are loading a font with
// color characters, but not passing this flag simply *prevents* WebRender from

View file

@ -17,6 +17,7 @@ use core_text::font::CTFont;
use core_text::font_descriptor::{
kCTFontDefaultOrientation, CTFontTraits, SymbolicTraitAccessors, TraitAccessors,
};
use euclid::default::{Point2D, Rect, Size2D};
use log::debug;
use style::values::computed::font::{FontStretch, FontStyle, FontWeight};
use webrender_api::FontInstanceFlags;
@ -325,6 +326,16 @@ impl PlatformFontMethods for PlatformFont {
}
FontInstanceFlags::empty()
}
fn typographic_bounds(&self, glyph_id: GlyphId) -> Rect<f32> {
let rect = self
.ctfont
.get_bounding_rects_for_glyphs(kCTFontDefaultOrientation, &[glyph_id as u16]);
Rect::new(
Point2D::new(rect.origin.x as f32, rect.origin.y as f32),
Size2D::new(rect.size.width as f32, rect.size.height as f32),
)
}
}
pub(super) trait CoreTextFontTraitsMapping {

View file

@ -14,6 +14,7 @@ use std::sync::Arc;
use app_units::Au;
use dwrote::{FontFace, FontFile};
use euclid::default::{Point2D, Rect, Size2D};
use log::{debug, warn};
use style::computed_values::font_stretch::T as StyleFontStretch;
use style::computed_values::font_weight::T as StyleFontWeight;
@ -273,4 +274,26 @@ impl PlatformFontMethods for PlatformFont {
fn webrender_font_instance_flags(&self) -> FontInstanceFlags {
FontInstanceFlags::empty()
}
fn typographic_bounds(&self, glyph_id: GlyphId) -> Rect<f32> {
let metrics = self
.face
.get_design_glyph_metrics(&[glyph_id as u16], false);
let metrics = &metrics[0];
let advance_width = metrics.advanceWidth as f32;
let advance_height = metrics.advanceHeight as f32;
let left_side_bearing = metrics.leftSideBearing as f32;
let right_side_bearing = metrics.rightSideBearing as f32;
let top_side_bearing = metrics.topSideBearing as f32;
let bottom_side_bearing = metrics.bottomSideBearing as f32;
let vertical_origin_y = metrics.verticalOriginY as f32;
let y_offset = vertical_origin_y + bottom_side_bearing - advance_height;
let width = advance_width - (left_side_bearing + right_side_bearing);
let height = advance_height - (top_side_bearing + bottom_side_bearing);
Rect::new(
Point2D::new(left_side_bearing, y_offset),
Size2D::new(width, height),
)
}
}