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