|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef GFX_FONT_H |
|
7 #define GFX_FONT_H |
|
8 |
|
9 #include "gfxTypes.h" |
|
10 #include "nsString.h" |
|
11 #include "gfxPoint.h" |
|
12 #include "gfxFontUtils.h" |
|
13 #include "nsTArray.h" |
|
14 #include "nsTHashtable.h" |
|
15 #include "nsHashKeys.h" |
|
16 #include "gfxSkipChars.h" |
|
17 #include "gfxRect.h" |
|
18 #include "nsExpirationTracker.h" |
|
19 #include "gfxPlatform.h" |
|
20 #include "nsIAtom.h" |
|
21 #include "mozilla/HashFunctions.h" |
|
22 #include "nsIMemoryReporter.h" |
|
23 #include "nsIObserver.h" |
|
24 #include "gfxFontFeatures.h" |
|
25 #include "mozilla/MemoryReporting.h" |
|
26 #include "mozilla/Attributes.h" |
|
27 #include <algorithm> |
|
28 #include "DrawMode.h" |
|
29 #include "nsUnicodeScriptCodes.h" |
|
30 #include "nsDataHashtable.h" |
|
31 #include "harfbuzz/hb.h" |
|
32 #include "mozilla/gfx/2D.h" |
|
33 |
|
34 typedef struct _cairo_scaled_font cairo_scaled_font_t; |
|
35 typedef struct gr_face gr_face; |
|
36 |
|
37 #ifdef DEBUG |
|
38 #include <stdio.h> |
|
39 #endif |
|
40 |
|
41 class gfxContext; |
|
42 class gfxTextRun; |
|
43 class gfxFont; |
|
44 class gfxFontFamily; |
|
45 class gfxFontGroup; |
|
46 class gfxGraphiteShaper; |
|
47 class gfxHarfBuzzShaper; |
|
48 class gfxUserFontSet; |
|
49 class gfxUserFontData; |
|
50 class gfxShapedText; |
|
51 class gfxShapedWord; |
|
52 class gfxSVGGlyphs; |
|
53 class gfxMathTable; |
|
54 class gfxTextContextPaint; |
|
55 class FontInfoData; |
|
56 |
|
57 class nsILanguageAtomService; |
|
58 |
|
59 #define FONT_MAX_SIZE 2000.0 |
|
60 |
|
61 #define NO_FONT_LANGUAGE_OVERRIDE 0 |
|
62 |
|
63 struct FontListSizes; |
|
64 struct gfxTextRunDrawCallbacks; |
|
65 |
|
66 namespace mozilla { |
|
67 namespace gfx { |
|
68 class GlyphRenderingOptions; |
|
69 } |
|
70 } |
|
71 |
|
72 struct gfxFontStyle { |
|
73 gfxFontStyle(); |
|
74 gfxFontStyle(uint8_t aStyle, uint16_t aWeight, int16_t aStretch, |
|
75 gfxFloat aSize, nsIAtom *aLanguage, |
|
76 float aSizeAdjust, bool aSystemFont, |
|
77 bool aPrinterFont, |
|
78 const nsString& aLanguageOverride); |
|
79 gfxFontStyle(const gfxFontStyle& aStyle); |
|
80 |
|
81 // the language (may be an internal langGroup code rather than an actual |
|
82 // language code) specified in the document or element's lang property, |
|
83 // or inferred from the charset |
|
84 nsRefPtr<nsIAtom> language; |
|
85 |
|
86 // Features are composed of (1) features from style rules (2) features |
|
87 // from feature setttings rules and (3) family-specific features. (1) and |
|
88 // (3) are guaranteed to be mutually exclusive |
|
89 |
|
90 // custom opentype feature settings |
|
91 nsTArray<gfxFontFeature> featureSettings; |
|
92 |
|
93 // Some font-variant property values require font-specific settings |
|
94 // defined via @font-feature-values rules. These are resolved after |
|
95 // font matching occurs. |
|
96 |
|
97 // -- list of value tags for specific alternate features |
|
98 nsTArray<gfxAlternateValue> alternateValues; |
|
99 |
|
100 // -- object used to look these up once the font is matched |
|
101 nsRefPtr<gfxFontFeatureValueSet> featureValueLookup; |
|
102 |
|
103 // The logical size of the font, in pixels |
|
104 gfxFloat size; |
|
105 |
|
106 // The aspect-value (ie., the ratio actualsize:actualxheight) that any |
|
107 // actual physical font created from this font structure must have when |
|
108 // rendering or measuring a string. A value of 0 means no adjustment |
|
109 // needs to be done. |
|
110 float sizeAdjust; |
|
111 |
|
112 // Language system tag, to override document language; |
|
113 // an OpenType "language system" tag represented as a 32-bit integer |
|
114 // (see http://www.microsoft.com/typography/otspec/languagetags.htm). |
|
115 // Normally 0, so font rendering will use the document or element language |
|
116 // (see above) to control any language-specific rendering, but the author |
|
117 // can override this for cases where the options implemented in the font |
|
118 // do not directly match the actual language. (E.g. lang may be Macedonian, |
|
119 // but the font in use does not explicitly support this; the author can |
|
120 // use font-language-override to request the Serbian option in the font |
|
121 // in order to get correct glyph shapes.) |
|
122 uint32_t languageOverride; |
|
123 |
|
124 // The weight of the font: 100, 200, ... 900. |
|
125 uint16_t weight; |
|
126 |
|
127 // The stretch of the font (the sum of various NS_FONT_STRETCH_* |
|
128 // constants; see gfxFontConstants.h). |
|
129 int8_t stretch; |
|
130 |
|
131 // Say that this font is a system font and therefore does not |
|
132 // require certain fixup that we do for fonts from untrusted |
|
133 // sources. |
|
134 bool systemFont : 1; |
|
135 |
|
136 // Say that this font is used for print or print preview. |
|
137 bool printerFont : 1; |
|
138 |
|
139 // Used to imitate -webkit-font-smoothing: antialiased |
|
140 bool useGrayscaleAntialiasing : 1; |
|
141 |
|
142 // The style of font (normal, italic, oblique) |
|
143 uint8_t style : 2; |
|
144 |
|
145 // Return the final adjusted font size for the given aspect ratio. |
|
146 // Not meant to be called when sizeAdjust = 0. |
|
147 gfxFloat GetAdjustedSize(gfxFloat aspect) const { |
|
148 NS_ASSERTION(sizeAdjust != 0.0, "Not meant to be called when sizeAdjust = 0"); |
|
149 gfxFloat adjustedSize = std::max(NS_round(size*(sizeAdjust/aspect)), 1.0); |
|
150 return std::min(adjustedSize, FONT_MAX_SIZE); |
|
151 } |
|
152 |
|
153 PLDHashNumber Hash() const { |
|
154 return ((style + (systemFont << 7) + |
|
155 (weight << 8)) + uint32_t(size*1000) + uint32_t(sizeAdjust*1000)) ^ |
|
156 nsISupportsHashKey::HashKey(language); |
|
157 } |
|
158 |
|
159 int8_t ComputeWeight() const; |
|
160 |
|
161 bool Equals(const gfxFontStyle& other) const { |
|
162 return |
|
163 (*reinterpret_cast<const uint64_t*>(&size) == |
|
164 *reinterpret_cast<const uint64_t*>(&other.size)) && |
|
165 (style == other.style) && |
|
166 (systemFont == other.systemFont) && |
|
167 (printerFont == other.printerFont) && |
|
168 (useGrayscaleAntialiasing == other.useGrayscaleAntialiasing) && |
|
169 (weight == other.weight) && |
|
170 (stretch == other.stretch) && |
|
171 (language == other.language) && |
|
172 (*reinterpret_cast<const uint32_t*>(&sizeAdjust) == |
|
173 *reinterpret_cast<const uint32_t*>(&other.sizeAdjust)) && |
|
174 (featureSettings == other.featureSettings) && |
|
175 (languageOverride == other.languageOverride) && |
|
176 (alternateValues == other.alternateValues) && |
|
177 (featureValueLookup == other.featureValueLookup); |
|
178 } |
|
179 |
|
180 static void ParseFontFeatureSettings(const nsString& aFeatureString, |
|
181 nsTArray<gfxFontFeature>& aFeatures); |
|
182 |
|
183 static uint32_t ParseFontLanguageOverride(const nsString& aLangTag); |
|
184 }; |
|
185 |
|
186 class gfxCharacterMap : public gfxSparseBitSet { |
|
187 public: |
|
188 nsrefcnt AddRef() { |
|
189 NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt"); |
|
190 ++mRefCnt; |
|
191 NS_LOG_ADDREF(this, mRefCnt, "gfxCharacterMap", sizeof(*this)); |
|
192 return mRefCnt; |
|
193 } |
|
194 |
|
195 nsrefcnt Release() { |
|
196 NS_PRECONDITION(0 != mRefCnt, "dup release"); |
|
197 --mRefCnt; |
|
198 NS_LOG_RELEASE(this, mRefCnt, "gfxCharacterMap"); |
|
199 if (mRefCnt == 0) { |
|
200 NotifyReleased(); |
|
201 // |this| has been deleted. |
|
202 return 0; |
|
203 } |
|
204 return mRefCnt; |
|
205 } |
|
206 |
|
207 gfxCharacterMap() : |
|
208 mHash(0), mBuildOnTheFly(false), mShared(false) |
|
209 { } |
|
210 |
|
211 void CalcHash() { mHash = GetChecksum(); } |
|
212 |
|
213 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { |
|
214 return gfxSparseBitSet::SizeOfExcludingThis(aMallocSizeOf); |
|
215 } |
|
216 |
|
217 // hash of the cmap bitvector |
|
218 uint32_t mHash; |
|
219 |
|
220 // if cmap is built on the fly it's never shared |
|
221 bool mBuildOnTheFly; |
|
222 |
|
223 // cmap is shared globally |
|
224 bool mShared; |
|
225 |
|
226 protected: |
|
227 void NotifyReleased(); |
|
228 |
|
229 nsAutoRefCnt mRefCnt; |
|
230 |
|
231 private: |
|
232 gfxCharacterMap(const gfxCharacterMap&); |
|
233 gfxCharacterMap& operator=(const gfxCharacterMap&); |
|
234 }; |
|
235 |
|
236 class gfxFontEntry { |
|
237 public: |
|
238 NS_INLINE_DECL_REFCOUNTING(gfxFontEntry) |
|
239 |
|
240 gfxFontEntry(const nsAString& aName, bool aIsStandardFace = false); |
|
241 |
|
242 // unique name for the face, *not* the family; not necessarily the |
|
243 // "real" or user-friendly name, may be an internal identifier |
|
244 const nsString& Name() const { return mName; } |
|
245 |
|
246 // family name |
|
247 const nsString& FamilyName() const { return mFamilyName; } |
|
248 |
|
249 // The following two methods may be relatively expensive, as they |
|
250 // will (usually, except on Linux) load and parse the 'name' table; |
|
251 // they are intended only for the font-inspection API, not for |
|
252 // perf-critical layout/drawing work. |
|
253 |
|
254 // The "real" name of the face, if available from the font resource; |
|
255 // returns Name() if nothing better is available. |
|
256 virtual nsString RealFaceName(); |
|
257 |
|
258 uint16_t Weight() const { return mWeight; } |
|
259 int16_t Stretch() const { return mStretch; } |
|
260 |
|
261 bool IsUserFont() const { return mIsUserFont; } |
|
262 bool IsLocalUserFont() const { return mIsLocalUserFont; } |
|
263 bool IsFixedPitch() const { return mFixedPitch; } |
|
264 bool IsItalic() const { return mItalic; } |
|
265 bool IsBold() const { return mWeight >= 600; } // bold == weights 600 and above |
|
266 bool IgnoreGDEF() const { return mIgnoreGDEF; } |
|
267 bool IgnoreGSUB() const { return mIgnoreGSUB; } |
|
268 |
|
269 virtual bool IsSymbolFont(); |
|
270 |
|
271 virtual bool HasFontTable(uint32_t aTableTag); |
|
272 |
|
273 inline bool HasGraphiteTables() { |
|
274 if (!mCheckedForGraphiteTables) { |
|
275 CheckForGraphiteTables(); |
|
276 mCheckedForGraphiteTables = true; |
|
277 } |
|
278 return mHasGraphiteTables; |
|
279 } |
|
280 |
|
281 inline bool HasCmapTable() { |
|
282 if (!mCharacterMap) { |
|
283 ReadCMAP(); |
|
284 NS_ASSERTION(mCharacterMap, "failed to initialize character map"); |
|
285 } |
|
286 return mHasCmapTable; |
|
287 } |
|
288 |
|
289 inline bool HasCharacter(uint32_t ch) { |
|
290 if (mCharacterMap && mCharacterMap->test(ch)) { |
|
291 return true; |
|
292 } |
|
293 return TestCharacterMap(ch); |
|
294 } |
|
295 |
|
296 virtual bool SkipDuringSystemFallback() { return false; } |
|
297 virtual bool TestCharacterMap(uint32_t aCh); |
|
298 nsresult InitializeUVSMap(); |
|
299 uint16_t GetUVSGlyph(uint32_t aCh, uint32_t aVS); |
|
300 |
|
301 // All concrete gfxFontEntry subclasses (except gfxProxyFontEntry) need |
|
302 // to override this, otherwise the font will never be used as it will |
|
303 // be considered to support no characters. |
|
304 // ReadCMAP() must *always* set the mCharacterMap pointer to a valid |
|
305 // gfxCharacterMap, even if empty, as other code assumes this pointer |
|
306 // can be safely dereferenced. |
|
307 virtual nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr); |
|
308 |
|
309 bool TryGetSVGData(gfxFont* aFont); |
|
310 bool HasSVGGlyph(uint32_t aGlyphId); |
|
311 bool GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId, |
|
312 gfxRect *aResult); |
|
313 bool RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId, int aDrawMode, |
|
314 gfxTextContextPaint *aContextPaint); |
|
315 // Call this when glyph geometry or rendering has changed |
|
316 // (e.g. animated SVG glyphs) |
|
317 void NotifyGlyphsChanged(); |
|
318 |
|
319 enum MathConstant { |
|
320 // The order of the constants must match the order of the fields |
|
321 // defined in the MATH table. |
|
322 ScriptPercentScaleDown, |
|
323 ScriptScriptPercentScaleDown, |
|
324 DelimitedSubFormulaMinHeight, |
|
325 DisplayOperatorMinHeight, |
|
326 MathLeading, |
|
327 AxisHeight, |
|
328 AccentBaseHeight, |
|
329 FlattenedAccentBaseHeight, |
|
330 SubscriptShiftDown, |
|
331 SubscriptTopMax, |
|
332 SubscriptBaselineDropMin, |
|
333 SuperscriptShiftUp, |
|
334 SuperscriptShiftUpCramped, |
|
335 SuperscriptBottomMin, |
|
336 SuperscriptBaselineDropMax, |
|
337 SubSuperscriptGapMin, |
|
338 SuperscriptBottomMaxWithSubscript, |
|
339 SpaceAfterScript, |
|
340 UpperLimitGapMin, |
|
341 UpperLimitBaselineRiseMin, |
|
342 LowerLimitGapMin, |
|
343 LowerLimitBaselineDropMin, |
|
344 StackTopShiftUp, |
|
345 StackTopDisplayStyleShiftUp, |
|
346 StackBottomShiftDown, |
|
347 StackBottomDisplayStyleShiftDown, |
|
348 StackGapMin, |
|
349 StackDisplayStyleGapMin, |
|
350 StretchStackTopShiftUp, |
|
351 StretchStackBottomShiftDown, |
|
352 StretchStackGapAboveMin, |
|
353 StretchStackGapBelowMin, |
|
354 FractionNumeratorShiftUp, |
|
355 FractionNumeratorDisplayStyleShiftUp, |
|
356 FractionDenominatorShiftDown, |
|
357 FractionDenominatorDisplayStyleShiftDown, |
|
358 FractionNumeratorGapMin, |
|
359 FractionNumDisplayStyleGapMin, |
|
360 FractionRuleThickness, |
|
361 FractionDenominatorGapMin, |
|
362 FractionDenomDisplayStyleGapMin, |
|
363 SkewedFractionHorizontalGap, |
|
364 SkewedFractionVerticalGap, |
|
365 OverbarVerticalGap, |
|
366 OverbarRuleThickness, |
|
367 OverbarExtraAscender, |
|
368 UnderbarVerticalGap, |
|
369 UnderbarRuleThickness, |
|
370 UnderbarExtraDescender, |
|
371 RadicalVerticalGap, |
|
372 RadicalDisplayStyleVerticalGap, |
|
373 RadicalRuleThickness, |
|
374 RadicalExtraAscender, |
|
375 RadicalKernBeforeDegree, |
|
376 RadicalKernAfterDegree, |
|
377 RadicalDegreeBottomRaisePercent |
|
378 }; |
|
379 |
|
380 // Call TryGetMathTable to try to load the Open Type MATH table. The other |
|
381 // functions forward the call to the gfxMathTable class. The GetMath...() |
|
382 // functions MUST NOT be called unless TryGetMathTable() has returned true. |
|
383 bool TryGetMathTable(gfxFont* aFont); |
|
384 gfxFloat GetMathConstant(MathConstant aConstant); |
|
385 bool GetMathItalicsCorrection(uint32_t aGlyphID, |
|
386 gfxFloat* aItalicCorrection); |
|
387 uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical, |
|
388 uint16_t aSize); |
|
389 bool GetMathVariantsParts(uint32_t aGlyphID, bool aVertical, |
|
390 uint32_t aGlyphs[4]); |
|
391 |
|
392 virtual bool MatchesGenericFamily(const nsACString& aGeneric) const { |
|
393 return true; |
|
394 } |
|
395 virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const { |
|
396 return true; |
|
397 } |
|
398 |
|
399 // Access to raw font table data (needed for Harfbuzz): |
|
400 // returns a pointer to data owned by the fontEntry or the OS, |
|
401 // which will remain valid until the blob is destroyed. |
|
402 // The data MUST be treated as read-only; we may be getting a |
|
403 // reference to a shared system font cache. |
|
404 // |
|
405 // The default implementation uses CopyFontTable to get the data |
|
406 // into a byte array, and maintains a cache of loaded tables. |
|
407 // |
|
408 // Subclasses should override this if they can provide more efficient |
|
409 // access than copying table data into our own buffers. |
|
410 // |
|
411 // Get blob that encapsulates a specific font table, or nullptr if |
|
412 // the table doesn't exist in the font. |
|
413 // |
|
414 // Caller is responsible to call hb_blob_destroy() on the returned blob |
|
415 // (if non-nullptr) when no longer required. For transient access to a |
|
416 // table, use of AutoTable (below) is generally preferred. |
|
417 virtual hb_blob_t *GetFontTable(uint32_t aTag); |
|
418 |
|
419 // Stack-based utility to return a specified table, automatically releasing |
|
420 // the blob when the AutoTable goes out of scope. |
|
421 class AutoTable { |
|
422 public: |
|
423 AutoTable(gfxFontEntry* aFontEntry, uint32_t aTag) |
|
424 { |
|
425 mBlob = aFontEntry->GetFontTable(aTag); |
|
426 } |
|
427 ~AutoTable() { |
|
428 if (mBlob) { |
|
429 hb_blob_destroy(mBlob); |
|
430 } |
|
431 } |
|
432 operator hb_blob_t*() const { return mBlob; } |
|
433 private: |
|
434 hb_blob_t* mBlob; |
|
435 // not implemented: |
|
436 AutoTable(const AutoTable&) MOZ_DELETE; |
|
437 AutoTable& operator=(const AutoTable&) MOZ_DELETE; |
|
438 }; |
|
439 |
|
440 already_AddRefed<gfxFont> FindOrMakeFont(const gfxFontStyle *aStyle, |
|
441 bool aNeedsBold); |
|
442 |
|
443 // Get an existing font table cache entry in aBlob if it has been |
|
444 // registered, or return false if not. Callers must call |
|
445 // hb_blob_destroy on aBlob if true is returned. |
|
446 // |
|
447 // Note that some gfxFont implementations may not call this at all, |
|
448 // if it is more efficient to get the table from the OS at that level. |
|
449 bool GetExistingFontTable(uint32_t aTag, hb_blob_t** aBlob); |
|
450 |
|
451 // Elements of aTable are transferred (not copied) to and returned in a |
|
452 // new hb_blob_t which is registered on the gfxFontEntry, but the initial |
|
453 // reference is owned by the caller. Removing the last reference |
|
454 // unregisters the table from the font entry. |
|
455 // |
|
456 // Pass nullptr for aBuffer to indicate that the table is not present and |
|
457 // nullptr will be returned. Also returns nullptr on OOM. |
|
458 hb_blob_t *ShareFontTableAndGetBlob(uint32_t aTag, |
|
459 FallibleTArray<uint8_t>* aTable); |
|
460 |
|
461 // Get the font's unitsPerEm from the 'head' table, in the case of an |
|
462 // sfnt resource. Will return kInvalidUPEM for non-sfnt fonts, |
|
463 // if present on the platform. |
|
464 uint16_t UnitsPerEm(); |
|
465 enum { |
|
466 kMinUPEM = 16, // Limits on valid unitsPerEm range, from the |
|
467 kMaxUPEM = 16384, // OpenType spec |
|
468 kInvalidUPEM = uint16_t(-1) |
|
469 }; |
|
470 |
|
471 // Shaper face accessors: |
|
472 // NOTE that harfbuzz and graphite handle ownership/lifetime of the face |
|
473 // object in completely different ways. |
|
474 |
|
475 // Get HarfBuzz face corresponding to this font file. |
|
476 // Caller must release with hb_face_destroy() when finished with it, |
|
477 // and the font entry will be notified via ForgetHBFace. |
|
478 hb_face_t* GetHBFace(); |
|
479 virtual void ForgetHBFace(); |
|
480 |
|
481 // Get Graphite face corresponding to this font file. |
|
482 // Caller must call gfxFontEntry::ReleaseGrFace when finished with it. |
|
483 gr_face* GetGrFace(); |
|
484 virtual void ReleaseGrFace(gr_face* aFace); |
|
485 |
|
486 // Release any SVG-glyphs document this font may have loaded. |
|
487 void DisconnectSVG(); |
|
488 |
|
489 // Called to notify that aFont is being destroyed. Needed when we're tracking |
|
490 // the fonts belonging to this font entry. |
|
491 void NotifyFontDestroyed(gfxFont* aFont); |
|
492 |
|
493 // For memory reporting |
|
494 virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, |
|
495 FontListSizes* aSizes) const; |
|
496 virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, |
|
497 FontListSizes* aSizes) const; |
|
498 |
|
499 // Used when checking for complex script support, to mask off cmap ranges |
|
500 struct ScriptRange { |
|
501 uint32_t rangeStart; |
|
502 uint32_t rangeEnd; |
|
503 hb_tag_t tags[3]; // one or two OpenType script tags to check, |
|
504 // plus a NULL terminator |
|
505 }; |
|
506 |
|
507 bool SupportsScriptInGSUB(const hb_tag_t* aScriptTags); |
|
508 |
|
509 nsString mName; |
|
510 nsString mFamilyName; |
|
511 |
|
512 bool mItalic : 1; |
|
513 bool mFixedPitch : 1; |
|
514 bool mIsProxy : 1; |
|
515 bool mIsValid : 1; |
|
516 bool mIsBadUnderlineFont : 1; |
|
517 bool mIsUserFont : 1; |
|
518 bool mIsLocalUserFont : 1; |
|
519 bool mStandardFace : 1; |
|
520 bool mSymbolFont : 1; |
|
521 bool mIgnoreGDEF : 1; |
|
522 bool mIgnoreGSUB : 1; |
|
523 bool mSVGInitialized : 1; |
|
524 bool mMathInitialized : 1; |
|
525 bool mHasSpaceFeaturesInitialized : 1; |
|
526 bool mHasSpaceFeatures : 1; |
|
527 bool mHasSpaceFeaturesKerning : 1; |
|
528 bool mHasSpaceFeaturesNonKerning : 1; |
|
529 bool mSkipDefaultFeatureSpaceCheck : 1; |
|
530 bool mHasGraphiteTables : 1; |
|
531 bool mCheckedForGraphiteTables : 1; |
|
532 bool mHasCmapTable : 1; |
|
533 bool mGrFaceInitialized : 1; |
|
534 |
|
535 // bitvector of substitution space features per script, one each |
|
536 // for default and non-default features |
|
537 uint32_t mDefaultSubSpaceFeatures[(MOZ_NUM_SCRIPT_CODES + 31) / 32]; |
|
538 uint32_t mNonDefaultSubSpaceFeatures[(MOZ_NUM_SCRIPT_CODES + 31) / 32]; |
|
539 |
|
540 uint16_t mWeight; |
|
541 int16_t mStretch; |
|
542 |
|
543 nsRefPtr<gfxCharacterMap> mCharacterMap; |
|
544 uint32_t mUVSOffset; |
|
545 nsAutoArrayPtr<uint8_t> mUVSData; |
|
546 nsAutoPtr<gfxUserFontData> mUserFontData; |
|
547 nsAutoPtr<gfxSVGGlyphs> mSVGGlyphs; |
|
548 // list of gfxFonts that are using SVG glyphs |
|
549 nsTArray<gfxFont*> mFontsUsingSVGGlyphs; |
|
550 nsAutoPtr<gfxMathTable> mMathTable; |
|
551 nsTArray<gfxFontFeature> mFeatureSettings; |
|
552 uint32_t mLanguageOverride; |
|
553 |
|
554 protected: |
|
555 friend class gfxPlatformFontList; |
|
556 friend class gfxMacPlatformFontList; |
|
557 friend class gfxUserFcFontEntry; |
|
558 friend class gfxFontFamily; |
|
559 friend class gfxSingleFaceMacFontFamily; |
|
560 |
|
561 gfxFontEntry(); |
|
562 |
|
563 // Protected destructor, to discourage deletion outside of Release(): |
|
564 virtual ~gfxFontEntry(); |
|
565 |
|
566 virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold) { |
|
567 NS_NOTREACHED("oops, somebody didn't override CreateFontInstance"); |
|
568 return nullptr; |
|
569 } |
|
570 |
|
571 virtual void CheckForGraphiteTables(); |
|
572 |
|
573 // Copy a font table into aBuffer. |
|
574 // The caller will be responsible for ownership of the data. |
|
575 virtual nsresult CopyFontTable(uint32_t aTableTag, |
|
576 FallibleTArray<uint8_t>& aBuffer) { |
|
577 NS_NOTREACHED("forgot to override either GetFontTable or CopyFontTable?"); |
|
578 return NS_ERROR_FAILURE; |
|
579 } |
|
580 |
|
581 // Return a blob that wraps a table found within a buffer of font data. |
|
582 // The blob does NOT own its data; caller guarantees that the buffer |
|
583 // will remain valid at least as long as the blob. |
|
584 // Returns null if the specified table is not found. |
|
585 // This method assumes aFontData is valid 'sfnt' data; before using this, |
|
586 // caller is responsible to do any sanitization/validation necessary. |
|
587 hb_blob_t* GetTableFromFontData(const void* aFontData, uint32_t aTableTag); |
|
588 |
|
589 // lookup the cmap in cached font data |
|
590 virtual already_AddRefed<gfxCharacterMap> |
|
591 GetCMAPFromFontInfo(FontInfoData *aFontInfoData, |
|
592 uint32_t& aUVSOffset, |
|
593 bool& aSymbolFont); |
|
594 |
|
595 // Font's unitsPerEm from the 'head' table, if available (will be set to |
|
596 // kInvalidUPEM for non-sfnt font formats) |
|
597 uint16_t mUnitsPerEm; |
|
598 |
|
599 // Shaper-specific face objects, shared by all instantiations of the same |
|
600 // physical font, regardless of size. |
|
601 // Usually, only one of these will actually be created for any given font |
|
602 // entry, depending on the font tables that are present. |
|
603 |
|
604 // hb_face_t is refcounted internally, so each shaper that's using it will |
|
605 // bump the ref count when it acquires the face, and "destroy" (release) it |
|
606 // in its destructor. The font entry has only this non-owning reference to |
|
607 // the face; when the face is deleted, it will tell the font entry to forget |
|
608 // it, so that a new face will be created next time it is needed. |
|
609 hb_face_t* mHBFace; |
|
610 |
|
611 static hb_blob_t* HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData); |
|
612 |
|
613 // Callback that the hb_face will use to tell us when it is being deleted. |
|
614 static void HBFaceDeletedCallback(void *aUserData); |
|
615 |
|
616 // gr_face is -not- refcounted, so it will be owned directly by the font |
|
617 // entry, and we'll keep a count of how many references we've handed out; |
|
618 // each shaper is responsible to call ReleaseGrFace on its entry when |
|
619 // finished with it, so that we know when it can be deleted. |
|
620 gr_face* mGrFace; |
|
621 |
|
622 // hashtable to map raw table data ptr back to its owning blob, for use by |
|
623 // graphite table-release callback |
|
624 nsDataHashtable<nsPtrHashKey<const void>,void*>* mGrTableMap; |
|
625 |
|
626 // number of current users of this entry's mGrFace |
|
627 nsrefcnt mGrFaceRefCnt; |
|
628 |
|
629 static const void* GrGetTable(const void *aAppFaceHandle, |
|
630 unsigned int aName, |
|
631 size_t *aLen); |
|
632 static void GrReleaseTable(const void *aAppFaceHandle, |
|
633 const void *aTableBuffer); |
|
634 |
|
635 private: |
|
636 /** |
|
637 * Font table hashtable, to support GetFontTable for harfbuzz. |
|
638 * |
|
639 * The harfbuzz shaper (and potentially other clients) needs access to raw |
|
640 * font table data. This needs to be cached so that it can be used |
|
641 * repeatedly (each time we construct a text run; in some cases, for |
|
642 * each character/glyph within the run) without re-fetching large tables |
|
643 * every time. |
|
644 * |
|
645 * Because we may instantiate many gfxFonts for the same physical font |
|
646 * file (at different sizes), we should ensure that they can share a |
|
647 * single cached copy of the font tables. To do this, we implement table |
|
648 * access and sharing on the fontEntry rather than the font itself. |
|
649 * |
|
650 * The default implementation uses GetFontTable() to read font table |
|
651 * data into byte arrays, and wraps them in blobs which are registered in |
|
652 * a hashtable. The hashtable can then return pre-existing blobs to |
|
653 * harfbuzz. |
|
654 * |
|
655 * Harfbuzz will "destroy" the blobs when it is finished with them. When |
|
656 * the last blob reference is removed, the FontTableBlobData user data |
|
657 * will remove the blob from the hashtable if still registered. |
|
658 */ |
|
659 |
|
660 class FontTableBlobData; |
|
661 |
|
662 /** |
|
663 * FontTableHashEntry manages the entries of hb_blob_t's containing font |
|
664 * table data. |
|
665 * |
|
666 * This is used to share font tables across fonts with the same |
|
667 * font entry (but different sizes) for use by HarfBuzz. The hashtable |
|
668 * does not own a strong reference to the blob, but keeps a weak pointer, |
|
669 * managed by FontTableBlobData. Similarly FontTableBlobData keeps only a |
|
670 * weak pointer to the hashtable, managed by FontTableHashEntry. |
|
671 */ |
|
672 |
|
673 class FontTableHashEntry : public nsUint32HashKey |
|
674 { |
|
675 public: |
|
676 // Declarations for nsTHashtable |
|
677 |
|
678 typedef nsUint32HashKey KeyClass; |
|
679 typedef KeyClass::KeyType KeyType; |
|
680 typedef KeyClass::KeyTypePointer KeyTypePointer; |
|
681 |
|
682 FontTableHashEntry(KeyTypePointer aTag) |
|
683 : KeyClass(aTag) |
|
684 , mSharedBlobData(nullptr) |
|
685 , mBlob(nullptr) |
|
686 { } |
|
687 |
|
688 // NOTE: This assumes the new entry belongs to the same hashtable as |
|
689 // the old, because the mHashtable pointer in mSharedBlobData (if |
|
690 // present) will not be updated. |
|
691 FontTableHashEntry(FontTableHashEntry&& toMove) |
|
692 : KeyClass(mozilla::Move(toMove)) |
|
693 , mSharedBlobData(mozilla::Move(toMove.mSharedBlobData)) |
|
694 , mBlob(mozilla::Move(toMove.mBlob)) |
|
695 { |
|
696 toMove.mSharedBlobData = nullptr; |
|
697 toMove.mBlob = nullptr; |
|
698 } |
|
699 |
|
700 ~FontTableHashEntry() { Clear(); } |
|
701 |
|
702 // FontTable/Blob API |
|
703 |
|
704 // Transfer (not copy) elements of aTable to a new hb_blob_t and |
|
705 // return ownership to the caller. A weak reference to the blob is |
|
706 // recorded in the hashtable entry so that others may use the same |
|
707 // table. |
|
708 hb_blob_t * |
|
709 ShareTableAndGetBlob(FallibleTArray<uint8_t>& aTable, |
|
710 nsTHashtable<FontTableHashEntry> *aHashtable); |
|
711 |
|
712 // Return a strong reference to the blob. |
|
713 // Callers must hb_blob_destroy the returned blob. |
|
714 hb_blob_t *GetBlob() const; |
|
715 |
|
716 void Clear(); |
|
717 |
|
718 static size_t |
|
719 SizeOfEntryExcludingThis(FontTableHashEntry *aEntry, |
|
720 mozilla::MallocSizeOf aMallocSizeOf, |
|
721 void* aUserArg); |
|
722 |
|
723 private: |
|
724 static void DeleteFontTableBlobData(void *aBlobData); |
|
725 // not implemented |
|
726 FontTableHashEntry& operator=(FontTableHashEntry& toCopy); |
|
727 |
|
728 FontTableBlobData *mSharedBlobData; |
|
729 hb_blob_t *mBlob; |
|
730 }; |
|
731 |
|
732 nsAutoPtr<nsTHashtable<FontTableHashEntry> > mFontTableCache; |
|
733 |
|
734 gfxFontEntry(const gfxFontEntry&); |
|
735 gfxFontEntry& operator=(const gfxFontEntry&); |
|
736 }; |
|
737 |
|
738 |
|
739 // used when iterating over all fonts looking for a match for a given character |
|
740 struct GlobalFontMatch { |
|
741 GlobalFontMatch(const uint32_t aCharacter, |
|
742 int32_t aRunScript, |
|
743 const gfxFontStyle *aStyle) : |
|
744 mCh(aCharacter), mRunScript(aRunScript), mStyle(aStyle), |
|
745 mMatchRank(0), mCount(0), mCmapsTested(0) |
|
746 { |
|
747 |
|
748 } |
|
749 |
|
750 const uint32_t mCh; // codepoint to be matched |
|
751 int32_t mRunScript; // Unicode script for the codepoint |
|
752 const gfxFontStyle* mStyle; // style to match |
|
753 int32_t mMatchRank; // metric indicating closest match |
|
754 nsRefPtr<gfxFontEntry> mBestMatch; // current best match |
|
755 nsRefPtr<gfxFontFamily> mMatchedFamily; // the family it belongs to |
|
756 uint32_t mCount; // number of fonts matched |
|
757 uint32_t mCmapsTested; // number of cmaps tested |
|
758 }; |
|
759 |
|
760 class gfxFontFamily { |
|
761 public: |
|
762 NS_INLINE_DECL_REFCOUNTING(gfxFontFamily) |
|
763 |
|
764 gfxFontFamily(const nsAString& aName) : |
|
765 mName(aName), |
|
766 mOtherFamilyNamesInitialized(false), |
|
767 mHasOtherFamilyNames(false), |
|
768 mFaceNamesInitialized(false), |
|
769 mHasStyles(false), |
|
770 mIsSimpleFamily(false), |
|
771 mIsBadUnderlineFamily(false), |
|
772 mFamilyCharacterMapInitialized(false), |
|
773 mSkipDefaultFeatureSpaceCheck(false) |
|
774 { } |
|
775 |
|
776 const nsString& Name() { return mName; } |
|
777 |
|
778 virtual void LocalizedName(nsAString& aLocalizedName); |
|
779 virtual bool HasOtherFamilyNames(); |
|
780 |
|
781 nsTArray<nsRefPtr<gfxFontEntry> >& GetFontList() { return mAvailableFonts; } |
|
782 |
|
783 void AddFontEntry(nsRefPtr<gfxFontEntry> aFontEntry) { |
|
784 // bug 589682 - set the IgnoreGDEF flag on entries for Italic faces |
|
785 // of Times New Roman, because of buggy table in those fonts |
|
786 if (aFontEntry->IsItalic() && !aFontEntry->IsUserFont() && |
|
787 Name().EqualsLiteral("Times New Roman")) |
|
788 { |
|
789 aFontEntry->mIgnoreGDEF = true; |
|
790 } |
|
791 aFontEntry->mFamilyName = Name(); |
|
792 aFontEntry->mSkipDefaultFeatureSpaceCheck = mSkipDefaultFeatureSpaceCheck; |
|
793 mAvailableFonts.AppendElement(aFontEntry); |
|
794 } |
|
795 |
|
796 // note that the styles for this family have been added |
|
797 bool HasStyles() { return mHasStyles; } |
|
798 void SetHasStyles(bool aHasStyles) { mHasStyles = aHasStyles; } |
|
799 |
|
800 // choose a specific face to match a style using CSS font matching |
|
801 // rules (weight matching occurs here). may return a face that doesn't |
|
802 // precisely match (e.g. normal face when no italic face exists). |
|
803 // aNeedsSyntheticBold is set to true when synthetic bolding is |
|
804 // needed, false otherwise |
|
805 gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle, |
|
806 bool& aNeedsSyntheticBold); |
|
807 |
|
808 // checks for a matching font within the family |
|
809 // used as part of the font fallback process |
|
810 void FindFontForChar(GlobalFontMatch *aMatchData); |
|
811 |
|
812 // checks all fonts for a matching font within the family |
|
813 void SearchAllFontsForChar(GlobalFontMatch *aMatchData); |
|
814 |
|
815 // read in other family names, if any, and use functor to add each into cache |
|
816 virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList); |
|
817 |
|
818 // helper method for reading localized family names from the name table |
|
819 // of a single face |
|
820 static void ReadOtherFamilyNamesForFace(const nsAString& aFamilyName, |
|
821 const char *aNameData, |
|
822 uint32_t aDataLength, |
|
823 nsTArray<nsString>& aOtherFamilyNames, |
|
824 bool useFullName); |
|
825 |
|
826 // set when other family names have been read in |
|
827 void SetOtherFamilyNamesInitialized() { |
|
828 mOtherFamilyNamesInitialized = true; |
|
829 } |
|
830 |
|
831 // read in other localized family names, fullnames and Postscript names |
|
832 // for all faces and append to lookup tables |
|
833 virtual void ReadFaceNames(gfxPlatformFontList *aPlatformFontList, |
|
834 bool aNeedFullnamePostscriptNames, |
|
835 FontInfoData *aFontInfoData = nullptr); |
|
836 |
|
837 // find faces belonging to this family (platform implementations override this; |
|
838 // should be made pure virtual once all subclasses have been updated) |
|
839 virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) { } |
|
840 |
|
841 // search for a specific face using the Postscript name |
|
842 gfxFontEntry* FindFont(const nsAString& aPostscriptName); |
|
843 |
|
844 // read in cmaps for all the faces |
|
845 void ReadAllCMAPs(FontInfoData *aFontInfoData = nullptr); |
|
846 |
|
847 bool TestCharacterMap(uint32_t aCh) { |
|
848 if (!mFamilyCharacterMapInitialized) { |
|
849 ReadAllCMAPs(); |
|
850 } |
|
851 return mFamilyCharacterMap.test(aCh); |
|
852 } |
|
853 |
|
854 void ResetCharacterMap() { |
|
855 mFamilyCharacterMap.reset(); |
|
856 mFamilyCharacterMapInitialized = false; |
|
857 } |
|
858 |
|
859 // mark this family as being in the "bad" underline offset blacklist |
|
860 void SetBadUnderlineFamily() { |
|
861 mIsBadUnderlineFamily = true; |
|
862 if (mHasStyles) { |
|
863 SetBadUnderlineFonts(); |
|
864 } |
|
865 } |
|
866 |
|
867 bool IsBadUnderlineFamily() const { return mIsBadUnderlineFamily; } |
|
868 |
|
869 // sort available fonts to put preferred (standard) faces towards the end |
|
870 void SortAvailableFonts(); |
|
871 |
|
872 // check whether the family fits into the simple 4-face model, |
|
873 // so we can use simplified style-matching; |
|
874 // if so set the mIsSimpleFamily flag (defaults to False before we've checked) |
|
875 void CheckForSimpleFamily(); |
|
876 |
|
877 // For memory reporter |
|
878 virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, |
|
879 FontListSizes* aSizes) const; |
|
880 virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, |
|
881 FontListSizes* aSizes) const; |
|
882 |
|
883 // Only used for debugging checks - does a linear search |
|
884 bool ContainsFace(gfxFontEntry* aFontEntry) { |
|
885 uint32_t i, numFonts = mAvailableFonts.Length(); |
|
886 for (i = 0; i < numFonts; i++) { |
|
887 if (mAvailableFonts[i] == aFontEntry) { |
|
888 return true; |
|
889 } |
|
890 } |
|
891 return false; |
|
892 } |
|
893 |
|
894 void SetSkipSpaceFeatureCheck(bool aSkipCheck) { |
|
895 mSkipDefaultFeatureSpaceCheck = aSkipCheck; |
|
896 } |
|
897 |
|
898 protected: |
|
899 // Protected destructor, to discourage deletion outside of Release(): |
|
900 virtual ~gfxFontFamily() |
|
901 { |
|
902 } |
|
903 |
|
904 // fills in an array with weights of faces that match style, |
|
905 // returns whether any matching entries found |
|
906 virtual bool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], |
|
907 bool anItalic, int16_t aStretch); |
|
908 |
|
909 bool ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList, |
|
910 hb_blob_t *aNameTable, |
|
911 bool useFullName = false); |
|
912 |
|
913 // set whether this font family is in "bad" underline offset blacklist. |
|
914 void SetBadUnderlineFonts() { |
|
915 uint32_t i, numFonts = mAvailableFonts.Length(); |
|
916 for (i = 0; i < numFonts; i++) { |
|
917 if (mAvailableFonts[i]) { |
|
918 mAvailableFonts[i]->mIsBadUnderlineFont = true; |
|
919 } |
|
920 } |
|
921 } |
|
922 |
|
923 nsString mName; |
|
924 nsTArray<nsRefPtr<gfxFontEntry> > mAvailableFonts; |
|
925 gfxSparseBitSet mFamilyCharacterMap; |
|
926 bool mOtherFamilyNamesInitialized : 1; |
|
927 bool mHasOtherFamilyNames : 1; |
|
928 bool mFaceNamesInitialized : 1; |
|
929 bool mHasStyles : 1; |
|
930 bool mIsSimpleFamily : 1; |
|
931 bool mIsBadUnderlineFamily : 1; |
|
932 bool mFamilyCharacterMapInitialized : 1; |
|
933 bool mSkipDefaultFeatureSpaceCheck : 1; |
|
934 |
|
935 enum { |
|
936 // for "simple" families, the faces are stored in mAvailableFonts |
|
937 // with fixed positions: |
|
938 kRegularFaceIndex = 0, |
|
939 kBoldFaceIndex = 1, |
|
940 kItalicFaceIndex = 2, |
|
941 kBoldItalicFaceIndex = 3, |
|
942 // mask values for selecting face with bold and/or italic attributes |
|
943 kBoldMask = 0x01, |
|
944 kItalicMask = 0x02 |
|
945 }; |
|
946 }; |
|
947 |
|
948 struct gfxTextRange { |
|
949 enum { |
|
950 // flags for recording the kind of font-matching that was used |
|
951 kFontGroup = 0x0001, |
|
952 kPrefsFallback = 0x0002, |
|
953 kSystemFallback = 0x0004 |
|
954 }; |
|
955 gfxTextRange(uint32_t aStart, uint32_t aEnd, |
|
956 gfxFont* aFont, uint8_t aMatchType) |
|
957 : start(aStart), |
|
958 end(aEnd), |
|
959 font(aFont), |
|
960 matchType(aMatchType) |
|
961 { } |
|
962 uint32_t Length() const { return end - start; } |
|
963 uint32_t start, end; |
|
964 nsRefPtr<gfxFont> font; |
|
965 uint8_t matchType; |
|
966 }; |
|
967 |
|
968 |
|
969 /** |
|
970 * Font cache design: |
|
971 * |
|
972 * The mFonts hashtable contains most fonts, indexed by (gfxFontEntry*, style). |
|
973 * It does not add a reference to the fonts it contains. |
|
974 * When a font's refcount decreases to zero, instead of deleting it we |
|
975 * add it to our expiration tracker. |
|
976 * The expiration tracker tracks fonts with zero refcount. After a certain |
|
977 * period of time, such fonts expire and are deleted. |
|
978 * |
|
979 * We're using 3 generations with a ten-second generation interval, so |
|
980 * zero-refcount fonts will be deleted 20-30 seconds after their refcount |
|
981 * goes to zero, if timer events fire in a timely manner. |
|
982 * |
|
983 * The font cache also handles timed expiration of cached ShapedWords |
|
984 * for "persistent" fonts: it has a repeating timer, and notifies |
|
985 * each cached font to "age" its shaped words. The words will be released |
|
986 * by the fonts if they get aged three times without being re-used in the |
|
987 * meantime. |
|
988 * |
|
989 * Note that the ShapedWord timeout is much larger than the font timeout, |
|
990 * so that in the case of a short-lived font, we'll discard the gfxFont |
|
991 * completely, with all its words, and avoid the cost of aging the words |
|
992 * individually. That only happens with longer-lived fonts. |
|
993 */ |
|
994 struct FontCacheSizes { |
|
995 FontCacheSizes() |
|
996 : mFontInstances(0), mShapedWords(0) |
|
997 { } |
|
998 |
|
999 size_t mFontInstances; // memory used by instances of gfxFont subclasses |
|
1000 size_t mShapedWords; // memory used by the per-font shapedWord caches |
|
1001 }; |
|
1002 |
|
1003 class gfxFontCache MOZ_FINAL : public nsExpirationTracker<gfxFont,3> { |
|
1004 public: |
|
1005 enum { |
|
1006 FONT_TIMEOUT_SECONDS = 10, |
|
1007 SHAPED_WORD_TIMEOUT_SECONDS = 60 |
|
1008 }; |
|
1009 |
|
1010 gfxFontCache(); |
|
1011 ~gfxFontCache(); |
|
1012 |
|
1013 /* |
|
1014 * Get the global gfxFontCache. You must call Init() before |
|
1015 * calling this method --- the result will not be null. |
|
1016 */ |
|
1017 static gfxFontCache* GetCache() { |
|
1018 return gGlobalCache; |
|
1019 } |
|
1020 |
|
1021 static nsresult Init(); |
|
1022 // It's OK to call this even if Init() has not been called. |
|
1023 static void Shutdown(); |
|
1024 |
|
1025 // Look up a font in the cache. Returns an addrefed pointer, or null |
|
1026 // if there's nothing matching in the cache |
|
1027 already_AddRefed<gfxFont> Lookup(const gfxFontEntry *aFontEntry, |
|
1028 const gfxFontStyle *aStyle); |
|
1029 // We created a new font (presumably because Lookup returned null); |
|
1030 // put it in the cache. The font's refcount should be nonzero. It is |
|
1031 // allowable to add a new font even if there is one already in the |
|
1032 // cache with the same key; we'll forget about the old one. |
|
1033 void AddNew(gfxFont *aFont); |
|
1034 |
|
1035 // The font's refcount has gone to zero; give ownership of it to |
|
1036 // the cache. We delete it if it's not acquired again after a certain |
|
1037 // amount of time. |
|
1038 void NotifyReleased(gfxFont *aFont); |
|
1039 |
|
1040 // This gets called when the timeout has expired on a zero-refcount |
|
1041 // font; we just delete it. |
|
1042 virtual void NotifyExpired(gfxFont *aFont); |
|
1043 |
|
1044 // Cleans out the hashtable and removes expired fonts waiting for cleanup. |
|
1045 // Other gfxFont objects may be still in use but they will be pushed |
|
1046 // into the expiration queues and removed. |
|
1047 void Flush() { |
|
1048 mFonts.Clear(); |
|
1049 AgeAllGenerations(); |
|
1050 } |
|
1051 |
|
1052 void FlushShapedWordCaches() { |
|
1053 mFonts.EnumerateEntries(ClearCachedWordsForFont, nullptr); |
|
1054 } |
|
1055 |
|
1056 void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, |
|
1057 FontCacheSizes* aSizes) const; |
|
1058 void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, |
|
1059 FontCacheSizes* aSizes) const; |
|
1060 |
|
1061 protected: |
|
1062 class MemoryReporter MOZ_FINAL : public nsIMemoryReporter |
|
1063 { |
|
1064 public: |
|
1065 NS_DECL_ISUPPORTS |
|
1066 NS_DECL_NSIMEMORYREPORTER |
|
1067 }; |
|
1068 |
|
1069 // Observer for notifications that the font cache cares about |
|
1070 class Observer MOZ_FINAL |
|
1071 : public nsIObserver |
|
1072 { |
|
1073 public: |
|
1074 NS_DECL_ISUPPORTS |
|
1075 NS_DECL_NSIOBSERVER |
|
1076 }; |
|
1077 |
|
1078 void DestroyFont(gfxFont *aFont); |
|
1079 |
|
1080 static gfxFontCache *gGlobalCache; |
|
1081 |
|
1082 struct Key { |
|
1083 const gfxFontEntry* mFontEntry; |
|
1084 const gfxFontStyle* mStyle; |
|
1085 Key(const gfxFontEntry* aFontEntry, const gfxFontStyle* aStyle) |
|
1086 : mFontEntry(aFontEntry), mStyle(aStyle) {} |
|
1087 }; |
|
1088 |
|
1089 class HashEntry : public PLDHashEntryHdr { |
|
1090 public: |
|
1091 typedef const Key& KeyType; |
|
1092 typedef const Key* KeyTypePointer; |
|
1093 |
|
1094 // When constructing a new entry in the hashtable, we'll leave this |
|
1095 // blank. The caller of Put() will fill this in. |
|
1096 HashEntry(KeyTypePointer aStr) : mFont(nullptr) { } |
|
1097 HashEntry(const HashEntry& toCopy) : mFont(toCopy.mFont) { } |
|
1098 ~HashEntry() { } |
|
1099 |
|
1100 bool KeyEquals(const KeyTypePointer aKey) const; |
|
1101 static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } |
|
1102 static PLDHashNumber HashKey(const KeyTypePointer aKey) { |
|
1103 return mozilla::HashGeneric(aKey->mStyle->Hash(), aKey->mFontEntry); |
|
1104 } |
|
1105 enum { ALLOW_MEMMOVE = true }; |
|
1106 |
|
1107 gfxFont* mFont; |
|
1108 }; |
|
1109 |
|
1110 static size_t AddSizeOfFontEntryExcludingThis(HashEntry* aHashEntry, |
|
1111 mozilla::MallocSizeOf aMallocSizeOf, |
|
1112 void* aUserArg); |
|
1113 |
|
1114 nsTHashtable<HashEntry> mFonts; |
|
1115 |
|
1116 static PLDHashOperator ClearCachedWordsForFont(HashEntry* aHashEntry, void*); |
|
1117 static PLDHashOperator AgeCachedWordsForFont(HashEntry* aHashEntry, void*); |
|
1118 static void WordCacheExpirationTimerCallback(nsITimer* aTimer, void* aCache); |
|
1119 nsCOMPtr<nsITimer> mWordCacheExpirationTimer; |
|
1120 }; |
|
1121 |
|
1122 class gfxTextPerfMetrics { |
|
1123 public: |
|
1124 |
|
1125 struct TextCounts { |
|
1126 uint32_t numContentTextRuns; |
|
1127 uint32_t numChromeTextRuns; |
|
1128 uint32_t numChars; |
|
1129 uint32_t maxTextRunLen; |
|
1130 uint32_t wordCacheSpaceRules; |
|
1131 uint32_t wordCacheLong; |
|
1132 uint32_t wordCacheHit; |
|
1133 uint32_t wordCacheMiss; |
|
1134 uint32_t fallbackPrefs; |
|
1135 uint32_t fallbackSystem; |
|
1136 uint32_t textrunConst; |
|
1137 uint32_t textrunDestr; |
|
1138 }; |
|
1139 |
|
1140 uint32_t reflowCount; |
|
1141 |
|
1142 // counts per reflow operation |
|
1143 TextCounts current; |
|
1144 |
|
1145 // totals for the lifetime of a document |
|
1146 TextCounts cumulative; |
|
1147 |
|
1148 gfxTextPerfMetrics() { |
|
1149 memset(this, 0, sizeof(gfxTextPerfMetrics)); |
|
1150 } |
|
1151 |
|
1152 // add current totals to cumulative ones |
|
1153 void Accumulate() { |
|
1154 if (current.numChars == 0) { |
|
1155 return; |
|
1156 } |
|
1157 cumulative.numContentTextRuns += current.numContentTextRuns; |
|
1158 cumulative.numChromeTextRuns += current.numChromeTextRuns; |
|
1159 cumulative.numChars += current.numChars; |
|
1160 if (current.maxTextRunLen > cumulative.maxTextRunLen) { |
|
1161 cumulative.maxTextRunLen = current.maxTextRunLen; |
|
1162 } |
|
1163 cumulative.wordCacheSpaceRules += current.wordCacheSpaceRules; |
|
1164 cumulative.wordCacheLong += current.wordCacheLong; |
|
1165 cumulative.wordCacheHit += current.wordCacheHit; |
|
1166 cumulative.wordCacheMiss += current.wordCacheMiss; |
|
1167 cumulative.fallbackPrefs += current.fallbackPrefs; |
|
1168 cumulative.fallbackSystem += current.fallbackSystem; |
|
1169 cumulative.textrunConst += current.textrunConst; |
|
1170 cumulative.textrunDestr += current.textrunDestr; |
|
1171 memset(¤t, 0, sizeof(current)); |
|
1172 } |
|
1173 }; |
|
1174 |
|
1175 class gfxTextRunFactory { |
|
1176 NS_INLINE_DECL_REFCOUNTING(gfxTextRunFactory) |
|
1177 |
|
1178 public: |
|
1179 // Flags in the mask 0xFFFF0000 are reserved for textrun clients |
|
1180 // Flags in the mask 0x0000F000 are reserved for per-platform fonts |
|
1181 // Flags in the mask 0x00000FFF are set by the textrun creator. |
|
1182 enum { |
|
1183 CACHE_TEXT_FLAGS = 0xF0000000, |
|
1184 USER_TEXT_FLAGS = 0x0FFF0000, |
|
1185 PLATFORM_TEXT_FLAGS = 0x0000F000, |
|
1186 TEXTRUN_TEXT_FLAGS = 0x00000FFF, |
|
1187 SETTABLE_FLAGS = CACHE_TEXT_FLAGS | USER_TEXT_FLAGS, |
|
1188 |
|
1189 /** |
|
1190 * When set, the text string pointer used to create the text run |
|
1191 * is guaranteed to be available during the lifetime of the text run. |
|
1192 */ |
|
1193 TEXT_IS_PERSISTENT = 0x0001, |
|
1194 /** |
|
1195 * When set, the text is known to be all-ASCII (< 128). |
|
1196 */ |
|
1197 TEXT_IS_ASCII = 0x0002, |
|
1198 /** |
|
1199 * When set, the text is RTL. |
|
1200 */ |
|
1201 TEXT_IS_RTL = 0x0004, |
|
1202 /** |
|
1203 * When set, spacing is enabled and the textrun needs to call GetSpacing |
|
1204 * on the spacing provider. |
|
1205 */ |
|
1206 TEXT_ENABLE_SPACING = 0x0008, |
|
1207 /** |
|
1208 * When set, GetHyphenationBreaks may return true for some character |
|
1209 * positions, otherwise it will always return false for all characters. |
|
1210 */ |
|
1211 TEXT_ENABLE_HYPHEN_BREAKS = 0x0010, |
|
1212 /** |
|
1213 * When set, the text has no characters above 255 and it is stored |
|
1214 * in the textrun in 8-bit format. |
|
1215 */ |
|
1216 TEXT_IS_8BIT = 0x0020, |
|
1217 /** |
|
1218 * When set, the RunMetrics::mBoundingBox field will be initialized |
|
1219 * properly based on glyph extents, in particular, glyph extents that |
|
1220 * overflow the standard font-box (the box defined by the ascent, descent |
|
1221 * and advance width of the glyph). When not set, it may just be the |
|
1222 * standard font-box even if glyphs overflow. |
|
1223 */ |
|
1224 TEXT_NEED_BOUNDING_BOX = 0x0040, |
|
1225 /** |
|
1226 * When set, optional ligatures are disabled. Ligatures that are |
|
1227 * required for legible text should still be enabled. |
|
1228 */ |
|
1229 TEXT_DISABLE_OPTIONAL_LIGATURES = 0x0080, |
|
1230 /** |
|
1231 * When set, the textrun should favour speed of construction over |
|
1232 * quality. This may involve disabling ligatures and/or kerning or |
|
1233 * other effects. |
|
1234 */ |
|
1235 TEXT_OPTIMIZE_SPEED = 0x0100, |
|
1236 /** |
|
1237 * For internal use by the memory reporter when accounting for |
|
1238 * storage used by textruns. |
|
1239 * Because the reporter may visit each textrun multiple times while |
|
1240 * walking the frame trees and textrun cache, it needs to mark |
|
1241 * textruns that have been seen so as to avoid multiple-accounting. |
|
1242 */ |
|
1243 TEXT_RUN_SIZE_ACCOUNTED = 0x0200, |
|
1244 /** |
|
1245 * When set, the textrun should discard control characters instead of |
|
1246 * turning them into hexboxes. |
|
1247 */ |
|
1248 TEXT_HIDE_CONTROL_CHARACTERS = 0x0400, |
|
1249 |
|
1250 /** |
|
1251 * nsTextFrameThebes sets these, but they're defined here rather than |
|
1252 * in nsTextFrameUtils.h because ShapedWord creation/caching also needs |
|
1253 * to check the _INCOMING flag |
|
1254 */ |
|
1255 TEXT_TRAILING_ARABICCHAR = 0x20000000, |
|
1256 /** |
|
1257 * When set, the previous character for this textrun was an Arabic |
|
1258 * character. This is used for the context detection necessary for |
|
1259 * bidi.numeral implementation. |
|
1260 */ |
|
1261 TEXT_INCOMING_ARABICCHAR = 0x40000000, |
|
1262 |
|
1263 // Set if the textrun should use the OpenType 'math' script. |
|
1264 TEXT_USE_MATH_SCRIPT = 0x80000000, |
|
1265 |
|
1266 TEXT_UNUSED_FLAGS = 0x10000000 |
|
1267 }; |
|
1268 |
|
1269 /** |
|
1270 * This record contains all the parameters needed to initialize a textrun. |
|
1271 */ |
|
1272 struct Parameters { |
|
1273 // A reference context suggesting where the textrun will be rendered |
|
1274 gfxContext *mContext; |
|
1275 // Pointer to arbitrary user data (which should outlive the textrun) |
|
1276 void *mUserData; |
|
1277 // A description of which characters have been stripped from the original |
|
1278 // DOM string to produce the characters in the textrun. May be null |
|
1279 // if that information is not relevant. |
|
1280 gfxSkipChars *mSkipChars; |
|
1281 // A list of where linebreaks are currently placed in the textrun. May |
|
1282 // be null if mInitialBreakCount is zero. |
|
1283 uint32_t *mInitialBreaks; |
|
1284 uint32_t mInitialBreakCount; |
|
1285 // The ratio to use to convert device pixels to application layout units |
|
1286 int32_t mAppUnitsPerDevUnit; |
|
1287 }; |
|
1288 |
|
1289 protected: |
|
1290 // Protected destructor, to discourage deletion outside of Release(): |
|
1291 virtual ~gfxTextRunFactory() {} |
|
1292 }; |
|
1293 |
|
1294 /** |
|
1295 * This stores glyph bounds information for a particular gfxFont, at |
|
1296 * a particular appunits-per-dev-pixel ratio (because the compressed glyph |
|
1297 * width array is stored in appunits). |
|
1298 * |
|
1299 * We store a hashtable from glyph IDs to float bounding rects. For the |
|
1300 * common case where the glyph has no horizontal left bearing, and no |
|
1301 * y overflow above the font ascent or below the font descent, and tight |
|
1302 * bounding boxes are not required, we avoid storing the glyph ID in the hashtable |
|
1303 * and instead consult an array of 16-bit glyph XMost values (in appunits). |
|
1304 * This array always has an entry for the font's space glyph --- the width is |
|
1305 * assumed to be zero. |
|
1306 */ |
|
1307 class gfxGlyphExtents { |
|
1308 public: |
|
1309 gfxGlyphExtents(int32_t aAppUnitsPerDevUnit) : |
|
1310 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) { |
|
1311 MOZ_COUNT_CTOR(gfxGlyphExtents); |
|
1312 } |
|
1313 ~gfxGlyphExtents(); |
|
1314 |
|
1315 enum { INVALID_WIDTH = 0xFFFF }; |
|
1316 |
|
1317 void NotifyGlyphsChanged() { |
|
1318 mTightGlyphExtents.Clear(); |
|
1319 } |
|
1320 |
|
1321 // returns INVALID_WIDTH => not a contained glyph |
|
1322 // Otherwise the glyph has no before-bearing or vertical bearings, |
|
1323 // and the result is its width measured from the baseline origin, in |
|
1324 // appunits. |
|
1325 uint16_t GetContainedGlyphWidthAppUnits(uint32_t aGlyphID) const { |
|
1326 return mContainedGlyphWidths.Get(aGlyphID); |
|
1327 } |
|
1328 |
|
1329 bool IsGlyphKnown(uint32_t aGlyphID) const { |
|
1330 return mContainedGlyphWidths.Get(aGlyphID) != INVALID_WIDTH || |
|
1331 mTightGlyphExtents.GetEntry(aGlyphID) != nullptr; |
|
1332 } |
|
1333 |
|
1334 bool IsGlyphKnownWithTightExtents(uint32_t aGlyphID) const { |
|
1335 return mTightGlyphExtents.GetEntry(aGlyphID) != nullptr; |
|
1336 } |
|
1337 |
|
1338 // Get glyph extents; a rectangle relative to the left baseline origin |
|
1339 // Returns true on success. Can fail on OOM or when aContext is null |
|
1340 // and extents were not (successfully) prefetched. |
|
1341 bool GetTightGlyphExtentsAppUnits(gfxFont *aFont, gfxContext *aContext, |
|
1342 uint32_t aGlyphID, gfxRect *aExtents); |
|
1343 |
|
1344 void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID, uint16_t aWidth) { |
|
1345 mContainedGlyphWidths.Set(aGlyphID, aWidth); |
|
1346 } |
|
1347 void SetTightGlyphExtents(uint32_t aGlyphID, const gfxRect& aExtentsAppUnits); |
|
1348 |
|
1349 int32_t GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; } |
|
1350 |
|
1351 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
|
1352 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
|
1353 |
|
1354 private: |
|
1355 class HashEntry : public nsUint32HashKey { |
|
1356 public: |
|
1357 // When constructing a new entry in the hashtable, we'll leave this |
|
1358 // blank. The caller of Put() will fill this in. |
|
1359 HashEntry(KeyTypePointer aPtr) : nsUint32HashKey(aPtr) {} |
|
1360 HashEntry(const HashEntry& toCopy) : nsUint32HashKey(toCopy) { |
|
1361 x = toCopy.x; y = toCopy.y; width = toCopy.width; height = toCopy.height; |
|
1362 } |
|
1363 |
|
1364 float x, y, width, height; |
|
1365 }; |
|
1366 |
|
1367 enum { BLOCK_SIZE_BITS = 7, BLOCK_SIZE = 1 << BLOCK_SIZE_BITS }; // 128-glyph blocks |
|
1368 |
|
1369 class GlyphWidths { |
|
1370 public: |
|
1371 void Set(uint32_t aIndex, uint16_t aValue); |
|
1372 uint16_t Get(uint32_t aIndex) const { |
|
1373 uint32_t block = aIndex >> BLOCK_SIZE_BITS; |
|
1374 if (block >= mBlocks.Length()) |
|
1375 return INVALID_WIDTH; |
|
1376 uintptr_t bits = mBlocks[block]; |
|
1377 if (!bits) |
|
1378 return INVALID_WIDTH; |
|
1379 uint32_t indexInBlock = aIndex & (BLOCK_SIZE - 1); |
|
1380 if (bits & 0x1) { |
|
1381 if (GetGlyphOffset(bits) != indexInBlock) |
|
1382 return INVALID_WIDTH; |
|
1383 return GetWidth(bits); |
|
1384 } |
|
1385 uint16_t *widths = reinterpret_cast<uint16_t *>(bits); |
|
1386 return widths[indexInBlock]; |
|
1387 } |
|
1388 |
|
1389 uint32_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
|
1390 |
|
1391 ~GlyphWidths(); |
|
1392 |
|
1393 private: |
|
1394 static uint32_t GetGlyphOffset(uintptr_t aBits) { |
|
1395 NS_ASSERTION(aBits & 0x1, "This is really a pointer..."); |
|
1396 return (aBits >> 1) & ((1 << BLOCK_SIZE_BITS) - 1); |
|
1397 } |
|
1398 static uint32_t GetWidth(uintptr_t aBits) { |
|
1399 NS_ASSERTION(aBits & 0x1, "This is really a pointer..."); |
|
1400 return aBits >> (1 + BLOCK_SIZE_BITS); |
|
1401 } |
|
1402 static uintptr_t MakeSingle(uint32_t aGlyphOffset, uint16_t aWidth) { |
|
1403 return (aWidth << (1 + BLOCK_SIZE_BITS)) + (aGlyphOffset << 1) + 1; |
|
1404 } |
|
1405 |
|
1406 nsTArray<uintptr_t> mBlocks; |
|
1407 }; |
|
1408 |
|
1409 GlyphWidths mContainedGlyphWidths; |
|
1410 nsTHashtable<HashEntry> mTightGlyphExtents; |
|
1411 int32_t mAppUnitsPerDevUnit; |
|
1412 |
|
1413 private: |
|
1414 // not implemented: |
|
1415 gfxGlyphExtents(const gfxGlyphExtents& aOther) MOZ_DELETE; |
|
1416 gfxGlyphExtents& operator=(const gfxGlyphExtents& aOther) MOZ_DELETE; |
|
1417 }; |
|
1418 |
|
1419 /** |
|
1420 * gfxFontShaper |
|
1421 * |
|
1422 * This class implements text shaping (character to glyph mapping and |
|
1423 * glyph layout). There is a gfxFontShaper subclass for each text layout |
|
1424 * technology (uniscribe, core text, harfbuzz,....) we support. |
|
1425 * |
|
1426 * The shaper is responsible for setting up glyph data in gfxTextRuns. |
|
1427 * |
|
1428 * A generic, platform-independent shaper relies only on the standard |
|
1429 * gfxFont interface and can work with any concrete subclass of gfxFont. |
|
1430 * |
|
1431 * Platform-specific implementations designed to interface to platform |
|
1432 * shaping APIs such as Uniscribe or CoreText may rely on features of a |
|
1433 * specific font subclass to access native font references |
|
1434 * (such as CTFont, HFONT, DWriteFont, etc). |
|
1435 */ |
|
1436 |
|
1437 class gfxFontShaper { |
|
1438 public: |
|
1439 gfxFontShaper(gfxFont *aFont) |
|
1440 : mFont(aFont) |
|
1441 { |
|
1442 NS_ASSERTION(aFont, "shaper requires a valid font!"); |
|
1443 } |
|
1444 |
|
1445 virtual ~gfxFontShaper() { } |
|
1446 |
|
1447 // Shape a piece of text and store the resulting glyph data into |
|
1448 // aShapedText. Parameters aOffset/aLength indicate the range of |
|
1449 // aShapedText to be updated; aLength is also the length of aText. |
|
1450 virtual bool ShapeText(gfxContext *aContext, |
|
1451 const char16_t *aText, |
|
1452 uint32_t aOffset, |
|
1453 uint32_t aLength, |
|
1454 int32_t aScript, |
|
1455 gfxShapedText *aShapedText) = 0; |
|
1456 |
|
1457 gfxFont *GetFont() const { return mFont; } |
|
1458 |
|
1459 // returns true if features exist in output, false otherwise |
|
1460 static bool |
|
1461 MergeFontFeatures(const gfxFontStyle *aStyle, |
|
1462 const nsTArray<gfxFontFeature>& aFontFeatures, |
|
1463 bool aDisableLigatures, |
|
1464 const nsAString& aFamilyName, |
|
1465 nsDataHashtable<nsUint32HashKey,uint32_t>& aMergedFeatures); |
|
1466 |
|
1467 protected: |
|
1468 // the font this shaper is working with |
|
1469 gfxFont * mFont; |
|
1470 }; |
|
1471 |
|
1472 /* a SPECIFIC single font family */ |
|
1473 class gfxFont { |
|
1474 |
|
1475 friend class gfxHarfBuzzShaper; |
|
1476 friend class gfxGraphiteShaper; |
|
1477 |
|
1478 public: |
|
1479 nsrefcnt AddRef(void) { |
|
1480 NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt"); |
|
1481 if (mExpirationState.IsTracked()) { |
|
1482 gfxFontCache::GetCache()->RemoveObject(this); |
|
1483 } |
|
1484 ++mRefCnt; |
|
1485 NS_LOG_ADDREF(this, mRefCnt, "gfxFont", sizeof(*this)); |
|
1486 return mRefCnt; |
|
1487 } |
|
1488 nsrefcnt Release(void) { |
|
1489 NS_PRECONDITION(0 != mRefCnt, "dup release"); |
|
1490 --mRefCnt; |
|
1491 NS_LOG_RELEASE(this, mRefCnt, "gfxFont"); |
|
1492 if (mRefCnt == 0) { |
|
1493 NotifyReleased(); |
|
1494 // |this| may have been deleted. |
|
1495 return 0; |
|
1496 } |
|
1497 return mRefCnt; |
|
1498 } |
|
1499 |
|
1500 int32_t GetRefCount() { return mRefCnt; } |
|
1501 |
|
1502 // options to specify the kind of AA to be used when creating a font |
|
1503 typedef enum { |
|
1504 kAntialiasDefault, |
|
1505 kAntialiasNone, |
|
1506 kAntialiasGrayscale, |
|
1507 kAntialiasSubpixel |
|
1508 } AntialiasOption; |
|
1509 |
|
1510 protected: |
|
1511 nsAutoRefCnt mRefCnt; |
|
1512 cairo_scaled_font_t *mScaledFont; |
|
1513 |
|
1514 void NotifyReleased() { |
|
1515 gfxFontCache *cache = gfxFontCache::GetCache(); |
|
1516 if (cache) { |
|
1517 // Don't delete just yet; return the object to the cache for |
|
1518 // possibly recycling within some time limit |
|
1519 cache->NotifyReleased(this); |
|
1520 } else { |
|
1521 // The cache may have already been shut down. |
|
1522 delete this; |
|
1523 } |
|
1524 } |
|
1525 |
|
1526 gfxFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle, |
|
1527 AntialiasOption anAAOption = kAntialiasDefault, |
|
1528 cairo_scaled_font_t *aScaledFont = nullptr); |
|
1529 |
|
1530 public: |
|
1531 virtual ~gfxFont(); |
|
1532 |
|
1533 bool Valid() const { |
|
1534 return mIsValid; |
|
1535 } |
|
1536 |
|
1537 // options for the kind of bounding box to return from measurement |
|
1538 typedef enum { |
|
1539 LOOSE_INK_EXTENTS, |
|
1540 // A box that encloses all the painted pixels, and may |
|
1541 // include sidebearings and/or additional ascent/descent |
|
1542 // within the glyph cell even if the ink is smaller. |
|
1543 TIGHT_INK_EXTENTS, |
|
1544 // A box that tightly encloses all the painted pixels |
|
1545 // (although actually on Windows, at least, it may be |
|
1546 // slightly larger than strictly necessary because |
|
1547 // we can't get precise extents with ClearType). |
|
1548 TIGHT_HINTED_OUTLINE_EXTENTS |
|
1549 // A box that tightly encloses the glyph outline, |
|
1550 // ignoring possible antialiasing pixels that extend |
|
1551 // beyond this. |
|
1552 // NOTE: The default implementation of gfxFont::Measure(), |
|
1553 // which works with the glyph extents cache, does not |
|
1554 // differentiate between this and TIGHT_INK_EXTENTS. |
|
1555 // Whether the distinction is important depends on the |
|
1556 // antialiasing behavior of the platform; currently the |
|
1557 // distinction is only implemented in the gfxWindowsFont |
|
1558 // subclass, because of ClearType's tendency to paint |
|
1559 // outside the hinted outline. |
|
1560 // Also NOTE: it is relatively expensive to request this, |
|
1561 // as it does not use cached glyph extents in the font. |
|
1562 } BoundingBoxType; |
|
1563 |
|
1564 const nsString& GetName() const { return mFontEntry->Name(); } |
|
1565 const gfxFontStyle *GetStyle() const { return &mStyle; } |
|
1566 |
|
1567 virtual cairo_scaled_font_t* GetCairoScaledFont() { return mScaledFont; } |
|
1568 |
|
1569 virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption) { |
|
1570 // platforms where this actually matters should override |
|
1571 return nullptr; |
|
1572 } |
|
1573 |
|
1574 virtual gfxFloat GetAdjustedSize() { |
|
1575 return mAdjustedSize > 0.0 ? mAdjustedSize : 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 bool FontCanSupportHarfBuzz() { |
|
1586 return mFontEntry->HasCmapTable(); |
|
1587 } |
|
1588 |
|
1589 // check whether this is an sfnt we can potentially use with Graphite |
|
1590 bool FontCanSupportGraphite() { |
|
1591 return mFontEntry->HasGraphiteTables(); |
|
1592 } |
|
1593 |
|
1594 // Subclasses may choose to look up glyph ids for characters. |
|
1595 // If they do not override this, gfxHarfBuzzShaper will fetch the cmap |
|
1596 // table and use that. |
|
1597 virtual bool ProvidesGetGlyph() const { |
|
1598 return false; |
|
1599 } |
|
1600 // Map unicode character to glyph ID. |
|
1601 // Only used if ProvidesGetGlyph() returns true. |
|
1602 virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector) { |
|
1603 return 0; |
|
1604 } |
|
1605 // Return the horizontal advance of a glyph. |
|
1606 gfxFloat GetGlyphHAdvance(gfxContext *aCtx, uint16_t aGID); |
|
1607 |
|
1608 // Return Azure GlyphRenderingOptions for drawing this font. |
|
1609 virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> |
|
1610 GetGlyphRenderingOptions() { return nullptr; } |
|
1611 |
|
1612 gfxFloat SynthesizeSpaceWidth(uint32_t aCh); |
|
1613 |
|
1614 // Font metrics |
|
1615 struct Metrics { |
|
1616 gfxFloat xHeight; |
|
1617 gfxFloat superscriptOffset; |
|
1618 gfxFloat subscriptOffset; |
|
1619 gfxFloat strikeoutSize; |
|
1620 gfxFloat strikeoutOffset; |
|
1621 gfxFloat underlineSize; |
|
1622 gfxFloat underlineOffset; |
|
1623 |
|
1624 gfxFloat internalLeading; |
|
1625 gfxFloat externalLeading; |
|
1626 |
|
1627 gfxFloat emHeight; |
|
1628 gfxFloat emAscent; |
|
1629 gfxFloat emDescent; |
|
1630 gfxFloat maxHeight; |
|
1631 gfxFloat maxAscent; |
|
1632 gfxFloat maxDescent; |
|
1633 gfxFloat maxAdvance; |
|
1634 |
|
1635 gfxFloat aveCharWidth; |
|
1636 gfxFloat spaceWidth; |
|
1637 gfxFloat zeroOrAveCharWidth; // width of '0', or if there is |
|
1638 // no '0' glyph in this font, |
|
1639 // equal to .aveCharWidth |
|
1640 }; |
|
1641 virtual const gfxFont::Metrics& GetMetrics() = 0; |
|
1642 |
|
1643 /** |
|
1644 * We let layout specify spacing on either side of any |
|
1645 * character. We need to specify both before and after |
|
1646 * spacing so that substring measurement can do the right things. |
|
1647 * These values are in appunits. They're always an integral number of |
|
1648 * appunits, but we specify them in floats in case very large spacing |
|
1649 * values are required. |
|
1650 */ |
|
1651 struct Spacing { |
|
1652 gfxFloat mBefore; |
|
1653 gfxFloat mAfter; |
|
1654 }; |
|
1655 /** |
|
1656 * Metrics for a particular string |
|
1657 */ |
|
1658 struct RunMetrics { |
|
1659 RunMetrics() { |
|
1660 mAdvanceWidth = mAscent = mDescent = 0.0; |
|
1661 } |
|
1662 |
|
1663 void CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft); |
|
1664 |
|
1665 // can be negative (partly due to negative spacing). |
|
1666 // Advance widths should be additive: the advance width of the |
|
1667 // (offset1, length1) plus the advance width of (offset1 + length1, |
|
1668 // length2) should be the advance width of (offset1, length1 + length2) |
|
1669 gfxFloat mAdvanceWidth; |
|
1670 |
|
1671 // For zero-width substrings, these must be zero! |
|
1672 gfxFloat mAscent; // always non-negative |
|
1673 gfxFloat mDescent; // always non-negative |
|
1674 |
|
1675 // Bounding box that is guaranteed to include everything drawn. |
|
1676 // If a tight boundingBox was requested when these metrics were |
|
1677 // generated, this will tightly wrap the glyphs, otherwise it is |
|
1678 // "loose" and may be larger than the true bounding box. |
|
1679 // Coordinates are relative to the baseline left origin, so typically |
|
1680 // mBoundingBox.y == -mAscent |
|
1681 gfxRect mBoundingBox; |
|
1682 }; |
|
1683 |
|
1684 /** |
|
1685 * Draw a series of glyphs to aContext. The direction of aTextRun must |
|
1686 * be honoured. |
|
1687 * @param aStart the first character to draw |
|
1688 * @param aEnd draw characters up to here |
|
1689 * @param aBaselineOrigin the baseline origin; the left end of the baseline |
|
1690 * for LTR textruns, the right end of the baseline for RTL textruns. On return, |
|
1691 * this should be updated to the other end of the baseline. In application |
|
1692 * units, really! |
|
1693 * @param aSpacing spacing to insert before and after characters (for RTL |
|
1694 * glyphs, before-spacing is inserted to the right of characters). There |
|
1695 * are aEnd - aStart elements in this array, unless it's null to indicate |
|
1696 * that there is no spacing. |
|
1697 * @param aDrawMode specifies whether the fill or stroke of the glyph should be |
|
1698 * drawn, or if it should be drawn into the current path |
|
1699 * @param aContextPaint information about how to construct the fill and |
|
1700 * stroke pattern. Can be nullptr if we are not stroking the text, which |
|
1701 * indicates that the current source from aContext should be used for filling |
|
1702 * |
|
1703 * Callers guarantee: |
|
1704 * -- aStart and aEnd are aligned to cluster and ligature boundaries |
|
1705 * -- all glyphs use this font |
|
1706 * |
|
1707 * The default implementation builds a cairo glyph array and |
|
1708 * calls cairo_show_glyphs or cairo_glyph_path. |
|
1709 */ |
|
1710 virtual void Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd, |
|
1711 gfxContext *aContext, DrawMode aDrawMode, gfxPoint *aBaselineOrigin, |
|
1712 Spacing *aSpacing, gfxTextContextPaint *aContextPaint, |
|
1713 gfxTextRunDrawCallbacks *aCallbacks); |
|
1714 |
|
1715 /** |
|
1716 * Measure a run of characters. See gfxTextRun::Metrics. |
|
1717 * @param aTight if false, then return the union of the glyph extents |
|
1718 * with the font-box for the characters (the rectangle with x=0,width= |
|
1719 * the advance width for the character run,y=-(font ascent), and height= |
|
1720 * font ascent + font descent). Otherwise, we must return as tight as possible |
|
1721 * an approximation to the area actually painted by glyphs. |
|
1722 * @param aContextForTightBoundingBox when aTight is true, this must |
|
1723 * be non-null. |
|
1724 * @param aSpacing spacing to insert before and after glyphs. The bounding box |
|
1725 * need not include the spacing itself, but the spacing affects the glyph |
|
1726 * positions. null if there is no spacing. |
|
1727 * |
|
1728 * Callers guarantee: |
|
1729 * -- aStart and aEnd are aligned to cluster and ligature boundaries |
|
1730 * -- all glyphs use this font |
|
1731 * |
|
1732 * The default implementation just uses font metrics and aTextRun's |
|
1733 * advances, and assumes no characters fall outside the font box. In |
|
1734 * general this is insufficient, because that assumption is not always true. |
|
1735 */ |
|
1736 virtual RunMetrics Measure(gfxTextRun *aTextRun, |
|
1737 uint32_t aStart, uint32_t aEnd, |
|
1738 BoundingBoxType aBoundingBoxType, |
|
1739 gfxContext *aContextForTightBoundingBox, |
|
1740 Spacing *aSpacing); |
|
1741 /** |
|
1742 * Line breaks have been changed at the beginning and/or end of a substring |
|
1743 * of the text. Reshaping may be required; glyph updating is permitted. |
|
1744 * @return true if anything was changed, false otherwise |
|
1745 */ |
|
1746 bool NotifyLineBreaksChanged(gfxTextRun *aTextRun, |
|
1747 uint32_t aStart, uint32_t aLength) |
|
1748 { return false; } |
|
1749 |
|
1750 // Expiration tracking |
|
1751 nsExpirationState *GetExpirationState() { return &mExpirationState; } |
|
1752 |
|
1753 // Get the glyphID of a space |
|
1754 virtual uint32_t GetSpaceGlyph() = 0; |
|
1755 |
|
1756 gfxGlyphExtents *GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit); |
|
1757 |
|
1758 // You need to call SetupCairoFont on the aCR just before calling this |
|
1759 virtual void SetupGlyphExtents(gfxContext *aContext, uint32_t aGlyphID, |
|
1760 bool aNeedTight, gfxGlyphExtents *aExtents); |
|
1761 |
|
1762 // This is called by the default Draw() implementation above. |
|
1763 virtual bool SetupCairoFont(gfxContext *aContext) = 0; |
|
1764 |
|
1765 virtual bool AllowSubpixelAA() { return true; } |
|
1766 |
|
1767 bool IsSyntheticBold() { return mApplySyntheticBold; } |
|
1768 |
|
1769 // Amount by which synthetic bold "fattens" the glyphs: |
|
1770 // For size S up to a threshold size T, we use (0.25 + 3S / 4T), |
|
1771 // so that the result ranges from 0.25 to 1.0; thereafter, |
|
1772 // simply use (S / T). |
|
1773 gfxFloat GetSyntheticBoldOffset() { |
|
1774 gfxFloat size = GetAdjustedSize(); |
|
1775 const gfxFloat threshold = 48.0; |
|
1776 return size < threshold ? (0.25 + 0.75 * size / threshold) : |
|
1777 (size / threshold); |
|
1778 } |
|
1779 |
|
1780 gfxFontEntry *GetFontEntry() { return mFontEntry.get(); } |
|
1781 bool HasCharacter(uint32_t ch) { |
|
1782 if (!mIsValid) |
|
1783 return false; |
|
1784 return mFontEntry->HasCharacter(ch); |
|
1785 } |
|
1786 |
|
1787 uint16_t GetUVSGlyph(uint32_t aCh, uint32_t aVS) { |
|
1788 if (!mIsValid) { |
|
1789 return 0; |
|
1790 } |
|
1791 return mFontEntry->GetUVSGlyph(aCh, aVS); |
|
1792 } |
|
1793 |
|
1794 // call the (virtual) InitTextRun method to do glyph generation/shaping, |
|
1795 // limiting the length of text passed by processing the run in multiple |
|
1796 // segments if necessary |
|
1797 template<typename T> |
|
1798 bool SplitAndInitTextRun(gfxContext *aContext, |
|
1799 gfxTextRun *aTextRun, |
|
1800 const T *aString, |
|
1801 uint32_t aRunStart, |
|
1802 uint32_t aRunLength, |
|
1803 int32_t aRunScript); |
|
1804 |
|
1805 // Get a ShapedWord representing the given text (either 8- or 16-bit) |
|
1806 // for use in setting up a gfxTextRun. |
|
1807 template<typename T> |
|
1808 gfxShapedWord* GetShapedWord(gfxContext *aContext, |
|
1809 const T *aText, |
|
1810 uint32_t aLength, |
|
1811 uint32_t aHash, |
|
1812 int32_t aRunScript, |
|
1813 int32_t aAppUnitsPerDevUnit, |
|
1814 uint32_t aFlags, |
|
1815 gfxTextPerfMetrics *aTextPerf); |
|
1816 |
|
1817 // Ensure the ShapedWord cache is initialized. This MUST be called before |
|
1818 // any attempt to use GetShapedWord(). |
|
1819 void InitWordCache() { |
|
1820 if (!mWordCache) { |
|
1821 mWordCache = new nsTHashtable<CacheHashEntry>; |
|
1822 } |
|
1823 } |
|
1824 |
|
1825 // Called by the gfxFontCache timer to increment the age of all the words, |
|
1826 // so that they'll expire after a sufficient period of non-use |
|
1827 void AgeCachedWords() { |
|
1828 if (mWordCache) { |
|
1829 (void)mWordCache->EnumerateEntries(AgeCacheEntry, this); |
|
1830 } |
|
1831 } |
|
1832 |
|
1833 // Discard all cached word records; called on memory-pressure notification. |
|
1834 void ClearCachedWords() { |
|
1835 if (mWordCache) { |
|
1836 mWordCache->Clear(); |
|
1837 } |
|
1838 } |
|
1839 |
|
1840 // Glyph rendering/geometry has changed, so invalidate data as necessary. |
|
1841 void NotifyGlyphsChanged(); |
|
1842 |
|
1843 virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, |
|
1844 FontCacheSizes* aSizes) const; |
|
1845 virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, |
|
1846 FontCacheSizes* aSizes) const; |
|
1847 |
|
1848 typedef enum { |
|
1849 FONT_TYPE_DWRITE, |
|
1850 FONT_TYPE_GDI, |
|
1851 FONT_TYPE_FT2, |
|
1852 FONT_TYPE_MAC, |
|
1853 FONT_TYPE_OS2, |
|
1854 FONT_TYPE_CAIRO |
|
1855 } FontType; |
|
1856 |
|
1857 virtual FontType GetType() const = 0; |
|
1858 |
|
1859 virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget) |
|
1860 { return gfxPlatform::GetPlatform()->GetScaledFontForFont(aTarget, this); } |
|
1861 |
|
1862 bool KerningDisabled() { |
|
1863 return mKerningSet && !mKerningEnabled; |
|
1864 } |
|
1865 |
|
1866 /** |
|
1867 * Subclass this object to be notified of glyph changes. Delete the object |
|
1868 * when no longer needed. |
|
1869 */ |
|
1870 class GlyphChangeObserver { |
|
1871 public: |
|
1872 virtual ~GlyphChangeObserver() |
|
1873 { |
|
1874 if (mFont) { |
|
1875 mFont->RemoveGlyphChangeObserver(this); |
|
1876 } |
|
1877 } |
|
1878 // This gets called when the gfxFont dies. |
|
1879 void ForgetFont() { mFont = nullptr; } |
|
1880 virtual void NotifyGlyphsChanged() = 0; |
|
1881 protected: |
|
1882 GlyphChangeObserver(gfxFont *aFont) : mFont(aFont) |
|
1883 { |
|
1884 mFont->AddGlyphChangeObserver(this); |
|
1885 } |
|
1886 gfxFont* mFont; |
|
1887 }; |
|
1888 friend class GlyphChangeObserver; |
|
1889 |
|
1890 bool GlyphsMayChange() |
|
1891 { |
|
1892 // Currently only fonts with SVG glyphs can have animated glyphs |
|
1893 return mFontEntry->TryGetSVGData(this); |
|
1894 } |
|
1895 |
|
1896 static void DestroySingletons() { |
|
1897 delete sScriptTagToCode; |
|
1898 delete sDefaultFeatures; |
|
1899 } |
|
1900 |
|
1901 protected: |
|
1902 // subclasses may provide (possibly hinted) glyph widths (in font units); |
|
1903 // if they do not override this, harfbuzz will use unhinted widths |
|
1904 // derived from the font tables |
|
1905 virtual bool ProvidesGlyphWidths() { |
|
1906 return false; |
|
1907 } |
|
1908 |
|
1909 // The return value is interpreted as a horizontal advance in 16.16 fixed |
|
1910 // point format. |
|
1911 virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID) { |
|
1912 return -1; |
|
1913 } |
|
1914 |
|
1915 void AddGlyphChangeObserver(GlyphChangeObserver *aObserver); |
|
1916 void RemoveGlyphChangeObserver(GlyphChangeObserver *aObserver); |
|
1917 |
|
1918 // whether font contains substitution lookups containing spaces |
|
1919 bool HasSubstitutionRulesWithSpaceLookups(int32_t aRunScript); |
|
1920 |
|
1921 // do spaces participate in shaping rules? if so, can't used word cache |
|
1922 bool SpaceMayParticipateInShaping(int32_t aRunScript); |
|
1923 |
|
1924 // For 8-bit text, expand to 16-bit and then call the following method. |
|
1925 bool ShapeText(gfxContext *aContext, |
|
1926 const uint8_t *aText, |
|
1927 uint32_t aOffset, // dest offset in gfxShapedText |
|
1928 uint32_t aLength, |
|
1929 int32_t aScript, |
|
1930 gfxShapedText *aShapedText, // where to store the result |
|
1931 bool aPreferPlatformShaping = false); |
|
1932 |
|
1933 // Call the appropriate shaper to generate glyphs for aText and store |
|
1934 // them into aShapedText. |
|
1935 virtual bool ShapeText(gfxContext *aContext, |
|
1936 const char16_t *aText, |
|
1937 uint32_t aOffset, |
|
1938 uint32_t aLength, |
|
1939 int32_t aScript, |
|
1940 gfxShapedText *aShapedText, |
|
1941 bool aPreferPlatformShaping = false); |
|
1942 |
|
1943 // Helper to adjust for synthetic bold and set character-type flags |
|
1944 // in the shaped text; implementations of ShapeText should call this |
|
1945 // after glyph shaping has been completed. |
|
1946 void PostShapingFixup(gfxContext *aContext, |
|
1947 const char16_t *aText, |
|
1948 uint32_t aOffset, // position within aShapedText |
|
1949 uint32_t aLength, |
|
1950 gfxShapedText *aShapedText); |
|
1951 |
|
1952 // Shape text directly into a range within a textrun, without using the |
|
1953 // font's word cache. Intended for use when the font has layout features |
|
1954 // that involve space, and therefore require shaping complete runs rather |
|
1955 // than isolated words, or for long strings that are inefficient to cache. |
|
1956 // This will split the text on "invalid" characters (tab/newline) that are |
|
1957 // not handled via normal shaping, but does not otherwise divide up the |
|
1958 // text. |
|
1959 template<typename T> |
|
1960 bool ShapeTextWithoutWordCache(gfxContext *aContext, |
|
1961 const T *aText, |
|
1962 uint32_t aOffset, |
|
1963 uint32_t aLength, |
|
1964 int32_t aScript, |
|
1965 gfxTextRun *aTextRun); |
|
1966 |
|
1967 // Shape a fragment of text (a run that is known to contain only |
|
1968 // "valid" characters, no newlines/tabs/other control chars). |
|
1969 // All non-wordcache shaping goes through here; this is the function |
|
1970 // that will ensure we don't pass excessively long runs to the various |
|
1971 // platform shapers. |
|
1972 template<typename T> |
|
1973 bool ShapeFragmentWithoutWordCache(gfxContext *aContext, |
|
1974 const T *aText, |
|
1975 uint32_t aOffset, |
|
1976 uint32_t aLength, |
|
1977 int32_t aScript, |
|
1978 gfxTextRun *aTextRun); |
|
1979 |
|
1980 void CheckForFeaturesInvolvingSpace(); |
|
1981 |
|
1982 // whether a given feature is included in feature settings from both the |
|
1983 // font and the style. aFeatureOn set if resolved feature value is non-zero |
|
1984 bool HasFeatureSet(uint32_t aFeature, bool& aFeatureOn); |
|
1985 |
|
1986 // used when analyzing whether a font has space contextual lookups |
|
1987 static nsDataHashtable<nsUint32HashKey, int32_t> *sScriptTagToCode; |
|
1988 static nsTHashtable<nsUint32HashKey> *sDefaultFeatures; |
|
1989 |
|
1990 nsRefPtr<gfxFontEntry> mFontEntry; |
|
1991 |
|
1992 struct CacheHashKey { |
|
1993 union { |
|
1994 const uint8_t *mSingle; |
|
1995 const char16_t *mDouble; |
|
1996 } mText; |
|
1997 uint32_t mLength; |
|
1998 uint32_t mFlags; |
|
1999 int32_t mScript; |
|
2000 int32_t mAppUnitsPerDevUnit; |
|
2001 PLDHashNumber mHashKey; |
|
2002 bool mTextIs8Bit; |
|
2003 |
|
2004 CacheHashKey(const uint8_t *aText, uint32_t aLength, |
|
2005 uint32_t aStringHash, |
|
2006 int32_t aScriptCode, int32_t aAppUnitsPerDevUnit, |
|
2007 uint32_t aFlags) |
|
2008 : mLength(aLength), |
|
2009 mFlags(aFlags), |
|
2010 mScript(aScriptCode), |
|
2011 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit), |
|
2012 mHashKey(aStringHash + aScriptCode + |
|
2013 aAppUnitsPerDevUnit * 0x100 + aFlags * 0x10000), |
|
2014 mTextIs8Bit(true) |
|
2015 { |
|
2016 NS_ASSERTION(aFlags & gfxTextRunFactory::TEXT_IS_8BIT, |
|
2017 "8-bit flag should have been set"); |
|
2018 mText.mSingle = aText; |
|
2019 } |
|
2020 |
|
2021 CacheHashKey(const char16_t *aText, uint32_t aLength, |
|
2022 uint32_t aStringHash, |
|
2023 int32_t aScriptCode, int32_t aAppUnitsPerDevUnit, |
|
2024 uint32_t aFlags) |
|
2025 : mLength(aLength), |
|
2026 mFlags(aFlags), |
|
2027 mScript(aScriptCode), |
|
2028 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit), |
|
2029 mHashKey(aStringHash + aScriptCode + |
|
2030 aAppUnitsPerDevUnit * 0x100 + aFlags * 0x10000), |
|
2031 mTextIs8Bit(false) |
|
2032 { |
|
2033 // We can NOT assert that TEXT_IS_8BIT is false in aFlags here, |
|
2034 // because this might be an 8bit-only word from a 16-bit textrun, |
|
2035 // in which case the text we're passed is still in 16-bit form, |
|
2036 // and we'll have to use an 8-to-16bit comparison in KeyEquals. |
|
2037 mText.mDouble = aText; |
|
2038 } |
|
2039 }; |
|
2040 |
|
2041 class CacheHashEntry : public PLDHashEntryHdr { |
|
2042 public: |
|
2043 typedef const CacheHashKey &KeyType; |
|
2044 typedef const CacheHashKey *KeyTypePointer; |
|
2045 |
|
2046 // When constructing a new entry in the hashtable, the caller of Put() |
|
2047 // will fill us in. |
|
2048 CacheHashEntry(KeyTypePointer aKey) { } |
|
2049 CacheHashEntry(const CacheHashEntry& toCopy) { NS_ERROR("Should not be called"); } |
|
2050 ~CacheHashEntry() { } |
|
2051 |
|
2052 bool KeyEquals(const KeyTypePointer aKey) const; |
|
2053 |
|
2054 static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } |
|
2055 |
|
2056 static PLDHashNumber HashKey(const KeyTypePointer aKey) { |
|
2057 return aKey->mHashKey; |
|
2058 } |
|
2059 |
|
2060 enum { ALLOW_MEMMOVE = true }; |
|
2061 |
|
2062 nsAutoPtr<gfxShapedWord> mShapedWord; |
|
2063 }; |
|
2064 |
|
2065 static size_t |
|
2066 WordCacheEntrySizeOfExcludingThis(CacheHashEntry* aHashEntry, |
|
2067 mozilla::MallocSizeOf aMallocSizeOf, |
|
2068 void* aUserArg); |
|
2069 |
|
2070 nsAutoPtr<nsTHashtable<CacheHashEntry> > mWordCache; |
|
2071 |
|
2072 static PLDHashOperator AgeCacheEntry(CacheHashEntry *aEntry, void *aUserData); |
|
2073 static const uint32_t kShapedWordCacheMaxAge = 3; |
|
2074 |
|
2075 bool mIsValid; |
|
2076 |
|
2077 // use synthetic bolding for environments where this is not supported |
|
2078 // by the platform |
|
2079 bool mApplySyntheticBold; |
|
2080 |
|
2081 bool mKerningSet; // kerning explicitly set? |
|
2082 bool mKerningEnabled; // if set, on or off? |
|
2083 |
|
2084 nsExpirationState mExpirationState; |
|
2085 gfxFontStyle mStyle; |
|
2086 nsAutoTArray<gfxGlyphExtents*,1> mGlyphExtentsArray; |
|
2087 nsAutoPtr<nsTHashtable<nsPtrHashKey<GlyphChangeObserver> > > mGlyphChangeObservers; |
|
2088 |
|
2089 gfxFloat mAdjustedSize; |
|
2090 |
|
2091 float mFUnitsConvFactor; // conversion factor from font units to dev units |
|
2092 |
|
2093 // the AA setting requested for this font - may affect glyph bounds |
|
2094 AntialiasOption mAntialiasOption; |
|
2095 |
|
2096 // a copy of the font without antialiasing, if needed for separate |
|
2097 // measurement by mathml code |
|
2098 nsAutoPtr<gfxFont> mNonAAFont; |
|
2099 |
|
2100 // we may switch between these shapers on the fly, based on the script |
|
2101 // of the text run being shaped |
|
2102 nsAutoPtr<gfxFontShaper> mPlatformShaper; |
|
2103 nsAutoPtr<gfxFontShaper> mHarfBuzzShaper; |
|
2104 nsAutoPtr<gfxFontShaper> mGraphiteShaper; |
|
2105 |
|
2106 mozilla::RefPtr<mozilla::gfx::ScaledFont> mAzureScaledFont; |
|
2107 |
|
2108 // Create a default platform text shaper for this font. |
|
2109 // (TODO: This should become pure virtual once all font backends have |
|
2110 // been updated.) |
|
2111 virtual void CreatePlatformShaper() { } |
|
2112 |
|
2113 // Helper for subclasses that want to initialize standard metrics from the |
|
2114 // tables of sfnt (TrueType/OpenType) fonts. |
|
2115 // This will use mFUnitsConvFactor if it is already set, else compute it |
|
2116 // from mAdjustedSize and the unitsPerEm in the font's 'head' table. |
|
2117 // Returns TRUE and sets mIsValid=TRUE if successful; |
|
2118 // Returns TRUE but leaves mIsValid=FALSE if the font seems to be broken. |
|
2119 // Returns FALSE if the font does not appear to be an sfnt at all, |
|
2120 // and should be handled (if possible) using other APIs. |
|
2121 bool InitMetricsFromSfntTables(Metrics& aMetrics); |
|
2122 |
|
2123 // Helper to calculate various derived metrics from the results of |
|
2124 // InitMetricsFromSfntTables or equivalent platform code |
|
2125 void CalculateDerivedMetrics(Metrics& aMetrics); |
|
2126 |
|
2127 // some fonts have bad metrics, this method sanitize them. |
|
2128 // if this font has bad underline offset, aIsBadUnderlineFont should be true. |
|
2129 void SanitizeMetrics(gfxFont::Metrics *aMetrics, bool aIsBadUnderlineFont); |
|
2130 |
|
2131 bool RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode, |
|
2132 uint32_t aGlyphId, gfxTextContextPaint *aContextPaint); |
|
2133 bool RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode, |
|
2134 uint32_t aGlyphId, gfxTextContextPaint *aContextPaint, |
|
2135 gfxTextRunDrawCallbacks *aCallbacks, |
|
2136 bool& aEmittedGlyphs); |
|
2137 |
|
2138 // Bug 674909. When synthetic bolding text by drawing twice, need to |
|
2139 // render using a pixel offset in device pixels, otherwise text |
|
2140 // doesn't appear bolded, it appears as if a bad text shadow exists |
|
2141 // when a non-identity transform exists. Use an offset factor so that |
|
2142 // the second draw occurs at a constant offset in device pixels. |
|
2143 // This helper calculates the scale factor we need to apply to the |
|
2144 // synthetic-bold offset. |
|
2145 static double CalcXScale(gfxContext *aContext); |
|
2146 }; |
|
2147 |
|
2148 // proportion of ascent used for x-height, if unable to read value from font |
|
2149 #define DEFAULT_XHEIGHT_FACTOR 0.56f |
|
2150 |
|
2151 /* |
|
2152 * gfxShapedText is an abstract superclass for gfxShapedWord and gfxTextRun. |
|
2153 * These are objects that store a list of zero or more glyphs for each character. |
|
2154 * For each glyph we store the glyph ID, the advance, and possibly x/y-offsets. |
|
2155 * The idea is that a string is rendered by a loop that draws each glyph |
|
2156 * at its designated offset from the current point, then advances the current |
|
2157 * point by the glyph's advance in the direction of the textrun (LTR or RTL). |
|
2158 * Each glyph advance is always rounded to the nearest appunit; this ensures |
|
2159 * consistent results when dividing the text in a textrun into multiple text |
|
2160 * frames (frame boundaries are always aligned to appunits). We optimize |
|
2161 * for the case where a character has a single glyph and zero xoffset and yoffset, |
|
2162 * and the glyph ID and advance are in a reasonable range so we can pack all |
|
2163 * necessary data into 32 bits. |
|
2164 * |
|
2165 * gfxFontShaper can shape text into either a gfxShapedWord (cached by a gfxFont) |
|
2166 * or directly into a gfxTextRun (for cases where we want to shape textruns in |
|
2167 * their entirety rather than using cached words, because there may be layout |
|
2168 * features that depend on the inter-word spaces). |
|
2169 */ |
|
2170 class gfxShapedText |
|
2171 { |
|
2172 public: |
|
2173 gfxShapedText(uint32_t aLength, uint32_t aFlags, |
|
2174 int32_t aAppUnitsPerDevUnit) |
|
2175 : mLength(aLength) |
|
2176 , mFlags(aFlags) |
|
2177 , mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) |
|
2178 { } |
|
2179 |
|
2180 virtual ~gfxShapedText() { } |
|
2181 |
|
2182 /** |
|
2183 * This class records the information associated with a character in the |
|
2184 * input string. It's optimized for the case where there is one glyph |
|
2185 * representing that character alone. |
|
2186 * |
|
2187 * A character can have zero or more associated glyphs. Each glyph |
|
2188 * has an advance width and an x and y offset. |
|
2189 * A character may be the start of a cluster. |
|
2190 * A character may be the start of a ligature group. |
|
2191 * A character can be "missing", indicating that the system is unable |
|
2192 * to render the character. |
|
2193 * |
|
2194 * All characters in a ligature group conceptually share all the glyphs |
|
2195 * associated with the characters in a group. |
|
2196 */ |
|
2197 class CompressedGlyph { |
|
2198 public: |
|
2199 CompressedGlyph() { mValue = 0; } |
|
2200 |
|
2201 enum { |
|
2202 // Indicates that a cluster and ligature group starts at this |
|
2203 // character; this character has a single glyph with a reasonable |
|
2204 // advance and zero offsets. A "reasonable" advance |
|
2205 // is one that fits in the available bits (currently 12) (specified |
|
2206 // in appunits). |
|
2207 FLAG_IS_SIMPLE_GLYPH = 0x80000000U, |
|
2208 |
|
2209 // Indicates whether a linebreak is allowed before this character; |
|
2210 // this is a two-bit field that holds a FLAG_BREAK_TYPE_xxx value |
|
2211 // indicating the kind of linebreak (if any) allowed here. |
|
2212 FLAGS_CAN_BREAK_BEFORE = 0x60000000U, |
|
2213 |
|
2214 FLAGS_CAN_BREAK_SHIFT = 29, |
|
2215 FLAG_BREAK_TYPE_NONE = 0, |
|
2216 FLAG_BREAK_TYPE_NORMAL = 1, |
|
2217 FLAG_BREAK_TYPE_HYPHEN = 2, |
|
2218 |
|
2219 FLAG_CHAR_IS_SPACE = 0x10000000U, |
|
2220 |
|
2221 // The advance is stored in appunits |
|
2222 ADVANCE_MASK = 0x0FFF0000U, |
|
2223 ADVANCE_SHIFT = 16, |
|
2224 |
|
2225 GLYPH_MASK = 0x0000FFFFU, |
|
2226 |
|
2227 // Non-simple glyphs may or may not have glyph data in the |
|
2228 // corresponding mDetailedGlyphs entry. They have the following |
|
2229 // flag bits: |
|
2230 |
|
2231 // When NOT set, indicates that this character corresponds to a |
|
2232 // missing glyph and should be skipped (or possibly, render the character |
|
2233 // Unicode value in some special way). If there are glyphs, |
|
2234 // the mGlyphID is actually the UTF16 character code. The bit is |
|
2235 // inverted so we can memset the array to zero to indicate all missing. |
|
2236 FLAG_NOT_MISSING = 0x01, |
|
2237 FLAG_NOT_CLUSTER_START = 0x02, |
|
2238 FLAG_NOT_LIGATURE_GROUP_START = 0x04, |
|
2239 |
|
2240 FLAG_CHAR_IS_TAB = 0x08, |
|
2241 FLAG_CHAR_IS_NEWLINE = 0x10, |
|
2242 FLAG_CHAR_IS_LOW_SURROGATE = 0x20, |
|
2243 CHAR_IDENTITY_FLAGS_MASK = 0x38, |
|
2244 |
|
2245 GLYPH_COUNT_MASK = 0x00FFFF00U, |
|
2246 GLYPH_COUNT_SHIFT = 8 |
|
2247 }; |
|
2248 |
|
2249 // "Simple glyphs" have a simple glyph ID, simple advance and their |
|
2250 // x and y offsets are zero. Also the glyph extents do not overflow |
|
2251 // the font-box defined by the font ascent, descent and glyph advance width. |
|
2252 // These case is optimized to avoid storing DetailedGlyphs. |
|
2253 |
|
2254 // Returns true if the glyph ID aGlyph fits into the compressed representation |
|
2255 static bool IsSimpleGlyphID(uint32_t aGlyph) { |
|
2256 return (aGlyph & GLYPH_MASK) == aGlyph; |
|
2257 } |
|
2258 // Returns true if the advance aAdvance fits into the compressed representation. |
|
2259 // aAdvance is in appunits. |
|
2260 static bool IsSimpleAdvance(uint32_t aAdvance) { |
|
2261 return (aAdvance & (ADVANCE_MASK >> ADVANCE_SHIFT)) == aAdvance; |
|
2262 } |
|
2263 |
|
2264 bool IsSimpleGlyph() const { return (mValue & FLAG_IS_SIMPLE_GLYPH) != 0; } |
|
2265 uint32_t GetSimpleAdvance() const { return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT; } |
|
2266 uint32_t GetSimpleGlyph() const { return mValue & GLYPH_MASK; } |
|
2267 |
|
2268 bool IsMissing() const { return (mValue & (FLAG_NOT_MISSING|FLAG_IS_SIMPLE_GLYPH)) == 0; } |
|
2269 bool IsClusterStart() const { |
|
2270 return (mValue & FLAG_IS_SIMPLE_GLYPH) || !(mValue & FLAG_NOT_CLUSTER_START); |
|
2271 } |
|
2272 bool IsLigatureGroupStart() const { |
|
2273 return (mValue & FLAG_IS_SIMPLE_GLYPH) || !(mValue & FLAG_NOT_LIGATURE_GROUP_START); |
|
2274 } |
|
2275 bool IsLigatureContinuation() const { |
|
2276 return (mValue & FLAG_IS_SIMPLE_GLYPH) == 0 && |
|
2277 (mValue & (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING)) == |
|
2278 (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING); |
|
2279 } |
|
2280 |
|
2281 // Return true if the original character was a normal (breakable, |
|
2282 // trimmable) space (U+0020). Not true for other characters that |
|
2283 // may happen to map to the space glyph (U+00A0). |
|
2284 bool CharIsSpace() const { |
|
2285 return (mValue & FLAG_CHAR_IS_SPACE) != 0; |
|
2286 } |
|
2287 |
|
2288 bool CharIsTab() const { |
|
2289 return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_TAB) != 0; |
|
2290 } |
|
2291 bool CharIsNewline() const { |
|
2292 return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_NEWLINE) != 0; |
|
2293 } |
|
2294 bool CharIsLowSurrogate() const { |
|
2295 return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_LOW_SURROGATE) != 0; |
|
2296 } |
|
2297 |
|
2298 uint32_t CharIdentityFlags() const { |
|
2299 return IsSimpleGlyph() ? 0 : (mValue & CHAR_IDENTITY_FLAGS_MASK); |
|
2300 } |
|
2301 |
|
2302 void SetClusterStart(bool aIsClusterStart) { |
|
2303 NS_ASSERTION(!IsSimpleGlyph(), |
|
2304 "can't call SetClusterStart on simple glyphs"); |
|
2305 if (aIsClusterStart) { |
|
2306 mValue &= ~FLAG_NOT_CLUSTER_START; |
|
2307 } else { |
|
2308 mValue |= FLAG_NOT_CLUSTER_START; |
|
2309 } |
|
2310 } |
|
2311 |
|
2312 uint8_t CanBreakBefore() const { |
|
2313 return (mValue & FLAGS_CAN_BREAK_BEFORE) >> FLAGS_CAN_BREAK_SHIFT; |
|
2314 } |
|
2315 // Returns FLAGS_CAN_BREAK_BEFORE if the setting changed, 0 otherwise |
|
2316 uint32_t SetCanBreakBefore(uint8_t aCanBreakBefore) { |
|
2317 NS_ASSERTION(aCanBreakBefore <= 2, |
|
2318 "Bogus break-before value!"); |
|
2319 uint32_t breakMask = (uint32_t(aCanBreakBefore) << FLAGS_CAN_BREAK_SHIFT); |
|
2320 uint32_t toggle = breakMask ^ (mValue & FLAGS_CAN_BREAK_BEFORE); |
|
2321 mValue ^= toggle; |
|
2322 return toggle; |
|
2323 } |
|
2324 |
|
2325 CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits, uint32_t aGlyph) { |
|
2326 NS_ASSERTION(IsSimpleAdvance(aAdvanceAppUnits), "Advance overflow"); |
|
2327 NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow"); |
|
2328 NS_ASSERTION(!CharIdentityFlags(), "Char identity flags lost"); |
|
2329 mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) | |
|
2330 FLAG_IS_SIMPLE_GLYPH | |
|
2331 (aAdvanceAppUnits << ADVANCE_SHIFT) | aGlyph; |
|
2332 return *this; |
|
2333 } |
|
2334 CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart, |
|
2335 uint32_t aGlyphCount) { |
|
2336 mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) | |
|
2337 FLAG_NOT_MISSING | |
|
2338 CharIdentityFlags() | |
|
2339 (aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) | |
|
2340 (aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) | |
|
2341 (aGlyphCount << GLYPH_COUNT_SHIFT); |
|
2342 return *this; |
|
2343 } |
|
2344 /** |
|
2345 * Missing glyphs are treated as ligature group starts; don't mess with |
|
2346 * the cluster-start flag (see bugs 618870 and 619286). |
|
2347 */ |
|
2348 CompressedGlyph& SetMissing(uint32_t aGlyphCount) { |
|
2349 mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_NOT_CLUSTER_START | |
|
2350 FLAG_CHAR_IS_SPACE)) | |
|
2351 CharIdentityFlags() | |
|
2352 (aGlyphCount << GLYPH_COUNT_SHIFT); |
|
2353 return *this; |
|
2354 } |
|
2355 uint32_t GetGlyphCount() const { |
|
2356 NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph"); |
|
2357 return (mValue & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT; |
|
2358 } |
|
2359 |
|
2360 void SetIsSpace() { |
|
2361 mValue |= FLAG_CHAR_IS_SPACE; |
|
2362 } |
|
2363 void SetIsTab() { |
|
2364 NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph"); |
|
2365 mValue |= FLAG_CHAR_IS_TAB; |
|
2366 } |
|
2367 void SetIsNewline() { |
|
2368 NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph"); |
|
2369 mValue |= FLAG_CHAR_IS_NEWLINE; |
|
2370 } |
|
2371 void SetIsLowSurrogate() { |
|
2372 NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph"); |
|
2373 mValue |= FLAG_CHAR_IS_LOW_SURROGATE; |
|
2374 } |
|
2375 |
|
2376 private: |
|
2377 uint32_t mValue; |
|
2378 }; |
|
2379 |
|
2380 // Accessor for the array of CompressedGlyph records, which will be in |
|
2381 // a different place in gfxShapedWord vs gfxTextRun |
|
2382 virtual CompressedGlyph *GetCharacterGlyphs() = 0; |
|
2383 |
|
2384 /** |
|
2385 * When the glyphs for a character don't fit into a CompressedGlyph record |
|
2386 * in SimpleGlyph format, we use an array of DetailedGlyphs instead. |
|
2387 */ |
|
2388 struct DetailedGlyph { |
|
2389 /** The glyphID, or the Unicode character |
|
2390 * if this is a missing glyph */ |
|
2391 uint32_t mGlyphID; |
|
2392 /** The advance, x-offset and y-offset of the glyph, in appunits |
|
2393 * mAdvance is in the text direction (RTL or LTR) |
|
2394 * mXOffset is always from left to right |
|
2395 * mYOffset is always from top to bottom */ |
|
2396 int32_t mAdvance; |
|
2397 float mXOffset, mYOffset; |
|
2398 }; |
|
2399 |
|
2400 void SetGlyphs(uint32_t aCharIndex, CompressedGlyph aGlyph, |
|
2401 const DetailedGlyph *aGlyphs); |
|
2402 |
|
2403 void SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont *aFont); |
|
2404 |
|
2405 void SetIsSpace(uint32_t aIndex) { |
|
2406 GetCharacterGlyphs()[aIndex].SetIsSpace(); |
|
2407 } |
|
2408 |
|
2409 void SetIsLowSurrogate(uint32_t aIndex) { |
|
2410 SetGlyphs(aIndex, CompressedGlyph().SetComplex(false, false, 0), nullptr); |
|
2411 GetCharacterGlyphs()[aIndex].SetIsLowSurrogate(); |
|
2412 } |
|
2413 |
|
2414 bool HasDetailedGlyphs() const { |
|
2415 return mDetailedGlyphs != nullptr; |
|
2416 } |
|
2417 |
|
2418 bool IsClusterStart(uint32_t aPos) { |
|
2419 NS_ASSERTION(aPos < GetLength(), "aPos out of range"); |
|
2420 return GetCharacterGlyphs()[aPos].IsClusterStart(); |
|
2421 } |
|
2422 |
|
2423 bool IsLigatureGroupStart(uint32_t aPos) { |
|
2424 NS_ASSERTION(aPos < GetLength(), "aPos out of range"); |
|
2425 return GetCharacterGlyphs()[aPos].IsLigatureGroupStart(); |
|
2426 } |
|
2427 |
|
2428 // NOTE that this must not be called for a character offset that does |
|
2429 // not have any DetailedGlyph records; callers must have verified that |
|
2430 // GetCharacterGlyphs()[aCharIndex].GetGlyphCount() is greater than zero. |
|
2431 DetailedGlyph *GetDetailedGlyphs(uint32_t aCharIndex) { |
|
2432 NS_ASSERTION(GetCharacterGlyphs() && HasDetailedGlyphs() && |
|
2433 !GetCharacterGlyphs()[aCharIndex].IsSimpleGlyph() && |
|
2434 GetCharacterGlyphs()[aCharIndex].GetGlyphCount() > 0, |
|
2435 "invalid use of GetDetailedGlyphs; check the caller!"); |
|
2436 return mDetailedGlyphs->Get(aCharIndex); |
|
2437 } |
|
2438 |
|
2439 void AdjustAdvancesForSyntheticBold(float aSynBoldOffset, |
|
2440 uint32_t aOffset, uint32_t aLength); |
|
2441 |
|
2442 // Mark clusters in the CompressedGlyph records, starting at aOffset, |
|
2443 // based on the Unicode properties of the text in aString. |
|
2444 // This is also responsible to set the IsSpace flag for space characters. |
|
2445 void SetupClusterBoundaries(uint32_t aOffset, |
|
2446 const char16_t *aString, |
|
2447 uint32_t aLength); |
|
2448 // In 8-bit text, there won't actually be any clusters, but we still need |
|
2449 // the space-marking functionality. |
|
2450 void SetupClusterBoundaries(uint32_t aOffset, |
|
2451 const uint8_t *aString, |
|
2452 uint32_t aLength); |
|
2453 |
|
2454 uint32_t Flags() const { |
|
2455 return mFlags; |
|
2456 } |
|
2457 |
|
2458 bool IsRightToLeft() const { |
|
2459 return (Flags() & gfxTextRunFactory::TEXT_IS_RTL) != 0; |
|
2460 } |
|
2461 |
|
2462 float GetDirection() const { |
|
2463 return IsRightToLeft() ? -1.0f : 1.0f; |
|
2464 } |
|
2465 |
|
2466 bool DisableLigatures() const { |
|
2467 return (Flags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) != 0; |
|
2468 } |
|
2469 |
|
2470 bool TextIs8Bit() const { |
|
2471 return (Flags() & gfxTextRunFactory::TEXT_IS_8BIT) != 0; |
|
2472 } |
|
2473 |
|
2474 int32_t GetAppUnitsPerDevUnit() const { |
|
2475 return mAppUnitsPerDevUnit; |
|
2476 } |
|
2477 |
|
2478 uint32_t GetLength() const { |
|
2479 return mLength; |
|
2480 } |
|
2481 |
|
2482 bool FilterIfIgnorable(uint32_t aIndex, uint32_t aCh); |
|
2483 |
|
2484 protected: |
|
2485 // Allocate aCount DetailedGlyphs for the given index |
|
2486 DetailedGlyph *AllocateDetailedGlyphs(uint32_t aCharIndex, |
|
2487 uint32_t aCount); |
|
2488 |
|
2489 // For characters whose glyph data does not fit the "simple" glyph criteria |
|
2490 // in CompressedGlyph, we use a sorted array to store the association |
|
2491 // between the source character offset and an index into an array |
|
2492 // DetailedGlyphs. The CompressedGlyph record includes a count of |
|
2493 // the number of DetailedGlyph records that belong to the character, |
|
2494 // starting at the given index. |
|
2495 class DetailedGlyphStore { |
|
2496 public: |
|
2497 DetailedGlyphStore() |
|
2498 : mLastUsed(0) |
|
2499 { } |
|
2500 |
|
2501 // This is optimized for the most common calling patterns: |
|
2502 // we rarely need random access to the records, access is most commonly |
|
2503 // sequential through the textRun, so we record the last-used index |
|
2504 // and check whether the caller wants the same record again, or the |
|
2505 // next; if not, it's most likely we're starting over from the start |
|
2506 // of the run, so we check the first entry before resorting to binary |
|
2507 // search as a last resort. |
|
2508 // NOTE that this must not be called for a character offset that does |
|
2509 // not have any DetailedGlyph records; callers must have verified that |
|
2510 // mCharacterGlyphs[aOffset].GetGlyphCount() is greater than zero |
|
2511 // before calling this, otherwise the assertions here will fire (in a |
|
2512 // debug build), and we'll probably crash. |
|
2513 DetailedGlyph* Get(uint32_t aOffset) { |
|
2514 NS_ASSERTION(mOffsetToIndex.Length() > 0, |
|
2515 "no detailed glyph records!"); |
|
2516 DetailedGlyph* details = mDetails.Elements(); |
|
2517 // check common cases (fwd iteration, initial entry, etc) first |
|
2518 if (mLastUsed < mOffsetToIndex.Length() - 1 && |
|
2519 aOffset == mOffsetToIndex[mLastUsed + 1].mOffset) { |
|
2520 ++mLastUsed; |
|
2521 } else if (aOffset == mOffsetToIndex[0].mOffset) { |
|
2522 mLastUsed = 0; |
|
2523 } else if (aOffset == mOffsetToIndex[mLastUsed].mOffset) { |
|
2524 // do nothing |
|
2525 } else if (mLastUsed > 0 && |
|
2526 aOffset == mOffsetToIndex[mLastUsed - 1].mOffset) { |
|
2527 --mLastUsed; |
|
2528 } else { |
|
2529 mLastUsed = |
|
2530 mOffsetToIndex.BinaryIndexOf(aOffset, CompareToOffset()); |
|
2531 } |
|
2532 NS_ASSERTION(mLastUsed != nsTArray<DGRec>::NoIndex, |
|
2533 "detailed glyph record missing!"); |
|
2534 return details + mOffsetToIndex[mLastUsed].mIndex; |
|
2535 } |
|
2536 |
|
2537 DetailedGlyph* Allocate(uint32_t aOffset, uint32_t aCount) { |
|
2538 uint32_t detailIndex = mDetails.Length(); |
|
2539 DetailedGlyph *details = mDetails.AppendElements(aCount); |
|
2540 if (!details) { |
|
2541 return nullptr; |
|
2542 } |
|
2543 // We normally set up glyph records sequentially, so the common case |
|
2544 // here is to append new records to the mOffsetToIndex array; |
|
2545 // test for that before falling back to the InsertElementSorted |
|
2546 // method. |
|
2547 if (mOffsetToIndex.Length() == 0 || |
|
2548 aOffset > mOffsetToIndex[mOffsetToIndex.Length() - 1].mOffset) { |
|
2549 if (!mOffsetToIndex.AppendElement(DGRec(aOffset, detailIndex))) { |
|
2550 return nullptr; |
|
2551 } |
|
2552 } else { |
|
2553 if (!mOffsetToIndex.InsertElementSorted(DGRec(aOffset, detailIndex), |
|
2554 CompareRecordOffsets())) { |
|
2555 return nullptr; |
|
2556 } |
|
2557 } |
|
2558 return details; |
|
2559 } |
|
2560 |
|
2561 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { |
|
2562 return aMallocSizeOf(this) + |
|
2563 mDetails.SizeOfExcludingThis(aMallocSizeOf) + |
|
2564 mOffsetToIndex.SizeOfExcludingThis(aMallocSizeOf); |
|
2565 } |
|
2566 |
|
2567 private: |
|
2568 struct DGRec { |
|
2569 DGRec(const uint32_t& aOffset, const uint32_t& aIndex) |
|
2570 : mOffset(aOffset), mIndex(aIndex) { } |
|
2571 uint32_t mOffset; // source character offset in the textrun |
|
2572 uint32_t mIndex; // index where this char's DetailedGlyphs begin |
|
2573 }; |
|
2574 |
|
2575 struct CompareToOffset { |
|
2576 bool Equals(const DGRec& a, const uint32_t& b) const { |
|
2577 return a.mOffset == b; |
|
2578 } |
|
2579 bool LessThan(const DGRec& a, const uint32_t& b) const { |
|
2580 return a.mOffset < b; |
|
2581 } |
|
2582 }; |
|
2583 |
|
2584 struct CompareRecordOffsets { |
|
2585 bool Equals(const DGRec& a, const DGRec& b) const { |
|
2586 return a.mOffset == b.mOffset; |
|
2587 } |
|
2588 bool LessThan(const DGRec& a, const DGRec& b) const { |
|
2589 return a.mOffset < b.mOffset; |
|
2590 } |
|
2591 }; |
|
2592 |
|
2593 // Concatenated array of all the DetailedGlyph records needed for the |
|
2594 // textRun; individual character offsets are associated with indexes |
|
2595 // into this array via the mOffsetToIndex table. |
|
2596 nsTArray<DetailedGlyph> mDetails; |
|
2597 |
|
2598 // For each character offset that needs DetailedGlyphs, we record the |
|
2599 // index in mDetails where the list of glyphs begins. This array is |
|
2600 // sorted by mOffset. |
|
2601 nsTArray<DGRec> mOffsetToIndex; |
|
2602 |
|
2603 // Records the most recently used index into mOffsetToIndex, so that |
|
2604 // we can support sequential access more quickly than just doing |
|
2605 // a binary search each time. |
|
2606 nsTArray<DGRec>::index_type mLastUsed; |
|
2607 }; |
|
2608 |
|
2609 nsAutoPtr<DetailedGlyphStore> mDetailedGlyphs; |
|
2610 |
|
2611 // Number of char16_t characters and CompressedGlyph glyph records |
|
2612 uint32_t mLength; |
|
2613 |
|
2614 // Shaping flags (direction, ligature-suppression) |
|
2615 uint32_t mFlags; |
|
2616 |
|
2617 int32_t mAppUnitsPerDevUnit; |
|
2618 }; |
|
2619 |
|
2620 /* |
|
2621 * gfxShapedWord: an individual (space-delimited) run of text shaped with a |
|
2622 * particular font, without regard to external context. |
|
2623 * |
|
2624 * The glyph data is copied into gfxTextRuns as needed from the cache of |
|
2625 * ShapedWords associated with each gfxFont instance. |
|
2626 */ |
|
2627 class gfxShapedWord : public gfxShapedText |
|
2628 { |
|
2629 public: |
|
2630 // Create a ShapedWord that can hold glyphs for aLength characters, |
|
2631 // with mCharacterGlyphs sized appropriately. |
|
2632 // |
|
2633 // Returns null on allocation failure (does NOT use infallible alloc) |
|
2634 // so caller must check for success. |
|
2635 // |
|
2636 // This does NOT perform shaping, so the returned word contains no |
|
2637 // glyph data; the caller must call gfxFont::ShapeText() with appropriate |
|
2638 // parameters to set up the glyphs. |
|
2639 static gfxShapedWord* Create(const uint8_t *aText, uint32_t aLength, |
|
2640 int32_t aRunScript, |
|
2641 int32_t aAppUnitsPerDevUnit, |
|
2642 uint32_t aFlags) { |
|
2643 NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(), |
|
2644 "excessive length for gfxShapedWord!"); |
|
2645 |
|
2646 // Compute size needed including the mCharacterGlyphs array |
|
2647 // and a copy of the original text |
|
2648 uint32_t size = |
|
2649 offsetof(gfxShapedWord, mCharGlyphsStorage) + |
|
2650 aLength * (sizeof(CompressedGlyph) + sizeof(uint8_t)); |
|
2651 void *storage = moz_malloc(size); |
|
2652 if (!storage) { |
|
2653 return nullptr; |
|
2654 } |
|
2655 |
|
2656 // Construct in the pre-allocated storage, using placement new |
|
2657 return new (storage) gfxShapedWord(aText, aLength, aRunScript, |
|
2658 aAppUnitsPerDevUnit, aFlags); |
|
2659 } |
|
2660 |
|
2661 static gfxShapedWord* Create(const char16_t *aText, uint32_t aLength, |
|
2662 int32_t aRunScript, |
|
2663 int32_t aAppUnitsPerDevUnit, |
|
2664 uint32_t aFlags) { |
|
2665 NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(), |
|
2666 "excessive length for gfxShapedWord!"); |
|
2667 |
|
2668 // In the 16-bit version of Create, if the TEXT_IS_8BIT flag is set, |
|
2669 // then we convert the text to an 8-bit version and call the 8-bit |
|
2670 // Create function instead. |
|
2671 if (aFlags & gfxTextRunFactory::TEXT_IS_8BIT) { |
|
2672 nsAutoCString narrowText; |
|
2673 LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength), |
|
2674 narrowText); |
|
2675 return Create((const uint8_t*)(narrowText.BeginReading()), |
|
2676 aLength, aRunScript, aAppUnitsPerDevUnit, aFlags); |
|
2677 } |
|
2678 |
|
2679 uint32_t size = |
|
2680 offsetof(gfxShapedWord, mCharGlyphsStorage) + |
|
2681 aLength * (sizeof(CompressedGlyph) + sizeof(char16_t)); |
|
2682 void *storage = moz_malloc(size); |
|
2683 if (!storage) { |
|
2684 return nullptr; |
|
2685 } |
|
2686 |
|
2687 return new (storage) gfxShapedWord(aText, aLength, aRunScript, |
|
2688 aAppUnitsPerDevUnit, aFlags); |
|
2689 } |
|
2690 |
|
2691 // Override operator delete to properly free the object that was |
|
2692 // allocated via moz_malloc. |
|
2693 void operator delete(void* p) { |
|
2694 moz_free(p); |
|
2695 } |
|
2696 |
|
2697 CompressedGlyph *GetCharacterGlyphs() { |
|
2698 return &mCharGlyphsStorage[0]; |
|
2699 } |
|
2700 |
|
2701 const uint8_t* Text8Bit() const { |
|
2702 NS_ASSERTION(TextIs8Bit(), "invalid use of Text8Bit()"); |
|
2703 return reinterpret_cast<const uint8_t*>(mCharGlyphsStorage + GetLength()); |
|
2704 } |
|
2705 |
|
2706 const char16_t* TextUnicode() const { |
|
2707 NS_ASSERTION(!TextIs8Bit(), "invalid use of TextUnicode()"); |
|
2708 return reinterpret_cast<const char16_t*>(mCharGlyphsStorage + GetLength()); |
|
2709 } |
|
2710 |
|
2711 char16_t GetCharAt(uint32_t aOffset) const { |
|
2712 NS_ASSERTION(aOffset < GetLength(), "aOffset out of range"); |
|
2713 return TextIs8Bit() ? |
|
2714 char16_t(Text8Bit()[aOffset]) : TextUnicode()[aOffset]; |
|
2715 } |
|
2716 |
|
2717 int32_t Script() const { |
|
2718 return mScript; |
|
2719 } |
|
2720 |
|
2721 void ResetAge() { |
|
2722 mAgeCounter = 0; |
|
2723 } |
|
2724 uint32_t IncrementAge() { |
|
2725 return ++mAgeCounter; |
|
2726 } |
|
2727 |
|
2728 private: |
|
2729 // so that gfxTextRun can share our DetailedGlyphStore class |
|
2730 friend class gfxTextRun; |
|
2731 |
|
2732 // Construct storage for a ShapedWord, ready to receive glyph data |
|
2733 gfxShapedWord(const uint8_t *aText, uint32_t aLength, |
|
2734 int32_t aRunScript, int32_t aAppUnitsPerDevUnit, |
|
2735 uint32_t aFlags) |
|
2736 : gfxShapedText(aLength, aFlags | gfxTextRunFactory::TEXT_IS_8BIT, |
|
2737 aAppUnitsPerDevUnit) |
|
2738 , mScript(aRunScript) |
|
2739 , mAgeCounter(0) |
|
2740 { |
|
2741 memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph)); |
|
2742 uint8_t *text = reinterpret_cast<uint8_t*>(&mCharGlyphsStorage[aLength]); |
|
2743 memcpy(text, aText, aLength * sizeof(uint8_t)); |
|
2744 } |
|
2745 |
|
2746 gfxShapedWord(const char16_t *aText, uint32_t aLength, |
|
2747 int32_t aRunScript, int32_t aAppUnitsPerDevUnit, |
|
2748 uint32_t aFlags) |
|
2749 : gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit) |
|
2750 , mScript(aRunScript) |
|
2751 , mAgeCounter(0) |
|
2752 { |
|
2753 memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph)); |
|
2754 char16_t *text = reinterpret_cast<char16_t*>(&mCharGlyphsStorage[aLength]); |
|
2755 memcpy(text, aText, aLength * sizeof(char16_t)); |
|
2756 SetupClusterBoundaries(0, aText, aLength); |
|
2757 } |
|
2758 |
|
2759 int32_t mScript; |
|
2760 |
|
2761 uint32_t mAgeCounter; |
|
2762 |
|
2763 // The mCharGlyphsStorage array is actually a variable-size member; |
|
2764 // when the ShapedWord is created, its size will be increased as necessary |
|
2765 // to allow the proper number of glyphs to be stored. |
|
2766 // The original text, in either 8-bit or 16-bit form, will be stored |
|
2767 // immediately following the CompressedGlyphs. |
|
2768 CompressedGlyph mCharGlyphsStorage[1]; |
|
2769 }; |
|
2770 |
|
2771 /** |
|
2772 * Callback for Draw() to use when drawing text with mode |
|
2773 * DrawMode::GLYPH_PATH. |
|
2774 */ |
|
2775 struct gfxTextRunDrawCallbacks { |
|
2776 |
|
2777 /** |
|
2778 * Constructs a new DrawCallbacks object. |
|
2779 * |
|
2780 * @param aShouldPaintSVGGlyphs If true, SVG glyphs will be |
|
2781 * painted and the NotifyBeforeSVGGlyphPainted/NotifyAfterSVGGlyphPainted |
|
2782 * callbacks will be invoked for each SVG glyph. If false, SVG glyphs |
|
2783 * will not be painted; fallback plain glyphs are not emitted either. |
|
2784 */ |
|
2785 gfxTextRunDrawCallbacks(bool aShouldPaintSVGGlyphs = false) |
|
2786 : mShouldPaintSVGGlyphs(aShouldPaintSVGGlyphs) |
|
2787 { |
|
2788 } |
|
2789 |
|
2790 /** |
|
2791 * Called when a path has been emitted to the gfxContext when |
|
2792 * painting a text run. This can be called any number of times, |
|
2793 * due to partial ligatures and intervening SVG glyphs. |
|
2794 */ |
|
2795 virtual void NotifyGlyphPathEmitted() = 0; |
|
2796 |
|
2797 /** |
|
2798 * Called just before an SVG glyph has been painted to the gfxContext. |
|
2799 */ |
|
2800 virtual void NotifyBeforeSVGGlyphPainted() { } |
|
2801 |
|
2802 /** |
|
2803 * Called just after an SVG glyph has been painted to the gfxContext. |
|
2804 */ |
|
2805 virtual void NotifyAfterSVGGlyphPainted() { } |
|
2806 |
|
2807 bool mShouldPaintSVGGlyphs; |
|
2808 }; |
|
2809 |
|
2810 /** |
|
2811 * gfxTextRun is an abstraction for drawing and measuring substrings of a run |
|
2812 * of text. It stores runs of positioned glyph data, each run having a single |
|
2813 * gfxFont. The glyphs are associated with a string of source text, and the |
|
2814 * gfxTextRun APIs take parameters that are offsets into that source text. |
|
2815 * |
|
2816 * gfxTextRuns are not refcounted. They should be deleted when no longer required. |
|
2817 * |
|
2818 * gfxTextRuns are mostly immutable. The only things that can change are |
|
2819 * inter-cluster spacing and line break placement. Spacing is always obtained |
|
2820 * lazily by methods that need it, it is not cached. Line breaks are stored |
|
2821 * persistently (insofar as they affect the shaping of glyphs; gfxTextRun does |
|
2822 * not actually do anything to explicitly account for line breaks). Initially |
|
2823 * there are no line breaks. The textrun can record line breaks before or after |
|
2824 * any given cluster. (Line breaks specified inside clusters are ignored.) |
|
2825 * |
|
2826 * It is important that zero-length substrings are handled correctly. This will |
|
2827 * be on the test! |
|
2828 */ |
|
2829 class gfxTextRun : public gfxShapedText { |
|
2830 public: |
|
2831 |
|
2832 // Override operator delete to properly free the object that was |
|
2833 // allocated via moz_malloc. |
|
2834 void operator delete(void* p) { |
|
2835 moz_free(p); |
|
2836 } |
|
2837 |
|
2838 virtual ~gfxTextRun(); |
|
2839 |
|
2840 typedef gfxFont::RunMetrics Metrics; |
|
2841 |
|
2842 // Public textrun API for general use |
|
2843 |
|
2844 bool IsClusterStart(uint32_t aPos) { |
|
2845 NS_ASSERTION(aPos < GetLength(), "aPos out of range"); |
|
2846 return mCharacterGlyphs[aPos].IsClusterStart(); |
|
2847 } |
|
2848 bool IsLigatureGroupStart(uint32_t aPos) { |
|
2849 NS_ASSERTION(aPos < GetLength(), "aPos out of range"); |
|
2850 return mCharacterGlyphs[aPos].IsLigatureGroupStart(); |
|
2851 } |
|
2852 bool CanBreakLineBefore(uint32_t aPos) { |
|
2853 NS_ASSERTION(aPos < GetLength(), "aPos out of range"); |
|
2854 return mCharacterGlyphs[aPos].CanBreakBefore() == |
|
2855 CompressedGlyph::FLAG_BREAK_TYPE_NORMAL; |
|
2856 } |
|
2857 bool CanHyphenateBefore(uint32_t aPos) { |
|
2858 NS_ASSERTION(aPos < GetLength(), "aPos out of range"); |
|
2859 return mCharacterGlyphs[aPos].CanBreakBefore() == |
|
2860 CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN; |
|
2861 } |
|
2862 |
|
2863 bool CharIsSpace(uint32_t aPos) { |
|
2864 NS_ASSERTION(aPos < GetLength(), "aPos out of range"); |
|
2865 return mCharacterGlyphs[aPos].CharIsSpace(); |
|
2866 } |
|
2867 bool CharIsTab(uint32_t aPos) { |
|
2868 NS_ASSERTION(aPos < GetLength(), "aPos out of range"); |
|
2869 return mCharacterGlyphs[aPos].CharIsTab(); |
|
2870 } |
|
2871 bool CharIsNewline(uint32_t aPos) { |
|
2872 NS_ASSERTION(aPos < GetLength(), "aPos out of range"); |
|
2873 return mCharacterGlyphs[aPos].CharIsNewline(); |
|
2874 } |
|
2875 bool CharIsLowSurrogate(uint32_t aPos) { |
|
2876 NS_ASSERTION(aPos < GetLength(), "aPos out of range"); |
|
2877 return mCharacterGlyphs[aPos].CharIsLowSurrogate(); |
|
2878 } |
|
2879 |
|
2880 uint32_t GetLength() { return mLength; } |
|
2881 |
|
2882 // All uint32_t aStart, uint32_t aLength ranges below are restricted to |
|
2883 // grapheme cluster boundaries! All offsets are in terms of the string |
|
2884 // passed into MakeTextRun. |
|
2885 |
|
2886 // All coordinates are in layout/app units |
|
2887 |
|
2888 /** |
|
2889 * Set the potential linebreaks for a substring of the textrun. These are |
|
2890 * the "allow break before" points. Initially, there are no potential |
|
2891 * linebreaks. |
|
2892 * |
|
2893 * This can change glyphs and/or geometry! Some textruns' shapes |
|
2894 * depend on potential line breaks (e.g., title-case-converting textruns). |
|
2895 * This function is virtual so that those textruns can reshape themselves. |
|
2896 * |
|
2897 * @return true if this changed the linebreaks, false if the new line |
|
2898 * breaks are the same as the old |
|
2899 */ |
|
2900 virtual bool SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength, |
|
2901 uint8_t *aBreakBefore, |
|
2902 gfxContext *aRefContext); |
|
2903 |
|
2904 /** |
|
2905 * Layout provides PropertyProvider objects. These allow detection of |
|
2906 * potential line break points and computation of spacing. We pass the data |
|
2907 * this way to allow lazy data acquisition; for example BreakAndMeasureText |
|
2908 * will want to only ask for properties of text it's actually looking at. |
|
2909 * |
|
2910 * NOTE that requested spacing may not actually be applied, if the textrun |
|
2911 * is unable to apply it in some context. Exception: spacing around a |
|
2912 * whitespace character MUST always be applied. |
|
2913 */ |
|
2914 class PropertyProvider { |
|
2915 public: |
|
2916 // Detect hyphenation break opportunities in the given range; breaks |
|
2917 // not at cluster boundaries will be ignored. |
|
2918 virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength, |
|
2919 bool *aBreakBefore) = 0; |
|
2920 |
|
2921 // Returns the provider's hyphenation setting, so callers can decide |
|
2922 // whether it is necessary to call GetHyphenationBreaks. |
|
2923 // Result is an NS_STYLE_HYPHENS_* value. |
|
2924 virtual int8_t GetHyphensOption() = 0; |
|
2925 |
|
2926 // Returns the extra width that will be consumed by a hyphen. This should |
|
2927 // be constant for a given textrun. |
|
2928 virtual gfxFloat GetHyphenWidth() = 0; |
|
2929 |
|
2930 typedef gfxFont::Spacing Spacing; |
|
2931 |
|
2932 /** |
|
2933 * Get the spacing around the indicated characters. Spacing must be zero |
|
2934 * inside clusters. In other words, if character i is not |
|
2935 * CLUSTER_START, then character i-1 must have zero after-spacing and |
|
2936 * character i must have zero before-spacing. |
|
2937 */ |
|
2938 virtual void GetSpacing(uint32_t aStart, uint32_t aLength, |
|
2939 Spacing *aSpacing) = 0; |
|
2940 |
|
2941 // Returns a gfxContext that can be used to measure the hyphen glyph. |
|
2942 // Only called if the hyphen width is requested. |
|
2943 virtual already_AddRefed<gfxContext> GetContext() = 0; |
|
2944 |
|
2945 // Return the appUnitsPerDevUnit value to be used when measuring. |
|
2946 // Only called if the hyphen width is requested. |
|
2947 virtual uint32_t GetAppUnitsPerDevUnit() = 0; |
|
2948 }; |
|
2949 |
|
2950 class ClusterIterator { |
|
2951 public: |
|
2952 ClusterIterator(gfxTextRun *aTextRun); |
|
2953 |
|
2954 void Reset(); |
|
2955 |
|
2956 bool NextCluster(); |
|
2957 |
|
2958 uint32_t Position() const { |
|
2959 return mCurrentChar; |
|
2960 } |
|
2961 |
|
2962 uint32_t ClusterLength() const; |
|
2963 |
|
2964 gfxFloat ClusterAdvance(PropertyProvider *aProvider) const; |
|
2965 |
|
2966 private: |
|
2967 gfxTextRun *mTextRun; |
|
2968 uint32_t mCurrentChar; |
|
2969 }; |
|
2970 |
|
2971 /** |
|
2972 * Draws a substring. Uses only GetSpacing from aBreakProvider. |
|
2973 * The provided point is the baseline origin on the left of the string |
|
2974 * for LTR, on the right of the string for RTL. |
|
2975 * @param aAdvanceWidth if non-null, the advance width of the substring |
|
2976 * is returned here. |
|
2977 * |
|
2978 * Drawing should respect advance widths in the sense that for LTR runs, |
|
2979 * Draw(ctx, pt, offset1, length1, dirty, &provider, &advance) followed by |
|
2980 * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1 + length1, length2, |
|
2981 * dirty, &provider, nullptr) should have the same effect as |
|
2982 * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr). |
|
2983 * For RTL runs the rule is: |
|
2984 * Draw(ctx, pt, offset1 + length1, length2, dirty, &provider, &advance) followed by |
|
2985 * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1, length1, |
|
2986 * dirty, &provider, nullptr) should have the same effect as |
|
2987 * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr). |
|
2988 * |
|
2989 * Glyphs should be drawn in logical content order, which can be significant |
|
2990 * if they overlap (perhaps due to negative spacing). |
|
2991 */ |
|
2992 void Draw(gfxContext *aContext, gfxPoint aPt, |
|
2993 DrawMode aDrawMode, |
|
2994 uint32_t aStart, uint32_t aLength, |
|
2995 PropertyProvider *aProvider, |
|
2996 gfxFloat *aAdvanceWidth, gfxTextContextPaint *aContextPaint, |
|
2997 gfxTextRunDrawCallbacks *aCallbacks = nullptr); |
|
2998 |
|
2999 /** |
|
3000 * Computes the ReflowMetrics for a substring. |
|
3001 * Uses GetSpacing from aBreakProvider. |
|
3002 * @param aBoundingBoxType which kind of bounding box (loose/tight) |
|
3003 */ |
|
3004 Metrics MeasureText(uint32_t aStart, uint32_t aLength, |
|
3005 gfxFont::BoundingBoxType aBoundingBoxType, |
|
3006 gfxContext *aRefContextForTightBoundingBox, |
|
3007 PropertyProvider *aProvider); |
|
3008 |
|
3009 /** |
|
3010 * Computes just the advance width for a substring. |
|
3011 * Uses GetSpacing from aBreakProvider. |
|
3012 */ |
|
3013 gfxFloat GetAdvanceWidth(uint32_t aStart, uint32_t aLength, |
|
3014 PropertyProvider *aProvider); |
|
3015 |
|
3016 /** |
|
3017 * Clear all stored line breaks for the given range (both before and after), |
|
3018 * and then set the line-break state before aStart to aBreakBefore and |
|
3019 * after the last cluster to aBreakAfter. |
|
3020 * |
|
3021 * We require that before and after line breaks be consistent. For clusters |
|
3022 * i and i+1, we require that if there is a break after cluster i, a break |
|
3023 * will be specified before cluster i+1. This may be temporarily violated |
|
3024 * (e.g. after reflowing line L and before reflowing line L+1); to handle |
|
3025 * these temporary violations, we say that there is a break betwen i and i+1 |
|
3026 * if a break is specified after i OR a break is specified before i+1. |
|
3027 * |
|
3028 * This can change textrun geometry! The existence of a linebreak can affect |
|
3029 * the advance width of the cluster before the break (when kerning) or the |
|
3030 * geometry of one cluster before the break or any number of clusters |
|
3031 * after the break. (The one-cluster-before-the-break limit is somewhat |
|
3032 * arbitrary; if some scripts require breaking it, then we need to |
|
3033 * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase |
|
3034 * it could affect the layout of frames before it...) |
|
3035 * |
|
3036 * We return true if glyphs or geometry changed, false otherwise. This |
|
3037 * function is virtual so that gfxTextRun subclasses can reshape |
|
3038 * properly. |
|
3039 * |
|
3040 * @param aAdvanceWidthDelta if non-null, returns the change in advance |
|
3041 * width of the given range. |
|
3042 */ |
|
3043 virtual bool SetLineBreaks(uint32_t aStart, uint32_t aLength, |
|
3044 bool aLineBreakBefore, bool aLineBreakAfter, |
|
3045 gfxFloat *aAdvanceWidthDelta, |
|
3046 gfxContext *aRefContext); |
|
3047 |
|
3048 /** |
|
3049 * Finds the longest substring that will fit into the given width. |
|
3050 * Uses GetHyphenationBreaks and GetSpacing from aBreakProvider. |
|
3051 * Guarantees the following: |
|
3052 * -- 0 <= result <= aMaxLength |
|
3053 * -- result is the maximal value of N such that either |
|
3054 * N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth |
|
3055 * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth |
|
3056 * OR N == aMaxLength && GetAdvanceWidth(aStart, N) <= aWidth |
|
3057 * where GetAdvanceWidth assumes the effect of |
|
3058 * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider) |
|
3059 * -- if no such N exists, then result is the smallest N such that |
|
3060 * N < aMaxLength && line break at N |
|
3061 * OR N < aMaxLength && hyphen break at N |
|
3062 * OR N == aMaxLength |
|
3063 * |
|
3064 * The call has the effect of |
|
3065 * SetLineBreaks(aStart, result, aLineBreakBefore, result < aMaxLength, aProvider) |
|
3066 * and the returned metrics and the invariants above reflect this. |
|
3067 * |
|
3068 * @param aMaxLength this can be UINT32_MAX, in which case the length used |
|
3069 * is up to the end of the string |
|
3070 * @param aLineBreakBefore set to true if and only if there is an actual |
|
3071 * line break at the start of this string. |
|
3072 * @param aSuppressInitialBreak if true, then we assume there is no possible |
|
3073 * linebreak before aStart. If false, then we will check the internal |
|
3074 * line break opportunity state before deciding whether to return 0 as the |
|
3075 * character to break before. |
|
3076 * @param aTrimWhitespace if non-null, then we allow a trailing run of |
|
3077 * spaces to be trimmed; the width of the space(s) will not be included in |
|
3078 * the measured string width for comparison with the limit aWidth, and |
|
3079 * trimmed spaces will not be included in returned metrics. The width |
|
3080 * of the trimmed spaces will be returned in aTrimWhitespace. |
|
3081 * Trimmed spaces are still counted in the "characters fit" result. |
|
3082 * @param aMetrics if non-null, we fill this in for the returned substring. |
|
3083 * If a hyphenation break was used, the hyphen is NOT included in the returned metrics. |
|
3084 * @param aBoundingBoxType whether to make the bounding box in aMetrics tight |
|
3085 * @param aRefContextForTightBoundingBox a reference context to get the |
|
3086 * tight bounding box, if requested |
|
3087 * @param aUsedHyphenation if non-null, records if we selected a hyphenation break |
|
3088 * @param aLastBreak if non-null and result is aMaxLength, we set this to |
|
3089 * the maximal N such that |
|
3090 * N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth |
|
3091 * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth |
|
3092 * or UINT32_MAX if no such N exists, where GetAdvanceWidth assumes |
|
3093 * the effect of |
|
3094 * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider) |
|
3095 * |
|
3096 * @param aCanWordWrap true if we can break between any two grapheme |
|
3097 * clusters. This is set by word-wrap: break-word |
|
3098 * |
|
3099 * @param aBreakPriority in/out the priority of the break opportunity |
|
3100 * saved in the line. If we are prioritizing break opportunities, we will |
|
3101 * not set a break with a lower priority. @see gfxBreakPriority. |
|
3102 * |
|
3103 * Note that negative advance widths are possible especially if negative |
|
3104 * spacing is provided. |
|
3105 */ |
|
3106 uint32_t BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, |
|
3107 bool aLineBreakBefore, gfxFloat aWidth, |
|
3108 PropertyProvider *aProvider, |
|
3109 bool aSuppressInitialBreak, |
|
3110 gfxFloat *aTrimWhitespace, |
|
3111 Metrics *aMetrics, |
|
3112 gfxFont::BoundingBoxType aBoundingBoxType, |
|
3113 gfxContext *aRefContextForTightBoundingBox, |
|
3114 bool *aUsedHyphenation, |
|
3115 uint32_t *aLastBreak, |
|
3116 bool aCanWordWrap, |
|
3117 gfxBreakPriority *aBreakPriority); |
|
3118 |
|
3119 /** |
|
3120 * Update the reference context. |
|
3121 * XXX this is a hack. New text frame does not call this. Use only |
|
3122 * temporarily for old text frame. |
|
3123 */ |
|
3124 void SetContext(gfxContext *aContext) {} |
|
3125 |
|
3126 // Utility getters |
|
3127 |
|
3128 gfxFloat GetDirection() const { return (mFlags & gfxTextRunFactory::TEXT_IS_RTL) ? -1.0 : 1.0; } |
|
3129 void *GetUserData() const { return mUserData; } |
|
3130 void SetUserData(void *aUserData) { mUserData = aUserData; } |
|
3131 uint32_t GetFlags() const { return mFlags; } |
|
3132 void SetFlagBits(uint32_t aFlags) { |
|
3133 NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS), |
|
3134 "Only user flags should be mutable"); |
|
3135 mFlags |= aFlags; |
|
3136 } |
|
3137 void ClearFlagBits(uint32_t aFlags) { |
|
3138 NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS), |
|
3139 "Only user flags should be mutable"); |
|
3140 mFlags &= ~aFlags; |
|
3141 } |
|
3142 const gfxSkipChars& GetSkipChars() const { return mSkipChars; } |
|
3143 gfxFontGroup *GetFontGroup() const { return mFontGroup; } |
|
3144 |
|
3145 |
|
3146 // Call this, don't call "new gfxTextRun" directly. This does custom |
|
3147 // allocation and initialization |
|
3148 static gfxTextRun *Create(const gfxTextRunFactory::Parameters *aParams, |
|
3149 uint32_t aLength, gfxFontGroup *aFontGroup, |
|
3150 uint32_t aFlags); |
|
3151 |
|
3152 // The text is divided into GlyphRuns as necessary |
|
3153 struct GlyphRun { |
|
3154 nsRefPtr<gfxFont> mFont; // never null |
|
3155 uint32_t mCharacterOffset; // into original UTF16 string |
|
3156 uint8_t mMatchType; |
|
3157 }; |
|
3158 |
|
3159 class GlyphRunIterator { |
|
3160 public: |
|
3161 GlyphRunIterator(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aLength) |
|
3162 : mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) { |
|
3163 mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart); |
|
3164 } |
|
3165 bool NextRun(); |
|
3166 GlyphRun *GetGlyphRun() { return mGlyphRun; } |
|
3167 uint32_t GetStringStart() { return mStringStart; } |
|
3168 uint32_t GetStringEnd() { return mStringEnd; } |
|
3169 private: |
|
3170 gfxTextRun *mTextRun; |
|
3171 GlyphRun *mGlyphRun; |
|
3172 uint32_t mStringStart; |
|
3173 uint32_t mStringEnd; |
|
3174 uint32_t mNextIndex; |
|
3175 uint32_t mStartOffset; |
|
3176 uint32_t mEndOffset; |
|
3177 }; |
|
3178 |
|
3179 class GlyphRunOffsetComparator { |
|
3180 public: |
|
3181 bool Equals(const GlyphRun& a, |
|
3182 const GlyphRun& b) const |
|
3183 { |
|
3184 return a.mCharacterOffset == b.mCharacterOffset; |
|
3185 } |
|
3186 |
|
3187 bool LessThan(const GlyphRun& a, |
|
3188 const GlyphRun& b) const |
|
3189 { |
|
3190 return a.mCharacterOffset < b.mCharacterOffset; |
|
3191 } |
|
3192 }; |
|
3193 |
|
3194 friend class GlyphRunIterator; |
|
3195 friend class FontSelector; |
|
3196 |
|
3197 // API for setting up the textrun glyphs. Should only be called by |
|
3198 // things that construct textruns. |
|
3199 /** |
|
3200 * We've found a run of text that should use a particular font. Call this |
|
3201 * only during initialization when font substitution has been computed. |
|
3202 * Call it before setting up the glyphs for the characters in this run; |
|
3203 * SetMissingGlyph requires that the correct glyphrun be installed. |
|
3204 * |
|
3205 * If aForceNewRun, a new glyph run will be added, even if the |
|
3206 * previously added run uses the same font. If glyph runs are |
|
3207 * added out of strictly increasing aStartCharIndex order (via |
|
3208 * force), then SortGlyphRuns must be called after all glyph runs |
|
3209 * are added before any further operations are performed with this |
|
3210 * TextRun. |
|
3211 */ |
|
3212 nsresult AddGlyphRun(gfxFont *aFont, uint8_t aMatchType, |
|
3213 uint32_t aStartCharIndex, bool aForceNewRun); |
|
3214 void ResetGlyphRuns() { mGlyphRuns.Clear(); } |
|
3215 void SortGlyphRuns(); |
|
3216 void SanitizeGlyphRuns(); |
|
3217 |
|
3218 CompressedGlyph* GetCharacterGlyphs() { |
|
3219 NS_ASSERTION(mCharacterGlyphs, "failed to initialize mCharacterGlyphs"); |
|
3220 return mCharacterGlyphs; |
|
3221 } |
|
3222 |
|
3223 void SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, uint32_t aCharIndex); |
|
3224 |
|
3225 // Set the glyph data for the given character index to the font's |
|
3226 // space glyph, IF this can be done as a "simple" glyph record |
|
3227 // (not requiring a DetailedGlyph entry). This avoids the need to call |
|
3228 // the font shaper and go through the shaped-word cache for most spaces. |
|
3229 // |
|
3230 // The parameter aSpaceChar is the original character code for which |
|
3231 // this space glyph is being used; if this is U+0020, we need to record |
|
3232 // that it could be trimmed at a run edge, whereas other kinds of space |
|
3233 // (currently just U+00A0) would not be trimmable/breakable. |
|
3234 // |
|
3235 // Returns true if it was able to set simple glyph data for the space; |
|
3236 // if it returns false, the caller needs to fall back to some other |
|
3237 // means to create the necessary (detailed) glyph data. |
|
3238 bool SetSpaceGlyphIfSimple(gfxFont *aFont, gfxContext *aContext, |
|
3239 uint32_t aCharIndex, char16_t aSpaceChar); |
|
3240 |
|
3241 // Record the positions of specific characters that layout may need to |
|
3242 // detect in the textrun, even though it doesn't have an explicit copy |
|
3243 // of the original text. These are recorded using flag bits in the |
|
3244 // CompressedGlyph record; if necessary, we convert "simple" glyph records |
|
3245 // to "complex" ones as the Tab and Newline flags are not present in |
|
3246 // simple CompressedGlyph records. |
|
3247 void SetIsTab(uint32_t aIndex) { |
|
3248 CompressedGlyph *g = &mCharacterGlyphs[aIndex]; |
|
3249 if (g->IsSimpleGlyph()) { |
|
3250 DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1); |
|
3251 details->mGlyphID = g->GetSimpleGlyph(); |
|
3252 details->mAdvance = g->GetSimpleAdvance(); |
|
3253 details->mXOffset = details->mYOffset = 0; |
|
3254 SetGlyphs(aIndex, CompressedGlyph().SetComplex(true, true, 1), details); |
|
3255 } |
|
3256 g->SetIsTab(); |
|
3257 } |
|
3258 void SetIsNewline(uint32_t aIndex) { |
|
3259 CompressedGlyph *g = &mCharacterGlyphs[aIndex]; |
|
3260 if (g->IsSimpleGlyph()) { |
|
3261 DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1); |
|
3262 details->mGlyphID = g->GetSimpleGlyph(); |
|
3263 details->mAdvance = g->GetSimpleAdvance(); |
|
3264 details->mXOffset = details->mYOffset = 0; |
|
3265 SetGlyphs(aIndex, CompressedGlyph().SetComplex(true, true, 1), details); |
|
3266 } |
|
3267 g->SetIsNewline(); |
|
3268 } |
|
3269 void SetIsLowSurrogate(uint32_t aIndex) { |
|
3270 SetGlyphs(aIndex, CompressedGlyph().SetComplex(false, false, 0), nullptr); |
|
3271 mCharacterGlyphs[aIndex].SetIsLowSurrogate(); |
|
3272 } |
|
3273 |
|
3274 /** |
|
3275 * Prefetch all the glyph extents needed to ensure that Measure calls |
|
3276 * on this textrun not requesting tight boundingBoxes will succeed. Note |
|
3277 * that some glyph extents might not be fetched due to OOM or other |
|
3278 * errors. |
|
3279 */ |
|
3280 void FetchGlyphExtents(gfxContext *aRefContext); |
|
3281 |
|
3282 uint32_t CountMissingGlyphs(); |
|
3283 const GlyphRun *GetGlyphRuns(uint32_t *aNumGlyphRuns) { |
|
3284 *aNumGlyphRuns = mGlyphRuns.Length(); |
|
3285 return mGlyphRuns.Elements(); |
|
3286 } |
|
3287 // Returns the index of the GlyphRun containing the given offset. |
|
3288 // Returns mGlyphRuns.Length() when aOffset is mCharacterCount. |
|
3289 uint32_t FindFirstGlyphRunContaining(uint32_t aOffset); |
|
3290 |
|
3291 // Copy glyph data from a ShapedWord into this textrun. |
|
3292 void CopyGlyphDataFrom(gfxShapedWord *aSource, uint32_t aStart); |
|
3293 |
|
3294 // Copy glyph data for a range of characters from aSource to this |
|
3295 // textrun. |
|
3296 void CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart, |
|
3297 uint32_t aLength, uint32_t aDest); |
|
3298 |
|
3299 nsExpirationState *GetExpirationState() { return &mExpirationState; } |
|
3300 |
|
3301 // Tell the textrun to release its reference to its creating gfxFontGroup |
|
3302 // immediately, rather than on destruction. This is used for textruns |
|
3303 // that are actually owned by a gfxFontGroup, so that they don't keep it |
|
3304 // permanently alive due to a circular reference. (The caller of this is |
|
3305 // taking responsibility for ensuring the textrun will not outlive its |
|
3306 // mFontGroup.) |
|
3307 void ReleaseFontGroup(); |
|
3308 |
|
3309 struct LigatureData { |
|
3310 // textrun offsets of the start and end of the containing ligature |
|
3311 uint32_t mLigatureStart; |
|
3312 uint32_t mLigatureEnd; |
|
3313 // appunits advance to the start of the ligature part within the ligature; |
|
3314 // never includes any spacing |
|
3315 gfxFloat mPartAdvance; |
|
3316 // appunits width of the ligature part; includes before-spacing |
|
3317 // when the part is at the start of the ligature, and after-spacing |
|
3318 // when the part is as the end of the ligature |
|
3319 gfxFloat mPartWidth; |
|
3320 |
|
3321 bool mClipBeforePart; |
|
3322 bool mClipAfterPart; |
|
3323 }; |
|
3324 |
|
3325 // return storage used by this run, for memory reporter; |
|
3326 // nsTransformedTextRun needs to override this as it holds additional data |
|
3327 virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) |
|
3328 MOZ_MUST_OVERRIDE; |
|
3329 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) |
|
3330 MOZ_MUST_OVERRIDE; |
|
3331 |
|
3332 // Get the size, if it hasn't already been gotten, marking as it goes. |
|
3333 size_t MaybeSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { |
|
3334 if (mFlags & gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED) { |
|
3335 return 0; |
|
3336 } |
|
3337 mFlags |= gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED; |
|
3338 return SizeOfIncludingThis(aMallocSizeOf); |
|
3339 } |
|
3340 void ResetSizeOfAccountingFlags() { |
|
3341 mFlags &= ~gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED; |
|
3342 } |
|
3343 |
|
3344 #ifdef DEBUG |
|
3345 void Dump(FILE* aOutput); |
|
3346 #endif |
|
3347 |
|
3348 protected: |
|
3349 /** |
|
3350 * Create a textrun, and set its mCharacterGlyphs to point immediately |
|
3351 * after the base object; this is ONLY used in conjunction with placement |
|
3352 * new, after allocating a block large enough for the glyph records to |
|
3353 * follow the base textrun object. |
|
3354 */ |
|
3355 gfxTextRun(const gfxTextRunFactory::Parameters *aParams, |
|
3356 uint32_t aLength, gfxFontGroup *aFontGroup, uint32_t aFlags); |
|
3357 |
|
3358 /** |
|
3359 * Helper for the Create() factory method to allocate the required |
|
3360 * glyph storage for a textrun object with the basic size aSize, |
|
3361 * plus room for aLength glyph records. |
|
3362 */ |
|
3363 static void* AllocateStorageForTextRun(size_t aSize, uint32_t aLength); |
|
3364 |
|
3365 // Pointer to the array of CompressedGlyph records; must be initialized |
|
3366 // when the object is constructed. |
|
3367 CompressedGlyph *mCharacterGlyphs; |
|
3368 |
|
3369 private: |
|
3370 // **** general helpers **** |
|
3371 |
|
3372 // Allocate aCount DetailedGlyphs for the given index |
|
3373 DetailedGlyph *AllocateDetailedGlyphs(uint32_t aCharIndex, uint32_t aCount); |
|
3374 |
|
3375 // Get the total advance for a range of glyphs. |
|
3376 int32_t GetAdvanceForGlyphs(uint32_t aStart, uint32_t aEnd); |
|
3377 |
|
3378 // Spacing for characters outside the range aSpacingStart/aSpacingEnd |
|
3379 // is assumed to be zero; such characters are not passed to aProvider. |
|
3380 // This is useful to protect aProvider from being passed character indices |
|
3381 // it is not currently able to handle. |
|
3382 bool GetAdjustedSpacingArray(uint32_t aStart, uint32_t aEnd, |
|
3383 PropertyProvider *aProvider, |
|
3384 uint32_t aSpacingStart, uint32_t aSpacingEnd, |
|
3385 nsTArray<PropertyProvider::Spacing> *aSpacing); |
|
3386 |
|
3387 // **** ligature helpers **** |
|
3388 // (Platforms do the actual ligaturization, but we need to do a bunch of stuff |
|
3389 // to handle requests that begin or end inside a ligature) |
|
3390 |
|
3391 // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero |
|
3392 LigatureData ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd, |
|
3393 PropertyProvider *aProvider); |
|
3394 gfxFloat ComputePartialLigatureWidth(uint32_t aPartStart, uint32_t aPartEnd, |
|
3395 PropertyProvider *aProvider); |
|
3396 void DrawPartialLigature(gfxFont *aFont, gfxContext *aCtx, |
|
3397 uint32_t aStart, uint32_t aEnd, gfxPoint *aPt, |
|
3398 PropertyProvider *aProvider, |
|
3399 gfxTextRunDrawCallbacks *aCallbacks); |
|
3400 // Advance aStart to the start of the nearest ligature; back up aEnd |
|
3401 // to the nearest ligature end; may result in *aStart == *aEnd |
|
3402 void ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd); |
|
3403 // result in appunits |
|
3404 gfxFloat GetPartialLigatureWidth(uint32_t aStart, uint32_t aEnd, PropertyProvider *aProvider); |
|
3405 void AccumulatePartialLigatureMetrics(gfxFont *aFont, |
|
3406 uint32_t aStart, uint32_t aEnd, |
|
3407 gfxFont::BoundingBoxType aBoundingBoxType, |
|
3408 gfxContext *aRefContext, |
|
3409 PropertyProvider *aProvider, |
|
3410 Metrics *aMetrics); |
|
3411 |
|
3412 // **** measurement helper **** |
|
3413 void AccumulateMetricsForRun(gfxFont *aFont, uint32_t aStart, uint32_t aEnd, |
|
3414 gfxFont::BoundingBoxType aBoundingBoxType, |
|
3415 gfxContext *aRefContext, |
|
3416 PropertyProvider *aProvider, |
|
3417 uint32_t aSpacingStart, uint32_t aSpacingEnd, |
|
3418 Metrics *aMetrics); |
|
3419 |
|
3420 // **** drawing helper **** |
|
3421 void DrawGlyphs(gfxFont *aFont, gfxContext *aContext, |
|
3422 DrawMode aDrawMode, gfxPoint *aPt, |
|
3423 gfxTextContextPaint *aContextPaint, uint32_t aStart, |
|
3424 uint32_t aEnd, PropertyProvider *aProvider, |
|
3425 uint32_t aSpacingStart, uint32_t aSpacingEnd, |
|
3426 gfxTextRunDrawCallbacks *aCallbacks); |
|
3427 |
|
3428 // XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*, |
|
3429 // for smaller size especially in the super-common one-glyphrun case |
|
3430 nsAutoTArray<GlyphRun,1> mGlyphRuns; |
|
3431 |
|
3432 void *mUserData; |
|
3433 gfxFontGroup *mFontGroup; // addrefed on creation, but our reference |
|
3434 // may be released by ReleaseFontGroup() |
|
3435 gfxSkipChars mSkipChars; |
|
3436 nsExpirationState mExpirationState; |
|
3437 |
|
3438 bool mSkipDrawing; // true if the font group we used had a user font |
|
3439 // download that's in progress, so we should hide text |
|
3440 // until the download completes (or timeout fires) |
|
3441 bool mReleasedFontGroup; // we already called NS_RELEASE on |
|
3442 // mFontGroup, so don't do it again |
|
3443 }; |
|
3444 |
|
3445 class gfxFontGroup : public gfxTextRunFactory { |
|
3446 public: |
|
3447 class FamilyFace { |
|
3448 public: |
|
3449 FamilyFace() { } |
|
3450 |
|
3451 FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont) |
|
3452 : mFamily(aFamily), mFont(aFont) |
|
3453 { |
|
3454 NS_ASSERTION(aFont, "font pointer must not be null"); |
|
3455 NS_ASSERTION(!aFamily || |
|
3456 aFamily->ContainsFace(aFont->GetFontEntry()), |
|
3457 "font is not a member of the given family"); |
|
3458 } |
|
3459 |
|
3460 gfxFontFamily* Family() const { return mFamily.get(); } |
|
3461 gfxFont* Font() const { return mFont.get(); } |
|
3462 |
|
3463 private: |
|
3464 nsRefPtr<gfxFontFamily> mFamily; |
|
3465 nsRefPtr<gfxFont> mFont; |
|
3466 }; |
|
3467 |
|
3468 static void Shutdown(); // platform must call this to release the languageAtomService |
|
3469 |
|
3470 gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet = nullptr); |
|
3471 |
|
3472 virtual ~gfxFontGroup(); |
|
3473 |
|
3474 virtual gfxFont *GetFontAt(int32_t i) { |
|
3475 // If it turns out to be hard for all clients that cache font |
|
3476 // groups to call UpdateFontList at appropriate times, we could |
|
3477 // instead consider just calling UpdateFontList from someplace |
|
3478 // more central (such as here). |
|
3479 NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(), |
|
3480 "Whoever was caching this font group should have " |
|
3481 "called UpdateFontList on it"); |
|
3482 NS_ASSERTION(mFonts.Length() > uint32_t(i) && mFonts[i].Font(), |
|
3483 "Requesting a font index that doesn't exist"); |
|
3484 |
|
3485 return mFonts[i].Font(); |
|
3486 } |
|
3487 |
|
3488 uint32_t FontListLength() const { |
|
3489 return mFonts.Length(); |
|
3490 } |
|
3491 |
|
3492 bool Equals(const gfxFontGroup& other) const { |
|
3493 return mFamilies.Equals(other.mFamilies) && |
|
3494 mStyle.Equals(other.mStyle); |
|
3495 } |
|
3496 |
|
3497 const gfxFontStyle *GetStyle() const { return &mStyle; } |
|
3498 |
|
3499 virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle); |
|
3500 |
|
3501 /** |
|
3502 * The listed characters should be treated as invisible and zero-width |
|
3503 * when creating textruns. |
|
3504 */ |
|
3505 static bool IsInvalidChar(uint8_t ch); |
|
3506 static bool IsInvalidChar(char16_t ch); |
|
3507 |
|
3508 /** |
|
3509 * Make a textrun for a given string. |
|
3510 * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the |
|
3511 * textrun will copy it. |
|
3512 * This calls FetchGlyphExtents on the textrun. |
|
3513 */ |
|
3514 virtual gfxTextRun *MakeTextRun(const char16_t *aString, uint32_t aLength, |
|
3515 const Parameters *aParams, uint32_t aFlags); |
|
3516 /** |
|
3517 * Make a textrun for a given string. |
|
3518 * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the |
|
3519 * textrun will copy it. |
|
3520 * This calls FetchGlyphExtents on the textrun. |
|
3521 */ |
|
3522 virtual gfxTextRun *MakeTextRun(const uint8_t *aString, uint32_t aLength, |
|
3523 const Parameters *aParams, uint32_t aFlags); |
|
3524 |
|
3525 /** |
|
3526 * Textrun creation helper for clients that don't want to pass |
|
3527 * a full Parameters record. |
|
3528 */ |
|
3529 template<typename T> |
|
3530 gfxTextRun *MakeTextRun(const T *aString, uint32_t aLength, |
|
3531 gfxContext *aRefContext, |
|
3532 int32_t aAppUnitsPerDevUnit, |
|
3533 uint32_t aFlags) |
|
3534 { |
|
3535 gfxTextRunFactory::Parameters params = { |
|
3536 aRefContext, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit |
|
3537 }; |
|
3538 return MakeTextRun(aString, aLength, ¶ms, aFlags); |
|
3539 } |
|
3540 |
|
3541 /** |
|
3542 * Get the (possibly-cached) width of the hyphen character. |
|
3543 * The aCtx and aAppUnitsPerDevUnit parameters will be used only if |
|
3544 * needed to initialize the cached hyphen width; otherwise they are |
|
3545 * ignored. |
|
3546 */ |
|
3547 gfxFloat GetHyphenWidth(gfxTextRun::PropertyProvider* aProvider); |
|
3548 |
|
3549 /** |
|
3550 * Make a text run representing a single hyphen character. |
|
3551 * This will use U+2010 HYPHEN if available in the first font, |
|
3552 * otherwise fall back to U+002D HYPHEN-MINUS. |
|
3553 * The caller is responsible for deleting the returned text run |
|
3554 * when no longer required. |
|
3555 */ |
|
3556 gfxTextRun *MakeHyphenTextRun(gfxContext *aCtx, |
|
3557 uint32_t aAppUnitsPerDevUnit); |
|
3558 |
|
3559 /* helper function for splitting font families on commas and |
|
3560 * calling a function for each family to fill the mFonts array |
|
3561 */ |
|
3562 typedef bool (*FontCreationCallback) (const nsAString& aName, |
|
3563 const nsACString& aGenericName, |
|
3564 bool aUseFontSet, |
|
3565 void *closure); |
|
3566 bool ForEachFont(const nsAString& aFamilies, |
|
3567 nsIAtom *aLanguage, |
|
3568 FontCreationCallback fc, |
|
3569 void *closure); |
|
3570 bool ForEachFont(FontCreationCallback fc, void *closure); |
|
3571 |
|
3572 /** |
|
3573 * Check whether a given font (specified by its gfxFontEntry) |
|
3574 * is already in the fontgroup's list of actual fonts |
|
3575 */ |
|
3576 bool HasFont(const gfxFontEntry *aFontEntry); |
|
3577 |
|
3578 const nsString& GetFamilies() { return mFamilies; } |
|
3579 |
|
3580 // This returns the preferred underline for this font group. |
|
3581 // Some CJK fonts have wrong underline offset in its metrics. |
|
3582 // If this group has such "bad" font, each platform's gfxFontGroup initialized mUnderlineOffset. |
|
3583 // The value should be lower value of first font's metrics and the bad font's metrics. |
|
3584 // Otherwise, this returns from first font's metrics. |
|
3585 enum { UNDERLINE_OFFSET_NOT_SET = INT16_MAX }; |
|
3586 virtual gfxFloat GetUnderlineOffset() { |
|
3587 if (mUnderlineOffset == UNDERLINE_OFFSET_NOT_SET) |
|
3588 mUnderlineOffset = GetFontAt(0)->GetMetrics().underlineOffset; |
|
3589 return mUnderlineOffset; |
|
3590 } |
|
3591 |
|
3592 virtual already_AddRefed<gfxFont> |
|
3593 FindFontForChar(uint32_t ch, uint32_t prevCh, int32_t aRunScript, |
|
3594 gfxFont *aPrevMatchedFont, |
|
3595 uint8_t *aMatchType); |
|
3596 |
|
3597 // search through pref fonts for a character, return nullptr if no matching pref font |
|
3598 virtual already_AddRefed<gfxFont> WhichPrefFontSupportsChar(uint32_t aCh); |
|
3599 |
|
3600 virtual already_AddRefed<gfxFont> |
|
3601 WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript); |
|
3602 |
|
3603 template<typename T> |
|
3604 void ComputeRanges(nsTArray<gfxTextRange>& mRanges, |
|
3605 const T *aString, uint32_t aLength, |
|
3606 int32_t aRunScript); |
|
3607 |
|
3608 gfxUserFontSet* GetUserFontSet(); |
|
3609 |
|
3610 // With downloadable fonts, the composition of the font group can change as fonts are downloaded |
|
3611 // for each change in state of the user font set, the generation value is bumped to avoid picking up |
|
3612 // previously created text runs in the text run word cache. For font groups based on stylesheets |
|
3613 // with no @font-face rule, this always returns 0. |
|
3614 uint64_t GetGeneration(); |
|
3615 |
|
3616 // used when logging text performance |
|
3617 gfxTextPerfMetrics *GetTextPerfMetrics() { return mTextPerf; } |
|
3618 void SetTextPerfMetrics(gfxTextPerfMetrics *aTextPerf) { mTextPerf = aTextPerf; } |
|
3619 |
|
3620 // This will call UpdateFontList() if the user font set is changed. |
|
3621 void SetUserFontSet(gfxUserFontSet *aUserFontSet); |
|
3622 |
|
3623 // If there is a user font set, check to see whether the font list or any |
|
3624 // caches need updating. |
|
3625 virtual void UpdateFontList(); |
|
3626 |
|
3627 bool ShouldSkipDrawing() const { |
|
3628 return mSkipDrawing; |
|
3629 } |
|
3630 |
|
3631 class LazyReferenceContextGetter { |
|
3632 public: |
|
3633 virtual already_AddRefed<gfxContext> GetRefContext() = 0; |
|
3634 }; |
|
3635 // The gfxFontGroup keeps ownership of this textrun. |
|
3636 // It is only guaranteed to exist until the next call to GetEllipsisTextRun |
|
3637 // (which might use a different appUnitsPerDev value) for the font group, |
|
3638 // or until UpdateFontList is called, or the fontgroup is destroyed. |
|
3639 // Get it/use it/forget it :) - don't keep a reference that might go stale. |
|
3640 gfxTextRun* GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel, |
|
3641 LazyReferenceContextGetter& aRefContextGetter); |
|
3642 |
|
3643 protected: |
|
3644 nsString mFamilies; |
|
3645 gfxFontStyle mStyle; |
|
3646 nsTArray<FamilyFace> mFonts; |
|
3647 gfxFloat mUnderlineOffset; |
|
3648 gfxFloat mHyphenWidth; |
|
3649 |
|
3650 nsRefPtr<gfxUserFontSet> mUserFontSet; |
|
3651 uint64_t mCurrGeneration; // track the current user font set generation, rebuild font list if needed |
|
3652 |
|
3653 gfxTextPerfMetrics *mTextPerf; |
|
3654 |
|
3655 // Cache a textrun representing an ellipsis (useful for CSS text-overflow) |
|
3656 // at a specific appUnitsPerDevPixel size |
|
3657 nsAutoPtr<gfxTextRun> mCachedEllipsisTextRun; |
|
3658 |
|
3659 // cache the most recent pref font to avoid general pref font lookup |
|
3660 nsRefPtr<gfxFontFamily> mLastPrefFamily; |
|
3661 nsRefPtr<gfxFont> mLastPrefFont; |
|
3662 eFontPrefLang mLastPrefLang; // lang group for last pref font |
|
3663 eFontPrefLang mPageLang; |
|
3664 bool mLastPrefFirstFont; // is this the first font in the list of pref fonts for this lang group? |
|
3665 |
|
3666 bool mSkipDrawing; // hide text while waiting for a font |
|
3667 // download to complete (or fallback |
|
3668 // timer to fire) |
|
3669 |
|
3670 /** |
|
3671 * Textrun creation short-cuts for special cases where we don't need to |
|
3672 * call a font shaper to generate glyphs. |
|
3673 */ |
|
3674 gfxTextRun *MakeEmptyTextRun(const Parameters *aParams, uint32_t aFlags); |
|
3675 gfxTextRun *MakeSpaceTextRun(const Parameters *aParams, uint32_t aFlags); |
|
3676 gfxTextRun *MakeBlankTextRun(uint32_t aLength, |
|
3677 const Parameters *aParams, uint32_t aFlags); |
|
3678 |
|
3679 // Initialize the list of fonts |
|
3680 void BuildFontList(); |
|
3681 |
|
3682 // Init this font group's font metrics. If there no bad fonts, you don't need to call this. |
|
3683 // But if there are one or more bad fonts which have bad underline offset, |
|
3684 // you should call this with the *first* bad font. |
|
3685 void InitMetricsForBadFont(gfxFont* aBadFont); |
|
3686 |
|
3687 // Set up the textrun glyphs for an entire text run: |
|
3688 // find script runs, and then call InitScriptRun for each |
|
3689 template<typename T> |
|
3690 void InitTextRun(gfxContext *aContext, |
|
3691 gfxTextRun *aTextRun, |
|
3692 const T *aString, |
|
3693 uint32_t aLength); |
|
3694 |
|
3695 // InitTextRun helper to handle a single script run, by finding font ranges |
|
3696 // and calling each font's InitTextRun() as appropriate |
|
3697 template<typename T> |
|
3698 void InitScriptRun(gfxContext *aContext, |
|
3699 gfxTextRun *aTextRun, |
|
3700 const T *aString, |
|
3701 uint32_t aScriptRunStart, |
|
3702 uint32_t aScriptRunEnd, |
|
3703 int32_t aRunScript); |
|
3704 |
|
3705 /* If aResolveGeneric is true, then CSS/Gecko generic family names are |
|
3706 * replaced with preferred fonts. |
|
3707 * |
|
3708 * If aResolveFontName is true then fc() is called only for existing fonts |
|
3709 * and with actual font names. If false then fc() is called with each |
|
3710 * family name in aFamilies (after resolving CSS/Gecko generic family names |
|
3711 * if aResolveGeneric). |
|
3712 * If aUseFontSet is true, the fontgroup's user font set is checked; |
|
3713 * if false then it is skipped. |
|
3714 */ |
|
3715 bool ForEachFontInternal(const nsAString& aFamilies, |
|
3716 nsIAtom *aLanguage, |
|
3717 bool aResolveGeneric, |
|
3718 bool aResolveFontName, |
|
3719 bool aUseFontSet, |
|
3720 FontCreationCallback fc, |
|
3721 void *closure); |
|
3722 |
|
3723 // Helper for font-matching: |
|
3724 // see if aCh is supported in any of the faces from aFamily; |
|
3725 // if so return the best style match, else return null. |
|
3726 already_AddRefed<gfxFont> TryAllFamilyMembers(gfxFontFamily* aFamily, |
|
3727 uint32_t aCh); |
|
3728 |
|
3729 static bool FontResolverProc(const nsAString& aName, void *aClosure); |
|
3730 |
|
3731 static bool FindPlatformFont(const nsAString& aName, |
|
3732 const nsACString& aGenericName, |
|
3733 bool aUseFontSet, |
|
3734 void *closure); |
|
3735 |
|
3736 static NS_HIDDEN_(nsILanguageAtomService*) gLangService; |
|
3737 }; |
|
3738 #endif |