tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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(&current, 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