1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=4 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef GFX_TEXTRUN_H 8 #define GFX_TEXTRUN_H 9 10 #include <stdint.h> 11 12 #include "gfxTypes.h" 13 #include "gfxPoint.h" 14 #include "gfxFont.h" 15 #include "gfxFontConstants.h" 16 #include "gfxSkipChars.h" 17 #include "gfxPlatform.h" 18 #include "gfxPlatformFontList.h" 19 #include "gfxUserFontSet.h" 20 #include "mozilla/MemoryReporting.h" 21 #include "mozilla/RefPtr.h" 22 #include "mozilla/intl/UnicodeScriptCodes.h" 23 #include "nsPoint.h" 24 #include "nsString.h" 25 #include "nsTArray.h" 26 #include "nsTHashSet.h" 27 #include "nsTextFrameUtils.h" 28 #include "DrawMode.h" 29 #include "harfbuzz/hb.h" 30 #include "nsColor.h" 31 #include "nsFrameList.h" 32 #include "X11UndefineNone.h" 33 34 #ifdef DEBUG_FRAME_DUMP 35 # include <stdio.h> 36 #endif 37 38 class gfxContext; 39 class gfxFontGroup; 40 class nsAtom; 41 class nsLanguageAtomService; 42 class gfxMissingFontRecorder; 43 44 namespace mozilla { 45 class PostTraversalTask; 46 class SVGContextPaint; 47 enum class StyleHyphens : uint8_t; 48 }; // namespace mozilla 49 50 /** 51 * Callback for Draw() to use when drawing text with mode 52 * DrawMode::GLYPH_PATH. 53 */ 54 struct gfxTextRunDrawCallbacks { 55 /** 56 * Constructs a new DrawCallbacks object. 57 * 58 * @param aShouldPaintSVGGlyphs If true, SVG glyphs will be painted. If 59 * false, SVG glyphs will not be painted; fallback plain glyphs are not 60 * emitted either. 61 */ 62 explicit gfxTextRunDrawCallbacks(bool aShouldPaintSVGGlyphs = false) mShouldPaintSVGGlyphsgfxTextRunDrawCallbacks63 : mShouldPaintSVGGlyphs(aShouldPaintSVGGlyphs) {} 64 65 /** 66 * Called when a path has been emitted to the gfxContext when 67 * painting a text run. This can be called any number of times, 68 * due to partial ligatures and intervening SVG glyphs. 69 */ 70 virtual void NotifyGlyphPathEmitted() = 0; 71 72 bool mShouldPaintSVGGlyphs; 73 }; 74 75 /** 76 * gfxTextRun is an abstraction for drawing and measuring substrings of a run 77 * of text. It stores runs of positioned glyph data, each run having a single 78 * gfxFont. The glyphs are associated with a string of source text, and the 79 * gfxTextRun APIs take parameters that are offsets into that source text. 80 * 81 * gfxTextRuns are mostly immutable. The only things that can change are 82 * inter-cluster spacing and line break placement. Spacing is always obtained 83 * lazily by methods that need it, it is not cached. Line breaks are stored 84 * persistently (insofar as they affect the shaping of glyphs; gfxTextRun does 85 * not actually do anything to explicitly account for line breaks). Initially 86 * there are no line breaks. The textrun can record line breaks before or after 87 * any given cluster. (Line breaks specified inside clusters are ignored.) 88 * 89 * It is important that zero-length substrings are handled correctly. This will 90 * be on the test! 91 */ 92 class gfxTextRun : public gfxShapedText { 93 NS_INLINE_DECL_REFCOUNTING(gfxTextRun); 94 95 protected: 96 // Override operator delete to properly free the object that was 97 // allocated via malloc. delete(void * p)98 void operator delete(void* p) { free(p); } 99 100 virtual ~gfxTextRun(); 101 102 public: 103 typedef gfxFont::RunMetrics Metrics; 104 typedef mozilla::gfx::DrawTarget DrawTarget; 105 106 // Public textrun API for general use 107 IsClusterStart(uint32_t aPos)108 bool IsClusterStart(uint32_t aPos) const { 109 MOZ_ASSERT(aPos < GetLength()); 110 return mCharacterGlyphs[aPos].IsClusterStart(); 111 } IsLigatureGroupStart(uint32_t aPos)112 bool IsLigatureGroupStart(uint32_t aPos) const { 113 MOZ_ASSERT(aPos < GetLength()); 114 return mCharacterGlyphs[aPos].IsLigatureGroupStart(); 115 } CanBreakLineBefore(uint32_t aPos)116 bool CanBreakLineBefore(uint32_t aPos) const { 117 return CanBreakBefore(aPos) == CompressedGlyph::FLAG_BREAK_TYPE_NORMAL; 118 } CanHyphenateBefore(uint32_t aPos)119 bool CanHyphenateBefore(uint32_t aPos) const { 120 return CanBreakBefore(aPos) == CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN; 121 } 122 123 // Returns a gfxShapedText::CompressedGlyph::FLAG_BREAK_TYPE_* value 124 // as defined in gfxFont.h (may be NONE, NORMAL or HYPHEN). CanBreakBefore(uint32_t aPos)125 uint8_t CanBreakBefore(uint32_t aPos) const { 126 MOZ_ASSERT(aPos < GetLength()); 127 return mCharacterGlyphs[aPos].CanBreakBefore(); 128 } 129 CharIsSpace(uint32_t aPos)130 bool CharIsSpace(uint32_t aPos) const { 131 MOZ_ASSERT(aPos < GetLength()); 132 return mCharacterGlyphs[aPos].CharIsSpace(); 133 } CharIsTab(uint32_t aPos)134 bool CharIsTab(uint32_t aPos) const { 135 MOZ_ASSERT(aPos < GetLength()); 136 return mCharacterGlyphs[aPos].CharIsTab(); 137 } CharIsNewline(uint32_t aPos)138 bool CharIsNewline(uint32_t aPos) const { 139 MOZ_ASSERT(aPos < GetLength()); 140 return mCharacterGlyphs[aPos].CharIsNewline(); 141 } CharMayHaveEmphasisMark(uint32_t aPos)142 bool CharMayHaveEmphasisMark(uint32_t aPos) const { 143 MOZ_ASSERT(aPos < GetLength()); 144 return mCharacterGlyphs[aPos].CharMayHaveEmphasisMark(); 145 } CharIsFormattingControl(uint32_t aPos)146 bool CharIsFormattingControl(uint32_t aPos) const { 147 MOZ_ASSERT(aPos < GetLength()); 148 return mCharacterGlyphs[aPos].CharIsFormattingControl(); 149 } 150 151 // All offsets are in terms of the string passed into MakeTextRun. 152 153 // Describe range [start, end) of a text run. The range is 154 // restricted to grapheme cluster boundaries. 155 struct Range { 156 uint32_t start; 157 uint32_t end; LengthRange158 uint32_t Length() const { return end - start; } 159 RangeRange160 Range() : start(0), end(0) {} RangeRange161 Range(uint32_t aStart, uint32_t aEnd) : start(aStart), end(aEnd) {} RangeRange162 explicit Range(const gfxTextRun* aTextRun) 163 : start(0), end(aTextRun->GetLength()) {} 164 }; 165 166 // All coordinates are in layout/app units 167 168 /** 169 * Set the potential linebreaks for a substring of the textrun. These are 170 * the "allow break before" points. Initially, there are no potential 171 * linebreaks. 172 * 173 * This can change glyphs and/or geometry! Some textruns' shapes 174 * depend on potential line breaks (e.g., title-case-converting textruns). 175 * This function is virtual so that those textruns can reshape themselves. 176 * 177 * @return true if this changed the linebreaks, false if the new line 178 * breaks are the same as the old 179 */ 180 virtual bool SetPotentialLineBreaks(Range aRange, 181 const uint8_t* aBreakBefore); 182 183 enum class HyphenType : uint8_t { 184 // Code in BreakAndMeasureText depends on the ordering of these values! 185 None, 186 Explicit, 187 Soft, 188 AutoWithManualInSameWord, 189 AutoWithoutManualInSameWord 190 }; 191 IsOptionalHyphenBreak(HyphenType aType)192 static bool IsOptionalHyphenBreak(HyphenType aType) { 193 return aType >= HyphenType::Soft; 194 } 195 196 struct HyphenationState { 197 uint32_t mostRecentBoundary = 0; 198 bool hasManualHyphen = false; 199 bool hasExplicitHyphen = false; 200 bool hasAutoHyphen = false; 201 }; 202 203 /** 204 * Layout provides PropertyProvider objects. These allow detection of 205 * potential line break points and computation of spacing. We pass the data 206 * this way to allow lazy data acquisition; for example BreakAndMeasureText 207 * will want to only ask for properties of text it's actually looking at. 208 * 209 * NOTE that requested spacing may not actually be applied, if the textrun 210 * is unable to apply it in some context. Exception: spacing around a 211 * whitespace character MUST always be applied. 212 */ 213 class PropertyProvider { 214 public: 215 // Detect hyphenation break opportunities in the given range; breaks 216 // not at cluster boundaries will be ignored. 217 virtual void GetHyphenationBreaks(Range aRange, 218 HyphenType* aBreakBefore) const = 0; 219 220 // Returns the provider's hyphenation setting, so callers can decide 221 // whether it is necessary to call GetHyphenationBreaks. 222 // Result is an StyleHyphens value. 223 virtual mozilla::StyleHyphens GetHyphensOption() const = 0; 224 225 // Returns the extra width that will be consumed by a hyphen. This should 226 // be constant for a given textrun. 227 virtual gfxFloat GetHyphenWidth() const = 0; 228 229 // Return orientation flags to be used when creating a hyphen textrun. 230 virtual mozilla::gfx::ShapedTextFlags GetShapedTextFlags() const = 0; 231 232 typedef gfxFont::Spacing Spacing; 233 234 /** 235 * Get the spacing around the indicated characters. Spacing must be zero 236 * inside clusters. In other words, if character i is not 237 * CLUSTER_START, then character i-1 must have zero after-spacing and 238 * character i must have zero before-spacing. 239 */ 240 virtual void GetSpacing(Range aRange, Spacing* aSpacing) const = 0; 241 242 // Returns a gfxContext that can be used to measure the hyphen glyph. 243 // Only called if the hyphen width is requested. 244 virtual already_AddRefed<DrawTarget> GetDrawTarget() const = 0; 245 246 // Return the appUnitsPerDevUnit value to be used when measuring. 247 // Only called if the hyphen width is requested. 248 virtual uint32_t GetAppUnitsPerDevUnit() const = 0; 249 }; 250 251 struct MOZ_STACK_CLASS DrawParams { 252 gfxContext* context; 253 DrawMode drawMode = DrawMode::GLYPH_FILL; 254 nscolor textStrokeColor = 0; 255 gfxPattern* textStrokePattern = nullptr; 256 const mozilla::gfx::StrokeOptions* strokeOpts = nullptr; 257 const mozilla::gfx::DrawOptions* drawOpts = nullptr; 258 PropertyProvider* provider = nullptr; 259 // If non-null, the advance width of the substring is set. 260 gfxFloat* advanceWidth = nullptr; 261 mozilla::SVGContextPaint* contextPaint = nullptr; 262 gfxTextRunDrawCallbacks* callbacks = nullptr; 263 bool allowGDI = true; DrawParamsDrawParams264 explicit DrawParams(gfxContext* aContext) : context(aContext) {} 265 }; 266 267 /** 268 * Draws a substring. Uses only GetSpacing from aBreakProvider. 269 * The provided point is the baseline origin on the left of the string 270 * for LTR, on the right of the string for RTL. 271 * 272 * Drawing should respect advance widths in the sense that for LTR runs, 273 * Draw(Range(start, middle), pt, ...) followed by 274 * Draw(Range(middle, end), gfxPoint(pt.x + advance, pt.y), ...) 275 * should have the same effect as 276 * Draw(Range(start, end), pt, ...) 277 * 278 * For RTL runs the rule is: 279 * Draw(Range(middle, end), pt, ...) followed by 280 * Draw(Range(start, middle), gfxPoint(pt.x + advance, pt.y), ...) 281 * should have the same effect as 282 * Draw(Range(start, end), pt, ...) 283 * 284 * Glyphs should be drawn in logical content order, which can be significant 285 * if they overlap (perhaps due to negative spacing). 286 */ 287 void Draw(const Range aRange, const mozilla::gfx::Point aPt, 288 const DrawParams& aParams) const; 289 290 /** 291 * Draws the emphasis marks for this text run. Uses only GetSpacing 292 * from aProvider. The provided point is the baseline origin of the 293 * line of emphasis marks. 294 */ 295 void DrawEmphasisMarks(gfxContext* aContext, gfxTextRun* aMark, 296 gfxFloat aMarkAdvance, mozilla::gfx::Point aPt, 297 Range aRange, PropertyProvider* aProvider) const; 298 299 /** 300 * Computes the ReflowMetrics for a substring. 301 * Uses GetSpacing from aBreakProvider. 302 * @param aBoundingBoxType which kind of bounding box (loose/tight) 303 */ 304 Metrics MeasureText(Range aRange, gfxFont::BoundingBoxType aBoundingBoxType, 305 DrawTarget* aDrawTargetForTightBoundingBox, 306 PropertyProvider* aProvider) const; 307 308 Metrics MeasureText(gfxFont::BoundingBoxType aBoundingBoxType, 309 DrawTarget* aDrawTargetForTightBoundingBox, 310 PropertyProvider* aProvider = nullptr) const { 311 return MeasureText(Range(this), aBoundingBoxType, 312 aDrawTargetForTightBoundingBox, aProvider); 313 } 314 315 /** 316 * Computes just the advance width for a substring. 317 * Uses GetSpacing from aBreakProvider. 318 * If aSpacing is not null, the spacing attached before and after 319 * the substring would be returned in it. NOTE: the spacing is 320 * included in the advance width. 321 */ 322 gfxFloat GetAdvanceWidth(Range aRange, PropertyProvider* aProvider, 323 PropertyProvider::Spacing* aSpacing = nullptr) const; 324 GetAdvanceWidth()325 gfxFloat GetAdvanceWidth() const { 326 return GetAdvanceWidth(Range(this), nullptr); 327 } 328 329 /** 330 * Computes the minimum advance width for a substring assuming line 331 * breaking is allowed everywhere. 332 */ 333 gfxFloat GetMinAdvanceWidth(Range aRange); 334 335 /** 336 * Clear all stored line breaks for the given range (both before and after), 337 * and then set the line-break state before aRange.start to aBreakBefore and 338 * after the last cluster to aBreakAfter. 339 * 340 * We require that before and after line breaks be consistent. For clusters 341 * i and i+1, we require that if there is a break after cluster i, a break 342 * will be specified before cluster i+1. This may be temporarily violated 343 * (e.g. after reflowing line L and before reflowing line L+1); to handle 344 * these temporary violations, we say that there is a break betwen i and i+1 345 * if a break is specified after i OR a break is specified before i+1. 346 * 347 * This can change textrun geometry! The existence of a linebreak can affect 348 * the advance width of the cluster before the break (when kerning) or the 349 * geometry of one cluster before the break or any number of clusters 350 * after the break. (The one-cluster-before-the-break limit is somewhat 351 * arbitrary; if some scripts require breaking it, then we need to 352 * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase 353 * it could affect the layout of frames before it...) 354 * 355 * We return true if glyphs or geometry changed, false otherwise. This 356 * function is virtual so that gfxTextRun subclasses can reshape 357 * properly. 358 * 359 * @param aAdvanceWidthDelta if non-null, returns the change in advance 360 * width of the given range. 361 */ 362 virtual bool SetLineBreaks(Range aRange, bool aLineBreakBefore, 363 bool aLineBreakAfter, 364 gfxFloat* aAdvanceWidthDelta); 365 366 enum SuppressBreak { 367 eNoSuppressBreak, 368 // Measure the range of text as if there is no break before it. 369 eSuppressInitialBreak, 370 // Measure the range of text as if it contains no break 371 eSuppressAllBreaks 372 }; 373 374 void ClassifyAutoHyphenations(uint32_t aStart, Range aRange, 375 nsTArray<HyphenType>& aHyphenBuffer, 376 HyphenationState* aWordState); 377 378 /** 379 * Finds the longest substring that will fit into the given width. 380 * Uses GetHyphenationBreaks and GetSpacing from aProvider. 381 * Guarantees the following: 382 * -- 0 <= result <= aMaxLength 383 * -- result is the maximal value of N such that either 384 * N < aMaxLength && line break at N && 385 * GetAdvanceWidth(Range(aStart, N), aProvider) <= aWidth 386 * OR N < aMaxLength && hyphen break at N && 387 * GetAdvanceWidth(Range(aStart, N), aProvider) + 388 * GetHyphenWidth() <= aWidth 389 * OR N == aMaxLength && 390 * GetAdvanceWidth(Range(aStart, N), aProvider) <= aWidth 391 * where GetAdvanceWidth assumes the effect of 392 * SetLineBreaks(Range(aStart, N), 393 * aLineBreakBefore, N < aMaxLength, aProvider) 394 * -- if no such N exists, then result is the smallest N such that 395 * N < aMaxLength && line break at N 396 * OR N < aMaxLength && hyphen break at N 397 * OR N == aMaxLength 398 * 399 * The call has the effect of 400 * SetLineBreaks(Range(aStart, result), aLineBreakBefore, 401 * result < aMaxLength, aProvider) 402 * and the returned metrics and the invariants above reflect this. 403 * 404 * @param aMaxLength this can be UINT32_MAX, in which case the length used 405 * is up to the end of the string 406 * @param aLineBreakBefore set to true if and only if there is an actual 407 * line break at the start of this string. 408 * @param aSuppressBreak what break should be suppressed. 409 * @param aTrimWhitespace if non-null, then we allow a trailing run of 410 * spaces to be trimmed; the width of the space(s) will not be included in 411 * the measured string width for comparison with the limit aWidth, and 412 * trimmed spaces will not be included in returned metrics. The width 413 * of the trimmed spaces will be returned in aTrimWhitespace. 414 * Trimmed spaces are still counted in the "characters fit" result. 415 * @param aHangWhitespace true if we allow whitespace to overflow the 416 * container at a soft-wrap 417 * @param aMetrics if non-null, we fill this in for the returned substring. 418 * If a hyphenation break was used, the hyphen is NOT included in the returned 419 * metrics. 420 * @param aBoundingBoxType whether to make the bounding box in aMetrics tight 421 * @param aDrawTargetForTightBoundingbox a reference DrawTarget to get the 422 * tight bounding box, if requested 423 * @param aUsedHyphenation if non-null, records if we selected a hyphenation 424 * break 425 * @param aLastBreak if non-null and result is aMaxLength, we set this to 426 * the maximal N such that 427 * N < aMaxLength && line break at N && 428 * GetAdvanceWidth(Range(aStart, N), aProvider) <= aWidth 429 * OR N < aMaxLength && hyphen break at N && 430 * GetAdvanceWidth(Range(aStart, N), aProvider) + 431 * GetHyphenWidth() <= aWidth 432 * or UINT32_MAX if no such N exists, where GetAdvanceWidth assumes 433 * the effect of 434 * SetLineBreaks(Range(aStart, N), aLineBreakBefore, 435 * N < aMaxLength, aProvider) 436 * 437 * @param aCanWordWrap true if we can break between any two grapheme 438 * clusters. This is set by overflow-wrap|word-wrap: break-word 439 * 440 * @param aBreakPriority in/out the priority of the break opportunity 441 * saved in the line. If we are prioritizing break opportunities, we will 442 * not set a break with a lower priority. @see gfxBreakPriority. 443 * 444 * Note that negative advance widths are possible especially if negative 445 * spacing is provided. 446 */ 447 uint32_t BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, 448 bool aLineBreakBefore, gfxFloat aWidth, 449 PropertyProvider* aProvider, 450 SuppressBreak aSuppressBreak, 451 gfxFloat* aTrimWhitespace, bool aHangWhitespace, 452 Metrics* aMetrics, 453 gfxFont::BoundingBoxType aBoundingBoxType, 454 DrawTarget* aDrawTargetForTightBoundingBox, 455 bool* aUsedHyphenation, uint32_t* aLastBreak, 456 bool aCanWordWrap, bool aCanWhitespaceWrap, 457 gfxBreakPriority* aBreakPriority); 458 459 // Utility getters 460 GetUserData()461 void* GetUserData() const { return mUserData; } SetUserData(void * aUserData)462 void SetUserData(void* aUserData) { mUserData = aUserData; } 463 SetFlagBits(nsTextFrameUtils::Flags aFlags)464 void SetFlagBits(nsTextFrameUtils::Flags aFlags) { mFlags2 |= aFlags; } ClearFlagBits(nsTextFrameUtils::Flags aFlags)465 void ClearFlagBits(nsTextFrameUtils::Flags aFlags) { mFlags2 &= ~aFlags; } GetSkipChars()466 const gfxSkipChars& GetSkipChars() const { return mSkipChars; } GetFontGroup()467 gfxFontGroup* GetFontGroup() const { return mFontGroup; } 468 469 // Call this, don't call "new gfxTextRun" directly. This does custom 470 // allocation and initialization 471 static already_AddRefed<gfxTextRun> Create( 472 const gfxTextRunFactory::Parameters* aParams, uint32_t aLength, 473 gfxFontGroup* aFontGroup, mozilla::gfx::ShapedTextFlags aFlags, 474 nsTextFrameUtils::Flags aFlags2); 475 476 // The text is divided into GlyphRuns as necessary. (In the vast majority 477 // of cases, a gfxTextRun contains just a single GlyphRun.) 478 struct GlyphRun { 479 RefPtr<gfxFont> mFont; // never null in a valid GlyphRun 480 uint32_t mCharacterOffset; // into original UTF16 string 481 mozilla::gfx::ShapedTextFlags 482 mOrientation; // gfxTextRunFactory::TEXT_ORIENT_* value 483 FontMatchType mMatchType; 484 bool mIsCJK; // Whether the text was a CJK script run (used to decide if 485 // text-decoration-skip-ink should not be applied) 486 487 // Set up the properties (but NOT offset) of the GlyphRun. SetPropertiesGlyphRun488 void SetProperties(gfxFont* aFont, 489 mozilla::gfx::ShapedTextFlags aOrientation, bool aIsCJK, 490 FontMatchType aMatchType) { 491 mFont = aFont; 492 mOrientation = aOrientation; 493 mIsCJK = aIsCJK; 494 mMatchType = aMatchType; 495 } 496 497 // Return whether the GlyphRun matches the given properties; 498 // the given FontMatchType will be added to the run if not present. MatchesGlyphRun499 bool Matches(gfxFont* aFont, mozilla::gfx::ShapedTextFlags aOrientation, 500 bool aIsCJK, FontMatchType aMatchType) { 501 if (mFont == aFont && mOrientation == aOrientation && mIsCJK == aIsCJK) { 502 mMatchType.kind |= aMatchType.kind; 503 if (mMatchType.generic == mozilla::StyleGenericFontFamily::None) { 504 mMatchType.generic = aMatchType.generic; 505 } 506 return true; 507 } 508 return false; 509 } 510 }; 511 512 // Script run codes that we will mark as CJK to suppress skip-ink behavior. IsCJKScript(Script aScript)513 static inline bool IsCJKScript(Script aScript) { 514 switch (aScript) { 515 case Script::BOPOMOFO: 516 case Script::HAN: 517 case Script::HANGUL: 518 case Script::HIRAGANA: 519 case Script::KATAKANA: 520 case Script::KATAKANA_OR_HIRAGANA: 521 case Script::SIMPLIFIED_HAN: 522 case Script::TRADITIONAL_HAN: 523 case Script::JAPANESE: 524 case Script::KOREAN: 525 case Script::HAN_WITH_BOPOMOFO: 526 case Script::JAMO: 527 return true; 528 default: 529 return false; 530 } 531 } 532 533 class MOZ_STACK_CLASS GlyphRunIterator { 534 public: 535 GlyphRunIterator(const gfxTextRun* aTextRun, Range aRange, 536 bool aReverse = false) mTextRun(aTextRun)537 : mTextRun(aTextRun), 538 mDirection(aReverse ? -1 : 1), 539 mStartOffset(aRange.start), 540 mEndOffset(aRange.end) { 541 mNextIndex = mTextRun->FindFirstGlyphRunContaining( 542 aReverse ? aRange.end - 1 : aRange.start); 543 } 544 bool NextRun(); GetGlyphRun()545 const GlyphRun* GetGlyphRun() const { return mGlyphRun; } GetStringStart()546 uint32_t GetStringStart() const { return mStringStart; } GetStringEnd()547 uint32_t GetStringEnd() const { return mStringEnd; } 548 549 private: 550 const gfxTextRun* mTextRun; 551 MOZ_INIT_OUTSIDE_CTOR const GlyphRun* mGlyphRun; 552 MOZ_INIT_OUTSIDE_CTOR uint32_t mStringStart; 553 MOZ_INIT_OUTSIDE_CTOR uint32_t mStringEnd; 554 const int32_t mDirection; 555 int32_t mNextIndex; 556 uint32_t mStartOffset; 557 uint32_t mEndOffset; 558 }; 559 560 class GlyphRunOffsetComparator { 561 public: Equals(const GlyphRun & a,const GlyphRun & b)562 bool Equals(const GlyphRun& a, const GlyphRun& b) const { 563 return a.mCharacterOffset == b.mCharacterOffset; 564 } 565 LessThan(const GlyphRun & a,const GlyphRun & b)566 bool LessThan(const GlyphRun& a, const GlyphRun& b) const { 567 return a.mCharacterOffset < b.mCharacterOffset; 568 } 569 }; 570 571 friend class GlyphRunIterator; 572 friend class FontSelector; 573 574 // API for setting up the textrun glyphs. Should only be called by 575 // things that construct textruns. 576 /** 577 * We've found a run of text that should use a particular font. Call this 578 * only during initialization when font substitution has been computed. 579 * Call it before setting up the glyphs for the characters in this run; 580 * SetMissingGlyph requires that the correct glyphrun be installed. 581 * 582 * If aForceNewRun, a new glyph run will be added, even if the 583 * previously added run uses the same font. If glyph runs are 584 * added out of strictly increasing aStartCharIndex order (via 585 * force), then SortGlyphRuns must be called after all glyph runs 586 * are added before any further operations are performed with this 587 * TextRun. 588 */ 589 void AddGlyphRun(gfxFont* aFont, FontMatchType aMatchType, 590 uint32_t aUTF16Offset, bool aForceNewRun, 591 mozilla::gfx::ShapedTextFlags aOrientation, bool aIsCJK); ResetGlyphRuns()592 void ResetGlyphRuns() { 593 if (mHasGlyphRunArray) { 594 MOZ_ASSERT(mGlyphRunArray.Length() > 1); 595 // Discard all but the first GlyphRun... 596 mGlyphRunArray.TruncateLength(1); 597 // ...and then convert to the single-run representation. 598 ConvertFromGlyphRunArray(); 599 } 600 // Clear out the one remaining GlyphRun. 601 mSingleGlyphRun.mFont = nullptr; 602 } 603 void SortGlyphRuns(); 604 void SanitizeGlyphRuns(); 605 GetCharacterGlyphs()606 const CompressedGlyph* GetCharacterGlyphs() const final { 607 MOZ_ASSERT(mCharacterGlyphs, "failed to initialize mCharacterGlyphs"); 608 return mCharacterGlyphs; 609 } GetCharacterGlyphs()610 CompressedGlyph* GetCharacterGlyphs() final { 611 MOZ_ASSERT(mCharacterGlyphs, "failed to initialize mCharacterGlyphs"); 612 return mCharacterGlyphs; 613 } 614 615 // clean out results from shaping in progress, used for fallback scenarios 616 void ClearGlyphsAndCharacters(); 617 618 void SetSpaceGlyph(gfxFont* aFont, DrawTarget* aDrawTarget, 619 uint32_t aCharIndex, 620 mozilla::gfx::ShapedTextFlags aOrientation); 621 622 // Set the glyph data for the given character index to the font's 623 // space glyph, IF this can be done as a "simple" glyph record 624 // (not requiring a DetailedGlyph entry). This avoids the need to call 625 // the font shaper and go through the shaped-word cache for most spaces. 626 // 627 // The parameter aSpaceChar is the original character code for which 628 // this space glyph is being used; if this is U+0020, we need to record 629 // that it could be trimmed at a run edge, whereas other kinds of space 630 // (currently just U+00A0) would not be trimmable/breakable. 631 // 632 // Returns true if it was able to set simple glyph data for the space; 633 // if it returns false, the caller needs to fall back to some other 634 // means to create the necessary (detailed) glyph data. 635 bool SetSpaceGlyphIfSimple(gfxFont* aFont, uint32_t aCharIndex, 636 char16_t aSpaceChar, 637 mozilla::gfx::ShapedTextFlags aOrientation); 638 639 // Record the positions of specific characters that layout may need to 640 // detect in the textrun, even though it doesn't have an explicit copy 641 // of the original text. These are recorded using flag bits in the 642 // CompressedGlyph record; if necessary, we convert "simple" glyph records 643 // to "complex" ones as the Tab and Newline flags are not present in 644 // simple CompressedGlyph records. SetIsTab(uint32_t aIndex)645 void SetIsTab(uint32_t aIndex) { EnsureComplexGlyph(aIndex).SetIsTab(); } SetIsNewline(uint32_t aIndex)646 void SetIsNewline(uint32_t aIndex) { 647 EnsureComplexGlyph(aIndex).SetIsNewline(); 648 } SetNoEmphasisMark(uint32_t aIndex)649 void SetNoEmphasisMark(uint32_t aIndex) { 650 EnsureComplexGlyph(aIndex).SetNoEmphasisMark(); 651 } SetIsFormattingControl(uint32_t aIndex)652 void SetIsFormattingControl(uint32_t aIndex) { 653 EnsureComplexGlyph(aIndex).SetIsFormattingControl(); 654 } 655 656 /** 657 * Prefetch all the glyph extents needed to ensure that Measure calls 658 * on this textrun not requesting tight boundingBoxes will succeed. Note 659 * that some glyph extents might not be fetched due to OOM or other 660 * errors. 661 */ 662 void FetchGlyphExtents(DrawTarget* aRefDrawTarget); 663 GetGlyphRuns(uint32_t * aNumGlyphRuns)664 const GlyphRun* GetGlyphRuns(uint32_t* aNumGlyphRuns) const { 665 if (mHasGlyphRunArray) { 666 *aNumGlyphRuns = mGlyphRunArray.Length(); 667 return mGlyphRunArray.Elements(); 668 } else { 669 *aNumGlyphRuns = mSingleGlyphRun.mFont ? 1 : 0; 670 return &mSingleGlyphRun; 671 } 672 } 673 TrailingGlyphRun()674 const GlyphRun* TrailingGlyphRun() const { 675 uint32_t count; 676 const GlyphRun* runs = GetGlyphRuns(&count); 677 return count ? runs + count - 1 : nullptr; 678 } 679 680 // Returns the index of the GlyphRun containing the given offset. 681 // Returns mGlyphRuns.Length() when aOffset is mCharacterCount. 682 uint32_t FindFirstGlyphRunContaining(uint32_t aOffset) const; 683 684 // Copy glyph data from a ShapedWord into this textrun. 685 void CopyGlyphDataFrom(gfxShapedWord* aSource, uint32_t aStart); 686 687 // Copy glyph data for a range of characters from aSource to this 688 // textrun. 689 void CopyGlyphDataFrom(gfxTextRun* aSource, Range aRange, uint32_t aDest); 690 691 // Tell the textrun to release its reference to its creating gfxFontGroup 692 // immediately, rather than on destruction. This is used for textruns 693 // that are actually owned by a gfxFontGroup, so that they don't keep it 694 // permanently alive due to a circular reference. (The caller of this is 695 // taking responsibility for ensuring the textrun will not outlive its 696 // mFontGroup.) 697 void ReleaseFontGroup(); 698 699 struct LigatureData { 700 // textrun range of the containing ligature 701 Range mRange; 702 // appunits advance to the start of the ligature part within the ligature; 703 // never includes any spacing 704 gfxFloat mPartAdvance; 705 // appunits width of the ligature part; includes before-spacing 706 // when the part is at the start of the ligature, and after-spacing 707 // when the part is as the end of the ligature 708 gfxFloat mPartWidth; 709 710 bool mClipBeforePart; 711 bool mClipAfterPart; 712 }; 713 714 // return storage used by this run, for memory reporter; 715 // nsTransformedTextRun needs to override this as it holds additional data 716 virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) 717 MOZ_MUST_OVERRIDE; 718 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) 719 MOZ_MUST_OVERRIDE; 720 GetFlags2()721 nsTextFrameUtils::Flags GetFlags2() const { return mFlags2; } 722 723 // Get the size, if it hasn't already been gotten, marking as it goes. MaybeSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)724 size_t MaybeSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { 725 if (mFlags2 & nsTextFrameUtils::Flags::RunSizeAccounted) { 726 return 0; 727 } 728 mFlags2 |= nsTextFrameUtils::Flags::RunSizeAccounted; 729 return SizeOfIncludingThis(aMallocSizeOf); 730 } ResetSizeOfAccountingFlags()731 void ResetSizeOfAccountingFlags() { 732 mFlags2 &= ~nsTextFrameUtils::Flags::RunSizeAccounted; 733 } 734 735 // shaping state - for some font features, fallback is required that 736 // affects the entire run. for example, fallback for one script/font 737 // portion of a textrun requires fallback to be applied to the entire run 738 739 enum ShapingState : uint8_t { 740 eShapingState_Normal, // default state 741 eShapingState_ShapingWithFeature, // have shaped with feature 742 eShapingState_ShapingWithFallback, // have shaped with fallback 743 eShapingState_Aborted, // abort initial iteration 744 eShapingState_ForceFallbackFeature // redo with fallback forced on 745 }; 746 GetShapingState()747 ShapingState GetShapingState() const { return mShapingState; } SetShapingState(ShapingState aShapingState)748 void SetShapingState(ShapingState aShapingState) { 749 mShapingState = aShapingState; 750 } 751 GetAdvanceForGlyph(uint32_t aIndex)752 int32_t GetAdvanceForGlyph(uint32_t aIndex) const { 753 const CompressedGlyph& glyphData = mCharacterGlyphs[aIndex]; 754 if (glyphData.IsSimpleGlyph()) { 755 return glyphData.GetSimpleAdvance(); 756 } 757 uint32_t glyphCount = glyphData.GetGlyphCount(); 758 if (!glyphCount) { 759 return 0; 760 } 761 const DetailedGlyph* details = GetDetailedGlyphs(aIndex); 762 int32_t advance = 0; 763 for (uint32_t j = 0; j < glyphCount; ++j, ++details) { 764 advance += details->mAdvance; 765 } 766 return advance; 767 } 768 769 #ifdef DEBUG_FRAME_DUMP 770 void Dump(FILE* aOutput = stderr); 771 #endif 772 773 protected: 774 /** 775 * Create a textrun, and set its mCharacterGlyphs to point immediately 776 * after the base object; this is ONLY used in conjunction with placement 777 * new, after allocating a block large enough for the glyph records to 778 * follow the base textrun object. 779 */ 780 gfxTextRun(const gfxTextRunFactory::Parameters* aParams, uint32_t aLength, 781 gfxFontGroup* aFontGroup, mozilla::gfx::ShapedTextFlags aFlags, 782 nsTextFrameUtils::Flags aFlags2); 783 784 /** 785 * Helper for the Create() factory method to allocate the required 786 * glyph storage for a textrun object with the basic size aSize, 787 * plus room for aLength glyph records. 788 */ 789 static void* AllocateStorageForTextRun(size_t aSize, uint32_t aLength); 790 791 // Pointer to the array of CompressedGlyph records; must be initialized 792 // when the object is constructed. 793 CompressedGlyph* mCharacterGlyphs; 794 795 private: 796 // **** general helpers **** 797 798 // Get the total advance for a range of glyphs. 799 int32_t GetAdvanceForGlyphs(Range aRange) const; 800 801 // Spacing for characters outside the range aSpacingStart/aSpacingEnd 802 // is assumed to be zero; such characters are not passed to aProvider. 803 // This is useful to protect aProvider from being passed character indices 804 // it is not currently able to handle. 805 bool GetAdjustedSpacingArray( 806 Range aRange, PropertyProvider* aProvider, Range aSpacingRange, 807 nsTArray<PropertyProvider::Spacing>* aSpacing) const; 808 EnsureComplexGlyph(uint32_t aIndex)809 CompressedGlyph& EnsureComplexGlyph(uint32_t aIndex) { 810 gfxShapedText::EnsureComplexGlyph(aIndex, mCharacterGlyphs[aIndex]); 811 return mCharacterGlyphs[aIndex]; 812 } 813 814 // **** ligature helpers **** 815 // (Platforms do the actual ligaturization, but we need to do a bunch of stuff 816 // to handle requests that begin or end inside a ligature) 817 818 // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero 819 LigatureData ComputeLigatureData(Range aPartRange, 820 PropertyProvider* aProvider) const; 821 gfxFloat ComputePartialLigatureWidth(Range aPartRange, 822 PropertyProvider* aProvider) const; 823 void DrawPartialLigature(gfxFont* aFont, Range aRange, 824 mozilla::gfx::Point* aPt, 825 PropertyProvider* aProvider, 826 TextRunDrawParams& aParams, 827 mozilla::gfx::ShapedTextFlags aOrientation) const; 828 // Advance aRange.start to the start of the nearest ligature, back 829 // up aRange.end to the nearest ligature end; may result in 830 // aRange->start == aRange->end. 831 void ShrinkToLigatureBoundaries(Range* aRange) const; 832 // result in appunits 833 gfxFloat GetPartialLigatureWidth(Range aRange, 834 PropertyProvider* aProvider) const; 835 void AccumulatePartialLigatureMetrics( 836 gfxFont* aFont, Range aRange, gfxFont::BoundingBoxType aBoundingBoxType, 837 DrawTarget* aRefDrawTarget, PropertyProvider* aProvider, 838 mozilla::gfx::ShapedTextFlags aOrientation, Metrics* aMetrics) const; 839 840 // **** measurement helper **** 841 void AccumulateMetricsForRun(gfxFont* aFont, Range aRange, 842 gfxFont::BoundingBoxType aBoundingBoxType, 843 DrawTarget* aRefDrawTarget, 844 PropertyProvider* aProvider, Range aSpacingRange, 845 mozilla::gfx::ShapedTextFlags aOrientation, 846 Metrics* aMetrics) const; 847 848 // **** drawing helper **** 849 void DrawGlyphs(gfxFont* aFont, Range aRange, mozilla::gfx::Point* aPt, 850 PropertyProvider* aProvider, Range aSpacingRange, 851 TextRunDrawParams& aParams, 852 mozilla::gfx::ShapedTextFlags aOrientation) const; 853 854 // The textrun holds either a single GlyphRun -or- an array; 855 // the flag mHasGlyphRunArray tells us which is present. 856 union { 857 GlyphRun mSingleGlyphRun; 858 nsTArray<GlyphRun> mGlyphRunArray; 859 }; 860 ConvertToGlyphRunArray()861 void ConvertToGlyphRunArray() { 862 MOZ_ASSERT(!mHasGlyphRunArray && mSingleGlyphRun.mFont); 863 GlyphRun tmp = std::move(mSingleGlyphRun); 864 mSingleGlyphRun.~GlyphRun(); 865 new (&mGlyphRunArray) nsTArray<GlyphRun>(2); 866 mGlyphRunArray.AppendElement(std::move(tmp)); 867 mHasGlyphRunArray = true; 868 } 869 ConvertFromGlyphRunArray()870 void ConvertFromGlyphRunArray() { 871 MOZ_ASSERT(mHasGlyphRunArray && mGlyphRunArray.Length() == 1); 872 GlyphRun tmp = std::move(mGlyphRunArray[0]); 873 mGlyphRunArray.~nsTArray<GlyphRun>(); 874 new (&mSingleGlyphRun) GlyphRun(std::move(tmp)); 875 mHasGlyphRunArray = false; 876 } 877 878 void* mUserData; 879 880 // mFontGroup is usually a strong reference, but refcounting is managed 881 // manually because it may be explicitly released by ReleaseFontGroup() 882 // in the case where the font group actually owns the textrun. 883 gfxFontGroup* MOZ_OWNING_REF mFontGroup; 884 885 gfxSkipChars mSkipChars; 886 887 nsTextFrameUtils::Flags 888 mFlags2; // additional flags (see also gfxShapedText::mFlags) 889 890 bool mDontSkipDrawing; // true if the text run must not skip drawing, even if 891 // waiting for a user font download, e.g. because we 892 // are using it to draw canvas text 893 bool mReleasedFontGroup; // we already called NS_RELEASE on 894 // mFontGroup, so don't do it again 895 bool mReleasedFontGroupSkippedDrawing; // whether our old mFontGroup value 896 // was set to skip drawing 897 bool mHasGlyphRunArray; // whether we're using an array or 898 // just storing a single glyphrun 899 900 // shaping state for handling variant fallback features 901 // such as subscript/superscript variant glyphs 902 ShapingState mShapingState; 903 }; 904 905 class gfxFontGroup final : public gfxTextRunFactory { 906 public: 907 typedef mozilla::intl::Script Script; 908 typedef gfxShapedText::CompressedGlyph CompressedGlyph; 909 910 static void 911 Shutdown(); // platform must call this to release the languageAtomService 912 913 gfxFontGroup(nsPresContext* aPresContext, 914 const mozilla::StyleFontFamilyList& aFontFamilyList, 915 const gfxFontStyle* aStyle, nsAtom* aLanguage, 916 bool aExplicitLanguage, gfxTextPerfMetrics* aTextPerf, 917 gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize); 918 919 virtual ~gfxFontGroup(); 920 921 gfxFontGroup(const gfxFontGroup& aOther) = delete; 922 923 // Returns first valid font in the fontlist or default font. 924 // Initiates userfont loads if userfont not loaded. 925 // aGeneric: if non-null, returns the CSS generic type that was mapped to 926 // this font 927 gfxFont* GetFirstValidFont( 928 uint32_t aCh = 0x20, mozilla::StyleGenericFontFamily* aGeneric = nullptr); 929 930 // Returns the first font in the font-group that has an OpenType MATH table, 931 // or null if no such font is available. The GetMathConstant methods may be 932 // called on the returned font. 933 gfxFont* GetFirstMathFont(); 934 GetStyle()935 const gfxFontStyle* GetStyle() const { return &mStyle; } 936 937 /** 938 * The listed characters should be treated as invisible and zero-width 939 * when creating textruns. 940 */ 941 static bool IsInvalidChar(uint8_t ch); 942 static bool IsInvalidChar(char16_t ch); 943 944 /** 945 * Make a textrun for a given string. 946 * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the 947 * textrun will copy it. 948 * This calls FetchGlyphExtents on the textrun. 949 */ 950 already_AddRefed<gfxTextRun> MakeTextRun(const char16_t* aString, 951 uint32_t aLength, 952 const Parameters* aParams, 953 mozilla::gfx::ShapedTextFlags aFlags, 954 nsTextFrameUtils::Flags aFlags2, 955 gfxMissingFontRecorder* aMFR); 956 /** 957 * Make a textrun for a given string. 958 * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the 959 * textrun will copy it. 960 * This calls FetchGlyphExtents on the textrun. 961 */ 962 already_AddRefed<gfxTextRun> MakeTextRun(const uint8_t* aString, 963 uint32_t aLength, 964 const Parameters* aParams, 965 mozilla::gfx::ShapedTextFlags aFlags, 966 nsTextFrameUtils::Flags aFlags2, 967 gfxMissingFontRecorder* aMFR); 968 969 /** 970 * Textrun creation helper for clients that don't want to pass 971 * a full Parameters record. 972 */ 973 template <typename T> MakeTextRun(const T * aString,uint32_t aLength,DrawTarget * aRefDrawTarget,int32_t aAppUnitsPerDevUnit,mozilla::gfx::ShapedTextFlags aFlags,nsTextFrameUtils::Flags aFlags2,gfxMissingFontRecorder * aMFR)974 already_AddRefed<gfxTextRun> MakeTextRun(const T* aString, uint32_t aLength, 975 DrawTarget* aRefDrawTarget, 976 int32_t aAppUnitsPerDevUnit, 977 mozilla::gfx::ShapedTextFlags aFlags, 978 nsTextFrameUtils::Flags aFlags2, 979 gfxMissingFontRecorder* aMFR) { 980 gfxTextRunFactory::Parameters params = { 981 aRefDrawTarget, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit}; 982 return MakeTextRun(aString, aLength, ¶ms, aFlags, aFlags2, aMFR); 983 } 984 985 // Get the (possibly-cached) width of the hyphen character. 986 gfxFloat GetHyphenWidth(const gfxTextRun::PropertyProvider* aProvider); 987 988 /** 989 * Make a text run representing a single hyphen character. 990 * This will use U+2010 HYPHEN if available in the first font, 991 * otherwise fall back to U+002D HYPHEN-MINUS. 992 * The caller is responsible for deleting the returned text run 993 * when no longer required. 994 */ 995 already_AddRefed<gfxTextRun> MakeHyphenTextRun( 996 DrawTarget* aDrawTarget, mozilla::gfx::ShapedTextFlags aFlags, 997 uint32_t aAppUnitsPerDevUnit); 998 999 /** 1000 * Check whether a given font (specified by its gfxFontEntry) 1001 * is already in the fontgroup's list of actual fonts 1002 */ 1003 bool HasFont(const gfxFontEntry* aFontEntry); 1004 1005 // This returns the preferred underline for this font group. 1006 // Some CJK fonts have wrong underline offset in its metrics. 1007 // If this group has such "bad" font, each platform's gfxFontGroup 1008 // initialized mUnderlineOffset. The value should be lower value of 1009 // first font's metrics and the bad font's metrics. Otherwise, this 1010 // returns from first font's metrics. 1011 enum { UNDERLINE_OFFSET_NOT_SET = INT16_MAX }; 1012 gfxFloat GetUnderlineOffset(); 1013 1014 gfxFont* FindFontForChar(uint32_t ch, uint32_t prevCh, uint32_t aNextCh, 1015 Script aRunScript, gfxFont* aPrevMatchedFont, 1016 FontMatchType* aMatchType); 1017 1018 gfxUserFontSet* GetUserFontSet(); 1019 1020 // With downloadable fonts, the composition of the font group can change as 1021 // fonts are downloaded for each change in state of the user font set, the 1022 // generation value is bumped to avoid picking up previously created text runs 1023 // in the text run word cache. For font groups based on stylesheets with no 1024 // @font-face rule, this always returns 0. 1025 uint64_t GetGeneration(); 1026 1027 // generation of the latest fontset rebuild, 0 when no fontset present 1028 uint64_t GetRebuildGeneration(); 1029 1030 // used when logging text performance GetTextPerfMetrics()1031 gfxTextPerfMetrics* GetTextPerfMetrics() const { return mTextPerf; } 1032 1033 // This will call UpdateUserFonts() if the user font set is changed. 1034 void SetUserFontSet(gfxUserFontSet* aUserFontSet); 1035 ClearCachedData()1036 void ClearCachedData() { 1037 mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET; 1038 mSkipDrawing = false; 1039 mHyphenWidth = -1; 1040 mCachedEllipsisTextRun = nullptr; 1041 } 1042 1043 // If there is a user font set, check to see whether the font list or any 1044 // caches need updating. 1045 void UpdateUserFonts(); 1046 1047 // search for a specific userfont in the list of fonts 1048 bool ContainsUserFont(const gfxUserFontEntry* aUserFont); 1049 ShouldSkipDrawing()1050 bool ShouldSkipDrawing() const { return mSkipDrawing; } 1051 1052 class LazyReferenceDrawTargetGetter { 1053 public: 1054 virtual already_AddRefed<DrawTarget> GetRefDrawTarget() = 0; 1055 }; 1056 // The gfxFontGroup keeps ownership of this textrun. 1057 // It is only guaranteed to exist until the next call to GetEllipsisTextRun 1058 // (which might use a different appUnitsPerDev value or flags) for the font 1059 // group, or until UpdateUserFonts is called, or the fontgroup is destroyed. 1060 // Get it/use it/forget it :) - don't keep a reference that might go stale. 1061 gfxTextRun* GetEllipsisTextRun( 1062 int32_t aAppUnitsPerDevPixel, mozilla::gfx::ShapedTextFlags aFlags, 1063 LazyReferenceDrawTargetGetter& aRefDrawTargetGetter); 1064 CheckForUpdatedPlatformList()1065 void CheckForUpdatedPlatformList() { 1066 auto* pfl = gfxPlatformFontList::PlatformFontList(); 1067 if (mFontListGeneration != pfl->GetGeneration()) { 1068 // Forget cached fonts that may no longer be valid. 1069 mLastPrefFamily = FontFamily(); 1070 mLastPrefFont = nullptr; 1071 mDefaultFont = nullptr; 1072 mFonts.Clear(); 1073 BuildFontList(); 1074 } 1075 } 1076 Language()1077 nsAtom* Language() const { return mLanguage.get(); } 1078 1079 protected: 1080 friend class mozilla::PostTraversalTask; 1081 1082 struct TextRange { TextRangeTextRange1083 TextRange(uint32_t aStart, uint32_t aEnd, gfxFont* aFont, 1084 FontMatchType aMatchType, 1085 mozilla::gfx::ShapedTextFlags aOrientation) 1086 : start(aStart), 1087 end(aEnd), 1088 font(aFont), 1089 matchType(aMatchType), 1090 orientation(aOrientation) {} LengthTextRange1091 uint32_t Length() const { return end - start; } 1092 uint32_t start, end; 1093 RefPtr<gfxFont> font; 1094 FontMatchType matchType; 1095 mozilla::gfx::ShapedTextFlags orientation; 1096 }; 1097 1098 // search through pref fonts for a character, return nullptr if no matching 1099 // pref font 1100 gfxFont* WhichPrefFontSupportsChar(uint32_t aCh, uint32_t aNextCh, 1101 eFontPresentation aPresentation); 1102 1103 gfxFont* WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh, 1104 Script aRunScript, 1105 eFontPresentation aPresentation); 1106 1107 template <typename T> 1108 void ComputeRanges(nsTArray<TextRange>& aRanges, const T* aString, 1109 uint32_t aLength, Script aRunScript, 1110 mozilla::gfx::ShapedTextFlags aOrientation); 1111 1112 class FamilyFace { 1113 public: FamilyFace()1114 FamilyFace() 1115 : mOwnedFamily(nullptr), 1116 mFontEntry(nullptr), 1117 mGeneric(mozilla::StyleGenericFontFamily::None), 1118 mFontCreated(false), 1119 mLoading(false), 1120 mInvalid(false), 1121 mCheckForFallbackFaces(false), 1122 mIsSharedFamily(false), 1123 mHasFontEntry(false) {} 1124 FamilyFace(gfxFontFamily * aFamily,gfxFont * aFont,mozilla::StyleGenericFontFamily aGeneric)1125 FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont, 1126 mozilla::StyleGenericFontFamily aGeneric) 1127 : mOwnedFamily(aFamily), 1128 mGeneric(aGeneric), 1129 mFontCreated(true), 1130 mLoading(false), 1131 mInvalid(false), 1132 mCheckForFallbackFaces(false), 1133 mIsSharedFamily(false), 1134 mHasFontEntry(false) { 1135 NS_ASSERTION(aFont, "font pointer must not be null"); 1136 NS_ASSERTION(!aFamily || aFamily->ContainsFace(aFont->GetFontEntry()), 1137 "font is not a member of the given family"); 1138 NS_IF_ADDREF(aFamily); 1139 mFont = aFont; 1140 NS_ADDREF(aFont); 1141 } 1142 FamilyFace(gfxFontFamily * aFamily,gfxFontEntry * aFontEntry,mozilla::StyleGenericFontFamily aGeneric)1143 FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry, 1144 mozilla::StyleGenericFontFamily aGeneric) 1145 : mOwnedFamily(aFamily), 1146 mGeneric(aGeneric), 1147 mFontCreated(false), 1148 mLoading(false), 1149 mInvalid(false), 1150 mCheckForFallbackFaces(false), 1151 mIsSharedFamily(false), 1152 mHasFontEntry(true) { 1153 NS_ASSERTION(aFontEntry, "font entry pointer must not be null"); 1154 NS_ASSERTION(!aFamily || aFamily->ContainsFace(aFontEntry), 1155 "font is not a member of the given family"); 1156 NS_IF_ADDREF(aFamily); 1157 mFontEntry = aFontEntry; 1158 NS_ADDREF(aFontEntry); 1159 } 1160 FamilyFace(mozilla::fontlist::Family * aFamily,gfxFontEntry * aFontEntry,mozilla::StyleGenericFontFamily aGeneric)1161 FamilyFace(mozilla::fontlist::Family* aFamily, gfxFontEntry* aFontEntry, 1162 mozilla::StyleGenericFontFamily aGeneric) 1163 : mSharedFamily(aFamily), 1164 mGeneric(aGeneric), 1165 mFontCreated(false), 1166 mLoading(false), 1167 mInvalid(false), 1168 mCheckForFallbackFaces(false), 1169 mIsSharedFamily(true), 1170 mHasFontEntry(true) { 1171 MOZ_ASSERT(aFamily && aFontEntry && aFontEntry->mShmemFace); 1172 mFontEntry = aFontEntry; 1173 NS_ADDREF(aFontEntry); 1174 } 1175 FamilyFace(const FamilyFace & aOtherFamilyFace)1176 FamilyFace(const FamilyFace& aOtherFamilyFace) 1177 : mGeneric(aOtherFamilyFace.mGeneric), 1178 mFontCreated(aOtherFamilyFace.mFontCreated), 1179 mLoading(aOtherFamilyFace.mLoading), 1180 mInvalid(aOtherFamilyFace.mInvalid), 1181 mCheckForFallbackFaces(aOtherFamilyFace.mCheckForFallbackFaces), 1182 mIsSharedFamily(aOtherFamilyFace.mIsSharedFamily), 1183 mHasFontEntry(aOtherFamilyFace.mHasFontEntry) { 1184 if (mIsSharedFamily) { 1185 mSharedFamily = aOtherFamilyFace.mSharedFamily; 1186 if (mFontCreated) { 1187 mFont = aOtherFamilyFace.mFont; 1188 NS_ADDREF(mFont); 1189 } else if (mHasFontEntry) { 1190 mFontEntry = aOtherFamilyFace.mFontEntry; 1191 NS_ADDREF(mFontEntry); 1192 } else { 1193 mSharedFace = aOtherFamilyFace.mSharedFace; 1194 } 1195 } else { 1196 mOwnedFamily = aOtherFamilyFace.mOwnedFamily; 1197 NS_IF_ADDREF(mOwnedFamily); 1198 if (mFontCreated) { 1199 mFont = aOtherFamilyFace.mFont; 1200 NS_ADDREF(mFont); 1201 } else { 1202 mFontEntry = aOtherFamilyFace.mFontEntry; 1203 NS_IF_ADDREF(mFontEntry); 1204 } 1205 } 1206 } 1207 ~FamilyFace()1208 ~FamilyFace() { 1209 if (mFontCreated) { 1210 NS_RELEASE(mFont); 1211 } 1212 if (!mIsSharedFamily) { 1213 NS_IF_RELEASE(mOwnedFamily); 1214 } 1215 if (mHasFontEntry) { 1216 NS_RELEASE(mFontEntry); 1217 } 1218 } 1219 1220 FamilyFace& operator=(const FamilyFace& aOther) { 1221 if (mFontCreated) { 1222 NS_RELEASE(mFont); 1223 } 1224 if (!mIsSharedFamily) { 1225 NS_IF_RELEASE(mOwnedFamily); 1226 } 1227 if (mHasFontEntry) { 1228 NS_RELEASE(mFontEntry); 1229 } 1230 1231 mGeneric = aOther.mGeneric; 1232 mFontCreated = aOther.mFontCreated; 1233 mLoading = aOther.mLoading; 1234 mInvalid = aOther.mInvalid; 1235 mIsSharedFamily = aOther.mIsSharedFamily; 1236 mHasFontEntry = aOther.mHasFontEntry; 1237 1238 if (mIsSharedFamily) { 1239 mSharedFamily = aOther.mSharedFamily; 1240 if (mFontCreated) { 1241 mFont = aOther.mFont; 1242 NS_ADDREF(mFont); 1243 } else if (mHasFontEntry) { 1244 mFontEntry = aOther.mFontEntry; 1245 NS_ADDREF(mFontEntry); 1246 } else { 1247 mSharedFace = aOther.mSharedFace; 1248 } 1249 } else { 1250 mOwnedFamily = aOther.mOwnedFamily; 1251 NS_IF_ADDREF(mOwnedFamily); 1252 if (mFontCreated) { 1253 mFont = aOther.mFont; 1254 NS_ADDREF(mFont); 1255 } else { 1256 mFontEntry = aOther.mFontEntry; 1257 NS_IF_ADDREF(mFontEntry); 1258 } 1259 } 1260 1261 return *this; 1262 } 1263 OwnedFamily()1264 gfxFontFamily* OwnedFamily() const { 1265 MOZ_ASSERT(!mIsSharedFamily); 1266 return mOwnedFamily; 1267 } SharedFamily()1268 mozilla::fontlist::Family* SharedFamily() const { 1269 MOZ_ASSERT(mIsSharedFamily); 1270 return mSharedFamily; 1271 } Font()1272 gfxFont* Font() const { return mFontCreated ? mFont : nullptr; } 1273 FontEntry()1274 gfxFontEntry* FontEntry() const { 1275 if (mFontCreated) { 1276 return mFont->GetFontEntry(); 1277 } 1278 if (mHasFontEntry) { 1279 return mFontEntry; 1280 } 1281 if (mIsSharedFamily) { 1282 return gfxPlatformFontList::PlatformFontList()->GetOrCreateFontEntry( 1283 mSharedFace, SharedFamily()); 1284 } 1285 return nullptr; 1286 } 1287 Generic()1288 mozilla::StyleGenericFontFamily Generic() const { return mGeneric; } 1289 IsSharedFamily()1290 bool IsSharedFamily() const { return mIsSharedFamily; } IsUserFontContainer()1291 bool IsUserFontContainer() const { 1292 gfxFontEntry* fe = FontEntry(); 1293 return fe && fe->mIsUserFontContainer; 1294 } IsLoading()1295 bool IsLoading() const { return mLoading; } IsInvalid()1296 bool IsInvalid() const { return mInvalid; } 1297 void CheckState(bool& aSkipDrawing); SetLoading(bool aIsLoading)1298 void SetLoading(bool aIsLoading) { mLoading = aIsLoading; } SetInvalid()1299 void SetInvalid() { mInvalid = true; } CheckForFallbackFaces()1300 bool CheckForFallbackFaces() const { return mCheckForFallbackFaces; } SetCheckForFallbackFaces()1301 void SetCheckForFallbackFaces() { mCheckForFallbackFaces = true; } 1302 1303 // Return true if we're currently loading (or waiting for) a resource that 1304 // may support the given character. IsLoadingFor(uint32_t aCh)1305 bool IsLoadingFor(uint32_t aCh) { 1306 if (!IsLoading()) { 1307 return false; 1308 } 1309 MOZ_ASSERT(IsUserFontContainer()); 1310 auto* ufe = static_cast<gfxUserFontEntry*>(FontEntry()); 1311 return ufe && ufe->CharacterInUnicodeRange(aCh); 1312 } 1313 SetFont(gfxFont * aFont)1314 void SetFont(gfxFont* aFont) { 1315 NS_ASSERTION(aFont, "font pointer must not be null"); 1316 NS_ADDREF(aFont); 1317 if (mFontCreated) { 1318 NS_RELEASE(mFont); 1319 } else if (mHasFontEntry) { 1320 NS_RELEASE(mFontEntry); 1321 mHasFontEntry = false; 1322 } 1323 mFont = aFont; 1324 mFontCreated = true; 1325 mLoading = false; 1326 } 1327 1328 bool EqualsUserFont(const gfxUserFontEntry* aUserFont) const; 1329 1330 private: 1331 union { 1332 gfxFontFamily* MOZ_OWNING_REF mOwnedFamily; 1333 mozilla::fontlist::Family* MOZ_NON_OWNING_REF mSharedFamily; 1334 }; 1335 // either a font or a font entry exists 1336 union { 1337 // Whichever of these fields is actually present will be a strong 1338 // reference, with refcounting handled manually. 1339 gfxFont* MOZ_OWNING_REF mFont; 1340 gfxFontEntry* MOZ_OWNING_REF mFontEntry; 1341 mozilla::fontlist::Face* MOZ_NON_OWNING_REF mSharedFace; 1342 }; 1343 mozilla::StyleGenericFontFamily mGeneric; 1344 bool mFontCreated : 1; 1345 bool mLoading : 1; 1346 bool mInvalid : 1; 1347 bool mCheckForFallbackFaces : 1; 1348 bool mIsSharedFamily : 1; 1349 bool mHasFontEntry : 1; 1350 }; 1351 1352 nsPresContext* mPresContext = nullptr; 1353 1354 // List of font families, either named or generic. 1355 // Generic names map to system pref fonts based on language. 1356 mozilla::StyleFontFamilyList mFamilyList; 1357 1358 // Fontlist containing a font entry for each family found. gfxFont objects 1359 // are created as needed and userfont loads are initiated when needed. 1360 // Code should be careful about addressing this array directly. 1361 nsTArray<FamilyFace> mFonts; 1362 1363 RefPtr<gfxFont> mDefaultFont; 1364 gfxFontStyle mStyle; 1365 1366 RefPtr<nsAtom> mLanguage; 1367 1368 gfxFloat mUnderlineOffset; 1369 gfxFloat mHyphenWidth; 1370 gfxFloat mDevToCssSize; 1371 1372 RefPtr<gfxUserFontSet> mUserFontSet; 1373 uint64_t mCurrGeneration; // track the current user font set generation, 1374 // rebuild font list if needed 1375 1376 gfxTextPerfMetrics* mTextPerf; 1377 1378 // Cache a textrun representing an ellipsis (useful for CSS text-overflow) 1379 // at a specific appUnitsPerDevPixel size and orientation 1380 RefPtr<gfxTextRun> mCachedEllipsisTextRun; 1381 1382 // cache the most recent pref font to avoid general pref font lookup 1383 FontFamily mLastPrefFamily; 1384 RefPtr<gfxFont> mLastPrefFont; 1385 eFontPrefLang mLastPrefLang; // lang group for last pref font 1386 eFontPrefLang mPageLang; 1387 bool mLastPrefFirstFont; // is this the first font in the list of pref fonts 1388 // for this lang group? 1389 1390 bool mSkipDrawing; // hide text while waiting for a font 1391 // download to complete (or fallback 1392 // timer to fire) 1393 1394 bool mExplicitLanguage; // Does mLanguage come from an explicit attribute? 1395 1396 // Generic font family used to select among font prefs during fallback. 1397 mozilla::StyleGenericFontFamily mFallbackGeneric = 1398 mozilla::StyleGenericFontFamily::None; 1399 1400 uint32_t mFontListGeneration = 0; // platform font list generation for this 1401 // fontgroup 1402 1403 /** 1404 * Textrun creation short-cuts for special cases where we don't need to 1405 * call a font shaper to generate glyphs. 1406 */ 1407 already_AddRefed<gfxTextRun> MakeEmptyTextRun( 1408 const Parameters* aParams, mozilla::gfx::ShapedTextFlags aFlags, 1409 nsTextFrameUtils::Flags aFlags2); 1410 1411 already_AddRefed<gfxTextRun> MakeSpaceTextRun( 1412 const Parameters* aParams, mozilla::gfx::ShapedTextFlags aFlags, 1413 nsTextFrameUtils::Flags aFlags2); 1414 1415 template <typename T> 1416 already_AddRefed<gfxTextRun> MakeBlankTextRun( 1417 const T* aString, uint32_t aLength, const Parameters* aParams, 1418 mozilla::gfx::ShapedTextFlags aFlags, nsTextFrameUtils::Flags aFlags2); 1419 1420 // Initialize the list of fonts 1421 void BuildFontList(); 1422 1423 // Get the font at index i within the fontlist, for character aCh (in case 1424 // of fonts with multiple resources and unicode-range partitioning). 1425 // Will initiate userfont load if not already loaded. 1426 // May return null if userfont not loaded or if font invalid. 1427 // If *aLoading is true, a relevant resource is already being loaded so no 1428 // new download will be initiated; if a download is started, *aLoading will 1429 // be set to true on return. 1430 gfxFont* GetFontAt(int32_t i, uint32_t aCh, bool* aLoading); 1431 1432 // Simplified version of GetFontAt() for use where we just need a font for 1433 // metrics, math layout tables, etc. 1434 gfxFont* GetFontAt(int32_t i, uint32_t aCh = 0x20) { 1435 bool loading = false; 1436 return GetFontAt(i, aCh, &loading); 1437 } 1438 1439 // will always return a font or force a shutdown 1440 gfxFont* GetDefaultFont(); 1441 1442 // Init this font group's font metrics. If there no bad fonts, you don't need 1443 // to call this. But if there are one or more bad fonts which have bad 1444 // underline offset, you should call this with the *first* bad font. 1445 void InitMetricsForBadFont(gfxFont* aBadFont); 1446 1447 // Set up the textrun glyphs for an entire text run: 1448 // find script runs, and then call InitScriptRun for each 1449 template <typename T> 1450 void InitTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun, 1451 const T* aString, uint32_t aLength, 1452 gfxMissingFontRecorder* aMFR); 1453 1454 // InitTextRun helper to handle a single script run, by finding font ranges 1455 // and calling each font's InitTextRun() as appropriate 1456 template <typename T> 1457 void InitScriptRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun, 1458 const T* aString, uint32_t aScriptRunStart, 1459 uint32_t aScriptRunEnd, Script aRunScript, 1460 gfxMissingFontRecorder* aMFR); 1461 1462 // Helper for font-matching: 1463 // search all faces in a family for a fallback in cases where it's unclear 1464 // whether the family might have a font for a given character 1465 gfxFont* FindFallbackFaceForChar(const FamilyFace& aFamily, uint32_t aCh, 1466 uint32_t aNextCh, 1467 eFontPresentation aPresentation); 1468 1469 gfxFont* FindFallbackFaceForChar(mozilla::fontlist::Family* aFamily, 1470 uint32_t aCh, uint32_t aNextCh, 1471 eFontPresentation aPresentation); 1472 1473 gfxFont* FindFallbackFaceForChar(gfxFontFamily* aFamily, uint32_t aCh, 1474 uint32_t aNextCh, 1475 eFontPresentation aPresentation); 1476 1477 // helper methods for looking up fonts 1478 1479 // lookup and add a font with a given name (i.e. *not* a generic!) 1480 void AddPlatformFont(const nsACString& aName, bool aQuotedName, 1481 nsTArray<FamilyAndGeneric>& aFamilyList); 1482 1483 // do style selection and add entries to list 1484 void AddFamilyToFontList(gfxFontFamily* aFamily, 1485 mozilla::StyleGenericFontFamily aGeneric); 1486 void AddFamilyToFontList(mozilla::fontlist::Family* aFamily, 1487 mozilla::StyleGenericFontFamily aGeneric); 1488 }; 1489 1490 // A "missing font recorder" is to be used during text-run creation to keep 1491 // a record of any scripts encountered for which font coverage was lacking; 1492 // when Flush() is called, it sends a notification that front-end code can use 1493 // to download fonts on demand (or whatever else it wants to do). 1494 1495 #define GFX_MISSING_FONTS_NOTIFY_PREF "gfx.missing_fonts.notify" 1496 1497 class gfxMissingFontRecorder { 1498 public: gfxMissingFontRecorder()1499 gfxMissingFontRecorder() { 1500 MOZ_COUNT_CTOR(gfxMissingFontRecorder); 1501 memset(&mMissingFonts, 0, sizeof(mMissingFonts)); 1502 } 1503 ~gfxMissingFontRecorder()1504 ~gfxMissingFontRecorder() { 1505 #ifdef DEBUG 1506 for (uint32_t i = 0; i < kNumScriptBitsWords; i++) { 1507 NS_ASSERTION(mMissingFonts[i] == 0, 1508 "failed to flush the missing-font recorder"); 1509 } 1510 #endif 1511 MOZ_COUNT_DTOR(gfxMissingFontRecorder); 1512 } 1513 1514 // record this script code in our mMissingFonts bitset RecordScript(mozilla::intl::Script aScriptCode)1515 void RecordScript(mozilla::intl::Script aScriptCode) { 1516 mMissingFonts[static_cast<uint32_t>(aScriptCode) >> 5] |= 1517 (1 << (static_cast<uint32_t>(aScriptCode) & 0x1f)); 1518 } 1519 1520 // send a notification of any missing-scripts that have been 1521 // recorded, and clear the mMissingFonts set for re-use 1522 void Flush(); 1523 1524 // forget any missing-scripts that have been recorded up to now; 1525 // called before discarding a recorder we no longer care about Clear()1526 void Clear() { memset(&mMissingFonts, 0, sizeof(mMissingFonts)); } 1527 1528 private: 1529 // Number of 32-bit words needed for the missing-script flags 1530 static const uint32_t kNumScriptBitsWords = 1531 ((static_cast<int>(mozilla::intl::Script::NUM_SCRIPT_CODES) + 31) / 32); 1532 uint32_t mMissingFonts[kNumScriptBitsWords]; 1533 }; 1534 1535 #endif 1536