gfxFont.h (93627B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=4 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef GFX_FONT_H 8 #define GFX_FONT_H 9 10 #include <new> 11 #include <functional> 12 #include "PLDHashTable.h" 13 #include "ThebesRLBoxTypes.h" 14 #include "gfxFontVariations.h" 15 #include "gfxRect.h" 16 #include "gfxTypes.h" 17 #include "mozilla/AlreadyAddRefed.h" 18 #include "mozilla/Attributes.h" 19 #include "mozilla/FontPropertyTypes.h" 20 #include "mozilla/HashTable.h" 21 #include "mozilla/MemoryReporting.h" 22 #include "mozilla/Mutex.h" 23 #include "mozilla/RefPtr.h" 24 #include "mozilla/RWLock.h" 25 #include "mozilla/TypedEnumBits.h" 26 #include "mozilla/UniquePtr.h" 27 #include "mozilla/gfx/FontPaletteCache.h" 28 #include "mozilla/gfx/MatrixFwd.h" 29 #include "mozilla/gfx/Point.h" 30 #include "mozilla/gfx/2D.h" 31 #include "mozilla/intl/UnicodeScriptCodes.h" 32 #include "nsCOMPtr.h" 33 #include "nsColor.h" 34 #include "nsTHashMap.h" 35 #include "nsTHashSet.h" 36 #include "nsExpirationTracker.h" 37 #include "nsFontMetrics.h" 38 #include "nsHashKeys.h" 39 #include "nsIMemoryReporter.h" 40 #include "nsIObserver.h" 41 #include "nsISupports.h" 42 #include "nsString.h" 43 #include "nsTArray.h" 44 #include "nsTHashtable.h" 45 #include "nscore.h" 46 #include "DrawMode.h" 47 48 // Only required for function bodies 49 #include "gfxFontEntry.h" 50 #include "gfxFontFeatures.h" 51 52 class FontVisibilityProvider; 53 class gfxContext; 54 class gfxGraphiteShaper; 55 class gfxHarfBuzzShaper; 56 class gfxGlyphExtents; 57 class gfxMathTable; 58 class gfxPattern; 59 class gfxShapedText; 60 class gfxShapedWord; 61 class gfxSkipChars; 62 class gfxTextRun; 63 class nsIEventTarget; 64 class nsITimer; 65 struct gfxTextRunDrawCallbacks; 66 67 namespace mozilla { 68 class SVGContextPaint; 69 namespace layout { 70 class TextDrawTarget; 71 } 72 } // namespace mozilla 73 74 typedef struct _cairo cairo_t; 75 typedef struct _cairo_scaled_font cairo_scaled_font_t; 76 77 #define FONT_MAX_SIZE 2000.0 78 79 #define SMALL_CAPS_SCALE_FACTOR 0.8 80 81 // The skew factor used for synthetic-italic [oblique] fonts; 82 // we use a platform-dependent value to harmonize with the platform's own APIs. 83 #ifdef XP_WIN 84 # define OBLIQUE_SKEW_FACTOR 0.3f 85 #elif defined(MOZ_WIDGET_GTK) 86 # define OBLIQUE_SKEW_FACTOR 0.2f 87 #else 88 # define OBLIQUE_SKEW_FACTOR 0.25f 89 #endif 90 91 struct gfxFontStyle { 92 using FontStretch = mozilla::FontStretch; 93 using FontSlantStyle = mozilla::FontSlantStyle; 94 using FontWeight = mozilla::FontWeight; 95 using FontSizeAdjust = mozilla::StyleFontSizeAdjust; 96 97 gfxFontStyle(); 98 gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight, FontStretch aStretch, 99 gfxFloat aSize, const FontSizeAdjust& aSizeAdjust, 100 bool aSystemFont, bool aPrinterFont, 101 #ifdef XP_WIN 102 bool aAllowForceGDIClassic, 103 #endif 104 bool aWeightSynthesis, 105 mozilla::StyleFontSynthesisStyle aStyleSynthesis, 106 bool aSmallCapsSynthesis, bool aPositionSynthesis, 107 mozilla::StyleFontLanguageOverride aLanguageOverride); 108 // Features are composed of (1) features from style rules (2) features 109 // from feature settings rules and (3) family-specific features. (1) and 110 // (3) are guaranteed to be mutually exclusive 111 112 // custom opentype feature settings 113 CopyableTArray<gfxFontFeature> featureSettings; 114 115 // Some font-variant property values require font-specific settings 116 // defined via @font-feature-values rules. These are resolved after 117 // font matching occurs. 118 119 // -- list of value tags for specific alternate features 120 mozilla::StyleFontVariantAlternates variantAlternates; 121 122 // -- object used to look these up once the font is matched 123 RefPtr<gfxFontFeatureValueSet> featureValueLookup; 124 125 // opentype variation settings 126 CopyableTArray<gfxFontVariation> variationSettings; 127 128 // The logical size of the font, in pixels 129 gfxFloat size; 130 131 // The optical size value to apply (if supported); negative means none. 132 float autoOpticalSize = -1.0f; 133 134 // The aspect-value (ie., the ratio actualsize:actualxheight) that any 135 // actual physical font created from this font structure must have when 136 // rendering or measuring a string. A value of -1.0 means no adjustment 137 // needs to be done; otherwise the value must be nonnegative. 138 float sizeAdjust; 139 140 // baseline offset, used when simulating sub/superscript glyphs 141 float baselineOffset; 142 143 // Language system tag, to override document language; 144 // an OpenType "language system" tag represented as a 32-bit integer 145 // (see http://www.microsoft.com/typography/otspec/languagetags.htm). 146 // Normally 0, so font rendering will use the document or element language 147 // (see above) to control any language-specific rendering, but the author 148 // can override this for cases where the options implemented in the font 149 // do not directly match the actual language. (E.g. lang may be Macedonian, 150 // but the font in use does not explicitly support this; the author can 151 // use font-language-override to request the Serbian option in the font 152 // in order to get correct glyph shapes.) 153 mozilla::StyleFontLanguageOverride languageOverride; 154 155 // The Font{Weight,Stretch,SlantStyle} fields are each a 16-bit type. 156 157 // The weight of the font: 100, 200, ... 900. 158 FontWeight weight; 159 160 // The stretch of the font 161 FontStretch stretch; 162 163 // The style of font 164 FontSlantStyle style; 165 166 // Whether face-selection properties weight/style/stretch are all 'normal' 167 bool IsNormalStyle() const { 168 return weight.IsNormal() && style.IsNormal() && stretch.IsNormal(); 169 } 170 171 // We pack these three small-integer fields into a single byte to avoid 172 // overflowing an 8-byte boundary [in a 64-bit build] and ending up with 173 // 7 bytes of padding at the end of the struct. 174 175 // caps variant (small-caps, petite-caps, etc.) 176 uint8_t variantCaps : 3; // uses range 0..6 177 178 // sub/superscript variant 179 uint8_t variantSubSuper : 2; // uses range 0..2 180 181 // font metric used as basis of font-size-adjust 182 uint8_t sizeAdjustBasis : 3; // uses range 0..4 183 184 // Say that this font is a system font and therefore does not 185 // require certain fixup that we do for fonts from untrusted 186 // sources. 187 bool systemFont : 1; 188 189 // Say that this font is used for print or print preview. 190 bool printerFont : 1; 191 192 #ifdef XP_WIN 193 bool allowForceGDIClassic : 1; 194 #endif 195 196 // Used to imitate -webkit-font-smoothing: antialiased 197 bool useGrayscaleAntialiasing : 1; 198 199 // Whether synthetic styles are allowed (required, in the case of position) 200 bool allowSyntheticWeight : 1; 201 mozilla::StyleFontSynthesisStyle synthesisStyle : 2; 202 bool allowSyntheticSmallCaps : 1; 203 bool useSyntheticPosition : 1; 204 205 // some variant features require fallback which complicates the shaping 206 // code, so set up a bool to indicate when shaping with fallback is needed 207 bool noFallbackVariantFeatures : 1; 208 209 // Return the final adjusted font size for the given aspect ratio. 210 // Not meant to be called when sizeAdjustBasis is NONE. 211 gfxFloat GetAdjustedSize(gfxFloat aspect) const { 212 MOZ_ASSERT( 213 FontSizeAdjust::Tag(sizeAdjustBasis) != FontSizeAdjust::Tag::None, 214 "Not meant to be called when sizeAdjustBasis is none"); 215 gfxFloat adjustedSize = 216 std::max(NS_round(size * (sizeAdjust / aspect)), 1.0); 217 return std::min(adjustedSize, FONT_MAX_SIZE); 218 } 219 220 // Some callers want to take a short-circuit path if they can be sure the 221 // adjusted size will be zero. 222 bool AdjustedSizeMustBeZero() const { 223 return size == 0.0 || 224 (FontSizeAdjust::Tag(sizeAdjustBasis) != FontSizeAdjust::Tag::None && 225 sizeAdjust == 0.0); 226 } 227 228 PLDHashNumber Hash() const; 229 230 // Adjust this style to simulate sub/superscript (as requested in the 231 // variantSubSuper field) using size and baselineOffset instead. 232 void AdjustForSubSuperscript(int32_t aAppUnitsPerDevPixel); 233 234 // Should this style cause the given font entry to use synthetic bold? 235 bool NeedsSyntheticBold(gfxFontEntry* aFontEntry) const { 236 return weight.IsBold() && allowSyntheticWeight && 237 !aFontEntry->SupportsBold(); 238 } 239 240 bool Equals(const gfxFontStyle& other) const { 241 return mozilla::NumbersAreBitwiseIdentical(size, other.size) && 242 (style == other.style) && (weight == other.weight) && 243 (stretch == other.stretch) && (variantCaps == other.variantCaps) && 244 (variantSubSuper == other.variantSubSuper) && 245 (allowSyntheticWeight == other.allowSyntheticWeight) && 246 (synthesisStyle == other.synthesisStyle) && 247 (allowSyntheticSmallCaps == other.allowSyntheticSmallCaps) && 248 (useSyntheticPosition == other.useSyntheticPosition) && 249 (systemFont == other.systemFont) && 250 (printerFont == other.printerFont) && 251 #ifdef XP_WIN 252 (allowForceGDIClassic == other.allowForceGDIClassic) && 253 #endif 254 (useGrayscaleAntialiasing == other.useGrayscaleAntialiasing) && 255 (baselineOffset == other.baselineOffset) && 256 mozilla::NumbersAreBitwiseIdentical(sizeAdjust, other.sizeAdjust) && 257 (sizeAdjustBasis == other.sizeAdjustBasis) && 258 (featureSettings == other.featureSettings) && 259 (variantAlternates == other.variantAlternates) && 260 (featureValueLookup == other.featureValueLookup) && 261 (variationSettings == other.variationSettings) && 262 (languageOverride == other.languageOverride) && 263 mozilla::NumbersAreBitwiseIdentical(autoOpticalSize, 264 other.autoOpticalSize); 265 } 266 }; 267 268 /** 269 * Font cache design: 270 * 271 * The mFonts hashtable contains most fonts, indexed by (gfxFontEntry*, style). 272 * It maintains a strong reference to the fonts it contains. 273 * Whenever a font is accessed, it is marked as used to move it to a new 274 * generation in the tracker to avoid expiration. 275 * The expiration tracker will only expire fonts with a single reference, the 276 * cache itself. Fonts with more than one reference are marked as used. 277 * 278 * We're using 3 generations with a ten-second generation interval, so 279 * zero-refcount fonts will be deleted 20-30 seconds after their refcount 280 * goes to zero, if timer events fire in a timely manner. 281 * 282 * The font cache also handles timed expiration of cached ShapedWords 283 * for "persistent" fonts: it has a repeating timer, and notifies 284 * each cached font to "age" its shaped words. The words will be released 285 * by the fonts if they get aged three times without being re-used in the 286 * meantime. 287 * 288 * Note that the ShapedWord timeout is much larger than the font timeout, 289 * so that in the case of a short-lived font, we'll discard the gfxFont 290 * completely, with all its words, and avoid the cost of aging the words 291 * individually. That only happens with longer-lived fonts. 292 */ 293 struct FontCacheSizes { 294 FontCacheSizes() : mFontInstances(0), mShapedWords(0) {} 295 296 size_t mFontInstances; // memory used by instances of gfxFont subclasses 297 size_t mShapedWords; // memory used by the per-font shapedWord caches 298 }; 299 300 class gfxFontCache final 301 : public ExpirationTrackerImpl<gfxFont, 3, mozilla::Mutex, 302 mozilla::MutexAutoLock> { 303 protected: 304 // Expiration tracker implementation. 305 enum { FONT_TIMEOUT_SECONDS = 10 }; 306 307 typedef mozilla::Mutex Lock; 308 typedef mozilla::MutexAutoLock AutoLock; 309 310 // This protects the ExpirationTracker tables. 311 Lock mMutex = Lock("fontCacheExpirationMutex"); 312 313 Lock& GetMutex() override { return mMutex; } 314 315 public: 316 explicit gfxFontCache(nsIEventTarget* aEventTarget); 317 ~gfxFontCache(); 318 319 enum { SHAPED_WORD_TIMEOUT_SECONDS = 60 }; 320 321 /* 322 * Get the global gfxFontCache. You must call Init() before 323 * calling this method --- the result will not be null. 324 */ 325 static gfxFontCache* GetCache() { return gGlobalCache; } 326 327 static nsresult Init(); 328 // It's OK to call this even if Init() has not been called. 329 static void Shutdown(); 330 331 // Look up a font in the cache. Returns null if there's nothing matching 332 // in the cache 333 already_AddRefed<gfxFont> Lookup(const gfxFontEntry* aFontEntry, 334 const gfxFontStyle* aStyle, 335 const gfxCharacterMap* aUnicodeRangeMap); 336 337 // We created a new font (presumably because Lookup returned null); 338 // put it in the cache. The font's refcount should be nonzero. It is 339 // allowable to add a new font even if there is one already in the 340 // cache with the same key, as we may race with other threads to do 341 // the insertion -- in that case we will return the original font, 342 // and destroy the new one. 343 already_AddRefed<gfxFont> MaybeInsert(gfxFont* aFont); 344 345 bool MaybeDestroy(gfxFont* aFont); 346 347 // Cleans out the hashtable and removes expired fonts waiting for cleanup. 348 // Other gfxFont objects may be still in use but they will be pushed 349 // into the expiration queues and removed. 350 void Flush(); 351 352 void FlushShapedWordCaches(); 353 void NotifyGlyphsChanged(); 354 355 void AgeCachedWords(); 356 357 void RunWordCacheExpirationTimer() { 358 if (!mTimerRunning) { 359 mozilla::MutexAutoLock lock(mMutex); 360 if (!mTimerRunning && mWordCacheExpirationTimer) { 361 mWordCacheExpirationTimer->InitWithNamedFuncCallback( 362 WordCacheExpirationTimerCallback, this, 363 SHAPED_WORD_TIMEOUT_SECONDS * 1000, nsITimer::TYPE_REPEATING_SLACK, 364 "gfxFontCache::WordCacheExpiration"_ns); 365 mTimerRunning = true; 366 } 367 } 368 } 369 void PauseWordCacheExpirationTimer() { 370 if (mTimerRunning) { 371 mozilla::MutexAutoLock lock(mMutex); 372 if (mTimerRunning && mWordCacheExpirationTimer) { 373 mWordCacheExpirationTimer->Cancel(); 374 mTimerRunning = false; 375 } 376 } 377 } 378 379 void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, 380 FontCacheSizes* aSizes) const; 381 void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, 382 FontCacheSizes* aSizes) const; 383 384 protected: 385 class MemoryReporter final : public nsIMemoryReporter { 386 ~MemoryReporter() = default; 387 388 public: 389 NS_DECL_ISUPPORTS 390 NS_DECL_NSIMEMORYREPORTER 391 }; 392 393 // Observer for notifications that the font cache cares about 394 class Observer final : public nsIObserver { 395 ~Observer() = default; 396 397 public: 398 NS_DECL_ISUPPORTS 399 NS_DECL_NSIOBSERVER 400 }; 401 402 nsresult AddObject(gfxFont* aFont) { 403 AutoLock lock(mMutex); 404 return AddObjectLocked(aFont, lock); 405 } 406 407 // This gets called when the timeout has expired on a single-refcount 408 // font; we just delete it. 409 void NotifyExpiredLocked(gfxFont* aFont, const AutoLock&) 410 MOZ_REQUIRES(mMutex) override; 411 void NotifyHandlerEnd() override; 412 413 void DestroyDiscard(nsTArray<gfxFont*>& aDiscard); 414 415 static gfxFontCache* gGlobalCache; 416 417 struct MOZ_STACK_CLASS Key { 418 const gfxFontEntry* mFontEntry; 419 const gfxFontStyle* mStyle; 420 const gfxCharacterMap* mUnicodeRangeMap; 421 Key(const gfxFontEntry* aFontEntry, const gfxFontStyle* aStyle, 422 const gfxCharacterMap* aUnicodeRangeMap) 423 : mFontEntry(aFontEntry), 424 mStyle(aStyle), 425 mUnicodeRangeMap(aUnicodeRangeMap) {} 426 }; 427 428 class HashEntry : public PLDHashEntryHdr { 429 public: 430 typedef const Key& KeyType; 431 typedef const Key* KeyTypePointer; 432 433 // When constructing a new entry in the hashtable, we'll leave this 434 // blank. The caller of Put() will fill this in. 435 explicit HashEntry(KeyTypePointer aStr) {} 436 437 bool KeyEquals(const KeyTypePointer aKey) const; 438 static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } 439 static PLDHashNumber HashKey(const KeyTypePointer aKey) { 440 return mozilla::HashGeneric(aKey->mStyle->Hash(), aKey->mFontEntry, 441 aKey->mUnicodeRangeMap); 442 } 443 enum { ALLOW_MEMMOVE = true }; 444 445 gfxFont* MOZ_UNSAFE_REF("tracking for deferred deletion") mFont = nullptr; 446 }; 447 448 nsTHashtable<HashEntry> mFonts MOZ_GUARDED_BY(mMutex); 449 450 nsTArray<gfxFont*> mTrackerDiscard MOZ_GUARDED_BY(mMutex); 451 452 static void WordCacheExpirationTimerCallback(nsITimer* aTimer, void* aCache); 453 454 nsCOMPtr<nsITimer> mWordCacheExpirationTimer MOZ_GUARDED_BY(mMutex); 455 std::atomic<bool> mTimerRunning = false; 456 }; 457 458 class gfxTextPerfMetrics { 459 public: 460 struct TextCounts { 461 uint32_t numContentTextRuns; 462 uint32_t numChromeTextRuns; 463 uint32_t numChars; 464 uint32_t maxTextRunLen; 465 uint32_t wordCacheSpaceRules; 466 uint32_t wordCacheLong; 467 uint32_t wordCacheHit; 468 uint32_t wordCacheMiss; 469 uint32_t fallbackPrefs; 470 uint32_t fallbackSystem; 471 uint32_t textrunConst; 472 uint32_t textrunDestr; 473 uint32_t genericLookups; 474 }; 475 476 uint32_t reflowCount; 477 478 // counts per reflow operation 479 TextCounts current; 480 481 // totals for the lifetime of a document 482 TextCounts cumulative; 483 484 gfxTextPerfMetrics() { memset(this, 0, sizeof(gfxTextPerfMetrics)); } 485 486 // add current totals to cumulative ones 487 void Accumulate() { 488 if (current.numChars == 0) { 489 return; 490 } 491 cumulative.numContentTextRuns += current.numContentTextRuns; 492 cumulative.numChromeTextRuns += current.numChromeTextRuns; 493 cumulative.numChars += current.numChars; 494 if (current.maxTextRunLen > cumulative.maxTextRunLen) { 495 cumulative.maxTextRunLen = current.maxTextRunLen; 496 } 497 cumulative.wordCacheSpaceRules += current.wordCacheSpaceRules; 498 cumulative.wordCacheLong += current.wordCacheLong; 499 cumulative.wordCacheHit += current.wordCacheHit; 500 cumulative.wordCacheMiss += current.wordCacheMiss; 501 cumulative.fallbackPrefs += current.fallbackPrefs; 502 cumulative.fallbackSystem += current.fallbackSystem; 503 cumulative.textrunConst += current.textrunConst; 504 cumulative.textrunDestr += current.textrunDestr; 505 cumulative.genericLookups += current.genericLookups; 506 memset(¤t, 0, sizeof(current)); 507 } 508 }; 509 510 namespace mozilla { 511 namespace gfx { 512 513 class UnscaledFont; 514 515 // Flags that live in the gfxShapedText::mFlags field. 516 // (Note that gfxTextRun has an additional mFlags2 field for use 517 // by textrun clients like nsTextFrame.) 518 // 519 // If you add a flag, please add support for it in gfxTextRun::Dump. 520 enum class ShapedTextFlags : uint16_t { 521 /** 522 * When set, the text is RTL. 523 */ 524 TEXT_IS_RTL = 0x0001, 525 /** 526 * When set, spacing is enabled and the textrun needs to call GetSpacing 527 * on the spacing provider. 528 */ 529 TEXT_ENABLE_SPACING = 0x0002, 530 /** 531 * When set, the text has no characters above 255 and it is stored 532 * in the textrun in 8-bit format. 533 */ 534 TEXT_IS_8BIT = 0x0004, 535 /** 536 * When set, GetHyphenationBreaks may return true for some character 537 * positions, otherwise it will always return false for all characters. 538 */ 539 TEXT_ENABLE_HYPHEN_BREAKS = 0x0008, 540 /** 541 * When set, the RunMetrics::mBoundingBox field will be initialized 542 * properly based on glyph extents, in particular, glyph extents that 543 * overflow the standard font-box (the box defined by the ascent, descent 544 * and advance width of the glyph). When not set, it may just be the 545 * standard font-box even if glyphs overflow. 546 */ 547 TEXT_NEED_BOUNDING_BOX = 0x0010, 548 /** 549 * When set, optional ligatures are disabled. Ligatures that are 550 * required for legible text should still be enabled. 551 */ 552 TEXT_DISABLE_OPTIONAL_LIGATURES = 0x0020, 553 /** 554 * When set, the textrun should favour speed of construction over 555 * quality. This may involve disabling ligatures and/or kerning or 556 * other effects. 557 */ 558 TEXT_OPTIMIZE_SPEED = 0x0040, 559 /** 560 * When set, the textrun should discard control characters instead of 561 * turning them into hexboxes. 562 */ 563 TEXT_HIDE_CONTROL_CHARACTERS = 0x0080, 564 565 /** 566 * nsTextFrameThebes sets these, but they're defined here rather than 567 * in nsTextFrameUtils.h because ShapedWord creation/caching also needs 568 * to check the _INCOMING flag 569 */ 570 TEXT_TRAILING_ARABICCHAR = 0x0100, 571 /** 572 * When set, the previous character for this textrun was an Arabic 573 * character. This is used for the context detection necessary for 574 * bidi.numeral implementation. 575 */ 576 TEXT_INCOMING_ARABICCHAR = 0x0200, 577 578 /** 579 * Set if the textrun should use the OpenType 'math' script. 580 */ 581 TEXT_USE_MATH_SCRIPT = 0x0400, 582 583 /* 584 * Bit 0x0800 is currently unused. 585 */ 586 587 /** 588 * Field for orientation of the textrun and glyphs within it. 589 * Possible values of the TEXT_ORIENT_MASK field: 590 * TEXT_ORIENT_HORIZONTAL 591 * TEXT_ORIENT_VERTICAL_UPRIGHT 592 * TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT 593 * TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT 594 * TEXT_ORIENT_VERTICAL_MIXED 595 * For all VERTICAL settings, the x and y coordinates of glyph 596 * positions are exchanged, so that simple advances are vertical. 597 * 598 * The MIXED value indicates vertical textRuns for which the CSS 599 * text-orientation property is 'mixed', but is never used for 600 * individual glyphRuns; it will be resolved to either UPRIGHT 601 * or SIDEWAYS_RIGHT according to the UTR50 properties of the 602 * characters, and separate glyphRuns created for the resulting 603 * glyph orientations. 604 */ 605 TEXT_ORIENT_MASK = 0x7000, 606 TEXT_ORIENT_HORIZONTAL = 0x0000, 607 TEXT_ORIENT_VERTICAL_UPRIGHT = 0x1000, 608 TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT = 0x2000, 609 TEXT_ORIENT_VERTICAL_MIXED = 0x3000, 610 TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT = 0x4000, 611 }; 612 613 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ShapedTextFlags) 614 } // namespace gfx 615 } // namespace mozilla 616 617 class gfxTextRunFactory { 618 // Used by stylo 619 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxTextRunFactory) 620 621 public: 622 typedef mozilla::gfx::DrawTarget DrawTarget; 623 624 /** 625 * This record contains all the parameters needed to initialize a textrun. 626 */ 627 struct MOZ_STACK_CLASS Parameters { 628 // Shape text params suggesting where the textrun will be rendered 629 DrawTarget* mDrawTarget; 630 // Pointer to arbitrary user data (which should outlive the textrun) 631 void* mUserData; 632 // A description of which characters have been stripped from the original 633 // DOM string to produce the characters in the textrun. May be null 634 // if that information is not relevant. 635 gfxSkipChars* mSkipChars; 636 // A list of where linebreaks are currently placed in the textrun. May 637 // be null if mInitialBreakCount is zero. 638 uint32_t* mInitialBreaks; 639 uint32_t mInitialBreakCount; 640 // The ratio to use to convert device pixels to application layout units 641 int32_t mAppUnitsPerDevUnit; 642 }; 643 644 protected: 645 // Protected destructor, to discourage deletion outside of Release(): 646 virtual ~gfxTextRunFactory(); 647 }; 648 649 /** 650 * gfxFontShaper 651 * 652 * This class implements text shaping (character to glyph mapping and 653 * glyph layout). There is a gfxFontShaper subclass for each text layout 654 * technology (uniscribe, core text, harfbuzz,....) we support. 655 * 656 * The shaper is responsible for setting up glyph data in gfxTextRuns. 657 * 658 * A generic, platform-independent shaper relies only on the standard 659 * gfxFont interface and can work with any concrete subclass of gfxFont. 660 * 661 * Platform-specific implementations designed to interface to platform 662 * shaping APIs such as Uniscribe or CoreText may rely on features of a 663 * specific font subclass to access native font references 664 * (such as CTFont, HFONT, DWriteFont, etc). 665 */ 666 667 class gfxFontShaper { 668 public: 669 typedef mozilla::gfx::DrawTarget DrawTarget; 670 typedef mozilla::intl::Script Script; 671 672 enum class RoundingFlags : uint8_t { kRoundX = 0x01, kRoundY = 0x02 }; 673 674 explicit gfxFontShaper(gfxFont* aFont) : mFont(aFont) { 675 NS_ASSERTION(aFont, "shaper requires a valid font!"); 676 } 677 678 virtual ~gfxFontShaper() = default; 679 680 // Shape a piece of text and store the resulting glyph data into 681 // aShapedText. Parameters aOffset/aLength indicate the range of 682 // aShapedText to be updated; aLength is also the length of aText. 683 virtual bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, 684 uint32_t aOffset, uint32_t aLength, Script aScript, 685 nsAtom* aLanguage, // may be null, indicating no 686 // lang-specific shaping to be 687 // applied 688 bool aVertical, RoundingFlags aRounding, 689 gfxShapedText* aShapedText) = 0; 690 691 gfxFont* GetFont() const { return mFont; } 692 693 static void MergeFontFeatures( 694 const gfxFontStyle* aStyle, const nsTArray<gfxFontFeature>& aFontFeatures, 695 bool aDisableLigatures, const nsACString& aFamilyName, bool aAddSmallCaps, 696 void (*aHandleFeature)(uint32_t, uint32_t, void*), 697 void* aHandleFeatureData); 698 699 protected: 700 // the font this shaper is working with. The font owns a UniquePtr reference 701 // to this object, and will destroy it before it dies. Thus, mFont will always 702 // be valid. 703 gfxFont* MOZ_NON_OWNING_REF mFont; 704 }; 705 706 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(gfxFontShaper::RoundingFlags) 707 708 /* 709 * gfxShapedText is an abstract superclass for gfxShapedWord and gfxTextRun. 710 * These are objects that store a list of zero or more glyphs for each 711 * character. For each glyph we store the glyph ID, the advance, and possibly 712 * x/y-offsets. The idea is that a string is rendered by a loop that draws each 713 * glyph at its designated offset from the current point, then advances the 714 * current point by the glyph's advance in the direction of the textrun (LTR or 715 * RTL). Each glyph advance is always rounded to the nearest appunit; this 716 * ensures consistent results when dividing the text in a textrun into multiple 717 * text frames (frame boundaries are always aligned to appunits). We optimize 718 * for the case where a character has a single glyph and zero xoffset and 719 * yoffset, and the glyph ID and advance are in a reasonable range so we can 720 * pack all necessary data into 32 bits. 721 * 722 * gfxFontShaper can shape text into either a gfxShapedWord (cached by a 723 * gfxFont) or directly into a gfxTextRun (for cases where we want to shape 724 * textruns in their entirety rather than using cached words, because there may 725 * be layout features that depend on the inter-word spaces). 726 */ 727 class gfxShapedText { 728 public: 729 typedef mozilla::intl::Script Script; 730 731 gfxShapedText(uint32_t aLength, mozilla::gfx::ShapedTextFlags aFlags, 732 uint16_t aAppUnitsPerDevUnit) 733 : mLength(aLength), 734 mFlags(aFlags), 735 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) {} 736 737 virtual ~gfxShapedText() = default; 738 739 /** 740 * This class records the information associated with a character in the 741 * input string. It's optimized for the case where there is one glyph 742 * representing that character alone. 743 * 744 * A character can have zero or more associated glyphs. Each glyph 745 * has an advance width and an x and y offset. 746 * A character may be the start of a cluster. 747 * A character may be the start of a ligature group. 748 * A character can be "missing", indicating that the system is unable 749 * to render the character. 750 * 751 * All characters in a ligature group conceptually share all the glyphs 752 * associated with the characters in a group. 753 */ 754 class CompressedGlyph { 755 public: 756 enum { 757 // Indicates that a cluster and ligature group starts at this 758 // character; this character has a single glyph with a reasonable 759 // advance and zero offsets. A "reasonable" advance 760 // is one that fits in the available bits (currently 12) (specified 761 // in appunits). 762 FLAG_IS_SIMPLE_GLYPH = 0x80000000U, 763 764 // These flags are applicable to both "simple" and "complex" records. 765 COMMON_FLAGS_MASK = 0x70000000U, 766 767 // Indicates whether a linebreak is allowed before this character; 768 // this is a two-bit field that holds a FLAG_BREAK_TYPE_xxx value 769 // indicating the kind of linebreak (if any) allowed here. 770 FLAGS_CAN_BREAK_BEFORE = 0x60000000U, 771 772 FLAGS_CAN_BREAK_SHIFT = 29, 773 FLAG_BREAK_TYPE_NONE = 0, 774 FLAG_BREAK_TYPE_NORMAL = 1, 775 FLAG_BREAK_TYPE_HYPHEN = 2, 776 // Allow break before this position if needed to avoid overflow: 777 FLAG_BREAK_TYPE_EMERGENCY_WRAP = 3, 778 779 FLAG_CHAR_IS_SPACE = 0x10000000U, 780 781 // Fields present only when FLAG_IS_SIMPLE_GLYPH is /true/. 782 // The advance is stored in appunits as a 12-bit field: 783 ADVANCE_MASK = 0x0FFF0000U, 784 ADVANCE_SHIFT = 16, 785 // and the glyph ID is stored in the low 16 bits. 786 GLYPH_MASK = 0x0000FFFFU, 787 788 // Fields present only when FLAG_IS_SIMPLE_GLYPH is /false/. 789 // Non-simple glyphs may or may not have glyph data in the 790 // corresponding mDetailedGlyphs entry. They have a glyph count 791 // stored in the low 16 bits, and the following flag bits: 792 GLYPH_COUNT_MASK = 0x0000FFFFU, 793 794 // When NOT set, indicates that this character corresponds to a 795 // missing glyph and should be skipped (or possibly, render the character 796 // Unicode value in some special way). If there are glyphs, 797 // the mGlyphID is actually the UTF16 character code. The bit is 798 // inverted so we can memset the array to zero to indicate all missing. 799 FLAG_NOT_MISSING = 0x010000, 800 FLAG_NOT_CLUSTER_START = 0x020000, 801 FLAG_NOT_LIGATURE_GROUP_START = 0x040000, 802 // Flag bit 0x080000 is currently unused. 803 804 // Certain types of characters are marked so that they can be given 805 // special treatment in rendering. This may require use of a "complex" 806 // CompressedGlyph record even for a character that would otherwise be 807 // treated as "simple". 808 CHAR_TYPE_FLAGS_MASK = 0xF00000, 809 FLAG_CHAR_IS_TAB = 0x100000, 810 FLAG_CHAR_IS_NEWLINE = 0x200000, 811 // Per CSS Text Decoration Module Level 3, emphasis marks are not 812 // drawn for any character in Unicode categories Z*, Cc, Cf, and Cn 813 // which is not combined with any combining characters. This flag is 814 // set for all those characters except 0x20 whitespace. 815 FLAG_CHAR_NO_EMPHASIS_MARK = 0x400000, 816 // Per CSS Text, letter-spacing is not applied to formatting chars 817 // (category Cf). We mark those in the textrun so as to be able to 818 // skip them when setting up spacing in nsTextFrame. 819 FLAG_CHAR_IS_FORMATTING_CONTROL = 0x800000, 820 821 // The bits 0x0F000000 are currently unused in non-simple glyphs. 822 }; 823 824 // "Simple glyphs" have a simple glyph ID, simple advance and their 825 // x and y offsets are zero. Also the glyph extents do not overflow 826 // the font-box defined by the font ascent, descent and glyph advance width. 827 // These case is optimized to avoid storing DetailedGlyphs. 828 829 // Returns true if the glyph ID aGlyph fits into the compressed 830 // representation 831 static bool IsSimpleGlyphID(uint32_t aGlyph) { 832 return (aGlyph & GLYPH_MASK) == aGlyph; 833 } 834 // Returns true if the advance aAdvance fits into the compressed 835 // representation. aAdvance is in appunits. 836 static bool IsSimpleAdvance(uint32_t aAdvance) { 837 return (aAdvance & (ADVANCE_MASK >> ADVANCE_SHIFT)) == aAdvance; 838 } 839 840 bool IsSimpleGlyph() const { return mValue & FLAG_IS_SIMPLE_GLYPH; } 841 uint32_t GetSimpleAdvance() const { 842 MOZ_ASSERT(IsSimpleGlyph()); 843 return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT; 844 } 845 uint32_t GetSimpleGlyph() const { 846 MOZ_ASSERT(IsSimpleGlyph()); 847 return mValue & GLYPH_MASK; 848 } 849 850 bool IsMissing() const { 851 return !(mValue & (FLAG_NOT_MISSING | FLAG_IS_SIMPLE_GLYPH)); 852 } 853 bool IsClusterStart() const { 854 return IsSimpleGlyph() || !(mValue & FLAG_NOT_CLUSTER_START); 855 } 856 bool IsLigatureGroupStart() const { 857 return IsSimpleGlyph() || !(mValue & FLAG_NOT_LIGATURE_GROUP_START); 858 } 859 bool IsLigatureContinuation() const { 860 return !IsSimpleGlyph() && 861 (mValue & (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING)) == 862 (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING); 863 } 864 865 // Return true if the original character was a normal (breakable, 866 // trimmable) space (U+0020). Not true for other characters that 867 // may happen to map to the space glyph (U+00A0). 868 bool CharIsSpace() const { return mValue & FLAG_CHAR_IS_SPACE; } 869 870 bool CharIsTab() const { 871 return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_TAB); 872 } 873 bool CharIsNewline() const { 874 return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_NEWLINE); 875 } 876 bool CharMayHaveEmphasisMark() const { 877 return !CharIsSpace() && 878 (IsSimpleGlyph() || !(mValue & FLAG_CHAR_NO_EMPHASIS_MARK)); 879 } 880 bool CharIsFormattingControl() const { 881 return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_FORMATTING_CONTROL); 882 } 883 884 uint32_t CharTypeFlags() const { 885 return IsSimpleGlyph() ? 0 : (mValue & CHAR_TYPE_FLAGS_MASK); 886 } 887 888 void SetClusterStart(bool aIsClusterStart) { 889 MOZ_ASSERT(!IsSimpleGlyph()); 890 if (aIsClusterStart) { 891 mValue &= ~FLAG_NOT_CLUSTER_START; 892 } else { 893 mValue |= FLAG_NOT_CLUSTER_START; 894 } 895 } 896 897 uint8_t CanBreakBefore() const { 898 return (mValue & FLAGS_CAN_BREAK_BEFORE) >> FLAGS_CAN_BREAK_SHIFT; 899 } 900 // Returns FLAGS_CAN_BREAK_BEFORE if the setting changed, 0 otherwise 901 uint32_t SetCanBreakBefore(uint8_t aCanBreakBefore) { 902 MOZ_ASSERT(aCanBreakBefore <= 3, "Bogus break-flags value!"); 903 uint32_t breakMask = (uint32_t(aCanBreakBefore) << FLAGS_CAN_BREAK_SHIFT); 904 uint32_t toggle = breakMask ^ (mValue & FLAGS_CAN_BREAK_BEFORE); 905 mValue ^= toggle; 906 return toggle; 907 } 908 909 // Create a CompressedGlyph value representing a simple glyph with 910 // no extra flags (line-break or is_space) set. 911 static CompressedGlyph MakeSimpleGlyph(uint32_t aAdvanceAppUnits, 912 uint32_t aGlyph) { 913 MOZ_ASSERT(IsSimpleAdvance(aAdvanceAppUnits)); 914 MOZ_ASSERT(IsSimpleGlyphID(aGlyph)); 915 CompressedGlyph g; 916 g.mValue = 917 FLAG_IS_SIMPLE_GLYPH | (aAdvanceAppUnits << ADVANCE_SHIFT) | aGlyph; 918 return g; 919 } 920 921 // Assign a simple glyph value to an existing CompressedGlyph record, 922 // preserving line-break/is-space flags if present. 923 CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits, 924 uint32_t aGlyph) { 925 MOZ_ASSERT(!CharTypeFlags(), "Char type flags lost"); 926 mValue = (mValue & COMMON_FLAGS_MASK) | 927 MakeSimpleGlyph(aAdvanceAppUnits, aGlyph).mValue; 928 return *this; 929 } 930 931 // Create a CompressedGlyph value representing a complex glyph record, 932 // without any line-break or char-type flags. 933 static CompressedGlyph MakeComplex(bool aClusterStart, 934 bool aLigatureStart) { 935 CompressedGlyph g; 936 g.mValue = FLAG_NOT_MISSING | 937 (aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) | 938 (aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START); 939 return g; 940 } 941 942 // Assign a complex glyph value to an existing CompressedGlyph record, 943 // preserving line-break/char-type flags if present. 944 // This sets the glyphCount to zero; it will be updated when we call 945 // gfxShapedText::SetDetailedGlyphs. 946 CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart) { 947 mValue = (mValue & COMMON_FLAGS_MASK) | CharTypeFlags() | 948 MakeComplex(aClusterStart, aLigatureStart).mValue; 949 return *this; 950 } 951 952 /** 953 * Mark a glyph record as being a missing-glyph. 954 * Missing glyphs are treated as ligature group starts; don't mess with 955 * the cluster-start flag (see bugs 618870 and 619286). 956 * We also preserve the glyph count here, as this is used after any 957 * required DetailedGlyphs (to store the char code for a hexbox) has been 958 * set up. 959 * This must be called *after* SetDetailedGlyphs is used for the relevant 960 * offset in the shaped-word, because that will mark it as not-missing. 961 */ 962 CompressedGlyph& SetMissing() { 963 MOZ_ASSERT(!IsSimpleGlyph()); 964 mValue &= ~(FLAG_NOT_MISSING | FLAG_NOT_LIGATURE_GROUP_START); 965 return *this; 966 } 967 968 uint32_t GetGlyphCount() const { 969 MOZ_ASSERT(!IsSimpleGlyph()); 970 return mValue & GLYPH_COUNT_MASK; 971 } 972 void SetGlyphCount(uint32_t aGlyphCount) { 973 MOZ_ASSERT(!IsSimpleGlyph()); 974 MOZ_ASSERT(GetGlyphCount() == 0, "Glyph count already set"); 975 MOZ_ASSERT(aGlyphCount <= 0xffff, "Glyph count out of range"); 976 mValue |= FLAG_NOT_MISSING | aGlyphCount; 977 } 978 979 void SetIsSpace() { mValue |= FLAG_CHAR_IS_SPACE; } 980 void SetIsTab() { 981 MOZ_ASSERT(!IsSimpleGlyph()); 982 mValue |= FLAG_CHAR_IS_TAB; 983 } 984 void SetIsNewline() { 985 MOZ_ASSERT(!IsSimpleGlyph()); 986 mValue |= FLAG_CHAR_IS_NEWLINE; 987 } 988 void SetNoEmphasisMark() { 989 MOZ_ASSERT(!IsSimpleGlyph()); 990 mValue |= FLAG_CHAR_NO_EMPHASIS_MARK; 991 } 992 void SetIsFormattingControl() { 993 MOZ_ASSERT(!IsSimpleGlyph()); 994 mValue |= FLAG_CHAR_IS_FORMATTING_CONTROL; 995 } 996 997 private: 998 uint32_t mValue; 999 }; 1000 1001 // Accessor for the array of CompressedGlyph records, which will be in 1002 // a different place in gfxShapedWord vs gfxTextRun 1003 virtual const CompressedGlyph* GetCharacterGlyphs() const = 0; 1004 virtual CompressedGlyph* GetCharacterGlyphs() = 0; 1005 1006 /** 1007 * When the glyphs for a character don't fit into a CompressedGlyph record 1008 * in SimpleGlyph format, we use an array of DetailedGlyphs instead. 1009 */ 1010 struct DetailedGlyph { 1011 // The glyphID, or the Unicode character if this is a missing glyph 1012 uint32_t mGlyphID; 1013 // The advance of the glyph, in appunits. 1014 // mAdvance is in the text direction (RTL or LTR), 1015 // and will normally be non-negative (although this is not guaranteed) 1016 int32_t mAdvance; 1017 // The offset from the glyph's default position, in line-relative 1018 // coordinates (so mOffset.x is an offset in the line-right direction, 1019 // and mOffset.y is an offset in line-downwards direction). 1020 // These values are in floating-point appUnits. 1021 mozilla::gfx::Point mOffset; 1022 }; 1023 1024 // Store DetailedGlyph records for the given index. (This does not modify 1025 // the associated CompressedGlyph character-type or break flags.) 1026 void SetDetailedGlyphs(uint32_t aIndex, uint32_t aGlyphCount, 1027 const DetailedGlyph* aGlyphs); 1028 1029 void SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont* aFont); 1030 1031 void SetIsSpace(uint32_t aIndex) { 1032 GetCharacterGlyphs()[aIndex].SetIsSpace(); 1033 } 1034 1035 bool HasDetailedGlyphs() const { return mDetailedGlyphs != nullptr; } 1036 1037 bool IsLigatureGroupStart(uint32_t aPos) { 1038 NS_ASSERTION(aPos < GetLength(), "aPos out of range"); 1039 return GetCharacterGlyphs()[aPos].IsLigatureGroupStart(); 1040 } 1041 1042 // NOTE that this must not be called for a character offset that does 1043 // not have any DetailedGlyph records; callers must have verified that 1044 // GetCharacterGlyphs()[aCharIndex].GetGlyphCount() is greater than zero. 1045 DetailedGlyph* GetDetailedGlyphs(uint32_t aCharIndex) const { 1046 NS_ASSERTION(GetCharacterGlyphs() && HasDetailedGlyphs() && 1047 !GetCharacterGlyphs()[aCharIndex].IsSimpleGlyph() && 1048 GetCharacterGlyphs()[aCharIndex].GetGlyphCount() > 0, 1049 "invalid use of GetDetailedGlyphs; check the caller!"); 1050 return mDetailedGlyphs->Get(aCharIndex); 1051 } 1052 1053 void ApplyTrackingToClusters(gfxFloat aTrackingAdjustment, uint32_t aOffset, 1054 uint32_t aLength); 1055 1056 // Mark clusters in the CompressedGlyph records, starting at aOffset, 1057 // based on the Unicode properties of the text in aString. 1058 // This is also responsible to set the IsSpace flag for space characters. 1059 void SetupClusterBoundaries(uint32_t aOffset, const char16_t* aString, 1060 uint32_t aLength); 1061 // In 8-bit text, there won't actually be any clusters, but we still need 1062 // the space-marking functionality. 1063 void SetupClusterBoundaries(uint32_t aOffset, const uint8_t* aString, 1064 uint32_t aLength); 1065 1066 mozilla::gfx::ShapedTextFlags GetFlags() const { return mFlags; } 1067 1068 bool IsVertical() const { 1069 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK) != 1070 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_HORIZONTAL; 1071 } 1072 1073 bool UseCenterBaseline() const { 1074 mozilla::gfx::ShapedTextFlags orient = 1075 GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK; 1076 return orient == 1077 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_MIXED || 1078 orient == 1079 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_UPRIGHT; 1080 } 1081 1082 bool IsRightToLeft() const { 1083 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_IS_RTL) == 1084 mozilla::gfx::ShapedTextFlags::TEXT_IS_RTL; 1085 } 1086 1087 bool IsSidewaysLeft() const { 1088 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK) == 1089 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT; 1090 } 1091 1092 // Return true if the logical inline direction is reversed compared to 1093 // normal physical coordinates (i.e. if it is leftwards or upwards) 1094 bool IsInlineReversed() const { return IsSidewaysLeft() != IsRightToLeft(); } 1095 1096 gfxFloat GetDirection() const { return IsInlineReversed() ? -1.0f : 1.0f; } 1097 1098 bool DisableLigatures() const { 1099 return (GetFlags() & 1100 mozilla::gfx::ShapedTextFlags::TEXT_DISABLE_OPTIONAL_LIGATURES) == 1101 mozilla::gfx::ShapedTextFlags::TEXT_DISABLE_OPTIONAL_LIGATURES; 1102 } 1103 1104 bool TextIs8Bit() const { 1105 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT) == 1106 mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT; 1107 } 1108 1109 int32_t GetAppUnitsPerDevUnit() const { return mAppUnitsPerDevUnit; } 1110 1111 uint32_t GetLength() const { return mLength; } 1112 1113 bool FilterIfIgnorable(uint32_t aIndex, uint32_t aCh); 1114 1115 protected: 1116 // Allocate aCount DetailedGlyphs for the given index 1117 DetailedGlyph* AllocateDetailedGlyphs(uint32_t aCharIndex, uint32_t aCount); 1118 1119 // Ensure the glyph on the given index is complex glyph so that we can use 1120 // it to record specific characters that layout may need to detect. 1121 void EnsureComplexGlyph(uint32_t aIndex, CompressedGlyph& aGlyph) { 1122 MOZ_ASSERT(GetCharacterGlyphs() + aIndex == &aGlyph); 1123 if (aGlyph.IsSimpleGlyph()) { 1124 DetailedGlyph details = {aGlyph.GetSimpleGlyph(), 1125 (int32_t)aGlyph.GetSimpleAdvance(), 1126 mozilla::gfx::Point()}; 1127 aGlyph.SetComplex(true, true); 1128 SetDetailedGlyphs(aIndex, 1, &details); 1129 } 1130 } 1131 1132 // For characters whose glyph data does not fit the "simple" glyph criteria 1133 // in CompressedGlyph, we use a sorted array to store the association 1134 // between the source character offset and an index into an array 1135 // DetailedGlyphs. The CompressedGlyph record includes a count of 1136 // the number of DetailedGlyph records that belong to the character, 1137 // starting at the given index. 1138 class DetailedGlyphStore { 1139 public: 1140 DetailedGlyphStore() = default; 1141 1142 // This is optimized for the most common calling patterns: 1143 // we rarely need random access to the records, access is most commonly 1144 // sequential through the textRun, so we record the last-used index 1145 // and check whether the caller wants the same record again, or the 1146 // next; if not, it's most likely we're starting over from the start 1147 // of the run, so we check the first entry before resorting to binary 1148 // search as a last resort. 1149 // NOTE that this must not be called for a character offset that does 1150 // not have any DetailedGlyph records; callers must have verified that 1151 // mCharacterGlyphs[aOffset].GetGlyphCount() is greater than zero 1152 // before calling this, otherwise the assertions here will fire (in a 1153 // debug build), and we'll probably crash. 1154 DetailedGlyph* Get(uint32_t aOffset) { 1155 NS_ASSERTION(mOffsetToIndex.Length() > 0, "no detailed glyph records!"); 1156 DetailedGlyph* details = mDetails.Elements(); 1157 // check common cases (fwd iteration, initial entry, etc) first 1158 if (mLastUsed < mOffsetToIndex.Length() - 1 && 1159 aOffset == mOffsetToIndex[mLastUsed + 1].mOffset) { 1160 ++mLastUsed; 1161 } else if (aOffset == mOffsetToIndex[0].mOffset) { 1162 mLastUsed = 0; 1163 } else if (aOffset == mOffsetToIndex[mLastUsed].mOffset) { 1164 // do nothing 1165 } else if (mLastUsed > 0 && 1166 aOffset == mOffsetToIndex[mLastUsed - 1].mOffset) { 1167 --mLastUsed; 1168 } else { 1169 mLastUsed = mOffsetToIndex.BinaryIndexOf(aOffset, CompareToOffset()); 1170 } 1171 NS_ASSERTION(mLastUsed != nsTArray<DGRec>::NoIndex, 1172 "detailed glyph record missing!"); 1173 return details + mOffsetToIndex[mLastUsed].mIndex; 1174 } 1175 1176 DetailedGlyph* Allocate(uint32_t aOffset, uint32_t aCount) { 1177 uint32_t detailIndex = mDetails.Length(); 1178 DetailedGlyph* details = mDetails.AppendElements(aCount); 1179 // We normally set up glyph records sequentially, so the common case 1180 // here is to append new records to the mOffsetToIndex array; 1181 // test for that before falling back to the InsertElementSorted 1182 // method. 1183 if (mOffsetToIndex.Length() == 0 || 1184 aOffset > mOffsetToIndex[mOffsetToIndex.Length() - 1].mOffset) { 1185 mOffsetToIndex.AppendElement(DGRec(aOffset, detailIndex)); 1186 } else { 1187 mOffsetToIndex.InsertElementSorted(DGRec(aOffset, detailIndex), 1188 CompareRecordOffsets()); 1189 } 1190 return details; 1191 } 1192 1193 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { 1194 return aMallocSizeOf(this) + 1195 mDetails.ShallowSizeOfExcludingThis(aMallocSizeOf) + 1196 mOffsetToIndex.ShallowSizeOfExcludingThis(aMallocSizeOf); 1197 } 1198 1199 private: 1200 struct DGRec { 1201 DGRec(const uint32_t& aOffset, const uint32_t& aIndex) 1202 : mOffset(aOffset), mIndex(aIndex) {} 1203 uint32_t mOffset; // source character offset in the textrun 1204 uint32_t mIndex; // index where this char's DetailedGlyphs begin 1205 }; 1206 1207 struct CompareToOffset { 1208 bool Equals(const DGRec& a, const uint32_t& b) const { 1209 return a.mOffset == b; 1210 } 1211 bool LessThan(const DGRec& a, const uint32_t& b) const { 1212 return a.mOffset < b; 1213 } 1214 }; 1215 1216 struct CompareRecordOffsets { 1217 bool Equals(const DGRec& a, const DGRec& b) const { 1218 return a.mOffset == b.mOffset; 1219 } 1220 bool LessThan(const DGRec& a, const DGRec& b) const { 1221 return a.mOffset < b.mOffset; 1222 } 1223 }; 1224 1225 // Concatenated array of all the DetailedGlyph records needed for the 1226 // textRun; individual character offsets are associated with indexes 1227 // into this array via the mOffsetToIndex table. 1228 nsTArray<DetailedGlyph> mDetails; 1229 1230 // For each character offset that needs DetailedGlyphs, we record the 1231 // index in mDetails where the list of glyphs begins. This array is 1232 // sorted by mOffset. 1233 nsTArray<DGRec> mOffsetToIndex; 1234 1235 // Records the most recently used index into mOffsetToIndex, so that 1236 // we can support sequential access more quickly than just doing 1237 // a binary search each time. 1238 nsTArray<DGRec>::index_type mLastUsed = 0; 1239 }; 1240 1241 mozilla::UniquePtr<DetailedGlyphStore> mDetailedGlyphs; 1242 1243 // Number of char16_t characters and CompressedGlyph glyph records 1244 uint32_t mLength; 1245 1246 // Shaping flags (direction, ligature-suppression) 1247 mozilla::gfx::ShapedTextFlags mFlags; 1248 1249 uint16_t mAppUnitsPerDevUnit; 1250 }; 1251 1252 /* 1253 * gfxShapedWord: an individual (space-delimited) run of text shaped with a 1254 * particular font, without regard to external context. 1255 * 1256 * The glyph data is copied into gfxTextRuns as needed from the cache of 1257 * ShapedWords associated with each gfxFont instance. 1258 */ 1259 class gfxShapedWord final : public gfxShapedText { 1260 public: 1261 typedef mozilla::intl::Script Script; 1262 1263 // Create a ShapedWord that can hold glyphs for aLength characters, 1264 // with mCharacterGlyphs sized appropriately. 1265 // 1266 // Returns null on allocation failure (does NOT use infallible alloc) 1267 // so caller must check for success. 1268 // 1269 // This does NOT perform shaping, so the returned word contains no 1270 // glyph data; the caller must call gfxFont::ShapeText() with appropriate 1271 // parameters to set up the glyphs. 1272 static gfxShapedWord* Create(const uint8_t* aText, uint32_t aLength, 1273 Script aRunScript, nsAtom* aLanguage, 1274 uint16_t aAppUnitsPerDevUnit, 1275 mozilla::gfx::ShapedTextFlags aFlags, 1276 gfxFontShaper::RoundingFlags aRounding) { 1277 NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(), 1278 "excessive length for gfxShapedWord!"); 1279 1280 // Compute size needed including the mCharacterGlyphs array 1281 // and a copy of the original text 1282 uint32_t size = offsetof(gfxShapedWord, mCharGlyphsStorage) + 1283 aLength * (sizeof(CompressedGlyph) + sizeof(uint8_t)); 1284 void* storage = malloc(size); 1285 if (!storage) { 1286 return nullptr; 1287 } 1288 1289 // Construct in the pre-allocated storage, using placement new 1290 return new (storage) gfxShapedWord(aText, aLength, aRunScript, aLanguage, 1291 aAppUnitsPerDevUnit, aFlags, aRounding); 1292 } 1293 1294 static gfxShapedWord* Create(const char16_t* aText, uint32_t aLength, 1295 Script aRunScript, nsAtom* aLanguage, 1296 uint16_t aAppUnitsPerDevUnit, 1297 mozilla::gfx::ShapedTextFlags aFlags, 1298 gfxFontShaper::RoundingFlags aRounding) { 1299 NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(), 1300 "excessive length for gfxShapedWord!"); 1301 1302 // In the 16-bit version of Create, if the TEXT_IS_8BIT flag is set, 1303 // then we convert the text to an 8-bit version and call the 8-bit 1304 // Create function instead. 1305 if (aFlags & mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT) { 1306 nsAutoCString narrowText; 1307 LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength), narrowText); 1308 return Create((const uint8_t*)(narrowText.BeginReading()), aLength, 1309 aRunScript, aLanguage, aAppUnitsPerDevUnit, aFlags, 1310 aRounding); 1311 } 1312 1313 uint32_t size = offsetof(gfxShapedWord, mCharGlyphsStorage) + 1314 aLength * (sizeof(CompressedGlyph) + sizeof(char16_t)); 1315 void* storage = malloc(size); 1316 if (!storage) { 1317 return nullptr; 1318 } 1319 1320 return new (storage) gfxShapedWord(aText, aLength, aRunScript, aLanguage, 1321 aAppUnitsPerDevUnit, aFlags, aRounding); 1322 } 1323 1324 // Override operator delete to properly free the object that was 1325 // allocated via malloc. 1326 void operator delete(void* p) { free(p); } 1327 1328 const CompressedGlyph* GetCharacterGlyphs() const override { 1329 return &mCharGlyphsStorage[0]; 1330 } 1331 CompressedGlyph* GetCharacterGlyphs() override { 1332 return &mCharGlyphsStorage[0]; 1333 } 1334 1335 const uint8_t* Text8Bit() const { 1336 NS_ASSERTION(TextIs8Bit(), "invalid use of Text8Bit()"); 1337 return reinterpret_cast<const uint8_t*>(mCharGlyphsStorage + GetLength()); 1338 } 1339 1340 const char16_t* TextUnicode() const { 1341 NS_ASSERTION(!TextIs8Bit(), "invalid use of TextUnicode()"); 1342 return reinterpret_cast<const char16_t*>(mCharGlyphsStorage + GetLength()); 1343 } 1344 1345 char16_t GetCharAt(uint32_t aOffset) const { 1346 NS_ASSERTION(aOffset < GetLength(), "aOffset out of range"); 1347 return TextIs8Bit() ? char16_t(Text8Bit()[aOffset]) 1348 : TextUnicode()[aOffset]; 1349 } 1350 1351 Script GetScript() const { return mScript; } 1352 nsAtom* GetLanguage() const { return mLanguage.get(); } 1353 1354 gfxFontShaper::RoundingFlags GetRounding() const { return mRounding; } 1355 1356 void ResetAge() { mAgeCounter = 0; } 1357 uint32_t IncrementAge() { return ++mAgeCounter; } 1358 1359 // Helper used when hashing a word for the shaped-word caches 1360 static uint32_t HashMix(uint32_t aHash, char16_t aCh) { 1361 return (aHash >> 28) ^ (aHash << 4) ^ aCh; 1362 } 1363 1364 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 1365 1366 private: 1367 // so that gfxTextRun can share our DetailedGlyphStore class 1368 friend class gfxTextRun; 1369 1370 // Construct storage for a ShapedWord, ready to receive glyph data 1371 gfxShapedWord(const uint8_t* aText, uint32_t aLength, Script aRunScript, 1372 nsAtom* aLanguage, uint16_t aAppUnitsPerDevUnit, 1373 mozilla::gfx::ShapedTextFlags aFlags, 1374 gfxFontShaper::RoundingFlags aRounding) 1375 : gfxShapedText(aLength, 1376 aFlags | mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT, 1377 aAppUnitsPerDevUnit), 1378 mLanguage(aLanguage), 1379 mScript(aRunScript), 1380 mRounding(aRounding), 1381 mAgeCounter(0) { 1382 memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph)); 1383 uint8_t* text = reinterpret_cast<uint8_t*>(&mCharGlyphsStorage[aLength]); 1384 memcpy(text, aText, aLength * sizeof(uint8_t)); 1385 SetupClusterBoundaries(0, aText, aLength); 1386 } 1387 1388 gfxShapedWord(const char16_t* aText, uint32_t aLength, Script aRunScript, 1389 nsAtom* aLanguage, uint16_t aAppUnitsPerDevUnit, 1390 mozilla::gfx::ShapedTextFlags aFlags, 1391 gfxFontShaper::RoundingFlags aRounding) 1392 : gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit), 1393 mLanguage(aLanguage), 1394 mScript(aRunScript), 1395 mRounding(aRounding), 1396 mAgeCounter(0) { 1397 memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph)); 1398 char16_t* text = reinterpret_cast<char16_t*>(&mCharGlyphsStorage[aLength]); 1399 memcpy(text, aText, aLength * sizeof(char16_t)); 1400 SetupClusterBoundaries(0, aText, aLength); 1401 } 1402 1403 RefPtr<nsAtom> mLanguage; 1404 Script mScript; 1405 1406 gfxFontShaper::RoundingFlags mRounding; 1407 1408 // With multithreaded shaping, this may be updated by any thread. 1409 std::atomic<uint32_t> mAgeCounter; 1410 1411 // The mCharGlyphsStorage array is actually a variable-size member; 1412 // when the ShapedWord is created, its size will be increased as necessary 1413 // to allow the proper number of glyphs to be stored. 1414 // The original text, in either 8-bit or 16-bit form, will be stored 1415 // immediately following the CompressedGlyphs. 1416 CompressedGlyph mCharGlyphsStorage[1]; 1417 }; 1418 1419 class GlyphBufferAzure; 1420 struct TextRunDrawParams; 1421 struct FontDrawParams; 1422 struct EmphasisMarkDrawParams; 1423 1424 class gfxFont { 1425 friend class gfxHarfBuzzShaper; 1426 friend class gfxGraphiteShaper; 1427 1428 protected: 1429 using DrawTarget = mozilla::gfx::DrawTarget; 1430 using Script = mozilla::intl::Script; 1431 using SVGContextPaint = mozilla::SVGContextPaint; 1432 1433 using RoundingFlags = gfxFontShaper::RoundingFlags; 1434 using ShapedTextFlags = mozilla::gfx::ShapedTextFlags; 1435 1436 public: 1437 using FontSlantStyle = mozilla::FontSlantStyle; 1438 using FontSizeAdjust = mozilla::StyleFontSizeAdjust; 1439 1440 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(gfxFont, MaybeDestroy()) 1441 int32_t GetRefCount() { return int32_t(mRefCnt); } 1442 1443 // options to specify the kind of AA to be used when creating a font 1444 typedef enum : uint8_t { 1445 kAntialiasDefault, 1446 kAntialiasNone, 1447 kAntialiasGrayscale, 1448 kAntialiasSubpixel 1449 } AntialiasOption; 1450 1451 protected: 1452 gfxFont(const RefPtr<mozilla::gfx::UnscaledFont>& aUnscaledFont, 1453 gfxFontEntry* aFontEntry, const gfxFontStyle* aFontStyle, 1454 AntialiasOption anAAOption = kAntialiasDefault); 1455 1456 virtual ~gfxFont(); 1457 1458 void MaybeDestroy() { 1459 bool destroy = true; 1460 if (gfxFontCache* fc = gfxFontCache::GetCache()) { 1461 destroy = fc->MaybeDestroy(this); 1462 } 1463 if (destroy) { 1464 Destroy(); 1465 } 1466 } 1467 1468 public: 1469 void Destroy() { 1470 MOZ_ASSERT(GetRefCount() == 0); 1471 delete this; 1472 } 1473 1474 bool Valid() const { return mIsValid; } 1475 1476 // options for the kind of bounding box to return from measurement 1477 typedef enum { 1478 LOOSE_INK_EXTENTS, 1479 // A box that encloses all the painted pixels, and may 1480 // include sidebearings and/or additional ascent/descent 1481 // within the glyph cell even if the ink is smaller. 1482 TIGHT_INK_EXTENTS, 1483 // A box that tightly encloses all the painted pixels 1484 // (although actually on Windows, at least, it may be 1485 // slightly larger than strictly necessary because 1486 // we can't get precise extents with ClearType). 1487 TIGHT_HINTED_OUTLINE_EXTENTS 1488 // A box that tightly encloses the glyph outline, 1489 // ignoring possible antialiasing pixels that extend 1490 // beyond this. 1491 // NOTE: The default implementation of gfxFont::Measure(), 1492 // which works with the glyph extents cache, does not 1493 // differentiate between this and TIGHT_INK_EXTENTS. 1494 // Whether the distinction is important depends on the 1495 // antialiasing behavior of the platform; currently the 1496 // distinction is only implemented in the gfxWindowsFont 1497 // subclass, because of ClearType's tendency to paint 1498 // outside the hinted outline. 1499 // Also NOTE: it is relatively expensive to request this, 1500 // as it does not use cached glyph extents in the font. 1501 } BoundingBoxType; 1502 1503 const nsCString& GetName() const { return mFontEntry->Name(); } 1504 const gfxFontStyle* GetStyle() const { return &mStyle; } 1505 1506 virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption) const { 1507 // platforms where this actually matters should override 1508 return nullptr; 1509 } 1510 1511 gfxFloat GetAdjustedSize() const { 1512 // mAdjustedSize is cached here if not already set to a non-zero value; 1513 // but it may be overridden by a value computed in metrics initialization 1514 // from font-size-adjust. 1515 if (mAdjustedSize < 0.0) { 1516 mAdjustedSize = mStyle.AdjustedSizeMustBeZero() 1517 ? 0.0 1518 : mStyle.size * mFontEntry->mSizeAdjust; 1519 } 1520 return mAdjustedSize; 1521 } 1522 1523 float FUnitsToDevUnitsFactor() const { 1524 // check this was set up during font initialization 1525 NS_ASSERTION(mFUnitsConvFactor >= 0.0f, "mFUnitsConvFactor not valid"); 1526 return mFUnitsConvFactor; 1527 } 1528 1529 // check whether this is an sfnt we can potentially use with harfbuzz 1530 bool FontCanSupportHarfBuzz() const { return mFontEntry->HasCmapTable(); } 1531 1532 // check whether this is an sfnt we can potentially use with Graphite 1533 bool FontCanSupportGraphite() const { 1534 return mFontEntry->HasGraphiteTables(); 1535 } 1536 1537 // Whether this is a font that may be doing full-color rendering, 1538 // and therefore needs us to use a mask for text-shadow even when 1539 // we're not actually blurring. 1540 bool AlwaysNeedsMaskForShadow() const { 1541 return mFontEntry->AlwaysNeedsMaskForShadow(); 1542 } 1543 1544 // whether a feature is supported by the font (limited to a small set 1545 // of features for which some form of fallback needs to be implemented) 1546 bool SupportsFeature(Script aScript, uint32_t aFeatureTag); 1547 1548 // whether the font supports "real" small caps, petite caps etc. 1549 // aFallbackToSmallCaps true when petite caps should fallback to small caps 1550 bool SupportsVariantCaps(Script aScript, uint32_t aVariantCaps, 1551 bool& aFallbackToSmallCaps, 1552 bool& aSyntheticLowerToSmallCaps, 1553 bool& aSyntheticUpperToSmallCaps); 1554 1555 // whether the font supports subscript/superscript feature 1556 // for fallback, need to verify that all characters in the run 1557 // have variant substitutions 1558 bool SupportsSubSuperscript(uint32_t aSubSuperscript, const uint8_t* aString, 1559 uint32_t aLength, Script aRunScript); 1560 1561 bool SupportsSubSuperscript(uint32_t aSubSuperscript, const char16_t* aString, 1562 uint32_t aLength, Script aRunScript); 1563 1564 // whether the specified feature will apply to the given character 1565 bool FeatureWillHandleChar(Script aRunScript, uint32_t aFeature, 1566 uint32_t aUnicode); 1567 1568 // Subclasses may choose to look up glyph ids for characters. 1569 // If they do not override this, gfxHarfBuzzShaper will fetch the cmap 1570 // table and use that. 1571 virtual bool ProvidesGetGlyph() const { return false; } 1572 // Map unicode character to glyph ID. 1573 // Only used if ProvidesGetGlyph() returns true. 1574 virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector) { 1575 return 0; 1576 } 1577 1578 // Return the advance of a glyph. 1579 gfxFloat GetGlyphAdvance(uint16_t aGID, bool aVertical = false); 1580 1581 // Return the advance of a given Unicode char in isolation. 1582 // Returns -1.0 if the char is not supported. 1583 gfxFloat GetCharAdvance(uint32_t aUnicode, bool aVertical = false); 1584 1585 gfxFloat SynthesizeSpaceWidth(uint32_t aCh); 1586 1587 // Work out whether cairo will snap inter-glyph spacing to pixels 1588 // when rendering to the given drawTarget. 1589 RoundingFlags GetRoundOffsetsToPixels(DrawTarget* aDrawTarget); 1590 1591 virtual bool ShouldHintMetrics() const { return true; } 1592 virtual bool ShouldRoundXOffset(cairo_t* aCairo) const { return true; } 1593 1594 // Return the font's owned harfbuzz shaper, creating and initializing it if 1595 // necessary; returns null if shaper initialization has failed. 1596 gfxHarfBuzzShaper* GetHarfBuzzShaper(); 1597 1598 // Font metrics 1599 struct Metrics { 1600 gfxFloat capHeight; 1601 gfxFloat xHeight; 1602 gfxFloat strikeoutSize; 1603 gfxFloat strikeoutOffset; 1604 gfxFloat underlineSize; 1605 gfxFloat underlineOffset; 1606 1607 gfxFloat internalLeading; 1608 gfxFloat externalLeading; 1609 1610 gfxFloat emHeight; 1611 gfxFloat emAscent; 1612 gfxFloat emDescent; 1613 gfxFloat maxHeight; 1614 gfxFloat maxAscent; 1615 gfxFloat maxDescent; 1616 gfxFloat maxAdvance; 1617 1618 gfxFloat aveCharWidth; 1619 gfxFloat spaceWidth; 1620 gfxFloat zeroWidth; // -1 if there was no zero glyph 1621 gfxFloat ideographicWidth; // -1 if kWaterIdeograph is not supported 1622 1623 gfxFloat ZeroOrAveCharWidth() const { 1624 return zeroWidth >= 0 ? zeroWidth : aveCharWidth; 1625 } 1626 }; 1627 // Unicode character used as basis for 'ic' unit: 1628 static constexpr uint32_t kWaterIdeograph = 0x6C34; 1629 1630 typedef nsFontMetrics::FontOrientation Orientation; 1631 1632 const Metrics& GetMetrics(Orientation aOrientation) { 1633 if (aOrientation == nsFontMetrics::eHorizontal) { 1634 return GetHorizontalMetrics(); 1635 } 1636 if (!mVerticalMetrics) { 1637 CreateVerticalMetrics(); 1638 } 1639 return *mVerticalMetrics; 1640 } 1641 1642 struct Baselines { 1643 gfxFloat mAlphabetic; 1644 gfxFloat mHanging; 1645 gfxFloat mIdeographic; 1646 }; 1647 Baselines GetBaselines(Orientation aOrientation); 1648 1649 /** 1650 * We let layout specify spacing on either side of any 1651 * character. We need to specify both before and after 1652 * spacing so that substring measurement can do the right things. 1653 * These values are in appunits. 1654 */ 1655 struct Spacing { 1656 nscoord mBefore; 1657 nscoord mAfter; 1658 }; 1659 /** 1660 * Metrics for a particular string 1661 */ 1662 struct RunMetrics { 1663 RunMetrics() { mAdvanceWidth = mAscent = mDescent = 0.0; } 1664 1665 void CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft); 1666 1667 // can be negative (partly due to negative spacing). 1668 // Advance widths should be additive: the advance width of the 1669 // (offset1, length1) plus the advance width of (offset1 + length1, 1670 // length2) should be the advance width of (offset1, length1 + length2) 1671 gfxFloat mAdvanceWidth; 1672 1673 // For zero-width substrings, these must be zero! 1674 gfxFloat mAscent; // always non-negative 1675 gfxFloat mDescent; // always non-negative 1676 1677 // Bounding box that is guaranteed to include everything drawn. 1678 // If a tight boundingBox was requested when these metrics were 1679 // generated, this will tightly wrap the glyphs, otherwise it is 1680 // "loose" and may be larger than the true bounding box. 1681 // Coordinates are relative to the baseline left origin, so typically 1682 // mBoundingBox.y == -mAscent 1683 gfxRect mBoundingBox; 1684 }; 1685 1686 /** 1687 * Draw a series of glyphs to aContext. The direction of aTextRun must 1688 * be honoured. 1689 * @param aStart the first character to draw 1690 * @param aEnd draw characters up to here 1691 * @param aPt the baseline origin; the left end of the baseline 1692 * for LTR textruns, the right end for RTL textruns. 1693 * On return, this will be updated to the other end of the baseline. 1694 * In application units, really! 1695 * @param aRunParams record with drawing parameters, see TextRunDrawParams. 1696 * Particular fields of interest include 1697 * .spacing spacing to insert before and after characters (for RTL 1698 * glyphs, before-spacing is inserted to the right of characters). There 1699 * are aEnd - aStart elements in this array, unless it's null to indicate 1700 * that there is no spacing. 1701 * .drawMode specifies whether the fill or stroke of the glyph should be 1702 * drawn, or if it should be drawn into the current path 1703 * .contextPaint information about how to construct the fill and 1704 * stroke pattern. Can be nullptr if we are not stroking the text, which 1705 * indicates that the current source from context should be used for fill 1706 * .context the Thebes graphics context to which we're drawing 1707 * .dt Moz2D DrawTarget to which we're drawing 1708 * 1709 * Callers guarantee: 1710 * -- aStart and aEnd are aligned to cluster and ligature boundaries 1711 * -- all glyphs use this font 1712 */ 1713 void Draw(const gfxTextRun* aTextRun, uint32_t aStart, uint32_t aEnd, 1714 mozilla::gfx::Point* aPt, TextRunDrawParams& aRunParams, 1715 mozilla::gfx::ShapedTextFlags aOrientation); 1716 1717 /** 1718 * Draw the emphasis marks for the given text run. Its prerequisite 1719 * and output are similiar to the method Draw(). 1720 * @param aPt the baseline origin of the emphasis marks. 1721 * @param aParams some drawing parameters, see EmphasisMarkDrawParams. 1722 */ 1723 void DrawEmphasisMarks(const gfxTextRun* aShapedText, 1724 mozilla::gfx::Point* aPt, uint32_t aOffset, 1725 uint32_t aCount, 1726 const EmphasisMarkDrawParams& aParams); 1727 1728 /** 1729 * Measure a run of characters. See gfxTextRun::Metrics. 1730 * @param aTight if false, then return the union of the glyph extents 1731 * with the font-box for the characters (the rectangle with x=0,width= 1732 * the advance width for the character run,y=-(font ascent), and height= 1733 * font ascent + font descent). Otherwise, we must return as tight as possible 1734 * an approximation to the area actually painted by glyphs. 1735 * @param aDrawTargetForTightBoundingBox when aTight is true, this must 1736 * be non-null. 1737 * @param aSpacing spacing to insert before and after glyphs. The bounding box 1738 * need not include the spacing itself, but the spacing affects the glyph 1739 * positions. null if there is no spacing. 1740 * 1741 * Callers guarantee: 1742 * -- aStart and aEnd are aligned to cluster and ligature boundaries 1743 * -- all glyphs use this font 1744 * 1745 * The default implementation just uses font metrics and aTextRun's 1746 * advances, and assumes no characters fall outside the font box. In 1747 * general this is insufficient, because that assumption is not always true. 1748 */ 1749 virtual RunMetrics Measure(const gfxTextRun* aTextRun, uint32_t aStart, 1750 uint32_t aEnd, BoundingBoxType aBoundingBoxType, 1751 DrawTarget* aDrawTargetForTightBoundingBox, 1752 Spacing* aSpacing, 1753 mozilla::gfx::ShapedTextFlags aOrientation); 1754 /** 1755 * Line breaks have been changed at the beginning and/or end of a substring 1756 * of the text. Reshaping may be required; glyph updating is permitted. 1757 * @return true if anything was changed, false otherwise 1758 */ 1759 bool NotifyLineBreaksChanged(gfxTextRun* aTextRun, uint32_t aStart, 1760 uint32_t aLength) { 1761 return false; 1762 } 1763 1764 // Expiration tracking 1765 nsExpirationState* GetExpirationState() { return &mExpirationState; } 1766 1767 // Get the glyphID of a space 1768 uint16_t GetSpaceGlyph() const { return mSpaceGlyph; } 1769 1770 gfxGlyphExtents* GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit); 1771 1772 void SetupGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphID, 1773 bool aNeedTight, gfxGlyphExtents* aExtents); 1774 1775 virtual bool AllowSubpixelAA() const { return true; } 1776 1777 bool ApplySyntheticBold() const { return mApplySyntheticBold; } 1778 1779 float AngleForSyntheticOblique() const; 1780 float SkewForSyntheticOblique() const; 1781 1782 // Amount by which synthetic bold "fattens" the glyphs: 1783 // For size S up to a threshold size T, we use (0.25 + 3S / 4T), 1784 // so that the result ranges from 0.25 to 1.0; thereafter, 1785 // simply use (S / T). 1786 gfxFloat GetSyntheticBoldOffset() const { 1787 gfxFloat size = GetAdjustedSize(); 1788 const gfxFloat threshold = 48.0; 1789 return size < threshold ? (0.25 + 0.75 * size / threshold) 1790 : (size / threshold); 1791 } 1792 1793 gfxFontEntry* GetFontEntry() const { return mFontEntry.get(); } 1794 bool HasCharacter(uint32_t ch) const { 1795 if (!mIsValid || (mUnicodeRangeMap && !mUnicodeRangeMap->test(ch))) { 1796 return false; 1797 } 1798 return mFontEntry->HasCharacter(ch); 1799 } 1800 1801 const gfxCharacterMap* GetUnicodeRangeMap() const { 1802 return mUnicodeRangeMap.get(); 1803 } 1804 1805 void SetUnicodeRangeMap(gfxCharacterMap* aUnicodeRangeMap) { 1806 mUnicodeRangeMap = aUnicodeRangeMap; 1807 } 1808 1809 uint16_t GetUVSGlyph(uint32_t aCh, uint32_t aVS) const { 1810 if (!mIsValid) { 1811 return 0; 1812 } 1813 return mFontEntry->GetUVSGlyph(aCh, aVS); 1814 } 1815 1816 template <typename T> 1817 bool InitFakeSmallCapsRun(FontVisibilityProvider* aFontVisibilityProvider, 1818 DrawTarget* aDrawTarget, gfxTextRun* aTextRun, 1819 const T* aText, uint32_t aOffset, uint32_t aLength, 1820 FontMatchType aMatchType, 1821 mozilla::gfx::ShapedTextFlags aOrientation, 1822 Script aScript, nsAtom* aLanguage, 1823 bool aSyntheticLower, bool aSyntheticUpper); 1824 1825 // call the (virtual) InitTextRun method to do glyph generation/shaping, 1826 // limiting the length of text passed by processing the run in multiple 1827 // segments if necessary 1828 template <typename T> 1829 bool SplitAndInitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun, 1830 const T* aString, uint32_t aRunStart, 1831 uint32_t aRunLength, Script aRunScript, 1832 nsAtom* aLanguage, 1833 mozilla::gfx::ShapedTextFlags aOrientation); 1834 1835 // Get a ShapedWord representing a single space for use in setting up a 1836 // gfxTextRun. 1837 bool ProcessSingleSpaceShapedWord( 1838 DrawTarget* aDrawTarget, bool aVertical, int32_t aAppUnitsPerDevUnit, 1839 mozilla::gfx::ShapedTextFlags aFlags, RoundingFlags aRounding, 1840 const std::function<void(gfxShapedWord*)>& aCallback); 1841 1842 // Called by the gfxFontCache timer to increment the age of all the words, 1843 // so that they'll expire after a sufficient period of non-use. 1844 // Returns true if the cache is now empty, otherwise false. 1845 bool AgeCachedWords(); 1846 1847 // Discard all cached word records; called on memory-pressure notification. 1848 void ClearCachedWords() { 1849 mozilla::AutoWriteLock lock(mLock); 1850 if (mWordCache) { 1851 ClearCachedWordsLocked(); 1852 } 1853 } 1854 void ClearCachedWordsLocked() MOZ_REQUIRES(mLock) { 1855 MOZ_ASSERT(mWordCache); 1856 mWordCache->clear(); 1857 } 1858 1859 // Glyph rendering/geometry has changed, so invalidate data as necessary. 1860 void NotifyGlyphsChanged() const; 1861 1862 virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1863 FontCacheSizes* aSizes) const; 1864 virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1865 FontCacheSizes* aSizes) const; 1866 1867 typedef enum { 1868 FONT_TYPE_DWRITE, 1869 FONT_TYPE_GDI, 1870 FONT_TYPE_FT2, 1871 FONT_TYPE_MAC, 1872 FONT_TYPE_OS2, 1873 FONT_TYPE_CAIRO, 1874 FONT_TYPE_FONTCONFIG 1875 } FontType; 1876 1877 virtual FontType GetType() const = 0; 1878 1879 const RefPtr<mozilla::gfx::UnscaledFont>& GetUnscaledFont() const { 1880 return mUnscaledFont; 1881 } 1882 1883 virtual already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFont( 1884 const TextRunDrawParams& aRunParams) = 0; 1885 already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFont( 1886 mozilla::gfx::DrawTarget* aDrawTarget); 1887 1888 // gfxFont implementations may cache ScaledFont versions other than the 1889 // default, so InitializeScaledFont must support explicitly specifying 1890 // which ScaledFonts to initialize. 1891 void InitializeScaledFont( 1892 const RefPtr<mozilla::gfx::ScaledFont>& aScaledFont); 1893 1894 bool KerningDisabled() const { return mKerningSet && !mKerningEnabled; } 1895 1896 /** 1897 * Subclass this object to be notified of glyph changes. Delete the object 1898 * when no longer needed. 1899 */ 1900 class GlyphChangeObserver { 1901 public: 1902 virtual ~GlyphChangeObserver() { 1903 if (mFont) { 1904 mFont->RemoveGlyphChangeObserver(this); 1905 } 1906 } 1907 // This gets called when the gfxFont dies. 1908 void ForgetFont() { mFont = nullptr; } 1909 virtual void NotifyGlyphsChanged() = 0; 1910 1911 protected: 1912 explicit GlyphChangeObserver(gfxFont* aFont) : mFont(aFont) { 1913 mFont->AddGlyphChangeObserver(this); 1914 } 1915 // This pointer is nulled by ForgetFont in the gfxFont's 1916 // destructor. Before the gfxFont dies. 1917 gfxFont* MOZ_NON_OWNING_REF mFont; 1918 }; 1919 friend class GlyphChangeObserver; 1920 1921 bool GlyphsMayChange() const { 1922 // Currently only fonts with SVG glyphs can have animated glyphs 1923 return mFontEntry->TryGetSVGData(this); 1924 } 1925 1926 static void DestroySingletons() { 1927 delete sScriptTagToCode; 1928 delete sDefaultFeatures; 1929 } 1930 1931 // Call TryGetMathTable() to try and load the Open Type MATH table. 1932 // If (and ONLY if) TryGetMathTable() has returned true, the MathTable() 1933 // method may be called to access the gfxMathTable data. 1934 bool TryGetMathTable(); 1935 gfxMathTable* MathTable() const { 1936 MOZ_RELEASE_ASSERT(mMathTable, 1937 "A successful call to TryGetMathTable() must be " 1938 "performed before calling this function"); 1939 return mMathTable; 1940 } 1941 1942 // Return a cloned font resized and offset to simulate sub/superscript 1943 // glyphs. This does not add a reference to the returned font. 1944 already_AddRefed<gfxFont> GetSubSuperscriptFont( 1945 int32_t aAppUnitsPerDevPixel) const; 1946 1947 bool HasColorGlyphFor(uint32_t aCh, uint32_t aNextCh); 1948 1949 protected: 1950 virtual const Metrics& GetHorizontalMetrics() const = 0; 1951 1952 void CreateVerticalMetrics(); 1953 1954 bool MeasureGlyphs(const gfxTextRun* aTextRun, uint32_t aStart, uint32_t aEnd, 1955 BoundingBoxType aBoundingBoxType, 1956 DrawTarget* aRefDrawTarget, Spacing* aSpacing, 1957 gfxGlyphExtents* aExtents, bool aIsRTL, 1958 bool aNeedsGlyphExtents, RunMetrics& aMetrics, 1959 gfxFloat* aAdvanceMin, gfxFloat* aAdvanceMax); 1960 1961 bool MeasureGlyphs(const gfxTextRun* aTextRun, uint32_t aStart, uint32_t aEnd, 1962 BoundingBoxType aBoundingBoxType, 1963 DrawTarget* aRefDrawTarget, Spacing* aSpacing, bool aIsRTL, 1964 RunMetrics& aMetrics); 1965 1966 // Template parameters for DrawGlyphs/DrawOneGlyph, used to select 1967 // simplified versions of the methods in the most common cases. 1968 enum class FontComplexityT { SimpleFont, ComplexFont }; 1969 enum class SpacingT { NoSpacing, HasSpacing }; 1970 1971 // Output a run of glyphs at *aPt, which is updated to follow the last glyph 1972 // in the run. This method also takes account of any letter-spacing provided 1973 // in aRunParams. 1974 template <FontComplexityT FC, SpacingT S> 1975 bool DrawGlyphs(const gfxShapedText* aShapedText, 1976 uint32_t aOffset, // offset in the textrun 1977 uint32_t aCount, // length of run to draw 1978 mozilla::gfx::Point* aPt, 1979 // transform for mOffset field in DetailedGlyph records, 1980 // to account for rotations (may be null) 1981 const mozilla::gfx::Matrix* aOffsetMatrix, 1982 GlyphBufferAzure& aBuffer); 1983 1984 // Output a single glyph at *aPt. 1985 // Normal glyphs are simply accumulated in aBuffer until it is full and 1986 // gets flushed, but SVG or color-font glyphs will instead be rendered 1987 // directly to the destination (found from the buffer's parameters). 1988 template <FontComplexityT FC> 1989 void DrawOneGlyph(uint32_t aGlyphID, const mozilla::gfx::Point& aPt, 1990 GlyphBufferAzure& aBuffer, bool* aEmittedGlyphs); 1991 1992 // Helper for DrawOneGlyph to handle missing glyphs, rendering either 1993 // nothing (for default-ignorables) or a missing-glyph hexbox. 1994 bool DrawMissingGlyph(const TextRunDrawParams& aRunParams, 1995 const FontDrawParams& aFontParams, 1996 const gfxShapedText::DetailedGlyph* aDetails, 1997 const mozilla::gfx::Point& aPt); 1998 1999 // set the font size and offset used for 2000 // synthetic subscript/superscript glyphs 2001 void CalculateSubSuperSizeAndOffset(int32_t aAppUnitsPerDevPixel, 2002 gfxFloat& aSubSuperSizeRatio, 2003 float& aBaselineOffset); 2004 2005 // Return a font that is a "clone" of this one, but reduced to 80% size 2006 // (and with variantCaps set to normal). This does not add a reference to 2007 // the returned font. 2008 already_AddRefed<gfxFont> GetSmallCapsFont() const; 2009 2010 // subclasses may provide (possibly hinted) glyph widths (in font units); 2011 // if they do not override this, harfbuzz will use unhinted widths 2012 // derived from the font tables 2013 virtual bool ProvidesGlyphWidths() const { return false; } 2014 2015 // The return value is interpreted as a horizontal advance in 16.16 fixed 2016 // point format. 2017 virtual int32_t GetGlyphWidth(uint16_t aGID) { return -1; } 2018 2019 virtual bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, 2020 bool aTight = false) { 2021 return false; 2022 } 2023 2024 bool IsSpaceGlyphInvisible(DrawTarget* aRefDrawTarget, 2025 const gfxTextRun* aTextRun); 2026 2027 void AddGlyphChangeObserver(GlyphChangeObserver* aObserver); 2028 void RemoveGlyphChangeObserver(GlyphChangeObserver* aObserver); 2029 2030 // whether font contains substitution lookups containing spaces 2031 bool HasSubstitutionRulesWithSpaceLookups(Script aRunScript) const; 2032 2033 // do spaces participate in shaping rules? if so, can't used word cache 2034 // Note that this function uses HasGraphiteSpaceContextuals, so it can only 2035 // return a "hint" to the correct answer. The calling code must ensure it 2036 // performs safe actions independent of the value returned. 2037 tainted_boolean_hint SpaceMayParticipateInShaping(Script aRunScript) const; 2038 2039 // For 8-bit text, expand to 16-bit and then call the following method. 2040 bool ShapeText(DrawTarget* aContext, const uint8_t* aText, 2041 uint32_t aOffset, // dest offset in gfxShapedText 2042 uint32_t aLength, Script aScript, nsAtom* aLanguage, 2043 bool aVertical, RoundingFlags aRounding, 2044 gfxShapedText* aShapedText); // where to store the result 2045 2046 // Call the appropriate shaper to generate glyphs for aText and store 2047 // them into aShapedText. 2048 virtual bool ShapeText(DrawTarget* aContext, const char16_t* aText, 2049 uint32_t aOffset, uint32_t aLength, Script aScript, 2050 nsAtom* aLanguage, bool aVertical, 2051 RoundingFlags aRounding, gfxShapedText* aShapedText); 2052 2053 // Helper to adjust for synthetic bold and set character-type flags 2054 // in the shaped text; implementations of ShapeText should call this 2055 // after glyph shaping has been completed. 2056 void PostShapingFixup(DrawTarget* aContext, const char16_t* aText, 2057 uint32_t aOffset, // position within aShapedText 2058 uint32_t aLength, bool aVertical, 2059 gfxShapedText* aShapedText); 2060 2061 // Shape text directly into a range within a textrun, without using the 2062 // font's word cache. Intended for use when the font has layout features 2063 // that involve space, and therefore require shaping complete runs rather 2064 // than isolated words, or for long strings that are inefficient to cache. 2065 // This will split the text on "invalid" characters (tab/newline) that are 2066 // not handled via normal shaping, but does not otherwise divide up the 2067 // text. 2068 template <typename T> 2069 bool ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText, 2070 uint32_t aOffset, uint32_t aLength, 2071 Script aScript, nsAtom* aLanguage, 2072 bool aVertical, RoundingFlags aRounding, 2073 gfxTextRun* aTextRun); 2074 2075 // Shape a fragment of text (a run that is known to contain only 2076 // "valid" characters, no newlines/tabs/other control chars). 2077 // All non-wordcache shaping goes through here; this is the function 2078 // that will ensure we don't pass excessively long runs to the various 2079 // platform shapers. 2080 template <typename T> 2081 bool ShapeFragmentWithoutWordCache(DrawTarget* aDrawTarget, const T* aText, 2082 uint32_t aOffset, uint32_t aLength, 2083 Script aScript, nsAtom* aLanguage, 2084 bool aVertical, RoundingFlags aRounding, 2085 gfxTextRun* aTextRun); 2086 2087 void CheckForFeaturesInvolvingSpace() const; 2088 2089 // Get a ShapedWord representing the given text (either 8- or 16-bit) 2090 // for use in setting up a gfxTextRun. 2091 template <typename T, typename Func> 2092 bool ProcessShapedWordInternal(DrawTarget* aDrawTarget, const T* aText, 2093 uint32_t aLength, uint32_t aHash, 2094 Script aRunScript, nsAtom* aLanguage, 2095 bool aVertical, int32_t aAppUnitsPerDevUnit, 2096 mozilla::gfx::ShapedTextFlags aFlags, 2097 RoundingFlags aRounding, 2098 gfxTextPerfMetrics* aTextPerf, Func aCallback); 2099 2100 // whether a given feature is included in feature settings from both the 2101 // font and the style. aFeatureOn set if resolved feature value is non-zero 2102 bool HasFeatureSet(uint32_t aFeature, bool& aFeatureOn); 2103 2104 // used when analyzing whether a font has space contextual lookups 2105 static mozilla::Atomic<nsTHashMap<nsUint32HashKey, Script>*> sScriptTagToCode; 2106 static mozilla::Atomic<nsTHashSet<uint32_t>*> sDefaultFeatures; 2107 2108 RefPtr<gfxFontEntry> mFontEntry; 2109 mutable mozilla::RWLock mLock; 2110 2111 // Note that WordCacheKey contains a pointer to the text of the word, which 2112 // must be valid for as long as the key is in use. When using for a Lookup, 2113 // the string may be local/temporary, but when storing in the HashMap, we 2114 // set the Key text pointer to reference the text in the associated 2115 // gfxShapedWord that is being stored. 2116 struct WordCacheKey { 2117 union { 2118 const uint8_t* mSingle; 2119 const char16_t* mDouble; 2120 } mText; 2121 uint32_t mLength; 2122 ShapedTextFlags mFlags; 2123 Script mScript; 2124 RefPtr<nsAtom> mLanguage; 2125 int32_t mAppUnitsPerDevUnit; 2126 PLDHashNumber mHashKey; 2127 bool mTextIs8Bit; 2128 RoundingFlags mRounding; 2129 2130 WordCacheKey(const uint8_t* aText, uint32_t aLength, uint32_t aStringHash, 2131 Script aScriptCode, nsAtom* aLanguage, 2132 int32_t aAppUnitsPerDevUnit, ShapedTextFlags aFlags, 2133 RoundingFlags aRounding) 2134 : mLength(aLength), 2135 mFlags(aFlags), 2136 mScript(aScriptCode), 2137 mLanguage(aLanguage), 2138 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit), 2139 mHashKey(aStringHash + static_cast<int32_t>(aScriptCode) + 2140 aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 + 2141 int(aRounding) + (aLanguage ? aLanguage->hash() : 0)), 2142 mTextIs8Bit(true), 2143 mRounding(aRounding) { 2144 NS_ASSERTION(aFlags & ShapedTextFlags::TEXT_IS_8BIT, 2145 "8-bit flag should have been set"); 2146 mText.mSingle = aText; 2147 } 2148 2149 WordCacheKey(const char16_t* aText, uint32_t aLength, uint32_t aStringHash, 2150 Script aScriptCode, nsAtom* aLanguage, 2151 int32_t aAppUnitsPerDevUnit, ShapedTextFlags aFlags, 2152 RoundingFlags aRounding) 2153 : mLength(aLength), 2154 mFlags(aFlags), 2155 mScript(aScriptCode), 2156 mLanguage(aLanguage), 2157 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit), 2158 mHashKey(aStringHash + static_cast<int32_t>(aScriptCode) + 2159 aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 + 2160 int(aRounding)), 2161 mTextIs8Bit(false), 2162 mRounding(aRounding) { 2163 // We can NOT assert that TEXT_IS_8BIT is false in aFlags here, 2164 // because this might be an 8bit-only word from a 16-bit textrun, 2165 // in which case the text we're passed is still in 16-bit form, 2166 // and we'll have to use an 8-to-16bit comparison in KeyEquals. 2167 mText.mDouble = aText; 2168 } 2169 2170 bool Matches(const WordCacheKey& aLookup) const; 2171 2172 class HashPolicy { 2173 public: 2174 typedef WordCacheKey Key; 2175 typedef WordCacheKey Lookup; 2176 static mozilla::HashNumber hash(const Lookup& aLookup) { 2177 return aLookup.mHashKey; 2178 } 2179 static bool match(const Key& aKey, const Lookup& aLookup); 2180 }; 2181 }; 2182 2183 mozilla::UniquePtr< 2184 mozilla::HashMap<WordCacheKey, mozilla::UniquePtr<gfxShapedWord>, 2185 WordCacheKey::HashPolicy>> 2186 mWordCache MOZ_GUARDED_BY(mLock); 2187 2188 static const uint32_t kShapedWordCacheMaxAge = 3; 2189 2190 nsTArray<mozilla::UniquePtr<gfxGlyphExtents>> mGlyphExtentsArray 2191 MOZ_GUARDED_BY(mLock); 2192 mozilla::UniquePtr<nsTHashSet<GlyphChangeObserver*>> mGlyphChangeObservers 2193 MOZ_GUARDED_BY(mLock); 2194 2195 // a copy of the font without antialiasing, if needed for separate 2196 // measurement by mathml code 2197 mozilla::Atomic<gfxFont*> mNonAAFont; 2198 2199 // we create either or both of these shapers when needed, depending 2200 // whether the font has graphite tables, and whether graphite shaping 2201 // is actually enabled 2202 mozilla::Atomic<gfxHarfBuzzShaper*> mHarfBuzzShaper; 2203 mozilla::Atomic<gfxGraphiteShaper*> mGraphiteShaper; 2204 2205 // If a userfont with unicode-range specified, contains map of *possible* 2206 // ranges supported by font. This is set during user-font initialization, 2207 // before the font is available to other threads, and thereafter is inert 2208 // so no guard is needed. 2209 RefPtr<gfxCharacterMap> mUnicodeRangeMap; 2210 2211 // This is immutable once initialized by the constructor, so does not need 2212 // locking. 2213 RefPtr<mozilla::gfx::UnscaledFont> mUnscaledFont; 2214 2215 mozilla::Atomic<mozilla::gfx::ScaledFont*> mAzureScaledFont; 2216 2217 // For vertical metrics, created on demand. 2218 mozilla::Atomic<Metrics*> mVerticalMetrics; 2219 2220 // Table used for MathML layout. 2221 mozilla::Atomic<gfxMathTable*> mMathTable; 2222 2223 gfxFontStyle mStyle; 2224 mutable gfxFloat mAdjustedSize; 2225 2226 // Tracking adjustment to be applied for CSS px size mCachedTrackingSize. 2227 gfxFloat mTracking = 0.0; 2228 gfxFloat mCachedTrackingSize = -1.0; 2229 2230 // Conversion factor from font units to dev units; note that this may be 2231 // zero (in the degenerate case where mAdjustedSize has become zero). 2232 // This is OK because we only multiply by this factor, never divide. 2233 float mFUnitsConvFactor; 2234 2235 // This is guarded by gfxFontCache::GetCache()->GetMutex() but it is difficult 2236 // to annotate that fact. 2237 nsExpirationState mExpirationState; 2238 2239 // Glyph ID of the font's <space> glyph, zero if missing 2240 uint16_t mSpaceGlyph = 0; 2241 2242 // the AA setting requested for this font - may affect glyph bounds 2243 AntialiasOption mAntialiasOption; 2244 2245 bool mIsValid; 2246 2247 // use synthetic bolding for environments where this is not supported 2248 // by the platform 2249 bool mApplySyntheticBold; 2250 2251 bool mKerningSet; // kerning explicitly set? 2252 bool mKerningEnabled; // if set, on or off? 2253 2254 mozilla::Atomic<bool> mMathInitialized; // TryGetMathTable() called? 2255 2256 // Helper for subclasses that want to initialize standard metrics from the 2257 // tables of sfnt (TrueType/OpenType) fonts. 2258 // This will use mFUnitsConvFactor if it is already set, else compute it 2259 // from mAdjustedSize and the unitsPerEm in the font's 'head' table. 2260 // Returns TRUE and sets mIsValid=TRUE if successful; 2261 // Returns TRUE but leaves mIsValid=FALSE if the font seems to be broken. 2262 // Returns FALSE if the font does not appear to be an sfnt at all, 2263 // and should be handled (if possible) using other APIs. 2264 bool InitMetricsFromSfntTables(Metrics& aMetrics); 2265 2266 // Helper to calculate various derived metrics from the results of 2267 // InitMetricsFromSfntTables or equivalent platform code 2268 void CalculateDerivedMetrics(Metrics& aMetrics); 2269 2270 // some fonts have bad metrics, this method sanitize them. 2271 // if this font has bad underline offset, aIsBadUnderlineFont should be true. 2272 void SanitizeMetrics(Metrics* aMetrics, bool aIsBadUnderlineFont); 2273 2274 bool RenderSVGGlyph(gfxContext* aContext, 2275 mozilla::layout::TextDrawTarget* aTextDrawer, 2276 mozilla::gfx::Point aPoint, uint32_t aGlyphId, 2277 SVGContextPaint* aContextPaint) const; 2278 bool RenderSVGGlyph(gfxContext* aContext, 2279 mozilla::layout::TextDrawTarget* aTextDrawer, 2280 mozilla::gfx::Point aPoint, uint32_t aGlyphId, 2281 SVGContextPaint* aContextPaint, 2282 gfxTextRunDrawCallbacks* aCallbacks, 2283 bool& aEmittedGlyphs) const; 2284 2285 bool RenderColorGlyph(DrawTarget* aDrawTarget, gfxContext* aContext, 2286 mozilla::layout::TextDrawTarget* aTextDrawer, 2287 const FontDrawParams& aFontParams, 2288 const mozilla::gfx::Point& aPoint, uint32_t aGlyphId); 2289 2290 class ColorGlyphCache { 2291 public: 2292 ColorGlyphCache() = default; 2293 ~ColorGlyphCache() = default; 2294 2295 void SetColors(mozilla::gfx::sRGBColor aCurrentColor, 2296 mozilla::gfx::FontPalette* aPalette); 2297 2298 mozilla::HashMap<uint32_t, RefPtr<mozilla::gfx::SourceSurface>> mCache; 2299 2300 private: 2301 mozilla::gfx::sRGBColor mCurrentColor; 2302 RefPtr<mozilla::gfx::FontPalette> mPalette; 2303 }; 2304 mozilla::UniquePtr<ColorGlyphCache> mColorGlyphCache; 2305 2306 // Subclasses can override to return true if the platform is able to render 2307 // COLR-font glyphs directly, instead of us painting the layers explicitly. 2308 // (Currently used only for COLR.v0 fonts on macOS.) 2309 virtual bool UseNativeColrFontSupport() const { return false; } 2310 2311 // Bug 674909. When synthetic bolding text by drawing twice, need to 2312 // render using a pixel offset in device pixels, otherwise text 2313 // doesn't appear bolded, it appears as if a bad text shadow exists 2314 // when a non-identity transform exists. Use an offset factor so that 2315 // the second draw occurs at a constant offset in device pixels. 2316 // This helper calculates the scale factor we need to apply to the 2317 // synthetic-bold offset. 2318 static mozilla::gfx::Float CalcXScale(DrawTarget* aDrawTarget); 2319 }; 2320 2321 // proportion of ascent used for x-height, if unable to read value from font 2322 #define DEFAULT_XHEIGHT_FACTOR 0.56f 2323 2324 // Parameters passed to gfxFont methods for drawing glyphs from a textrun. 2325 // The TextRunDrawParams are set up once per textrun; the FontDrawParams 2326 // are dependent on the specific font, so they are set per GlyphRun. 2327 2328 struct MOZ_STACK_CLASS TextRunDrawParams { 2329 explicit TextRunDrawParams(mozilla::gfx::PaletteCache& aPaletteCache) 2330 : paletteCache(aPaletteCache) {} 2331 2332 mozilla::gfx::PaletteCache& paletteCache; 2333 RefPtr<mozilla::gfx::DrawTarget> dt; 2334 gfxContext* context = nullptr; 2335 gfxFont::Spacing* spacing = nullptr; 2336 gfxTextRunDrawCallbacks* callbacks = nullptr; 2337 mozilla::SVGContextPaint* runContextPaint = nullptr; 2338 mozilla::layout::TextDrawTarget* textDrawer = nullptr; 2339 mozilla::LayoutDeviceRect clipRect; 2340 mozilla::gfx::Float direction = 1.0f; 2341 double devPerApp = 1.0; 2342 nscolor textStrokeColor = 0; 2343 gfxPattern* textStrokePattern = nullptr; 2344 const mozilla::gfx::StrokeOptions* strokeOpts = nullptr; 2345 const mozilla::gfx::DrawOptions* drawOpts = nullptr; 2346 nsAtom* fontPalette = nullptr; 2347 DrawMode drawMode = DrawMode::GLYPH_FILL; 2348 bool isVerticalRun = false; 2349 bool isRTL = false; 2350 bool paintSVGGlyphs = true; 2351 bool allowGDI = true; 2352 bool hasTextShadow = false; 2353 }; 2354 2355 struct MOZ_STACK_CLASS FontDrawParams { 2356 RefPtr<mozilla::gfx::ScaledFont> scaledFont; 2357 mozilla::SVGContextPaint* contextPaint; 2358 mozilla::gfx::Float synBoldOnePixelOffset; 2359 mozilla::gfx::Float obliqueSkew; 2360 int32_t extraStrikes; 2361 mozilla::gfx::DrawOptions drawOptions; 2362 gfxFloat advanceDirection; 2363 mozilla::gfx::sRGBColor currentColor; 2364 RefPtr<mozilla::gfx::FontPalette> palette; 2365 mozilla::gfx::Rect fontExtents; 2366 bool isVerticalFont; 2367 bool haveSVGGlyphs; 2368 bool haveColorGlyphs; 2369 bool hasTextShadow; // whether we're rendering with a text-shadow 2370 }; 2371 2372 struct MOZ_STACK_CLASS EmphasisMarkDrawParams { 2373 EmphasisMarkDrawParams(gfxContext* aContext, 2374 mozilla::gfx::PaletteCache& aPaletteCache) 2375 : context(aContext), paletteCache(aPaletteCache) {} 2376 gfxContext* context; 2377 mozilla::gfx::PaletteCache& paletteCache; 2378 gfxFont::Spacing* spacing; 2379 gfxTextRun* mark; 2380 gfxFloat advance; 2381 gfxFloat direction; 2382 bool isVertical; 2383 }; 2384 2385 #endif