Coverage Report

Created: 2018-09-25 14:53

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