diff options
author | kaiakz <kaiakx@yandex.com> | 2020-02-15 20:52:51 +0800 |
---|---|---|
committer | kaiakz <kaiakx@yandex.com> | 2020-03-19 15:40:14 +0800 |
commit | 0d0ac986b7637185c22920b2f9c14afdb09aa940 (patch) | |
tree | be2b95883de91b17bdef57c0c325457ac597917d /components/canvas/raqote_backend.rs | |
parent | 2b0a48f291bf6968ce9d13822fd242d46f4f0412 (diff) | |
download | servo-0d0ac986b7637185c22920b2f9c14afdb09aa940.tar.gz servo-0d0ac986b7637185c22920b2f9c14afdb09aa940.zip |
Add a simple implementation of CanvasRenderingContext2d.fillText
Diffstat (limited to 'components/canvas/raqote_backend.rs')
-rw-r--r-- | components/canvas/raqote_backend.rs | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/components/canvas/raqote_backend.rs b/components/canvas/raqote_backend.rs index 72eae8b40c8..6daa8712421 100644 --- a/components/canvas/raqote_backend.rs +++ b/components/canvas/raqote_backend.rs @@ -13,6 +13,9 @@ use canvas_traits::canvas::*; use cssparser::RGBA; use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D}; use euclid::Angle; +use font_kit::family_name::FamilyName; +use font_kit::properties::Properties; +use font_kit::source::SystemSource; use lyon_geom::Arc; use raqote::PathOp; use std::marker::PhantomData; @@ -539,6 +542,84 @@ impl GenericDrawTarget for raqote::DrawTarget { &DrawOptions::Raqote(draw_options), ); } + // TODO + // This should eventually use the same infrastructure as layout + // (i.e. layout should be updated to use font-kit as well). + // Need to implement .font . + fn fill_text( + &mut self, + text: String, + x: f32, + y: f32, + max_width: Option<f64>, + pattern: canvas_data::Pattern, + draw_options: &DrawOptions, + ) { + // Replace all ASCII whitespace in text with U+0020 SPACE characters. + fn replace_whitespace(text: String) -> String { + text.chars() + .map(|c| match c { + '\x09'..='\x0D' => '\x20', + _ => c, + }) + .collect() + } + + // Compute the width of the text + fn get_text_width(text: &str, font: &font_kit::font::Font) -> f64 { + let point_size = 24.; + let mut length = 0.; + for c in text.chars() { + let id = font.glyph_for_char(c).unwrap(); + length += (font.advance(id).unwrap() * point_size / 24. / 96.).x; + } + length as f64 + } + + let font = SystemSource::new() + .select_best_match(&[FamilyName::SansSerif], &Properties::new()) + .unwrap() + .load() + .unwrap(); + + // text preparation algorithm + let (scale_factor, replaced_text) = match max_width { + Some(value) => { + if value <= 0. || !value.is_finite() { + return; + } else { + let replaced_text = replace_whitespace(text); + let text_width = get_text_width(&replaced_text, &font); + if value > text_width { + (1., replaced_text) + } else { + (value / text_width, replaced_text) + } + } + }, + _ => (1., replace_whitespace(text)), + }; + + // Text scaling + let old_transform = self.get_transform().clone(); + let new_transform = old_transform + .pre_translate(Vector2D::new(x as f32, 0.)) + .pre_scale(scale_factor as f32, 1.) + .pre_translate(Vector2D::new(-x as f32, 0.)); + self.set_transform(&new_transform); + + self.draw_text( + &font, + 24., + &replaced_text, + Point2D::new(x, y), + &pattern.source(), + draw_options.as_raqote(), + ); + + // Restore the transform + self.set_transform(&old_transform); + } fn get_format(&self) -> SurfaceFormat { SurfaceFormat::Raqote(()) } |