gfx/thebes/gfxFont.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:57bad8b508df
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(&current, 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, &params, 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

mercurial