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