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/. */
13 #include "PLDHashTable.h"
14 #include "ThebesRLBoxTypes.h"
15 #include "gfxFontVariations.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"
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"
46 #include "nsTHashtable.h"
50 // Only required for function bodies
51 #include "gfxFontEntry.h"
52 #include "gfxFontFeatures.h"
55 class gfxGraphiteShaper
;
56 class gfxHarfBuzzShaper
;
57 class gfxGlyphExtents
;
66 struct gfxTextRunDrawCallbacks
;
69 class SVGContextPaint
;
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.
85 # define OBLIQUE_SKEW_FACTOR 0.3f
86 #elif defined(MOZ_WIDGET_GTK)
87 # define OBLIQUE_SKEW_FACTOR 0.2f
89 # define OBLIQUE_SKEW_FACTOR 0.25f
93 using FontStretch
= mozilla::FontStretch
;
94 using FontSlantStyle
= mozilla::FontSlantStyle
;
95 using FontWeight
= mozilla::FontWeight
;
96 using FontSizeAdjust
= mozilla::StyleFontSizeAdjust
;
99 gfxFontStyle(FontSlantStyle aStyle
, FontWeight aWeight
, FontStretch aStretch
,
100 gfxFloat aSize
, const FontSizeAdjust
& aSizeAdjust
,
101 bool aSystemFont
, bool aPrinterFont
, bool aWeightSynthesis
,
102 bool aStyleSynthesis
, bool aSmallCapsSynthesis
,
103 bool aPositionSynthesis
, uint32_t aLanguageOverride
);
104 // Features are composed of (1) features from style rules (2) features
105 // from feature settings rules and (3) family-specific features. (1) and
106 // (3) are guaranteed to be mutually exclusive
108 // custom opentype feature settings
109 CopyableTArray
<gfxFontFeature
> featureSettings
;
111 // Some font-variant property values require font-specific settings
112 // defined via @font-feature-values rules. These are resolved after
113 // font matching occurs.
115 // -- list of value tags for specific alternate features
116 mozilla::StyleFontVariantAlternates variantAlternates
;
118 // -- object used to look these up once the font is matched
119 RefPtr
<gfxFontFeatureValueSet
> featureValueLookup
;
121 // opentype variation settings
122 CopyableTArray
<gfxFontVariation
> variationSettings
;
124 // The logical size of the font, in pixels
127 // The optical size value to apply (if supported); negative means none.
128 float autoOpticalSize
= -1.0f
;
130 // The aspect-value (ie., the ratio actualsize:actualxheight) that any
131 // actual physical font created from this font structure must have when
132 // rendering or measuring a string. A value of -1.0 means no adjustment
133 // needs to be done; otherwise the value must be nonnegative.
136 // baseline offset, used when simulating sub/superscript glyphs
137 float baselineOffset
;
139 // Language system tag, to override document language;
140 // an OpenType "language system" tag represented as a 32-bit integer
141 // (see http://www.microsoft.com/typography/otspec/languagetags.htm).
142 // Normally 0, so font rendering will use the document or element language
143 // (see above) to control any language-specific rendering, but the author
144 // can override this for cases where the options implemented in the font
145 // do not directly match the actual language. (E.g. lang may be Macedonian,
146 // but the font in use does not explicitly support this; the author can
147 // use font-language-override to request the Serbian option in the font
148 // in order to get correct glyph shapes.)
149 uint32_t languageOverride
;
151 // The Font{Weight,Stretch,SlantStyle} fields are each a 16-bit type.
153 // The weight of the font: 100, 200, ... 900.
156 // The stretch of the font
160 FontSlantStyle style
;
162 // Whether face-selection properties weight/style/stretch are all 'normal'
163 bool IsNormalStyle() const {
164 return weight
.IsNormal() && style
.IsNormal() && stretch
.IsNormal();
167 // We pack these three small-integer fields into a single byte to avoid
168 // overflowing an 8-byte boundary [in a 64-bit build] and ending up with
169 // 7 bytes of padding at the end of the struct.
171 // caps variant (small-caps, petite-caps, etc.)
172 uint8_t variantCaps
: 3; // uses range 0..6
174 // sub/superscript variant
175 uint8_t variantSubSuper
: 2; // uses range 0..2
177 // font metric used as basis of font-size-adjust
178 uint8_t sizeAdjustBasis
: 3; // uses range 0..4
180 // Say that this font is a system font and therefore does not
181 // require certain fixup that we do for fonts from untrusted
185 // Say that this font is used for print or print preview.
186 bool printerFont
: 1;
188 // Used to imitate -webkit-font-smoothing: antialiased
189 bool useGrayscaleAntialiasing
: 1;
191 // Whether synthetic styles are allowed (required, in the case of position)
192 bool allowSyntheticWeight
: 1;
193 bool allowSyntheticStyle
: 1;
194 bool allowSyntheticSmallCaps
: 1;
195 bool useSyntheticPosition
: 1;
197 // some variant features require fallback which complicates the shaping
198 // code, so set up a bool to indicate when shaping with fallback is needed
199 bool noFallbackVariantFeatures
: 1;
201 // Return the final adjusted font size for the given aspect ratio.
202 // Not meant to be called when sizeAdjustBasis is NONE.
203 gfxFloat
GetAdjustedSize(gfxFloat aspect
) const {
205 FontSizeAdjust::Tag(sizeAdjustBasis
) != FontSizeAdjust::Tag::None
,
206 "Not meant to be called when sizeAdjustBasis is none");
207 gfxFloat adjustedSize
=
208 std::max(NS_round(size
* (sizeAdjust
/ aspect
)), 1.0);
209 return std::min(adjustedSize
, FONT_MAX_SIZE
);
212 // Some callers want to take a short-circuit path if they can be sure the
213 // adjusted size will be zero.
214 bool AdjustedSizeMustBeZero() const {
215 return size
== 0.0 ||
216 (FontSizeAdjust::Tag(sizeAdjustBasis
) != FontSizeAdjust::Tag::None
&&
220 PLDHashNumber
Hash() const;
222 // Adjust this style to simulate sub/superscript (as requested in the
223 // variantSubSuper field) using size and baselineOffset instead.
224 void AdjustForSubSuperscript(int32_t aAppUnitsPerDevPixel
);
226 // Should this style cause the given font entry to use synthetic bold?
227 bool NeedsSyntheticBold(gfxFontEntry
* aFontEntry
) const {
228 return weight
.IsBold() && allowSyntheticWeight
&&
229 !aFontEntry
->SupportsBold();
232 bool Equals(const gfxFontStyle
& other
) const {
233 return mozilla::NumbersAreBitwiseIdentical(size
, other
.size
) &&
234 (style
== other
.style
) && (weight
== other
.weight
) &&
235 (stretch
== other
.stretch
) && (variantCaps
== other
.variantCaps
) &&
236 (variantSubSuper
== other
.variantSubSuper
) &&
237 (allowSyntheticWeight
== other
.allowSyntheticWeight
) &&
238 (allowSyntheticStyle
== other
.allowSyntheticStyle
) &&
239 (allowSyntheticSmallCaps
== other
.allowSyntheticSmallCaps
) &&
240 (useSyntheticPosition
== other
.useSyntheticPosition
) &&
241 (systemFont
== other
.systemFont
) &&
242 (printerFont
== other
.printerFont
) &&
243 (useGrayscaleAntialiasing
== other
.useGrayscaleAntialiasing
) &&
244 (baselineOffset
== other
.baselineOffset
) &&
245 mozilla::NumbersAreBitwiseIdentical(sizeAdjust
, other
.sizeAdjust
) &&
246 (sizeAdjustBasis
== other
.sizeAdjustBasis
) &&
247 (featureSettings
== other
.featureSettings
) &&
248 (variantAlternates
== other
.variantAlternates
) &&
249 (featureValueLookup
== other
.featureValueLookup
) &&
250 (variationSettings
== other
.variationSettings
) &&
251 (languageOverride
== other
.languageOverride
) &&
252 mozilla::NumbersAreBitwiseIdentical(autoOpticalSize
,
253 other
.autoOpticalSize
);
260 * The mFonts hashtable contains most fonts, indexed by (gfxFontEntry*, style).
261 * It maintains a strong reference to the fonts it contains.
262 * Whenever a font is accessed, it is marked as used to move it to a new
263 * generation in the tracker to avoid expiration.
264 * The expiration tracker will only expire fonts with a single reference, the
265 * cache itself. Fonts with more than one reference are marked as used.
267 * We're using 3 generations with a ten-second generation interval, so
268 * zero-refcount fonts will be deleted 20-30 seconds after their refcount
269 * goes to zero, if timer events fire in a timely manner.
271 * The font cache also handles timed expiration of cached ShapedWords
272 * for "persistent" fonts: it has a repeating timer, and notifies
273 * each cached font to "age" its shaped words. The words will be released
274 * by the fonts if they get aged three times without being re-used in the
277 * Note that the ShapedWord timeout is much larger than the font timeout,
278 * so that in the case of a short-lived font, we'll discard the gfxFont
279 * completely, with all its words, and avoid the cost of aging the words
280 * individually. That only happens with longer-lived fonts.
282 struct FontCacheSizes
{
283 FontCacheSizes() : mFontInstances(0), mShapedWords(0) {}
285 size_t mFontInstances
; // memory used by instances of gfxFont subclasses
286 size_t mShapedWords
; // memory used by the per-font shapedWord caches
289 class gfxFontCache final
290 : public ExpirationTrackerImpl
<gfxFont
, 3, mozilla::Mutex
,
291 mozilla::MutexAutoLock
> {
293 // Expiration tracker implementation.
294 enum { FONT_TIMEOUT_SECONDS
= 10 };
296 typedef mozilla::Mutex Lock
;
297 typedef mozilla::MutexAutoLock AutoLock
;
299 // This protects the ExpirationTracker tables.
300 Lock mMutex
= Lock("fontCacheExpirationMutex");
302 Lock
& GetMutex() override
{ return mMutex
; }
305 explicit gfxFontCache(nsIEventTarget
* aEventTarget
);
308 enum { SHAPED_WORD_TIMEOUT_SECONDS
= 60 };
311 * Get the global gfxFontCache. You must call Init() before
312 * calling this method --- the result will not be null.
314 static gfxFontCache
* GetCache() { return gGlobalCache
; }
316 static nsresult
Init();
317 // It's OK to call this even if Init() has not been called.
318 static void Shutdown();
320 // Look up a font in the cache. Returns null if there's nothing matching
322 already_AddRefed
<gfxFont
> Lookup(const gfxFontEntry
* aFontEntry
,
323 const gfxFontStyle
* aStyle
,
324 const gfxCharacterMap
* aUnicodeRangeMap
);
326 // We created a new font (presumably because Lookup returned null);
327 // put it in the cache. The font's refcount should be nonzero. It is
328 // allowable to add a new font even if there is one already in the
329 // cache with the same key, as we may race with other threads to do
330 // the insertion -- in that case we will return the original font,
331 // and destroy the new one.
332 already_AddRefed
<gfxFont
> MaybeInsert(gfxFont
* aFont
);
334 bool MaybeDestroy(gfxFont
* aFont
);
336 // Cleans out the hashtable and removes expired fonts waiting for cleanup.
337 // Other gfxFont objects may be still in use but they will be pushed
338 // into the expiration queues and removed.
341 void FlushShapedWordCaches();
342 void NotifyGlyphsChanged();
344 void AgeCachedWords();
346 void RunWordCacheExpirationTimer() {
347 if (!mTimerRunning
) {
348 mozilla::MutexAutoLock
lock(mMutex
);
349 if (!mTimerRunning
&& mWordCacheExpirationTimer
) {
350 mWordCacheExpirationTimer
->InitWithNamedFuncCallback(
351 WordCacheExpirationTimerCallback
, this,
352 SHAPED_WORD_TIMEOUT_SECONDS
* 1000, nsITimer::TYPE_REPEATING_SLACK
,
353 "gfxFontCache::WordCacheExpiration");
354 mTimerRunning
= true;
358 void PauseWordCacheExpirationTimer() {
360 mozilla::MutexAutoLock
lock(mMutex
);
361 if (mTimerRunning
&& mWordCacheExpirationTimer
) {
362 mWordCacheExpirationTimer
->Cancel();
363 mTimerRunning
= false;
368 void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
369 FontCacheSizes
* aSizes
) const;
370 void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
371 FontCacheSizes
* aSizes
) const;
374 class MemoryReporter final
: public nsIMemoryReporter
{
375 ~MemoryReporter() = default;
379 NS_DECL_NSIMEMORYREPORTER
382 // Observer for notifications that the font cache cares about
383 class Observer final
: public nsIObserver
{
384 ~Observer() = default;
391 nsresult
AddObject(gfxFont
* aFont
) {
392 AutoLock
lock(mMutex
);
393 return AddObjectLocked(aFont
, lock
);
396 // This gets called when the timeout has expired on a single-refcount
397 // font; we just delete it.
398 void NotifyExpiredLocked(gfxFont
* aFont
, const AutoLock
&)
399 MOZ_REQUIRES(mMutex
) override
;
400 void NotifyHandlerEnd() override
;
402 void DestroyDiscard(nsTArray
<gfxFont
*>& aDiscard
);
404 static gfxFontCache
* gGlobalCache
;
406 struct MOZ_STACK_CLASS Key
{
407 const gfxFontEntry
* mFontEntry
;
408 const gfxFontStyle
* mStyle
;
409 const gfxCharacterMap
* mUnicodeRangeMap
;
410 Key(const gfxFontEntry
* aFontEntry
, const gfxFontStyle
* aStyle
,
411 const gfxCharacterMap
* aUnicodeRangeMap
)
412 : mFontEntry(aFontEntry
),
414 mUnicodeRangeMap(aUnicodeRangeMap
) {}
417 class HashEntry
: public PLDHashEntryHdr
{
419 typedef const Key
& KeyType
;
420 typedef const Key
* KeyTypePointer
;
422 // When constructing a new entry in the hashtable, we'll leave this
423 // blank. The caller of Put() will fill this in.
424 explicit HashEntry(KeyTypePointer aStr
) {}
426 bool KeyEquals(const KeyTypePointer aKey
) const;
427 static KeyTypePointer
KeyToPointer(KeyType aKey
) { return &aKey
; }
428 static PLDHashNumber
HashKey(const KeyTypePointer aKey
) {
429 return mozilla::HashGeneric(aKey
->mStyle
->Hash(), aKey
->mFontEntry
,
430 aKey
->mUnicodeRangeMap
);
432 enum { ALLOW_MEMMOVE
= true };
434 gfxFont
* MOZ_UNSAFE_REF("tracking for deferred deletion") mFont
= nullptr;
437 nsTHashtable
<HashEntry
> mFonts
MOZ_GUARDED_BY(mMutex
);
439 nsTArray
<gfxFont
*> mTrackerDiscard
MOZ_GUARDED_BY(mMutex
);
441 static void WordCacheExpirationTimerCallback(nsITimer
* aTimer
, void* aCache
);
443 nsCOMPtr
<nsITimer
> mWordCacheExpirationTimer
MOZ_GUARDED_BY(mMutex
);
444 std::atomic
<bool> mTimerRunning
= false;
447 class gfxTextPerfMetrics
{
450 uint32_t numContentTextRuns
;
451 uint32_t numChromeTextRuns
;
453 uint32_t maxTextRunLen
;
454 uint32_t wordCacheSpaceRules
;
455 uint32_t wordCacheLong
;
456 uint32_t wordCacheHit
;
457 uint32_t wordCacheMiss
;
458 uint32_t fallbackPrefs
;
459 uint32_t fallbackSystem
;
460 uint32_t textrunConst
;
461 uint32_t textrunDestr
;
462 uint32_t genericLookups
;
465 uint32_t reflowCount
;
467 // counts per reflow operation
470 // totals for the lifetime of a document
471 TextCounts cumulative
;
473 gfxTextPerfMetrics() { memset(this, 0, sizeof(gfxTextPerfMetrics
)); }
475 // add current totals to cumulative ones
477 if (current
.numChars
== 0) {
480 cumulative
.numContentTextRuns
+= current
.numContentTextRuns
;
481 cumulative
.numChromeTextRuns
+= current
.numChromeTextRuns
;
482 cumulative
.numChars
+= current
.numChars
;
483 if (current
.maxTextRunLen
> cumulative
.maxTextRunLen
) {
484 cumulative
.maxTextRunLen
= current
.maxTextRunLen
;
486 cumulative
.wordCacheSpaceRules
+= current
.wordCacheSpaceRules
;
487 cumulative
.wordCacheLong
+= current
.wordCacheLong
;
488 cumulative
.wordCacheHit
+= current
.wordCacheHit
;
489 cumulative
.wordCacheMiss
+= current
.wordCacheMiss
;
490 cumulative
.fallbackPrefs
+= current
.fallbackPrefs
;
491 cumulative
.fallbackSystem
+= current
.fallbackSystem
;
492 cumulative
.textrunConst
+= current
.textrunConst
;
493 cumulative
.textrunDestr
+= current
.textrunDestr
;
494 cumulative
.genericLookups
+= current
.genericLookups
;
495 memset(¤t
, 0, sizeof(current
));
504 // Flags that live in the gfxShapedText::mFlags field.
505 // (Note that gfxTextRun has an additional mFlags2 field for use
506 // by textrun clients like nsTextFrame.)
508 // If you add a flag, please add support for it in gfxTextRun::Dump.
509 enum class ShapedTextFlags
: uint16_t {
511 * When set, the text is RTL.
513 TEXT_IS_RTL
= 0x0001,
515 * When set, spacing is enabled and the textrun needs to call GetSpacing
516 * on the spacing provider.
518 TEXT_ENABLE_SPACING
= 0x0002,
520 * When set, the text has no characters above 255 and it is stored
521 * in the textrun in 8-bit format.
523 TEXT_IS_8BIT
= 0x0004,
525 * When set, GetHyphenationBreaks may return true for some character
526 * positions, otherwise it will always return false for all characters.
528 TEXT_ENABLE_HYPHEN_BREAKS
= 0x0008,
530 * When set, the RunMetrics::mBoundingBox field will be initialized
531 * properly based on glyph extents, in particular, glyph extents that
532 * overflow the standard font-box (the box defined by the ascent, descent
533 * and advance width of the glyph). When not set, it may just be the
534 * standard font-box even if glyphs overflow.
536 TEXT_NEED_BOUNDING_BOX
= 0x0010,
538 * When set, optional ligatures are disabled. Ligatures that are
539 * required for legible text should still be enabled.
541 TEXT_DISABLE_OPTIONAL_LIGATURES
= 0x0020,
543 * When set, the textrun should favour speed of construction over
544 * quality. This may involve disabling ligatures and/or kerning or
547 TEXT_OPTIMIZE_SPEED
= 0x0040,
549 * When set, the textrun should discard control characters instead of
550 * turning them into hexboxes.
552 TEXT_HIDE_CONTROL_CHARACTERS
= 0x0080,
555 * nsTextFrameThebes sets these, but they're defined here rather than
556 * in nsTextFrameUtils.h because ShapedWord creation/caching also needs
557 * to check the _INCOMING flag
559 TEXT_TRAILING_ARABICCHAR
= 0x0100,
561 * When set, the previous character for this textrun was an Arabic
562 * character. This is used for the context detection necessary for
563 * bidi.numeral implementation.
565 TEXT_INCOMING_ARABICCHAR
= 0x0200,
568 * Set if the textrun should use the OpenType 'math' script.
570 TEXT_USE_MATH_SCRIPT
= 0x0400,
573 * Bit 0x0800 is currently unused.
577 * Field for orientation of the textrun and glyphs within it.
578 * Possible values of the TEXT_ORIENT_MASK field:
579 * TEXT_ORIENT_HORIZONTAL
580 * TEXT_ORIENT_VERTICAL_UPRIGHT
581 * TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT
582 * TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT
583 * TEXT_ORIENT_VERTICAL_MIXED
584 * For all VERTICAL settings, the x and y coordinates of glyph
585 * positions are exchanged, so that simple advances are vertical.
587 * The MIXED value indicates vertical textRuns for which the CSS
588 * text-orientation property is 'mixed', but is never used for
589 * individual glyphRuns; it will be resolved to either UPRIGHT
590 * or SIDEWAYS_RIGHT according to the UTR50 properties of the
591 * characters, and separate glyphRuns created for the resulting
592 * glyph orientations.
594 TEXT_ORIENT_MASK
= 0x7000,
595 TEXT_ORIENT_HORIZONTAL
= 0x0000,
596 TEXT_ORIENT_VERTICAL_UPRIGHT
= 0x1000,
597 TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT
= 0x2000,
598 TEXT_ORIENT_VERTICAL_MIXED
= 0x3000,
599 TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT
= 0x4000,
602 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ShapedTextFlags
)
604 } // namespace mozilla
606 class gfxTextRunFactory
{
608 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxTextRunFactory
)
611 typedef mozilla::gfx::DrawTarget DrawTarget
;
614 * This record contains all the parameters needed to initialize a textrun.
616 struct MOZ_STACK_CLASS Parameters
{
617 // Shape text params suggesting where the textrun will be rendered
618 DrawTarget
* mDrawTarget
;
619 // Pointer to arbitrary user data (which should outlive the textrun)
621 // A description of which characters have been stripped from the original
622 // DOM string to produce the characters in the textrun. May be null
623 // if that information is not relevant.
624 gfxSkipChars
* mSkipChars
;
625 // A list of where linebreaks are currently placed in the textrun. May
626 // be null if mInitialBreakCount is zero.
627 uint32_t* mInitialBreaks
;
628 uint32_t mInitialBreakCount
;
629 // The ratio to use to convert device pixels to application layout units
630 int32_t mAppUnitsPerDevUnit
;
634 // Protected destructor, to discourage deletion outside of Release():
635 virtual ~gfxTextRunFactory();
641 * This class implements text shaping (character to glyph mapping and
642 * glyph layout). There is a gfxFontShaper subclass for each text layout
643 * technology (uniscribe, core text, harfbuzz,....) we support.
645 * The shaper is responsible for setting up glyph data in gfxTextRuns.
647 * A generic, platform-independent shaper relies only on the standard
648 * gfxFont interface and can work with any concrete subclass of gfxFont.
650 * Platform-specific implementations designed to interface to platform
651 * shaping APIs such as Uniscribe or CoreText may rely on features of a
652 * specific font subclass to access native font references
653 * (such as CTFont, HFONT, DWriteFont, etc).
656 class gfxFontShaper
{
658 typedef mozilla::gfx::DrawTarget DrawTarget
;
659 typedef mozilla::intl::Script Script
;
661 enum class RoundingFlags
: uint8_t { kRoundX
= 0x01, kRoundY
= 0x02 };
663 explicit gfxFontShaper(gfxFont
* aFont
) : mFont(aFont
) {
664 NS_ASSERTION(aFont
, "shaper requires a valid font!");
667 virtual ~gfxFontShaper() = default;
669 // Shape a piece of text and store the resulting glyph data into
670 // aShapedText. Parameters aOffset/aLength indicate the range of
671 // aShapedText to be updated; aLength is also the length of aText.
672 virtual bool ShapeText(DrawTarget
* aDrawTarget
, const char16_t
* aText
,
673 uint32_t aOffset
, uint32_t aLength
, Script aScript
,
674 nsAtom
* aLanguage
, // may be null, indicating no
675 // lang-specific shaping to be
677 bool aVertical
, RoundingFlags aRounding
,
678 gfxShapedText
* aShapedText
) = 0;
680 gfxFont
* GetFont() const { return mFont
; }
682 static void MergeFontFeatures(
683 const gfxFontStyle
* aStyle
, const nsTArray
<gfxFontFeature
>& aFontFeatures
,
684 bool aDisableLigatures
, const nsACString
& aFamilyName
, bool aAddSmallCaps
,
685 void (*aHandleFeature
)(uint32_t, uint32_t, void*),
686 void* aHandleFeatureData
);
689 // the font this shaper is working with. The font owns a UniquePtr reference
690 // to this object, and will destroy it before it dies. Thus, mFont will always
692 gfxFont
* MOZ_NON_OWNING_REF mFont
;
695 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(gfxFontShaper::RoundingFlags
)
698 * gfxShapedText is an abstract superclass for gfxShapedWord and gfxTextRun.
699 * These are objects that store a list of zero or more glyphs for each
700 * character. For each glyph we store the glyph ID, the advance, and possibly
701 * x/y-offsets. The idea is that a string is rendered by a loop that draws each
702 * glyph at its designated offset from the current point, then advances the
703 * current point by the glyph's advance in the direction of the textrun (LTR or
704 * RTL). Each glyph advance is always rounded to the nearest appunit; this
705 * ensures consistent results when dividing the text in a textrun into multiple
706 * text frames (frame boundaries are always aligned to appunits). We optimize
707 * for the case where a character has a single glyph and zero xoffset and
708 * yoffset, and the glyph ID and advance are in a reasonable range so we can
709 * pack all necessary data into 32 bits.
711 * gfxFontShaper can shape text into either a gfxShapedWord (cached by a
712 * gfxFont) or directly into a gfxTextRun (for cases where we want to shape
713 * textruns in their entirety rather than using cached words, because there may
714 * be layout features that depend on the inter-word spaces).
716 class gfxShapedText
{
718 typedef mozilla::intl::Script Script
;
720 gfxShapedText(uint32_t aLength
, mozilla::gfx::ShapedTextFlags aFlags
,
721 uint16_t aAppUnitsPerDevUnit
)
724 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit
) {}
726 virtual ~gfxShapedText() = default;
729 * This class records the information associated with a character in the
730 * input string. It's optimized for the case where there is one glyph
731 * representing that character alone.
733 * A character can have zero or more associated glyphs. Each glyph
734 * has an advance width and an x and y offset.
735 * A character may be the start of a cluster.
736 * A character may be the start of a ligature group.
737 * A character can be "missing", indicating that the system is unable
738 * to render the character.
740 * All characters in a ligature group conceptually share all the glyphs
741 * associated with the characters in a group.
743 class CompressedGlyph
{
746 // Indicates that a cluster and ligature group starts at this
747 // character; this character has a single glyph with a reasonable
748 // advance and zero offsets. A "reasonable" advance
749 // is one that fits in the available bits (currently 12) (specified
751 FLAG_IS_SIMPLE_GLYPH
= 0x80000000U
,
753 // These flags are applicable to both "simple" and "complex" records.
754 COMMON_FLAGS_MASK
= 0x70000000U
,
756 // Indicates whether a linebreak is allowed before this character;
757 // this is a two-bit field that holds a FLAG_BREAK_TYPE_xxx value
758 // indicating the kind of linebreak (if any) allowed here.
759 FLAGS_CAN_BREAK_BEFORE
= 0x60000000U
,
761 FLAGS_CAN_BREAK_SHIFT
= 29,
762 FLAG_BREAK_TYPE_NONE
= 0,
763 FLAG_BREAK_TYPE_NORMAL
= 1,
764 FLAG_BREAK_TYPE_HYPHEN
= 2,
765 // Allow break before this position if needed to avoid overflow:
766 FLAG_BREAK_TYPE_EMERGENCY_WRAP
= 3,
768 FLAG_CHAR_IS_SPACE
= 0x10000000U
,
770 // Fields present only when FLAG_IS_SIMPLE_GLYPH is /true/.
771 // The advance is stored in appunits as a 12-bit field:
772 ADVANCE_MASK
= 0x0FFF0000U
,
774 // and the glyph ID is stored in the low 16 bits.
775 GLYPH_MASK
= 0x0000FFFFU
,
777 // Fields present only when FLAG_IS_SIMPLE_GLYPH is /false/.
778 // Non-simple glyphs may or may not have glyph data in the
779 // corresponding mDetailedGlyphs entry. They have a glyph count
780 // stored in the low 16 bits, and the following flag bits:
781 GLYPH_COUNT_MASK
= 0x0000FFFFU
,
783 // When NOT set, indicates that this character corresponds to a
784 // missing glyph and should be skipped (or possibly, render the character
785 // Unicode value in some special way). If there are glyphs,
786 // the mGlyphID is actually the UTF16 character code. The bit is
787 // inverted so we can memset the array to zero to indicate all missing.
788 FLAG_NOT_MISSING
= 0x010000,
789 FLAG_NOT_CLUSTER_START
= 0x020000,
790 FLAG_NOT_LIGATURE_GROUP_START
= 0x040000,
791 // Flag bit 0x080000 is currently unused.
793 // Certain types of characters are marked so that they can be given
794 // special treatment in rendering. This may require use of a "complex"
795 // CompressedGlyph record even for a character that would otherwise be
796 // treated as "simple".
797 CHAR_TYPE_FLAGS_MASK
= 0xF00000,
798 FLAG_CHAR_IS_TAB
= 0x100000,
799 FLAG_CHAR_IS_NEWLINE
= 0x200000,
800 // Per CSS Text Decoration Module Level 3, emphasis marks are not
801 // drawn for any character in Unicode categories Z*, Cc, Cf, and Cn
802 // which is not combined with any combining characters. This flag is
803 // set for all those characters except 0x20 whitespace.
804 FLAG_CHAR_NO_EMPHASIS_MARK
= 0x400000,
805 // Per CSS Text, letter-spacing is not applied to formatting chars
806 // (category Cf). We mark those in the textrun so as to be able to
807 // skip them when setting up spacing in nsTextFrame.
808 FLAG_CHAR_IS_FORMATTING_CONTROL
= 0x800000,
810 // The bits 0x0F000000 are currently unused in non-simple glyphs.
813 // "Simple glyphs" have a simple glyph ID, simple advance and their
814 // x and y offsets are zero. Also the glyph extents do not overflow
815 // the font-box defined by the font ascent, descent and glyph advance width.
816 // These case is optimized to avoid storing DetailedGlyphs.
818 // Returns true if the glyph ID aGlyph fits into the compressed
820 static bool IsSimpleGlyphID(uint32_t aGlyph
) {
821 return (aGlyph
& GLYPH_MASK
) == aGlyph
;
823 // Returns true if the advance aAdvance fits into the compressed
824 // representation. aAdvance is in appunits.
825 static bool IsSimpleAdvance(uint32_t aAdvance
) {
826 return (aAdvance
& (ADVANCE_MASK
>> ADVANCE_SHIFT
)) == aAdvance
;
829 bool IsSimpleGlyph() const { return mValue
& FLAG_IS_SIMPLE_GLYPH
; }
830 uint32_t GetSimpleAdvance() const {
831 MOZ_ASSERT(IsSimpleGlyph());
832 return (mValue
& ADVANCE_MASK
) >> ADVANCE_SHIFT
;
834 uint32_t GetSimpleGlyph() const {
835 MOZ_ASSERT(IsSimpleGlyph());
836 return mValue
& GLYPH_MASK
;
839 bool IsMissing() const {
840 return !(mValue
& (FLAG_NOT_MISSING
| FLAG_IS_SIMPLE_GLYPH
));
842 bool IsClusterStart() const {
843 return IsSimpleGlyph() || !(mValue
& FLAG_NOT_CLUSTER_START
);
845 bool IsLigatureGroupStart() const {
846 return IsSimpleGlyph() || !(mValue
& FLAG_NOT_LIGATURE_GROUP_START
);
848 bool IsLigatureContinuation() const {
849 return !IsSimpleGlyph() &&
850 (mValue
& (FLAG_NOT_LIGATURE_GROUP_START
| FLAG_NOT_MISSING
)) ==
851 (FLAG_NOT_LIGATURE_GROUP_START
| FLAG_NOT_MISSING
);
854 // Return true if the original character was a normal (breakable,
855 // trimmable) space (U+0020). Not true for other characters that
856 // may happen to map to the space glyph (U+00A0).
857 bool CharIsSpace() const { return mValue
& FLAG_CHAR_IS_SPACE
; }
859 bool CharIsTab() const {
860 return !IsSimpleGlyph() && (mValue
& FLAG_CHAR_IS_TAB
);
862 bool CharIsNewline() const {
863 return !IsSimpleGlyph() && (mValue
& FLAG_CHAR_IS_NEWLINE
);
865 bool CharMayHaveEmphasisMark() const {
866 return !CharIsSpace() &&
867 (IsSimpleGlyph() || !(mValue
& FLAG_CHAR_NO_EMPHASIS_MARK
));
869 bool CharIsFormattingControl() const {
870 return !IsSimpleGlyph() && (mValue
& FLAG_CHAR_IS_FORMATTING_CONTROL
);
873 uint32_t CharTypeFlags() const {
874 return IsSimpleGlyph() ? 0 : (mValue
& CHAR_TYPE_FLAGS_MASK
);
877 void SetClusterStart(bool aIsClusterStart
) {
878 MOZ_ASSERT(!IsSimpleGlyph());
879 if (aIsClusterStart
) {
880 mValue
&= ~FLAG_NOT_CLUSTER_START
;
882 mValue
|= FLAG_NOT_CLUSTER_START
;
886 uint8_t CanBreakBefore() const {
887 return (mValue
& FLAGS_CAN_BREAK_BEFORE
) >> FLAGS_CAN_BREAK_SHIFT
;
889 // Returns FLAGS_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
890 uint32_t SetCanBreakBefore(uint8_t aCanBreakBefore
) {
891 MOZ_ASSERT(aCanBreakBefore
<= 3, "Bogus break-flags value!");
892 uint32_t breakMask
= (uint32_t(aCanBreakBefore
) << FLAGS_CAN_BREAK_SHIFT
);
893 uint32_t toggle
= breakMask
^ (mValue
& FLAGS_CAN_BREAK_BEFORE
);
898 // Create a CompressedGlyph value representing a simple glyph with
899 // no extra flags (line-break or is_space) set.
900 static CompressedGlyph
MakeSimpleGlyph(uint32_t aAdvanceAppUnits
,
902 MOZ_ASSERT(IsSimpleAdvance(aAdvanceAppUnits
));
903 MOZ_ASSERT(IsSimpleGlyphID(aGlyph
));
906 FLAG_IS_SIMPLE_GLYPH
| (aAdvanceAppUnits
<< ADVANCE_SHIFT
) | aGlyph
;
910 // Assign a simple glyph value to an existing CompressedGlyph record,
911 // preserving line-break/is-space flags if present.
912 CompressedGlyph
& SetSimpleGlyph(uint32_t aAdvanceAppUnits
,
914 MOZ_ASSERT(!CharTypeFlags(), "Char type flags lost");
915 mValue
= (mValue
& COMMON_FLAGS_MASK
) |
916 MakeSimpleGlyph(aAdvanceAppUnits
, aGlyph
).mValue
;
920 // Create a CompressedGlyph value representing a complex glyph record,
921 // without any line-break or char-type flags.
922 static CompressedGlyph
MakeComplex(bool aClusterStart
,
923 bool aLigatureStart
) {
925 g
.mValue
= FLAG_NOT_MISSING
|
926 (aClusterStart
? 0 : FLAG_NOT_CLUSTER_START
) |
927 (aLigatureStart
? 0 : FLAG_NOT_LIGATURE_GROUP_START
);
931 // Assign a complex glyph value to an existing CompressedGlyph record,
932 // preserving line-break/char-type flags if present.
933 // This sets the glyphCount to zero; it will be updated when we call
934 // gfxShapedText::SetDetailedGlyphs.
935 CompressedGlyph
& SetComplex(bool aClusterStart
, bool aLigatureStart
) {
936 mValue
= (mValue
& COMMON_FLAGS_MASK
) | CharTypeFlags() |
937 MakeComplex(aClusterStart
, aLigatureStart
).mValue
;
942 * Mark a glyph record as being a missing-glyph.
943 * Missing glyphs are treated as ligature group starts; don't mess with
944 * the cluster-start flag (see bugs 618870 and 619286).
945 * We also preserve the glyph count here, as this is used after any
946 * required DetailedGlyphs (to store the char code for a hexbox) has been
948 * This must be called *after* SetDetailedGlyphs is used for the relevant
949 * offset in the shaped-word, because that will mark it as not-missing.
951 CompressedGlyph
& SetMissing() {
952 MOZ_ASSERT(!IsSimpleGlyph());
953 mValue
&= ~(FLAG_NOT_MISSING
| FLAG_NOT_LIGATURE_GROUP_START
);
957 uint32_t GetGlyphCount() const {
958 MOZ_ASSERT(!IsSimpleGlyph());
959 return mValue
& GLYPH_COUNT_MASK
;
961 void SetGlyphCount(uint32_t aGlyphCount
) {
962 MOZ_ASSERT(!IsSimpleGlyph());
963 MOZ_ASSERT(GetGlyphCount() == 0, "Glyph count already set");
964 MOZ_ASSERT(aGlyphCount
<= 0xffff, "Glyph count out of range");
965 mValue
|= FLAG_NOT_MISSING
| aGlyphCount
;
968 void SetIsSpace() { mValue
|= FLAG_CHAR_IS_SPACE
; }
970 MOZ_ASSERT(!IsSimpleGlyph());
971 mValue
|= FLAG_CHAR_IS_TAB
;
973 void SetIsNewline() {
974 MOZ_ASSERT(!IsSimpleGlyph());
975 mValue
|= FLAG_CHAR_IS_NEWLINE
;
977 void SetNoEmphasisMark() {
978 MOZ_ASSERT(!IsSimpleGlyph());
979 mValue
|= FLAG_CHAR_NO_EMPHASIS_MARK
;
981 void SetIsFormattingControl() {
982 MOZ_ASSERT(!IsSimpleGlyph());
983 mValue
|= FLAG_CHAR_IS_FORMATTING_CONTROL
;
990 // Accessor for the array of CompressedGlyph records, which will be in
991 // a different place in gfxShapedWord vs gfxTextRun
992 virtual const CompressedGlyph
* GetCharacterGlyphs() const = 0;
993 virtual CompressedGlyph
* GetCharacterGlyphs() = 0;
996 * When the glyphs for a character don't fit into a CompressedGlyph record
997 * in SimpleGlyph format, we use an array of DetailedGlyphs instead.
999 struct DetailedGlyph
{
1000 // The glyphID, or the Unicode character if this is a missing glyph
1002 // The advance of the glyph, in appunits.
1003 // mAdvance is in the text direction (RTL or LTR),
1004 // and will normally be non-negative (although this is not guaranteed)
1006 // The offset from the glyph's default position, in line-relative
1007 // coordinates (so mOffset.x is an offset in the line-right direction,
1008 // and mOffset.y is an offset in line-downwards direction).
1009 // These values are in floating-point appUnits.
1010 mozilla::gfx::Point mOffset
;
1013 // Store DetailedGlyph records for the given index. (This does not modify
1014 // the associated CompressedGlyph character-type or break flags.)
1015 void SetDetailedGlyphs(uint32_t aIndex
, uint32_t aGlyphCount
,
1016 const DetailedGlyph
* aGlyphs
);
1018 void SetMissingGlyph(uint32_t aIndex
, uint32_t aChar
, gfxFont
* aFont
);
1020 void SetIsSpace(uint32_t aIndex
) {
1021 GetCharacterGlyphs()[aIndex
].SetIsSpace();
1024 bool HasDetailedGlyphs() const { return mDetailedGlyphs
!= nullptr; }
1026 bool IsLigatureGroupStart(uint32_t aPos
) {
1027 NS_ASSERTION(aPos
< GetLength(), "aPos out of range");
1028 return GetCharacterGlyphs()[aPos
].IsLigatureGroupStart();
1031 // NOTE that this must not be called for a character offset that does
1032 // not have any DetailedGlyph records; callers must have verified that
1033 // GetCharacterGlyphs()[aCharIndex].GetGlyphCount() is greater than zero.
1034 DetailedGlyph
* GetDetailedGlyphs(uint32_t aCharIndex
) const {
1035 NS_ASSERTION(GetCharacterGlyphs() && HasDetailedGlyphs() &&
1036 !GetCharacterGlyphs()[aCharIndex
].IsSimpleGlyph() &&
1037 GetCharacterGlyphs()[aCharIndex
].GetGlyphCount() > 0,
1038 "invalid use of GetDetailedGlyphs; check the caller!");
1039 return mDetailedGlyphs
->Get(aCharIndex
);
1042 void ApplyTrackingToClusters(gfxFloat aTrackingAdjustment
, uint32_t aOffset
,
1045 // Mark clusters in the CompressedGlyph records, starting at aOffset,
1046 // based on the Unicode properties of the text in aString.
1047 // This is also responsible to set the IsSpace flag for space characters.
1048 void SetupClusterBoundaries(uint32_t aOffset
, const char16_t
* aString
,
1050 // In 8-bit text, there won't actually be any clusters, but we still need
1051 // the space-marking functionality.
1052 void SetupClusterBoundaries(uint32_t aOffset
, const uint8_t* aString
,
1055 mozilla::gfx::ShapedTextFlags
GetFlags() const { return mFlags
; }
1057 bool IsVertical() const {
1058 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK
) !=
1059 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_HORIZONTAL
;
1062 bool UseCenterBaseline() const {
1063 mozilla::gfx::ShapedTextFlags orient
=
1064 GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK
;
1066 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_MIXED
||
1068 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_UPRIGHT
;
1071 bool IsRightToLeft() const {
1072 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_IS_RTL
) ==
1073 mozilla::gfx::ShapedTextFlags::TEXT_IS_RTL
;
1076 bool IsSidewaysLeft() const {
1077 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_MASK
) ==
1078 mozilla::gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT
;
1081 // Return true if the logical inline direction is reversed compared to
1082 // normal physical coordinates (i.e. if it is leftwards or upwards)
1083 bool IsInlineReversed() const { return IsSidewaysLeft() != IsRightToLeft(); }
1085 gfxFloat
GetDirection() const { return IsInlineReversed() ? -1.0f
: 1.0f
; }
1087 bool DisableLigatures() const {
1088 return (GetFlags() &
1089 mozilla::gfx::ShapedTextFlags::TEXT_DISABLE_OPTIONAL_LIGATURES
) ==
1090 mozilla::gfx::ShapedTextFlags::TEXT_DISABLE_OPTIONAL_LIGATURES
;
1093 bool TextIs8Bit() const {
1094 return (GetFlags() & mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT
) ==
1095 mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT
;
1098 int32_t GetAppUnitsPerDevUnit() const { return mAppUnitsPerDevUnit
; }
1100 uint32_t GetLength() const { return mLength
; }
1102 bool FilterIfIgnorable(uint32_t aIndex
, uint32_t aCh
);
1105 // Allocate aCount DetailedGlyphs for the given index
1106 DetailedGlyph
* AllocateDetailedGlyphs(uint32_t aCharIndex
, uint32_t aCount
);
1108 // Ensure the glyph on the given index is complex glyph so that we can use
1109 // it to record specific characters that layout may need to detect.
1110 void EnsureComplexGlyph(uint32_t aIndex
, CompressedGlyph
& aGlyph
) {
1111 MOZ_ASSERT(GetCharacterGlyphs() + aIndex
== &aGlyph
);
1112 if (aGlyph
.IsSimpleGlyph()) {
1113 DetailedGlyph details
= {aGlyph
.GetSimpleGlyph(),
1114 (int32_t)aGlyph
.GetSimpleAdvance(),
1115 mozilla::gfx::Point()};
1116 aGlyph
.SetComplex(true, true);
1117 SetDetailedGlyphs(aIndex
, 1, &details
);
1121 // For characters whose glyph data does not fit the "simple" glyph criteria
1122 // in CompressedGlyph, we use a sorted array to store the association
1123 // between the source character offset and an index into an array
1124 // DetailedGlyphs. The CompressedGlyph record includes a count of
1125 // the number of DetailedGlyph records that belong to the character,
1126 // starting at the given index.
1127 class DetailedGlyphStore
{
1129 DetailedGlyphStore() = default;
1131 // This is optimized for the most common calling patterns:
1132 // we rarely need random access to the records, access is most commonly
1133 // sequential through the textRun, so we record the last-used index
1134 // and check whether the caller wants the same record again, or the
1135 // next; if not, it's most likely we're starting over from the start
1136 // of the run, so we check the first entry before resorting to binary
1137 // search as a last resort.
1138 // NOTE that this must not be called for a character offset that does
1139 // not have any DetailedGlyph records; callers must have verified that
1140 // mCharacterGlyphs[aOffset].GetGlyphCount() is greater than zero
1141 // before calling this, otherwise the assertions here will fire (in a
1142 // debug build), and we'll probably crash.
1143 DetailedGlyph
* Get(uint32_t aOffset
) {
1144 NS_ASSERTION(mOffsetToIndex
.Length() > 0, "no detailed glyph records!");
1145 DetailedGlyph
* details
= mDetails
.Elements();
1146 // check common cases (fwd iteration, initial entry, etc) first
1147 if (mLastUsed
< mOffsetToIndex
.Length() - 1 &&
1148 aOffset
== mOffsetToIndex
[mLastUsed
+ 1].mOffset
) {
1150 } else if (aOffset
== mOffsetToIndex
[0].mOffset
) {
1152 } else if (aOffset
== mOffsetToIndex
[mLastUsed
].mOffset
) {
1154 } else if (mLastUsed
> 0 &&
1155 aOffset
== mOffsetToIndex
[mLastUsed
- 1].mOffset
) {
1158 mLastUsed
= mOffsetToIndex
.BinaryIndexOf(aOffset
, CompareToOffset());
1160 NS_ASSERTION(mLastUsed
!= nsTArray
<DGRec
>::NoIndex
,
1161 "detailed glyph record missing!");
1162 return details
+ mOffsetToIndex
[mLastUsed
].mIndex
;
1165 DetailedGlyph
* Allocate(uint32_t aOffset
, uint32_t aCount
) {
1166 uint32_t detailIndex
= mDetails
.Length();
1167 DetailedGlyph
* details
= mDetails
.AppendElements(aCount
);
1168 // We normally set up glyph records sequentially, so the common case
1169 // here is to append new records to the mOffsetToIndex array;
1170 // test for that before falling back to the InsertElementSorted
1172 if (mOffsetToIndex
.Length() == 0 ||
1173 aOffset
> mOffsetToIndex
[mOffsetToIndex
.Length() - 1].mOffset
) {
1174 mOffsetToIndex
.AppendElement(DGRec(aOffset
, detailIndex
));
1176 mOffsetToIndex
.InsertElementSorted(DGRec(aOffset
, detailIndex
),
1177 CompareRecordOffsets());
1182 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) {
1183 return aMallocSizeOf(this) +
1184 mDetails
.ShallowSizeOfExcludingThis(aMallocSizeOf
) +
1185 mOffsetToIndex
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1190 DGRec(const uint32_t& aOffset
, const uint32_t& aIndex
)
1191 : mOffset(aOffset
), mIndex(aIndex
) {}
1192 uint32_t mOffset
; // source character offset in the textrun
1193 uint32_t mIndex
; // index where this char's DetailedGlyphs begin
1196 struct CompareToOffset
{
1197 bool Equals(const DGRec
& a
, const uint32_t& b
) const {
1198 return a
.mOffset
== b
;
1200 bool LessThan(const DGRec
& a
, const uint32_t& b
) const {
1201 return a
.mOffset
< b
;
1205 struct CompareRecordOffsets
{
1206 bool Equals(const DGRec
& a
, const DGRec
& b
) const {
1207 return a
.mOffset
== b
.mOffset
;
1209 bool LessThan(const DGRec
& a
, const DGRec
& b
) const {
1210 return a
.mOffset
< b
.mOffset
;
1214 // Concatenated array of all the DetailedGlyph records needed for the
1215 // textRun; individual character offsets are associated with indexes
1216 // into this array via the mOffsetToIndex table.
1217 nsTArray
<DetailedGlyph
> mDetails
;
1219 // For each character offset that needs DetailedGlyphs, we record the
1220 // index in mDetails where the list of glyphs begins. This array is
1221 // sorted by mOffset.
1222 nsTArray
<DGRec
> mOffsetToIndex
;
1224 // Records the most recently used index into mOffsetToIndex, so that
1225 // we can support sequential access more quickly than just doing
1226 // a binary search each time.
1227 nsTArray
<DGRec
>::index_type mLastUsed
= 0;
1230 mozilla::UniquePtr
<DetailedGlyphStore
> mDetailedGlyphs
;
1232 // Number of char16_t characters and CompressedGlyph glyph records
1235 // Shaping flags (direction, ligature-suppression)
1236 mozilla::gfx::ShapedTextFlags mFlags
;
1238 uint16_t mAppUnitsPerDevUnit
;
1242 * gfxShapedWord: an individual (space-delimited) run of text shaped with a
1243 * particular font, without regard to external context.
1245 * The glyph data is copied into gfxTextRuns as needed from the cache of
1246 * ShapedWords associated with each gfxFont instance.
1248 class gfxShapedWord final
: public gfxShapedText
{
1250 typedef mozilla::intl::Script Script
;
1252 // Create a ShapedWord that can hold glyphs for aLength characters,
1253 // with mCharacterGlyphs sized appropriately.
1255 // Returns null on allocation failure (does NOT use infallible alloc)
1256 // so caller must check for success.
1258 // This does NOT perform shaping, so the returned word contains no
1259 // glyph data; the caller must call gfxFont::ShapeText() with appropriate
1260 // parameters to set up the glyphs.
1261 static gfxShapedWord
* Create(const uint8_t* aText
, uint32_t aLength
,
1262 Script aRunScript
, nsAtom
* aLanguage
,
1263 uint16_t aAppUnitsPerDevUnit
,
1264 mozilla::gfx::ShapedTextFlags aFlags
,
1265 gfxFontShaper::RoundingFlags aRounding
) {
1266 NS_ASSERTION(aLength
<= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
1267 "excessive length for gfxShapedWord!");
1269 // Compute size needed including the mCharacterGlyphs array
1270 // and a copy of the original text
1271 uint32_t size
= offsetof(gfxShapedWord
, mCharGlyphsStorage
) +
1272 aLength
* (sizeof(CompressedGlyph
) + sizeof(uint8_t));
1273 void* storage
= malloc(size
);
1278 // Construct in the pre-allocated storage, using placement new
1279 return new (storage
) gfxShapedWord(aText
, aLength
, aRunScript
, aLanguage
,
1280 aAppUnitsPerDevUnit
, aFlags
, aRounding
);
1283 static gfxShapedWord
* Create(const char16_t
* aText
, uint32_t aLength
,
1284 Script aRunScript
, nsAtom
* aLanguage
,
1285 uint16_t aAppUnitsPerDevUnit
,
1286 mozilla::gfx::ShapedTextFlags aFlags
,
1287 gfxFontShaper::RoundingFlags aRounding
) {
1288 NS_ASSERTION(aLength
<= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
1289 "excessive length for gfxShapedWord!");
1291 // In the 16-bit version of Create, if the TEXT_IS_8BIT flag is set,
1292 // then we convert the text to an 8-bit version and call the 8-bit
1293 // Create function instead.
1294 if (aFlags
& mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT
) {
1295 nsAutoCString narrowText
;
1296 LossyAppendUTF16toASCII(nsDependentSubstring(aText
, aLength
), narrowText
);
1297 return Create((const uint8_t*)(narrowText
.BeginReading()), aLength
,
1298 aRunScript
, aLanguage
, aAppUnitsPerDevUnit
, aFlags
,
1302 uint32_t size
= offsetof(gfxShapedWord
, mCharGlyphsStorage
) +
1303 aLength
* (sizeof(CompressedGlyph
) + sizeof(char16_t
));
1304 void* storage
= malloc(size
);
1309 return new (storage
) gfxShapedWord(aText
, aLength
, aRunScript
, aLanguage
,
1310 aAppUnitsPerDevUnit
, aFlags
, aRounding
);
1313 // Override operator delete to properly free the object that was
1314 // allocated via malloc.
1315 void operator delete(void* p
) { free(p
); }
1317 const CompressedGlyph
* GetCharacterGlyphs() const override
{
1318 return &mCharGlyphsStorage
[0];
1320 CompressedGlyph
* GetCharacterGlyphs() override
{
1321 return &mCharGlyphsStorage
[0];
1324 const uint8_t* Text8Bit() const {
1325 NS_ASSERTION(TextIs8Bit(), "invalid use of Text8Bit()");
1326 return reinterpret_cast<const uint8_t*>(mCharGlyphsStorage
+ GetLength());
1329 const char16_t
* TextUnicode() const {
1330 NS_ASSERTION(!TextIs8Bit(), "invalid use of TextUnicode()");
1331 return reinterpret_cast<const char16_t
*>(mCharGlyphsStorage
+ GetLength());
1334 char16_t
GetCharAt(uint32_t aOffset
) const {
1335 NS_ASSERTION(aOffset
< GetLength(), "aOffset out of range");
1336 return TextIs8Bit() ? char16_t(Text8Bit()[aOffset
])
1337 : TextUnicode()[aOffset
];
1340 Script
GetScript() const { return mScript
; }
1341 nsAtom
* GetLanguage() const { return mLanguage
.get(); }
1343 gfxFontShaper::RoundingFlags
GetRounding() const { return mRounding
; }
1345 void ResetAge() { mAgeCounter
= 0; }
1346 uint32_t IncrementAge() { return ++mAgeCounter
; }
1348 // Helper used when hashing a word for the shaped-word caches
1349 static uint32_t HashMix(uint32_t aHash
, char16_t aCh
) {
1350 return (aHash
>> 28) ^ (aHash
<< 4) ^ aCh
;
1353 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const;
1356 // so that gfxTextRun can share our DetailedGlyphStore class
1357 friend class gfxTextRun
;
1359 // Construct storage for a ShapedWord, ready to receive glyph data
1360 gfxShapedWord(const uint8_t* aText
, uint32_t aLength
, Script aRunScript
,
1361 nsAtom
* aLanguage
, uint16_t aAppUnitsPerDevUnit
,
1362 mozilla::gfx::ShapedTextFlags aFlags
,
1363 gfxFontShaper::RoundingFlags aRounding
)
1364 : gfxShapedText(aLength
,
1365 aFlags
| mozilla::gfx::ShapedTextFlags::TEXT_IS_8BIT
,
1366 aAppUnitsPerDevUnit
),
1367 mLanguage(aLanguage
),
1368 mScript(aRunScript
),
1369 mRounding(aRounding
),
1371 memset(mCharGlyphsStorage
, 0, aLength
* sizeof(CompressedGlyph
));
1372 uint8_t* text
= reinterpret_cast<uint8_t*>(&mCharGlyphsStorage
[aLength
]);
1373 memcpy(text
, aText
, aLength
* sizeof(uint8_t));
1374 SetupClusterBoundaries(0, aText
, aLength
);
1377 gfxShapedWord(const char16_t
* aText
, uint32_t aLength
, Script aRunScript
,
1378 nsAtom
* aLanguage
, uint16_t aAppUnitsPerDevUnit
,
1379 mozilla::gfx::ShapedTextFlags aFlags
,
1380 gfxFontShaper::RoundingFlags aRounding
)
1381 : gfxShapedText(aLength
, aFlags
, aAppUnitsPerDevUnit
),
1382 mLanguage(aLanguage
),
1383 mScript(aRunScript
),
1384 mRounding(aRounding
),
1386 memset(mCharGlyphsStorage
, 0, aLength
* sizeof(CompressedGlyph
));
1387 char16_t
* text
= reinterpret_cast<char16_t
*>(&mCharGlyphsStorage
[aLength
]);
1388 memcpy(text
, aText
, aLength
* sizeof(char16_t
));
1389 SetupClusterBoundaries(0, aText
, aLength
);
1392 RefPtr
<nsAtom
> mLanguage
;
1395 gfxFontShaper::RoundingFlags mRounding
;
1397 // With multithreaded shaping, this may be updated by any thread.
1398 std::atomic
<uint32_t> mAgeCounter
;
1400 // The mCharGlyphsStorage array is actually a variable-size member;
1401 // when the ShapedWord is created, its size will be increased as necessary
1402 // to allow the proper number of glyphs to be stored.
1403 // The original text, in either 8-bit or 16-bit form, will be stored
1404 // immediately following the CompressedGlyphs.
1405 CompressedGlyph mCharGlyphsStorage
[1];
1408 class GlyphBufferAzure
;
1409 struct TextRunDrawParams
;
1410 struct FontDrawParams
;
1411 struct EmphasisMarkDrawParams
;
1414 friend class gfxHarfBuzzShaper
;
1415 friend class gfxGraphiteShaper
;
1418 using DrawTarget
= mozilla::gfx::DrawTarget
;
1419 using Script
= mozilla::intl::Script
;
1420 using SVGContextPaint
= mozilla::SVGContextPaint
;
1422 using RoundingFlags
= gfxFontShaper::RoundingFlags
;
1423 using ShapedTextFlags
= mozilla::gfx::ShapedTextFlags
;
1426 using FontSlantStyle
= mozilla::FontSlantStyle
;
1427 using FontSizeAdjust
= mozilla::StyleFontSizeAdjust
;
1429 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(gfxFont
, MaybeDestroy())
1430 int32_t GetRefCount() { return int32_t(mRefCnt
); }
1432 // options to specify the kind of AA to be used when creating a font
1433 typedef enum : uint8_t {
1436 kAntialiasGrayscale
,
1441 gfxFont(const RefPtr
<mozilla::gfx::UnscaledFont
>& aUnscaledFont
,
1442 gfxFontEntry
* aFontEntry
, const gfxFontStyle
* aFontStyle
,
1443 AntialiasOption anAAOption
= kAntialiasDefault
);
1447 void MaybeDestroy() {
1448 bool destroy
= true;
1449 if (gfxFontCache
* fc
= gfxFontCache::GetCache()) {
1450 destroy
= fc
->MaybeDestroy(this);
1459 MOZ_ASSERT(GetRefCount() == 0);
1463 bool Valid() const { return mIsValid
; }
1465 // options for the kind of bounding box to return from measurement
1468 // A box that encloses all the painted pixels, and may
1469 // include sidebearings and/or additional ascent/descent
1470 // within the glyph cell even if the ink is smaller.
1472 // A box that tightly encloses all the painted pixels
1473 // (although actually on Windows, at least, it may be
1474 // slightly larger than strictly necessary because
1475 // we can't get precise extents with ClearType).
1476 TIGHT_HINTED_OUTLINE_EXTENTS
1477 // A box that tightly encloses the glyph outline,
1478 // ignoring possible antialiasing pixels that extend
1480 // NOTE: The default implementation of gfxFont::Measure(),
1481 // which works with the glyph extents cache, does not
1482 // differentiate between this and TIGHT_INK_EXTENTS.
1483 // Whether the distinction is important depends on the
1484 // antialiasing behavior of the platform; currently the
1485 // distinction is only implemented in the gfxWindowsFont
1486 // subclass, because of ClearType's tendency to paint
1487 // outside the hinted outline.
1488 // Also NOTE: it is relatively expensive to request this,
1489 // as it does not use cached glyph extents in the font.
1492 const nsCString
& GetName() const { return mFontEntry
->Name(); }
1493 const gfxFontStyle
* GetStyle() const { return &mStyle
; }
1495 virtual gfxFont
* CopyWithAntialiasOption(AntialiasOption anAAOption
) const {
1496 // platforms where this actually matters should override
1500 gfxFloat
GetAdjustedSize() const {
1501 // mAdjustedSize is cached here if not already set to a non-zero value;
1502 // but it may be overridden by a value computed in metrics initialization
1503 // from font-size-adjust.
1504 if (mAdjustedSize
< 0.0) {
1505 mAdjustedSize
= mStyle
.AdjustedSizeMustBeZero()
1507 : mStyle
.size
* mFontEntry
->mSizeAdjust
;
1509 return mAdjustedSize
;
1512 float FUnitsToDevUnitsFactor() const {
1513 // check this was set up during font initialization
1514 NS_ASSERTION(mFUnitsConvFactor
>= 0.0f
, "mFUnitsConvFactor not valid");
1515 return mFUnitsConvFactor
;
1518 // check whether this is an sfnt we can potentially use with harfbuzz
1519 bool FontCanSupportHarfBuzz() const { return mFontEntry
->HasCmapTable(); }
1521 // check whether this is an sfnt we can potentially use with Graphite
1522 bool FontCanSupportGraphite() const {
1523 return mFontEntry
->HasGraphiteTables();
1526 // Whether this is a font that may be doing full-color rendering,
1527 // and therefore needs us to use a mask for text-shadow even when
1528 // we're not actually blurring.
1529 bool AlwaysNeedsMaskForShadow() const {
1530 return mFontEntry
->TryGetColorGlyphs() || mFontEntry
->TryGetSVGData(this) ||
1531 mFontEntry
->HasFontTable(TRUETYPE_TAG('C', 'B', 'D', 'T')) ||
1532 mFontEntry
->HasFontTable(TRUETYPE_TAG('s', 'b', 'i', 'x'));
1535 // whether a feature is supported by the font (limited to a small set
1536 // of features for which some form of fallback needs to be implemented)
1537 bool SupportsFeature(Script aScript
, uint32_t aFeatureTag
);
1539 // whether the font supports "real" small caps, petite caps etc.
1540 // aFallbackToSmallCaps true when petite caps should fallback to small caps
1541 bool SupportsVariantCaps(Script aScript
, uint32_t aVariantCaps
,
1542 bool& aFallbackToSmallCaps
,
1543 bool& aSyntheticLowerToSmallCaps
,
1544 bool& aSyntheticUpperToSmallCaps
);
1546 // whether the font supports subscript/superscript feature
1547 // for fallback, need to verify that all characters in the run
1548 // have variant substitutions
1549 bool SupportsSubSuperscript(uint32_t aSubSuperscript
, const uint8_t* aString
,
1550 uint32_t aLength
, Script aRunScript
);
1552 bool SupportsSubSuperscript(uint32_t aSubSuperscript
, const char16_t
* aString
,
1553 uint32_t aLength
, Script aRunScript
);
1555 // whether the specified feature will apply to the given character
1556 bool FeatureWillHandleChar(Script aRunScript
, uint32_t aFeature
,
1559 // Subclasses may choose to look up glyph ids for characters.
1560 // If they do not override this, gfxHarfBuzzShaper will fetch the cmap
1561 // table and use that.
1562 virtual bool ProvidesGetGlyph() const { return false; }
1563 // Map unicode character to glyph ID.
1564 // Only used if ProvidesGetGlyph() returns true.
1565 virtual uint32_t GetGlyph(uint32_t unicode
, uint32_t variation_selector
) {
1569 // Return the advance of a glyph.
1570 gfxFloat
GetGlyphAdvance(uint16_t aGID
, bool aVertical
= false);
1572 // Return the advance of a given Unicode char in isolation.
1573 // Returns -1.0 if the char is not supported.
1574 gfxFloat
GetCharAdvance(uint32_t aUnicode
, bool aVertical
= false);
1576 gfxFloat
SynthesizeSpaceWidth(uint32_t aCh
);
1578 // Work out whether cairo will snap inter-glyph spacing to pixels
1579 // when rendering to the given drawTarget.
1580 RoundingFlags
GetRoundOffsetsToPixels(DrawTarget
* aDrawTarget
);
1582 virtual bool ShouldHintMetrics() const { return true; }
1583 virtual bool ShouldRoundXOffset(cairo_t
* aCairo
) const { return true; }
1585 // Return the font's owned harfbuzz shaper, creating and initializing it if
1586 // necessary; returns null if shaper initialization has failed.
1587 gfxHarfBuzzShaper
* GetHarfBuzzShaper();
1593 gfxFloat strikeoutSize
;
1594 gfxFloat strikeoutOffset
;
1595 gfxFloat underlineSize
;
1596 gfxFloat underlineOffset
;
1598 gfxFloat internalLeading
;
1599 gfxFloat externalLeading
;
1606 gfxFloat maxDescent
;
1607 gfxFloat maxAdvance
;
1609 gfxFloat aveCharWidth
;
1610 gfxFloat spaceWidth
;
1611 gfxFloat zeroWidth
; // -1 if there was no zero glyph
1612 gfxFloat ideographicWidth
; // -1 if kWaterIdeograph is not supported
1614 gfxFloat
ZeroOrAveCharWidth() const {
1615 return zeroWidth
>= 0 ? zeroWidth
: aveCharWidth
;
1618 // Unicode character used as basis for 'ic' unit:
1619 static constexpr uint32_t kWaterIdeograph
= 0x6C34;
1621 typedef nsFontMetrics::FontOrientation Orientation
;
1623 const Metrics
& GetMetrics(Orientation aOrientation
) {
1624 if (aOrientation
== nsFontMetrics::eHorizontal
) {
1625 return GetHorizontalMetrics();
1627 if (!mVerticalMetrics
) {
1628 CreateVerticalMetrics();
1630 return *mVerticalMetrics
;
1634 gfxFloat mAlphabetic
;
1636 gfxFloat mIdeographic
;
1638 Baselines
GetBaselines(Orientation aOrientation
);
1641 * We let layout specify spacing on either side of any
1642 * character. We need to specify both before and after
1643 * spacing so that substring measurement can do the right things.
1644 * These values are in appunits. They're always an integral number of
1645 * appunits, but we specify them in floats in case very large spacing
1646 * values are required.
1653 * Metrics for a particular string
1656 RunMetrics() { mAdvanceWidth
= mAscent
= mDescent
= 0.0; }
1658 void CombineWith(const RunMetrics
& aOther
, bool aOtherIsOnLeft
);
1660 // can be negative (partly due to negative spacing).
1661 // Advance widths should be additive: the advance width of the
1662 // (offset1, length1) plus the advance width of (offset1 + length1,
1663 // length2) should be the advance width of (offset1, length1 + length2)
1664 gfxFloat mAdvanceWidth
;
1666 // For zero-width substrings, these must be zero!
1667 gfxFloat mAscent
; // always non-negative
1668 gfxFloat mDescent
; // always non-negative
1670 // Bounding box that is guaranteed to include everything drawn.
1671 // If a tight boundingBox was requested when these metrics were
1672 // generated, this will tightly wrap the glyphs, otherwise it is
1673 // "loose" and may be larger than the true bounding box.
1674 // Coordinates are relative to the baseline left origin, so typically
1675 // mBoundingBox.y == -mAscent
1676 gfxRect mBoundingBox
;
1680 * Draw a series of glyphs to aContext. The direction of aTextRun must
1682 * @param aStart the first character to draw
1683 * @param aEnd draw characters up to here
1684 * @param aPt the baseline origin; the left end of the baseline
1685 * for LTR textruns, the right end for RTL textruns.
1686 * On return, this will be updated to the other end of the baseline.
1687 * In application units, really!
1688 * @param aRunParams record with drawing parameters, see TextRunDrawParams.
1689 * Particular fields of interest include
1690 * .spacing spacing to insert before and after characters (for RTL
1691 * glyphs, before-spacing is inserted to the right of characters). There
1692 * are aEnd - aStart elements in this array, unless it's null to indicate
1693 * that there is no spacing.
1694 * .drawMode specifies whether the fill or stroke of the glyph should be
1695 * drawn, or if it should be drawn into the current path
1696 * .contextPaint information about how to construct the fill and
1697 * stroke pattern. Can be nullptr if we are not stroking the text, which
1698 * indicates that the current source from context should be used for fill
1699 * .context the Thebes graphics context to which we're drawing
1700 * .dt Moz2D DrawTarget to which we're drawing
1702 * Callers guarantee:
1703 * -- aStart and aEnd are aligned to cluster and ligature boundaries
1704 * -- all glyphs use this font
1706 void Draw(const gfxTextRun
* aTextRun
, uint32_t aStart
, uint32_t aEnd
,
1707 mozilla::gfx::Point
* aPt
, TextRunDrawParams
& aRunParams
,
1708 mozilla::gfx::ShapedTextFlags aOrientation
);
1711 * Draw the emphasis marks for the given text run. Its prerequisite
1712 * and output are similiar to the method Draw().
1713 * @param aPt the baseline origin of the emphasis marks.
1714 * @param aParams some drawing parameters, see EmphasisMarkDrawParams.
1716 void DrawEmphasisMarks(const gfxTextRun
* aShapedText
,
1717 mozilla::gfx::Point
* aPt
, uint32_t aOffset
,
1719 const EmphasisMarkDrawParams
& aParams
);
1722 * Measure a run of characters. See gfxTextRun::Metrics.
1723 * @param aTight if false, then return the union of the glyph extents
1724 * with the font-box for the characters (the rectangle with x=0,width=
1725 * the advance width for the character run,y=-(font ascent), and height=
1726 * font ascent + font descent). Otherwise, we must return as tight as possible
1727 * an approximation to the area actually painted by glyphs.
1728 * @param aDrawTargetForTightBoundingBox when aTight is true, this must
1730 * @param aSpacing spacing to insert before and after glyphs. The bounding box
1731 * need not include the spacing itself, but the spacing affects the glyph
1732 * positions. null if there is no spacing.
1734 * Callers guarantee:
1735 * -- aStart and aEnd are aligned to cluster and ligature boundaries
1736 * -- all glyphs use this font
1738 * The default implementation just uses font metrics and aTextRun's
1739 * advances, and assumes no characters fall outside the font box. In
1740 * general this is insufficient, because that assumption is not always true.
1742 virtual RunMetrics
Measure(const gfxTextRun
* aTextRun
, uint32_t aStart
,
1743 uint32_t aEnd
, BoundingBoxType aBoundingBoxType
,
1744 DrawTarget
* aDrawTargetForTightBoundingBox
,
1746 mozilla::gfx::ShapedTextFlags aOrientation
);
1748 * Line breaks have been changed at the beginning and/or end of a substring
1749 * of the text. Reshaping may be required; glyph updating is permitted.
1750 * @return true if anything was changed, false otherwise
1752 bool NotifyLineBreaksChanged(gfxTextRun
* aTextRun
, uint32_t aStart
,
1757 // Expiration tracking
1758 nsExpirationState
* GetExpirationState() { return &mExpirationState
; }
1760 // Get the glyphID of a space
1761 uint16_t GetSpaceGlyph() const { return mSpaceGlyph
; }
1763 gfxGlyphExtents
* GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit
);
1765 void SetupGlyphExtents(DrawTarget
* aDrawTarget
, uint32_t aGlyphID
,
1766 bool aNeedTight
, gfxGlyphExtents
* aExtents
);
1768 virtual bool AllowSubpixelAA() const { return true; }
1770 bool ApplySyntheticBold() const { return mApplySyntheticBold
; }
1772 float AngleForSyntheticOblique() const;
1773 float SkewForSyntheticOblique() const;
1775 // Amount by which synthetic bold "fattens" the glyphs:
1776 // For size S up to a threshold size T, we use (0.25 + 3S / 4T),
1777 // so that the result ranges from 0.25 to 1.0; thereafter,
1778 // simply use (S / T).
1779 gfxFloat
GetSyntheticBoldOffset() const {
1780 gfxFloat size
= GetAdjustedSize();
1781 const gfxFloat threshold
= 48.0;
1782 return size
< threshold
? (0.25 + 0.75 * size
/ threshold
)
1783 : (size
/ threshold
);
1786 gfxFontEntry
* GetFontEntry() const { return mFontEntry
.get(); }
1787 bool HasCharacter(uint32_t ch
) const {
1788 if (!mIsValid
|| (mUnicodeRangeMap
&& !mUnicodeRangeMap
->test(ch
))) {
1791 return mFontEntry
->HasCharacter(ch
);
1794 const gfxCharacterMap
* GetUnicodeRangeMap() const {
1795 return mUnicodeRangeMap
.get();
1798 void SetUnicodeRangeMap(gfxCharacterMap
* aUnicodeRangeMap
) {
1799 mUnicodeRangeMap
= aUnicodeRangeMap
;
1802 uint16_t GetUVSGlyph(uint32_t aCh
, uint32_t aVS
) const {
1806 return mFontEntry
->GetUVSGlyph(aCh
, aVS
);
1809 template <typename T
>
1810 bool InitFakeSmallCapsRun(nsPresContext
* aPresContext
,
1811 DrawTarget
* aDrawTarget
, gfxTextRun
* aTextRun
,
1812 const T
* aText
, uint32_t aOffset
, uint32_t aLength
,
1813 FontMatchType aMatchType
,
1814 mozilla::gfx::ShapedTextFlags aOrientation
,
1815 Script aScript
, nsAtom
* aLanguage
,
1816 bool aSyntheticLower
, bool aSyntheticUpper
);
1818 // call the (virtual) InitTextRun method to do glyph generation/shaping,
1819 // limiting the length of text passed by processing the run in multiple
1820 // segments if necessary
1821 template <typename T
>
1822 bool SplitAndInitTextRun(DrawTarget
* aDrawTarget
, gfxTextRun
* aTextRun
,
1823 const T
* aString
, uint32_t aRunStart
,
1824 uint32_t aRunLength
, Script aRunScript
,
1826 mozilla::gfx::ShapedTextFlags aOrientation
);
1828 // Get a ShapedWord representing a single space for use in setting up a
1830 bool ProcessSingleSpaceShapedWord(
1831 DrawTarget
* aDrawTarget
, bool aVertical
, int32_t aAppUnitsPerDevUnit
,
1832 mozilla::gfx::ShapedTextFlags aFlags
, RoundingFlags aRounding
,
1833 const std::function
<void(gfxShapedWord
*)>& aCallback
);
1835 // Called by the gfxFontCache timer to increment the age of all the words,
1836 // so that they'll expire after a sufficient period of non-use.
1837 // Returns true if the cache is now empty, otherwise false.
1838 bool AgeCachedWords();
1840 // Discard all cached word records; called on memory-pressure notification.
1841 void ClearCachedWords() {
1842 mozilla::AutoWriteLock
lock(mLock
);
1844 ClearCachedWordsLocked();
1847 void ClearCachedWordsLocked() MOZ_REQUIRES(mLock
) {
1848 MOZ_ASSERT(mWordCache
);
1849 mWordCache
->clear();
1852 // Glyph rendering/geometry has changed, so invalidate data as necessary.
1853 void NotifyGlyphsChanged() const;
1855 virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
1856 FontCacheSizes
* aSizes
) const;
1857 virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
,
1858 FontCacheSizes
* aSizes
) const;
1867 FONT_TYPE_FONTCONFIG
1870 virtual FontType
GetType() const = 0;
1872 const RefPtr
<mozilla::gfx::UnscaledFont
>& GetUnscaledFont() const {
1873 return mUnscaledFont
;
1876 virtual already_AddRefed
<mozilla::gfx::ScaledFont
> GetScaledFont(
1877 const TextRunDrawParams
& aRunParams
) = 0;
1878 already_AddRefed
<mozilla::gfx::ScaledFont
> GetScaledFont(
1879 mozilla::gfx::DrawTarget
* aDrawTarget
);
1881 // gfxFont implementations may cache ScaledFont versions other than the
1882 // default, so InitializeScaledFont must support explicitly specifying
1883 // which ScaledFonts to initialize.
1884 void InitializeScaledFont(
1885 const RefPtr
<mozilla::gfx::ScaledFont
>& aScaledFont
);
1887 bool KerningDisabled() const { return mKerningSet
&& !mKerningEnabled
; }
1890 * Subclass this object to be notified of glyph changes. Delete the object
1891 * when no longer needed.
1893 class GlyphChangeObserver
{
1895 virtual ~GlyphChangeObserver() {
1897 mFont
->RemoveGlyphChangeObserver(this);
1900 // This gets called when the gfxFont dies.
1901 void ForgetFont() { mFont
= nullptr; }
1902 virtual void NotifyGlyphsChanged() = 0;
1905 explicit GlyphChangeObserver(gfxFont
* aFont
) : mFont(aFont
) {
1906 mFont
->AddGlyphChangeObserver(this);
1908 // This pointer is nulled by ForgetFont in the gfxFont's
1909 // destructor. Before the gfxFont dies.
1910 gfxFont
* MOZ_NON_OWNING_REF mFont
;
1912 friend class GlyphChangeObserver
;
1914 bool GlyphsMayChange() const {
1915 // Currently only fonts with SVG glyphs can have animated glyphs
1916 return mFontEntry
->TryGetSVGData(this);
1919 static void DestroySingletons() {
1920 delete sScriptTagToCode
;
1921 delete sDefaultFeatures
;
1924 // Call TryGetMathTable() to try and load the Open Type MATH table.
1925 // If (and ONLY if) TryGetMathTable() has returned true, the MathTable()
1926 // method may be called to access the gfxMathTable data.
1927 bool TryGetMathTable();
1928 gfxMathTable
* MathTable() const {
1929 MOZ_RELEASE_ASSERT(mMathTable
,
1930 "A successful call to TryGetMathTable() must be "
1931 "performed before calling this function");
1935 // Return a cloned font resized and offset to simulate sub/superscript
1936 // glyphs. This does not add a reference to the returned font.
1937 already_AddRefed
<gfxFont
> GetSubSuperscriptFont(
1938 int32_t aAppUnitsPerDevPixel
) const;
1940 bool HasColorGlyphFor(uint32_t aCh
, uint32_t aNextCh
);
1943 virtual const Metrics
& GetHorizontalMetrics() const = 0;
1945 void CreateVerticalMetrics();
1947 bool MeasureGlyphs(const gfxTextRun
* aTextRun
, uint32_t aStart
, uint32_t aEnd
,
1948 BoundingBoxType aBoundingBoxType
,
1949 DrawTarget
* aRefDrawTarget
, Spacing
* aSpacing
,
1950 gfxGlyphExtents
* aExtents
, bool aIsRTL
,
1951 bool aNeedsGlyphExtents
, RunMetrics
& aMetrics
,
1952 gfxFloat
* aAdvanceMin
, gfxFloat
* aAdvanceMax
);
1954 bool MeasureGlyphs(const gfxTextRun
* aTextRun
, uint32_t aStart
, uint32_t aEnd
,
1955 BoundingBoxType aBoundingBoxType
,
1956 DrawTarget
* aRefDrawTarget
, Spacing
* aSpacing
, bool aIsRTL
,
1957 RunMetrics
& aMetrics
);
1959 // Template parameters for DrawGlyphs/DrawOneGlyph, used to select
1960 // simplified versions of the methods in the most common cases.
1961 enum class FontComplexityT
{ SimpleFont
, ComplexFont
};
1962 enum class SpacingT
{ NoSpacing
, HasSpacing
};
1964 // Output a run of glyphs at *aPt, which is updated to follow the last glyph
1965 // in the run. This method also takes account of any letter-spacing provided
1967 template <FontComplexityT FC
, SpacingT S
>
1968 bool DrawGlyphs(const gfxShapedText
* aShapedText
,
1969 uint32_t aOffset
, // offset in the textrun
1970 uint32_t aCount
, // length of run to draw
1971 mozilla::gfx::Point
* aPt
,
1972 // transform for mOffset field in DetailedGlyph records,
1973 // to account for rotations (may be null)
1974 const mozilla::gfx::Matrix
* aOffsetMatrix
,
1975 GlyphBufferAzure
& aBuffer
);
1977 // Output a single glyph at *aPt.
1978 // Normal glyphs are simply accumulated in aBuffer until it is full and
1979 // gets flushed, but SVG or color-font glyphs will instead be rendered
1980 // directly to the destination (found from the buffer's parameters).
1981 template <FontComplexityT FC
>
1982 void DrawOneGlyph(uint32_t aGlyphID
, const mozilla::gfx::Point
& aPt
,
1983 GlyphBufferAzure
& aBuffer
, bool* aEmittedGlyphs
);
1985 // Helper for DrawOneGlyph to handle missing glyphs, rendering either
1986 // nothing (for default-ignorables) or a missing-glyph hexbox.
1987 bool DrawMissingGlyph(const TextRunDrawParams
& aRunParams
,
1988 const FontDrawParams
& aFontParams
,
1989 const gfxShapedText::DetailedGlyph
* aDetails
,
1990 const mozilla::gfx::Point
& aPt
);
1992 // set the font size and offset used for
1993 // synthetic subscript/superscript glyphs
1994 void CalculateSubSuperSizeAndOffset(int32_t aAppUnitsPerDevPixel
,
1995 gfxFloat
& aSubSuperSizeRatio
,
1996 float& aBaselineOffset
);
1998 // Return a font that is a "clone" of this one, but reduced to 80% size
1999 // (and with variantCaps set to normal). This does not add a reference to
2000 // the returned font.
2001 already_AddRefed
<gfxFont
> GetSmallCapsFont() const;
2003 // subclasses may provide (possibly hinted) glyph widths (in font units);
2004 // if they do not override this, harfbuzz will use unhinted widths
2005 // derived from the font tables
2006 virtual bool ProvidesGlyphWidths() const { return false; }
2008 // The return value is interpreted as a horizontal advance in 16.16 fixed
2010 virtual int32_t GetGlyphWidth(uint16_t aGID
) { return -1; }
2012 virtual bool GetGlyphBounds(uint16_t aGID
, gfxRect
* aBounds
,
2013 bool aTight
= false) {
2017 bool IsSpaceGlyphInvisible(DrawTarget
* aRefDrawTarget
,
2018 const gfxTextRun
* aTextRun
);
2020 void AddGlyphChangeObserver(GlyphChangeObserver
* aObserver
);
2021 void RemoveGlyphChangeObserver(GlyphChangeObserver
* aObserver
);
2023 // whether font contains substitution lookups containing spaces
2024 bool HasSubstitutionRulesWithSpaceLookups(Script aRunScript
) const;
2026 // do spaces participate in shaping rules? if so, can't used word cache
2027 // Note that this function uses HasGraphiteSpaceContextuals, so it can only
2028 // return a "hint" to the correct answer. The calling code must ensure it
2029 // performs safe actions independent of the value returned.
2030 tainted_boolean_hint
SpaceMayParticipateInShaping(Script aRunScript
) const;
2032 // For 8-bit text, expand to 16-bit and then call the following method.
2033 bool ShapeText(DrawTarget
* aContext
, const uint8_t* aText
,
2034 uint32_t aOffset
, // dest offset in gfxShapedText
2035 uint32_t aLength
, Script aScript
, nsAtom
* aLanguage
,
2036 bool aVertical
, RoundingFlags aRounding
,
2037 gfxShapedText
* aShapedText
); // where to store the result
2039 // Call the appropriate shaper to generate glyphs for aText and store
2040 // them into aShapedText.
2041 virtual bool ShapeText(DrawTarget
* aContext
, const char16_t
* aText
,
2042 uint32_t aOffset
, uint32_t aLength
, Script aScript
,
2043 nsAtom
* aLanguage
, bool aVertical
,
2044 RoundingFlags aRounding
, gfxShapedText
* aShapedText
);
2046 // Helper to adjust for synthetic bold and set character-type flags
2047 // in the shaped text; implementations of ShapeText should call this
2048 // after glyph shaping has been completed.
2049 void PostShapingFixup(DrawTarget
* aContext
, const char16_t
* aText
,
2050 uint32_t aOffset
, // position within aShapedText
2051 uint32_t aLength
, bool aVertical
,
2052 gfxShapedText
* aShapedText
);
2054 // Shape text directly into a range within a textrun, without using the
2055 // font's word cache. Intended for use when the font has layout features
2056 // that involve space, and therefore require shaping complete runs rather
2057 // than isolated words, or for long strings that are inefficient to cache.
2058 // This will split the text on "invalid" characters (tab/newline) that are
2059 // not handled via normal shaping, but does not otherwise divide up the
2061 template <typename T
>
2062 bool ShapeTextWithoutWordCache(DrawTarget
* aDrawTarget
, const T
* aText
,
2063 uint32_t aOffset
, uint32_t aLength
,
2064 Script aScript
, nsAtom
* aLanguage
,
2065 bool aVertical
, RoundingFlags aRounding
,
2066 gfxTextRun
* aTextRun
);
2068 // Shape a fragment of text (a run that is known to contain only
2069 // "valid" characters, no newlines/tabs/other control chars).
2070 // All non-wordcache shaping goes through here; this is the function
2071 // that will ensure we don't pass excessively long runs to the various
2072 // platform shapers.
2073 template <typename T
>
2074 bool ShapeFragmentWithoutWordCache(DrawTarget
* aDrawTarget
, const T
* aText
,
2075 uint32_t aOffset
, uint32_t aLength
,
2076 Script aScript
, nsAtom
* aLanguage
,
2077 bool aVertical
, RoundingFlags aRounding
,
2078 gfxTextRun
* aTextRun
);
2080 void CheckForFeaturesInvolvingSpace() const;
2082 // Get a ShapedWord representing the given text (either 8- or 16-bit)
2083 // for use in setting up a gfxTextRun.
2084 template <typename T
, typename Func
>
2085 bool ProcessShapedWordInternal(DrawTarget
* aDrawTarget
, const T
* aText
,
2086 uint32_t aLength
, uint32_t aHash
,
2087 Script aRunScript
, nsAtom
* aLanguage
,
2088 bool aVertical
, int32_t aAppUnitsPerDevUnit
,
2089 mozilla::gfx::ShapedTextFlags aFlags
,
2090 RoundingFlags aRounding
,
2091 gfxTextPerfMetrics
* aTextPerf
, Func aCallback
);
2093 // whether a given feature is included in feature settings from both the
2094 // font and the style. aFeatureOn set if resolved feature value is non-zero
2095 bool HasFeatureSet(uint32_t aFeature
, bool& aFeatureOn
);
2097 // used when analyzing whether a font has space contextual lookups
2098 static mozilla::Atomic
<nsTHashMap
<nsUint32HashKey
, Script
>*> sScriptTagToCode
;
2099 static mozilla::Atomic
<nsTHashSet
<uint32_t>*> sDefaultFeatures
;
2101 RefPtr
<gfxFontEntry
> mFontEntry
;
2102 mutable mozilla::RWLock mLock
;
2104 // Note that WordCacheKey contains a pointer to the text of the word, which
2105 // must be valid for as long as the key is in use. When using for a Lookup,
2106 // the string may be local/temporary, but when storing in the HashMap, we
2107 // set the Key text pointer to reference the text in the associated
2108 // gfxShapedWord that is being stored.
2109 struct WordCacheKey
{
2111 const uint8_t* mSingle
;
2112 const char16_t
* mDouble
;
2115 ShapedTextFlags mFlags
;
2117 RefPtr
<nsAtom
> mLanguage
;
2118 int32_t mAppUnitsPerDevUnit
;
2119 PLDHashNumber mHashKey
;
2121 RoundingFlags mRounding
;
2123 WordCacheKey(const uint8_t* aText
, uint32_t aLength
, uint32_t aStringHash
,
2124 Script aScriptCode
, nsAtom
* aLanguage
,
2125 int32_t aAppUnitsPerDevUnit
, ShapedTextFlags aFlags
,
2126 RoundingFlags aRounding
)
2129 mScript(aScriptCode
),
2130 mLanguage(aLanguage
),
2131 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit
),
2132 mHashKey(aStringHash
+ static_cast<int32_t>(aScriptCode
) +
2133 aAppUnitsPerDevUnit
* 0x100 + uint16_t(aFlags
) * 0x10000 +
2134 int(aRounding
) + (aLanguage
? aLanguage
->hash() : 0)),
2136 mRounding(aRounding
) {
2137 NS_ASSERTION(aFlags
& ShapedTextFlags::TEXT_IS_8BIT
,
2138 "8-bit flag should have been set");
2139 mText
.mSingle
= aText
;
2142 WordCacheKey(const char16_t
* aText
, uint32_t aLength
, uint32_t aStringHash
,
2143 Script aScriptCode
, nsAtom
* aLanguage
,
2144 int32_t aAppUnitsPerDevUnit
, ShapedTextFlags aFlags
,
2145 RoundingFlags aRounding
)
2148 mScript(aScriptCode
),
2149 mLanguage(aLanguage
),
2150 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit
),
2151 mHashKey(aStringHash
+ static_cast<int32_t>(aScriptCode
) +
2152 aAppUnitsPerDevUnit
* 0x100 + uint16_t(aFlags
) * 0x10000 +
2155 mRounding(aRounding
) {
2156 // We can NOT assert that TEXT_IS_8BIT is false in aFlags here,
2157 // because this might be an 8bit-only word from a 16-bit textrun,
2158 // in which case the text we're passed is still in 16-bit form,
2159 // and we'll have to use an 8-to-16bit comparison in KeyEquals.
2160 mText
.mDouble
= aText
;
2163 bool Matches(const WordCacheKey
& aLookup
) const;
2167 typedef WordCacheKey Key
;
2168 typedef WordCacheKey Lookup
;
2169 static mozilla::HashNumber
hash(const Lookup
& aLookup
) {
2170 return aLookup
.mHashKey
;
2172 static bool match(const Key
& aKey
, const Lookup
& aLookup
);
2177 mozilla::HashMap
<WordCacheKey
, mozilla::UniquePtr
<gfxShapedWord
>,
2178 WordCacheKey::HashPolicy
>>
2179 mWordCache
MOZ_GUARDED_BY(mLock
);
2181 static const uint32_t kShapedWordCacheMaxAge
= 3;
2183 nsTArray
<mozilla::UniquePtr
<gfxGlyphExtents
>> mGlyphExtentsArray
2184 MOZ_GUARDED_BY(mLock
);
2185 mozilla::UniquePtr
<nsTHashSet
<GlyphChangeObserver
*>> mGlyphChangeObservers
2186 MOZ_GUARDED_BY(mLock
);
2188 // a copy of the font without antialiasing, if needed for separate
2189 // measurement by mathml code
2190 mozilla::Atomic
<gfxFont
*> mNonAAFont
;
2192 // we create either or both of these shapers when needed, depending
2193 // whether the font has graphite tables, and whether graphite shaping
2194 // is actually enabled
2195 mozilla::Atomic
<gfxHarfBuzzShaper
*> mHarfBuzzShaper
;
2196 mozilla::Atomic
<gfxGraphiteShaper
*> mGraphiteShaper
;
2198 // If a userfont with unicode-range specified, contains map of *possible*
2199 // ranges supported by font. This is set during user-font initialization,
2200 // before the font is available to other threads, and thereafter is inert
2201 // so no guard is needed.
2202 RefPtr
<gfxCharacterMap
> mUnicodeRangeMap
;
2204 // This is immutable once initialized by the constructor, so does not need
2206 RefPtr
<mozilla::gfx::UnscaledFont
> mUnscaledFont
;
2208 mozilla::Atomic
<mozilla::gfx::ScaledFont
*> mAzureScaledFont
;
2210 // For vertical metrics, created on demand.
2211 mozilla::Atomic
<Metrics
*> mVerticalMetrics
;
2213 // Table used for MathML layout.
2214 mozilla::Atomic
<gfxMathTable
*> mMathTable
;
2216 gfxFontStyle mStyle
;
2217 mutable gfxFloat mAdjustedSize
;
2219 // Tracking adjustment to be applied for CSS px size mCachedTrackingSize.
2220 gfxFloat mTracking
= 0.0;
2221 gfxFloat mCachedTrackingSize
= -1.0;
2223 // Conversion factor from font units to dev units; note that this may be
2224 // zero (in the degenerate case where mAdjustedSize has become zero).
2225 // This is OK because we only multiply by this factor, never divide.
2226 float mFUnitsConvFactor
;
2228 // This is guarded by gfxFontCache::GetCache()->GetMutex() but it is difficult
2229 // to annotate that fact.
2230 nsExpirationState mExpirationState
;
2232 // Glyph ID of the font's <space> glyph, zero if missing
2233 uint16_t mSpaceGlyph
= 0;
2235 // the AA setting requested for this font - may affect glyph bounds
2236 AntialiasOption mAntialiasOption
;
2240 // use synthetic bolding for environments where this is not supported
2242 bool mApplySyntheticBold
;
2244 bool mKerningSet
; // kerning explicitly set?
2245 bool mKerningEnabled
; // if set, on or off?
2247 mozilla::Atomic
<bool> mMathInitialized
; // TryGetMathTable() called?
2249 // Helper for subclasses that want to initialize standard metrics from the
2250 // tables of sfnt (TrueType/OpenType) fonts.
2251 // This will use mFUnitsConvFactor if it is already set, else compute it
2252 // from mAdjustedSize and the unitsPerEm in the font's 'head' table.
2253 // Returns TRUE and sets mIsValid=TRUE if successful;
2254 // Returns TRUE but leaves mIsValid=FALSE if the font seems to be broken.
2255 // Returns FALSE if the font does not appear to be an sfnt at all,
2256 // and should be handled (if possible) using other APIs.
2257 bool InitMetricsFromSfntTables(Metrics
& aMetrics
);
2259 // Helper to calculate various derived metrics from the results of
2260 // InitMetricsFromSfntTables or equivalent platform code
2261 void CalculateDerivedMetrics(Metrics
& aMetrics
);
2263 // some fonts have bad metrics, this method sanitize them.
2264 // if this font has bad underline offset, aIsBadUnderlineFont should be true.
2265 void SanitizeMetrics(Metrics
* aMetrics
, bool aIsBadUnderlineFont
);
2267 bool RenderSVGGlyph(gfxContext
* aContext
,
2268 mozilla::layout::TextDrawTarget
* aTextDrawer
,
2269 mozilla::gfx::Point aPoint
, uint32_t aGlyphId
,
2270 SVGContextPaint
* aContextPaint
) const;
2271 bool RenderSVGGlyph(gfxContext
* aContext
,
2272 mozilla::layout::TextDrawTarget
* aTextDrawer
,
2273 mozilla::gfx::Point aPoint
, uint32_t aGlyphId
,
2274 SVGContextPaint
* aContextPaint
,
2275 gfxTextRunDrawCallbacks
* aCallbacks
,
2276 bool& aEmittedGlyphs
) const;
2278 bool RenderColorGlyph(DrawTarget
* aDrawTarget
, gfxContext
* aContext
,
2279 mozilla::layout::TextDrawTarget
* aTextDrawer
,
2280 const FontDrawParams
& aFontParams
,
2281 const mozilla::gfx::Point
& aPoint
, uint32_t aGlyphId
);
2283 class ColorGlyphCache
{
2285 ColorGlyphCache() = default;
2286 ~ColorGlyphCache() = default;
2288 void SetColors(mozilla::gfx::sRGBColor aCurrentColor
,
2289 mozilla::gfx::FontPalette
* aPalette
);
2291 mozilla::HashMap
<uint32_t, RefPtr
<mozilla::gfx::SourceSurface
>> mCache
;
2294 mozilla::gfx::sRGBColor mCurrentColor
;
2295 RefPtr
<mozilla::gfx::FontPalette
> mPalette
;
2297 mozilla::UniquePtr
<ColorGlyphCache
> mColorGlyphCache
;
2299 // Subclasses can override to return true if the platform is able to render
2300 // COLR-font glyphs directly, instead of us painting the layers explicitly.
2301 // (Currently used only for COLR.v0 fonts on macOS.)
2302 virtual bool UseNativeColrFontSupport() const { return false; }
2304 // Bug 674909. When synthetic bolding text by drawing twice, need to
2305 // render using a pixel offset in device pixels, otherwise text
2306 // doesn't appear bolded, it appears as if a bad text shadow exists
2307 // when a non-identity transform exists. Use an offset factor so that
2308 // the second draw occurs at a constant offset in device pixels.
2309 // This helper calculates the scale factor we need to apply to the
2310 // synthetic-bold offset.
2311 static mozilla::gfx::Float
CalcXScale(DrawTarget
* aDrawTarget
);
2314 // proportion of ascent used for x-height, if unable to read value from font
2315 #define DEFAULT_XHEIGHT_FACTOR 0.56f
2317 // Parameters passed to gfxFont methods for drawing glyphs from a textrun.
2318 // The TextRunDrawParams are set up once per textrun; the FontDrawParams
2319 // are dependent on the specific font, so they are set per GlyphRun.
2321 struct MOZ_STACK_CLASS TextRunDrawParams
{
2322 explicit TextRunDrawParams(mozilla::gfx::PaletteCache
& aPaletteCache
)
2323 : paletteCache(aPaletteCache
) {}
2325 mozilla::gfx::PaletteCache
& paletteCache
;
2326 RefPtr
<mozilla::gfx::DrawTarget
> dt
;
2327 gfxContext
* context
= nullptr;
2328 gfxFont::Spacing
* spacing
= nullptr;
2329 gfxTextRunDrawCallbacks
* callbacks
= nullptr;
2330 mozilla::SVGContextPaint
* runContextPaint
= nullptr;
2331 mozilla::layout::TextDrawTarget
* textDrawer
= nullptr;
2332 mozilla::LayoutDeviceRect clipRect
;
2333 mozilla::gfx::Float direction
= 1.0f
;
2334 double devPerApp
= 1.0;
2335 nscolor textStrokeColor
= 0;
2336 gfxPattern
* textStrokePattern
= nullptr;
2337 const mozilla::gfx::StrokeOptions
* strokeOpts
= nullptr;
2338 const mozilla::gfx::DrawOptions
* drawOpts
= nullptr;
2339 nsAtom
* fontPalette
= nullptr;
2340 DrawMode drawMode
= DrawMode::GLYPH_FILL
;
2341 bool isVerticalRun
= false;
2343 bool paintSVGGlyphs
= true;
2344 bool allowGDI
= true;
2345 bool hasTextShadow
= false;
2348 struct MOZ_STACK_CLASS FontDrawParams
{
2349 RefPtr
<mozilla::gfx::ScaledFont
> scaledFont
;
2350 mozilla::SVGContextPaint
* contextPaint
;
2351 mozilla::gfx::Float synBoldOnePixelOffset
;
2352 mozilla::gfx::Float obliqueSkew
;
2353 int32_t extraStrikes
;
2354 mozilla::gfx::DrawOptions drawOptions
;
2355 gfxFloat advanceDirection
;
2356 mozilla::gfx::sRGBColor currentColor
;
2357 RefPtr
<mozilla::gfx::FontPalette
> palette
;
2358 mozilla::gfx::Rect fontExtents
;
2359 bool isVerticalFont
;
2361 bool haveColorGlyphs
;
2362 bool hasTextShadow
; // whether we're rendering with a text-shadow
2365 struct MOZ_STACK_CLASS EmphasisMarkDrawParams
{
2366 EmphasisMarkDrawParams(gfxContext
* aContext
,
2367 mozilla::gfx::PaletteCache
& aPaletteCache
)
2368 : context(aContext
), paletteCache(aPaletteCache
) {}
2369 gfxContext
* context
;
2370 mozilla::gfx::PaletteCache
& paletteCache
;
2371 gfxFont::Spacing
* spacing
;