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