Skip to main content

wr_glyph_rasterizer/
rasterizer.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use api::{FontInstanceData, FontInstanceFlags, FontInstanceKey};
6use api::{FontInstanceOptions, FontInstancePlatformOptions};
7use api::{FontKey, FontRenderMode, FontSize, FontTemplate, FontVariation};
8use api::{ColorU, GlyphIndex, GlyphDimensions, SyntheticItalics};
9use api::{IdNamespace, BlobImageResources};
10use api::channel::crossbeam::{unbounded, Receiver, Sender};
11use api::units::*;
12use api::ImageFormat;
13use crate::platform::font::FontContext;
14use crate::profiler::GlyphRasterizeProfiler;
15use crate::types::{FastHashMap, FastHashSet};
16use crate::telemetry::Telemetry;
17use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
18use rayon::ThreadPool;
19use rayon::prelude::*;
20use euclid::approxeq::ApproxEq;
21use smallvec::SmallVec;
22use std::cmp;
23use std::cell::Cell;
24use std::hash::{Hash, Hasher};
25use std::mem;
26use std::ops::Deref;
27use std::sync::{Arc, Condvar, Mutex, MutexGuard, Weak};
28use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
29use std::sync::atomic::{AtomicBool, Ordering};
30
31pub static GLYPH_FLASHING: AtomicBool = AtomicBool::new(false);
32const GLYPH_BATCH_SIZE: usize = 32;
33
34impl FontContexts {
35    /// Get access to the font context associated to the current thread.
36    pub fn lock_current_context(&self) -> MutexGuard<FontContext> {
37        match self.current_worker_id() {
38            Some(id) => self.lock_context(id),
39            None => self.lock_any_context(),
40        }
41    }
42
43    pub(in super) fn current_worker_id(&self) -> Option<usize> {
44        self.workers.current_thread_index()
45    }
46}
47
48thread_local! {
49    pub static SEED: Cell<u32> = Cell::new(0);
50}
51
52// super simple random to avoid dependency on rand
53fn random() -> u32 {
54    SEED.with(|seed| {
55        seed.set(seed.get().wrapping_mul(22695477).wrapping_add(1));
56        seed.get()
57    })
58}
59
60impl GlyphRasterizer {
61    pub fn request_glyphs<F>(
62        &mut self,
63        font: FontInstance,
64        glyph_keys: &[GlyphKey],
65        mut handle: F,
66    )
67    where F: FnMut(&GlyphKey) -> bool
68    {
69        assert!(self.has_font(font.font_key));
70
71        let mut batch_size = 0;
72
73        // select glyphs that have not been requested yet.
74        for key in glyph_keys {
75            if !handle(key) {
76                continue;
77            }
78
79            // Increment the total number of glyphs that are pending. This is used to determine
80            // later whether to use worker threads for the remaining glyphs during resolve time.
81            self.pending_glyph_count += 1;
82            self.glyph_request_count += 1;
83
84            // Find a batch container for the font instance for this glyph. Use get_mut to avoid
85            // cloning the font instance, since this is the common path.
86            match self.pending_glyph_requests.get_mut(&font) {
87                Some(container) => {
88                    container.push(*key);
89                    batch_size = container.len();
90                }
91                None => {
92                    // If no batch exists for this font instance, add the glyph to a new one.
93                    self.pending_glyph_requests.insert(
94                        font.clone(),
95                        smallvec![*key],
96                    );
97                }
98            }
99        }
100
101        // If the batch for this font instance is big enough, kick off an async
102        // job to start rasterizing these glyphs on other threads now.
103        if batch_size >= GLYPH_BATCH_SIZE {
104            let container = self.pending_glyph_requests.get_mut(&font).unwrap();
105            let glyphs = mem::replace(container, SmallVec::new());
106            self.flush_glyph_requests(font, glyphs, true);
107        }
108    }
109
110    pub fn enable_multithreading(&mut self, enable: bool) {
111        self.enable_multithreading = enable;
112    }
113
114    /// Internal method to flush a list of glyph requests to a set of worker threads,
115    /// or process on this thread if there isn't much work to do (in which case the
116    /// overhead of processing these on a thread is unlikely to be a performance win).
117    fn flush_glyph_requests(
118        &mut self,
119        font: FontInstance,
120        glyphs: SmallVec<[GlyphKey; 16]>,
121        use_workers: bool,
122    ) {
123        let font = Arc::new(font);
124        let font_contexts = Arc::clone(&self.font_contexts);
125        self.pending_glyph_jobs += glyphs.len();
126        self.pending_glyph_count -= glyphs.len();
127
128        let can_use_r8_format = self.can_use_r8_format;
129
130        // if the number of glyphs is small, do it inline to avoid the threading overhead;
131        // send the result into glyph_tx so downstream code can't tell the difference.
132        if let Some(thread) = &self.dedicated_thread {
133            let tx = self.glyph_tx.clone();
134            let _ = thread.tx.send(GlyphRasterMsg::Rasterize { font, glyphs, can_use_r8_format, tx });
135        } else if self.enable_multithreading && use_workers {
136            // spawn an async task to get off of the render backend thread as early as
137            // possible and in that task use rayon's fork join dispatch to rasterize the
138            // glyphs in the thread pool.
139            profile_scope!("spawning process_glyph jobs");
140            let tx = self.glyph_tx.clone();
141            self.workers.spawn(move || {
142                FontContext::begin_rasterize(&font);
143                // If the FontContext supports distributing a font across multiple threads,
144                // then use par_iter so different glyphs of the same font are processed on
145                // multiple threads.
146                if FontContext::distribute_across_threads() {
147                    glyphs.par_iter().for_each(|key| {
148                        let mut context = font_contexts.lock_current_context();
149                        let job_font = font.clone();
150                        let job = process_glyph(&mut context, can_use_r8_format, job_font, *key);
151                        tx.send(job).unwrap();
152                    });
153                } else {
154                    // For FontContexts that prefer to localize a font to a single thread,
155                    // just process all the glyphs on the same worker to avoid contention.
156                    for key in glyphs {
157                        let mut context = font_contexts.lock_current_context();
158                        let job_font = font.clone();
159                        let job = process_glyph(&mut context, can_use_r8_format, job_font, key);
160                        tx.send(job).unwrap();
161                    }
162                }
163                FontContext::end_rasterize(&font);
164            });
165        } else {
166            FontContext::begin_rasterize(&font);
167            for key in glyphs {
168                let mut context = font_contexts.lock_current_context();
169                let job_font = font.clone();
170                let job = process_glyph(&mut context, can_use_r8_format, job_font, key);
171            self.glyph_tx.send(job).unwrap();
172            }
173            FontContext::end_rasterize(&font);
174        }
175    }
176
177    pub fn resolve_glyphs<F, G>(
178        &mut self,
179        mut handle: F,
180        profile: &mut G,
181    )
182    where
183        F: FnMut(GlyphRasterJob, bool),
184        G: GlyphRasterizeProfiler,
185    {
186        profile.start_time();
187        let timer_id = Telemetry::start_rasterize_glyphs_time();
188
189        // Work around the borrow checker, since we call flush_glyph_requests below
190        let mut pending_glyph_requests = mem::replace(
191            &mut self.pending_glyph_requests,
192            FastHashMap::default(),
193        );
194        // If we have a large amount of remaining work to do, spawn to worker threads,
195        // even if that work is shared among a number of different font instances.
196        let use_workers = self.pending_glyph_count >= 8;
197        for (font, pending_glyphs) in pending_glyph_requests.drain() {
198            self.flush_glyph_requests(
199                font,
200                pending_glyphs,
201                use_workers,
202            );
203        }
204        // Restore this so that we don't heap allocate next frame
205        self.pending_glyph_requests = pending_glyph_requests;
206        debug_assert_eq!(self.pending_glyph_count, 0);
207        debug_assert!(self.pending_glyph_requests.is_empty());
208
209        if self.glyph_request_count > 0 {
210            profile.set(self.glyph_request_count as f64);
211            self.glyph_request_count = 0;
212        }
213
214        profile_scope!("resolve_glyphs");
215        // TODO: rather than blocking until all pending glyphs are available
216        // we could try_recv and steal work from the thread pool to take advantage
217        // of the fact that this thread is alive and we avoid the added latency
218        // of blocking it.
219        let mut jobs = {
220            profile_scope!("blocking wait on glyph_rx");
221            self.glyph_rx.iter().take(self.pending_glyph_jobs).collect::<Vec<_>>()
222        };
223        assert_eq!(jobs.len(), self.pending_glyph_jobs, "BUG: Didn't receive all pending glyphs!");
224        self.pending_glyph_jobs = 0;
225
226        // Ensure that the glyphs are always processed in the same
227        // order for a given text run (since iterating a hash set doesn't
228        // guarantee order). This can show up as very small float inaccuracy
229        // differences in rasterizers due to the different coordinates
230        // that text runs get associated with by the texture cache allocator.
231        jobs.sort_by(|a, b| (*a.font).cmp(&*b.font).then(a.key.cmp(&b.key)));
232
233        for job in jobs {
234            handle(job, self.can_use_r8_format);
235        }
236
237        // Now that we are done with the critical path (rendering the glyphs),
238        // we can schedule removing the fonts if needed.
239        self.remove_dead_fonts();
240
241        Telemetry::stop_and_accumulate_rasterize_glyphs_time(timer_id);
242        profile.end_time();
243    }
244}
245
246#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd)]
247#[cfg_attr(feature = "capture", derive(Serialize))]
248#[cfg_attr(feature = "replay", derive(Deserialize))]
249pub struct FontTransform {
250    pub scale_x: f32,
251    pub skew_x: f32,
252    pub skew_y: f32,
253    pub scale_y: f32,
254}
255
256// Floats don't impl Hash/Eq/Ord...
257impl Eq for FontTransform {}
258impl Ord for FontTransform {
259    fn cmp(&self, other: &Self) -> cmp::Ordering {
260        self.partial_cmp(other).unwrap_or(cmp::Ordering::Equal)
261    }
262}
263impl Hash for FontTransform {
264    fn hash<H: Hasher>(&self, state: &mut H) {
265        // Note: this is inconsistent with the Eq impl for -0.0 (don't care).
266        self.scale_x.to_bits().hash(state);
267        self.skew_x.to_bits().hash(state);
268        self.skew_y.to_bits().hash(state);
269        self.scale_y.to_bits().hash(state);
270    }
271}
272
273impl FontTransform {
274    const QUANTIZE_SCALE: f32 = 1024.0;
275
276    pub fn new(scale_x: f32, skew_x: f32, skew_y: f32, scale_y: f32) -> Self {
277        FontTransform { scale_x, skew_x, skew_y, scale_y }
278    }
279
280    pub fn identity() -> Self {
281        FontTransform::new(1.0, 0.0, 0.0, 1.0)
282    }
283
284    #[allow(dead_code)]
285    pub fn is_identity(&self) -> bool {
286        *self == FontTransform::identity()
287    }
288
289    pub fn quantize(&self) -> Self {
290        FontTransform::new(
291            (self.scale_x * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE,
292            (self.skew_x * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE,
293            (self.skew_y * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE,
294            (self.scale_y * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE,
295        )
296    }
297
298    #[allow(dead_code)]
299    pub fn determinant(&self) -> f64 {
300        self.scale_x as f64 * self.scale_y as f64 - self.skew_y as f64 * self.skew_x as f64
301    }
302
303    #[allow(dead_code)]
304    pub fn compute_scale(&self) -> Option<(f64, f64)> {
305        let det = self.determinant();
306        if det != 0.0 {
307            let x_scale = (self.scale_x as f64).hypot(self.skew_y as f64);
308            let y_scale = det.abs() / x_scale;
309            Some((x_scale, y_scale))
310        } else {
311            None
312        }
313    }
314
315    #[allow(dead_code)]
316    pub fn pre_scale(&self, scale_x: f32, scale_y: f32) -> Self {
317        FontTransform::new(
318            self.scale_x * scale_x,
319            self.skew_x * scale_y,
320            self.skew_y * scale_x,
321            self.scale_y * scale_y,
322        )
323    }
324
325    #[allow(dead_code)]
326    pub fn scale(&self, scale: f32) -> Self { self.pre_scale(scale, scale) }
327
328    #[allow(dead_code)]
329    pub fn invert_scale(&self, x_scale: f64, y_scale: f64) -> Self {
330        self.pre_scale(x_scale.recip() as f32, y_scale.recip() as f32)
331    }
332
333    pub fn synthesize_italics(&self, angle: SyntheticItalics, size: f64, vertical: bool) -> (Self, (f64, f64)) {
334        let skew_factor = angle.to_skew();
335        if vertical {
336          // origin delta to be applied so that we effectively skew around
337          // the middle rather than edge of the glyph
338          let (tx, ty) = (0.0, -size * 0.5 * skew_factor as f64);
339          (FontTransform::new(
340              self.scale_x + self.skew_x * skew_factor,
341              self.skew_x,
342              self.skew_y + self.scale_y * skew_factor,
343              self.scale_y,
344          ), (self.scale_x as f64 * tx + self.skew_x as f64 * ty,
345              self.skew_y as f64 * tx + self.scale_y as f64 * ty))
346        } else {
347          (FontTransform::new(
348              self.scale_x,
349              self.skew_x - self.scale_x * skew_factor,
350              self.skew_y,
351              self.scale_y - self.skew_y * skew_factor,
352          ), (0.0, 0.0))
353        }
354    }
355
356    pub fn swap_xy(&self) -> Self {
357        FontTransform::new(self.skew_x, self.scale_x, self.scale_y, self.skew_y)
358    }
359
360    pub fn flip_x(&self) -> Self {
361        FontTransform::new(-self.scale_x, self.skew_x, -self.skew_y, self.scale_y)
362    }
363
364    pub fn flip_y(&self) -> Self {
365        FontTransform::new(self.scale_x, -self.skew_x, self.skew_y, -self.scale_y)
366    }
367
368    pub fn transform(&self, point: &LayoutPoint) -> DevicePoint {
369        DevicePoint::new(
370            self.scale_x * point.x + self.skew_x * point.y,
371            self.skew_y * point.x + self.scale_y * point.y,
372        )
373    }
374
375    pub fn get_subpx_dir(&self) -> SubpixelDirection {
376        if self.skew_y.approx_eq(&0.0) {
377            // The X axis is not projected onto the Y axis
378            SubpixelDirection::Horizontal
379        } else if self.scale_x.approx_eq(&0.0) {
380            // The X axis has been swapped with the Y axis
381            SubpixelDirection::Vertical
382        } else {
383            // Mixed transforms get no subpixel positioning
384            SubpixelDirection::None
385        }
386    }
387}
388
389impl<'a> From<&'a LayoutToWorldTransform> for FontTransform {
390    fn from(xform: &'a LayoutToWorldTransform) -> Self {
391        FontTransform::new(xform.m11, xform.m21, xform.m12, xform.m22)
392    }
393}
394
395// Some platforms (i.e. Windows) may have trouble rasterizing glyphs above this size.
396// Ensure glyph sizes are reasonably limited to avoid that scenario.
397pub const FONT_SIZE_LIMIT: f32 = 320.0;
398
399/// Immutable description of a font instance's shared state.
400///
401/// `BaseFontInstance` can be identified by a `FontInstanceKey` to avoid hashing it.
402#[derive(Clone, Debug, Ord, PartialOrd, MallocSizeOf)]
403#[cfg_attr(feature = "capture", derive(Serialize))]
404#[cfg_attr(feature = "replay", derive(Deserialize))]
405pub struct BaseFontInstance {
406    ///
407    pub instance_key: FontInstanceKey,
408    ///
409    pub font_key: FontKey,
410    ///
411    pub size: FontSize,
412    ///
413    pub options: FontInstanceOptions,
414    ///
415    #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
416    pub platform_options: Option<FontInstancePlatformOptions>,
417    ///
418    pub variations: Vec<FontVariation>,
419}
420
421impl BaseFontInstance {
422    pub fn new(
423        instance_key: FontInstanceKey,
424        font_key: FontKey,
425        size: f32,
426        options: Option<FontInstanceOptions>,
427        platform_options: Option<FontInstancePlatformOptions>,
428        variations: Vec<FontVariation>,
429    ) -> Self {
430        BaseFontInstance {
431            instance_key,
432            font_key,
433            size: size.into(),
434            options: options.unwrap_or_default(),
435            platform_options,
436            variations,
437        }
438    }
439}
440
441impl Deref for BaseFontInstance {
442    type Target = FontInstanceOptions;
443    fn deref(&self) -> &FontInstanceOptions {
444        &self.options
445    }
446}
447
448impl Hash for BaseFontInstance {
449    fn hash<H: Hasher>(&self, state: &mut H) {
450        // Skip the instance key.
451        self.font_key.hash(state);
452        self.size.hash(state);
453        self.options.hash(state);
454        self.platform_options.hash(state);
455        self.variations.hash(state);
456    }
457}
458
459impl PartialEq for BaseFontInstance {
460    fn eq(&self, other: &BaseFontInstance) -> bool {
461        // Skip the instance key.
462        self.font_key == other.font_key &&
463            self.size == other.size &&
464            self.options == other.options &&
465            self.platform_options == other.platform_options &&
466            self.variations == other.variations
467    }
468}
469impl Eq for BaseFontInstance {}
470
471struct MappedFontKey {
472    font_key: FontKey,
473    template: FontTemplate,
474}
475
476struct FontKeyMapLocked {
477    namespace: IdNamespace,
478    next_id: u32,
479    template_map: FastHashMap<FontTemplate, Arc<MappedFontKey>>,
480    key_map: FastHashMap<FontKey, Arc<MappedFontKey>>,
481}
482
483/// A shared map from fonts key local to a namespace to shared font keys that
484/// can be shared across many namespaces. Local keys are tracked in a hashmap
485/// that stores a strong reference per mapping so that their count can be
486/// tracked. A map of font templates is used to hash font templates to their
487/// final shared key. The shared key will stay alive so long as there are
488/// any strong references to the mapping entry. Care must be taken when
489/// clearing namespaces of shared keys as this may trigger shared font keys
490/// to expire which require individual processing. Shared font keys will be
491/// created within the provided unique namespace.
492#[derive(Clone)]
493pub struct FontKeyMap(Arc<RwLock<FontKeyMapLocked>>);
494
495impl FontKeyMap {
496    pub fn new(namespace: IdNamespace) -> Self {
497        FontKeyMap(Arc::new(RwLock::new(FontKeyMapLocked {
498            namespace,
499            next_id: 1,
500            template_map: FastHashMap::default(),
501            key_map: FastHashMap::default(),
502        })))
503    }
504
505    fn lock(&self) -> RwLockReadGuard<FontKeyMapLocked> {
506        self.0.read().unwrap()
507    }
508
509    fn lock_mut(&mut self) -> RwLockWriteGuard<FontKeyMapLocked> {
510        self.0.write().unwrap()
511    }
512
513    pub fn keys(&self) -> Vec<FontKey> {
514        self.lock().key_map.keys().cloned().collect()
515    }
516
517    pub fn map_key(&self, font_key: &FontKey) -> FontKey {
518        match self.lock().key_map.get(font_key) {
519            Some(mapped) => mapped.font_key,
520            None => *font_key,
521        }
522    }
523
524    pub fn add_key(&mut self, font_key: &FontKey, template: &FontTemplate) -> Option<FontKey> {
525        let mut locked = self.lock_mut();
526        if locked.key_map.contains_key(font_key) {
527            return None;
528        }
529        if let Some(mapped) = locked.template_map.get(template).cloned() {
530            locked.key_map.insert(*font_key, mapped);
531            return None;
532        }
533        let shared_key = FontKey::new(locked.namespace, locked.next_id);
534        locked.next_id += 1;
535        let mapped = Arc::new(MappedFontKey {
536            font_key: shared_key,
537            template: template.clone(),
538        });
539        locked.template_map.insert(template.clone(), mapped.clone());
540        locked.key_map.insert(*font_key, mapped);
541        Some(shared_key)
542    }
543
544    pub fn delete_key(&mut self, font_key: &FontKey) -> Option<FontKey> {
545        let mut locked = self.lock_mut();
546        let mapped = match locked.key_map.remove(font_key) {
547            Some(mapped) => mapped,
548            None => return Some(*font_key),
549        };
550        if Arc::strong_count(&mapped) <= 2 {
551            // Only the last mapped key and template map point to it.
552            locked.template_map.remove(&mapped.template);
553            Some(mapped.font_key)
554        } else {
555            None
556        }
557    }
558
559    pub fn clear_namespace(&mut self, namespace: IdNamespace) -> Vec<FontKey> {
560        let mut locked = self.lock_mut();
561        locked.key_map.retain(|key, _| {
562            if key.0 == namespace {
563                false
564            } else {
565                true
566            }
567        });
568        let mut deleted_keys = Vec::new();
569        locked.template_map.retain(|_, mapped| {
570            if Arc::strong_count(mapped) <= 1 {
571                // Only the template map points to it.
572                deleted_keys.push(mapped.font_key);
573                false
574            } else {
575                true
576            }
577        });
578        deleted_keys
579    }
580}
581
582type FontTemplateMapLocked = FastHashMap<FontKey, FontTemplate>;
583
584/// A map of font keys to font templates that might hold both namespace-local
585/// font templates as well as shared templates.
586#[derive(Clone)]
587pub struct FontTemplateMap(Arc<RwLock<FontTemplateMapLocked>>);
588
589impl FontTemplateMap {
590    pub fn new() -> Self {
591        FontTemplateMap(Arc::new(RwLock::new(FastHashMap::default())))
592    }
593
594    pub fn lock(&self) -> RwLockReadGuard<FontTemplateMapLocked> {
595        self.0.read().unwrap()
596    }
597
598    fn lock_mut(&mut self) -> RwLockWriteGuard<FontTemplateMapLocked> {
599        self.0.write().unwrap()
600    }
601
602    pub fn clear(&mut self) {
603        self.lock_mut().clear();
604    }
605
606    pub fn len(&self) -> usize {
607        self.lock().len()
608    }
609
610    pub fn has_font(&self, key: &FontKey) -> bool {
611        self.lock().contains_key(key)
612    }
613
614    pub fn get_font(&self, key: &FontKey) -> Option<FontTemplate> {
615        self.lock().get(key).cloned()
616    }
617
618    pub fn add_font(&mut self, key: FontKey, template: FontTemplate) -> bool {
619        self.lock_mut().insert(key, template).is_none()
620    }
621
622    pub fn delete_font(&mut self, key: &FontKey) -> Option<FontTemplate> {
623        self.lock_mut().remove(key)
624    }
625
626    pub fn delete_fonts(&mut self, keys: &[FontKey]) {
627        if !keys.is_empty() {
628            let mut map = self.lock_mut();
629            for key in keys {
630                map.remove(key);
631            }
632        }
633    }
634
635    pub fn clear_namespace(&mut self, namespace: IdNamespace) -> Vec<FontKey> {
636        let mut deleted_keys = Vec::new();
637        self.lock_mut().retain(|key, _| {
638            if key.0 == namespace {
639                deleted_keys.push(*key);
640                false
641            } else {
642                true
643            }
644        });
645        deleted_keys
646    }
647}
648
649struct FontInstanceKeyMapLocked {
650    namespace: IdNamespace,
651    next_id: u32,
652    instances: FastHashSet<Arc<BaseFontInstance>>,
653    key_map: FastHashMap<FontInstanceKey, Weak<BaseFontInstance>>,
654}
655
656/// A map of namespace-local font instance keys to shared keys. Weak references
657/// are used to track the liveness of each key mapping as other consumers of
658/// BaseFontInstance might hold strong references to the entry. A mapping from
659/// BaseFontInstance to the shared key is then used to determine which shared
660/// key to assign to that instance. When the weak count of the mapping is zero,
661/// the entry is allowed to expire. Again, care must be taken when clearing
662/// a namespace within the key map as it may cause shared key expirations that
663/// require individual processing. Shared instance keys will be created within
664/// the provided unique namespace.
665#[derive(Clone)]
666pub struct FontInstanceKeyMap(Arc<RwLock<FontInstanceKeyMapLocked>>);
667
668impl FontInstanceKeyMap {
669    pub fn new(namespace: IdNamespace) -> Self {
670        FontInstanceKeyMap(Arc::new(RwLock::new(FontInstanceKeyMapLocked {
671            namespace,
672            next_id: 1,
673            instances: FastHashSet::default(),
674            key_map: FastHashMap::default(),
675        })))
676    }
677
678    fn lock(&self) -> RwLockReadGuard<FontInstanceKeyMapLocked> {
679        self.0.read().unwrap()
680    }
681
682    fn lock_mut(&mut self) -> RwLockWriteGuard<FontInstanceKeyMapLocked> {
683        self.0.write().unwrap()
684    }
685
686    pub fn keys(&self) -> Vec<FontInstanceKey> {
687        self.lock().key_map.keys().cloned().collect()
688    }
689
690    pub fn map_key(&self, key: &FontInstanceKey) -> FontInstanceKey {
691        match self.lock().key_map.get(key).and_then(|weak| weak.upgrade()) {
692            Some(mapped) => mapped.instance_key,
693            None => *key,
694        }
695    }
696
697    pub fn add_key(&mut self, mut instance: BaseFontInstance) -> Option<Arc<BaseFontInstance>> {
698        let mut locked = self.lock_mut();
699        if locked.key_map.contains_key(&instance.instance_key) {
700            return None;
701        }
702        if let Some(weak) = locked.instances.get(&instance).map(|mapped| Arc::downgrade(mapped)) {
703            locked.key_map.insert(instance.instance_key, weak);
704            return None;
705        }
706        let unmapped_key = instance.instance_key;
707        instance.instance_key = FontInstanceKey::new(locked.namespace, locked.next_id);
708        locked.next_id += 1;
709        let shared_instance = Arc::new(instance);
710        locked.instances.insert(shared_instance.clone());
711        locked.key_map.insert(unmapped_key, Arc::downgrade(&shared_instance));
712        Some(shared_instance)
713    }
714
715    pub fn delete_key(&mut self, key: &FontInstanceKey) -> Option<FontInstanceKey> {
716        let mut locked = self.lock_mut();
717        let mapped = match locked.key_map.remove(key).and_then(|weak| weak.upgrade()) {
718            Some(mapped) => mapped,
719            None => return Some(*key),
720        };
721        if Arc::weak_count(&mapped) == 0 {
722            // Only the instance set points to it.
723            locked.instances.remove(&mapped);
724            Some(mapped.instance_key)
725        } else {
726            None
727        }
728    }
729
730    pub fn clear_namespace(&mut self, namespace: IdNamespace) -> Vec<FontInstanceKey> {
731        let mut locked = self.lock_mut();
732        locked.key_map.retain(|key, _| {
733            if key.0 == namespace {
734                false
735            } else {
736                true
737            }
738        });
739        let mut deleted_keys = Vec::new();
740        locked.instances.retain(|mapped| {
741            if Arc::weak_count(mapped) == 0 {
742                // Only the instance set points to it.
743                deleted_keys.push(mapped.instance_key);
744                false
745            } else {
746                true
747            }
748        });
749        deleted_keys
750    }
751}
752
753type FontInstanceMapLocked = FastHashMap<FontInstanceKey, Arc<BaseFontInstance>>;
754
755/// A map of font instance data accessed concurrently from multiple threads.
756#[derive(Clone)]
757pub struct FontInstanceMap(Arc<RwLock<FontInstanceMapLocked>>);
758
759impl FontInstanceMap {
760    /// Creates an empty shared map.
761    pub fn new() -> Self {
762        FontInstanceMap(Arc::new(RwLock::new(FastHashMap::default())))
763    }
764
765    /// Acquires a read lock on the shared map.
766    pub fn lock(&self) -> RwLockReadGuard<FontInstanceMapLocked> {
767        self.0.read().unwrap()
768    }
769
770    /// Acquires a read lock on the shared map.
771    fn lock_mut(&mut self) -> RwLockWriteGuard<FontInstanceMapLocked> {
772        self.0.write().unwrap()
773    }
774
775    ///
776    pub fn clear(&mut self) {
777        self.lock_mut().clear();
778    }
779
780    ///
781    pub fn get_font_instance_data(&self, key: FontInstanceKey) -> Option<FontInstanceData> {
782        match self.lock().get(&key) {
783            Some(instance) => Some(FontInstanceData {
784                font_key: instance.font_key,
785                size: instance.size.into(),
786                options: Some(FontInstanceOptions {
787                  render_mode: instance.render_mode,
788                  flags: instance.flags,
789                  synthetic_italics: instance.synthetic_italics,
790                  _padding: 0,
791                }),
792                platform_options: instance.platform_options,
793                variations: instance.variations.clone(),
794            }),
795            None => None,
796        }
797    }
798
799    ///
800    pub fn get_font_instance(&self, instance_key: FontInstanceKey) -> Option<Arc<BaseFontInstance>> {
801        let instance_map = self.lock();
802        instance_map.get(&instance_key).cloned()
803    }
804
805    ///
806    pub fn add_font_instance(&mut self, instance: Arc<BaseFontInstance>) {
807        self.lock_mut().insert(instance.instance_key, instance);
808    }
809
810    ///
811    pub fn delete_font_instance(&mut self, instance_key: FontInstanceKey) {
812        self.lock_mut().remove(&instance_key);
813    }
814
815    ///
816    pub fn delete_font_instances(&mut self, keys: &[FontInstanceKey]) {
817        if !keys.is_empty() {
818            let mut map = self.lock_mut();
819            for key in keys {
820                map.remove(key);
821            }
822        }
823    }
824
825    ///
826    pub fn clear_namespace(&mut self, namespace: IdNamespace) {
827        self.lock_mut().retain(|key, _| key.0 != namespace);
828    }
829}
830
831/// Shared font resources that may need to be passed between multiple threads
832/// such as font templates and font instances. They are individually protected
833/// by locks to ensure safety.
834#[derive(Clone)]
835pub struct SharedFontResources {
836    pub templates: FontTemplateMap,
837    pub instances: FontInstanceMap,
838    pub font_keys: FontKeyMap,
839    pub instance_keys: FontInstanceKeyMap,
840}
841
842impl SharedFontResources {
843    pub fn new(namespace: IdNamespace) -> Self {
844        SharedFontResources {
845            templates: FontTemplateMap::new(),
846            instances: FontInstanceMap::new(),
847            font_keys: FontKeyMap::new(namespace),
848            instance_keys: FontInstanceKeyMap::new(namespace),
849        }
850    }
851}
852
853impl BlobImageResources for SharedFontResources {
854    fn get_font_data(&self, key: FontKey) -> Option<FontTemplate> {
855        let shared_key = self.font_keys.map_key(&key);
856        self.templates.get_font(&shared_key)
857    }
858
859    fn get_font_instance_data(&self, key: FontInstanceKey) -> Option<FontInstanceData> {
860        let shared_key = self.instance_keys.map_key(&key);
861        self.instances.get_font_instance_data(shared_key)
862    }
863}
864
865/// A mutable font instance description.
866///
867/// Performance is sensitive to the size of this structure, so it should only contain
868/// the fields that we need to modify from the original base font instance.
869#[derive(Clone, Debug, Ord, PartialOrd)]
870#[cfg_attr(feature = "capture", derive(Serialize))]
871#[cfg_attr(feature = "replay", derive(Deserialize))]
872pub struct FontInstance {
873    pub base: Arc<BaseFontInstance>,
874    pub transform: FontTransform,
875    pub render_mode: FontRenderMode,
876    pub flags: FontInstanceFlags,
877    pub color: ColorU,
878    // The font size is in *device/raster* pixels, not logical pixels.
879    // It is stored as an f32 since we need sub-pixel sizes.
880    pub size: FontSize,
881}
882
883impl Hash for FontInstance {
884    fn hash<H: Hasher>(&self, state: &mut H) {
885        // Hash only the base instance's key to avoid the cost of hashing
886        // the rest.
887        self.base.instance_key.hash(state);
888        self.transform.hash(state);
889        self.render_mode.hash(state);
890        self.flags.hash(state);
891        self.color.hash(state);
892        self.size.hash(state);
893    }
894}
895
896impl PartialEq for FontInstance {
897    fn eq(&self, other: &FontInstance) -> bool {
898        // Compare only the base instance's key.
899        self.base.instance_key == other.base.instance_key &&
900            self.transform == other.transform &&
901            self.render_mode == other.render_mode &&
902            self.flags == other.flags &&
903            self.color == other.color &&
904            self.size == other.size
905    }
906}
907impl Eq for FontInstance {}
908
909impl Deref for FontInstance {
910    type Target = BaseFontInstance;
911    fn deref(&self) -> &BaseFontInstance {
912        self.base.as_ref()
913    }
914}
915
916impl MallocSizeOf for  FontInstance {
917    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { 0 }
918}
919
920impl FontInstance {
921    pub fn new(
922        base: Arc<BaseFontInstance>,
923        color: ColorU,
924        render_mode: FontRenderMode,
925        flags: FontInstanceFlags,
926    ) -> Self {
927        FontInstance {
928            transform: FontTransform::identity(),
929            color,
930            size: base.size,
931            base,
932            render_mode,
933            flags,
934        }
935    }
936
937    pub fn from_base(
938        base: Arc<BaseFontInstance>,
939    ) -> Self {
940        let color = ColorU::new(0, 0, 0, 255);
941        let render_mode = base.render_mode;
942        let flags = base.flags;
943        Self::new(base, color, render_mode, flags)
944    }
945
946    pub fn use_texture_padding(&self) -> bool {
947        self.flags.contains(FontInstanceFlags::TEXTURE_PADDING)
948    }
949
950    pub fn use_transform_glyphs(&self) -> bool {
951        self.flags.contains(FontInstanceFlags::TRANSFORM_GLYPHS)
952    }
953
954    pub fn get_alpha_glyph_format(&self) -> GlyphFormat {
955        if self.use_transform_glyphs() { GlyphFormat::TransformedAlpha } else { GlyphFormat::Alpha }
956    }
957
958    pub fn get_subpixel_glyph_format(&self) -> GlyphFormat {
959        if self.use_transform_glyphs() { GlyphFormat::TransformedSubpixel } else { GlyphFormat::Subpixel }
960    }
961
962    pub fn disable_subpixel_aa(&mut self) {
963        self.render_mode = self.render_mode.limit_by(FontRenderMode::Alpha);
964    }
965
966    pub fn disable_subpixel_position(&mut self) {
967        self.flags.remove(FontInstanceFlags::SUBPIXEL_POSITION);
968    }
969
970    pub fn use_subpixel_position(&self) -> bool {
971        self.flags.contains(FontInstanceFlags::SUBPIXEL_POSITION) &&
972        self.render_mode != FontRenderMode::Mono
973    }
974
975    pub fn get_subpx_dir(&self) -> SubpixelDirection {
976        if self.use_subpixel_position() {
977            let mut subpx_dir = self.transform.get_subpx_dir();
978            if self.flags.contains(FontInstanceFlags::TRANSPOSE) {
979                subpx_dir = subpx_dir.swap_xy();
980            }
981            subpx_dir
982        } else {
983            SubpixelDirection::None
984        }
985    }
986
987    #[allow(dead_code)]
988    pub fn get_subpx_offset(&self, glyph: &GlyphKey) -> (f64, f64) {
989        if self.use_subpixel_position() {
990            let (dx, dy) = glyph.subpixel_offset();
991            (dx.into(), dy.into())
992        } else {
993            (0.0, 0.0)
994        }
995    }
996
997    #[allow(dead_code)]
998    pub fn get_glyph_format(&self) -> GlyphFormat {
999        match self.render_mode {
1000            FontRenderMode::Mono | FontRenderMode::Alpha => self.get_alpha_glyph_format(),
1001            FontRenderMode::Subpixel => self.get_subpixel_glyph_format(),
1002        }
1003    }
1004
1005    #[allow(dead_code)]
1006    pub fn get_extra_strikes(&self, flags: FontInstanceFlags, x_scale: f64) -> usize {
1007        if self.flags.intersects(flags) {
1008            let mut bold_offset = self.size.to_f64_px() / 48.0;
1009            if bold_offset < 1.0 {
1010                bold_offset = 0.25 + 0.75 * bold_offset;
1011            }
1012            (bold_offset * x_scale).max(1.0).round() as usize
1013        } else {
1014            0
1015        }
1016    }
1017
1018    pub fn synthesize_italics(&self, transform: FontTransform, size: f64) -> (FontTransform, (f64, f64)) {
1019        transform.synthesize_italics(self.synthetic_italics, size, self.flags.contains(FontInstanceFlags::VERTICAL))
1020    }
1021
1022    #[allow(dead_code)]
1023    pub fn get_transformed_size(&self) -> f64 {
1024        let (_, y_scale) = self.transform.compute_scale().unwrap_or((1.0, 1.0));
1025        self.size.to_f64_px() * y_scale
1026    }
1027}
1028
1029#[repr(u32)]
1030#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
1031pub enum SubpixelDirection {
1032    None = 0,
1033    Horizontal,
1034    Vertical,
1035}
1036
1037impl SubpixelDirection {
1038    // Limit the subpixel direction to what is supported by the glyph format.
1039    pub fn limit_by(self, glyph_format: GlyphFormat) -> Self {
1040        match glyph_format {
1041            GlyphFormat::Bitmap |
1042            GlyphFormat::ColorBitmap => SubpixelDirection::None,
1043            _ => self,
1044        }
1045    }
1046
1047    pub fn swap_xy(self) -> Self {
1048        match self {
1049            SubpixelDirection::None => self,
1050            SubpixelDirection::Horizontal => SubpixelDirection::Vertical,
1051            SubpixelDirection::Vertical => SubpixelDirection::Horizontal,
1052        }
1053    }
1054}
1055
1056#[repr(u8)]
1057#[derive(Hash, Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1058#[cfg_attr(feature = "capture", derive(Serialize))]
1059#[cfg_attr(feature = "replay", derive(Deserialize))]
1060pub enum SubpixelOffset {
1061    Zero = 0,
1062    Quarter = 1,
1063    Half = 2,
1064    ThreeQuarters = 3,
1065}
1066
1067impl SubpixelOffset {
1068    // Skia quantizes subpixel offsets into 1/4 increments.
1069    // Given the absolute position, return the quantized increment
1070    fn quantize(pos: f32) -> Self {
1071        // Following the conventions of Gecko and Skia, we want
1072        // to quantize the subpixel position, such that abs(pos) gives:
1073        // [0.0, 0.125) -> Zero
1074        // [0.125, 0.375) -> Quarter
1075        // [0.375, 0.625) -> Half
1076        // [0.625, 0.875) -> ThreeQuarters,
1077        // [0.875, 1.0) -> Zero
1078        // The unit tests below check for this.
1079        let apos = ((pos - pos.floor()) * 8.0) as i32;
1080
1081        match apos {
1082            1..=2 => SubpixelOffset::Quarter,
1083            3..=4 => SubpixelOffset::Half,
1084            5..=6 => SubpixelOffset::ThreeQuarters,
1085            _ => SubpixelOffset::Zero,
1086        }
1087    }
1088}
1089
1090impl Into<f64> for SubpixelOffset {
1091    fn into(self) -> f64 {
1092        match self {
1093            SubpixelOffset::Zero => 0.0,
1094            SubpixelOffset::Quarter => 0.25,
1095            SubpixelOffset::Half => 0.5,
1096            SubpixelOffset::ThreeQuarters => 0.75,
1097        }
1098    }
1099}
1100
1101impl SubpixelOffset {
1102    fn to_f32(self) -> f32 {
1103        match self {
1104            SubpixelOffset::Zero => 0.0,
1105            SubpixelOffset::Quarter => 0.25,
1106            SubpixelOffset::Half => 0.5,
1107            SubpixelOffset::ThreeQuarters => 0.75,
1108        }
1109    }
1110}
1111
1112#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
1113#[cfg_attr(feature = "capture", derive(Serialize))]
1114#[cfg_attr(feature = "replay", derive(Deserialize))]
1115pub struct GlyphKey(u32);
1116
1117#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
1118#[cfg_attr(feature = "capture", derive(Serialize))]
1119#[cfg_attr(feature = "replay", derive(Deserialize))]
1120pub struct GlyphCacheKey(u32);
1121
1122impl GlyphKey {
1123    pub fn new(
1124        index: u32,
1125        point: DevicePoint,
1126        subpx_dir: SubpixelDirection,
1127    ) -> Self {
1128        let (dx, dy) = match subpx_dir {
1129            SubpixelDirection::None => (0.0, 0.0),
1130            SubpixelDirection::Horizontal => (point.x, 0.0),
1131            SubpixelDirection::Vertical => (0.0, point.y),
1132        };
1133        let sox = SubpixelOffset::quantize(dx);
1134        let soy = SubpixelOffset::quantize(dy);
1135        assert_eq!(0, index & 0xFC000000);
1136
1137        GlyphKey(index | (sox as u32) << 26 | (soy as u32) << 28 | (subpx_dir as u32) << 30)
1138    }
1139
1140    pub fn index(&self) -> GlyphIndex {
1141        self.0 & 0x03FFFFFF
1142    }
1143
1144    pub fn subpixel_offset(&self) -> (SubpixelOffset, SubpixelOffset) {
1145        let x = (self.0 >> 26) as u8 & 3;
1146        let y = (self.0 >> 28) as u8 & 3;
1147        unsafe {
1148            (mem::transmute(x), mem::transmute(y))
1149        }
1150    }
1151
1152    pub fn subpixel_dir(&self) -> SubpixelDirection {
1153        let dir = (self.0 >> 30) as u8 & 3;
1154        unsafe {
1155            mem::transmute(dir as u32)
1156        }
1157    }
1158
1159    pub fn cache_key(&self) -> GlyphCacheKey {
1160        let index = self.index();
1161        let subpx_dir = self.subpixel_dir();
1162        assert_eq!(0, index & 0xFC000000);
1163        GlyphCacheKey(index | (subpx_dir as u32) << 30)
1164    }
1165}
1166
1167impl GlyphCacheKey {
1168    pub fn index(&self) -> GlyphIndex {
1169        self.0 & 0x03FFFFFF
1170    }
1171
1172    pub fn subpixel_dir(&self) -> SubpixelDirection {
1173        let dir = ((self.0 >> 30) & 3) as u32;
1174        unsafe {
1175            mem::transmute(dir)
1176        }
1177    }
1178}
1179
1180#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
1181#[cfg_attr(feature = "capture", derive(Serialize))]
1182#[cfg_attr(feature = "replay", derive(Deserialize))]
1183#[allow(dead_code)]
1184pub enum GlyphFormat {
1185    Alpha,
1186    TransformedAlpha,
1187    Subpixel,
1188    TransformedSubpixel,
1189    Bitmap,
1190    ColorBitmap,
1191}
1192
1193impl GlyphFormat {
1194    /// Returns the ImageFormat that a glyph should be stored as in the texture cache.
1195    /// can_use_r8_format should be set false on platforms where we have encountered
1196    /// issues with R8 textures, so that we do not use them for glyphs.
1197    pub fn image_format(&self, can_use_r8_format: bool) -> ImageFormat {
1198        match *self {
1199            GlyphFormat::Alpha |
1200            GlyphFormat::TransformedAlpha |
1201            GlyphFormat::Bitmap => {
1202                if can_use_r8_format {
1203                    ImageFormat::R8
1204                } else {
1205                    ImageFormat::BGRA8
1206                }
1207            }
1208            GlyphFormat::Subpixel |
1209            GlyphFormat::TransformedSubpixel |
1210            GlyphFormat::ColorBitmap => ImageFormat::BGRA8,
1211        }
1212    }
1213}
1214
1215#[allow(dead_code)]
1216#[inline]
1217fn blend_strike_pixel(dest: u8, src: u32, src_alpha: u32) -> u8 {
1218    // Assume premultiplied alpha such that src and dest are already multiplied
1219    // by their respective alpha values and in range 0..=255. The rounded over
1220    // blend is then (src * 255 + dest * (255 - src_alpha) + 128) / 255.
1221    // We approximate (x + 128) / 255 as (x + 128 + ((x + 128) >> 8)) >> 8.
1222    let x = src * 255 + dest as u32 * (255 - src_alpha) + 128;
1223    ((x + (x >> 8)) >> 8) as u8
1224}
1225
1226// Blends a single strike at a given offset into a destination buffer, assuming
1227// the destination has been allocated with enough extra space to accommodate the
1228// offset.
1229#[allow(dead_code)]
1230fn blend_strike(
1231    dest_bitmap: &mut [u8],
1232    src_bitmap: &[u8],
1233    width: usize,
1234    height: usize,
1235    subpixel_mask: bool,
1236    offset: f64,
1237) {
1238    let dest_stride = dest_bitmap.len() / height;
1239    let src_stride = width * 4;
1240    let offset_integer = offset.floor() as usize * 4;
1241    let offset_fract = (offset.fract() * 256.0) as u32;
1242    for (src_row, dest_row) in src_bitmap.chunks(src_stride).zip(dest_bitmap.chunks_mut(dest_stride)) {
1243        let mut prev_px = [0u32; 4];
1244        let dest_row_offset = &mut dest_row[offset_integer .. offset_integer + src_stride];
1245        for (src, dest) in src_row.chunks(4).zip(dest_row_offset.chunks_mut(4)) {
1246            let px = [src[0] as u32, src[1] as u32, src[2] as u32, src[3] as u32];
1247            // Blend current pixel with previous pixel based on fractional offset.
1248            let next_px = [px[0] * offset_fract,
1249                           px[1] * offset_fract,
1250                           px[2] * offset_fract,
1251                           px[3] * offset_fract];
1252            let offset_px = [(((px[0] << 8) - next_px[0]) + prev_px[0] + 128) >> 8,
1253                             (((px[1] << 8) - next_px[1]) + prev_px[1] + 128) >> 8,
1254                             (((px[2] << 8) - next_px[2]) + prev_px[2] + 128) >> 8,
1255                             (((px[3] << 8) - next_px[3]) + prev_px[3] + 128) >> 8];
1256            if subpixel_mask {
1257                // Subpixel masks assume each component is an independent weight.
1258                dest[0] = blend_strike_pixel(dest[0], offset_px[0], offset_px[0]);
1259                dest[1] = blend_strike_pixel(dest[1], offset_px[1], offset_px[1]);
1260                dest[2] = blend_strike_pixel(dest[2], offset_px[2], offset_px[2]);
1261                dest[3] = blend_strike_pixel(dest[3], offset_px[3], offset_px[3]);
1262            } else {
1263                // Otherwise assume we have a premultiplied alpha BGRA value.
1264                dest[0] = blend_strike_pixel(dest[0], offset_px[0], offset_px[3]);
1265                dest[1] = blend_strike_pixel(dest[1], offset_px[1], offset_px[3]);
1266                dest[2] = blend_strike_pixel(dest[2], offset_px[2], offset_px[3]);
1267                dest[3] = blend_strike_pixel(dest[3], offset_px[3], offset_px[3]);
1268            }
1269            // Save the remainder for blending onto the next pixel.
1270            prev_px = next_px;
1271        }
1272        if offset_fract > 0 {
1273            // When there is fractional offset, there will be a remaining value
1274            // from the previous pixel but no next pixel, so just use that.
1275            let dest = &mut dest_row[offset_integer + src_stride .. ];
1276            let offset_px = [(prev_px[0] + 128) >> 8,
1277                             (prev_px[1] + 128) >> 8,
1278                             (prev_px[2] + 128) >> 8,
1279                             (prev_px[3] + 128) >> 8];
1280            if subpixel_mask {
1281                dest[0] = blend_strike_pixel(dest[0], offset_px[0], offset_px[0]);
1282                dest[1] = blend_strike_pixel(dest[1], offset_px[1], offset_px[1]);
1283                dest[2] = blend_strike_pixel(dest[2], offset_px[2], offset_px[2]);
1284                dest[3] = blend_strike_pixel(dest[3], offset_px[3], offset_px[3]);
1285            } else {
1286                dest[0] = blend_strike_pixel(dest[0], offset_px[0], offset_px[3]);
1287                dest[1] = blend_strike_pixel(dest[1], offset_px[1], offset_px[3]);
1288                dest[2] = blend_strike_pixel(dest[2], offset_px[2], offset_px[3]);
1289                dest[3] = blend_strike_pixel(dest[3], offset_px[3], offset_px[3]);
1290            }
1291        }
1292    }
1293}
1294
1295// Applies multistrike bold to a source bitmap. This assumes the source bitmap
1296// is a tighly packed slice of BGRA pixel values of exactly the specified width
1297// and height. The specified extra strikes and pixel step control where to put
1298// each strike. The pixel step is allowed to have a fractional offset and does
1299// not strictly need to be integer.
1300#[allow(dead_code)]
1301pub fn apply_multistrike_bold(
1302    src_bitmap: &[u8],
1303    width: usize,
1304    height: usize,
1305    subpixel_mask: bool,
1306    extra_strikes: usize,
1307    pixel_step: f64,
1308) -> (Vec<u8>, usize) {
1309    let src_stride = width * 4;
1310    // The amount of extra width added to the bitmap from the extra strikes.
1311    let extra_width = (extra_strikes as f64 * pixel_step).ceil() as usize;
1312    let dest_width = width + extra_width;
1313    let dest_stride = dest_width * 4;
1314    // Zero out the initial bitmap so any extra width is cleared.
1315    let mut dest_bitmap = vec![0u8; dest_stride * height];
1316    for (src_row, dest_row) in src_bitmap.chunks(src_stride).zip(dest_bitmap.chunks_mut(dest_stride)) {
1317        // Copy the initial bitmap strike rows directly from the source.
1318        dest_row[0 .. src_stride].copy_from_slice(src_row);
1319    }
1320    // Finally blend each extra strike in turn.
1321    for i in 1 ..= extra_strikes {
1322        let offset = i as f64 * pixel_step;
1323        blend_strike(&mut dest_bitmap, src_bitmap, width, height, subpixel_mask, offset);
1324    }
1325    (dest_bitmap, dest_width)
1326}
1327
1328pub struct RasterizedGlyph {
1329    pub top: f32,
1330    pub left: f32,
1331    pub width: i32,
1332    pub height: i32,
1333    pub scale: f32,
1334    pub format: GlyphFormat,
1335    pub bytes: Vec<u8>,
1336    pub is_packed_glyph: bool,
1337}
1338
1339impl RasterizedGlyph {
1340    #[allow(dead_code)]
1341    pub fn downscale_bitmap_if_required(&mut self, font: &FontInstance) {
1342        // Check if the glyph is going to be downscaled in the shader. If the scaling is
1343        // less than 0.5, that means bilinear filtering can't effectively filter the glyph
1344        // without aliasing artifacts.
1345        //
1346        // Instead of fixing this by mipmapping the glyph cache texture, rather manually
1347        // produce the appropriate mip level for individual glyphs where bilinear filtering
1348        // will still produce acceptable results.
1349        match self.format {
1350            GlyphFormat::Bitmap | GlyphFormat::ColorBitmap => {},
1351            _ => return,
1352        }
1353        let (x_scale, y_scale) = font.transform.compute_scale().unwrap_or((1.0, 1.0));
1354        let upscaled = x_scale.max(y_scale) as f32;
1355        let mut new_scale = self.scale;
1356        if new_scale * upscaled <= 0.0 {
1357            return;
1358        }
1359        let mut steps = 0;
1360        while new_scale * upscaled <= 0.5 {
1361            new_scale *= 2.0;
1362            steps += 1;
1363        }
1364        // If no mipping is necessary, just bail.
1365        if steps == 0 {
1366            return;
1367        }
1368
1369        // Calculate the actual size of the mip level.
1370        let new_width = (self.width as usize + (1 << steps) - 1) >> steps;
1371        let new_height = (self.height as usize + (1 << steps) - 1) >> steps;
1372        let mut new_bytes: Vec<u8> = Vec::with_capacity(new_width * new_height * 4);
1373
1374        // Produce destination pixels by applying a box filter to the source pixels.
1375        // The box filter corresponds to how graphics drivers may generate mipmaps.
1376        for y in 0 .. new_height {
1377            for x in 0 .. new_width {
1378                // Calculate the number of source samples that contribute to the destination pixel.
1379                let src_y = y << steps;
1380                let src_x = x << steps;
1381                let y_samples = (1 << steps).min(self.height as usize - src_y);
1382                let x_samples = (1 << steps).min(self.width as usize - src_x);
1383                let num_samples = (x_samples * y_samples) as u32;
1384
1385                let mut src_idx = (src_y * self.width as usize + src_x) * 4;
1386                // Initialize the accumulator with half an increment so that when later divided
1387                // by the sample count, it will effectively round the accumulator to the nearest
1388                // increment.
1389                let mut accum = [num_samples / 2; 4];
1390                // Accumulate all the contributing source sampless.
1391                for _ in 0 .. y_samples {
1392                    for _ in 0 .. x_samples {
1393                        accum[0] += self.bytes[src_idx + 0] as u32;
1394                        accum[1] += self.bytes[src_idx + 1] as u32;
1395                        accum[2] += self.bytes[src_idx + 2] as u32;
1396                        accum[3] += self.bytes[src_idx + 3] as u32;
1397                        src_idx += 4;
1398                    }
1399                    src_idx += (self.width as usize - x_samples) * 4;
1400                }
1401
1402                // Finally, divide by the sample count to get the mean value for the new pixel.
1403                new_bytes.extend_from_slice(&[
1404                    (accum[0] / num_samples) as u8,
1405                    (accum[1] / num_samples) as u8,
1406                    (accum[2] / num_samples) as u8,
1407                    (accum[3] / num_samples) as u8,
1408                ]);
1409            }
1410        }
1411
1412        // Fix the bounds for the new glyph data.
1413        self.top /= (1 << steps) as f32;
1414        self.left /= (1 << steps) as f32;
1415        self.width = new_width as i32;
1416        self.height = new_height as i32;
1417        self.scale = new_scale;
1418        self.bytes = new_bytes;
1419    }
1420}
1421
1422pub struct FontContexts {
1423    // These worker are mostly accessed from their corresponding worker threads.
1424    // The goal is that there should be no noticeable contention on the mutexes.
1425    worker_contexts: Vec<Mutex<FontContext>>,
1426    // Stored here as a convenience to get the current thread index.
1427    #[allow(dead_code)]
1428    workers: Arc<ThreadPool>,
1429    locked_mutex: Mutex<bool>,
1430    locked_cond: Condvar,
1431}
1432
1433impl FontContexts {
1434    /// Get access to any particular font context.
1435    ///
1436    /// The id is an index between 0 and num_worker_contexts for font contexts
1437    /// associated to the thread pool.
1438    pub fn lock_context(&self, id: usize) -> MutexGuard<FontContext> {
1439        self.worker_contexts[id].lock().unwrap()
1440    }
1441
1442    // Find a context that is currently unlocked to use, otherwise defaulting
1443    // to the first context.
1444    pub fn lock_any_context(&self) -> MutexGuard<FontContext> {
1445        for context in &self.worker_contexts {
1446            if let Ok(mutex) = context.try_lock() {
1447                return mutex;
1448            }
1449        }
1450        self.lock_context(0)
1451    }
1452
1453    // number of contexts associated to workers
1454    pub fn num_worker_contexts(&self) -> usize {
1455        self.worker_contexts.len()
1456    }
1457}
1458
1459pub trait AsyncForEach<T> {
1460    fn async_for_each<F: Fn(MutexGuard<T>) + Send + 'static>(&self, f: F);
1461}
1462
1463impl AsyncForEach<FontContext> for Arc<FontContexts> {
1464    fn async_for_each<F: Fn(MutexGuard<FontContext>) + Send + 'static>(&self, f: F) {
1465        // Reset the locked condition.
1466        let mut locked = self.locked_mutex.lock().unwrap();
1467        *locked = false;
1468
1469        // Arc that can be safely moved into a spawn closure.
1470        let font_contexts = self.clone();
1471        // Spawn a new thread on which to run the for-each off the main thread.
1472        self.workers.spawn(move || {
1473            // Lock the shared and worker contexts up front.
1474            let mut locks = Vec::with_capacity(font_contexts.num_worker_contexts());
1475            for i in 0 .. font_contexts.num_worker_contexts() {
1476                locks.push(font_contexts.lock_context(i));
1477            }
1478
1479            // Signal the locked condition now that all contexts are locked.
1480            *font_contexts.locked_mutex.lock().unwrap() = true;
1481            font_contexts.locked_cond.notify_all();
1482
1483            // Now that everything is locked, proceed to processing each locked context.
1484            for context in locks {
1485                f(context);
1486            }
1487        });
1488
1489        // Wait for locked condition before resuming. Safe to proceed thereafter
1490        // since any other thread that needs to use a FontContext will try to lock
1491        // it first.
1492        while !*locked {
1493            locked = self.locked_cond.wait(locked).unwrap();
1494        }
1495    }
1496}
1497
1498pub struct GlyphRasterizer {
1499    #[allow(dead_code)]
1500    workers: Arc<ThreadPool>,
1501    font_contexts: Arc<FontContexts>,
1502    dedicated_thread: Option<GlyphRasterThread>,
1503
1504    /// The current set of loaded fonts.
1505    fonts: FastHashSet<FontKey>,
1506
1507    /// The current number of individual glyphs waiting in pending batches.
1508    pending_glyph_count: usize,
1509
1510    /// The current number of glyph request jobs that have been kicked to worker threads.
1511    pending_glyph_jobs: usize,
1512
1513    /// The number of glyphs requested this frame.
1514    glyph_request_count: usize,
1515
1516    /// A map of current glyph request batches.
1517    pending_glyph_requests: FastHashMap<FontInstance, SmallVec<[GlyphKey; 16]>>,
1518
1519    // Receives the rendered glyphs.
1520    glyph_rx: Receiver<GlyphRasterJob>,
1521    glyph_tx: Sender<GlyphRasterJob>,
1522
1523    // We defer removing fonts to the end of the frame so that:
1524    // - this work is done outside of the critical path,
1525    // - we don't have to worry about the ordering of events if a font is used on
1526    //   a frame where it is used (although it seems unlikely).
1527    fonts_to_remove: Vec<FontKey>,
1528    // Defer removal of font instances, as for fonts.
1529    font_instances_to_remove: Vec<FontInstance>,
1530
1531    // Whether to parallelize glyph rasterization with rayon.
1532    enable_multithreading: bool,
1533
1534    // Whether glyphs can be rasterized in r8 format when it makes sense.
1535    can_use_r8_format: bool,
1536}
1537
1538impl GlyphRasterizer {
1539    pub fn new(workers: Arc<ThreadPool>, dedicated_thread: Option<GlyphRasterThread>, can_use_r8_format: bool) -> Self {
1540        let (glyph_tx, glyph_rx) = unbounded();
1541
1542        let num_workers = workers.current_num_threads();
1543        let mut contexts = Vec::with_capacity(num_workers);
1544
1545        for _ in 0 .. num_workers {
1546            contexts.push(Mutex::new(FontContext::new()));
1547        }
1548
1549        let font_context = FontContexts {
1550            worker_contexts: contexts,
1551            workers: Arc::clone(&workers),
1552            locked_mutex: Mutex::new(false),
1553            locked_cond: Condvar::new(),
1554        };
1555
1556        GlyphRasterizer {
1557            font_contexts: Arc::new(font_context),
1558            fonts: FastHashSet::default(),
1559            dedicated_thread,
1560            pending_glyph_jobs: 0,
1561            pending_glyph_count: 0,
1562            glyph_request_count: 0,
1563            glyph_rx,
1564            glyph_tx,
1565            workers,
1566            fonts_to_remove: Vec::new(),
1567            font_instances_to_remove: Vec::new(),
1568            enable_multithreading: true,
1569            pending_glyph_requests: FastHashMap::default(),
1570            can_use_r8_format,
1571        }
1572    }
1573
1574    pub fn add_font(&mut self, font_key: FontKey, template: FontTemplate) {
1575        // Only add font to FontContexts if not previously added.
1576        if self.fonts.insert(font_key.clone()) {
1577            if let Some(thread) = &self.dedicated_thread {
1578                let _ = thread.tx.send(GlyphRasterMsg::AddFont { font_key, template });
1579            } else {
1580                self.font_contexts.async_for_each(move |mut context| {
1581                    context.add_font(&font_key, &template);
1582                });
1583            }
1584        }
1585    }
1586
1587    pub fn delete_font(&mut self, font_key: FontKey) {
1588        self.fonts_to_remove.push(font_key);
1589    }
1590
1591    pub fn delete_fonts(&mut self, font_keys: &[FontKey]) {
1592        self.fonts_to_remove.extend_from_slice(font_keys);
1593    }
1594
1595    pub fn delete_font_instance(&mut self, instance: &FontInstance) {
1596        self.font_instances_to_remove.push(instance.clone());
1597    }
1598
1599    pub fn prepare_font(&self, font: &mut FontInstance) {
1600        FontContext::prepare_font(font);
1601
1602        // Quantize the transform to minimize thrashing of the glyph cache, but
1603        // only quantize the transform when preparing to access the glyph cache.
1604        // This way, the glyph subpixel positions, which are calculated before
1605        // this, can still use the precise transform which is required to match
1606        // the subpixel positions computed for glyphs in the text run shader.
1607        font.transform = font.transform.quantize();
1608    }
1609
1610    pub fn has_font(&self, font_key: FontKey) -> bool {
1611        self.fonts.contains(&font_key)
1612    }
1613
1614    pub fn get_glyph_dimensions(
1615        &mut self,
1616        font: &FontInstance,
1617        glyph_index: GlyphIndex,
1618    ) -> Option<GlyphDimensions> {
1619        let glyph_key = GlyphKey::new(
1620            glyph_index,
1621            DevicePoint::zero(),
1622            SubpixelDirection::None,
1623        );
1624
1625        self.font_contexts
1626            .lock_any_context()
1627            .get_glyph_dimensions(font, &glyph_key)
1628    }
1629
1630    pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
1631        self.font_contexts
1632            .lock_any_context()
1633            .get_glyph_index(font_key, ch)
1634    }
1635
1636    fn remove_dead_fonts(&mut self) {
1637        if self.fonts_to_remove.is_empty() && self.font_instances_to_remove.is_empty() {
1638            return
1639        }
1640
1641        profile_scope!("remove_dead_fonts");
1642        let mut fonts_to_remove = mem::replace(& mut self.fonts_to_remove, Vec::new());
1643        // Only remove font from FontContexts if previously added.
1644        fonts_to_remove.retain(|font| self.fonts.remove(font));
1645        let font_instances_to_remove = mem::replace(& mut self.font_instances_to_remove, Vec::new());
1646        if let Some(thread) = &self.dedicated_thread {
1647            for font_key in fonts_to_remove {
1648                let _ = thread.tx.send(GlyphRasterMsg::DeleteFont { font_key });
1649            }
1650            for instance in font_instances_to_remove {
1651                let _ = thread.tx.send(GlyphRasterMsg::DeleteFontInstance { instance });
1652            }
1653        } else {
1654            self.font_contexts.async_for_each(move |mut context| {
1655                for font_key in &fonts_to_remove {
1656                    context.delete_font(font_key);
1657                }
1658                for instance in &font_instances_to_remove {
1659                    context.delete_font_instance(instance);
1660                }
1661            });
1662        }
1663    }
1664
1665    #[cfg(feature = "replay")]
1666    pub fn reset(&mut self) {
1667        //TODO: any signals need to be sent to the workers?
1668        self.pending_glyph_jobs = 0;
1669        self.pending_glyph_count = 0;
1670        self.glyph_request_count = 0;
1671        self.fonts_to_remove.clear();
1672        self.font_instances_to_remove.clear();
1673    }
1674}
1675
1676trait AddFont {
1677    fn add_font(&mut self, font_key: &FontKey, template: &FontTemplate);
1678}
1679
1680impl AddFont for FontContext {
1681    fn add_font(&mut self, font_key: &FontKey, template: &FontTemplate) {
1682        match *template {
1683            FontTemplate::Raw(ref bytes, index) => {
1684                self.add_raw_font(font_key, bytes.clone(), index);
1685            }
1686            FontTemplate::Native(ref native_font_handle) => {
1687                self.add_native_font(font_key, (*native_font_handle).clone());
1688            }
1689        }
1690    }
1691}
1692
1693#[allow(dead_code)]
1694pub struct GlyphRasterJob {
1695    pub font: Arc<FontInstance>,
1696    pub key: GlyphKey,
1697    pub result: GlyphRasterResult,
1698}
1699
1700#[allow(dead_code)]
1701#[derive(Debug)]
1702pub enum GlyphRasterError {
1703    LoadFailed,
1704}
1705
1706#[allow(dead_code)]
1707pub type GlyphRasterResult = Result<RasterizedGlyph, GlyphRasterError>;
1708
1709#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
1710#[cfg_attr(feature = "capture", derive(Serialize))]
1711#[cfg_attr(feature = "replay", derive(Deserialize))]
1712pub struct GpuGlyphCacheKey(pub u32);
1713
1714fn pack_glyph_variants_horizontal(variants: &[RasterizedGlyph]) -> RasterizedGlyph {
1715    // Pack 4 glyph variants horizontally into a single texture.
1716    // Normalize both left and top offsets via padding so all variants can use the same base offsets.
1717
1718    let min_left = variants.iter().map(|v| v.left.floor()).fold(f32::INFINITY, f32::min);
1719    let max_top = variants.iter().map(|v| v.top.floor()).fold(f32::NEG_INFINITY, f32::max);
1720
1721    // Slot width must accommodate the widest variant plus left padding
1722    let slot_width = variants.iter()
1723        .map(|v| v.width + (v.left.floor() - min_left) as i32)
1724        .max().unwrap();
1725
1726    // Slot height must accommodate the tallest variant plus top padding
1727    let slot_height = variants.iter()
1728        .map(|v| v.height + (max_top - v.top.floor()) as i32)
1729        .max().unwrap();
1730
1731    let packed_width = slot_width * 4;
1732    let bpp = 4;
1733
1734    let mut packed_bytes = vec![0u8; (packed_width * slot_height * bpp) as usize];
1735
1736    for (variant_idx, variant) in variants.iter().enumerate() {
1737        // Compute padding needed to normalize both left and top offsets
1738        let left_pad = (variant.left.floor() - min_left) as i32;
1739        let top_pad = (max_top - variant.top.floor()) as i32;
1740        let slot_x = variant_idx as i32 * slot_width;
1741
1742        for src_y in 0..variant.height {
1743            let dst_y = src_y + top_pad;
1744            if dst_y >= slot_height {
1745                break;
1746            }
1747
1748            let dst_x = slot_x + left_pad;
1749            if dst_x < 0 {
1750                continue;
1751            }
1752
1753            let src_row_start = (src_y * variant.width * bpp) as usize;
1754            let src_row_end = src_row_start + (variant.width * bpp) as usize;
1755            let dst_row_start = (dst_y * packed_width * bpp + dst_x * bpp) as usize;
1756            let dst_row_end = dst_row_start + (variant.width * bpp) as usize;
1757
1758            if dst_row_end <= packed_bytes.len() && src_row_end <= variant.bytes.len() {
1759                packed_bytes[dst_row_start..dst_row_end]
1760                    .copy_from_slice(&variant.bytes[src_row_start..src_row_end]);
1761            }
1762        }
1763    }
1764
1765    RasterizedGlyph {
1766        top: max_top,
1767        left: min_left,
1768        width: packed_width,
1769        height: slot_height,
1770        scale: variants[0].scale,
1771        format: variants[0].format,
1772        bytes: packed_bytes,
1773        is_packed_glyph: true,
1774    }
1775}
1776
1777fn process_glyph(
1778    context: &mut FontContext,
1779    can_use_r8_format: bool,
1780    font: Arc<FontInstance>,
1781    key: GlyphKey,
1782) -> GlyphRasterJob {
1783    profile_scope!("glyph-raster");
1784
1785    let subpx_dir = key.subpixel_dir();
1786
1787    let result = if subpx_dir == SubpixelDirection::None {
1788        context.rasterize_glyph(&font, &key)
1789    } else {
1790        let offsets = [
1791            SubpixelOffset::Zero,
1792            SubpixelOffset::Quarter,
1793            SubpixelOffset::Half,
1794            SubpixelOffset::ThreeQuarters,
1795        ];
1796
1797        let mut variants = Vec::with_capacity(4);
1798        for offset in &offsets {
1799            let variant_key = GlyphKey::new(
1800                key.index(),
1801                match subpx_dir {
1802                    SubpixelDirection::Horizontal => DevicePoint::new(offset.to_f32(), 0.0),
1803                    SubpixelDirection::Vertical => DevicePoint::new(0.0, offset.to_f32()),
1804                    SubpixelDirection::None => DevicePoint::zero(),
1805                },
1806                subpx_dir,
1807            );
1808
1809            match context.rasterize_glyph(&font, &variant_key) {
1810                Ok(glyph) => variants.push(glyph),
1811                Err(e) => return GlyphRasterJob {
1812                    font: font,
1813                    key: key.clone(),
1814                    result: Err(e),
1815                },
1816            }
1817        }
1818
1819        Ok(pack_glyph_variants_horizontal(&variants))
1820    };
1821
1822    let mut job = GlyphRasterJob {
1823        font: font,
1824        key: key.clone(),
1825        result,
1826    };
1827
1828    if let Ok(ref mut glyph) = job.result {
1829        // Sanity check.
1830        let bpp = 4; // We always render glyphs in 32 bits RGBA format.
1831        assert_eq!(
1832            glyph.bytes.len(),
1833            bpp * (glyph.width * glyph.height) as usize
1834        );
1835
1836        // a quick-and-dirty monochrome over
1837        fn over(dst: u8, src: u8) -> u8 {
1838            let a = src as u32;
1839            let a = 256 - a;
1840            let dst = ((dst as u32 * a) >> 8) as u8;
1841            src + dst
1842        }
1843
1844        if GLYPH_FLASHING.load(Ordering::Relaxed) {
1845            let color = (random() & 0xff) as u8;
1846            for i in &mut glyph.bytes {
1847                *i = over(*i, color);
1848            }
1849        }
1850
1851        assert_eq!((glyph.left.fract(), glyph.top.fract()), (0.0, 0.0));
1852
1853        // Check if the glyph has a bitmap that needs to be downscaled.
1854        glyph.downscale_bitmap_if_required(&job.font);
1855
1856        // Convert from BGRA8 to R8 if required. In the future we can make it the
1857        // backends' responsibility to output glyphs in the desired format,
1858        // potentially reducing the number of copies.
1859        if glyph.format.image_format(can_use_r8_format).bytes_per_pixel() == 1 {
1860            glyph.bytes = glyph.bytes
1861                .chunks_mut(4)
1862                .map(|pixel| pixel[3])
1863                .collect::<Vec<_>>();
1864        }
1865    }
1866
1867    job
1868}
1869
1870
1871pub enum GlyphRasterMsg {
1872    Rasterize {
1873        font: Arc<FontInstance>,
1874        glyphs: SmallVec<[GlyphKey; 16]>,
1875        can_use_r8_format: bool,
1876        tx: Sender<GlyphRasterJob>,
1877    },
1878    AddFont { font_key: FontKey, template: FontTemplate },
1879    DeleteFont { font_key: FontKey },
1880    DeleteFontInstance { instance: FontInstance },
1881    ShutDown,
1882}
1883
1884#[derive(Clone)]
1885pub struct GlyphRasterThread {
1886    tx: Sender<GlyphRasterMsg>,
1887}
1888
1889impl GlyphRasterThread {
1890    pub fn new(
1891        on_start: impl FnOnce() + Send + 'static,
1892        on_end: impl FnOnce() + Send+ 'static,
1893    ) -> std::io::Result<Self> {
1894        let (tx, rx) = unbounded();
1895
1896        std::thread::Builder::new().name("Glyph rasterizer".to_string()).spawn(move || {
1897            on_start();
1898
1899            let mut context = FontContext::new();
1900
1901            loop {
1902                match rx.recv() {
1903                    Ok(GlyphRasterMsg::Rasterize { font, glyphs, can_use_r8_format, tx }) => {
1904                        for glyph in &glyphs {
1905                            let job = process_glyph(&mut context, can_use_r8_format, font.clone(), *glyph);
1906                            let _ = tx.send(job);
1907                        }
1908                    }
1909                    Ok(GlyphRasterMsg::AddFont { font_key, template }) => {
1910                        context.add_font(&font_key, &template)
1911                    }
1912                    Ok(GlyphRasterMsg::DeleteFont { font_key }) => {
1913                        context.delete_font(&font_key)
1914                    }
1915                    Ok(GlyphRasterMsg::DeleteFontInstance { instance }) => {
1916                        context.delete_font_instance(&instance)
1917                    }
1918                    Ok(GlyphRasterMsg::ShutDown) => {
1919                        break;
1920                    }
1921                    Err(..) => {
1922                        break;
1923                    }
1924                }
1925            }
1926
1927            on_end();
1928        })?;
1929
1930        Ok(GlyphRasterThread {
1931            tx,
1932        })
1933    }
1934
1935    pub fn shut_down(&self) {
1936        let _ = self.tx.send(GlyphRasterMsg::ShutDown);
1937    }
1938}
1939
1940#[cfg(test)]
1941mod test_glyph_rasterizer {
1942    use crate::profiler::GlyphRasterizeProfiler;
1943
1944    struct Profiler;
1945    impl GlyphRasterizeProfiler for Profiler {
1946        fn start_time(&mut self) {}
1947        fn end_time(&mut self) -> f64 {
1948            0.
1949        }
1950        fn set(&mut self, _value: f64) {}
1951    }
1952
1953    #[test]
1954    fn rasterize_200_glyphs() {
1955        // This test loads a font from disc, the renders 4 requests containing
1956        // 50 glyphs each, deletes the font and waits for the result.
1957
1958        use rayon::ThreadPoolBuilder;
1959        use std::fs::File;
1960        use std::io::Read;
1961        use api::{FontKey, FontInstanceKey, FontTemplate, IdNamespace};
1962        use api::units::DevicePoint;
1963        use std::sync::Arc;
1964        use crate::rasterizer::{FontInstance, BaseFontInstance, GlyphKey, GlyphRasterizer};
1965
1966        let worker = ThreadPoolBuilder::new()
1967            .thread_name(|idx|{ format!("WRWorker#{}", idx) })
1968            .build();
1969        let workers = Arc::new(worker.unwrap());
1970        let mut glyph_rasterizer = GlyphRasterizer::new(workers, None, true);
1971        let mut font_file =
1972            File::open("../wrench/reftests/text/VeraBd.ttf").expect("Couldn't open font file");
1973        let mut font_data = vec![];
1974        font_file
1975            .read_to_end(&mut font_data)
1976            .expect("failed to read font file");
1977
1978        let font_key = FontKey::new(IdNamespace(0), 0);
1979        glyph_rasterizer.add_font(font_key, FontTemplate::Raw(Arc::new(font_data), 0));
1980
1981        let font = FontInstance::from_base(Arc::new(BaseFontInstance::new(
1982            FontInstanceKey::new(IdNamespace(0), 0),
1983            font_key,
1984            32.0,
1985            None,
1986            None,
1987            Vec::new(),
1988        )));
1989
1990        let subpx_dir = font.get_subpx_dir();
1991
1992        let mut glyph_keys = Vec::with_capacity(200);
1993        for i in 0 .. 200 {
1994            glyph_keys.push(GlyphKey::new(
1995                i,
1996                DevicePoint::zero(),
1997                subpx_dir,
1998            ));
1999        }
2000
2001        for i in 0 .. 4 {
2002            glyph_rasterizer.request_glyphs(
2003                font.clone(),
2004                &glyph_keys[(50 * i) .. (50 * (i + 1))],
2005                |_| true,
2006            );
2007        }
2008
2009        glyph_rasterizer.delete_font(font_key);
2010
2011        glyph_rasterizer.resolve_glyphs(
2012            |_, _| {},
2013            &mut Profiler,
2014        );
2015    }
2016
2017    #[test]
2018    fn rasterize_large_glyphs() {
2019        // This test loads a font from disc and rasterize a few glyphs with a size of 200px to check
2020        // that the texture cache handles them properly.
2021        use rayon::ThreadPoolBuilder;
2022        use std::fs::File;
2023        use std::io::Read;
2024        use api::{FontKey, FontInstanceKey, FontTemplate, IdNamespace};
2025        use api::units::DevicePoint;
2026        use std::sync::Arc;
2027        use crate::rasterizer::{FontInstance, BaseFontInstance, GlyphKey, GlyphRasterizer};
2028
2029        let worker = ThreadPoolBuilder::new()
2030            .thread_name(|idx|{ format!("WRWorker#{}", idx) })
2031            .build();
2032        let workers = Arc::new(worker.unwrap());
2033        let mut glyph_rasterizer = GlyphRasterizer::new(workers, None, true);
2034        let mut font_file =
2035            File::open("../wrench/reftests/text/VeraBd.ttf").expect("Couldn't open font file");
2036        let mut font_data = vec![];
2037        font_file
2038            .read_to_end(&mut font_data)
2039            .expect("failed to read font file");
2040
2041        let font_key = FontKey::new(IdNamespace(0), 0);
2042        glyph_rasterizer.add_font(font_key, FontTemplate::Raw(Arc::new(font_data), 0));
2043
2044        let font = FontInstance::from_base(Arc::new(BaseFontInstance::new(
2045            FontInstanceKey::new(IdNamespace(0), 0),
2046            font_key,
2047            200.0,
2048            None,
2049            None,
2050            Vec::new(),
2051        )));
2052
2053        let subpx_dir = font.get_subpx_dir();
2054
2055        let mut glyph_keys = Vec::with_capacity(10);
2056        for i in 0 .. 10 {
2057            glyph_keys.push(GlyphKey::new(
2058                i,
2059                DevicePoint::zero(),
2060                subpx_dir,
2061            ));
2062        }
2063
2064        glyph_rasterizer.request_glyphs(
2065            font.clone(),
2066            &glyph_keys,
2067            |_| true,
2068        );
2069
2070        glyph_rasterizer.delete_font(font_key);
2071
2072        glyph_rasterizer.resolve_glyphs(
2073            |_, _| {},
2074            &mut Profiler,
2075        );
2076    }
2077
2078    #[test]
2079    fn test_subpx_quantize() {
2080        use crate::rasterizer::SubpixelOffset;
2081
2082        assert_eq!(SubpixelOffset::quantize(0.0), SubpixelOffset::Zero);
2083        assert_eq!(SubpixelOffset::quantize(-0.0), SubpixelOffset::Zero);
2084
2085        assert_eq!(SubpixelOffset::quantize(0.1), SubpixelOffset::Zero);
2086        assert_eq!(SubpixelOffset::quantize(0.01), SubpixelOffset::Zero);
2087        assert_eq!(SubpixelOffset::quantize(0.05), SubpixelOffset::Zero);
2088        assert_eq!(SubpixelOffset::quantize(0.12), SubpixelOffset::Zero);
2089        assert_eq!(SubpixelOffset::quantize(0.124), SubpixelOffset::Zero);
2090
2091        assert_eq!(SubpixelOffset::quantize(0.125), SubpixelOffset::Quarter);
2092        assert_eq!(SubpixelOffset::quantize(0.2), SubpixelOffset::Quarter);
2093        assert_eq!(SubpixelOffset::quantize(0.25), SubpixelOffset::Quarter);
2094        assert_eq!(SubpixelOffset::quantize(0.33), SubpixelOffset::Quarter);
2095        assert_eq!(SubpixelOffset::quantize(0.374), SubpixelOffset::Quarter);
2096
2097        assert_eq!(SubpixelOffset::quantize(0.375), SubpixelOffset::Half);
2098        assert_eq!(SubpixelOffset::quantize(0.4), SubpixelOffset::Half);
2099        assert_eq!(SubpixelOffset::quantize(0.5), SubpixelOffset::Half);
2100        assert_eq!(SubpixelOffset::quantize(0.58), SubpixelOffset::Half);
2101        assert_eq!(SubpixelOffset::quantize(0.624), SubpixelOffset::Half);
2102
2103        assert_eq!(SubpixelOffset::quantize(0.625), SubpixelOffset::ThreeQuarters);
2104        assert_eq!(SubpixelOffset::quantize(0.67), SubpixelOffset::ThreeQuarters);
2105        assert_eq!(SubpixelOffset::quantize(0.7), SubpixelOffset::ThreeQuarters);
2106        assert_eq!(SubpixelOffset::quantize(0.78), SubpixelOffset::ThreeQuarters);
2107        assert_eq!(SubpixelOffset::quantize(0.874), SubpixelOffset::ThreeQuarters);
2108
2109        assert_eq!(SubpixelOffset::quantize(0.875), SubpixelOffset::Zero);
2110        assert_eq!(SubpixelOffset::quantize(0.89), SubpixelOffset::Zero);
2111        assert_eq!(SubpixelOffset::quantize(0.91), SubpixelOffset::Zero);
2112        assert_eq!(SubpixelOffset::quantize(0.967), SubpixelOffset::Zero);
2113        assert_eq!(SubpixelOffset::quantize(0.999), SubpixelOffset::Zero);
2114
2115        assert_eq!(SubpixelOffset::quantize(-1.0), SubpixelOffset::Zero);
2116        assert_eq!(SubpixelOffset::quantize(1.0), SubpixelOffset::Zero);
2117        assert_eq!(SubpixelOffset::quantize(1.5), SubpixelOffset::Half);
2118        assert_eq!(SubpixelOffset::quantize(-1.625), SubpixelOffset::Half);
2119        assert_eq!(SubpixelOffset::quantize(-4.33), SubpixelOffset::ThreeQuarters);
2120    }
2121}