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