rasterizer.rs (75170B)
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::{FontInstanceData, FontInstanceFlags, FontInstanceKey}; 6 use api::{FontInstanceOptions, FontInstancePlatformOptions}; 7 use api::{FontKey, FontRenderMode, FontSize, FontTemplate, FontVariation}; 8 use api::{ColorU, GlyphIndex, GlyphDimensions, SyntheticItalics}; 9 use api::{IdNamespace, BlobImageResources}; 10 use api::channel::crossbeam::{unbounded, Receiver, Sender}; 11 use api::units::*; 12 use api::ImageFormat; 13 use crate::platform::font::FontContext; 14 use crate::profiler::GlyphRasterizeProfiler; 15 use crate::types::{FastHashMap, FastHashSet}; 16 use crate::telemetry::Telemetry; 17 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; 18 use rayon::ThreadPool; 19 use rayon::prelude::*; 20 use euclid::approxeq::ApproxEq; 21 use smallvec::SmallVec; 22 use std::cmp; 23 use std::cell::Cell; 24 use std::hash::{Hash, Hasher}; 25 use std::mem; 26 use std::ops::Deref; 27 use std::sync::{Arc, Condvar, Mutex, MutexGuard, Weak}; 28 use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; 29 use std::sync::atomic::{AtomicBool, Ordering}; 30 31 pub static GLYPH_FLASHING: AtomicBool = AtomicBool::new(false); 32 const GLYPH_BATCH_SIZE: usize = 32; 33 34 impl 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 48 thread_local! { 49 pub static SEED: Cell<u32> = Cell::new(0); 50 } 51 52 // super simple random to avoid dependency on rand 53 fn random() -> u32 { 54 SEED.with(|seed| { 55 seed.set(seed.get().wrapping_mul(22695477).wrapping_add(1)); 56 seed.get() 57 }) 58 } 59 60 impl 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))] 249 pub 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... 257 impl Eq for FontTransform {} 258 impl Ord for FontTransform { 259 fn cmp(&self, other: &Self) -> cmp::Ordering { 260 self.partial_cmp(other).unwrap_or(cmp::Ordering::Equal) 261 } 262 } 263 impl 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 273 impl FontTransform { 274 const QUANTIZE_SCALE: f32 = 1024.0; 275 276 pub fn new(scale_x: f32, skew_x: f32, skew_y: f32, scale_y: f32) -> Self { 277 FontTransform { scale_x, skew_x, skew_y, scale_y } 278 } 279 280 pub fn identity() -> Self { 281 FontTransform::new(1.0, 0.0, 0.0, 1.0) 282 } 283 284 #[allow(dead_code)] 285 pub fn is_identity(&self) -> bool { 286 *self == FontTransform::identity() 287 } 288 289 pub fn quantize(&self) -> Self { 290 FontTransform::new( 291 (self.scale_x * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE, 292 (self.skew_x * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE, 293 (self.skew_y * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE, 294 (self.scale_y * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE, 295 ) 296 } 297 298 #[allow(dead_code)] 299 pub fn determinant(&self) -> f64 { 300 self.scale_x as f64 * self.scale_y as f64 - self.skew_y as f64 * self.skew_x as f64 301 } 302 303 #[allow(dead_code)] 304 pub fn compute_scale(&self) -> Option<(f64, f64)> { 305 let det = self.determinant(); 306 if det != 0.0 { 307 let x_scale = (self.scale_x as f64).hypot(self.skew_y as f64); 308 let y_scale = det.abs() / x_scale; 309 Some((x_scale, y_scale)) 310 } else { 311 None 312 } 313 } 314 315 #[allow(dead_code)] 316 pub fn pre_scale(&self, scale_x: f32, scale_y: f32) -> Self { 317 FontTransform::new( 318 self.scale_x * scale_x, 319 self.skew_x * scale_y, 320 self.skew_y * scale_x, 321 self.scale_y * scale_y, 322 ) 323 } 324 325 #[allow(dead_code)] 326 pub fn scale(&self, scale: f32) -> Self { self.pre_scale(scale, scale) } 327 328 #[allow(dead_code)] 329 pub fn invert_scale(&self, x_scale: f64, y_scale: f64) -> Self { 330 self.pre_scale(x_scale.recip() as f32, y_scale.recip() as f32) 331 } 332 333 pub fn synthesize_italics(&self, angle: SyntheticItalics, size: f64, vertical: bool) -> (Self, (f64, f64)) { 334 let skew_factor = angle.to_skew(); 335 if vertical { 336 // origin delta to be applied so that we effectively skew around 337 // the middle rather than edge of the glyph 338 let (tx, ty) = (0.0, -size * 0.5 * skew_factor as f64); 339 (FontTransform::new( 340 self.scale_x + self.skew_x * skew_factor, 341 self.skew_x, 342 self.skew_y + self.scale_y * skew_factor, 343 self.scale_y, 344 ), (self.scale_x as f64 * tx + self.skew_x as f64 * ty, 345 self.skew_y as f64 * tx + self.scale_y as f64 * ty)) 346 } else { 347 (FontTransform::new( 348 self.scale_x, 349 self.skew_x - self.scale_x * skew_factor, 350 self.skew_y, 351 self.scale_y - self.skew_y * skew_factor, 352 ), (0.0, 0.0)) 353 } 354 } 355 356 pub fn swap_xy(&self) -> Self { 357 FontTransform::new(self.skew_x, self.scale_x, self.scale_y, self.skew_y) 358 } 359 360 pub fn flip_x(&self) -> Self { 361 FontTransform::new(-self.scale_x, self.skew_x, -self.skew_y, self.scale_y) 362 } 363 364 pub fn flip_y(&self) -> Self { 365 FontTransform::new(self.scale_x, -self.skew_x, self.skew_y, -self.scale_y) 366 } 367 368 pub fn transform(&self, point: &LayoutPoint) -> DevicePoint { 369 DevicePoint::new( 370 self.scale_x * point.x + self.skew_x * point.y, 371 self.skew_y * point.x + self.scale_y * point.y, 372 ) 373 } 374 375 pub fn get_subpx_dir(&self) -> SubpixelDirection { 376 if self.skew_y.approx_eq(&0.0) { 377 // The X axis is not projected onto the Y axis 378 SubpixelDirection::Horizontal 379 } else if self.scale_x.approx_eq(&0.0) { 380 // The X axis has been swapped with the Y axis 381 SubpixelDirection::Vertical 382 } else { 383 // Mixed transforms get no subpixel positioning 384 SubpixelDirection::None 385 } 386 } 387 } 388 389 impl<'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. 397 pub 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))] 405 pub 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 421 impl 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 441 impl Deref for BaseFontInstance { 442 type Target = FontInstanceOptions; 443 fn deref(&self) -> &FontInstanceOptions { 444 &self.options 445 } 446 } 447 448 impl 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 459 impl 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 } 469 impl Eq for BaseFontInstance {} 470 471 struct MappedFontKey { 472 font_key: FontKey, 473 template: FontTemplate, 474 } 475 476 struct 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)] 493 pub struct FontKeyMap(Arc<RwLock<FontKeyMapLocked>>); 494 495 impl 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 582 type 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)] 587 pub struct FontTemplateMap(Arc<RwLock<FontTemplateMapLocked>>); 588 589 impl 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 649 struct 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)] 666 pub struct FontInstanceKeyMap(Arc<RwLock<FontInstanceKeyMapLocked>>); 667 668 impl 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 753 type FontInstanceMapLocked = FastHashMap<FontInstanceKey, Arc<BaseFontInstance>>; 754 755 /// A map of font instance data accessed concurrently from multiple threads. 756 #[derive(Clone)] 757 pub struct FontInstanceMap(Arc<RwLock<FontInstanceMapLocked>>); 758 759 impl 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)] 835 pub struct SharedFontResources { 836 pub templates: FontTemplateMap, 837 pub instances: FontInstanceMap, 838 pub font_keys: FontKeyMap, 839 pub instance_keys: FontInstanceKeyMap, 840 } 841 842 impl 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 853 impl 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))] 872 pub 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 883 impl 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 896 impl 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 } 907 impl Eq for FontInstance {} 908 909 impl Deref for FontInstance { 910 type Target = BaseFontInstance; 911 fn deref(&self) -> &BaseFontInstance { 912 self.base.as_ref() 913 } 914 } 915 916 impl MallocSizeOf for FontInstance { 917 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { 0 } 918 } 919 920 impl 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)] 1031 pub enum SubpixelDirection { 1032 None = 0, 1033 Horizontal, 1034 Vertical, 1035 } 1036 1037 impl SubpixelDirection { 1038 // Limit the subpixel direction to what is supported by the glyph format. 1039 pub fn limit_by(self, glyph_format: GlyphFormat) -> Self { 1040 match glyph_format { 1041 GlyphFormat::Bitmap | 1042 GlyphFormat::ColorBitmap => SubpixelDirection::None, 1043 _ => self, 1044 } 1045 } 1046 1047 pub fn swap_xy(self) -> Self { 1048 match self { 1049 SubpixelDirection::None => self, 1050 SubpixelDirection::Horizontal => SubpixelDirection::Vertical, 1051 SubpixelDirection::Vertical => SubpixelDirection::Horizontal, 1052 } 1053 } 1054 } 1055 1056 #[repr(u8)] 1057 #[derive(Hash, Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] 1058 #[cfg_attr(feature = "capture", derive(Serialize))] 1059 #[cfg_attr(feature = "replay", derive(Deserialize))] 1060 pub enum SubpixelOffset { 1061 Zero = 0, 1062 Quarter = 1, 1063 Half = 2, 1064 ThreeQuarters = 3, 1065 } 1066 1067 impl SubpixelOffset { 1068 // Skia quantizes subpixel offsets into 1/4 increments. 1069 // Given the absolute position, return the quantized increment 1070 fn quantize(pos: f32) -> Self { 1071 // Following the conventions of Gecko and Skia, we want 1072 // to quantize the subpixel position, such that abs(pos) gives: 1073 // [0.0, 0.125) -> Zero 1074 // [0.125, 0.375) -> Quarter 1075 // [0.375, 0.625) -> Half 1076 // [0.625, 0.875) -> ThreeQuarters, 1077 // [0.875, 1.0) -> Zero 1078 // The unit tests below check for this. 1079 let apos = ((pos - pos.floor()) * 8.0) as i32; 1080 1081 match apos { 1082 1..=2 => SubpixelOffset::Quarter, 1083 3..=4 => SubpixelOffset::Half, 1084 5..=6 => SubpixelOffset::ThreeQuarters, 1085 _ => SubpixelOffset::Zero, 1086 } 1087 } 1088 } 1089 1090 impl Into<f64> for SubpixelOffset { 1091 fn into(self) -> f64 { 1092 match self { 1093 SubpixelOffset::Zero => 0.0, 1094 SubpixelOffset::Quarter => 0.25, 1095 SubpixelOffset::Half => 0.5, 1096 SubpixelOffset::ThreeQuarters => 0.75, 1097 } 1098 } 1099 } 1100 1101 impl SubpixelOffset { 1102 fn to_f32(self) -> f32 { 1103 match self { 1104 SubpixelOffset::Zero => 0.0, 1105 SubpixelOffset::Quarter => 0.25, 1106 SubpixelOffset::Half => 0.5, 1107 SubpixelOffset::ThreeQuarters => 0.75, 1108 } 1109 } 1110 } 1111 1112 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)] 1113 #[cfg_attr(feature = "capture", derive(Serialize))] 1114 #[cfg_attr(feature = "replay", derive(Deserialize))] 1115 pub struct GlyphKey(u32); 1116 1117 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)] 1118 #[cfg_attr(feature = "capture", derive(Serialize))] 1119 #[cfg_attr(feature = "replay", derive(Deserialize))] 1120 pub struct GlyphCacheKey(u32); 1121 1122 impl GlyphKey { 1123 pub fn new( 1124 index: u32, 1125 point: DevicePoint, 1126 subpx_dir: SubpixelDirection, 1127 ) -> Self { 1128 let (dx, dy) = match subpx_dir { 1129 SubpixelDirection::None => (0.0, 0.0), 1130 SubpixelDirection::Horizontal => (point.x, 0.0), 1131 SubpixelDirection::Vertical => (0.0, point.y), 1132 }; 1133 let sox = SubpixelOffset::quantize(dx); 1134 let soy = SubpixelOffset::quantize(dy); 1135 assert_eq!(0, index & 0xFC000000); 1136 1137 GlyphKey(index | (sox as u32) << 26 | (soy as u32) << 28 | (subpx_dir as u32) << 30) 1138 } 1139 1140 pub fn index(&self) -> GlyphIndex { 1141 self.0 & 0x03FFFFFF 1142 } 1143 1144 pub fn subpixel_offset(&self) -> (SubpixelOffset, SubpixelOffset) { 1145 let x = (self.0 >> 26) as u8 & 3; 1146 let y = (self.0 >> 28) as u8 & 3; 1147 unsafe { 1148 (mem::transmute(x), mem::transmute(y)) 1149 } 1150 } 1151 1152 pub fn subpixel_dir(&self) -> SubpixelDirection { 1153 let dir = (self.0 >> 30) as u8 & 3; 1154 unsafe { 1155 mem::transmute(dir as u32) 1156 } 1157 } 1158 1159 pub fn cache_key(&self) -> GlyphCacheKey { 1160 let index = self.index(); 1161 let subpx_dir = self.subpixel_dir(); 1162 assert_eq!(0, index & 0xFC000000); 1163 GlyphCacheKey(index | (subpx_dir as u32) << 30) 1164 } 1165 } 1166 1167 impl GlyphCacheKey { 1168 pub fn index(&self) -> GlyphIndex { 1169 self.0 & 0x03FFFFFF 1170 } 1171 1172 pub fn subpixel_dir(&self) -> SubpixelDirection { 1173 let dir = ((self.0 >> 30) & 3) as u32; 1174 unsafe { 1175 mem::transmute(dir) 1176 } 1177 } 1178 } 1179 1180 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] 1181 #[cfg_attr(feature = "capture", derive(Serialize))] 1182 #[cfg_attr(feature = "replay", derive(Deserialize))] 1183 #[allow(dead_code)] 1184 pub enum GlyphFormat { 1185 Alpha, 1186 TransformedAlpha, 1187 Subpixel, 1188 TransformedSubpixel, 1189 Bitmap, 1190 ColorBitmap, 1191 } 1192 1193 impl GlyphFormat { 1194 /// Returns the ImageFormat that a glyph should be stored as in the texture cache. 1195 /// can_use_r8_format should be set false on platforms where we have encountered 1196 /// issues with R8 textures, so that we do not use them for glyphs. 1197 pub fn image_format(&self, can_use_r8_format: bool) -> ImageFormat { 1198 match *self { 1199 GlyphFormat::Alpha | 1200 GlyphFormat::TransformedAlpha | 1201 GlyphFormat::Bitmap => { 1202 if can_use_r8_format { 1203 ImageFormat::R8 1204 } else { 1205 ImageFormat::BGRA8 1206 } 1207 } 1208 GlyphFormat::Subpixel | 1209 GlyphFormat::TransformedSubpixel | 1210 GlyphFormat::ColorBitmap => ImageFormat::BGRA8, 1211 } 1212 } 1213 } 1214 1215 #[allow(dead_code)] 1216 #[inline] 1217 fn blend_strike_pixel(dest: u8, src: u32, src_alpha: u32) -> u8 { 1218 // Assume premultiplied alpha such that src and dest are already multiplied 1219 // by their respective alpha values and in range 0..=255. The rounded over 1220 // blend is then (src * 255 + dest * (255 - src_alpha) + 128) / 255. 1221 // We approximate (x + 128) / 255 as (x + 128 + ((x + 128) >> 8)) >> 8. 1222 let x = src * 255 + dest as u32 * (255 - src_alpha) + 128; 1223 ((x + (x >> 8)) >> 8) as u8 1224 } 1225 1226 // Blends a single strike at a given offset into a destination buffer, assuming 1227 // the destination has been allocated with enough extra space to accommodate the 1228 // offset. 1229 #[allow(dead_code)] 1230 fn blend_strike( 1231 dest_bitmap: &mut [u8], 1232 src_bitmap: &[u8], 1233 width: usize, 1234 height: usize, 1235 subpixel_mask: bool, 1236 offset: f64, 1237 ) { 1238 let dest_stride = dest_bitmap.len() / height; 1239 let src_stride = width * 4; 1240 let offset_integer = offset.floor() as usize * 4; 1241 let offset_fract = (offset.fract() * 256.0) as u32; 1242 for (src_row, dest_row) in src_bitmap.chunks(src_stride).zip(dest_bitmap.chunks_mut(dest_stride)) { 1243 let mut prev_px = [0u32; 4]; 1244 let dest_row_offset = &mut dest_row[offset_integer .. offset_integer + src_stride]; 1245 for (src, dest) in src_row.chunks(4).zip(dest_row_offset.chunks_mut(4)) { 1246 let px = [src[0] as u32, src[1] as u32, src[2] as u32, src[3] as u32]; 1247 // Blend current pixel with previous pixel based on fractional offset. 1248 let next_px = [px[0] * offset_fract, 1249 px[1] * offset_fract, 1250 px[2] * offset_fract, 1251 px[3] * offset_fract]; 1252 let offset_px = [(((px[0] << 8) - next_px[0]) + prev_px[0] + 128) >> 8, 1253 (((px[1] << 8) - next_px[1]) + prev_px[1] + 128) >> 8, 1254 (((px[2] << 8) - next_px[2]) + prev_px[2] + 128) >> 8, 1255 (((px[3] << 8) - next_px[3]) + prev_px[3] + 128) >> 8]; 1256 if subpixel_mask { 1257 // Subpixel masks assume each component is an independent weight. 1258 dest[0] = blend_strike_pixel(dest[0], offset_px[0], offset_px[0]); 1259 dest[1] = blend_strike_pixel(dest[1], offset_px[1], offset_px[1]); 1260 dest[2] = blend_strike_pixel(dest[2], offset_px[2], offset_px[2]); 1261 dest[3] = blend_strike_pixel(dest[3], offset_px[3], offset_px[3]); 1262 } else { 1263 // Otherwise assume we have a premultiplied alpha BGRA value. 1264 dest[0] = blend_strike_pixel(dest[0], offset_px[0], offset_px[3]); 1265 dest[1] = blend_strike_pixel(dest[1], offset_px[1], offset_px[3]); 1266 dest[2] = blend_strike_pixel(dest[2], offset_px[2], offset_px[3]); 1267 dest[3] = blend_strike_pixel(dest[3], offset_px[3], offset_px[3]); 1268 } 1269 // Save the remainder for blending onto the next pixel. 1270 prev_px = next_px; 1271 } 1272 if offset_fract > 0 { 1273 // When there is fractional offset, there will be a remaining value 1274 // from the previous pixel but no next pixel, so just use that. 1275 let dest = &mut dest_row[offset_integer + src_stride .. ]; 1276 let offset_px = [(prev_px[0] + 128) >> 8, 1277 (prev_px[1] + 128) >> 8, 1278 (prev_px[2] + 128) >> 8, 1279 (prev_px[3] + 128) >> 8]; 1280 if subpixel_mask { 1281 dest[0] = blend_strike_pixel(dest[0], offset_px[0], offset_px[0]); 1282 dest[1] = blend_strike_pixel(dest[1], offset_px[1], offset_px[1]); 1283 dest[2] = blend_strike_pixel(dest[2], offset_px[2], offset_px[2]); 1284 dest[3] = blend_strike_pixel(dest[3], offset_px[3], offset_px[3]); 1285 } else { 1286 dest[0] = blend_strike_pixel(dest[0], offset_px[0], offset_px[3]); 1287 dest[1] = blend_strike_pixel(dest[1], offset_px[1], offset_px[3]); 1288 dest[2] = blend_strike_pixel(dest[2], offset_px[2], offset_px[3]); 1289 dest[3] = blend_strike_pixel(dest[3], offset_px[3], offset_px[3]); 1290 } 1291 } 1292 } 1293 } 1294 1295 // Applies multistrike bold to a source bitmap. This assumes the source bitmap 1296 // is a tighly packed slice of BGRA pixel values of exactly the specified width 1297 // and height. The specified extra strikes and pixel step control where to put 1298 // each strike. The pixel step is allowed to have a fractional offset and does 1299 // not strictly need to be integer. 1300 #[allow(dead_code)] 1301 pub fn apply_multistrike_bold( 1302 src_bitmap: &[u8], 1303 width: usize, 1304 height: usize, 1305 subpixel_mask: bool, 1306 extra_strikes: usize, 1307 pixel_step: f64, 1308 ) -> (Vec<u8>, usize) { 1309 let src_stride = width * 4; 1310 // The amount of extra width added to the bitmap from the extra strikes. 1311 let extra_width = (extra_strikes as f64 * pixel_step).ceil() as usize; 1312 let dest_width = width + extra_width; 1313 let dest_stride = dest_width * 4; 1314 // Zero out the initial bitmap so any extra width is cleared. 1315 let mut dest_bitmap = vec![0u8; dest_stride * height]; 1316 for (src_row, dest_row) in src_bitmap.chunks(src_stride).zip(dest_bitmap.chunks_mut(dest_stride)) { 1317 // Copy the initial bitmap strike rows directly from the source. 1318 dest_row[0 .. src_stride].copy_from_slice(src_row); 1319 } 1320 // Finally blend each extra strike in turn. 1321 for i in 1 ..= extra_strikes { 1322 let offset = i as f64 * pixel_step; 1323 blend_strike(&mut dest_bitmap, src_bitmap, width, height, subpixel_mask, offset); 1324 } 1325 (dest_bitmap, dest_width) 1326 } 1327 1328 pub struct RasterizedGlyph { 1329 pub top: f32, 1330 pub left: f32, 1331 pub width: i32, 1332 pub height: i32, 1333 pub scale: f32, 1334 pub format: GlyphFormat, 1335 pub bytes: Vec<u8>, 1336 pub is_packed_glyph: bool, 1337 } 1338 1339 impl RasterizedGlyph { 1340 #[allow(dead_code)] 1341 pub fn downscale_bitmap_if_required(&mut self, font: &FontInstance) { 1342 // Check if the glyph is going to be downscaled in the shader. If the scaling is 1343 // less than 0.5, that means bilinear filtering can't effectively filter the glyph 1344 // without aliasing artifacts. 1345 // 1346 // Instead of fixing this by mipmapping the glyph cache texture, rather manually 1347 // produce the appropriate mip level for individual glyphs where bilinear filtering 1348 // will still produce acceptable results. 1349 match self.format { 1350 GlyphFormat::Bitmap | GlyphFormat::ColorBitmap => {}, 1351 _ => return, 1352 } 1353 let (x_scale, y_scale) = font.transform.compute_scale().unwrap_or((1.0, 1.0)); 1354 let upscaled = x_scale.max(y_scale) as f32; 1355 let mut new_scale = self.scale; 1356 if new_scale * upscaled <= 0.0 { 1357 return; 1358 } 1359 let mut steps = 0; 1360 while new_scale * upscaled <= 0.5 { 1361 new_scale *= 2.0; 1362 steps += 1; 1363 } 1364 // If no mipping is necessary, just bail. 1365 if steps == 0 { 1366 return; 1367 } 1368 1369 // Calculate the actual size of the mip level. 1370 let new_width = (self.width as usize + (1 << steps) - 1) >> steps; 1371 let new_height = (self.height as usize + (1 << steps) - 1) >> steps; 1372 let mut new_bytes: Vec<u8> = Vec::with_capacity(new_width * new_height * 4); 1373 1374 // Produce destination pixels by applying a box filter to the source pixels. 1375 // The box filter corresponds to how graphics drivers may generate mipmaps. 1376 for y in 0 .. new_height { 1377 for x in 0 .. new_width { 1378 // Calculate the number of source samples that contribute to the destination pixel. 1379 let src_y = y << steps; 1380 let src_x = x << steps; 1381 let y_samples = (1 << steps).min(self.height as usize - src_y); 1382 let x_samples = (1 << steps).min(self.width as usize - src_x); 1383 let num_samples = (x_samples * y_samples) as u32; 1384 1385 let mut src_idx = (src_y * self.width as usize + src_x) * 4; 1386 // Initialize the accumulator with half an increment so that when later divided 1387 // by the sample count, it will effectively round the accumulator to the nearest 1388 // increment. 1389 let mut accum = [num_samples / 2; 4]; 1390 // Accumulate all the contributing source sampless. 1391 for _ in 0 .. y_samples { 1392 for _ in 0 .. x_samples { 1393 accum[0] += self.bytes[src_idx + 0] as u32; 1394 accum[1] += self.bytes[src_idx + 1] as u32; 1395 accum[2] += self.bytes[src_idx + 2] as u32; 1396 accum[3] += self.bytes[src_idx + 3] as u32; 1397 src_idx += 4; 1398 } 1399 src_idx += (self.width as usize - x_samples) * 4; 1400 } 1401 1402 // Finally, divide by the sample count to get the mean value for the new pixel. 1403 new_bytes.extend_from_slice(&[ 1404 (accum[0] / num_samples) as u8, 1405 (accum[1] / num_samples) as u8, 1406 (accum[2] / num_samples) as u8, 1407 (accum[3] / num_samples) as u8, 1408 ]); 1409 } 1410 } 1411 1412 // Fix the bounds for the new glyph data. 1413 self.top /= (1 << steps) as f32; 1414 self.left /= (1 << steps) as f32; 1415 self.width = new_width as i32; 1416 self.height = new_height as i32; 1417 self.scale = new_scale; 1418 self.bytes = new_bytes; 1419 } 1420 } 1421 1422 pub struct FontContexts { 1423 // These worker are mostly accessed from their corresponding worker threads. 1424 // The goal is that there should be no noticeable contention on the mutexes. 1425 worker_contexts: Vec<Mutex<FontContext>>, 1426 // Stored here as a convenience to get the current thread index. 1427 #[allow(dead_code)] 1428 workers: Arc<ThreadPool>, 1429 locked_mutex: Mutex<bool>, 1430 locked_cond: Condvar, 1431 } 1432 1433 impl FontContexts { 1434 /// Get access to any particular font context. 1435 /// 1436 /// The id is an index between 0 and num_worker_contexts for font contexts 1437 /// associated to the thread pool. 1438 pub fn lock_context(&self, id: usize) -> MutexGuard<FontContext> { 1439 self.worker_contexts[id].lock().unwrap() 1440 } 1441 1442 // Find a context that is currently unlocked to use, otherwise defaulting 1443 // to the first context. 1444 pub fn lock_any_context(&self) -> MutexGuard<FontContext> { 1445 for context in &self.worker_contexts { 1446 if let Ok(mutex) = context.try_lock() { 1447 return mutex; 1448 } 1449 } 1450 self.lock_context(0) 1451 } 1452 1453 // number of contexts associated to workers 1454 pub fn num_worker_contexts(&self) -> usize { 1455 self.worker_contexts.len() 1456 } 1457 } 1458 1459 pub trait AsyncForEach<T> { 1460 fn async_for_each<F: Fn(MutexGuard<T>) + Send + 'static>(&self, f: F); 1461 } 1462 1463 impl AsyncForEach<FontContext> for Arc<FontContexts> { 1464 fn async_for_each<F: Fn(MutexGuard<FontContext>) + Send + 'static>(&self, f: F) { 1465 // Reset the locked condition. 1466 let mut locked = self.locked_mutex.lock().unwrap(); 1467 *locked = false; 1468 1469 // Arc that can be safely moved into a spawn closure. 1470 let font_contexts = self.clone(); 1471 // Spawn a new thread on which to run the for-each off the main thread. 1472 self.workers.spawn(move || { 1473 // Lock the shared and worker contexts up front. 1474 let mut locks = Vec::with_capacity(font_contexts.num_worker_contexts()); 1475 for i in 0 .. font_contexts.num_worker_contexts() { 1476 locks.push(font_contexts.lock_context(i)); 1477 } 1478 1479 // Signal the locked condition now that all contexts are locked. 1480 *font_contexts.locked_mutex.lock().unwrap() = true; 1481 font_contexts.locked_cond.notify_all(); 1482 1483 // Now that everything is locked, proceed to processing each locked context. 1484 for context in locks { 1485 f(context); 1486 } 1487 }); 1488 1489 // Wait for locked condition before resuming. Safe to proceed thereafter 1490 // since any other thread that needs to use a FontContext will try to lock 1491 // it first. 1492 while !*locked { 1493 locked = self.locked_cond.wait(locked).unwrap(); 1494 } 1495 } 1496 } 1497 1498 pub struct GlyphRasterizer { 1499 #[allow(dead_code)] 1500 workers: Arc<ThreadPool>, 1501 font_contexts: Arc<FontContexts>, 1502 dedicated_thread: Option<GlyphRasterThread>, 1503 1504 /// The current set of loaded fonts. 1505 fonts: FastHashSet<FontKey>, 1506 1507 /// The current number of individual glyphs waiting in pending batches. 1508 pending_glyph_count: usize, 1509 1510 /// The current number of glyph request jobs that have been kicked to worker threads. 1511 pending_glyph_jobs: usize, 1512 1513 /// The number of glyphs requested this frame. 1514 glyph_request_count: usize, 1515 1516 /// A map of current glyph request batches. 1517 pending_glyph_requests: FastHashMap<FontInstance, SmallVec<[GlyphKey; 16]>>, 1518 1519 // Receives the rendered glyphs. 1520 glyph_rx: Receiver<GlyphRasterJob>, 1521 glyph_tx: Sender<GlyphRasterJob>, 1522 1523 // We defer removing fonts to the end of the frame so that: 1524 // - this work is done outside of the critical path, 1525 // - we don't have to worry about the ordering of events if a font is used on 1526 // a frame where it is used (although it seems unlikely). 1527 fonts_to_remove: Vec<FontKey>, 1528 // Defer removal of font instances, as for fonts. 1529 font_instances_to_remove: Vec<FontInstance>, 1530 1531 // Whether to parallelize glyph rasterization with rayon. 1532 enable_multithreading: bool, 1533 1534 // Whether glyphs can be rasterized in r8 format when it makes sense. 1535 can_use_r8_format: bool, 1536 } 1537 1538 impl GlyphRasterizer { 1539 pub fn new(workers: Arc<ThreadPool>, dedicated_thread: Option<GlyphRasterThread>, can_use_r8_format: bool) -> Self { 1540 let (glyph_tx, glyph_rx) = unbounded(); 1541 1542 let num_workers = workers.current_num_threads(); 1543 let mut contexts = Vec::with_capacity(num_workers); 1544 1545 for _ in 0 .. num_workers { 1546 contexts.push(Mutex::new(FontContext::new())); 1547 } 1548 1549 let font_context = FontContexts { 1550 worker_contexts: contexts, 1551 workers: Arc::clone(&workers), 1552 locked_mutex: Mutex::new(false), 1553 locked_cond: Condvar::new(), 1554 }; 1555 1556 GlyphRasterizer { 1557 font_contexts: Arc::new(font_context), 1558 fonts: FastHashSet::default(), 1559 dedicated_thread, 1560 pending_glyph_jobs: 0, 1561 pending_glyph_count: 0, 1562 glyph_request_count: 0, 1563 glyph_rx, 1564 glyph_tx, 1565 workers, 1566 fonts_to_remove: Vec::new(), 1567 font_instances_to_remove: Vec::new(), 1568 enable_multithreading: true, 1569 pending_glyph_requests: FastHashMap::default(), 1570 can_use_r8_format, 1571 } 1572 } 1573 1574 pub fn add_font(&mut self, font_key: FontKey, template: FontTemplate) { 1575 // Only add font to FontContexts if not previously added. 1576 if self.fonts.insert(font_key.clone()) { 1577 if let Some(thread) = &self.dedicated_thread { 1578 let _ = thread.tx.send(GlyphRasterMsg::AddFont { font_key, template }); 1579 } else { 1580 self.font_contexts.async_for_each(move |mut context| { 1581 context.add_font(&font_key, &template); 1582 }); 1583 } 1584 } 1585 } 1586 1587 pub fn delete_font(&mut self, font_key: FontKey) { 1588 self.fonts_to_remove.push(font_key); 1589 } 1590 1591 pub fn delete_fonts(&mut self, font_keys: &[FontKey]) { 1592 self.fonts_to_remove.extend_from_slice(font_keys); 1593 } 1594 1595 pub fn delete_font_instance(&mut self, instance: &FontInstance) { 1596 self.font_instances_to_remove.push(instance.clone()); 1597 } 1598 1599 pub fn prepare_font(&self, font: &mut FontInstance) { 1600 FontContext::prepare_font(font); 1601 1602 // Quantize the transform to minimize thrashing of the glyph cache, but 1603 // only quantize the transform when preparing to access the glyph cache. 1604 // This way, the glyph subpixel positions, which are calculated before 1605 // this, can still use the precise transform which is required to match 1606 // the subpixel positions computed for glyphs in the text run shader. 1607 font.transform = font.transform.quantize(); 1608 } 1609 1610 pub fn has_font(&self, font_key: FontKey) -> bool { 1611 self.fonts.contains(&font_key) 1612 } 1613 1614 pub fn get_glyph_dimensions( 1615 &mut self, 1616 font: &FontInstance, 1617 glyph_index: GlyphIndex, 1618 ) -> Option<GlyphDimensions> { 1619 let glyph_key = GlyphKey::new( 1620 glyph_index, 1621 DevicePoint::zero(), 1622 SubpixelDirection::None, 1623 ); 1624 1625 self.font_contexts 1626 .lock_any_context() 1627 .get_glyph_dimensions(font, &glyph_key) 1628 } 1629 1630 pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> { 1631 self.font_contexts 1632 .lock_any_context() 1633 .get_glyph_index(font_key, ch) 1634 } 1635 1636 fn remove_dead_fonts(&mut self) { 1637 if self.fonts_to_remove.is_empty() && self.font_instances_to_remove.is_empty() { 1638 return 1639 } 1640 1641 profile_scope!("remove_dead_fonts"); 1642 let mut fonts_to_remove = mem::replace(& mut self.fonts_to_remove, Vec::new()); 1643 // Only remove font from FontContexts if previously added. 1644 fonts_to_remove.retain(|font| self.fonts.remove(font)); 1645 let font_instances_to_remove = mem::replace(& mut self.font_instances_to_remove, Vec::new()); 1646 if let Some(thread) = &self.dedicated_thread { 1647 for font_key in fonts_to_remove { 1648 let _ = thread.tx.send(GlyphRasterMsg::DeleteFont { font_key }); 1649 } 1650 for instance in font_instances_to_remove { 1651 let _ = thread.tx.send(GlyphRasterMsg::DeleteFontInstance { instance }); 1652 } 1653 } else { 1654 self.font_contexts.async_for_each(move |mut context| { 1655 for font_key in &fonts_to_remove { 1656 context.delete_font(font_key); 1657 } 1658 for instance in &font_instances_to_remove { 1659 context.delete_font_instance(instance); 1660 } 1661 }); 1662 } 1663 } 1664 1665 #[cfg(feature = "replay")] 1666 pub fn reset(&mut self) { 1667 //TODO: any signals need to be sent to the workers? 1668 self.pending_glyph_jobs = 0; 1669 self.pending_glyph_count = 0; 1670 self.glyph_request_count = 0; 1671 self.fonts_to_remove.clear(); 1672 self.font_instances_to_remove.clear(); 1673 } 1674 } 1675 1676 trait AddFont { 1677 fn add_font(&mut self, font_key: &FontKey, template: &FontTemplate); 1678 } 1679 1680 impl AddFont for FontContext { 1681 fn add_font(&mut self, font_key: &FontKey, template: &FontTemplate) { 1682 match *template { 1683 FontTemplate::Raw(ref bytes, index) => { 1684 self.add_raw_font(font_key, bytes.clone(), index); 1685 } 1686 FontTemplate::Native(ref native_font_handle) => { 1687 self.add_native_font(font_key, (*native_font_handle).clone()); 1688 } 1689 } 1690 } 1691 } 1692 1693 #[allow(dead_code)] 1694 pub struct GlyphRasterJob { 1695 pub font: Arc<FontInstance>, 1696 pub key: GlyphKey, 1697 pub result: GlyphRasterResult, 1698 } 1699 1700 #[allow(dead_code)] 1701 #[derive(Debug)] 1702 pub enum GlyphRasterError { 1703 LoadFailed, 1704 } 1705 1706 #[allow(dead_code)] 1707 pub type GlyphRasterResult = Result<RasterizedGlyph, GlyphRasterError>; 1708 1709 #[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)] 1710 #[cfg_attr(feature = "capture", derive(Serialize))] 1711 #[cfg_attr(feature = "replay", derive(Deserialize))] 1712 pub struct GpuGlyphCacheKey(pub u32); 1713 1714 fn pack_glyph_variants_horizontal(variants: &[RasterizedGlyph]) -> RasterizedGlyph { 1715 // Pack 4 glyph variants horizontally into a single texture. 1716 // Normalize both left and top offsets via padding so all variants can use the same base offsets. 1717 1718 let min_left = variants.iter().map(|v| v.left.floor()).fold(f32::INFINITY, f32::min); 1719 let max_top = variants.iter().map(|v| v.top.floor()).fold(f32::NEG_INFINITY, f32::max); 1720 1721 // Slot width must accommodate the widest variant plus left padding 1722 let slot_width = variants.iter() 1723 .map(|v| v.width + (v.left.floor() - min_left) as i32) 1724 .max().unwrap(); 1725 1726 // Slot height must accommodate the tallest variant plus top padding 1727 let slot_height = variants.iter() 1728 .map(|v| v.height + (max_top - v.top.floor()) as i32) 1729 .max().unwrap(); 1730 1731 let packed_width = slot_width * 4; 1732 let bpp = 4; 1733 1734 let mut packed_bytes = vec![0u8; (packed_width * slot_height * bpp) as usize]; 1735 1736 for (variant_idx, variant) in variants.iter().enumerate() { 1737 // Compute padding needed to normalize both left and top offsets 1738 let left_pad = (variant.left.floor() - min_left) as i32; 1739 let top_pad = (max_top - variant.top.floor()) as i32; 1740 let slot_x = variant_idx as i32 * slot_width; 1741 1742 for src_y in 0..variant.height { 1743 let dst_y = src_y + top_pad; 1744 if dst_y >= slot_height { 1745 break; 1746 } 1747 1748 let dst_x = slot_x + left_pad; 1749 if dst_x < 0 { 1750 continue; 1751 } 1752 1753 let src_row_start = (src_y * variant.width * bpp) as usize; 1754 let src_row_end = src_row_start + (variant.width * bpp) as usize; 1755 let dst_row_start = (dst_y * packed_width * bpp + dst_x * bpp) as usize; 1756 let dst_row_end = dst_row_start + (variant.width * bpp) as usize; 1757 1758 if dst_row_end <= packed_bytes.len() && src_row_end <= variant.bytes.len() { 1759 packed_bytes[dst_row_start..dst_row_end] 1760 .copy_from_slice(&variant.bytes[src_row_start..src_row_end]); 1761 } 1762 } 1763 } 1764 1765 RasterizedGlyph { 1766 top: max_top, 1767 left: min_left, 1768 width: packed_width, 1769 height: slot_height, 1770 scale: variants[0].scale, 1771 format: variants[0].format, 1772 bytes: packed_bytes, 1773 is_packed_glyph: true, 1774 } 1775 } 1776 1777 fn process_glyph( 1778 context: &mut FontContext, 1779 can_use_r8_format: bool, 1780 font: Arc<FontInstance>, 1781 key: GlyphKey, 1782 ) -> GlyphRasterJob { 1783 profile_scope!("glyph-raster"); 1784 1785 let subpx_dir = key.subpixel_dir(); 1786 1787 let result = if subpx_dir == SubpixelDirection::None { 1788 context.rasterize_glyph(&font, &key) 1789 } else { 1790 let offsets = [ 1791 SubpixelOffset::Zero, 1792 SubpixelOffset::Quarter, 1793 SubpixelOffset::Half, 1794 SubpixelOffset::ThreeQuarters, 1795 ]; 1796 1797 let mut variants = Vec::with_capacity(4); 1798 for offset in &offsets { 1799 let variant_key = GlyphKey::new( 1800 key.index(), 1801 match subpx_dir { 1802 SubpixelDirection::Horizontal => DevicePoint::new(offset.to_f32(), 0.0), 1803 SubpixelDirection::Vertical => DevicePoint::new(0.0, offset.to_f32()), 1804 SubpixelDirection::None => DevicePoint::zero(), 1805 }, 1806 subpx_dir, 1807 ); 1808 1809 match context.rasterize_glyph(&font, &variant_key) { 1810 Ok(glyph) => variants.push(glyph), 1811 Err(e) => return GlyphRasterJob { 1812 font: font, 1813 key: key.clone(), 1814 result: Err(e), 1815 }, 1816 } 1817 } 1818 1819 Ok(pack_glyph_variants_horizontal(&variants)) 1820 }; 1821 1822 let mut job = GlyphRasterJob { 1823 font: font, 1824 key: key.clone(), 1825 result, 1826 }; 1827 1828 if let Ok(ref mut glyph) = job.result { 1829 // Sanity check. 1830 let bpp = 4; // We always render glyphs in 32 bits RGBA format. 1831 assert_eq!( 1832 glyph.bytes.len(), 1833 bpp * (glyph.width * glyph.height) as usize 1834 ); 1835 1836 // a quick-and-dirty monochrome over 1837 fn over(dst: u8, src: u8) -> u8 { 1838 let a = src as u32; 1839 let a = 256 - a; 1840 let dst = ((dst as u32 * a) >> 8) as u8; 1841 src + dst 1842 } 1843 1844 if GLYPH_FLASHING.load(Ordering::Relaxed) { 1845 let color = (random() & 0xff) as u8; 1846 for i in &mut glyph.bytes { 1847 *i = over(*i, color); 1848 } 1849 } 1850 1851 assert_eq!((glyph.left.fract(), glyph.top.fract()), (0.0, 0.0)); 1852 1853 // Check if the glyph has a bitmap that needs to be downscaled. 1854 glyph.downscale_bitmap_if_required(&job.font); 1855 1856 // Convert from BGRA8 to R8 if required. In the future we can make it the 1857 // backends' responsibility to output glyphs in the desired format, 1858 // potentially reducing the number of copies. 1859 if glyph.format.image_format(can_use_r8_format).bytes_per_pixel() == 1 { 1860 glyph.bytes = glyph.bytes 1861 .chunks_mut(4) 1862 .map(|pixel| pixel[3]) 1863 .collect::<Vec<_>>(); 1864 } 1865 } 1866 1867 job 1868 } 1869 1870 1871 pub enum GlyphRasterMsg { 1872 Rasterize { 1873 font: Arc<FontInstance>, 1874 glyphs: SmallVec<[GlyphKey; 16]>, 1875 can_use_r8_format: bool, 1876 tx: Sender<GlyphRasterJob>, 1877 }, 1878 AddFont { font_key: FontKey, template: FontTemplate }, 1879 DeleteFont { font_key: FontKey }, 1880 DeleteFontInstance { instance: FontInstance }, 1881 ShutDown, 1882 } 1883 1884 #[derive(Clone)] 1885 pub struct GlyphRasterThread { 1886 tx: Sender<GlyphRasterMsg>, 1887 } 1888 1889 impl GlyphRasterThread { 1890 pub fn new( 1891 on_start: impl FnOnce() + Send + 'static, 1892 on_end: impl FnOnce() + Send+ 'static, 1893 ) -> std::io::Result<Self> { 1894 let (tx, rx) = unbounded(); 1895 1896 std::thread::Builder::new().name("Glyph rasterizer".to_string()).spawn(move || { 1897 on_start(); 1898 1899 let mut context = FontContext::new(); 1900 1901 loop { 1902 match rx.recv() { 1903 Ok(GlyphRasterMsg::Rasterize { font, glyphs, can_use_r8_format, tx }) => { 1904 for glyph in &glyphs { 1905 let job = process_glyph(&mut context, can_use_r8_format, font.clone(), *glyph); 1906 let _ = tx.send(job); 1907 } 1908 } 1909 Ok(GlyphRasterMsg::AddFont { font_key, template }) => { 1910 context.add_font(&font_key, &template) 1911 } 1912 Ok(GlyphRasterMsg::DeleteFont { font_key }) => { 1913 context.delete_font(&font_key) 1914 } 1915 Ok(GlyphRasterMsg::DeleteFontInstance { instance }) => { 1916 context.delete_font_instance(&instance) 1917 } 1918 Ok(GlyphRasterMsg::ShutDown) => { 1919 break; 1920 } 1921 Err(..) => { 1922 break; 1923 } 1924 } 1925 } 1926 1927 on_end(); 1928 })?; 1929 1930 Ok(GlyphRasterThread { 1931 tx, 1932 }) 1933 } 1934 1935 pub fn shut_down(&self) { 1936 let _ = self.tx.send(GlyphRasterMsg::ShutDown); 1937 } 1938 } 1939 1940 #[cfg(test)] 1941 mod test_glyph_rasterizer { 1942 use crate::profiler::GlyphRasterizeProfiler; 1943 1944 struct Profiler; 1945 impl GlyphRasterizeProfiler for Profiler { 1946 fn start_time(&mut self) {} 1947 fn end_time(&mut self) -> f64 { 1948 0. 1949 } 1950 fn set(&mut self, _value: f64) {} 1951 } 1952 1953 #[test] 1954 fn rasterize_200_glyphs() { 1955 // This test loads a font from disc, the renders 4 requests containing 1956 // 50 glyphs each, deletes the font and waits for the result. 1957 1958 use rayon::ThreadPoolBuilder; 1959 use std::fs::File; 1960 use std::io::Read; 1961 use api::{FontKey, FontInstanceKey, FontTemplate, IdNamespace}; 1962 use api::units::DevicePoint; 1963 use std::sync::Arc; 1964 use crate::rasterizer::{FontInstance, BaseFontInstance, GlyphKey, GlyphRasterizer}; 1965 1966 let worker = ThreadPoolBuilder::new() 1967 .thread_name(|idx|{ format!("WRWorker#{}", idx) }) 1968 .build(); 1969 let workers = Arc::new(worker.unwrap()); 1970 let mut glyph_rasterizer = GlyphRasterizer::new(workers, None, true); 1971 let mut font_file = 1972 File::open("../wrench/reftests/text/VeraBd.ttf").expect("Couldn't open font file"); 1973 let mut font_data = vec![]; 1974 font_file 1975 .read_to_end(&mut font_data) 1976 .expect("failed to read font file"); 1977 1978 let font_key = FontKey::new(IdNamespace(0), 0); 1979 glyph_rasterizer.add_font(font_key, FontTemplate::Raw(Arc::new(font_data), 0)); 1980 1981 let font = FontInstance::from_base(Arc::new(BaseFontInstance::new( 1982 FontInstanceKey::new(IdNamespace(0), 0), 1983 font_key, 1984 32.0, 1985 None, 1986 None, 1987 Vec::new(), 1988 ))); 1989 1990 let subpx_dir = font.get_subpx_dir(); 1991 1992 let mut glyph_keys = Vec::with_capacity(200); 1993 for i in 0 .. 200 { 1994 glyph_keys.push(GlyphKey::new( 1995 i, 1996 DevicePoint::zero(), 1997 subpx_dir, 1998 )); 1999 } 2000 2001 for i in 0 .. 4 { 2002 glyph_rasterizer.request_glyphs( 2003 font.clone(), 2004 &glyph_keys[(50 * i) .. (50 * (i + 1))], 2005 |_| true, 2006 ); 2007 } 2008 2009 glyph_rasterizer.delete_font(font_key); 2010 2011 glyph_rasterizer.resolve_glyphs( 2012 |_, _| {}, 2013 &mut Profiler, 2014 ); 2015 } 2016 2017 #[test] 2018 fn rasterize_large_glyphs() { 2019 // This test loads a font from disc and rasterize a few glyphs with a size of 200px to check 2020 // that the texture cache handles them properly. 2021 use rayon::ThreadPoolBuilder; 2022 use std::fs::File; 2023 use std::io::Read; 2024 use api::{FontKey, FontInstanceKey, FontTemplate, IdNamespace}; 2025 use api::units::DevicePoint; 2026 use std::sync::Arc; 2027 use crate::rasterizer::{FontInstance, BaseFontInstance, GlyphKey, GlyphRasterizer}; 2028 2029 let worker = ThreadPoolBuilder::new() 2030 .thread_name(|idx|{ format!("WRWorker#{}", idx) }) 2031 .build(); 2032 let workers = Arc::new(worker.unwrap()); 2033 let mut glyph_rasterizer = GlyphRasterizer::new(workers, None, true); 2034 let mut font_file = 2035 File::open("../wrench/reftests/text/VeraBd.ttf").expect("Couldn't open font file"); 2036 let mut font_data = vec![]; 2037 font_file 2038 .read_to_end(&mut font_data) 2039 .expect("failed to read font file"); 2040 2041 let font_key = FontKey::new(IdNamespace(0), 0); 2042 glyph_rasterizer.add_font(font_key, FontTemplate::Raw(Arc::new(font_data), 0)); 2043 2044 let font = FontInstance::from_base(Arc::new(BaseFontInstance::new( 2045 FontInstanceKey::new(IdNamespace(0), 0), 2046 font_key, 2047 200.0, 2048 None, 2049 None, 2050 Vec::new(), 2051 ))); 2052 2053 let subpx_dir = font.get_subpx_dir(); 2054 2055 let mut glyph_keys = Vec::with_capacity(10); 2056 for i in 0 .. 10 { 2057 glyph_keys.push(GlyphKey::new( 2058 i, 2059 DevicePoint::zero(), 2060 subpx_dir, 2061 )); 2062 } 2063 2064 glyph_rasterizer.request_glyphs( 2065 font.clone(), 2066 &glyph_keys, 2067 |_| true, 2068 ); 2069 2070 glyph_rasterizer.delete_font(font_key); 2071 2072 glyph_rasterizer.resolve_glyphs( 2073 |_, _| {}, 2074 &mut Profiler, 2075 ); 2076 } 2077 2078 #[test] 2079 fn test_subpx_quantize() { 2080 use crate::rasterizer::SubpixelOffset; 2081 2082 assert_eq!(SubpixelOffset::quantize(0.0), SubpixelOffset::Zero); 2083 assert_eq!(SubpixelOffset::quantize(-0.0), SubpixelOffset::Zero); 2084 2085 assert_eq!(SubpixelOffset::quantize(0.1), SubpixelOffset::Zero); 2086 assert_eq!(SubpixelOffset::quantize(0.01), SubpixelOffset::Zero); 2087 assert_eq!(SubpixelOffset::quantize(0.05), SubpixelOffset::Zero); 2088 assert_eq!(SubpixelOffset::quantize(0.12), SubpixelOffset::Zero); 2089 assert_eq!(SubpixelOffset::quantize(0.124), SubpixelOffset::Zero); 2090 2091 assert_eq!(SubpixelOffset::quantize(0.125), SubpixelOffset::Quarter); 2092 assert_eq!(SubpixelOffset::quantize(0.2), SubpixelOffset::Quarter); 2093 assert_eq!(SubpixelOffset::quantize(0.25), SubpixelOffset::Quarter); 2094 assert_eq!(SubpixelOffset::quantize(0.33), SubpixelOffset::Quarter); 2095 assert_eq!(SubpixelOffset::quantize(0.374), SubpixelOffset::Quarter); 2096 2097 assert_eq!(SubpixelOffset::quantize(0.375), SubpixelOffset::Half); 2098 assert_eq!(SubpixelOffset::quantize(0.4), SubpixelOffset::Half); 2099 assert_eq!(SubpixelOffset::quantize(0.5), SubpixelOffset::Half); 2100 assert_eq!(SubpixelOffset::quantize(0.58), SubpixelOffset::Half); 2101 assert_eq!(SubpixelOffset::quantize(0.624), SubpixelOffset::Half); 2102 2103 assert_eq!(SubpixelOffset::quantize(0.625), SubpixelOffset::ThreeQuarters); 2104 assert_eq!(SubpixelOffset::quantize(0.67), SubpixelOffset::ThreeQuarters); 2105 assert_eq!(SubpixelOffset::quantize(0.7), SubpixelOffset::ThreeQuarters); 2106 assert_eq!(SubpixelOffset::quantize(0.78), SubpixelOffset::ThreeQuarters); 2107 assert_eq!(SubpixelOffset::quantize(0.874), SubpixelOffset::ThreeQuarters); 2108 2109 assert_eq!(SubpixelOffset::quantize(0.875), SubpixelOffset::Zero); 2110 assert_eq!(SubpixelOffset::quantize(0.89), SubpixelOffset::Zero); 2111 assert_eq!(SubpixelOffset::quantize(0.91), SubpixelOffset::Zero); 2112 assert_eq!(SubpixelOffset::quantize(0.967), SubpixelOffset::Zero); 2113 assert_eq!(SubpixelOffset::quantize(0.999), SubpixelOffset::Zero); 2114 2115 assert_eq!(SubpixelOffset::quantize(-1.0), SubpixelOffset::Zero); 2116 assert_eq!(SubpixelOffset::quantize(1.0), SubpixelOffset::Zero); 2117 assert_eq!(SubpixelOffset::quantize(1.5), SubpixelOffset::Half); 2118 assert_eq!(SubpixelOffset::quantize(-1.625), SubpixelOffset::Half); 2119 assert_eq!(SubpixelOffset::quantize(-4.33), SubpixelOffset::ThreeQuarters); 2120 } 2121 }