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