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