tor-browser

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

gfxTextRun.h (61321B)


      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_TEXTRUN_H
      8 #define GFX_TEXTRUN_H
      9 
     10 #include <stdint.h>
     11 
     12 #include "gfxTypes.h"
     13 #include "gfxPoint.h"
     14 #include "gfxFont.h"
     15 #include "gfxFontConstants.h"
     16 #include "gfxSkipChars.h"
     17 #include "gfxPlatform.h"
     18 #include "gfxPlatformFontList.h"
     19 #include "gfxUserFontSet.h"
     20 #include "gfxUtils.h"
     21 #include "mozilla/MemoryReporting.h"
     22 #include "mozilla/RefPtr.h"
     23 #include "mozilla/intl/UnicodeScriptCodes.h"
     24 #include "nsPoint.h"
     25 #include "nsString.h"
     26 #include "nsTArray.h"
     27 #include "nsTHashSet.h"
     28 #include "nsTextFrameUtils.h"
     29 #include "DrawMode.h"
     30 #include "harfbuzz/hb.h"
     31 #include "nsColor.h"
     32 #include "nsFrameList.h"
     33 #include "X11UndefineNone.h"
     34 
     35 #ifdef DEBUG_FRAME_DUMP
     36 #  include <stdio.h>
     37 #endif
     38 
     39 class FontVisibilityProvider;
     40 class gfxContext;
     41 class gfxFontGroup;
     42 class nsAtom;
     43 class nsLanguageAtomService;
     44 class gfxMissingFontRecorder;
     45 
     46 namespace mozilla {
     47 class PostTraversalTask;
     48 class SVGContextPaint;
     49 enum class StyleHyphens : uint8_t;
     50 };  // namespace mozilla
     51 
     52 /**
     53 * Callback for Draw() to use when drawing text with mode
     54 * DrawMode::GLYPH_PATH.
     55 */
     56 struct MOZ_STACK_CLASS gfxTextRunDrawCallbacks {
     57  /**
     58   * Constructs a new DrawCallbacks object.
     59   *
     60   * @param aShouldPaintSVGGlyphs If true, SVG glyphs will be painted.  If
     61   *   false, SVG glyphs will not be painted; fallback plain glyphs are not
     62   *   emitted either.
     63   */
     64  explicit gfxTextRunDrawCallbacks(bool aShouldPaintSVGGlyphs = false)
     65      : mShouldPaintSVGGlyphs(aShouldPaintSVGGlyphs) {}
     66 
     67  /**
     68   * Called when a path has been emitted to the gfxContext when
     69   * painting a text run.  This can be called any number of times,
     70   * due to partial ligatures and intervening SVG glyphs.
     71   */
     72  virtual void NotifyGlyphPathEmitted() = 0;
     73 
     74  bool mShouldPaintSVGGlyphs;
     75 };
     76 
     77 /**
     78 * gfxTextRun is an abstraction for drawing and measuring substrings of a run
     79 * of text. It stores runs of positioned glyph data, each run having a single
     80 * gfxFont. The glyphs are associated with a string of source text, and the
     81 * gfxTextRun APIs take parameters that are offsets into that source text.
     82 *
     83 * gfxTextRuns are mostly immutable. The only things that can change are
     84 * inter-cluster spacing and line break placement. Spacing is always obtained
     85 * lazily by methods that need it, it is not cached. Line breaks are stored
     86 * persistently (insofar as they affect the shaping of glyphs; gfxTextRun does
     87 * not actually do anything to explicitly account for line breaks). Initially
     88 * there are no line breaks. The textrun can record line breaks before or after
     89 * any given cluster. (Line breaks specified inside clusters are ignored.)
     90 *
     91 * It is important that zero-length substrings are handled correctly. This will
     92 * be on the test!
     93 */
     94 class gfxTextRun : public gfxShapedText {
     95  NS_INLINE_DECL_REFCOUNTING(gfxTextRun);
     96 
     97 protected:
     98  // Override operator delete to properly free the object that was
     99  // allocated via malloc.
    100  void operator delete(void* p) { free(p); }
    101 
    102  virtual ~gfxTextRun();
    103 
    104 public:
    105  typedef gfxFont::RunMetrics Metrics;
    106  typedef mozilla::gfx::DrawTarget DrawTarget;
    107 
    108  // Public textrun API for general use
    109 
    110  bool IsClusterStart(uint32_t aPos) const {
    111    MOZ_ASSERT(aPos < GetLength());
    112    return mCharacterGlyphs[aPos].IsClusterStart();
    113  }
    114  bool IsLigatureGroupStart(uint32_t aPos) const {
    115    MOZ_ASSERT(aPos < GetLength());
    116    return mCharacterGlyphs[aPos].IsLigatureGroupStart();
    117  }
    118  bool CanBreakLineBefore(uint32_t aPos) const {
    119    return CanBreakBefore(aPos) == CompressedGlyph::FLAG_BREAK_TYPE_NORMAL;
    120  }
    121  bool CanHyphenateBefore(uint32_t aPos) const {
    122    return CanBreakBefore(aPos) == CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN;
    123  }
    124 
    125  // Returns a gfxShapedText::CompressedGlyph::FLAG_BREAK_TYPE_* value
    126  // as defined in gfxFont.h (may be NONE, NORMAL, HYPHEN or EMERGENCY_WRAP).
    127  uint8_t CanBreakBefore(uint32_t aPos) const {
    128    MOZ_ASSERT(aPos < GetLength());
    129    return mCharacterGlyphs[aPos].CanBreakBefore();
    130  }
    131 
    132  bool CharIsSpace(uint32_t aPos) const {
    133    MOZ_ASSERT(aPos < GetLength());
    134    return mCharacterGlyphs[aPos].CharIsSpace();
    135  }
    136  bool CharIsTab(uint32_t aPos) const {
    137    MOZ_ASSERT(aPos < GetLength());
    138    return mCharacterGlyphs[aPos].CharIsTab();
    139  }
    140  bool CharIsNewline(uint32_t aPos) const {
    141    MOZ_ASSERT(aPos < GetLength());
    142    return mCharacterGlyphs[aPos].CharIsNewline();
    143  }
    144  bool CharMayHaveEmphasisMark(uint32_t aPos) const {
    145    MOZ_ASSERT(aPos < GetLength());
    146    return mCharacterGlyphs[aPos].CharMayHaveEmphasisMark();
    147  }
    148  bool CharIsFormattingControl(uint32_t aPos) const {
    149    MOZ_ASSERT(aPos < GetLength());
    150    return mCharacterGlyphs[aPos].CharIsFormattingControl();
    151  }
    152 
    153  // All offsets are in terms of the string passed into MakeTextRun.
    154 
    155  // Describe range [start, end) of a text run. The range is
    156  // restricted to grapheme cluster boundaries.
    157  struct Range {
    158    uint32_t start = 0;
    159    uint32_t end = 0;
    160    uint32_t Length() const { return end - start; }
    161 
    162    Range() = default;
    163    Range(uint32_t aStart, uint32_t aEnd) : start(aStart), end(aEnd) {}
    164    explicit Range(const gfxTextRun* aTextRun)
    165        : Range(0, aTextRun->GetLength()) {}
    166 
    167    bool Intersects(const Range& aOther) const {
    168      return start < aOther.end && end > aOther.start;
    169    }
    170  };
    171 
    172  // All coordinates are in layout/app units
    173 
    174  /**
    175   * Set the potential linebreaks for a substring of the textrun. These are
    176   * the "allow break before" points. Initially, there are no potential
    177   * linebreaks.
    178   *
    179   * This can change glyphs and/or geometry! Some textruns' shapes
    180   * depend on potential line breaks (e.g., title-case-converting textruns).
    181   * This function is virtual so that those textruns can reshape themselves.
    182   *
    183   * @return true if this changed the linebreaks, false if the new line
    184   * breaks are the same as the old
    185   */
    186  virtual bool SetPotentialLineBreaks(Range aRange,
    187                                      const uint8_t* aBreakBefore);
    188 
    189  enum class HyphenType : uint8_t {
    190    // Code in BreakAndMeasureText depends on the ordering of these values!
    191    None,
    192    Explicit,
    193    Soft,
    194    AutoWithManualInSameWord,
    195    AutoWithoutManualInSameWord
    196  };
    197 
    198  static bool IsOptionalHyphenBreak(HyphenType aType) {
    199    return aType >= HyphenType::Soft;
    200  }
    201 
    202  struct HyphenationState {
    203    uint32_t mostRecentBoundary = 0;
    204    bool hasManualHyphen = false;
    205    bool hasExplicitHyphen = false;
    206    bool hasAutoHyphen = false;
    207  };
    208 
    209  /**
    210   * Layout provides PropertyProvider objects. These allow detection of
    211   * potential line break points and computation of spacing. We pass the data
    212   * this way to allow lazy data acquisition; for example BreakAndMeasureText
    213   * will want to only ask for properties of text it's actually looking at.
    214   *
    215   * NOTE that requested spacing may not actually be applied, if the textrun
    216   * is unable to apply it in some context. Exception: spacing around a
    217   * whitespace character MUST always be applied.
    218   */
    219  class PropertyProvider {
    220   public:
    221    // Detect hyphenation break opportunities in the given range; breaks
    222    // not at cluster boundaries will be ignored.
    223    virtual void GetHyphenationBreaks(Range aRange,
    224                                      HyphenType* aBreakBefore) const = 0;
    225 
    226    // Returns the provider's hyphenation setting, so callers can decide
    227    // whether it is necessary to call GetHyphenationBreaks.
    228    // Result is an StyleHyphens value.
    229    virtual mozilla::StyleHyphens GetHyphensOption() const = 0;
    230 
    231    // Returns the extra width that will be consumed by a hyphen. This should
    232    // be constant for a given textrun.
    233    virtual gfxFloat GetHyphenWidth() const = 0;
    234 
    235    // Return orientation flags to be used when creating a hyphen textrun.
    236    virtual mozilla::gfx::ShapedTextFlags GetShapedTextFlags() const = 0;
    237 
    238    typedef gfxFont::Spacing Spacing;
    239 
    240    /**
    241     * Get the spacing around the indicated characters. Spacing must be zero
    242     * inside clusters. In other words, if character i is not
    243     * CLUSTER_START, then character i-1 must have zero after-spacing and
    244     * character i must have zero before-spacing.
    245     * Returns true if there is (or may be) any custom spacing; false if we
    246     * are sure that aSpacing contains only zero values.
    247     */
    248    virtual bool GetSpacing(Range aRange, Spacing* aSpacing) const = 0;
    249 
    250    // Returns a gfxContext that can be used to measure the hyphen glyph.
    251    // Only called if the hyphen width is requested.
    252    virtual already_AddRefed<DrawTarget> GetDrawTarget() const = 0;
    253 
    254    // Return the appUnitsPerDevUnit value to be used when measuring.
    255    // Only called if the hyphen width is requested.
    256    virtual uint32_t GetAppUnitsPerDevUnit() const = 0;
    257  };
    258 
    259  struct MOZ_STACK_CLASS DrawParams {
    260    gfxContext* context;
    261    mozilla::gfx::PaletteCache& paletteCache;
    262    DrawMode drawMode = DrawMode::GLYPH_FILL;
    263    nscolor textStrokeColor = 0;
    264    nsAtom* fontPalette = nullptr;
    265    gfxPattern* textStrokePattern = nullptr;
    266    const mozilla::gfx::StrokeOptions* strokeOpts = nullptr;
    267    const mozilla::gfx::DrawOptions* drawOpts = nullptr;
    268    const PropertyProvider* provider = nullptr;
    269    // If non-null, the advance width of the substring is set.
    270    gfxFloat* advanceWidth = nullptr;
    271    mozilla::SVGContextPaint* contextPaint = nullptr;
    272    gfxTextRunDrawCallbacks* callbacks = nullptr;
    273    bool allowGDI = true;
    274    bool hasTextShadow = false;
    275    DrawParams(gfxContext* aContext, mozilla::gfx::PaletteCache& aPaletteCache)
    276        : context(aContext), paletteCache(aPaletteCache) {}
    277  };
    278 
    279  /**
    280   * Draws a substring. Uses only GetSpacing from aBreakProvider.
    281   * The provided point is the baseline origin on the left of the string
    282   * for LTR, on the right of the string for RTL.
    283   *
    284   * Drawing should respect advance widths in the sense that for LTR runs,
    285   *   Draw(Range(start, middle), pt, ...) followed by
    286   *   Draw(Range(middle, end), gfxPoint(pt.x + advance, pt.y), ...)
    287   * should have the same effect as
    288   *   Draw(Range(start, end), pt, ...)
    289   *
    290   * For RTL runs the rule is:
    291   *   Draw(Range(middle, end), pt, ...) followed by
    292   *   Draw(Range(start, middle), gfxPoint(pt.x + advance, pt.y), ...)
    293   * should have the same effect as
    294   *   Draw(Range(start, end), pt, ...)
    295   *
    296   * Glyphs should be drawn in logical content order, which can be significant
    297   * if they overlap (perhaps due to negative spacing).
    298   */
    299  void Draw(const Range aRange, const mozilla::gfx::Point aPt,
    300            const DrawParams& aParams) const;
    301 
    302  /**
    303   * Draws the emphasis marks for this text run. Uses only GetSpacing
    304   * from aProvider. The provided point is the baseline origin of the
    305   * line of emphasis marks.
    306   */
    307  void DrawEmphasisMarks(gfxContext* aContext, gfxTextRun* aMark,
    308                         gfxFloat aMarkAdvance, mozilla::gfx::Point aPt,
    309                         Range aRange, const PropertyProvider* aProvider,
    310                         mozilla::gfx::PaletteCache& aPaletteCache) const;
    311 
    312  /**
    313   * Computes the ReflowMetrics for a substring.
    314   * Uses GetSpacing from aBreakProvider.
    315   * @param aBoundingBoxType which kind of bounding box (loose/tight)
    316   */
    317  Metrics MeasureText(Range aRange, gfxFont::BoundingBoxType aBoundingBoxType,
    318                      DrawTarget* aDrawTargetForTightBoundingBox,
    319                      const PropertyProvider* aProvider) const;
    320 
    321  Metrics MeasureText(gfxFont::BoundingBoxType aBoundingBoxType,
    322                      DrawTarget* aDrawTargetForTightBoundingBox,
    323                      const PropertyProvider* aProvider = nullptr) const {
    324    return MeasureText(Range(this), aBoundingBoxType,
    325                       aDrawTargetForTightBoundingBox, aProvider);
    326  }
    327 
    328  void GetLineHeightMetrics(Range aRange, gfxFloat& aAscent,
    329                            gfxFloat& aDescent) const;
    330  void GetLineHeightMetrics(gfxFloat& aAscent, gfxFloat& aDescent) const {
    331    GetLineHeightMetrics(Range(this), aAscent, aDescent);
    332  }
    333 
    334  /**
    335   * Computes just the advance width for a substring.
    336   * Uses GetSpacing from aBreakProvider.
    337   * If aSpacing is not null, the spacing attached before and after
    338   * the substring would be returned in it. NOTE: the spacing is
    339   * included in the advance width.
    340   */
    341  gfxFloat GetAdvanceWidth(Range aRange, const PropertyProvider* aProvider,
    342                           PropertyProvider::Spacing* aSpacing = nullptr) const;
    343 
    344  gfxFloat GetAdvanceWidth() const {
    345    return GetAdvanceWidth(Range(this), nullptr);
    346  }
    347 
    348  /**
    349   * Computes the minimum advance width for a substring assuming line
    350   * breaking is allowed everywhere.
    351   */
    352  gfxFloat GetMinAdvanceWidth(Range aRange);
    353 
    354  /**
    355   * Clear all stored line breaks for the given range (both before and after),
    356   * and then set the line-break state before aRange.start to aBreakBefore and
    357   * after the last cluster to aBreakAfter.
    358   *
    359   * We require that before and after line breaks be consistent. For clusters
    360   * i and i+1, we require that if there is a break after cluster i, a break
    361   * will be specified before cluster i+1. This may be temporarily violated
    362   * (e.g. after reflowing line L and before reflowing line L+1); to handle
    363   * these temporary violations, we say that there is a break betwen i and i+1
    364   * if a break is specified after i OR a break is specified before i+1.
    365   *
    366   * This can change textrun geometry! The existence of a linebreak can affect
    367   * the advance width of the cluster before the break (when kerning) or the
    368   * geometry of one cluster before the break or any number of clusters
    369   * after the break. (The one-cluster-before-the-break limit is somewhat
    370   * arbitrary; if some scripts require breaking it, then we need to
    371   * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase
    372   * it could affect the layout of frames before it...)
    373   *
    374   * We return true if glyphs or geometry changed, false otherwise. This
    375   * function is virtual so that gfxTextRun subclasses can reshape
    376   * properly.
    377   *
    378   * @param aAdvanceWidthDelta if non-null, returns the change in advance
    379   * width of the given range.
    380   */
    381  virtual bool SetLineBreaks(Range aRange, bool aLineBreakBefore,
    382                             bool aLineBreakAfter,
    383                             gfxFloat* aAdvanceWidthDelta);
    384 
    385  enum SuppressBreak {
    386    eNoSuppressBreak,
    387    // Measure the range of text as if there is no break before it.
    388    eSuppressInitialBreak,
    389    // Measure the range of text as if it contains no break
    390    eSuppressAllBreaks
    391  };
    392 
    393  void ClassifyAutoHyphenations(uint32_t aStart, Range aRange,
    394                                nsTArray<HyphenType>& aHyphenBuffer,
    395                                HyphenationState* aWordState);
    396 
    397  // Struct used by BreakAndMeasureText to return the amount of trimmable
    398  // trailing whitespace included in the run.
    399  struct TrimmableWS {
    400    mozilla::gfx::Float mAdvance = 0;
    401    uint32_t mCount = 0;
    402  };
    403 
    404  /**
    405   * Finds the longest substring that will fit into the given width.
    406   * Uses GetHyphenationBreaks and GetSpacing from aProvider.
    407   * Guarantees the following:
    408   * -- 0 <= result <= aMaxLength
    409   * -- result is the maximal value of N such that either
    410   *       N < aMaxLength && line break at N &&
    411   *       GetAdvanceWidth(Range(aStart, N), aProvider) <= aWidth
    412   *   OR  N < aMaxLength && hyphen break at N &&
    413   *       GetAdvanceWidth(Range(aStart, N), aProvider) +
    414   *       GetHyphenWidth() <= aWidth
    415   *   OR  N == aMaxLength &&
    416   *       GetAdvanceWidth(Range(aStart, N), aProvider) <= aWidth
    417   * where GetAdvanceWidth assumes the effect of
    418   * SetLineBreaks(Range(aStart, N),
    419   *               aLineBreakBefore, N < aMaxLength, aProvider)
    420   * -- if no such N exists, then result is the smallest N such that
    421   *       N < aMaxLength && line break at N
    422   *   OR  N < aMaxLength && hyphen break at N
    423   *   OR  N == aMaxLength
    424   *
    425   * The call has the effect of
    426   * SetLineBreaks(Range(aStart, result), aLineBreakBefore,
    427   *               result < aMaxLength, aProvider)
    428   * and the returned metrics and the invariants above reflect this.
    429   *
    430   * @param aMaxLength this can be UINT32_MAX, in which case the length used
    431   * is up to the end of the string
    432   * @param aLineBreakBefore set to true if and only if there is an actual
    433   * line break at the start of this string.
    434   * @param aSuppressBreak what break should be suppressed.
    435   * @param aOutTrimmableWhitespace if non-null, returns the advance of any
    436   * run of trailing spaces that might be trimmed if the run ends up at
    437   * end-of-line.
    438   * Trimmable spaces are still counted in the "characters fit" result, and
    439   * contribute to the returned Metrics values.
    440   * @param aOutMetrics we fill this in for the returned substring.
    441   * If a hyphenation break was used, the hyphen is NOT included in the returned
    442   * metrics.
    443   * @param aBoundingBoxType whether to make the bounding box in aMetrics tight
    444   * @param aRefDrawTarget a reference DrawTarget to get the tight bounding box,
    445   * if requested
    446   * @param aOutUsedHyphenation records if we selected a hyphenation break
    447   * @param aOutLastBreak if result is aMaxLength, we set this to
    448   * the maximal N such that
    449   *       N < aMaxLength && line break at N &&
    450   *       GetAdvanceWidth(Range(aStart, N), aProvider) <= aWidth
    451   *   OR  N < aMaxLength && hyphen break at N &&
    452   *       GetAdvanceWidth(Range(aStart, N), aProvider) +
    453   *         GetHyphenWidth() <= aWidth
    454   * or UINT32_MAX if no such N exists, where GetAdvanceWidth assumes
    455   * the effect of
    456   * SetLineBreaks(Range(aStart, N), aLineBreakBefore,
    457   *               N < aMaxLength, aProvider)
    458   *
    459   * @param aCanWordWrap true if we can break between any two grapheme
    460   * clusters. This is set by overflow-wrap|word-wrap: break-word
    461   *
    462   * @param aBreakPriority in/out the priority of the break opportunity
    463   * saved in the line. If we are prioritizing break opportunities, we will
    464   * not set a break with a lower priority. @see gfxBreakPriority.
    465   *
    466   * Note that negative advance widths are possible especially if negative
    467   * spacing is provided.
    468   */
    469  uint32_t BreakAndMeasureText(
    470      uint32_t aStart, uint32_t aMaxLength, bool aLineBreakBefore,
    471      gfxFloat aWidth, const PropertyProvider& aProvider,
    472      SuppressBreak aSuppressBreak, gfxFont::BoundingBoxType aBoundingBoxType,
    473      DrawTarget* aRefDrawTarget, bool aCanWordWrap, bool aCanWhitespaceWrap,
    474      bool aIsBreakSpaces,
    475      // Output parameters:
    476      TrimmableWS* aOutTrimmableWhitespace,  // may be null
    477      Metrics& aOutMetrics, bool& aOutUsedHyphenation, uint32_t& aOutLastBreak,
    478      // In/out:
    479      gfxBreakPriority& aBreakPriority);
    480 
    481  // Utility getters
    482 
    483  void* GetUserData() const { return mUserData; }
    484  void SetUserData(void* aUserData) { mUserData = aUserData; }
    485 
    486  void SetFlagBits(nsTextFrameUtils::Flags aFlags) { mFlags2 |= aFlags; }
    487  void ClearFlagBits(nsTextFrameUtils::Flags aFlags) { mFlags2 &= ~aFlags; }
    488  const gfxSkipChars& GetSkipChars() const { return mSkipChars; }
    489  gfxFontGroup* GetFontGroup() const { return mFontGroup; }
    490 
    491  // Call this, don't call "new gfxTextRun" directly. This does custom
    492  // allocation and initialization
    493  static already_AddRefed<gfxTextRun> Create(
    494      const gfxTextRunFactory::Parameters* aParams, uint32_t aLength,
    495      gfxFontGroup* aFontGroup, mozilla::gfx::ShapedTextFlags aFlags,
    496      nsTextFrameUtils::Flags aFlags2);
    497 
    498  // The text is divided into GlyphRuns as necessary. (In the vast majority
    499  // of cases, a gfxTextRun contains just a single GlyphRun.)
    500  struct GlyphRun {
    501    RefPtr<gfxFont> mFont;      // never null in a valid GlyphRun
    502    uint32_t mCharacterOffset;  // into original UTF16 string
    503    mozilla::gfx::ShapedTextFlags
    504        mOrientation;  // gfxTextRunFactory::TEXT_ORIENT_* value
    505    FontMatchType mMatchType;
    506    bool mIsCJK;  // Whether the text was a CJK script run (used to decide if
    507                  // text-decoration-skip-ink should not be applied)
    508 
    509    // Set up the properties (but NOT offset) of the GlyphRun.
    510    void SetProperties(gfxFont* aFont,
    511                       mozilla::gfx::ShapedTextFlags aOrientation, bool aIsCJK,
    512                       FontMatchType aMatchType) {
    513      mFont = aFont;
    514      mOrientation = aOrientation;
    515      mIsCJK = aIsCJK;
    516      mMatchType = aMatchType;
    517    }
    518 
    519    // Return whether the GlyphRun matches the given properties;
    520    // the given FontMatchType will be added to the run if not present.
    521    bool Matches(gfxFont* aFont, mozilla::gfx::ShapedTextFlags aOrientation,
    522                 bool aIsCJK, FontMatchType aMatchType) {
    523      if (mFont == aFont && mOrientation == aOrientation && mIsCJK == aIsCJK) {
    524        mMatchType.kind |= aMatchType.kind;
    525        if (mMatchType.generic == mozilla::StyleGenericFontFamily::None) {
    526          mMatchType.generic = aMatchType.generic;
    527        }
    528        return true;
    529      }
    530      return false;
    531    }
    532 
    533    bool IsSidewaysLeft() const {
    534      return (mOrientation & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK) ==
    535             mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT;
    536    }
    537 
    538    bool IsSidewaysRight() const {
    539      return (mOrientation & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK) ==
    540             mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT;
    541    }
    542  };
    543 
    544  // Script run codes that we will mark as CJK to suppress skip-ink behavior.
    545  static inline bool IsCJKScript(Script aScript) {
    546    switch (aScript) {
    547      case Script::BOPOMOFO:
    548      case Script::HAN:
    549      case Script::HANGUL:
    550      case Script::HIRAGANA:
    551      case Script::KATAKANA:
    552      case Script::KATAKANA_OR_HIRAGANA:
    553      case Script::SIMPLIFIED_HAN:
    554      case Script::TRADITIONAL_HAN:
    555      case Script::TRADITIONAL_HAN_WITH_LATIN:
    556      case Script::JAPANESE:
    557      case Script::KOREAN:
    558      case Script::HAN_WITH_BOPOMOFO:
    559      case Script::JAMO:
    560        return true;
    561      default:
    562        return false;
    563    }
    564  }
    565 
    566  class MOZ_STACK_CLASS GlyphRunIterator {
    567   public:
    568    GlyphRunIterator(const gfxTextRun* aTextRun, Range aRange,
    569                     bool aReverse = false)
    570        : mTextRun(aTextRun),
    571          mStartOffset(aRange.start),
    572          mEndOffset(aRange.end),
    573          mReverse(aReverse) {
    574      mGlyphRun = mTextRun->FindFirstGlyphRunContaining(
    575          aReverse ? aRange.end - 1 : aRange.start);
    576      if (!mGlyphRun) {
    577        mStringEnd = mStringStart = mStartOffset;
    578        return;
    579      }
    580      uint32_t glyphRunEndOffset = mGlyphRun == mTextRun->mGlyphRuns.end() - 1
    581                                       ? mTextRun->GetLength()
    582                                       : (mGlyphRun + 1)->mCharacterOffset;
    583      mStringEnd = std::min(mEndOffset, glyphRunEndOffset);
    584      mStringStart = std::max(mStartOffset, mGlyphRun->mCharacterOffset);
    585    }
    586    void NextRun();
    587    bool AtEnd() const { return mGlyphRun == nullptr; }
    588    const struct GlyphRun* GlyphRun() const { return mGlyphRun; }
    589    uint32_t StringStart() const { return mStringStart; }
    590    uint32_t StringEnd() const { return mStringEnd; }
    591 
    592   private:
    593    const gfxTextRun* mTextRun;
    594    const struct GlyphRun* mGlyphRun;
    595    uint32_t mStringStart;
    596    uint32_t mStringEnd;
    597    uint32_t mStartOffset;
    598    uint32_t mEndOffset;
    599    bool mReverse;
    600  };
    601 
    602  class GlyphRunOffsetComparator {
    603   public:
    604    bool Equals(const GlyphRun& a, const GlyphRun& b) const {
    605      return a.mCharacterOffset == b.mCharacterOffset;
    606    }
    607 
    608    bool LessThan(const GlyphRun& a, const GlyphRun& b) const {
    609      return a.mCharacterOffset < b.mCharacterOffset;
    610    }
    611  };
    612 
    613  // API for setting up the textrun glyphs. Should only be called by
    614  // things that construct textruns.
    615  /**
    616   * We've found a run of text that should use a particular font. Call this
    617   * only during initialization when font substitution has been computed.
    618   * Call it before setting up the glyphs for the characters in this run;
    619   * SetMissingGlyph requires that the correct glyphrun be installed.
    620   *
    621   * If aForceNewRun, a new glyph run will be added, even if the
    622   * previously added run uses the same font.  If glyph runs are
    623   * added out of strictly increasing aStartCharIndex order (via
    624   * force), then SortGlyphRuns must be called after all glyph runs
    625   * are added before any further operations are performed with this
    626   * TextRun.
    627   */
    628  void AddGlyphRun(gfxFont* aFont, FontMatchType aMatchType,
    629                   uint32_t aUTF16Offset, bool aForceNewRun,
    630                   mozilla::gfx::ShapedTextFlags aOrientation, bool aIsCJK);
    631  void ResetGlyphRuns() { mGlyphRuns.Clear(); }
    632  void SanitizeGlyphRuns();
    633 
    634  const CompressedGlyph* GetCharacterGlyphs() const final {
    635    MOZ_ASSERT(mCharacterGlyphs, "failed to initialize mCharacterGlyphs");
    636    return mCharacterGlyphs;
    637  }
    638  CompressedGlyph* GetCharacterGlyphs() final {
    639    MOZ_ASSERT(mCharacterGlyphs, "failed to initialize mCharacterGlyphs");
    640    return mCharacterGlyphs;
    641  }
    642 
    643  // clean out results from shaping in progress, used for fallback scenarios
    644  void ClearGlyphsAndCharacters();
    645 
    646  void SetSpaceGlyph(gfxFont* aFont, DrawTarget* aDrawTarget,
    647                     uint32_t aCharIndex,
    648                     mozilla::gfx::ShapedTextFlags aOrientation);
    649 
    650  // Set the glyph data for the given character index to the font's
    651  // space glyph, IF this can be done as a "simple" glyph record
    652  // (not requiring a DetailedGlyph entry). This avoids the need to call
    653  // the font shaper and go through the shaped-word cache for most spaces.
    654  //
    655  // The parameter aSpaceChar is the original character code for which
    656  // this space glyph is being used; if this is U+0020, we need to record
    657  // that it could be trimmed at a run edge, whereas other kinds of space
    658  // (currently just U+00A0) would not be trimmable/breakable.
    659  //
    660  // Returns true if it was able to set simple glyph data for the space;
    661  // if it returns false, the caller needs to fall back to some other
    662  // means to create the necessary (detailed) glyph data.
    663  bool SetSpaceGlyphIfSimple(gfxFont* aFont, uint32_t aCharIndex,
    664                             char16_t aSpaceChar,
    665                             mozilla::gfx::ShapedTextFlags aOrientation);
    666 
    667  // Record the positions of specific characters that layout may need to
    668  // detect in the textrun, even though it doesn't have an explicit copy
    669  // of the original text. These are recorded using flag bits in the
    670  // CompressedGlyph record; if necessary, we convert "simple" glyph records
    671  // to "complex" ones as the Tab and Newline flags are not present in
    672  // simple CompressedGlyph records.
    673  void SetIsTab(uint32_t aIndex) { EnsureComplexGlyph(aIndex).SetIsTab(); }
    674  void SetIsNewline(uint32_t aIndex) {
    675    EnsureComplexGlyph(aIndex).SetIsNewline();
    676  }
    677  void SetNoEmphasisMark(uint32_t aIndex) {
    678    EnsureComplexGlyph(aIndex).SetNoEmphasisMark();
    679  }
    680  void SetIsFormattingControl(uint32_t aIndex) {
    681    EnsureComplexGlyph(aIndex).SetIsFormattingControl();
    682  }
    683 
    684  /**
    685   * Prefetch all the glyph extents needed to ensure that Measure calls
    686   * on this textrun not requesting tight boundingBoxes will succeed. Note
    687   * that some glyph extents might not be fetched due to OOM or other
    688   * errors.
    689   */
    690  void FetchGlyphExtents(DrawTarget* aRefDrawTarget) const;
    691 
    692  const GlyphRun* GetGlyphRuns(uint32_t* aNumGlyphRuns) const {
    693    *aNumGlyphRuns = mGlyphRuns.Length();
    694    return mGlyphRuns.begin();
    695  }
    696 
    697  uint32_t GlyphRunCount() const { return mGlyphRuns.Length(); }
    698 
    699  const GlyphRun* TrailingGlyphRun() const {
    700    return mGlyphRuns.IsEmpty() ? nullptr : mGlyphRuns.end() - 1;
    701  }
    702 
    703  // Returns the GlyphRun containing the given offset.
    704  // (Returns mGlyphRuns.end()-1 when aOffset is mCharacterCount; returns
    705  // nullptr if textrun is empty and no glyph runs are present.)
    706  const GlyphRun* FindFirstGlyphRunContaining(uint32_t aOffset) const;
    707 
    708  // Copy glyph data from a ShapedWord into this textrun.
    709  void CopyGlyphDataFrom(gfxShapedWord* aSource, uint32_t aStart);
    710 
    711  // Copy glyph data for a range of characters from aSource to this
    712  // textrun.
    713  void CopyGlyphDataFrom(gfxTextRun* aSource, Range aRange, uint32_t aDest);
    714 
    715  // Tell the textrun to release its reference to its creating gfxFontGroup
    716  // immediately, rather than on destruction. This is used for textruns
    717  // that are actually owned by a gfxFontGroup, so that they don't keep it
    718  // permanently alive due to a circular reference. (The caller of this is
    719  // taking responsibility for ensuring the textrun will not outlive its
    720  // mFontGroup.)
    721  void ReleaseFontGroup();
    722 
    723  struct LigatureData {
    724    // textrun range of the containing ligature
    725    Range mRange;
    726    // appunits advance to the start of the ligature part within the ligature;
    727    // never includes any spacing
    728    gfxFloat mPartAdvance;
    729    // appunits width of the ligature part; includes before-spacing
    730    // when the part is at the start of the ligature, and after-spacing
    731    // when the part is as the end of the ligature
    732    gfxFloat mPartWidth;
    733 
    734    bool mClipBeforePart;
    735    bool mClipAfterPart;
    736  };
    737 
    738  // return storage used by this run, for memory reporter;
    739  // nsTransformedTextRun needs to override this as it holds additional data
    740  virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
    741      MOZ_MUST_OVERRIDE;
    742  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
    743      MOZ_MUST_OVERRIDE;
    744 
    745  nsTextFrameUtils::Flags GetFlags2() const { return mFlags2; }
    746 
    747  // Get the size, if it hasn't already been gotten, marking as it goes.
    748  size_t MaybeSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
    749    if (mFlags2 & nsTextFrameUtils::Flags::RunSizeAccounted) {
    750      return 0;
    751    }
    752    mFlags2 |= nsTextFrameUtils::Flags::RunSizeAccounted;
    753    return SizeOfIncludingThis(aMallocSizeOf);
    754  }
    755  void ResetSizeOfAccountingFlags() {
    756    mFlags2 &= ~nsTextFrameUtils::Flags::RunSizeAccounted;
    757  }
    758 
    759  // shaping state - for some font features, fallback is required that
    760  // affects the entire run. for example, fallback for one script/font
    761  // portion of a textrun requires fallback to be applied to the entire run
    762 
    763  enum ShapingState : uint8_t {
    764    eShapingState_Normal,               // default state
    765    eShapingState_ShapingWithFeature,   // have shaped with feature
    766    eShapingState_ShapingWithFallback,  // have shaped with fallback
    767    eShapingState_Aborted,              // abort initial iteration
    768    eShapingState_ForceFallbackFeature  // redo with fallback forced on
    769  };
    770 
    771  ShapingState GetShapingState() const { return mShapingState; }
    772  void SetShapingState(ShapingState aShapingState) {
    773    mShapingState = aShapingState;
    774  }
    775 
    776  int32_t GetAdvanceForGlyph(uint32_t aIndex) const {
    777    const CompressedGlyph& glyphData = mCharacterGlyphs[aIndex];
    778    if (glyphData.IsSimpleGlyph()) {
    779      return glyphData.GetSimpleAdvance();
    780    }
    781    uint32_t glyphCount = glyphData.GetGlyphCount();
    782    if (!glyphCount) {
    783      return 0;
    784    }
    785    const DetailedGlyph* details = GetDetailedGlyphs(aIndex);
    786    int32_t advance = 0;
    787    for (uint32_t j = 0; j < glyphCount; ++j, ++details) {
    788      advance += details->mAdvance;
    789    }
    790    return advance;
    791  }
    792 
    793 #ifdef DEBUG_FRAME_DUMP
    794  void Dump(FILE* aOutput = stderr);
    795 #endif
    796 
    797 protected:
    798  /**
    799   * Create a textrun, and set its mCharacterGlyphs to point immediately
    800   * after the base object; this is ONLY used in conjunction with placement
    801   * new, after allocating a block large enough for the glyph records to
    802   * follow the base textrun object.
    803   */
    804  gfxTextRun(const gfxTextRunFactory::Parameters* aParams, uint32_t aLength,
    805             gfxFontGroup* aFontGroup, mozilla::gfx::ShapedTextFlags aFlags,
    806             nsTextFrameUtils::Flags aFlags2);
    807 
    808  // Whether we need to fetch actual glyph extents from the fonts.
    809  bool NeedsGlyphExtents() const;
    810 
    811  /**
    812   * Helper for the Create() factory method to allocate the required
    813   * glyph storage for a textrun object with the basic size aSize,
    814   * plus room for aLength glyph records.
    815   */
    816  static void* AllocateStorageForTextRun(size_t aSize, uint32_t aLength);
    817 
    818  // Pointer to the array of CompressedGlyph records; must be initialized
    819  // when the object is constructed.
    820  CompressedGlyph* mCharacterGlyphs;
    821 
    822 private:
    823  // **** general helpers ****
    824 
    825  // Get the total advance for a range of glyphs.
    826  int32_t GetAdvanceForGlyphs(Range aRange) const;
    827 
    828  // Spacing for characters outside the range aSpacingStart/aSpacingEnd
    829  // is assumed to be zero; such characters are not passed to aProvider.
    830  // This is useful to protect aProvider from being passed character indices
    831  // it is not currently able to handle.
    832  bool GetAdjustedSpacingArray(
    833      Range aRange, const PropertyProvider* aProvider, Range aSpacingRange,
    834      nsTArray<PropertyProvider::Spacing>* aSpacing) const;
    835 
    836  CompressedGlyph& EnsureComplexGlyph(uint32_t aIndex) {
    837    gfxShapedText::EnsureComplexGlyph(aIndex, mCharacterGlyphs[aIndex]);
    838    return mCharacterGlyphs[aIndex];
    839  }
    840 
    841  //  **** ligature helpers ****
    842  // (Platforms do the actual ligaturization, but we need to do a bunch of stuff
    843  // to handle requests that begin or end inside a ligature)
    844 
    845  // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
    846  LigatureData ComputeLigatureData(Range aPartRange,
    847                                   const PropertyProvider* aProvider) const;
    848  gfxFloat ComputePartialLigatureWidth(Range aPartRange,
    849                                       const PropertyProvider* aProvider) const;
    850  void DrawPartialLigature(gfxFont* aFont, Range aRange,
    851                           mozilla::gfx::Point* aPt,
    852                           const PropertyProvider* aProvider,
    853                           TextRunDrawParams& aParams,
    854                           mozilla::gfx::ShapedTextFlags aOrientation) const;
    855  // Advance aRange.start to the start of the nearest ligature, back
    856  // up aRange.end to the nearest ligature end; may result in
    857  // aRange->start == aRange->end.
    858  // Returns whether any adjustment was made.
    859  bool ShrinkToLigatureBoundaries(Range* aRange) const;
    860  // result in appunits
    861  gfxFloat GetPartialLigatureWidth(Range aRange,
    862                                   const PropertyProvider* aProvider) const;
    863  void AccumulatePartialLigatureMetrics(
    864      gfxFont* aFont, Range aRange, gfxFont::BoundingBoxType aBoundingBoxType,
    865      DrawTarget* aRefDrawTarget, const PropertyProvider* aProvider,
    866      mozilla::gfx::ShapedTextFlags aOrientation, Metrics* aMetrics) const;
    867 
    868  // **** measurement helper ****
    869  void AccumulateMetricsForRun(gfxFont* aFont, Range aRange,
    870                               gfxFont::BoundingBoxType aBoundingBoxType,
    871                               DrawTarget* aRefDrawTarget,
    872                               const PropertyProvider* aProvider,
    873                               Range aSpacingRange,
    874                               mozilla::gfx::ShapedTextFlags aOrientation,
    875                               Metrics* aMetrics) const;
    876 
    877  // **** drawing helper ****
    878  void DrawGlyphs(gfxFont* aFont, Range aRange, mozilla::gfx::Point* aPt,
    879                  const PropertyProvider* aProvider, Range aSpacingRange,
    880                  TextRunDrawParams& aParams,
    881                  mozilla::gfx::ShapedTextFlags aOrientation) const;
    882 
    883  // The textrun holds either a single GlyphRun -or- an array.
    884  mozilla::ElementOrArray<GlyphRun> mGlyphRuns;
    885 
    886  void* mUserData;
    887 
    888  // mFontGroup is usually a strong reference, but refcounting is managed
    889  // manually because it may be explicitly released by ReleaseFontGroup()
    890  // in the case where the font group actually owns the textrun.
    891  gfxFontGroup* MOZ_OWNING_REF mFontGroup;
    892 
    893  gfxSkipChars mSkipChars;
    894 
    895  nsTextFrameUtils::Flags
    896      mFlags2;  // additional flags (see also gfxShapedText::mFlags)
    897 
    898  bool mDontSkipDrawing;  // true if the text run must not skip drawing, even if
    899                          // waiting for a user font download, e.g. because we
    900                          // are using it to draw canvas text
    901  bool mReleasedFontGroup;                // we already called NS_RELEASE on
    902                                          // mFontGroup, so don't do it again
    903  bool mReleasedFontGroupSkippedDrawing;  // whether our old mFontGroup value
    904                                          // was set to skip drawing
    905 
    906  // shaping state for handling variant fallback features
    907  // such as subscript/superscript variant glyphs
    908  ShapingState mShapingState;
    909 };
    910 
    911 class gfxFontGroup final : public gfxTextRunFactory {
    912 public:
    913  typedef mozilla::intl::Script Script;
    914  typedef gfxShapedText::CompressedGlyph CompressedGlyph;
    915  friend class MathMLTextRunFactory;
    916  friend class nsCaseTransformTextRunFactory;
    917 
    918  static void
    919  Shutdown();  // platform must call this to release the languageAtomService
    920 
    921  gfxFontGroup(FontVisibilityProvider* aFontVisibilityProvider,
    922               const mozilla::StyleFontFamilyList& aFontFamilyList,
    923               const gfxFontStyle* aStyle, nsAtom* aLanguage,
    924               bool aExplicitLanguage, gfxTextPerfMetrics* aTextPerf,
    925               gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize,
    926               StyleFontVariantEmoji aVariantEmoji);
    927 
    928  virtual ~gfxFontGroup();
    929 
    930  gfxFontGroup(const gfxFontGroup& aOther) = delete;
    931 
    932  // Returns first valid font in the fontlist or default font.
    933  // Initiates userfont loads if userfont not loaded.
    934  // aCh: character to look for, or kCSSFirstAvailableFont for default "first
    935  //      available font" as defined by CSS Fonts (i.e. the first font whose
    936  //      unicode-range includes <space>, but does not require space to
    937  //      actually be present)
    938  // aGeneric: if non-null, returns the CSS generic type that was mapped to
    939  //           this font
    940  // aIsFirst: if non-null, returns whether the font was first in the list
    941  static constexpr uint32_t kCSSFirstAvailableFont = UINT32_MAX;
    942  already_AddRefed<gfxFont> GetFirstValidFont(
    943      uint32_t aCh = kCSSFirstAvailableFont,
    944      mozilla::StyleGenericFontFamily* aGeneric = nullptr,
    945      bool* aIsFirst = nullptr);
    946 
    947  // Returns the first font in the font-group that has an OpenType MATH table,
    948  // or null if no such font is available. The GetMathConstant methods may be
    949  // called on the returned font.
    950  already_AddRefed<gfxFont> GetFirstMathFont();
    951 
    952  const gfxFontStyle* GetStyle() const { return &mStyle; }
    953 
    954  // Get the presContext for which this fontGroup was constructed. This may be
    955  // null! (In the case of canvas not connected to a document.)
    956  FontVisibilityProvider* GetFontVisibilityProvider() const {
    957    return mFontVisibilityProvider;
    958  }
    959 
    960  /**
    961   * The listed characters should be treated as invisible and zero-width
    962   * when creating textruns.
    963   */
    964  static bool IsInvalidChar(uint8_t ch);
    965  static bool IsInvalidChar(char16_t ch);
    966 
    967  /**
    968   * Make a textrun for a given string.
    969   * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
    970   * textrun will copy it.
    971   * This calls FetchGlyphExtents on the textrun.
    972   */
    973  template <typename T>
    974  already_AddRefed<gfxTextRun> MakeTextRun(const T* aString, uint32_t aLength,
    975                                           const Parameters* aParams,
    976                                           mozilla::gfx::ShapedTextFlags aFlags,
    977                                           nsTextFrameUtils::Flags aFlags2,
    978                                           gfxMissingFontRecorder* aMFR);
    979 
    980  /**
    981   * Textrun creation helper for clients that don't want to pass
    982   * a full Parameters record.
    983   */
    984  template <typename T>
    985  already_AddRefed<gfxTextRun> MakeTextRun(const T* aString, uint32_t aLength,
    986                                           DrawTarget* aRefDrawTarget,
    987                                           int32_t aAppUnitsPerDevUnit,
    988                                           mozilla::gfx::ShapedTextFlags aFlags,
    989                                           nsTextFrameUtils::Flags aFlags2,
    990                                           gfxMissingFontRecorder* aMFR) {
    991    gfxTextRunFactory::Parameters params = {
    992        aRefDrawTarget, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit};
    993    return MakeTextRun(aString, aLength, &params, aFlags, aFlags2, aMFR);
    994  }
    995 
    996  // Get the (possibly-cached) width of the hyphen character.
    997  gfxFloat GetHyphenWidth(const gfxTextRun::PropertyProvider* aProvider);
    998 
    999  /**
   1000   * Make a text run representing a single hyphen character.
   1001   * This will use U+2010 HYPHEN if available in the first font,
   1002   * otherwise fall back to U+002D HYPHEN-MINUS.
   1003   * The caller is responsible for deleting the returned text run
   1004   * when no longer required.
   1005   */
   1006  already_AddRefed<gfxTextRun> MakeHyphenTextRun(
   1007      DrawTarget* aDrawTarget, mozilla::gfx::ShapedTextFlags aFlags,
   1008      uint32_t aAppUnitsPerDevUnit);
   1009 
   1010  /**
   1011   * Check whether a given font (specified by its gfxFontEntry)
   1012   * is already in the fontgroup's list of actual fonts
   1013   */
   1014  bool HasFont(const gfxFontEntry* aFontEntry);
   1015 
   1016  // This returns the preferred underline for this font group.
   1017  // Some CJK fonts have wrong underline offset in its metrics.
   1018  // If this group has such "bad" font, each platform's gfxFontGroup
   1019  // initialized mUnderlineOffset. The value should be lower value of
   1020  // first font's metrics and the bad font's metrics. Otherwise, this
   1021  // returns from first font's metrics.
   1022  static constexpr gfxFloat UNDERLINE_OFFSET_NOT_SET = INT16_MAX;
   1023  gfxFloat GetUnderlineOffset();
   1024 
   1025  already_AddRefed<gfxFont> FindFontForChar(uint32_t ch, uint32_t prevCh,
   1026                                            uint32_t aNextCh, Script aRunScript,
   1027                                            gfxFont* aPrevMatchedFont,
   1028                                            FontMatchType* aMatchType);
   1029 
   1030  gfxUserFontSet* GetUserFontSet();
   1031 
   1032  // With downloadable fonts, the composition of the font group can change as
   1033  // fonts are downloaded for each change in state of the user font set, the
   1034  // generation value is bumped to avoid picking up previously created text runs
   1035  // in the text run word cache.  For font groups based on stylesheets with no
   1036  // @font-face rule, this always returns 0.
   1037  uint64_t GetGeneration();
   1038 
   1039  // generation of the latest fontset rebuild, 0 when no fontset present
   1040  uint64_t GetRebuildGeneration();
   1041 
   1042  // used when logging text performance
   1043  gfxTextPerfMetrics* GetTextPerfMetrics() const { return mTextPerf; }
   1044 
   1045  // This will call UpdateUserFonts() if the user font set is changed.
   1046  void SetUserFontSet(gfxUserFontSet* aUserFontSet);
   1047 
   1048  void ClearCachedData() {
   1049    mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
   1050    mSkipDrawing = false;
   1051    mHyphenWidth = -1;
   1052    mCachedEllipsisTextRun = nullptr;
   1053  }
   1054 
   1055  // If there is a user font set, check to see whether the font list or any
   1056  // caches need updating.
   1057  void UpdateUserFonts();
   1058 
   1059  // search for a specific userfont in the list of fonts
   1060  bool ContainsUserFont(const gfxUserFontEntry* aUserFont);
   1061 
   1062  bool ShouldSkipDrawing() const { return mSkipDrawing; }
   1063 
   1064  class LazyReferenceDrawTargetGetter {
   1065   public:
   1066    virtual already_AddRefed<DrawTarget> GetRefDrawTarget() = 0;
   1067  };
   1068  // The gfxFontGroup keeps ownership of this textrun.
   1069  // It is only guaranteed to exist until the next call to GetEllipsisTextRun
   1070  // (which might use a different appUnitsPerDev value or flags) for the font
   1071  // group, or until UpdateUserFonts is called, or the fontgroup is destroyed.
   1072  // Get it/use it/forget it :) - don't keep a reference that might go stale.
   1073  gfxTextRun* GetEllipsisTextRun(
   1074      int32_t aAppUnitsPerDevPixel, mozilla::gfx::ShapedTextFlags aFlags,
   1075      LazyReferenceDrawTargetGetter& aRefDrawTargetGetter);
   1076 
   1077  nsAtom* Language() const { return mLanguage.get(); }
   1078 
   1079  // Get font metrics to be used as the basis for CSS font-relative units.
   1080  // Note that these may be a "composite" of metrics from multiple fonts,
   1081  // because the 'ch' and 'ic' units depend on the font that would be used
   1082  // to render specific characters, not simply the "first available" font.
   1083  // https://drafts.csswg.org/css-values-4/#ch
   1084  // https://drafts.csswg.org/css-values-4/#ic
   1085  // Whether extra font resources may be loaded to resolve 'ch' and 'ic'
   1086  // depends on the corresponding flags passed by the caller.
   1087  gfxFont::Metrics GetMetricsForCSSUnits(
   1088      gfxFont::Orientation aOrientation,
   1089      mozilla::StyleQueryFontMetricsFlags aFlags);
   1090 
   1091 protected:
   1092  friend class mozilla::PostTraversalTask;
   1093  friend class DeferredClearResolvedFonts;
   1094 
   1095  struct TextRange {
   1096    TextRange(uint32_t aStart, uint32_t aEnd, gfxFont* aFont,
   1097              FontMatchType aMatchType,
   1098              mozilla::gfx::ShapedTextFlags aOrientation)
   1099        : start(aStart),
   1100          end(aEnd),
   1101          font(aFont),
   1102          matchType(aMatchType),
   1103          orientation(aOrientation) {}
   1104    uint32_t Length() const { return end - start; }
   1105    uint32_t start, end;
   1106    RefPtr<gfxFont> font;
   1107    FontMatchType matchType;
   1108    mozilla::gfx::ShapedTextFlags orientation;
   1109  };
   1110 
   1111  // search through pref fonts for a character, return nullptr if no matching
   1112  // pref font
   1113  already_AddRefed<gfxFont> WhichPrefFontSupportsChar(
   1114      uint32_t aCh, uint32_t aNextCh, FontPresentation aPresentation);
   1115 
   1116  already_AddRefed<gfxFont> WhichSystemFontSupportsChar(
   1117      uint32_t aCh, uint32_t aNextCh, Script aRunScript,
   1118      FontPresentation aPresentation);
   1119 
   1120  template <typename T>
   1121  void ComputeRanges(nsTArray<TextRange>& aRanges, const T* aString,
   1122                     uint32_t aLength, Script aRunScript,
   1123                     mozilla::gfx::ShapedTextFlags aOrientation);
   1124 
   1125  class FamilyFace {
   1126   public:
   1127    FamilyFace()
   1128        : mOwnedFamily(nullptr),
   1129          mFontEntry(nullptr),
   1130          mGeneric(mozilla::StyleGenericFontFamily::None),
   1131          mFontCreated(false),
   1132          mLoading(false),
   1133          mInvalid(false),
   1134          mCheckForFallbackFaces(false),
   1135          mIsSharedFamily(false),
   1136          mHasFontEntry(false) {}
   1137 
   1138    FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont,
   1139               mozilla::StyleGenericFontFamily aGeneric)
   1140        : mOwnedFamily(aFamily),
   1141          mGeneric(aGeneric),
   1142          mFontCreated(true),
   1143          mLoading(false),
   1144          mInvalid(false),
   1145          mCheckForFallbackFaces(false),
   1146          mIsSharedFamily(false),
   1147          mHasFontEntry(false) {
   1148      NS_ASSERTION(aFont, "font pointer must not be null");
   1149      NS_ASSERTION(!aFamily || aFamily->ContainsFace(aFont->GetFontEntry()),
   1150                   "font is not a member of the given family");
   1151      NS_IF_ADDREF(aFamily);
   1152      mFont = aFont;
   1153      NS_ADDREF(aFont);
   1154    }
   1155 
   1156    FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry,
   1157               mozilla::StyleGenericFontFamily aGeneric)
   1158        : mOwnedFamily(aFamily),
   1159          mGeneric(aGeneric),
   1160          mFontCreated(false),
   1161          mLoading(false),
   1162          mInvalid(false),
   1163          mCheckForFallbackFaces(false),
   1164          mIsSharedFamily(false),
   1165          mHasFontEntry(true) {
   1166      NS_ASSERTION(aFontEntry, "font entry pointer must not be null");
   1167      NS_ASSERTION(!aFamily || aFamily->ContainsFace(aFontEntry),
   1168                   "font is not a member of the given family");
   1169      NS_IF_ADDREF(aFamily);
   1170      mFontEntry = aFontEntry;
   1171      NS_ADDREF(aFontEntry);
   1172    }
   1173 
   1174    FamilyFace(mozilla::fontlist::Family* aFamily, gfxFontEntry* aFontEntry,
   1175               mozilla::StyleGenericFontFamily aGeneric)
   1176        : mSharedFamily(aFamily),
   1177          mGeneric(aGeneric),
   1178          mFontCreated(false),
   1179          mLoading(false),
   1180          mInvalid(false),
   1181          mCheckForFallbackFaces(false),
   1182          mIsSharedFamily(true),
   1183          mHasFontEntry(true) {
   1184      MOZ_ASSERT(aFamily && aFontEntry && aFontEntry->mShmemFace);
   1185      mFontEntry = aFontEntry;
   1186      NS_ADDREF(aFontEntry);
   1187    }
   1188 
   1189    FamilyFace(const FamilyFace& aOtherFamilyFace)
   1190        : mGeneric(aOtherFamilyFace.mGeneric),
   1191          mFontCreated(aOtherFamilyFace.mFontCreated),
   1192          mLoading(aOtherFamilyFace.mLoading),
   1193          mInvalid(aOtherFamilyFace.mInvalid),
   1194          mCheckForFallbackFaces(aOtherFamilyFace.mCheckForFallbackFaces),
   1195          mIsSharedFamily(aOtherFamilyFace.mIsSharedFamily),
   1196          mHasFontEntry(aOtherFamilyFace.mHasFontEntry) {
   1197      if (mIsSharedFamily) {
   1198        mSharedFamily = aOtherFamilyFace.mSharedFamily;
   1199        if (mFontCreated) {
   1200          mFont = aOtherFamilyFace.mFont;
   1201          NS_ADDREF(mFont);
   1202        } else if (mHasFontEntry) {
   1203          mFontEntry = aOtherFamilyFace.mFontEntry;
   1204          NS_ADDREF(mFontEntry);
   1205        } else {
   1206          mSharedFace = aOtherFamilyFace.mSharedFace;
   1207        }
   1208      } else {
   1209        mOwnedFamily = aOtherFamilyFace.mOwnedFamily;
   1210        NS_IF_ADDREF(mOwnedFamily);
   1211        if (mFontCreated) {
   1212          mFont = aOtherFamilyFace.mFont;
   1213          NS_ADDREF(mFont);
   1214        } else {
   1215          mFontEntry = aOtherFamilyFace.mFontEntry;
   1216          NS_IF_ADDREF(mFontEntry);
   1217        }
   1218      }
   1219    }
   1220 
   1221    ~FamilyFace() {
   1222      if (mFontCreated) {
   1223        NS_RELEASE(mFont);
   1224      }
   1225      if (!mIsSharedFamily) {
   1226        NS_IF_RELEASE(mOwnedFamily);
   1227      }
   1228      if (mHasFontEntry) {
   1229        NS_RELEASE(mFontEntry);
   1230      }
   1231    }
   1232 
   1233    FamilyFace& operator=(const FamilyFace& aOther) {
   1234      if (mFontCreated) {
   1235        NS_RELEASE(mFont);
   1236      }
   1237      if (!mIsSharedFamily) {
   1238        NS_IF_RELEASE(mOwnedFamily);
   1239      }
   1240      if (mHasFontEntry) {
   1241        NS_RELEASE(mFontEntry);
   1242      }
   1243 
   1244      mGeneric = aOther.mGeneric;
   1245      mFontCreated = aOther.mFontCreated;
   1246      mLoading = aOther.mLoading;
   1247      mInvalid = aOther.mInvalid;
   1248      mIsSharedFamily = aOther.mIsSharedFamily;
   1249      mHasFontEntry = aOther.mHasFontEntry;
   1250 
   1251      if (mIsSharedFamily) {
   1252        mSharedFamily = aOther.mSharedFamily;
   1253        if (mFontCreated) {
   1254          mFont = aOther.mFont;
   1255          NS_ADDREF(mFont);
   1256        } else if (mHasFontEntry) {
   1257          mFontEntry = aOther.mFontEntry;
   1258          NS_ADDREF(mFontEntry);
   1259        } else {
   1260          mSharedFace = aOther.mSharedFace;
   1261        }
   1262      } else {
   1263        mOwnedFamily = aOther.mOwnedFamily;
   1264        NS_IF_ADDREF(mOwnedFamily);
   1265        if (mFontCreated) {
   1266          mFont = aOther.mFont;
   1267          NS_ADDREF(mFont);
   1268        } else {
   1269          mFontEntry = aOther.mFontEntry;
   1270          NS_IF_ADDREF(mFontEntry);
   1271        }
   1272      }
   1273 
   1274      return *this;
   1275    }
   1276 
   1277    gfxFontFamily* OwnedFamily() const {
   1278      MOZ_ASSERT(!mIsSharedFamily);
   1279      return mOwnedFamily;
   1280    }
   1281    mozilla::fontlist::Family* SharedFamily() const {
   1282      MOZ_ASSERT(mIsSharedFamily);
   1283      return mSharedFamily;
   1284    }
   1285    gfxFont* Font() const { return mFontCreated ? mFont : nullptr; }
   1286 
   1287    gfxFontEntry* FontEntry() const {
   1288      if (mFontCreated) {
   1289        return mFont->GetFontEntry();
   1290      }
   1291      if (mHasFontEntry) {
   1292        return mFontEntry;
   1293      }
   1294      if (mIsSharedFamily) {
   1295        return gfxPlatformFontList::PlatformFontList()->GetOrCreateFontEntry(
   1296            mSharedFace, SharedFamily());
   1297      }
   1298      return nullptr;
   1299    }
   1300 
   1301    mozilla::StyleGenericFontFamily Generic() const { return mGeneric; }
   1302 
   1303    bool IsSharedFamily() const { return mIsSharedFamily; }
   1304    bool IsUserFontContainer() const {
   1305      gfxFontEntry* fe = FontEntry();
   1306      return fe && fe->mIsUserFontContainer;
   1307    }
   1308    bool IsLoading() const { return mLoading; }
   1309    bool IsInvalid() const { return mInvalid; }
   1310    void CheckState(bool& aSkipDrawing);
   1311    void SetLoading(bool aIsLoading) { mLoading = aIsLoading; }
   1312    void SetInvalid() { mInvalid = true; }
   1313    bool CheckForFallbackFaces() const { return mCheckForFallbackFaces; }
   1314    void SetCheckForFallbackFaces() { mCheckForFallbackFaces = true; }
   1315 
   1316    // Return true if we're currently loading (or waiting for) a resource that
   1317    // may support the given character.
   1318    bool IsLoadingFor(uint32_t aCh) {
   1319      if (!IsLoading()) {
   1320        return false;
   1321      }
   1322      MOZ_ASSERT(IsUserFontContainer());
   1323      auto* ufe = static_cast<gfxUserFontEntry*>(FontEntry());
   1324      return ufe && ufe->CharacterInUnicodeRange(aCh);
   1325    }
   1326 
   1327    void SetFont(gfxFont* aFont) {
   1328      NS_ASSERTION(aFont, "font pointer must not be null");
   1329      NS_ADDREF(aFont);
   1330      if (mFontCreated) {
   1331        NS_RELEASE(mFont);
   1332      } else if (mHasFontEntry) {
   1333        NS_RELEASE(mFontEntry);
   1334        mHasFontEntry = false;
   1335      }
   1336      mFont = aFont;
   1337      mFontCreated = true;
   1338      mLoading = false;
   1339    }
   1340 
   1341    bool EqualsUserFont(const gfxUserFontEntry* aUserFont) const;
   1342 
   1343   private:
   1344    union {
   1345      gfxFontFamily* MOZ_OWNING_REF mOwnedFamily;
   1346      mozilla::fontlist::Family* MOZ_NON_OWNING_REF mSharedFamily;
   1347    };
   1348    // either a font or a font entry exists
   1349    union {
   1350      // Whichever of these fields is actually present will be a strong
   1351      // reference, with refcounting handled manually.
   1352      gfxFont* MOZ_OWNING_REF mFont;
   1353      gfxFontEntry* MOZ_OWNING_REF mFontEntry;
   1354      mozilla::fontlist::Face* MOZ_NON_OWNING_REF mSharedFace;
   1355    };
   1356    mozilla::StyleGenericFontFamily mGeneric;
   1357    bool mFontCreated : 1;
   1358    bool mLoading : 1;
   1359    bool mInvalid : 1;
   1360    bool mCheckForFallbackFaces : 1;
   1361    bool mIsSharedFamily : 1;
   1362    bool mHasFontEntry : 1;
   1363  };
   1364 
   1365  FontVisibilityProvider* mFontVisibilityProvider = nullptr;
   1366 
   1367  // List of font families, either named or generic.
   1368  // Generic names map to system pref fonts based on language.
   1369  mozilla::StyleFontFamilyList mFamilyList;
   1370 
   1371  // Fontlist containing a font entry for each family found. gfxFont objects
   1372  // are created as needed and userfont loads are initiated when needed.
   1373  // Code should be careful about addressing this array directly.
   1374  nsTArray<FamilyFace> mFonts;
   1375 
   1376  RefPtr<gfxFont> mDefaultFont;
   1377  gfxFontStyle mStyle;
   1378 
   1379  RefPtr<nsAtom> mLanguage;
   1380 
   1381  gfxFloat mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
   1382  gfxFloat mHyphenWidth = -1.0;  // negative indicates not yet measured
   1383  gfxFloat mDevToCssSize;
   1384 
   1385  RefPtr<gfxUserFontSet> mUserFontSet;
   1386  uint64_t mCurrGeneration = 0;  // track the current user font set generation,
   1387                                 // rebuild font list if needed
   1388 
   1389  gfxTextPerfMetrics* mTextPerf;
   1390 
   1391  // Cache a textrun representing an ellipsis (useful for CSS text-overflow)
   1392  // at a specific appUnitsPerDevPixel size and orientation
   1393  RefPtr<gfxTextRun> mCachedEllipsisTextRun;
   1394 
   1395  // cache the most recent pref font to avoid general pref font lookup
   1396  FontFamily mLastPrefFamily;
   1397  RefPtr<gfxFont> mLastPrefFont;
   1398  eFontPrefLang mLastPrefLang = eFontPrefLang_Western;  // lang group for last
   1399                                                        // pref font
   1400  eFontPrefLang mPageLang;
   1401  bool mLastPrefFirstFont;  // is this the first font in the list of pref fonts
   1402                            // for this lang group?
   1403 
   1404  bool mSkipDrawing = false;  // hide text while waiting for a font
   1405                              // download to complete (or fallback
   1406                              // timer to fire)
   1407 
   1408  bool mExplicitLanguage = false;  // Is mLanguage from an explicit attribute?
   1409 
   1410  bool mResolvedFonts = false;  // Whether the mFonts array has been set up.
   1411 
   1412  StyleFontVariantEmoji mFontVariantEmoji = StyleFontVariantEmoji::Normal;
   1413 
   1414  // Generic font family used to select among font prefs during fallback.
   1415  mozilla::StyleGenericFontFamily mFallbackGeneric =
   1416      mozilla::StyleGenericFontFamily::None;
   1417 
   1418  uint32_t mFontListGeneration = 0;  // platform font list generation for this
   1419                                     // fontgroup
   1420 
   1421  /**
   1422   * Textrun creation short-cuts for special cases where we don't need to
   1423   * call a font shaper to generate glyphs.
   1424   */
   1425  already_AddRefed<gfxTextRun> MakeEmptyTextRun(
   1426      const Parameters* aParams, mozilla::gfx::ShapedTextFlags aFlags,
   1427      nsTextFrameUtils::Flags aFlags2);
   1428 
   1429  already_AddRefed<gfxTextRun> MakeSpaceTextRun(
   1430      const Parameters* aParams, mozilla::gfx::ShapedTextFlags aFlags,
   1431      nsTextFrameUtils::Flags aFlags2);
   1432 
   1433  template <typename T>
   1434  already_AddRefed<gfxTextRun> MakeBlankTextRun(
   1435      const T* aString, uint32_t aLength, const Parameters* aParams,
   1436      mozilla::gfx::ShapedTextFlags aFlags, nsTextFrameUtils::Flags aFlags2);
   1437 
   1438  // Ensure the font-family list & style properties from CSS/prefs/defaults is
   1439  // resolved to the array of available font faces we'll actually use.
   1440  void EnsureFontList();
   1441 
   1442  // Get the font at index i within the fontlist, for character aCh (in case
   1443  // of fonts with multiple resources and unicode-range partitioning).
   1444  // Will initiate userfont load if not already loaded.
   1445  // May return null if userfont not loaded or if font invalid.
   1446  // If *aLoading is true, a relevant resource is already being loaded so no
   1447  // new download will be initiated; if a download is started, *aLoading will
   1448  // be set to true on return.
   1449  already_AddRefed<gfxFont> GetFontAt(uint32_t i, uint32_t aCh, bool* aLoading);
   1450 
   1451  // Simplified version of GetFontAt() for use where we just need a font for
   1452  // metrics, math layout tables, etc.
   1453  already_AddRefed<gfxFont> GetFontAt(uint32_t i, uint32_t aCh = 0x20) {
   1454    bool loading = false;
   1455    return GetFontAt(i, aCh, &loading);
   1456  }
   1457 
   1458  // will always return a font or force a shutdown
   1459  already_AddRefed<gfxFont> GetDefaultFont();
   1460 
   1461  // Init this font group's font metrics. If there no bad fonts, you don't need
   1462  // to call this. But if there are one or more bad fonts which have bad
   1463  // underline offset, you should call this with the *first* bad font.
   1464  void InitMetricsForBadFont(gfxFont* aBadFont);
   1465 
   1466  // Set up the textrun glyphs for an entire text run:
   1467  // find script runs, and then call InitScriptRun for each
   1468  template <typename T>
   1469  void InitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
   1470                   const T* aString, uint32_t aLength,
   1471                   gfxMissingFontRecorder* aMFR);
   1472 
   1473  // InitTextRun helper to handle a single script run, by finding font ranges
   1474  // and calling each font's InitTextRun() as appropriate
   1475  template <typename T>
   1476  void InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
   1477                     const T* aString, uint32_t aScriptRunStart,
   1478                     uint32_t aScriptRunEnd, Script aRunScript,
   1479                     gfxMissingFontRecorder* aMFR);
   1480 
   1481  // Helper for font-matching:
   1482  // search all faces in a family for a fallback in cases where it's unclear
   1483  // whether the family might have a font for a given character
   1484  already_AddRefed<gfxFont> FindFallbackFaceForChar(
   1485      const FamilyFace& aFamily, uint32_t aCh, uint32_t aNextCh,
   1486      FontPresentation aPresentation);
   1487 
   1488  already_AddRefed<gfxFont> FindFallbackFaceForChar(
   1489      mozilla::fontlist::Family* aFamily, uint32_t aCh, uint32_t aNextCh,
   1490      FontPresentation aPresentation);
   1491 
   1492  already_AddRefed<gfxFont> FindFallbackFaceForChar(
   1493      gfxFontFamily* aFamily, uint32_t aCh, uint32_t aNextCh,
   1494      FontPresentation aPresentation);
   1495 
   1496  // helper methods for looking up fonts
   1497 
   1498  // lookup and add a font with a given name (i.e. *not* a generic!)
   1499  void AddPlatformFont(const nsACString& aName, bool aQuotedName,
   1500                       nsTArray<FamilyAndGeneric>& aFamilyList);
   1501 
   1502  // do style selection and add entries to list
   1503  void AddFamilyToFontList(gfxFontFamily* aFamily,
   1504                           mozilla::StyleGenericFontFamily aGeneric);
   1505  void AddFamilyToFontList(mozilla::fontlist::Family* aFamily,
   1506                           mozilla::StyleGenericFontFamily aGeneric);
   1507 };
   1508 
   1509 // A "missing font recorder" is to be used during text-run creation to keep
   1510 // a record of any scripts encountered for which font coverage was lacking;
   1511 // when Flush() is called, it sends a notification that front-end code can use
   1512 // to download fonts on demand (or whatever else it wants to do).
   1513 
   1514 #define GFX_MISSING_FONTS_NOTIFY_PREF "gfx.missing_fonts.notify"
   1515 
   1516 class gfxMissingFontRecorder {
   1517 public:
   1518  gfxMissingFontRecorder() {
   1519    MOZ_COUNT_CTOR(gfxMissingFontRecorder);
   1520    memset(&mMissingFonts, 0, sizeof(mMissingFonts));
   1521  }
   1522 
   1523  ~gfxMissingFontRecorder() {
   1524 #ifdef DEBUG
   1525    for (uint32_t i = 0; i < kNumScriptBitsWords; i++) {
   1526      NS_ASSERTION(mMissingFonts[i] == 0,
   1527                   "failed to flush the missing-font recorder");
   1528    }
   1529 #endif
   1530    MOZ_COUNT_DTOR(gfxMissingFontRecorder);
   1531  }
   1532 
   1533  // record this script code in our mMissingFonts bitset
   1534  void RecordScript(mozilla::intl::Script aScriptCode) {
   1535    mMissingFonts[static_cast<uint32_t>(aScriptCode) >> 5] |=
   1536        (1 << (static_cast<uint32_t>(aScriptCode) & 0x1f));
   1537  }
   1538 
   1539  // send a notification of any missing-scripts that have been
   1540  // recorded, and clear the mMissingFonts set for re-use
   1541  void Flush();
   1542 
   1543  // forget any missing-scripts that have been recorded up to now;
   1544  // called before discarding a recorder we no longer care about
   1545  void Clear() { memset(&mMissingFonts, 0, sizeof(mMissingFonts)); }
   1546 
   1547 private:
   1548  // Number of 32-bit words needed for the missing-script flags
   1549  static const uint32_t kNumScriptBitsWords =
   1550      ((static_cast<int>(mozilla::intl::Script::NUM_SCRIPT_CODES) + 31) / 32);
   1551  uint32_t mMissingFonts[kNumScriptBitsWords];
   1552 };
   1553 
   1554 #endif