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