Bug 1932613 - temporarily disable browser_ml_end_to_end.js for permanent failures...
[gecko.git] / gfx / thebes / gfxFont.h
blob4b0da03abe8d3bc208b954bac6d23d705f79721e
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 <functional>
13 #include "PLDHashTable.h"
14 #include "ThebesRLBoxTypes.h"
15 #include "gfxFontVariations.h"
16 #include "gfxRect.h"
17 #include "gfxTypes.h"
18 #include "mozilla/AlreadyAddRefed.h"
19 #include "mozilla/Attributes.h"
20 #include "mozilla/FontPropertyTypes.h"
21 #include "mozilla/HashTable.h"
22 #include "mozilla/MemoryReporting.h"
23 #include "mozilla/MruCache.h"
24 #include "mozilla/Mutex.h"
25 #include "mozilla/RefPtr.h"
26 #include "mozilla/RWLock.h"
27 #include "mozilla/TypedEnumBits.h"
28 #include "mozilla/UniquePtr.h"
29 #include "mozilla/gfx/FontPaletteCache.h"
30 #include "mozilla/gfx/MatrixFwd.h"
31 #include "mozilla/gfx/Point.h"
32 #include "mozilla/gfx/2D.h"
33 #include "mozilla/intl/UnicodeScriptCodes.h"
34 #include "nsCOMPtr.h"
35 #include "nsColor.h"
36 #include "nsTHashMap.h"
37 #include "nsTHashSet.h"
38 #include "nsExpirationTracker.h"
39 #include "nsFontMetrics.h"
40 #include "nsHashKeys.h"
41 #include "nsIMemoryReporter.h"
42 #include "nsIObserver.h"
43 #include "nsISupports.h"
44 #include "nsString.h"
45 #include "nsTArray.h"
46 #include "nsTHashtable.h"
47 #include "nscore.h"
48 #include "DrawMode.h"
50 // Only required for function bodies
51 #include "gfxFontEntry.h"
52 #include "gfxFontFeatures.h"
54 class gfxContext;
55 class gfxGraphiteShaper;
56 class gfxHarfBuzzShaper;
57 class gfxGlyphExtents;
58 class gfxMathTable;
59 class gfxPattern;
60 class gfxShapedText;
61 class gfxShapedWord;
62 class gfxSkipChars;
63 class gfxTextRun;
64 class nsIEventTarget;
65 class nsITimer;
66 struct gfxTextRunDrawCallbacks;
68 namespace mozilla {
69 class SVGContextPaint;
70 namespace layout {
71 class TextDrawTarget;
73 } // namespace mozilla
75 typedef struct _cairo cairo_t;
76 typedef struct _cairo_scaled_font cairo_scaled_font_t;
78 #define FONT_MAX_SIZE 2000.0
80 #define SMALL_CAPS_SCALE_FACTOR 0.8
82 // The skew factor used for synthetic-italic [oblique] fonts;
83 // we use a platform-dependent value to harmonize with the platform's own APIs.
84 #ifdef XP_WIN
85 # define OBLIQUE_SKEW_FACTOR 0.3f
86 #elif defined(MOZ_WIDGET_GTK)
87 # define OBLIQUE_SKEW_FACTOR 0.2f
88 #else
89 # define OBLIQUE_SKEW_FACTOR 0.25f
90 #endif
92 struct gfxFontStyle {
93 using FontStretch = mozilla::FontStretch;
94 using FontSlantStyle = mozilla::FontSlantStyle;
95 using FontWeight = mozilla::FontWeight;
96 using FontSizeAdjust = mozilla::StyleFontSizeAdjust;
98 gfxFontStyle();
99 gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight, FontStretch aStretch,
100 gfxFloat aSize, const FontSizeAdjust& aSizeAdjust,
101 bool aSystemFont, bool aPrinterFont,
102 #ifdef XP_WIN
103 bool aAllowForceGDIClassic,
104 #endif
105 bool aWeightSynthesis, bool aStyleSynthesis,
106 bool aSmallCapsSynthesis, bool aPositionSynthesis,
107 mozilla::StyleFontLanguageOverride aLanguageOverride);
108 // Features are composed of (1) features from style rules (2) features
109 // from feature settings rules and (3) family-specific features. (1) and
110 // (3) are guaranteed to be mutually exclusive
112 // custom opentype feature settings
113 CopyableTArray<gfxFontFeature> featureSettings;
115 // Some font-variant property values require font-specific settings
116 // defined via @font-feature-values rules. These are resolved after
117 // font matching occurs.
119 // -- list of value tags for specific alternate features
120 mozilla::StyleFontVariantAlternates variantAlternates;
122 // -- object used to look these up once the font is matched
123 RefPtr<gfxFontFeatureValueSet> featureValueLookup;
125 // opentype variation settings
126 CopyableTArray<gfxFontVariation> variationSettings;
128 // The logical size of the font, in pixels
129 gfxFloat size;
131 // The optical size value to apply (if supported); negative means none.
132 float autoOpticalSize = -1.0f;
134 // The aspect-value (ie., the ratio actualsize:actualxheight) that any
135 // actual physical font created from this font structure must have when
136 // rendering or measuring a string. A value of -1.0 means no adjustment
137 // needs to be done; otherwise the value must be nonnegative.
138 float sizeAdjust;
140 // baseline offset, used when simulating sub/superscript glyphs
141 float baselineOffset;
143 // Language system tag, to override document language;
144 // an OpenType "language system" tag represented as a 32-bit integer
145 // (see http://www.microsoft.com/typography/otspec/languagetags.htm).
146 // Normally 0, so font rendering will use the document or element language
147 // (see above) to control any language-specific rendering, but the author
148 // can override this for cases where the options implemented in the font
149 // do not directly match the actual language. (E.g. lang may be Macedonian,
150 // but the font in use does not explicitly support this; the author can
151 // use font-language-override to request the Serbian option in the font
152 // in order to get correct glyph shapes.)
153 mozilla::StyleFontLanguageOverride languageOverride;
155 // The Font{Weight,Stretch,SlantStyle} fields are each a 16-bit type.
157 // The weight of the font: 100, 200, ... 900.
158 FontWeight weight;
160 // The stretch of the font
161 FontStretch stretch;
163 // The style of font
164 FontSlantStyle style;
166 // Whether face-selection properties weight/style/stretch are all 'normal'
167 bool IsNormalStyle() const {
168 return weight.IsNormal() && style.IsNormal() && stretch.IsNormal();
171 // We pack these three small-integer fields into a single byte to avoid
172 // overflowing an 8-byte boundary [in a 64-bit build] and ending up with
173 // 7 bytes of padding at the end of the struct.
175 // caps variant (small-caps, petite-caps, etc.)
176 uint8_t variantCaps : 3; // uses range 0..6
178 // sub/superscript variant
179 uint8_t variantSubSuper : 2; // uses range 0..2
181 // font metric used as basis of font-size-adjust
182 uint8_t sizeAdjustBasis : 3; // uses range 0..4
184 // Say that this font is a system font and therefore does not
185 // require certain fixup that we do for fonts from untrusted
186 // sources.
187 bool systemFont : 1;
189 // Say that this font is used for print or print preview.
190 bool printerFont : 1;
192 #ifdef XP_WIN
193 bool allowForceGDIClassic : 1;
194 #endif
196 // Used to imitate -webkit-font-smoothing: antialiased
197 bool useGrayscaleAntialiasing : 1;
199 // Whether synthetic styles are allowed (required, in the case of position)
200 bool allowSyntheticWeight : 1;
201 bool allowSyntheticStyle : 1;
202 bool allowSyntheticSmallCaps : 1;
203 bool useSyntheticPosition : 1;
205 // some variant features require fallback which complicates the shaping
206 // code, so set up a bool to indicate when shaping with fallback is needed
207 bool noFallbackVariantFeatures : 1;
209 // Return the final adjusted font size for the given aspect ratio.
210 // Not meant to be called when sizeAdjustBasis is NONE.
211 gfxFloat GetAdjustedSize(gfxFloat aspect) const {
212 MOZ_ASSERT(
213 FontSizeAdjust::Tag(sizeAdjustBasis) != FontSizeAdjust::Tag::None,
214 "Not meant to be called when sizeAdjustBasis is none");
215 gfxFloat adjustedSize =
216 std::max(NS_round(size * (sizeAdjust / aspect)), 1.0);
217 return std::min(adjustedSize, FONT_MAX_SIZE);
220 // Some callers want to take a short-circuit path if they can be sure the
221 // adjusted size will be zero.
222 bool AdjustedSizeMustBeZero() const {
223 return size == 0.0 ||
224 (FontSizeAdjust::Tag(sizeAdjustBasis) != FontSizeAdjust::Tag::None &&
225 sizeAdjust == 0.0);
228 PLDHashNumber Hash() const;
230 // Adjust this style to simulate sub/superscript (as requested in the
231 // variantSubSuper field) using size and baselineOffset instead.
232 void AdjustForSubSuperscript(int32_t aAppUnitsPerDevPixel);
234 // Should this style cause the given font entry to use synthetic bold?
235 bool NeedsSyntheticBold(gfxFontEntry* aFontEntry) const {
236 return weight.IsBold() && allowSyntheticWeight &&
237 !aFontEntry->SupportsBold();
240 bool Equals(const gfxFontStyle& other) const {
241 return mozilla::NumbersAreBitwiseIdentical(size, other.size) &&
242 (style == other.style) && (weight == other.weight) &&
243 (stretch == other.stretch) && (variantCaps == other.variantCaps) &&
244 (variantSubSuper == other.variantSubSuper) &&
245 (allowSyntheticWeight == other.allowSyntheticWeight) &&
246 (allowSyntheticStyle == other.allowSyntheticStyle) &&
247 (allowSyntheticSmallCaps == other.allowSyntheticSmallCaps) &&
248 (useSyntheticPosition == other.useSyntheticPosition) &&
249 (systemFont == other.systemFont) &&
250 (printerFont == other.printerFont) &&
251 #ifdef XP_WIN
252 (allowForceGDIClassic == other.allowForceGDIClassic) &&
253 #endif
254 (useGrayscaleAntialiasing == other.useGrayscaleAntialiasing) &&
255 (baselineOffset == other.baselineOffset) &&
256 mozilla::NumbersAreBitwiseIdentical(sizeAdjust, other.sizeAdjust) &&
257 (sizeAdjustBasis == other.sizeAdjustBasis) &&
258 (featureSettings == other.featureSettings) &&
259 (variantAlternates == other.variantAlternates) &&
260 (featureValueLookup == other.featureValueLookup) &&
261 (variationSettings == other.variationSettings) &&
262 (languageOverride == other.languageOverride) &&
263 mozilla::NumbersAreBitwiseIdentical(autoOpticalSize,
264 other.autoOpticalSize);
269 * Font cache design:
271 * The mFonts hashtable contains most fonts, indexed by (gfxFontEntry*, style).
272 * It maintains a strong reference to the fonts it contains.
273 * Whenever a font is accessed, it is marked as used to move it to a new
274 * generation in the tracker to avoid expiration.
275 * The expiration tracker will only expire fonts with a single reference, the
276 * cache itself. Fonts with more than one reference are marked as used.
278 * We're using 3 generations with a ten-second generation interval, so
279 * zero-refcount fonts will be deleted 20-30 seconds after their refcount
280 * goes to zero, if timer events fire in a timely manner.
282 * The font cache also handles timed expiration of cached ShapedWords
283 * for "persistent" fonts: it has a repeating timer, and notifies
284 * each cached font to "age" its shaped words. The words will be released
285 * by the fonts if they get aged three times without being re-used in the
286 * meantime.
288 * Note that the ShapedWord timeout is much larger than the font timeout,
289 * so that in the case of a short-lived font, we'll discard the gfxFont
290 * completely, with all its words, and avoid the cost of aging the words
291 * individually. That only happens with longer-lived fonts.
293 struct FontCacheSizes {
294 FontCacheSizes() : mFontInstances(0), mShapedWords(0) {}
296 size_t mFontInstances; // memory used by instances of gfxFont subclasses
297 size_t mShapedWords; // memory used by the per-font shapedWord caches
300 class gfxFontCache final
301 : public ExpirationTrackerImpl<gfxFont, 3, mozilla::Mutex,
302 mozilla::MutexAutoLock> {
303 protected:
304 // Expiration tracker implementation.
305 enum { FONT_TIMEOUT_SECONDS = 10 };
307 typedef mozilla::Mutex Lock;
308 typedef mozilla::MutexAutoLock AutoLock;
310 // This protects the ExpirationTracker tables.
311 Lock mMutex = Lock("fontCacheExpirationMutex");
313 Lock& GetMutex() override { return mMutex; }
315 public:
316 explicit gfxFontCache(nsIEventTarget* aEventTarget);
317 ~gfxFontCache();
319 enum { SHAPED_WORD_TIMEOUT_SECONDS = 60 };
322 * Get the global gfxFontCache. You must call Init() before
323 * calling this method --- the result will not be null.
325 static gfxFontCache* GetCache() { return gGlobalCache; }
327 static nsresult Init();
328 // It's OK to call this even if Init() has not been called.
329 static void Shutdown();
331 // Look up a font in the cache. Returns null if there's nothing matching
332 // in the cache
333 already_AddRefed<gfxFont> Lookup(const gfxFontEntry* aFontEntry,
334 const gfxFontStyle* aStyle,
335 const gfxCharacterMap* aUnicodeRangeMap);
337 // We created a new font (presumably because Lookup returned null);
338 // put it in the cache. The font's refcount should be nonzero. It is
339 // allowable to add a new font even if there is one already in the
340 // cache with the same key, as we may race with other threads to do
341 // the insertion -- in that case we will return the original font,
342 // and destroy the new one.
343 already_AddRefed<gfxFont> MaybeInsert(gfxFont* aFont);
345 bool MaybeDestroy(gfxFont* aFont);
347 // Cleans out the hashtable and removes expired fonts waiting for cleanup.
348 // Other gfxFont objects may be still in use but they will be pushed
349 // into the expiration queues and removed.
350 void Flush();
352 void FlushShapedWordCaches();
353 void NotifyGlyphsChanged();
355 void AgeCachedWords();
357 void RunWordCacheExpirationTimer() {
358 if (!mTimerRunning) {
359 mozilla::MutexAutoLock lock(mMutex);
360 if (!mTimerRunning && mWordCacheExpirationTimer) {
361 mWordCacheExpirationTimer->InitWithNamedFuncCallback(
362 WordCacheExpirationTimerCallback, this,
363 SHAPED_WORD_TIMEOUT_SECONDS * 1000, nsITimer::TYPE_REPEATING_SLACK,
364 "gfxFontCache::WordCacheExpiration");
365 mTimerRunning = true;
369 void PauseWordCacheExpirationTimer() {
370 if (mTimerRunning) {
371 mozilla::MutexAutoLock lock(mMutex);
372 if (mTimerRunning && mWordCacheExpirationTimer) {
373 mWordCacheExpirationTimer->Cancel();
374 mTimerRunning = false;
379 void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
380 FontCacheSizes* aSizes) const;
381 void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
382 FontCacheSizes* aSizes) const;
384 protected:
385 class MemoryReporter final : public nsIMemoryReporter {
386 ~MemoryReporter() = default;
388 public:
389 NS_DECL_ISUPPORTS
390 NS_DECL_NSIMEMORYREPORTER
393 // Observer for notifications that the font cache cares about
394 class Observer final : public nsIObserver {
395 ~Observer() = default;
397 public:
398 NS_DECL_ISUPPORTS
399 NS_DECL_NSIOBSERVER
402 nsresult AddObject(gfxFont* aFont) {
403 AutoLock lock(mMutex);
404 return AddObjectLocked(aFont, lock);
407 // This gets called when the timeout has expired on a single-refcount
408 // font; we just delete it.
409 void NotifyExpiredLocked(gfxFont* aFont, const AutoLock&)
410 MOZ_REQUIRES(mMutex) override;
411 void NotifyHandlerEnd() override;
413 void DestroyDiscard(nsTArray<gfxFont*>& aDiscard);
415 static gfxFontCache* gGlobalCache;
417 struct MOZ_STACK_CLASS Key {
418 const gfxFontEntry* mFontEntry;
419 const gfxFontStyle* mStyle;
420 const gfxCharacterMap* mUnicodeRangeMap;
421 Key(const gfxFontEntry* aFontEntry, const gfxFontStyle* aStyle,
422 const gfxCharacterMap* aUnicodeRangeMap)
423 : mFontEntry(aFontEntry),
424 mStyle(aStyle),
425 mUnicodeRangeMap(aUnicodeRangeMap) {}
428 class HashEntry : public PLDHashEntryHdr {
429 public:
430 typedef const Key& KeyType;
431 typedef const Key* KeyTypePointer;
433 // When constructing a new entry in the hashtable, we'll leave this
434 // blank. The caller of Put() will fill this in.
435 explicit HashEntry(KeyTypePointer aStr) {}
437 bool KeyEquals(const KeyTypePointer aKey) const;
438 static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
439 static PLDHashNumber HashKey(const KeyTypePointer aKey) {
440 return mozilla::HashGeneric(aKey->mStyle->Hash(), aKey->mFontEntry,
441 aKey->mUnicodeRangeMap);
443 enum { ALLOW_MEMMOVE = true };
445 gfxFont* MOZ_UNSAFE_REF("tracking for deferred deletion") mFont = nullptr;
448 nsTHashtable<HashEntry> mFonts MOZ_GUARDED_BY(mMutex);
450 nsTArray<gfxFont*> mTrackerDiscard MOZ_GUARDED_BY(mMutex);
452 static void WordCacheExpirationTimerCallback(nsITimer* aTimer, void* aCache);
454 nsCOMPtr<nsITimer> mWordCacheExpirationTimer MOZ_GUARDED_BY(mMutex);
455 std::atomic<bool> mTimerRunning = false;
458 class gfxTextPerfMetrics {
459 public:
460 struct TextCounts {
461 uint32_t numContentTextRuns;
462 uint32_t numChromeTextRuns;
463 uint32_t numChars;
464 uint32_t maxTextRunLen;
465 uint32_t wordCacheSpaceRules;
466 uint32_t wordCacheLong;
467 uint32_t wordCacheHit;
468 uint32_t wordCacheMiss;
469 uint32_t fallbackPrefs;
470 uint32_t fallbackSystem;
471 uint32_t textrunConst;
472 uint32_t textrunDestr;
473 uint32_t genericLookups;
476 uint32_t reflowCount;
478 // counts per reflow operation
479 TextCounts current;
481 // totals for the lifetime of a document
482 TextCounts cumulative;
484 gfxTextPerfMetrics() { memset(this, 0, sizeof(gfxTextPerfMetrics)); }
486 // add current totals to cumulative ones
487 void Accumulate() {
488 if (current.numChars == 0) {
489 return;
491 cumulative.numContentTextRuns += current.numContentTextRuns;
492 cumulative.numChromeTextRuns += current.numChromeTextRuns;
493 cumulative.numChars += current.numChars;
494 if (current.maxTextRunLen > cumulative.maxTextRunLen) {
495 cumulative.maxTextRunLen = current.maxTextRunLen;
497 cumulative.wordCacheSpaceRules += current.wordCacheSpaceRules;
498 cumulative.wordCacheLong += current.wordCacheLong;
499 cumulative.wordCacheHit += current.wordCacheHit;
500 cumulative.wordCacheMiss += current.wordCacheMiss;
501 cumulative.fallbackPrefs += current.fallbackPrefs;
502 cumulative.fallbackSystem += current.fallbackSystem;
503 cumulative.textrunConst += current.textrunConst;
504 cumulative.textrunDestr += current.textrunDestr;
505 cumulative.genericLookups += current.genericLookups;
506 memset(&current, 0, sizeof(current));
510 namespace mozilla {
511 namespace gfx {
513 class UnscaledFont;
515 // Flags that live in the gfxShapedText::mFlags field.
516 // (Note that gfxTextRun has an additional mFlags2 field for use
517 // by textrun clients like nsTextFrame.)
519 // If you add a flag, please add support for it in gfxTextRun::Dump.
520 enum class ShapedTextFlags : uint16_t {
522 * When set, the text is RTL.
524 TEXT_IS_RTL = 0x0001,
526 * When set, spacing is enabled and the textrun needs to call GetSpacing
527 * on the spacing provider.
529 TEXT_ENABLE_SPACING = 0x0002,
531 * When set, the text has no characters above 255 and it is stored
532 * in the textrun in 8-bit format.
534 TEXT_IS_8BIT = 0x0004,
536 * When set, GetHyphenationBreaks may return true for some character
537 * positions, otherwise it will always return false for all characters.
539 TEXT_ENABLE_HYPHEN_BREAKS = 0x0008,
541 * When set, the RunMetrics::mBoundingBox field will be initialized
542 * properly based on glyph extents, in particular, glyph extents that
543 * overflow the standard font-box (the box defined by the ascent, descent
544 * and advance width of the glyph). When not set, it may just be the
545 * standard font-box even if glyphs overflow.
547 TEXT_NEED_BOUNDING_BOX = 0x0010,
549 * When set, optional ligatures are disabled. Ligatures that are
550 * required for legible text should still be enabled.
552 TEXT_DISABLE_OPTIONAL_LIGATURES = 0x0020,
554 * When set, the textrun should favour speed of construction over
555 * quality. This may involve disabling ligatures and/or kerning or
556 * other effects.
558 TEXT_OPTIMIZE_SPEED = 0x0040,
560 * When set, the textrun should discard control characters instead of
561 * turning them into hexboxes.
563 TEXT_HIDE_CONTROL_CHARACTERS = 0x0080,
566 * nsTextFrameThebes sets these, but they're defined here rather than
567 * in nsTextFrameUtils.h because ShapedWord creation/caching also needs
568 * to check the _INCOMING flag
570 TEXT_TRAILING_ARABICCHAR = 0x0100,
572 * When set, the previous character for this textrun was an Arabic
573 * character. This is used for the context detection necessary for
574 * bidi.numeral implementation.
576 TEXT_INCOMING_ARABICCHAR = 0x0200,
579 * Set if the textrun should use the OpenType 'math' script.
581 TEXT_USE_MATH_SCRIPT = 0x0400,
584 * Bit 0x0800 is currently unused.
588 * Field for orientation of the textrun and glyphs within it.
589 * Possible values of the TEXT_ORIENT_MASK field:
590 * TEXT_ORIENT_HORIZONTAL
591 * TEXT_ORIENT_VERTICAL_UPRIGHT
592 * TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT
593 * TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT
594 * TEXT_ORIENT_VERTICAL_MIXED
595 * For all VERTICAL settings, the x and y coordinates of glyph
596 * positions are exchanged, so that simple advances are vertical.
598 * The MIXED value indicates vertical textRuns for which the CSS
599 * text-orientation property is 'mixed', but is never used for
600 * individual glyphRuns; it will be resolved to either UPRIGHT
601 * or SIDEWAYS_RIGHT according to the UTR50 properties of the
602 * characters, and separate glyphRuns created for the resulting
603 * glyph orientations.
605 TEXT_ORIENT_MASK = 0x7000,
606 TEXT_ORIENT_HORIZONTAL = 0x0000,
607 TEXT_ORIENT_VERTICAL_UPRIGHT = 0x1000,
608 TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT = 0x2000,
609 TEXT_ORIENT_VERTICAL_MIXED = 0x3000,
610 TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT = 0x4000,
613 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ShapedTextFlags)
614 } // namespace gfx
615 } // namespace mozilla
617 class gfxTextRunFactory {
618 // Used by stylo
619 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxTextRunFactory)
621 public:
622 typedef mozilla::gfx::DrawTarget DrawTarget;
625 * This record contains all the parameters needed to initialize a textrun.
627 struct MOZ_STACK_CLASS Parameters {
628 // Shape text params suggesting where the textrun will be rendered
629 DrawTarget* mDrawTarget;
630 // Pointer to arbitrary user data (which should outlive the textrun)
631 void* mUserData;
632 // A description of which characters have been stripped from the original
633 // DOM string to produce the characters in the textrun. May be null
634 // if that information is not relevant.
635 gfxSkipChars* mSkipChars;
636 // A list of where linebreaks are currently placed in the textrun. May
637 // be null if mInitialBreakCount is zero.
638 uint32_t* mInitialBreaks;
639 uint32_t mInitialBreakCount;
640 // The ratio to use to convert device pixels to application layout units
641 int32_t mAppUnitsPerDevUnit;
644 protected:
645 // Protected destructor, to discourage deletion outside of Release():
646 virtual ~gfxTextRunFactory();
650 * gfxFontShaper
652 * This class implements text shaping (character to glyph mapping and
653 * glyph layout). There is a gfxFontShaper subclass for each text layout
654 * technology (uniscribe, core text, harfbuzz,....) we support.
656 * The shaper is responsible for setting up glyph data in gfxTextRuns.
658 * A generic, platform-independent shaper relies only on the standard
659 * gfxFont interface and can work with any concrete subclass of gfxFont.
661 * Platform-specific implementations designed to interface to platform
662 * shaping APIs such as Uniscribe or CoreText may rely on features of a
663 * specific font subclass to access native font references
664 * (such as CTFont, HFONT, DWriteFont, etc).
667 class gfxFontShaper {
668 public:
669 typedef mozilla::gfx::DrawTarget DrawTarget;
670 typedef mozilla::intl::Script Script;
672 enum class RoundingFlags : uint8_t { kRoundX = 0x01, kRoundY = 0x02 };
674 explicit gfxFontShaper(gfxFont* aFont) : mFont(aFont) {
675 NS_ASSERTION(aFont, "shaper requires a valid font!");
678 virtual ~gfxFontShaper() = default;
680 // Shape a piece of text and store the resulting glyph data into
681 // aShapedText. Parameters aOffset/aLength indicate the range of
682 // aShapedText to be updated; aLength is also the length of aText.
683 virtual bool ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
684 uint32_t aOffset, uint32_t aLength, Script aScript,
685 nsAtom* aLanguage, // may be null, indicating no
686 // lang-specific shaping to be
687 // applied
688 bool aVertical, RoundingFlags aRounding,
689 gfxShapedText* aShapedText) = 0;
691 gfxFont* GetFont() const { return mFont; }
693 static void MergeFontFeatures(
694 const gfxFontStyle* aStyle, const nsTArray<gfxFontFeature>& aFontFeatures,
695 bool aDisableLigatures, const nsACString& aFamilyName, bool aAddSmallCaps,
696 void (*aHandleFeature)(uint32_t, uint32_t, void*),
697 void* aHandleFeatureData);
699 protected:
700 // the font this shaper is working with. The font owns a UniquePtr reference
701 // to this object, and will destroy it before it dies. Thus, mFont will always
702 // be valid.
703 gfxFont* MOZ_NON_OWNING_REF mFont;
706 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(gfxFontShaper::RoundingFlags)
709 * gfxShapedText is an abstract superclass for gfxShapedWord and gfxTextRun.
710 * These are objects that store a list of zero or more glyphs for each
711 * character. For each glyph we store the glyph ID, the advance, and possibly
712 * x/y-offsets. The idea is that a string is rendered by a loop that draws each
713 * glyph at its designated offset from the current point, then advances the
714 * current point by the glyph's advance in the direction of the textrun (LTR or
715 * RTL). Each glyph advance is always rounded to the nearest appunit; this
716 * ensures consistent results when dividing the text in a textrun into multiple
717 * text frames (frame boundaries are always aligned to appunits). We optimize
718 * for the case where a character has a single glyph and zero xoffset and
719 * yoffset, and the glyph ID and advance are in a reasonable range so we can
720 * pack all necessary data into 32 bits.
722 * gfxFontShaper can shape text into either a gfxShapedWord (cached by a
723 * gfxFont) or directly into a gfxTextRun (for cases where we want to shape
724 * textruns in their entirety rather than using cached words, because there may
725 * be layout features that depend on the inter-word spaces).
727 class gfxShapedText {
728 public:
729 typedef mozilla::intl::Script Script;
731 gfxShapedText(uint32_t aLength, mozilla::gfx::ShapedTextFlags aFlags,
732 uint16_t aAppUnitsPerDevUnit)
733 : mLength(aLength),
734 mFlags(aFlags),
735 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) {}
737 virtual ~gfxShapedText() = default;
740 * This class records the information associated with a character in the
741 * input string. It's optimized for the case where there is one glyph
742 * representing that character alone.
744 * A character can have zero or more associated glyphs. Each glyph
745 * has an advance width and an x and y offset.
746 * A character may be the start of a cluster.
747 * A character may be the start of a ligature group.
748 * A character can be "missing", indicating that the system is unable
749 * to render the character.
751 * All characters in a ligature group conceptually share all the glyphs
752 * associated with the characters in a group.
754 class CompressedGlyph {
755 public:
756 enum {
757 // Indicates that a cluster and ligature group starts at this
758 // character; this character has a single glyph with a reasonable
759 // advance and zero offsets. A "reasonable" advance
760 // is one that fits in the available bits (currently 12) (specified
761 // in appunits).
762 FLAG_IS_SIMPLE_GLYPH = 0x80000000U,
764 // These flags are applicable to both "simple" and "complex" records.
765 COMMON_FLAGS_MASK = 0x70000000U,
767 // Indicates whether a linebreak is allowed before this character;
768 // this is a two-bit field that holds a FLAG_BREAK_TYPE_xxx value
769 // indicating the kind of linebreak (if any) allowed here.
770 FLAGS_CAN_BREAK_BEFORE = 0x60000000U,
772 FLAGS_CAN_BREAK_SHIFT = 29,
773 FLAG_BREAK_TYPE_NONE = 0,
774 FLAG_BREAK_TYPE_NORMAL = 1,
775 FLAG_BREAK_TYPE_HYPHEN = 2,
776 // Allow break before this position if needed to avoid overflow:
777 FLAG_BREAK_TYPE_EMERGENCY_WRAP = 3,
779 FLAG_CHAR_IS_SPACE = 0x10000000U,
781 // Fields present only when FLAG_IS_SIMPLE_GLYPH is /true/.
782 // The advance is stored in appunits as a 12-bit field:
783 ADVANCE_MASK = 0x0FFF0000U,
784 ADVANCE_SHIFT = 16,
785 // and the glyph ID is stored in the low 16 bits.
786 GLYPH_MASK = 0x0000FFFFU,
788 // Fields present only when FLAG_IS_SIMPLE_GLYPH is /false/.
789 // Non-simple glyphs may or may not have glyph data in the
790 // corresponding mDetailedGlyphs entry. They have a glyph count
791 // stored in the low 16 bits, and the following flag bits:
792 GLYPH_COUNT_MASK = 0x0000FFFFU,
794 // When NOT set, indicates that this character corresponds to a
795 // missing glyph and should be skipped (or possibly, render the character
796 // Unicode value in some special way). If there are glyphs,
797 // the mGlyphID is actually the UTF16 character code. The bit is
798 // inverted so we can memset the array to zero to indicate all missing.
799 FLAG_NOT_MISSING = 0x010000,
800 FLAG_NOT_CLUSTER_START = 0x020000,
801 FLAG_NOT_LIGATURE_GROUP_START = 0x040000,
802 // Flag bit 0x080000 is currently unused.
804 // Certain types of characters are marked so that they can be given
805 // special treatment in rendering. This may require use of a "complex"
806 // CompressedGlyph record even for a character that would otherwise be
807 // treated as "simple".
808 CHAR_TYPE_FLAGS_MASK = 0xF00000,
809 FLAG_CHAR_IS_TAB = 0x100000,
810 FLAG_CHAR_IS_NEWLINE = 0x200000,
811 // Per CSS Text Decoration Module Level 3, emphasis marks are not
812 // drawn for any character in Unicode categories Z*, Cc, Cf, and Cn
813 // which is not combined with any combining characters. This flag is
814 // set for all those characters except 0x20 whitespace.
815 FLAG_CHAR_NO_EMPHASIS_MARK = 0x400000,
816 // Per CSS Text, letter-spacing is not applied to formatting chars
817 // (category Cf). We mark those in the textrun so as to be able to
818 // skip them when setting up spacing in nsTextFrame.
819 FLAG_CHAR_IS_FORMATTING_CONTROL = 0x800000,
821 // The bits 0x0F000000 are currently unused in non-simple glyphs.
824 // "Simple glyphs" have a simple glyph ID, simple advance and their
825 // x and y offsets are zero. Also the glyph extents do not overflow
826 // the font-box defined by the font ascent, descent and glyph advance width.
827 // These case is optimized to avoid storing DetailedGlyphs.
829 // Returns true if the glyph ID aGlyph fits into the compressed
830 // representation
831 static bool IsSimpleGlyphID(uint32_t aGlyph) {
832 return (aGlyph & GLYPH_MASK) == aGlyph;
834 // Returns true if the advance aAdvance fits into the compressed
835 // representation. aAdvance is in appunits.
836 static bool IsSimpleAdvance(uint32_t aAdvance) {
837 return (aAdvance & (ADVANCE_MASK >> ADVANCE_SHIFT)) == aAdvance;
840 bool IsSimpleGlyph() const { return mValue & FLAG_IS_SIMPLE_GLYPH; }
841 uint32_t GetSimpleAdvance() const {
842 MOZ_ASSERT(IsSimpleGlyph());
843 return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT;
845 uint32_t GetSimpleGlyph() const {
846 MOZ_ASSERT(IsSimpleGlyph());
847 return mValue & GLYPH_MASK;
850 bool IsMissing() const {
851 return !(mValue & (FLAG_NOT_MISSING | FLAG_IS_SIMPLE_GLYPH));
853 bool IsClusterStart() const {
854 return IsSimpleGlyph() || !(mValue & FLAG_NOT_CLUSTER_START);
856 bool IsLigatureGroupStart() const {
857 return IsSimpleGlyph() || !(mValue & FLAG_NOT_LIGATURE_GROUP_START);
859 bool IsLigatureContinuation() const {
860 return !IsSimpleGlyph() &&
861 (mValue & (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING)) ==
862 (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING);
865 // Return true if the original character was a normal (breakable,
866 // trimmable) space (U+0020). Not true for other characters that
867 // may happen to map to the space glyph (U+00A0).
868 bool CharIsSpace() const { return mValue & FLAG_CHAR_IS_SPACE; }
870 bool CharIsTab() const {
871 return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_TAB);
873 bool CharIsNewline() const {
874 return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_NEWLINE);
876 bool CharMayHaveEmphasisMark() const {
877 return !CharIsSpace() &&
878 (IsSimpleGlyph() || !(mValue & FLAG_CHAR_NO_EMPHASIS_MARK));
880 bool CharIsFormattingControl() const {
881 return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_FORMATTING_CONTROL);
884 uint32_t CharTypeFlags() const {
885 return IsSimpleGlyph() ? 0 : (mValue & CHAR_TYPE_FLAGS_MASK);
888 void SetClusterStart(bool aIsClusterStart) {
889 MOZ_ASSERT(!IsSimpleGlyph());
890 if (aIsClusterStart) {
891 mValue &= ~FLAG_NOT_CLUSTER_START;
892 } else {
893 mValue |= FLAG_NOT_CLUSTER_START;
897 uint8_t CanBreakBefore() const {
898 return (mValue & FLAGS_CAN_BREAK_BEFORE) >> FLAGS_CAN_BREAK_SHIFT;
900 // Returns FLAGS_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
901 uint32_t SetCanBreakBefore(uint8_t aCanBreakBefore) {
902 MOZ_ASSERT(aCanBreakBefore <= 3, "Bogus break-flags value!");
903 uint32_t breakMask = (uint32_t(aCanBreakBefore) << FLAGS_CAN_BREAK_SHIFT);
904 uint32_t toggle = breakMask ^ (mValue & FLAGS_CAN_BREAK_BEFORE);
905 mValue ^= toggle;
906 return toggle;
909 // Create a CompressedGlyph value representing a simple glyph with
910 // no extra flags (line-break or is_space) set.
911 static CompressedGlyph MakeSimpleGlyph(uint32_t aAdvanceAppUnits,
912 uint32_t aGlyph) {
913 MOZ_ASSERT(IsSimpleAdvance(aAdvanceAppUnits));
914 MOZ_ASSERT(IsSimpleGlyphID(aGlyph));
915 CompressedGlyph g;
916 g.mValue =
917 FLAG_IS_SIMPLE_GLYPH | (aAdvanceAppUnits << ADVANCE_SHIFT) | aGlyph;
918 return g;
921 // Assign a simple glyph value to an existing CompressedGlyph record,
922 // preserving line-break/is-space flags if present.
923 CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits,
924 uint32_t aGlyph) {
925 MOZ_ASSERT(!CharTypeFlags(), "Char type flags lost");
926 mValue = (mValue & COMMON_FLAGS_MASK) |
927 MakeSimpleGlyph(aAdvanceAppUnits, aGlyph).mValue;
928 return *this;
931 // Create a CompressedGlyph value representing a complex glyph record,
932 // without any line-break or char-type flags.
933 static CompressedGlyph MakeComplex(bool aClusterStart,
934 bool aLigatureStart) {
935 CompressedGlyph g;
936 g.mValue = FLAG_NOT_MISSING |
937 (aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) |
938 (aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START);
939 return g;
942 // Assign a complex glyph value to an existing CompressedGlyph record,
943 // preserving line-break/char-type flags if present.
944 // This sets the glyphCount to zero; it will be updated when we call
945 // gfxShapedText::SetDetailedGlyphs.
946 CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart) {
947 mValue = (mValue & COMMON_FLAGS_MASK) | CharTypeFlags() |
948 MakeComplex(aClusterStart, aLigatureStart).mValue;
949 return *this;
953 * Mark a glyph record as being a missing-glyph.
954 * Missing glyphs are treated as ligature group starts; don't mess with
955 * the cluster-start flag (see bugs 618870 and 619286).
956 * We also preserve the glyph count here, as this is used after any
957 * required DetailedGlyphs (to store the char code for a hexbox) has been
958 * set up.
959 * This must be called *after* SetDetailedGlyphs is used for the relevant
960 * offset in the shaped-word, because that will mark it as not-missing.
962 CompressedGlyph& SetMissing() {
963 MOZ_ASSERT(!IsSimpleGlyph());
964 mValue &= ~(FLAG_NOT_MISSING | FLAG_NOT_LIGATURE_GROUP_START);
965 return *this;
968 uint32_t GetGlyphCount() const {
969 MOZ_ASSERT(!IsSimpleGlyph());
970 return mValue & GLYPH_COUNT_MASK;
972 void SetGlyphCount(uint32_t aGlyphCount) {
973 MOZ_ASSERT(!IsSimpleGlyph());
974 MOZ_ASSERT(GetGlyphCount() == 0, "Glyph count already set");
975 MOZ_ASSERT(aGlyphCount <= 0xffff, "Glyph count out of range");
976 mValue |= FLAG_NOT_MISSING | aGlyphCount;
979 void SetIsSpace() { mValue |= FLAG_CHAR_IS_SPACE; }
980 void SetIsTab() {
981 MOZ_ASSERT(!IsSimpleGlyph());
982 mValue |= FLAG_CHAR_IS_TAB;
984 void SetIsNewline() {
985 MOZ_ASSERT(!IsSimpleGlyph());
986 mValue |= FLAG_CHAR_IS_NEWLINE;
988 void SetNoEmphasisMark() {
989 MOZ_ASSERT(!IsSimpleGlyph());
990 mValue |= FLAG_CHAR_NO_EMPHASIS_MARK;
992 void SetIsFormattingControl() {
993 MOZ_ASSERT(!IsSimpleGlyph());
994 mValue |= FLAG_CHAR_IS_FORMATTING_CONTROL;
997 private:
998 uint32_t mValue;
1001 // Accessor for the array of CompressedGlyph records, which will be in
1002 // a different place in gfxShapedWord vs gfxTextRun
1003 virtual const CompressedGlyph* GetCharacterGlyphs() const = 0;
1004 virtual CompressedGlyph* GetCharacterGlyphs() = 0;
1007 * When the glyphs for a character don't fit into a CompressedGlyph record
1008 * in SimpleGlyph format, we use an array of DetailedGlyphs instead.
1010 struct DetailedGlyph {
1011 // The glyphID, or the Unicode character if this is a missing glyph
1012 uint32_t mGlyphID;
1013 // The advance of the glyph, in appunits.
1014 // mAdvance is in the text direction (RTL or LTR),
1015 // and will normally be non-negative (although this is not guaranteed)
1016 int32_t mAdvance;
1017 // The offset from the glyph's default position, in line-relative
1018 // coordinates (so mOffset.x is an offset in the line-right direction,
1019 // and mOffset.y is an offset in line-downwards direction).
1020 // These values are in floating-point appUnits.
1021 mozilla::gfx::Point mOffset;
1024 // Store DetailedGlyph records for the given index. (This does not modify
1025 // the associated CompressedGlyph character-type or break flags.)
1026 void SetDetailedGlyphs(uint32_t aIndex, uint32_t aGlyphCount,
1027 const DetailedGlyph* aGlyphs);
1029 void SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont* aFont);
1031 void SetIsSpace(uint32_t aIndex) {
1032 GetCharacterGlyphs()[aIndex].SetIsSpace();
1035 bool HasDetailedGlyphs() const { return mDetailedGlyphs != nullptr; }
1037 bool IsLigatureGroupStart(uint32_t aPos) {
1038 NS_ASSERTION(aPos < GetLength(), "aPos out of range");
1039 return GetCharacterGlyphs()[aPos].IsLigatureGroupStart();
1042 // NOTE that this must not be called for a character offset that does
1043 // not have any DetailedGlyph records; callers must have verified that
1044 // GetCharacterGlyphs()[aCharIndex].GetGlyphCount() is greater than zero.
1045 DetailedGlyph* GetDetailedGlyphs(uint32_t aCharIndex) const {
1046 NS_ASSERTION(GetCharacterGlyphs() && HasDetailedGlyphs() &&
1047 !GetCharacterGlyphs()[aCharIndex].IsSimpleGlyph() &&
1048 GetCharacterGlyphs()[aCharIndex].GetGlyphCount() > 0,
1049 "invalid use of GetDetailedGlyphs; check the caller!");
1050 return mDetailedGlyphs->Get(aCharIndex);
1053 void ApplyTrackingToClusters(gfxFloat aTrackingAdjustment, uint32_t aOffset,
1054 uint32_t aLength);
1056 // Mark clusters in the CompressedGlyph records, starting at aOffset,
1057 // based on the Unicode properties of the text in aString.
1058 // This is also responsible to set the IsSpace flag for space characters.
1059 void SetupClusterBoundaries(uint32_t aOffset, const char16_t* aString,
1060 uint32_t aLength);
1061 // In 8-bit text, there won't actually be any clusters, but we still need
1062 // the space-marking functionality.
1063 void SetupClusterBoundaries(uint32_t aOffset, const uint8_t* aString,
1064 uint32_t aLength);
1066 mozilla::gfx::ShapedTextFlags GetFlags() const { return mFlags; }
1068 bool IsVertical() const {
1069 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK) !=
1070 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_HORIZONTAL;
1073 bool UseCenterBaseline() const {
1074 mozilla::gfx::ShapedTextFlags orient =
1075 GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK;
1076 return orient ==
1077 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_MIXED ||
1078 orient ==
1079 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_UPRIGHT;
1082 bool IsRightToLeft() const {
1083 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_IS_RTL) ==
1084 mozilla::gfx::ShapedTextFlags::TEXT_IS_RTL;
1087 bool IsSidewaysLeft() const {
1088 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK) ==
1089 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT;
1092 // Return true if the logical inline direction is reversed compared to
1093 // normal physical coordinates (i.e. if it is leftwards or upwards)
1094 bool IsInlineReversed() const { return IsSidewaysLeft() != IsRightToLeft(); }
1096 gfxFloat GetDirection() const { return IsInlineReversed() ? -1.0f : 1.0f; }
1098 bool DisableLigatures() const {
1099 return (GetFlags() &
1100 mozilla::gfx::ShapedTextFlags::TEXT_DISABLE_OPTIONAL_LIGATURES) ==
1101 mozilla::gfx::ShapedTextFlags::TEXT_DISABLE_OPTIONAL_LIGATURES;
1104 bool TextIs8Bit() const {
1105 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT) ==
1106 mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT;
1109 int32_t GetAppUnitsPerDevUnit() const { return mAppUnitsPerDevUnit; }
1111 uint32_t GetLength() const { return mLength; }
1113 bool FilterIfIgnorable(uint32_t aIndex, uint32_t aCh);
1115 protected:
1116 // Allocate aCount DetailedGlyphs for the given index
1117 DetailedGlyph* AllocateDetailedGlyphs(uint32_t aCharIndex, uint32_t aCount);
1119 // Ensure the glyph on the given index is complex glyph so that we can use
1120 // it to record specific characters that layout may need to detect.
1121 void EnsureComplexGlyph(uint32_t aIndex, CompressedGlyph& aGlyph) {
1122 MOZ_ASSERT(GetCharacterGlyphs() + aIndex == &aGlyph);
1123 if (aGlyph.IsSimpleGlyph()) {
1124 DetailedGlyph details = {aGlyph.GetSimpleGlyph(),
1125 (int32_t)aGlyph.GetSimpleAdvance(),
1126 mozilla::gfx::Point()};
1127 aGlyph.SetComplex(true, true);
1128 SetDetailedGlyphs(aIndex, 1, &details);
1132 // For characters whose glyph data does not fit the "simple" glyph criteria
1133 // in CompressedGlyph, we use a sorted array to store the association
1134 // between the source character offset and an index into an array
1135 // DetailedGlyphs. The CompressedGlyph record includes a count of
1136 // the number of DetailedGlyph records that belong to the character,
1137 // starting at the given index.
1138 class DetailedGlyphStore {
1139 public:
1140 DetailedGlyphStore() = default;
1142 // This is optimized for the most common calling patterns:
1143 // we rarely need random access to the records, access is most commonly
1144 // sequential through the textRun, so we record the last-used index
1145 // and check whether the caller wants the same record again, or the
1146 // next; if not, it's most likely we're starting over from the start
1147 // of the run, so we check the first entry before resorting to binary
1148 // search as a last resort.
1149 // NOTE that this must not be called for a character offset that does
1150 // not have any DetailedGlyph records; callers must have verified that
1151 // mCharacterGlyphs[aOffset].GetGlyphCount() is greater than zero
1152 // before calling this, otherwise the assertions here will fire (in a
1153 // debug build), and we'll probably crash.
1154 DetailedGlyph* Get(uint32_t aOffset) {
1155 NS_ASSERTION(mOffsetToIndex.Length() > 0, "no detailed glyph records!");
1156 DetailedGlyph* details = mDetails.Elements();
1157 // check common cases (fwd iteration, initial entry, etc) first
1158 if (mLastUsed < mOffsetToIndex.Length() - 1 &&
1159 aOffset == mOffsetToIndex[mLastUsed + 1].mOffset) {
1160 ++mLastUsed;
1161 } else if (aOffset == mOffsetToIndex[0].mOffset) {
1162 mLastUsed = 0;
1163 } else if (aOffset == mOffsetToIndex[mLastUsed].mOffset) {
1164 // do nothing
1165 } else if (mLastUsed > 0 &&
1166 aOffset == mOffsetToIndex[mLastUsed - 1].mOffset) {
1167 --mLastUsed;
1168 } else {
1169 mLastUsed = mOffsetToIndex.BinaryIndexOf(aOffset, CompareToOffset());
1171 NS_ASSERTION(mLastUsed != nsTArray<DGRec>::NoIndex,
1172 "detailed glyph record missing!");
1173 return details + mOffsetToIndex[mLastUsed].mIndex;
1176 DetailedGlyph* Allocate(uint32_t aOffset, uint32_t aCount) {
1177 uint32_t detailIndex = mDetails.Length();
1178 DetailedGlyph* details = mDetails.AppendElements(aCount);
1179 // We normally set up glyph records sequentially, so the common case
1180 // here is to append new records to the mOffsetToIndex array;
1181 // test for that before falling back to the InsertElementSorted
1182 // method.
1183 if (mOffsetToIndex.Length() == 0 ||
1184 aOffset > mOffsetToIndex[mOffsetToIndex.Length() - 1].mOffset) {
1185 mOffsetToIndex.AppendElement(DGRec(aOffset, detailIndex));
1186 } else {
1187 mOffsetToIndex.InsertElementSorted(DGRec(aOffset, detailIndex),
1188 CompareRecordOffsets());
1190 return details;
1193 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
1194 return aMallocSizeOf(this) +
1195 mDetails.ShallowSizeOfExcludingThis(aMallocSizeOf) +
1196 mOffsetToIndex.ShallowSizeOfExcludingThis(aMallocSizeOf);
1199 private:
1200 struct DGRec {
1201 DGRec(const uint32_t& aOffset, const uint32_t& aIndex)
1202 : mOffset(aOffset), mIndex(aIndex) {}
1203 uint32_t mOffset; // source character offset in the textrun
1204 uint32_t mIndex; // index where this char's DetailedGlyphs begin
1207 struct CompareToOffset {
1208 bool Equals(const DGRec& a, const uint32_t& b) const {
1209 return a.mOffset == b;
1211 bool LessThan(const DGRec& a, const uint32_t& b) const {
1212 return a.mOffset < b;
1216 struct CompareRecordOffsets {
1217 bool Equals(const DGRec& a, const DGRec& b) const {
1218 return a.mOffset == b.mOffset;
1220 bool LessThan(const DGRec& a, const DGRec& b) const {
1221 return a.mOffset < b.mOffset;
1225 // Concatenated array of all the DetailedGlyph records needed for the
1226 // textRun; individual character offsets are associated with indexes
1227 // into this array via the mOffsetToIndex table.
1228 nsTArray<DetailedGlyph> mDetails;
1230 // For each character offset that needs DetailedGlyphs, we record the
1231 // index in mDetails where the list of glyphs begins. This array is
1232 // sorted by mOffset.
1233 nsTArray<DGRec> mOffsetToIndex;
1235 // Records the most recently used index into mOffsetToIndex, so that
1236 // we can support sequential access more quickly than just doing
1237 // a binary search each time.
1238 nsTArray<DGRec>::index_type mLastUsed = 0;
1241 mozilla::UniquePtr<DetailedGlyphStore> mDetailedGlyphs;
1243 // Number of char16_t characters and CompressedGlyph glyph records
1244 uint32_t mLength;
1246 // Shaping flags (direction, ligature-suppression)
1247 mozilla::gfx::ShapedTextFlags mFlags;
1249 uint16_t mAppUnitsPerDevUnit;
1253 * gfxShapedWord: an individual (space-delimited) run of text shaped with a
1254 * particular font, without regard to external context.
1256 * The glyph data is copied into gfxTextRuns as needed from the cache of
1257 * ShapedWords associated with each gfxFont instance.
1259 class gfxShapedWord final : public gfxShapedText {
1260 public:
1261 typedef mozilla::intl::Script Script;
1263 // Create a ShapedWord that can hold glyphs for aLength characters,
1264 // with mCharacterGlyphs sized appropriately.
1266 // Returns null on allocation failure (does NOT use infallible alloc)
1267 // so caller must check for success.
1269 // This does NOT perform shaping, so the returned word contains no
1270 // glyph data; the caller must call gfxFont::ShapeText() with appropriate
1271 // parameters to set up the glyphs.
1272 static gfxShapedWord* Create(const uint8_t* aText, uint32_t aLength,
1273 Script aRunScript, nsAtom* aLanguage,
1274 uint16_t aAppUnitsPerDevUnit,
1275 mozilla::gfx::ShapedTextFlags aFlags,
1276 gfxFontShaper::RoundingFlags aRounding) {
1277 NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
1278 "excessive length for gfxShapedWord!");
1280 // Compute size needed including the mCharacterGlyphs array
1281 // and a copy of the original text
1282 uint32_t size = offsetof(gfxShapedWord, mCharGlyphsStorage) +
1283 aLength * (sizeof(CompressedGlyph) + sizeof(uint8_t));
1284 void* storage = malloc(size);
1285 if (!storage) {
1286 return nullptr;
1289 // Construct in the pre-allocated storage, using placement new
1290 return new (storage) gfxShapedWord(aText, aLength, aRunScript, aLanguage,
1291 aAppUnitsPerDevUnit, aFlags, aRounding);
1294 static gfxShapedWord* Create(const char16_t* aText, uint32_t aLength,
1295 Script aRunScript, nsAtom* aLanguage,
1296 uint16_t aAppUnitsPerDevUnit,
1297 mozilla::gfx::ShapedTextFlags aFlags,
1298 gfxFontShaper::RoundingFlags aRounding) {
1299 NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
1300 "excessive length for gfxShapedWord!");
1302 // In the 16-bit version of Create, if the TEXT_IS_8BIT flag is set,
1303 // then we convert the text to an 8-bit version and call the 8-bit
1304 // Create function instead.
1305 if (aFlags & mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT) {
1306 nsAutoCString narrowText;
1307 LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength), narrowText);
1308 return Create((const uint8_t*)(narrowText.BeginReading()), aLength,
1309 aRunScript, aLanguage, aAppUnitsPerDevUnit, aFlags,
1310 aRounding);
1313 uint32_t size = offsetof(gfxShapedWord, mCharGlyphsStorage) +
1314 aLength * (sizeof(CompressedGlyph) + sizeof(char16_t));
1315 void* storage = malloc(size);
1316 if (!storage) {
1317 return nullptr;
1320 return new (storage) gfxShapedWord(aText, aLength, aRunScript, aLanguage,
1321 aAppUnitsPerDevUnit, aFlags, aRounding);
1324 // Override operator delete to properly free the object that was
1325 // allocated via malloc.
1326 void operator delete(void* p) { free(p); }
1328 const CompressedGlyph* GetCharacterGlyphs() const override {
1329 return &mCharGlyphsStorage[0];
1331 CompressedGlyph* GetCharacterGlyphs() override {
1332 return &mCharGlyphsStorage[0];
1335 const uint8_t* Text8Bit() const {
1336 NS_ASSERTION(TextIs8Bit(), "invalid use of Text8Bit()");
1337 return reinterpret_cast<const uint8_t*>(mCharGlyphsStorage + GetLength());
1340 const char16_t* TextUnicode() const {
1341 NS_ASSERTION(!TextIs8Bit(), "invalid use of TextUnicode()");
1342 return reinterpret_cast<const char16_t*>(mCharGlyphsStorage + GetLength());
1345 char16_t GetCharAt(uint32_t aOffset) const {
1346 NS_ASSERTION(aOffset < GetLength(), "aOffset out of range");
1347 return TextIs8Bit() ? char16_t(Text8Bit()[aOffset])
1348 : TextUnicode()[aOffset];
1351 Script GetScript() const { return mScript; }
1352 nsAtom* GetLanguage() const { return mLanguage.get(); }
1354 gfxFontShaper::RoundingFlags GetRounding() const { return mRounding; }
1356 void ResetAge() { mAgeCounter = 0; }
1357 uint32_t IncrementAge() { return ++mAgeCounter; }
1359 // Helper used when hashing a word for the shaped-word caches
1360 static uint32_t HashMix(uint32_t aHash, char16_t aCh) {
1361 return (aHash >> 28) ^ (aHash << 4) ^ aCh;
1364 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
1366 private:
1367 // so that gfxTextRun can share our DetailedGlyphStore class
1368 friend class gfxTextRun;
1370 // Construct storage for a ShapedWord, ready to receive glyph data
1371 gfxShapedWord(const uint8_t* aText, uint32_t aLength, Script aRunScript,
1372 nsAtom* aLanguage, uint16_t aAppUnitsPerDevUnit,
1373 mozilla::gfx::ShapedTextFlags aFlags,
1374 gfxFontShaper::RoundingFlags aRounding)
1375 : gfxShapedText(aLength,
1376 aFlags | mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT,
1377 aAppUnitsPerDevUnit),
1378 mLanguage(aLanguage),
1379 mScript(aRunScript),
1380 mRounding(aRounding),
1381 mAgeCounter(0) {
1382 memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph));
1383 uint8_t* text = reinterpret_cast<uint8_t*>(&mCharGlyphsStorage[aLength]);
1384 memcpy(text, aText, aLength * sizeof(uint8_t));
1385 SetupClusterBoundaries(0, aText, aLength);
1388 gfxShapedWord(const char16_t* aText, uint32_t aLength, Script aRunScript,
1389 nsAtom* aLanguage, uint16_t aAppUnitsPerDevUnit,
1390 mozilla::gfx::ShapedTextFlags aFlags,
1391 gfxFontShaper::RoundingFlags aRounding)
1392 : gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit),
1393 mLanguage(aLanguage),
1394 mScript(aRunScript),
1395 mRounding(aRounding),
1396 mAgeCounter(0) {
1397 memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph));
1398 char16_t* text = reinterpret_cast<char16_t*>(&mCharGlyphsStorage[aLength]);
1399 memcpy(text, aText, aLength * sizeof(char16_t));
1400 SetupClusterBoundaries(0, aText, aLength);
1403 RefPtr<nsAtom> mLanguage;
1404 Script mScript;
1406 gfxFontShaper::RoundingFlags mRounding;
1408 // With multithreaded shaping, this may be updated by any thread.
1409 std::atomic<uint32_t> mAgeCounter;
1411 // The mCharGlyphsStorage array is actually a variable-size member;
1412 // when the ShapedWord is created, its size will be increased as necessary
1413 // to allow the proper number of glyphs to be stored.
1414 // The original text, in either 8-bit or 16-bit form, will be stored
1415 // immediately following the CompressedGlyphs.
1416 CompressedGlyph mCharGlyphsStorage[1];
1419 class GlyphBufferAzure;
1420 struct TextRunDrawParams;
1421 struct FontDrawParams;
1422 struct EmphasisMarkDrawParams;
1424 class gfxFont {
1425 friend class gfxHarfBuzzShaper;
1426 friend class gfxGraphiteShaper;
1428 protected:
1429 using DrawTarget = mozilla::gfx::DrawTarget;
1430 using Script = mozilla::intl::Script;
1431 using SVGContextPaint = mozilla::SVGContextPaint;
1433 using RoundingFlags = gfxFontShaper::RoundingFlags;
1434 using ShapedTextFlags = mozilla::gfx::ShapedTextFlags;
1436 public:
1437 using FontSlantStyle = mozilla::FontSlantStyle;
1438 using FontSizeAdjust = mozilla::StyleFontSizeAdjust;
1440 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(gfxFont, MaybeDestroy())
1441 int32_t GetRefCount() { return int32_t(mRefCnt); }
1443 // options to specify the kind of AA to be used when creating a font
1444 typedef enum : uint8_t {
1445 kAntialiasDefault,
1446 kAntialiasNone,
1447 kAntialiasGrayscale,
1448 kAntialiasSubpixel
1449 } AntialiasOption;
1451 protected:
1452 gfxFont(const RefPtr<mozilla::gfx::UnscaledFont>& aUnscaledFont,
1453 gfxFontEntry* aFontEntry, const gfxFontStyle* aFontStyle,
1454 AntialiasOption anAAOption = kAntialiasDefault);
1456 virtual ~gfxFont();
1458 void MaybeDestroy() {
1459 bool destroy = true;
1460 if (gfxFontCache* fc = gfxFontCache::GetCache()) {
1461 destroy = fc->MaybeDestroy(this);
1463 if (destroy) {
1464 Destroy();
1468 public:
1469 void Destroy() {
1470 MOZ_ASSERT(GetRefCount() == 0);
1471 delete this;
1474 bool Valid() const { return mIsValid; }
1476 // options for the kind of bounding box to return from measurement
1477 typedef enum {
1478 LOOSE_INK_EXTENTS,
1479 // A box that encloses all the painted pixels, and may
1480 // include sidebearings and/or additional ascent/descent
1481 // within the glyph cell even if the ink is smaller.
1482 TIGHT_INK_EXTENTS,
1483 // A box that tightly encloses all the painted pixels
1484 // (although actually on Windows, at least, it may be
1485 // slightly larger than strictly necessary because
1486 // we can't get precise extents with ClearType).
1487 TIGHT_HINTED_OUTLINE_EXTENTS
1488 // A box that tightly encloses the glyph outline,
1489 // ignoring possible antialiasing pixels that extend
1490 // beyond this.
1491 // NOTE: The default implementation of gfxFont::Measure(),
1492 // which works with the glyph extents cache, does not
1493 // differentiate between this and TIGHT_INK_EXTENTS.
1494 // Whether the distinction is important depends on the
1495 // antialiasing behavior of the platform; currently the
1496 // distinction is only implemented in the gfxWindowsFont
1497 // subclass, because of ClearType's tendency to paint
1498 // outside the hinted outline.
1499 // Also NOTE: it is relatively expensive to request this,
1500 // as it does not use cached glyph extents in the font.
1501 } BoundingBoxType;
1503 const nsCString& GetName() const { return mFontEntry->Name(); }
1504 const gfxFontStyle* GetStyle() const { return &mStyle; }
1506 virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption) const {
1507 // platforms where this actually matters should override
1508 return nullptr;
1511 gfxFloat GetAdjustedSize() const {
1512 // mAdjustedSize is cached here if not already set to a non-zero value;
1513 // but it may be overridden by a value computed in metrics initialization
1514 // from font-size-adjust.
1515 if (mAdjustedSize < 0.0) {
1516 mAdjustedSize = mStyle.AdjustedSizeMustBeZero()
1517 ? 0.0
1518 : mStyle.size * mFontEntry->mSizeAdjust;
1520 return mAdjustedSize;
1523 float FUnitsToDevUnitsFactor() const {
1524 // check this was set up during font initialization
1525 NS_ASSERTION(mFUnitsConvFactor >= 0.0f, "mFUnitsConvFactor not valid");
1526 return mFUnitsConvFactor;
1529 // check whether this is an sfnt we can potentially use with harfbuzz
1530 bool FontCanSupportHarfBuzz() const { return mFontEntry->HasCmapTable(); }
1532 // check whether this is an sfnt we can potentially use with Graphite
1533 bool FontCanSupportGraphite() const {
1534 return mFontEntry->HasGraphiteTables();
1537 // Whether this is a font that may be doing full-color rendering,
1538 // and therefore needs us to use a mask for text-shadow even when
1539 // we're not actually blurring.
1540 bool AlwaysNeedsMaskForShadow() const {
1541 return mFontEntry->AlwaysNeedsMaskForShadow();
1544 // whether a feature is supported by the font (limited to a small set
1545 // of features for which some form of fallback needs to be implemented)
1546 bool SupportsFeature(Script aScript, uint32_t aFeatureTag);
1548 // whether the font supports "real" small caps, petite caps etc.
1549 // aFallbackToSmallCaps true when petite caps should fallback to small caps
1550 bool SupportsVariantCaps(Script aScript, uint32_t aVariantCaps,
1551 bool& aFallbackToSmallCaps,
1552 bool& aSyntheticLowerToSmallCaps,
1553 bool& aSyntheticUpperToSmallCaps);
1555 // whether the font supports subscript/superscript feature
1556 // for fallback, need to verify that all characters in the run
1557 // have variant substitutions
1558 bool SupportsSubSuperscript(uint32_t aSubSuperscript, const uint8_t* aString,
1559 uint32_t aLength, Script aRunScript);
1561 bool SupportsSubSuperscript(uint32_t aSubSuperscript, const char16_t* aString,
1562 uint32_t aLength, Script aRunScript);
1564 // whether the specified feature will apply to the given character
1565 bool FeatureWillHandleChar(Script aRunScript, uint32_t aFeature,
1566 uint32_t aUnicode);
1568 // Subclasses may choose to look up glyph ids for characters.
1569 // If they do not override this, gfxHarfBuzzShaper will fetch the cmap
1570 // table and use that.
1571 virtual bool ProvidesGetGlyph() const { return false; }
1572 // Map unicode character to glyph ID.
1573 // Only used if ProvidesGetGlyph() returns true.
1574 virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector) {
1575 return 0;
1578 // Return the advance of a glyph.
1579 gfxFloat GetGlyphAdvance(uint16_t aGID, bool aVertical = false);
1581 // Return the advance of a given Unicode char in isolation.
1582 // Returns -1.0 if the char is not supported.
1583 gfxFloat GetCharAdvance(uint32_t aUnicode, bool aVertical = false);
1585 gfxFloat SynthesizeSpaceWidth(uint32_t aCh);
1587 // Work out whether cairo will snap inter-glyph spacing to pixels
1588 // when rendering to the given drawTarget.
1589 RoundingFlags GetRoundOffsetsToPixels(DrawTarget* aDrawTarget);
1591 virtual bool ShouldHintMetrics() const { return true; }
1592 virtual bool ShouldRoundXOffset(cairo_t* aCairo) const { return true; }
1594 // Return the font's owned harfbuzz shaper, creating and initializing it if
1595 // necessary; returns null if shaper initialization has failed.
1596 gfxHarfBuzzShaper* GetHarfBuzzShaper();
1598 // Font metrics
1599 struct Metrics {
1600 gfxFloat capHeight;
1601 gfxFloat xHeight;
1602 gfxFloat strikeoutSize;
1603 gfxFloat strikeoutOffset;
1604 gfxFloat underlineSize;
1605 gfxFloat underlineOffset;
1607 gfxFloat internalLeading;
1608 gfxFloat externalLeading;
1610 gfxFloat emHeight;
1611 gfxFloat emAscent;
1612 gfxFloat emDescent;
1613 gfxFloat maxHeight;
1614 gfxFloat maxAscent;
1615 gfxFloat maxDescent;
1616 gfxFloat maxAdvance;
1618 gfxFloat aveCharWidth;
1619 gfxFloat spaceWidth;
1620 gfxFloat zeroWidth; // -1 if there was no zero glyph
1621 gfxFloat ideographicWidth; // -1 if kWaterIdeograph is not supported
1623 gfxFloat ZeroOrAveCharWidth() const {
1624 return zeroWidth >= 0 ? zeroWidth : aveCharWidth;
1627 // Unicode character used as basis for 'ic' unit:
1628 static constexpr uint32_t kWaterIdeograph = 0x6C34;
1630 typedef nsFontMetrics::FontOrientation Orientation;
1632 const Metrics& GetMetrics(Orientation aOrientation) {
1633 if (aOrientation == nsFontMetrics::eHorizontal) {
1634 return GetHorizontalMetrics();
1636 if (!mVerticalMetrics) {
1637 CreateVerticalMetrics();
1639 return *mVerticalMetrics;
1642 struct Baselines {
1643 gfxFloat mAlphabetic;
1644 gfxFloat mHanging;
1645 gfxFloat mIdeographic;
1647 Baselines GetBaselines(Orientation aOrientation);
1650 * We let layout specify spacing on either side of any
1651 * character. We need to specify both before and after
1652 * spacing so that substring measurement can do the right things.
1653 * These values are in appunits. They're always an integral number of
1654 * appunits, but we specify them in floats in case very large spacing
1655 * values are required.
1657 struct Spacing {
1658 gfxFloat mBefore;
1659 gfxFloat mAfter;
1662 * Metrics for a particular string
1664 struct RunMetrics {
1665 RunMetrics() { mAdvanceWidth = mAscent = mDescent = 0.0; }
1667 void CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft);
1669 // can be negative (partly due to negative spacing).
1670 // Advance widths should be additive: the advance width of the
1671 // (offset1, length1) plus the advance width of (offset1 + length1,
1672 // length2) should be the advance width of (offset1, length1 + length2)
1673 gfxFloat mAdvanceWidth;
1675 // For zero-width substrings, these must be zero!
1676 gfxFloat mAscent; // always non-negative
1677 gfxFloat mDescent; // always non-negative
1679 // Bounding box that is guaranteed to include everything drawn.
1680 // If a tight boundingBox was requested when these metrics were
1681 // generated, this will tightly wrap the glyphs, otherwise it is
1682 // "loose" and may be larger than the true bounding box.
1683 // Coordinates are relative to the baseline left origin, so typically
1684 // mBoundingBox.y == -mAscent
1685 gfxRect mBoundingBox;
1689 * Draw a series of glyphs to aContext. The direction of aTextRun must
1690 * be honoured.
1691 * @param aStart the first character to draw
1692 * @param aEnd draw characters up to here
1693 * @param aPt the baseline origin; the left end of the baseline
1694 * for LTR textruns, the right end for RTL textruns.
1695 * On return, this will be updated to the other end of the baseline.
1696 * In application units, really!
1697 * @param aRunParams record with drawing parameters, see TextRunDrawParams.
1698 * Particular fields of interest include
1699 * .spacing spacing to insert before and after characters (for RTL
1700 * glyphs, before-spacing is inserted to the right of characters). There
1701 * are aEnd - aStart elements in this array, unless it's null to indicate
1702 * that there is no spacing.
1703 * .drawMode specifies whether the fill or stroke of the glyph should be
1704 * drawn, or if it should be drawn into the current path
1705 * .contextPaint information about how to construct the fill and
1706 * stroke pattern. Can be nullptr if we are not stroking the text, which
1707 * indicates that the current source from context should be used for fill
1708 * .context the Thebes graphics context to which we're drawing
1709 * .dt Moz2D DrawTarget to which we're drawing
1711 * Callers guarantee:
1712 * -- aStart and aEnd are aligned to cluster and ligature boundaries
1713 * -- all glyphs use this font
1715 void Draw(const gfxTextRun* aTextRun, uint32_t aStart, uint32_t aEnd,
1716 mozilla::gfx::Point* aPt, TextRunDrawParams& aRunParams,
1717 mozilla::gfx::ShapedTextFlags aOrientation);
1720 * Draw the emphasis marks for the given text run. Its prerequisite
1721 * and output are similiar to the method Draw().
1722 * @param aPt the baseline origin of the emphasis marks.
1723 * @param aParams some drawing parameters, see EmphasisMarkDrawParams.
1725 void DrawEmphasisMarks(const gfxTextRun* aShapedText,
1726 mozilla::gfx::Point* aPt, uint32_t aOffset,
1727 uint32_t aCount,
1728 const EmphasisMarkDrawParams& aParams);
1731 * Measure a run of characters. See gfxTextRun::Metrics.
1732 * @param aTight if false, then return the union of the glyph extents
1733 * with the font-box for the characters (the rectangle with x=0,width=
1734 * the advance width for the character run,y=-(font ascent), and height=
1735 * font ascent + font descent). Otherwise, we must return as tight as possible
1736 * an approximation to the area actually painted by glyphs.
1737 * @param aDrawTargetForTightBoundingBox when aTight is true, this must
1738 * be non-null.
1739 * @param aSpacing spacing to insert before and after glyphs. The bounding box
1740 * need not include the spacing itself, but the spacing affects the glyph
1741 * positions. null if there is no spacing.
1743 * Callers guarantee:
1744 * -- aStart and aEnd are aligned to cluster and ligature boundaries
1745 * -- all glyphs use this font
1747 * The default implementation just uses font metrics and aTextRun's
1748 * advances, and assumes no characters fall outside the font box. In
1749 * general this is insufficient, because that assumption is not always true.
1751 virtual RunMetrics Measure(const gfxTextRun* aTextRun, uint32_t aStart,
1752 uint32_t aEnd, BoundingBoxType aBoundingBoxType,
1753 DrawTarget* aDrawTargetForTightBoundingBox,
1754 Spacing* aSpacing,
1755 mozilla::gfx::ShapedTextFlags aOrientation);
1757 * Line breaks have been changed at the beginning and/or end of a substring
1758 * of the text. Reshaping may be required; glyph updating is permitted.
1759 * @return true if anything was changed, false otherwise
1761 bool NotifyLineBreaksChanged(gfxTextRun* aTextRun, uint32_t aStart,
1762 uint32_t aLength) {
1763 return false;
1766 // Expiration tracking
1767 nsExpirationState* GetExpirationState() { return &mExpirationState; }
1769 // Get the glyphID of a space
1770 uint16_t GetSpaceGlyph() const { return mSpaceGlyph; }
1772 gfxGlyphExtents* GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit);
1774 void SetupGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphID,
1775 bool aNeedTight, gfxGlyphExtents* aExtents);
1777 virtual bool AllowSubpixelAA() const { return true; }
1779 bool ApplySyntheticBold() const { return mApplySyntheticBold; }
1781 float AngleForSyntheticOblique() const;
1782 float SkewForSyntheticOblique() const;
1784 // Amount by which synthetic bold "fattens" the glyphs:
1785 // For size S up to a threshold size T, we use (0.25 + 3S / 4T),
1786 // so that the result ranges from 0.25 to 1.0; thereafter,
1787 // simply use (S / T).
1788 gfxFloat GetSyntheticBoldOffset() const {
1789 gfxFloat size = GetAdjustedSize();
1790 const gfxFloat threshold = 48.0;
1791 return size < threshold ? (0.25 + 0.75 * size / threshold)
1792 : (size / threshold);
1795 gfxFontEntry* GetFontEntry() const { return mFontEntry.get(); }
1796 bool HasCharacter(uint32_t ch) const {
1797 if (!mIsValid || (mUnicodeRangeMap && !mUnicodeRangeMap->test(ch))) {
1798 return false;
1800 return mFontEntry->HasCharacter(ch);
1803 const gfxCharacterMap* GetUnicodeRangeMap() const {
1804 return mUnicodeRangeMap.get();
1807 void SetUnicodeRangeMap(gfxCharacterMap* aUnicodeRangeMap) {
1808 mUnicodeRangeMap = aUnicodeRangeMap;
1811 uint16_t GetUVSGlyph(uint32_t aCh, uint32_t aVS) const {
1812 if (!mIsValid) {
1813 return 0;
1815 return mFontEntry->GetUVSGlyph(aCh, aVS);
1818 template <typename T>
1819 bool InitFakeSmallCapsRun(nsPresContext* aPresContext,
1820 DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
1821 const T* aText, uint32_t aOffset, uint32_t aLength,
1822 FontMatchType aMatchType,
1823 mozilla::gfx::ShapedTextFlags aOrientation,
1824 Script aScript, nsAtom* aLanguage,
1825 bool aSyntheticLower, bool aSyntheticUpper);
1827 // call the (virtual) InitTextRun method to do glyph generation/shaping,
1828 // limiting the length of text passed by processing the run in multiple
1829 // segments if necessary
1830 template <typename T>
1831 bool SplitAndInitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun,
1832 const T* aString, uint32_t aRunStart,
1833 uint32_t aRunLength, Script aRunScript,
1834 nsAtom* aLanguage,
1835 mozilla::gfx::ShapedTextFlags aOrientation);
1837 // Get a ShapedWord representing a single space for use in setting up a
1838 // gfxTextRun.
1839 bool ProcessSingleSpaceShapedWord(
1840 DrawTarget* aDrawTarget, bool aVertical, int32_t aAppUnitsPerDevUnit,
1841 mozilla::gfx::ShapedTextFlags aFlags, RoundingFlags aRounding,
1842 const std::function<void(gfxShapedWord*)>& aCallback);
1844 // Called by the gfxFontCache timer to increment the age of all the words,
1845 // so that they'll expire after a sufficient period of non-use.
1846 // Returns true if the cache is now empty, otherwise false.
1847 bool AgeCachedWords();
1849 // Discard all cached word records; called on memory-pressure notification.
1850 void ClearCachedWords() {
1851 mozilla::AutoWriteLock lock(mLock);
1852 if (mWordCache) {
1853 ClearCachedWordsLocked();
1856 void ClearCachedWordsLocked() MOZ_REQUIRES(mLock) {
1857 MOZ_ASSERT(mWordCache);
1858 mWordCache->clear();
1861 // Glyph rendering/geometry has changed, so invalidate data as necessary.
1862 void NotifyGlyphsChanged() const;
1864 virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
1865 FontCacheSizes* aSizes) const;
1866 virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
1867 FontCacheSizes* aSizes) const;
1869 typedef enum {
1870 FONT_TYPE_DWRITE,
1871 FONT_TYPE_GDI,
1872 FONT_TYPE_FT2,
1873 FONT_TYPE_MAC,
1874 FONT_TYPE_OS2,
1875 FONT_TYPE_CAIRO,
1876 FONT_TYPE_FONTCONFIG
1877 } FontType;
1879 virtual FontType GetType() const = 0;
1881 const RefPtr<mozilla::gfx::UnscaledFont>& GetUnscaledFont() const {
1882 return mUnscaledFont;
1885 virtual already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFont(
1886 const TextRunDrawParams& aRunParams) = 0;
1887 already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFont(
1888 mozilla::gfx::DrawTarget* aDrawTarget);
1890 // gfxFont implementations may cache ScaledFont versions other than the
1891 // default, so InitializeScaledFont must support explicitly specifying
1892 // which ScaledFonts to initialize.
1893 void InitializeScaledFont(
1894 const RefPtr<mozilla::gfx::ScaledFont>& aScaledFont);
1896 bool KerningDisabled() const { return mKerningSet && !mKerningEnabled; }
1899 * Subclass this object to be notified of glyph changes. Delete the object
1900 * when no longer needed.
1902 class GlyphChangeObserver {
1903 public:
1904 virtual ~GlyphChangeObserver() {
1905 if (mFont) {
1906 mFont->RemoveGlyphChangeObserver(this);
1909 // This gets called when the gfxFont dies.
1910 void ForgetFont() { mFont = nullptr; }
1911 virtual void NotifyGlyphsChanged() = 0;
1913 protected:
1914 explicit GlyphChangeObserver(gfxFont* aFont) : mFont(aFont) {
1915 mFont->AddGlyphChangeObserver(this);
1917 // This pointer is nulled by ForgetFont in the gfxFont's
1918 // destructor. Before the gfxFont dies.
1919 gfxFont* MOZ_NON_OWNING_REF mFont;
1921 friend class GlyphChangeObserver;
1923 bool GlyphsMayChange() const {
1924 // Currently only fonts with SVG glyphs can have animated glyphs
1925 return mFontEntry->TryGetSVGData(this);
1928 static void DestroySingletons() {
1929 delete sScriptTagToCode;
1930 delete sDefaultFeatures;
1933 // Call TryGetMathTable() to try and load the Open Type MATH table.
1934 // If (and ONLY if) TryGetMathTable() has returned true, the MathTable()
1935 // method may be called to access the gfxMathTable data.
1936 bool TryGetMathTable();
1937 gfxMathTable* MathTable() const {
1938 MOZ_RELEASE_ASSERT(mMathTable,
1939 "A successful call to TryGetMathTable() must be "
1940 "performed before calling this function");
1941 return mMathTable;
1944 // Return a cloned font resized and offset to simulate sub/superscript
1945 // glyphs. This does not add a reference to the returned font.
1946 already_AddRefed<gfxFont> GetSubSuperscriptFont(
1947 int32_t aAppUnitsPerDevPixel) const;
1949 bool HasColorGlyphFor(uint32_t aCh, uint32_t aNextCh);
1951 protected:
1952 virtual const Metrics& GetHorizontalMetrics() const = 0;
1954 void CreateVerticalMetrics();
1956 bool MeasureGlyphs(const gfxTextRun* aTextRun, uint32_t aStart, uint32_t aEnd,
1957 BoundingBoxType aBoundingBoxType,
1958 DrawTarget* aRefDrawTarget, Spacing* aSpacing,
1959 gfxGlyphExtents* aExtents, bool aIsRTL,
1960 bool aNeedsGlyphExtents, RunMetrics& aMetrics,
1961 gfxFloat* aAdvanceMin, gfxFloat* aAdvanceMax);
1963 bool MeasureGlyphs(const gfxTextRun* aTextRun, uint32_t aStart, uint32_t aEnd,
1964 BoundingBoxType aBoundingBoxType,
1965 DrawTarget* aRefDrawTarget, Spacing* aSpacing, bool aIsRTL,
1966 RunMetrics& aMetrics);
1968 // Template parameters for DrawGlyphs/DrawOneGlyph, used to select
1969 // simplified versions of the methods in the most common cases.
1970 enum class FontComplexityT { SimpleFont, ComplexFont };
1971 enum class SpacingT { NoSpacing, HasSpacing };
1973 // Output a run of glyphs at *aPt, which is updated to follow the last glyph
1974 // in the run. This method also takes account of any letter-spacing provided
1975 // in aRunParams.
1976 template <FontComplexityT FC, SpacingT S>
1977 bool DrawGlyphs(const gfxShapedText* aShapedText,
1978 uint32_t aOffset, // offset in the textrun
1979 uint32_t aCount, // length of run to draw
1980 mozilla::gfx::Point* aPt,
1981 // transform for mOffset field in DetailedGlyph records,
1982 // to account for rotations (may be null)
1983 const mozilla::gfx::Matrix* aOffsetMatrix,
1984 GlyphBufferAzure& aBuffer);
1986 // Output a single glyph at *aPt.
1987 // Normal glyphs are simply accumulated in aBuffer until it is full and
1988 // gets flushed, but SVG or color-font glyphs will instead be rendered
1989 // directly to the destination (found from the buffer's parameters).
1990 template <FontComplexityT FC>
1991 void DrawOneGlyph(uint32_t aGlyphID, const mozilla::gfx::Point& aPt,
1992 GlyphBufferAzure& aBuffer, bool* aEmittedGlyphs);
1994 // Helper for DrawOneGlyph to handle missing glyphs, rendering either
1995 // nothing (for default-ignorables) or a missing-glyph hexbox.
1996 bool DrawMissingGlyph(const TextRunDrawParams& aRunParams,
1997 const FontDrawParams& aFontParams,
1998 const gfxShapedText::DetailedGlyph* aDetails,
1999 const mozilla::gfx::Point& aPt);
2001 // set the font size and offset used for
2002 // synthetic subscript/superscript glyphs
2003 void CalculateSubSuperSizeAndOffset(int32_t aAppUnitsPerDevPixel,
2004 gfxFloat& aSubSuperSizeRatio,
2005 float& aBaselineOffset);
2007 // Return a font that is a "clone" of this one, but reduced to 80% size
2008 // (and with variantCaps set to normal). This does not add a reference to
2009 // the returned font.
2010 already_AddRefed<gfxFont> GetSmallCapsFont() const;
2012 // subclasses may provide (possibly hinted) glyph widths (in font units);
2013 // if they do not override this, harfbuzz will use unhinted widths
2014 // derived from the font tables
2015 virtual bool ProvidesGlyphWidths() const { return false; }
2017 // The return value is interpreted as a horizontal advance in 16.16 fixed
2018 // point format.
2019 virtual int32_t GetGlyphWidth(uint16_t aGID) { return -1; }
2021 virtual bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds,
2022 bool aTight = false) {
2023 return false;
2026 bool IsSpaceGlyphInvisible(DrawTarget* aRefDrawTarget,
2027 const gfxTextRun* aTextRun);
2029 void AddGlyphChangeObserver(GlyphChangeObserver* aObserver);
2030 void RemoveGlyphChangeObserver(GlyphChangeObserver* aObserver);
2032 // whether font contains substitution lookups containing spaces
2033 bool HasSubstitutionRulesWithSpaceLookups(Script aRunScript) const;
2035 // do spaces participate in shaping rules? if so, can't used word cache
2036 // Note that this function uses HasGraphiteSpaceContextuals, so it can only
2037 // return a "hint" to the correct answer. The calling code must ensure it
2038 // performs safe actions independent of the value returned.
2039 tainted_boolean_hint SpaceMayParticipateInShaping(Script aRunScript) const;
2041 // For 8-bit text, expand to 16-bit and then call the following method.
2042 bool ShapeText(DrawTarget* aContext, const uint8_t* aText,
2043 uint32_t aOffset, // dest offset in gfxShapedText
2044 uint32_t aLength, Script aScript, nsAtom* aLanguage,
2045 bool aVertical, RoundingFlags aRounding,
2046 gfxShapedText* aShapedText); // where to store the result
2048 // Call the appropriate shaper to generate glyphs for aText and store
2049 // them into aShapedText.
2050 virtual bool ShapeText(DrawTarget* aContext, const char16_t* aText,
2051 uint32_t aOffset, uint32_t aLength, Script aScript,
2052 nsAtom* aLanguage, bool aVertical,
2053 RoundingFlags aRounding, gfxShapedText* aShapedText);
2055 // Helper to adjust for synthetic bold and set character-type flags
2056 // in the shaped text; implementations of ShapeText should call this
2057 // after glyph shaping has been completed.
2058 void PostShapingFixup(DrawTarget* aContext, const char16_t* aText,
2059 uint32_t aOffset, // position within aShapedText
2060 uint32_t aLength, bool aVertical,
2061 gfxShapedText* aShapedText);
2063 // Shape text directly into a range within a textrun, without using the
2064 // font's word cache. Intended for use when the font has layout features
2065 // that involve space, and therefore require shaping complete runs rather
2066 // than isolated words, or for long strings that are inefficient to cache.
2067 // This will split the text on "invalid" characters (tab/newline) that are
2068 // not handled via normal shaping, but does not otherwise divide up the
2069 // text.
2070 template <typename T>
2071 bool ShapeTextWithoutWordCache(DrawTarget* aDrawTarget, const T* aText,
2072 uint32_t aOffset, uint32_t aLength,
2073 Script aScript, nsAtom* aLanguage,
2074 bool aVertical, RoundingFlags aRounding,
2075 gfxTextRun* aTextRun);
2077 // Shape a fragment of text (a run that is known to contain only
2078 // "valid" characters, no newlines/tabs/other control chars).
2079 // All non-wordcache shaping goes through here; this is the function
2080 // that will ensure we don't pass excessively long runs to the various
2081 // platform shapers.
2082 template <typename T>
2083 bool ShapeFragmentWithoutWordCache(DrawTarget* aDrawTarget, const T* aText,
2084 uint32_t aOffset, uint32_t aLength,
2085 Script aScript, nsAtom* aLanguage,
2086 bool aVertical, RoundingFlags aRounding,
2087 gfxTextRun* aTextRun);
2089 void CheckForFeaturesInvolvingSpace() const;
2091 // Get a ShapedWord representing the given text (either 8- or 16-bit)
2092 // for use in setting up a gfxTextRun.
2093 template <typename T, typename Func>
2094 bool ProcessShapedWordInternal(DrawTarget* aDrawTarget, const T* aText,
2095 uint32_t aLength, uint32_t aHash,
2096 Script aRunScript, nsAtom* aLanguage,
2097 bool aVertical, int32_t aAppUnitsPerDevUnit,
2098 mozilla::gfx::ShapedTextFlags aFlags,
2099 RoundingFlags aRounding,
2100 gfxTextPerfMetrics* aTextPerf, Func aCallback);
2102 // whether a given feature is included in feature settings from both the
2103 // font and the style. aFeatureOn set if resolved feature value is non-zero
2104 bool HasFeatureSet(uint32_t aFeature, bool& aFeatureOn);
2106 // used when analyzing whether a font has space contextual lookups
2107 static mozilla::Atomic<nsTHashMap<nsUint32HashKey, Script>*> sScriptTagToCode;
2108 static mozilla::Atomic<nsTHashSet<uint32_t>*> sDefaultFeatures;
2110 RefPtr<gfxFontEntry> mFontEntry;
2111 mutable mozilla::RWLock mLock;
2113 // Note that WordCacheKey contains a pointer to the text of the word, which
2114 // must be valid for as long as the key is in use. When using for a Lookup,
2115 // the string may be local/temporary, but when storing in the HashMap, we
2116 // set the Key text pointer to reference the text in the associated
2117 // gfxShapedWord that is being stored.
2118 struct WordCacheKey {
2119 union {
2120 const uint8_t* mSingle;
2121 const char16_t* mDouble;
2122 } mText;
2123 uint32_t mLength;
2124 ShapedTextFlags mFlags;
2125 Script mScript;
2126 RefPtr<nsAtom> mLanguage;
2127 int32_t mAppUnitsPerDevUnit;
2128 PLDHashNumber mHashKey;
2129 bool mTextIs8Bit;
2130 RoundingFlags mRounding;
2132 WordCacheKey(const uint8_t* aText, uint32_t aLength, uint32_t aStringHash,
2133 Script aScriptCode, nsAtom* aLanguage,
2134 int32_t aAppUnitsPerDevUnit, ShapedTextFlags aFlags,
2135 RoundingFlags aRounding)
2136 : mLength(aLength),
2137 mFlags(aFlags),
2138 mScript(aScriptCode),
2139 mLanguage(aLanguage),
2140 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
2141 mHashKey(aStringHash + static_cast<int32_t>(aScriptCode) +
2142 aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 +
2143 int(aRounding) + (aLanguage ? aLanguage->hash() : 0)),
2144 mTextIs8Bit(true),
2145 mRounding(aRounding) {
2146 NS_ASSERTION(aFlags & ShapedTextFlags::TEXT_IS_8BIT,
2147 "8-bit flag should have been set");
2148 mText.mSingle = aText;
2151 WordCacheKey(const char16_t* aText, uint32_t aLength, uint32_t aStringHash,
2152 Script aScriptCode, nsAtom* aLanguage,
2153 int32_t aAppUnitsPerDevUnit, ShapedTextFlags aFlags,
2154 RoundingFlags aRounding)
2155 : mLength(aLength),
2156 mFlags(aFlags),
2157 mScript(aScriptCode),
2158 mLanguage(aLanguage),
2159 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
2160 mHashKey(aStringHash + static_cast<int32_t>(aScriptCode) +
2161 aAppUnitsPerDevUnit * 0x100 + uint16_t(aFlags) * 0x10000 +
2162 int(aRounding)),
2163 mTextIs8Bit(false),
2164 mRounding(aRounding) {
2165 // We can NOT assert that TEXT_IS_8BIT is false in aFlags here,
2166 // because this might be an 8bit-only word from a 16-bit textrun,
2167 // in which case the text we're passed is still in 16-bit form,
2168 // and we'll have to use an 8-to-16bit comparison in KeyEquals.
2169 mText.mDouble = aText;
2172 bool Matches(const WordCacheKey& aLookup) const;
2174 class HashPolicy {
2175 public:
2176 typedef WordCacheKey Key;
2177 typedef WordCacheKey Lookup;
2178 static mozilla::HashNumber hash(const Lookup& aLookup) {
2179 return aLookup.mHashKey;
2181 static bool match(const Key& aKey, const Lookup& aLookup);
2185 mozilla::UniquePtr<
2186 mozilla::HashMap<WordCacheKey, mozilla::UniquePtr<gfxShapedWord>,
2187 WordCacheKey::HashPolicy>>
2188 mWordCache MOZ_GUARDED_BY(mLock);
2190 static const uint32_t kShapedWordCacheMaxAge = 3;
2192 nsTArray<mozilla::UniquePtr<gfxGlyphExtents>> mGlyphExtentsArray
2193 MOZ_GUARDED_BY(mLock);
2194 mozilla::UniquePtr<nsTHashSet<GlyphChangeObserver*>> mGlyphChangeObservers
2195 MOZ_GUARDED_BY(mLock);
2197 // a copy of the font without antialiasing, if needed for separate
2198 // measurement by mathml code
2199 mozilla::Atomic<gfxFont*> mNonAAFont;
2201 // we create either or both of these shapers when needed, depending
2202 // whether the font has graphite tables, and whether graphite shaping
2203 // is actually enabled
2204 mozilla::Atomic<gfxHarfBuzzShaper*> mHarfBuzzShaper;
2205 mozilla::Atomic<gfxGraphiteShaper*> mGraphiteShaper;
2207 // If a userfont with unicode-range specified, contains map of *possible*
2208 // ranges supported by font. This is set during user-font initialization,
2209 // before the font is available to other threads, and thereafter is inert
2210 // so no guard is needed.
2211 RefPtr<gfxCharacterMap> mUnicodeRangeMap;
2213 // This is immutable once initialized by the constructor, so does not need
2214 // locking.
2215 RefPtr<mozilla::gfx::UnscaledFont> mUnscaledFont;
2217 mozilla::Atomic<mozilla::gfx::ScaledFont*> mAzureScaledFont;
2219 // For vertical metrics, created on demand.
2220 mozilla::Atomic<Metrics*> mVerticalMetrics;
2222 // Table used for MathML layout.
2223 mozilla::Atomic<gfxMathTable*> mMathTable;
2225 gfxFontStyle mStyle;
2226 mutable gfxFloat mAdjustedSize;
2228 // Tracking adjustment to be applied for CSS px size mCachedTrackingSize.
2229 gfxFloat mTracking = 0.0;
2230 gfxFloat mCachedTrackingSize = -1.0;
2232 // Conversion factor from font units to dev units; note that this may be
2233 // zero (in the degenerate case where mAdjustedSize has become zero).
2234 // This is OK because we only multiply by this factor, never divide.
2235 float mFUnitsConvFactor;
2237 // This is guarded by gfxFontCache::GetCache()->GetMutex() but it is difficult
2238 // to annotate that fact.
2239 nsExpirationState mExpirationState;
2241 // Glyph ID of the font's <space> glyph, zero if missing
2242 uint16_t mSpaceGlyph = 0;
2244 // the AA setting requested for this font - may affect glyph bounds
2245 AntialiasOption mAntialiasOption;
2247 bool mIsValid;
2249 // use synthetic bolding for environments where this is not supported
2250 // by the platform
2251 bool mApplySyntheticBold;
2253 bool mKerningSet; // kerning explicitly set?
2254 bool mKerningEnabled; // if set, on or off?
2256 mozilla::Atomic<bool> mMathInitialized; // TryGetMathTable() called?
2258 // Helper for subclasses that want to initialize standard metrics from the
2259 // tables of sfnt (TrueType/OpenType) fonts.
2260 // This will use mFUnitsConvFactor if it is already set, else compute it
2261 // from mAdjustedSize and the unitsPerEm in the font's 'head' table.
2262 // Returns TRUE and sets mIsValid=TRUE if successful;
2263 // Returns TRUE but leaves mIsValid=FALSE if the font seems to be broken.
2264 // Returns FALSE if the font does not appear to be an sfnt at all,
2265 // and should be handled (if possible) using other APIs.
2266 bool InitMetricsFromSfntTables(Metrics& aMetrics);
2268 // Helper to calculate various derived metrics from the results of
2269 // InitMetricsFromSfntTables or equivalent platform code
2270 void CalculateDerivedMetrics(Metrics& aMetrics);
2272 // some fonts have bad metrics, this method sanitize them.
2273 // if this font has bad underline offset, aIsBadUnderlineFont should be true.
2274 void SanitizeMetrics(Metrics* aMetrics, bool aIsBadUnderlineFont);
2276 bool RenderSVGGlyph(gfxContext* aContext,
2277 mozilla::layout::TextDrawTarget* aTextDrawer,
2278 mozilla::gfx::Point aPoint, uint32_t aGlyphId,
2279 SVGContextPaint* aContextPaint) const;
2280 bool RenderSVGGlyph(gfxContext* aContext,
2281 mozilla::layout::TextDrawTarget* aTextDrawer,
2282 mozilla::gfx::Point aPoint, uint32_t aGlyphId,
2283 SVGContextPaint* aContextPaint,
2284 gfxTextRunDrawCallbacks* aCallbacks,
2285 bool& aEmittedGlyphs) const;
2287 bool RenderColorGlyph(DrawTarget* aDrawTarget, gfxContext* aContext,
2288 mozilla::layout::TextDrawTarget* aTextDrawer,
2289 const FontDrawParams& aFontParams,
2290 const mozilla::gfx::Point& aPoint, uint32_t aGlyphId);
2292 class ColorGlyphCache {
2293 public:
2294 ColorGlyphCache() = default;
2295 ~ColorGlyphCache() = default;
2297 void SetColors(mozilla::gfx::sRGBColor aCurrentColor,
2298 mozilla::gfx::FontPalette* aPalette);
2300 mozilla::HashMap<uint32_t, RefPtr<mozilla::gfx::SourceSurface>> mCache;
2302 private:
2303 mozilla::gfx::sRGBColor mCurrentColor;
2304 RefPtr<mozilla::gfx::FontPalette> mPalette;
2306 mozilla::UniquePtr<ColorGlyphCache> mColorGlyphCache;
2308 // Subclasses can override to return true if the platform is able to render
2309 // COLR-font glyphs directly, instead of us painting the layers explicitly.
2310 // (Currently used only for COLR.v0 fonts on macOS.)
2311 virtual bool UseNativeColrFontSupport() const { return false; }
2313 // Bug 674909. When synthetic bolding text by drawing twice, need to
2314 // render using a pixel offset in device pixels, otherwise text
2315 // doesn't appear bolded, it appears as if a bad text shadow exists
2316 // when a non-identity transform exists. Use an offset factor so that
2317 // the second draw occurs at a constant offset in device pixels.
2318 // This helper calculates the scale factor we need to apply to the
2319 // synthetic-bold offset.
2320 static mozilla::gfx::Float CalcXScale(DrawTarget* aDrawTarget);
2323 // proportion of ascent used for x-height, if unable to read value from font
2324 #define DEFAULT_XHEIGHT_FACTOR 0.56f
2326 // Parameters passed to gfxFont methods for drawing glyphs from a textrun.
2327 // The TextRunDrawParams are set up once per textrun; the FontDrawParams
2328 // are dependent on the specific font, so they are set per GlyphRun.
2330 struct MOZ_STACK_CLASS TextRunDrawParams {
2331 explicit TextRunDrawParams(mozilla::gfx::PaletteCache& aPaletteCache)
2332 : paletteCache(aPaletteCache) {}
2334 mozilla::gfx::PaletteCache& paletteCache;
2335 RefPtr<mozilla::gfx::DrawTarget> dt;
2336 gfxContext* context = nullptr;
2337 gfxFont::Spacing* spacing = nullptr;
2338 gfxTextRunDrawCallbacks* callbacks = nullptr;
2339 mozilla::SVGContextPaint* runContextPaint = nullptr;
2340 mozilla::layout::TextDrawTarget* textDrawer = nullptr;
2341 mozilla::LayoutDeviceRect clipRect;
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 nsAtom* fontPalette = nullptr;
2349 DrawMode drawMode = DrawMode::GLYPH_FILL;
2350 bool isVerticalRun = false;
2351 bool isRTL = false;
2352 bool paintSVGGlyphs = true;
2353 bool allowGDI = true;
2354 bool hasTextShadow = false;
2357 struct MOZ_STACK_CLASS FontDrawParams {
2358 RefPtr<mozilla::gfx::ScaledFont> scaledFont;
2359 mozilla::SVGContextPaint* contextPaint;
2360 mozilla::gfx::Float synBoldOnePixelOffset;
2361 mozilla::gfx::Float obliqueSkew;
2362 int32_t extraStrikes;
2363 mozilla::gfx::DrawOptions drawOptions;
2364 gfxFloat advanceDirection;
2365 mozilla::gfx::sRGBColor currentColor;
2366 RefPtr<mozilla::gfx::FontPalette> palette;
2367 mozilla::gfx::Rect fontExtents;
2368 bool isVerticalFont;
2369 bool haveSVGGlyphs;
2370 bool haveColorGlyphs;
2371 bool hasTextShadow; // whether we're rendering with a text-shadow
2374 struct MOZ_STACK_CLASS EmphasisMarkDrawParams {
2375 EmphasisMarkDrawParams(gfxContext* aContext,
2376 mozilla::gfx::PaletteCache& aPaletteCache)
2377 : context(aContext), paletteCache(aPaletteCache) {}
2378 gfxContext* context;
2379 mozilla::gfx::PaletteCache& paletteCache;
2380 gfxFont::Spacing* spacing;
2381 gfxTextRun* mark;
2382 gfxFloat advance;
2383 gfxFloat direction;
2384 bool isVertical;
2387 #endif