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