1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
14 #include "gfxSkipChars.h"
15 #include "gfxPlatform.h"
16 #include "mozilla/MemoryReporting.h"
18 #include "harfbuzz/hb.h"
19 #include "nsUnicodeScriptCodes.h"
28 class gfxTextContextPaint
;
30 class nsILanguageAtomService
;
31 class gfxMissingFontRecorder
;
34 * Callback for Draw() to use when drawing text with mode
35 * DrawMode::GLYPH_PATH.
37 struct gfxTextRunDrawCallbacks
{
40 * Constructs a new DrawCallbacks object.
42 * @param aShouldPaintSVGGlyphs If true, SVG glyphs will be
43 * painted and the NotifyBeforeSVGGlyphPainted/NotifyAfterSVGGlyphPainted
44 * callbacks will be invoked for each SVG glyph. If false, SVG glyphs
45 * will not be painted; fallback plain glyphs are not emitted either.
47 explicit gfxTextRunDrawCallbacks(bool aShouldPaintSVGGlyphs
= false)
48 : mShouldPaintSVGGlyphs(aShouldPaintSVGGlyphs
)
53 * Called when a path has been emitted to the gfxContext when
54 * painting a text run. This can be called any number of times,
55 * due to partial ligatures and intervening SVG glyphs.
57 virtual void NotifyGlyphPathEmitted() = 0;
60 * Called just before an SVG glyph has been painted to the gfxContext.
62 virtual void NotifyBeforeSVGGlyphPainted() { }
65 * Called just after an SVG glyph has been painted to the gfxContext.
67 virtual void NotifyAfterSVGGlyphPainted() { }
69 bool mShouldPaintSVGGlyphs
;
73 * gfxTextRun is an abstraction for drawing and measuring substrings of a run
74 * of text. It stores runs of positioned glyph data, each run having a single
75 * gfxFont. The glyphs are associated with a string of source text, and the
76 * gfxTextRun APIs take parameters that are offsets into that source text.
78 * gfxTextRuns are not refcounted. They should be deleted when no longer required.
80 * gfxTextRuns are mostly immutable. The only things that can change are
81 * inter-cluster spacing and line break placement. Spacing is always obtained
82 * lazily by methods that need it, it is not cached. Line breaks are stored
83 * persistently (insofar as they affect the shaping of glyphs; gfxTextRun does
84 * not actually do anything to explicitly account for line breaks). Initially
85 * there are no line breaks. The textrun can record line breaks before or after
86 * any given cluster. (Line breaks specified inside clusters are ignored.)
88 * It is important that zero-length substrings are handled correctly. This will
91 class gfxTextRun
: public gfxShapedText
{
94 // Override operator delete to properly free the object that was
95 // allocated via moz_malloc.
96 void operator delete(void* p
) {
100 virtual ~gfxTextRun();
102 typedef gfxFont::RunMetrics Metrics
;
104 // Public textrun API for general use
106 bool IsClusterStart(uint32_t aPos
) {
107 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
108 return mCharacterGlyphs
[aPos
].IsClusterStart();
110 bool IsLigatureGroupStart(uint32_t aPos
) {
111 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
112 return mCharacterGlyphs
[aPos
].IsLigatureGroupStart();
114 bool CanBreakLineBefore(uint32_t aPos
) {
115 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
116 return mCharacterGlyphs
[aPos
].CanBreakBefore() ==
117 CompressedGlyph::FLAG_BREAK_TYPE_NORMAL
;
119 bool CanHyphenateBefore(uint32_t aPos
) {
120 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
121 return mCharacterGlyphs
[aPos
].CanBreakBefore() ==
122 CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN
;
125 bool CharIsSpace(uint32_t aPos
) {
126 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
127 return mCharacterGlyphs
[aPos
].CharIsSpace();
129 bool CharIsTab(uint32_t aPos
) {
130 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
131 return mCharacterGlyphs
[aPos
].CharIsTab();
133 bool CharIsNewline(uint32_t aPos
) {
134 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
135 return mCharacterGlyphs
[aPos
].CharIsNewline();
137 bool CharIsLowSurrogate(uint32_t aPos
) {
138 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
139 return mCharacterGlyphs
[aPos
].CharIsLowSurrogate();
142 // All uint32_t aStart, uint32_t aLength ranges below are restricted to
143 // grapheme cluster boundaries! All offsets are in terms of the string
144 // passed into MakeTextRun.
146 // All coordinates are in layout/app units
149 * Set the potential linebreaks for a substring of the textrun. These are
150 * the "allow break before" points. Initially, there are no potential
153 * This can change glyphs and/or geometry! Some textruns' shapes
154 * depend on potential line breaks (e.g., title-case-converting textruns).
155 * This function is virtual so that those textruns can reshape themselves.
157 * @return true if this changed the linebreaks, false if the new line
158 * breaks are the same as the old
160 virtual bool SetPotentialLineBreaks(uint32_t aStart
, uint32_t aLength
,
161 uint8_t *aBreakBefore
,
162 gfxContext
*aRefContext
);
165 * Layout provides PropertyProvider objects. These allow detection of
166 * potential line break points and computation of spacing. We pass the data
167 * this way to allow lazy data acquisition; for example BreakAndMeasureText
168 * will want to only ask for properties of text it's actually looking at.
170 * NOTE that requested spacing may not actually be applied, if the textrun
171 * is unable to apply it in some context. Exception: spacing around a
172 * whitespace character MUST always be applied.
174 class PropertyProvider
{
176 // Detect hyphenation break opportunities in the given range; breaks
177 // not at cluster boundaries will be ignored.
178 virtual void GetHyphenationBreaks(uint32_t aStart
, uint32_t aLength
,
179 bool *aBreakBefore
) = 0;
181 // Returns the provider's hyphenation setting, so callers can decide
182 // whether it is necessary to call GetHyphenationBreaks.
183 // Result is an NS_STYLE_HYPHENS_* value.
184 virtual int8_t GetHyphensOption() = 0;
186 // Returns the extra width that will be consumed by a hyphen. This should
187 // be constant for a given textrun.
188 virtual gfxFloat
GetHyphenWidth() = 0;
190 typedef gfxFont::Spacing Spacing
;
193 * Get the spacing around the indicated characters. Spacing must be zero
194 * inside clusters. In other words, if character i is not
195 * CLUSTER_START, then character i-1 must have zero after-spacing and
196 * character i must have zero before-spacing.
198 virtual void GetSpacing(uint32_t aStart
, uint32_t aLength
,
199 Spacing
*aSpacing
) = 0;
201 // Returns a gfxContext that can be used to measure the hyphen glyph.
202 // Only called if the hyphen width is requested.
203 virtual already_AddRefed
<gfxContext
> GetContext() = 0;
205 // Return the appUnitsPerDevUnit value to be used when measuring.
206 // Only called if the hyphen width is requested.
207 virtual uint32_t GetAppUnitsPerDevUnit() = 0;
210 class ClusterIterator
{
212 explicit ClusterIterator(gfxTextRun
*aTextRun
);
218 uint32_t Position() const {
222 uint32_t ClusterLength() const;
224 gfxFloat
ClusterAdvance(PropertyProvider
*aProvider
) const;
227 gfxTextRun
*mTextRun
;
228 uint32_t mCurrentChar
;
232 * Draws a substring. Uses only GetSpacing from aBreakProvider.
233 * The provided point is the baseline origin on the left of the string
234 * for LTR, on the right of the string for RTL.
235 * @param aAdvanceWidth if non-null, the advance width of the substring
238 * Drawing should respect advance widths in the sense that for LTR runs,
239 * Draw(ctx, pt, offset1, length1, dirty, &provider, &advance) followed by
240 * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1 + length1, length2,
241 * dirty, &provider, nullptr) should have the same effect as
242 * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr).
243 * For RTL runs the rule is:
244 * Draw(ctx, pt, offset1 + length1, length2, dirty, &provider, &advance) followed by
245 * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1, length1,
246 * dirty, &provider, nullptr) should have the same effect as
247 * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr).
249 * Glyphs should be drawn in logical content order, which can be significant
250 * if they overlap (perhaps due to negative spacing).
252 void Draw(gfxContext
*aContext
, gfxPoint aPt
,
254 uint32_t aStart
, uint32_t aLength
,
255 PropertyProvider
*aProvider
,
256 gfxFloat
*aAdvanceWidth
, gfxTextContextPaint
*aContextPaint
,
257 gfxTextRunDrawCallbacks
*aCallbacks
= nullptr);
260 * Computes the ReflowMetrics for a substring.
261 * Uses GetSpacing from aBreakProvider.
262 * @param aBoundingBoxType which kind of bounding box (loose/tight)
264 Metrics
MeasureText(uint32_t aStart
, uint32_t aLength
,
265 gfxFont::BoundingBoxType aBoundingBoxType
,
266 gfxContext
*aRefContextForTightBoundingBox
,
267 PropertyProvider
*aProvider
);
270 * Computes just the advance width for a substring.
271 * Uses GetSpacing from aBreakProvider.
272 * If aSpacing is not null, the spacing attached before and after
273 * the substring would be returned in it. NOTE: the spacing is
274 * included in the advance width.
276 gfxFloat
GetAdvanceWidth(uint32_t aStart
, uint32_t aLength
,
277 PropertyProvider
*aProvider
,
278 PropertyProvider::Spacing
* aSpacing
= nullptr);
281 * Clear all stored line breaks for the given range (both before and after),
282 * and then set the line-break state before aStart to aBreakBefore and
283 * after the last cluster to aBreakAfter.
285 * We require that before and after line breaks be consistent. For clusters
286 * i and i+1, we require that if there is a break after cluster i, a break
287 * will be specified before cluster i+1. This may be temporarily violated
288 * (e.g. after reflowing line L and before reflowing line L+1); to handle
289 * these temporary violations, we say that there is a break betwen i and i+1
290 * if a break is specified after i OR a break is specified before i+1.
292 * This can change textrun geometry! The existence of a linebreak can affect
293 * the advance width of the cluster before the break (when kerning) or the
294 * geometry of one cluster before the break or any number of clusters
295 * after the break. (The one-cluster-before-the-break limit is somewhat
296 * arbitrary; if some scripts require breaking it, then we need to
297 * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase
298 * it could affect the layout of frames before it...)
300 * We return true if glyphs or geometry changed, false otherwise. This
301 * function is virtual so that gfxTextRun subclasses can reshape
304 * @param aAdvanceWidthDelta if non-null, returns the change in advance
305 * width of the given range.
307 virtual bool SetLineBreaks(uint32_t aStart
, uint32_t aLength
,
308 bool aLineBreakBefore
, bool aLineBreakAfter
,
309 gfxFloat
*aAdvanceWidthDelta
,
310 gfxContext
*aRefContext
);
314 // Measure the range of text as if there is no break before it.
315 eSuppressInitialBreak
,
316 // Measure the range of text as if it contains no break
321 * Finds the longest substring that will fit into the given width.
322 * Uses GetHyphenationBreaks and GetSpacing from aBreakProvider.
323 * Guarantees the following:
324 * -- 0 <= result <= aMaxLength
325 * -- result is the maximal value of N such that either
326 * N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
327 * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
328 * OR N == aMaxLength && GetAdvanceWidth(aStart, N) <= aWidth
329 * where GetAdvanceWidth assumes the effect of
330 * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
331 * -- if no such N exists, then result is the smallest N such that
332 * N < aMaxLength && line break at N
333 * OR N < aMaxLength && hyphen break at N
336 * The call has the effect of
337 * SetLineBreaks(aStart, result, aLineBreakBefore, result < aMaxLength, aProvider)
338 * and the returned metrics and the invariants above reflect this.
340 * @param aMaxLength this can be UINT32_MAX, in which case the length used
341 * is up to the end of the string
342 * @param aLineBreakBefore set to true if and only if there is an actual
343 * line break at the start of this string.
344 * @param aSuppressBreak what break should be suppressed.
345 * @param aTrimWhitespace if non-null, then we allow a trailing run of
346 * spaces to be trimmed; the width of the space(s) will not be included in
347 * the measured string width for comparison with the limit aWidth, and
348 * trimmed spaces will not be included in returned metrics. The width
349 * of the trimmed spaces will be returned in aTrimWhitespace.
350 * Trimmed spaces are still counted in the "characters fit" result.
351 * @param aMetrics if non-null, we fill this in for the returned substring.
352 * If a hyphenation break was used, the hyphen is NOT included in the returned metrics.
353 * @param aBoundingBoxType whether to make the bounding box in aMetrics tight
354 * @param aRefContextForTightBoundingBox a reference context to get the
355 * tight bounding box, if requested
356 * @param aUsedHyphenation if non-null, records if we selected a hyphenation break
357 * @param aLastBreak if non-null and result is aMaxLength, we set this to
358 * the maximal N such that
359 * N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
360 * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
361 * or UINT32_MAX if no such N exists, where GetAdvanceWidth assumes
363 * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
365 * @param aCanWordWrap true if we can break between any two grapheme
366 * clusters. This is set by word-wrap: break-word
368 * @param aBreakPriority in/out the priority of the break opportunity
369 * saved in the line. If we are prioritizing break opportunities, we will
370 * not set a break with a lower priority. @see gfxBreakPriority.
372 * Note that negative advance widths are possible especially if negative
373 * spacing is provided.
375 uint32_t BreakAndMeasureText(uint32_t aStart
, uint32_t aMaxLength
,
376 bool aLineBreakBefore
, gfxFloat aWidth
,
377 PropertyProvider
*aProvider
,
378 SuppressBreak aSuppressBreak
,
379 gfxFloat
*aTrimWhitespace
,
381 gfxFont::BoundingBoxType aBoundingBoxType
,
382 gfxContext
*aRefContextForTightBoundingBox
,
383 bool *aUsedHyphenation
,
384 uint32_t *aLastBreak
,
386 gfxBreakPriority
*aBreakPriority
);
389 * Update the reference context.
390 * XXX this is a hack. New text frame does not call this. Use only
391 * temporarily for old text frame.
393 void SetContext(gfxContext
*aContext
) {}
397 void *GetUserData() const { return mUserData
; }
398 void SetUserData(void *aUserData
) { mUserData
= aUserData
; }
400 void SetFlagBits(uint32_t aFlags
) {
401 NS_ASSERTION(!(aFlags
& ~gfxTextRunFactory::SETTABLE_FLAGS
),
402 "Only user flags should be mutable");
405 void ClearFlagBits(uint32_t aFlags
) {
406 NS_ASSERTION(!(aFlags
& ~gfxTextRunFactory::SETTABLE_FLAGS
),
407 "Only user flags should be mutable");
410 const gfxSkipChars
& GetSkipChars() const { return mSkipChars
; }
411 gfxFontGroup
*GetFontGroup() const { return mFontGroup
; }
414 // Call this, don't call "new gfxTextRun" directly. This does custom
415 // allocation and initialization
416 static gfxTextRun
*Create(const gfxTextRunFactory::Parameters
*aParams
,
417 uint32_t aLength
, gfxFontGroup
*aFontGroup
,
420 // The text is divided into GlyphRuns as necessary
422 nsRefPtr
<gfxFont
> mFont
; // never null
423 uint32_t mCharacterOffset
; // into original UTF16 string
425 uint16_t mOrientation
; // gfxTextRunFactory::TEXT_ORIENT_* value
428 class GlyphRunIterator
{
430 GlyphRunIterator(gfxTextRun
*aTextRun
, uint32_t aStart
, uint32_t aLength
)
431 : mTextRun(aTextRun
), mStartOffset(aStart
), mEndOffset(aStart
+ aLength
) {
432 mNextIndex
= mTextRun
->FindFirstGlyphRunContaining(aStart
);
435 GlyphRun
*GetGlyphRun() { return mGlyphRun
; }
436 uint32_t GetStringStart() { return mStringStart
; }
437 uint32_t GetStringEnd() { return mStringEnd
; }
439 gfxTextRun
*mTextRun
;
441 uint32_t mStringStart
;
444 uint32_t mStartOffset
;
448 class GlyphRunOffsetComparator
{
450 bool Equals(const GlyphRun
& a
,
451 const GlyphRun
& b
) const
453 return a
.mCharacterOffset
== b
.mCharacterOffset
;
456 bool LessThan(const GlyphRun
& a
,
457 const GlyphRun
& b
) const
459 return a
.mCharacterOffset
< b
.mCharacterOffset
;
463 friend class GlyphRunIterator
;
464 friend class FontSelector
;
466 // API for setting up the textrun glyphs. Should only be called by
467 // things that construct textruns.
469 * We've found a run of text that should use a particular font. Call this
470 * only during initialization when font substitution has been computed.
471 * Call it before setting up the glyphs for the characters in this run;
472 * SetMissingGlyph requires that the correct glyphrun be installed.
474 * If aForceNewRun, a new glyph run will be added, even if the
475 * previously added run uses the same font. If glyph runs are
476 * added out of strictly increasing aStartCharIndex order (via
477 * force), then SortGlyphRuns must be called after all glyph runs
478 * are added before any further operations are performed with this
481 nsresult
AddGlyphRun(gfxFont
*aFont
, uint8_t aMatchType
,
482 uint32_t aStartCharIndex
, bool aForceNewRun
,
483 uint16_t aOrientation
);
484 void ResetGlyphRuns() { mGlyphRuns
.Clear(); }
485 void SortGlyphRuns();
486 void SanitizeGlyphRuns();
488 CompressedGlyph
* GetCharacterGlyphs() {
489 NS_ASSERTION(mCharacterGlyphs
, "failed to initialize mCharacterGlyphs");
490 return mCharacterGlyphs
;
493 // clean out results from shaping in progress, used for fallback scenarios
494 void ClearGlyphsAndCharacters();
496 void SetSpaceGlyph(gfxFont
*aFont
, gfxContext
*aContext
, uint32_t aCharIndex
,
497 uint16_t aOrientation
);
499 // Set the glyph data for the given character index to the font's
500 // space glyph, IF this can be done as a "simple" glyph record
501 // (not requiring a DetailedGlyph entry). This avoids the need to call
502 // the font shaper and go through the shaped-word cache for most spaces.
504 // The parameter aSpaceChar is the original character code for which
505 // this space glyph is being used; if this is U+0020, we need to record
506 // that it could be trimmed at a run edge, whereas other kinds of space
507 // (currently just U+00A0) would not be trimmable/breakable.
509 // Returns true if it was able to set simple glyph data for the space;
510 // if it returns false, the caller needs to fall back to some other
511 // means to create the necessary (detailed) glyph data.
512 bool SetSpaceGlyphIfSimple(gfxFont
*aFont
, gfxContext
*aContext
,
513 uint32_t aCharIndex
, char16_t aSpaceChar
,
514 uint16_t aOrientation
);
516 // Record the positions of specific characters that layout may need to
517 // detect in the textrun, even though it doesn't have an explicit copy
518 // of the original text. These are recorded using flag bits in the
519 // CompressedGlyph record; if necessary, we convert "simple" glyph records
520 // to "complex" ones as the Tab and Newline flags are not present in
521 // simple CompressedGlyph records.
522 void SetIsTab(uint32_t aIndex
) {
523 CompressedGlyph
*g
= &mCharacterGlyphs
[aIndex
];
524 if (g
->IsSimpleGlyph()) {
525 DetailedGlyph
*details
= AllocateDetailedGlyphs(aIndex
, 1);
526 details
->mGlyphID
= g
->GetSimpleGlyph();
527 details
->mAdvance
= g
->GetSimpleAdvance();
528 details
->mXOffset
= details
->mYOffset
= 0;
529 SetGlyphs(aIndex
, CompressedGlyph().SetComplex(true, true, 1), details
);
533 void SetIsNewline(uint32_t aIndex
) {
534 CompressedGlyph
*g
= &mCharacterGlyphs
[aIndex
];
535 if (g
->IsSimpleGlyph()) {
536 DetailedGlyph
*details
= AllocateDetailedGlyphs(aIndex
, 1);
537 details
->mGlyphID
= g
->GetSimpleGlyph();
538 details
->mAdvance
= g
->GetSimpleAdvance();
539 details
->mXOffset
= details
->mYOffset
= 0;
540 SetGlyphs(aIndex
, CompressedGlyph().SetComplex(true, true, 1), details
);
544 void SetIsLowSurrogate(uint32_t aIndex
) {
545 SetGlyphs(aIndex
, CompressedGlyph().SetComplex(false, false, 0), nullptr);
546 mCharacterGlyphs
[aIndex
].SetIsLowSurrogate();
550 * Prefetch all the glyph extents needed to ensure that Measure calls
551 * on this textrun not requesting tight boundingBoxes will succeed. Note
552 * that some glyph extents might not be fetched due to OOM or other
555 void FetchGlyphExtents(gfxContext
*aRefContext
);
557 uint32_t CountMissingGlyphs();
558 const GlyphRun
*GetGlyphRuns(uint32_t *aNumGlyphRuns
) {
559 *aNumGlyphRuns
= mGlyphRuns
.Length();
560 return mGlyphRuns
.Elements();
562 // Returns the index of the GlyphRun containing the given offset.
563 // Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
564 uint32_t FindFirstGlyphRunContaining(uint32_t aOffset
);
566 // Copy glyph data from a ShapedWord into this textrun.
567 void CopyGlyphDataFrom(gfxShapedWord
*aSource
, uint32_t aStart
);
569 // Copy glyph data for a range of characters from aSource to this
571 void CopyGlyphDataFrom(gfxTextRun
*aSource
, uint32_t aStart
,
572 uint32_t aLength
, uint32_t aDest
);
574 nsExpirationState
*GetExpirationState() { return &mExpirationState
; }
576 // Tell the textrun to release its reference to its creating gfxFontGroup
577 // immediately, rather than on destruction. This is used for textruns
578 // that are actually owned by a gfxFontGroup, so that they don't keep it
579 // permanently alive due to a circular reference. (The caller of this is
580 // taking responsibility for ensuring the textrun will not outlive its
582 void ReleaseFontGroup();
584 struct LigatureData
{
585 // textrun offsets of the start and end of the containing ligature
586 uint32_t mLigatureStart
;
587 uint32_t mLigatureEnd
;
588 // appunits advance to the start of the ligature part within the ligature;
589 // never includes any spacing
590 gfxFloat mPartAdvance
;
591 // appunits width of the ligature part; includes before-spacing
592 // when the part is at the start of the ligature, and after-spacing
593 // when the part is as the end of the ligature
596 bool mClipBeforePart
;
600 // return storage used by this run, for memory reporter;
601 // nsTransformedTextRun needs to override this as it holds additional data
602 virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
)
604 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
)
607 // Get the size, if it hasn't already been gotten, marking as it goes.
608 size_t MaybeSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) {
609 if (mFlags
& gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED
) {
612 mFlags
|= gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED
;
613 return SizeOfIncludingThis(aMallocSizeOf
);
615 void ResetSizeOfAccountingFlags() {
616 mFlags
&= ~gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED
;
619 // shaping state - for some font features, fallback is required that
620 // affects the entire run. for example, fallback for one script/font
621 // portion of a textrun requires fallback to be applied to the entire run
624 eShapingState_Normal
, // default state
625 eShapingState_ShapingWithFeature
, // have shaped with feature
626 eShapingState_ShapingWithFallback
, // have shaped with fallback
627 eShapingState_Aborted
, // abort initial iteration
628 eShapingState_ForceFallbackFeature
// redo with fallback forced on
631 ShapingState
GetShapingState() const { return mShapingState
; }
632 void SetShapingState(ShapingState aShapingState
) {
633 mShapingState
= aShapingState
;
637 void Dump(FILE* aOutput
);
642 * Create a textrun, and set its mCharacterGlyphs to point immediately
643 * after the base object; this is ONLY used in conjunction with placement
644 * new, after allocating a block large enough for the glyph records to
645 * follow the base textrun object.
647 gfxTextRun(const gfxTextRunFactory::Parameters
*aParams
,
648 uint32_t aLength
, gfxFontGroup
*aFontGroup
, uint32_t aFlags
);
651 * Helper for the Create() factory method to allocate the required
652 * glyph storage for a textrun object with the basic size aSize,
653 * plus room for aLength glyph records.
655 static void* AllocateStorageForTextRun(size_t aSize
, uint32_t aLength
);
657 // Pointer to the array of CompressedGlyph records; must be initialized
658 // when the object is constructed.
659 CompressedGlyph
*mCharacterGlyphs
;
662 // **** general helpers ****
664 // Get the total advance for a range of glyphs.
665 int32_t GetAdvanceForGlyphs(uint32_t aStart
, uint32_t aEnd
);
667 // Spacing for characters outside the range aSpacingStart/aSpacingEnd
668 // is assumed to be zero; such characters are not passed to aProvider.
669 // This is useful to protect aProvider from being passed character indices
670 // it is not currently able to handle.
671 bool GetAdjustedSpacingArray(uint32_t aStart
, uint32_t aEnd
,
672 PropertyProvider
*aProvider
,
673 uint32_t aSpacingStart
, uint32_t aSpacingEnd
,
674 nsTArray
<PropertyProvider::Spacing
> *aSpacing
);
676 // **** ligature helpers ****
677 // (Platforms do the actual ligaturization, but we need to do a bunch of stuff
678 // to handle requests that begin or end inside a ligature)
680 // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
681 LigatureData
ComputeLigatureData(uint32_t aPartStart
, uint32_t aPartEnd
,
682 PropertyProvider
*aProvider
);
683 gfxFloat
ComputePartialLigatureWidth(uint32_t aPartStart
, uint32_t aPartEnd
,
684 PropertyProvider
*aProvider
);
685 void DrawPartialLigature(gfxFont
*aFont
, uint32_t aStart
, uint32_t aEnd
,
686 gfxPoint
*aPt
, PropertyProvider
*aProvider
,
687 TextRunDrawParams
& aParams
, uint16_t aOrientation
);
688 // Advance aStart to the start of the nearest ligature; back up aEnd
689 // to the nearest ligature end; may result in *aStart == *aEnd
690 void ShrinkToLigatureBoundaries(uint32_t *aStart
, uint32_t *aEnd
);
691 // result in appunits
692 gfxFloat
GetPartialLigatureWidth(uint32_t aStart
, uint32_t aEnd
, PropertyProvider
*aProvider
);
693 void AccumulatePartialLigatureMetrics(gfxFont
*aFont
,
694 uint32_t aStart
, uint32_t aEnd
,
695 gfxFont::BoundingBoxType aBoundingBoxType
,
696 gfxContext
*aRefContext
,
697 PropertyProvider
*aProvider
,
698 uint16_t aOrientation
,
701 // **** measurement helper ****
702 void AccumulateMetricsForRun(gfxFont
*aFont
, uint32_t aStart
, uint32_t aEnd
,
703 gfxFont::BoundingBoxType aBoundingBoxType
,
704 gfxContext
*aRefContext
,
705 PropertyProvider
*aProvider
,
706 uint32_t aSpacingStart
, uint32_t aSpacingEnd
,
707 uint16_t aOrientation
,
710 // **** drawing helper ****
711 void DrawGlyphs(gfxFont
*aFont
, uint32_t aStart
, uint32_t aEnd
,
712 gfxPoint
*aPt
, PropertyProvider
*aProvider
,
713 uint32_t aSpacingStart
, uint32_t aSpacingEnd
,
714 TextRunDrawParams
& aParams
, uint16_t aOrientation
);
716 // XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
717 // for smaller size especially in the super-common one-glyphrun case
718 nsAutoTArray
<GlyphRun
,1> mGlyphRuns
;
721 gfxFontGroup
*mFontGroup
; // addrefed on creation, but our reference
722 // may be released by ReleaseFontGroup()
723 gfxSkipChars mSkipChars
;
724 nsExpirationState mExpirationState
;
726 bool mSkipDrawing
; // true if the font group we used had a user font
727 // download that's in progress, so we should hide text
728 // until the download completes (or timeout fires)
729 bool mReleasedFontGroup
; // we already called NS_RELEASE on
730 // mFontGroup, so don't do it again
732 // shaping state for handling variant fallback features
733 // such as subscript/superscript variant glyphs
734 ShapingState mShapingState
;
737 class gfxFontGroup
: public gfxTextRunFactory
{
739 static void Shutdown(); // platform must call this to release the languageAtomService
741 gfxFontGroup(const mozilla::FontFamilyList
& aFontFamilyList
,
742 const gfxFontStyle
*aStyle
,
743 gfxUserFontSet
*aUserFontSet
= nullptr);
745 virtual ~gfxFontGroup();
747 // Returns first valid font in the fontlist or default font.
748 // Initiates userfont loads if userfont not loaded
749 virtual gfxFont
* GetFirstValidFont(uint32_t aCh
= 0x20);
751 // Returns the first font in the font-group that has an OpenType MATH table,
752 // or null if no such font is available. The GetMathConstant methods may be
753 // called on the returned font.
754 gfxFont
*GetFirstMathFont();
756 const gfxFontStyle
*GetStyle() const { return &mStyle
; }
758 virtual gfxFontGroup
*Copy(const gfxFontStyle
*aStyle
);
761 * The listed characters should be treated as invisible and zero-width
762 * when creating textruns.
764 static bool IsInvalidChar(uint8_t ch
);
765 static bool IsInvalidChar(char16_t ch
);
768 * Make a textrun for a given string.
769 * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
770 * textrun will copy it.
771 * This calls FetchGlyphExtents on the textrun.
773 virtual gfxTextRun
*MakeTextRun(const char16_t
*aString
, uint32_t aLength
,
774 const Parameters
*aParams
, uint32_t aFlags
,
775 gfxMissingFontRecorder
*aMFR
);
777 * Make a textrun for a given string.
778 * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
779 * textrun will copy it.
780 * This calls FetchGlyphExtents on the textrun.
782 virtual gfxTextRun
*MakeTextRun(const uint8_t *aString
, uint32_t aLength
,
783 const Parameters
*aParams
, uint32_t aFlags
,
784 gfxMissingFontRecorder
*aMFR
);
787 * Textrun creation helper for clients that don't want to pass
788 * a full Parameters record.
791 gfxTextRun
*MakeTextRun(const T
*aString
, uint32_t aLength
,
792 gfxContext
*aRefContext
,
793 int32_t aAppUnitsPerDevUnit
,
795 gfxMissingFontRecorder
*aMFR
)
797 gfxTextRunFactory::Parameters params
= {
798 aRefContext
, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit
800 return MakeTextRun(aString
, aLength
, ¶ms
, aFlags
, aMFR
);
804 * Get the (possibly-cached) width of the hyphen character.
805 * The aCtx and aAppUnitsPerDevUnit parameters will be used only if
806 * needed to initialize the cached hyphen width; otherwise they are
809 gfxFloat
GetHyphenWidth(gfxTextRun::PropertyProvider
* aProvider
);
812 * Make a text run representing a single hyphen character.
813 * This will use U+2010 HYPHEN if available in the first font,
814 * otherwise fall back to U+002D HYPHEN-MINUS.
815 * The caller is responsible for deleting the returned text run
816 * when no longer required.
818 gfxTextRun
*MakeHyphenTextRun(gfxContext
*aCtx
,
819 uint32_t aAppUnitsPerDevUnit
);
822 * Check whether a given font (specified by its gfxFontEntry)
823 * is already in the fontgroup's list of actual fonts
825 bool HasFont(const gfxFontEntry
*aFontEntry
);
827 // This returns the preferred underline for this font group.
828 // Some CJK fonts have wrong underline offset in its metrics.
829 // If this group has such "bad" font, each platform's gfxFontGroup
830 // initialized mUnderlineOffset. The value should be lower value of
831 // first font's metrics and the bad font's metrics. Otherwise, this
832 // returns from first font's metrics.
833 enum { UNDERLINE_OFFSET_NOT_SET
= INT16_MAX
};
834 virtual gfxFloat
GetUnderlineOffset();
836 virtual already_AddRefed
<gfxFont
>
837 FindFontForChar(uint32_t ch
, uint32_t prevCh
, uint32_t aNextCh
,
838 int32_t aRunScript
, gfxFont
*aPrevMatchedFont
,
839 uint8_t *aMatchType
);
841 // search through pref fonts for a character, return nullptr if no matching pref font
842 virtual already_AddRefed
<gfxFont
> WhichPrefFontSupportsChar(uint32_t aCh
);
844 already_AddRefed
<gfxFont
>
845 WhichSystemFontSupportsChar(uint32_t aCh
, uint32_t aNextCh
,
849 void ComputeRanges(nsTArray
<gfxTextRange
>& mRanges
,
850 const T
*aString
, uint32_t aLength
,
851 int32_t aRunScript
, uint16_t aOrientation
);
853 gfxUserFontSet
* GetUserFontSet();
855 // With downloadable fonts, the composition of the font group can change as fonts are downloaded
856 // for each change in state of the user font set, the generation value is bumped to avoid picking up
857 // previously created text runs in the text run word cache. For font groups based on stylesheets
858 // with no @font-face rule, this always returns 0.
859 uint64_t GetGeneration();
861 // generation of the latest fontset rebuild, 0 when no fontset present
862 uint64_t GetRebuildGeneration();
864 // used when logging text performance
865 gfxTextPerfMetrics
*GetTextPerfMetrics() { return mTextPerf
; }
866 void SetTextPerfMetrics(gfxTextPerfMetrics
*aTextPerf
) { mTextPerf
= aTextPerf
; }
868 // This will call UpdateUserFonts() if the user font set is changed.
869 void SetUserFontSet(gfxUserFontSet
*aUserFontSet
);
871 // If there is a user font set, check to see whether the font list or any
872 // caches need updating.
873 virtual void UpdateUserFonts();
875 bool ShouldSkipDrawing() const {
879 class LazyReferenceContextGetter
{
881 virtual already_AddRefed
<gfxContext
> GetRefContext() = 0;
883 // The gfxFontGroup keeps ownership of this textrun.
884 // It is only guaranteed to exist until the next call to GetEllipsisTextRun
885 // (which might use a different appUnitsPerDev value) for the font group,
886 // or until UpdateUserFonts is called, or the fontgroup is destroyed.
887 // Get it/use it/forget it :) - don't keep a reference that might go stale.
888 gfxTextRun
* GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel
,
889 LazyReferenceContextGetter
& aRefContextGetter
);
891 // helper method for resolving generic font families
893 ResolveGenericFontNames(mozilla::FontFamilyType aGenericType
,
895 nsTArray
<nsString
>& aGenericFamilies
);
900 FamilyFace() : mFamily(nullptr), mFontEntry(nullptr),
901 mNeedsBold(false), mFontCreated(false),
902 mLoading(false), mInvalid(false)
905 FamilyFace(gfxFontFamily
* aFamily
, gfxFont
* aFont
)
906 : mFamily(aFamily
), mNeedsBold(false), mFontCreated(true),
907 mLoading(false), mInvalid(false)
909 NS_ASSERTION(aFont
, "font pointer must not be null");
910 NS_ASSERTION(!aFamily
||
911 aFamily
->ContainsFace(aFont
->GetFontEntry()),
912 "font is not a member of the given family");
917 FamilyFace(gfxFontFamily
* aFamily
, gfxFontEntry
* aFontEntry
,
919 : mFamily(aFamily
), mNeedsBold(aNeedsBold
), mFontCreated(false),
920 mLoading(false), mInvalid(false)
922 NS_ASSERTION(aFontEntry
, "font entry pointer must not be null");
923 NS_ASSERTION(!aFamily
||
924 aFamily
->ContainsFace(aFontEntry
),
925 "font is not a member of the given family");
926 mFontEntry
= aFontEntry
;
927 NS_ADDREF(aFontEntry
);
930 FamilyFace(const FamilyFace
& aOtherFamilyFace
)
931 : mFamily(aOtherFamilyFace
.mFamily
),
932 mNeedsBold(aOtherFamilyFace
.mNeedsBold
),
933 mFontCreated(aOtherFamilyFace
.mFontCreated
),
934 mLoading(aOtherFamilyFace
.mLoading
),
935 mInvalid(aOtherFamilyFace
.mInvalid
)
938 mFont
= aOtherFamilyFace
.mFont
;
941 mFontEntry
= aOtherFamilyFace
.mFontEntry
;
942 NS_IF_ADDREF(mFontEntry
);
951 NS_IF_RELEASE(mFontEntry
);
955 FamilyFace
& operator=(const FamilyFace
& aOther
)
960 NS_IF_RELEASE(mFontEntry
);
963 mFamily
= aOther
.mFamily
;
964 mNeedsBold
= aOther
.mNeedsBold
;
965 mFontCreated
= aOther
.mFontCreated
;
966 mLoading
= aOther
.mLoading
;
967 mInvalid
= aOther
.mInvalid
;
970 mFont
= aOther
.mFont
;
973 mFontEntry
= aOther
.mFontEntry
;
974 NS_IF_ADDREF(mFontEntry
);
980 gfxFontFamily
* Family() const { return mFamily
.get(); }
981 gfxFont
* Font() const {
982 return mFontCreated
? mFont
: nullptr;
985 gfxFontEntry
* FontEntry() const {
986 return mFontCreated
? mFont
->GetFontEntry() : mFontEntry
;
989 bool NeedsBold() const { return mNeedsBold
; }
990 bool IsUserFontContainer() const {
991 return FontEntry()->mIsUserFontContainer
;
993 bool IsLoading() const { return mLoading
; }
994 bool IsInvalid() const { return mInvalid
; }
995 void CheckState(bool& aSkipDrawing
);
996 void SetLoading(bool aIsLoading
) { mLoading
= aIsLoading
; }
997 void SetInvalid() { mInvalid
= true; }
999 void SetFont(gfxFont
* aFont
)
1001 NS_ASSERTION(aFont
, "font pointer must not be null");
1006 NS_IF_RELEASE(mFontEntry
);
1009 mFontCreated
= true;
1014 nsRefPtr
<gfxFontFamily
> mFamily
;
1015 // either a font or a font entry exists
1018 gfxFontEntry
* mFontEntry
;
1020 bool mNeedsBold
: 1;
1021 bool mFontCreated
: 1;
1026 // List of font families, either named or generic.
1027 // Generic names map to system pref fonts based on language.
1028 mozilla::FontFamilyList mFamilyList
;
1030 // Fontlist containing a font entry for each family found. gfxFont objects
1031 // are created as needed and userfont loads are initiated when needed.
1032 // Code should be careful about addressing this array directly.
1033 nsTArray
<FamilyFace
> mFonts
;
1035 nsRefPtr
<gfxFont
> mDefaultFont
;
1036 gfxFontStyle mStyle
;
1038 gfxFloat mUnderlineOffset
;
1039 gfxFloat mHyphenWidth
;
1041 nsRefPtr
<gfxUserFontSet
> mUserFontSet
;
1042 uint64_t mCurrGeneration
; // track the current user font set generation, rebuild font list if needed
1044 gfxTextPerfMetrics
*mTextPerf
;
1046 // Cache a textrun representing an ellipsis (useful for CSS text-overflow)
1047 // at a specific appUnitsPerDevPixel size
1048 nsAutoPtr
<gfxTextRun
> mCachedEllipsisTextRun
;
1050 // cache the most recent pref font to avoid general pref font lookup
1051 nsRefPtr
<gfxFontFamily
> mLastPrefFamily
;
1052 nsRefPtr
<gfxFont
> mLastPrefFont
;
1053 eFontPrefLang mLastPrefLang
; // lang group for last pref font
1054 eFontPrefLang mPageLang
;
1055 bool mLastPrefFirstFont
; // is this the first font in the list of pref fonts for this lang group?
1057 bool mSkipDrawing
; // hide text while waiting for a font
1058 // download to complete (or fallback
1062 * Textrun creation short-cuts for special cases where we don't need to
1063 * call a font shaper to generate glyphs.
1065 gfxTextRun
*MakeEmptyTextRun(const Parameters
*aParams
, uint32_t aFlags
);
1066 gfxTextRun
*MakeSpaceTextRun(const Parameters
*aParams
, uint32_t aFlags
);
1067 gfxTextRun
*MakeBlankTextRun(uint32_t aLength
,
1068 const Parameters
*aParams
, uint32_t aFlags
);
1070 // Initialize the list of fonts
1071 void BuildFontList();
1073 // Get the font at index i within the fontlist.
1074 // Will initiate userfont load if not already loaded.
1075 // May return null if userfont not loaded or if font invalid
1076 virtual gfxFont
* GetFontAt(int32_t i
, uint32_t aCh
= 0x20);
1078 // Whether there's a font loading for a given family in the fontlist
1079 // for a given character
1080 bool FontLoadingForFamily(gfxFontFamily
* aFamily
, uint32_t aCh
) const;
1082 // will always return a font or force a shutdown
1083 gfxFont
* GetDefaultFont();
1085 // Init this font group's font metrics. If there no bad fonts, you don't need to call this.
1086 // But if there are one or more bad fonts which have bad underline offset,
1087 // you should call this with the *first* bad font.
1088 void InitMetricsForBadFont(gfxFont
* aBadFont
);
1090 // Set up the textrun glyphs for an entire text run:
1091 // find script runs, and then call InitScriptRun for each
1092 template<typename T
>
1093 void InitTextRun(gfxContext
*aContext
,
1094 gfxTextRun
*aTextRun
,
1097 gfxMissingFontRecorder
*aMFR
);
1099 // InitTextRun helper to handle a single script run, by finding font ranges
1100 // and calling each font's InitTextRun() as appropriate
1101 template<typename T
>
1102 void InitScriptRun(gfxContext
*aContext
,
1103 gfxTextRun
*aTextRun
,
1105 uint32_t aScriptRunStart
,
1106 uint32_t aScriptRunEnd
,
1108 gfxMissingFontRecorder
*aMFR
);
1110 // Helper for font-matching:
1111 // When matching the italic case, allow use of the regular face
1112 // if it supports a character but the italic one doesn't.
1113 // Return null if regular face doesn't support aCh
1114 already_AddRefed
<gfxFont
>
1115 FindNonItalicFaceForChar(gfxFontFamily
* aFamily
, uint32_t aCh
);
1117 // helper methods for looking up fonts
1119 // iterate over the fontlist, lookup names and expand generics
1120 void EnumerateFontList(nsIAtom
*aLanguage
, void *aClosure
= nullptr);
1122 // expand a generic to a list of specific names based on prefs
1123 void FindGenericFonts(mozilla::FontFamilyType aGenericType
,
1127 // lookup and add a font with a given name (i.e. *not* a generic!)
1128 virtual void FindPlatformFont(const nsAString
& aName
,
1132 static nsILanguageAtomService
* gLangService
;
1135 // A "missing font recorder" is to be used during text-run creation to keep
1136 // a record of any scripts encountered for which font coverage was lacking;
1137 // when Flush() is called, it sends a notification that front-end code can use
1138 // to download fonts on demand (or whatever else it wants to do).
1140 #define GFX_MISSING_FONTS_NOTIFY_PREF "gfx.missing_fonts.notify"
1142 class gfxMissingFontRecorder
{
1144 gfxMissingFontRecorder()
1146 MOZ_COUNT_CTOR(gfxMissingFontRecorder
);
1147 memset(&mMissingFonts
, 0, sizeof(mMissingFonts
));
1150 ~gfxMissingFontRecorder()
1153 for (uint32_t i
= 0; i
< kNumScriptBitsWords
; i
++) {
1154 NS_ASSERTION(mMissingFonts
[i
] == 0,
1155 "failed to flush the missing-font recorder");
1158 MOZ_COUNT_DTOR(gfxMissingFontRecorder
);
1161 // record this script code in our mMissingFonts bitset
1162 void RecordScript(int32_t aScriptCode
)
1164 mMissingFonts
[uint32_t(aScriptCode
) >> 5] |=
1165 (1 << (uint32_t(aScriptCode
) & 0x1f));
1168 // send a notification of any missing-scripts that have been
1169 // recorded, and clear the mMissingFonts set for re-use
1172 // forget any missing-scripts that have been recorded up to now;
1173 // called before discarding a recorder we no longer care about
1176 memset(&mMissingFonts
, 0, sizeof(mMissingFonts
));
1180 // Number of 32-bit words needed for the missing-script flags
1181 static const uint32_t kNumScriptBitsWords
=
1182 ((MOZ_NUM_SCRIPT_CODES
+ 31) / 32);
1183 uint32_t mMissingFonts
[kNumScriptBitsWords
];