Bug 1874684 - Part 28: Return DateDuration from DifferenceISODateTime. r=mgaudet
[gecko.git] / gfx / thebes / gfxTextRun.h
blob61cdd3b2516d8fd0fa965b785325637245d036d0
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 "gfxUtils.h"
21 #include "mozilla/MemoryReporting.h"
22 #include "mozilla/RefPtr.h"
23 #include "mozilla/intl/UnicodeScriptCodes.h"
24 #include "nsPoint.h"
25 #include "nsString.h"
26 #include "nsTArray.h"
27 #include "nsTHashSet.h"
28 #include "nsTextFrameUtils.h"
29 #include "DrawMode.h"
30 #include "harfbuzz/hb.h"
31 #include "nsColor.h"
32 #include "nsFrameList.h"
33 #include "X11UndefineNone.h"
35 #ifdef DEBUG_FRAME_DUMP
36 # include <stdio.h>
37 #endif
39 class gfxContext;
40 class gfxFontGroup;
41 class nsAtom;
42 class nsLanguageAtomService;
43 class gfxMissingFontRecorder;
45 namespace mozilla {
46 class PostTraversalTask;
47 class SVGContextPaint;
48 enum class StyleHyphens : uint8_t;
49 }; // namespace mozilla
51 /**
52 * Callback for Draw() to use when drawing text with mode
53 * DrawMode::GLYPH_PATH.
55 struct MOZ_STACK_CLASS gfxTextRunDrawCallbacks {
56 /**
57 * Constructs a new DrawCallbacks object.
59 * @param aShouldPaintSVGGlyphs If true, SVG glyphs will be painted. If
60 * false, SVG glyphs will not be painted; fallback plain glyphs are not
61 * emitted either.
63 explicit gfxTextRunDrawCallbacks(bool aShouldPaintSVGGlyphs = false)
64 : mShouldPaintSVGGlyphs(aShouldPaintSVGGlyphs) {}
66 /**
67 * Called when a path has been emitted to the gfxContext when
68 * painting a text run. This can be called any number of times,
69 * due to partial ligatures and intervening SVG glyphs.
71 virtual void NotifyGlyphPathEmitted() = 0;
73 bool mShouldPaintSVGGlyphs;
76 /**
77 * gfxTextRun is an abstraction for drawing and measuring substrings of a run
78 * of text. It stores runs of positioned glyph data, each run having a single
79 * gfxFont. The glyphs are associated with a string of source text, and the
80 * gfxTextRun APIs take parameters that are offsets into that source text.
82 * gfxTextRuns are mostly immutable. The only things that can change are
83 * inter-cluster spacing and line break placement. Spacing is always obtained
84 * lazily by methods that need it, it is not cached. Line breaks are stored
85 * persistently (insofar as they affect the shaping of glyphs; gfxTextRun does
86 * not actually do anything to explicitly account for line breaks). Initially
87 * there are no line breaks. The textrun can record line breaks before or after
88 * any given cluster. (Line breaks specified inside clusters are ignored.)
90 * It is important that zero-length substrings are handled correctly. This will
91 * be on the test!
93 class gfxTextRun : public gfxShapedText {
94 NS_INLINE_DECL_REFCOUNTING(gfxTextRun);
96 protected:
97 // Override operator delete to properly free the object that was
98 // allocated via malloc.
99 void operator delete(void* p) { free(p); }
101 virtual ~gfxTextRun();
103 public:
104 typedef gfxFont::RunMetrics Metrics;
105 typedef mozilla::gfx::DrawTarget DrawTarget;
107 // Public textrun API for general use
109 bool IsClusterStart(uint32_t aPos) const {
110 MOZ_ASSERT(aPos < GetLength());
111 return mCharacterGlyphs[aPos].IsClusterStart();
113 bool IsLigatureGroupStart(uint32_t aPos) const {
114 MOZ_ASSERT(aPos < GetLength());
115 return mCharacterGlyphs[aPos].IsLigatureGroupStart();
117 bool CanBreakLineBefore(uint32_t aPos) const {
118 return CanBreakBefore(aPos) == CompressedGlyph::FLAG_BREAK_TYPE_NORMAL;
120 bool CanHyphenateBefore(uint32_t aPos) const {
121 return CanBreakBefore(aPos) == CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN;
124 // Returns a gfxShapedText::CompressedGlyph::FLAG_BREAK_TYPE_* value
125 // as defined in gfxFont.h (may be NONE, NORMAL, HYPHEN or EMERGENCY_WRAP).
126 uint8_t CanBreakBefore(uint32_t aPos) const {
127 MOZ_ASSERT(aPos < GetLength());
128 return mCharacterGlyphs[aPos].CanBreakBefore();
131 bool CharIsSpace(uint32_t aPos) const {
132 MOZ_ASSERT(aPos < GetLength());
133 return mCharacterGlyphs[aPos].CharIsSpace();
135 bool CharIsTab(uint32_t aPos) const {
136 MOZ_ASSERT(aPos < GetLength());
137 return mCharacterGlyphs[aPos].CharIsTab();
139 bool CharIsNewline(uint32_t aPos) const {
140 MOZ_ASSERT(aPos < GetLength());
141 return mCharacterGlyphs[aPos].CharIsNewline();
143 bool CharMayHaveEmphasisMark(uint32_t aPos) const {
144 MOZ_ASSERT(aPos < GetLength());
145 return mCharacterGlyphs[aPos].CharMayHaveEmphasisMark();
147 bool CharIsFormattingControl(uint32_t aPos) const {
148 MOZ_ASSERT(aPos < GetLength());
149 return mCharacterGlyphs[aPos].CharIsFormattingControl();
152 // All offsets are in terms of the string passed into MakeTextRun.
154 // Describe range [start, end) of a text run. The range is
155 // restricted to grapheme cluster boundaries.
156 struct Range {
157 uint32_t start;
158 uint32_t end;
159 uint32_t Length() const { return end - start; }
161 Range() : start(0), end(0) {}
162 Range(uint32_t aStart, uint32_t aEnd) : start(aStart), end(aEnd) {}
163 explicit Range(const gfxTextRun* aTextRun)
164 : start(0), end(aTextRun->GetLength()) {}
167 // All coordinates are in layout/app units
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.
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.
178 * @return true if this changed the linebreaks, false if the new line
179 * breaks are the same as the old
181 virtual bool SetPotentialLineBreaks(Range aRange,
182 const uint8_t* aBreakBefore);
184 enum class HyphenType : uint8_t {
185 // Code in BreakAndMeasureText depends on the ordering of these values!
186 None,
187 Explicit,
188 Soft,
189 AutoWithManualInSameWord,
190 AutoWithoutManualInSameWord
193 static bool IsOptionalHyphenBreak(HyphenType aType) {
194 return aType >= HyphenType::Soft;
197 struct HyphenationState {
198 uint32_t mostRecentBoundary = 0;
199 bool hasManualHyphen = false;
200 bool hasExplicitHyphen = false;
201 bool hasAutoHyphen = false;
205 * Layout provides PropertyProvider objects. These allow detection of
206 * potential line break points and computation of spacing. We pass the data
207 * this way to allow lazy data acquisition; for example BreakAndMeasureText
208 * will want to only ask for properties of text it's actually looking at.
210 * NOTE that requested spacing may not actually be applied, if the textrun
211 * is unable to apply it in some context. Exception: spacing around a
212 * whitespace character MUST always be applied.
214 class PropertyProvider {
215 public:
216 // Detect hyphenation break opportunities in the given range; breaks
217 // not at cluster boundaries will be ignored.
218 virtual void GetHyphenationBreaks(Range aRange,
219 HyphenType* aBreakBefore) const = 0;
221 // Returns the provider's hyphenation setting, so callers can decide
222 // whether it is necessary to call GetHyphenationBreaks.
223 // Result is an StyleHyphens value.
224 virtual mozilla::StyleHyphens GetHyphensOption() const = 0;
226 // Returns the extra width that will be consumed by a hyphen. This should
227 // be constant for a given textrun.
228 virtual gfxFloat GetHyphenWidth() const = 0;
230 // Return orientation flags to be used when creating a hyphen textrun.
231 virtual mozilla::gfx::ShapedTextFlags GetShapedTextFlags() const = 0;
233 typedef gfxFont::Spacing Spacing;
236 * Get the spacing around the indicated characters. Spacing must be zero
237 * inside clusters. In other words, if character i is not
238 * CLUSTER_START, then character i-1 must have zero after-spacing and
239 * character i must have zero before-spacing.
241 virtual void GetSpacing(Range aRange, Spacing* aSpacing) const = 0;
243 // Returns a gfxContext that can be used to measure the hyphen glyph.
244 // Only called if the hyphen width is requested.
245 virtual already_AddRefed<DrawTarget> GetDrawTarget() const = 0;
247 // Return the appUnitsPerDevUnit value to be used when measuring.
248 // Only called if the hyphen width is requested.
249 virtual uint32_t GetAppUnitsPerDevUnit() const = 0;
252 struct MOZ_STACK_CLASS DrawParams {
253 gfxContext* context;
254 mozilla::gfx::PaletteCache& paletteCache;
255 DrawMode drawMode = DrawMode::GLYPH_FILL;
256 nscolor textStrokeColor = 0;
257 nsAtom* fontPalette = nullptr;
258 gfxPattern* textStrokePattern = nullptr;
259 const mozilla::gfx::StrokeOptions* strokeOpts = nullptr;
260 const mozilla::gfx::DrawOptions* drawOpts = nullptr;
261 const PropertyProvider* provider = nullptr;
262 // If non-null, the advance width of the substring is set.
263 gfxFloat* advanceWidth = nullptr;
264 mozilla::SVGContextPaint* contextPaint = nullptr;
265 gfxTextRunDrawCallbacks* callbacks = nullptr;
266 bool allowGDI = true;
267 bool hasTextShadow = false;
268 DrawParams(gfxContext* aContext, mozilla::gfx::PaletteCache& aPaletteCache)
269 : context(aContext), paletteCache(aPaletteCache) {}
273 * Draws a substring. Uses only GetSpacing from aBreakProvider.
274 * The provided point is the baseline origin on the left of the string
275 * for LTR, on the right of the string for RTL.
277 * Drawing should respect advance widths in the sense that for LTR runs,
278 * Draw(Range(start, middle), pt, ...) followed by
279 * Draw(Range(middle, end), gfxPoint(pt.x + advance, pt.y), ...)
280 * should have the same effect as
281 * Draw(Range(start, end), pt, ...)
283 * For RTL runs the rule is:
284 * Draw(Range(middle, end), pt, ...) followed by
285 * Draw(Range(start, middle), gfxPoint(pt.x + advance, pt.y), ...)
286 * should have the same effect as
287 * Draw(Range(start, end), pt, ...)
289 * Glyphs should be drawn in logical content order, which can be significant
290 * if they overlap (perhaps due to negative spacing).
292 void Draw(const Range aRange, const mozilla::gfx::Point aPt,
293 const DrawParams& aParams) const;
296 * Draws the emphasis marks for this text run. Uses only GetSpacing
297 * from aProvider. The provided point is the baseline origin of the
298 * line of emphasis marks.
300 void DrawEmphasisMarks(gfxContext* aContext, gfxTextRun* aMark,
301 gfxFloat aMarkAdvance, mozilla::gfx::Point aPt,
302 Range aRange, const PropertyProvider* aProvider,
303 mozilla::gfx::PaletteCache& aPaletteCache) const;
306 * Computes the ReflowMetrics for a substring.
307 * Uses GetSpacing from aBreakProvider.
308 * @param aBoundingBoxType which kind of bounding box (loose/tight)
310 Metrics MeasureText(Range aRange, gfxFont::BoundingBoxType aBoundingBoxType,
311 DrawTarget* aDrawTargetForTightBoundingBox,
312 const PropertyProvider* aProvider) const;
314 Metrics MeasureText(gfxFont::BoundingBoxType aBoundingBoxType,
315 DrawTarget* aDrawTargetForTightBoundingBox,
316 const PropertyProvider* aProvider = nullptr) const {
317 return MeasureText(Range(this), aBoundingBoxType,
318 aDrawTargetForTightBoundingBox, aProvider);
321 void GetLineHeightMetrics(Range aRange, gfxFloat& aAscent,
322 gfxFloat& aDescent) const;
323 void GetLineHeightMetrics(gfxFloat& aAscent, gfxFloat& aDescent) const {
324 GetLineHeightMetrics(Range(this), aAscent, aDescent);
328 * Computes just the advance width for a substring.
329 * Uses GetSpacing from aBreakProvider.
330 * If aSpacing is not null, the spacing attached before and after
331 * the substring would be returned in it. NOTE: the spacing is
332 * included in the advance width.
334 gfxFloat GetAdvanceWidth(Range aRange, const PropertyProvider* aProvider,
335 PropertyProvider::Spacing* aSpacing = nullptr) const;
337 gfxFloat GetAdvanceWidth() const {
338 return GetAdvanceWidth(Range(this), nullptr);
342 * Computes the minimum advance width for a substring assuming line
343 * breaking is allowed everywhere.
345 gfxFloat GetMinAdvanceWidth(Range aRange);
348 * Clear all stored line breaks for the given range (both before and after),
349 * and then set the line-break state before aRange.start to aBreakBefore and
350 * after the last cluster to aBreakAfter.
352 * We require that before and after line breaks be consistent. For clusters
353 * i and i+1, we require that if there is a break after cluster i, a break
354 * will be specified before cluster i+1. This may be temporarily violated
355 * (e.g. after reflowing line L and before reflowing line L+1); to handle
356 * these temporary violations, we say that there is a break betwen i and i+1
357 * if a break is specified after i OR a break is specified before i+1.
359 * This can change textrun geometry! The existence of a linebreak can affect
360 * the advance width of the cluster before the break (when kerning) or the
361 * geometry of one cluster before the break or any number of clusters
362 * after the break. (The one-cluster-before-the-break limit is somewhat
363 * arbitrary; if some scripts require breaking it, then we need to
364 * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase
365 * it could affect the layout of frames before it...)
367 * We return true if glyphs or geometry changed, false otherwise. This
368 * function is virtual so that gfxTextRun subclasses can reshape
369 * properly.
371 * @param aAdvanceWidthDelta if non-null, returns the change in advance
372 * width of the given range.
374 virtual bool SetLineBreaks(Range aRange, bool aLineBreakBefore,
375 bool aLineBreakAfter,
376 gfxFloat* aAdvanceWidthDelta);
378 enum SuppressBreak {
379 eNoSuppressBreak,
380 // Measure the range of text as if there is no break before it.
381 eSuppressInitialBreak,
382 // Measure the range of text as if it contains no break
383 eSuppressAllBreaks
386 void ClassifyAutoHyphenations(uint32_t aStart, Range aRange,
387 nsTArray<HyphenType>& aHyphenBuffer,
388 HyphenationState* aWordState);
390 // Struct used by BreakAndMeasureText to return the amount of trimmable
391 // trailing whitespace included in the run.
392 struct TrimmableWS {
393 mozilla::gfx::Float mAdvance = 0;
394 uint32_t mCount = 0;
398 * Finds the longest substring that will fit into the given width.
399 * Uses GetHyphenationBreaks and GetSpacing from aProvider.
400 * Guarantees the following:
401 * -- 0 <= result <= aMaxLength
402 * -- result is the maximal value of N such that either
403 * N < aMaxLength && line break at N &&
404 * GetAdvanceWidth(Range(aStart, N), aProvider) <= aWidth
405 * OR N < aMaxLength && hyphen break at N &&
406 * GetAdvanceWidth(Range(aStart, N), aProvider) +
407 * GetHyphenWidth() <= aWidth
408 * OR N == aMaxLength &&
409 * GetAdvanceWidth(Range(aStart, N), aProvider) <= aWidth
410 * where GetAdvanceWidth assumes the effect of
411 * SetLineBreaks(Range(aStart, N),
412 * aLineBreakBefore, N < aMaxLength, aProvider)
413 * -- if no such N exists, then result is the smallest N such that
414 * N < aMaxLength && line break at N
415 * OR N < aMaxLength && hyphen break at N
416 * OR N == aMaxLength
418 * The call has the effect of
419 * SetLineBreaks(Range(aStart, result), aLineBreakBefore,
420 * result < aMaxLength, aProvider)
421 * and the returned metrics and the invariants above reflect this.
423 * @param aMaxLength this can be UINT32_MAX, in which case the length used
424 * is up to the end of the string
425 * @param aLineBreakBefore set to true if and only if there is an actual
426 * line break at the start of this string.
427 * @param aSuppressBreak what break should be suppressed.
428 * @param aOutTrimmableWhitespace if non-null, returns the advance of any
429 * run of trailing spaces that might be trimmed if the run ends up at
430 * end-of-line.
431 * Trimmable spaces are still counted in the "characters fit" result, and
432 * contribute to the returned Metrics values.
433 * @param aOutMetrics we fill this in for the returned substring.
434 * If a hyphenation break was used, the hyphen is NOT included in the returned
435 * metrics.
436 * @param aBoundingBoxType whether to make the bounding box in aMetrics tight
437 * @param aRefDrawTarget a reference DrawTarget to get the tight bounding box,
438 * if requested
439 * @param aOutUsedHyphenation records if we selected a hyphenation break
440 * @param aOutLastBreak if result is aMaxLength, we set this to
441 * the maximal N such that
442 * N < aMaxLength && line break at N &&
443 * GetAdvanceWidth(Range(aStart, N), aProvider) <= aWidth
444 * OR N < aMaxLength && hyphen break at N &&
445 * GetAdvanceWidth(Range(aStart, N), aProvider) +
446 * GetHyphenWidth() <= aWidth
447 * or UINT32_MAX if no such N exists, where GetAdvanceWidth assumes
448 * the effect of
449 * SetLineBreaks(Range(aStart, N), aLineBreakBefore,
450 * N < aMaxLength, aProvider)
452 * @param aCanWordWrap true if we can break between any two grapheme
453 * clusters. This is set by overflow-wrap|word-wrap: break-word
455 * @param aBreakPriority in/out the priority of the break opportunity
456 * saved in the line. If we are prioritizing break opportunities, we will
457 * not set a break with a lower priority. @see gfxBreakPriority.
459 * Note that negative advance widths are possible especially if negative
460 * spacing is provided.
462 uint32_t BreakAndMeasureText(
463 uint32_t aStart, uint32_t aMaxLength, bool aLineBreakBefore,
464 gfxFloat aWidth, const PropertyProvider& aProvider,
465 SuppressBreak aSuppressBreak, gfxFont::BoundingBoxType aBoundingBoxType,
466 DrawTarget* aRefDrawTarget, bool aCanWordWrap, bool aCanWhitespaceWrap,
467 bool aIsBreakSpaces,
468 // Output parameters:
469 TrimmableWS* aOutTrimmableWhitespace, // may be null
470 Metrics& aOutMetrics, bool& aOutUsedHyphenation, uint32_t& aOutLastBreak,
471 // In/out:
472 gfxBreakPriority& aBreakPriority);
474 // Utility getters
476 void* GetUserData() const { return mUserData; }
477 void SetUserData(void* aUserData) { mUserData = aUserData; }
479 void SetFlagBits(nsTextFrameUtils::Flags aFlags) { mFlags2 |= aFlags; }
480 void ClearFlagBits(nsTextFrameUtils::Flags aFlags) { mFlags2 &= ~aFlags; }
481 const gfxSkipChars& GetSkipChars() const { return mSkipChars; }
482 gfxFontGroup* GetFontGroup() const { return mFontGroup; }
484 // Call this, don't call "new gfxTextRun" directly. This does custom
485 // allocation and initialization
486 static already_AddRefed<gfxTextRun> Create(
487 const gfxTextRunFactory::Parameters* aParams, uint32_t aLength,
488 gfxFontGroup* aFontGroup, mozilla::gfx::ShapedTextFlags aFlags,
489 nsTextFrameUtils::Flags aFlags2);
491 // The text is divided into GlyphRuns as necessary. (In the vast majority
492 // of cases, a gfxTextRun contains just a single GlyphRun.)
493 struct GlyphRun {
494 RefPtr<gfxFont> mFont; // never null in a valid GlyphRun
495 uint32_t mCharacterOffset; // into original UTF16 string
496 mozilla::gfx::ShapedTextFlags
497 mOrientation; // gfxTextRunFactory::TEXT_ORIENT_* value
498 FontMatchType mMatchType;
499 bool mIsCJK; // Whether the text was a CJK script run (used to decide if
500 // text-decoration-skip-ink should not be applied)
502 // Set up the properties (but NOT offset) of the GlyphRun.
503 void SetProperties(gfxFont* aFont,
504 mozilla::gfx::ShapedTextFlags aOrientation, bool aIsCJK,
505 FontMatchType aMatchType) {
506 mFont = aFont;
507 mOrientation = aOrientation;
508 mIsCJK = aIsCJK;
509 mMatchType = aMatchType;
512 // Return whether the GlyphRun matches the given properties;
513 // the given FontMatchType will be added to the run if not present.
514 bool Matches(gfxFont* aFont, mozilla::gfx::ShapedTextFlags aOrientation,
515 bool aIsCJK, FontMatchType aMatchType) {
516 if (mFont == aFont && mOrientation == aOrientation && mIsCJK == aIsCJK) {
517 mMatchType.kind |= aMatchType.kind;
518 if (mMatchType.generic == mozilla::StyleGenericFontFamily::None) {
519 mMatchType.generic = aMatchType.generic;
521 return true;
523 return false;
526 bool IsSidewaysLeft() const {
527 return (mOrientation & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK) ==
528 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT;
531 bool IsSidewaysRight() const {
532 return (mOrientation & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK) ==
533 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT;
537 // Script run codes that we will mark as CJK to suppress skip-ink behavior.
538 static inline bool IsCJKScript(Script aScript) {
539 switch (aScript) {
540 case Script::BOPOMOFO:
541 case Script::HAN:
542 case Script::HANGUL:
543 case Script::HIRAGANA:
544 case Script::KATAKANA:
545 case Script::KATAKANA_OR_HIRAGANA:
546 case Script::SIMPLIFIED_HAN:
547 case Script::TRADITIONAL_HAN:
548 case Script::JAPANESE:
549 case Script::KOREAN:
550 case Script::HAN_WITH_BOPOMOFO:
551 case Script::JAMO:
552 return true;
553 default:
554 return false;
558 class MOZ_STACK_CLASS GlyphRunIterator {
559 public:
560 GlyphRunIterator(const gfxTextRun* aTextRun, Range aRange,
561 bool aReverse = false)
562 : mTextRun(aTextRun),
563 mStartOffset(aRange.start),
564 mEndOffset(aRange.end),
565 mReverse(aReverse) {
566 mGlyphRun = mTextRun->FindFirstGlyphRunContaining(
567 aReverse ? aRange.end - 1 : aRange.start);
568 if (!mGlyphRun) {
569 mStringEnd = mStringStart = mStartOffset;
570 return;
572 uint32_t glyphRunEndOffset = mGlyphRun == mTextRun->mGlyphRuns.end() - 1
573 ? mTextRun->GetLength()
574 : (mGlyphRun + 1)->mCharacterOffset;
575 mStringEnd = std::min(mEndOffset, glyphRunEndOffset);
576 mStringStart = std::max(mStartOffset, mGlyphRun->mCharacterOffset);
578 void NextRun();
579 bool AtEnd() const { return mGlyphRun == nullptr; }
580 const struct GlyphRun* GlyphRun() const { return mGlyphRun; }
581 uint32_t StringStart() const { return mStringStart; }
582 uint32_t StringEnd() const { return mStringEnd; }
584 private:
585 const gfxTextRun* mTextRun;
586 const struct GlyphRun* mGlyphRun;
587 uint32_t mStringStart;
588 uint32_t mStringEnd;
589 uint32_t mStartOffset;
590 uint32_t mEndOffset;
591 bool mReverse;
594 class GlyphRunOffsetComparator {
595 public:
596 bool Equals(const GlyphRun& a, const GlyphRun& b) const {
597 return a.mCharacterOffset == b.mCharacterOffset;
600 bool LessThan(const GlyphRun& a, const GlyphRun& b) const {
601 return a.mCharacterOffset < b.mCharacterOffset;
605 // API for setting up the textrun glyphs. Should only be called by
606 // things that construct textruns.
608 * We've found a run of text that should use a particular font. Call this
609 * only during initialization when font substitution has been computed.
610 * Call it before setting up the glyphs for the characters in this run;
611 * SetMissingGlyph requires that the correct glyphrun be installed.
613 * If aForceNewRun, a new glyph run will be added, even if the
614 * previously added run uses the same font. If glyph runs are
615 * added out of strictly increasing aStartCharIndex order (via
616 * force), then SortGlyphRuns must be called after all glyph runs
617 * are added before any further operations are performed with this
618 * TextRun.
620 void AddGlyphRun(gfxFont* aFont, FontMatchType aMatchType,
621 uint32_t aUTF16Offset, bool aForceNewRun,
622 mozilla::gfx::ShapedTextFlags aOrientation, bool aIsCJK);
623 void ResetGlyphRuns() { mGlyphRuns.Clear(); }
624 void SanitizeGlyphRuns();
626 const CompressedGlyph* GetCharacterGlyphs() const final {
627 MOZ_ASSERT(mCharacterGlyphs, "failed to initialize mCharacterGlyphs");
628 return mCharacterGlyphs;
630 CompressedGlyph* GetCharacterGlyphs() final {
631 MOZ_ASSERT(mCharacterGlyphs, "failed to initialize mCharacterGlyphs");
632 return mCharacterGlyphs;
635 // clean out results from shaping in progress, used for fallback scenarios
636 void ClearGlyphsAndCharacters();
638 void SetSpaceGlyph(gfxFont* aFont, DrawTarget* aDrawTarget,
639 uint32_t aCharIndex,
640 mozilla::gfx::ShapedTextFlags aOrientation);
642 // Set the glyph data for the given character index to the font's
643 // space glyph, IF this can be done as a "simple" glyph record
644 // (not requiring a DetailedGlyph entry). This avoids the need to call
645 // the font shaper and go through the shaped-word cache for most spaces.
647 // The parameter aSpaceChar is the original character code for which
648 // this space glyph is being used; if this is U+0020, we need to record
649 // that it could be trimmed at a run edge, whereas other kinds of space
650 // (currently just U+00A0) would not be trimmable/breakable.
652 // Returns true if it was able to set simple glyph data for the space;
653 // if it returns false, the caller needs to fall back to some other
654 // means to create the necessary (detailed) glyph data.
655 bool SetSpaceGlyphIfSimple(gfxFont* aFont, uint32_t aCharIndex,
656 char16_t aSpaceChar,
657 mozilla::gfx::ShapedTextFlags aOrientation);
659 // Record the positions of specific characters that layout may need to
660 // detect in the textrun, even though it doesn't have an explicit copy
661 // of the original text. These are recorded using flag bits in the
662 // CompressedGlyph record; if necessary, we convert "simple" glyph records
663 // to "complex" ones as the Tab and Newline flags are not present in
664 // simple CompressedGlyph records.
665 void SetIsTab(uint32_t aIndex) { EnsureComplexGlyph(aIndex).SetIsTab(); }
666 void SetIsNewline(uint32_t aIndex) {
667 EnsureComplexGlyph(aIndex).SetIsNewline();
669 void SetNoEmphasisMark(uint32_t aIndex) {
670 EnsureComplexGlyph(aIndex).SetNoEmphasisMark();
672 void SetIsFormattingControl(uint32_t aIndex) {
673 EnsureComplexGlyph(aIndex).SetIsFormattingControl();
677 * Prefetch all the glyph extents needed to ensure that Measure calls
678 * on this textrun not requesting tight boundingBoxes will succeed. Note
679 * that some glyph extents might not be fetched due to OOM or other
680 * errors.
682 void FetchGlyphExtents(DrawTarget* aRefDrawTarget) const;
684 const GlyphRun* GetGlyphRuns(uint32_t* aNumGlyphRuns) const {
685 *aNumGlyphRuns = mGlyphRuns.Length();
686 return mGlyphRuns.begin();
689 uint32_t GlyphRunCount() const { return mGlyphRuns.Length(); }
691 const GlyphRun* TrailingGlyphRun() const {
692 return mGlyphRuns.IsEmpty() ? nullptr : mGlyphRuns.end() - 1;
695 // Returns the GlyphRun containing the given offset.
696 // (Returns mGlyphRuns.end()-1 when aOffset is mCharacterCount; returns
697 // nullptr if textrun is empty and no glyph runs are present.)
698 const GlyphRun* FindFirstGlyphRunContaining(uint32_t aOffset) const;
700 // Copy glyph data from a ShapedWord into this textrun.
701 void CopyGlyphDataFrom(gfxShapedWord* aSource, uint32_t aStart);
703 // Copy glyph data for a range of characters from aSource to this
704 // textrun.
705 void CopyGlyphDataFrom(gfxTextRun* aSource, Range aRange, uint32_t aDest);
707 // Tell the textrun to release its reference to its creating gfxFontGroup
708 // immediately, rather than on destruction. This is used for textruns
709 // that are actually owned by a gfxFontGroup, so that they don't keep it
710 // permanently alive due to a circular reference. (The caller of this is
711 // taking responsibility for ensuring the textrun will not outlive its
712 // mFontGroup.)
713 void ReleaseFontGroup();
715 struct LigatureData {
716 // textrun range of the containing ligature
717 Range mRange;
718 // appunits advance to the start of the ligature part within the ligature;
719 // never includes any spacing
720 gfxFloat mPartAdvance;
721 // appunits width of the ligature part; includes before-spacing
722 // when the part is at the start of the ligature, and after-spacing
723 // when the part is as the end of the ligature
724 gfxFloat mPartWidth;
726 bool mClipBeforePart;
727 bool mClipAfterPart;
730 // return storage used by this run, for memory reporter;
731 // nsTransformedTextRun needs to override this as it holds additional data
732 virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
733 MOZ_MUST_OVERRIDE;
734 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
735 MOZ_MUST_OVERRIDE;
737 nsTextFrameUtils::Flags GetFlags2() const { return mFlags2; }
739 // Get the size, if it hasn't already been gotten, marking as it goes.
740 size_t MaybeSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
741 if (mFlags2 & nsTextFrameUtils::Flags::RunSizeAccounted) {
742 return 0;
744 mFlags2 |= nsTextFrameUtils::Flags::RunSizeAccounted;
745 return SizeOfIncludingThis(aMallocSizeOf);
747 void ResetSizeOfAccountingFlags() {
748 mFlags2 &= ~nsTextFrameUtils::Flags::RunSizeAccounted;
751 // shaping state - for some font features, fallback is required that
752 // affects the entire run. for example, fallback for one script/font
753 // portion of a textrun requires fallback to be applied to the entire run
755 enum ShapingState : uint8_t {
756 eShapingState_Normal, // default state
757 eShapingState_ShapingWithFeature, // have shaped with feature
758 eShapingState_ShapingWithFallback, // have shaped with fallback
759 eShapingState_Aborted, // abort initial iteration
760 eShapingState_ForceFallbackFeature // redo with fallback forced on
763 ShapingState GetShapingState() const { return mShapingState; }
764 void SetShapingState(ShapingState aShapingState) {
765 mShapingState = aShapingState;
768 int32_t GetAdvanceForGlyph(uint32_t aIndex) const {
769 const CompressedGlyph& glyphData = mCharacterGlyphs[aIndex];
770 if (glyphData.IsSimpleGlyph()) {
771 return glyphData.GetSimpleAdvance();
773 uint32_t glyphCount = glyphData.GetGlyphCount();
774 if (!glyphCount) {
775 return 0;
777 const DetailedGlyph* details = GetDetailedGlyphs(aIndex);
778 int32_t advance = 0;
779 for (uint32_t j = 0; j < glyphCount; ++j, ++details) {
780 advance += details->mAdvance;
782 return advance;
785 #ifdef DEBUG_FRAME_DUMP
786 void Dump(FILE* aOutput = stderr);
787 #endif
789 protected:
791 * Create a textrun, and set its mCharacterGlyphs to point immediately
792 * after the base object; this is ONLY used in conjunction with placement
793 * new, after allocating a block large enough for the glyph records to
794 * follow the base textrun object.
796 gfxTextRun(const gfxTextRunFactory::Parameters* aParams, uint32_t aLength,
797 gfxFontGroup* aFontGroup, mozilla::gfx::ShapedTextFlags aFlags,
798 nsTextFrameUtils::Flags aFlags2);
800 // Whether we need to fetch actual glyph extents from the fonts.
801 bool NeedsGlyphExtents() const;
804 * Helper for the Create() factory method to allocate the required
805 * glyph storage for a textrun object with the basic size aSize,
806 * plus room for aLength glyph records.
808 static void* AllocateStorageForTextRun(size_t aSize, uint32_t aLength);
810 // Pointer to the array of CompressedGlyph records; must be initialized
811 // when the object is constructed.
812 CompressedGlyph* mCharacterGlyphs;
814 private:
815 // **** general helpers ****
817 // Get the total advance for a range of glyphs.
818 int32_t GetAdvanceForGlyphs(Range aRange) const;
820 // Spacing for characters outside the range aSpacingStart/aSpacingEnd
821 // is assumed to be zero; such characters are not passed to aProvider.
822 // This is useful to protect aProvider from being passed character indices
823 // it is not currently able to handle.
824 bool GetAdjustedSpacingArray(
825 Range aRange, const PropertyProvider* aProvider, Range aSpacingRange,
826 nsTArray<PropertyProvider::Spacing>* aSpacing) const;
828 CompressedGlyph& EnsureComplexGlyph(uint32_t aIndex) {
829 gfxShapedText::EnsureComplexGlyph(aIndex, mCharacterGlyphs[aIndex]);
830 return mCharacterGlyphs[aIndex];
833 // **** ligature helpers ****
834 // (Platforms do the actual ligaturization, but we need to do a bunch of stuff
835 // to handle requests that begin or end inside a ligature)
837 // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
838 LigatureData ComputeLigatureData(Range aPartRange,
839 const PropertyProvider* aProvider) const;
840 gfxFloat ComputePartialLigatureWidth(Range aPartRange,
841 const PropertyProvider* aProvider) const;
842 void DrawPartialLigature(gfxFont* aFont, Range aRange,
843 mozilla::gfx::Point* aPt,
844 const PropertyProvider* aProvider,
845 TextRunDrawParams& aParams,
846 mozilla::gfx::ShapedTextFlags aOrientation) const;
847 // Advance aRange.start to the start of the nearest ligature, back
848 // up aRange.end to the nearest ligature end; may result in
849 // aRange->start == aRange->end.
850 // Returns whether any adjustment was made.
851 bool ShrinkToLigatureBoundaries(Range* aRange) const;
852 // result in appunits
853 gfxFloat GetPartialLigatureWidth(Range aRange,
854 const PropertyProvider* aProvider) const;
855 void AccumulatePartialLigatureMetrics(
856 gfxFont* aFont, Range aRange, gfxFont::BoundingBoxType aBoundingBoxType,
857 DrawTarget* aRefDrawTarget, const PropertyProvider* aProvider,
858 mozilla::gfx::ShapedTextFlags aOrientation, Metrics* aMetrics) const;
860 // **** measurement helper ****
861 void AccumulateMetricsForRun(gfxFont* aFont, Range aRange,
862 gfxFont::BoundingBoxType aBoundingBoxType,
863 DrawTarget* aRefDrawTarget,
864 const PropertyProvider* aProvider,
865 Range aSpacingRange,
866 mozilla::gfx::ShapedTextFlags aOrientation,
867 Metrics* aMetrics) const;
869 // **** drawing helper ****
870 void DrawGlyphs(gfxFont* aFont, Range aRange, mozilla::gfx::Point* aPt,
871 const PropertyProvider* aProvider, Range aSpacingRange,
872 TextRunDrawParams& aParams,
873 mozilla::gfx::ShapedTextFlags aOrientation) const;
875 // The textrun holds either a single GlyphRun -or- an array.
876 mozilla::ElementOrArray<GlyphRun> mGlyphRuns;
878 void* mUserData;
880 // mFontGroup is usually a strong reference, but refcounting is managed
881 // manually because it may be explicitly released by ReleaseFontGroup()
882 // in the case where the font group actually owns the textrun.
883 gfxFontGroup* MOZ_OWNING_REF mFontGroup;
885 gfxSkipChars mSkipChars;
887 nsTextFrameUtils::Flags
888 mFlags2; // additional flags (see also gfxShapedText::mFlags)
890 bool mDontSkipDrawing; // true if the text run must not skip drawing, even if
891 // waiting for a user font download, e.g. because we
892 // are using it to draw canvas text
893 bool mReleasedFontGroup; // we already called NS_RELEASE on
894 // mFontGroup, so don't do it again
895 bool mReleasedFontGroupSkippedDrawing; // whether our old mFontGroup value
896 // was set to skip drawing
898 // shaping state for handling variant fallback features
899 // such as subscript/superscript variant glyphs
900 ShapingState mShapingState;
903 class gfxFontGroup final : public gfxTextRunFactory {
904 public:
905 typedef mozilla::intl::Script Script;
906 typedef gfxShapedText::CompressedGlyph CompressedGlyph;
908 static void
909 Shutdown(); // platform must call this to release the languageAtomService
911 gfxFontGroup(nsPresContext* aPresContext,
912 const mozilla::StyleFontFamilyList& aFontFamilyList,
913 const gfxFontStyle* aStyle, nsAtom* aLanguage,
914 bool aExplicitLanguage, gfxTextPerfMetrics* aTextPerf,
915 gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize,
916 StyleFontVariantEmoji aVariantEmoji);
918 virtual ~gfxFontGroup();
920 gfxFontGroup(const gfxFontGroup& aOther) = delete;
922 // Returns first valid font in the fontlist or default font.
923 // Initiates userfont loads if userfont not loaded.
924 // aCh: character to look for, or kCSSFirstAvailableFont for default "first
925 // available font" as defined by CSS Fonts (i.e. the first font whose
926 // unicode-range includes <space>, but does not require space to
927 // actually be present)
928 // aGeneric: if non-null, returns the CSS generic type that was mapped to
929 // this font
930 // aIsFirst: if non-null, returns whether the font was first in the list
931 static constexpr uint32_t kCSSFirstAvailableFont = UINT32_MAX;
932 already_AddRefed<gfxFont> GetFirstValidFont(
933 uint32_t aCh = kCSSFirstAvailableFont,
934 mozilla::StyleGenericFontFamily* aGeneric = nullptr,
935 bool* aIsFirst = nullptr);
937 // Returns the first font in the font-group that has an OpenType MATH table,
938 // or null if no such font is available. The GetMathConstant methods may be
939 // called on the returned font.
940 already_AddRefed<gfxFont> GetFirstMathFont();
942 const gfxFontStyle* GetStyle() const { return &mStyle; }
944 // Get the presContext for which this fontGroup was constructed. This may be
945 // null! (In the case of canvas not connected to a document.)
946 nsPresContext* GetPresContext() const { return mPresContext; }
949 * The listed characters should be treated as invisible and zero-width
950 * when creating textruns.
952 static bool IsInvalidChar(uint8_t ch);
953 static bool IsInvalidChar(char16_t ch);
956 * Make a textrun for a given string.
957 * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
958 * textrun will copy it.
959 * This calls FetchGlyphExtents on the textrun.
961 template <typename T>
962 already_AddRefed<gfxTextRun> MakeTextRun(const T* aString, uint32_t aLength,
963 const Parameters* aParams,
964 mozilla::gfx::ShapedTextFlags aFlags,
965 nsTextFrameUtils::Flags aFlags2,
966 gfxMissingFontRecorder* aMFR);
969 * Textrun creation helper for clients that don't want to pass
970 * a full Parameters record.
972 template <typename T>
973 already_AddRefed<gfxTextRun> MakeTextRun(const T* aString, uint32_t aLength,
974 DrawTarget* aRefDrawTarget,
975 int32_t aAppUnitsPerDevUnit,
976 mozilla::gfx::ShapedTextFlags aFlags,
977 nsTextFrameUtils::Flags aFlags2,
978 gfxMissingFontRecorder* aMFR) {
979 gfxTextRunFactory::Parameters params = {
980 aRefDrawTarget, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit};
981 return MakeTextRun(aString, aLength, &params, aFlags, aFlags2, aMFR);
984 // Get the (possibly-cached) width of the hyphen character.
985 gfxFloat GetHyphenWidth(const gfxTextRun::PropertyProvider* aProvider);
988 * Make a text run representing a single hyphen character.
989 * This will use U+2010 HYPHEN if available in the first font,
990 * otherwise fall back to U+002D HYPHEN-MINUS.
991 * The caller is responsible for deleting the returned text run
992 * when no longer required.
994 already_AddRefed<gfxTextRun> MakeHyphenTextRun(
995 DrawTarget* aDrawTarget, mozilla::gfx::ShapedTextFlags aFlags,
996 uint32_t aAppUnitsPerDevUnit);
999 * Check whether a given font (specified by its gfxFontEntry)
1000 * is already in the fontgroup's list of actual fonts
1002 bool HasFont(const gfxFontEntry* aFontEntry);
1004 // This returns the preferred underline for this font group.
1005 // Some CJK fonts have wrong underline offset in its metrics.
1006 // If this group has such "bad" font, each platform's gfxFontGroup
1007 // initialized mUnderlineOffset. The value should be lower value of
1008 // first font's metrics and the bad font's metrics. Otherwise, this
1009 // returns from first font's metrics.
1010 static constexpr gfxFloat UNDERLINE_OFFSET_NOT_SET = INT16_MAX;
1011 gfxFloat GetUnderlineOffset();
1013 already_AddRefed<gfxFont> FindFontForChar(uint32_t ch, uint32_t prevCh,
1014 uint32_t aNextCh, Script aRunScript,
1015 gfxFont* aPrevMatchedFont,
1016 FontMatchType* aMatchType);
1018 gfxUserFontSet* GetUserFontSet();
1020 // With downloadable fonts, the composition of the font group can change as
1021 // fonts are downloaded for each change in state of the user font set, the
1022 // generation value is bumped to avoid picking up previously created text runs
1023 // in the text run word cache. For font groups based on stylesheets with no
1024 // @font-face rule, this always returns 0.
1025 uint64_t GetGeneration();
1027 // generation of the latest fontset rebuild, 0 when no fontset present
1028 uint64_t GetRebuildGeneration();
1030 // used when logging text performance
1031 gfxTextPerfMetrics* GetTextPerfMetrics() const { return mTextPerf; }
1033 // This will call UpdateUserFonts() if the user font set is changed.
1034 void SetUserFontSet(gfxUserFontSet* aUserFontSet);
1036 void ClearCachedData() {
1037 mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
1038 mSkipDrawing = false;
1039 mHyphenWidth = -1;
1040 mCachedEllipsisTextRun = nullptr;
1043 // If there is a user font set, check to see whether the font list or any
1044 // caches need updating.
1045 void UpdateUserFonts();
1047 // search for a specific userfont in the list of fonts
1048 bool ContainsUserFont(const gfxUserFontEntry* aUserFont);
1050 bool ShouldSkipDrawing() const { return mSkipDrawing; }
1052 class LazyReferenceDrawTargetGetter {
1053 public:
1054 virtual already_AddRefed<DrawTarget> GetRefDrawTarget() = 0;
1056 // The gfxFontGroup keeps ownership of this textrun.
1057 // It is only guaranteed to exist until the next call to GetEllipsisTextRun
1058 // (which might use a different appUnitsPerDev value or flags) for the font
1059 // group, or until UpdateUserFonts is called, or the fontgroup is destroyed.
1060 // Get it/use it/forget it :) - don't keep a reference that might go stale.
1061 gfxTextRun* GetEllipsisTextRun(
1062 int32_t aAppUnitsPerDevPixel, mozilla::gfx::ShapedTextFlags aFlags,
1063 LazyReferenceDrawTargetGetter& aRefDrawTargetGetter);
1065 void CheckForUpdatedPlatformList() {
1066 auto* pfl = gfxPlatformFontList::PlatformFontList();
1067 if (mFontListGeneration != pfl->GetGeneration()) {
1068 // Forget cached fonts that may no longer be valid.
1069 mLastPrefFamily = FontFamily();
1070 mLastPrefFont = nullptr;
1071 mDefaultFont = nullptr;
1072 mFonts.Clear();
1073 BuildFontList();
1077 nsAtom* Language() const { return mLanguage.get(); }
1079 // Get font metrics to be used as the basis for CSS font-relative units.
1080 // Note that these may be a "composite" of metrics from multiple fonts,
1081 // because the 'ch' and 'ic' units depend on the font that would be used
1082 // to render specific characters, not simply the "first available" font.
1083 // https://drafts.csswg.org/css-values-4/#ch
1084 // https://drafts.csswg.org/css-values-4/#ic
1085 gfxFont::Metrics GetMetricsForCSSUnits(gfxFont::Orientation aOrientation);
1087 protected:
1088 friend class mozilla::PostTraversalTask;
1090 struct TextRange {
1091 TextRange(uint32_t aStart, uint32_t aEnd, gfxFont* aFont,
1092 FontMatchType aMatchType,
1093 mozilla::gfx::ShapedTextFlags aOrientation)
1094 : start(aStart),
1095 end(aEnd),
1096 font(aFont),
1097 matchType(aMatchType),
1098 orientation(aOrientation) {}
1099 uint32_t Length() const { return end - start; }
1100 uint32_t start, end;
1101 RefPtr<gfxFont> font;
1102 FontMatchType matchType;
1103 mozilla::gfx::ShapedTextFlags orientation;
1106 // search through pref fonts for a character, return nullptr if no matching
1107 // pref font
1108 already_AddRefed<gfxFont> WhichPrefFontSupportsChar(
1109 uint32_t aCh, uint32_t aNextCh, eFontPresentation aPresentation);
1111 already_AddRefed<gfxFont> WhichSystemFontSupportsChar(
1112 uint32_t aCh, uint32_t aNextCh, Script aRunScript,
1113 eFontPresentation aPresentation);
1115 template <typename T>
1116 void ComputeRanges(nsTArray<TextRange>& aRanges, const T* aString,
1117 uint32_t aLength, Script aRunScript,
1118 mozilla::gfx::ShapedTextFlags aOrientation);
1120 class FamilyFace {
1121 public:
1122 FamilyFace()
1123 : mOwnedFamily(nullptr),
1124 mFontEntry(nullptr),
1125 mGeneric(mozilla::StyleGenericFontFamily::None),
1126 mFontCreated(false),
1127 mLoading(false),
1128 mInvalid(false),
1129 mCheckForFallbackFaces(false),
1130 mIsSharedFamily(false),
1131 mHasFontEntry(false) {}
1133 FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont,
1134 mozilla::StyleGenericFontFamily aGeneric)
1135 : mOwnedFamily(aFamily),
1136 mGeneric(aGeneric),
1137 mFontCreated(true),
1138 mLoading(false),
1139 mInvalid(false),
1140 mCheckForFallbackFaces(false),
1141 mIsSharedFamily(false),
1142 mHasFontEntry(false) {
1143 NS_ASSERTION(aFont, "font pointer must not be null");
1144 NS_ASSERTION(!aFamily || aFamily->ContainsFace(aFont->GetFontEntry()),
1145 "font is not a member of the given family");
1146 NS_IF_ADDREF(aFamily);
1147 mFont = aFont;
1148 NS_ADDREF(aFont);
1151 FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry,
1152 mozilla::StyleGenericFontFamily aGeneric)
1153 : mOwnedFamily(aFamily),
1154 mGeneric(aGeneric),
1155 mFontCreated(false),
1156 mLoading(false),
1157 mInvalid(false),
1158 mCheckForFallbackFaces(false),
1159 mIsSharedFamily(false),
1160 mHasFontEntry(true) {
1161 NS_ASSERTION(aFontEntry, "font entry pointer must not be null");
1162 NS_ASSERTION(!aFamily || aFamily->ContainsFace(aFontEntry),
1163 "font is not a member of the given family");
1164 NS_IF_ADDREF(aFamily);
1165 mFontEntry = aFontEntry;
1166 NS_ADDREF(aFontEntry);
1169 FamilyFace(mozilla::fontlist::Family* aFamily, gfxFontEntry* aFontEntry,
1170 mozilla::StyleGenericFontFamily aGeneric)
1171 : mSharedFamily(aFamily),
1172 mGeneric(aGeneric),
1173 mFontCreated(false),
1174 mLoading(false),
1175 mInvalid(false),
1176 mCheckForFallbackFaces(false),
1177 mIsSharedFamily(true),
1178 mHasFontEntry(true) {
1179 MOZ_ASSERT(aFamily && aFontEntry && aFontEntry->mShmemFace);
1180 mFontEntry = aFontEntry;
1181 NS_ADDREF(aFontEntry);
1184 FamilyFace(const FamilyFace& aOtherFamilyFace)
1185 : mGeneric(aOtherFamilyFace.mGeneric),
1186 mFontCreated(aOtherFamilyFace.mFontCreated),
1187 mLoading(aOtherFamilyFace.mLoading),
1188 mInvalid(aOtherFamilyFace.mInvalid),
1189 mCheckForFallbackFaces(aOtherFamilyFace.mCheckForFallbackFaces),
1190 mIsSharedFamily(aOtherFamilyFace.mIsSharedFamily),
1191 mHasFontEntry(aOtherFamilyFace.mHasFontEntry) {
1192 if (mIsSharedFamily) {
1193 mSharedFamily = aOtherFamilyFace.mSharedFamily;
1194 if (mFontCreated) {
1195 mFont = aOtherFamilyFace.mFont;
1196 NS_ADDREF(mFont);
1197 } else if (mHasFontEntry) {
1198 mFontEntry = aOtherFamilyFace.mFontEntry;
1199 NS_ADDREF(mFontEntry);
1200 } else {
1201 mSharedFace = aOtherFamilyFace.mSharedFace;
1203 } else {
1204 mOwnedFamily = aOtherFamilyFace.mOwnedFamily;
1205 NS_IF_ADDREF(mOwnedFamily);
1206 if (mFontCreated) {
1207 mFont = aOtherFamilyFace.mFont;
1208 NS_ADDREF(mFont);
1209 } else {
1210 mFontEntry = aOtherFamilyFace.mFontEntry;
1211 NS_IF_ADDREF(mFontEntry);
1216 ~FamilyFace() {
1217 if (mFontCreated) {
1218 NS_RELEASE(mFont);
1220 if (!mIsSharedFamily) {
1221 NS_IF_RELEASE(mOwnedFamily);
1223 if (mHasFontEntry) {
1224 NS_RELEASE(mFontEntry);
1228 FamilyFace& operator=(const FamilyFace& aOther) {
1229 if (mFontCreated) {
1230 NS_RELEASE(mFont);
1232 if (!mIsSharedFamily) {
1233 NS_IF_RELEASE(mOwnedFamily);
1235 if (mHasFontEntry) {
1236 NS_RELEASE(mFontEntry);
1239 mGeneric = aOther.mGeneric;
1240 mFontCreated = aOther.mFontCreated;
1241 mLoading = aOther.mLoading;
1242 mInvalid = aOther.mInvalid;
1243 mIsSharedFamily = aOther.mIsSharedFamily;
1244 mHasFontEntry = aOther.mHasFontEntry;
1246 if (mIsSharedFamily) {
1247 mSharedFamily = aOther.mSharedFamily;
1248 if (mFontCreated) {
1249 mFont = aOther.mFont;
1250 NS_ADDREF(mFont);
1251 } else if (mHasFontEntry) {
1252 mFontEntry = aOther.mFontEntry;
1253 NS_ADDREF(mFontEntry);
1254 } else {
1255 mSharedFace = aOther.mSharedFace;
1257 } else {
1258 mOwnedFamily = aOther.mOwnedFamily;
1259 NS_IF_ADDREF(mOwnedFamily);
1260 if (mFontCreated) {
1261 mFont = aOther.mFont;
1262 NS_ADDREF(mFont);
1263 } else {
1264 mFontEntry = aOther.mFontEntry;
1265 NS_IF_ADDREF(mFontEntry);
1269 return *this;
1272 gfxFontFamily* OwnedFamily() const {
1273 MOZ_ASSERT(!mIsSharedFamily);
1274 return mOwnedFamily;
1276 mozilla::fontlist::Family* SharedFamily() const {
1277 MOZ_ASSERT(mIsSharedFamily);
1278 return mSharedFamily;
1280 gfxFont* Font() const { return mFontCreated ? mFont : nullptr; }
1282 gfxFontEntry* FontEntry() const {
1283 if (mFontCreated) {
1284 return mFont->GetFontEntry();
1286 if (mHasFontEntry) {
1287 return mFontEntry;
1289 if (mIsSharedFamily) {
1290 return gfxPlatformFontList::PlatformFontList()->GetOrCreateFontEntry(
1291 mSharedFace, SharedFamily());
1293 return nullptr;
1296 mozilla::StyleGenericFontFamily Generic() const { return mGeneric; }
1298 bool IsSharedFamily() const { return mIsSharedFamily; }
1299 bool IsUserFontContainer() const {
1300 gfxFontEntry* fe = FontEntry();
1301 return fe && fe->mIsUserFontContainer;
1303 bool IsLoading() const { return mLoading; }
1304 bool IsInvalid() const { return mInvalid; }
1305 void CheckState(bool& aSkipDrawing);
1306 void SetLoading(bool aIsLoading) { mLoading = aIsLoading; }
1307 void SetInvalid() { mInvalid = true; }
1308 bool CheckForFallbackFaces() const { return mCheckForFallbackFaces; }
1309 void SetCheckForFallbackFaces() { mCheckForFallbackFaces = true; }
1311 // Return true if we're currently loading (or waiting for) a resource that
1312 // may support the given character.
1313 bool IsLoadingFor(uint32_t aCh) {
1314 if (!IsLoading()) {
1315 return false;
1317 MOZ_ASSERT(IsUserFontContainer());
1318 auto* ufe = static_cast<gfxUserFontEntry*>(FontEntry());
1319 return ufe && ufe->CharacterInUnicodeRange(aCh);
1322 void SetFont(gfxFont* aFont) {
1323 NS_ASSERTION(aFont, "font pointer must not be null");
1324 NS_ADDREF(aFont);
1325 if (mFontCreated) {
1326 NS_RELEASE(mFont);
1327 } else if (mHasFontEntry) {
1328 NS_RELEASE(mFontEntry);
1329 mHasFontEntry = false;
1331 mFont = aFont;
1332 mFontCreated = true;
1333 mLoading = false;
1336 bool EqualsUserFont(const gfxUserFontEntry* aUserFont) const;
1338 private:
1339 union {
1340 gfxFontFamily* MOZ_OWNING_REF mOwnedFamily;
1341 mozilla::fontlist::Family* MOZ_NON_OWNING_REF mSharedFamily;
1343 // either a font or a font entry exists
1344 union {
1345 // Whichever of these fields is actually present will be a strong
1346 // reference, with refcounting handled manually.
1347 gfxFont* MOZ_OWNING_REF mFont;
1348 gfxFontEntry* MOZ_OWNING_REF mFontEntry;
1349 mozilla::fontlist::Face* MOZ_NON_OWNING_REF mSharedFace;
1351 mozilla::StyleGenericFontFamily mGeneric;
1352 bool mFontCreated : 1;
1353 bool mLoading : 1;
1354 bool mInvalid : 1;
1355 bool mCheckForFallbackFaces : 1;
1356 bool mIsSharedFamily : 1;
1357 bool mHasFontEntry : 1;
1360 nsPresContext* mPresContext = nullptr;
1362 // List of font families, either named or generic.
1363 // Generic names map to system pref fonts based on language.
1364 mozilla::StyleFontFamilyList mFamilyList;
1366 // Fontlist containing a font entry for each family found. gfxFont objects
1367 // are created as needed and userfont loads are initiated when needed.
1368 // Code should be careful about addressing this array directly.
1369 nsTArray<FamilyFace> mFonts;
1371 RefPtr<gfxFont> mDefaultFont;
1372 gfxFontStyle mStyle;
1374 RefPtr<nsAtom> mLanguage;
1376 gfxFloat mUnderlineOffset;
1377 gfxFloat mHyphenWidth;
1378 gfxFloat mDevToCssSize;
1380 RefPtr<gfxUserFontSet> mUserFontSet;
1381 uint64_t mCurrGeneration; // track the current user font set generation,
1382 // rebuild font list if needed
1384 gfxTextPerfMetrics* mTextPerf;
1386 // Cache a textrun representing an ellipsis (useful for CSS text-overflow)
1387 // at a specific appUnitsPerDevPixel size and orientation
1388 RefPtr<gfxTextRun> mCachedEllipsisTextRun;
1390 // cache the most recent pref font to avoid general pref font lookup
1391 FontFamily mLastPrefFamily;
1392 RefPtr<gfxFont> mLastPrefFont;
1393 eFontPrefLang mLastPrefLang; // lang group for last pref font
1394 eFontPrefLang mPageLang;
1395 bool mLastPrefFirstFont; // is this the first font in the list of pref fonts
1396 // for this lang group?
1398 bool mSkipDrawing; // hide text while waiting for a font
1399 // download to complete (or fallback
1400 // timer to fire)
1402 bool mExplicitLanguage; // Does mLanguage come from an explicit attribute?
1404 eFontPresentation mEmojiPresentation = eFontPresentation::Any;
1406 // Generic font family used to select among font prefs during fallback.
1407 mozilla::StyleGenericFontFamily mFallbackGeneric =
1408 mozilla::StyleGenericFontFamily::None;
1410 uint32_t mFontListGeneration = 0; // platform font list generation for this
1411 // fontgroup
1414 * Textrun creation short-cuts for special cases where we don't need to
1415 * call a font shaper to generate glyphs.
1417 already_AddRefed<gfxTextRun> MakeEmptyTextRun(
1418 const Parameters* aParams, mozilla::gfx::ShapedTextFlags aFlags,
1419 nsTextFrameUtils::Flags aFlags2);
1421 already_AddRefed<gfxTextRun> MakeSpaceTextRun(
1422 const Parameters* aParams, mozilla::gfx::ShapedTextFlags aFlags,
1423 nsTextFrameUtils::Flags aFlags2);
1425 template <typename T>
1426 already_AddRefed<gfxTextRun> MakeBlankTextRun(
1427 const T* aString, uint32_t aLength, const Parameters* aParams,
1428 mozilla::gfx::ShapedTextFlags aFlags, nsTextFrameUtils::Flags aFlags2);
1430 // Initialize the list of fonts
1431 void BuildFontList();
1433 // Get the font at index i within the fontlist, for character aCh (in case
1434 // of fonts with multiple resources and unicode-range partitioning).
1435 // Will initiate userfont load if not already loaded.
1436 // May return null if userfont not loaded or if font invalid.
1437 // If *aLoading is true, a relevant resource is already being loaded so no
1438 // new download will be initiated; if a download is started, *aLoading will
1439 // be set to true on return.
1440 already_AddRefed<gfxFont> GetFontAt(uint32_t i, uint32_t aCh, bool* aLoading);
1442 // Simplified version of GetFontAt() for use where we just need a font for
1443 // metrics, math layout tables, etc.
1444 already_AddRefed<gfxFont> GetFontAt(uint32_t i, uint32_t aCh = 0x20) {
1445 bool loading = false;
1446 return GetFontAt(i, aCh, &loading);
1449 // will always return a font or force a shutdown
1450 already_AddRefed<gfxFont> GetDefaultFont();
1452 // Init this font group's font metrics. If there no bad fonts, you don't need
1453 // to call this. But if there are one or more bad fonts which have bad
1454 // underline offset, you should call this with the *first* bad font.
1455 void InitMetricsForBadFont(gfxFont* aBadFont);
1457 // Set up the textrun glyphs for an entire text run:
1458 // find script runs, and then call InitScriptRun for each
1459 template <typename T>
1460 void InitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
1461 const T* aString, uint32_t aLength,
1462 gfxMissingFontRecorder* aMFR);
1464 // InitTextRun helper to handle a single script run, by finding font ranges
1465 // and calling each font's InitTextRun() as appropriate
1466 template <typename T>
1467 void InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
1468 const T* aString, uint32_t aScriptRunStart,
1469 uint32_t aScriptRunEnd, Script aRunScript,
1470 gfxMissingFontRecorder* aMFR);
1472 // Helper for font-matching:
1473 // search all faces in a family for a fallback in cases where it's unclear
1474 // whether the family might have a font for a given character
1475 already_AddRefed<gfxFont> FindFallbackFaceForChar(
1476 const FamilyFace& aFamily, uint32_t aCh, uint32_t aNextCh,
1477 eFontPresentation aPresentation);
1479 already_AddRefed<gfxFont> FindFallbackFaceForChar(
1480 mozilla::fontlist::Family* aFamily, uint32_t aCh, uint32_t aNextCh,
1481 eFontPresentation aPresentation);
1483 already_AddRefed<gfxFont> FindFallbackFaceForChar(
1484 gfxFontFamily* aFamily, uint32_t aCh, uint32_t aNextCh,
1485 eFontPresentation aPresentation);
1487 // helper methods for looking up fonts
1489 // lookup and add a font with a given name (i.e. *not* a generic!)
1490 void AddPlatformFont(const nsACString& aName, bool aQuotedName,
1491 nsTArray<FamilyAndGeneric>& aFamilyList);
1493 // do style selection and add entries to list
1494 void AddFamilyToFontList(gfxFontFamily* aFamily,
1495 mozilla::StyleGenericFontFamily aGeneric);
1496 void AddFamilyToFontList(mozilla::fontlist::Family* aFamily,
1497 mozilla::StyleGenericFontFamily aGeneric);
1500 // A "missing font recorder" is to be used during text-run creation to keep
1501 // a record of any scripts encountered for which font coverage was lacking;
1502 // when Flush() is called, it sends a notification that front-end code can use
1503 // to download fonts on demand (or whatever else it wants to do).
1505 #define GFX_MISSING_FONTS_NOTIFY_PREF "gfx.missing_fonts.notify"
1507 class gfxMissingFontRecorder {
1508 public:
1509 gfxMissingFontRecorder() {
1510 MOZ_COUNT_CTOR(gfxMissingFontRecorder);
1511 memset(&mMissingFonts, 0, sizeof(mMissingFonts));
1514 ~gfxMissingFontRecorder() {
1515 #ifdef DEBUG
1516 for (uint32_t i = 0; i < kNumScriptBitsWords; i++) {
1517 NS_ASSERTION(mMissingFonts[i] == 0,
1518 "failed to flush the missing-font recorder");
1520 #endif
1521 MOZ_COUNT_DTOR(gfxMissingFontRecorder);
1524 // record this script code in our mMissingFonts bitset
1525 void RecordScript(mozilla::intl::Script aScriptCode) {
1526 mMissingFonts[static_cast<uint32_t>(aScriptCode) >> 5] |=
1527 (1 << (static_cast<uint32_t>(aScriptCode) & 0x1f));
1530 // send a notification of any missing-scripts that have been
1531 // recorded, and clear the mMissingFonts set for re-use
1532 void Flush();
1534 // forget any missing-scripts that have been recorded up to now;
1535 // called before discarding a recorder we no longer care about
1536 void Clear() { memset(&mMissingFonts, 0, sizeof(mMissingFonts)); }
1538 private:
1539 // Number of 32-bit words needed for the missing-script flags
1540 static const uint32_t kNumScriptBitsWords =
1541 ((static_cast<int>(mozilla::intl::Script::NUM_SCRIPT_CODES) + 31) / 32);
1542 uint32_t mMissingFonts[kNumScriptBitsWords];
1545 #endif