aboutsummaryrefslogtreecommitdiffstats
path: root/components/canvas/raqote_backend.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/canvas/raqote_backend.rs')
-rw-r--r--components/canvas/raqote_backend.rs105
1 files changed, 68 insertions, 37 deletions
diff --git a/components/canvas/raqote_backend.rs b/components/canvas/raqote_backend.rs
index 8a9223bb191..359b0271368 100644
--- a/components/canvas/raqote_backend.rs
+++ b/components/canvas/raqote_backend.rs
@@ -2,23 +2,36 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+use std::cell::RefCell;
+use std::collections::HashMap;
+
use canvas_traits::canvas::*;
use cssparser::color::clamp_unit_f32;
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
use euclid::Angle;
use font_kit::font::Font;
+use fonts::{ByteIndex, FontIdentifier, FontTemplateRefMethods};
use log::warn;
use lyon_geom::Arc;
+use range::Range;
use raqote::PathOp;
use style::color::AbsoluteColor;
-use crate::canvas_data;
use crate::canvas_data::{
- Backend, CanvasPaintState, Color, CompositionOp, DrawOptions, Filter, GenericDrawTarget,
- GenericPathBuilder, GradientStop, GradientStops, Path, SourceSurface, StrokeOptions,
+ self, Backend, CanvasPaintState, Color, CompositionOp, DrawOptions, Filter, GenericDrawTarget,
+ GenericPathBuilder, GradientStop, GradientStops, Path, SourceSurface, StrokeOptions, TextRun,
};
use crate::canvas_paint_thread::AntialiasMode;
+thread_local! {
+ /// The shared font cache used by all canvases that render on a thread. It would be nicer
+ /// to have a global cache, but it looks like font-kit uses a per-thread FreeType, so
+ /// in order to ensure that fonts are particular to a thread we have to make our own
+ /// cache thread local as well.
+ static SHARED_FONT_CACHE: RefCell<HashMap<FontIdentifier, Font>> = RefCell::default();
+}
+
+#[derive(Default)]
pub struct RaqoteBackend;
impl Backend for RaqoteBackend {
@@ -508,43 +521,61 @@ impl GenericDrawTarget for raqote::DrawTarget {
fn fill_text(
&mut self,
- font: &Font,
- point_size: f32,
- text: &str,
+ text_runs: Vec<TextRun>,
start: Point2D<f32>,
pattern: &canvas_data::Pattern,
- options: &DrawOptions,
+ draw_options: &DrawOptions,
) {
- let mut start = pathfinder_geometry::vector::vec2f(start.x, start.y);
- let mut ids = Vec::new();
- let mut positions = Vec::new();
- for c in text.chars() {
- let id = match font.glyph_for_char(c) {
- Some(id) => id,
- None => {
- warn!("Skipping non-existent glyph {}", c);
- continue;
- },
- };
- ids.push(id);
- positions.push(Point2D::new(start.x(), start.y()));
- let advance = match font.advance(id) {
- Ok(advance) => advance,
- Err(e) => {
- warn!("Skipping glyph {} with missing advance: {:?}", c, e);
- continue;
- },
- };
- start += advance * point_size / 24. / 96.;
- }
- self.draw_glyphs(
- font,
- point_size,
- &ids,
- &positions,
- &pattern.source(),
- options.as_raqote(),
- );
+ let mut advance = 0.;
+ for run in text_runs.iter() {
+ let mut positions = Vec::new();
+ let glyphs = &run.glyphs;
+ let ids: Vec<_> = glyphs
+ .iter_glyphs_for_byte_range(&Range::new(ByteIndex(0), glyphs.len()))
+ .map(|glyph| {
+ let glyph_offset = glyph.offset().unwrap_or(Point2D::zero());
+ positions.push(Point2D::new(
+ advance + start.x + glyph_offset.x.to_f32_px(),
+ start.y + glyph_offset.y.to_f32_px(),
+ ));
+ advance += glyph.advance().to_f32_px();
+ glyph.id()
+ })
+ .collect();
+
+ // TODO: raqote uses font-kit to rasterize glyphs, but font-kit fails an assertion when
+ // using color bitmap fonts in the FreeType backend. For now, simply do not render these
+ // type of fonts.
+ if run.font.has_color_bitmap_or_colr_table() {
+ continue;
+ }
+
+ let template = &run.font.template;
+
+ SHARED_FONT_CACHE.with(|font_cache| {
+ let identifier = template.identifier();
+ if !font_cache.borrow().contains_key(&identifier) {
+ let Ok(font) = Font::from_bytes(template.data(), identifier.index()) else {
+ return;
+ };
+ font_cache.borrow_mut().insert(identifier.clone(), font);
+ }
+
+ let font_cache = font_cache.borrow();
+ let Some(font) = font_cache.get(&identifier) else {
+ return;
+ };
+
+ self.draw_glyphs(
+ &font,
+ run.font.descriptor.pt_size.to_f32_px(),
+ &ids,
+ &positions,
+ &pattern.source(),
+ draw_options.as_raqote(),
+ );
+ })
+ }
}
fn fill_rect(