Bumping manifests a=b2g-bump
[gecko.git] / gfx / thebes / gfxTextRun.h
blob8b3fcb2908cd2c19c5b03370dc0824d96d8f39d5
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/. */
6 #ifndef GFX_TEXTRUN_H
7 #define GFX_TEXTRUN_H
9 #include "gfxTypes.h"
10 #include "nsString.h"
11 #include "gfxPoint.h"
12 #include "gfxFont.h"
13 #include "nsTArray.h"
14 #include "gfxSkipChars.h"
15 #include "gfxPlatform.h"
16 #include "mozilla/MemoryReporting.h"
17 #include "DrawMode.h"
18 #include "harfbuzz/hb.h"
19 #include "nsUnicodeScriptCodes.h"
21 #ifdef DEBUG
22 #include <stdio.h>
23 #endif
25 class gfxContext;
26 class gfxFontGroup;
27 class gfxUserFontSet;
28 class gfxTextContextPaint;
29 class nsIAtom;
30 class nsILanguageAtomService;
31 class gfxMissingFontRecorder;
33 /**
34 * Callback for Draw() to use when drawing text with mode
35 * DrawMode::GLYPH_PATH.
37 struct gfxTextRunDrawCallbacks {
39 /**
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)
52 /**
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;
59 /**
60 * Called just before an SVG glyph has been painted to the gfxContext.
62 virtual void NotifyBeforeSVGGlyphPainted() { }
64 /**
65 * Called just after an SVG glyph has been painted to the gfxContext.
67 virtual void NotifyAfterSVGGlyphPainted() { }
69 bool mShouldPaintSVGGlyphs;
72 /**
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
89 * be on the test!
91 class gfxTextRun : public gfxShapedText {
92 public:
94 // Override operator delete to properly free the object that was
95 // allocated via moz_malloc.
96 void operator delete(void* p) {
97 moz_free(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
151 * linebreaks.
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 {
175 public:
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 {
211 public:
212 explicit ClusterIterator(gfxTextRun *aTextRun);
214 void Reset();
216 bool NextCluster();
218 uint32_t Position() const {
219 return mCurrentChar;
222 uint32_t ClusterLength() const;
224 gfxFloat ClusterAdvance(PropertyProvider *aProvider) const;
226 private:
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
236 * is returned here.
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,
253 DrawMode aDrawMode,
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
302 * properly.
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);
312 enum SuppressBreak {
313 eNoSuppressBreak,
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
317 eSuppressAllBreaks
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
334 * OR N == aMaxLength
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
362 * the effect of
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,
380 Metrics *aMetrics,
381 gfxFont::BoundingBoxType aBoundingBoxType,
382 gfxContext *aRefContextForTightBoundingBox,
383 bool *aUsedHyphenation,
384 uint32_t *aLastBreak,
385 bool aCanWordWrap,
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) {}
395 // Utility getters
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");
403 mFlags |= aFlags;
405 void ClearFlagBits(uint32_t aFlags) {
406 NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS),
407 "Only user flags should be mutable");
408 mFlags &= ~aFlags;
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,
418 uint32_t aFlags);
420 // The text is divided into GlyphRuns as necessary
421 struct GlyphRun {
422 nsRefPtr<gfxFont> mFont; // never null
423 uint32_t mCharacterOffset; // into original UTF16 string
424 uint8_t mMatchType;
425 uint16_t mOrientation; // gfxTextRunFactory::TEXT_ORIENT_* value
428 class GlyphRunIterator {
429 public:
430 GlyphRunIterator(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aLength)
431 : mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) {
432 mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart);
434 bool NextRun();
435 GlyphRun *GetGlyphRun() { return mGlyphRun; }
436 uint32_t GetStringStart() { return mStringStart; }
437 uint32_t GetStringEnd() { return mStringEnd; }
438 private:
439 gfxTextRun *mTextRun;
440 GlyphRun *mGlyphRun;
441 uint32_t mStringStart;
442 uint32_t mStringEnd;
443 uint32_t mNextIndex;
444 uint32_t mStartOffset;
445 uint32_t mEndOffset;
448 class GlyphRunOffsetComparator {
449 public:
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
479 * TextRun.
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);
531 g->SetIsTab();
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);
542 g->SetIsNewline();
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
553 * errors.
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
570 // textrun.
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
581 // mFontGroup.)
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
594 gfxFloat mPartWidth;
596 bool mClipBeforePart;
597 bool mClipAfterPart;
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)
603 MOZ_MUST_OVERRIDE;
604 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
605 MOZ_MUST_OVERRIDE;
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) {
610 return 0;
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
623 enum ShapingState {
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;
636 #ifdef DEBUG
637 void Dump(FILE* aOutput);
638 #endif
640 protected:
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;
661 private:
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,
699 Metrics *aMetrics);
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,
708 Metrics *aMetrics);
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;
720 void *mUserData;
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 {
738 public:
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.
790 template<typename T>
791 gfxTextRun *MakeTextRun(const T *aString, uint32_t aLength,
792 gfxContext *aRefContext,
793 int32_t aAppUnitsPerDevUnit,
794 uint32_t aFlags,
795 gfxMissingFontRecorder *aMFR)
797 gfxTextRunFactory::Parameters params = {
798 aRefContext, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit
800 return MakeTextRun(aString, aLength, &params, 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
807 * ignored.
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,
846 int32_t aRunScript);
848 template<typename T>
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 {
876 return mSkipDrawing;
879 class LazyReferenceContextGetter {
880 public:
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
892 static void
893 ResolveGenericFontNames(mozilla::FontFamilyType aGenericType,
894 nsIAtom *aLanguage,
895 nsTArray<nsString>& aGenericFamilies);
897 protected:
898 class FamilyFace {
899 public:
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");
913 mFont = aFont;
914 NS_ADDREF(aFont);
917 FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry,
918 bool aNeedsBold)
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)
937 if (mFontCreated) {
938 mFont = aOtherFamilyFace.mFont;
939 NS_ADDREF(mFont);
940 } else {
941 mFontEntry = aOtherFamilyFace.mFontEntry;
942 NS_IF_ADDREF(mFontEntry);
946 ~FamilyFace()
948 if (mFontCreated) {
949 NS_RELEASE(mFont);
950 } else {
951 NS_IF_RELEASE(mFontEntry);
955 FamilyFace& operator=(const FamilyFace& aOther)
957 if (mFontCreated) {
958 NS_RELEASE(mFont);
959 } else {
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;
969 if (mFontCreated) {
970 mFont = aOther.mFont;
971 NS_ADDREF(mFont);
972 } else {
973 mFontEntry = aOther.mFontEntry;
974 NS_IF_ADDREF(mFontEntry);
977 return *this;
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");
1002 NS_ADDREF(aFont);
1003 if (mFontCreated) {
1004 NS_RELEASE(mFont);
1005 } else {
1006 NS_IF_RELEASE(mFontEntry);
1008 mFont = aFont;
1009 mFontCreated = true;
1010 mLoading = false;
1013 private:
1014 nsRefPtr<gfxFontFamily> mFamily;
1015 // either a font or a font entry exists
1016 union {
1017 gfxFont* mFont;
1018 gfxFontEntry* mFontEntry;
1020 bool mNeedsBold : 1;
1021 bool mFontCreated : 1;
1022 bool mLoading : 1;
1023 bool mInvalid : 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
1059 // timer to fire)
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,
1095 const T *aString,
1096 uint32_t aLength,
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,
1104 const T *aString,
1105 uint32_t aScriptRunStart,
1106 uint32_t aScriptRunEnd,
1107 int32_t aRunScript,
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,
1124 nsIAtom *aLanguage,
1125 void *aClosure);
1127 // lookup and add a font with a given name (i.e. *not* a generic!)
1128 virtual void FindPlatformFont(const nsAString& aName,
1129 bool aUseFontSet,
1130 void *aClosure);
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 {
1143 public:
1144 gfxMissingFontRecorder()
1146 MOZ_COUNT_CTOR(gfxMissingFontRecorder);
1147 memset(&mMissingFonts, 0, sizeof(mMissingFonts));
1150 ~gfxMissingFontRecorder()
1152 #ifdef DEBUG
1153 for (uint32_t i = 0; i < kNumScriptBitsWords; i++) {
1154 NS_ASSERTION(mMissingFonts[i] == 0,
1155 "failed to flush the missing-font recorder");
1157 #endif
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
1170 void Flush();
1172 // forget any missing-scripts that have been recorded up to now;
1173 // called before discarding a recorder we no longer care about
1174 void Clear()
1176 memset(&mMissingFonts, 0, sizeof(mMissingFonts));
1179 private:
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];
1186 #endif