diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/canvas/canvas_data.rs | 175 | ||||
-rw-r--r-- | components/canvas/canvas_paint_thread.rs | 4 | ||||
-rw-r--r-- | components/fonts/font.rs | 18 | ||||
-rw-r--r-- | components/fonts/platform/freetype/font.rs | 25 | ||||
-rw-r--r-- | components/fonts/platform/macos/font.rs | 11 | ||||
-rw-r--r-- | components/fonts/platform/windows/font.rs | 23 | ||||
-rw-r--r-- | components/fonts/shaper.rs | 55 | ||||
-rw-r--r-- | components/script/canvas_state.rs | 33 | ||||
-rw-r--r-- | components/script/dom/canvasrenderingcontext2d.rs | 3 | ||||
-rw-r--r-- | components/script/dom/offscreencanvasrenderingcontext2d.rs | 3 | ||||
-rw-r--r-- | components/shared/canvas/canvas.rs | 17 |
11 files changed, 325 insertions, 42 deletions
diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index 68adda8883b..9c2b37110ea 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -7,15 +7,16 @@ use std::sync::Arc; use app_units::Au; use canvas_traits::canvas::*; -use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D}; +use euclid::default::{Box2D, Point2D, Rect, Size2D, Transform2D, Vector2D}; use euclid::point2; use fonts::{ - FontCacheThread, FontContext, FontMetrics, FontRef, GlyphStore, ShapingFlags, ShapingOptions, - LAST_RESORT_GLYPH_ADVANCE, + ByteIndex, FontBaseline, FontCacheThread, FontContext, FontGroup, FontMetrics, FontRef, + GlyphInfo, GlyphStore, ShapingFlags, ShapingOptions, LAST_RESORT_GLYPH_ADVANCE, }; use ipc_channel::ipc::{IpcSender, IpcSharedMemory}; use log::{debug, warn}; use num_traits::ToPrimitive; +use range::Range; use servo_arc::Arc as ServoArc; use style::color::AbsoluteColor; use style::properties::style_structs::Font as FontStyleStruct; @@ -277,6 +278,29 @@ pub struct TextRun { pub glyphs: Arc<GlyphStore>, } +impl TextRun { + fn bounding_box(&self) -> Rect<f32> { + let mut bounding_box = None; + let mut bounds_offset: f32 = 0.; + let glyph_ids = self + .glyphs + .iter_glyphs_for_byte_range(&Range::new(ByteIndex(0), self.glyphs.len())) + .map(GlyphInfo::id); + for glyph_id in glyph_ids { + let bounds = self.font.typographic_bounds(glyph_id); + let amount = Vector2D::new(bounds_offset, 0.); + let bounds = bounds.translate(amount); + let initiated_bbox = bounding_box.get_or_insert_with(|| { + let origin = Point2D::new(bounds.min_x(), 0.); + Box2D::new(origin, origin).to_rect() + }); + bounding_box = Some(initiated_bbox.union(&bounds)); + bounds_offset = bounds.max_x(); + } + bounding_box.unwrap_or_default() + } +} + // This defines required methods for a DrawTarget (currently only implemented for raqote). The // prototypes are derived from the now-removed Azure backend's methods. pub trait GenericDrawTarget { @@ -523,33 +547,7 @@ impl<'a> CanvasData<'a> { return; }; - let mut runs = Vec::new(); - let mut current_text_run = UnshapedTextRun::default(); - let mut current_text_run_start_index = 0; - for (index, character) in text.char_indices() { - // TODO: This should ultimately handle emoji variation selectors, but raqote does not yet - // have support for color glyphs. - let script = Script::from(character); - let font = font_group.find_by_codepoint(&self.font_context, character, None); - - if !current_text_run.script_and_font_compatible(script, &font) { - let previous_text_run = mem::replace( - &mut current_text_run, - UnshapedTextRun { - font: font.clone(), - script, - ..Default::default() - }, - ); - current_text_run_start_index = index; - runs.push(previous_text_run) - } - - current_text_run.string = - &text[current_text_run_start_index..index + character.len_utf8()]; - } - runs.push(current_text_run); - + let runs = self.build_unshaped_text_runs(&text, &mut font_group); // TODO: This doesn't do any kind of line layout at all. In particular, there needs // to be some alignment along a baseline and also support for bidi text. let shaped_runs: Vec<_> = runs @@ -617,6 +615,123 @@ impl<'a> CanvasData<'a> { self.fill_text_with_size(text, x, y, max_width, is_rtl, size.px() as f64); } + /// <https://html.spec.whatwg.org/multipage/#text-preparation-algorithm> + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-measuretext> + pub fn measure_text(&mut self, text: String) -> TextMetrics { + // > Step 2: Replace all ASCII whitespace in text with U+0020 SPACE characters. + let text = replace_ascii_whitespace(text); + let Some(ref font_style) = self.state.font_style else { + return TextMetrics::default(); + }; + + let font_group = self.font_context.font_group(font_style.clone()); + let mut font_group = font_group.write(); + let font = font_group + .first(&self.font_context) + .expect("couldn't find font"); + let ascent = font.metrics.ascent.to_f32_px(); + let descent = font.metrics.descent.to_f32_px(); + let runs = self.build_unshaped_text_runs(&text, &mut font_group); + + let shaped_runs: Vec<_> = runs + .into_iter() + .filter_map(UnshapedTextRun::to_shaped_text_run) + .collect(); + let total_advance = shaped_runs + .iter() + .map(|run| run.glyphs.total_advance()) + .sum::<Au>() + .to_f32_px(); + let bounding_box = shaped_runs + .iter() + .map(TextRun::bounding_box) + .reduce(|a, b| { + let amount = Vector2D::new(a.max_x(), 0.); + let bounding_box = b.translate(amount); + a.union(&bounding_box) + }) + .unwrap_or_default(); + + let FontBaseline { + ideographic_baseline, + alphabetic_baseline, + hanging_baseline, + } = match font.get_baseline() { + Some(baseline) => baseline, + None => FontBaseline { + hanging_baseline: ascent * HANGING_BASELINE_DEFAULT, + ideographic_baseline: -descent * IDEOGRAPHIC_BASELINE_DEFAULT, + alphabetic_baseline: 0., + }, + }; + + let anchor_x = match self.state.text_align { + TextAlign::End => total_advance, + TextAlign::Center => total_advance / 2., + TextAlign::Right => total_advance, + _ => 0., + }; + let anchor_y = match self.state.text_baseline { + TextBaseline::Top => ascent, + TextBaseline::Hanging => hanging_baseline, + TextBaseline::Ideographic => ideographic_baseline, + TextBaseline::Middle => (ascent - descent) / 2., + TextBaseline::Alphabetic => alphabetic_baseline, + TextBaseline::Bottom => -descent, + }; + + TextMetrics { + width: total_advance, + actual_boundingbox_left: anchor_x - bounding_box.min_x(), + actual_boundingbox_right: bounding_box.max_x() - anchor_x, + actual_boundingbox_ascent: bounding_box.max_y() - anchor_y, + actual_boundingbox_descent: anchor_y - bounding_box.min_y(), + font_boundingbox_ascent: ascent - anchor_y, + font_boundingbox_descent: descent + anchor_y, + em_height_ascent: ascent - anchor_y, + em_height_descent: descent + anchor_y, + hanging_baseline: hanging_baseline - anchor_y, + alphabetic_baseline: alphabetic_baseline - anchor_y, + ideographic_baseline: ideographic_baseline - anchor_y, + } + } + + fn build_unshaped_text_runs<'b>( + &self, + text: &'b str, + font_group: &mut FontGroup, + ) -> Vec<UnshapedTextRun<'b>> { + let mut runs = Vec::new(); + let mut current_text_run = UnshapedTextRun::default(); + let mut current_text_run_start_index = 0; + + for (index, character) in text.char_indices() { + // TODO: This should ultimately handle emoji variation selectors, but raqote does not yet + // have support for color glyphs. + let script = Script::from(character); + let font = font_group.find_by_codepoint(&self.font_context, character, None); + + if !current_text_run.script_and_font_compatible(script, &font) { + let previous_text_run = mem::replace( + &mut current_text_run, + UnshapedTextRun { + font: font.clone(), + script, + ..Default::default() + }, + ); + current_text_run_start_index = index; + runs.push(previous_text_run) + } + + current_text_run.string = + &text[current_text_run_start_index..index + character.len_utf8()]; + } + + runs.push(current_text_run); + runs + } + /// Find the *anchor_point* for the given parameters of a line of text. /// See <https://html.spec.whatwg.org/multipage/#text-preparation-algorithm>. fn find_anchor_point_for_line_of_text( diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index d4d2bb877c7..37ccace4592 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -234,6 +234,10 @@ impl<'a> CanvasPaintThread<'a> { Canvas2dMsg::Ellipse(ref center, radius_x, radius_y, rotation, start, end, ccw) => self .canvas(canvas_id) .ellipse(center, radius_x, radius_y, rotation, start, end, ccw), + Canvas2dMsg::MeasureText(text, sender) => { + let metrics = self.canvas(canvas_id).measure_text(text); + sender.send(metrics).unwrap(); + }, Canvas2dMsg::RestoreContext => self.canvas(canvas_id).restore_context_state(), Canvas2dMsg::SaveContext => self.canvas(canvas_id).save_context_state(), Canvas2dMsg::SetLineWidth(width) => self.canvas(canvas_id).set_line_width(width), diff --git a/components/fonts/font.rs b/components/fonts/font.rs index 719ec70f144..67236debef1 100644 --- a/components/fonts/font.rs +++ b/components/fonts/font.rs @@ -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 diff --git a/components/fonts/platform/freetype/font.rs b/components/fonts/platform/freetype/font.rs index 831ab717479..2f0fe23eb80 100644 --- a/components/fonts/platform/freetype/font.rs +++ b/components/fonts/platform/freetype/font.rs @@ -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 diff --git a/components/fonts/platform/macos/font.rs b/components/fonts/platform/macos/font.rs index 437950fbf4d..14e3382d5a2 100644 --- a/components/fonts/platform/macos/font.rs +++ b/components/fonts/platform/macos/font.rs @@ -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 { diff --git a/components/fonts/platform/windows/font.rs b/components/fonts/platform/windows/font.rs index 8dd2d78bb1f..2f1bb9c524a 100644 --- a/components/fonts/platform/windows/font.rs +++ b/components/fonts/platform/windows/font.rs @@ -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), + ) + } } diff --git a/components/fonts/shaper.rs b/components/fonts/shaper.rs index 72d47de28fb..f5dbb5b0c74 100644 --- a/components/fonts/shaper.rs +++ b/components/fonts/shaper.rs @@ -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. diff --git a/components/script/canvas_state.rs b/components/script/canvas_state.rs index b5b1a555f90..e3e43d032da 100644 --- a/components/script/canvas_state.rs +++ b/components/script/canvas_state.rs @@ -10,7 +10,7 @@ use std::sync::Arc; use canvas_traits::canvas::{ Canvas2dMsg, CanvasId, CanvasMsg, CompositionOrBlending, Direction, FillOrStrokeStyle, FillRule, LineCapStyle, LineJoinStyle, LinearGradientStyle, RadialGradientStyle, - RepetitionStyle, TextAlign, TextBaseline, + RepetitionStyle, TextAlign, TextBaseline, TextMetrics as CanvasTextMetrics, }; use cssparser::color::clamp_unit_f32; use cssparser::{Parser, ParserInput}; @@ -1030,11 +1030,34 @@ impl CanvasState { } // https://html.spec.whatwg.org/multipage/#textmetrics - pub fn measure_text(&self, global: &GlobalScope, _text: DOMString) -> DomRoot<TextMetrics> { - // FIXME: for now faking the implementation of MeasureText(). - // See https://github.com/servo/servo/issues/5411#issuecomment-533776291 + pub fn measure_text( + &self, + global: &GlobalScope, + canvas: Option<&HTMLCanvasElement>, + text: DOMString, + ) -> DomRoot<TextMetrics> { + if self.state.borrow().font_style.is_none() { + self.set_font(canvas, CanvasContextState::DEFAULT_FONT_STYLE.into()); + } + + let (sender, receiver) = ipc::channel::<CanvasTextMetrics>().unwrap(); + self.send_canvas_2d_msg(Canvas2dMsg::MeasureText(text.into(), sender)); + let metrics = receiver.recv().unwrap(); + TextMetrics::new( - global, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + global, + metrics.width.into(), + metrics.actual_boundingbox_left.into(), + metrics.actual_boundingbox_right.into(), + metrics.font_boundingbox_ascent.into(), + metrics.font_boundingbox_descent.into(), + metrics.actual_boundingbox_ascent.into(), + metrics.actual_boundingbox_descent.into(), + metrics.em_height_ascent.into(), + metrics.em_height_descent.into(), + metrics.hanging_baseline.into(), + metrics.alphabetic_baseline.into(), + metrics.ideographic_baseline.into(), ) } diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 1f4c8bd7152..5aac664e480 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -292,7 +292,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { // https://html.spec.whatwg.org/multipage/#textmetrics fn MeasureText(&self, text: DOMString) -> DomRoot<TextMetrics> { - self.canvas_state.measure_text(&self.global(), text) + self.canvas_state + .measure_text(&self.global(), self.canvas.as_deref(), text) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-font diff --git a/components/script/dom/offscreencanvasrenderingcontext2d.rs b/components/script/dom/offscreencanvasrenderingcontext2d.rs index bbf2fb384ae..a71d3158297 100644 --- a/components/script/dom/offscreencanvasrenderingcontext2d.rs +++ b/components/script/dom/offscreencanvasrenderingcontext2d.rs @@ -256,7 +256,8 @@ impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContex // https://html.spec.whatwg.org/multipage/#textmetrics fn MeasureText(&self, text: DOMString) -> DomRoot<TextMetrics> { - self.canvas_state.measure_text(&self.global(), text) + self.canvas_state + .measure_text(&self.global(), self.htmlcanvas.as_deref(), text) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-font diff --git a/components/shared/canvas/canvas.rs b/components/shared/canvas/canvas.rs index 43d21fd58fe..d1f59ebea3b 100644 --- a/components/shared/canvas/canvas.rs +++ b/components/shared/canvas/canvas.rs @@ -58,6 +58,7 @@ pub enum Canvas2dMsg { IsPointInPath(f64, f64, FillRule, IpcSender<bool>), LineTo(Point2D<f32>), MoveTo(Point2D<f32>), + MeasureText(String, IpcSender<TextMetrics>), PutImageData(Rect<u64>, IpcBytesReceiver), QuadraticCurveTo(Point2D<f32>, Point2D<f32>), Rect(Rect<f32>), @@ -474,3 +475,19 @@ impl FromStr for Direction { } } } + +#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)] +pub struct TextMetrics { + pub width: f32, + pub actual_boundingbox_left: f32, + pub actual_boundingbox_right: f32, + pub actual_boundingbox_ascent: f32, + pub actual_boundingbox_descent: f32, + pub font_boundingbox_ascent: f32, + pub font_boundingbox_descent: f32, + pub em_height_ascent: f32, + pub em_height_descent: f32, + pub hanging_baseline: f32, + pub alphabetic_baseline: f32, + pub ideographic_baseline: f32, +} |