Bumping manifests a=b2g-bump
[gecko.git] / gfx / thebes / gfxFont.h
blobf8e1f585b247209a6ca641292f44d9ed0e6b7754
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef GFX_FONT_H
7 #define GFX_FONT_H
9 #include "gfxTypes.h"
10 #include "nsString.h"
11 #include "gfxPoint.h"
12 #include "gfxFontFamilyList.h"
13 #include "gfxFontUtils.h"
14 #include "nsTArray.h"
15 #include "nsTHashtable.h"
16 #include "nsHashKeys.h"
17 #include "gfxSkipChars.h"
18 #include "gfxRect.h"
19 #include "nsExpirationTracker.h"
20 #include "gfxPlatform.h"
21 #include "nsIAtom.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"
28 #include <algorithm>
29 #include "DrawMode.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;
38 #ifdef DEBUG
39 #include <stdio.h>
40 #endif
42 class gfxContext;
43 class gfxTextRun;
44 class gfxFont;
45 class gfxFontFamily;
46 class gfxFontGroup;
47 class gfxGraphiteShaper;
48 class gfxHarfBuzzShaper;
49 class gfxUserFontSet;
50 class gfxUserFontData;
51 class gfxShapedText;
52 class gfxShapedWord;
53 class gfxSVGGlyphs;
54 class gfxMathTable;
55 class gfxTextContextPaint;
56 class FontInfoData;
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
66 struct FontListSizes;
67 struct gfxTextRunDrawCallbacks;
69 namespace mozilla {
70 namespace gfx {
71 class GlyphRenderingOptions;
75 struct gfxFontStyle {
76 gfxFontStyle();
77 gfxFontStyle(uint8_t aStyle, uint16_t aWeight, int16_t aStretch,
78 gfxFloat aSize, nsIAtom *aLanguage,
79 float aSizeAdjust, bool aSystemFont,
80 bool aPrinterFont,
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
108 gfxFloat size;
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
113 // needs to be done.
114 float sizeAdjust;
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.
132 uint16_t weight;
134 // The stretch of the font (the sum of various NS_FONT_STRETCH_*
135 // constants; see gfxFontConstants.h).
136 int8_t stretch;
138 // Say that this font is a system font and therefore does not
139 // require certain fixup that we do for fonts from untrusted
140 // sources.
141 bool systemFont : 1;
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)
150 uint8_t style : 2;
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.)
161 uint8_t variantCaps;
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 {
187 return
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 {
217 public:
218 nsrefcnt AddRef() {
219 NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt");
220 ++mRefCnt;
221 NS_LOG_ADDREF(this, mRefCnt, "gfxCharacterMap", sizeof(*this));
222 return mRefCnt;
225 nsrefcnt Release() {
226 NS_PRECONDITION(0 != mRefCnt, "dup release");
227 --mRefCnt;
228 NS_LOG_RELEASE(this, mRefCnt, "gfxCharacterMap");
229 if (mRefCnt == 0) {
230 NotifyReleased();
231 // |this| has been deleted.
232 return 0;
234 return mRefCnt;
237 gfxCharacterMap() :
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
248 uint32_t mHash;
250 // if cmap is built on the fly it's never shared
251 bool mBuildOnTheFly;
253 // cmap is shared globally
254 bool mShared;
256 protected:
257 void NotifyReleased();
259 nsAutoRefCnt mRefCnt;
261 private:
262 gfxCharacterMap(const gfxCharacterMap&);
263 gfxCharacterMap& operator=(const gfxCharacterMap&);
266 class gfxFontEntry {
267 public:
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; }
276 // family name
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
305 const hb_set_t*
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) {
322 ReadCMAP();
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)) {
330 return true;
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,
351 gfxRect *aResult);
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();
358 enum MathConstant {
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,
365 MathLeading,
366 AxisHeight,
367 AccentBaseHeight,
368 FlattenedAccentBaseHeight,
369 SubscriptShiftDown,
370 SubscriptTopMax,
371 SubscriptBaselineDropMin,
372 SuperscriptShiftUp,
373 SuperscriptShiftUpCramped,
374 SuperscriptBottomMin,
375 SuperscriptBaselineDropMax,
376 SubSuperscriptGapMin,
377 SuperscriptBottomMaxWithSubscript,
378 SpaceAfterScript,
379 UpperLimitGapMin,
380 UpperLimitBaselineRiseMin,
381 LowerLimitGapMin,
382 LowerLimitBaselineDropMin,
383 StackTopShiftUp,
384 StackTopDisplayStyleShiftUp,
385 StackBottomShiftDown,
386 StackBottomDisplayStyleShiftDown,
387 StackGapMin,
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,
404 OverbarVerticalGap,
405 OverbarRuleThickness,
406 OverbarExtraAscender,
407 UnderbarVerticalGap,
408 UnderbarRuleThickness,
409 UnderbarExtraDescender,
410 RadicalVerticalGap,
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,
427 uint16_t aSize);
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 {
437 return true;
439 virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const {
440 return true;
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.
465 class AutoTable {
466 public:
467 AutoTable(gfxFontEntry* aFontEntry, uint32_t aTag)
469 mBlob = aFontEntry->GetFontTable(aTag);
471 ~AutoTable() {
472 if (mBlob) {
473 hb_blob_destroy(mBlob);
476 operator hb_blob_t*() const { return mBlob; }
477 private:
478 hb_blob_t* mBlob;
479 // not implemented:
480 AutoTable(const AutoTable&) MOZ_DELETE;
481 AutoTable& operator=(const AutoTable&) MOZ_DELETE;
484 already_AddRefed<gfxFont> FindOrMakeFont(const gfxFontStyle *aStyle,
485 bool aNeedsBold);
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();
509 enum {
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
544 struct ScriptRange {
545 uint32_t rangeStart;
546 uint32_t rangeEnd;
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);
553 nsString mName;
554 nsString mFamilyName;
556 bool mItalic : 1;
557 bool mFixedPitch : 1;
558 bool mIsProxy : 1;
559 bool mIsValid : 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];
585 uint16_t mWeight;
586 int16_t mStretch;
588 nsRefPtr<gfxCharacterMap> mCharacterMap;
589 uint32_t mUVSOffset;
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
602 hb_blob_t* mCOLR;
603 hb_blob_t* mCPAL;
605 protected:
606 friend class gfxPlatformFontList;
607 friend class gfxMacPlatformFontList;
608 friend class gfxUserFcFontEntry;
609 friend class gfxFontFamily;
610 friend class gfxSingleFaceMacFontFamily;
612 gfxFontEntry();
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");
619 return nullptr;
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,
644 bool& aSymbolFont);
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.
660 hb_face_t* mHBFace;
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.
671 gr_face* mGrFace;
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,
681 unsigned int aName,
682 size_t *aLen);
683 static void GrReleaseTable(const void *aAppFaceHandle,
684 const void *aTableBuffer);
686 private:
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
694 * every time.
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
704 * harfbuzz.
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
715 * table data.
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
726 public:
727 // Declarations for nsTHashtable
729 typedef nsUint32HashKey KeyClass;
730 typedef KeyClass::KeyType KeyType;
731 typedef KeyClass::KeyTypePointer KeyTypePointer;
733 explicit FontTableHashEntry(KeyTypePointer aTag)
734 : KeyClass(aTag)
735 , mSharedBlobData(nullptr)
736 , mBlob(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
758 // table.
759 hb_blob_t *
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;
767 void Clear();
769 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
771 private:
772 static void DeleteFontTableBlobData(void *aBlobData);
773 // not implemented
774 FontTableHashEntry& operator=(FontTableHashEntry& toCopy);
776 FontTableBlobData *mSharedBlobData;
777 hb_blob_t *mBlob;
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,
790 int32_t aRunScript,
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 {
809 public:
810 NS_INLINE_DECL_REFCOUNTING(gfxFontFamily)
812 explicit gfxFontFamily(const nsAString& aName) :
813 mName(aName),
814 mOtherFamilyNamesInitialized(false),
815 mHasOtherFamilyNames(false),
816 mFaceNamesInitialized(false),
817 mHasStyles(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();
841 } else {
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
871 // of a single face
872 static void ReadOtherFamilyNamesForFace(const nsAString& aFamilyName,
873 const char *aNameData,
874 uint32_t aDataLength,
875 nsTArray<nsString>& aOtherFamilyNames,
876 bool useFullName);
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) {
901 ReadAllCMAPs();
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;
914 if (mHasStyles) {
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) {
940 return true;
943 return false;
946 void SetSkipSpaceFeatureCheck(bool aSkipCheck) {
947 mSkipDefaultFeatureSpaceCheck = aSkipCheck;
950 protected:
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;
975 nsString mName;
976 nsTArray<nsRefPtr<gfxFontEntry> > mAvailableFonts;
977 gfxSparseBitSet mFamilyCharacterMap;
978 bool mOtherFamilyNamesInitialized : 1;
979 bool mHasOtherFamilyNames : 1;
980 bool mFaceNamesInitialized : 1;
981 bool mHasStyles : 1;
982 bool mIsSimpleFamily : 1;
983 bool mIsBadUnderlineFamily : 1;
984 bool mFamilyCharacterMapInitialized : 1;
985 bool mSkipDefaultFeatureSpaceCheck : 1;
987 enum {
988 // for "simple" families, the faces are stored in mAvailableFonts
989 // with fixed positions:
990 kRegularFaceIndex = 0,
991 kBoldFaceIndex = 1,
992 kItalicFaceIndex = 2,
993 kBoldItalicFaceIndex = 3,
994 // mask values for selecting face with bold and/or italic attributes
995 kBoldMask = 0x01,
996 kItalicMask = 0x02
1000 struct gfxTextRange {
1001 enum {
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)
1009 : start(aStart),
1010 end(aEnd),
1011 font(aFont),
1012 matchType(aMatchType)
1014 uint32_t Length() const { return end - start; }
1015 uint32_t start, end;
1016 nsRefPtr<gfxFont> font;
1017 uint8_t matchType;
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
1039 * meantime.
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 {
1047 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> {
1056 public:
1057 enum {
1058 FONT_TIMEOUT_SECONDS = 10,
1059 SHAPED_WORD_TIMEOUT_SECONDS = 60
1062 gfxFontCache();
1063 ~gfxFontCache();
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
1089 // amount of time.
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.
1099 void Flush() {
1100 mFonts.Clear();
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;
1113 protected:
1114 class MemoryReporter MOZ_FINAL : public nsIMemoryReporter
1116 ~MemoryReporter() {}
1117 public:
1118 NS_DECL_ISUPPORTS
1119 NS_DECL_NSIMEMORYREPORTER
1122 // Observer for notifications that the font cache cares about
1123 class Observer MOZ_FINAL
1124 : public nsIObserver
1126 ~Observer() {}
1127 public:
1128 NS_DECL_ISUPPORTS
1129 NS_DECL_NSIOBSERVER
1132 void DestroyFont(gfxFont *aFont);
1134 static gfxFontCache *gGlobalCache;
1136 struct Key {
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 {
1144 public:
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) { }
1152 ~HashEntry() { }
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 };
1161 gfxFont* mFont;
1164 static size_t AddSizeOfFontEntryExcludingThis(HashEntry* aHashEntry,
1165 mozilla::MallocSizeOf aMallocSizeOf,
1166 void* aUserArg);
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 {
1177 public:
1179 struct TextCounts {
1180 uint32_t numContentTextRuns;
1181 uint32_t numChromeTextRuns;
1182 uint32_t numChars;
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
1197 TextCounts current;
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
1207 void Accumulate() {
1208 if (current.numChars == 0) {
1209 return;
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(&current, 0, sizeof(current));
1229 class gfxTextRunFactory {
1230 NS_INLINE_DECL_REFCOUNTING(gfxTextRunFactory)
1232 public:
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.
1236 enum {
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
1287 * other effects.
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.
1326 struct Parameters {
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)
1330 void *mUserData;
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;
1343 protected:
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 {
1362 public:
1363 explicit gfxGlyphExtents(int32_t aAppUnitsPerDevUnit) :
1364 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) {
1365 MOZ_COUNT_CTOR(gfxGlyphExtents);
1367 ~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
1378 // appunits.
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;
1408 private:
1409 class HashEntry : public nsUint32HashKey {
1410 public:
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
1423 class GlyphWidths {
1424 public:
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];
1431 if (!bits)
1432 return INVALID_WIDTH;
1433 uint32_t indexInBlock = aIndex & (BLOCK_SIZE - 1);
1434 if (bits & 0x1) {
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;
1445 ~GlyphWidths();
1447 private:
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;
1467 private:
1468 // not implemented:
1469 gfxGlyphExtents(const gfxGlyphExtents& aOther) MOZ_DELETE;
1470 gfxGlyphExtents& operator=(const gfxGlyphExtents& aOther) MOZ_DELETE;
1474 * gfxFontShaper
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 {
1492 public:
1493 explicit gfxFontShaper(gfxFont *aFont)
1494 : mFont(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,
1506 uint32_t aOffset,
1507 uint32_t aLength,
1508 int32_t aScript,
1509 gfxShapedText *aShapedText) = 0;
1511 gfxFont *GetFont() const { return mFont; }
1513 // returns true if features exist in output, false otherwise
1514 static bool
1515 MergeFontFeatures(const gfxFontStyle *aStyle,
1516 const nsTArray<gfxFontFeature>& aFontFeatures,
1517 bool aDisableLigatures,
1518 const nsAString& aFamilyName,
1519 bool aAddSmallCaps,
1520 nsDataHashtable<nsUint32HashKey,uint32_t>& aMergedFeatures);
1522 protected:
1523 // the font this shaper is working with
1524 gfxFont * mFont;
1528 class GlyphBufferAzure;
1529 struct TextRunDrawParams;
1530 struct FontDrawParams;
1532 class gfxFont {
1534 friend class gfxHarfBuzzShaper;
1535 friend class gfxGraphiteShaper;
1537 public:
1538 nsrefcnt AddRef(void) {
1539 NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt");
1540 if (mExpirationState.IsTracked()) {
1541 gfxFontCache::GetCache()->RemoveObject(this);
1543 ++mRefCnt;
1544 NS_LOG_ADDREF(this, mRefCnt, "gfxFont", sizeof(*this));
1545 return mRefCnt;
1547 nsrefcnt Release(void) {
1548 NS_PRECONDITION(0 != mRefCnt, "dup release");
1549 --mRefCnt;
1550 NS_LOG_RELEASE(this, mRefCnt, "gfxFont");
1551 if (mRefCnt == 0) {
1552 NotifyReleased();
1553 // |this| may have been deleted.
1554 return 0;
1556 return mRefCnt;
1559 int32_t GetRefCount() { return mRefCnt; }
1561 // options to specify the kind of AA to be used when creating a font
1562 typedef enum {
1563 kAntialiasDefault,
1564 kAntialiasNone,
1565 kAntialiasGrayscale,
1566 kAntialiasSubpixel
1567 } AntialiasOption;
1569 protected:
1570 nsAutoRefCnt mRefCnt;
1571 cairo_scaled_font_t *mScaledFont;
1573 void NotifyReleased() {
1574 gfxFontCache *cache = gfxFontCache::GetCache();
1575 if (cache) {
1576 // Don't delete just yet; return the object to the cache for
1577 // possibly recycling within some time limit
1578 cache->NotifyReleased(this);
1579 } else {
1580 // The cache may have already been shut down.
1581 delete this;
1585 gfxFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
1586 AntialiasOption anAAOption = kAntialiasDefault,
1587 cairo_scaled_font_t *aScaledFont = nullptr);
1589 public:
1590 virtual ~gfxFont();
1592 bool Valid() const {
1593 return mIsValid;
1596 // options for the kind of bounding box to return from measurement
1597 typedef enum {
1598 LOOSE_INK_EXTENTS,
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.
1602 TIGHT_INK_EXTENTS,
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
1610 // beyond this.
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.
1621 } BoundingBoxType;
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
1630 return nullptr;
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 {
1679 return false;
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) {
1684 return 0;
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);
1695 // Font metrics
1696 struct Metrics {
1697 gfxFloat xHeight;
1698 gfxFloat strikeoutSize;
1699 gfxFloat strikeoutOffset;
1700 gfxFloat underlineSize;
1701 gfxFloat underlineOffset;
1703 gfxFloat internalLeading;
1704 gfxFloat externalLeading;
1706 gfxFloat emHeight;
1707 gfxFloat emAscent;
1708 gfxFloat emDescent;
1709 gfxFloat maxHeight;
1710 gfxFloat maxAscent;
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.
1730 struct Spacing {
1731 gfxFloat mBefore;
1732 gfxFloat mAfter;
1735 * Metrics for a particular string
1737 struct RunMetrics {
1738 RunMetrics() {
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
1765 * be honoured.
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
1801 * be non-null.
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,
1818 Spacing *aSpacing);
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)
1826 { return false; }
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) :
1855 (size / threshold);
1858 gfxFontEntry *GetFontEntry() const { return mFontEntry.get(); }
1859 bool HasCharacter(uint32_t ch) {
1860 if (!mIsValid)
1861 return false;
1862 return mFontEntry->HasCharacter(ch);
1865 uint16_t GetUVSGlyph(uint32_t aCh, uint32_t aVS) {
1866 if (!mIsValid) {
1867 return 0;
1869 return mFontEntry->GetUVSGlyph(aCh, aVS);
1872 bool InitFakeSmallCapsRun(gfxContext *aContext,
1873 gfxTextRun *aTextRun,
1874 const uint8_t *aText,
1875 uint32_t aOffset,
1876 uint32_t aLength,
1877 uint8_t aMatchType,
1878 int32_t aScript,
1879 bool aSyntheticLower,
1880 bool aSyntheticUpper);
1882 bool InitFakeSmallCapsRun(gfxContext *aContext,
1883 gfxTextRun *aTextRun,
1884 const char16_t *aText,
1885 uint32_t aOffset,
1886 uint32_t aLength,
1887 uint8_t aMatchType,
1888 int32_t aScript,
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,
1898 const T *aString,
1899 uint32_t aRunStart,
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,
1907 const T *aText,
1908 uint32_t aLength,
1909 uint32_t aHash,
1910 int32_t aRunScript,
1911 int32_t aAppUnitsPerDevUnit,
1912 uint32_t aFlags,
1913 gfxTextPerfMetrics *aTextPerf);
1915 // Ensure the ShapedWord cache is initialized. This MUST be called before
1916 // any attempt to use GetShapedWord().
1917 void InitWordCache() {
1918 if (!mWordCache) {
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() {
1926 if (mWordCache) {
1927 (void)mWordCache->EnumerateEntries(AgeCacheEntry, this);
1931 // Discard all cached word records; called on memory-pressure notification.
1932 void ClearCachedWords() {
1933 if (mWordCache) {
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;
1946 typedef enum {
1947 FONT_TYPE_DWRITE,
1948 FONT_TYPE_GDI,
1949 FONT_TYPE_FT2,
1950 FONT_TYPE_MAC,
1951 FONT_TYPE_OS2,
1952 FONT_TYPE_CAIRO
1953 } FontType;
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 {
1969 public:
1970 virtual ~GlyphChangeObserver()
1972 if (mFont) {
1973 mFont->RemoveGlyphChangeObserver(this);
1976 // This gets called when the gfxFont dies.
1977 void ForgetFont() { mFont = nullptr; }
1978 virtual void NotifyGlyphsChanged() = 0;
1979 protected:
1980 explicit GlyphChangeObserver(gfxFont *aFont) : mFont(aFont)
1982 mFont->AddGlyphChangeObserver(this);
1984 gfxFont* mFont;
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);
2021 protected:
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,
2027 double aAdvance,
2028 gfxPoint *aPt,
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
2034 // in aRunParams.
2035 bool DrawGlyphs(gfxShapedText *aShapedText,
2036 uint32_t aOffset, // offset in the textrun
2037 uint32_t aCount, // length of run to draw
2038 gfxPoint *aPt,
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 {
2059 return false;
2062 // The return value is interpreted as a horizontal advance in 16.16 fixed
2063 // point format.
2064 virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID) {
2065 return -1;
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
2081 uint32_t aLength,
2082 int32_t aScript,
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,
2089 uint32_t aOffset,
2090 uint32_t aLength,
2091 int32_t aScript,
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
2100 uint32_t aLength,
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
2109 // text.
2110 template<typename T>
2111 bool ShapeTextWithoutWordCache(gfxContext *aContext,
2112 const T *aText,
2113 uint32_t aOffset,
2114 uint32_t aLength,
2115 int32_t aScript,
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,
2125 const T *aText,
2126 uint32_t aOffset,
2127 uint32_t aLength,
2128 int32_t aScript,
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 {
2144 union {
2145 const uint8_t *mSingle;
2146 const char16_t *mDouble;
2147 } mText;
2148 uint32_t mLength;
2149 uint32_t mFlags;
2150 int32_t mScript;
2151 int32_t mAppUnitsPerDevUnit;
2152 PLDHashNumber mHashKey;
2153 bool mTextIs8Bit;
2155 CacheHashKey(const uint8_t *aText, uint32_t aLength,
2156 uint32_t aStringHash,
2157 int32_t aScriptCode, int32_t aAppUnitsPerDevUnit,
2158 uint32_t aFlags)
2159 : mLength(aLength),
2160 mFlags(aFlags),
2161 mScript(aScriptCode),
2162 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
2163 mHashKey(aStringHash + aScriptCode +
2164 aAppUnitsPerDevUnit * 0x100 + aFlags * 0x10000),
2165 mTextIs8Bit(true)
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,
2175 uint32_t aFlags)
2176 : mLength(aLength),
2177 mFlags(aFlags),
2178 mScript(aScriptCode),
2179 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
2180 mHashKey(aStringHash + aScriptCode +
2181 aAppUnitsPerDevUnit * 0x100 + aFlags * 0x10000),
2182 mTextIs8Bit(false)
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 {
2193 public:
2194 typedef const CacheHashKey &KeyType;
2195 typedef const CacheHashKey *KeyTypePointer;
2197 // When constructing a new entry in the hashtable, the caller of Put()
2198 // will fill us in.
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;
2226 bool mIsValid;
2228 // use synthetic bolding for environments where this is not supported
2229 // by the platform
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).
2323 class gfxShapedText
2325 public:
2326 gfxShapedText(uint32_t aLength, uint32_t aFlags,
2327 int32_t aAppUnitsPerDevUnit)
2328 : mLength(aLength)
2329 , mFlags(aFlags)
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 {
2351 public:
2352 CompressedGlyph() { mValue = 0; }
2354 enum {
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
2359 // in appunits).
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,
2376 ADVANCE_SHIFT = 16,
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
2382 // flag bits:
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;
2460 } else {
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);
2474 mValue ^= toggle;
2475 return toggle;
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;
2485 return *this;
2487 CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart,
2488 uint32_t aGlyphCount) {
2489 mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
2490 FLAG_NOT_MISSING |
2491 CharIdentityFlags() |
2492 (aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) |
2493 (aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) |
2494 (aGlyphCount << GLYPH_COUNT_SHIFT);
2495 return *this;
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);
2506 return *this;
2508 uint32_t GetGlyphCount() const {
2509 NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
2510 return (mValue & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT;
2513 void SetIsSpace() {
2514 mValue |= FLAG_CHAR_IS_SPACE;
2516 void SetIsTab() {
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;
2529 private:
2530 uint32_t mValue;
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 */
2544 uint32_t mGlyphID;
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 */
2549 int32_t mAdvance;
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,
2600 uint32_t aLength);
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,
2605 uint32_t aLength);
2607 uint32_t Flags() const {
2608 return mFlags;
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 {
2632 return mLength;
2635 bool FilterIfIgnorable(uint32_t aIndex, uint32_t aCh);
2637 protected:
2638 // Allocate aCount DetailedGlyphs for the given index
2639 DetailedGlyph *AllocateDetailedGlyphs(uint32_t aCharIndex,
2640 uint32_t aCount);
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 {
2649 public:
2650 DetailedGlyphStore()
2651 : mLastUsed(0)
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) {
2673 ++mLastUsed;
2674 } else if (aOffset == mOffsetToIndex[0].mOffset) {
2675 mLastUsed = 0;
2676 } else if (aOffset == mOffsetToIndex[mLastUsed].mOffset) {
2677 // do nothing
2678 } else if (mLastUsed > 0 &&
2679 aOffset == mOffsetToIndex[mLastUsed - 1].mOffset) {
2680 --mLastUsed;
2681 } else {
2682 mLastUsed =
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
2696 // method.
2697 if (mOffsetToIndex.Length() == 0 ||
2698 aOffset > mOffsetToIndex[mOffsetToIndex.Length() - 1].mOffset) {
2699 mOffsetToIndex.AppendElement(DGRec(aOffset, detailIndex));
2700 } else {
2701 mOffsetToIndex.InsertElementSorted(DGRec(aOffset, detailIndex),
2702 CompareRecordOffsets());
2704 return details;
2707 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
2708 return aMallocSizeOf(this) +
2709 mDetails.SizeOfExcludingThis(aMallocSizeOf) +
2710 mOffsetToIndex.SizeOfExcludingThis(aMallocSizeOf);
2713 private:
2714 struct DGRec {
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
2758 uint32_t mLength;
2760 // Shaping flags (direction, ligature-suppression)
2761 uint32_t mFlags;
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
2775 public:
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,
2786 int32_t aRunScript,
2787 int32_t aAppUnitsPerDevUnit,
2788 uint32_t aFlags) {
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
2794 uint32_t size =
2795 offsetof(gfxShapedWord, mCharGlyphsStorage) +
2796 aLength * (sizeof(CompressedGlyph) + sizeof(uint8_t));
2797 void *storage = moz_malloc(size);
2798 if (!storage) {
2799 return nullptr;
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,
2808 int32_t aRunScript,
2809 int32_t aAppUnitsPerDevUnit,
2810 uint32_t aFlags) {
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),
2820 narrowText);
2821 return Create((const uint8_t*)(narrowText.BeginReading()),
2822 aLength, aRunScript, aAppUnitsPerDevUnit, aFlags);
2825 uint32_t size =
2826 offsetof(gfxShapedWord, mCharGlyphsStorage) +
2827 aLength * (sizeof(CompressedGlyph) + sizeof(char16_t));
2828 void *storage = moz_malloc(size);
2829 if (!storage) {
2830 return nullptr;
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) {
2840 moz_free(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 {
2864 return mScript;
2867 void ResetAge() {
2868 mAgeCounter = 0;
2870 uint32_t IncrementAge() {
2871 return ++mAgeCounter;
2874 private:
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,
2881 uint32_t aFlags)
2882 : gfxShapedText(aLength, aFlags | gfxTextRunFactory::TEXT_IS_8BIT,
2883 aAppUnitsPerDevUnit)
2884 , mScript(aRunScript)
2885 , mAgeCounter(0)
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,
2894 uint32_t aFlags)
2895 : gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit)
2896 , mScript(aRunScript)
2897 , mAgeCounter(0)
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);
2905 int32_t mScript;
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
2973 * be on the test!
2975 class gfxTextRun : public gfxShapedText {
2976 public:
2978 // Override operator delete to properly free the object that was
2979 // allocated via moz_malloc.
2980 void operator delete(void* p) {
2981 moz_free(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
3037 * linebreaks.
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 {
3061 public:
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 {
3097 public:
3098 explicit ClusterIterator(gfxTextRun *aTextRun);
3100 void Reset();
3102 bool NextCluster();
3104 uint32_t Position() const {
3105 return mCurrentChar;
3108 uint32_t ClusterLength() const;
3110 gfxFloat ClusterAdvance(PropertyProvider *aProvider) const;
3112 private:
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
3122 * is returned here.
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,
3139 DrawMode aDrawMode,
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
3184 * properly.
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
3239 * the effect of
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,
3257 Metrics *aMetrics,
3258 gfxFont::BoundingBoxType aBoundingBoxType,
3259 gfxContext *aRefContextForTightBoundingBox,
3260 bool *aUsedHyphenation,
3261 uint32_t *aLastBreak,
3262 bool aCanWordWrap,
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) {}
3272 // Utility getters
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");
3281 mFlags |= aFlags;
3283 void ClearFlagBits(uint32_t aFlags) {
3284 NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS),
3285 "Only user flags should be mutable");
3286 mFlags &= ~aFlags;
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,
3296 uint32_t aFlags);
3298 // The text is divided into GlyphRuns as necessary
3299 struct GlyphRun {
3300 nsRefPtr<gfxFont> mFont; // never null
3301 uint32_t mCharacterOffset; // into original UTF16 string
3302 uint8_t mMatchType;
3305 class GlyphRunIterator {
3306 public:
3307 GlyphRunIterator(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aLength)
3308 : mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) {
3309 mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart);
3311 bool NextRun();
3312 GlyphRun *GetGlyphRun() { return mGlyphRun; }
3313 uint32_t GetStringStart() { return mStringStart; }
3314 uint32_t GetStringEnd() { return mStringEnd; }
3315 private:
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 {
3326 public:
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
3356 * TextRun.
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);
3405 g->SetIsTab();
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);
3416 g->SetIsNewline();
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
3427 * errors.
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
3444 // textrun.
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
3455 // mFontGroup.)
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)
3477 MOZ_MUST_OVERRIDE;
3478 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
3479 MOZ_MUST_OVERRIDE;
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) {
3484 return 0;
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
3497 enum ShapingState {
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;
3510 #ifdef DEBUG
3511 void Dump(FILE* aOutput);
3512 #endif
3514 protected:
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;
3535 private:
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,
3572 Metrics *aMetrics);
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,
3580 Metrics *aMetrics);
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;
3592 void *mUserData;
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 {
3610 public:
3611 class FamilyFace {
3612 public:
3613 FamilyFace() { }
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(); }
3627 private:
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,
3699 uint32_t aFlags)
3701 gfxTextRunFactory::Parameters params = {
3702 aRefContext, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit
3704 return MakeTextRun(aString, aLength, &params, 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
3711 * ignored.
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 {
3783 public:
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
3795 static void
3796 ResolveGenericFontNames(mozilla::FontFamilyType aGenericType,
3797 nsIAtom *aLanguage,
3798 nsTArray<nsString>& aGenericFamilies);
3800 protected:
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
3825 // timer to fire)
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,
3849 const T *aString,
3850 uint32_t aLength);
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,
3857 const T *aString,
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,
3866 uint32_t aCh);
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,
3875 nsIAtom *aLanguage,
3876 void *aClosure);
3878 // lookup and add a font with a given name (i.e. *not* a generic!)
3879 virtual void FindPlatformFont(const nsAString& aName,
3880 bool aUseFontSet,
3881 void *aClosure);
3883 static nsILanguageAtomService* gLangService;
3885 #endif