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