1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxFont.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,3738 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef GFX_FONT_H 1.10 +#define GFX_FONT_H 1.11 + 1.12 +#include "gfxTypes.h" 1.13 +#include "nsString.h" 1.14 +#include "gfxPoint.h" 1.15 +#include "gfxFontUtils.h" 1.16 +#include "nsTArray.h" 1.17 +#include "nsTHashtable.h" 1.18 +#include "nsHashKeys.h" 1.19 +#include "gfxSkipChars.h" 1.20 +#include "gfxRect.h" 1.21 +#include "nsExpirationTracker.h" 1.22 +#include "gfxPlatform.h" 1.23 +#include "nsIAtom.h" 1.24 +#include "mozilla/HashFunctions.h" 1.25 +#include "nsIMemoryReporter.h" 1.26 +#include "nsIObserver.h" 1.27 +#include "gfxFontFeatures.h" 1.28 +#include "mozilla/MemoryReporting.h" 1.29 +#include "mozilla/Attributes.h" 1.30 +#include <algorithm> 1.31 +#include "DrawMode.h" 1.32 +#include "nsUnicodeScriptCodes.h" 1.33 +#include "nsDataHashtable.h" 1.34 +#include "harfbuzz/hb.h" 1.35 +#include "mozilla/gfx/2D.h" 1.36 + 1.37 +typedef struct _cairo_scaled_font cairo_scaled_font_t; 1.38 +typedef struct gr_face gr_face; 1.39 + 1.40 +#ifdef DEBUG 1.41 +#include <stdio.h> 1.42 +#endif 1.43 + 1.44 +class gfxContext; 1.45 +class gfxTextRun; 1.46 +class gfxFont; 1.47 +class gfxFontFamily; 1.48 +class gfxFontGroup; 1.49 +class gfxGraphiteShaper; 1.50 +class gfxHarfBuzzShaper; 1.51 +class gfxUserFontSet; 1.52 +class gfxUserFontData; 1.53 +class gfxShapedText; 1.54 +class gfxShapedWord; 1.55 +class gfxSVGGlyphs; 1.56 +class gfxMathTable; 1.57 +class gfxTextContextPaint; 1.58 +class FontInfoData; 1.59 + 1.60 +class nsILanguageAtomService; 1.61 + 1.62 +#define FONT_MAX_SIZE 2000.0 1.63 + 1.64 +#define NO_FONT_LANGUAGE_OVERRIDE 0 1.65 + 1.66 +struct FontListSizes; 1.67 +struct gfxTextRunDrawCallbacks; 1.68 + 1.69 +namespace mozilla { 1.70 +namespace gfx { 1.71 +class GlyphRenderingOptions; 1.72 +} 1.73 +} 1.74 + 1.75 +struct gfxFontStyle { 1.76 + gfxFontStyle(); 1.77 + gfxFontStyle(uint8_t aStyle, uint16_t aWeight, int16_t aStretch, 1.78 + gfxFloat aSize, nsIAtom *aLanguage, 1.79 + float aSizeAdjust, bool aSystemFont, 1.80 + bool aPrinterFont, 1.81 + const nsString& aLanguageOverride); 1.82 + gfxFontStyle(const gfxFontStyle& aStyle); 1.83 + 1.84 + // the language (may be an internal langGroup code rather than an actual 1.85 + // language code) specified in the document or element's lang property, 1.86 + // or inferred from the charset 1.87 + nsRefPtr<nsIAtom> language; 1.88 + 1.89 + // Features are composed of (1) features from style rules (2) features 1.90 + // from feature setttings rules and (3) family-specific features. (1) and 1.91 + // (3) are guaranteed to be mutually exclusive 1.92 + 1.93 + // custom opentype feature settings 1.94 + nsTArray<gfxFontFeature> featureSettings; 1.95 + 1.96 + // Some font-variant property values require font-specific settings 1.97 + // defined via @font-feature-values rules. These are resolved after 1.98 + // font matching occurs. 1.99 + 1.100 + // -- list of value tags for specific alternate features 1.101 + nsTArray<gfxAlternateValue> alternateValues; 1.102 + 1.103 + // -- object used to look these up once the font is matched 1.104 + nsRefPtr<gfxFontFeatureValueSet> featureValueLookup; 1.105 + 1.106 + // The logical size of the font, in pixels 1.107 + gfxFloat size; 1.108 + 1.109 + // The aspect-value (ie., the ratio actualsize:actualxheight) that any 1.110 + // actual physical font created from this font structure must have when 1.111 + // rendering or measuring a string. A value of 0 means no adjustment 1.112 + // needs to be done. 1.113 + float sizeAdjust; 1.114 + 1.115 + // Language system tag, to override document language; 1.116 + // an OpenType "language system" tag represented as a 32-bit integer 1.117 + // (see http://www.microsoft.com/typography/otspec/languagetags.htm). 1.118 + // Normally 0, so font rendering will use the document or element language 1.119 + // (see above) to control any language-specific rendering, but the author 1.120 + // can override this for cases where the options implemented in the font 1.121 + // do not directly match the actual language. (E.g. lang may be Macedonian, 1.122 + // but the font in use does not explicitly support this; the author can 1.123 + // use font-language-override to request the Serbian option in the font 1.124 + // in order to get correct glyph shapes.) 1.125 + uint32_t languageOverride; 1.126 + 1.127 + // The weight of the font: 100, 200, ... 900. 1.128 + uint16_t weight; 1.129 + 1.130 + // The stretch of the font (the sum of various NS_FONT_STRETCH_* 1.131 + // constants; see gfxFontConstants.h). 1.132 + int8_t stretch; 1.133 + 1.134 + // Say that this font is a system font and therefore does not 1.135 + // require certain fixup that we do for fonts from untrusted 1.136 + // sources. 1.137 + bool systemFont : 1; 1.138 + 1.139 + // Say that this font is used for print or print preview. 1.140 + bool printerFont : 1; 1.141 + 1.142 + // Used to imitate -webkit-font-smoothing: antialiased 1.143 + bool useGrayscaleAntialiasing : 1; 1.144 + 1.145 + // The style of font (normal, italic, oblique) 1.146 + uint8_t style : 2; 1.147 + 1.148 + // Return the final adjusted font size for the given aspect ratio. 1.149 + // Not meant to be called when sizeAdjust = 0. 1.150 + gfxFloat GetAdjustedSize(gfxFloat aspect) const { 1.151 + NS_ASSERTION(sizeAdjust != 0.0, "Not meant to be called when sizeAdjust = 0"); 1.152 + gfxFloat adjustedSize = std::max(NS_round(size*(sizeAdjust/aspect)), 1.0); 1.153 + return std::min(adjustedSize, FONT_MAX_SIZE); 1.154 + } 1.155 + 1.156 + PLDHashNumber Hash() const { 1.157 + return ((style + (systemFont << 7) + 1.158 + (weight << 8)) + uint32_t(size*1000) + uint32_t(sizeAdjust*1000)) ^ 1.159 + nsISupportsHashKey::HashKey(language); 1.160 + } 1.161 + 1.162 + int8_t ComputeWeight() const; 1.163 + 1.164 + bool Equals(const gfxFontStyle& other) const { 1.165 + return 1.166 + (*reinterpret_cast<const uint64_t*>(&size) == 1.167 + *reinterpret_cast<const uint64_t*>(&other.size)) && 1.168 + (style == other.style) && 1.169 + (systemFont == other.systemFont) && 1.170 + (printerFont == other.printerFont) && 1.171 + (useGrayscaleAntialiasing == other.useGrayscaleAntialiasing) && 1.172 + (weight == other.weight) && 1.173 + (stretch == other.stretch) && 1.174 + (language == other.language) && 1.175 + (*reinterpret_cast<const uint32_t*>(&sizeAdjust) == 1.176 + *reinterpret_cast<const uint32_t*>(&other.sizeAdjust)) && 1.177 + (featureSettings == other.featureSettings) && 1.178 + (languageOverride == other.languageOverride) && 1.179 + (alternateValues == other.alternateValues) && 1.180 + (featureValueLookup == other.featureValueLookup); 1.181 + } 1.182 + 1.183 + static void ParseFontFeatureSettings(const nsString& aFeatureString, 1.184 + nsTArray<gfxFontFeature>& aFeatures); 1.185 + 1.186 + static uint32_t ParseFontLanguageOverride(const nsString& aLangTag); 1.187 +}; 1.188 + 1.189 +class gfxCharacterMap : public gfxSparseBitSet { 1.190 +public: 1.191 + nsrefcnt AddRef() { 1.192 + NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt"); 1.193 + ++mRefCnt; 1.194 + NS_LOG_ADDREF(this, mRefCnt, "gfxCharacterMap", sizeof(*this)); 1.195 + return mRefCnt; 1.196 + } 1.197 + 1.198 + nsrefcnt Release() { 1.199 + NS_PRECONDITION(0 != mRefCnt, "dup release"); 1.200 + --mRefCnt; 1.201 + NS_LOG_RELEASE(this, mRefCnt, "gfxCharacterMap"); 1.202 + if (mRefCnt == 0) { 1.203 + NotifyReleased(); 1.204 + // |this| has been deleted. 1.205 + return 0; 1.206 + } 1.207 + return mRefCnt; 1.208 + } 1.209 + 1.210 + gfxCharacterMap() : 1.211 + mHash(0), mBuildOnTheFly(false), mShared(false) 1.212 + { } 1.213 + 1.214 + void CalcHash() { mHash = GetChecksum(); } 1.215 + 1.216 + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { 1.217 + return gfxSparseBitSet::SizeOfExcludingThis(aMallocSizeOf); 1.218 + } 1.219 + 1.220 + // hash of the cmap bitvector 1.221 + uint32_t mHash; 1.222 + 1.223 + // if cmap is built on the fly it's never shared 1.224 + bool mBuildOnTheFly; 1.225 + 1.226 + // cmap is shared globally 1.227 + bool mShared; 1.228 + 1.229 +protected: 1.230 + void NotifyReleased(); 1.231 + 1.232 + nsAutoRefCnt mRefCnt; 1.233 + 1.234 +private: 1.235 + gfxCharacterMap(const gfxCharacterMap&); 1.236 + gfxCharacterMap& operator=(const gfxCharacterMap&); 1.237 +}; 1.238 + 1.239 +class gfxFontEntry { 1.240 +public: 1.241 + NS_INLINE_DECL_REFCOUNTING(gfxFontEntry) 1.242 + 1.243 + gfxFontEntry(const nsAString& aName, bool aIsStandardFace = false); 1.244 + 1.245 + // unique name for the face, *not* the family; not necessarily the 1.246 + // "real" or user-friendly name, may be an internal identifier 1.247 + const nsString& Name() const { return mName; } 1.248 + 1.249 + // family name 1.250 + const nsString& FamilyName() const { return mFamilyName; } 1.251 + 1.252 + // The following two methods may be relatively expensive, as they 1.253 + // will (usually, except on Linux) load and parse the 'name' table; 1.254 + // they are intended only for the font-inspection API, not for 1.255 + // perf-critical layout/drawing work. 1.256 + 1.257 + // The "real" name of the face, if available from the font resource; 1.258 + // returns Name() if nothing better is available. 1.259 + virtual nsString RealFaceName(); 1.260 + 1.261 + uint16_t Weight() const { return mWeight; } 1.262 + int16_t Stretch() const { return mStretch; } 1.263 + 1.264 + bool IsUserFont() const { return mIsUserFont; } 1.265 + bool IsLocalUserFont() const { return mIsLocalUserFont; } 1.266 + bool IsFixedPitch() const { return mFixedPitch; } 1.267 + bool IsItalic() const { return mItalic; } 1.268 + bool IsBold() const { return mWeight >= 600; } // bold == weights 600 and above 1.269 + bool IgnoreGDEF() const { return mIgnoreGDEF; } 1.270 + bool IgnoreGSUB() const { return mIgnoreGSUB; } 1.271 + 1.272 + virtual bool IsSymbolFont(); 1.273 + 1.274 + virtual bool HasFontTable(uint32_t aTableTag); 1.275 + 1.276 + inline bool HasGraphiteTables() { 1.277 + if (!mCheckedForGraphiteTables) { 1.278 + CheckForGraphiteTables(); 1.279 + mCheckedForGraphiteTables = true; 1.280 + } 1.281 + return mHasGraphiteTables; 1.282 + } 1.283 + 1.284 + inline bool HasCmapTable() { 1.285 + if (!mCharacterMap) { 1.286 + ReadCMAP(); 1.287 + NS_ASSERTION(mCharacterMap, "failed to initialize character map"); 1.288 + } 1.289 + return mHasCmapTable; 1.290 + } 1.291 + 1.292 + inline bool HasCharacter(uint32_t ch) { 1.293 + if (mCharacterMap && mCharacterMap->test(ch)) { 1.294 + return true; 1.295 + } 1.296 + return TestCharacterMap(ch); 1.297 + } 1.298 + 1.299 + virtual bool SkipDuringSystemFallback() { return false; } 1.300 + virtual bool TestCharacterMap(uint32_t aCh); 1.301 + nsresult InitializeUVSMap(); 1.302 + uint16_t GetUVSGlyph(uint32_t aCh, uint32_t aVS); 1.303 + 1.304 + // All concrete gfxFontEntry subclasses (except gfxProxyFontEntry) need 1.305 + // to override this, otherwise the font will never be used as it will 1.306 + // be considered to support no characters. 1.307 + // ReadCMAP() must *always* set the mCharacterMap pointer to a valid 1.308 + // gfxCharacterMap, even if empty, as other code assumes this pointer 1.309 + // can be safely dereferenced. 1.310 + virtual nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr); 1.311 + 1.312 + bool TryGetSVGData(gfxFont* aFont); 1.313 + bool HasSVGGlyph(uint32_t aGlyphId); 1.314 + bool GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId, 1.315 + gfxRect *aResult); 1.316 + bool RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId, int aDrawMode, 1.317 + gfxTextContextPaint *aContextPaint); 1.318 + // Call this when glyph geometry or rendering has changed 1.319 + // (e.g. animated SVG glyphs) 1.320 + void NotifyGlyphsChanged(); 1.321 + 1.322 + enum MathConstant { 1.323 + // The order of the constants must match the order of the fields 1.324 + // defined in the MATH table. 1.325 + ScriptPercentScaleDown, 1.326 + ScriptScriptPercentScaleDown, 1.327 + DelimitedSubFormulaMinHeight, 1.328 + DisplayOperatorMinHeight, 1.329 + MathLeading, 1.330 + AxisHeight, 1.331 + AccentBaseHeight, 1.332 + FlattenedAccentBaseHeight, 1.333 + SubscriptShiftDown, 1.334 + SubscriptTopMax, 1.335 + SubscriptBaselineDropMin, 1.336 + SuperscriptShiftUp, 1.337 + SuperscriptShiftUpCramped, 1.338 + SuperscriptBottomMin, 1.339 + SuperscriptBaselineDropMax, 1.340 + SubSuperscriptGapMin, 1.341 + SuperscriptBottomMaxWithSubscript, 1.342 + SpaceAfterScript, 1.343 + UpperLimitGapMin, 1.344 + UpperLimitBaselineRiseMin, 1.345 + LowerLimitGapMin, 1.346 + LowerLimitBaselineDropMin, 1.347 + StackTopShiftUp, 1.348 + StackTopDisplayStyleShiftUp, 1.349 + StackBottomShiftDown, 1.350 + StackBottomDisplayStyleShiftDown, 1.351 + StackGapMin, 1.352 + StackDisplayStyleGapMin, 1.353 + StretchStackTopShiftUp, 1.354 + StretchStackBottomShiftDown, 1.355 + StretchStackGapAboveMin, 1.356 + StretchStackGapBelowMin, 1.357 + FractionNumeratorShiftUp, 1.358 + FractionNumeratorDisplayStyleShiftUp, 1.359 + FractionDenominatorShiftDown, 1.360 + FractionDenominatorDisplayStyleShiftDown, 1.361 + FractionNumeratorGapMin, 1.362 + FractionNumDisplayStyleGapMin, 1.363 + FractionRuleThickness, 1.364 + FractionDenominatorGapMin, 1.365 + FractionDenomDisplayStyleGapMin, 1.366 + SkewedFractionHorizontalGap, 1.367 + SkewedFractionVerticalGap, 1.368 + OverbarVerticalGap, 1.369 + OverbarRuleThickness, 1.370 + OverbarExtraAscender, 1.371 + UnderbarVerticalGap, 1.372 + UnderbarRuleThickness, 1.373 + UnderbarExtraDescender, 1.374 + RadicalVerticalGap, 1.375 + RadicalDisplayStyleVerticalGap, 1.376 + RadicalRuleThickness, 1.377 + RadicalExtraAscender, 1.378 + RadicalKernBeforeDegree, 1.379 + RadicalKernAfterDegree, 1.380 + RadicalDegreeBottomRaisePercent 1.381 + }; 1.382 + 1.383 + // Call TryGetMathTable to try to load the Open Type MATH table. The other 1.384 + // functions forward the call to the gfxMathTable class. The GetMath...() 1.385 + // functions MUST NOT be called unless TryGetMathTable() has returned true. 1.386 + bool TryGetMathTable(gfxFont* aFont); 1.387 + gfxFloat GetMathConstant(MathConstant aConstant); 1.388 + bool GetMathItalicsCorrection(uint32_t aGlyphID, 1.389 + gfxFloat* aItalicCorrection); 1.390 + uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical, 1.391 + uint16_t aSize); 1.392 + bool GetMathVariantsParts(uint32_t aGlyphID, bool aVertical, 1.393 + uint32_t aGlyphs[4]); 1.394 + 1.395 + virtual bool MatchesGenericFamily(const nsACString& aGeneric) const { 1.396 + return true; 1.397 + } 1.398 + virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const { 1.399 + return true; 1.400 + } 1.401 + 1.402 + // Access to raw font table data (needed for Harfbuzz): 1.403 + // returns a pointer to data owned by the fontEntry or the OS, 1.404 + // which will remain valid until the blob is destroyed. 1.405 + // The data MUST be treated as read-only; we may be getting a 1.406 + // reference to a shared system font cache. 1.407 + // 1.408 + // The default implementation uses CopyFontTable to get the data 1.409 + // into a byte array, and maintains a cache of loaded tables. 1.410 + // 1.411 + // Subclasses should override this if they can provide more efficient 1.412 + // access than copying table data into our own buffers. 1.413 + // 1.414 + // Get blob that encapsulates a specific font table, or nullptr if 1.415 + // the table doesn't exist in the font. 1.416 + // 1.417 + // Caller is responsible to call hb_blob_destroy() on the returned blob 1.418 + // (if non-nullptr) when no longer required. For transient access to a 1.419 + // table, use of AutoTable (below) is generally preferred. 1.420 + virtual hb_blob_t *GetFontTable(uint32_t aTag); 1.421 + 1.422 + // Stack-based utility to return a specified table, automatically releasing 1.423 + // the blob when the AutoTable goes out of scope. 1.424 + class AutoTable { 1.425 + public: 1.426 + AutoTable(gfxFontEntry* aFontEntry, uint32_t aTag) 1.427 + { 1.428 + mBlob = aFontEntry->GetFontTable(aTag); 1.429 + } 1.430 + ~AutoTable() { 1.431 + if (mBlob) { 1.432 + hb_blob_destroy(mBlob); 1.433 + } 1.434 + } 1.435 + operator hb_blob_t*() const { return mBlob; } 1.436 + private: 1.437 + hb_blob_t* mBlob; 1.438 + // not implemented: 1.439 + AutoTable(const AutoTable&) MOZ_DELETE; 1.440 + AutoTable& operator=(const AutoTable&) MOZ_DELETE; 1.441 + }; 1.442 + 1.443 + already_AddRefed<gfxFont> FindOrMakeFont(const gfxFontStyle *aStyle, 1.444 + bool aNeedsBold); 1.445 + 1.446 + // Get an existing font table cache entry in aBlob if it has been 1.447 + // registered, or return false if not. Callers must call 1.448 + // hb_blob_destroy on aBlob if true is returned. 1.449 + // 1.450 + // Note that some gfxFont implementations may not call this at all, 1.451 + // if it is more efficient to get the table from the OS at that level. 1.452 + bool GetExistingFontTable(uint32_t aTag, hb_blob_t** aBlob); 1.453 + 1.454 + // Elements of aTable are transferred (not copied) to and returned in a 1.455 + // new hb_blob_t which is registered on the gfxFontEntry, but the initial 1.456 + // reference is owned by the caller. Removing the last reference 1.457 + // unregisters the table from the font entry. 1.458 + // 1.459 + // Pass nullptr for aBuffer to indicate that the table is not present and 1.460 + // nullptr will be returned. Also returns nullptr on OOM. 1.461 + hb_blob_t *ShareFontTableAndGetBlob(uint32_t aTag, 1.462 + FallibleTArray<uint8_t>* aTable); 1.463 + 1.464 + // Get the font's unitsPerEm from the 'head' table, in the case of an 1.465 + // sfnt resource. Will return kInvalidUPEM for non-sfnt fonts, 1.466 + // if present on the platform. 1.467 + uint16_t UnitsPerEm(); 1.468 + enum { 1.469 + kMinUPEM = 16, // Limits on valid unitsPerEm range, from the 1.470 + kMaxUPEM = 16384, // OpenType spec 1.471 + kInvalidUPEM = uint16_t(-1) 1.472 + }; 1.473 + 1.474 + // Shaper face accessors: 1.475 + // NOTE that harfbuzz and graphite handle ownership/lifetime of the face 1.476 + // object in completely different ways. 1.477 + 1.478 + // Get HarfBuzz face corresponding to this font file. 1.479 + // Caller must release with hb_face_destroy() when finished with it, 1.480 + // and the font entry will be notified via ForgetHBFace. 1.481 + hb_face_t* GetHBFace(); 1.482 + virtual void ForgetHBFace(); 1.483 + 1.484 + // Get Graphite face corresponding to this font file. 1.485 + // Caller must call gfxFontEntry::ReleaseGrFace when finished with it. 1.486 + gr_face* GetGrFace(); 1.487 + virtual void ReleaseGrFace(gr_face* aFace); 1.488 + 1.489 + // Release any SVG-glyphs document this font may have loaded. 1.490 + void DisconnectSVG(); 1.491 + 1.492 + // Called to notify that aFont is being destroyed. Needed when we're tracking 1.493 + // the fonts belonging to this font entry. 1.494 + void NotifyFontDestroyed(gfxFont* aFont); 1.495 + 1.496 + // For memory reporting 1.497 + virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.498 + FontListSizes* aSizes) const; 1.499 + virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.500 + FontListSizes* aSizes) const; 1.501 + 1.502 + // Used when checking for complex script support, to mask off cmap ranges 1.503 + struct ScriptRange { 1.504 + uint32_t rangeStart; 1.505 + uint32_t rangeEnd; 1.506 + hb_tag_t tags[3]; // one or two OpenType script tags to check, 1.507 + // plus a NULL terminator 1.508 + }; 1.509 + 1.510 + bool SupportsScriptInGSUB(const hb_tag_t* aScriptTags); 1.511 + 1.512 + nsString mName; 1.513 + nsString mFamilyName; 1.514 + 1.515 + bool mItalic : 1; 1.516 + bool mFixedPitch : 1; 1.517 + bool mIsProxy : 1; 1.518 + bool mIsValid : 1; 1.519 + bool mIsBadUnderlineFont : 1; 1.520 + bool mIsUserFont : 1; 1.521 + bool mIsLocalUserFont : 1; 1.522 + bool mStandardFace : 1; 1.523 + bool mSymbolFont : 1; 1.524 + bool mIgnoreGDEF : 1; 1.525 + bool mIgnoreGSUB : 1; 1.526 + bool mSVGInitialized : 1; 1.527 + bool mMathInitialized : 1; 1.528 + bool mHasSpaceFeaturesInitialized : 1; 1.529 + bool mHasSpaceFeatures : 1; 1.530 + bool mHasSpaceFeaturesKerning : 1; 1.531 + bool mHasSpaceFeaturesNonKerning : 1; 1.532 + bool mSkipDefaultFeatureSpaceCheck : 1; 1.533 + bool mHasGraphiteTables : 1; 1.534 + bool mCheckedForGraphiteTables : 1; 1.535 + bool mHasCmapTable : 1; 1.536 + bool mGrFaceInitialized : 1; 1.537 + 1.538 + // bitvector of substitution space features per script, one each 1.539 + // for default and non-default features 1.540 + uint32_t mDefaultSubSpaceFeatures[(MOZ_NUM_SCRIPT_CODES + 31) / 32]; 1.541 + uint32_t mNonDefaultSubSpaceFeatures[(MOZ_NUM_SCRIPT_CODES + 31) / 32]; 1.542 + 1.543 + uint16_t mWeight; 1.544 + int16_t mStretch; 1.545 + 1.546 + nsRefPtr<gfxCharacterMap> mCharacterMap; 1.547 + uint32_t mUVSOffset; 1.548 + nsAutoArrayPtr<uint8_t> mUVSData; 1.549 + nsAutoPtr<gfxUserFontData> mUserFontData; 1.550 + nsAutoPtr<gfxSVGGlyphs> mSVGGlyphs; 1.551 + // list of gfxFonts that are using SVG glyphs 1.552 + nsTArray<gfxFont*> mFontsUsingSVGGlyphs; 1.553 + nsAutoPtr<gfxMathTable> mMathTable; 1.554 + nsTArray<gfxFontFeature> mFeatureSettings; 1.555 + uint32_t mLanguageOverride; 1.556 + 1.557 +protected: 1.558 + friend class gfxPlatformFontList; 1.559 + friend class gfxMacPlatformFontList; 1.560 + friend class gfxUserFcFontEntry; 1.561 + friend class gfxFontFamily; 1.562 + friend class gfxSingleFaceMacFontFamily; 1.563 + 1.564 + gfxFontEntry(); 1.565 + 1.566 + // Protected destructor, to discourage deletion outside of Release(): 1.567 + virtual ~gfxFontEntry(); 1.568 + 1.569 + virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold) { 1.570 + NS_NOTREACHED("oops, somebody didn't override CreateFontInstance"); 1.571 + return nullptr; 1.572 + } 1.573 + 1.574 + virtual void CheckForGraphiteTables(); 1.575 + 1.576 + // Copy a font table into aBuffer. 1.577 + // The caller will be responsible for ownership of the data. 1.578 + virtual nsresult CopyFontTable(uint32_t aTableTag, 1.579 + FallibleTArray<uint8_t>& aBuffer) { 1.580 + NS_NOTREACHED("forgot to override either GetFontTable or CopyFontTable?"); 1.581 + return NS_ERROR_FAILURE; 1.582 + } 1.583 + 1.584 + // Return a blob that wraps a table found within a buffer of font data. 1.585 + // The blob does NOT own its data; caller guarantees that the buffer 1.586 + // will remain valid at least as long as the blob. 1.587 + // Returns null if the specified table is not found. 1.588 + // This method assumes aFontData is valid 'sfnt' data; before using this, 1.589 + // caller is responsible to do any sanitization/validation necessary. 1.590 + hb_blob_t* GetTableFromFontData(const void* aFontData, uint32_t aTableTag); 1.591 + 1.592 + // lookup the cmap in cached font data 1.593 + virtual already_AddRefed<gfxCharacterMap> 1.594 + GetCMAPFromFontInfo(FontInfoData *aFontInfoData, 1.595 + uint32_t& aUVSOffset, 1.596 + bool& aSymbolFont); 1.597 + 1.598 + // Font's unitsPerEm from the 'head' table, if available (will be set to 1.599 + // kInvalidUPEM for non-sfnt font formats) 1.600 + uint16_t mUnitsPerEm; 1.601 + 1.602 + // Shaper-specific face objects, shared by all instantiations of the same 1.603 + // physical font, regardless of size. 1.604 + // Usually, only one of these will actually be created for any given font 1.605 + // entry, depending on the font tables that are present. 1.606 + 1.607 + // hb_face_t is refcounted internally, so each shaper that's using it will 1.608 + // bump the ref count when it acquires the face, and "destroy" (release) it 1.609 + // in its destructor. The font entry has only this non-owning reference to 1.610 + // the face; when the face is deleted, it will tell the font entry to forget 1.611 + // it, so that a new face will be created next time it is needed. 1.612 + hb_face_t* mHBFace; 1.613 + 1.614 + static hb_blob_t* HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData); 1.615 + 1.616 + // Callback that the hb_face will use to tell us when it is being deleted. 1.617 + static void HBFaceDeletedCallback(void *aUserData); 1.618 + 1.619 + // gr_face is -not- refcounted, so it will be owned directly by the font 1.620 + // entry, and we'll keep a count of how many references we've handed out; 1.621 + // each shaper is responsible to call ReleaseGrFace on its entry when 1.622 + // finished with it, so that we know when it can be deleted. 1.623 + gr_face* mGrFace; 1.624 + 1.625 + // hashtable to map raw table data ptr back to its owning blob, for use by 1.626 + // graphite table-release callback 1.627 + nsDataHashtable<nsPtrHashKey<const void>,void*>* mGrTableMap; 1.628 + 1.629 + // number of current users of this entry's mGrFace 1.630 + nsrefcnt mGrFaceRefCnt; 1.631 + 1.632 + static const void* GrGetTable(const void *aAppFaceHandle, 1.633 + unsigned int aName, 1.634 + size_t *aLen); 1.635 + static void GrReleaseTable(const void *aAppFaceHandle, 1.636 + const void *aTableBuffer); 1.637 + 1.638 +private: 1.639 + /** 1.640 + * Font table hashtable, to support GetFontTable for harfbuzz. 1.641 + * 1.642 + * The harfbuzz shaper (and potentially other clients) needs access to raw 1.643 + * font table data. This needs to be cached so that it can be used 1.644 + * repeatedly (each time we construct a text run; in some cases, for 1.645 + * each character/glyph within the run) without re-fetching large tables 1.646 + * every time. 1.647 + * 1.648 + * Because we may instantiate many gfxFonts for the same physical font 1.649 + * file (at different sizes), we should ensure that they can share a 1.650 + * single cached copy of the font tables. To do this, we implement table 1.651 + * access and sharing on the fontEntry rather than the font itself. 1.652 + * 1.653 + * The default implementation uses GetFontTable() to read font table 1.654 + * data into byte arrays, and wraps them in blobs which are registered in 1.655 + * a hashtable. The hashtable can then return pre-existing blobs to 1.656 + * harfbuzz. 1.657 + * 1.658 + * Harfbuzz will "destroy" the blobs when it is finished with them. When 1.659 + * the last blob reference is removed, the FontTableBlobData user data 1.660 + * will remove the blob from the hashtable if still registered. 1.661 + */ 1.662 + 1.663 + class FontTableBlobData; 1.664 + 1.665 + /** 1.666 + * FontTableHashEntry manages the entries of hb_blob_t's containing font 1.667 + * table data. 1.668 + * 1.669 + * This is used to share font tables across fonts with the same 1.670 + * font entry (but different sizes) for use by HarfBuzz. The hashtable 1.671 + * does not own a strong reference to the blob, but keeps a weak pointer, 1.672 + * managed by FontTableBlobData. Similarly FontTableBlobData keeps only a 1.673 + * weak pointer to the hashtable, managed by FontTableHashEntry. 1.674 + */ 1.675 + 1.676 + class FontTableHashEntry : public nsUint32HashKey 1.677 + { 1.678 + public: 1.679 + // Declarations for nsTHashtable 1.680 + 1.681 + typedef nsUint32HashKey KeyClass; 1.682 + typedef KeyClass::KeyType KeyType; 1.683 + typedef KeyClass::KeyTypePointer KeyTypePointer; 1.684 + 1.685 + FontTableHashEntry(KeyTypePointer aTag) 1.686 + : KeyClass(aTag) 1.687 + , mSharedBlobData(nullptr) 1.688 + , mBlob(nullptr) 1.689 + { } 1.690 + 1.691 + // NOTE: This assumes the new entry belongs to the same hashtable as 1.692 + // the old, because the mHashtable pointer in mSharedBlobData (if 1.693 + // present) will not be updated. 1.694 + FontTableHashEntry(FontTableHashEntry&& toMove) 1.695 + : KeyClass(mozilla::Move(toMove)) 1.696 + , mSharedBlobData(mozilla::Move(toMove.mSharedBlobData)) 1.697 + , mBlob(mozilla::Move(toMove.mBlob)) 1.698 + { 1.699 + toMove.mSharedBlobData = nullptr; 1.700 + toMove.mBlob = nullptr; 1.701 + } 1.702 + 1.703 + ~FontTableHashEntry() { Clear(); } 1.704 + 1.705 + // FontTable/Blob API 1.706 + 1.707 + // Transfer (not copy) elements of aTable to a new hb_blob_t and 1.708 + // return ownership to the caller. A weak reference to the blob is 1.709 + // recorded in the hashtable entry so that others may use the same 1.710 + // table. 1.711 + hb_blob_t * 1.712 + ShareTableAndGetBlob(FallibleTArray<uint8_t>& aTable, 1.713 + nsTHashtable<FontTableHashEntry> *aHashtable); 1.714 + 1.715 + // Return a strong reference to the blob. 1.716 + // Callers must hb_blob_destroy the returned blob. 1.717 + hb_blob_t *GetBlob() const; 1.718 + 1.719 + void Clear(); 1.720 + 1.721 + static size_t 1.722 + SizeOfEntryExcludingThis(FontTableHashEntry *aEntry, 1.723 + mozilla::MallocSizeOf aMallocSizeOf, 1.724 + void* aUserArg); 1.725 + 1.726 + private: 1.727 + static void DeleteFontTableBlobData(void *aBlobData); 1.728 + // not implemented 1.729 + FontTableHashEntry& operator=(FontTableHashEntry& toCopy); 1.730 + 1.731 + FontTableBlobData *mSharedBlobData; 1.732 + hb_blob_t *mBlob; 1.733 + }; 1.734 + 1.735 + nsAutoPtr<nsTHashtable<FontTableHashEntry> > mFontTableCache; 1.736 + 1.737 + gfxFontEntry(const gfxFontEntry&); 1.738 + gfxFontEntry& operator=(const gfxFontEntry&); 1.739 +}; 1.740 + 1.741 + 1.742 +// used when iterating over all fonts looking for a match for a given character 1.743 +struct GlobalFontMatch { 1.744 + GlobalFontMatch(const uint32_t aCharacter, 1.745 + int32_t aRunScript, 1.746 + const gfxFontStyle *aStyle) : 1.747 + mCh(aCharacter), mRunScript(aRunScript), mStyle(aStyle), 1.748 + mMatchRank(0), mCount(0), mCmapsTested(0) 1.749 + { 1.750 + 1.751 + } 1.752 + 1.753 + const uint32_t mCh; // codepoint to be matched 1.754 + int32_t mRunScript; // Unicode script for the codepoint 1.755 + const gfxFontStyle* mStyle; // style to match 1.756 + int32_t mMatchRank; // metric indicating closest match 1.757 + nsRefPtr<gfxFontEntry> mBestMatch; // current best match 1.758 + nsRefPtr<gfxFontFamily> mMatchedFamily; // the family it belongs to 1.759 + uint32_t mCount; // number of fonts matched 1.760 + uint32_t mCmapsTested; // number of cmaps tested 1.761 +}; 1.762 + 1.763 +class gfxFontFamily { 1.764 +public: 1.765 + NS_INLINE_DECL_REFCOUNTING(gfxFontFamily) 1.766 + 1.767 + gfxFontFamily(const nsAString& aName) : 1.768 + mName(aName), 1.769 + mOtherFamilyNamesInitialized(false), 1.770 + mHasOtherFamilyNames(false), 1.771 + mFaceNamesInitialized(false), 1.772 + mHasStyles(false), 1.773 + mIsSimpleFamily(false), 1.774 + mIsBadUnderlineFamily(false), 1.775 + mFamilyCharacterMapInitialized(false), 1.776 + mSkipDefaultFeatureSpaceCheck(false) 1.777 + { } 1.778 + 1.779 + const nsString& Name() { return mName; } 1.780 + 1.781 + virtual void LocalizedName(nsAString& aLocalizedName); 1.782 + virtual bool HasOtherFamilyNames(); 1.783 + 1.784 + nsTArray<nsRefPtr<gfxFontEntry> >& GetFontList() { return mAvailableFonts; } 1.785 + 1.786 + void AddFontEntry(nsRefPtr<gfxFontEntry> aFontEntry) { 1.787 + // bug 589682 - set the IgnoreGDEF flag on entries for Italic faces 1.788 + // of Times New Roman, because of buggy table in those fonts 1.789 + if (aFontEntry->IsItalic() && !aFontEntry->IsUserFont() && 1.790 + Name().EqualsLiteral("Times New Roman")) 1.791 + { 1.792 + aFontEntry->mIgnoreGDEF = true; 1.793 + } 1.794 + aFontEntry->mFamilyName = Name(); 1.795 + aFontEntry->mSkipDefaultFeatureSpaceCheck = mSkipDefaultFeatureSpaceCheck; 1.796 + mAvailableFonts.AppendElement(aFontEntry); 1.797 + } 1.798 + 1.799 + // note that the styles for this family have been added 1.800 + bool HasStyles() { return mHasStyles; } 1.801 + void SetHasStyles(bool aHasStyles) { mHasStyles = aHasStyles; } 1.802 + 1.803 + // choose a specific face to match a style using CSS font matching 1.804 + // rules (weight matching occurs here). may return a face that doesn't 1.805 + // precisely match (e.g. normal face when no italic face exists). 1.806 + // aNeedsSyntheticBold is set to true when synthetic bolding is 1.807 + // needed, false otherwise 1.808 + gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle, 1.809 + bool& aNeedsSyntheticBold); 1.810 + 1.811 + // checks for a matching font within the family 1.812 + // used as part of the font fallback process 1.813 + void FindFontForChar(GlobalFontMatch *aMatchData); 1.814 + 1.815 + // checks all fonts for a matching font within the family 1.816 + void SearchAllFontsForChar(GlobalFontMatch *aMatchData); 1.817 + 1.818 + // read in other family names, if any, and use functor to add each into cache 1.819 + virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList); 1.820 + 1.821 + // helper method for reading localized family names from the name table 1.822 + // of a single face 1.823 + static void ReadOtherFamilyNamesForFace(const nsAString& aFamilyName, 1.824 + const char *aNameData, 1.825 + uint32_t aDataLength, 1.826 + nsTArray<nsString>& aOtherFamilyNames, 1.827 + bool useFullName); 1.828 + 1.829 + // set when other family names have been read in 1.830 + void SetOtherFamilyNamesInitialized() { 1.831 + mOtherFamilyNamesInitialized = true; 1.832 + } 1.833 + 1.834 + // read in other localized family names, fullnames and Postscript names 1.835 + // for all faces and append to lookup tables 1.836 + virtual void ReadFaceNames(gfxPlatformFontList *aPlatformFontList, 1.837 + bool aNeedFullnamePostscriptNames, 1.838 + FontInfoData *aFontInfoData = nullptr); 1.839 + 1.840 + // find faces belonging to this family (platform implementations override this; 1.841 + // should be made pure virtual once all subclasses have been updated) 1.842 + virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) { } 1.843 + 1.844 + // search for a specific face using the Postscript name 1.845 + gfxFontEntry* FindFont(const nsAString& aPostscriptName); 1.846 + 1.847 + // read in cmaps for all the faces 1.848 + void ReadAllCMAPs(FontInfoData *aFontInfoData = nullptr); 1.849 + 1.850 + bool TestCharacterMap(uint32_t aCh) { 1.851 + if (!mFamilyCharacterMapInitialized) { 1.852 + ReadAllCMAPs(); 1.853 + } 1.854 + return mFamilyCharacterMap.test(aCh); 1.855 + } 1.856 + 1.857 + void ResetCharacterMap() { 1.858 + mFamilyCharacterMap.reset(); 1.859 + mFamilyCharacterMapInitialized = false; 1.860 + } 1.861 + 1.862 + // mark this family as being in the "bad" underline offset blacklist 1.863 + void SetBadUnderlineFamily() { 1.864 + mIsBadUnderlineFamily = true; 1.865 + if (mHasStyles) { 1.866 + SetBadUnderlineFonts(); 1.867 + } 1.868 + } 1.869 + 1.870 + bool IsBadUnderlineFamily() const { return mIsBadUnderlineFamily; } 1.871 + 1.872 + // sort available fonts to put preferred (standard) faces towards the end 1.873 + void SortAvailableFonts(); 1.874 + 1.875 + // check whether the family fits into the simple 4-face model, 1.876 + // so we can use simplified style-matching; 1.877 + // if so set the mIsSimpleFamily flag (defaults to False before we've checked) 1.878 + void CheckForSimpleFamily(); 1.879 + 1.880 + // For memory reporter 1.881 + virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.882 + FontListSizes* aSizes) const; 1.883 + virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.884 + FontListSizes* aSizes) const; 1.885 + 1.886 + // Only used for debugging checks - does a linear search 1.887 + bool ContainsFace(gfxFontEntry* aFontEntry) { 1.888 + uint32_t i, numFonts = mAvailableFonts.Length(); 1.889 + for (i = 0; i < numFonts; i++) { 1.890 + if (mAvailableFonts[i] == aFontEntry) { 1.891 + return true; 1.892 + } 1.893 + } 1.894 + return false; 1.895 + } 1.896 + 1.897 + void SetSkipSpaceFeatureCheck(bool aSkipCheck) { 1.898 + mSkipDefaultFeatureSpaceCheck = aSkipCheck; 1.899 + } 1.900 + 1.901 +protected: 1.902 + // Protected destructor, to discourage deletion outside of Release(): 1.903 + virtual ~gfxFontFamily() 1.904 + { 1.905 + } 1.906 + 1.907 + // fills in an array with weights of faces that match style, 1.908 + // returns whether any matching entries found 1.909 + virtual bool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], 1.910 + bool anItalic, int16_t aStretch); 1.911 + 1.912 + bool ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList, 1.913 + hb_blob_t *aNameTable, 1.914 + bool useFullName = false); 1.915 + 1.916 + // set whether this font family is in "bad" underline offset blacklist. 1.917 + void SetBadUnderlineFonts() { 1.918 + uint32_t i, numFonts = mAvailableFonts.Length(); 1.919 + for (i = 0; i < numFonts; i++) { 1.920 + if (mAvailableFonts[i]) { 1.921 + mAvailableFonts[i]->mIsBadUnderlineFont = true; 1.922 + } 1.923 + } 1.924 + } 1.925 + 1.926 + nsString mName; 1.927 + nsTArray<nsRefPtr<gfxFontEntry> > mAvailableFonts; 1.928 + gfxSparseBitSet mFamilyCharacterMap; 1.929 + bool mOtherFamilyNamesInitialized : 1; 1.930 + bool mHasOtherFamilyNames : 1; 1.931 + bool mFaceNamesInitialized : 1; 1.932 + bool mHasStyles : 1; 1.933 + bool mIsSimpleFamily : 1; 1.934 + bool mIsBadUnderlineFamily : 1; 1.935 + bool mFamilyCharacterMapInitialized : 1; 1.936 + bool mSkipDefaultFeatureSpaceCheck : 1; 1.937 + 1.938 + enum { 1.939 + // for "simple" families, the faces are stored in mAvailableFonts 1.940 + // with fixed positions: 1.941 + kRegularFaceIndex = 0, 1.942 + kBoldFaceIndex = 1, 1.943 + kItalicFaceIndex = 2, 1.944 + kBoldItalicFaceIndex = 3, 1.945 + // mask values for selecting face with bold and/or italic attributes 1.946 + kBoldMask = 0x01, 1.947 + kItalicMask = 0x02 1.948 + }; 1.949 +}; 1.950 + 1.951 +struct gfxTextRange { 1.952 + enum { 1.953 + // flags for recording the kind of font-matching that was used 1.954 + kFontGroup = 0x0001, 1.955 + kPrefsFallback = 0x0002, 1.956 + kSystemFallback = 0x0004 1.957 + }; 1.958 + gfxTextRange(uint32_t aStart, uint32_t aEnd, 1.959 + gfxFont* aFont, uint8_t aMatchType) 1.960 + : start(aStart), 1.961 + end(aEnd), 1.962 + font(aFont), 1.963 + matchType(aMatchType) 1.964 + { } 1.965 + uint32_t Length() const { return end - start; } 1.966 + uint32_t start, end; 1.967 + nsRefPtr<gfxFont> font; 1.968 + uint8_t matchType; 1.969 +}; 1.970 + 1.971 + 1.972 +/** 1.973 + * Font cache design: 1.974 + * 1.975 + * The mFonts hashtable contains most fonts, indexed by (gfxFontEntry*, style). 1.976 + * It does not add a reference to the fonts it contains. 1.977 + * When a font's refcount decreases to zero, instead of deleting it we 1.978 + * add it to our expiration tracker. 1.979 + * The expiration tracker tracks fonts with zero refcount. After a certain 1.980 + * period of time, such fonts expire and are deleted. 1.981 + * 1.982 + * We're using 3 generations with a ten-second generation interval, so 1.983 + * zero-refcount fonts will be deleted 20-30 seconds after their refcount 1.984 + * goes to zero, if timer events fire in a timely manner. 1.985 + * 1.986 + * The font cache also handles timed expiration of cached ShapedWords 1.987 + * for "persistent" fonts: it has a repeating timer, and notifies 1.988 + * each cached font to "age" its shaped words. The words will be released 1.989 + * by the fonts if they get aged three times without being re-used in the 1.990 + * meantime. 1.991 + * 1.992 + * Note that the ShapedWord timeout is much larger than the font timeout, 1.993 + * so that in the case of a short-lived font, we'll discard the gfxFont 1.994 + * completely, with all its words, and avoid the cost of aging the words 1.995 + * individually. That only happens with longer-lived fonts. 1.996 + */ 1.997 +struct FontCacheSizes { 1.998 + FontCacheSizes() 1.999 + : mFontInstances(0), mShapedWords(0) 1.1000 + { } 1.1001 + 1.1002 + size_t mFontInstances; // memory used by instances of gfxFont subclasses 1.1003 + size_t mShapedWords; // memory used by the per-font shapedWord caches 1.1004 +}; 1.1005 + 1.1006 +class gfxFontCache MOZ_FINAL : public nsExpirationTracker<gfxFont,3> { 1.1007 +public: 1.1008 + enum { 1.1009 + FONT_TIMEOUT_SECONDS = 10, 1.1010 + SHAPED_WORD_TIMEOUT_SECONDS = 60 1.1011 + }; 1.1012 + 1.1013 + gfxFontCache(); 1.1014 + ~gfxFontCache(); 1.1015 + 1.1016 + /* 1.1017 + * Get the global gfxFontCache. You must call Init() before 1.1018 + * calling this method --- the result will not be null. 1.1019 + */ 1.1020 + static gfxFontCache* GetCache() { 1.1021 + return gGlobalCache; 1.1022 + } 1.1023 + 1.1024 + static nsresult Init(); 1.1025 + // It's OK to call this even if Init() has not been called. 1.1026 + static void Shutdown(); 1.1027 + 1.1028 + // Look up a font in the cache. Returns an addrefed pointer, or null 1.1029 + // if there's nothing matching in the cache 1.1030 + already_AddRefed<gfxFont> Lookup(const gfxFontEntry *aFontEntry, 1.1031 + const gfxFontStyle *aStyle); 1.1032 + // We created a new font (presumably because Lookup returned null); 1.1033 + // put it in the cache. The font's refcount should be nonzero. It is 1.1034 + // allowable to add a new font even if there is one already in the 1.1035 + // cache with the same key; we'll forget about the old one. 1.1036 + void AddNew(gfxFont *aFont); 1.1037 + 1.1038 + // The font's refcount has gone to zero; give ownership of it to 1.1039 + // the cache. We delete it if it's not acquired again after a certain 1.1040 + // amount of time. 1.1041 + void NotifyReleased(gfxFont *aFont); 1.1042 + 1.1043 + // This gets called when the timeout has expired on a zero-refcount 1.1044 + // font; we just delete it. 1.1045 + virtual void NotifyExpired(gfxFont *aFont); 1.1046 + 1.1047 + // Cleans out the hashtable and removes expired fonts waiting for cleanup. 1.1048 + // Other gfxFont objects may be still in use but they will be pushed 1.1049 + // into the expiration queues and removed. 1.1050 + void Flush() { 1.1051 + mFonts.Clear(); 1.1052 + AgeAllGenerations(); 1.1053 + } 1.1054 + 1.1055 + void FlushShapedWordCaches() { 1.1056 + mFonts.EnumerateEntries(ClearCachedWordsForFont, nullptr); 1.1057 + } 1.1058 + 1.1059 + void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.1060 + FontCacheSizes* aSizes) const; 1.1061 + void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.1062 + FontCacheSizes* aSizes) const; 1.1063 + 1.1064 +protected: 1.1065 + class MemoryReporter MOZ_FINAL : public nsIMemoryReporter 1.1066 + { 1.1067 + public: 1.1068 + NS_DECL_ISUPPORTS 1.1069 + NS_DECL_NSIMEMORYREPORTER 1.1070 + }; 1.1071 + 1.1072 + // Observer for notifications that the font cache cares about 1.1073 + class Observer MOZ_FINAL 1.1074 + : public nsIObserver 1.1075 + { 1.1076 + public: 1.1077 + NS_DECL_ISUPPORTS 1.1078 + NS_DECL_NSIOBSERVER 1.1079 + }; 1.1080 + 1.1081 + void DestroyFont(gfxFont *aFont); 1.1082 + 1.1083 + static gfxFontCache *gGlobalCache; 1.1084 + 1.1085 + struct Key { 1.1086 + const gfxFontEntry* mFontEntry; 1.1087 + const gfxFontStyle* mStyle; 1.1088 + Key(const gfxFontEntry* aFontEntry, const gfxFontStyle* aStyle) 1.1089 + : mFontEntry(aFontEntry), mStyle(aStyle) {} 1.1090 + }; 1.1091 + 1.1092 + class HashEntry : public PLDHashEntryHdr { 1.1093 + public: 1.1094 + typedef const Key& KeyType; 1.1095 + typedef const Key* KeyTypePointer; 1.1096 + 1.1097 + // When constructing a new entry in the hashtable, we'll leave this 1.1098 + // blank. The caller of Put() will fill this in. 1.1099 + HashEntry(KeyTypePointer aStr) : mFont(nullptr) { } 1.1100 + HashEntry(const HashEntry& toCopy) : mFont(toCopy.mFont) { } 1.1101 + ~HashEntry() { } 1.1102 + 1.1103 + bool KeyEquals(const KeyTypePointer aKey) const; 1.1104 + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } 1.1105 + static PLDHashNumber HashKey(const KeyTypePointer aKey) { 1.1106 + return mozilla::HashGeneric(aKey->mStyle->Hash(), aKey->mFontEntry); 1.1107 + } 1.1108 + enum { ALLOW_MEMMOVE = true }; 1.1109 + 1.1110 + gfxFont* mFont; 1.1111 + }; 1.1112 + 1.1113 + static size_t AddSizeOfFontEntryExcludingThis(HashEntry* aHashEntry, 1.1114 + mozilla::MallocSizeOf aMallocSizeOf, 1.1115 + void* aUserArg); 1.1116 + 1.1117 + nsTHashtable<HashEntry> mFonts; 1.1118 + 1.1119 + static PLDHashOperator ClearCachedWordsForFont(HashEntry* aHashEntry, void*); 1.1120 + static PLDHashOperator AgeCachedWordsForFont(HashEntry* aHashEntry, void*); 1.1121 + static void WordCacheExpirationTimerCallback(nsITimer* aTimer, void* aCache); 1.1122 + nsCOMPtr<nsITimer> mWordCacheExpirationTimer; 1.1123 +}; 1.1124 + 1.1125 +class gfxTextPerfMetrics { 1.1126 +public: 1.1127 + 1.1128 + struct TextCounts { 1.1129 + uint32_t numContentTextRuns; 1.1130 + uint32_t numChromeTextRuns; 1.1131 + uint32_t numChars; 1.1132 + uint32_t maxTextRunLen; 1.1133 + uint32_t wordCacheSpaceRules; 1.1134 + uint32_t wordCacheLong; 1.1135 + uint32_t wordCacheHit; 1.1136 + uint32_t wordCacheMiss; 1.1137 + uint32_t fallbackPrefs; 1.1138 + uint32_t fallbackSystem; 1.1139 + uint32_t textrunConst; 1.1140 + uint32_t textrunDestr; 1.1141 + }; 1.1142 + 1.1143 + uint32_t reflowCount; 1.1144 + 1.1145 + // counts per reflow operation 1.1146 + TextCounts current; 1.1147 + 1.1148 + // totals for the lifetime of a document 1.1149 + TextCounts cumulative; 1.1150 + 1.1151 + gfxTextPerfMetrics() { 1.1152 + memset(this, 0, sizeof(gfxTextPerfMetrics)); 1.1153 + } 1.1154 + 1.1155 + // add current totals to cumulative ones 1.1156 + void Accumulate() { 1.1157 + if (current.numChars == 0) { 1.1158 + return; 1.1159 + } 1.1160 + cumulative.numContentTextRuns += current.numContentTextRuns; 1.1161 + cumulative.numChromeTextRuns += current.numChromeTextRuns; 1.1162 + cumulative.numChars += current.numChars; 1.1163 + if (current.maxTextRunLen > cumulative.maxTextRunLen) { 1.1164 + cumulative.maxTextRunLen = current.maxTextRunLen; 1.1165 + } 1.1166 + cumulative.wordCacheSpaceRules += current.wordCacheSpaceRules; 1.1167 + cumulative.wordCacheLong += current.wordCacheLong; 1.1168 + cumulative.wordCacheHit += current.wordCacheHit; 1.1169 + cumulative.wordCacheMiss += current.wordCacheMiss; 1.1170 + cumulative.fallbackPrefs += current.fallbackPrefs; 1.1171 + cumulative.fallbackSystem += current.fallbackSystem; 1.1172 + cumulative.textrunConst += current.textrunConst; 1.1173 + cumulative.textrunDestr += current.textrunDestr; 1.1174 + memset(¤t, 0, sizeof(current)); 1.1175 + } 1.1176 +}; 1.1177 + 1.1178 +class gfxTextRunFactory { 1.1179 + NS_INLINE_DECL_REFCOUNTING(gfxTextRunFactory) 1.1180 + 1.1181 +public: 1.1182 + // Flags in the mask 0xFFFF0000 are reserved for textrun clients 1.1183 + // Flags in the mask 0x0000F000 are reserved for per-platform fonts 1.1184 + // Flags in the mask 0x00000FFF are set by the textrun creator. 1.1185 + enum { 1.1186 + CACHE_TEXT_FLAGS = 0xF0000000, 1.1187 + USER_TEXT_FLAGS = 0x0FFF0000, 1.1188 + PLATFORM_TEXT_FLAGS = 0x0000F000, 1.1189 + TEXTRUN_TEXT_FLAGS = 0x00000FFF, 1.1190 + SETTABLE_FLAGS = CACHE_TEXT_FLAGS | USER_TEXT_FLAGS, 1.1191 + 1.1192 + /** 1.1193 + * When set, the text string pointer used to create the text run 1.1194 + * is guaranteed to be available during the lifetime of the text run. 1.1195 + */ 1.1196 + TEXT_IS_PERSISTENT = 0x0001, 1.1197 + /** 1.1198 + * When set, the text is known to be all-ASCII (< 128). 1.1199 + */ 1.1200 + TEXT_IS_ASCII = 0x0002, 1.1201 + /** 1.1202 + * When set, the text is RTL. 1.1203 + */ 1.1204 + TEXT_IS_RTL = 0x0004, 1.1205 + /** 1.1206 + * When set, spacing is enabled and the textrun needs to call GetSpacing 1.1207 + * on the spacing provider. 1.1208 + */ 1.1209 + TEXT_ENABLE_SPACING = 0x0008, 1.1210 + /** 1.1211 + * When set, GetHyphenationBreaks may return true for some character 1.1212 + * positions, otherwise it will always return false for all characters. 1.1213 + */ 1.1214 + TEXT_ENABLE_HYPHEN_BREAKS = 0x0010, 1.1215 + /** 1.1216 + * When set, the text has no characters above 255 and it is stored 1.1217 + * in the textrun in 8-bit format. 1.1218 + */ 1.1219 + TEXT_IS_8BIT = 0x0020, 1.1220 + /** 1.1221 + * When set, the RunMetrics::mBoundingBox field will be initialized 1.1222 + * properly based on glyph extents, in particular, glyph extents that 1.1223 + * overflow the standard font-box (the box defined by the ascent, descent 1.1224 + * and advance width of the glyph). When not set, it may just be the 1.1225 + * standard font-box even if glyphs overflow. 1.1226 + */ 1.1227 + TEXT_NEED_BOUNDING_BOX = 0x0040, 1.1228 + /** 1.1229 + * When set, optional ligatures are disabled. Ligatures that are 1.1230 + * required for legible text should still be enabled. 1.1231 + */ 1.1232 + TEXT_DISABLE_OPTIONAL_LIGATURES = 0x0080, 1.1233 + /** 1.1234 + * When set, the textrun should favour speed of construction over 1.1235 + * quality. This may involve disabling ligatures and/or kerning or 1.1236 + * other effects. 1.1237 + */ 1.1238 + TEXT_OPTIMIZE_SPEED = 0x0100, 1.1239 + /** 1.1240 + * For internal use by the memory reporter when accounting for 1.1241 + * storage used by textruns. 1.1242 + * Because the reporter may visit each textrun multiple times while 1.1243 + * walking the frame trees and textrun cache, it needs to mark 1.1244 + * textruns that have been seen so as to avoid multiple-accounting. 1.1245 + */ 1.1246 + TEXT_RUN_SIZE_ACCOUNTED = 0x0200, 1.1247 + /** 1.1248 + * When set, the textrun should discard control characters instead of 1.1249 + * turning them into hexboxes. 1.1250 + */ 1.1251 + TEXT_HIDE_CONTROL_CHARACTERS = 0x0400, 1.1252 + 1.1253 + /** 1.1254 + * nsTextFrameThebes sets these, but they're defined here rather than 1.1255 + * in nsTextFrameUtils.h because ShapedWord creation/caching also needs 1.1256 + * to check the _INCOMING flag 1.1257 + */ 1.1258 + TEXT_TRAILING_ARABICCHAR = 0x20000000, 1.1259 + /** 1.1260 + * When set, the previous character for this textrun was an Arabic 1.1261 + * character. This is used for the context detection necessary for 1.1262 + * bidi.numeral implementation. 1.1263 + */ 1.1264 + TEXT_INCOMING_ARABICCHAR = 0x40000000, 1.1265 + 1.1266 + // Set if the textrun should use the OpenType 'math' script. 1.1267 + TEXT_USE_MATH_SCRIPT = 0x80000000, 1.1268 + 1.1269 + TEXT_UNUSED_FLAGS = 0x10000000 1.1270 + }; 1.1271 + 1.1272 + /** 1.1273 + * This record contains all the parameters needed to initialize a textrun. 1.1274 + */ 1.1275 + struct Parameters { 1.1276 + // A reference context suggesting where the textrun will be rendered 1.1277 + gfxContext *mContext; 1.1278 + // Pointer to arbitrary user data (which should outlive the textrun) 1.1279 + void *mUserData; 1.1280 + // A description of which characters have been stripped from the original 1.1281 + // DOM string to produce the characters in the textrun. May be null 1.1282 + // if that information is not relevant. 1.1283 + gfxSkipChars *mSkipChars; 1.1284 + // A list of where linebreaks are currently placed in the textrun. May 1.1285 + // be null if mInitialBreakCount is zero. 1.1286 + uint32_t *mInitialBreaks; 1.1287 + uint32_t mInitialBreakCount; 1.1288 + // The ratio to use to convert device pixels to application layout units 1.1289 + int32_t mAppUnitsPerDevUnit; 1.1290 + }; 1.1291 + 1.1292 +protected: 1.1293 + // Protected destructor, to discourage deletion outside of Release(): 1.1294 + virtual ~gfxTextRunFactory() {} 1.1295 +}; 1.1296 + 1.1297 +/** 1.1298 + * This stores glyph bounds information for a particular gfxFont, at 1.1299 + * a particular appunits-per-dev-pixel ratio (because the compressed glyph 1.1300 + * width array is stored in appunits). 1.1301 + * 1.1302 + * We store a hashtable from glyph IDs to float bounding rects. For the 1.1303 + * common case where the glyph has no horizontal left bearing, and no 1.1304 + * y overflow above the font ascent or below the font descent, and tight 1.1305 + * bounding boxes are not required, we avoid storing the glyph ID in the hashtable 1.1306 + * and instead consult an array of 16-bit glyph XMost values (in appunits). 1.1307 + * This array always has an entry for the font's space glyph --- the width is 1.1308 + * assumed to be zero. 1.1309 + */ 1.1310 +class gfxGlyphExtents { 1.1311 +public: 1.1312 + gfxGlyphExtents(int32_t aAppUnitsPerDevUnit) : 1.1313 + mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) { 1.1314 + MOZ_COUNT_CTOR(gfxGlyphExtents); 1.1315 + } 1.1316 + ~gfxGlyphExtents(); 1.1317 + 1.1318 + enum { INVALID_WIDTH = 0xFFFF }; 1.1319 + 1.1320 + void NotifyGlyphsChanged() { 1.1321 + mTightGlyphExtents.Clear(); 1.1322 + } 1.1323 + 1.1324 + // returns INVALID_WIDTH => not a contained glyph 1.1325 + // Otherwise the glyph has no before-bearing or vertical bearings, 1.1326 + // and the result is its width measured from the baseline origin, in 1.1327 + // appunits. 1.1328 + uint16_t GetContainedGlyphWidthAppUnits(uint32_t aGlyphID) const { 1.1329 + return mContainedGlyphWidths.Get(aGlyphID); 1.1330 + } 1.1331 + 1.1332 + bool IsGlyphKnown(uint32_t aGlyphID) const { 1.1333 + return mContainedGlyphWidths.Get(aGlyphID) != INVALID_WIDTH || 1.1334 + mTightGlyphExtents.GetEntry(aGlyphID) != nullptr; 1.1335 + } 1.1336 + 1.1337 + bool IsGlyphKnownWithTightExtents(uint32_t aGlyphID) const { 1.1338 + return mTightGlyphExtents.GetEntry(aGlyphID) != nullptr; 1.1339 + } 1.1340 + 1.1341 + // Get glyph extents; a rectangle relative to the left baseline origin 1.1342 + // Returns true on success. Can fail on OOM or when aContext is null 1.1343 + // and extents were not (successfully) prefetched. 1.1344 + bool GetTightGlyphExtentsAppUnits(gfxFont *aFont, gfxContext *aContext, 1.1345 + uint32_t aGlyphID, gfxRect *aExtents); 1.1346 + 1.1347 + void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID, uint16_t aWidth) { 1.1348 + mContainedGlyphWidths.Set(aGlyphID, aWidth); 1.1349 + } 1.1350 + void SetTightGlyphExtents(uint32_t aGlyphID, const gfxRect& aExtentsAppUnits); 1.1351 + 1.1352 + int32_t GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; } 1.1353 + 1.1354 + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 1.1355 + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 1.1356 + 1.1357 +private: 1.1358 + class HashEntry : public nsUint32HashKey { 1.1359 + public: 1.1360 + // When constructing a new entry in the hashtable, we'll leave this 1.1361 + // blank. The caller of Put() will fill this in. 1.1362 + HashEntry(KeyTypePointer aPtr) : nsUint32HashKey(aPtr) {} 1.1363 + HashEntry(const HashEntry& toCopy) : nsUint32HashKey(toCopy) { 1.1364 + x = toCopy.x; y = toCopy.y; width = toCopy.width; height = toCopy.height; 1.1365 + } 1.1366 + 1.1367 + float x, y, width, height; 1.1368 + }; 1.1369 + 1.1370 + enum { BLOCK_SIZE_BITS = 7, BLOCK_SIZE = 1 << BLOCK_SIZE_BITS }; // 128-glyph blocks 1.1371 + 1.1372 + class GlyphWidths { 1.1373 + public: 1.1374 + void Set(uint32_t aIndex, uint16_t aValue); 1.1375 + uint16_t Get(uint32_t aIndex) const { 1.1376 + uint32_t block = aIndex >> BLOCK_SIZE_BITS; 1.1377 + if (block >= mBlocks.Length()) 1.1378 + return INVALID_WIDTH; 1.1379 + uintptr_t bits = mBlocks[block]; 1.1380 + if (!bits) 1.1381 + return INVALID_WIDTH; 1.1382 + uint32_t indexInBlock = aIndex & (BLOCK_SIZE - 1); 1.1383 + if (bits & 0x1) { 1.1384 + if (GetGlyphOffset(bits) != indexInBlock) 1.1385 + return INVALID_WIDTH; 1.1386 + return GetWidth(bits); 1.1387 + } 1.1388 + uint16_t *widths = reinterpret_cast<uint16_t *>(bits); 1.1389 + return widths[indexInBlock]; 1.1390 + } 1.1391 + 1.1392 + uint32_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 1.1393 + 1.1394 + ~GlyphWidths(); 1.1395 + 1.1396 + private: 1.1397 + static uint32_t GetGlyphOffset(uintptr_t aBits) { 1.1398 + NS_ASSERTION(aBits & 0x1, "This is really a pointer..."); 1.1399 + return (aBits >> 1) & ((1 << BLOCK_SIZE_BITS) - 1); 1.1400 + } 1.1401 + static uint32_t GetWidth(uintptr_t aBits) { 1.1402 + NS_ASSERTION(aBits & 0x1, "This is really a pointer..."); 1.1403 + return aBits >> (1 + BLOCK_SIZE_BITS); 1.1404 + } 1.1405 + static uintptr_t MakeSingle(uint32_t aGlyphOffset, uint16_t aWidth) { 1.1406 + return (aWidth << (1 + BLOCK_SIZE_BITS)) + (aGlyphOffset << 1) + 1; 1.1407 + } 1.1408 + 1.1409 + nsTArray<uintptr_t> mBlocks; 1.1410 + }; 1.1411 + 1.1412 + GlyphWidths mContainedGlyphWidths; 1.1413 + nsTHashtable<HashEntry> mTightGlyphExtents; 1.1414 + int32_t mAppUnitsPerDevUnit; 1.1415 + 1.1416 +private: 1.1417 + // not implemented: 1.1418 + gfxGlyphExtents(const gfxGlyphExtents& aOther) MOZ_DELETE; 1.1419 + gfxGlyphExtents& operator=(const gfxGlyphExtents& aOther) MOZ_DELETE; 1.1420 +}; 1.1421 + 1.1422 +/** 1.1423 + * gfxFontShaper 1.1424 + * 1.1425 + * This class implements text shaping (character to glyph mapping and 1.1426 + * glyph layout). There is a gfxFontShaper subclass for each text layout 1.1427 + * technology (uniscribe, core text, harfbuzz,....) we support. 1.1428 + * 1.1429 + * The shaper is responsible for setting up glyph data in gfxTextRuns. 1.1430 + * 1.1431 + * A generic, platform-independent shaper relies only on the standard 1.1432 + * gfxFont interface and can work with any concrete subclass of gfxFont. 1.1433 + * 1.1434 + * Platform-specific implementations designed to interface to platform 1.1435 + * shaping APIs such as Uniscribe or CoreText may rely on features of a 1.1436 + * specific font subclass to access native font references 1.1437 + * (such as CTFont, HFONT, DWriteFont, etc). 1.1438 + */ 1.1439 + 1.1440 +class gfxFontShaper { 1.1441 +public: 1.1442 + gfxFontShaper(gfxFont *aFont) 1.1443 + : mFont(aFont) 1.1444 + { 1.1445 + NS_ASSERTION(aFont, "shaper requires a valid font!"); 1.1446 + } 1.1447 + 1.1448 + virtual ~gfxFontShaper() { } 1.1449 + 1.1450 + // Shape a piece of text and store the resulting glyph data into 1.1451 + // aShapedText. Parameters aOffset/aLength indicate the range of 1.1452 + // aShapedText to be updated; aLength is also the length of aText. 1.1453 + virtual bool ShapeText(gfxContext *aContext, 1.1454 + const char16_t *aText, 1.1455 + uint32_t aOffset, 1.1456 + uint32_t aLength, 1.1457 + int32_t aScript, 1.1458 + gfxShapedText *aShapedText) = 0; 1.1459 + 1.1460 + gfxFont *GetFont() const { return mFont; } 1.1461 + 1.1462 + // returns true if features exist in output, false otherwise 1.1463 + static bool 1.1464 + MergeFontFeatures(const gfxFontStyle *aStyle, 1.1465 + const nsTArray<gfxFontFeature>& aFontFeatures, 1.1466 + bool aDisableLigatures, 1.1467 + const nsAString& aFamilyName, 1.1468 + nsDataHashtable<nsUint32HashKey,uint32_t>& aMergedFeatures); 1.1469 + 1.1470 +protected: 1.1471 + // the font this shaper is working with 1.1472 + gfxFont * mFont; 1.1473 +}; 1.1474 + 1.1475 +/* a SPECIFIC single font family */ 1.1476 +class gfxFont { 1.1477 + 1.1478 + friend class gfxHarfBuzzShaper; 1.1479 + friend class gfxGraphiteShaper; 1.1480 + 1.1481 +public: 1.1482 + nsrefcnt AddRef(void) { 1.1483 + NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt"); 1.1484 + if (mExpirationState.IsTracked()) { 1.1485 + gfxFontCache::GetCache()->RemoveObject(this); 1.1486 + } 1.1487 + ++mRefCnt; 1.1488 + NS_LOG_ADDREF(this, mRefCnt, "gfxFont", sizeof(*this)); 1.1489 + return mRefCnt; 1.1490 + } 1.1491 + nsrefcnt Release(void) { 1.1492 + NS_PRECONDITION(0 != mRefCnt, "dup release"); 1.1493 + --mRefCnt; 1.1494 + NS_LOG_RELEASE(this, mRefCnt, "gfxFont"); 1.1495 + if (mRefCnt == 0) { 1.1496 + NotifyReleased(); 1.1497 + // |this| may have been deleted. 1.1498 + return 0; 1.1499 + } 1.1500 + return mRefCnt; 1.1501 + } 1.1502 + 1.1503 + int32_t GetRefCount() { return mRefCnt; } 1.1504 + 1.1505 + // options to specify the kind of AA to be used when creating a font 1.1506 + typedef enum { 1.1507 + kAntialiasDefault, 1.1508 + kAntialiasNone, 1.1509 + kAntialiasGrayscale, 1.1510 + kAntialiasSubpixel 1.1511 + } AntialiasOption; 1.1512 + 1.1513 +protected: 1.1514 + nsAutoRefCnt mRefCnt; 1.1515 + cairo_scaled_font_t *mScaledFont; 1.1516 + 1.1517 + void NotifyReleased() { 1.1518 + gfxFontCache *cache = gfxFontCache::GetCache(); 1.1519 + if (cache) { 1.1520 + // Don't delete just yet; return the object to the cache for 1.1521 + // possibly recycling within some time limit 1.1522 + cache->NotifyReleased(this); 1.1523 + } else { 1.1524 + // The cache may have already been shut down. 1.1525 + delete this; 1.1526 + } 1.1527 + } 1.1528 + 1.1529 + gfxFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle, 1.1530 + AntialiasOption anAAOption = kAntialiasDefault, 1.1531 + cairo_scaled_font_t *aScaledFont = nullptr); 1.1532 + 1.1533 +public: 1.1534 + virtual ~gfxFont(); 1.1535 + 1.1536 + bool Valid() const { 1.1537 + return mIsValid; 1.1538 + } 1.1539 + 1.1540 + // options for the kind of bounding box to return from measurement 1.1541 + typedef enum { 1.1542 + LOOSE_INK_EXTENTS, 1.1543 + // A box that encloses all the painted pixels, and may 1.1544 + // include sidebearings and/or additional ascent/descent 1.1545 + // within the glyph cell even if the ink is smaller. 1.1546 + TIGHT_INK_EXTENTS, 1.1547 + // A box that tightly encloses all the painted pixels 1.1548 + // (although actually on Windows, at least, it may be 1.1549 + // slightly larger than strictly necessary because 1.1550 + // we can't get precise extents with ClearType). 1.1551 + TIGHT_HINTED_OUTLINE_EXTENTS 1.1552 + // A box that tightly encloses the glyph outline, 1.1553 + // ignoring possible antialiasing pixels that extend 1.1554 + // beyond this. 1.1555 + // NOTE: The default implementation of gfxFont::Measure(), 1.1556 + // which works with the glyph extents cache, does not 1.1557 + // differentiate between this and TIGHT_INK_EXTENTS. 1.1558 + // Whether the distinction is important depends on the 1.1559 + // antialiasing behavior of the platform; currently the 1.1560 + // distinction is only implemented in the gfxWindowsFont 1.1561 + // subclass, because of ClearType's tendency to paint 1.1562 + // outside the hinted outline. 1.1563 + // Also NOTE: it is relatively expensive to request this, 1.1564 + // as it does not use cached glyph extents in the font. 1.1565 + } BoundingBoxType; 1.1566 + 1.1567 + const nsString& GetName() const { return mFontEntry->Name(); } 1.1568 + const gfxFontStyle *GetStyle() const { return &mStyle; } 1.1569 + 1.1570 + virtual cairo_scaled_font_t* GetCairoScaledFont() { return mScaledFont; } 1.1571 + 1.1572 + virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption) { 1.1573 + // platforms where this actually matters should override 1.1574 + return nullptr; 1.1575 + } 1.1576 + 1.1577 + virtual gfxFloat GetAdjustedSize() { 1.1578 + return mAdjustedSize > 0.0 ? mAdjustedSize : mStyle.size; 1.1579 + } 1.1580 + 1.1581 + float FUnitsToDevUnitsFactor() const { 1.1582 + // check this was set up during font initialization 1.1583 + NS_ASSERTION(mFUnitsConvFactor > 0.0f, "mFUnitsConvFactor not valid"); 1.1584 + return mFUnitsConvFactor; 1.1585 + } 1.1586 + 1.1587 + // check whether this is an sfnt we can potentially use with harfbuzz 1.1588 + bool FontCanSupportHarfBuzz() { 1.1589 + return mFontEntry->HasCmapTable(); 1.1590 + } 1.1591 + 1.1592 + // check whether this is an sfnt we can potentially use with Graphite 1.1593 + bool FontCanSupportGraphite() { 1.1594 + return mFontEntry->HasGraphiteTables(); 1.1595 + } 1.1596 + 1.1597 + // Subclasses may choose to look up glyph ids for characters. 1.1598 + // If they do not override this, gfxHarfBuzzShaper will fetch the cmap 1.1599 + // table and use that. 1.1600 + virtual bool ProvidesGetGlyph() const { 1.1601 + return false; 1.1602 + } 1.1603 + // Map unicode character to glyph ID. 1.1604 + // Only used if ProvidesGetGlyph() returns true. 1.1605 + virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector) { 1.1606 + return 0; 1.1607 + } 1.1608 + // Return the horizontal advance of a glyph. 1.1609 + gfxFloat GetGlyphHAdvance(gfxContext *aCtx, uint16_t aGID); 1.1610 + 1.1611 + // Return Azure GlyphRenderingOptions for drawing this font. 1.1612 + virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> 1.1613 + GetGlyphRenderingOptions() { return nullptr; } 1.1614 + 1.1615 + gfxFloat SynthesizeSpaceWidth(uint32_t aCh); 1.1616 + 1.1617 + // Font metrics 1.1618 + struct Metrics { 1.1619 + gfxFloat xHeight; 1.1620 + gfxFloat superscriptOffset; 1.1621 + gfxFloat subscriptOffset; 1.1622 + gfxFloat strikeoutSize; 1.1623 + gfxFloat strikeoutOffset; 1.1624 + gfxFloat underlineSize; 1.1625 + gfxFloat underlineOffset; 1.1626 + 1.1627 + gfxFloat internalLeading; 1.1628 + gfxFloat externalLeading; 1.1629 + 1.1630 + gfxFloat emHeight; 1.1631 + gfxFloat emAscent; 1.1632 + gfxFloat emDescent; 1.1633 + gfxFloat maxHeight; 1.1634 + gfxFloat maxAscent; 1.1635 + gfxFloat maxDescent; 1.1636 + gfxFloat maxAdvance; 1.1637 + 1.1638 + gfxFloat aveCharWidth; 1.1639 + gfxFloat spaceWidth; 1.1640 + gfxFloat zeroOrAveCharWidth; // width of '0', or if there is 1.1641 + // no '0' glyph in this font, 1.1642 + // equal to .aveCharWidth 1.1643 + }; 1.1644 + virtual const gfxFont::Metrics& GetMetrics() = 0; 1.1645 + 1.1646 + /** 1.1647 + * We let layout specify spacing on either side of any 1.1648 + * character. We need to specify both before and after 1.1649 + * spacing so that substring measurement can do the right things. 1.1650 + * These values are in appunits. They're always an integral number of 1.1651 + * appunits, but we specify them in floats in case very large spacing 1.1652 + * values are required. 1.1653 + */ 1.1654 + struct Spacing { 1.1655 + gfxFloat mBefore; 1.1656 + gfxFloat mAfter; 1.1657 + }; 1.1658 + /** 1.1659 + * Metrics for a particular string 1.1660 + */ 1.1661 + struct RunMetrics { 1.1662 + RunMetrics() { 1.1663 + mAdvanceWidth = mAscent = mDescent = 0.0; 1.1664 + } 1.1665 + 1.1666 + void CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft); 1.1667 + 1.1668 + // can be negative (partly due to negative spacing). 1.1669 + // Advance widths should be additive: the advance width of the 1.1670 + // (offset1, length1) plus the advance width of (offset1 + length1, 1.1671 + // length2) should be the advance width of (offset1, length1 + length2) 1.1672 + gfxFloat mAdvanceWidth; 1.1673 + 1.1674 + // For zero-width substrings, these must be zero! 1.1675 + gfxFloat mAscent; // always non-negative 1.1676 + gfxFloat mDescent; // always non-negative 1.1677 + 1.1678 + // Bounding box that is guaranteed to include everything drawn. 1.1679 + // If a tight boundingBox was requested when these metrics were 1.1680 + // generated, this will tightly wrap the glyphs, otherwise it is 1.1681 + // "loose" and may be larger than the true bounding box. 1.1682 + // Coordinates are relative to the baseline left origin, so typically 1.1683 + // mBoundingBox.y == -mAscent 1.1684 + gfxRect mBoundingBox; 1.1685 + }; 1.1686 + 1.1687 + /** 1.1688 + * Draw a series of glyphs to aContext. The direction of aTextRun must 1.1689 + * be honoured. 1.1690 + * @param aStart the first character to draw 1.1691 + * @param aEnd draw characters up to here 1.1692 + * @param aBaselineOrigin the baseline origin; the left end of the baseline 1.1693 + * for LTR textruns, the right end of the baseline for RTL textruns. On return, 1.1694 + * this should be updated to the other end of the baseline. In application 1.1695 + * units, really! 1.1696 + * @param aSpacing spacing to insert before and after characters (for RTL 1.1697 + * glyphs, before-spacing is inserted to the right of characters). There 1.1698 + * are aEnd - aStart elements in this array, unless it's null to indicate 1.1699 + * that there is no spacing. 1.1700 + * @param aDrawMode specifies whether the fill or stroke of the glyph should be 1.1701 + * drawn, or if it should be drawn into the current path 1.1702 + * @param aContextPaint information about how to construct the fill and 1.1703 + * stroke pattern. Can be nullptr if we are not stroking the text, which 1.1704 + * indicates that the current source from aContext should be used for filling 1.1705 + * 1.1706 + * Callers guarantee: 1.1707 + * -- aStart and aEnd are aligned to cluster and ligature boundaries 1.1708 + * -- all glyphs use this font 1.1709 + * 1.1710 + * The default implementation builds a cairo glyph array and 1.1711 + * calls cairo_show_glyphs or cairo_glyph_path. 1.1712 + */ 1.1713 + virtual void Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd, 1.1714 + gfxContext *aContext, DrawMode aDrawMode, gfxPoint *aBaselineOrigin, 1.1715 + Spacing *aSpacing, gfxTextContextPaint *aContextPaint, 1.1716 + gfxTextRunDrawCallbacks *aCallbacks); 1.1717 + 1.1718 + /** 1.1719 + * Measure a run of characters. See gfxTextRun::Metrics. 1.1720 + * @param aTight if false, then return the union of the glyph extents 1.1721 + * with the font-box for the characters (the rectangle with x=0,width= 1.1722 + * the advance width for the character run,y=-(font ascent), and height= 1.1723 + * font ascent + font descent). Otherwise, we must return as tight as possible 1.1724 + * an approximation to the area actually painted by glyphs. 1.1725 + * @param aContextForTightBoundingBox when aTight is true, this must 1.1726 + * be non-null. 1.1727 + * @param aSpacing spacing to insert before and after glyphs. The bounding box 1.1728 + * need not include the spacing itself, but the spacing affects the glyph 1.1729 + * positions. null if there is no spacing. 1.1730 + * 1.1731 + * Callers guarantee: 1.1732 + * -- aStart and aEnd are aligned to cluster and ligature boundaries 1.1733 + * -- all glyphs use this font 1.1734 + * 1.1735 + * The default implementation just uses font metrics and aTextRun's 1.1736 + * advances, and assumes no characters fall outside the font box. In 1.1737 + * general this is insufficient, because that assumption is not always true. 1.1738 + */ 1.1739 + virtual RunMetrics Measure(gfxTextRun *aTextRun, 1.1740 + uint32_t aStart, uint32_t aEnd, 1.1741 + BoundingBoxType aBoundingBoxType, 1.1742 + gfxContext *aContextForTightBoundingBox, 1.1743 + Spacing *aSpacing); 1.1744 + /** 1.1745 + * Line breaks have been changed at the beginning and/or end of a substring 1.1746 + * of the text. Reshaping may be required; glyph updating is permitted. 1.1747 + * @return true if anything was changed, false otherwise 1.1748 + */ 1.1749 + bool NotifyLineBreaksChanged(gfxTextRun *aTextRun, 1.1750 + uint32_t aStart, uint32_t aLength) 1.1751 + { return false; } 1.1752 + 1.1753 + // Expiration tracking 1.1754 + nsExpirationState *GetExpirationState() { return &mExpirationState; } 1.1755 + 1.1756 + // Get the glyphID of a space 1.1757 + virtual uint32_t GetSpaceGlyph() = 0; 1.1758 + 1.1759 + gfxGlyphExtents *GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit); 1.1760 + 1.1761 + // You need to call SetupCairoFont on the aCR just before calling this 1.1762 + virtual void SetupGlyphExtents(gfxContext *aContext, uint32_t aGlyphID, 1.1763 + bool aNeedTight, gfxGlyphExtents *aExtents); 1.1764 + 1.1765 + // This is called by the default Draw() implementation above. 1.1766 + virtual bool SetupCairoFont(gfxContext *aContext) = 0; 1.1767 + 1.1768 + virtual bool AllowSubpixelAA() { return true; } 1.1769 + 1.1770 + bool IsSyntheticBold() { return mApplySyntheticBold; } 1.1771 + 1.1772 + // Amount by which synthetic bold "fattens" the glyphs: 1.1773 + // For size S up to a threshold size T, we use (0.25 + 3S / 4T), 1.1774 + // so that the result ranges from 0.25 to 1.0; thereafter, 1.1775 + // simply use (S / T). 1.1776 + gfxFloat GetSyntheticBoldOffset() { 1.1777 + gfxFloat size = GetAdjustedSize(); 1.1778 + const gfxFloat threshold = 48.0; 1.1779 + return size < threshold ? (0.25 + 0.75 * size / threshold) : 1.1780 + (size / threshold); 1.1781 + } 1.1782 + 1.1783 + gfxFontEntry *GetFontEntry() { return mFontEntry.get(); } 1.1784 + bool HasCharacter(uint32_t ch) { 1.1785 + if (!mIsValid) 1.1786 + return false; 1.1787 + return mFontEntry->HasCharacter(ch); 1.1788 + } 1.1789 + 1.1790 + uint16_t GetUVSGlyph(uint32_t aCh, uint32_t aVS) { 1.1791 + if (!mIsValid) { 1.1792 + return 0; 1.1793 + } 1.1794 + return mFontEntry->GetUVSGlyph(aCh, aVS); 1.1795 + } 1.1796 + 1.1797 + // call the (virtual) InitTextRun method to do glyph generation/shaping, 1.1798 + // limiting the length of text passed by processing the run in multiple 1.1799 + // segments if necessary 1.1800 + template<typename T> 1.1801 + bool SplitAndInitTextRun(gfxContext *aContext, 1.1802 + gfxTextRun *aTextRun, 1.1803 + const T *aString, 1.1804 + uint32_t aRunStart, 1.1805 + uint32_t aRunLength, 1.1806 + int32_t aRunScript); 1.1807 + 1.1808 + // Get a ShapedWord representing the given text (either 8- or 16-bit) 1.1809 + // for use in setting up a gfxTextRun. 1.1810 + template<typename T> 1.1811 + gfxShapedWord* GetShapedWord(gfxContext *aContext, 1.1812 + const T *aText, 1.1813 + uint32_t aLength, 1.1814 + uint32_t aHash, 1.1815 + int32_t aRunScript, 1.1816 + int32_t aAppUnitsPerDevUnit, 1.1817 + uint32_t aFlags, 1.1818 + gfxTextPerfMetrics *aTextPerf); 1.1819 + 1.1820 + // Ensure the ShapedWord cache is initialized. This MUST be called before 1.1821 + // any attempt to use GetShapedWord(). 1.1822 + void InitWordCache() { 1.1823 + if (!mWordCache) { 1.1824 + mWordCache = new nsTHashtable<CacheHashEntry>; 1.1825 + } 1.1826 + } 1.1827 + 1.1828 + // Called by the gfxFontCache timer to increment the age of all the words, 1.1829 + // so that they'll expire after a sufficient period of non-use 1.1830 + void AgeCachedWords() { 1.1831 + if (mWordCache) { 1.1832 + (void)mWordCache->EnumerateEntries(AgeCacheEntry, this); 1.1833 + } 1.1834 + } 1.1835 + 1.1836 + // Discard all cached word records; called on memory-pressure notification. 1.1837 + void ClearCachedWords() { 1.1838 + if (mWordCache) { 1.1839 + mWordCache->Clear(); 1.1840 + } 1.1841 + } 1.1842 + 1.1843 + // Glyph rendering/geometry has changed, so invalidate data as necessary. 1.1844 + void NotifyGlyphsChanged(); 1.1845 + 1.1846 + virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.1847 + FontCacheSizes* aSizes) const; 1.1848 + virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.1849 + FontCacheSizes* aSizes) const; 1.1850 + 1.1851 + typedef enum { 1.1852 + FONT_TYPE_DWRITE, 1.1853 + FONT_TYPE_GDI, 1.1854 + FONT_TYPE_FT2, 1.1855 + FONT_TYPE_MAC, 1.1856 + FONT_TYPE_OS2, 1.1857 + FONT_TYPE_CAIRO 1.1858 + } FontType; 1.1859 + 1.1860 + virtual FontType GetType() const = 0; 1.1861 + 1.1862 + virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget) 1.1863 + { return gfxPlatform::GetPlatform()->GetScaledFontForFont(aTarget, this); } 1.1864 + 1.1865 + bool KerningDisabled() { 1.1866 + return mKerningSet && !mKerningEnabled; 1.1867 + } 1.1868 + 1.1869 + /** 1.1870 + * Subclass this object to be notified of glyph changes. Delete the object 1.1871 + * when no longer needed. 1.1872 + */ 1.1873 + class GlyphChangeObserver { 1.1874 + public: 1.1875 + virtual ~GlyphChangeObserver() 1.1876 + { 1.1877 + if (mFont) { 1.1878 + mFont->RemoveGlyphChangeObserver(this); 1.1879 + } 1.1880 + } 1.1881 + // This gets called when the gfxFont dies. 1.1882 + void ForgetFont() { mFont = nullptr; } 1.1883 + virtual void NotifyGlyphsChanged() = 0; 1.1884 + protected: 1.1885 + GlyphChangeObserver(gfxFont *aFont) : mFont(aFont) 1.1886 + { 1.1887 + mFont->AddGlyphChangeObserver(this); 1.1888 + } 1.1889 + gfxFont* mFont; 1.1890 + }; 1.1891 + friend class GlyphChangeObserver; 1.1892 + 1.1893 + bool GlyphsMayChange() 1.1894 + { 1.1895 + // Currently only fonts with SVG glyphs can have animated glyphs 1.1896 + return mFontEntry->TryGetSVGData(this); 1.1897 + } 1.1898 + 1.1899 + static void DestroySingletons() { 1.1900 + delete sScriptTagToCode; 1.1901 + delete sDefaultFeatures; 1.1902 + } 1.1903 + 1.1904 +protected: 1.1905 + // subclasses may provide (possibly hinted) glyph widths (in font units); 1.1906 + // if they do not override this, harfbuzz will use unhinted widths 1.1907 + // derived from the font tables 1.1908 + virtual bool ProvidesGlyphWidths() { 1.1909 + return false; 1.1910 + } 1.1911 + 1.1912 + // The return value is interpreted as a horizontal advance in 16.16 fixed 1.1913 + // point format. 1.1914 + virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID) { 1.1915 + return -1; 1.1916 + } 1.1917 + 1.1918 + void AddGlyphChangeObserver(GlyphChangeObserver *aObserver); 1.1919 + void RemoveGlyphChangeObserver(GlyphChangeObserver *aObserver); 1.1920 + 1.1921 + // whether font contains substitution lookups containing spaces 1.1922 + bool HasSubstitutionRulesWithSpaceLookups(int32_t aRunScript); 1.1923 + 1.1924 + // do spaces participate in shaping rules? if so, can't used word cache 1.1925 + bool SpaceMayParticipateInShaping(int32_t aRunScript); 1.1926 + 1.1927 + // For 8-bit text, expand to 16-bit and then call the following method. 1.1928 + bool ShapeText(gfxContext *aContext, 1.1929 + const uint8_t *aText, 1.1930 + uint32_t aOffset, // dest offset in gfxShapedText 1.1931 + uint32_t aLength, 1.1932 + int32_t aScript, 1.1933 + gfxShapedText *aShapedText, // where to store the result 1.1934 + bool aPreferPlatformShaping = false); 1.1935 + 1.1936 + // Call the appropriate shaper to generate glyphs for aText and store 1.1937 + // them into aShapedText. 1.1938 + virtual bool ShapeText(gfxContext *aContext, 1.1939 + const char16_t *aText, 1.1940 + uint32_t aOffset, 1.1941 + uint32_t aLength, 1.1942 + int32_t aScript, 1.1943 + gfxShapedText *aShapedText, 1.1944 + bool aPreferPlatformShaping = false); 1.1945 + 1.1946 + // Helper to adjust for synthetic bold and set character-type flags 1.1947 + // in the shaped text; implementations of ShapeText should call this 1.1948 + // after glyph shaping has been completed. 1.1949 + void PostShapingFixup(gfxContext *aContext, 1.1950 + const char16_t *aText, 1.1951 + uint32_t aOffset, // position within aShapedText 1.1952 + uint32_t aLength, 1.1953 + gfxShapedText *aShapedText); 1.1954 + 1.1955 + // Shape text directly into a range within a textrun, without using the 1.1956 + // font's word cache. Intended for use when the font has layout features 1.1957 + // that involve space, and therefore require shaping complete runs rather 1.1958 + // than isolated words, or for long strings that are inefficient to cache. 1.1959 + // This will split the text on "invalid" characters (tab/newline) that are 1.1960 + // not handled via normal shaping, but does not otherwise divide up the 1.1961 + // text. 1.1962 + template<typename T> 1.1963 + bool ShapeTextWithoutWordCache(gfxContext *aContext, 1.1964 + const T *aText, 1.1965 + uint32_t aOffset, 1.1966 + uint32_t aLength, 1.1967 + int32_t aScript, 1.1968 + gfxTextRun *aTextRun); 1.1969 + 1.1970 + // Shape a fragment of text (a run that is known to contain only 1.1971 + // "valid" characters, no newlines/tabs/other control chars). 1.1972 + // All non-wordcache shaping goes through here; this is the function 1.1973 + // that will ensure we don't pass excessively long runs to the various 1.1974 + // platform shapers. 1.1975 + template<typename T> 1.1976 + bool ShapeFragmentWithoutWordCache(gfxContext *aContext, 1.1977 + const T *aText, 1.1978 + uint32_t aOffset, 1.1979 + uint32_t aLength, 1.1980 + int32_t aScript, 1.1981 + gfxTextRun *aTextRun); 1.1982 + 1.1983 + void CheckForFeaturesInvolvingSpace(); 1.1984 + 1.1985 + // whether a given feature is included in feature settings from both the 1.1986 + // font and the style. aFeatureOn set if resolved feature value is non-zero 1.1987 + bool HasFeatureSet(uint32_t aFeature, bool& aFeatureOn); 1.1988 + 1.1989 + // used when analyzing whether a font has space contextual lookups 1.1990 + static nsDataHashtable<nsUint32HashKey, int32_t> *sScriptTagToCode; 1.1991 + static nsTHashtable<nsUint32HashKey> *sDefaultFeatures; 1.1992 + 1.1993 + nsRefPtr<gfxFontEntry> mFontEntry; 1.1994 + 1.1995 + struct CacheHashKey { 1.1996 + union { 1.1997 + const uint8_t *mSingle; 1.1998 + const char16_t *mDouble; 1.1999 + } mText; 1.2000 + uint32_t mLength; 1.2001 + uint32_t mFlags; 1.2002 + int32_t mScript; 1.2003 + int32_t mAppUnitsPerDevUnit; 1.2004 + PLDHashNumber mHashKey; 1.2005 + bool mTextIs8Bit; 1.2006 + 1.2007 + CacheHashKey(const uint8_t *aText, uint32_t aLength, 1.2008 + uint32_t aStringHash, 1.2009 + int32_t aScriptCode, int32_t aAppUnitsPerDevUnit, 1.2010 + uint32_t aFlags) 1.2011 + : mLength(aLength), 1.2012 + mFlags(aFlags), 1.2013 + mScript(aScriptCode), 1.2014 + mAppUnitsPerDevUnit(aAppUnitsPerDevUnit), 1.2015 + mHashKey(aStringHash + aScriptCode + 1.2016 + aAppUnitsPerDevUnit * 0x100 + aFlags * 0x10000), 1.2017 + mTextIs8Bit(true) 1.2018 + { 1.2019 + NS_ASSERTION(aFlags & gfxTextRunFactory::TEXT_IS_8BIT, 1.2020 + "8-bit flag should have been set"); 1.2021 + mText.mSingle = aText; 1.2022 + } 1.2023 + 1.2024 + CacheHashKey(const char16_t *aText, uint32_t aLength, 1.2025 + uint32_t aStringHash, 1.2026 + int32_t aScriptCode, int32_t aAppUnitsPerDevUnit, 1.2027 + uint32_t aFlags) 1.2028 + : mLength(aLength), 1.2029 + mFlags(aFlags), 1.2030 + mScript(aScriptCode), 1.2031 + mAppUnitsPerDevUnit(aAppUnitsPerDevUnit), 1.2032 + mHashKey(aStringHash + aScriptCode + 1.2033 + aAppUnitsPerDevUnit * 0x100 + aFlags * 0x10000), 1.2034 + mTextIs8Bit(false) 1.2035 + { 1.2036 + // We can NOT assert that TEXT_IS_8BIT is false in aFlags here, 1.2037 + // because this might be an 8bit-only word from a 16-bit textrun, 1.2038 + // in which case the text we're passed is still in 16-bit form, 1.2039 + // and we'll have to use an 8-to-16bit comparison in KeyEquals. 1.2040 + mText.mDouble = aText; 1.2041 + } 1.2042 + }; 1.2043 + 1.2044 + class CacheHashEntry : public PLDHashEntryHdr { 1.2045 + public: 1.2046 + typedef const CacheHashKey &KeyType; 1.2047 + typedef const CacheHashKey *KeyTypePointer; 1.2048 + 1.2049 + // When constructing a new entry in the hashtable, the caller of Put() 1.2050 + // will fill us in. 1.2051 + CacheHashEntry(KeyTypePointer aKey) { } 1.2052 + CacheHashEntry(const CacheHashEntry& toCopy) { NS_ERROR("Should not be called"); } 1.2053 + ~CacheHashEntry() { } 1.2054 + 1.2055 + bool KeyEquals(const KeyTypePointer aKey) const; 1.2056 + 1.2057 + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } 1.2058 + 1.2059 + static PLDHashNumber HashKey(const KeyTypePointer aKey) { 1.2060 + return aKey->mHashKey; 1.2061 + } 1.2062 + 1.2063 + enum { ALLOW_MEMMOVE = true }; 1.2064 + 1.2065 + nsAutoPtr<gfxShapedWord> mShapedWord; 1.2066 + }; 1.2067 + 1.2068 + static size_t 1.2069 + WordCacheEntrySizeOfExcludingThis(CacheHashEntry* aHashEntry, 1.2070 + mozilla::MallocSizeOf aMallocSizeOf, 1.2071 + void* aUserArg); 1.2072 + 1.2073 + nsAutoPtr<nsTHashtable<CacheHashEntry> > mWordCache; 1.2074 + 1.2075 + static PLDHashOperator AgeCacheEntry(CacheHashEntry *aEntry, void *aUserData); 1.2076 + static const uint32_t kShapedWordCacheMaxAge = 3; 1.2077 + 1.2078 + bool mIsValid; 1.2079 + 1.2080 + // use synthetic bolding for environments where this is not supported 1.2081 + // by the platform 1.2082 + bool mApplySyntheticBold; 1.2083 + 1.2084 + bool mKerningSet; // kerning explicitly set? 1.2085 + bool mKerningEnabled; // if set, on or off? 1.2086 + 1.2087 + nsExpirationState mExpirationState; 1.2088 + gfxFontStyle mStyle; 1.2089 + nsAutoTArray<gfxGlyphExtents*,1> mGlyphExtentsArray; 1.2090 + nsAutoPtr<nsTHashtable<nsPtrHashKey<GlyphChangeObserver> > > mGlyphChangeObservers; 1.2091 + 1.2092 + gfxFloat mAdjustedSize; 1.2093 + 1.2094 + float mFUnitsConvFactor; // conversion factor from font units to dev units 1.2095 + 1.2096 + // the AA setting requested for this font - may affect glyph bounds 1.2097 + AntialiasOption mAntialiasOption; 1.2098 + 1.2099 + // a copy of the font without antialiasing, if needed for separate 1.2100 + // measurement by mathml code 1.2101 + nsAutoPtr<gfxFont> mNonAAFont; 1.2102 + 1.2103 + // we may switch between these shapers on the fly, based on the script 1.2104 + // of the text run being shaped 1.2105 + nsAutoPtr<gfxFontShaper> mPlatformShaper; 1.2106 + nsAutoPtr<gfxFontShaper> mHarfBuzzShaper; 1.2107 + nsAutoPtr<gfxFontShaper> mGraphiteShaper; 1.2108 + 1.2109 + mozilla::RefPtr<mozilla::gfx::ScaledFont> mAzureScaledFont; 1.2110 + 1.2111 + // Create a default platform text shaper for this font. 1.2112 + // (TODO: This should become pure virtual once all font backends have 1.2113 + // been updated.) 1.2114 + virtual void CreatePlatformShaper() { } 1.2115 + 1.2116 + // Helper for subclasses that want to initialize standard metrics from the 1.2117 + // tables of sfnt (TrueType/OpenType) fonts. 1.2118 + // This will use mFUnitsConvFactor if it is already set, else compute it 1.2119 + // from mAdjustedSize and the unitsPerEm in the font's 'head' table. 1.2120 + // Returns TRUE and sets mIsValid=TRUE if successful; 1.2121 + // Returns TRUE but leaves mIsValid=FALSE if the font seems to be broken. 1.2122 + // Returns FALSE if the font does not appear to be an sfnt at all, 1.2123 + // and should be handled (if possible) using other APIs. 1.2124 + bool InitMetricsFromSfntTables(Metrics& aMetrics); 1.2125 + 1.2126 + // Helper to calculate various derived metrics from the results of 1.2127 + // InitMetricsFromSfntTables or equivalent platform code 1.2128 + void CalculateDerivedMetrics(Metrics& aMetrics); 1.2129 + 1.2130 + // some fonts have bad metrics, this method sanitize them. 1.2131 + // if this font has bad underline offset, aIsBadUnderlineFont should be true. 1.2132 + void SanitizeMetrics(gfxFont::Metrics *aMetrics, bool aIsBadUnderlineFont); 1.2133 + 1.2134 + bool RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode, 1.2135 + uint32_t aGlyphId, gfxTextContextPaint *aContextPaint); 1.2136 + bool RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode, 1.2137 + uint32_t aGlyphId, gfxTextContextPaint *aContextPaint, 1.2138 + gfxTextRunDrawCallbacks *aCallbacks, 1.2139 + bool& aEmittedGlyphs); 1.2140 + 1.2141 + // Bug 674909. When synthetic bolding text by drawing twice, need to 1.2142 + // render using a pixel offset in device pixels, otherwise text 1.2143 + // doesn't appear bolded, it appears as if a bad text shadow exists 1.2144 + // when a non-identity transform exists. Use an offset factor so that 1.2145 + // the second draw occurs at a constant offset in device pixels. 1.2146 + // This helper calculates the scale factor we need to apply to the 1.2147 + // synthetic-bold offset. 1.2148 + static double CalcXScale(gfxContext *aContext); 1.2149 +}; 1.2150 + 1.2151 +// proportion of ascent used for x-height, if unable to read value from font 1.2152 +#define DEFAULT_XHEIGHT_FACTOR 0.56f 1.2153 + 1.2154 +/* 1.2155 + * gfxShapedText is an abstract superclass for gfxShapedWord and gfxTextRun. 1.2156 + * These are objects that store a list of zero or more glyphs for each character. 1.2157 + * For each glyph we store the glyph ID, the advance, and possibly x/y-offsets. 1.2158 + * The idea is that a string is rendered by a loop that draws each glyph 1.2159 + * at its designated offset from the current point, then advances the current 1.2160 + * point by the glyph's advance in the direction of the textrun (LTR or RTL). 1.2161 + * Each glyph advance is always rounded to the nearest appunit; this ensures 1.2162 + * consistent results when dividing the text in a textrun into multiple text 1.2163 + * frames (frame boundaries are always aligned to appunits). We optimize 1.2164 + * for the case where a character has a single glyph and zero xoffset and yoffset, 1.2165 + * and the glyph ID and advance are in a reasonable range so we can pack all 1.2166 + * necessary data into 32 bits. 1.2167 + * 1.2168 + * gfxFontShaper can shape text into either a gfxShapedWord (cached by a gfxFont) 1.2169 + * or directly into a gfxTextRun (for cases where we want to shape textruns in 1.2170 + * their entirety rather than using cached words, because there may be layout 1.2171 + * features that depend on the inter-word spaces). 1.2172 + */ 1.2173 +class gfxShapedText 1.2174 +{ 1.2175 +public: 1.2176 + gfxShapedText(uint32_t aLength, uint32_t aFlags, 1.2177 + int32_t aAppUnitsPerDevUnit) 1.2178 + : mLength(aLength) 1.2179 + , mFlags(aFlags) 1.2180 + , mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) 1.2181 + { } 1.2182 + 1.2183 + virtual ~gfxShapedText() { } 1.2184 + 1.2185 + /** 1.2186 + * This class records the information associated with a character in the 1.2187 + * input string. It's optimized for the case where there is one glyph 1.2188 + * representing that character alone. 1.2189 + * 1.2190 + * A character can have zero or more associated glyphs. Each glyph 1.2191 + * has an advance width and an x and y offset. 1.2192 + * A character may be the start of a cluster. 1.2193 + * A character may be the start of a ligature group. 1.2194 + * A character can be "missing", indicating that the system is unable 1.2195 + * to render the character. 1.2196 + * 1.2197 + * All characters in a ligature group conceptually share all the glyphs 1.2198 + * associated with the characters in a group. 1.2199 + */ 1.2200 + class CompressedGlyph { 1.2201 + public: 1.2202 + CompressedGlyph() { mValue = 0; } 1.2203 + 1.2204 + enum { 1.2205 + // Indicates that a cluster and ligature group starts at this 1.2206 + // character; this character has a single glyph with a reasonable 1.2207 + // advance and zero offsets. A "reasonable" advance 1.2208 + // is one that fits in the available bits (currently 12) (specified 1.2209 + // in appunits). 1.2210 + FLAG_IS_SIMPLE_GLYPH = 0x80000000U, 1.2211 + 1.2212 + // Indicates whether a linebreak is allowed before this character; 1.2213 + // this is a two-bit field that holds a FLAG_BREAK_TYPE_xxx value 1.2214 + // indicating the kind of linebreak (if any) allowed here. 1.2215 + FLAGS_CAN_BREAK_BEFORE = 0x60000000U, 1.2216 + 1.2217 + FLAGS_CAN_BREAK_SHIFT = 29, 1.2218 + FLAG_BREAK_TYPE_NONE = 0, 1.2219 + FLAG_BREAK_TYPE_NORMAL = 1, 1.2220 + FLAG_BREAK_TYPE_HYPHEN = 2, 1.2221 + 1.2222 + FLAG_CHAR_IS_SPACE = 0x10000000U, 1.2223 + 1.2224 + // The advance is stored in appunits 1.2225 + ADVANCE_MASK = 0x0FFF0000U, 1.2226 + ADVANCE_SHIFT = 16, 1.2227 + 1.2228 + GLYPH_MASK = 0x0000FFFFU, 1.2229 + 1.2230 + // Non-simple glyphs may or may not have glyph data in the 1.2231 + // corresponding mDetailedGlyphs entry. They have the following 1.2232 + // flag bits: 1.2233 + 1.2234 + // When NOT set, indicates that this character corresponds to a 1.2235 + // missing glyph and should be skipped (or possibly, render the character 1.2236 + // Unicode value in some special way). If there are glyphs, 1.2237 + // the mGlyphID is actually the UTF16 character code. The bit is 1.2238 + // inverted so we can memset the array to zero to indicate all missing. 1.2239 + FLAG_NOT_MISSING = 0x01, 1.2240 + FLAG_NOT_CLUSTER_START = 0x02, 1.2241 + FLAG_NOT_LIGATURE_GROUP_START = 0x04, 1.2242 + 1.2243 + FLAG_CHAR_IS_TAB = 0x08, 1.2244 + FLAG_CHAR_IS_NEWLINE = 0x10, 1.2245 + FLAG_CHAR_IS_LOW_SURROGATE = 0x20, 1.2246 + CHAR_IDENTITY_FLAGS_MASK = 0x38, 1.2247 + 1.2248 + GLYPH_COUNT_MASK = 0x00FFFF00U, 1.2249 + GLYPH_COUNT_SHIFT = 8 1.2250 + }; 1.2251 + 1.2252 + // "Simple glyphs" have a simple glyph ID, simple advance and their 1.2253 + // x and y offsets are zero. Also the glyph extents do not overflow 1.2254 + // the font-box defined by the font ascent, descent and glyph advance width. 1.2255 + // These case is optimized to avoid storing DetailedGlyphs. 1.2256 + 1.2257 + // Returns true if the glyph ID aGlyph fits into the compressed representation 1.2258 + static bool IsSimpleGlyphID(uint32_t aGlyph) { 1.2259 + return (aGlyph & GLYPH_MASK) == aGlyph; 1.2260 + } 1.2261 + // Returns true if the advance aAdvance fits into the compressed representation. 1.2262 + // aAdvance is in appunits. 1.2263 + static bool IsSimpleAdvance(uint32_t aAdvance) { 1.2264 + return (aAdvance & (ADVANCE_MASK >> ADVANCE_SHIFT)) == aAdvance; 1.2265 + } 1.2266 + 1.2267 + bool IsSimpleGlyph() const { return (mValue & FLAG_IS_SIMPLE_GLYPH) != 0; } 1.2268 + uint32_t GetSimpleAdvance() const { return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT; } 1.2269 + uint32_t GetSimpleGlyph() const { return mValue & GLYPH_MASK; } 1.2270 + 1.2271 + bool IsMissing() const { return (mValue & (FLAG_NOT_MISSING|FLAG_IS_SIMPLE_GLYPH)) == 0; } 1.2272 + bool IsClusterStart() const { 1.2273 + return (mValue & FLAG_IS_SIMPLE_GLYPH) || !(mValue & FLAG_NOT_CLUSTER_START); 1.2274 + } 1.2275 + bool IsLigatureGroupStart() const { 1.2276 + return (mValue & FLAG_IS_SIMPLE_GLYPH) || !(mValue & FLAG_NOT_LIGATURE_GROUP_START); 1.2277 + } 1.2278 + bool IsLigatureContinuation() const { 1.2279 + return (mValue & FLAG_IS_SIMPLE_GLYPH) == 0 && 1.2280 + (mValue & (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING)) == 1.2281 + (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING); 1.2282 + } 1.2283 + 1.2284 + // Return true if the original character was a normal (breakable, 1.2285 + // trimmable) space (U+0020). Not true for other characters that 1.2286 + // may happen to map to the space glyph (U+00A0). 1.2287 + bool CharIsSpace() const { 1.2288 + return (mValue & FLAG_CHAR_IS_SPACE) != 0; 1.2289 + } 1.2290 + 1.2291 + bool CharIsTab() const { 1.2292 + return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_TAB) != 0; 1.2293 + } 1.2294 + bool CharIsNewline() const { 1.2295 + return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_NEWLINE) != 0; 1.2296 + } 1.2297 + bool CharIsLowSurrogate() const { 1.2298 + return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_LOW_SURROGATE) != 0; 1.2299 + } 1.2300 + 1.2301 + uint32_t CharIdentityFlags() const { 1.2302 + return IsSimpleGlyph() ? 0 : (mValue & CHAR_IDENTITY_FLAGS_MASK); 1.2303 + } 1.2304 + 1.2305 + void SetClusterStart(bool aIsClusterStart) { 1.2306 + NS_ASSERTION(!IsSimpleGlyph(), 1.2307 + "can't call SetClusterStart on simple glyphs"); 1.2308 + if (aIsClusterStart) { 1.2309 + mValue &= ~FLAG_NOT_CLUSTER_START; 1.2310 + } else { 1.2311 + mValue |= FLAG_NOT_CLUSTER_START; 1.2312 + } 1.2313 + } 1.2314 + 1.2315 + uint8_t CanBreakBefore() const { 1.2316 + return (mValue & FLAGS_CAN_BREAK_BEFORE) >> FLAGS_CAN_BREAK_SHIFT; 1.2317 + } 1.2318 + // Returns FLAGS_CAN_BREAK_BEFORE if the setting changed, 0 otherwise 1.2319 + uint32_t SetCanBreakBefore(uint8_t aCanBreakBefore) { 1.2320 + NS_ASSERTION(aCanBreakBefore <= 2, 1.2321 + "Bogus break-before value!"); 1.2322 + uint32_t breakMask = (uint32_t(aCanBreakBefore) << FLAGS_CAN_BREAK_SHIFT); 1.2323 + uint32_t toggle = breakMask ^ (mValue & FLAGS_CAN_BREAK_BEFORE); 1.2324 + mValue ^= toggle; 1.2325 + return toggle; 1.2326 + } 1.2327 + 1.2328 + CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits, uint32_t aGlyph) { 1.2329 + NS_ASSERTION(IsSimpleAdvance(aAdvanceAppUnits), "Advance overflow"); 1.2330 + NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow"); 1.2331 + NS_ASSERTION(!CharIdentityFlags(), "Char identity flags lost"); 1.2332 + mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) | 1.2333 + FLAG_IS_SIMPLE_GLYPH | 1.2334 + (aAdvanceAppUnits << ADVANCE_SHIFT) | aGlyph; 1.2335 + return *this; 1.2336 + } 1.2337 + CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart, 1.2338 + uint32_t aGlyphCount) { 1.2339 + mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) | 1.2340 + FLAG_NOT_MISSING | 1.2341 + CharIdentityFlags() | 1.2342 + (aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) | 1.2343 + (aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) | 1.2344 + (aGlyphCount << GLYPH_COUNT_SHIFT); 1.2345 + return *this; 1.2346 + } 1.2347 + /** 1.2348 + * Missing glyphs are treated as ligature group starts; don't mess with 1.2349 + * the cluster-start flag (see bugs 618870 and 619286). 1.2350 + */ 1.2351 + CompressedGlyph& SetMissing(uint32_t aGlyphCount) { 1.2352 + mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_NOT_CLUSTER_START | 1.2353 + FLAG_CHAR_IS_SPACE)) | 1.2354 + CharIdentityFlags() | 1.2355 + (aGlyphCount << GLYPH_COUNT_SHIFT); 1.2356 + return *this; 1.2357 + } 1.2358 + uint32_t GetGlyphCount() const { 1.2359 + NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph"); 1.2360 + return (mValue & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT; 1.2361 + } 1.2362 + 1.2363 + void SetIsSpace() { 1.2364 + mValue |= FLAG_CHAR_IS_SPACE; 1.2365 + } 1.2366 + void SetIsTab() { 1.2367 + NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph"); 1.2368 + mValue |= FLAG_CHAR_IS_TAB; 1.2369 + } 1.2370 + void SetIsNewline() { 1.2371 + NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph"); 1.2372 + mValue |= FLAG_CHAR_IS_NEWLINE; 1.2373 + } 1.2374 + void SetIsLowSurrogate() { 1.2375 + NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph"); 1.2376 + mValue |= FLAG_CHAR_IS_LOW_SURROGATE; 1.2377 + } 1.2378 + 1.2379 + private: 1.2380 + uint32_t mValue; 1.2381 + }; 1.2382 + 1.2383 + // Accessor for the array of CompressedGlyph records, which will be in 1.2384 + // a different place in gfxShapedWord vs gfxTextRun 1.2385 + virtual CompressedGlyph *GetCharacterGlyphs() = 0; 1.2386 + 1.2387 + /** 1.2388 + * When the glyphs for a character don't fit into a CompressedGlyph record 1.2389 + * in SimpleGlyph format, we use an array of DetailedGlyphs instead. 1.2390 + */ 1.2391 + struct DetailedGlyph { 1.2392 + /** The glyphID, or the Unicode character 1.2393 + * if this is a missing glyph */ 1.2394 + uint32_t mGlyphID; 1.2395 + /** The advance, x-offset and y-offset of the glyph, in appunits 1.2396 + * mAdvance is in the text direction (RTL or LTR) 1.2397 + * mXOffset is always from left to right 1.2398 + * mYOffset is always from top to bottom */ 1.2399 + int32_t mAdvance; 1.2400 + float mXOffset, mYOffset; 1.2401 + }; 1.2402 + 1.2403 + void SetGlyphs(uint32_t aCharIndex, CompressedGlyph aGlyph, 1.2404 + const DetailedGlyph *aGlyphs); 1.2405 + 1.2406 + void SetMissingGlyph(uint32_t aIndex, uint32_t aChar, gfxFont *aFont); 1.2407 + 1.2408 + void SetIsSpace(uint32_t aIndex) { 1.2409 + GetCharacterGlyphs()[aIndex].SetIsSpace(); 1.2410 + } 1.2411 + 1.2412 + void SetIsLowSurrogate(uint32_t aIndex) { 1.2413 + SetGlyphs(aIndex, CompressedGlyph().SetComplex(false, false, 0), nullptr); 1.2414 + GetCharacterGlyphs()[aIndex].SetIsLowSurrogate(); 1.2415 + } 1.2416 + 1.2417 + bool HasDetailedGlyphs() const { 1.2418 + return mDetailedGlyphs != nullptr; 1.2419 + } 1.2420 + 1.2421 + bool IsClusterStart(uint32_t aPos) { 1.2422 + NS_ASSERTION(aPos < GetLength(), "aPos out of range"); 1.2423 + return GetCharacterGlyphs()[aPos].IsClusterStart(); 1.2424 + } 1.2425 + 1.2426 + bool IsLigatureGroupStart(uint32_t aPos) { 1.2427 + NS_ASSERTION(aPos < GetLength(), "aPos out of range"); 1.2428 + return GetCharacterGlyphs()[aPos].IsLigatureGroupStart(); 1.2429 + } 1.2430 + 1.2431 + // NOTE that this must not be called for a character offset that does 1.2432 + // not have any DetailedGlyph records; callers must have verified that 1.2433 + // GetCharacterGlyphs()[aCharIndex].GetGlyphCount() is greater than zero. 1.2434 + DetailedGlyph *GetDetailedGlyphs(uint32_t aCharIndex) { 1.2435 + NS_ASSERTION(GetCharacterGlyphs() && HasDetailedGlyphs() && 1.2436 + !GetCharacterGlyphs()[aCharIndex].IsSimpleGlyph() && 1.2437 + GetCharacterGlyphs()[aCharIndex].GetGlyphCount() > 0, 1.2438 + "invalid use of GetDetailedGlyphs; check the caller!"); 1.2439 + return mDetailedGlyphs->Get(aCharIndex); 1.2440 + } 1.2441 + 1.2442 + void AdjustAdvancesForSyntheticBold(float aSynBoldOffset, 1.2443 + uint32_t aOffset, uint32_t aLength); 1.2444 + 1.2445 + // Mark clusters in the CompressedGlyph records, starting at aOffset, 1.2446 + // based on the Unicode properties of the text in aString. 1.2447 + // This is also responsible to set the IsSpace flag for space characters. 1.2448 + void SetupClusterBoundaries(uint32_t aOffset, 1.2449 + const char16_t *aString, 1.2450 + uint32_t aLength); 1.2451 + // In 8-bit text, there won't actually be any clusters, but we still need 1.2452 + // the space-marking functionality. 1.2453 + void SetupClusterBoundaries(uint32_t aOffset, 1.2454 + const uint8_t *aString, 1.2455 + uint32_t aLength); 1.2456 + 1.2457 + uint32_t Flags() const { 1.2458 + return mFlags; 1.2459 + } 1.2460 + 1.2461 + bool IsRightToLeft() const { 1.2462 + return (Flags() & gfxTextRunFactory::TEXT_IS_RTL) != 0; 1.2463 + } 1.2464 + 1.2465 + float GetDirection() const { 1.2466 + return IsRightToLeft() ? -1.0f : 1.0f; 1.2467 + } 1.2468 + 1.2469 + bool DisableLigatures() const { 1.2470 + return (Flags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) != 0; 1.2471 + } 1.2472 + 1.2473 + bool TextIs8Bit() const { 1.2474 + return (Flags() & gfxTextRunFactory::TEXT_IS_8BIT) != 0; 1.2475 + } 1.2476 + 1.2477 + int32_t GetAppUnitsPerDevUnit() const { 1.2478 + return mAppUnitsPerDevUnit; 1.2479 + } 1.2480 + 1.2481 + uint32_t GetLength() const { 1.2482 + return mLength; 1.2483 + } 1.2484 + 1.2485 + bool FilterIfIgnorable(uint32_t aIndex, uint32_t aCh); 1.2486 + 1.2487 +protected: 1.2488 + // Allocate aCount DetailedGlyphs for the given index 1.2489 + DetailedGlyph *AllocateDetailedGlyphs(uint32_t aCharIndex, 1.2490 + uint32_t aCount); 1.2491 + 1.2492 + // For characters whose glyph data does not fit the "simple" glyph criteria 1.2493 + // in CompressedGlyph, we use a sorted array to store the association 1.2494 + // between the source character offset and an index into an array 1.2495 + // DetailedGlyphs. The CompressedGlyph record includes a count of 1.2496 + // the number of DetailedGlyph records that belong to the character, 1.2497 + // starting at the given index. 1.2498 + class DetailedGlyphStore { 1.2499 + public: 1.2500 + DetailedGlyphStore() 1.2501 + : mLastUsed(0) 1.2502 + { } 1.2503 + 1.2504 + // This is optimized for the most common calling patterns: 1.2505 + // we rarely need random access to the records, access is most commonly 1.2506 + // sequential through the textRun, so we record the last-used index 1.2507 + // and check whether the caller wants the same record again, or the 1.2508 + // next; if not, it's most likely we're starting over from the start 1.2509 + // of the run, so we check the first entry before resorting to binary 1.2510 + // search as a last resort. 1.2511 + // NOTE that this must not be called for a character offset that does 1.2512 + // not have any DetailedGlyph records; callers must have verified that 1.2513 + // mCharacterGlyphs[aOffset].GetGlyphCount() is greater than zero 1.2514 + // before calling this, otherwise the assertions here will fire (in a 1.2515 + // debug build), and we'll probably crash. 1.2516 + DetailedGlyph* Get(uint32_t aOffset) { 1.2517 + NS_ASSERTION(mOffsetToIndex.Length() > 0, 1.2518 + "no detailed glyph records!"); 1.2519 + DetailedGlyph* details = mDetails.Elements(); 1.2520 + // check common cases (fwd iteration, initial entry, etc) first 1.2521 + if (mLastUsed < mOffsetToIndex.Length() - 1 && 1.2522 + aOffset == mOffsetToIndex[mLastUsed + 1].mOffset) { 1.2523 + ++mLastUsed; 1.2524 + } else if (aOffset == mOffsetToIndex[0].mOffset) { 1.2525 + mLastUsed = 0; 1.2526 + } else if (aOffset == mOffsetToIndex[mLastUsed].mOffset) { 1.2527 + // do nothing 1.2528 + } else if (mLastUsed > 0 && 1.2529 + aOffset == mOffsetToIndex[mLastUsed - 1].mOffset) { 1.2530 + --mLastUsed; 1.2531 + } else { 1.2532 + mLastUsed = 1.2533 + mOffsetToIndex.BinaryIndexOf(aOffset, CompareToOffset()); 1.2534 + } 1.2535 + NS_ASSERTION(mLastUsed != nsTArray<DGRec>::NoIndex, 1.2536 + "detailed glyph record missing!"); 1.2537 + return details + mOffsetToIndex[mLastUsed].mIndex; 1.2538 + } 1.2539 + 1.2540 + DetailedGlyph* Allocate(uint32_t aOffset, uint32_t aCount) { 1.2541 + uint32_t detailIndex = mDetails.Length(); 1.2542 + DetailedGlyph *details = mDetails.AppendElements(aCount); 1.2543 + if (!details) { 1.2544 + return nullptr; 1.2545 + } 1.2546 + // We normally set up glyph records sequentially, so the common case 1.2547 + // here is to append new records to the mOffsetToIndex array; 1.2548 + // test for that before falling back to the InsertElementSorted 1.2549 + // method. 1.2550 + if (mOffsetToIndex.Length() == 0 || 1.2551 + aOffset > mOffsetToIndex[mOffsetToIndex.Length() - 1].mOffset) { 1.2552 + if (!mOffsetToIndex.AppendElement(DGRec(aOffset, detailIndex))) { 1.2553 + return nullptr; 1.2554 + } 1.2555 + } else { 1.2556 + if (!mOffsetToIndex.InsertElementSorted(DGRec(aOffset, detailIndex), 1.2557 + CompareRecordOffsets())) { 1.2558 + return nullptr; 1.2559 + } 1.2560 + } 1.2561 + return details; 1.2562 + } 1.2563 + 1.2564 + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { 1.2565 + return aMallocSizeOf(this) + 1.2566 + mDetails.SizeOfExcludingThis(aMallocSizeOf) + 1.2567 + mOffsetToIndex.SizeOfExcludingThis(aMallocSizeOf); 1.2568 + } 1.2569 + 1.2570 + private: 1.2571 + struct DGRec { 1.2572 + DGRec(const uint32_t& aOffset, const uint32_t& aIndex) 1.2573 + : mOffset(aOffset), mIndex(aIndex) { } 1.2574 + uint32_t mOffset; // source character offset in the textrun 1.2575 + uint32_t mIndex; // index where this char's DetailedGlyphs begin 1.2576 + }; 1.2577 + 1.2578 + struct CompareToOffset { 1.2579 + bool Equals(const DGRec& a, const uint32_t& b) const { 1.2580 + return a.mOffset == b; 1.2581 + } 1.2582 + bool LessThan(const DGRec& a, const uint32_t& b) const { 1.2583 + return a.mOffset < b; 1.2584 + } 1.2585 + }; 1.2586 + 1.2587 + struct CompareRecordOffsets { 1.2588 + bool Equals(const DGRec& a, const DGRec& b) const { 1.2589 + return a.mOffset == b.mOffset; 1.2590 + } 1.2591 + bool LessThan(const DGRec& a, const DGRec& b) const { 1.2592 + return a.mOffset < b.mOffset; 1.2593 + } 1.2594 + }; 1.2595 + 1.2596 + // Concatenated array of all the DetailedGlyph records needed for the 1.2597 + // textRun; individual character offsets are associated with indexes 1.2598 + // into this array via the mOffsetToIndex table. 1.2599 + nsTArray<DetailedGlyph> mDetails; 1.2600 + 1.2601 + // For each character offset that needs DetailedGlyphs, we record the 1.2602 + // index in mDetails where the list of glyphs begins. This array is 1.2603 + // sorted by mOffset. 1.2604 + nsTArray<DGRec> mOffsetToIndex; 1.2605 + 1.2606 + // Records the most recently used index into mOffsetToIndex, so that 1.2607 + // we can support sequential access more quickly than just doing 1.2608 + // a binary search each time. 1.2609 + nsTArray<DGRec>::index_type mLastUsed; 1.2610 + }; 1.2611 + 1.2612 + nsAutoPtr<DetailedGlyphStore> mDetailedGlyphs; 1.2613 + 1.2614 + // Number of char16_t characters and CompressedGlyph glyph records 1.2615 + uint32_t mLength; 1.2616 + 1.2617 + // Shaping flags (direction, ligature-suppression) 1.2618 + uint32_t mFlags; 1.2619 + 1.2620 + int32_t mAppUnitsPerDevUnit; 1.2621 +}; 1.2622 + 1.2623 +/* 1.2624 + * gfxShapedWord: an individual (space-delimited) run of text shaped with a 1.2625 + * particular font, without regard to external context. 1.2626 + * 1.2627 + * The glyph data is copied into gfxTextRuns as needed from the cache of 1.2628 + * ShapedWords associated with each gfxFont instance. 1.2629 + */ 1.2630 +class gfxShapedWord : public gfxShapedText 1.2631 +{ 1.2632 +public: 1.2633 + // Create a ShapedWord that can hold glyphs for aLength characters, 1.2634 + // with mCharacterGlyphs sized appropriately. 1.2635 + // 1.2636 + // Returns null on allocation failure (does NOT use infallible alloc) 1.2637 + // so caller must check for success. 1.2638 + // 1.2639 + // This does NOT perform shaping, so the returned word contains no 1.2640 + // glyph data; the caller must call gfxFont::ShapeText() with appropriate 1.2641 + // parameters to set up the glyphs. 1.2642 + static gfxShapedWord* Create(const uint8_t *aText, uint32_t aLength, 1.2643 + int32_t aRunScript, 1.2644 + int32_t aAppUnitsPerDevUnit, 1.2645 + uint32_t aFlags) { 1.2646 + NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(), 1.2647 + "excessive length for gfxShapedWord!"); 1.2648 + 1.2649 + // Compute size needed including the mCharacterGlyphs array 1.2650 + // and a copy of the original text 1.2651 + uint32_t size = 1.2652 + offsetof(gfxShapedWord, mCharGlyphsStorage) + 1.2653 + aLength * (sizeof(CompressedGlyph) + sizeof(uint8_t)); 1.2654 + void *storage = moz_malloc(size); 1.2655 + if (!storage) { 1.2656 + return nullptr; 1.2657 + } 1.2658 + 1.2659 + // Construct in the pre-allocated storage, using placement new 1.2660 + return new (storage) gfxShapedWord(aText, aLength, aRunScript, 1.2661 + aAppUnitsPerDevUnit, aFlags); 1.2662 + } 1.2663 + 1.2664 + static gfxShapedWord* Create(const char16_t *aText, uint32_t aLength, 1.2665 + int32_t aRunScript, 1.2666 + int32_t aAppUnitsPerDevUnit, 1.2667 + uint32_t aFlags) { 1.2668 + NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(), 1.2669 + "excessive length for gfxShapedWord!"); 1.2670 + 1.2671 + // In the 16-bit version of Create, if the TEXT_IS_8BIT flag is set, 1.2672 + // then we convert the text to an 8-bit version and call the 8-bit 1.2673 + // Create function instead. 1.2674 + if (aFlags & gfxTextRunFactory::TEXT_IS_8BIT) { 1.2675 + nsAutoCString narrowText; 1.2676 + LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength), 1.2677 + narrowText); 1.2678 + return Create((const uint8_t*)(narrowText.BeginReading()), 1.2679 + aLength, aRunScript, aAppUnitsPerDevUnit, aFlags); 1.2680 + } 1.2681 + 1.2682 + uint32_t size = 1.2683 + offsetof(gfxShapedWord, mCharGlyphsStorage) + 1.2684 + aLength * (sizeof(CompressedGlyph) + sizeof(char16_t)); 1.2685 + void *storage = moz_malloc(size); 1.2686 + if (!storage) { 1.2687 + return nullptr; 1.2688 + } 1.2689 + 1.2690 + return new (storage) gfxShapedWord(aText, aLength, aRunScript, 1.2691 + aAppUnitsPerDevUnit, aFlags); 1.2692 + } 1.2693 + 1.2694 + // Override operator delete to properly free the object that was 1.2695 + // allocated via moz_malloc. 1.2696 + void operator delete(void* p) { 1.2697 + moz_free(p); 1.2698 + } 1.2699 + 1.2700 + CompressedGlyph *GetCharacterGlyphs() { 1.2701 + return &mCharGlyphsStorage[0]; 1.2702 + } 1.2703 + 1.2704 + const uint8_t* Text8Bit() const { 1.2705 + NS_ASSERTION(TextIs8Bit(), "invalid use of Text8Bit()"); 1.2706 + return reinterpret_cast<const uint8_t*>(mCharGlyphsStorage + GetLength()); 1.2707 + } 1.2708 + 1.2709 + const char16_t* TextUnicode() const { 1.2710 + NS_ASSERTION(!TextIs8Bit(), "invalid use of TextUnicode()"); 1.2711 + return reinterpret_cast<const char16_t*>(mCharGlyphsStorage + GetLength()); 1.2712 + } 1.2713 + 1.2714 + char16_t GetCharAt(uint32_t aOffset) const { 1.2715 + NS_ASSERTION(aOffset < GetLength(), "aOffset out of range"); 1.2716 + return TextIs8Bit() ? 1.2717 + char16_t(Text8Bit()[aOffset]) : TextUnicode()[aOffset]; 1.2718 + } 1.2719 + 1.2720 + int32_t Script() const { 1.2721 + return mScript; 1.2722 + } 1.2723 + 1.2724 + void ResetAge() { 1.2725 + mAgeCounter = 0; 1.2726 + } 1.2727 + uint32_t IncrementAge() { 1.2728 + return ++mAgeCounter; 1.2729 + } 1.2730 + 1.2731 +private: 1.2732 + // so that gfxTextRun can share our DetailedGlyphStore class 1.2733 + friend class gfxTextRun; 1.2734 + 1.2735 + // Construct storage for a ShapedWord, ready to receive glyph data 1.2736 + gfxShapedWord(const uint8_t *aText, uint32_t aLength, 1.2737 + int32_t aRunScript, int32_t aAppUnitsPerDevUnit, 1.2738 + uint32_t aFlags) 1.2739 + : gfxShapedText(aLength, aFlags | gfxTextRunFactory::TEXT_IS_8BIT, 1.2740 + aAppUnitsPerDevUnit) 1.2741 + , mScript(aRunScript) 1.2742 + , mAgeCounter(0) 1.2743 + { 1.2744 + memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph)); 1.2745 + uint8_t *text = reinterpret_cast<uint8_t*>(&mCharGlyphsStorage[aLength]); 1.2746 + memcpy(text, aText, aLength * sizeof(uint8_t)); 1.2747 + } 1.2748 + 1.2749 + gfxShapedWord(const char16_t *aText, uint32_t aLength, 1.2750 + int32_t aRunScript, int32_t aAppUnitsPerDevUnit, 1.2751 + uint32_t aFlags) 1.2752 + : gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit) 1.2753 + , mScript(aRunScript) 1.2754 + , mAgeCounter(0) 1.2755 + { 1.2756 + memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph)); 1.2757 + char16_t *text = reinterpret_cast<char16_t*>(&mCharGlyphsStorage[aLength]); 1.2758 + memcpy(text, aText, aLength * sizeof(char16_t)); 1.2759 + SetupClusterBoundaries(0, aText, aLength); 1.2760 + } 1.2761 + 1.2762 + int32_t mScript; 1.2763 + 1.2764 + uint32_t mAgeCounter; 1.2765 + 1.2766 + // The mCharGlyphsStorage array is actually a variable-size member; 1.2767 + // when the ShapedWord is created, its size will be increased as necessary 1.2768 + // to allow the proper number of glyphs to be stored. 1.2769 + // The original text, in either 8-bit or 16-bit form, will be stored 1.2770 + // immediately following the CompressedGlyphs. 1.2771 + CompressedGlyph mCharGlyphsStorage[1]; 1.2772 +}; 1.2773 + 1.2774 +/** 1.2775 + * Callback for Draw() to use when drawing text with mode 1.2776 + * DrawMode::GLYPH_PATH. 1.2777 + */ 1.2778 +struct gfxTextRunDrawCallbacks { 1.2779 + 1.2780 + /** 1.2781 + * Constructs a new DrawCallbacks object. 1.2782 + * 1.2783 + * @param aShouldPaintSVGGlyphs If true, SVG glyphs will be 1.2784 + * painted and the NotifyBeforeSVGGlyphPainted/NotifyAfterSVGGlyphPainted 1.2785 + * callbacks will be invoked for each SVG glyph. If false, SVG glyphs 1.2786 + * will not be painted; fallback plain glyphs are not emitted either. 1.2787 + */ 1.2788 + gfxTextRunDrawCallbacks(bool aShouldPaintSVGGlyphs = false) 1.2789 + : mShouldPaintSVGGlyphs(aShouldPaintSVGGlyphs) 1.2790 + { 1.2791 + } 1.2792 + 1.2793 + /** 1.2794 + * Called when a path has been emitted to the gfxContext when 1.2795 + * painting a text run. This can be called any number of times, 1.2796 + * due to partial ligatures and intervening SVG glyphs. 1.2797 + */ 1.2798 + virtual void NotifyGlyphPathEmitted() = 0; 1.2799 + 1.2800 + /** 1.2801 + * Called just before an SVG glyph has been painted to the gfxContext. 1.2802 + */ 1.2803 + virtual void NotifyBeforeSVGGlyphPainted() { } 1.2804 + 1.2805 + /** 1.2806 + * Called just after an SVG glyph has been painted to the gfxContext. 1.2807 + */ 1.2808 + virtual void NotifyAfterSVGGlyphPainted() { } 1.2809 + 1.2810 + bool mShouldPaintSVGGlyphs; 1.2811 +}; 1.2812 + 1.2813 +/** 1.2814 + * gfxTextRun is an abstraction for drawing and measuring substrings of a run 1.2815 + * of text. It stores runs of positioned glyph data, each run having a single 1.2816 + * gfxFont. The glyphs are associated with a string of source text, and the 1.2817 + * gfxTextRun APIs take parameters that are offsets into that source text. 1.2818 + * 1.2819 + * gfxTextRuns are not refcounted. They should be deleted when no longer required. 1.2820 + * 1.2821 + * gfxTextRuns are mostly immutable. The only things that can change are 1.2822 + * inter-cluster spacing and line break placement. Spacing is always obtained 1.2823 + * lazily by methods that need it, it is not cached. Line breaks are stored 1.2824 + * persistently (insofar as they affect the shaping of glyphs; gfxTextRun does 1.2825 + * not actually do anything to explicitly account for line breaks). Initially 1.2826 + * there are no line breaks. The textrun can record line breaks before or after 1.2827 + * any given cluster. (Line breaks specified inside clusters are ignored.) 1.2828 + * 1.2829 + * It is important that zero-length substrings are handled correctly. This will 1.2830 + * be on the test! 1.2831 + */ 1.2832 +class gfxTextRun : public gfxShapedText { 1.2833 +public: 1.2834 + 1.2835 + // Override operator delete to properly free the object that was 1.2836 + // allocated via moz_malloc. 1.2837 + void operator delete(void* p) { 1.2838 + moz_free(p); 1.2839 + } 1.2840 + 1.2841 + virtual ~gfxTextRun(); 1.2842 + 1.2843 + typedef gfxFont::RunMetrics Metrics; 1.2844 + 1.2845 + // Public textrun API for general use 1.2846 + 1.2847 + bool IsClusterStart(uint32_t aPos) { 1.2848 + NS_ASSERTION(aPos < GetLength(), "aPos out of range"); 1.2849 + return mCharacterGlyphs[aPos].IsClusterStart(); 1.2850 + } 1.2851 + bool IsLigatureGroupStart(uint32_t aPos) { 1.2852 + NS_ASSERTION(aPos < GetLength(), "aPos out of range"); 1.2853 + return mCharacterGlyphs[aPos].IsLigatureGroupStart(); 1.2854 + } 1.2855 + bool CanBreakLineBefore(uint32_t aPos) { 1.2856 + NS_ASSERTION(aPos < GetLength(), "aPos out of range"); 1.2857 + return mCharacterGlyphs[aPos].CanBreakBefore() == 1.2858 + CompressedGlyph::FLAG_BREAK_TYPE_NORMAL; 1.2859 + } 1.2860 + bool CanHyphenateBefore(uint32_t aPos) { 1.2861 + NS_ASSERTION(aPos < GetLength(), "aPos out of range"); 1.2862 + return mCharacterGlyphs[aPos].CanBreakBefore() == 1.2863 + CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN; 1.2864 + } 1.2865 + 1.2866 + bool CharIsSpace(uint32_t aPos) { 1.2867 + NS_ASSERTION(aPos < GetLength(), "aPos out of range"); 1.2868 + return mCharacterGlyphs[aPos].CharIsSpace(); 1.2869 + } 1.2870 + bool CharIsTab(uint32_t aPos) { 1.2871 + NS_ASSERTION(aPos < GetLength(), "aPos out of range"); 1.2872 + return mCharacterGlyphs[aPos].CharIsTab(); 1.2873 + } 1.2874 + bool CharIsNewline(uint32_t aPos) { 1.2875 + NS_ASSERTION(aPos < GetLength(), "aPos out of range"); 1.2876 + return mCharacterGlyphs[aPos].CharIsNewline(); 1.2877 + } 1.2878 + bool CharIsLowSurrogate(uint32_t aPos) { 1.2879 + NS_ASSERTION(aPos < GetLength(), "aPos out of range"); 1.2880 + return mCharacterGlyphs[aPos].CharIsLowSurrogate(); 1.2881 + } 1.2882 + 1.2883 + uint32_t GetLength() { return mLength; } 1.2884 + 1.2885 + // All uint32_t aStart, uint32_t aLength ranges below are restricted to 1.2886 + // grapheme cluster boundaries! All offsets are in terms of the string 1.2887 + // passed into MakeTextRun. 1.2888 + 1.2889 + // All coordinates are in layout/app units 1.2890 + 1.2891 + /** 1.2892 + * Set the potential linebreaks for a substring of the textrun. These are 1.2893 + * the "allow break before" points. Initially, there are no potential 1.2894 + * linebreaks. 1.2895 + * 1.2896 + * This can change glyphs and/or geometry! Some textruns' shapes 1.2897 + * depend on potential line breaks (e.g., title-case-converting textruns). 1.2898 + * This function is virtual so that those textruns can reshape themselves. 1.2899 + * 1.2900 + * @return true if this changed the linebreaks, false if the new line 1.2901 + * breaks are the same as the old 1.2902 + */ 1.2903 + virtual bool SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength, 1.2904 + uint8_t *aBreakBefore, 1.2905 + gfxContext *aRefContext); 1.2906 + 1.2907 + /** 1.2908 + * Layout provides PropertyProvider objects. These allow detection of 1.2909 + * potential line break points and computation of spacing. We pass the data 1.2910 + * this way to allow lazy data acquisition; for example BreakAndMeasureText 1.2911 + * will want to only ask for properties of text it's actually looking at. 1.2912 + * 1.2913 + * NOTE that requested spacing may not actually be applied, if the textrun 1.2914 + * is unable to apply it in some context. Exception: spacing around a 1.2915 + * whitespace character MUST always be applied. 1.2916 + */ 1.2917 + class PropertyProvider { 1.2918 + public: 1.2919 + // Detect hyphenation break opportunities in the given range; breaks 1.2920 + // not at cluster boundaries will be ignored. 1.2921 + virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength, 1.2922 + bool *aBreakBefore) = 0; 1.2923 + 1.2924 + // Returns the provider's hyphenation setting, so callers can decide 1.2925 + // whether it is necessary to call GetHyphenationBreaks. 1.2926 + // Result is an NS_STYLE_HYPHENS_* value. 1.2927 + virtual int8_t GetHyphensOption() = 0; 1.2928 + 1.2929 + // Returns the extra width that will be consumed by a hyphen. This should 1.2930 + // be constant for a given textrun. 1.2931 + virtual gfxFloat GetHyphenWidth() = 0; 1.2932 + 1.2933 + typedef gfxFont::Spacing Spacing; 1.2934 + 1.2935 + /** 1.2936 + * Get the spacing around the indicated characters. Spacing must be zero 1.2937 + * inside clusters. In other words, if character i is not 1.2938 + * CLUSTER_START, then character i-1 must have zero after-spacing and 1.2939 + * character i must have zero before-spacing. 1.2940 + */ 1.2941 + virtual void GetSpacing(uint32_t aStart, uint32_t aLength, 1.2942 + Spacing *aSpacing) = 0; 1.2943 + 1.2944 + // Returns a gfxContext that can be used to measure the hyphen glyph. 1.2945 + // Only called if the hyphen width is requested. 1.2946 + virtual already_AddRefed<gfxContext> GetContext() = 0; 1.2947 + 1.2948 + // Return the appUnitsPerDevUnit value to be used when measuring. 1.2949 + // Only called if the hyphen width is requested. 1.2950 + virtual uint32_t GetAppUnitsPerDevUnit() = 0; 1.2951 + }; 1.2952 + 1.2953 + class ClusterIterator { 1.2954 + public: 1.2955 + ClusterIterator(gfxTextRun *aTextRun); 1.2956 + 1.2957 + void Reset(); 1.2958 + 1.2959 + bool NextCluster(); 1.2960 + 1.2961 + uint32_t Position() const { 1.2962 + return mCurrentChar; 1.2963 + } 1.2964 + 1.2965 + uint32_t ClusterLength() const; 1.2966 + 1.2967 + gfxFloat ClusterAdvance(PropertyProvider *aProvider) const; 1.2968 + 1.2969 + private: 1.2970 + gfxTextRun *mTextRun; 1.2971 + uint32_t mCurrentChar; 1.2972 + }; 1.2973 + 1.2974 + /** 1.2975 + * Draws a substring. Uses only GetSpacing from aBreakProvider. 1.2976 + * The provided point is the baseline origin on the left of the string 1.2977 + * for LTR, on the right of the string for RTL. 1.2978 + * @param aAdvanceWidth if non-null, the advance width of the substring 1.2979 + * is returned here. 1.2980 + * 1.2981 + * Drawing should respect advance widths in the sense that for LTR runs, 1.2982 + * Draw(ctx, pt, offset1, length1, dirty, &provider, &advance) followed by 1.2983 + * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1 + length1, length2, 1.2984 + * dirty, &provider, nullptr) should have the same effect as 1.2985 + * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr). 1.2986 + * For RTL runs the rule is: 1.2987 + * Draw(ctx, pt, offset1 + length1, length2, dirty, &provider, &advance) followed by 1.2988 + * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1, length1, 1.2989 + * dirty, &provider, nullptr) should have the same effect as 1.2990 + * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr). 1.2991 + * 1.2992 + * Glyphs should be drawn in logical content order, which can be significant 1.2993 + * if they overlap (perhaps due to negative spacing). 1.2994 + */ 1.2995 + void Draw(gfxContext *aContext, gfxPoint aPt, 1.2996 + DrawMode aDrawMode, 1.2997 + uint32_t aStart, uint32_t aLength, 1.2998 + PropertyProvider *aProvider, 1.2999 + gfxFloat *aAdvanceWidth, gfxTextContextPaint *aContextPaint, 1.3000 + gfxTextRunDrawCallbacks *aCallbacks = nullptr); 1.3001 + 1.3002 + /** 1.3003 + * Computes the ReflowMetrics for a substring. 1.3004 + * Uses GetSpacing from aBreakProvider. 1.3005 + * @param aBoundingBoxType which kind of bounding box (loose/tight) 1.3006 + */ 1.3007 + Metrics MeasureText(uint32_t aStart, uint32_t aLength, 1.3008 + gfxFont::BoundingBoxType aBoundingBoxType, 1.3009 + gfxContext *aRefContextForTightBoundingBox, 1.3010 + PropertyProvider *aProvider); 1.3011 + 1.3012 + /** 1.3013 + * Computes just the advance width for a substring. 1.3014 + * Uses GetSpacing from aBreakProvider. 1.3015 + */ 1.3016 + gfxFloat GetAdvanceWidth(uint32_t aStart, uint32_t aLength, 1.3017 + PropertyProvider *aProvider); 1.3018 + 1.3019 + /** 1.3020 + * Clear all stored line breaks for the given range (both before and after), 1.3021 + * and then set the line-break state before aStart to aBreakBefore and 1.3022 + * after the last cluster to aBreakAfter. 1.3023 + * 1.3024 + * We require that before and after line breaks be consistent. For clusters 1.3025 + * i and i+1, we require that if there is a break after cluster i, a break 1.3026 + * will be specified before cluster i+1. This may be temporarily violated 1.3027 + * (e.g. after reflowing line L and before reflowing line L+1); to handle 1.3028 + * these temporary violations, we say that there is a break betwen i and i+1 1.3029 + * if a break is specified after i OR a break is specified before i+1. 1.3030 + * 1.3031 + * This can change textrun geometry! The existence of a linebreak can affect 1.3032 + * the advance width of the cluster before the break (when kerning) or the 1.3033 + * geometry of one cluster before the break or any number of clusters 1.3034 + * after the break. (The one-cluster-before-the-break limit is somewhat 1.3035 + * arbitrary; if some scripts require breaking it, then we need to 1.3036 + * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase 1.3037 + * it could affect the layout of frames before it...) 1.3038 + * 1.3039 + * We return true if glyphs or geometry changed, false otherwise. This 1.3040 + * function is virtual so that gfxTextRun subclasses can reshape 1.3041 + * properly. 1.3042 + * 1.3043 + * @param aAdvanceWidthDelta if non-null, returns the change in advance 1.3044 + * width of the given range. 1.3045 + */ 1.3046 + virtual bool SetLineBreaks(uint32_t aStart, uint32_t aLength, 1.3047 + bool aLineBreakBefore, bool aLineBreakAfter, 1.3048 + gfxFloat *aAdvanceWidthDelta, 1.3049 + gfxContext *aRefContext); 1.3050 + 1.3051 + /** 1.3052 + * Finds the longest substring that will fit into the given width. 1.3053 + * Uses GetHyphenationBreaks and GetSpacing from aBreakProvider. 1.3054 + * Guarantees the following: 1.3055 + * -- 0 <= result <= aMaxLength 1.3056 + * -- result is the maximal value of N such that either 1.3057 + * N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth 1.3058 + * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth 1.3059 + * OR N == aMaxLength && GetAdvanceWidth(aStart, N) <= aWidth 1.3060 + * where GetAdvanceWidth assumes the effect of 1.3061 + * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider) 1.3062 + * -- if no such N exists, then result is the smallest N such that 1.3063 + * N < aMaxLength && line break at N 1.3064 + * OR N < aMaxLength && hyphen break at N 1.3065 + * OR N == aMaxLength 1.3066 + * 1.3067 + * The call has the effect of 1.3068 + * SetLineBreaks(aStart, result, aLineBreakBefore, result < aMaxLength, aProvider) 1.3069 + * and the returned metrics and the invariants above reflect this. 1.3070 + * 1.3071 + * @param aMaxLength this can be UINT32_MAX, in which case the length used 1.3072 + * is up to the end of the string 1.3073 + * @param aLineBreakBefore set to true if and only if there is an actual 1.3074 + * line break at the start of this string. 1.3075 + * @param aSuppressInitialBreak if true, then we assume there is no possible 1.3076 + * linebreak before aStart. If false, then we will check the internal 1.3077 + * line break opportunity state before deciding whether to return 0 as the 1.3078 + * character to break before. 1.3079 + * @param aTrimWhitespace if non-null, then we allow a trailing run of 1.3080 + * spaces to be trimmed; the width of the space(s) will not be included in 1.3081 + * the measured string width for comparison with the limit aWidth, and 1.3082 + * trimmed spaces will not be included in returned metrics. The width 1.3083 + * of the trimmed spaces will be returned in aTrimWhitespace. 1.3084 + * Trimmed spaces are still counted in the "characters fit" result. 1.3085 + * @param aMetrics if non-null, we fill this in for the returned substring. 1.3086 + * If a hyphenation break was used, the hyphen is NOT included in the returned metrics. 1.3087 + * @param aBoundingBoxType whether to make the bounding box in aMetrics tight 1.3088 + * @param aRefContextForTightBoundingBox a reference context to get the 1.3089 + * tight bounding box, if requested 1.3090 + * @param aUsedHyphenation if non-null, records if we selected a hyphenation break 1.3091 + * @param aLastBreak if non-null and result is aMaxLength, we set this to 1.3092 + * the maximal N such that 1.3093 + * N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth 1.3094 + * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth 1.3095 + * or UINT32_MAX if no such N exists, where GetAdvanceWidth assumes 1.3096 + * the effect of 1.3097 + * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider) 1.3098 + * 1.3099 + * @param aCanWordWrap true if we can break between any two grapheme 1.3100 + * clusters. This is set by word-wrap: break-word 1.3101 + * 1.3102 + * @param aBreakPriority in/out the priority of the break opportunity 1.3103 + * saved in the line. If we are prioritizing break opportunities, we will 1.3104 + * not set a break with a lower priority. @see gfxBreakPriority. 1.3105 + * 1.3106 + * Note that negative advance widths are possible especially if negative 1.3107 + * spacing is provided. 1.3108 + */ 1.3109 + uint32_t BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, 1.3110 + bool aLineBreakBefore, gfxFloat aWidth, 1.3111 + PropertyProvider *aProvider, 1.3112 + bool aSuppressInitialBreak, 1.3113 + gfxFloat *aTrimWhitespace, 1.3114 + Metrics *aMetrics, 1.3115 + gfxFont::BoundingBoxType aBoundingBoxType, 1.3116 + gfxContext *aRefContextForTightBoundingBox, 1.3117 + bool *aUsedHyphenation, 1.3118 + uint32_t *aLastBreak, 1.3119 + bool aCanWordWrap, 1.3120 + gfxBreakPriority *aBreakPriority); 1.3121 + 1.3122 + /** 1.3123 + * Update the reference context. 1.3124 + * XXX this is a hack. New text frame does not call this. Use only 1.3125 + * temporarily for old text frame. 1.3126 + */ 1.3127 + void SetContext(gfxContext *aContext) {} 1.3128 + 1.3129 + // Utility getters 1.3130 + 1.3131 + gfxFloat GetDirection() const { return (mFlags & gfxTextRunFactory::TEXT_IS_RTL) ? -1.0 : 1.0; } 1.3132 + void *GetUserData() const { return mUserData; } 1.3133 + void SetUserData(void *aUserData) { mUserData = aUserData; } 1.3134 + uint32_t GetFlags() const { return mFlags; } 1.3135 + void SetFlagBits(uint32_t aFlags) { 1.3136 + NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS), 1.3137 + "Only user flags should be mutable"); 1.3138 + mFlags |= aFlags; 1.3139 + } 1.3140 + void ClearFlagBits(uint32_t aFlags) { 1.3141 + NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS), 1.3142 + "Only user flags should be mutable"); 1.3143 + mFlags &= ~aFlags; 1.3144 + } 1.3145 + const gfxSkipChars& GetSkipChars() const { return mSkipChars; } 1.3146 + gfxFontGroup *GetFontGroup() const { return mFontGroup; } 1.3147 + 1.3148 + 1.3149 + // Call this, don't call "new gfxTextRun" directly. This does custom 1.3150 + // allocation and initialization 1.3151 + static gfxTextRun *Create(const gfxTextRunFactory::Parameters *aParams, 1.3152 + uint32_t aLength, gfxFontGroup *aFontGroup, 1.3153 + uint32_t aFlags); 1.3154 + 1.3155 + // The text is divided into GlyphRuns as necessary 1.3156 + struct GlyphRun { 1.3157 + nsRefPtr<gfxFont> mFont; // never null 1.3158 + uint32_t mCharacterOffset; // into original UTF16 string 1.3159 + uint8_t mMatchType; 1.3160 + }; 1.3161 + 1.3162 + class GlyphRunIterator { 1.3163 + public: 1.3164 + GlyphRunIterator(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aLength) 1.3165 + : mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) { 1.3166 + mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart); 1.3167 + } 1.3168 + bool NextRun(); 1.3169 + GlyphRun *GetGlyphRun() { return mGlyphRun; } 1.3170 + uint32_t GetStringStart() { return mStringStart; } 1.3171 + uint32_t GetStringEnd() { return mStringEnd; } 1.3172 + private: 1.3173 + gfxTextRun *mTextRun; 1.3174 + GlyphRun *mGlyphRun; 1.3175 + uint32_t mStringStart; 1.3176 + uint32_t mStringEnd; 1.3177 + uint32_t mNextIndex; 1.3178 + uint32_t mStartOffset; 1.3179 + uint32_t mEndOffset; 1.3180 + }; 1.3181 + 1.3182 + class GlyphRunOffsetComparator { 1.3183 + public: 1.3184 + bool Equals(const GlyphRun& a, 1.3185 + const GlyphRun& b) const 1.3186 + { 1.3187 + return a.mCharacterOffset == b.mCharacterOffset; 1.3188 + } 1.3189 + 1.3190 + bool LessThan(const GlyphRun& a, 1.3191 + const GlyphRun& b) const 1.3192 + { 1.3193 + return a.mCharacterOffset < b.mCharacterOffset; 1.3194 + } 1.3195 + }; 1.3196 + 1.3197 + friend class GlyphRunIterator; 1.3198 + friend class FontSelector; 1.3199 + 1.3200 + // API for setting up the textrun glyphs. Should only be called by 1.3201 + // things that construct textruns. 1.3202 + /** 1.3203 + * We've found a run of text that should use a particular font. Call this 1.3204 + * only during initialization when font substitution has been computed. 1.3205 + * Call it before setting up the glyphs for the characters in this run; 1.3206 + * SetMissingGlyph requires that the correct glyphrun be installed. 1.3207 + * 1.3208 + * If aForceNewRun, a new glyph run will be added, even if the 1.3209 + * previously added run uses the same font. If glyph runs are 1.3210 + * added out of strictly increasing aStartCharIndex order (via 1.3211 + * force), then SortGlyphRuns must be called after all glyph runs 1.3212 + * are added before any further operations are performed with this 1.3213 + * TextRun. 1.3214 + */ 1.3215 + nsresult AddGlyphRun(gfxFont *aFont, uint8_t aMatchType, 1.3216 + uint32_t aStartCharIndex, bool aForceNewRun); 1.3217 + void ResetGlyphRuns() { mGlyphRuns.Clear(); } 1.3218 + void SortGlyphRuns(); 1.3219 + void SanitizeGlyphRuns(); 1.3220 + 1.3221 + CompressedGlyph* GetCharacterGlyphs() { 1.3222 + NS_ASSERTION(mCharacterGlyphs, "failed to initialize mCharacterGlyphs"); 1.3223 + return mCharacterGlyphs; 1.3224 + } 1.3225 + 1.3226 + void SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, uint32_t aCharIndex); 1.3227 + 1.3228 + // Set the glyph data for the given character index to the font's 1.3229 + // space glyph, IF this can be done as a "simple" glyph record 1.3230 + // (not requiring a DetailedGlyph entry). This avoids the need to call 1.3231 + // the font shaper and go through the shaped-word cache for most spaces. 1.3232 + // 1.3233 + // The parameter aSpaceChar is the original character code for which 1.3234 + // this space glyph is being used; if this is U+0020, we need to record 1.3235 + // that it could be trimmed at a run edge, whereas other kinds of space 1.3236 + // (currently just U+00A0) would not be trimmable/breakable. 1.3237 + // 1.3238 + // Returns true if it was able to set simple glyph data for the space; 1.3239 + // if it returns false, the caller needs to fall back to some other 1.3240 + // means to create the necessary (detailed) glyph data. 1.3241 + bool SetSpaceGlyphIfSimple(gfxFont *aFont, gfxContext *aContext, 1.3242 + uint32_t aCharIndex, char16_t aSpaceChar); 1.3243 + 1.3244 + // Record the positions of specific characters that layout may need to 1.3245 + // detect in the textrun, even though it doesn't have an explicit copy 1.3246 + // of the original text. These are recorded using flag bits in the 1.3247 + // CompressedGlyph record; if necessary, we convert "simple" glyph records 1.3248 + // to "complex" ones as the Tab and Newline flags are not present in 1.3249 + // simple CompressedGlyph records. 1.3250 + void SetIsTab(uint32_t aIndex) { 1.3251 + CompressedGlyph *g = &mCharacterGlyphs[aIndex]; 1.3252 + if (g->IsSimpleGlyph()) { 1.3253 + DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1); 1.3254 + details->mGlyphID = g->GetSimpleGlyph(); 1.3255 + details->mAdvance = g->GetSimpleAdvance(); 1.3256 + details->mXOffset = details->mYOffset = 0; 1.3257 + SetGlyphs(aIndex, CompressedGlyph().SetComplex(true, true, 1), details); 1.3258 + } 1.3259 + g->SetIsTab(); 1.3260 + } 1.3261 + void SetIsNewline(uint32_t aIndex) { 1.3262 + CompressedGlyph *g = &mCharacterGlyphs[aIndex]; 1.3263 + if (g->IsSimpleGlyph()) { 1.3264 + DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1); 1.3265 + details->mGlyphID = g->GetSimpleGlyph(); 1.3266 + details->mAdvance = g->GetSimpleAdvance(); 1.3267 + details->mXOffset = details->mYOffset = 0; 1.3268 + SetGlyphs(aIndex, CompressedGlyph().SetComplex(true, true, 1), details); 1.3269 + } 1.3270 + g->SetIsNewline(); 1.3271 + } 1.3272 + void SetIsLowSurrogate(uint32_t aIndex) { 1.3273 + SetGlyphs(aIndex, CompressedGlyph().SetComplex(false, false, 0), nullptr); 1.3274 + mCharacterGlyphs[aIndex].SetIsLowSurrogate(); 1.3275 + } 1.3276 + 1.3277 + /** 1.3278 + * Prefetch all the glyph extents needed to ensure that Measure calls 1.3279 + * on this textrun not requesting tight boundingBoxes will succeed. Note 1.3280 + * that some glyph extents might not be fetched due to OOM or other 1.3281 + * errors. 1.3282 + */ 1.3283 + void FetchGlyphExtents(gfxContext *aRefContext); 1.3284 + 1.3285 + uint32_t CountMissingGlyphs(); 1.3286 + const GlyphRun *GetGlyphRuns(uint32_t *aNumGlyphRuns) { 1.3287 + *aNumGlyphRuns = mGlyphRuns.Length(); 1.3288 + return mGlyphRuns.Elements(); 1.3289 + } 1.3290 + // Returns the index of the GlyphRun containing the given offset. 1.3291 + // Returns mGlyphRuns.Length() when aOffset is mCharacterCount. 1.3292 + uint32_t FindFirstGlyphRunContaining(uint32_t aOffset); 1.3293 + 1.3294 + // Copy glyph data from a ShapedWord into this textrun. 1.3295 + void CopyGlyphDataFrom(gfxShapedWord *aSource, uint32_t aStart); 1.3296 + 1.3297 + // Copy glyph data for a range of characters from aSource to this 1.3298 + // textrun. 1.3299 + void CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart, 1.3300 + uint32_t aLength, uint32_t aDest); 1.3301 + 1.3302 + nsExpirationState *GetExpirationState() { return &mExpirationState; } 1.3303 + 1.3304 + // Tell the textrun to release its reference to its creating gfxFontGroup 1.3305 + // immediately, rather than on destruction. This is used for textruns 1.3306 + // that are actually owned by a gfxFontGroup, so that they don't keep it 1.3307 + // permanently alive due to a circular reference. (The caller of this is 1.3308 + // taking responsibility for ensuring the textrun will not outlive its 1.3309 + // mFontGroup.) 1.3310 + void ReleaseFontGroup(); 1.3311 + 1.3312 + struct LigatureData { 1.3313 + // textrun offsets of the start and end of the containing ligature 1.3314 + uint32_t mLigatureStart; 1.3315 + uint32_t mLigatureEnd; 1.3316 + // appunits advance to the start of the ligature part within the ligature; 1.3317 + // never includes any spacing 1.3318 + gfxFloat mPartAdvance; 1.3319 + // appunits width of the ligature part; includes before-spacing 1.3320 + // when the part is at the start of the ligature, and after-spacing 1.3321 + // when the part is as the end of the ligature 1.3322 + gfxFloat mPartWidth; 1.3323 + 1.3324 + bool mClipBeforePart; 1.3325 + bool mClipAfterPart; 1.3326 + }; 1.3327 + 1.3328 + // return storage used by this run, for memory reporter; 1.3329 + // nsTransformedTextRun needs to override this as it holds additional data 1.3330 + virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) 1.3331 + MOZ_MUST_OVERRIDE; 1.3332 + virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) 1.3333 + MOZ_MUST_OVERRIDE; 1.3334 + 1.3335 + // Get the size, if it hasn't already been gotten, marking as it goes. 1.3336 + size_t MaybeSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { 1.3337 + if (mFlags & gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED) { 1.3338 + return 0; 1.3339 + } 1.3340 + mFlags |= gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED; 1.3341 + return SizeOfIncludingThis(aMallocSizeOf); 1.3342 + } 1.3343 + void ResetSizeOfAccountingFlags() { 1.3344 + mFlags &= ~gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED; 1.3345 + } 1.3346 + 1.3347 +#ifdef DEBUG 1.3348 + void Dump(FILE* aOutput); 1.3349 +#endif 1.3350 + 1.3351 +protected: 1.3352 + /** 1.3353 + * Create a textrun, and set its mCharacterGlyphs to point immediately 1.3354 + * after the base object; this is ONLY used in conjunction with placement 1.3355 + * new, after allocating a block large enough for the glyph records to 1.3356 + * follow the base textrun object. 1.3357 + */ 1.3358 + gfxTextRun(const gfxTextRunFactory::Parameters *aParams, 1.3359 + uint32_t aLength, gfxFontGroup *aFontGroup, uint32_t aFlags); 1.3360 + 1.3361 + /** 1.3362 + * Helper for the Create() factory method to allocate the required 1.3363 + * glyph storage for a textrun object with the basic size aSize, 1.3364 + * plus room for aLength glyph records. 1.3365 + */ 1.3366 + static void* AllocateStorageForTextRun(size_t aSize, uint32_t aLength); 1.3367 + 1.3368 + // Pointer to the array of CompressedGlyph records; must be initialized 1.3369 + // when the object is constructed. 1.3370 + CompressedGlyph *mCharacterGlyphs; 1.3371 + 1.3372 +private: 1.3373 + // **** general helpers **** 1.3374 + 1.3375 + // Allocate aCount DetailedGlyphs for the given index 1.3376 + DetailedGlyph *AllocateDetailedGlyphs(uint32_t aCharIndex, uint32_t aCount); 1.3377 + 1.3378 + // Get the total advance for a range of glyphs. 1.3379 + int32_t GetAdvanceForGlyphs(uint32_t aStart, uint32_t aEnd); 1.3380 + 1.3381 + // Spacing for characters outside the range aSpacingStart/aSpacingEnd 1.3382 + // is assumed to be zero; such characters are not passed to aProvider. 1.3383 + // This is useful to protect aProvider from being passed character indices 1.3384 + // it is not currently able to handle. 1.3385 + bool GetAdjustedSpacingArray(uint32_t aStart, uint32_t aEnd, 1.3386 + PropertyProvider *aProvider, 1.3387 + uint32_t aSpacingStart, uint32_t aSpacingEnd, 1.3388 + nsTArray<PropertyProvider::Spacing> *aSpacing); 1.3389 + 1.3390 + // **** ligature helpers **** 1.3391 + // (Platforms do the actual ligaturization, but we need to do a bunch of stuff 1.3392 + // to handle requests that begin or end inside a ligature) 1.3393 + 1.3394 + // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero 1.3395 + LigatureData ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd, 1.3396 + PropertyProvider *aProvider); 1.3397 + gfxFloat ComputePartialLigatureWidth(uint32_t aPartStart, uint32_t aPartEnd, 1.3398 + PropertyProvider *aProvider); 1.3399 + void DrawPartialLigature(gfxFont *aFont, gfxContext *aCtx, 1.3400 + uint32_t aStart, uint32_t aEnd, gfxPoint *aPt, 1.3401 + PropertyProvider *aProvider, 1.3402 + gfxTextRunDrawCallbacks *aCallbacks); 1.3403 + // Advance aStart to the start of the nearest ligature; back up aEnd 1.3404 + // to the nearest ligature end; may result in *aStart == *aEnd 1.3405 + void ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd); 1.3406 + // result in appunits 1.3407 + gfxFloat GetPartialLigatureWidth(uint32_t aStart, uint32_t aEnd, PropertyProvider *aProvider); 1.3408 + void AccumulatePartialLigatureMetrics(gfxFont *aFont, 1.3409 + uint32_t aStart, uint32_t aEnd, 1.3410 + gfxFont::BoundingBoxType aBoundingBoxType, 1.3411 + gfxContext *aRefContext, 1.3412 + PropertyProvider *aProvider, 1.3413 + Metrics *aMetrics); 1.3414 + 1.3415 + // **** measurement helper **** 1.3416 + void AccumulateMetricsForRun(gfxFont *aFont, uint32_t aStart, uint32_t aEnd, 1.3417 + gfxFont::BoundingBoxType aBoundingBoxType, 1.3418 + gfxContext *aRefContext, 1.3419 + PropertyProvider *aProvider, 1.3420 + uint32_t aSpacingStart, uint32_t aSpacingEnd, 1.3421 + Metrics *aMetrics); 1.3422 + 1.3423 + // **** drawing helper **** 1.3424 + void DrawGlyphs(gfxFont *aFont, gfxContext *aContext, 1.3425 + DrawMode aDrawMode, gfxPoint *aPt, 1.3426 + gfxTextContextPaint *aContextPaint, uint32_t aStart, 1.3427 + uint32_t aEnd, PropertyProvider *aProvider, 1.3428 + uint32_t aSpacingStart, uint32_t aSpacingEnd, 1.3429 + gfxTextRunDrawCallbacks *aCallbacks); 1.3430 + 1.3431 + // XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*, 1.3432 + // for smaller size especially in the super-common one-glyphrun case 1.3433 + nsAutoTArray<GlyphRun,1> mGlyphRuns; 1.3434 + 1.3435 + void *mUserData; 1.3436 + gfxFontGroup *mFontGroup; // addrefed on creation, but our reference 1.3437 + // may be released by ReleaseFontGroup() 1.3438 + gfxSkipChars mSkipChars; 1.3439 + nsExpirationState mExpirationState; 1.3440 + 1.3441 + bool mSkipDrawing; // true if the font group we used had a user font 1.3442 + // download that's in progress, so we should hide text 1.3443 + // until the download completes (or timeout fires) 1.3444 + bool mReleasedFontGroup; // we already called NS_RELEASE on 1.3445 + // mFontGroup, so don't do it again 1.3446 +}; 1.3447 + 1.3448 +class gfxFontGroup : public gfxTextRunFactory { 1.3449 +public: 1.3450 + class FamilyFace { 1.3451 + public: 1.3452 + FamilyFace() { } 1.3453 + 1.3454 + FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont) 1.3455 + : mFamily(aFamily), mFont(aFont) 1.3456 + { 1.3457 + NS_ASSERTION(aFont, "font pointer must not be null"); 1.3458 + NS_ASSERTION(!aFamily || 1.3459 + aFamily->ContainsFace(aFont->GetFontEntry()), 1.3460 + "font is not a member of the given family"); 1.3461 + } 1.3462 + 1.3463 + gfxFontFamily* Family() const { return mFamily.get(); } 1.3464 + gfxFont* Font() const { return mFont.get(); } 1.3465 + 1.3466 + private: 1.3467 + nsRefPtr<gfxFontFamily> mFamily; 1.3468 + nsRefPtr<gfxFont> mFont; 1.3469 + }; 1.3470 + 1.3471 + static void Shutdown(); // platform must call this to release the languageAtomService 1.3472 + 1.3473 + gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet = nullptr); 1.3474 + 1.3475 + virtual ~gfxFontGroup(); 1.3476 + 1.3477 + virtual gfxFont *GetFontAt(int32_t i) { 1.3478 + // If it turns out to be hard for all clients that cache font 1.3479 + // groups to call UpdateFontList at appropriate times, we could 1.3480 + // instead consider just calling UpdateFontList from someplace 1.3481 + // more central (such as here). 1.3482 + NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(), 1.3483 + "Whoever was caching this font group should have " 1.3484 + "called UpdateFontList on it"); 1.3485 + NS_ASSERTION(mFonts.Length() > uint32_t(i) && mFonts[i].Font(), 1.3486 + "Requesting a font index that doesn't exist"); 1.3487 + 1.3488 + return mFonts[i].Font(); 1.3489 + } 1.3490 + 1.3491 + uint32_t FontListLength() const { 1.3492 + return mFonts.Length(); 1.3493 + } 1.3494 + 1.3495 + bool Equals(const gfxFontGroup& other) const { 1.3496 + return mFamilies.Equals(other.mFamilies) && 1.3497 + mStyle.Equals(other.mStyle); 1.3498 + } 1.3499 + 1.3500 + const gfxFontStyle *GetStyle() const { return &mStyle; } 1.3501 + 1.3502 + virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle); 1.3503 + 1.3504 + /** 1.3505 + * The listed characters should be treated as invisible and zero-width 1.3506 + * when creating textruns. 1.3507 + */ 1.3508 + static bool IsInvalidChar(uint8_t ch); 1.3509 + static bool IsInvalidChar(char16_t ch); 1.3510 + 1.3511 + /** 1.3512 + * Make a textrun for a given string. 1.3513 + * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the 1.3514 + * textrun will copy it. 1.3515 + * This calls FetchGlyphExtents on the textrun. 1.3516 + */ 1.3517 + virtual gfxTextRun *MakeTextRun(const char16_t *aString, uint32_t aLength, 1.3518 + const Parameters *aParams, uint32_t aFlags); 1.3519 + /** 1.3520 + * Make a textrun for a given string. 1.3521 + * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the 1.3522 + * textrun will copy it. 1.3523 + * This calls FetchGlyphExtents on the textrun. 1.3524 + */ 1.3525 + virtual gfxTextRun *MakeTextRun(const uint8_t *aString, uint32_t aLength, 1.3526 + const Parameters *aParams, uint32_t aFlags); 1.3527 + 1.3528 + /** 1.3529 + * Textrun creation helper for clients that don't want to pass 1.3530 + * a full Parameters record. 1.3531 + */ 1.3532 + template<typename T> 1.3533 + gfxTextRun *MakeTextRun(const T *aString, uint32_t aLength, 1.3534 + gfxContext *aRefContext, 1.3535 + int32_t aAppUnitsPerDevUnit, 1.3536 + uint32_t aFlags) 1.3537 + { 1.3538 + gfxTextRunFactory::Parameters params = { 1.3539 + aRefContext, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit 1.3540 + }; 1.3541 + return MakeTextRun(aString, aLength, ¶ms, aFlags); 1.3542 + } 1.3543 + 1.3544 + /** 1.3545 + * Get the (possibly-cached) width of the hyphen character. 1.3546 + * The aCtx and aAppUnitsPerDevUnit parameters will be used only if 1.3547 + * needed to initialize the cached hyphen width; otherwise they are 1.3548 + * ignored. 1.3549 + */ 1.3550 + gfxFloat GetHyphenWidth(gfxTextRun::PropertyProvider* aProvider); 1.3551 + 1.3552 + /** 1.3553 + * Make a text run representing a single hyphen character. 1.3554 + * This will use U+2010 HYPHEN if available in the first font, 1.3555 + * otherwise fall back to U+002D HYPHEN-MINUS. 1.3556 + * The caller is responsible for deleting the returned text run 1.3557 + * when no longer required. 1.3558 + */ 1.3559 + gfxTextRun *MakeHyphenTextRun(gfxContext *aCtx, 1.3560 + uint32_t aAppUnitsPerDevUnit); 1.3561 + 1.3562 + /* helper function for splitting font families on commas and 1.3563 + * calling a function for each family to fill the mFonts array 1.3564 + */ 1.3565 + typedef bool (*FontCreationCallback) (const nsAString& aName, 1.3566 + const nsACString& aGenericName, 1.3567 + bool aUseFontSet, 1.3568 + void *closure); 1.3569 + bool ForEachFont(const nsAString& aFamilies, 1.3570 + nsIAtom *aLanguage, 1.3571 + FontCreationCallback fc, 1.3572 + void *closure); 1.3573 + bool ForEachFont(FontCreationCallback fc, void *closure); 1.3574 + 1.3575 + /** 1.3576 + * Check whether a given font (specified by its gfxFontEntry) 1.3577 + * is already in the fontgroup's list of actual fonts 1.3578 + */ 1.3579 + bool HasFont(const gfxFontEntry *aFontEntry); 1.3580 + 1.3581 + const nsString& GetFamilies() { return mFamilies; } 1.3582 + 1.3583 + // This returns the preferred underline for this font group. 1.3584 + // Some CJK fonts have wrong underline offset in its metrics. 1.3585 + // If this group has such "bad" font, each platform's gfxFontGroup initialized mUnderlineOffset. 1.3586 + // The value should be lower value of first font's metrics and the bad font's metrics. 1.3587 + // Otherwise, this returns from first font's metrics. 1.3588 + enum { UNDERLINE_OFFSET_NOT_SET = INT16_MAX }; 1.3589 + virtual gfxFloat GetUnderlineOffset() { 1.3590 + if (mUnderlineOffset == UNDERLINE_OFFSET_NOT_SET) 1.3591 + mUnderlineOffset = GetFontAt(0)->GetMetrics().underlineOffset; 1.3592 + return mUnderlineOffset; 1.3593 + } 1.3594 + 1.3595 + virtual already_AddRefed<gfxFont> 1.3596 + FindFontForChar(uint32_t ch, uint32_t prevCh, int32_t aRunScript, 1.3597 + gfxFont *aPrevMatchedFont, 1.3598 + uint8_t *aMatchType); 1.3599 + 1.3600 + // search through pref fonts for a character, return nullptr if no matching pref font 1.3601 + virtual already_AddRefed<gfxFont> WhichPrefFontSupportsChar(uint32_t aCh); 1.3602 + 1.3603 + virtual already_AddRefed<gfxFont> 1.3604 + WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript); 1.3605 + 1.3606 + template<typename T> 1.3607 + void ComputeRanges(nsTArray<gfxTextRange>& mRanges, 1.3608 + const T *aString, uint32_t aLength, 1.3609 + int32_t aRunScript); 1.3610 + 1.3611 + gfxUserFontSet* GetUserFontSet(); 1.3612 + 1.3613 + // With downloadable fonts, the composition of the font group can change as fonts are downloaded 1.3614 + // for each change in state of the user font set, the generation value is bumped to avoid picking up 1.3615 + // previously created text runs in the text run word cache. For font groups based on stylesheets 1.3616 + // with no @font-face rule, this always returns 0. 1.3617 + uint64_t GetGeneration(); 1.3618 + 1.3619 + // used when logging text performance 1.3620 + gfxTextPerfMetrics *GetTextPerfMetrics() { return mTextPerf; } 1.3621 + void SetTextPerfMetrics(gfxTextPerfMetrics *aTextPerf) { mTextPerf = aTextPerf; } 1.3622 + 1.3623 + // This will call UpdateFontList() if the user font set is changed. 1.3624 + void SetUserFontSet(gfxUserFontSet *aUserFontSet); 1.3625 + 1.3626 + // If there is a user font set, check to see whether the font list or any 1.3627 + // caches need updating. 1.3628 + virtual void UpdateFontList(); 1.3629 + 1.3630 + bool ShouldSkipDrawing() const { 1.3631 + return mSkipDrawing; 1.3632 + } 1.3633 + 1.3634 + class LazyReferenceContextGetter { 1.3635 + public: 1.3636 + virtual already_AddRefed<gfxContext> GetRefContext() = 0; 1.3637 + }; 1.3638 + // The gfxFontGroup keeps ownership of this textrun. 1.3639 + // It is only guaranteed to exist until the next call to GetEllipsisTextRun 1.3640 + // (which might use a different appUnitsPerDev value) for the font group, 1.3641 + // or until UpdateFontList is called, or the fontgroup is destroyed. 1.3642 + // Get it/use it/forget it :) - don't keep a reference that might go stale. 1.3643 + gfxTextRun* GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel, 1.3644 + LazyReferenceContextGetter& aRefContextGetter); 1.3645 + 1.3646 +protected: 1.3647 + nsString mFamilies; 1.3648 + gfxFontStyle mStyle; 1.3649 + nsTArray<FamilyFace> mFonts; 1.3650 + gfxFloat mUnderlineOffset; 1.3651 + gfxFloat mHyphenWidth; 1.3652 + 1.3653 + nsRefPtr<gfxUserFontSet> mUserFontSet; 1.3654 + uint64_t mCurrGeneration; // track the current user font set generation, rebuild font list if needed 1.3655 + 1.3656 + gfxTextPerfMetrics *mTextPerf; 1.3657 + 1.3658 + // Cache a textrun representing an ellipsis (useful for CSS text-overflow) 1.3659 + // at a specific appUnitsPerDevPixel size 1.3660 + nsAutoPtr<gfxTextRun> mCachedEllipsisTextRun; 1.3661 + 1.3662 + // cache the most recent pref font to avoid general pref font lookup 1.3663 + nsRefPtr<gfxFontFamily> mLastPrefFamily; 1.3664 + nsRefPtr<gfxFont> mLastPrefFont; 1.3665 + eFontPrefLang mLastPrefLang; // lang group for last pref font 1.3666 + eFontPrefLang mPageLang; 1.3667 + bool mLastPrefFirstFont; // is this the first font in the list of pref fonts for this lang group? 1.3668 + 1.3669 + bool mSkipDrawing; // hide text while waiting for a font 1.3670 + // download to complete (or fallback 1.3671 + // timer to fire) 1.3672 + 1.3673 + /** 1.3674 + * Textrun creation short-cuts for special cases where we don't need to 1.3675 + * call a font shaper to generate glyphs. 1.3676 + */ 1.3677 + gfxTextRun *MakeEmptyTextRun(const Parameters *aParams, uint32_t aFlags); 1.3678 + gfxTextRun *MakeSpaceTextRun(const Parameters *aParams, uint32_t aFlags); 1.3679 + gfxTextRun *MakeBlankTextRun(uint32_t aLength, 1.3680 + const Parameters *aParams, uint32_t aFlags); 1.3681 + 1.3682 + // Initialize the list of fonts 1.3683 + void BuildFontList(); 1.3684 + 1.3685 + // Init this font group's font metrics. If there no bad fonts, you don't need to call this. 1.3686 + // But if there are one or more bad fonts which have bad underline offset, 1.3687 + // you should call this with the *first* bad font. 1.3688 + void InitMetricsForBadFont(gfxFont* aBadFont); 1.3689 + 1.3690 + // Set up the textrun glyphs for an entire text run: 1.3691 + // find script runs, and then call InitScriptRun for each 1.3692 + template<typename T> 1.3693 + void InitTextRun(gfxContext *aContext, 1.3694 + gfxTextRun *aTextRun, 1.3695 + const T *aString, 1.3696 + uint32_t aLength); 1.3697 + 1.3698 + // InitTextRun helper to handle a single script run, by finding font ranges 1.3699 + // and calling each font's InitTextRun() as appropriate 1.3700 + template<typename T> 1.3701 + void InitScriptRun(gfxContext *aContext, 1.3702 + gfxTextRun *aTextRun, 1.3703 + const T *aString, 1.3704 + uint32_t aScriptRunStart, 1.3705 + uint32_t aScriptRunEnd, 1.3706 + int32_t aRunScript); 1.3707 + 1.3708 + /* If aResolveGeneric is true, then CSS/Gecko generic family names are 1.3709 + * replaced with preferred fonts. 1.3710 + * 1.3711 + * If aResolveFontName is true then fc() is called only for existing fonts 1.3712 + * and with actual font names. If false then fc() is called with each 1.3713 + * family name in aFamilies (after resolving CSS/Gecko generic family names 1.3714 + * if aResolveGeneric). 1.3715 + * If aUseFontSet is true, the fontgroup's user font set is checked; 1.3716 + * if false then it is skipped. 1.3717 + */ 1.3718 + bool ForEachFontInternal(const nsAString& aFamilies, 1.3719 + nsIAtom *aLanguage, 1.3720 + bool aResolveGeneric, 1.3721 + bool aResolveFontName, 1.3722 + bool aUseFontSet, 1.3723 + FontCreationCallback fc, 1.3724 + void *closure); 1.3725 + 1.3726 + // Helper for font-matching: 1.3727 + // see if aCh is supported in any of the faces from aFamily; 1.3728 + // if so return the best style match, else return null. 1.3729 + already_AddRefed<gfxFont> TryAllFamilyMembers(gfxFontFamily* aFamily, 1.3730 + uint32_t aCh); 1.3731 + 1.3732 + static bool FontResolverProc(const nsAString& aName, void *aClosure); 1.3733 + 1.3734 + static bool FindPlatformFont(const nsAString& aName, 1.3735 + const nsACString& aGenericName, 1.3736 + bool aUseFontSet, 1.3737 + void *closure); 1.3738 + 1.3739 + static NS_HIDDEN_(nsILanguageAtomService*) gLangService; 1.3740 +}; 1.3741 +#endif