gfx/thebes/gfxFont.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial