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            // Use subpixel precision on all axes
384            SubpixelDirection::Mixed
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    Mixed,
1036}
1037
1038impl SubpixelDirection {
1039    // Limit the subpixel direction to what is supported by the glyph format.
1040    pub fn limit_by(self, glyph_format: GlyphFormat) -> Self {
1041        match glyph_format {
1042            GlyphFormat::Bitmap |
1043            GlyphFormat::ColorBitmap => SubpixelDirection::None,
1044            _ => self,
1045        }
1046    }
1047
1048    pub fn swap_xy(self) -> Self {
1049        match self {
1050            SubpixelDirection::None | SubpixelDirection::Mixed => self,
1051            SubpixelDirection::Horizontal => SubpixelDirection::Vertical,
1052            SubpixelDirection::Vertical => SubpixelDirection::Horizontal,
1053        }
1054    }
1055}
1056
1057#[repr(u8)]
1058#[derive(Hash, Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1059#[cfg_attr(feature = "capture", derive(Serialize))]
1060#[cfg_attr(feature = "replay", derive(Deserialize))]
1061pub enum SubpixelOffset {
1062    Zero = 0,
1063    Quarter = 1,
1064    Half = 2,
1065    ThreeQuarters = 3,
1066}
1067
1068impl SubpixelOffset {
1069    // Skia quantizes subpixel offsets into 1/4 increments.
1070    // Given the absolute position, return the quantized increment
1071    fn quantize(pos: f32) -> Self {
1072        // Following the conventions of Gecko and Skia, we want
1073        // to quantize the subpixel position, such that abs(pos) gives:
1074        // [0.0, 0.125) -> Zero
1075        // [0.125, 0.375) -> Quarter
1076        // [0.375, 0.625) -> Half
1077        // [0.625, 0.875) -> ThreeQuarters,
1078        // [0.875, 1.0) -> Zero
1079        // The unit tests below check for this.
1080        let apos = ((pos - pos.floor()) * 8.0) as i32;
1081
1082        match apos {
1083            1..=2 => SubpixelOffset::Quarter,
1084            3..=4 => SubpixelOffset::Half,
1085            5..=6 => SubpixelOffset::ThreeQuarters,
1086            _ => SubpixelOffset::Zero,
1087        }
1088    }
1089}
1090
1091impl Into<f64> for SubpixelOffset {
1092    fn into(self) -> f64 {
1093        match self {
1094            SubpixelOffset::Zero => 0.0,
1095            SubpixelOffset::Quarter => 0.25,
1096            SubpixelOffset::Half => 0.5,
1097            SubpixelOffset::ThreeQuarters => 0.75,
1098        }
1099    }
1100}
1101
1102#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
1103#[cfg_attr(feature = "capture", derive(Serialize))]
1104#[cfg_attr(feature = "replay", derive(Deserialize))]
1105pub struct GlyphKey(u32);
1106
1107impl GlyphKey {
1108    pub fn new(
1109        index: u32,
1110        point: DevicePoint,
1111        subpx_dir: SubpixelDirection,
1112    ) -> Self {
1113        let (dx, dy) = match subpx_dir {
1114            SubpixelDirection::None => (0.0, 0.0),
1115            SubpixelDirection::Horizontal => (point.x, 0.0),
1116            SubpixelDirection::Vertical => (0.0, point.y),
1117            SubpixelDirection::Mixed => (point.x, point.y),
1118        };
1119        let sox = SubpixelOffset::quantize(dx);
1120        let soy = SubpixelOffset::quantize(dy);
1121        assert_eq!(0, index & 0xF0000000);
1122
1123        GlyphKey(index | (sox as u32) << 28 | (soy as u32) << 30)
1124    }
1125
1126    pub fn index(&self) -> GlyphIndex {
1127        self.0 & 0x0FFFFFFF
1128    }
1129
1130    fn subpixel_offset(&self) -> (SubpixelOffset, SubpixelOffset) {
1131        let x = (self.0 >> 28) as u8 & 3;
1132        let y = (self.0 >> 30) as u8 & 3;
1133        unsafe {
1134            (mem::transmute(x), mem::transmute(y))
1135        }
1136    }
1137}
1138
1139#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
1140#[cfg_attr(feature = "capture", derive(Serialize))]
1141#[cfg_attr(feature = "replay", derive(Deserialize))]
1142#[allow(dead_code)]
1143pub enum GlyphFormat {
1144    Alpha,
1145    TransformedAlpha,
1146    Subpixel,
1147    TransformedSubpixel,
1148    Bitmap,
1149    ColorBitmap,
1150}
1151
1152impl GlyphFormat {
1153    /// Returns the ImageFormat that a glyph should be stored as in the texture cache.
1154    /// can_use_r8_format should be set false on platforms where we have encountered
1155    /// issues with R8 textures, so that we do not use them for glyphs.
1156    pub fn image_format(&self, can_use_r8_format: bool) -> ImageFormat {
1157        match *self {
1158            GlyphFormat::Alpha |
1159            GlyphFormat::TransformedAlpha |
1160            GlyphFormat::Bitmap => {
1161                if can_use_r8_format {
1162                    ImageFormat::R8
1163                } else {
1164                    ImageFormat::BGRA8
1165                }
1166            }
1167            GlyphFormat::Subpixel |
1168            GlyphFormat::TransformedSubpixel |
1169            GlyphFormat::ColorBitmap => ImageFormat::BGRA8,
1170        }
1171    }
1172}
1173
1174#[allow(dead_code)]
1175#[inline]
1176fn blend_strike_pixel(dest: u8, src: u32, src_alpha: u32) -> u8 {
1177    // Assume premultiplied alpha such that src and dest are already multiplied
1178    // by their respective alpha values and in range 0..=255. The rounded over
1179    // blend is then (src * 255 + dest * (255 - src_alpha) + 128) / 255.
1180    // We approximate (x + 128) / 255 as (x + 128 + ((x + 128) >> 8)) >> 8.
1181    let x = src * 255 + dest as u32 * (255 - src_alpha) + 128;
1182    ((x + (x >> 8)) >> 8) as u8
1183}
1184
1185// Blends a single strike at a given offset into a destination buffer, assuming
1186// the destination has been allocated with enough extra space to accommodate the
1187// offset.
1188#[allow(dead_code)]
1189fn blend_strike(
1190    dest_bitmap: &mut [u8],
1191    src_bitmap: &[u8],
1192    width: usize,
1193    height: usize,
1194    subpixel_mask: bool,
1195    offset: f64,
1196) {
1197    let dest_stride = dest_bitmap.len() / height;
1198    let src_stride = width * 4;
1199    let offset_integer = offset.floor() as usize * 4;
1200    let offset_fract = (offset.fract() * 256.0) as u32;
1201    for (src_row, dest_row) in src_bitmap.chunks(src_stride).zip(dest_bitmap.chunks_mut(dest_stride)) {
1202        let mut prev_px = [0u32; 4];
1203        let dest_row_offset = &mut dest_row[offset_integer .. offset_integer + src_stride];
1204        for (src, dest) in src_row.chunks(4).zip(dest_row_offset.chunks_mut(4)) {
1205            let px = [src[0] as u32, src[1] as u32, src[2] as u32, src[3] as u32];
1206            // Blend current pixel with previous pixel based on fractional offset.
1207            let next_px = [px[0] * offset_fract,
1208                           px[1] * offset_fract,
1209                           px[2] * offset_fract,
1210                           px[3] * offset_fract];
1211            let offset_px = [(((px[0] << 8) - next_px[0]) + prev_px[0] + 128) >> 8,
1212                             (((px[1] << 8) - next_px[1]) + prev_px[1] + 128) >> 8,
1213                             (((px[2] << 8) - next_px[2]) + prev_px[2] + 128) >> 8,
1214                             (((px[3] << 8) - next_px[3]) + prev_px[3] + 128) >> 8];
1215            if subpixel_mask {
1216                // Subpixel masks assume each component is an independent weight.
1217                dest[0] = blend_strike_pixel(dest[0], offset_px[0], offset_px[0]);
1218                dest[1] = blend_strike_pixel(dest[1], offset_px[1], offset_px[1]);
1219                dest[2] = blend_strike_pixel(dest[2], offset_px[2], offset_px[2]);
1220                dest[3] = blend_strike_pixel(dest[3], offset_px[3], offset_px[3]);
1221            } else {
1222                // Otherwise assume we have a premultiplied alpha BGRA value.
1223                dest[0] = blend_strike_pixel(dest[0], offset_px[0], offset_px[3]);
1224                dest[1] = blend_strike_pixel(dest[1], offset_px[1], offset_px[3]);
1225                dest[2] = blend_strike_pixel(dest[2], offset_px[2], offset_px[3]);
1226                dest[3] = blend_strike_pixel(dest[3], offset_px[3], offset_px[3]);
1227            }
1228            // Save the remainder for blending onto the next pixel.
1229            prev_px = next_px;
1230        }
1231        if offset_fract > 0 {
1232            // When there is fractional offset, there will be a remaining value
1233            // from the previous pixel but no next pixel, so just use that.
1234            let dest = &mut dest_row[offset_integer + src_stride .. ];
1235            let offset_px = [(prev_px[0] + 128) >> 8,
1236                             (prev_px[1] + 128) >> 8,
1237                             (prev_px[2] + 128) >> 8,
1238                             (prev_px[3] + 128) >> 8];
1239            if subpixel_mask {
1240                dest[0] = blend_strike_pixel(dest[0], offset_px[0], offset_px[0]);
1241                dest[1] = blend_strike_pixel(dest[1], offset_px[1], offset_px[1]);
1242                dest[2] = blend_strike_pixel(dest[2], offset_px[2], offset_px[2]);
1243                dest[3] = blend_strike_pixel(dest[3], offset_px[3], offset_px[3]);
1244            } else {
1245                dest[0] = blend_strike_pixel(dest[0], offset_px[0], offset_px[3]);
1246                dest[1] = blend_strike_pixel(dest[1], offset_px[1], offset_px[3]);
1247                dest[2] = blend_strike_pixel(dest[2], offset_px[2], offset_px[3]);
1248                dest[3] = blend_strike_pixel(dest[3], offset_px[3], offset_px[3]);
1249            }
1250        }
1251    }
1252}
1253
1254// Applies multistrike bold to a source bitmap. This assumes the source bitmap
1255// is a tighly packed slice of BGRA pixel values of exactly the specified width
1256// and height. The specified extra strikes and pixel step control where to put
1257// each strike. The pixel step is allowed to have a fractional offset and does
1258// not strictly need to be integer.
1259#[allow(dead_code)]
1260pub fn apply_multistrike_bold(
1261    src_bitmap: &[u8],
1262    width: usize,
1263    height: usize,
1264    subpixel_mask: bool,
1265    extra_strikes: usize,
1266    pixel_step: f64,
1267) -> (Vec<u8>, usize) {
1268    let src_stride = width * 4;
1269    // The amount of extra width added to the bitmap from the extra strikes.
1270    let extra_width = (extra_strikes as f64 * pixel_step).ceil() as usize;
1271    let dest_width = width + extra_width;
1272    let dest_stride = dest_width * 4;
1273    // Zero out the initial bitmap so any extra width is cleared.
1274    let mut dest_bitmap = vec![0u8; dest_stride * height];
1275    for (src_row, dest_row) in src_bitmap.chunks(src_stride).zip(dest_bitmap.chunks_mut(dest_stride)) {
1276        // Copy the initial bitmap strike rows directly from the source.
1277        dest_row[0 .. src_stride].copy_from_slice(src_row);
1278    }
1279    // Finally blend each extra strike in turn.
1280    for i in 1 ..= extra_strikes {
1281        let offset = i as f64 * pixel_step;
1282        blend_strike(&mut dest_bitmap, src_bitmap, width, height, subpixel_mask, offset);
1283    }
1284    (dest_bitmap, dest_width)
1285}
1286
1287pub struct RasterizedGlyph {
1288    pub top: f32,
1289    pub left: f32,
1290    pub width: i32,
1291    pub height: i32,
1292    pub scale: f32,
1293    pub format: GlyphFormat,
1294    pub bytes: Vec<u8>,
1295}
1296
1297impl RasterizedGlyph {
1298    #[allow(dead_code)]
1299    pub fn downscale_bitmap_if_required(&mut self, font: &FontInstance) {
1300        // Check if the glyph is going to be downscaled in the shader. If the scaling is
1301        // less than 0.5, that means bilinear filtering can't effectively filter the glyph
1302        // without aliasing artifacts.
1303        //
1304        // Instead of fixing this by mipmapping the glyph cache texture, rather manually
1305        // produce the appropriate mip level for individual glyphs where bilinear filtering
1306        // will still produce acceptable results.
1307        match self.format {
1308            GlyphFormat::Bitmap | GlyphFormat::ColorBitmap => {},
1309            _ => return,
1310        }
1311        let (x_scale, y_scale) = font.transform.compute_scale().unwrap_or((1.0, 1.0));
1312        let upscaled = x_scale.max(y_scale) as f32;
1313        let mut new_scale = self.scale;
1314        if new_scale * upscaled <= 0.0 {
1315            return;
1316        }
1317        let mut steps = 0;
1318        while new_scale * upscaled <= 0.5 {
1319            new_scale *= 2.0;
1320            steps += 1;
1321        }
1322        // If no mipping is necessary, just bail.
1323        if steps == 0 {
1324            return;
1325        }
1326
1327        // Calculate the actual size of the mip level.
1328        let new_width = (self.width as usize + (1 << steps) - 1) >> steps;
1329        let new_height = (self.height as usize + (1 << steps) - 1) >> steps;
1330        let mut new_bytes: Vec<u8> = Vec::with_capacity(new_width * new_height * 4);
1331
1332        // Produce destination pixels by applying a box filter to the source pixels.
1333        // The box filter corresponds to how graphics drivers may generate mipmaps.
1334        for y in 0 .. new_height {
1335            for x in 0 .. new_width {
1336                // Calculate the number of source samples that contribute to the destination pixel.
1337                let src_y = y << steps;
1338                let src_x = x << steps;
1339                let y_samples = (1 << steps).min(self.height as usize - src_y);
1340                let x_samples = (1 << steps).min(self.width as usize - src_x);
1341                let num_samples = (x_samples * y_samples) as u32;
1342
1343                let mut src_idx = (src_y * self.width as usize + src_x) * 4;
1344                // Initialize the accumulator with half an increment so that when later divided
1345                // by the sample count, it will effectively round the accumulator to the nearest
1346                // increment.
1347                let mut accum = [num_samples / 2; 4];
1348                // Accumulate all the contributing source sampless.
1349                for _ in 0 .. y_samples {
1350                    for _ in 0 .. x_samples {
1351                        accum[0] += self.bytes[src_idx + 0] as u32;
1352                        accum[1] += self.bytes[src_idx + 1] as u32;
1353                        accum[2] += self.bytes[src_idx + 2] as u32;
1354                        accum[3] += self.bytes[src_idx + 3] as u32;
1355                        src_idx += 4;
1356                    }
1357                    src_idx += (self.width as usize - x_samples) * 4;
1358                }
1359
1360                // Finally, divide by the sample count to get the mean value for the new pixel.
1361                new_bytes.extend_from_slice(&[
1362                    (accum[0] / num_samples) as u8,
1363                    (accum[1] / num_samples) as u8,
1364                    (accum[2] / num_samples) as u8,
1365                    (accum[3] / num_samples) as u8,
1366                ]);
1367            }
1368        }
1369
1370        // Fix the bounds for the new glyph data.
1371        self.top /= (1 << steps) as f32;
1372        self.left /= (1 << steps) as f32;
1373        self.width = new_width as i32;
1374        self.height = new_height as i32;
1375        self.scale = new_scale;
1376        self.bytes = new_bytes;
1377    }
1378}
1379
1380pub struct FontContexts {
1381    // These worker are mostly accessed from their corresponding worker threads.
1382    // The goal is that there should be no noticeable contention on the mutexes.
1383    worker_contexts: Vec<Mutex<FontContext>>,
1384    // Stored here as a convenience to get the current thread index.
1385    #[allow(dead_code)]
1386    workers: Arc<ThreadPool>,
1387    locked_mutex: Mutex<bool>,
1388    locked_cond: Condvar,
1389}
1390
1391impl FontContexts {
1392    /// Get access to any particular font context.
1393    ///
1394    /// The id is an index between 0 and num_worker_contexts for font contexts
1395    /// associated to the thread pool.
1396    pub fn lock_context(&self, id: usize) -> MutexGuard<FontContext> {
1397        self.worker_contexts[id].lock().unwrap()
1398    }
1399
1400    // Find a context that is currently unlocked to use, otherwise defaulting
1401    // to the first context.
1402    pub fn lock_any_context(&self) -> MutexGuard<FontContext> {
1403        for context in &self.worker_contexts {
1404            if let Ok(mutex) = context.try_lock() {
1405                return mutex;
1406            }
1407        }
1408        self.lock_context(0)
1409    }
1410
1411    // number of contexts associated to workers
1412    pub fn num_worker_contexts(&self) -> usize {
1413        self.worker_contexts.len()
1414    }
1415}
1416
1417pub trait AsyncForEach<T> {
1418    fn async_for_each<F: Fn(MutexGuard<T>) + Send + 'static>(&self, f: F);
1419}
1420
1421impl AsyncForEach<FontContext> for Arc<FontContexts> {
1422    fn async_for_each<F: Fn(MutexGuard<FontContext>) + Send + 'static>(&self, f: F) {
1423        // Reset the locked condition.
1424        let mut locked = self.locked_mutex.lock().unwrap();
1425        *locked = false;
1426
1427        // Arc that can be safely moved into a spawn closure.
1428        let font_contexts = self.clone();
1429        // Spawn a new thread on which to run the for-each off the main thread.
1430        self.workers.spawn(move || {
1431            // Lock the shared and worker contexts up front.
1432            let mut locks = Vec::with_capacity(font_contexts.num_worker_contexts());
1433            for i in 0 .. font_contexts.num_worker_contexts() {
1434                locks.push(font_contexts.lock_context(i));
1435            }
1436
1437            // Signal the locked condition now that all contexts are locked.
1438            *font_contexts.locked_mutex.lock().unwrap() = true;
1439            font_contexts.locked_cond.notify_all();
1440
1441            // Now that everything is locked, proceed to processing each locked context.
1442            for context in locks {
1443                f(context);
1444            }
1445        });
1446
1447        // Wait for locked condition before resuming. Safe to proceed thereafter
1448        // since any other thread that needs to use a FontContext will try to lock
1449        // it first.
1450        while !*locked {
1451            locked = self.locked_cond.wait(locked).unwrap();
1452        }
1453    }
1454}
1455
1456pub struct GlyphRasterizer {
1457    #[allow(dead_code)]
1458    workers: Arc<ThreadPool>,
1459    font_contexts: Arc<FontContexts>,
1460    dedicated_thread: Option<GlyphRasterThread>,
1461
1462    /// The current set of loaded fonts.
1463    fonts: FastHashSet<FontKey>,
1464
1465    /// The current number of individual glyphs waiting in pending batches.
1466    pending_glyph_count: usize,
1467
1468    /// The current number of glyph request jobs that have been kicked to worker threads.
1469    pending_glyph_jobs: usize,
1470
1471    /// The number of glyphs requested this frame.
1472    glyph_request_count: usize,
1473
1474    /// A map of current glyph request batches.
1475    pending_glyph_requests: FastHashMap<FontInstance, SmallVec<[GlyphKey; 16]>>,
1476
1477    // Receives the rendered glyphs.
1478    glyph_rx: Receiver<GlyphRasterJob>,
1479    glyph_tx: Sender<GlyphRasterJob>,
1480
1481    // We defer removing fonts to the end of the frame so that:
1482    // - this work is done outside of the critical path,
1483    // - we don't have to worry about the ordering of events if a font is used on
1484    //   a frame where it is used (although it seems unlikely).
1485    fonts_to_remove: Vec<FontKey>,
1486    // Defer removal of font instances, as for fonts.
1487    font_instances_to_remove: Vec<FontInstance>,
1488
1489    // Whether to parallelize glyph rasterization with rayon.
1490    enable_multithreading: bool,
1491
1492    // Whether glyphs can be rasterized in r8 format when it makes sense.
1493    can_use_r8_format: bool,
1494}
1495
1496impl GlyphRasterizer {
1497    pub fn new(workers: Arc<ThreadPool>, dedicated_thread: Option<GlyphRasterThread>, can_use_r8_format: bool) -> Self {
1498        let (glyph_tx, glyph_rx) = unbounded();
1499
1500        let num_workers = workers.current_num_threads();
1501        let mut contexts = Vec::with_capacity(num_workers);
1502
1503        for _ in 0 .. num_workers {
1504            contexts.push(Mutex::new(FontContext::new()));
1505        }
1506
1507        let font_context = FontContexts {
1508            worker_contexts: contexts,
1509            workers: Arc::clone(&workers),
1510            locked_mutex: Mutex::new(false),
1511            locked_cond: Condvar::new(),
1512        };
1513
1514        GlyphRasterizer {
1515            font_contexts: Arc::new(font_context),
1516            fonts: FastHashSet::default(),
1517            dedicated_thread,
1518            pending_glyph_jobs: 0,
1519            pending_glyph_count: 0,
1520            glyph_request_count: 0,
1521            glyph_rx,
1522            glyph_tx,
1523            workers,
1524            fonts_to_remove: Vec::new(),
1525            font_instances_to_remove: Vec::new(),
1526            enable_multithreading: true,
1527            pending_glyph_requests: FastHashMap::default(),
1528            can_use_r8_format,
1529        }
1530    }
1531
1532    pub fn add_font(&mut self, font_key: FontKey, template: FontTemplate) {
1533        // Only add font to FontContexts if not previously added.
1534        if self.fonts.insert(font_key.clone()) {
1535            if let Some(thread) = &self.dedicated_thread {
1536                let _ = thread.tx.send(GlyphRasterMsg::AddFont { font_key, template });
1537            } else {
1538                self.font_contexts.async_for_each(move |mut context| {
1539                    context.add_font(&font_key, &template);
1540                });
1541            }
1542        }
1543    }
1544
1545    pub fn delete_font(&mut self, font_key: FontKey) {
1546        self.fonts_to_remove.push(font_key);
1547    }
1548
1549    pub fn delete_fonts(&mut self, font_keys: &[FontKey]) {
1550        self.fonts_to_remove.extend_from_slice(font_keys);
1551    }
1552
1553    pub fn delete_font_instance(&mut self, instance: &FontInstance) {
1554        self.font_instances_to_remove.push(instance.clone());
1555    }
1556
1557    pub fn prepare_font(&self, font: &mut FontInstance) {
1558        FontContext::prepare_font(font);
1559
1560        // Quantize the transform to minimize thrashing of the glyph cache, but
1561        // only quantize the transform when preparing to access the glyph cache.
1562        // This way, the glyph subpixel positions, which are calculated before
1563        // this, can still use the precise transform which is required to match
1564        // the subpixel positions computed for glyphs in the text run shader.
1565        font.transform = font.transform.quantize();
1566    }
1567
1568    pub fn has_font(&self, font_key: FontKey) -> bool {
1569        self.fonts.contains(&font_key)
1570    }
1571
1572    pub fn get_glyph_dimensions(
1573        &mut self,
1574        font: &FontInstance,
1575        glyph_index: GlyphIndex,
1576    ) -> Option<GlyphDimensions> {
1577        let glyph_key = GlyphKey::new(
1578            glyph_index,
1579            DevicePoint::zero(),
1580            SubpixelDirection::None,
1581        );
1582
1583        self.font_contexts
1584            .lock_any_context()
1585            .get_glyph_dimensions(font, &glyph_key)
1586    }
1587
1588    pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
1589        self.font_contexts
1590            .lock_any_context()
1591            .get_glyph_index(font_key, ch)
1592    }
1593
1594    fn remove_dead_fonts(&mut self) {
1595        if self.fonts_to_remove.is_empty() && self.font_instances_to_remove.is_empty() {
1596            return
1597        }
1598
1599        profile_scope!("remove_dead_fonts");
1600        let mut fonts_to_remove = mem::replace(& mut self.fonts_to_remove, Vec::new());
1601        // Only remove font from FontContexts if previously added.
1602        fonts_to_remove.retain(|font| self.fonts.remove(font));
1603        let font_instances_to_remove = mem::replace(& mut self.font_instances_to_remove, Vec::new());
1604        if let Some(thread) = &self.dedicated_thread {
1605            for font_key in fonts_to_remove {
1606                let _ = thread.tx.send(GlyphRasterMsg::DeleteFont { font_key });
1607            }
1608            for instance in font_instances_to_remove {
1609                let _ = thread.tx.send(GlyphRasterMsg::DeleteFontInstance { instance });
1610            }
1611        } else {
1612            self.font_contexts.async_for_each(move |mut context| {
1613                for font_key in &fonts_to_remove {
1614                    context.delete_font(font_key);
1615                }
1616                for instance in &font_instances_to_remove {
1617                    context.delete_font_instance(instance);
1618                }
1619            });
1620        }
1621    }
1622
1623    #[cfg(feature = "replay")]
1624    pub fn reset(&mut self) {
1625        //TODO: any signals need to be sent to the workers?
1626        self.pending_glyph_jobs = 0;
1627        self.pending_glyph_count = 0;
1628        self.glyph_request_count = 0;
1629        self.fonts_to_remove.clear();
1630        self.font_instances_to_remove.clear();
1631    }
1632}
1633
1634trait AddFont {
1635    fn add_font(&mut self, font_key: &FontKey, template: &FontTemplate);
1636}
1637
1638impl AddFont for FontContext {
1639    fn add_font(&mut self, font_key: &FontKey, template: &FontTemplate) {
1640        match *template {
1641            FontTemplate::Raw(ref bytes, index) => {
1642                self.add_raw_font(font_key, bytes.clone(), index);
1643            }
1644            FontTemplate::Native(ref native_font_handle) => {
1645                self.add_native_font(font_key, (*native_font_handle).clone());
1646            }
1647        }
1648    }
1649}
1650
1651#[allow(dead_code)]
1652pub struct GlyphRasterJob {
1653    pub font: Arc<FontInstance>,
1654    pub key: GlyphKey,
1655    pub result: GlyphRasterResult,
1656}
1657
1658#[allow(dead_code)]
1659#[derive(Debug)]
1660pub enum GlyphRasterError {
1661    LoadFailed,
1662}
1663
1664#[allow(dead_code)]
1665pub type GlyphRasterResult = Result<RasterizedGlyph, GlyphRasterError>;
1666
1667#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
1668#[cfg_attr(feature = "capture", derive(Serialize))]
1669#[cfg_attr(feature = "replay", derive(Deserialize))]
1670pub struct GpuGlyphCacheKey(pub u32);
1671
1672fn process_glyph(
1673    context: &mut FontContext,
1674    can_use_r8_format: bool,
1675    font: Arc<FontInstance>,
1676    key: GlyphKey,
1677) -> GlyphRasterJob {
1678    profile_scope!("glyph-raster");
1679    let result = context.rasterize_glyph(&font, &key);
1680    let mut job = GlyphRasterJob {
1681        font: font,
1682        key: key.clone(),
1683        result,
1684    };
1685
1686    if let Ok(ref mut glyph) = job.result {
1687        // Sanity check.
1688        let bpp = 4; // We always render glyphs in 32 bits RGBA format.
1689        assert_eq!(
1690            glyph.bytes.len(),
1691            bpp * (glyph.width * glyph.height) as usize
1692        );
1693
1694        // a quick-and-dirty monochrome over
1695        fn over(dst: u8, src: u8) -> u8 {
1696            let a = src as u32;
1697            let a = 256 - a;
1698            let dst = ((dst as u32 * a) >> 8) as u8;
1699            src + dst
1700        }
1701
1702        if GLYPH_FLASHING.load(Ordering::Relaxed) {
1703            let color = (random() & 0xff) as u8;
1704            for i in &mut glyph.bytes {
1705                *i = over(*i, color);
1706            }
1707        }
1708
1709        assert_eq!((glyph.left.fract(), glyph.top.fract()), (0.0, 0.0));
1710
1711        // Check if the glyph has a bitmap that needs to be downscaled.
1712        glyph.downscale_bitmap_if_required(&job.font);
1713
1714        // Convert from BGRA8 to R8 if required. In the future we can make it the
1715        // backends' responsibility to output glyphs in the desired format,
1716        // potentially reducing the number of copies.
1717        if glyph.format.image_format(can_use_r8_format).bytes_per_pixel() == 1 {
1718            glyph.bytes = glyph.bytes
1719                .chunks_mut(4)
1720                .map(|pixel| pixel[3])
1721                .collect::<Vec<_>>();
1722        }
1723    }
1724
1725    job
1726}
1727
1728
1729pub enum GlyphRasterMsg {
1730    Rasterize {
1731        font: Arc<FontInstance>,
1732        glyphs: SmallVec<[GlyphKey; 16]>,
1733        can_use_r8_format: bool,
1734        tx: Sender<GlyphRasterJob>,
1735    },
1736    AddFont { font_key: FontKey, template: FontTemplate },
1737    DeleteFont { font_key: FontKey },
1738    DeleteFontInstance { instance: FontInstance },
1739    ShutDown,
1740}
1741
1742#[derive(Clone)]
1743pub struct GlyphRasterThread {
1744    tx: Sender<GlyphRasterMsg>,
1745}
1746
1747impl GlyphRasterThread {
1748    pub fn new(
1749        on_start: impl FnOnce() + Send + 'static,
1750        on_end: impl FnOnce() + Send+ 'static,
1751    ) -> std::io::Result<Self> {
1752        let (tx, rx) = unbounded();
1753
1754        std::thread::Builder::new().name("Glyph rasterizer".to_string()).spawn(move || {
1755            on_start();
1756
1757            let mut context = FontContext::new();
1758
1759            loop {
1760                match rx.recv() {
1761                    Ok(GlyphRasterMsg::Rasterize { font, glyphs, can_use_r8_format, tx }) => {
1762                        for glyph in &glyphs {
1763                            let job = process_glyph(&mut context, can_use_r8_format, font.clone(), *glyph);
1764                            let _ = tx.send(job);
1765                        }
1766                    }
1767                    Ok(GlyphRasterMsg::AddFont { font_key, template }) => {
1768                        context.add_font(&font_key, &template)
1769                    }
1770                    Ok(GlyphRasterMsg::DeleteFont { font_key }) => {
1771                        context.delete_font(&font_key)
1772                    }
1773                    Ok(GlyphRasterMsg::DeleteFontInstance { instance }) => {
1774                        context.delete_font_instance(&instance)
1775                    }
1776                    Ok(GlyphRasterMsg::ShutDown) => {
1777                        break;
1778                    }
1779                    Err(..) => {
1780                        break;
1781                    }
1782                }
1783            }
1784
1785            on_end();
1786        })?;
1787
1788        Ok(GlyphRasterThread {
1789            tx,
1790        })
1791    }
1792
1793    pub fn shut_down(&self) {
1794        let _ = self.tx.send(GlyphRasterMsg::ShutDown);
1795    }
1796}
1797
1798#[cfg(test)]
1799mod test_glyph_rasterizer {
1800    use crate::profiler::GlyphRasterizeProfiler;
1801
1802    struct Profiler;
1803    impl GlyphRasterizeProfiler for Profiler {
1804        fn start_time(&mut self) {}
1805        fn end_time(&mut self) -> f64 {
1806            0.
1807        }
1808        fn set(&mut self, _value: f64) {}
1809    }
1810
1811    #[test]
1812    fn rasterize_200_glyphs() {
1813        // This test loads a font from disc, the renders 4 requests containing
1814        // 50 glyphs each, deletes the font and waits for the result.
1815
1816        use rayon::ThreadPoolBuilder;
1817        use std::fs::File;
1818        use std::io::Read;
1819        use api::{FontKey, FontInstanceKey, FontTemplate, IdNamespace};
1820        use api::units::DevicePoint;
1821        use std::sync::Arc;
1822        use crate::rasterizer::{FontInstance, BaseFontInstance, GlyphKey, GlyphRasterizer};
1823
1824        let worker = ThreadPoolBuilder::new()
1825            .thread_name(|idx|{ format!("WRWorker#{}", idx) })
1826            .build();
1827        let workers = Arc::new(worker.unwrap());
1828        let mut glyph_rasterizer = GlyphRasterizer::new(workers, None, true);
1829        let mut font_file =
1830            File::open("../wrench/reftests/text/VeraBd.ttf").expect("Couldn't open font file");
1831        let mut font_data = vec![];
1832        font_file
1833            .read_to_end(&mut font_data)
1834            .expect("failed to read font file");
1835
1836        let font_key = FontKey::new(IdNamespace(0), 0);
1837        glyph_rasterizer.add_font(font_key, FontTemplate::Raw(Arc::new(font_data), 0));
1838
1839        let font = FontInstance::from_base(Arc::new(BaseFontInstance::new(
1840            FontInstanceKey::new(IdNamespace(0), 0),
1841            font_key,
1842            32.0,
1843            None,
1844            None,
1845            Vec::new(),
1846        )));
1847
1848        let subpx_dir = font.get_subpx_dir();
1849
1850        let mut glyph_keys = Vec::with_capacity(200);
1851        for i in 0 .. 200 {
1852            glyph_keys.push(GlyphKey::new(
1853                i,
1854                DevicePoint::zero(),
1855                subpx_dir,
1856            ));
1857        }
1858
1859        for i in 0 .. 4 {
1860            glyph_rasterizer.request_glyphs(
1861                font.clone(),
1862                &glyph_keys[(50 * i) .. (50 * (i + 1))],
1863                |_| true,
1864            );
1865        }
1866
1867        glyph_rasterizer.delete_font(font_key);
1868
1869        glyph_rasterizer.resolve_glyphs(
1870            |_, _| {},
1871            &mut Profiler,
1872        );
1873    }
1874
1875    #[test]
1876    fn rasterize_large_glyphs() {
1877        // This test loads a font from disc and rasterize a few glyphs with a size of 200px to check
1878        // that the texture cache handles them properly.
1879        use rayon::ThreadPoolBuilder;
1880        use std::fs::File;
1881        use std::io::Read;
1882        use api::{FontKey, FontInstanceKey, FontTemplate, IdNamespace};
1883        use api::units::DevicePoint;
1884        use std::sync::Arc;
1885        use crate::rasterizer::{FontInstance, BaseFontInstance, GlyphKey, GlyphRasterizer};
1886
1887        let worker = ThreadPoolBuilder::new()
1888            .thread_name(|idx|{ format!("WRWorker#{}", idx) })
1889            .build();
1890        let workers = Arc::new(worker.unwrap());
1891        let mut glyph_rasterizer = GlyphRasterizer::new(workers, None, true);
1892        let mut font_file =
1893            File::open("../wrench/reftests/text/VeraBd.ttf").expect("Couldn't open font file");
1894        let mut font_data = vec![];
1895        font_file
1896            .read_to_end(&mut font_data)
1897            .expect("failed to read font file");
1898
1899        let font_key = FontKey::new(IdNamespace(0), 0);
1900        glyph_rasterizer.add_font(font_key, FontTemplate::Raw(Arc::new(font_data), 0));
1901
1902        let font = FontInstance::from_base(Arc::new(BaseFontInstance::new(
1903            FontInstanceKey::new(IdNamespace(0), 0),
1904            font_key,
1905            200.0,
1906            None,
1907            None,
1908            Vec::new(),
1909        )));
1910
1911        let subpx_dir = font.get_subpx_dir();
1912
1913        let mut glyph_keys = Vec::with_capacity(10);
1914        for i in 0 .. 10 {
1915            glyph_keys.push(GlyphKey::new(
1916                i,
1917                DevicePoint::zero(),
1918                subpx_dir,
1919            ));
1920        }
1921
1922        glyph_rasterizer.request_glyphs(
1923            font.clone(),
1924            &glyph_keys,
1925            |_| true,
1926        );
1927
1928        glyph_rasterizer.delete_font(font_key);
1929
1930        glyph_rasterizer.resolve_glyphs(
1931            |_, _| {},
1932            &mut Profiler,
1933        );
1934    }
1935
1936    #[test]
1937    fn test_subpx_quantize() {
1938        use crate::rasterizer::SubpixelOffset;
1939
1940        assert_eq!(SubpixelOffset::quantize(0.0), SubpixelOffset::Zero);
1941        assert_eq!(SubpixelOffset::quantize(-0.0), SubpixelOffset::Zero);
1942
1943        assert_eq!(SubpixelOffset::quantize(0.1), SubpixelOffset::Zero);
1944        assert_eq!(SubpixelOffset::quantize(0.01), SubpixelOffset::Zero);
1945        assert_eq!(SubpixelOffset::quantize(0.05), SubpixelOffset::Zero);
1946        assert_eq!(SubpixelOffset::quantize(0.12), SubpixelOffset::Zero);
1947        assert_eq!(SubpixelOffset::quantize(0.124), SubpixelOffset::Zero);
1948
1949        assert_eq!(SubpixelOffset::quantize(0.125), SubpixelOffset::Quarter);
1950        assert_eq!(SubpixelOffset::quantize(0.2), SubpixelOffset::Quarter);
1951        assert_eq!(SubpixelOffset::quantize(0.25), SubpixelOffset::Quarter);
1952        assert_eq!(SubpixelOffset::quantize(0.33), SubpixelOffset::Quarter);
1953        assert_eq!(SubpixelOffset::quantize(0.374), SubpixelOffset::Quarter);
1954
1955        assert_eq!(SubpixelOffset::quantize(0.375), SubpixelOffset::Half);
1956        assert_eq!(SubpixelOffset::quantize(0.4), SubpixelOffset::Half);
1957        assert_eq!(SubpixelOffset::quantize(0.5), SubpixelOffset::Half);
1958        assert_eq!(SubpixelOffset::quantize(0.58), SubpixelOffset::Half);
1959        assert_eq!(SubpixelOffset::quantize(0.624), SubpixelOffset::Half);
1960
1961        assert_eq!(SubpixelOffset::quantize(0.625), SubpixelOffset::ThreeQuarters);
1962        assert_eq!(SubpixelOffset::quantize(0.67), SubpixelOffset::ThreeQuarters);
1963        assert_eq!(SubpixelOffset::quantize(0.7), SubpixelOffset::ThreeQuarters);
1964        assert_eq!(SubpixelOffset::quantize(0.78), SubpixelOffset::ThreeQuarters);
1965        assert_eq!(SubpixelOffset::quantize(0.874), SubpixelOffset::ThreeQuarters);
1966
1967        assert_eq!(SubpixelOffset::quantize(0.875), SubpixelOffset::Zero);
1968        assert_eq!(SubpixelOffset::quantize(0.89), SubpixelOffset::Zero);
1969        assert_eq!(SubpixelOffset::quantize(0.91), SubpixelOffset::Zero);
1970        assert_eq!(SubpixelOffset::quantize(0.967), SubpixelOffset::Zero);
1971        assert_eq!(SubpixelOffset::quantize(0.999), SubpixelOffset::Zero);
1972
1973        assert_eq!(SubpixelOffset::quantize(-1.0), SubpixelOffset::Zero);
1974        assert_eq!(SubpixelOffset::quantize(1.0), SubpixelOffset::Zero);
1975        assert_eq!(SubpixelOffset::quantize(1.5), SubpixelOffset::Half);
1976        assert_eq!(SubpixelOffset::quantize(-1.625), SubpixelOffset::Half);
1977        assert_eq!(SubpixelOffset::quantize(-4.33), SubpixelOffset::ThreeQuarters);
1978    }
1979}