mirror of
https://github.com/servo/servo.git
synced 2025-08-09 15:35:34 +01:00
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:
parent
d82232d549
commit
1223335547
14 changed files with 325 additions and 51 deletions
|
@ -49,6 +49,7 @@ pub const KERN: u32 = ot_tag!('k', 'e', 'r', 'n');
|
|||
pub const SBIX: u32 = ot_tag!('s', 'b', 'i', 'x');
|
||||
pub const CBDT: u32 = ot_tag!('C', 'B', 'D', 'T');
|
||||
pub const COLR: u32 = ot_tag!('C', 'O', 'L', 'R');
|
||||
pub const BASE: u32 = ot_tag!('B', 'A', 'S', 'E');
|
||||
|
||||
pub const LAST_RESORT_GLYPH_ADVANCE: FractionalPixel = 10.0;
|
||||
|
||||
|
@ -89,6 +90,7 @@ pub trait PlatformFontMethods: Sized {
|
|||
fn can_do_fast_shaping(&self) -> bool;
|
||||
fn metrics(&self) -> FontMetrics;
|
||||
fn table_for_tag(&self, _: FontTableTag) -> Option<FontTable>;
|
||||
fn typographic_bounds(&self, _: GlyphId) -> Rect<f32>;
|
||||
|
||||
/// Get the necessary [`FontInstanceFlags`]` for this font.
|
||||
fn webrender_font_instance_flags(&self) -> FontInstanceFlags;
|
||||
|
@ -464,6 +466,16 @@ impl Font {
|
|||
cache.glyph_advances.insert(glyph_id, new_width);
|
||||
new_width
|
||||
}
|
||||
|
||||
pub fn typographic_bounds(&self, glyph_id: GlyphId) -> Rect<f32> {
|
||||
self.handle.typographic_bounds(glyph_id)
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn get_baseline(&self) -> Option<FontBaseline> {
|
||||
let this = self as *const Font;
|
||||
unsafe { self.shaper.get_or_init(|| Shaper::new(this)).get_baseline() }
|
||||
}
|
||||
}
|
||||
|
||||
pub type FontRef = Arc<Font>;
|
||||
|
@ -805,6 +817,12 @@ impl FontFamilyDescriptor {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct FontBaseline {
|
||||
pub ideographic_baseline: f32,
|
||||
pub alphabetic_baseline: f32,
|
||||
pub hanging_baseline: f32,
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,20 +19,24 @@ use harfbuzz_sys::{
|
|||
hb_face_create_for_tables, hb_face_destroy, hb_face_t, hb_feature_t, hb_font_create,
|
||||
hb_font_destroy, hb_font_funcs_create, hb_font_funcs_set_glyph_h_advance_func,
|
||||
hb_font_funcs_set_nominal_glyph_func, hb_font_funcs_t, hb_font_set_funcs, hb_font_set_ppem,
|
||||
hb_font_set_scale, hb_font_t, hb_glyph_info_t, hb_glyph_position_t, hb_position_t, hb_shape,
|
||||
hb_tag_t, HB_DIRECTION_LTR, HB_DIRECTION_RTL, HB_MEMORY_MODE_READONLY,
|
||||
hb_font_set_scale, hb_font_t, hb_glyph_info_t, hb_glyph_position_t, hb_ot_layout_get_baseline,
|
||||
hb_position_t, hb_shape, hb_tag_t, HB_DIRECTION_LTR, HB_DIRECTION_RTL, HB_MEMORY_MODE_READONLY,
|
||||
HB_OT_LAYOUT_BASELINE_TAG_HANGING, HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
|
||||
HB_OT_LAYOUT_BASELINE_TAG_ROMAN,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use log::debug;
|
||||
|
||||
use crate::platform::font::FontTable;
|
||||
use crate::{
|
||||
fixed_to_float, float_to_fixed, ot_tag, ByteIndex, Font, FontTableMethods, FontTableTag,
|
||||
GlyphData, GlyphId, GlyphStore, ShapingFlags, ShapingOptions, KERN,
|
||||
fixed_to_float, float_to_fixed, ot_tag, ByteIndex, Font, FontBaseline, FontTableMethods,
|
||||
FontTableTag, GlyphData, GlyphId, GlyphStore, ShapingFlags, ShapingOptions, BASE, KERN,
|
||||
};
|
||||
|
||||
const NO_GLYPH: i32 = -1;
|
||||
const LIGA: u32 = ot_tag!('l', 'i', 'g', 'a');
|
||||
const HB_OT_TAG_DEFAULT_SCRIPT: u32 = ot_tag!('D', 'F', 'L', 'T');
|
||||
const HB_OT_TAG_DEFAULT_LANGUAGE: u32 = ot_tag!('d', 'f', 'l', 't');
|
||||
|
||||
pub struct ShapedGlyphData {
|
||||
count: usize,
|
||||
|
@ -606,6 +610,49 @@ impl Shaper {
|
|||
|
||||
advance
|
||||
}
|
||||
|
||||
pub unsafe fn get_baseline(&self) -> Option<FontBaseline> {
|
||||
if (*self.font).table_for_tag(BASE).is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut hanging_baseline = 0;
|
||||
let mut alphabetic_baseline = 0;
|
||||
let mut ideographic_baseline = 0;
|
||||
|
||||
hb_ot_layout_get_baseline(
|
||||
self.hb_font,
|
||||
HB_OT_LAYOUT_BASELINE_TAG_ROMAN,
|
||||
HB_DIRECTION_LTR,
|
||||
HB_OT_TAG_DEFAULT_SCRIPT,
|
||||
HB_OT_TAG_DEFAULT_LANGUAGE,
|
||||
&mut alphabetic_baseline as *mut _,
|
||||
);
|
||||
|
||||
hb_ot_layout_get_baseline(
|
||||
self.hb_font,
|
||||
HB_OT_LAYOUT_BASELINE_TAG_HANGING,
|
||||
HB_DIRECTION_LTR,
|
||||
HB_OT_TAG_DEFAULT_SCRIPT,
|
||||
HB_OT_TAG_DEFAULT_LANGUAGE,
|
||||
&mut hanging_baseline as *mut _,
|
||||
);
|
||||
|
||||
hb_ot_layout_get_baseline(
|
||||
self.hb_font,
|
||||
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT,
|
||||
HB_DIRECTION_LTR,
|
||||
HB_OT_TAG_DEFAULT_SCRIPT,
|
||||
HB_OT_TAG_DEFAULT_LANGUAGE,
|
||||
&mut ideographic_baseline as *mut _,
|
||||
);
|
||||
|
||||
Some(FontBaseline {
|
||||
ideographic_baseline: Shaper::fixed_to_float(ideographic_baseline) as f32,
|
||||
alphabetic_baseline: Shaper::fixed_to_float(alphabetic_baseline) as f32,
|
||||
hanging_baseline: Shaper::fixed_to_float(hanging_baseline) as f32,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Callbacks from Harfbuzz when font map and glyph advance lookup needed.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue