Bug 1758688 [wpt PR 33067] - [FedCM] Make revoke a non-static method, a=testonly
[gecko.git] / gfx / thebes / gfxFont.h
blob61704cc0631231761667db0e1e75a49e0dd4ab3d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=4 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef GFX_FONT_H
8 #define GFX_FONT_H
10 #include <new>
11 #include <utility>
12 #include "PLDHashTable.h"
13 #include "ThebesRLBoxTypes.h"
14 #include "gfxFontVariations.h"
15 #include "gfxRect.h"
16 #include "gfxTypes.h"
17 #include "mozilla/AlreadyAddRefed.h"
18 #include "mozilla/Attributes.h"
19 #include "mozilla/FontPropertyTypes.h"
20 #include "mozilla/MemoryReporting.h"
21 #include "mozilla/Mutex.h"
22 #include "mozilla/RefPtr.h"
23 #include "mozilla/RWLock.h"
24 #include "mozilla/ServoStyleConsts.h"
25 #include "mozilla/TypedEnumBits.h"
26 #include "mozilla/UniquePtr.h"
27 #include "mozilla/gfx/MatrixFwd.h"
28 #include "mozilla/gfx/Point.h"
29 #include "mozilla/intl/UnicodeScriptCodes.h"
30 #include "nsCOMPtr.h"
31 #include "nsColor.h"
32 #include "nsTHashMap.h"
33 #include "nsTHashSet.h"
34 #include "nsExpirationTracker.h"
35 #include "nsFontMetrics.h"
36 #include "nsHashKeys.h"
37 #include "nsIMemoryReporter.h"
38 #include "nsIObserver.h"
39 #include "nsISupports.h"
40 #include "nsString.h"
41 #include "nsTArray.h"
42 #include "nsTHashtable.h"
43 #include "nscore.h"
44 #include "DrawMode.h"
46 // Only required for function bodys
47 #include <stdlib.h>
48 #include <string.h>
49 #include <algorithm>
50 #include "mozilla/Assertions.h"
51 #include "mozilla/HashFunctions.h"
52 #include "mozilla/ServoUtils.h"
53 #include "mozilla/gfx/2D.h"
54 #include "gfxFontEntry.h"
55 #include "gfxFontFeatures.h"
56 #include "gfxFontUtils.h"
57 #include "gfxPlatform.h"
58 #include "nsAtom.h"
59 #include "nsDebug.h"
60 #include "nsMathUtils.h"
62 class gfxContext;
63 class gfxGraphiteShaper;
64 class gfxHarfBuzzShaper;
65 class gfxGlyphExtents;
66 class gfxMathTable;
67 class gfxPattern;
68 class gfxShapedText;
69 class gfxShapedWord;
70 class gfxSkipChars;
71 class gfxTextRun;
72 class nsIEventTarget;
73 class nsITimer;
74 struct gfxTextRunDrawCallbacks;
76 namespace mozilla {
77 class SVGContextPaint;
78 namespace layout {
79 class TextDrawTarget;
81 } // namespace mozilla
83 typedef struct _cairo cairo_t;
84 typedef struct _cairo_scaled_font cairo_scaled_font_t;
86 #define FONT_MAX_SIZE 2000.0
88 #define SMALL_CAPS_SCALE_FACTOR 0.8
90 // The skew factor used for synthetic-italic [oblique] fonts;
91 // we use a platform-dependent value to harmonize with the platform's own APIs.
92 #ifdef XP_WIN
93 # define OBLIQUE_SKEW_FACTOR 0.3f
94 #elif defined(MOZ_WIDGET_GTK)
95 # define OBLIQUE_SKEW_FACTOR 0.2f
96 #else
97 # define OBLIQUE_SKEW_FACTOR 0.25f
98 #endif
100 struct gfxFontStyle {
101 using FontStretch = mozilla::FontStretch;
102 using FontSlantStyle = mozilla::FontSlantStyle;
103 using FontWeight = mozilla::FontWeight;
104 using FontSizeAdjust = mozilla::StyleFontSizeAdjust;
106 gfxFontStyle();
107 gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight, FontStretch aStretch,
108 gfxFloat aSize, const FontSizeAdjust& aSizeAdjust,
109 bool aSystemFont, bool aPrinterFont, bool aWeightSynthesis,
110 bool aStyleSynthesis, bool aSmallCapsSynthesis,
111 uint32_t aLanguageOverride);
112 // Features are composed of (1) features from style rules (2) features
113 // from feature settings rules and (3) family-specific features. (1) and
114 // (3) are guaranteed to be mutually exclusive
116 // custom opentype feature settings
117 CopyableTArray<gfxFontFeature> featureSettings;
119 // Some font-variant property values require font-specific settings
120 // defined via @font-feature-values rules. These are resolved after
121 // font matching occurs.
123 // -- list of value tags for specific alternate features
124 mozilla::StyleVariantAlternatesList variantAlternates;
126 // -- object used to look these up once the font is matched
127 RefPtr<gfxFontFeatureValueSet> featureValueLookup;
129 // opentype variation settings
130 CopyableTArray<gfxFontVariation> variationSettings;
132 // The logical size of the font, in pixels
133 gfxFloat size;
135 // The optical size value to apply (if supported); negative means none.
136 float autoOpticalSize = -1.0f;
138 // The aspect-value (ie., the ratio actualsize:actualxheight) that any
139 // actual physical font created from this font structure must have when
140 // rendering or measuring a string. A value of -1.0 means no adjustment
141 // needs to be done; otherwise the value must be nonnegative.
142 float sizeAdjust;
144 // baseline offset, used when simulating sub/superscript glyphs
145 float baselineOffset;
147 // Language system tag, to override document language;
148 // an OpenType "language system" tag represented as a 32-bit integer
149 // (see http://www.microsoft.com/typography/otspec/languagetags.htm).
150 // Normally 0, so font rendering will use the document or element language
151 // (see above) to control any language-specific rendering, but the author
152 // can override this for cases where the options implemented in the font
153 // do not directly match the actual language. (E.g. lang may be Macedonian,
154 // but the font in use does not explicitly support this; the author can
155 // use font-language-override to request the Serbian option in the font
156 // in order to get correct glyph shapes.)
157 uint32_t languageOverride;
159 // The estimated background color behind the text. Enables a special
160 // rendering mode when NS_GET_A(.) > 0. Only used for text in the chrome.
161 nscolor fontSmoothingBackgroundColor;
163 // The Font{Weight,Stretch,SlantStyle} fields are each a 16-bit type.
165 // The weight of the font: 100, 200, ... 900.
166 FontWeight weight;
168 // The stretch of the font
169 FontStretch stretch;
171 // The style of font
172 FontSlantStyle style;
174 // Whether face-selection properties weight/style/stretch are all 'normal'
175 bool IsNormalStyle() const {
176 return weight.IsNormal() && style.IsNormal() && stretch.IsNormal();
179 // We pack these three small-integer fields into a single byte to avoid
180 // overflowing an 8-byte boundary [in a 64-bit build] and ending up with
181 // 7 bytes of padding at the end of the struct.
183 // caps variant (small-caps, petite-caps, etc.)
184 uint8_t variantCaps : 3; // uses range 0..6
186 // sub/superscript variant
187 uint8_t variantSubSuper : 2; // uses range 0..2
189 // font metric used as basis of font-size-adjust
190 uint8_t sizeAdjustBasis : 3; // uses range 0..4
192 // Say that this font is a system font and therefore does not
193 // require certain fixup that we do for fonts from untrusted
194 // sources.
195 bool systemFont : 1;
197 // Say that this font is used for print or print preview.
198 bool printerFont : 1;
200 // Used to imitate -webkit-font-smoothing: antialiased
201 bool useGrayscaleAntialiasing : 1;
203 // Whether synthetic styles are allowed
204 bool allowSyntheticWeight : 1;
205 bool allowSyntheticStyle : 1;
206 bool allowSyntheticSmallCaps : 1;
208 // some variant features require fallback which complicates the shaping
209 // code, so set up a bool to indicate when shaping with fallback is needed
210 bool noFallbackVariantFeatures : 1;
212 // Return the final adjusted font size for the given aspect ratio.
213 // Not meant to be called when sizeAdjustBasis is NONE.
214 gfxFloat GetAdjustedSize(gfxFloat aspect) const {
215 MOZ_ASSERT(
216 FontSizeAdjust::Tag(sizeAdjustBasis) != FontSizeAdjust::Tag::None,
217 "Not meant to be called when sizeAdjustBasis is none");
218 gfxFloat adjustedSize =
219 std::max(NS_round(size * (sizeAdjust / aspect)), 1.0);
220 return std::min(adjustedSize, FONT_MAX_SIZE);
223 // Some callers want to take a short-circuit path if they can be sure the
224 // adjusted size will be zero.
225 bool AdjustedSizeMustBeZero() const {
226 return size == 0.0 ||
227 (FontSizeAdjust::Tag(sizeAdjustBasis) != FontSizeAdjust::Tag::None &&
228 sizeAdjust == 0.0);
231 PLDHashNumber Hash() const;
233 // Adjust this style to simulate sub/superscript (as requested in the
234 // variantSubSuper field) using size and baselineOffset instead.
235 void AdjustForSubSuperscript(int32_t aAppUnitsPerDevPixel);
237 // Should this style cause the given font entry to use synthetic bold?
238 bool NeedsSyntheticBold(gfxFontEntry* aFontEntry) const {
239 return weight.IsBold() && allowSyntheticWeight &&
240 !aFontEntry->SupportsBold();
243 bool Equals(const gfxFontStyle& other) const {
244 return mozilla::NumbersAreBitwiseIdentical(size, other.size) &&
245 (style == other.style) && (weight == other.weight) &&
246 (stretch == other.stretch) && (variantCaps == other.variantCaps) &&
247 (variantSubSuper == other.variantSubSuper) &&
248 (allowSyntheticWeight == other.allowSyntheticWeight) &&
249 (allowSyntheticStyle == other.allowSyntheticStyle) &&
250 (systemFont == other.systemFont) &&
251 (printerFont == other.printerFont) &&
252 (useGrayscaleAntialiasing == other.useGrayscaleAntialiasing) &&
253 (baselineOffset == other.baselineOffset) &&
254 mozilla::NumbersAreBitwiseIdentical(sizeAdjust, other.sizeAdjust) &&
255 (sizeAdjustBasis == other.sizeAdjustBasis) &&
256 (featureSettings == other.featureSettings) &&
257 (variantAlternates == other.variantAlternates) &&
258 (featureValueLookup == other.featureValueLookup) &&
259 (variationSettings == other.variationSettings) &&
260 (languageOverride == other.languageOverride) &&
261 mozilla::NumbersAreBitwiseIdentical(autoOpticalSize,
262 other.autoOpticalSize) &&
263 (fontSmoothingBackgroundColor == other.fontSmoothingBackgroundColor);
268 * Font cache design:
270 * The mFonts hashtable contains most fonts, indexed by (gfxFontEntry*, style).
271 * It does not add a reference to the fonts it contains.
272 * When a font's refcount decreases to zero, instead of deleting it we
273 * add it to our expiration tracker.
274 * The expiration tracker tracks fonts with zero refcount. After a certain
275 * period of time, such fonts expire and are deleted.
277 * We're using 3 generations with a ten-second generation interval, so
278 * zero-refcount fonts will be deleted 20-30 seconds after their refcount
279 * goes to zero, if timer events fire in a timely manner.
281 * The font cache also handles timed expiration of cached ShapedWords
282 * for "persistent" fonts: it has a repeating timer, and notifies
283 * each cached font to "age" its shaped words. The words will be released
284 * by the fonts if they get aged three times without being re-used in the
285 * meantime.
287 * Note that the ShapedWord timeout is much larger than the font timeout,
288 * so that in the case of a short-lived font, we'll discard the gfxFont
289 * completely, with all its words, and avoid the cost of aging the words
290 * individually. That only happens with longer-lived fonts.
292 struct FontCacheSizes {
293 FontCacheSizes() : mFontInstances(0), mShapedWords(0) {}
295 size_t mFontInstances; // memory used by instances of gfxFont subclasses
296 size_t mShapedWords; // memory used by the per-font shapedWord caches
299 class gfxFontCache final
300 : public ExpirationTrackerImpl<gfxFont, 3, mozilla::Mutex,
301 mozilla::MutexAutoLock> {
302 protected:
303 // Expiration tracker implementation.
304 enum { FONT_TIMEOUT_SECONDS = 10 };
306 typedef mozilla::Mutex Lock;
307 typedef mozilla::MutexAutoLock AutoLock;
309 // This protects the ExpirationTracker tables.
310 Lock mMutex = Lock("fontCacheExpirationMutex");
312 Lock& GetMutex() override { return mMutex; }
314 public:
315 explicit gfxFontCache(nsIEventTarget* aEventTarget);
316 ~gfxFontCache();
318 enum { SHAPED_WORD_TIMEOUT_SECONDS = 60 };
321 * Get the global gfxFontCache. You must call Init() before
322 * calling this method --- the result will not be null.
324 static gfxFontCache* GetCache() { return gGlobalCache; }
326 static nsresult Init();
327 // It's OK to call this even if Init() has not been called.
328 static void Shutdown();
330 // Look up a font in the cache. Returns null if there's nothing matching
331 // in the cache
332 gfxFont* Lookup(const gfxFontEntry* aFontEntry, const gfxFontStyle* aStyle,
333 const gfxCharacterMap* aUnicodeRangeMap);
335 // We created a new font (presumably because Lookup returned null);
336 // put it in the cache. The font's refcount should be nonzero. It is
337 // allowable to add a new font even if there is one already in the
338 // cache with the same key; we'll forget about the old one.
339 void AddNew(gfxFont* aFont);
341 // The font's refcount has gone to zero; give ownership of it to
342 // the cache. We delete it if it's not acquired again after a certain
343 // amount of time.
344 void NotifyReleased(gfxFont* aFont);
346 // Cleans out the hashtable and removes expired fonts waiting for cleanup.
347 // Other gfxFont objects may be still in use but they will be pushed
348 // into the expiration queues and removed.
349 void Flush() {
351 mozilla::AutoWriteLock lock(mCacheLock);
352 mFonts.Clear();
354 AgeAllGenerations();
357 void FlushShapedWordCaches();
358 void NotifyGlyphsChanged();
360 void AgeCachedWords();
362 void RunWordCacheExpirationTimer() {
363 if (!mTimerRunning) {
364 mozilla::AutoWriteLock lock(mCacheLock);
365 if (!mTimerRunning && mWordCacheExpirationTimer) {
366 mWordCacheExpirationTimer->InitWithNamedFuncCallback(
367 WordCacheExpirationTimerCallback, this,
368 SHAPED_WORD_TIMEOUT_SECONDS * 1000, nsITimer::TYPE_REPEATING_SLACK,
369 "gfxFontCache::WordCacheExpiration");
370 mTimerRunning = true;
374 void PauseWordCacheExpirationTimer() {
375 if (mTimerRunning) {
376 mozilla::AutoWriteLock lock(mCacheLock);
377 if (mTimerRunning && mWordCacheExpirationTimer) {
378 mWordCacheExpirationTimer->Cancel();
379 mTimerRunning = false;
384 void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
385 FontCacheSizes* aSizes) const;
386 void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
387 FontCacheSizes* aSizes) const;
389 void AgeAllGenerations() {
390 AutoLock lock(mMutex);
391 AgeAllGenerationsLocked(lock);
394 void RemoveObject(gfxFont* aFont) {
395 AutoLock lock(mMutex);
396 RemoveObjectLocked(aFont, lock);
399 mozilla::RWLock& GetCacheLock() { return mCacheLock; }
401 protected:
402 // Guards the global font hashtable, separately from the expiration-tracker
403 // records.
404 mutable mozilla::RWLock mCacheLock = mozilla::RWLock("fontCacheLock");
406 class MemoryReporter final : public nsIMemoryReporter {
407 ~MemoryReporter() = default;
409 public:
410 NS_DECL_ISUPPORTS
411 NS_DECL_NSIMEMORYREPORTER
414 // Observer for notifications that the font cache cares about
415 class Observer final : public nsIObserver {
416 ~Observer() = default;
418 public:
419 NS_DECL_ISUPPORTS
420 NS_DECL_NSIOBSERVER
423 nsresult AddObject(gfxFont* aFont) {
424 AutoLock lock(mMutex);
425 return AddObjectLocked(aFont, lock);
428 // This gets called when the timeout has expired on a zero-refcount
429 // font; we just delete it.
430 void NotifyExpiredLocked(gfxFont* aFont, const AutoLock&) override;
431 void NotifyExpired(gfxFont* aFont);
433 void DestroyFont(gfxFont* aFont);
435 static gfxFontCache* gGlobalCache;
437 struct MOZ_STACK_CLASS Key {
438 const gfxFontEntry* mFontEntry;
439 const gfxFontStyle* mStyle;
440 const gfxCharacterMap* mUnicodeRangeMap;
441 Key(const gfxFontEntry* aFontEntry, const gfxFontStyle* aStyle,
442 const gfxCharacterMap* aUnicodeRangeMap)
443 : mFontEntry(aFontEntry),
444 mStyle(aStyle),
445 mUnicodeRangeMap(aUnicodeRangeMap) {}
448 class HashEntry : public PLDHashEntryHdr {
449 public:
450 typedef const Key& KeyType;
451 typedef const Key* KeyTypePointer;
453 // When constructing a new entry in the hashtable, we'll leave this
454 // blank. The caller of Put() will fill this in.
455 explicit HashEntry(KeyTypePointer aStr) : mFont(nullptr) {}
457 bool KeyEquals(const KeyTypePointer aKey) const;
458 static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
459 static PLDHashNumber HashKey(const KeyTypePointer aKey) {
460 return mozilla::HashGeneric(aKey->mStyle->Hash(), aKey->mFontEntry,
461 aKey->mUnicodeRangeMap);
463 enum { ALLOW_MEMMOVE = true };
465 // The cache tracks gfxFont objects whose refcount has dropped to zero,
466 // so they are not immediately deleted but may be "resurrected" if they
467 // have not yet expired from the tracker when they are needed again.
468 // See the custom AddRef/Release methods in gfxFont.
469 gfxFont* MOZ_UNSAFE_REF("tracking for deferred deletion") mFont;
472 nsTHashtable<HashEntry> mFonts GUARDED_BY(mCacheLock);
474 static void WordCacheExpirationTimerCallback(nsITimer* aTimer, void* aCache);
476 nsCOMPtr<nsITimer> mWordCacheExpirationTimer GUARDED_BY(mCacheLock);
477 std::atomic<bool> mTimerRunning = false;
480 class gfxTextPerfMetrics {
481 public:
482 struct TextCounts {
483 uint32_t numContentTextRuns;
484 uint32_t numChromeTextRuns;
485 uint32_t numChars;
486 uint32_t maxTextRunLen;
487 uint32_t wordCacheSpaceRules;
488 uint32_t wordCacheLong;
489 uint32_t wordCacheHit;
490 uint32_t wordCacheMiss;
491 uint32_t fallbackPrefs;
492 uint32_t fallbackSystem;
493 uint32_t textrunConst;
494 uint32_t textrunDestr;
495 uint32_t genericLookups;
498 uint32_t reflowCount;
500 // counts per reflow operation
501 TextCounts current;
503 // totals for the lifetime of a document
504 TextCounts cumulative;
506 gfxTextPerfMetrics() { memset(this, 0, sizeof(gfxTextPerfMetrics)); }
508 // add current totals to cumulative ones
509 void Accumulate() {
510 if (current.numChars == 0) {
511 return;
513 cumulative.numContentTextRuns += current.numContentTextRuns;
514 cumulative.numChromeTextRuns += current.numChromeTextRuns;
515 cumulative.numChars += current.numChars;
516 if (current.maxTextRunLen > cumulative.maxTextRunLen) {
517 cumulative.maxTextRunLen = current.maxTextRunLen;
519 cumulative.wordCacheSpaceRules += current.wordCacheSpaceRules;
520 cumulative.wordCacheLong += current.wordCacheLong;
521 cumulative.wordCacheHit += current.wordCacheHit;
522 cumulative.wordCacheMiss += current.wordCacheMiss;
523 cumulative.fallbackPrefs += current.fallbackPrefs;
524 cumulative.fallbackSystem += current.fallbackSystem;
525 cumulative.textrunConst += current.textrunConst;
526 cumulative.textrunDestr += current.textrunDestr;
527 cumulative.genericLookups += current.genericLookups;
528 memset(&current, 0, sizeof(current));
532 namespace mozilla {
533 namespace gfx {
534 // Flags that live in the gfxShapedText::mFlags field.
535 // (Note that gfxTextRun has an additional mFlags2 field for use
536 // by textrun clients like nsTextFrame.)
538 // If you add a flag, please add support for it in gfxTextRun::Dump.
539 enum class ShapedTextFlags : uint16_t {
541 * When set, the text is RTL.
543 TEXT_IS_RTL = 0x0001,
545 * When set, spacing is enabled and the textrun needs to call GetSpacing
546 * on the spacing provider.
548 TEXT_ENABLE_SPACING = 0x0002,
550 * When set, the text has no characters above 255 and it is stored
551 * in the textrun in 8-bit format.
553 TEXT_IS_8BIT = 0x0004,
555 * When set, GetHyphenationBreaks may return true for some character
556 * positions, otherwise it will always return false for all characters.
558 TEXT_ENABLE_HYPHEN_BREAKS = 0x0008,
560 * When set, the RunMetrics::mBoundingBox field will be initialized
561 * properly based on glyph extents, in particular, glyph extents that
562 * overflow the standard font-box (the box defined by the ascent, descent
563 * and advance width of the glyph). When not set, it may just be the
564 * standard font-box even if glyphs overflow.
566 TEXT_NEED_BOUNDING_BOX = 0x0010,
568 * When set, optional ligatures are disabled. Ligatures that are
569 * required for legible text should still be enabled.
571 TEXT_DISABLE_OPTIONAL_LIGATURES = 0x0020,
573 * When set, the textrun should favour speed of construction over
574 * quality. This may involve disabling ligatures and/or kerning or
575 * other effects.
577 TEXT_OPTIMIZE_SPEED = 0x0040,
579 * When set, the textrun should discard control characters instead of
580 * turning them into hexboxes.
582 TEXT_HIDE_CONTROL_CHARACTERS = 0x0080,
585 * nsTextFrameThebes sets these, but they're defined here rather than
586 * in nsTextFrameUtils.h because ShapedWord creation/caching also needs
587 * to check the _INCOMING flag
589 TEXT_TRAILING_ARABICCHAR = 0x0100,
591 * When set, the previous character for this textrun was an Arabic
592 * character. This is used for the context detection necessary for
593 * bidi.numeral implementation.
595 TEXT_INCOMING_ARABICCHAR = 0x0200,
598 * Set if the textrun should use the OpenType 'math' script.
600 TEXT_USE_MATH_SCRIPT = 0x0400,
603 * Bit 0x0800 is currently unused.
607 * Field for orientation of the textrun and glyphs within it.
608 * Possible values of the TEXT_ORIENT_MASK field:
609 * TEXT_ORIENT_HORIZONTAL
610 * TEXT_ORIENT_VERTICAL_UPRIGHT
611 * TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT
612 * TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT
613 * TEXT_ORIENT_VERTICAL_MIXED
614 * For all VERTICAL settings, the x and y coordinates of glyph
615 * positions are exchanged, so that simple advances are vertical.
617 * The MIXED value indicates vertical textRuns for which the CSS
618 * text-orientation property is 'mixed', but is never used for
619 * individual glyphRuns; it will be resolved to either UPRIGHT
620 * or SIDEWAYS_RIGHT according to the UTR50 properties of the
621 * characters, and separate glyphRuns created for the resulting
622 * glyph orientations.
624 TEXT_ORIENT_MASK = 0x7000,
625 TEXT_ORIENT_HORIZONTAL = 0x0000,
626 TEXT_ORIENT_VERTICAL_UPRIGHT = 0x1000,
627 TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT = 0x2000,
628 TEXT_ORIENT_VERTICAL_MIXED = 0x3000,
629 TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT = 0x4000,
632 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ShapedTextFlags)
633 } // namespace gfx
634 } // namespace mozilla
636 class gfxTextRunFactory {
637 // Used by stylo
638 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxTextRunFactory)
640 public:
641 typedef mozilla::gfx::DrawTarget DrawTarget;
644 * This record contains all the parameters needed to initialize a textrun.
646 struct MOZ_STACK_CLASS Parameters {
647 // Shape text params suggesting where the textrun will be rendered
648 DrawTarget* mDrawTarget;
649 // Pointer to arbitrary user data (which should outlive the textrun)
650 void* mUserData;
651 // A description of which characters have been stripped from the original
652 // DOM string to produce the characters in the textrun. May be null
653 // if that information is not relevant.
654 gfxSkipChars* mSkipChars;
655 // A list of where linebreaks are currently placed in the textrun. May
656 // be null if mInitialBreakCount is zero.
657 uint32_t* mInitialBreaks;
658 uint32_t mInitialBreakCount;
659 // The ratio to use to convert device pixels to application layout units
660 int32_t mAppUnitsPerDevUnit;
663 protected:
664 // Protected destructor, to discourage deletion outside of Release():
665 virtual ~gfxTextRunFactory();
669 * gfxFontShaper
671 * This class implements text shaping (character to glyph mapping and
672 * glyph layout). There is a gfxFontShaper subclass for each text layout
673 * technology (uniscribe, core text, harfbuzz,....) we support.
675 * The shaper is responsible for setting up glyph data in gfxTextRuns.
677 * A generic, platform-independent shaper relies only on the standard
678 * gfxFont interface and can work with any concrete subclass of gfxFont.
680 * Platform-specific implementations designed to interface to platform
681 * shaping APIs such as Uniscribe or CoreText may rely on features of a
682 * specific font subclass to access native font references
683 * (such as CTFont, HFONT, DWriteFont, etc).
686 class gfxFontShaper {
687 public:
688 typedef mozilla::gfx::DrawTarget DrawTarget;
689 typedef mozilla::intl::Script Script;
691 enum class RoundingFlags : uint8_t { kRoundX = 0x01, kRoundY = 0x02 };
693 explicit gfxFontShaper(gfxFont* aFont) : mFont(aFont) {
694 NS_ASSERTION(aFont, "shaper requires a valid font!");
697 virtual ~gfxFontShaper() = default;
699 // Shape a piece of text and store the resulting glyph data into
700 // aShapedText. Parameters aOffset/aLength indicate the range of
701 // aShapedText to be updated; aLength is also the length of aText.
702 virtual bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
703 uint32_t aOffset, uint32_t aLength, Script aScript,
704 nsAtom* aLanguage, // may be null, indicating no
705 // lang-specific shaping to be
706 // applied
707 bool aVertical, RoundingFlags aRounding,
708 gfxShapedText* aShapedText) = 0;
710 gfxFont* GetFont() const { return mFont; }
712 static void MergeFontFeatures(
713 const gfxFontStyle* aStyle, const nsTArray<gfxFontFeature>& aFontFeatures,
714 bool aDisableLigatures, const nsACString& aFamilyName, bool aAddSmallCaps,
715 void (*aHandleFeature)(const uint32_t&, uint32_t&, void*),
716 void* aHandleFeatureData);
718 protected:
719 // the font this shaper is working with. The font owns a UniquePtr reference
720 // to this object, and will destroy it before it dies. Thus, mFont will always
721 // be valid.
722 gfxFont* MOZ_NON_OWNING_REF mFont;
725 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(gfxFontShaper::RoundingFlags)
728 * gfxShapedText is an abstract superclass for gfxShapedWord and gfxTextRun.
729 * These are objects that store a list of zero or more glyphs for each
730 * character. For each glyph we store the glyph ID, the advance, and possibly
731 * x/y-offsets. The idea is that a string is rendered by a loop that draws each
732 * glyph at its designated offset from the current point, then advances the
733 * current point by the glyph's advance in the direction of the textrun (LTR or
734 * RTL). Each glyph advance is always rounded to the nearest appunit; this
735 * ensures consistent results when dividing the text in a textrun into multiple
736 * text frames (frame boundaries are always aligned to appunits). We optimize
737 * for the case where a character has a single glyph and zero xoffset and
738 * yoffset, and the glyph ID and advance are in a reasonable range so we can
739 * pack all necessary data into 32 bits.
741 * gfxFontShaper can shape text into either a gfxShapedWord (cached by a
742 * gfxFont) or directly into a gfxTextRun (for cases where we want to shape
743 * textruns in their entirety rather than using cached words, because there may
744 * be layout features that depend on the inter-word spaces).
746 class gfxShapedText {
747 public:
748 typedef mozilla::intl::Script Script;
750 gfxShapedText(uint32_t aLength, mozilla::gfx::ShapedTextFlags aFlags,
751 uint16_t aAppUnitsPerDevUnit)
752 : mLength(aLength),
753 mFlags(aFlags),
754 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) {}
756 virtual ~gfxShapedText() = default;
759 * This class records the information associated with a character in the
760 * input string. It's optimized for the case where there is one glyph
761 * representing that character alone.
763 * A character can have zero or more associated glyphs. Each glyph
764 * has an advance width and an x and y offset.
765 * A character may be the start of a cluster.
766 * A character may be the start of a ligature group.
767 * A character can be "missing", indicating that the system is unable
768 * to render the character.
770 * All characters in a ligature group conceptually share all the glyphs
771 * associated with the characters in a group.
773 class CompressedGlyph {
774 public:
775 enum {
776 // Indicates that a cluster and ligature group starts at this
777 // character; this character has a single glyph with a reasonable
778 // advance and zero offsets. A "reasonable" advance
779 // is one that fits in the available bits (currently 12) (specified
780 // in appunits).
781 FLAG_IS_SIMPLE_GLYPH = 0x80000000U,
783 // These flags are applicable to both "simple" and "complex" records.
784 COMMON_FLAGS_MASK = 0x70000000U,
786 // Indicates whether a linebreak is allowed before this character;
787 // this is a two-bit field that holds a FLAG_BREAK_TYPE_xxx value
788 // indicating the kind of linebreak (if any) allowed here.
789 FLAGS_CAN_BREAK_BEFORE = 0x60000000U,
791 FLAGS_CAN_BREAK_SHIFT = 29,
792 FLAG_BREAK_TYPE_NONE = 0,
793 FLAG_BREAK_TYPE_NORMAL = 1,
794 FLAG_BREAK_TYPE_HYPHEN = 2,
796 FLAG_CHAR_IS_SPACE = 0x10000000U,
798 // Fields present only when FLAG_IS_SIMPLE_GLYPH is /true/.
799 // The advance is stored in appunits as a 12-bit field:
800 ADVANCE_MASK = 0x0FFF0000U,
801 ADVANCE_SHIFT = 16,
802 // and the glyph ID is stored in the low 16 bits.
803 GLYPH_MASK = 0x0000FFFFU,
805 // Fields present only when FLAG_IS_SIMPLE_GLYPH is /false/.
806 // Non-simple glyphs may or may not have glyph data in the
807 // corresponding mDetailedGlyphs entry. They have a glyph count
808 // stored in the low 16 bits, and the following flag bits:
809 GLYPH_COUNT_MASK = 0x0000FFFFU,
811 // When NOT set, indicates that this character corresponds to a
812 // missing glyph and should be skipped (or possibly, render the character
813 // Unicode value in some special way). If there are glyphs,
814 // the mGlyphID is actually the UTF16 character code. The bit is
815 // inverted so we can memset the array to zero to indicate all missing.
816 FLAG_NOT_MISSING = 0x010000,
817 FLAG_NOT_CLUSTER_START = 0x020000,
818 FLAG_NOT_LIGATURE_GROUP_START = 0x040000,
819 // Flag bit 0x080000 is currently unused.
821 // Certain types of characters are marked so that they can be given
822 // special treatment in rendering. This may require use of a "complex"
823 // CompressedGlyph record even for a character that would otherwise be
824 // treated as "simple".
825 CHAR_TYPE_FLAGS_MASK = 0xF00000,
826 FLAG_CHAR_IS_TAB = 0x100000,
827 FLAG_CHAR_IS_NEWLINE = 0x200000,
828 // Per CSS Text Decoration Module Level 3, emphasis marks are not
829 // drawn for any character in Unicode categories Z*, Cc, Cf, and Cn
830 // which is not combined with any combining characters. This flag is
831 // set for all those characters except 0x20 whitespace.
832 FLAG_CHAR_NO_EMPHASIS_MARK = 0x400000,
833 // Per CSS Text, letter-spacing is not applied to formatting chars
834 // (category Cf). We mark those in the textrun so as to be able to
835 // skip them when setting up spacing in nsTextFrame.
836 FLAG_CHAR_IS_FORMATTING_CONTROL = 0x800000,
838 // The bits 0x0F000000 are currently unused in non-simple glyphs.
841 // "Simple glyphs" have a simple glyph ID, simple advance and their
842 // x and y offsets are zero. Also the glyph extents do not overflow
843 // the font-box defined by the font ascent, descent and glyph advance width.
844 // These case is optimized to avoid storing DetailedGlyphs.
846 // Returns true if the glyph ID aGlyph fits into the compressed
847 // representation
848 static bool IsSimpleGlyphID(uint32_t aGlyph) {
849 return (aGlyph & GLYPH_MASK) == aGlyph;
851 // Returns true if the advance aAdvance fits into the compressed
852 // representation. aAdvance is in appunits.
853 static bool IsSimpleAdvance(uint32_t aAdvance) {
854 return (aAdvance & (ADVANCE_MASK >> ADVANCE_SHIFT)) == aAdvance;
857 bool IsSimpleGlyph() const { return mValue & FLAG_IS_SIMPLE_GLYPH; }
858 uint32_t GetSimpleAdvance() const {
859 MOZ_ASSERT(IsSimpleGlyph());
860 return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT;
862 uint32_t GetSimpleGlyph() const {
863 MOZ_ASSERT(IsSimpleGlyph());
864 return mValue & GLYPH_MASK;
867 bool IsMissing() const {
868 return !(mValue & (FLAG_NOT_MISSING | FLAG_IS_SIMPLE_GLYPH));
870 bool IsClusterStart() const {
871 return IsSimpleGlyph() || !(mValue & FLAG_NOT_CLUSTER_START);
873 bool IsLigatureGroupStart() const {
874 return IsSimpleGlyph() || !(mValue & FLAG_NOT_LIGATURE_GROUP_START);
876 bool IsLigatureContinuation() const {
877 return !IsSimpleGlyph() &&
878 (mValue & (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING)) ==
879 (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING);
882 // Return true if the original character was a normal (breakable,
883 // trimmable) space (U+0020). Not true for other characters that
884 // may happen to map to the space glyph (U+00A0).
885 bool CharIsSpace() const { return mValue & FLAG_CHAR_IS_SPACE; }
887 bool CharIsTab() const {
888 return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_TAB);
890 bool CharIsNewline() const {
891 return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_NEWLINE);
893 bool CharMayHaveEmphasisMark() const {
894 return !CharIsSpace() &&
895 (IsSimpleGlyph() || !(mValue & FLAG_CHAR_NO_EMPHASIS_MARK));
897 bool CharIsFormattingControl() const {
898 return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_FORMATTING_CONTROL);
901 uint32_t CharTypeFlags() const {
902 return IsSimpleGlyph() ? 0 : (mValue & CHAR_TYPE_FLAGS_MASK);
905 void SetClusterStart(bool aIsClusterStart) {
906 MOZ_ASSERT(!IsSimpleGlyph());
907 if (aIsClusterStart) {
908 mValue &= ~FLAG_NOT_CLUSTER_START;
909 } else {
910 mValue |= FLAG_NOT_CLUSTER_START;
914 uint8_t CanBreakBefore() const {
915 return (mValue & FLAGS_CAN_BREAK_BEFORE) >> FLAGS_CAN_BREAK_SHIFT;
917 // Returns FLAGS_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
918 uint32_t SetCanBreakBefore(uint8_t aCanBreakBefore) {
919 MOZ_ASSERT(aCanBreakBefore <= 2, "Bogus break-before value!");
920 uint32_t breakMask = (uint32_t(aCanBreakBefore) << FLAGS_CAN_BREAK_SHIFT);
921 uint32_t toggle = breakMask ^ (mValue & FLAGS_CAN_BREAK_BEFORE);
922 mValue ^= toggle;
923 return toggle;
926 // Create a CompressedGlyph value representing a simple glyph with
927 // no extra flags (line-break or is_space) set.
928 static CompressedGlyph MakeSimpleGlyph(uint32_t aAdvanceAppUnits,
929 uint32_t aGlyph) {
930 MOZ_ASSERT(IsSimpleAdvance(aAdvanceAppUnits));
931 MOZ_ASSERT(IsSimpleGlyphID(aGlyph));
932 CompressedGlyph g;
933 g.mValue =
934 FLAG_IS_SIMPLE_GLYPH | (aAdvanceAppUnits << ADVANCE_SHIFT) | aGlyph;
935 return g;
938 // Assign a simple glyph value to an existing CompressedGlyph record,
939 // preserving line-break/is-space flags if present.
940 CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits,
941 uint32_t aGlyph) {
942 MOZ_ASSERT(!CharTypeFlags(), "Char type flags lost");
943 mValue = (mValue & COMMON_FLAGS_MASK) |
944 MakeSimpleGlyph(aAdvanceAppUnits, aGlyph).mValue;
945 return *this;
948 // Create a CompressedGlyph value representing a complex glyph record,
949 // without any line-break or char-type flags.
950 static CompressedGlyph MakeComplex(bool aClusterStart,
951 bool aLigatureStart) {
952 CompressedGlyph g;
953 g.mValue = FLAG_NOT_MISSING |
954 (aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) |
955 (aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START);
956 return g;
959 // Assign a complex glyph value to an existing CompressedGlyph record,
960 // preserving line-break/char-type flags if present.
961 // This sets the glyphCount to zero; it will be updated when we call
962 // gfxShapedText::SetDetailedGlyphs.
963 CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart) {
964 mValue = (mValue & COMMON_FLAGS_MASK) | CharTypeFlags() |
965 MakeComplex(aClusterStart, aLigatureStart).mValue;
966 return *this;
970 * Mark a glyph record as being a missing-glyph.
971 * Missing glyphs are treated as ligature group starts; don't mess with
972 * the cluster-start flag (see bugs 618870 and 619286).
973 * We also preserve the glyph count here, as this is used after any
974 * required DetailedGlyphs (to store the char code for a hexbox) has been
975 * set up.
976 * This must be called *after* SetDetailedGlyphs is used for the relevant
977 * offset in the shaped-word, because that will mark it as not-missing.
979 CompressedGlyph& SetMissing() {
980 MOZ_ASSERT(!IsSimpleGlyph());
981 mValue &= ~(FLAG_NOT_MISSING | FLAG_NOT_LIGATURE_GROUP_START);
982 return *this;
985 uint32_t GetGlyphCount() const {
986 MOZ_ASSERT(!IsSimpleGlyph());
987 return mValue & GLYPH_COUNT_MASK;
989 void SetGlyphCount(uint32_t aGlyphCount) {
990 MOZ_ASSERT(!IsSimpleGlyph());
991 MOZ_ASSERT(GetGlyphCount() == 0, "Glyph count already set");
992 MOZ_ASSERT(aGlyphCount <= 0xffff, "Glyph count out of range");
993 mValue |= FLAG_NOT_MISSING | aGlyphCount;
996 void SetIsSpace() { mValue |= FLAG_CHAR_IS_SPACE; }
997 void SetIsTab() {
998 MOZ_ASSERT(!IsSimpleGlyph());
999 mValue |= FLAG_CHAR_IS_TAB;
1001 void SetIsNewline() {
1002 MOZ_ASSERT(!IsSimpleGlyph());
1003 mValue |= FLAG_CHAR_IS_NEWLINE;
1005 void SetNoEmphasisMark() {
1006 MOZ_ASSERT(!IsSimpleGlyph());
1007 mValue |= FLAG_CHAR_NO_EMPHASIS_MARK;
1009 void SetIsFormattingControl() {
1010 MOZ_ASSERT(!IsSimpleGlyph());
1011 mValue |= FLAG_CHAR_IS_FORMATTING_CONTROL;
1014 private:
1015 uint32_t mValue;
1018 // Accessor for the array of CompressedGlyph records, which will be in
1019 // a different place in gfxShapedWord vs gfxTextRun
1020 virtual const CompressedGlyph* GetCharacterGlyphs() const = 0;
1021 virtual CompressedGlyph* GetCharacterGlyphs() = 0;
1024 * When the glyphs for a character don't fit into a CompressedGlyph record
1025 * in SimpleGlyph format, we use an array of DetailedGlyphs instead.
1027 struct DetailedGlyph {
1028 // The glyphID, or the Unicode character if this is a missing glyph
1029 uint32_t mGlyphID;
1030 // The advance of the glyph, in appunits.
1031 // mAdvance is in the text direction (RTL or LTR),
1032 // and will normally be non-negative (although this is not guaranteed)
1033 int32_t mAdvance;
1034 // The offset from the glyph's default position, in line-relative
1035 // coordinates (so mOffset.x is an offset in the line-right direction,
1036 // and mOffset.y is an offset in line-downwards direction).
1037 // These values are in floating-point appUnits.
1038 mozilla::gfx::Point mOffset;
1041 // Store DetailedGlyph records for the given index. (This does not modify
1042 // the associated CompressedGlyph character-type or break flags.)
1043 void SetDetailedGlyphs(uint32_t aIndex, uint32_t aGlyphCount,
1044 const DetailedGlyph* aGlyphs);
1046 void SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont* aFont);
1048 void SetIsSpace(uint32_t aIndex) {
1049 GetCharacterGlyphs()[aIndex].SetIsSpace();
1052 bool HasDetailedGlyphs() const { return mDetailedGlyphs != nullptr; }
1054 bool IsLigatureGroupStart(uint32_t aPos) {
1055 NS_ASSERTION(aPos < GetLength(), "aPos out of range");
1056 return GetCharacterGlyphs()[aPos].IsLigatureGroupStart();
1059 // NOTE that this must not be called for a character offset that does
1060 // not have any DetailedGlyph records; callers must have verified that
1061 // GetCharacterGlyphs()[aCharIndex].GetGlyphCount() is greater than zero.
1062 DetailedGlyph* GetDetailedGlyphs(uint32_t aCharIndex) const {
1063 NS_ASSERTION(GetCharacterGlyphs() && HasDetailedGlyphs() &&
1064 !GetCharacterGlyphs()[aCharIndex].IsSimpleGlyph() &&
1065 GetCharacterGlyphs()[aCharIndex].GetGlyphCount() > 0,
1066 "invalid use of GetDetailedGlyphs; check the caller!");
1067 return mDetailedGlyphs->Get(aCharIndex);
1070 void AdjustAdvancesForSyntheticBold(float aSynBoldOffset, uint32_t aOffset,
1071 uint32_t aLength);
1073 // Mark clusters in the CompressedGlyph records, starting at aOffset,
1074 // based on the Unicode properties of the text in aString.
1075 // This is also responsible to set the IsSpace flag for space characters.
1076 void SetupClusterBoundaries(uint32_t aOffset, const char16_t* aString,
1077 uint32_t aLength);
1078 // In 8-bit text, there won't actually be any clusters, but we still need
1079 // the space-marking functionality.
1080 void SetupClusterBoundaries(uint32_t aOffset, const uint8_t* aString,
1081 uint32_t aLength);
1083 mozilla::gfx::ShapedTextFlags GetFlags() const { return mFlags; }
1085 bool IsVertical() const {
1086 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK) !=
1087 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_HORIZONTAL;
1090 bool UseCenterBaseline() const {
1091 mozilla::gfx::ShapedTextFlags orient =
1092 GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK;
1093 return orient ==
1094 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_MIXED ||
1095 orient ==
1096 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_UPRIGHT;
1099 bool IsRightToLeft() const {
1100 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_IS_RTL) ==
1101 mozilla::gfx::ShapedTextFlags::TEXT_IS_RTL;
1104 bool IsSidewaysLeft() const {
1105 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK) ==
1106 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT;
1109 // Return true if the logical inline direction is reversed compared to
1110 // normal physical coordinates (i.e. if it is leftwards or upwards)
1111 bool IsInlineReversed() const { return IsSidewaysLeft() != IsRightToLeft(); }
1113 gfxFloat GetDirection() const { return IsInlineReversed() ? -1.0f : 1.0f; }
1115 bool DisableLigatures() const {
1116 return (GetFlags() &
1117 mozilla::gfx::ShapedTextFlags::TEXT_DISABLE_OPTIONAL_LIGATURES) ==
1118 mozilla::gfx::ShapedTextFlags::TEXT_DISABLE_OPTIONAL_LIGATURES;
1121 bool TextIs8Bit() const {
1122 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT) ==
1123 mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT;
1126 int32_t GetAppUnitsPerDevUnit() const { return mAppUnitsPerDevUnit; }
1128 uint32_t GetLength() const { return mLength; }
1130 bool FilterIfIgnorable(uint32_t aIndex, uint32_t aCh);
1132 protected:
1133 // Allocate aCount DetailedGlyphs for the given index
1134 DetailedGlyph* AllocateDetailedGlyphs(uint32_t aCharIndex, uint32_t aCount);
1136 // Ensure the glyph on the given index is complex glyph so that we can use
1137 // it to record specific characters that layout may need to detect.
1138 void EnsureComplexGlyph(uint32_t aIndex, CompressedGlyph& aGlyph) {
1139 MOZ_ASSERT(GetCharacterGlyphs() + aIndex == &aGlyph);
1140 if (aGlyph.IsSimpleGlyph()) {
1141 DetailedGlyph details = {aGlyph.GetSimpleGlyph(),
1142 (int32_t)aGlyph.GetSimpleAdvance(),
1143 mozilla::gfx::Point()};
1144 aGlyph.SetComplex(true, true);
1145 SetDetailedGlyphs(aIndex, 1, &details);
1149 // For characters whose glyph data does not fit the "simple" glyph criteria
1150 // in CompressedGlyph, we use a sorted array to store the association
1151 // between the source character offset and an index into an array
1152 // DetailedGlyphs. The CompressedGlyph record includes a count of
1153 // the number of DetailedGlyph records that belong to the character,
1154 // starting at the given index.
1155 class DetailedGlyphStore {
1156 public:
1157 DetailedGlyphStore() = default;
1159 // This is optimized for the most common calling patterns:
1160 // we rarely need random access to the records, access is most commonly
1161 // sequential through the textRun, so we record the last-used index
1162 // and check whether the caller wants the same record again, or the
1163 // next; if not, it's most likely we're starting over from the start
1164 // of the run, so we check the first entry before resorting to binary
1165 // search as a last resort.
1166 // NOTE that this must not be called for a character offset that does
1167 // not have any DetailedGlyph records; callers must have verified that
1168 // mCharacterGlyphs[aOffset].GetGlyphCount() is greater than zero
1169 // before calling this, otherwise the assertions here will fire (in a
1170 // debug build), and we'll probably crash.
1171 DetailedGlyph* Get(uint32_t aOffset) {
1172 NS_ASSERTION(mOffsetToIndex.Length() > 0, "no detailed glyph records!");
1173 DetailedGlyph* details = mDetails.Elements();
1174 // check common cases (fwd iteration, initial entry, etc) first
1175 if (mLastUsed < mOffsetToIndex.Length() - 1 &&
1176 aOffset == mOffsetToIndex[mLastUsed + 1].mOffset) {
1177 ++mLastUsed;
1178 } else if (aOffset == mOffsetToIndex[0].mOffset) {
1179 mLastUsed = 0;
1180 } else if (aOffset == mOffsetToIndex[mLastUsed].mOffset) {
1181 // do nothing
1182 } else if (mLastUsed > 0 &&
1183 aOffset == mOffsetToIndex[mLastUsed - 1].mOffset) {
1184 --mLastUsed;
1185 } else {
1186 mLastUsed = mOffsetToIndex.BinaryIndexOf(aOffset, CompareToOffset());
1188 NS_ASSERTION(mLastUsed != nsTArray<DGRec>::NoIndex,
1189 "detailed glyph record missing!");
1190 return details + mOffsetToIndex[mLastUsed].mIndex;
1193 DetailedGlyph* Allocate(uint32_t aOffset, uint32_t aCount) {
1194 uint32_t detailIndex = mDetails.Length();
1195 DetailedGlyph* details = mDetails.AppendElements(aCount);
1196 // We normally set up glyph records sequentially, so the common case
1197 // here is to append new records to the mOffsetToIndex array;
1198 // test for that before falling back to the InsertElementSorted
1199 // method.
1200 if (mOffsetToIndex.Length() == 0 ||
1201 aOffset > mOffsetToIndex[mOffsetToIndex.Length() - 1].mOffset) {
1202 mOffsetToIndex.AppendElement(DGRec(aOffset, detailIndex));
1203 } else {
1204 mOffsetToIndex.InsertElementSorted(DGRec(aOffset, detailIndex),
1205 CompareRecordOffsets());
1207 return details;
1210 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
1211 return aMallocSizeOf(this) +
1212 mDetails.ShallowSizeOfExcludingThis(aMallocSizeOf) +
1213 mOffsetToIndex.ShallowSizeOfExcludingThis(aMallocSizeOf);
1216 private:
1217 struct DGRec {
1218 DGRec(const uint32_t& aOffset, const uint32_t& aIndex)
1219 : mOffset(aOffset), mIndex(aIndex) {}
1220 uint32_t mOffset; // source character offset in the textrun
1221 uint32_t mIndex; // index where this char's DetailedGlyphs begin
1224 struct CompareToOffset {
1225 bool Equals(const DGRec& a, const uint32_t& b) const {
1226 return a.mOffset == b;
1228 bool LessThan(const DGRec& a, const uint32_t& b) const {
1229 return a.mOffset < b;
1233 struct CompareRecordOffsets {
1234 bool Equals(const DGRec& a, const DGRec& b) const {
1235 return a.mOffset == b.mOffset;
1237 bool LessThan(const DGRec& a, const DGRec& b) const {
1238 return a.mOffset < b.mOffset;
1242 // Concatenated array of all the DetailedGlyph records needed for the
1243 // textRun; individual character offsets are associated with indexes
1244 // into this array via the mOffsetToIndex table.
1245 nsTArray<DetailedGlyph> mDetails;
1247 // For each character offset that needs DetailedGlyphs, we record the
1248 // index in mDetails where the list of glyphs begins. This array is
1249 // sorted by mOffset.
1250 nsTArray<DGRec> mOffsetToIndex;
1252 // Records the most recently used index into mOffsetToIndex, so that
1253 // we can support sequential access more quickly than just doing
1254 // a binary search each time.
1255 nsTArray<DGRec>::index_type mLastUsed = 0;
1258 mozilla::UniquePtr<DetailedGlyphStore> mDetailedGlyphs;
1260 // Number of char16_t characters and CompressedGlyph glyph records
1261 uint32_t mLength;
1263 // Shaping flags (direction, ligature-suppression)
1264 mozilla::gfx::ShapedTextFlags mFlags;
1266 uint16_t mAppUnitsPerDevUnit;
1270 * gfxShapedWord: an individual (space-delimited) run of text shaped with a
1271 * particular font, without regard to external context.
1273 * The glyph data is copied into gfxTextRuns as needed from the cache of
1274 * ShapedWords associated with each gfxFont instance.
1276 class gfxShapedWord final : public gfxShapedText {
1277 public:
1278 typedef mozilla::intl::Script Script;
1280 // Create a ShapedWord that can hold glyphs for aLength characters,
1281 // with mCharacterGlyphs sized appropriately.
1283 // Returns null on allocation failure (does NOT use infallible alloc)
1284 // so caller must check for success.
1286 // This does NOT perform shaping, so the returned word contains no
1287 // glyph data; the caller must call gfxFont::ShapeText() with appropriate
1288 // parameters to set up the glyphs.
1289 static gfxShapedWord* Create(const uint8_t* aText, uint32_t aLength,
1290 Script aRunScript, nsAtom* aLanguage,
1291 uint16_t aAppUnitsPerDevUnit,
1292 mozilla::gfx::ShapedTextFlags aFlags,
1293 gfxFontShaper::RoundingFlags aRounding) {
1294 NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
1295 "excessive length for gfxShapedWord!");
1297 // Compute size needed including the mCharacterGlyphs array
1298 // and a copy of the original text
1299 uint32_t size = offsetof(gfxShapedWord, mCharGlyphsStorage) +
1300 aLength * (sizeof(CompressedGlyph) + sizeof(uint8_t));
1301 void* storage = malloc(size);
1302 if (!storage) {
1303 return nullptr;
1306 // Construct in the pre-allocated storage, using placement new
1307 return new (storage) gfxShapedWord(aText, aLength, aRunScript, aLanguage,
1308 aAppUnitsPerDevUnit, aFlags, aRounding);
1311 static gfxShapedWord* Create(const char16_t* aText, uint32_t aLength,
1312 Script aRunScript, nsAtom* aLanguage,
1313 uint16_t aAppUnitsPerDevUnit,
1314 mozilla::gfx::ShapedTextFlags aFlags,
1315 gfxFontShaper::RoundingFlags aRounding) {
1316 NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
1317 "excessive length for gfxShapedWord!");
1319 // In the 16-bit version of Create, if the TEXT_IS_8BIT flag is set,
1320 // then we convert the text to an 8-bit version and call the 8-bit
1321 // Create function instead.
1322 if (aFlags & mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT) {
1323 nsAutoCString narrowText;
1324 LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength), narrowText);
1325 return Create((const uint8_t*)(narrowText.BeginReading()), aLength,
1326 aRunScript, aLanguage, aAppUnitsPerDevUnit, aFlags,
1327 aRounding);
1330 uint32_t size = offsetof(gfxShapedWord, mCharGlyphsStorage) +
1331 aLength * (sizeof(CompressedGlyph) + sizeof(char16_t));
1332 void* storage = malloc(size);
1333 if (!storage) {
1334 return nullptr;
1337 return new (storage) gfxShapedWord(aText, aLength, aRunScript, aLanguage,
1338 aAppUnitsPerDevUnit, aFlags, aRounding);
1341 // Override operator delete to properly free the object that was
1342 // allocated via malloc.
1343 void operator delete(void* p) { free(p); }
1345 const CompressedGlyph* GetCharacterGlyphs() const override {
1346 return &mCharGlyphsStorage[0];
1348 CompressedGlyph* GetCharacterGlyphs() override {
1349 return &mCharGlyphsStorage[0];
1352 const uint8_t* Text8Bit() const {
1353 NS_ASSERTION(TextIs8Bit(), "invalid use of Text8Bit()");
1354 return reinterpret_cast<const uint8_t*>(mCharGlyphsStorage + GetLength());
1357 const char16_t* TextUnicode() const {
1358 NS_ASSERTION(!TextIs8Bit(), "invalid use of TextUnicode()");
1359 return reinterpret_cast<const char16_t*>(mCharGlyphsStorage + GetLength());
1362 char16_t GetCharAt(uint32_t aOffset) const {
1363 NS_ASSERTION(aOffset < GetLength(), "aOffset out of range");
1364 return TextIs8Bit() ? char16_t(Text8Bit()[aOffset])
1365 : TextUnicode()[aOffset];
1368 Script GetScript() const { return mScript; }
1369 nsAtom* GetLanguage() const { return mLanguage.get(); }
1371 gfxFontShaper::RoundingFlags GetRounding() const { return mRounding; }
1373 void ResetAge() { mAgeCounter = 0; }
1374 uint32_t IncrementAge() { return ++mAgeCounter; }
1376 // Helper used when hashing a word for the shaped-word caches
1377 static uint32_t HashMix(uint32_t aHash, char16_t aCh) {
1378 return (aHash >> 28) ^ (aHash << 4) ^ aCh;
1381 private:
1382 // so that gfxTextRun can share our DetailedGlyphStore class
1383 friend class gfxTextRun;
1385 // Construct storage for a ShapedWord, ready to receive glyph data
1386 gfxShapedWord(const uint8_t* aText, uint32_t aLength, Script aRunScript,
1387 nsAtom* aLanguage, uint16_t aAppUnitsPerDevUnit,
1388 mozilla::gfx::ShapedTextFlags aFlags,
1389 gfxFontShaper::RoundingFlags aRounding)
1390 : gfxShapedText(aLength,
1391 aFlags | mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT,
1392 aAppUnitsPerDevUnit),
1393 mLanguage(aLanguage),
1394 mScript(aRunScript),
1395 mRounding(aRounding),
1396 mAgeCounter(0) {
1397 memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph));
1398 uint8_t* text = reinterpret_cast<uint8_t*>(&mCharGlyphsStorage[aLength]);
1399 memcpy(text, aText, aLength * sizeof(uint8_t));
1402 gfxShapedWord(const char16_t* aText, uint32_t aLength, Script aRunScript,
1403 nsAtom* aLanguage, uint16_t aAppUnitsPerDevUnit,
1404 mozilla::gfx::ShapedTextFlags aFlags,
1405 gfxFontShaper::RoundingFlags aRounding)
1406 : gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit),
1407 mLanguage(aLanguage),
1408 mScript(aRunScript),
1409 mRounding(aRounding),
1410 mAgeCounter(0) {
1411 memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph));
1412 char16_t* text = reinterpret_cast<char16_t*>(&mCharGlyphsStorage[aLength]);
1413 memcpy(text, aText, aLength * sizeof(char16_t));
1414 SetupClusterBoundaries(0, aText, aLength);
1417 RefPtr<nsAtom> mLanguage;
1418 Script mScript;
1420 gfxFontShaper::RoundingFlags mRounding;
1422 // With multithreaded shaping, this may be updated by any thread.
1423 std::atomic<uint32_t> mAgeCounter;
1425 // The mCharGlyphsStorage array is actually a variable-size member;
1426 // when the ShapedWord is created, its size will be increased as necessary
1427 // to allow the proper number of glyphs to be stored.
1428 // The original text, in either 8-bit or 16-bit form, will be stored
1429 // immediately following the CompressedGlyphs.
1430 CompressedGlyph mCharGlyphsStorage[1];
1433 class GlyphBufferAzure;
1434 struct TextRunDrawParams;
1435 struct FontDrawParams;
1436 struct EmphasisMarkDrawParams;
1438 class gfxFont {
1439 friend class gfxHarfBuzzShaper;
1440 friend class gfxGraphiteShaper;
1442 protected:
1443 using DrawTarget = mozilla::gfx::DrawTarget;
1444 using Script = mozilla::intl::Script;
1445 using SVGContextPaint = mozilla::SVGContextPaint;
1447 using RoundingFlags = gfxFontShaper::RoundingFlags;
1449 public:
1450 using FontSlantStyle = mozilla::FontSlantStyle;
1451 using FontSizeAdjust = mozilla::StyleFontSizeAdjust;
1453 nsrefcnt AddRef(void) {
1454 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
1455 nsExpirationState state;
1457 mozilla::AutoReadLock lock(mLock);
1458 state = mExpirationState;
1460 if (state.IsTracked()) {
1461 gfxFontCache::GetCache()->RemoveObject(this);
1463 ++mRefCnt;
1464 NS_LOG_ADDREF(this, mRefCnt, "gfxFont", sizeof(*this));
1465 return mRefCnt;
1467 nsrefcnt Release(void) {
1468 MOZ_ASSERT(0 != mRefCnt, "dup release");
1469 --mRefCnt;
1470 NS_LOG_RELEASE(this, mRefCnt, "gfxFont");
1471 nsrefcnt rval = mRefCnt;
1472 if (!rval) {
1473 NotifyReleased();
1474 // |this| may have been deleted.
1476 return rval;
1479 int32_t GetRefCount() { return int32_t(mRefCnt); }
1481 // options to specify the kind of AA to be used when creating a font
1482 typedef enum : uint8_t {
1483 kAntialiasDefault,
1484 kAntialiasNone,
1485 kAntialiasGrayscale,
1486 kAntialiasSubpixel
1487 } AntialiasOption;
1489 protected:
1490 mozilla::ThreadSafeAutoRefCnt mRefCnt;
1492 void NotifyReleased() {
1493 gfxFontCache* cache = gfxFontCache::GetCache();
1494 if (cache) {
1495 // Don't delete just yet; return the object to the cache for
1496 // possibly recycling within some time limit
1497 cache->NotifyReleased(this);
1498 } else {
1499 // The cache may have already been shut down.
1500 delete this;
1504 gfxFont(const RefPtr<mozilla::gfx::UnscaledFont>& aUnscaledFont,
1505 gfxFontEntry* aFontEntry, const gfxFontStyle* aFontStyle,
1506 AntialiasOption anAAOption = kAntialiasDefault);
1508 public:
1509 virtual ~gfxFont();
1511 bool Valid() const { return mIsValid; }
1513 // options for the kind of bounding box to return from measurement
1514 typedef enum {
1515 LOOSE_INK_EXTENTS,
1516 // A box that encloses all the painted pixels, and may
1517 // include sidebearings and/or additional ascent/descent
1518 // within the glyph cell even if the ink is smaller.
1519 TIGHT_INK_EXTENTS,
1520 // A box that tightly encloses all the painted pixels
1521 // (although actually on Windows, at least, it may be
1522 // slightly larger than strictly necessary because
1523 // we can't get precise extents with ClearType).
1524 TIGHT_HINTED_OUTLINE_EXTENTS
1525 // A box that tightly encloses the glyph outline,
1526 // ignoring possible antialiasing pixels that extend
1527 // beyond this.
1528 // NOTE: The default implementation of gfxFont::Measure(),
1529 // which works with the glyph extents cache, does not
1530 // differentiate between this and TIGHT_INK_EXTENTS.
1531 // Whether the distinction is important depends on the
1532 // antialiasing behavior of the platform; currently the
1533 // distinction is only implemented in the gfxWindowsFont
1534 // subclass, because of ClearType's tendency to paint
1535 // outside the hinted outline.
1536 // Also NOTE: it is relatively expensive to request this,
1537 // as it does not use cached glyph extents in the font.
1538 } BoundingBoxType;
1540 const nsCString& GetName() const { return mFontEntry->Name(); }
1541 const gfxFontStyle* GetStyle() const { return &mStyle; }
1543 virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption) const {
1544 // platforms where this actually matters should override
1545 return nullptr;
1548 gfxFloat GetAdjustedSize() const {
1549 // mAdjustedSize is cached here if not already set to a non-zero value;
1550 // but it may be overridden by a value computed in metrics initialization
1551 // from font-size-adjust.
1552 if (mAdjustedSize < 0.0) {
1553 mAdjustedSize = mStyle.AdjustedSizeMustBeZero()
1554 ? 0.0
1555 : mStyle.size * mFontEntry->mSizeAdjust;
1557 return mAdjustedSize;
1560 float FUnitsToDevUnitsFactor() const {
1561 // check this was set up during font initialization
1562 NS_ASSERTION(mFUnitsConvFactor >= 0.0f, "mFUnitsConvFactor not valid");
1563 return mFUnitsConvFactor;
1566 // check whether this is an sfnt we can potentially use with harfbuzz
1567 bool FontCanSupportHarfBuzz() const { return mFontEntry->HasCmapTable(); }
1569 // check whether this is an sfnt we can potentially use with Graphite
1570 bool FontCanSupportGraphite() const {
1571 return mFontEntry->HasGraphiteTables();
1574 // Whether this is a font that may be doing full-color rendering,
1575 // and therefore needs us to use a mask for text-shadow even when
1576 // we're not actually blurring.
1577 bool AlwaysNeedsMaskForShadow() const {
1578 return mFontEntry->TryGetColorGlyphs() || mFontEntry->TryGetSVGData(this) ||
1579 mFontEntry->HasFontTable(TRUETYPE_TAG('C', 'B', 'D', 'T')) ||
1580 mFontEntry->HasFontTable(TRUETYPE_TAG('s', 'b', 'i', 'x'));
1583 // whether a feature is supported by the font (limited to a small set
1584 // of features for which some form of fallback needs to be implemented)
1585 bool SupportsFeature(Script aScript, uint32_t aFeatureTag);
1587 // whether the font supports "real" small caps, petite caps etc.
1588 // aFallbackToSmallCaps true when petite caps should fallback to small caps
1589 bool SupportsVariantCaps(Script aScript, uint32_t aVariantCaps,
1590 bool& aFallbackToSmallCaps,
1591 bool& aSyntheticLowerToSmallCaps,
1592 bool& aSyntheticUpperToSmallCaps);
1594 // whether the font supports subscript/superscript feature
1595 // for fallback, need to verify that all characters in the run
1596 // have variant substitutions
1597 bool SupportsSubSuperscript(uint32_t aSubSuperscript, const uint8_t* aString,
1598 uint32_t aLength, Script aRunScript);
1600 bool SupportsSubSuperscript(uint32_t aSubSuperscript, const char16_t* aString,
1601 uint32_t aLength, Script aRunScript);
1603 // whether the specified feature will apply to the given character
1604 bool FeatureWillHandleChar(Script aRunScript, uint32_t aFeature,
1605 uint32_t aUnicode);
1607 // Subclasses may choose to look up glyph ids for characters.
1608 // If they do not override this, gfxHarfBuzzShaper will fetch the cmap
1609 // table and use that.
1610 virtual bool ProvidesGetGlyph() const { return false; }
1611 // Map unicode character to glyph ID.
1612 // Only used if ProvidesGetGlyph() returns true.
1613 virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector) {
1614 return 0;
1617 // Return the advance of a glyph.
1618 gfxFloat GetGlyphAdvance(uint16_t aGID, bool aVertical = false);
1620 // Return the advance of a given Unicode char in isolation.
1621 // Returns -1.0 if the char is not supported.
1622 gfxFloat GetCharAdvance(uint32_t aUnicode, bool aVertical = false);
1624 gfxFloat SynthesizeSpaceWidth(uint32_t aCh);
1626 // Work out whether cairo will snap inter-glyph spacing to pixels
1627 // when rendering to the given drawTarget.
1628 RoundingFlags GetRoundOffsetsToPixels(DrawTarget* aDrawTarget);
1630 virtual bool ShouldHintMetrics() const { return true; }
1631 virtual bool ShouldRoundXOffset(cairo_t* aCairo) const { return true; }
1633 // Return the font's owned harfbuzz shaper, creating and initializing it if
1634 // necessary; returns null if shaper initialization has failed.
1635 gfxHarfBuzzShaper* GetHarfBuzzShaper();
1637 // Font metrics
1638 struct Metrics {
1639 gfxFloat capHeight;
1640 gfxFloat xHeight;
1641 gfxFloat strikeoutSize;
1642 gfxFloat strikeoutOffset;
1643 gfxFloat underlineSize;
1644 gfxFloat underlineOffset;
1646 gfxFloat internalLeading;
1647 gfxFloat externalLeading;
1649 gfxFloat emHeight;
1650 gfxFloat emAscent;
1651 gfxFloat emDescent;
1652 gfxFloat maxHeight;
1653 gfxFloat maxAscent;
1654 gfxFloat maxDescent;
1655 gfxFloat maxAdvance;
1657 gfxFloat aveCharWidth;
1658 gfxFloat spaceWidth;
1659 gfxFloat zeroWidth; // -1 if there was no zero glyph
1660 gfxFloat ideographicWidth; // -1 if kWaterIdeograph is not supported
1662 gfxFloat ZeroOrAveCharWidth() const {
1663 return zeroWidth >= 0 ? zeroWidth : aveCharWidth;
1666 // Unicode character used as basis for 'ic' unit:
1667 static constexpr uint32_t kWaterIdeograph = 0x6C34;
1669 typedef nsFontMetrics::FontOrientation Orientation;
1671 const Metrics& GetMetrics(Orientation aOrientation) {
1672 if (aOrientation == nsFontMetrics::eHorizontal) {
1673 return GetHorizontalMetrics();
1675 if (!mVerticalMetrics) {
1676 CreateVerticalMetrics();
1678 return *mVerticalMetrics;
1682 * We let layout specify spacing on either side of any
1683 * character. We need to specify both before and after
1684 * spacing so that substring measurement can do the right things.
1685 * These values are in appunits. They're always an integral number of
1686 * appunits, but we specify them in floats in case very large spacing
1687 * values are required.
1689 struct Spacing {
1690 gfxFloat mBefore;
1691 gfxFloat mAfter;
1694 * Metrics for a particular string
1696 struct RunMetrics {
1697 RunMetrics() { mAdvanceWidth = mAscent = mDescent = 0.0; }
1699 void CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft);
1701 // can be negative (partly due to negative spacing).
1702 // Advance widths should be additive: the advance width of the
1703 // (offset1, length1) plus the advance width of (offset1 + length1,
1704 // length2) should be the advance width of (offset1, length1 + length2)
1705 gfxFloat mAdvanceWidth;
1707 // For zero-width substrings, these must be zero!
1708 gfxFloat mAscent; // always non-negative
1709 gfxFloat mDescent; // always non-negative
1711 // Bounding box that is guaranteed to include everything drawn.
1712 // If a tight boundingBox was requested when these metrics were
1713 // generated, this will tightly wrap the glyphs, otherwise it is
1714 // "loose" and may be larger than the true bounding box.
1715 // Coordinates are relative to the baseline left origin, so typically
1716 // mBoundingBox.y == -mAscent
1717 gfxRect mBoundingBox;
1721 * Draw a series of glyphs to aContext. The direction of aTextRun must
1722 * be honoured.
1723 * @param aStart the first character to draw
1724 * @param aEnd draw characters up to here
1725 * @param aPt the baseline origin; the left end of the baseline
1726 * for LTR textruns, the right end for RTL textruns.
1727 * On return, this will be updated to the other end of the baseline.
1728 * In application units, really!
1729 * @param aRunParams record with drawing parameters, see TextRunDrawParams.
1730 * Particular fields of interest include
1731 * .spacing spacing to insert before and after characters (for RTL
1732 * glyphs, before-spacing is inserted to the right of characters). There
1733 * are aEnd - aStart elements in this array, unless it's null to indicate
1734 * that there is no spacing.
1735 * .drawMode specifies whether the fill or stroke of the glyph should be
1736 * drawn, or if it should be drawn into the current path
1737 * .contextPaint information about how to construct the fill and
1738 * stroke pattern. Can be nullptr if we are not stroking the text, which
1739 * indicates that the current source from context should be used for fill
1740 * .context the Thebes graphics context to which we're drawing
1741 * .dt Moz2D DrawTarget to which we're drawing
1743 * Callers guarantee:
1744 * -- aStart and aEnd are aligned to cluster and ligature boundaries
1745 * -- all glyphs use this font
1747 void Draw(const gfxTextRun* aTextRun, uint32_t aStart, uint32_t aEnd,
1748 mozilla::gfx::Point* aPt, const TextRunDrawParams& aRunParams,
1749 mozilla::gfx::ShapedTextFlags aOrientation);
1752 * Draw the emphasis marks for the given text run. Its prerequisite
1753 * and output are similiar to the method Draw().
1754 * @param aPt the baseline origin of the emphasis marks.
1755 * @param aParams some drawing parameters, see EmphasisMarkDrawParams.
1757 void DrawEmphasisMarks(const gfxTextRun* aShapedText,
1758 mozilla::gfx::Point* aPt, uint32_t aOffset,
1759 uint32_t aCount,
1760 const EmphasisMarkDrawParams& aParams);
1763 * Measure a run of characters. See gfxTextRun::Metrics.
1764 * @param aTight if false, then return the union of the glyph extents
1765 * with the font-box for the characters (the rectangle with x=0,width=
1766 * the advance width for the character run,y=-(font ascent), and height=
1767 * font ascent + font descent). Otherwise, we must return as tight as possible
1768 * an approximation to the area actually painted by glyphs.
1769 * @param aDrawTargetForTightBoundingBox when aTight is true, this must
1770 * be non-null.
1771 * @param aSpacing spacing to insert before and after glyphs. The bounding box
1772 * need not include the spacing itself, but the spacing affects the glyph
1773 * positions. null if there is no spacing.
1775 * Callers guarantee:
1776 * -- aStart and aEnd are aligned to cluster and ligature boundaries
1777 * -- all glyphs use this font
1779 * The default implementation just uses font metrics and aTextRun's
1780 * advances, and assumes no characters fall outside the font box. In
1781 * general this is insufficient, because that assumption is not always true.
1783 virtual RunMetrics Measure(const gfxTextRun* aTextRun, uint32_t aStart,
1784 uint32_t aEnd, BoundingBoxType aBoundingBoxType,
1785 DrawTarget* aDrawTargetForTightBoundingBox,
1786 Spacing* aSpacing,
1787 mozilla::gfx::ShapedTextFlags aOrientation);
1789 * Line breaks have been changed at the beginning and/or end of a substring
1790 * of the text. Reshaping may be required; glyph updating is permitted.
1791 * @return true if anything was changed, false otherwise
1793 bool NotifyLineBreaksChanged(gfxTextRun* aTextRun, uint32_t aStart,
1794 uint32_t aLength) {
1795 return false;
1798 // Expiration tracking
1799 nsExpirationState* GetExpirationState() { return &mExpirationState; }
1801 // Get the glyphID of a space
1802 uint16_t GetSpaceGlyph() const { return mSpaceGlyph; }
1804 gfxGlyphExtents* GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit);
1806 void SetupGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphID,
1807 bool aNeedTight, gfxGlyphExtents* aExtents);
1809 virtual bool AllowSubpixelAA() const { return true; }
1811 bool ApplySyntheticBold() const { return mApplySyntheticBold; }
1813 float AngleForSyntheticOblique() const;
1814 float SkewForSyntheticOblique() const;
1816 // Amount by which synthetic bold "fattens" the glyphs:
1817 // For size S up to a threshold size T, we use (0.25 + 3S / 4T),
1818 // so that the result ranges from 0.25 to 1.0; thereafter,
1819 // simply use (S / T).
1820 gfxFloat GetSyntheticBoldOffset() const {
1821 gfxFloat size = GetAdjustedSize();
1822 const gfxFloat threshold = 48.0;
1823 return size < threshold ? (0.25 + 0.75 * size / threshold)
1824 : (size / threshold);
1827 gfxFontEntry* GetFontEntry() const { return mFontEntry.get(); }
1828 bool HasCharacter(uint32_t ch) const {
1829 if (!mIsValid || (mUnicodeRangeMap && !mUnicodeRangeMap->test(ch))) {
1830 return false;
1832 return mFontEntry->HasCharacter(ch);
1835 const gfxCharacterMap* GetUnicodeRangeMap() const {
1836 return mUnicodeRangeMap.get();
1839 void SetUnicodeRangeMap(gfxCharacterMap* aUnicodeRangeMap) {
1840 mUnicodeRangeMap = aUnicodeRangeMap;
1843 uint16_t GetUVSGlyph(uint32_t aCh, uint32_t aVS) const {
1844 if (!mIsValid) {
1845 return 0;
1847 return mFontEntry->GetUVSGlyph(aCh, aVS);
1850 template <typename T>
1851 bool InitFakeSmallCapsRun(nsPresContext* aPresContext,
1852 DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
1853 const T* aText, uint32_t aOffset, uint32_t aLength,
1854 FontMatchType aMatchType,
1855 mozilla::gfx::ShapedTextFlags aOrientation,
1856 Script aScript, nsAtom* aLanguage,
1857 bool aSyntheticLower, bool aSyntheticUpper);
1859 // call the (virtual) InitTextRun method to do glyph generation/shaping,
1860 // limiting the length of text passed by processing the run in multiple
1861 // segments if necessary
1862 template <typename T>
1863 bool SplitAndInitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
1864 const T* aString, uint32_t aRunStart,
1865 uint32_t aRunLength, Script aRunScript,
1866 nsAtom* aLanguage,
1867 mozilla::gfx::ShapedTextFlags aOrientation);
1869 // Get a ShapedWord representing the given text (either 8- or 16-bit)
1870 // for use in setting up a gfxTextRun.
1871 template <typename T>
1872 gfxShapedWord* GetShapedWord(DrawTarget* aDrawTarget, const T* aText,
1873 uint32_t aLength, uint32_t aHash,
1874 Script aRunScript, nsAtom* aLanguage,
1875 bool aVertical, int32_t aAppUnitsPerDevUnit,
1876 mozilla::gfx::ShapedTextFlags aFlags,
1877 RoundingFlags aRounding,
1878 gfxTextPerfMetrics* aTextPerf);
1880 // Ensure the ShapedWord cache is initialized. This MUST be called before
1881 // any attempt to use GetShapedWord().
1882 void InitWordCache() {
1883 mLock.ReadLock();
1884 if (!mWordCache) {
1885 mLock.ReadUnlock();
1886 mozilla::AutoWriteLock lock(mLock);
1887 if (!mWordCache) {
1888 mWordCache = mozilla::MakeUnique<nsTHashtable<CacheHashEntry>>();
1890 } else {
1891 mLock.ReadUnlock();
1895 // Called by the gfxFontCache timer to increment the age of all the words,
1896 // so that they'll expire after a sufficient period of non-use.
1897 // Returns true if the cache is now empty, otherwise false.
1898 bool AgeCachedWords();
1900 // Discard all cached word records; called on memory-pressure notification.
1901 void ClearCachedWords() {
1902 mozilla::AutoWriteLock lock(mLock);
1903 if (mWordCache) {
1904 mWordCache->Clear();
1908 // Glyph rendering/geometry has changed, so invalidate data as necessary.
1909 void NotifyGlyphsChanged() const;
1911 virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
1912 FontCacheSizes* aSizes) const;
1913 virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
1914 FontCacheSizes* aSizes) const;
1916 typedef enum {
1917 FONT_TYPE_DWRITE,
1918 FONT_TYPE_GDI,
1919 FONT_TYPE_FT2,
1920 FONT_TYPE_MAC,
1921 FONT_TYPE_OS2,
1922 FONT_TYPE_CAIRO,
1923 FONT_TYPE_FONTCONFIG
1924 } FontType;
1926 virtual FontType GetType() const = 0;
1928 const RefPtr<mozilla::gfx::UnscaledFont>& GetUnscaledFont() const {
1929 return mUnscaledFont;
1932 virtual already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFont(
1933 const TextRunDrawParams& aRunParams) = 0;
1934 already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFont(
1935 mozilla::gfx::DrawTarget* aDrawTarget);
1937 // gfxFont implementations may cache ScaledFont versions other than the
1938 // default, so InitializeScaledFont must support explicitly specifying
1939 // which ScaledFonts to initialize.
1940 void InitializeScaledFont(
1941 const RefPtr<mozilla::gfx::ScaledFont>& aScaledFont);
1943 bool KerningDisabled() const { return mKerningSet && !mKerningEnabled; }
1946 * Subclass this object to be notified of glyph changes. Delete the object
1947 * when no longer needed.
1949 class GlyphChangeObserver {
1950 public:
1951 virtual ~GlyphChangeObserver() {
1952 if (mFont) {
1953 mFont->RemoveGlyphChangeObserver(this);
1956 // This gets called when the gfxFont dies.
1957 void ForgetFont() { mFont = nullptr; }
1958 virtual void NotifyGlyphsChanged() = 0;
1960 protected:
1961 explicit GlyphChangeObserver(gfxFont* aFont) : mFont(aFont) {
1962 mFont->AddGlyphChangeObserver(this);
1964 // This pointer is nulled by ForgetFont in the gfxFont's
1965 // destructor. Before the gfxFont dies.
1966 gfxFont* MOZ_NON_OWNING_REF mFont;
1968 friend class GlyphChangeObserver;
1970 bool GlyphsMayChange() const {
1971 // Currently only fonts with SVG glyphs can have animated glyphs
1972 return mFontEntry->TryGetSVGData(this);
1975 static void DestroySingletons() {
1976 delete sScriptTagToCode;
1977 delete sDefaultFeatures;
1980 // Call TryGetMathTable() to try and load the Open Type MATH table.
1981 // If (and ONLY if) TryGetMathTable() has returned true, the MathTable()
1982 // method may be called to access the gfxMathTable data.
1983 bool TryGetMathTable();
1984 gfxMathTable* MathTable() const {
1985 MOZ_RELEASE_ASSERT(mMathTable,
1986 "A successful call to TryGetMathTable() must be "
1987 "performed before calling this function");
1988 return mMathTable;
1991 // Return a cloned font resized and offset to simulate sub/superscript
1992 // glyphs. This does not add a reference to the returned font.
1993 gfxFont* GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) const;
1995 bool HasColorGlyphFor(uint32_t aCh, uint32_t aNextCh);
1997 protected:
1998 virtual const Metrics& GetHorizontalMetrics() const = 0;
2000 void CreateVerticalMetrics();
2002 // Template parameters for DrawGlyphs/DrawOneGlyph, used to select
2003 // simplified versions of the methods in the most common cases.
2004 enum class FontComplexityT { SimpleFont, ComplexFont };
2005 enum class SpacingT { NoSpacing, HasSpacing };
2007 // Output a run of glyphs at *aPt, which is updated to follow the last glyph
2008 // in the run. This method also takes account of any letter-spacing provided
2009 // in aRunParams.
2010 template <FontComplexityT FC, SpacingT S>
2011 bool DrawGlyphs(const gfxShapedText* aShapedText,
2012 uint32_t aOffset, // offset in the textrun
2013 uint32_t aCount, // length of run to draw
2014 mozilla::gfx::Point* aPt,
2015 // transform for mOffset field in DetailedGlyph records,
2016 // to account for rotations (may be null)
2017 const mozilla::gfx::Matrix* aOffsetMatrix,
2018 GlyphBufferAzure& aBuffer);
2020 // Output a single glyph at *aPt.
2021 // Normal glyphs are simply accumulated in aBuffer until it is full and
2022 // gets flushed, but SVG or color-font glyphs will instead be rendered
2023 // directly to the destination (found from the buffer's parameters).
2024 template <FontComplexityT FC>
2025 void DrawOneGlyph(uint32_t aGlyphID, const mozilla::gfx::Point& aPt,
2026 GlyphBufferAzure& aBuffer, bool* aEmittedGlyphs);
2028 // Helper for DrawOneGlyph to handle missing glyphs, rendering either
2029 // nothing (for default-ignorables) or a missing-glyph hexbox.
2030 bool DrawMissingGlyph(const TextRunDrawParams& aRunParams,
2031 const FontDrawParams& aFontParams,
2032 const gfxShapedText::DetailedGlyph* aDetails,
2033 const mozilla::gfx::Point& aPt);
2035 // set the font size and offset used for
2036 // synthetic subscript/superscript glyphs
2037 void CalculateSubSuperSizeAndOffset(int32_t aAppUnitsPerDevPixel,
2038 gfxFloat& aSubSuperSizeRatio,
2039 float& aBaselineOffset);
2041 // Return a font that is a "clone" of this one, but reduced to 80% size
2042 // (and with variantCaps set to normal). This does not add a reference to
2043 // the returned font.
2044 gfxFont* GetSmallCapsFont() const;
2046 // subclasses may provide (possibly hinted) glyph widths (in font units);
2047 // if they do not override this, harfbuzz will use unhinted widths
2048 // derived from the font tables
2049 virtual bool ProvidesGlyphWidths() const { return false; }
2051 // The return value is interpreted as a horizontal advance in 16.16 fixed
2052 // point format.
2053 virtual int32_t GetGlyphWidth(uint16_t aGID) { return -1; }
2055 virtual bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds,
2056 bool aTight = false) const {
2057 return false;
2060 bool IsSpaceGlyphInvisible(DrawTarget* aRefDrawTarget,
2061 const gfxTextRun* aTextRun);
2063 void AddGlyphChangeObserver(GlyphChangeObserver* aObserver);
2064 void RemoveGlyphChangeObserver(GlyphChangeObserver* aObserver);
2066 // whether font contains substitution lookups containing spaces
2067 bool HasSubstitutionRulesWithSpaceLookups(Script aRunScript) const;
2069 // do spaces participate in shaping rules? if so, can't used word cache
2070 // Note that this function uses HasGraphiteSpaceContextuals, so it can only
2071 // return a "hint" to the correct answer. The calling code must ensure it
2072 // performs safe actions independent of the value returned.
2073 tainted_boolean_hint SpaceMayParticipateInShaping(Script aRunScript) const;
2075 // For 8-bit text, expand to 16-bit and then call the following method.
2076 bool ShapeText(DrawTarget* aContext, const uint8_t* aText,
2077 uint32_t aOffset, // dest offset in gfxShapedText
2078 uint32_t aLength, Script aScript, nsAtom* aLanguage,
2079 bool aVertical, RoundingFlags aRounding,
2080 gfxShapedText* aShapedText); // where to store the result
2082 // Call the appropriate shaper to generate glyphs for aText and store
2083 // them into aShapedText.
2084 virtual bool ShapeText(DrawTarget* aContext, const char16_t* aText,
2085 uint32_t aOffset, uint32_t aLength, Script aScript,
2086 nsAtom* aLanguage, bool aVertical,
2087 RoundingFlags aRounding, gfxShapedText* aShapedText);
2089 // Helper to adjust for synthetic bold and set character-type flags
2090 // in the shaped text; implementations of ShapeText should call this
2091 // after glyph shaping has been completed.
2092 void PostShapingFixup(DrawTarget* aContext, const char16_t* aText,
2093 uint32_t aOffset, // position within aShapedText
2094 uint32_t aLength, bool aVertical,
2095 gfxShapedText* aShapedText);
2097 // Shape text directly into a range within a textrun, without using the
2098 // font's word cache. Intended for use when the font has layout features
2099 // that involve space, and therefore require shaping complete runs rather
2100 // than isolated words, or for long strings that are inefficient to cache.
2101 // This will split the text on "invalid" characters (tab/newline) that are
2102 // not handled via normal shaping, but does not otherwise divide up the
2103 // text.
2104 template <typename T>
2105 bool ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText,
2106 uint32_t aOffset, uint32_t aLength,
2107 Script aScript, nsAtom* aLanguage,
2108 bool aVertical, RoundingFlags aRounding,
2109 gfxTextRun* aTextRun);
2111 // Shape a fragment of text (a run that is known to contain only
2112 // "valid" characters, no newlines/tabs/other control chars).
2113 // All non-wordcache shaping goes through here; this is the function
2114 // that will ensure we don't pass excessively long runs to the various
2115 // platform shapers.
2116 template <typename T>
2117 bool ShapeFragmentWithoutWordCache(DrawTarget* aDrawTarget, const T* aText,
2118 uint32_t aOffset, uint32_t aLength,
2119 Script aScript, nsAtom* aLanguage,
2120 bool aVertical, RoundingFlags aRounding,
2121 gfxTextRun* aTextRun);
2123 void CheckForFeaturesInvolvingSpace() const;
2125 // whether a given feature is included in feature settings from both the
2126 // font and the style. aFeatureOn set if resolved feature value is non-zero
2127 bool HasFeatureSet(uint32_t aFeature, bool& aFeatureOn);
2129 // used when analyzing whether a font has space contextual lookups
2130 static nsTHashMap<nsUint32HashKey, Script>* sScriptTagToCode;
2131 static nsTHashSet<uint32_t>* sDefaultFeatures;
2133 RefPtr<gfxFontEntry> mFontEntry;
2134 mozilla::RWLock mLock;
2136 struct CacheHashKey {
2137 union {
2138 const uint8_t* mSingle;
2139 const char16_t* mDouble;
2140 } mText;
2141 uint32_t mLength;
2142 mozilla::gfx::ShapedTextFlags mFlags;
2143 Script mScript;
2144 RefPtr<nsAtom> mLanguage;
2145 int32_t mAppUnitsPerDevUnit;
2146 PLDHashNumber mHashKey;
2147 bool mTextIs8Bit;
2148 RoundingFlags mRounding;
2150 CacheHashKey(const uint8_t* aText, uint32_t aLength, uint32_t aStringHash,
2151 Script aScriptCode, nsAtom* aLanguage,
2152 int32_t aAppUnitsPerDevUnit,
2153 mozilla::gfx::ShapedTextFlags aFlags, RoundingFlags aRounding)
2154 : mLength(aLength),
2155 mFlags(aFlags),
2156 mScript(aScriptCode),
2157 mLanguage(aLanguage),
2158 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
2159 mHashKey(aStringHash + static_cast<int32_t>(aScriptCode) +
2160 aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 +
2161 int(aRounding) + (aLanguage ? aLanguage->hash() : 0)),
2162 mTextIs8Bit(true),
2163 mRounding(aRounding) {
2164 NS_ASSERTION(aFlags & mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT,
2165 "8-bit flag should have been set");
2166 mText.mSingle = aText;
2169 CacheHashKey(const char16_t* aText, uint32_t aLength, uint32_t aStringHash,
2170 Script aScriptCode, nsAtom* aLanguage,
2171 int32_t aAppUnitsPerDevUnit,
2172 mozilla::gfx::ShapedTextFlags aFlags, RoundingFlags aRounding)
2173 : mLength(aLength),
2174 mFlags(aFlags),
2175 mScript(aScriptCode),
2176 mLanguage(aLanguage),
2177 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
2178 mHashKey(aStringHash + static_cast<int32_t>(aScriptCode) +
2179 aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 +
2180 int(aRounding)),
2181 mTextIs8Bit(false),
2182 mRounding(aRounding) {
2183 // We can NOT assert that TEXT_IS_8BIT is false in aFlags here,
2184 // because this might be an 8bit-only word from a 16-bit textrun,
2185 // in which case the text we're passed is still in 16-bit form,
2186 // and we'll have to use an 8-to-16bit comparison in KeyEquals.
2187 mText.mDouble = aText;
2191 class CacheHashEntry : public PLDHashEntryHdr {
2192 public:
2193 typedef const CacheHashKey& KeyType;
2194 typedef const CacheHashKey* KeyTypePointer;
2196 // When constructing a new entry in the hashtable, the caller of Put()
2197 // will fill us in.
2198 explicit CacheHashEntry(KeyTypePointer aKey) {}
2199 CacheHashEntry(const CacheHashEntry&) = delete;
2200 CacheHashEntry& operator=(const CacheHashEntry&) = delete;
2201 CacheHashEntry(CacheHashEntry&&) = default;
2202 CacheHashEntry& operator=(CacheHashEntry&&) = default;
2204 bool KeyEquals(const KeyTypePointer aKey) const;
2206 static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
2208 static PLDHashNumber HashKey(const KeyTypePointer aKey) {
2209 return aKey->mHashKey;
2212 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
2213 return aMallocSizeOf(mShapedWord.get());
2216 enum { ALLOW_MEMMOVE = true };
2218 mozilla::UniquePtr<gfxShapedWord> mShapedWord;
2221 mozilla::UniquePtr<nsTHashtable<CacheHashEntry>> mWordCache GUARDED_BY(mLock);
2223 static const uint32_t kShapedWordCacheMaxAge = 3;
2225 nsTArray<mozilla::UniquePtr<gfxGlyphExtents>> mGlyphExtentsArray
2226 GUARDED_BY(mLock);
2227 mozilla::UniquePtr<nsTHashSet<GlyphChangeObserver*>> mGlyphChangeObservers
2228 GUARDED_BY(mLock);
2230 // a copy of the font without antialiasing, if needed for separate
2231 // measurement by mathml code
2232 mozilla::Atomic<gfxFont*> mNonAAFont;
2234 // we create either or both of these shapers when needed, depending
2235 // whether the font has graphite tables, and whether graphite shaping
2236 // is actually enabled
2237 mozilla::Atomic<gfxHarfBuzzShaper*> mHarfBuzzShaper;
2238 mozilla::Atomic<gfxGraphiteShaper*> mGraphiteShaper;
2240 // If a userfont with unicode-range specified, contains map of *possible*
2241 // ranges supported by font. This is set during user-font initialization,
2242 // before the font is available to other threads, and thereafter is inert
2243 // so no guard is needed.
2244 RefPtr<gfxCharacterMap> mUnicodeRangeMap;
2246 RefPtr<mozilla::gfx::UnscaledFont> mUnscaledFont GUARDED_BY(mLock);
2248 mozilla::Atomic<mozilla::gfx::ScaledFont*> mAzureScaledFont;
2250 // For vertical metrics, created on demand.
2251 mozilla::Atomic<Metrics*> mVerticalMetrics;
2253 // Table used for MathML layout.
2254 mozilla::Atomic<gfxMathTable*> mMathTable;
2256 gfxFontStyle mStyle;
2257 mutable gfxFloat mAdjustedSize;
2259 // Conversion factor from font units to dev units; note that this may be
2260 // zero (in the degenerate case where mAdjustedSize has become zero).
2261 // This is OK because we only multiply by this factor, never divide.
2262 float mFUnitsConvFactor;
2264 nsExpirationState mExpirationState GUARDED_BY(mLock);
2266 // Glyph ID of the font's <space> glyph, zero if missing
2267 uint16_t mSpaceGlyph = 0;
2269 // the AA setting requested for this font - may affect glyph bounds
2270 AntialiasOption mAntialiasOption;
2272 bool mIsValid;
2274 // use synthetic bolding for environments where this is not supported
2275 // by the platform
2276 bool mApplySyntheticBold;
2278 bool mKerningSet; // kerning explicitly set?
2279 bool mKerningEnabled; // if set, on or off?
2281 mozilla::Atomic<bool> mMathInitialized; // TryGetMathTable() called?
2283 // Helper for subclasses that want to initialize standard metrics from the
2284 // tables of sfnt (TrueType/OpenType) fonts.
2285 // This will use mFUnitsConvFactor if it is already set, else compute it
2286 // from mAdjustedSize and the unitsPerEm in the font's 'head' table.
2287 // Returns TRUE and sets mIsValid=TRUE if successful;
2288 // Returns TRUE but leaves mIsValid=FALSE if the font seems to be broken.
2289 // Returns FALSE if the font does not appear to be an sfnt at all,
2290 // and should be handled (if possible) using other APIs.
2291 bool InitMetricsFromSfntTables(Metrics& aMetrics);
2293 // Helper to calculate various derived metrics from the results of
2294 // InitMetricsFromSfntTables or equivalent platform code
2295 void CalculateDerivedMetrics(Metrics& aMetrics);
2297 // some fonts have bad metrics, this method sanitize them.
2298 // if this font has bad underline offset, aIsBadUnderlineFont should be true.
2299 void SanitizeMetrics(Metrics* aMetrics, bool aIsBadUnderlineFont);
2301 bool RenderSVGGlyph(gfxContext* aContext,
2302 mozilla::layout::TextDrawTarget* aTextDrawer,
2303 mozilla::gfx::Point aPoint, uint32_t aGlyphId,
2304 SVGContextPaint* aContextPaint) const;
2305 bool RenderSVGGlyph(gfxContext* aContext,
2306 mozilla::layout::TextDrawTarget* aTextDrawer,
2307 mozilla::gfx::Point aPoint, uint32_t aGlyphId,
2308 SVGContextPaint* aContextPaint,
2309 gfxTextRunDrawCallbacks* aCallbacks,
2310 bool& aEmittedGlyphs) const;
2312 bool RenderColorGlyph(DrawTarget* aDrawTarget, gfxContext* aContext,
2313 mozilla::layout::TextDrawTarget* aTextDrawer,
2314 mozilla::gfx::ScaledFont* scaledFont,
2315 mozilla::gfx::DrawOptions drawOptions,
2316 const mozilla::gfx::Point& aPoint,
2317 uint32_t aGlyphId) const;
2319 // Bug 674909. When synthetic bolding text by drawing twice, need to
2320 // render using a pixel offset in device pixels, otherwise text
2321 // doesn't appear bolded, it appears as if a bad text shadow exists
2322 // when a non-identity transform exists. Use an offset factor so that
2323 // the second draw occurs at a constant offset in device pixels.
2324 // This helper calculates the scale factor we need to apply to the
2325 // synthetic-bold offset.
2326 static mozilla::gfx::Float CalcXScale(DrawTarget* aDrawTarget);
2329 // proportion of ascent used for x-height, if unable to read value from font
2330 #define DEFAULT_XHEIGHT_FACTOR 0.56f
2332 // Parameters passed to gfxFont methods for drawing glyphs from a textrun.
2333 // The TextRunDrawParams are set up once per textrun; the FontDrawParams
2334 // are dependent on the specific font, so they are set per GlyphRun.
2336 struct MOZ_STACK_CLASS TextRunDrawParams {
2337 RefPtr<mozilla::gfx::DrawTarget> dt;
2338 gfxContext* context = nullptr;
2339 gfxFont::Spacing* spacing = nullptr;
2340 gfxTextRunDrawCallbacks* callbacks = nullptr;
2341 mozilla::SVGContextPaint* runContextPaint = nullptr;
2342 mozilla::gfx::Float direction = 1.0f;
2343 double devPerApp = 1.0;
2344 nscolor textStrokeColor = 0;
2345 gfxPattern* textStrokePattern = nullptr;
2346 const mozilla::gfx::StrokeOptions* strokeOpts = nullptr;
2347 const mozilla::gfx::DrawOptions* drawOpts = nullptr;
2348 DrawMode drawMode = DrawMode::GLYPH_FILL;
2349 bool isVerticalRun = false;
2350 bool isRTL = false;
2351 bool paintSVGGlyphs = true;
2352 bool allowGDI = true;
2355 struct MOZ_STACK_CLASS FontDrawParams {
2356 RefPtr<mozilla::gfx::ScaledFont> scaledFont;
2357 mozilla::SVGContextPaint* contextPaint;
2358 mozilla::gfx::Float synBoldOnePixelOffset;
2359 mozilla::gfx::Float obliqueSkew;
2360 int32_t extraStrikes;
2361 mozilla::gfx::DrawOptions drawOptions;
2362 gfxFloat advanceDirection;
2363 bool isVerticalFont;
2364 bool haveSVGGlyphs;
2365 bool haveColorGlyphs;
2368 struct MOZ_STACK_CLASS EmphasisMarkDrawParams {
2369 gfxContext* context;
2370 gfxFont::Spacing* spacing;
2371 gfxTextRun* mark;
2372 gfxFloat advance;
2373 gfxFloat direction;
2374 bool isVertical;
2377 #endif