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 
5 use api::{ColorF, ColorU, DevicePoint};
6 use api::{FontInstanceFlags, FontInstancePlatformOptions};
7 use api::{FontKey, FontRenderMode, FontTemplate, FontVariation};
8 use api::{GlyphIndex, GlyphDimensions, SyntheticItalics};
9 use api::{LayoutPoint, LayoutToWorldTransform, WorldPoint};
10 use app_units::Au;
11 use euclid::approxeq::ApproxEq;
12 use internal_types::ResourceCacheError;
13 use platform::font::FontContext;
14 use rayon::ThreadPool;
15 use std::cmp;
16 use std::hash::{Hash, Hasher};
17 use std::mem;
18 use std::sync::{Arc, Condvar, Mutex, MutexGuard};
19 use std::sync::mpsc::{channel, Receiver, Sender};
20 
21 #[cfg(feature = "pathfinder")]
22 mod pathfinder;
23 #[cfg(feature = "pathfinder")]
24 use self::pathfinder::create_pathfinder_font_context;
25 #[cfg(feature = "pathfinder")]
26 pub use self::pathfinder::{ThreadSafePathfinderFontContext, NativeFontHandleWrapper};
27 
28 #[cfg(not(feature = "pathfinder"))]
29 mod no_pathfinder;
30 
31 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd)]
32 #[cfg_attr(feature = "capture", derive(Serialize))]
33 #[cfg_attr(feature = "replay", derive(Deserialize))]
34 pub struct FontTransform {
35     pub scale_x: f32,
36     pub skew_x: f32,
37     pub skew_y: f32,
38     pub scale_y: f32,
39 }
40 
41 // Floats don't impl Hash/Eq/Ord...
42 impl Eq for FontTransform {}
43 impl Ord for FontTransform {
cmp(&self, other: &Self) -> cmp::Ordering44     fn cmp(&self, other: &Self) -> cmp::Ordering {
45         self.partial_cmp(other).unwrap_or(cmp::Ordering::Equal)
46     }
47 }
48 impl Hash for FontTransform {
hash<H: Hasher>(&self, state: &mut H)49     fn hash<H: Hasher>(&self, state: &mut H) {
50         // Note: this is inconsistent with the Eq impl for -0.0 (don't care).
51         self.scale_x.to_bits().hash(state);
52         self.skew_x.to_bits().hash(state);
53         self.skew_y.to_bits().hash(state);
54         self.scale_y.to_bits().hash(state);
55     }
56 }
57 
58 impl FontTransform {
59     const QUANTIZE_SCALE: f32 = 1024.0;
60 
new(scale_x: f32, skew_x: f32, skew_y: f32, scale_y: f32) -> Self61     pub fn new(scale_x: f32, skew_x: f32, skew_y: f32, scale_y: f32) -> Self {
62         FontTransform { scale_x, skew_x, skew_y, scale_y }
63     }
64 
identity() -> Self65     pub fn identity() -> Self {
66         FontTransform::new(1.0, 0.0, 0.0, 1.0)
67     }
68 
is_identity(&self) -> bool69     pub fn is_identity(&self) -> bool {
70         *self == FontTransform::identity()
71     }
72 
quantize(&self) -> Self73     pub fn quantize(&self) -> Self {
74         FontTransform::new(
75             (self.scale_x * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE,
76             (self.skew_x * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE,
77             (self.skew_y * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE,
78             (self.scale_y * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE,
79         )
80     }
81 
82     #[allow(dead_code)]
determinant(&self) -> f6483     pub fn determinant(&self) -> f64 {
84         self.scale_x as f64 * self.scale_y as f64 - self.skew_y as f64 * self.skew_x as f64
85     }
86 
87     #[allow(dead_code)]
compute_scale(&self) -> Option<(f64, f64)>88     pub fn compute_scale(&self) -> Option<(f64, f64)> {
89         let det = self.determinant();
90         if det != 0.0 {
91             let x_scale = (self.scale_x as f64).hypot(self.skew_y as f64);
92             let y_scale = det.abs() / x_scale;
93             Some((x_scale, y_scale))
94         } else {
95             None
96         }
97     }
98 
99     #[allow(dead_code)]
pre_scale(&self, scale_x: f32, scale_y: f32) -> Self100     pub fn pre_scale(&self, scale_x: f32, scale_y: f32) -> Self {
101         FontTransform::new(
102             self.scale_x * scale_x,
103             self.skew_x * scale_y,
104             self.skew_y * scale_x,
105             self.scale_y * scale_y,
106         )
107     }
108 
109     #[allow(dead_code)]
invert_scale(&self, x_scale: f64, y_scale: f64) -> Self110     pub fn invert_scale(&self, x_scale: f64, y_scale: f64) -> Self {
111         self.pre_scale(x_scale.recip() as f32, y_scale.recip() as f32)
112     }
113 
synthesize_italics(&self, angle: SyntheticItalics) -> Self114     pub fn synthesize_italics(&self, angle: SyntheticItalics) -> Self {
115         let skew_factor = angle.to_skew();
116         FontTransform::new(
117             self.scale_x,
118             self.skew_x - self.scale_x * skew_factor,
119             self.skew_y,
120             self.scale_y - self.skew_y * skew_factor,
121         )
122     }
123 
swap_xy(&self) -> Self124     pub fn swap_xy(&self) -> Self {
125         FontTransform::new(self.skew_x, self.scale_x, self.scale_y, self.skew_y)
126     }
127 
flip_x(&self) -> Self128     pub fn flip_x(&self) -> Self {
129         FontTransform::new(-self.scale_x, self.skew_x, -self.skew_y, self.scale_y)
130     }
131 
flip_y(&self) -> Self132     pub fn flip_y(&self) -> Self {
133         FontTransform::new(self.scale_x, -self.skew_x, self.skew_y, -self.scale_y)
134     }
135 
transform(&self, point: &LayoutPoint) -> WorldPoint136     pub fn transform(&self, point: &LayoutPoint) -> WorldPoint {
137         WorldPoint::new(
138             self.scale_x * point.x + self.skew_x * point.y,
139             self.skew_y * point.x + self.scale_y * point.y,
140         )
141     }
142 
get_subpx_dir(&self) -> SubpixelDirection143     pub fn get_subpx_dir(&self) -> SubpixelDirection {
144         if self.skew_y.approx_eq(&0.0) {
145             // The X axis is not projected onto the Y axis
146             SubpixelDirection::Horizontal
147         } else if self.scale_x.approx_eq(&0.0) {
148             // The X axis has been swapped with the Y axis
149             SubpixelDirection::Vertical
150         } else {
151             // Use subpixel precision on all axes
152             SubpixelDirection::Mixed
153         }
154     }
155 }
156 
157 impl<'a> From<&'a LayoutToWorldTransform> for FontTransform {
from(xform: &'a LayoutToWorldTransform) -> Self158     fn from(xform: &'a LayoutToWorldTransform) -> Self {
159         FontTransform::new(xform.m11, xform.m21, xform.m12, xform.m22)
160     }
161 }
162 
163 // Some platforms (i.e. Windows) may have trouble rasterizing glyphs above this size.
164 // Ensure glyph sizes are reasonably limited to avoid that scenario.
165 pub const FONT_SIZE_LIMIT: f64 = 512.0;
166 
167 #[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd, MallocSizeOf)]
168 #[cfg_attr(feature = "capture", derive(Serialize))]
169 #[cfg_attr(feature = "replay", derive(Deserialize))]
170 pub struct FontInstance {
171     pub font_key: FontKey,
172     // The font size is in *device* pixels, not logical pixels.
173     // It is stored as an Au since we need sub-pixel sizes, but
174     // can't store as a f32 due to use of this type as a hash key.
175     // TODO(gw): Perhaps consider having LogicalAu and DeviceAu
176     //           or something similar to that.
177     pub size: Au,
178     pub color: ColorU,
179     pub bg_color: ColorU,
180     pub render_mode: FontRenderMode,
181     pub flags: FontInstanceFlags,
182     pub synthetic_italics: SyntheticItalics,
183     #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
184     pub platform_options: Option<FontInstancePlatformOptions>,
185     pub variations: Vec<FontVariation>,
186     pub transform: FontTransform,
187 }
188 
189 impl FontInstance {
new( font_key: FontKey, size: Au, color: ColorF, bg_color: ColorU, render_mode: FontRenderMode, flags: FontInstanceFlags, synthetic_italics: SyntheticItalics, platform_options: Option<FontInstancePlatformOptions>, variations: Vec<FontVariation>, ) -> Self190     pub fn new(
191         font_key: FontKey,
192         size: Au,
193         color: ColorF,
194         bg_color: ColorU,
195         render_mode: FontRenderMode,
196         flags: FontInstanceFlags,
197         synthetic_italics: SyntheticItalics,
198         platform_options: Option<FontInstancePlatformOptions>,
199         variations: Vec<FontVariation>,
200     ) -> Self {
201         // If a background color is enabled, it only makes sense
202         // for it to be completely opaque.
203         debug_assert!(bg_color.a == 0 || bg_color.a == 255);
204 
205         FontInstance {
206             font_key,
207             size,
208             color: color.into(),
209             bg_color,
210             render_mode,
211             flags,
212             synthetic_italics,
213             platform_options,
214             variations,
215             transform: FontTransform::identity(),
216         }
217     }
218 
get_alpha_glyph_format(&self) -> GlyphFormat219     pub fn get_alpha_glyph_format(&self) -> GlyphFormat {
220         if self.transform.is_identity() { GlyphFormat::Alpha } else { GlyphFormat::TransformedAlpha }
221     }
222 
get_subpixel_glyph_format(&self) -> GlyphFormat223     pub fn get_subpixel_glyph_format(&self) -> GlyphFormat {
224         if self.transform.is_identity() { GlyphFormat::Subpixel } else { GlyphFormat::TransformedSubpixel }
225     }
226 
disable_subpixel_aa(&mut self)227     pub fn disable_subpixel_aa(&mut self) {
228         self.render_mode = self.render_mode.limit_by(FontRenderMode::Alpha);
229     }
230 
disable_subpixel_position(&mut self)231     pub fn disable_subpixel_position(&mut self) {
232         self.flags.remove(FontInstanceFlags::SUBPIXEL_POSITION);
233     }
234 
use_subpixel_position(&self) -> bool235     pub fn use_subpixel_position(&self) -> bool {
236         self.flags.contains(FontInstanceFlags::SUBPIXEL_POSITION) &&
237         self.render_mode != FontRenderMode::Mono
238     }
239 
get_subpx_dir(&self) -> SubpixelDirection240     pub fn get_subpx_dir(&self) -> SubpixelDirection {
241         if self.use_subpixel_position() {
242             let mut subpx_dir = self.transform.get_subpx_dir();
243             if self.flags.contains(FontInstanceFlags::TRANSPOSE) {
244                 subpx_dir = subpx_dir.swap_xy();
245             }
246             subpx_dir
247         } else {
248             SubpixelDirection::None
249         }
250     }
251 
252     #[allow(dead_code)]
get_subpx_offset(&self, glyph: &GlyphKey) -> (f64, f64)253     pub fn get_subpx_offset(&self, glyph: &GlyphKey) -> (f64, f64) {
254         if self.use_subpixel_position() {
255             let (dx, dy) = glyph.subpixel_offset();
256             (dx.into(), dy.into())
257         } else {
258             (0.0, 0.0)
259         }
260     }
261 
262     #[allow(dead_code)]
get_glyph_format(&self) -> GlyphFormat263     pub fn get_glyph_format(&self) -> GlyphFormat {
264         match self.render_mode {
265             FontRenderMode::Mono | FontRenderMode::Alpha => self.get_alpha_glyph_format(),
266             FontRenderMode::Subpixel => self.get_subpixel_glyph_format(),
267         }
268     }
269 
270     #[allow(dead_code)]
get_extra_strikes(&self, x_scale: f64) -> usize271     pub fn get_extra_strikes(&self, x_scale: f64) -> usize {
272         if self.flags.contains(FontInstanceFlags::SYNTHETIC_BOLD) {
273             let mut bold_offset = self.size.to_f64_px() / 48.0;
274             if bold_offset < 1.0 {
275                 bold_offset = 0.25 + 0.75 * bold_offset;
276             }
277             (bold_offset * x_scale).max(1.0).round() as usize
278         } else {
279             0
280         }
281     }
282 
oversized_scale_factor(&self, x_scale: f64, y_scale: f64) -> f64283     pub fn oversized_scale_factor(&self, x_scale: f64, y_scale: f64) -> f64 {
284         // If the scaled size is over the limit, then it will need to
285         // be scaled up from the size limit to the scaled size.
286         // However, this should only occur when the font isn't using any
287         // features that would tie it to device space, like transforms or
288         // subpixel AA.
289         let max_size = self.size.to_f64_px() * x_scale.max(y_scale);
290         if max_size > FONT_SIZE_LIMIT &&
291            self.transform.is_identity() &&
292            self.render_mode != FontRenderMode::Subpixel
293         {
294             max_size / FONT_SIZE_LIMIT
295         } else {
296             1.0
297         }
298     }
299 }
300 
301 #[repr(u32)]
302 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
303 pub enum SubpixelDirection {
304     None = 0,
305     Horizontal,
306     Vertical,
307     Mixed,
308 }
309 
310 impl SubpixelDirection {
311     // Limit the subpixel direction to what is supported by the glyph format.
limit_by(self, glyph_format: GlyphFormat) -> Self312     pub fn limit_by(self, glyph_format: GlyphFormat) -> Self {
313         match glyph_format {
314             GlyphFormat::Bitmap |
315             GlyphFormat::ColorBitmap => SubpixelDirection::None,
316             _ => self,
317         }
318     }
319 
swap_xy(self) -> Self320     pub fn swap_xy(self) -> Self {
321         match self {
322             SubpixelDirection::None | SubpixelDirection::Mixed => self,
323             SubpixelDirection::Horizontal => SubpixelDirection::Vertical,
324             SubpixelDirection::Vertical => SubpixelDirection::Horizontal,
325         }
326     }
327 }
328 
329 #[repr(u8)]
330 #[derive(Hash, Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
331 #[cfg_attr(feature = "capture", derive(Serialize))]
332 #[cfg_attr(feature = "replay", derive(Deserialize))]
333 pub enum SubpixelOffset {
334     Zero = 0,
335     Quarter = 1,
336     Half = 2,
337     ThreeQuarters = 3,
338 }
339 
340 impl SubpixelOffset {
341     // Skia quantizes subpixel offsets into 1/4 increments.
342     // Given the absolute position, return the quantized increment
quantize(pos: f32) -> Self343     fn quantize(pos: f32) -> Self {
344         // Following the conventions of Gecko and Skia, we want
345         // to quantize the subpixel position, such that abs(pos) gives:
346         // [0.0, 0.125) -> Zero
347         // [0.125, 0.375) -> Quarter
348         // [0.375, 0.625) -> Half
349         // [0.625, 0.875) -> ThreeQuarters,
350         // [0.875, 1.0) -> Zero
351         // The unit tests below check for this.
352         let apos = ((pos - pos.floor()) * 8.0) as i32;
353 
354         match apos {
355             1...2 => SubpixelOffset::Quarter,
356             3...4 => SubpixelOffset::Half,
357             5...6 => SubpixelOffset::ThreeQuarters,
358             _ => SubpixelOffset::Zero,
359         }
360     }
361 }
362 
363 impl Into<f64> for SubpixelOffset {
into(self) -> f64364     fn into(self) -> f64 {
365         match self {
366             SubpixelOffset::Zero => 0.0,
367             SubpixelOffset::Quarter => 0.25,
368             SubpixelOffset::Half => 0.5,
369             SubpixelOffset::ThreeQuarters => 0.75,
370         }
371     }
372 }
373 
374 #[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
375 #[cfg_attr(feature = "capture", derive(Serialize))]
376 #[cfg_attr(feature = "replay", derive(Deserialize))]
377 pub struct GlyphKey(u32);
378 
379 impl GlyphKey {
new( index: u32, point: DevicePoint, subpx_dir: SubpixelDirection, ) -> Self380     pub fn new(
381         index: u32,
382         point: DevicePoint,
383         subpx_dir: SubpixelDirection,
384     ) -> Self {
385         let (dx, dy) = match subpx_dir {
386             SubpixelDirection::None => (0.0, 0.0),
387             SubpixelDirection::Horizontal => (point.x, 0.0),
388             SubpixelDirection::Vertical => (0.0, point.y),
389             SubpixelDirection::Mixed => (point.x, point.y),
390         };
391         let sox = SubpixelOffset::quantize(dx);
392         let soy = SubpixelOffset::quantize(dy);
393         assert_eq!(0, index & 0xF0000000);
394 
395         GlyphKey(index | (sox as u32) << 28 | (soy as u32) << 30)
396     }
397 
index(&self) -> GlyphIndex398     pub fn index(&self) -> GlyphIndex {
399         self.0 & 0x0FFFFFFF
400     }
401 
subpixel_offset(&self) -> (SubpixelOffset, SubpixelOffset)402     fn subpixel_offset(&self) -> (SubpixelOffset, SubpixelOffset) {
403         let x = (self.0 >> 28) as u8 & 3;
404         let y = (self.0 >> 30) as u8 & 3;
405         unsafe {
406             (mem::transmute(x), mem::transmute(y))
407         }
408     }
409 }
410 
411 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
412 #[cfg_attr(feature = "capture", derive(Serialize))]
413 #[cfg_attr(feature = "replay", derive(Deserialize))]
414 #[allow(dead_code)]
415 pub enum GlyphFormat {
416     Alpha,
417     TransformedAlpha,
418     Subpixel,
419     TransformedSubpixel,
420     Bitmap,
421     ColorBitmap,
422 }
423 
424 impl GlyphFormat {
ignore_color(self) -> Self425     pub fn ignore_color(self) -> Self {
426         match self {
427             GlyphFormat::ColorBitmap => GlyphFormat::Bitmap,
428             _ => self,
429         }
430     }
431 }
432 
433 pub struct RasterizedGlyph {
434     pub top: f32,
435     pub left: f32,
436     pub width: i32,
437     pub height: i32,
438     pub scale: f32,
439     pub format: GlyphFormat,
440     pub bytes: Vec<u8>,
441 }
442 
443 pub struct FontContexts {
444     // These worker are mostly accessed from their corresponding worker threads.
445     // The goal is that there should be no noticeable contention on the mutexes.
446     worker_contexts: Vec<Mutex<FontContext>>,
447     // This worker should be accessed by threads that don't belong to the thread pool
448     // (in theory that's only the render backend thread so no contention expected either).
449     shared_context: Mutex<FontContext>,
450     #[cfg(feature = "pathfinder")]
451     pathfinder_context: Box<ThreadSafePathfinderFontContext>,
452     // Stored here as a convenience to get the current thread index.
453     #[allow(dead_code)]
454     workers: Arc<ThreadPool>,
455     locked_mutex: Mutex<bool>,
456     locked_cond: Condvar,
457 }
458 
459 impl FontContexts {
460 
461     /// Get access to any particular font context.
462     ///
463     /// The id is ```Some(i)``` where i is an index between 0 and num_worker_contexts
464     /// for font contexts associated to the thread pool, and None for the shared
465     /// global font context for use outside of the thread pool.
lock_context(&self, id: Option<usize>) -> MutexGuard<FontContext>466     pub fn lock_context(&self, id: Option<usize>) -> MutexGuard<FontContext> {
467         match id {
468             Some(index) => self.worker_contexts[index].lock().unwrap(),
469             None => self.shared_context.lock().unwrap(),
470         }
471     }
472 
473     /// Get access to the font context usable outside of the thread pool.
lock_shared_context(&self) -> MutexGuard<FontContext>474     pub fn lock_shared_context(&self) -> MutexGuard<FontContext> {
475         self.shared_context.lock().unwrap()
476     }
477 
478     // number of contexts associated to workers
num_worker_contexts(&self) -> usize479     pub fn num_worker_contexts(&self) -> usize {
480         self.worker_contexts.len()
481     }
482 }
483 
484 pub trait ForEach<T> {
for_each<F: Fn(MutexGuard<T>) + Send + 'static>(&self, f: F)485     fn for_each<F: Fn(MutexGuard<T>) + Send + 'static>(&self, f: F);
486 }
487 
488 impl ForEach<FontContext> for Arc<FontContexts> {
for_each<F: Fn(MutexGuard<FontContext>) + Send + 'static>(&self, f: F)489     fn for_each<F: Fn(MutexGuard<FontContext>) + Send + 'static>(&self, f: F) {
490         // Reset the locked condition.
491         let mut locked = self.locked_mutex.lock().unwrap();
492         *locked = false;
493 
494         // Arc that can be safely moved into a spawn closure.
495         let font_contexts = self.clone();
496         // Spawn a new thread on which to run the for-each off the main thread.
497         self.workers.spawn(move || {
498             // Lock the shared and worker contexts up front.
499             let mut locks = Vec::with_capacity(font_contexts.num_worker_contexts() + 1);
500             locks.push(font_contexts.lock_shared_context());
501             for i in 0 .. font_contexts.num_worker_contexts() {
502                 locks.push(font_contexts.lock_context(Some(i)));
503             }
504 
505             // Signal the locked condition now that all contexts are locked.
506             *font_contexts.locked_mutex.lock().unwrap() = true;
507             font_contexts.locked_cond.notify_all();
508 
509             // Now that everything is locked, proceed to processing each locked context.
510             for context in locks {
511                 f(context);
512             }
513         });
514 
515         // Wait for locked condition before resuming. Safe to proceed thereafter
516         // since any other thread that needs to use a FontContext will try to lock
517         // it first.
518         while !*locked {
519             locked = self.locked_cond.wait(locked).unwrap();
520         }
521     }
522 }
523 
524 pub struct GlyphRasterizer {
525     #[allow(dead_code)]
526     workers: Arc<ThreadPool>,
527     font_contexts: Arc<FontContexts>,
528 
529     // Maintain a set of glyphs that have been requested this
530     // frame. This ensures the glyph thread won't rasterize
531     // the same glyph more than once in a frame. This is required
532     // because the glyph cache hash table is not updated
533     // until the end of the frame when we wait for glyph requests
534     // to be resolved.
535     #[allow(dead_code)]
536     pending_glyphs: usize,
537 
538     // Receives the rendered glyphs.
539     #[allow(dead_code)]
540     glyph_rx: Receiver<GlyphRasterJobs>,
541     #[allow(dead_code)]
542     glyph_tx: Sender<GlyphRasterJobs>,
543 
544     // We defer removing fonts to the end of the frame so that:
545     // - this work is done outside of the critical path,
546     // - we don't have to worry about the ordering of events if a font is used on
547     //   a frame where it is used (although it seems unlikely).
548     fonts_to_remove: Vec<FontKey>,
549     // Defer removal of font instances, as for fonts.
550     font_instances_to_remove: Vec<FontInstance>,
551 
552     #[allow(dead_code)]
553     next_gpu_glyph_cache_key: GpuGlyphCacheKey,
554 }
555 
556 impl GlyphRasterizer {
new(workers: Arc<ThreadPool>) -> Result<Self, ResourceCacheError>557     pub fn new(workers: Arc<ThreadPool>) -> Result<Self, ResourceCacheError> {
558         let (glyph_tx, glyph_rx) = channel();
559 
560         let num_workers = workers.current_num_threads();
561         let mut contexts = Vec::with_capacity(num_workers);
562 
563         let shared_context = FontContext::new()?;
564 
565         for _ in 0 .. num_workers {
566             contexts.push(Mutex::new(FontContext::new()?));
567         }
568 
569         let font_context = FontContexts {
570                 worker_contexts: contexts,
571                 shared_context: Mutex::new(shared_context),
572                 #[cfg(feature = "pathfinder")]
573                 pathfinder_context: create_pathfinder_font_context()?,
574                 workers: Arc::clone(&workers),
575                 locked_mutex: Mutex::new(false),
576                 locked_cond: Condvar::new(),
577         };
578 
579         Ok(GlyphRasterizer {
580             font_contexts: Arc::new(font_context),
581             pending_glyphs: 0,
582             glyph_rx,
583             glyph_tx,
584             workers,
585             fonts_to_remove: Vec::new(),
586             font_instances_to_remove: Vec::new(),
587             next_gpu_glyph_cache_key: GpuGlyphCacheKey(0),
588         })
589     }
590 
add_font(&mut self, font_key: FontKey, template: FontTemplate)591     pub fn add_font(&mut self, font_key: FontKey, template: FontTemplate) {
592         #[cfg(feature = "pathfinder")]
593         self.add_font_to_pathfinder(&font_key, &template);
594 
595         self.font_contexts.for_each(move |mut context| {
596             context.add_font(&font_key, &template);
597         });
598     }
599 
delete_font(&mut self, font_key: FontKey)600     pub fn delete_font(&mut self, font_key: FontKey) {
601         self.fonts_to_remove.push(font_key);
602     }
603 
delete_font_instance(&mut self, instance: &FontInstance)604     pub fn delete_font_instance(&mut self, instance: &FontInstance) {
605         self.font_instances_to_remove.push(instance.clone());
606     }
607 
prepare_font(&self, font: &mut FontInstance)608     pub fn prepare_font(&self, font: &mut FontInstance) {
609         FontContext::prepare_font(font);
610     }
611 
get_glyph_dimensions( &mut self, font: &FontInstance, glyph_index: GlyphIndex, ) -> Option<GlyphDimensions>612     pub fn get_glyph_dimensions(
613         &mut self,
614         font: &FontInstance,
615         glyph_index: GlyphIndex,
616     ) -> Option<GlyphDimensions> {
617         let glyph_key = GlyphKey::new(
618             glyph_index,
619             DevicePoint::zero(),
620             SubpixelDirection::None,
621         );
622 
623         self.font_contexts
624             .lock_shared_context()
625             .get_glyph_dimensions(font, &glyph_key)
626     }
627 
get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32>628     pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
629         self.font_contexts
630             .lock_shared_context()
631             .get_glyph_index(font_key, ch)
632     }
633 
remove_dead_fonts(&mut self)634     fn remove_dead_fonts(&mut self) {
635         if self.fonts_to_remove.is_empty() && self.font_instances_to_remove.is_empty() {
636             return
637         }
638 
639         let fonts_to_remove = mem::replace(&mut self.fonts_to_remove, Vec::new());
640         let font_instances_to_remove = mem::replace(& mut self.font_instances_to_remove, Vec::new());
641         self.font_contexts.for_each(move |mut context| {
642             for font_key in &fonts_to_remove {
643                 context.delete_font(font_key);
644             }
645             for instance in &font_instances_to_remove {
646                 context.delete_font_instance(instance);
647             }
648         });
649     }
650 
651     #[cfg(feature = "replay")]
reset(&mut self)652     pub fn reset(&mut self) {
653         //TODO: any signals need to be sent to the workers?
654         self.pending_glyphs = 0;
655         self.fonts_to_remove.clear();
656         self.font_instances_to_remove.clear();
657     }
658 }
659 
660 trait AddFont {
add_font(&mut self, font_key: &FontKey, template: &FontTemplate)661     fn add_font(&mut self, font_key: &FontKey, template: &FontTemplate);
662 }
663 
664 impl AddFont for FontContext {
add_font(&mut self, font_key: &FontKey, template: &FontTemplate)665     fn add_font(&mut self, font_key: &FontKey, template: &FontTemplate) {
666         match *template {
667             FontTemplate::Raw(ref bytes, index) => {
668                 self.add_raw_font(font_key, bytes.clone(), index);
669             }
670             FontTemplate::Native(ref native_font_handle) => {
671                 self.add_native_font(font_key, (*native_font_handle).clone());
672             }
673         }
674     }
675 }
676 
677 #[allow(dead_code)]
678 pub(in glyph_rasterizer) struct GlyphRasterJob {
679     key: GlyphKey,
680     result: GlyphRasterResult,
681 }
682 
683 #[allow(dead_code)]
684 pub enum GlyphRasterError {
685     LoadFailed,
686 }
687 
688 #[allow(dead_code)]
689 pub type GlyphRasterResult = Result<RasterizedGlyph, GlyphRasterError>;
690 
691 #[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
692 #[cfg_attr(feature = "capture", derive(Serialize))]
693 #[cfg_attr(feature = "replay", derive(Deserialize))]
694 pub struct GpuGlyphCacheKey(pub u32);
695 
696 #[allow(dead_code)]
697 struct GlyphRasterJobs {
698     font: FontInstance,
699     jobs: Vec<GlyphRasterJob>,
700 }
701 
702 #[cfg(test)]
703 mod test_glyph_rasterizer {
704     #[test]
rasterize_200_glyphs()705     fn rasterize_200_glyphs() {
706         // This test loads a font from disc, the renders 4 requests containing
707         // 50 glyphs each, deletes the font and waits for the result.
708 
709         use rayon::ThreadPoolBuilder;
710         use std::fs::File;
711         use std::io::Read;
712         use texture_cache::TextureCache;
713         use glyph_cache::GlyphCache;
714         use gpu_cache::GpuCache;
715         use render_task::{RenderTaskCache, RenderTaskTree};
716         use profiler::TextureCacheProfileCounters;
717         use api::{FontKey, FontTemplate, FontRenderMode,
718                   IdNamespace, ColorF, ColorU, DevicePoint};
719         use render_backend::FrameId;
720         use app_units::Au;
721         use thread_profiler::register_thread_with_profiler;
722         use std::sync::Arc;
723         use glyph_rasterizer::{FontInstance, GlyphKey, GlyphRasterizer};
724 
725         let worker = ThreadPoolBuilder::new()
726             .thread_name(|idx|{ format!("WRWorker#{}", idx) })
727             .start_handler(move |idx| {
728                 register_thread_with_profiler(format!("WRWorker#{}", idx));
729             })
730             .build();
731         let workers = Arc::new(worker.unwrap());
732         let mut glyph_rasterizer = GlyphRasterizer::new(workers).unwrap();
733         let mut glyph_cache = GlyphCache::new();
734         let mut gpu_cache = GpuCache::new_for_testing();
735         let mut texture_cache = TextureCache::new_for_testing(2048, 1024);
736         let mut render_task_cache = RenderTaskCache::new();
737         let mut render_task_tree = RenderTaskTree::new(FrameId::INVALID);
738         let mut font_file =
739             File::open("../wrench/reftests/text/VeraBd.ttf").expect("Couldn't open font file");
740         let mut font_data = vec![];
741         font_file
742             .read_to_end(&mut font_data)
743             .expect("failed to read font file");
744 
745         let font_key = FontKey::new(IdNamespace(0), 0);
746         glyph_rasterizer.add_font(font_key, FontTemplate::Raw(Arc::new(font_data), 0));
747 
748         let font = FontInstance::new(
749             font_key,
750             Au::from_px(32),
751             ColorF::new(0.0, 0.0, 0.0, 1.0),
752             ColorU::new(0, 0, 0, 0),
753             FontRenderMode::Subpixel,
754             Default::default(),
755             Default::default(),
756             None,
757             Vec::new(),
758         );
759         let subpx_dir = font.get_subpx_dir();
760 
761         let mut glyph_keys = Vec::with_capacity(200);
762         for i in 0 .. 200 {
763             glyph_keys.push(GlyphKey::new(
764                 i,
765                 DevicePoint::zero(),
766                 subpx_dir,
767             ));
768         }
769 
770         for i in 0 .. 4 {
771             glyph_rasterizer.request_glyphs(
772                 &mut glyph_cache,
773                 font.clone(),
774                 &glyph_keys[(50 * i) .. (50 * (i + 1))],
775                 &mut texture_cache,
776                 &mut gpu_cache,
777                 &mut render_task_cache,
778                 &mut render_task_tree,
779             );
780         }
781 
782         glyph_rasterizer.delete_font(font_key);
783 
784         glyph_rasterizer.resolve_glyphs(
785             &mut glyph_cache,
786             &mut TextureCache::new_for_testing(4096, 1024),
787             &mut gpu_cache,
788             &mut render_task_cache,
789             &mut render_task_tree,
790             &mut TextureCacheProfileCounters::new(),
791         );
792     }
793 
794     #[test]
test_subpx_quantize()795     fn test_subpx_quantize() {
796         use glyph_rasterizer::SubpixelOffset;
797 
798         assert_eq!(SubpixelOffset::quantize(0.0), SubpixelOffset::Zero);
799         assert_eq!(SubpixelOffset::quantize(-0.0), SubpixelOffset::Zero);
800 
801         assert_eq!(SubpixelOffset::quantize(0.1), SubpixelOffset::Zero);
802         assert_eq!(SubpixelOffset::quantize(0.01), SubpixelOffset::Zero);
803         assert_eq!(SubpixelOffset::quantize(0.05), SubpixelOffset::Zero);
804         assert_eq!(SubpixelOffset::quantize(0.12), SubpixelOffset::Zero);
805         assert_eq!(SubpixelOffset::quantize(0.124), SubpixelOffset::Zero);
806 
807         assert_eq!(SubpixelOffset::quantize(0.125), SubpixelOffset::Quarter);
808         assert_eq!(SubpixelOffset::quantize(0.2), SubpixelOffset::Quarter);
809         assert_eq!(SubpixelOffset::quantize(0.25), SubpixelOffset::Quarter);
810         assert_eq!(SubpixelOffset::quantize(0.33), SubpixelOffset::Quarter);
811         assert_eq!(SubpixelOffset::quantize(0.374), SubpixelOffset::Quarter);
812 
813         assert_eq!(SubpixelOffset::quantize(0.375), SubpixelOffset::Half);
814         assert_eq!(SubpixelOffset::quantize(0.4), SubpixelOffset::Half);
815         assert_eq!(SubpixelOffset::quantize(0.5), SubpixelOffset::Half);
816         assert_eq!(SubpixelOffset::quantize(0.58), SubpixelOffset::Half);
817         assert_eq!(SubpixelOffset::quantize(0.624), SubpixelOffset::Half);
818 
819         assert_eq!(SubpixelOffset::quantize(0.625), SubpixelOffset::ThreeQuarters);
820         assert_eq!(SubpixelOffset::quantize(0.67), SubpixelOffset::ThreeQuarters);
821         assert_eq!(SubpixelOffset::quantize(0.7), SubpixelOffset::ThreeQuarters);
822         assert_eq!(SubpixelOffset::quantize(0.78), SubpixelOffset::ThreeQuarters);
823         assert_eq!(SubpixelOffset::quantize(0.874), SubpixelOffset::ThreeQuarters);
824 
825         assert_eq!(SubpixelOffset::quantize(0.875), SubpixelOffset::Zero);
826         assert_eq!(SubpixelOffset::quantize(0.89), SubpixelOffset::Zero);
827         assert_eq!(SubpixelOffset::quantize(0.91), SubpixelOffset::Zero);
828         assert_eq!(SubpixelOffset::quantize(0.967), SubpixelOffset::Zero);
829         assert_eq!(SubpixelOffset::quantize(0.999), SubpixelOffset::Zero);
830 
831         assert_eq!(SubpixelOffset::quantize(-1.0), SubpixelOffset::Zero);
832         assert_eq!(SubpixelOffset::quantize(1.0), SubpixelOffset::Zero);
833         assert_eq!(SubpixelOffset::quantize(1.5), SubpixelOffset::Half);
834         assert_eq!(SubpixelOffset::quantize(-1.625), SubpixelOffset::Half);
835         assert_eq!(SubpixelOffset::quantize(-4.33), SubpixelOffset::ThreeQuarters);
836     }
837 }
838