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/. */
12 #include "gfxFontFamilyList.h"
13 #include "gfxFontUtils.h"
15 #include "nsTHashtable.h"
16 #include "nsHashKeys.h"
17 #include "gfxSkipChars.h"
19 #include "nsExpirationTracker.h"
20 #include "gfxPlatform.h"
22 #include "mozilla/HashFunctions.h"
23 #include "nsIMemoryReporter.h"
24 #include "nsIObserver.h"
25 #include "gfxFontFeatures.h"
26 #include "mozilla/MemoryReporting.h"
27 #include "mozilla/Attributes.h"
30 #include "nsUnicodeScriptCodes.h"
31 #include "nsDataHashtable.h"
32 #include "harfbuzz/hb.h"
33 #include "mozilla/gfx/2D.h"
35 typedef struct _cairo_scaled_font cairo_scaled_font_t
;
36 typedef struct gr_face gr_face
;
47 class gfxGraphiteShaper
;
48 class gfxHarfBuzzShaper
;
50 class gfxUserFontData
;
55 class gfxTextContextPaint
;
58 class nsILanguageAtomService
;
60 #define FONT_MAX_SIZE 2000.0
62 #define NO_FONT_LANGUAGE_OVERRIDE 0
64 #define SMALL_CAPS_SCALE_FACTOR 0.8
67 struct gfxTextRunDrawCallbacks
;
71 class GlyphRenderingOptions
;
77 gfxFontStyle(uint8_t aStyle
, uint16_t aWeight
, int16_t aStretch
,
78 gfxFloat aSize
, nsIAtom
*aLanguage
,
79 float aSizeAdjust
, bool aSystemFont
,
81 bool aWeightSynthesis
, bool aStyleSynthesis
,
82 const nsString
& aLanguageOverride
);
83 gfxFontStyle(const gfxFontStyle
& aStyle
);
85 // the language (may be an internal langGroup code rather than an actual
86 // language code) specified in the document or element's lang property,
87 // or inferred from the charset
88 nsRefPtr
<nsIAtom
> language
;
90 // Features are composed of (1) features from style rules (2) features
91 // from feature setttings rules and (3) family-specific features. (1) and
92 // (3) are guaranteed to be mutually exclusive
94 // custom opentype feature settings
95 nsTArray
<gfxFontFeature
> featureSettings
;
97 // Some font-variant property values require font-specific settings
98 // defined via @font-feature-values rules. These are resolved after
99 // font matching occurs.
101 // -- list of value tags for specific alternate features
102 nsTArray
<gfxAlternateValue
> alternateValues
;
104 // -- object used to look these up once the font is matched
105 nsRefPtr
<gfxFontFeatureValueSet
> featureValueLookup
;
107 // The logical size of the font, in pixels
110 // The aspect-value (ie., the ratio actualsize:actualxheight) that any
111 // actual physical font created from this font structure must have when
112 // rendering or measuring a string. A value of 0 means no adjustment
116 // baseline offset, used when simulating sub/superscript glyphs
117 float baselineOffset
;
119 // Language system tag, to override document language;
120 // an OpenType "language system" tag represented as a 32-bit integer
121 // (see http://www.microsoft.com/typography/otspec/languagetags.htm).
122 // Normally 0, so font rendering will use the document or element language
123 // (see above) to control any language-specific rendering, but the author
124 // can override this for cases where the options implemented in the font
125 // do not directly match the actual language. (E.g. lang may be Macedonian,
126 // but the font in use does not explicitly support this; the author can
127 // use font-language-override to request the Serbian option in the font
128 // in order to get correct glyph shapes.)
129 uint32_t languageOverride
;
131 // The weight of the font: 100, 200, ... 900.
134 // The stretch of the font (the sum of various NS_FONT_STRETCH_*
135 // constants; see gfxFontConstants.h).
138 // Say that this font is a system font and therefore does not
139 // require certain fixup that we do for fonts from untrusted
143 // Say that this font is used for print or print preview.
144 bool printerFont
: 1;
146 // Used to imitate -webkit-font-smoothing: antialiased
147 bool useGrayscaleAntialiasing
: 1;
149 // The style of font (normal, italic, oblique)
152 // Whether synthetic styles are allowed
153 bool allowSyntheticWeight
: 1;
154 bool allowSyntheticStyle
: 1;
156 // some variant features require fallback which complicates the shaping
157 // code, so set up a bool to indicate when shaping with fallback is needed
158 bool noFallbackVariantFeatures
: 1;
160 // caps variant (small-caps, petite-caps, etc.)
163 // sub/superscript variant
164 uint8_t variantSubSuper
;
166 // Return the final adjusted font size for the given aspect ratio.
167 // Not meant to be called when sizeAdjust = 0.
168 gfxFloat
GetAdjustedSize(gfxFloat aspect
) const {
169 NS_ASSERTION(sizeAdjust
!= 0.0, "Not meant to be called when sizeAdjust = 0");
170 gfxFloat adjustedSize
= std::max(NS_round(size
*(sizeAdjust
/aspect
)), 1.0);
171 return std::min(adjustedSize
, FONT_MAX_SIZE
);
174 PLDHashNumber
Hash() const {
175 return ((style
+ (systemFont
<< 7) +
176 (weight
<< 8)) + uint32_t(size
*1000) + uint32_t(sizeAdjust
*1000)) ^
177 nsISupportsHashKey::HashKey(language
);
180 int8_t ComputeWeight() const;
182 // Adjust this style to simulate sub/superscript (as requested in the
183 // variantSubSuper field) using size and baselineOffset instead.
184 void AdjustForSubSuperscript(int32_t aAppUnitsPerDevPixel
);
186 bool Equals(const gfxFontStyle
& other
) const {
188 (*reinterpret_cast<const uint64_t*>(&size
) ==
189 *reinterpret_cast<const uint64_t*>(&other
.size
)) &&
190 (style
== other
.style
) &&
191 (variantCaps
== other
.variantCaps
) &&
192 (variantSubSuper
== other
.variantSubSuper
) &&
193 (allowSyntheticWeight
== other
.allowSyntheticWeight
) &&
194 (allowSyntheticStyle
== other
.allowSyntheticStyle
) &&
195 (systemFont
== other
.systemFont
) &&
196 (printerFont
== other
.printerFont
) &&
197 (useGrayscaleAntialiasing
== other
.useGrayscaleAntialiasing
) &&
198 (weight
== other
.weight
) &&
199 (stretch
== other
.stretch
) &&
200 (language
== other
.language
) &&
201 (baselineOffset
== other
.baselineOffset
) &&
202 (*reinterpret_cast<const uint32_t*>(&sizeAdjust
) ==
203 *reinterpret_cast<const uint32_t*>(&other
.sizeAdjust
)) &&
204 (featureSettings
== other
.featureSettings
) &&
205 (languageOverride
== other
.languageOverride
) &&
206 (alternateValues
== other
.alternateValues
) &&
207 (featureValueLookup
== other
.featureValueLookup
);
210 static void ParseFontFeatureSettings(const nsString
& aFeatureString
,
211 nsTArray
<gfxFontFeature
>& aFeatures
);
213 static uint32_t ParseFontLanguageOverride(const nsString
& aLangTag
);
216 class gfxCharacterMap
: public gfxSparseBitSet
{
219 NS_PRECONDITION(int32_t(mRefCnt
) >= 0, "illegal refcnt");
221 NS_LOG_ADDREF(this, mRefCnt
, "gfxCharacterMap", sizeof(*this));
226 NS_PRECONDITION(0 != mRefCnt
, "dup release");
228 NS_LOG_RELEASE(this, mRefCnt
, "gfxCharacterMap");
231 // |this| has been deleted.
238 mHash(0), mBuildOnTheFly(false), mShared(false)
241 void CalcHash() { mHash
= GetChecksum(); }
243 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const {
244 return gfxSparseBitSet::SizeOfExcludingThis(aMallocSizeOf
);
247 // hash of the cmap bitvector
250 // if cmap is built on the fly it's never shared
253 // cmap is shared globally
257 void NotifyReleased();
259 nsAutoRefCnt mRefCnt
;
262 gfxCharacterMap(const gfxCharacterMap
&);
263 gfxCharacterMap
& operator=(const gfxCharacterMap
&);
268 NS_INLINE_DECL_REFCOUNTING(gfxFontEntry
)
270 explicit gfxFontEntry(const nsAString
& aName
, bool aIsStandardFace
= false);
272 // unique name for the face, *not* the family; not necessarily the
273 // "real" or user-friendly name, may be an internal identifier
274 const nsString
& Name() const { return mName
; }
277 const nsString
& FamilyName() const { return mFamilyName
; }
279 // The following two methods may be relatively expensive, as they
280 // will (usually, except on Linux) load and parse the 'name' table;
281 // they are intended only for the font-inspection API, not for
282 // perf-critical layout/drawing work.
284 // The "real" name of the face, if available from the font resource;
285 // returns Name() if nothing better is available.
286 virtual nsString
RealFaceName();
288 uint16_t Weight() const { return mWeight
; }
289 int16_t Stretch() const { return mStretch
; }
291 bool IsUserFont() const { return mIsUserFont
; }
292 bool IsLocalUserFont() const { return mIsLocalUserFont
; }
293 bool IsFixedPitch() const { return mFixedPitch
; }
294 bool IsItalic() const { return mItalic
; }
295 bool IsBold() const { return mWeight
>= 600; } // bold == weights 600 and above
296 bool IgnoreGDEF() const { return mIgnoreGDEF
; }
297 bool IgnoreGSUB() const { return mIgnoreGSUB
; }
299 // whether a feature is supported by the font (limited to a small set
300 // of features for which some form of fallback needs to be implemented)
301 bool SupportsOpenTypeFeature(int32_t aScript
, uint32_t aFeatureTag
);
302 bool SupportsGraphiteFeature(uint32_t aFeatureTag
);
304 // returns a set containing all input glyph ids for a given feature
306 InputsForOpenTypeFeature(int32_t aScript
, uint32_t aFeatureTag
);
308 virtual bool IsSymbolFont();
310 virtual bool HasFontTable(uint32_t aTableTag
);
312 inline bool HasGraphiteTables() {
313 if (!mCheckedForGraphiteTables
) {
314 CheckForGraphiteTables();
315 mCheckedForGraphiteTables
= true;
317 return mHasGraphiteTables
;
320 inline bool HasCmapTable() {
321 if (!mCharacterMap
) {
323 NS_ASSERTION(mCharacterMap
, "failed to initialize character map");
325 return mHasCmapTable
;
328 inline bool HasCharacter(uint32_t ch
) {
329 if (mCharacterMap
&& mCharacterMap
->test(ch
)) {
332 return TestCharacterMap(ch
);
335 virtual bool SkipDuringSystemFallback() { return false; }
336 virtual bool TestCharacterMap(uint32_t aCh
);
337 nsresult
InitializeUVSMap();
338 uint16_t GetUVSGlyph(uint32_t aCh
, uint32_t aVS
);
340 // All concrete gfxFontEntry subclasses (except gfxProxyFontEntry) need
341 // to override this, otherwise the font will never be used as it will
342 // be considered to support no characters.
343 // ReadCMAP() must *always* set the mCharacterMap pointer to a valid
344 // gfxCharacterMap, even if empty, as other code assumes this pointer
345 // can be safely dereferenced.
346 virtual nsresult
ReadCMAP(FontInfoData
*aFontInfoData
= nullptr);
348 bool TryGetSVGData(gfxFont
* aFont
);
349 bool HasSVGGlyph(uint32_t aGlyphId
);
350 bool GetSVGGlyphExtents(gfxContext
*aContext
, uint32_t aGlyphId
,
352 bool RenderSVGGlyph(gfxContext
*aContext
, uint32_t aGlyphId
, int aDrawMode
,
353 gfxTextContextPaint
*aContextPaint
);
354 // Call this when glyph geometry or rendering has changed
355 // (e.g. animated SVG glyphs)
356 void NotifyGlyphsChanged();
359 // The order of the constants must match the order of the fields
360 // defined in the MATH table.
361 ScriptPercentScaleDown
,
362 ScriptScriptPercentScaleDown
,
363 DelimitedSubFormulaMinHeight
,
364 DisplayOperatorMinHeight
,
368 FlattenedAccentBaseHeight
,
371 SubscriptBaselineDropMin
,
373 SuperscriptShiftUpCramped
,
374 SuperscriptBottomMin
,
375 SuperscriptBaselineDropMax
,
376 SubSuperscriptGapMin
,
377 SuperscriptBottomMaxWithSubscript
,
380 UpperLimitBaselineRiseMin
,
382 LowerLimitBaselineDropMin
,
384 StackTopDisplayStyleShiftUp
,
385 StackBottomShiftDown
,
386 StackBottomDisplayStyleShiftDown
,
388 StackDisplayStyleGapMin
,
389 StretchStackTopShiftUp
,
390 StretchStackBottomShiftDown
,
391 StretchStackGapAboveMin
,
392 StretchStackGapBelowMin
,
393 FractionNumeratorShiftUp
,
394 FractionNumeratorDisplayStyleShiftUp
,
395 FractionDenominatorShiftDown
,
396 FractionDenominatorDisplayStyleShiftDown
,
397 FractionNumeratorGapMin
,
398 FractionNumDisplayStyleGapMin
,
399 FractionRuleThickness
,
400 FractionDenominatorGapMin
,
401 FractionDenomDisplayStyleGapMin
,
402 SkewedFractionHorizontalGap
,
403 SkewedFractionVerticalGap
,
405 OverbarRuleThickness
,
406 OverbarExtraAscender
,
408 UnderbarRuleThickness
,
409 UnderbarExtraDescender
,
411 RadicalDisplayStyleVerticalGap
,
412 RadicalRuleThickness
,
413 RadicalExtraAscender
,
414 RadicalKernBeforeDegree
,
415 RadicalKernAfterDegree
,
416 RadicalDegreeBottomRaisePercent
419 // Call TryGetMathTable to try to load the Open Type MATH table. The other
420 // functions forward the call to the gfxMathTable class. The GetMath...()
421 // functions MUST NOT be called unless TryGetMathTable() has returned true.
422 bool TryGetMathTable();
423 gfxFloat
GetMathConstant(MathConstant aConstant
);
424 bool GetMathItalicsCorrection(uint32_t aGlyphID
,
425 gfxFloat
* aItalicCorrection
);
426 uint32_t GetMathVariantsSize(uint32_t aGlyphID
, bool aVertical
,
428 bool GetMathVariantsParts(uint32_t aGlyphID
, bool aVertical
,
429 uint32_t aGlyphs
[4]);
431 bool TryGetColorGlyphs();
432 bool GetColorLayersInfo(uint32_t aGlyphId
,
433 nsTArray
<uint16_t>& layerGlyphs
,
434 nsTArray
<mozilla::gfx::Color
>& layerColors
);
436 virtual bool MatchesGenericFamily(const nsACString
& aGeneric
) const {
439 virtual bool SupportsLangGroup(nsIAtom
*aLangGroup
) const {
443 // Access to raw font table data (needed for Harfbuzz):
444 // returns a pointer to data owned by the fontEntry or the OS,
445 // which will remain valid until the blob is destroyed.
446 // The data MUST be treated as read-only; we may be getting a
447 // reference to a shared system font cache.
449 // The default implementation uses CopyFontTable to get the data
450 // into a byte array, and maintains a cache of loaded tables.
452 // Subclasses should override this if they can provide more efficient
453 // access than copying table data into our own buffers.
455 // Get blob that encapsulates a specific font table, or nullptr if
456 // the table doesn't exist in the font.
458 // Caller is responsible to call hb_blob_destroy() on the returned blob
459 // (if non-nullptr) when no longer required. For transient access to a
460 // table, use of AutoTable (below) is generally preferred.
461 virtual hb_blob_t
*GetFontTable(uint32_t aTag
);
463 // Stack-based utility to return a specified table, automatically releasing
464 // the blob when the AutoTable goes out of scope.
467 AutoTable(gfxFontEntry
* aFontEntry
, uint32_t aTag
)
469 mBlob
= aFontEntry
->GetFontTable(aTag
);
473 hb_blob_destroy(mBlob
);
476 operator hb_blob_t
*() const { return mBlob
; }
480 AutoTable(const AutoTable
&) MOZ_DELETE
;
481 AutoTable
& operator=(const AutoTable
&) MOZ_DELETE
;
484 already_AddRefed
<gfxFont
> FindOrMakeFont(const gfxFontStyle
*aStyle
,
487 // Get an existing font table cache entry in aBlob if it has been
488 // registered, or return false if not. Callers must call
489 // hb_blob_destroy on aBlob if true is returned.
491 // Note that some gfxFont implementations may not call this at all,
492 // if it is more efficient to get the table from the OS at that level.
493 bool GetExistingFontTable(uint32_t aTag
, hb_blob_t
** aBlob
);
495 // Elements of aTable are transferred (not copied) to and returned in a
496 // new hb_blob_t which is registered on the gfxFontEntry, but the initial
497 // reference is owned by the caller. Removing the last reference
498 // unregisters the table from the font entry.
500 // Pass nullptr for aBuffer to indicate that the table is not present and
501 // nullptr will be returned. Also returns nullptr on OOM.
502 hb_blob_t
*ShareFontTableAndGetBlob(uint32_t aTag
,
503 FallibleTArray
<uint8_t>* aTable
);
505 // Get the font's unitsPerEm from the 'head' table, in the case of an
506 // sfnt resource. Will return kInvalidUPEM for non-sfnt fonts,
507 // if present on the platform.
508 uint16_t UnitsPerEm();
510 kMinUPEM
= 16, // Limits on valid unitsPerEm range, from the
511 kMaxUPEM
= 16384, // OpenType spec
512 kInvalidUPEM
= uint16_t(-1)
515 // Shaper face accessors:
516 // NOTE that harfbuzz and graphite handle ownership/lifetime of the face
517 // object in completely different ways.
519 // Get HarfBuzz face corresponding to this font file.
520 // Caller must release with hb_face_destroy() when finished with it,
521 // and the font entry will be notified via ForgetHBFace.
522 hb_face_t
* GetHBFace();
523 virtual void ForgetHBFace();
525 // Get Graphite face corresponding to this font file.
526 // Caller must call gfxFontEntry::ReleaseGrFace when finished with it.
527 gr_face
* GetGrFace();
528 virtual void ReleaseGrFace(gr_face
* aFace
);
530 // Release any SVG-glyphs document this font may have loaded.
531 void DisconnectSVG();
533 // Called to notify that aFont is being destroyed. Needed when we're tracking
534 // the fonts belonging to this font entry.
535 void NotifyFontDestroyed(gfxFont
* aFont
);
537 // For memory reporting
538 virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
539 FontListSizes
* aSizes
) const;
540 virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
541 FontListSizes
* aSizes
) const;
543 // Used when checking for complex script support, to mask off cmap ranges
547 hb_tag_t tags
[3]; // one or two OpenType script tags to check,
548 // plus a NULL terminator
551 bool SupportsScriptInGSUB(const hb_tag_t
* aScriptTags
);
554 nsString mFamilyName
;
557 bool mFixedPitch
: 1;
560 bool mIsBadUnderlineFont
: 1;
561 bool mIsUserFont
: 1;
562 bool mIsLocalUserFont
: 1;
563 bool mStandardFace
: 1;
564 bool mSymbolFont
: 1;
565 bool mIgnoreGDEF
: 1;
566 bool mIgnoreGSUB
: 1;
567 bool mSVGInitialized
: 1;
568 bool mMathInitialized
: 1;
569 bool mHasSpaceFeaturesInitialized
: 1;
570 bool mHasSpaceFeatures
: 1;
571 bool mHasSpaceFeaturesKerning
: 1;
572 bool mHasSpaceFeaturesNonKerning
: 1;
573 bool mSkipDefaultFeatureSpaceCheck
: 1;
574 bool mHasGraphiteTables
: 1;
575 bool mCheckedForGraphiteTables
: 1;
576 bool mHasCmapTable
: 1;
577 bool mGrFaceInitialized
: 1;
578 bool mCheckedForColorGlyph
: 1;
580 // bitvector of substitution space features per script, one each
581 // for default and non-default features
582 uint32_t mDefaultSubSpaceFeatures
[(MOZ_NUM_SCRIPT_CODES
+ 31) / 32];
583 uint32_t mNonDefaultSubSpaceFeatures
[(MOZ_NUM_SCRIPT_CODES
+ 31) / 32];
588 nsRefPtr
<gfxCharacterMap
> mCharacterMap
;
590 nsAutoArrayPtr
<uint8_t> mUVSData
;
591 nsAutoPtr
<gfxUserFontData
> mUserFontData
;
592 nsAutoPtr
<gfxSVGGlyphs
> mSVGGlyphs
;
593 // list of gfxFonts that are using SVG glyphs
594 nsTArray
<gfxFont
*> mFontsUsingSVGGlyphs
;
595 nsAutoPtr
<gfxMathTable
> mMathTable
;
596 nsTArray
<gfxFontFeature
> mFeatureSettings
;
597 nsAutoPtr
<nsDataHashtable
<nsUint32HashKey
,bool>> mSupportedFeatures
;
598 nsAutoPtr
<nsDataHashtable
<nsUint32HashKey
,hb_set_t
*>> mFeatureInputs
;
599 uint32_t mLanguageOverride
;
601 // Color Layer font support
606 friend class gfxPlatformFontList
;
607 friend class gfxMacPlatformFontList
;
608 friend class gfxUserFcFontEntry
;
609 friend class gfxFontFamily
;
610 friend class gfxSingleFaceMacFontFamily
;
614 // Protected destructor, to discourage deletion outside of Release():
615 virtual ~gfxFontEntry();
617 virtual gfxFont
*CreateFontInstance(const gfxFontStyle
*aFontStyle
, bool aNeedsBold
) {
618 NS_NOTREACHED("oops, somebody didn't override CreateFontInstance");
622 virtual void CheckForGraphiteTables();
624 // Copy a font table into aBuffer.
625 // The caller will be responsible for ownership of the data.
626 virtual nsresult
CopyFontTable(uint32_t aTableTag
,
627 FallibleTArray
<uint8_t>& aBuffer
) {
628 NS_NOTREACHED("forgot to override either GetFontTable or CopyFontTable?");
629 return NS_ERROR_FAILURE
;
632 // Return a blob that wraps a table found within a buffer of font data.
633 // The blob does NOT own its data; caller guarantees that the buffer
634 // will remain valid at least as long as the blob.
635 // Returns null if the specified table is not found.
636 // This method assumes aFontData is valid 'sfnt' data; before using this,
637 // caller is responsible to do any sanitization/validation necessary.
638 hb_blob_t
* GetTableFromFontData(const void* aFontData
, uint32_t aTableTag
);
640 // lookup the cmap in cached font data
641 virtual already_AddRefed
<gfxCharacterMap
>
642 GetCMAPFromFontInfo(FontInfoData
*aFontInfoData
,
643 uint32_t& aUVSOffset
,
646 // Font's unitsPerEm from the 'head' table, if available (will be set to
647 // kInvalidUPEM for non-sfnt font formats)
648 uint16_t mUnitsPerEm
;
650 // Shaper-specific face objects, shared by all instantiations of the same
651 // physical font, regardless of size.
652 // Usually, only one of these will actually be created for any given font
653 // entry, depending on the font tables that are present.
655 // hb_face_t is refcounted internally, so each shaper that's using it will
656 // bump the ref count when it acquires the face, and "destroy" (release) it
657 // in its destructor. The font entry has only this non-owning reference to
658 // the face; when the face is deleted, it will tell the font entry to forget
659 // it, so that a new face will be created next time it is needed.
662 static hb_blob_t
* HBGetTable(hb_face_t
*face
, uint32_t aTag
, void *aUserData
);
664 // Callback that the hb_face will use to tell us when it is being deleted.
665 static void HBFaceDeletedCallback(void *aUserData
);
667 // gr_face is -not- refcounted, so it will be owned directly by the font
668 // entry, and we'll keep a count of how many references we've handed out;
669 // each shaper is responsible to call ReleaseGrFace on its entry when
670 // finished with it, so that we know when it can be deleted.
673 // hashtable to map raw table data ptr back to its owning blob, for use by
674 // graphite table-release callback
675 nsDataHashtable
<nsPtrHashKey
<const void>,void*>* mGrTableMap
;
677 // number of current users of this entry's mGrFace
678 nsrefcnt mGrFaceRefCnt
;
680 static const void* GrGetTable(const void *aAppFaceHandle
,
683 static void GrReleaseTable(const void *aAppFaceHandle
,
684 const void *aTableBuffer
);
688 * Font table hashtable, to support GetFontTable for harfbuzz.
690 * The harfbuzz shaper (and potentially other clients) needs access to raw
691 * font table data. This needs to be cached so that it can be used
692 * repeatedly (each time we construct a text run; in some cases, for
693 * each character/glyph within the run) without re-fetching large tables
696 * Because we may instantiate many gfxFonts for the same physical font
697 * file (at different sizes), we should ensure that they can share a
698 * single cached copy of the font tables. To do this, we implement table
699 * access and sharing on the fontEntry rather than the font itself.
701 * The default implementation uses GetFontTable() to read font table
702 * data into byte arrays, and wraps them in blobs which are registered in
703 * a hashtable. The hashtable can then return pre-existing blobs to
706 * Harfbuzz will "destroy" the blobs when it is finished with them. When
707 * the last blob reference is removed, the FontTableBlobData user data
708 * will remove the blob from the hashtable if still registered.
711 class FontTableBlobData
;
714 * FontTableHashEntry manages the entries of hb_blob_t's containing font
717 * This is used to share font tables across fonts with the same
718 * font entry (but different sizes) for use by HarfBuzz. The hashtable
719 * does not own a strong reference to the blob, but keeps a weak pointer,
720 * managed by FontTableBlobData. Similarly FontTableBlobData keeps only a
721 * weak pointer to the hashtable, managed by FontTableHashEntry.
724 class FontTableHashEntry
: public nsUint32HashKey
727 // Declarations for nsTHashtable
729 typedef nsUint32HashKey KeyClass
;
730 typedef KeyClass::KeyType KeyType
;
731 typedef KeyClass::KeyTypePointer KeyTypePointer
;
733 explicit FontTableHashEntry(KeyTypePointer aTag
)
735 , mSharedBlobData(nullptr)
739 // NOTE: This assumes the new entry belongs to the same hashtable as
740 // the old, because the mHashtable pointer in mSharedBlobData (if
741 // present) will not be updated.
742 FontTableHashEntry(FontTableHashEntry
&& toMove
)
743 : KeyClass(mozilla::Move(toMove
))
744 , mSharedBlobData(mozilla::Move(toMove
.mSharedBlobData
))
745 , mBlob(mozilla::Move(toMove
.mBlob
))
747 toMove
.mSharedBlobData
= nullptr;
748 toMove
.mBlob
= nullptr;
751 ~FontTableHashEntry() { Clear(); }
753 // FontTable/Blob API
755 // Transfer (not copy) elements of aTable to a new hb_blob_t and
756 // return ownership to the caller. A weak reference to the blob is
757 // recorded in the hashtable entry so that others may use the same
760 ShareTableAndGetBlob(FallibleTArray
<uint8_t>& aTable
,
761 nsTHashtable
<FontTableHashEntry
> *aHashtable
);
763 // Return a strong reference to the blob.
764 // Callers must hb_blob_destroy the returned blob.
765 hb_blob_t
*GetBlob() const;
769 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const;
772 static void DeleteFontTableBlobData(void *aBlobData
);
774 FontTableHashEntry
& operator=(FontTableHashEntry
& toCopy
);
776 FontTableBlobData
*mSharedBlobData
;
780 nsAutoPtr
<nsTHashtable
<FontTableHashEntry
> > mFontTableCache
;
782 gfxFontEntry(const gfxFontEntry
&);
783 gfxFontEntry
& operator=(const gfxFontEntry
&);
787 // used when iterating over all fonts looking for a match for a given character
788 struct GlobalFontMatch
{
789 GlobalFontMatch(const uint32_t aCharacter
,
791 const gfxFontStyle
*aStyle
) :
792 mCh(aCharacter
), mRunScript(aRunScript
), mStyle(aStyle
),
793 mMatchRank(0), mCount(0), mCmapsTested(0)
798 const uint32_t mCh
; // codepoint to be matched
799 int32_t mRunScript
; // Unicode script for the codepoint
800 const gfxFontStyle
* mStyle
; // style to match
801 int32_t mMatchRank
; // metric indicating closest match
802 nsRefPtr
<gfxFontEntry
> mBestMatch
; // current best match
803 nsRefPtr
<gfxFontFamily
> mMatchedFamily
; // the family it belongs to
804 uint32_t mCount
; // number of fonts matched
805 uint32_t mCmapsTested
; // number of cmaps tested
808 class gfxFontFamily
{
810 NS_INLINE_DECL_REFCOUNTING(gfxFontFamily
)
812 explicit gfxFontFamily(const nsAString
& aName
) :
814 mOtherFamilyNamesInitialized(false),
815 mHasOtherFamilyNames(false),
816 mFaceNamesInitialized(false),
818 mIsSimpleFamily(false),
819 mIsBadUnderlineFamily(false),
820 mFamilyCharacterMapInitialized(false),
821 mSkipDefaultFeatureSpaceCheck(false)
824 const nsString
& Name() { return mName
; }
826 virtual void LocalizedName(nsAString
& aLocalizedName
);
827 virtual bool HasOtherFamilyNames();
829 nsTArray
<nsRefPtr
<gfxFontEntry
> >& GetFontList() { return mAvailableFonts
; }
831 void AddFontEntry(nsRefPtr
<gfxFontEntry
> aFontEntry
) {
832 // bug 589682 - set the IgnoreGDEF flag on entries for Italic faces
833 // of Times New Roman, because of buggy table in those fonts
834 if (aFontEntry
->IsItalic() && !aFontEntry
->IsUserFont() &&
835 Name().EqualsLiteral("Times New Roman"))
837 aFontEntry
->mIgnoreGDEF
= true;
839 if (aFontEntry
->mFamilyName
.IsEmpty()) {
840 aFontEntry
->mFamilyName
= Name();
842 MOZ_ASSERT(aFontEntry
->mFamilyName
.Equals(Name()));
844 aFontEntry
->mSkipDefaultFeatureSpaceCheck
= mSkipDefaultFeatureSpaceCheck
;
845 mAvailableFonts
.AppendElement(aFontEntry
);
848 // note that the styles for this family have been added
849 bool HasStyles() { return mHasStyles
; }
850 void SetHasStyles(bool aHasStyles
) { mHasStyles
= aHasStyles
; }
852 // choose a specific face to match a style using CSS font matching
853 // rules (weight matching occurs here). may return a face that doesn't
854 // precisely match (e.g. normal face when no italic face exists).
855 // aNeedsSyntheticBold is set to true when synthetic bolding is
856 // needed, false otherwise
857 gfxFontEntry
*FindFontForStyle(const gfxFontStyle
& aFontStyle
,
858 bool& aNeedsSyntheticBold
);
860 // checks for a matching font within the family
861 // used as part of the font fallback process
862 void FindFontForChar(GlobalFontMatch
*aMatchData
);
864 // checks all fonts for a matching font within the family
865 void SearchAllFontsForChar(GlobalFontMatch
*aMatchData
);
867 // read in other family names, if any, and use functor to add each into cache
868 virtual void ReadOtherFamilyNames(gfxPlatformFontList
*aPlatformFontList
);
870 // helper method for reading localized family names from the name table
872 static void ReadOtherFamilyNamesForFace(const nsAString
& aFamilyName
,
873 const char *aNameData
,
874 uint32_t aDataLength
,
875 nsTArray
<nsString
>& aOtherFamilyNames
,
878 // set when other family names have been read in
879 void SetOtherFamilyNamesInitialized() {
880 mOtherFamilyNamesInitialized
= true;
883 // read in other localized family names, fullnames and Postscript names
884 // for all faces and append to lookup tables
885 virtual void ReadFaceNames(gfxPlatformFontList
*aPlatformFontList
,
886 bool aNeedFullnamePostscriptNames
,
887 FontInfoData
*aFontInfoData
= nullptr);
889 // find faces belonging to this family (platform implementations override this;
890 // should be made pure virtual once all subclasses have been updated)
891 virtual void FindStyleVariations(FontInfoData
*aFontInfoData
= nullptr) { }
893 // search for a specific face using the Postscript name
894 gfxFontEntry
* FindFont(const nsAString
& aPostscriptName
);
896 // read in cmaps for all the faces
897 void ReadAllCMAPs(FontInfoData
*aFontInfoData
= nullptr);
899 bool TestCharacterMap(uint32_t aCh
) {
900 if (!mFamilyCharacterMapInitialized
) {
903 return mFamilyCharacterMap
.test(aCh
);
906 void ResetCharacterMap() {
907 mFamilyCharacterMap
.reset();
908 mFamilyCharacterMapInitialized
= false;
911 // mark this family as being in the "bad" underline offset blacklist
912 void SetBadUnderlineFamily() {
913 mIsBadUnderlineFamily
= true;
915 SetBadUnderlineFonts();
919 bool IsBadUnderlineFamily() const { return mIsBadUnderlineFamily
; }
921 // sort available fonts to put preferred (standard) faces towards the end
922 void SortAvailableFonts();
924 // check whether the family fits into the simple 4-face model,
925 // so we can use simplified style-matching;
926 // if so set the mIsSimpleFamily flag (defaults to False before we've checked)
927 void CheckForSimpleFamily();
929 // For memory reporter
930 virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
931 FontListSizes
* aSizes
) const;
932 virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
933 FontListSizes
* aSizes
) const;
935 // Only used for debugging checks - does a linear search
936 bool ContainsFace(gfxFontEntry
* aFontEntry
) {
937 uint32_t i
, numFonts
= mAvailableFonts
.Length();
938 for (i
= 0; i
< numFonts
; i
++) {
939 if (mAvailableFonts
[i
] == aFontEntry
) {
946 void SetSkipSpaceFeatureCheck(bool aSkipCheck
) {
947 mSkipDefaultFeatureSpaceCheck
= aSkipCheck
;
951 // Protected destructor, to discourage deletion outside of Release():
952 virtual ~gfxFontFamily()
956 // fills in an array with weights of faces that match style,
957 // returns whether any matching entries found
958 virtual bool FindWeightsForStyle(gfxFontEntry
* aFontsForWeights
[],
959 bool anItalic
, int16_t aStretch
);
961 bool ReadOtherFamilyNamesForFace(gfxPlatformFontList
*aPlatformFontList
,
962 hb_blob_t
*aNameTable
,
963 bool useFullName
= false);
965 // set whether this font family is in "bad" underline offset blacklist.
966 void SetBadUnderlineFonts() {
967 uint32_t i
, numFonts
= mAvailableFonts
.Length();
968 for (i
= 0; i
< numFonts
; i
++) {
969 if (mAvailableFonts
[i
]) {
970 mAvailableFonts
[i
]->mIsBadUnderlineFont
= true;
976 nsTArray
<nsRefPtr
<gfxFontEntry
> > mAvailableFonts
;
977 gfxSparseBitSet mFamilyCharacterMap
;
978 bool mOtherFamilyNamesInitialized
: 1;
979 bool mHasOtherFamilyNames
: 1;
980 bool mFaceNamesInitialized
: 1;
982 bool mIsSimpleFamily
: 1;
983 bool mIsBadUnderlineFamily
: 1;
984 bool mFamilyCharacterMapInitialized
: 1;
985 bool mSkipDefaultFeatureSpaceCheck
: 1;
988 // for "simple" families, the faces are stored in mAvailableFonts
989 // with fixed positions:
990 kRegularFaceIndex
= 0,
992 kItalicFaceIndex
= 2,
993 kBoldItalicFaceIndex
= 3,
994 // mask values for selecting face with bold and/or italic attributes
1000 struct gfxTextRange
{
1002 // flags for recording the kind of font-matching that was used
1003 kFontGroup
= 0x0001,
1004 kPrefsFallback
= 0x0002,
1005 kSystemFallback
= 0x0004
1007 gfxTextRange(uint32_t aStart
, uint32_t aEnd
,
1008 gfxFont
* aFont
, uint8_t aMatchType
)
1012 matchType(aMatchType
)
1014 uint32_t Length() const { return end
- start
; }
1015 uint32_t start
, end
;
1016 nsRefPtr
<gfxFont
> font
;
1022 * Font cache design:
1024 * The mFonts hashtable contains most fonts, indexed by (gfxFontEntry*, style).
1025 * It does not add a reference to the fonts it contains.
1026 * When a font's refcount decreases to zero, instead of deleting it we
1027 * add it to our expiration tracker.
1028 * The expiration tracker tracks fonts with zero refcount. After a certain
1029 * period of time, such fonts expire and are deleted.
1031 * We're using 3 generations with a ten-second generation interval, so
1032 * zero-refcount fonts will be deleted 20-30 seconds after their refcount
1033 * goes to zero, if timer events fire in a timely manner.
1035 * The font cache also handles timed expiration of cached ShapedWords
1036 * for "persistent" fonts: it has a repeating timer, and notifies
1037 * each cached font to "age" its shaped words. The words will be released
1038 * by the fonts if they get aged three times without being re-used in the
1041 * Note that the ShapedWord timeout is much larger than the font timeout,
1042 * so that in the case of a short-lived font, we'll discard the gfxFont
1043 * completely, with all its words, and avoid the cost of aging the words
1044 * individually. That only happens with longer-lived fonts.
1046 struct FontCacheSizes
{
1048 : mFontInstances(0), mShapedWords(0)
1051 size_t mFontInstances
; // memory used by instances of gfxFont subclasses
1052 size_t mShapedWords
; // memory used by the per-font shapedWord caches
1055 class gfxFontCache MOZ_FINAL
: public nsExpirationTracker
<gfxFont
,3> {
1058 FONT_TIMEOUT_SECONDS
= 10,
1059 SHAPED_WORD_TIMEOUT_SECONDS
= 60
1066 * Get the global gfxFontCache. You must call Init() before
1067 * calling this method --- the result will not be null.
1069 static gfxFontCache
* GetCache() {
1070 return gGlobalCache
;
1073 static nsresult
Init();
1074 // It's OK to call this even if Init() has not been called.
1075 static void Shutdown();
1077 // Look up a font in the cache. Returns an addrefed pointer, or null
1078 // if there's nothing matching in the cache
1079 already_AddRefed
<gfxFont
> Lookup(const gfxFontEntry
*aFontEntry
,
1080 const gfxFontStyle
*aStyle
);
1081 // We created a new font (presumably because Lookup returned null);
1082 // put it in the cache. The font's refcount should be nonzero. It is
1083 // allowable to add a new font even if there is one already in the
1084 // cache with the same key; we'll forget about the old one.
1085 void AddNew(gfxFont
*aFont
);
1087 // The font's refcount has gone to zero; give ownership of it to
1088 // the cache. We delete it if it's not acquired again after a certain
1090 void NotifyReleased(gfxFont
*aFont
);
1092 // This gets called when the timeout has expired on a zero-refcount
1093 // font; we just delete it.
1094 virtual void NotifyExpired(gfxFont
*aFont
);
1096 // Cleans out the hashtable and removes expired fonts waiting for cleanup.
1097 // Other gfxFont objects may be still in use but they will be pushed
1098 // into the expiration queues and removed.
1101 AgeAllGenerations();
1104 void FlushShapedWordCaches() {
1105 mFonts
.EnumerateEntries(ClearCachedWordsForFont
, nullptr);
1108 void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
1109 FontCacheSizes
* aSizes
) const;
1110 void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
1111 FontCacheSizes
* aSizes
) const;
1114 class MemoryReporter MOZ_FINAL
: public nsIMemoryReporter
1116 ~MemoryReporter() {}
1119 NS_DECL_NSIMEMORYREPORTER
1122 // Observer for notifications that the font cache cares about
1123 class Observer MOZ_FINAL
1124 : public nsIObserver
1132 void DestroyFont(gfxFont
*aFont
);
1134 static gfxFontCache
*gGlobalCache
;
1137 const gfxFontEntry
* mFontEntry
;
1138 const gfxFontStyle
* mStyle
;
1139 Key(const gfxFontEntry
* aFontEntry
, const gfxFontStyle
* aStyle
)
1140 : mFontEntry(aFontEntry
), mStyle(aStyle
) {}
1143 class HashEntry
: public PLDHashEntryHdr
{
1145 typedef const Key
& KeyType
;
1146 typedef const Key
* KeyTypePointer
;
1148 // When constructing a new entry in the hashtable, we'll leave this
1149 // blank. The caller of Put() will fill this in.
1150 explicit HashEntry(KeyTypePointer aStr
) : mFont(nullptr) { }
1151 HashEntry(const HashEntry
& toCopy
) : mFont(toCopy
.mFont
) { }
1154 bool KeyEquals(const KeyTypePointer aKey
) const;
1155 static KeyTypePointer
KeyToPointer(KeyType aKey
) { return &aKey
; }
1156 static PLDHashNumber
HashKey(const KeyTypePointer aKey
) {
1157 return mozilla::HashGeneric(aKey
->mStyle
->Hash(), aKey
->mFontEntry
);
1159 enum { ALLOW_MEMMOVE
= true };
1164 static size_t AddSizeOfFontEntryExcludingThis(HashEntry
* aHashEntry
,
1165 mozilla::MallocSizeOf aMallocSizeOf
,
1168 nsTHashtable
<HashEntry
> mFonts
;
1170 static PLDHashOperator
ClearCachedWordsForFont(HashEntry
* aHashEntry
, void*);
1171 static PLDHashOperator
AgeCachedWordsForFont(HashEntry
* aHashEntry
, void*);
1172 static void WordCacheExpirationTimerCallback(nsITimer
* aTimer
, void* aCache
);
1173 nsCOMPtr
<nsITimer
> mWordCacheExpirationTimer
;
1176 class gfxTextPerfMetrics
{
1180 uint32_t numContentTextRuns
;
1181 uint32_t numChromeTextRuns
;
1183 uint32_t maxTextRunLen
;
1184 uint32_t wordCacheSpaceRules
;
1185 uint32_t wordCacheLong
;
1186 uint32_t wordCacheHit
;
1187 uint32_t wordCacheMiss
;
1188 uint32_t fallbackPrefs
;
1189 uint32_t fallbackSystem
;
1190 uint32_t textrunConst
;
1191 uint32_t textrunDestr
;
1194 uint32_t reflowCount
;
1196 // counts per reflow operation
1199 // totals for the lifetime of a document
1200 TextCounts cumulative
;
1202 gfxTextPerfMetrics() {
1203 memset(this, 0, sizeof(gfxTextPerfMetrics
));
1206 // add current totals to cumulative ones
1208 if (current
.numChars
== 0) {
1211 cumulative
.numContentTextRuns
+= current
.numContentTextRuns
;
1212 cumulative
.numChromeTextRuns
+= current
.numChromeTextRuns
;
1213 cumulative
.numChars
+= current
.numChars
;
1214 if (current
.maxTextRunLen
> cumulative
.maxTextRunLen
) {
1215 cumulative
.maxTextRunLen
= current
.maxTextRunLen
;
1217 cumulative
.wordCacheSpaceRules
+= current
.wordCacheSpaceRules
;
1218 cumulative
.wordCacheLong
+= current
.wordCacheLong
;
1219 cumulative
.wordCacheHit
+= current
.wordCacheHit
;
1220 cumulative
.wordCacheMiss
+= current
.wordCacheMiss
;
1221 cumulative
.fallbackPrefs
+= current
.fallbackPrefs
;
1222 cumulative
.fallbackSystem
+= current
.fallbackSystem
;
1223 cumulative
.textrunConst
+= current
.textrunConst
;
1224 cumulative
.textrunDestr
+= current
.textrunDestr
;
1225 memset(¤t
, 0, sizeof(current
));
1229 class gfxTextRunFactory
{
1230 NS_INLINE_DECL_REFCOUNTING(gfxTextRunFactory
)
1233 // Flags in the mask 0xFFFF0000 are reserved for textrun clients
1234 // Flags in the mask 0x0000F000 are reserved for per-platform fonts
1235 // Flags in the mask 0x00000FFF are set by the textrun creator.
1237 CACHE_TEXT_FLAGS
= 0xF0000000,
1238 USER_TEXT_FLAGS
= 0x0FFF0000,
1239 PLATFORM_TEXT_FLAGS
= 0x0000F000,
1240 TEXTRUN_TEXT_FLAGS
= 0x00000FFF,
1241 SETTABLE_FLAGS
= CACHE_TEXT_FLAGS
| USER_TEXT_FLAGS
,
1244 * When set, the text string pointer used to create the text run
1245 * is guaranteed to be available during the lifetime of the text run.
1247 TEXT_IS_PERSISTENT
= 0x0001,
1249 * When set, the text is known to be all-ASCII (< 128).
1251 TEXT_IS_ASCII
= 0x0002,
1253 * When set, the text is RTL.
1255 TEXT_IS_RTL
= 0x0004,
1257 * When set, spacing is enabled and the textrun needs to call GetSpacing
1258 * on the spacing provider.
1260 TEXT_ENABLE_SPACING
= 0x0008,
1262 * When set, GetHyphenationBreaks may return true for some character
1263 * positions, otherwise it will always return false for all characters.
1265 TEXT_ENABLE_HYPHEN_BREAKS
= 0x0010,
1267 * When set, the text has no characters above 255 and it is stored
1268 * in the textrun in 8-bit format.
1270 TEXT_IS_8BIT
= 0x0020,
1272 * When set, the RunMetrics::mBoundingBox field will be initialized
1273 * properly based on glyph extents, in particular, glyph extents that
1274 * overflow the standard font-box (the box defined by the ascent, descent
1275 * and advance width of the glyph). When not set, it may just be the
1276 * standard font-box even if glyphs overflow.
1278 TEXT_NEED_BOUNDING_BOX
= 0x0040,
1280 * When set, optional ligatures are disabled. Ligatures that are
1281 * required for legible text should still be enabled.
1283 TEXT_DISABLE_OPTIONAL_LIGATURES
= 0x0080,
1285 * When set, the textrun should favour speed of construction over
1286 * quality. This may involve disabling ligatures and/or kerning or
1289 TEXT_OPTIMIZE_SPEED
= 0x0100,
1291 * For internal use by the memory reporter when accounting for
1292 * storage used by textruns.
1293 * Because the reporter may visit each textrun multiple times while
1294 * walking the frame trees and textrun cache, it needs to mark
1295 * textruns that have been seen so as to avoid multiple-accounting.
1297 TEXT_RUN_SIZE_ACCOUNTED
= 0x0200,
1299 * When set, the textrun should discard control characters instead of
1300 * turning them into hexboxes.
1302 TEXT_HIDE_CONTROL_CHARACTERS
= 0x0400,
1305 * nsTextFrameThebes sets these, but they're defined here rather than
1306 * in nsTextFrameUtils.h because ShapedWord creation/caching also needs
1307 * to check the _INCOMING flag
1309 TEXT_TRAILING_ARABICCHAR
= 0x20000000,
1311 * When set, the previous character for this textrun was an Arabic
1312 * character. This is used for the context detection necessary for
1313 * bidi.numeral implementation.
1315 TEXT_INCOMING_ARABICCHAR
= 0x40000000,
1317 // Set if the textrun should use the OpenType 'math' script.
1318 TEXT_USE_MATH_SCRIPT
= 0x80000000,
1320 TEXT_UNUSED_FLAGS
= 0x10000000
1324 * This record contains all the parameters needed to initialize a textrun.
1327 // A reference context suggesting where the textrun will be rendered
1328 gfxContext
*mContext
;
1329 // Pointer to arbitrary user data (which should outlive the textrun)
1331 // A description of which characters have been stripped from the original
1332 // DOM string to produce the characters in the textrun. May be null
1333 // if that information is not relevant.
1334 gfxSkipChars
*mSkipChars
;
1335 // A list of where linebreaks are currently placed in the textrun. May
1336 // be null if mInitialBreakCount is zero.
1337 uint32_t *mInitialBreaks
;
1338 uint32_t mInitialBreakCount
;
1339 // The ratio to use to convert device pixels to application layout units
1340 int32_t mAppUnitsPerDevUnit
;
1344 // Protected destructor, to discourage deletion outside of Release():
1345 virtual ~gfxTextRunFactory() {}
1349 * This stores glyph bounds information for a particular gfxFont, at
1350 * a particular appunits-per-dev-pixel ratio (because the compressed glyph
1351 * width array is stored in appunits).
1353 * We store a hashtable from glyph IDs to float bounding rects. For the
1354 * common case where the glyph has no horizontal left bearing, and no
1355 * y overflow above the font ascent or below the font descent, and tight
1356 * bounding boxes are not required, we avoid storing the glyph ID in the hashtable
1357 * and instead consult an array of 16-bit glyph XMost values (in appunits).
1358 * This array always has an entry for the font's space glyph --- the width is
1359 * assumed to be zero.
1361 class gfxGlyphExtents
{
1363 explicit gfxGlyphExtents(int32_t aAppUnitsPerDevUnit
) :
1364 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit
) {
1365 MOZ_COUNT_CTOR(gfxGlyphExtents
);
1369 enum { INVALID_WIDTH
= 0xFFFF };
1371 void NotifyGlyphsChanged() {
1372 mTightGlyphExtents
.Clear();
1375 // returns INVALID_WIDTH => not a contained glyph
1376 // Otherwise the glyph has no before-bearing or vertical bearings,
1377 // and the result is its width measured from the baseline origin, in
1379 uint16_t GetContainedGlyphWidthAppUnits(uint32_t aGlyphID
) const {
1380 return mContainedGlyphWidths
.Get(aGlyphID
);
1383 bool IsGlyphKnown(uint32_t aGlyphID
) const {
1384 return mContainedGlyphWidths
.Get(aGlyphID
) != INVALID_WIDTH
||
1385 mTightGlyphExtents
.GetEntry(aGlyphID
) != nullptr;
1388 bool IsGlyphKnownWithTightExtents(uint32_t aGlyphID
) const {
1389 return mTightGlyphExtents
.GetEntry(aGlyphID
) != nullptr;
1392 // Get glyph extents; a rectangle relative to the left baseline origin
1393 // Returns true on success. Can fail on OOM or when aContext is null
1394 // and extents were not (successfully) prefetched.
1395 bool GetTightGlyphExtentsAppUnits(gfxFont
*aFont
, gfxContext
*aContext
,
1396 uint32_t aGlyphID
, gfxRect
*aExtents
);
1398 void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID
, uint16_t aWidth
) {
1399 mContainedGlyphWidths
.Set(aGlyphID
, aWidth
);
1401 void SetTightGlyphExtents(uint32_t aGlyphID
, const gfxRect
& aExtentsAppUnits
);
1403 int32_t GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit
; }
1405 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const;
1406 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const;
1409 class HashEntry
: public nsUint32HashKey
{
1411 // When constructing a new entry in the hashtable, we'll leave this
1412 // blank. The caller of Put() will fill this in.
1413 explicit HashEntry(KeyTypePointer aPtr
) : nsUint32HashKey(aPtr
) {}
1414 HashEntry(const HashEntry
& toCopy
) : nsUint32HashKey(toCopy
) {
1415 x
= toCopy
.x
; y
= toCopy
.y
; width
= toCopy
.width
; height
= toCopy
.height
;
1418 float x
, y
, width
, height
;
1421 enum { BLOCK_SIZE_BITS
= 7, BLOCK_SIZE
= 1 << BLOCK_SIZE_BITS
}; // 128-glyph blocks
1425 void Set(uint32_t aIndex
, uint16_t aValue
);
1426 uint16_t Get(uint32_t aIndex
) const {
1427 uint32_t block
= aIndex
>> BLOCK_SIZE_BITS
;
1428 if (block
>= mBlocks
.Length())
1429 return INVALID_WIDTH
;
1430 uintptr_t bits
= mBlocks
[block
];
1432 return INVALID_WIDTH
;
1433 uint32_t indexInBlock
= aIndex
& (BLOCK_SIZE
- 1);
1435 if (GetGlyphOffset(bits
) != indexInBlock
)
1436 return INVALID_WIDTH
;
1437 return GetWidth(bits
);
1439 uint16_t *widths
= reinterpret_cast<uint16_t *>(bits
);
1440 return widths
[indexInBlock
];
1443 uint32_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const;
1448 static uint32_t GetGlyphOffset(uintptr_t aBits
) {
1449 NS_ASSERTION(aBits
& 0x1, "This is really a pointer...");
1450 return (aBits
>> 1) & ((1 << BLOCK_SIZE_BITS
) - 1);
1452 static uint32_t GetWidth(uintptr_t aBits
) {
1453 NS_ASSERTION(aBits
& 0x1, "This is really a pointer...");
1454 return aBits
>> (1 + BLOCK_SIZE_BITS
);
1456 static uintptr_t MakeSingle(uint32_t aGlyphOffset
, uint16_t aWidth
) {
1457 return (aWidth
<< (1 + BLOCK_SIZE_BITS
)) + (aGlyphOffset
<< 1) + 1;
1460 nsTArray
<uintptr_t> mBlocks
;
1463 GlyphWidths mContainedGlyphWidths
;
1464 nsTHashtable
<HashEntry
> mTightGlyphExtents
;
1465 int32_t mAppUnitsPerDevUnit
;
1469 gfxGlyphExtents(const gfxGlyphExtents
& aOther
) MOZ_DELETE
;
1470 gfxGlyphExtents
& operator=(const gfxGlyphExtents
& aOther
) MOZ_DELETE
;
1476 * This class implements text shaping (character to glyph mapping and
1477 * glyph layout). There is a gfxFontShaper subclass for each text layout
1478 * technology (uniscribe, core text, harfbuzz,....) we support.
1480 * The shaper is responsible for setting up glyph data in gfxTextRuns.
1482 * A generic, platform-independent shaper relies only on the standard
1483 * gfxFont interface and can work with any concrete subclass of gfxFont.
1485 * Platform-specific implementations designed to interface to platform
1486 * shaping APIs such as Uniscribe or CoreText may rely on features of a
1487 * specific font subclass to access native font references
1488 * (such as CTFont, HFONT, DWriteFont, etc).
1491 class gfxFontShaper
{
1493 explicit gfxFontShaper(gfxFont
*aFont
)
1496 NS_ASSERTION(aFont
, "shaper requires a valid font!");
1499 virtual ~gfxFontShaper() { }
1501 // Shape a piece of text and store the resulting glyph data into
1502 // aShapedText. Parameters aOffset/aLength indicate the range of
1503 // aShapedText to be updated; aLength is also the length of aText.
1504 virtual bool ShapeText(gfxContext
*aContext
,
1505 const char16_t
*aText
,
1509 gfxShapedText
*aShapedText
) = 0;
1511 gfxFont
*GetFont() const { return mFont
; }
1513 // returns true if features exist in output, false otherwise
1515 MergeFontFeatures(const gfxFontStyle
*aStyle
,
1516 const nsTArray
<gfxFontFeature
>& aFontFeatures
,
1517 bool aDisableLigatures
,
1518 const nsAString
& aFamilyName
,
1520 nsDataHashtable
<nsUint32HashKey
,uint32_t>& aMergedFeatures
);
1523 // the font this shaper is working with
1528 class GlyphBufferAzure
;
1529 struct TextRunDrawParams
;
1530 struct FontDrawParams
;
1534 friend class gfxHarfBuzzShaper
;
1535 friend class gfxGraphiteShaper
;
1538 nsrefcnt
AddRef(void) {
1539 NS_PRECONDITION(int32_t(mRefCnt
) >= 0, "illegal refcnt");
1540 if (mExpirationState
.IsTracked()) {
1541 gfxFontCache::GetCache()->RemoveObject(this);
1544 NS_LOG_ADDREF(this, mRefCnt
, "gfxFont", sizeof(*this));
1547 nsrefcnt
Release(void) {
1548 NS_PRECONDITION(0 != mRefCnt
, "dup release");
1550 NS_LOG_RELEASE(this, mRefCnt
, "gfxFont");
1553 // |this| may have been deleted.
1559 int32_t GetRefCount() { return mRefCnt
; }
1561 // options to specify the kind of AA to be used when creating a font
1565 kAntialiasGrayscale
,
1570 nsAutoRefCnt mRefCnt
;
1571 cairo_scaled_font_t
*mScaledFont
;
1573 void NotifyReleased() {
1574 gfxFontCache
*cache
= gfxFontCache::GetCache();
1576 // Don't delete just yet; return the object to the cache for
1577 // possibly recycling within some time limit
1578 cache
->NotifyReleased(this);
1580 // The cache may have already been shut down.
1585 gfxFont(gfxFontEntry
*aFontEntry
, const gfxFontStyle
*aFontStyle
,
1586 AntialiasOption anAAOption
= kAntialiasDefault
,
1587 cairo_scaled_font_t
*aScaledFont
= nullptr);
1592 bool Valid() const {
1596 // options for the kind of bounding box to return from measurement
1599 // A box that encloses all the painted pixels, and may
1600 // include sidebearings and/or additional ascent/descent
1601 // within the glyph cell even if the ink is smaller.
1603 // A box that tightly encloses all the painted pixels
1604 // (although actually on Windows, at least, it may be
1605 // slightly larger than strictly necessary because
1606 // we can't get precise extents with ClearType).
1607 TIGHT_HINTED_OUTLINE_EXTENTS
1608 // A box that tightly encloses the glyph outline,
1609 // ignoring possible antialiasing pixels that extend
1611 // NOTE: The default implementation of gfxFont::Measure(),
1612 // which works with the glyph extents cache, does not
1613 // differentiate between this and TIGHT_INK_EXTENTS.
1614 // Whether the distinction is important depends on the
1615 // antialiasing behavior of the platform; currently the
1616 // distinction is only implemented in the gfxWindowsFont
1617 // subclass, because of ClearType's tendency to paint
1618 // outside the hinted outline.
1619 // Also NOTE: it is relatively expensive to request this,
1620 // as it does not use cached glyph extents in the font.
1623 const nsString
& GetName() const { return mFontEntry
->Name(); }
1624 const gfxFontStyle
*GetStyle() const { return &mStyle
; }
1626 virtual cairo_scaled_font_t
* GetCairoScaledFont() { return mScaledFont
; }
1628 virtual gfxFont
* CopyWithAntialiasOption(AntialiasOption anAAOption
) {
1629 // platforms where this actually matters should override
1633 virtual gfxFloat
GetAdjustedSize() const {
1634 return mAdjustedSize
> 0.0 ? mAdjustedSize
: mStyle
.size
;
1637 float FUnitsToDevUnitsFactor() const {
1638 // check this was set up during font initialization
1639 NS_ASSERTION(mFUnitsConvFactor
> 0.0f
, "mFUnitsConvFactor not valid");
1640 return mFUnitsConvFactor
;
1643 // check whether this is an sfnt we can potentially use with harfbuzz
1644 bool FontCanSupportHarfBuzz() {
1645 return mFontEntry
->HasCmapTable();
1648 // check whether this is an sfnt we can potentially use with Graphite
1649 bool FontCanSupportGraphite() {
1650 return mFontEntry
->HasGraphiteTables();
1653 // whether a feature is supported by the font (limited to a small set
1654 // of features for which some form of fallback needs to be implemented)
1655 bool SupportsFeature(int32_t aScript
, uint32_t aFeatureTag
);
1657 // whether the font supports "real" small caps, petite caps etc.
1658 // aFallbackToSmallCaps true when petite caps should fallback to small caps
1659 bool SupportsVariantCaps(int32_t aScript
, uint32_t aVariantCaps
,
1660 bool& aFallbackToSmallCaps
,
1661 bool& aSyntheticLowerToSmallCaps
,
1662 bool& aSyntheticUpperToSmallCaps
);
1664 // whether the font supports subscript/superscript feature
1665 // for fallback, need to verify that all characters in the run
1666 // have variant substitutions
1667 bool SupportsSubSuperscript(uint32_t aSubSuperscript
,
1668 const uint8_t *aString
,
1669 uint32_t aLength
, int32_t aRunScript
);
1671 bool SupportsSubSuperscript(uint32_t aSubSuperscript
,
1672 const char16_t
*aString
,
1673 uint32_t aLength
, int32_t aRunScript
);
1675 // Subclasses may choose to look up glyph ids for characters.
1676 // If they do not override this, gfxHarfBuzzShaper will fetch the cmap
1677 // table and use that.
1678 virtual bool ProvidesGetGlyph() const {
1681 // Map unicode character to glyph ID.
1682 // Only used if ProvidesGetGlyph() returns true.
1683 virtual uint32_t GetGlyph(uint32_t unicode
, uint32_t variation_selector
) {
1686 // Return the horizontal advance of a glyph.
1687 gfxFloat
GetGlyphHAdvance(gfxContext
*aCtx
, uint16_t aGID
);
1689 // Return Azure GlyphRenderingOptions for drawing this font.
1690 virtual mozilla::TemporaryRef
<mozilla::gfx::GlyphRenderingOptions
>
1691 GetGlyphRenderingOptions() { return nullptr; }
1693 gfxFloat
SynthesizeSpaceWidth(uint32_t aCh
);
1698 gfxFloat strikeoutSize
;
1699 gfxFloat strikeoutOffset
;
1700 gfxFloat underlineSize
;
1701 gfxFloat underlineOffset
;
1703 gfxFloat internalLeading
;
1704 gfxFloat externalLeading
;
1711 gfxFloat maxDescent
;
1712 gfxFloat maxAdvance
;
1714 gfxFloat aveCharWidth
;
1715 gfxFloat spaceWidth
;
1716 gfxFloat zeroOrAveCharWidth
; // width of '0', or if there is
1717 // no '0' glyph in this font,
1718 // equal to .aveCharWidth
1720 virtual const gfxFont::Metrics
& GetMetrics() = 0;
1723 * We let layout specify spacing on either side of any
1724 * character. We need to specify both before and after
1725 * spacing so that substring measurement can do the right things.
1726 * These values are in appunits. They're always an integral number of
1727 * appunits, but we specify them in floats in case very large spacing
1728 * values are required.
1735 * Metrics for a particular string
1739 mAdvanceWidth
= mAscent
= mDescent
= 0.0;
1742 void CombineWith(const RunMetrics
& aOther
, bool aOtherIsOnLeft
);
1744 // can be negative (partly due to negative spacing).
1745 // Advance widths should be additive: the advance width of the
1746 // (offset1, length1) plus the advance width of (offset1 + length1,
1747 // length2) should be the advance width of (offset1, length1 + length2)
1748 gfxFloat mAdvanceWidth
;
1750 // For zero-width substrings, these must be zero!
1751 gfxFloat mAscent
; // always non-negative
1752 gfxFloat mDescent
; // always non-negative
1754 // Bounding box that is guaranteed to include everything drawn.
1755 // If a tight boundingBox was requested when these metrics were
1756 // generated, this will tightly wrap the glyphs, otherwise it is
1757 // "loose" and may be larger than the true bounding box.
1758 // Coordinates are relative to the baseline left origin, so typically
1759 // mBoundingBox.y == -mAscent
1760 gfxRect mBoundingBox
;
1764 * Draw a series of glyphs to aContext. The direction of aTextRun must
1766 * @param aStart the first character to draw
1767 * @param aEnd draw characters up to here
1768 * @param aPt the baseline origin; the left end of the baseline
1769 * for LTR textruns, the right end for RTL textruns.
1770 * On return, this will be updated to the other end of the baseline.
1771 * In application units, really!
1772 * @param aRunParams record with drawing parameters, see TextRunDrawParams.
1773 * Particular fields of interest include
1774 * .spacing spacing to insert before and after characters (for RTL
1775 * glyphs, before-spacing is inserted to the right of characters). There
1776 * are aEnd - aStart elements in this array, unless it's null to indicate
1777 * that there is no spacing.
1778 * .drawMode specifies whether the fill or stroke of the glyph should be
1779 * drawn, or if it should be drawn into the current path
1780 * .contextPaint information about how to construct the fill and
1781 * stroke pattern. Can be nullptr if we are not stroking the text, which
1782 * indicates that the current source from context should be used for fill
1783 * .context the Thebes graphics context to which we're drawing
1784 * .dt Moz2D DrawTarget to which we're drawing
1786 * Callers guarantee:
1787 * -- aStart and aEnd are aligned to cluster and ligature boundaries
1788 * -- all glyphs use this font
1790 void Draw(gfxTextRun
*aTextRun
, uint32_t aStart
, uint32_t aEnd
,
1791 gfxPoint
*aPt
, const TextRunDrawParams
& aRunParams
);
1794 * Measure a run of characters. See gfxTextRun::Metrics.
1795 * @param aTight if false, then return the union of the glyph extents
1796 * with the font-box for the characters (the rectangle with x=0,width=
1797 * the advance width for the character run,y=-(font ascent), and height=
1798 * font ascent + font descent). Otherwise, we must return as tight as possible
1799 * an approximation to the area actually painted by glyphs.
1800 * @param aContextForTightBoundingBox when aTight is true, this must
1802 * @param aSpacing spacing to insert before and after glyphs. The bounding box
1803 * need not include the spacing itself, but the spacing affects the glyph
1804 * positions. null if there is no spacing.
1806 * Callers guarantee:
1807 * -- aStart and aEnd are aligned to cluster and ligature boundaries
1808 * -- all glyphs use this font
1810 * The default implementation just uses font metrics and aTextRun's
1811 * advances, and assumes no characters fall outside the font box. In
1812 * general this is insufficient, because that assumption is not always true.
1814 virtual RunMetrics
Measure(gfxTextRun
*aTextRun
,
1815 uint32_t aStart
, uint32_t aEnd
,
1816 BoundingBoxType aBoundingBoxType
,
1817 gfxContext
*aContextForTightBoundingBox
,
1820 * Line breaks have been changed at the beginning and/or end of a substring
1821 * of the text. Reshaping may be required; glyph updating is permitted.
1822 * @return true if anything was changed, false otherwise
1824 bool NotifyLineBreaksChanged(gfxTextRun
*aTextRun
,
1825 uint32_t aStart
, uint32_t aLength
)
1828 // Expiration tracking
1829 nsExpirationState
*GetExpirationState() { return &mExpirationState
; }
1831 // Get the glyphID of a space
1832 virtual uint32_t GetSpaceGlyph() = 0;
1834 gfxGlyphExtents
*GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit
);
1836 // You need to call SetupCairoFont on the aCR just before calling this
1837 virtual void SetupGlyphExtents(gfxContext
*aContext
, uint32_t aGlyphID
,
1838 bool aNeedTight
, gfxGlyphExtents
*aExtents
);
1840 // This is called by the default Draw() implementation above.
1841 virtual bool SetupCairoFont(gfxContext
*aContext
) = 0;
1843 virtual bool AllowSubpixelAA() { return true; }
1845 bool IsSyntheticBold() { return mApplySyntheticBold
; }
1847 // Amount by which synthetic bold "fattens" the glyphs:
1848 // For size S up to a threshold size T, we use (0.25 + 3S / 4T),
1849 // so that the result ranges from 0.25 to 1.0; thereafter,
1850 // simply use (S / T).
1851 gfxFloat
GetSyntheticBoldOffset() {
1852 gfxFloat size
= GetAdjustedSize();
1853 const gfxFloat threshold
= 48.0;
1854 return size
< threshold
? (0.25 + 0.75 * size
/ threshold
) :
1858 gfxFontEntry
*GetFontEntry() const { return mFontEntry
.get(); }
1859 bool HasCharacter(uint32_t ch
) {
1862 return mFontEntry
->HasCharacter(ch
);
1865 uint16_t GetUVSGlyph(uint32_t aCh
, uint32_t aVS
) {
1869 return mFontEntry
->GetUVSGlyph(aCh
, aVS
);
1872 bool InitFakeSmallCapsRun(gfxContext
*aContext
,
1873 gfxTextRun
*aTextRun
,
1874 const uint8_t *aText
,
1879 bool aSyntheticLower
,
1880 bool aSyntheticUpper
);
1882 bool InitFakeSmallCapsRun(gfxContext
*aContext
,
1883 gfxTextRun
*aTextRun
,
1884 const char16_t
*aText
,
1889 bool aSyntheticLower
,
1890 bool aSyntheticUpper
);
1892 // call the (virtual) InitTextRun method to do glyph generation/shaping,
1893 // limiting the length of text passed by processing the run in multiple
1894 // segments if necessary
1895 template<typename T
>
1896 bool SplitAndInitTextRun(gfxContext
*aContext
,
1897 gfxTextRun
*aTextRun
,
1900 uint32_t aRunLength
,
1901 int32_t aRunScript
);
1903 // Get a ShapedWord representing the given text (either 8- or 16-bit)
1904 // for use in setting up a gfxTextRun.
1905 template<typename T
>
1906 gfxShapedWord
* GetShapedWord(gfxContext
*aContext
,
1911 int32_t aAppUnitsPerDevUnit
,
1913 gfxTextPerfMetrics
*aTextPerf
);
1915 // Ensure the ShapedWord cache is initialized. This MUST be called before
1916 // any attempt to use GetShapedWord().
1917 void InitWordCache() {
1919 mWordCache
= new nsTHashtable
<CacheHashEntry
>;
1923 // Called by the gfxFontCache timer to increment the age of all the words,
1924 // so that they'll expire after a sufficient period of non-use
1925 void AgeCachedWords() {
1927 (void)mWordCache
->EnumerateEntries(AgeCacheEntry
, this);
1931 // Discard all cached word records; called on memory-pressure notification.
1932 void ClearCachedWords() {
1934 mWordCache
->Clear();
1938 // Glyph rendering/geometry has changed, so invalidate data as necessary.
1939 void NotifyGlyphsChanged();
1941 virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
1942 FontCacheSizes
* aSizes
) const;
1943 virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
1944 FontCacheSizes
* aSizes
) const;
1955 virtual FontType
GetType() const = 0;
1957 virtual mozilla::TemporaryRef
<mozilla::gfx::ScaledFont
> GetScaledFont(mozilla::gfx::DrawTarget
*aTarget
)
1958 { return gfxPlatform::GetPlatform()->GetScaledFontForFont(aTarget
, this); }
1960 bool KerningDisabled() {
1961 return mKerningSet
&& !mKerningEnabled
;
1965 * Subclass this object to be notified of glyph changes. Delete the object
1966 * when no longer needed.
1968 class GlyphChangeObserver
{
1970 virtual ~GlyphChangeObserver()
1973 mFont
->RemoveGlyphChangeObserver(this);
1976 // This gets called when the gfxFont dies.
1977 void ForgetFont() { mFont
= nullptr; }
1978 virtual void NotifyGlyphsChanged() = 0;
1980 explicit GlyphChangeObserver(gfxFont
*aFont
) : mFont(aFont
)
1982 mFont
->AddGlyphChangeObserver(this);
1986 friend class GlyphChangeObserver
;
1988 bool GlyphsMayChange()
1990 // Currently only fonts with SVG glyphs can have animated glyphs
1991 return mFontEntry
->TryGetSVGData(this);
1994 static void DestroySingletons() {
1995 delete sScriptTagToCode
;
1996 delete sDefaultFeatures
;
1999 // Get a font dimension from the MATH table, scaled to appUnits;
2000 // may only be called if mFontEntry->TryGetMathTable has succeeded
2001 // (i.e. the font is known to be a valid OpenType math font).
2002 nscoord
GetMathConstant(gfxFontEntry::MathConstant aConstant
,
2003 uint32_t aAppUnitsPerDevPixel
)
2005 return NSToCoordRound(mFontEntry
->GetMathConstant(aConstant
) *
2006 GetAdjustedSize() * aAppUnitsPerDevPixel
);
2009 // Get a dimensionless math constant (e.g. a percentage);
2010 // may only be called if mFontEntry->TryGetMathTable has succeeded
2011 // (i.e. the font is known to be a valid OpenType math font).
2012 float GetMathConstant(gfxFontEntry::MathConstant aConstant
)
2014 return mFontEntry
->GetMathConstant(aConstant
);
2017 // return a cloned font resized and offset to simulate sub/superscript glyphs
2018 virtual already_AddRefed
<gfxFont
>
2019 GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel
);
2022 // Output a single glyph at *aPt, which is updated by the glyph's advance.
2023 // Normal glyphs are simply accumulated in aBuffer until it is full and
2024 // gets flushed, but SVG or color-font glyphs will instead be rendered
2025 // directly to the destination (found from the buffer's parameters).
2026 void DrawOneGlyph(uint32_t aGlyphID
,
2029 GlyphBufferAzure
& aBuffer
,
2030 bool *aEmittedGlyphs
) const;
2032 // Output a run of glyphs at *aPt, which is updated to follow the last glyph
2033 // in the run. This method also takes account of any letter-spacing provided
2035 bool DrawGlyphs(gfxShapedText
*aShapedText
,
2036 uint32_t aOffset
, // offset in the textrun
2037 uint32_t aCount
, // length of run to draw
2039 const TextRunDrawParams
& aRunParams
,
2040 const FontDrawParams
& aFontParams
);
2042 // set the font size and offset used for
2043 // synthetic subscript/superscript glyphs
2044 void CalculateSubSuperSizeAndOffset(int32_t aAppUnitsPerDevPixel
,
2045 gfxFloat
& aSubSuperSizeRatio
,
2046 float& aBaselineOffset
);
2048 // Return a font that is a "clone" of this one, but reduced to 80% size
2049 // (and with variantCaps set to normal).
2050 // Default implementation relies on gfxFontEntry::CreateFontInstance;
2051 // backends that don't implement that will need to override this and use
2052 // an alternative technique. (gfxPangoFonts, I'm looking at you...)
2053 virtual already_AddRefed
<gfxFont
> GetSmallCapsFont();
2055 // subclasses may provide (possibly hinted) glyph widths (in font units);
2056 // if they do not override this, harfbuzz will use unhinted widths
2057 // derived from the font tables
2058 virtual bool ProvidesGlyphWidths() const {
2062 // The return value is interpreted as a horizontal advance in 16.16 fixed
2064 virtual int32_t GetGlyphWidth(gfxContext
*aCtx
, uint16_t aGID
) {
2068 void AddGlyphChangeObserver(GlyphChangeObserver
*aObserver
);
2069 void RemoveGlyphChangeObserver(GlyphChangeObserver
*aObserver
);
2071 // whether font contains substitution lookups containing spaces
2072 bool HasSubstitutionRulesWithSpaceLookups(int32_t aRunScript
);
2074 // do spaces participate in shaping rules? if so, can't used word cache
2075 bool SpaceMayParticipateInShaping(int32_t aRunScript
);
2077 // For 8-bit text, expand to 16-bit and then call the following method.
2078 bool ShapeText(gfxContext
*aContext
,
2079 const uint8_t *aText
,
2080 uint32_t aOffset
, // dest offset in gfxShapedText
2083 gfxShapedText
*aShapedText
); // where to store the result
2085 // Call the appropriate shaper to generate glyphs for aText and store
2086 // them into aShapedText.
2087 virtual bool ShapeText(gfxContext
*aContext
,
2088 const char16_t
*aText
,
2092 gfxShapedText
*aShapedText
);
2094 // Helper to adjust for synthetic bold and set character-type flags
2095 // in the shaped text; implementations of ShapeText should call this
2096 // after glyph shaping has been completed.
2097 void PostShapingFixup(gfxContext
*aContext
,
2098 const char16_t
*aText
,
2099 uint32_t aOffset
, // position within aShapedText
2101 gfxShapedText
*aShapedText
);
2103 // Shape text directly into a range within a textrun, without using the
2104 // font's word cache. Intended for use when the font has layout features
2105 // that involve space, and therefore require shaping complete runs rather
2106 // than isolated words, or for long strings that are inefficient to cache.
2107 // This will split the text on "invalid" characters (tab/newline) that are
2108 // not handled via normal shaping, but does not otherwise divide up the
2110 template<typename T
>
2111 bool ShapeTextWithoutWordCache(gfxContext
*aContext
,
2116 gfxTextRun
*aTextRun
);
2118 // Shape a fragment of text (a run that is known to contain only
2119 // "valid" characters, no newlines/tabs/other control chars).
2120 // All non-wordcache shaping goes through here; this is the function
2121 // that will ensure we don't pass excessively long runs to the various
2122 // platform shapers.
2123 template<typename T
>
2124 bool ShapeFragmentWithoutWordCache(gfxContext
*aContext
,
2129 gfxTextRun
*aTextRun
);
2131 void CheckForFeaturesInvolvingSpace();
2133 // whether a given feature is included in feature settings from both the
2134 // font and the style. aFeatureOn set if resolved feature value is non-zero
2135 bool HasFeatureSet(uint32_t aFeature
, bool& aFeatureOn
);
2137 // used when analyzing whether a font has space contextual lookups
2138 static nsDataHashtable
<nsUint32HashKey
, int32_t> *sScriptTagToCode
;
2139 static nsTHashtable
<nsUint32HashKey
> *sDefaultFeatures
;
2141 nsRefPtr
<gfxFontEntry
> mFontEntry
;
2143 struct CacheHashKey
{
2145 const uint8_t *mSingle
;
2146 const char16_t
*mDouble
;
2151 int32_t mAppUnitsPerDevUnit
;
2152 PLDHashNumber mHashKey
;
2155 CacheHashKey(const uint8_t *aText
, uint32_t aLength
,
2156 uint32_t aStringHash
,
2157 int32_t aScriptCode
, int32_t aAppUnitsPerDevUnit
,
2161 mScript(aScriptCode
),
2162 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit
),
2163 mHashKey(aStringHash
+ aScriptCode
+
2164 aAppUnitsPerDevUnit
* 0x100 + aFlags
* 0x10000),
2167 NS_ASSERTION(aFlags
& gfxTextRunFactory::TEXT_IS_8BIT
,
2168 "8-bit flag should have been set");
2169 mText
.mSingle
= aText
;
2172 CacheHashKey(const char16_t
*aText
, uint32_t aLength
,
2173 uint32_t aStringHash
,
2174 int32_t aScriptCode
, int32_t aAppUnitsPerDevUnit
,
2178 mScript(aScriptCode
),
2179 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit
),
2180 mHashKey(aStringHash
+ aScriptCode
+
2181 aAppUnitsPerDevUnit
* 0x100 + aFlags
* 0x10000),
2184 // We can NOT assert that TEXT_IS_8BIT is false in aFlags here,
2185 // because this might be an 8bit-only word from a 16-bit textrun,
2186 // in which case the text we're passed is still in 16-bit form,
2187 // and we'll have to use an 8-to-16bit comparison in KeyEquals.
2188 mText
.mDouble
= aText
;
2192 class CacheHashEntry
: public PLDHashEntryHdr
{
2194 typedef const CacheHashKey
&KeyType
;
2195 typedef const CacheHashKey
*KeyTypePointer
;
2197 // When constructing a new entry in the hashtable, the caller of Put()
2199 explicit CacheHashEntry(KeyTypePointer aKey
) { }
2200 CacheHashEntry(const CacheHashEntry
& toCopy
) { NS_ERROR("Should not be called"); }
2201 ~CacheHashEntry() { }
2203 bool KeyEquals(const KeyTypePointer aKey
) const;
2205 static KeyTypePointer
KeyToPointer(KeyType aKey
) { return &aKey
; }
2207 static PLDHashNumber
HashKey(const KeyTypePointer aKey
) {
2208 return aKey
->mHashKey
;
2211 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const
2213 return aMallocSizeOf(mShapedWord
.get());
2216 enum { ALLOW_MEMMOVE
= true };
2218 nsAutoPtr
<gfxShapedWord
> mShapedWord
;
2221 nsAutoPtr
<nsTHashtable
<CacheHashEntry
> > mWordCache
;
2223 static PLDHashOperator
AgeCacheEntry(CacheHashEntry
*aEntry
, void *aUserData
);
2224 static const uint32_t kShapedWordCacheMaxAge
= 3;
2228 // use synthetic bolding for environments where this is not supported
2230 bool mApplySyntheticBold
;
2232 bool mKerningSet
; // kerning explicitly set?
2233 bool mKerningEnabled
; // if set, on or off?
2235 nsExpirationState mExpirationState
;
2236 gfxFontStyle mStyle
;
2237 nsAutoTArray
<gfxGlyphExtents
*,1> mGlyphExtentsArray
;
2238 nsAutoPtr
<nsTHashtable
<nsPtrHashKey
<GlyphChangeObserver
> > > mGlyphChangeObservers
;
2240 gfxFloat mAdjustedSize
;
2242 float mFUnitsConvFactor
; // conversion factor from font units to dev units
2244 // the AA setting requested for this font - may affect glyph bounds
2245 AntialiasOption mAntialiasOption
;
2247 // a copy of the font without antialiasing, if needed for separate
2248 // measurement by mathml code
2249 nsAutoPtr
<gfxFont
> mNonAAFont
;
2251 // we create either or both of these shapers when needed, depending
2252 // whether the font has graphite tables, and whether graphite shaping
2253 // is actually enabled
2254 nsAutoPtr
<gfxFontShaper
> mHarfBuzzShaper
;
2255 nsAutoPtr
<gfxFontShaper
> mGraphiteShaper
;
2257 mozilla::RefPtr
<mozilla::gfx::ScaledFont
> mAzureScaledFont
;
2259 // Helper for subclasses that want to initialize standard metrics from the
2260 // tables of sfnt (TrueType/OpenType) fonts.
2261 // This will use mFUnitsConvFactor if it is already set, else compute it
2262 // from mAdjustedSize and the unitsPerEm in the font's 'head' table.
2263 // Returns TRUE and sets mIsValid=TRUE if successful;
2264 // Returns TRUE but leaves mIsValid=FALSE if the font seems to be broken.
2265 // Returns FALSE if the font does not appear to be an sfnt at all,
2266 // and should be handled (if possible) using other APIs.
2267 bool InitMetricsFromSfntTables(Metrics
& aMetrics
);
2269 // Helper to calculate various derived metrics from the results of
2270 // InitMetricsFromSfntTables or equivalent platform code
2271 void CalculateDerivedMetrics(Metrics
& aMetrics
);
2273 // some fonts have bad metrics, this method sanitize them.
2274 // if this font has bad underline offset, aIsBadUnderlineFont should be true.
2275 void SanitizeMetrics(gfxFont::Metrics
*aMetrics
, bool aIsBadUnderlineFont
);
2277 bool RenderSVGGlyph(gfxContext
*aContext
, gfxPoint aPoint
, DrawMode aDrawMode
,
2278 uint32_t aGlyphId
, gfxTextContextPaint
*aContextPaint
) const;
2279 bool RenderSVGGlyph(gfxContext
*aContext
, gfxPoint aPoint
, DrawMode aDrawMode
,
2280 uint32_t aGlyphId
, gfxTextContextPaint
*aContextPaint
,
2281 gfxTextRunDrawCallbacks
*aCallbacks
,
2282 bool& aEmittedGlyphs
) const;
2284 bool RenderColorGlyph(gfxContext
* aContext
,
2285 mozilla::gfx::ScaledFont
* scaledFont
,
2286 mozilla::gfx::GlyphRenderingOptions
* renderingOptions
,
2287 mozilla::gfx::DrawOptions drawOptions
,
2288 const mozilla::gfx::Point
& aPoint
,
2289 uint32_t aGlyphId
) const;
2291 // Bug 674909. When synthetic bolding text by drawing twice, need to
2292 // render using a pixel offset in device pixels, otherwise text
2293 // doesn't appear bolded, it appears as if a bad text shadow exists
2294 // when a non-identity transform exists. Use an offset factor so that
2295 // the second draw occurs at a constant offset in device pixels.
2296 // This helper calculates the scale factor we need to apply to the
2297 // synthetic-bold offset.
2298 static double CalcXScale(gfxContext
*aContext
);
2301 // proportion of ascent used for x-height, if unable to read value from font
2302 #define DEFAULT_XHEIGHT_FACTOR 0.56f
2305 * gfxShapedText is an abstract superclass for gfxShapedWord and gfxTextRun.
2306 * These are objects that store a list of zero or more glyphs for each character.
2307 * For each glyph we store the glyph ID, the advance, and possibly x/y-offsets.
2308 * The idea is that a string is rendered by a loop that draws each glyph
2309 * at its designated offset from the current point, then advances the current
2310 * point by the glyph's advance in the direction of the textrun (LTR or RTL).
2311 * Each glyph advance is always rounded to the nearest appunit; this ensures
2312 * consistent results when dividing the text in a textrun into multiple text
2313 * frames (frame boundaries are always aligned to appunits). We optimize
2314 * for the case where a character has a single glyph and zero xoffset and yoffset,
2315 * and the glyph ID and advance are in a reasonable range so we can pack all
2316 * necessary data into 32 bits.
2318 * gfxFontShaper can shape text into either a gfxShapedWord (cached by a gfxFont)
2319 * or directly into a gfxTextRun (for cases where we want to shape textruns in
2320 * their entirety rather than using cached words, because there may be layout
2321 * features that depend on the inter-word spaces).
2326 gfxShapedText(uint32_t aLength
, uint32_t aFlags
,
2327 int32_t aAppUnitsPerDevUnit
)
2330 , mAppUnitsPerDevUnit(aAppUnitsPerDevUnit
)
2333 virtual ~gfxShapedText() { }
2336 * This class records the information associated with a character in the
2337 * input string. It's optimized for the case where there is one glyph
2338 * representing that character alone.
2340 * A character can have zero or more associated glyphs. Each glyph
2341 * has an advance width and an x and y offset.
2342 * A character may be the start of a cluster.
2343 * A character may be the start of a ligature group.
2344 * A character can be "missing", indicating that the system is unable
2345 * to render the character.
2347 * All characters in a ligature group conceptually share all the glyphs
2348 * associated with the characters in a group.
2350 class CompressedGlyph
{
2352 CompressedGlyph() { mValue
= 0; }
2355 // Indicates that a cluster and ligature group starts at this
2356 // character; this character has a single glyph with a reasonable
2357 // advance and zero offsets. A "reasonable" advance
2358 // is one that fits in the available bits (currently 12) (specified
2360 FLAG_IS_SIMPLE_GLYPH
= 0x80000000U
,
2362 // Indicates whether a linebreak is allowed before this character;
2363 // this is a two-bit field that holds a FLAG_BREAK_TYPE_xxx value
2364 // indicating the kind of linebreak (if any) allowed here.
2365 FLAGS_CAN_BREAK_BEFORE
= 0x60000000U
,
2367 FLAGS_CAN_BREAK_SHIFT
= 29,
2368 FLAG_BREAK_TYPE_NONE
= 0,
2369 FLAG_BREAK_TYPE_NORMAL
= 1,
2370 FLAG_BREAK_TYPE_HYPHEN
= 2,
2372 FLAG_CHAR_IS_SPACE
= 0x10000000U
,
2374 // The advance is stored in appunits
2375 ADVANCE_MASK
= 0x0FFF0000U
,
2378 GLYPH_MASK
= 0x0000FFFFU
,
2380 // Non-simple glyphs may or may not have glyph data in the
2381 // corresponding mDetailedGlyphs entry. They have the following
2384 // When NOT set, indicates that this character corresponds to a
2385 // missing glyph and should be skipped (or possibly, render the character
2386 // Unicode value in some special way). If there are glyphs,
2387 // the mGlyphID is actually the UTF16 character code. The bit is
2388 // inverted so we can memset the array to zero to indicate all missing.
2389 FLAG_NOT_MISSING
= 0x01,
2390 FLAG_NOT_CLUSTER_START
= 0x02,
2391 FLAG_NOT_LIGATURE_GROUP_START
= 0x04,
2393 FLAG_CHAR_IS_TAB
= 0x08,
2394 FLAG_CHAR_IS_NEWLINE
= 0x10,
2395 FLAG_CHAR_IS_LOW_SURROGATE
= 0x20,
2396 CHAR_IDENTITY_FLAGS_MASK
= 0x38,
2398 GLYPH_COUNT_MASK
= 0x00FFFF00U
,
2399 GLYPH_COUNT_SHIFT
= 8
2402 // "Simple glyphs" have a simple glyph ID, simple advance and their
2403 // x and y offsets are zero. Also the glyph extents do not overflow
2404 // the font-box defined by the font ascent, descent and glyph advance width.
2405 // These case is optimized to avoid storing DetailedGlyphs.
2407 // Returns true if the glyph ID aGlyph fits into the compressed representation
2408 static bool IsSimpleGlyphID(uint32_t aGlyph
) {
2409 return (aGlyph
& GLYPH_MASK
) == aGlyph
;
2411 // Returns true if the advance aAdvance fits into the compressed representation.
2412 // aAdvance is in appunits.
2413 static bool IsSimpleAdvance(uint32_t aAdvance
) {
2414 return (aAdvance
& (ADVANCE_MASK
>> ADVANCE_SHIFT
)) == aAdvance
;
2417 bool IsSimpleGlyph() const { return (mValue
& FLAG_IS_SIMPLE_GLYPH
) != 0; }
2418 uint32_t GetSimpleAdvance() const { return (mValue
& ADVANCE_MASK
) >> ADVANCE_SHIFT
; }
2419 uint32_t GetSimpleGlyph() const { return mValue
& GLYPH_MASK
; }
2421 bool IsMissing() const { return (mValue
& (FLAG_NOT_MISSING
|FLAG_IS_SIMPLE_GLYPH
)) == 0; }
2422 bool IsClusterStart() const {
2423 return (mValue
& FLAG_IS_SIMPLE_GLYPH
) || !(mValue
& FLAG_NOT_CLUSTER_START
);
2425 bool IsLigatureGroupStart() const {
2426 return (mValue
& FLAG_IS_SIMPLE_GLYPH
) || !(mValue
& FLAG_NOT_LIGATURE_GROUP_START
);
2428 bool IsLigatureContinuation() const {
2429 return (mValue
& FLAG_IS_SIMPLE_GLYPH
) == 0 &&
2430 (mValue
& (FLAG_NOT_LIGATURE_GROUP_START
| FLAG_NOT_MISSING
)) ==
2431 (FLAG_NOT_LIGATURE_GROUP_START
| FLAG_NOT_MISSING
);
2434 // Return true if the original character was a normal (breakable,
2435 // trimmable) space (U+0020). Not true for other characters that
2436 // may happen to map to the space glyph (U+00A0).
2437 bool CharIsSpace() const {
2438 return (mValue
& FLAG_CHAR_IS_SPACE
) != 0;
2441 bool CharIsTab() const {
2442 return !IsSimpleGlyph() && (mValue
& FLAG_CHAR_IS_TAB
) != 0;
2444 bool CharIsNewline() const {
2445 return !IsSimpleGlyph() && (mValue
& FLAG_CHAR_IS_NEWLINE
) != 0;
2447 bool CharIsLowSurrogate() const {
2448 return !IsSimpleGlyph() && (mValue
& FLAG_CHAR_IS_LOW_SURROGATE
) != 0;
2451 uint32_t CharIdentityFlags() const {
2452 return IsSimpleGlyph() ? 0 : (mValue
& CHAR_IDENTITY_FLAGS_MASK
);
2455 void SetClusterStart(bool aIsClusterStart
) {
2456 NS_ASSERTION(!IsSimpleGlyph(),
2457 "can't call SetClusterStart on simple glyphs");
2458 if (aIsClusterStart
) {
2459 mValue
&= ~FLAG_NOT_CLUSTER_START
;
2461 mValue
|= FLAG_NOT_CLUSTER_START
;
2465 uint8_t CanBreakBefore() const {
2466 return (mValue
& FLAGS_CAN_BREAK_BEFORE
) >> FLAGS_CAN_BREAK_SHIFT
;
2468 // Returns FLAGS_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
2469 uint32_t SetCanBreakBefore(uint8_t aCanBreakBefore
) {
2470 NS_ASSERTION(aCanBreakBefore
<= 2,
2471 "Bogus break-before value!");
2472 uint32_t breakMask
= (uint32_t(aCanBreakBefore
) << FLAGS_CAN_BREAK_SHIFT
);
2473 uint32_t toggle
= breakMask
^ (mValue
& FLAGS_CAN_BREAK_BEFORE
);
2478 CompressedGlyph
& SetSimpleGlyph(uint32_t aAdvanceAppUnits
, uint32_t aGlyph
) {
2479 NS_ASSERTION(IsSimpleAdvance(aAdvanceAppUnits
), "Advance overflow");
2480 NS_ASSERTION(IsSimpleGlyphID(aGlyph
), "Glyph overflow");
2481 NS_ASSERTION(!CharIdentityFlags(), "Char identity flags lost");
2482 mValue
= (mValue
& (FLAGS_CAN_BREAK_BEFORE
| FLAG_CHAR_IS_SPACE
)) |
2483 FLAG_IS_SIMPLE_GLYPH
|
2484 (aAdvanceAppUnits
<< ADVANCE_SHIFT
) | aGlyph
;
2487 CompressedGlyph
& SetComplex(bool aClusterStart
, bool aLigatureStart
,
2488 uint32_t aGlyphCount
) {
2489 mValue
= (mValue
& (FLAGS_CAN_BREAK_BEFORE
| FLAG_CHAR_IS_SPACE
)) |
2491 CharIdentityFlags() |
2492 (aClusterStart
? 0 : FLAG_NOT_CLUSTER_START
) |
2493 (aLigatureStart
? 0 : FLAG_NOT_LIGATURE_GROUP_START
) |
2494 (aGlyphCount
<< GLYPH_COUNT_SHIFT
);
2498 * Missing glyphs are treated as ligature group starts; don't mess with
2499 * the cluster-start flag (see bugs 618870 and 619286).
2501 CompressedGlyph
& SetMissing(uint32_t aGlyphCount
) {
2502 mValue
= (mValue
& (FLAGS_CAN_BREAK_BEFORE
| FLAG_NOT_CLUSTER_START
|
2503 FLAG_CHAR_IS_SPACE
)) |
2504 CharIdentityFlags() |
2505 (aGlyphCount
<< GLYPH_COUNT_SHIFT
);
2508 uint32_t GetGlyphCount() const {
2509 NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
2510 return (mValue
& GLYPH_COUNT_MASK
) >> GLYPH_COUNT_SHIFT
;
2514 mValue
|= FLAG_CHAR_IS_SPACE
;
2517 NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
2518 mValue
|= FLAG_CHAR_IS_TAB
;
2520 void SetIsNewline() {
2521 NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
2522 mValue
|= FLAG_CHAR_IS_NEWLINE
;
2524 void SetIsLowSurrogate() {
2525 NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
2526 mValue
|= FLAG_CHAR_IS_LOW_SURROGATE
;
2533 // Accessor for the array of CompressedGlyph records, which will be in
2534 // a different place in gfxShapedWord vs gfxTextRun
2535 virtual CompressedGlyph
*GetCharacterGlyphs() = 0;
2538 * When the glyphs for a character don't fit into a CompressedGlyph record
2539 * in SimpleGlyph format, we use an array of DetailedGlyphs instead.
2541 struct DetailedGlyph
{
2542 /** The glyphID, or the Unicode character
2543 * if this is a missing glyph */
2545 /** The advance, x-offset and y-offset of the glyph, in appunits
2546 * mAdvance is in the text direction (RTL or LTR)
2547 * mXOffset is always from left to right
2548 * mYOffset is always from top to bottom */
2550 float mXOffset
, mYOffset
;
2553 void SetGlyphs(uint32_t aCharIndex
, CompressedGlyph aGlyph
,
2554 const DetailedGlyph
*aGlyphs
);
2556 void SetMissingGlyph(uint32_t aIndex
, uint32_t aChar
, gfxFont
*aFont
);
2558 void SetIsSpace(uint32_t aIndex
) {
2559 GetCharacterGlyphs()[aIndex
].SetIsSpace();
2562 void SetIsLowSurrogate(uint32_t aIndex
) {
2563 SetGlyphs(aIndex
, CompressedGlyph().SetComplex(false, false, 0), nullptr);
2564 GetCharacterGlyphs()[aIndex
].SetIsLowSurrogate();
2567 bool HasDetailedGlyphs() const {
2568 return mDetailedGlyphs
!= nullptr;
2571 bool IsClusterStart(uint32_t aPos
) {
2572 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
2573 return GetCharacterGlyphs()[aPos
].IsClusterStart();
2576 bool IsLigatureGroupStart(uint32_t aPos
) {
2577 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
2578 return GetCharacterGlyphs()[aPos
].IsLigatureGroupStart();
2581 // NOTE that this must not be called for a character offset that does
2582 // not have any DetailedGlyph records; callers must have verified that
2583 // GetCharacterGlyphs()[aCharIndex].GetGlyphCount() is greater than zero.
2584 DetailedGlyph
*GetDetailedGlyphs(uint32_t aCharIndex
) {
2585 NS_ASSERTION(GetCharacterGlyphs() && HasDetailedGlyphs() &&
2586 !GetCharacterGlyphs()[aCharIndex
].IsSimpleGlyph() &&
2587 GetCharacterGlyphs()[aCharIndex
].GetGlyphCount() > 0,
2588 "invalid use of GetDetailedGlyphs; check the caller!");
2589 return mDetailedGlyphs
->Get(aCharIndex
);
2592 void AdjustAdvancesForSyntheticBold(float aSynBoldOffset
,
2593 uint32_t aOffset
, uint32_t aLength
);
2595 // Mark clusters in the CompressedGlyph records, starting at aOffset,
2596 // based on the Unicode properties of the text in aString.
2597 // This is also responsible to set the IsSpace flag for space characters.
2598 void SetupClusterBoundaries(uint32_t aOffset
,
2599 const char16_t
*aString
,
2601 // In 8-bit text, there won't actually be any clusters, but we still need
2602 // the space-marking functionality.
2603 void SetupClusterBoundaries(uint32_t aOffset
,
2604 const uint8_t *aString
,
2607 uint32_t Flags() const {
2611 bool IsRightToLeft() const {
2612 return (Flags() & gfxTextRunFactory::TEXT_IS_RTL
) != 0;
2615 float GetDirection() const {
2616 return IsRightToLeft() ? -1.0f
: 1.0f
;
2619 bool DisableLigatures() const {
2620 return (Flags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES
) != 0;
2623 bool TextIs8Bit() const {
2624 return (Flags() & gfxTextRunFactory::TEXT_IS_8BIT
) != 0;
2627 int32_t GetAppUnitsPerDevUnit() const {
2628 return mAppUnitsPerDevUnit
;
2631 uint32_t GetLength() const {
2635 bool FilterIfIgnorable(uint32_t aIndex
, uint32_t aCh
);
2638 // Allocate aCount DetailedGlyphs for the given index
2639 DetailedGlyph
*AllocateDetailedGlyphs(uint32_t aCharIndex
,
2642 // For characters whose glyph data does not fit the "simple" glyph criteria
2643 // in CompressedGlyph, we use a sorted array to store the association
2644 // between the source character offset and an index into an array
2645 // DetailedGlyphs. The CompressedGlyph record includes a count of
2646 // the number of DetailedGlyph records that belong to the character,
2647 // starting at the given index.
2648 class DetailedGlyphStore
{
2650 DetailedGlyphStore()
2654 // This is optimized for the most common calling patterns:
2655 // we rarely need random access to the records, access is most commonly
2656 // sequential through the textRun, so we record the last-used index
2657 // and check whether the caller wants the same record again, or the
2658 // next; if not, it's most likely we're starting over from the start
2659 // of the run, so we check the first entry before resorting to binary
2660 // search as a last resort.
2661 // NOTE that this must not be called for a character offset that does
2662 // not have any DetailedGlyph records; callers must have verified that
2663 // mCharacterGlyphs[aOffset].GetGlyphCount() is greater than zero
2664 // before calling this, otherwise the assertions here will fire (in a
2665 // debug build), and we'll probably crash.
2666 DetailedGlyph
* Get(uint32_t aOffset
) {
2667 NS_ASSERTION(mOffsetToIndex
.Length() > 0,
2668 "no detailed glyph records!");
2669 DetailedGlyph
* details
= mDetails
.Elements();
2670 // check common cases (fwd iteration, initial entry, etc) first
2671 if (mLastUsed
< mOffsetToIndex
.Length() - 1 &&
2672 aOffset
== mOffsetToIndex
[mLastUsed
+ 1].mOffset
) {
2674 } else if (aOffset
== mOffsetToIndex
[0].mOffset
) {
2676 } else if (aOffset
== mOffsetToIndex
[mLastUsed
].mOffset
) {
2678 } else if (mLastUsed
> 0 &&
2679 aOffset
== mOffsetToIndex
[mLastUsed
- 1].mOffset
) {
2683 mOffsetToIndex
.BinaryIndexOf(aOffset
, CompareToOffset());
2685 NS_ASSERTION(mLastUsed
!= nsTArray
<DGRec
>::NoIndex
,
2686 "detailed glyph record missing!");
2687 return details
+ mOffsetToIndex
[mLastUsed
].mIndex
;
2690 DetailedGlyph
* Allocate(uint32_t aOffset
, uint32_t aCount
) {
2691 uint32_t detailIndex
= mDetails
.Length();
2692 DetailedGlyph
*details
= mDetails
.AppendElements(aCount
);
2693 // We normally set up glyph records sequentially, so the common case
2694 // here is to append new records to the mOffsetToIndex array;
2695 // test for that before falling back to the InsertElementSorted
2697 if (mOffsetToIndex
.Length() == 0 ||
2698 aOffset
> mOffsetToIndex
[mOffsetToIndex
.Length() - 1].mOffset
) {
2699 mOffsetToIndex
.AppendElement(DGRec(aOffset
, detailIndex
));
2701 mOffsetToIndex
.InsertElementSorted(DGRec(aOffset
, detailIndex
),
2702 CompareRecordOffsets());
2707 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) {
2708 return aMallocSizeOf(this) +
2709 mDetails
.SizeOfExcludingThis(aMallocSizeOf
) +
2710 mOffsetToIndex
.SizeOfExcludingThis(aMallocSizeOf
);
2715 DGRec(const uint32_t& aOffset
, const uint32_t& aIndex
)
2716 : mOffset(aOffset
), mIndex(aIndex
) { }
2717 uint32_t mOffset
; // source character offset in the textrun
2718 uint32_t mIndex
; // index where this char's DetailedGlyphs begin
2721 struct CompareToOffset
{
2722 bool Equals(const DGRec
& a
, const uint32_t& b
) const {
2723 return a
.mOffset
== b
;
2725 bool LessThan(const DGRec
& a
, const uint32_t& b
) const {
2726 return a
.mOffset
< b
;
2730 struct CompareRecordOffsets
{
2731 bool Equals(const DGRec
& a
, const DGRec
& b
) const {
2732 return a
.mOffset
== b
.mOffset
;
2734 bool LessThan(const DGRec
& a
, const DGRec
& b
) const {
2735 return a
.mOffset
< b
.mOffset
;
2739 // Concatenated array of all the DetailedGlyph records needed for the
2740 // textRun; individual character offsets are associated with indexes
2741 // into this array via the mOffsetToIndex table.
2742 nsTArray
<DetailedGlyph
> mDetails
;
2744 // For each character offset that needs DetailedGlyphs, we record the
2745 // index in mDetails where the list of glyphs begins. This array is
2746 // sorted by mOffset.
2747 nsTArray
<DGRec
> mOffsetToIndex
;
2749 // Records the most recently used index into mOffsetToIndex, so that
2750 // we can support sequential access more quickly than just doing
2751 // a binary search each time.
2752 nsTArray
<DGRec
>::index_type mLastUsed
;
2755 nsAutoPtr
<DetailedGlyphStore
> mDetailedGlyphs
;
2757 // Number of char16_t characters and CompressedGlyph glyph records
2760 // Shaping flags (direction, ligature-suppression)
2763 int32_t mAppUnitsPerDevUnit
;
2767 * gfxShapedWord: an individual (space-delimited) run of text shaped with a
2768 * particular font, without regard to external context.
2770 * The glyph data is copied into gfxTextRuns as needed from the cache of
2771 * ShapedWords associated with each gfxFont instance.
2773 class gfxShapedWord
: public gfxShapedText
2776 // Create a ShapedWord that can hold glyphs for aLength characters,
2777 // with mCharacterGlyphs sized appropriately.
2779 // Returns null on allocation failure (does NOT use infallible alloc)
2780 // so caller must check for success.
2782 // This does NOT perform shaping, so the returned word contains no
2783 // glyph data; the caller must call gfxFont::ShapeText() with appropriate
2784 // parameters to set up the glyphs.
2785 static gfxShapedWord
* Create(const uint8_t *aText
, uint32_t aLength
,
2787 int32_t aAppUnitsPerDevUnit
,
2789 NS_ASSERTION(aLength
<= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
2790 "excessive length for gfxShapedWord!");
2792 // Compute size needed including the mCharacterGlyphs array
2793 // and a copy of the original text
2795 offsetof(gfxShapedWord
, mCharGlyphsStorage
) +
2796 aLength
* (sizeof(CompressedGlyph
) + sizeof(uint8_t));
2797 void *storage
= moz_malloc(size
);
2802 // Construct in the pre-allocated storage, using placement new
2803 return new (storage
) gfxShapedWord(aText
, aLength
, aRunScript
,
2804 aAppUnitsPerDevUnit
, aFlags
);
2807 static gfxShapedWord
* Create(const char16_t
*aText
, uint32_t aLength
,
2809 int32_t aAppUnitsPerDevUnit
,
2811 NS_ASSERTION(aLength
<= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
2812 "excessive length for gfxShapedWord!");
2814 // In the 16-bit version of Create, if the TEXT_IS_8BIT flag is set,
2815 // then we convert the text to an 8-bit version and call the 8-bit
2816 // Create function instead.
2817 if (aFlags
& gfxTextRunFactory::TEXT_IS_8BIT
) {
2818 nsAutoCString narrowText
;
2819 LossyAppendUTF16toASCII(nsDependentSubstring(aText
, aLength
),
2821 return Create((const uint8_t*)(narrowText
.BeginReading()),
2822 aLength
, aRunScript
, aAppUnitsPerDevUnit
, aFlags
);
2826 offsetof(gfxShapedWord
, mCharGlyphsStorage
) +
2827 aLength
* (sizeof(CompressedGlyph
) + sizeof(char16_t
));
2828 void *storage
= moz_malloc(size
);
2833 return new (storage
) gfxShapedWord(aText
, aLength
, aRunScript
,
2834 aAppUnitsPerDevUnit
, aFlags
);
2837 // Override operator delete to properly free the object that was
2838 // allocated via moz_malloc.
2839 void operator delete(void* p
) {
2843 CompressedGlyph
*GetCharacterGlyphs() {
2844 return &mCharGlyphsStorage
[0];
2847 const uint8_t* Text8Bit() const {
2848 NS_ASSERTION(TextIs8Bit(), "invalid use of Text8Bit()");
2849 return reinterpret_cast<const uint8_t*>(mCharGlyphsStorage
+ GetLength());
2852 const char16_t
* TextUnicode() const {
2853 NS_ASSERTION(!TextIs8Bit(), "invalid use of TextUnicode()");
2854 return reinterpret_cast<const char16_t
*>(mCharGlyphsStorage
+ GetLength());
2857 char16_t
GetCharAt(uint32_t aOffset
) const {
2858 NS_ASSERTION(aOffset
< GetLength(), "aOffset out of range");
2859 return TextIs8Bit() ?
2860 char16_t(Text8Bit()[aOffset
]) : TextUnicode()[aOffset
];
2863 int32_t Script() const {
2870 uint32_t IncrementAge() {
2871 return ++mAgeCounter
;
2875 // so that gfxTextRun can share our DetailedGlyphStore class
2876 friend class gfxTextRun
;
2878 // Construct storage for a ShapedWord, ready to receive glyph data
2879 gfxShapedWord(const uint8_t *aText
, uint32_t aLength
,
2880 int32_t aRunScript
, int32_t aAppUnitsPerDevUnit
,
2882 : gfxShapedText(aLength
, aFlags
| gfxTextRunFactory::TEXT_IS_8BIT
,
2883 aAppUnitsPerDevUnit
)
2884 , mScript(aRunScript
)
2887 memset(mCharGlyphsStorage
, 0, aLength
* sizeof(CompressedGlyph
));
2888 uint8_t *text
= reinterpret_cast<uint8_t*>(&mCharGlyphsStorage
[aLength
]);
2889 memcpy(text
, aText
, aLength
* sizeof(uint8_t));
2892 gfxShapedWord(const char16_t
*aText
, uint32_t aLength
,
2893 int32_t aRunScript
, int32_t aAppUnitsPerDevUnit
,
2895 : gfxShapedText(aLength
, aFlags
, aAppUnitsPerDevUnit
)
2896 , mScript(aRunScript
)
2899 memset(mCharGlyphsStorage
, 0, aLength
* sizeof(CompressedGlyph
));
2900 char16_t
*text
= reinterpret_cast<char16_t
*>(&mCharGlyphsStorage
[aLength
]);
2901 memcpy(text
, aText
, aLength
* sizeof(char16_t
));
2902 SetupClusterBoundaries(0, aText
, aLength
);
2907 uint32_t mAgeCounter
;
2909 // The mCharGlyphsStorage array is actually a variable-size member;
2910 // when the ShapedWord is created, its size will be increased as necessary
2911 // to allow the proper number of glyphs to be stored.
2912 // The original text, in either 8-bit or 16-bit form, will be stored
2913 // immediately following the CompressedGlyphs.
2914 CompressedGlyph mCharGlyphsStorage
[1];
2918 * Callback for Draw() to use when drawing text with mode
2919 * DrawMode::GLYPH_PATH.
2921 struct gfxTextRunDrawCallbacks
{
2924 * Constructs a new DrawCallbacks object.
2926 * @param aShouldPaintSVGGlyphs If true, SVG glyphs will be
2927 * painted and the NotifyBeforeSVGGlyphPainted/NotifyAfterSVGGlyphPainted
2928 * callbacks will be invoked for each SVG glyph. If false, SVG glyphs
2929 * will not be painted; fallback plain glyphs are not emitted either.
2931 explicit gfxTextRunDrawCallbacks(bool aShouldPaintSVGGlyphs
= false)
2932 : mShouldPaintSVGGlyphs(aShouldPaintSVGGlyphs
)
2937 * Called when a path has been emitted to the gfxContext when
2938 * painting a text run. This can be called any number of times,
2939 * due to partial ligatures and intervening SVG glyphs.
2941 virtual void NotifyGlyphPathEmitted() = 0;
2944 * Called just before an SVG glyph has been painted to the gfxContext.
2946 virtual void NotifyBeforeSVGGlyphPainted() { }
2949 * Called just after an SVG glyph has been painted to the gfxContext.
2951 virtual void NotifyAfterSVGGlyphPainted() { }
2953 bool mShouldPaintSVGGlyphs
;
2957 * gfxTextRun is an abstraction for drawing and measuring substrings of a run
2958 * of text. It stores runs of positioned glyph data, each run having a single
2959 * gfxFont. The glyphs are associated with a string of source text, and the
2960 * gfxTextRun APIs take parameters that are offsets into that source text.
2962 * gfxTextRuns are not refcounted. They should be deleted when no longer required.
2964 * gfxTextRuns are mostly immutable. The only things that can change are
2965 * inter-cluster spacing and line break placement. Spacing is always obtained
2966 * lazily by methods that need it, it is not cached. Line breaks are stored
2967 * persistently (insofar as they affect the shaping of glyphs; gfxTextRun does
2968 * not actually do anything to explicitly account for line breaks). Initially
2969 * there are no line breaks. The textrun can record line breaks before or after
2970 * any given cluster. (Line breaks specified inside clusters are ignored.)
2972 * It is important that zero-length substrings are handled correctly. This will
2975 class gfxTextRun
: public gfxShapedText
{
2978 // Override operator delete to properly free the object that was
2979 // allocated via moz_malloc.
2980 void operator delete(void* p
) {
2984 virtual ~gfxTextRun();
2986 typedef gfxFont::RunMetrics Metrics
;
2988 // Public textrun API for general use
2990 bool IsClusterStart(uint32_t aPos
) {
2991 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
2992 return mCharacterGlyphs
[aPos
].IsClusterStart();
2994 bool IsLigatureGroupStart(uint32_t aPos
) {
2995 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
2996 return mCharacterGlyphs
[aPos
].IsLigatureGroupStart();
2998 bool CanBreakLineBefore(uint32_t aPos
) {
2999 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
3000 return mCharacterGlyphs
[aPos
].CanBreakBefore() ==
3001 CompressedGlyph::FLAG_BREAK_TYPE_NORMAL
;
3003 bool CanHyphenateBefore(uint32_t aPos
) {
3004 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
3005 return mCharacterGlyphs
[aPos
].CanBreakBefore() ==
3006 CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN
;
3009 bool CharIsSpace(uint32_t aPos
) {
3010 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
3011 return mCharacterGlyphs
[aPos
].CharIsSpace();
3013 bool CharIsTab(uint32_t aPos
) {
3014 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
3015 return mCharacterGlyphs
[aPos
].CharIsTab();
3017 bool CharIsNewline(uint32_t aPos
) {
3018 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
3019 return mCharacterGlyphs
[aPos
].CharIsNewline();
3021 bool CharIsLowSurrogate(uint32_t aPos
) {
3022 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
3023 return mCharacterGlyphs
[aPos
].CharIsLowSurrogate();
3026 uint32_t GetLength() { return mLength
; }
3028 // All uint32_t aStart, uint32_t aLength ranges below are restricted to
3029 // grapheme cluster boundaries! All offsets are in terms of the string
3030 // passed into MakeTextRun.
3032 // All coordinates are in layout/app units
3035 * Set the potential linebreaks for a substring of the textrun. These are
3036 * the "allow break before" points. Initially, there are no potential
3039 * This can change glyphs and/or geometry! Some textruns' shapes
3040 * depend on potential line breaks (e.g., title-case-converting textruns).
3041 * This function is virtual so that those textruns can reshape themselves.
3043 * @return true if this changed the linebreaks, false if the new line
3044 * breaks are the same as the old
3046 virtual bool SetPotentialLineBreaks(uint32_t aStart
, uint32_t aLength
,
3047 uint8_t *aBreakBefore
,
3048 gfxContext
*aRefContext
);
3051 * Layout provides PropertyProvider objects. These allow detection of
3052 * potential line break points and computation of spacing. We pass the data
3053 * this way to allow lazy data acquisition; for example BreakAndMeasureText
3054 * will want to only ask for properties of text it's actually looking at.
3056 * NOTE that requested spacing may not actually be applied, if the textrun
3057 * is unable to apply it in some context. Exception: spacing around a
3058 * whitespace character MUST always be applied.
3060 class PropertyProvider
{
3062 // Detect hyphenation break opportunities in the given range; breaks
3063 // not at cluster boundaries will be ignored.
3064 virtual void GetHyphenationBreaks(uint32_t aStart
, uint32_t aLength
,
3065 bool *aBreakBefore
) = 0;
3067 // Returns the provider's hyphenation setting, so callers can decide
3068 // whether it is necessary to call GetHyphenationBreaks.
3069 // Result is an NS_STYLE_HYPHENS_* value.
3070 virtual int8_t GetHyphensOption() = 0;
3072 // Returns the extra width that will be consumed by a hyphen. This should
3073 // be constant for a given textrun.
3074 virtual gfxFloat
GetHyphenWidth() = 0;
3076 typedef gfxFont::Spacing Spacing
;
3079 * Get the spacing around the indicated characters. Spacing must be zero
3080 * inside clusters. In other words, if character i is not
3081 * CLUSTER_START, then character i-1 must have zero after-spacing and
3082 * character i must have zero before-spacing.
3084 virtual void GetSpacing(uint32_t aStart
, uint32_t aLength
,
3085 Spacing
*aSpacing
) = 0;
3087 // Returns a gfxContext that can be used to measure the hyphen glyph.
3088 // Only called if the hyphen width is requested.
3089 virtual already_AddRefed
<gfxContext
> GetContext() = 0;
3091 // Return the appUnitsPerDevUnit value to be used when measuring.
3092 // Only called if the hyphen width is requested.
3093 virtual uint32_t GetAppUnitsPerDevUnit() = 0;
3096 class ClusterIterator
{
3098 explicit ClusterIterator(gfxTextRun
*aTextRun
);
3104 uint32_t Position() const {
3105 return mCurrentChar
;
3108 uint32_t ClusterLength() const;
3110 gfxFloat
ClusterAdvance(PropertyProvider
*aProvider
) const;
3113 gfxTextRun
*mTextRun
;
3114 uint32_t mCurrentChar
;
3118 * Draws a substring. Uses only GetSpacing from aBreakProvider.
3119 * The provided point is the baseline origin on the left of the string
3120 * for LTR, on the right of the string for RTL.
3121 * @param aAdvanceWidth if non-null, the advance width of the substring
3124 * Drawing should respect advance widths in the sense that for LTR runs,
3125 * Draw(ctx, pt, offset1, length1, dirty, &provider, &advance) followed by
3126 * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1 + length1, length2,
3127 * dirty, &provider, nullptr) should have the same effect as
3128 * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr).
3129 * For RTL runs the rule is:
3130 * Draw(ctx, pt, offset1 + length1, length2, dirty, &provider, &advance) followed by
3131 * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1, length1,
3132 * dirty, &provider, nullptr) should have the same effect as
3133 * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr).
3135 * Glyphs should be drawn in logical content order, which can be significant
3136 * if they overlap (perhaps due to negative spacing).
3138 void Draw(gfxContext
*aContext
, gfxPoint aPt
,
3140 uint32_t aStart
, uint32_t aLength
,
3141 PropertyProvider
*aProvider
,
3142 gfxFloat
*aAdvanceWidth
, gfxTextContextPaint
*aContextPaint
,
3143 gfxTextRunDrawCallbacks
*aCallbacks
= nullptr);
3146 * Computes the ReflowMetrics for a substring.
3147 * Uses GetSpacing from aBreakProvider.
3148 * @param aBoundingBoxType which kind of bounding box (loose/tight)
3150 Metrics
MeasureText(uint32_t aStart
, uint32_t aLength
,
3151 gfxFont::BoundingBoxType aBoundingBoxType
,
3152 gfxContext
*aRefContextForTightBoundingBox
,
3153 PropertyProvider
*aProvider
);
3156 * Computes just the advance width for a substring.
3157 * Uses GetSpacing from aBreakProvider.
3159 gfxFloat
GetAdvanceWidth(uint32_t aStart
, uint32_t aLength
,
3160 PropertyProvider
*aProvider
);
3163 * Clear all stored line breaks for the given range (both before and after),
3164 * and then set the line-break state before aStart to aBreakBefore and
3165 * after the last cluster to aBreakAfter.
3167 * We require that before and after line breaks be consistent. For clusters
3168 * i and i+1, we require that if there is a break after cluster i, a break
3169 * will be specified before cluster i+1. This may be temporarily violated
3170 * (e.g. after reflowing line L and before reflowing line L+1); to handle
3171 * these temporary violations, we say that there is a break betwen i and i+1
3172 * if a break is specified after i OR a break is specified before i+1.
3174 * This can change textrun geometry! The existence of a linebreak can affect
3175 * the advance width of the cluster before the break (when kerning) or the
3176 * geometry of one cluster before the break or any number of clusters
3177 * after the break. (The one-cluster-before-the-break limit is somewhat
3178 * arbitrary; if some scripts require breaking it, then we need to
3179 * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase
3180 * it could affect the layout of frames before it...)
3182 * We return true if glyphs or geometry changed, false otherwise. This
3183 * function is virtual so that gfxTextRun subclasses can reshape
3186 * @param aAdvanceWidthDelta if non-null, returns the change in advance
3187 * width of the given range.
3189 virtual bool SetLineBreaks(uint32_t aStart
, uint32_t aLength
,
3190 bool aLineBreakBefore
, bool aLineBreakAfter
,
3191 gfxFloat
*aAdvanceWidthDelta
,
3192 gfxContext
*aRefContext
);
3195 * Finds the longest substring that will fit into the given width.
3196 * Uses GetHyphenationBreaks and GetSpacing from aBreakProvider.
3197 * Guarantees the following:
3198 * -- 0 <= result <= aMaxLength
3199 * -- result is the maximal value of N such that either
3200 * N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
3201 * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
3202 * OR N == aMaxLength && GetAdvanceWidth(aStart, N) <= aWidth
3203 * where GetAdvanceWidth assumes the effect of
3204 * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
3205 * -- if no such N exists, then result is the smallest N such that
3206 * N < aMaxLength && line break at N
3207 * OR N < aMaxLength && hyphen break at N
3208 * OR N == aMaxLength
3210 * The call has the effect of
3211 * SetLineBreaks(aStart, result, aLineBreakBefore, result < aMaxLength, aProvider)
3212 * and the returned metrics and the invariants above reflect this.
3214 * @param aMaxLength this can be UINT32_MAX, in which case the length used
3215 * is up to the end of the string
3216 * @param aLineBreakBefore set to true if and only if there is an actual
3217 * line break at the start of this string.
3218 * @param aSuppressInitialBreak if true, then we assume there is no possible
3219 * linebreak before aStart. If false, then we will check the internal
3220 * line break opportunity state before deciding whether to return 0 as the
3221 * character to break before.
3222 * @param aTrimWhitespace if non-null, then we allow a trailing run of
3223 * spaces to be trimmed; the width of the space(s) will not be included in
3224 * the measured string width for comparison with the limit aWidth, and
3225 * trimmed spaces will not be included in returned metrics. The width
3226 * of the trimmed spaces will be returned in aTrimWhitespace.
3227 * Trimmed spaces are still counted in the "characters fit" result.
3228 * @param aMetrics if non-null, we fill this in for the returned substring.
3229 * If a hyphenation break was used, the hyphen is NOT included in the returned metrics.
3230 * @param aBoundingBoxType whether to make the bounding box in aMetrics tight
3231 * @param aRefContextForTightBoundingBox a reference context to get the
3232 * tight bounding box, if requested
3233 * @param aUsedHyphenation if non-null, records if we selected a hyphenation break
3234 * @param aLastBreak if non-null and result is aMaxLength, we set this to
3235 * the maximal N such that
3236 * N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
3237 * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
3238 * or UINT32_MAX if no such N exists, where GetAdvanceWidth assumes
3240 * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
3242 * @param aCanWordWrap true if we can break between any two grapheme
3243 * clusters. This is set by word-wrap: break-word
3245 * @param aBreakPriority in/out the priority of the break opportunity
3246 * saved in the line. If we are prioritizing break opportunities, we will
3247 * not set a break with a lower priority. @see gfxBreakPriority.
3249 * Note that negative advance widths are possible especially if negative
3250 * spacing is provided.
3252 uint32_t BreakAndMeasureText(uint32_t aStart
, uint32_t aMaxLength
,
3253 bool aLineBreakBefore
, gfxFloat aWidth
,
3254 PropertyProvider
*aProvider
,
3255 bool aSuppressInitialBreak
,
3256 gfxFloat
*aTrimWhitespace
,
3258 gfxFont::BoundingBoxType aBoundingBoxType
,
3259 gfxContext
*aRefContextForTightBoundingBox
,
3260 bool *aUsedHyphenation
,
3261 uint32_t *aLastBreak
,
3263 gfxBreakPriority
*aBreakPriority
);
3266 * Update the reference context.
3267 * XXX this is a hack. New text frame does not call this. Use only
3268 * temporarily for old text frame.
3270 void SetContext(gfxContext
*aContext
) {}
3274 gfxFloat
GetDirection() const { return (mFlags
& gfxTextRunFactory::TEXT_IS_RTL
) ? -1.0 : 1.0; }
3275 void *GetUserData() const { return mUserData
; }
3276 void SetUserData(void *aUserData
) { mUserData
= aUserData
; }
3277 uint32_t GetFlags() const { return mFlags
; }
3278 void SetFlagBits(uint32_t aFlags
) {
3279 NS_ASSERTION(!(aFlags
& ~gfxTextRunFactory::SETTABLE_FLAGS
),
3280 "Only user flags should be mutable");
3283 void ClearFlagBits(uint32_t aFlags
) {
3284 NS_ASSERTION(!(aFlags
& ~gfxTextRunFactory::SETTABLE_FLAGS
),
3285 "Only user flags should be mutable");
3288 const gfxSkipChars
& GetSkipChars() const { return mSkipChars
; }
3289 gfxFontGroup
*GetFontGroup() const { return mFontGroup
; }
3292 // Call this, don't call "new gfxTextRun" directly. This does custom
3293 // allocation and initialization
3294 static gfxTextRun
*Create(const gfxTextRunFactory::Parameters
*aParams
,
3295 uint32_t aLength
, gfxFontGroup
*aFontGroup
,
3298 // The text is divided into GlyphRuns as necessary
3300 nsRefPtr
<gfxFont
> mFont
; // never null
3301 uint32_t mCharacterOffset
; // into original UTF16 string
3305 class GlyphRunIterator
{
3307 GlyphRunIterator(gfxTextRun
*aTextRun
, uint32_t aStart
, uint32_t aLength
)
3308 : mTextRun(aTextRun
), mStartOffset(aStart
), mEndOffset(aStart
+ aLength
) {
3309 mNextIndex
= mTextRun
->FindFirstGlyphRunContaining(aStart
);
3312 GlyphRun
*GetGlyphRun() { return mGlyphRun
; }
3313 uint32_t GetStringStart() { return mStringStart
; }
3314 uint32_t GetStringEnd() { return mStringEnd
; }
3316 gfxTextRun
*mTextRun
;
3317 GlyphRun
*mGlyphRun
;
3318 uint32_t mStringStart
;
3319 uint32_t mStringEnd
;
3320 uint32_t mNextIndex
;
3321 uint32_t mStartOffset
;
3322 uint32_t mEndOffset
;
3325 class GlyphRunOffsetComparator
{
3327 bool Equals(const GlyphRun
& a
,
3328 const GlyphRun
& b
) const
3330 return a
.mCharacterOffset
== b
.mCharacterOffset
;
3333 bool LessThan(const GlyphRun
& a
,
3334 const GlyphRun
& b
) const
3336 return a
.mCharacterOffset
< b
.mCharacterOffset
;
3340 friend class GlyphRunIterator
;
3341 friend class FontSelector
;
3343 // API for setting up the textrun glyphs. Should only be called by
3344 // things that construct textruns.
3346 * We've found a run of text that should use a particular font. Call this
3347 * only during initialization when font substitution has been computed.
3348 * Call it before setting up the glyphs for the characters in this run;
3349 * SetMissingGlyph requires that the correct glyphrun be installed.
3351 * If aForceNewRun, a new glyph run will be added, even if the
3352 * previously added run uses the same font. If glyph runs are
3353 * added out of strictly increasing aStartCharIndex order (via
3354 * force), then SortGlyphRuns must be called after all glyph runs
3355 * are added before any further operations are performed with this
3358 nsresult
AddGlyphRun(gfxFont
*aFont
, uint8_t aMatchType
,
3359 uint32_t aStartCharIndex
, bool aForceNewRun
);
3360 void ResetGlyphRuns() { mGlyphRuns
.Clear(); }
3361 void SortGlyphRuns();
3362 void SanitizeGlyphRuns();
3364 CompressedGlyph
* GetCharacterGlyphs() {
3365 NS_ASSERTION(mCharacterGlyphs
, "failed to initialize mCharacterGlyphs");
3366 return mCharacterGlyphs
;
3369 // clean out results from shaping in progress, used for fallback scenarios
3370 void ClearGlyphsAndCharacters();
3372 void SetSpaceGlyph(gfxFont
*aFont
, gfxContext
*aContext
, uint32_t aCharIndex
);
3374 // Set the glyph data for the given character index to the font's
3375 // space glyph, IF this can be done as a "simple" glyph record
3376 // (not requiring a DetailedGlyph entry). This avoids the need to call
3377 // the font shaper and go through the shaped-word cache for most spaces.
3379 // The parameter aSpaceChar is the original character code for which
3380 // this space glyph is being used; if this is U+0020, we need to record
3381 // that it could be trimmed at a run edge, whereas other kinds of space
3382 // (currently just U+00A0) would not be trimmable/breakable.
3384 // Returns true if it was able to set simple glyph data for the space;
3385 // if it returns false, the caller needs to fall back to some other
3386 // means to create the necessary (detailed) glyph data.
3387 bool SetSpaceGlyphIfSimple(gfxFont
*aFont
, gfxContext
*aContext
,
3388 uint32_t aCharIndex
, char16_t aSpaceChar
);
3390 // Record the positions of specific characters that layout may need to
3391 // detect in the textrun, even though it doesn't have an explicit copy
3392 // of the original text. These are recorded using flag bits in the
3393 // CompressedGlyph record; if necessary, we convert "simple" glyph records
3394 // to "complex" ones as the Tab and Newline flags are not present in
3395 // simple CompressedGlyph records.
3396 void SetIsTab(uint32_t aIndex
) {
3397 CompressedGlyph
*g
= &mCharacterGlyphs
[aIndex
];
3398 if (g
->IsSimpleGlyph()) {
3399 DetailedGlyph
*details
= AllocateDetailedGlyphs(aIndex
, 1);
3400 details
->mGlyphID
= g
->GetSimpleGlyph();
3401 details
->mAdvance
= g
->GetSimpleAdvance();
3402 details
->mXOffset
= details
->mYOffset
= 0;
3403 SetGlyphs(aIndex
, CompressedGlyph().SetComplex(true, true, 1), details
);
3407 void SetIsNewline(uint32_t aIndex
) {
3408 CompressedGlyph
*g
= &mCharacterGlyphs
[aIndex
];
3409 if (g
->IsSimpleGlyph()) {
3410 DetailedGlyph
*details
= AllocateDetailedGlyphs(aIndex
, 1);
3411 details
->mGlyphID
= g
->GetSimpleGlyph();
3412 details
->mAdvance
= g
->GetSimpleAdvance();
3413 details
->mXOffset
= details
->mYOffset
= 0;
3414 SetGlyphs(aIndex
, CompressedGlyph().SetComplex(true, true, 1), details
);
3418 void SetIsLowSurrogate(uint32_t aIndex
) {
3419 SetGlyphs(aIndex
, CompressedGlyph().SetComplex(false, false, 0), nullptr);
3420 mCharacterGlyphs
[aIndex
].SetIsLowSurrogate();
3424 * Prefetch all the glyph extents needed to ensure that Measure calls
3425 * on this textrun not requesting tight boundingBoxes will succeed. Note
3426 * that some glyph extents might not be fetched due to OOM or other
3429 void FetchGlyphExtents(gfxContext
*aRefContext
);
3431 uint32_t CountMissingGlyphs();
3432 const GlyphRun
*GetGlyphRuns(uint32_t *aNumGlyphRuns
) {
3433 *aNumGlyphRuns
= mGlyphRuns
.Length();
3434 return mGlyphRuns
.Elements();
3436 // Returns the index of the GlyphRun containing the given offset.
3437 // Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
3438 uint32_t FindFirstGlyphRunContaining(uint32_t aOffset
);
3440 // Copy glyph data from a ShapedWord into this textrun.
3441 void CopyGlyphDataFrom(gfxShapedWord
*aSource
, uint32_t aStart
);
3443 // Copy glyph data for a range of characters from aSource to this
3445 void CopyGlyphDataFrom(gfxTextRun
*aSource
, uint32_t aStart
,
3446 uint32_t aLength
, uint32_t aDest
);
3448 nsExpirationState
*GetExpirationState() { return &mExpirationState
; }
3450 // Tell the textrun to release its reference to its creating gfxFontGroup
3451 // immediately, rather than on destruction. This is used for textruns
3452 // that are actually owned by a gfxFontGroup, so that they don't keep it
3453 // permanently alive due to a circular reference. (The caller of this is
3454 // taking responsibility for ensuring the textrun will not outlive its
3456 void ReleaseFontGroup();
3458 struct LigatureData
{
3459 // textrun offsets of the start and end of the containing ligature
3460 uint32_t mLigatureStart
;
3461 uint32_t mLigatureEnd
;
3462 // appunits advance to the start of the ligature part within the ligature;
3463 // never includes any spacing
3464 gfxFloat mPartAdvance
;
3465 // appunits width of the ligature part; includes before-spacing
3466 // when the part is at the start of the ligature, and after-spacing
3467 // when the part is as the end of the ligature
3468 gfxFloat mPartWidth
;
3470 bool mClipBeforePart
;
3471 bool mClipAfterPart
;
3474 // return storage used by this run, for memory reporter;
3475 // nsTransformedTextRun needs to override this as it holds additional data
3476 virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
)
3478 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
)
3481 // Get the size, if it hasn't already been gotten, marking as it goes.
3482 size_t MaybeSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) {
3483 if (mFlags
& gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED
) {
3486 mFlags
|= gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED
;
3487 return SizeOfIncludingThis(aMallocSizeOf
);
3489 void ResetSizeOfAccountingFlags() {
3490 mFlags
&= ~gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED
;
3493 // shaping state - for some font features, fallback is required that
3494 // affects the entire run. for example, fallback for one script/font
3495 // portion of a textrun requires fallback to be applied to the entire run
3498 eShapingState_Normal
, // default state
3499 eShapingState_ShapingWithFeature
, // have shaped with feature
3500 eShapingState_ShapingWithFallback
, // have shaped with fallback
3501 eShapingState_Aborted
, // abort initial iteration
3502 eShapingState_ForceFallbackFeature
// redo with fallback forced on
3505 ShapingState
GetShapingState() const { return mShapingState
; }
3506 void SetShapingState(ShapingState aShapingState
) {
3507 mShapingState
= aShapingState
;
3511 void Dump(FILE* aOutput
);
3516 * Create a textrun, and set its mCharacterGlyphs to point immediately
3517 * after the base object; this is ONLY used in conjunction with placement
3518 * new, after allocating a block large enough for the glyph records to
3519 * follow the base textrun object.
3521 gfxTextRun(const gfxTextRunFactory::Parameters
*aParams
,
3522 uint32_t aLength
, gfxFontGroup
*aFontGroup
, uint32_t aFlags
);
3525 * Helper for the Create() factory method to allocate the required
3526 * glyph storage for a textrun object with the basic size aSize,
3527 * plus room for aLength glyph records.
3529 static void* AllocateStorageForTextRun(size_t aSize
, uint32_t aLength
);
3531 // Pointer to the array of CompressedGlyph records; must be initialized
3532 // when the object is constructed.
3533 CompressedGlyph
*mCharacterGlyphs
;
3536 // **** general helpers ****
3538 // Get the total advance for a range of glyphs.
3539 int32_t GetAdvanceForGlyphs(uint32_t aStart
, uint32_t aEnd
);
3541 // Spacing for characters outside the range aSpacingStart/aSpacingEnd
3542 // is assumed to be zero; such characters are not passed to aProvider.
3543 // This is useful to protect aProvider from being passed character indices
3544 // it is not currently able to handle.
3545 bool GetAdjustedSpacingArray(uint32_t aStart
, uint32_t aEnd
,
3546 PropertyProvider
*aProvider
,
3547 uint32_t aSpacingStart
, uint32_t aSpacingEnd
,
3548 nsTArray
<PropertyProvider::Spacing
> *aSpacing
);
3550 // **** ligature helpers ****
3551 // (Platforms do the actual ligaturization, but we need to do a bunch of stuff
3552 // to handle requests that begin or end inside a ligature)
3554 // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
3555 LigatureData
ComputeLigatureData(uint32_t aPartStart
, uint32_t aPartEnd
,
3556 PropertyProvider
*aProvider
);
3557 gfxFloat
ComputePartialLigatureWidth(uint32_t aPartStart
, uint32_t aPartEnd
,
3558 PropertyProvider
*aProvider
);
3559 void DrawPartialLigature(gfxFont
*aFont
, uint32_t aStart
, uint32_t aEnd
,
3560 gfxPoint
*aPt
, PropertyProvider
*aProvider
,
3561 TextRunDrawParams
& aParams
);
3562 // Advance aStart to the start of the nearest ligature; back up aEnd
3563 // to the nearest ligature end; may result in *aStart == *aEnd
3564 void ShrinkToLigatureBoundaries(uint32_t *aStart
, uint32_t *aEnd
);
3565 // result in appunits
3566 gfxFloat
GetPartialLigatureWidth(uint32_t aStart
, uint32_t aEnd
, PropertyProvider
*aProvider
);
3567 void AccumulatePartialLigatureMetrics(gfxFont
*aFont
,
3568 uint32_t aStart
, uint32_t aEnd
,
3569 gfxFont::BoundingBoxType aBoundingBoxType
,
3570 gfxContext
*aRefContext
,
3571 PropertyProvider
*aProvider
,
3574 // **** measurement helper ****
3575 void AccumulateMetricsForRun(gfxFont
*aFont
, uint32_t aStart
, uint32_t aEnd
,
3576 gfxFont::BoundingBoxType aBoundingBoxType
,
3577 gfxContext
*aRefContext
,
3578 PropertyProvider
*aProvider
,
3579 uint32_t aSpacingStart
, uint32_t aSpacingEnd
,
3582 // **** drawing helper ****
3583 void DrawGlyphs(gfxFont
*aFont
, uint32_t aStart
, uint32_t aEnd
,
3584 gfxPoint
*aPt
, PropertyProvider
*aProvider
,
3585 uint32_t aSpacingStart
, uint32_t aSpacingEnd
,
3586 TextRunDrawParams
& aParams
);
3588 // XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
3589 // for smaller size especially in the super-common one-glyphrun case
3590 nsAutoTArray
<GlyphRun
,1> mGlyphRuns
;
3593 gfxFontGroup
*mFontGroup
; // addrefed on creation, but our reference
3594 // may be released by ReleaseFontGroup()
3595 gfxSkipChars mSkipChars
;
3596 nsExpirationState mExpirationState
;
3598 bool mSkipDrawing
; // true if the font group we used had a user font
3599 // download that's in progress, so we should hide text
3600 // until the download completes (or timeout fires)
3601 bool mReleasedFontGroup
; // we already called NS_RELEASE on
3602 // mFontGroup, so don't do it again
3604 // shaping state for handling variant fallback features
3605 // such as subscript/superscript variant glyphs
3606 ShapingState mShapingState
;
3609 class gfxFontGroup
: public gfxTextRunFactory
{
3615 FamilyFace(gfxFontFamily
* aFamily
, gfxFont
* aFont
)
3616 : mFamily(aFamily
), mFont(aFont
)
3618 NS_ASSERTION(aFont
, "font pointer must not be null");
3619 NS_ASSERTION(!aFamily
||
3620 aFamily
->ContainsFace(aFont
->GetFontEntry()),
3621 "font is not a member of the given family");
3624 gfxFontFamily
* Family() const { return mFamily
.get(); }
3625 gfxFont
* Font() const { return mFont
.get(); }
3628 nsRefPtr
<gfxFontFamily
> mFamily
;
3629 nsRefPtr
<gfxFont
> mFont
;
3632 static void Shutdown(); // platform must call this to release the languageAtomService
3634 gfxFontGroup(const mozilla::FontFamilyList
& aFontFamilyList
,
3635 const gfxFontStyle
*aStyle
,
3636 gfxUserFontSet
*aUserFontSet
= nullptr);
3638 virtual ~gfxFontGroup();
3640 virtual gfxFont
*GetFontAt(int32_t i
) {
3641 // If it turns out to be hard for all clients that cache font
3642 // groups to call UpdateFontList at appropriate times, we could
3643 // instead consider just calling UpdateFontList from someplace
3644 // more central (such as here).
3645 NS_ASSERTION(!mUserFontSet
|| mCurrGeneration
== GetGeneration(),
3646 "Whoever was caching this font group should have "
3647 "called UpdateFontList on it");
3648 NS_ASSERTION(mFonts
.Length() > uint32_t(i
) && mFonts
[i
].Font(),
3649 "Requesting a font index that doesn't exist");
3651 return mFonts
[i
].Font();
3654 // Returns the first font in the font-group that has an OpenType MATH table,
3655 // or null if no such font is available. The GetMathConstant methods may be
3656 // called on the returned font.
3657 gfxFont
*GetFirstMathFont();
3659 uint32_t FontListLength() const {
3660 return mFonts
.Length();
3663 const gfxFontStyle
*GetStyle() const { return &mStyle
; }
3665 virtual gfxFontGroup
*Copy(const gfxFontStyle
*aStyle
);
3668 * The listed characters should be treated as invisible and zero-width
3669 * when creating textruns.
3671 static bool IsInvalidChar(uint8_t ch
);
3672 static bool IsInvalidChar(char16_t ch
);
3675 * Make a textrun for a given string.
3676 * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
3677 * textrun will copy it.
3678 * This calls FetchGlyphExtents on the textrun.
3680 virtual gfxTextRun
*MakeTextRun(const char16_t
*aString
, uint32_t aLength
,
3681 const Parameters
*aParams
, uint32_t aFlags
);
3683 * Make a textrun for a given string.
3684 * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
3685 * textrun will copy it.
3686 * This calls FetchGlyphExtents on the textrun.
3688 virtual gfxTextRun
*MakeTextRun(const uint8_t *aString
, uint32_t aLength
,
3689 const Parameters
*aParams
, uint32_t aFlags
);
3692 * Textrun creation helper for clients that don't want to pass
3693 * a full Parameters record.
3695 template<typename T
>
3696 gfxTextRun
*MakeTextRun(const T
*aString
, uint32_t aLength
,
3697 gfxContext
*aRefContext
,
3698 int32_t aAppUnitsPerDevUnit
,
3701 gfxTextRunFactory::Parameters params
= {
3702 aRefContext
, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit
3704 return MakeTextRun(aString
, aLength
, ¶ms
, aFlags
);
3708 * Get the (possibly-cached) width of the hyphen character.
3709 * The aCtx and aAppUnitsPerDevUnit parameters will be used only if
3710 * needed to initialize the cached hyphen width; otherwise they are
3713 gfxFloat
GetHyphenWidth(gfxTextRun::PropertyProvider
* aProvider
);
3716 * Make a text run representing a single hyphen character.
3717 * This will use U+2010 HYPHEN if available in the first font,
3718 * otherwise fall back to U+002D HYPHEN-MINUS.
3719 * The caller is responsible for deleting the returned text run
3720 * when no longer required.
3722 gfxTextRun
*MakeHyphenTextRun(gfxContext
*aCtx
,
3723 uint32_t aAppUnitsPerDevUnit
);
3726 * Check whether a given font (specified by its gfxFontEntry)
3727 * is already in the fontgroup's list of actual fonts
3729 bool HasFont(const gfxFontEntry
*aFontEntry
);
3731 // This returns the preferred underline for this font group.
3732 // Some CJK fonts have wrong underline offset in its metrics.
3733 // If this group has such "bad" font, each platform's gfxFontGroup initialized mUnderlineOffset.
3734 // The value should be lower value of first font's metrics and the bad font's metrics.
3735 // Otherwise, this returns from first font's metrics.
3736 enum { UNDERLINE_OFFSET_NOT_SET
= INT16_MAX
};
3737 virtual gfxFloat
GetUnderlineOffset() {
3738 if (mUnderlineOffset
== UNDERLINE_OFFSET_NOT_SET
)
3739 mUnderlineOffset
= GetFontAt(0)->GetMetrics().underlineOffset
;
3740 return mUnderlineOffset
;
3743 virtual already_AddRefed
<gfxFont
>
3744 FindFontForChar(uint32_t ch
, uint32_t prevCh
, int32_t aRunScript
,
3745 gfxFont
*aPrevMatchedFont
,
3746 uint8_t *aMatchType
);
3748 // search through pref fonts for a character, return nullptr if no matching pref font
3749 virtual already_AddRefed
<gfxFont
> WhichPrefFontSupportsChar(uint32_t aCh
);
3751 virtual already_AddRefed
<gfxFont
>
3752 WhichSystemFontSupportsChar(uint32_t aCh
, int32_t aRunScript
);
3754 template<typename T
>
3755 void ComputeRanges(nsTArray
<gfxTextRange
>& mRanges
,
3756 const T
*aString
, uint32_t aLength
,
3757 int32_t aRunScript
);
3759 gfxUserFontSet
* GetUserFontSet();
3761 // With downloadable fonts, the composition of the font group can change as fonts are downloaded
3762 // for each change in state of the user font set, the generation value is bumped to avoid picking up
3763 // previously created text runs in the text run word cache. For font groups based on stylesheets
3764 // with no @font-face rule, this always returns 0.
3765 uint64_t GetGeneration();
3767 // used when logging text performance
3768 gfxTextPerfMetrics
*GetTextPerfMetrics() { return mTextPerf
; }
3769 void SetTextPerfMetrics(gfxTextPerfMetrics
*aTextPerf
) { mTextPerf
= aTextPerf
; }
3771 // This will call UpdateFontList() if the user font set is changed.
3772 void SetUserFontSet(gfxUserFontSet
*aUserFontSet
);
3774 // If there is a user font set, check to see whether the font list or any
3775 // caches need updating.
3776 virtual void UpdateFontList();
3778 bool ShouldSkipDrawing() const {
3779 return mSkipDrawing
;
3782 class LazyReferenceContextGetter
{
3784 virtual already_AddRefed
<gfxContext
> GetRefContext() = 0;
3786 // The gfxFontGroup keeps ownership of this textrun.
3787 // It is only guaranteed to exist until the next call to GetEllipsisTextRun
3788 // (which might use a different appUnitsPerDev value) for the font group,
3789 // or until UpdateFontList is called, or the fontgroup is destroyed.
3790 // Get it/use it/forget it :) - don't keep a reference that might go stale.
3791 gfxTextRun
* GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel
,
3792 LazyReferenceContextGetter
& aRefContextGetter
);
3794 // helper method for resolving generic font families
3796 ResolveGenericFontNames(mozilla::FontFamilyType aGenericType
,
3798 nsTArray
<nsString
>& aGenericFamilies
);
3801 mozilla::FontFamilyList mFamilyList
;
3802 gfxFontStyle mStyle
;
3803 nsTArray
<FamilyFace
> mFonts
;
3804 gfxFloat mUnderlineOffset
;
3805 gfxFloat mHyphenWidth
;
3807 nsRefPtr
<gfxUserFontSet
> mUserFontSet
;
3808 uint64_t mCurrGeneration
; // track the current user font set generation, rebuild font list if needed
3810 gfxTextPerfMetrics
*mTextPerf
;
3812 // Cache a textrun representing an ellipsis (useful for CSS text-overflow)
3813 // at a specific appUnitsPerDevPixel size
3814 nsAutoPtr
<gfxTextRun
> mCachedEllipsisTextRun
;
3816 // cache the most recent pref font to avoid general pref font lookup
3817 nsRefPtr
<gfxFontFamily
> mLastPrefFamily
;
3818 nsRefPtr
<gfxFont
> mLastPrefFont
;
3819 eFontPrefLang mLastPrefLang
; // lang group for last pref font
3820 eFontPrefLang mPageLang
;
3821 bool mLastPrefFirstFont
; // is this the first font in the list of pref fonts for this lang group?
3823 bool mSkipDrawing
; // hide text while waiting for a font
3824 // download to complete (or fallback
3828 * Textrun creation short-cuts for special cases where we don't need to
3829 * call a font shaper to generate glyphs.
3831 gfxTextRun
*MakeEmptyTextRun(const Parameters
*aParams
, uint32_t aFlags
);
3832 gfxTextRun
*MakeSpaceTextRun(const Parameters
*aParams
, uint32_t aFlags
);
3833 gfxTextRun
*MakeBlankTextRun(uint32_t aLength
,
3834 const Parameters
*aParams
, uint32_t aFlags
);
3836 // Initialize the list of fonts
3837 void BuildFontList();
3839 // Init this font group's font metrics. If there no bad fonts, you don't need to call this.
3840 // But if there are one or more bad fonts which have bad underline offset,
3841 // you should call this with the *first* bad font.
3842 void InitMetricsForBadFont(gfxFont
* aBadFont
);
3844 // Set up the textrun glyphs for an entire text run:
3845 // find script runs, and then call InitScriptRun for each
3846 template<typename T
>
3847 void InitTextRun(gfxContext
*aContext
,
3848 gfxTextRun
*aTextRun
,
3852 // InitTextRun helper to handle a single script run, by finding font ranges
3853 // and calling each font's InitTextRun() as appropriate
3854 template<typename T
>
3855 void InitScriptRun(gfxContext
*aContext
,
3856 gfxTextRun
*aTextRun
,
3858 uint32_t aScriptRunStart
,
3859 uint32_t aScriptRunEnd
,
3860 int32_t aRunScript
);
3862 // Helper for font-matching:
3863 // see if aCh is supported in any of the faces from aFamily;
3864 // if so return the best style match, else return null.
3865 already_AddRefed
<gfxFont
> TryAllFamilyMembers(gfxFontFamily
* aFamily
,
3868 // helper methods for looking up fonts
3870 // iterate over the fontlist, lookup names and expand generics
3871 void EnumerateFontList(nsIAtom
*aLanguage
, void *aClosure
= nullptr);
3873 // expand a generic to a list of specific names based on prefs
3874 void FindGenericFonts(mozilla::FontFamilyType aGenericType
,
3878 // lookup and add a font with a given name (i.e. *not* a generic!)
3879 virtual void FindPlatformFont(const nsAString
& aName
,
3883 static nsILanguageAtomService
* gLangService
;