Coverage Report

Created: 2018-09-25 14:53

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