1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Foundation code.
17 * The Initial Developer of the Original Code is Mozilla Foundation.
18 * Portions created by the Initial Developer are Copyright (C) 2005
19 * the Initial Developer. All Rights Reserved.
22 * Stuart Parmenter <stuart@mozilla.com>
23 * Masayuki Nakano <masayuki@d-toybox.com>
24 * John Daggett <jdaggett@mozilla.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
47 #include "gfxFontUtils.h"
49 #include "nsTHashtable.h"
50 #include "nsHashKeys.h"
51 #include "gfxSkipChars.h"
53 #include "nsExpirationTracker.h"
65 class gfxUserFontData
;
67 #define FONT_STYLE_NORMAL 0
68 #define FONT_STYLE_ITALIC 1
69 #define FONT_STYLE_OBLIQUE 2
71 #define FONT_WEIGHT_NORMAL 400
72 #define FONT_WEIGHT_BOLD 700
74 #define FONT_MAX_SIZE 2000.0
76 struct THEBES_API gfxFontStyle
{
78 gfxFontStyle(PRUint8 aStyle
, PRUint16 aWeight
, gfxFloat aSize
,
79 const nsACString
& aLangGroup
,
80 float aSizeAdjust
, PRPackedBool aSystemFont
,
81 PRPackedBool aFamilyNameQuirks
);
82 gfxFontStyle(const gfxFontStyle
& aStyle
);
84 // The style of font (normal, italic, oblique)
87 // Say that this font is a system font and therefore does not
88 // require certain fixup that we do for fonts from untrusted
90 PRPackedBool systemFont
: 1;
92 // True if the character set quirks (for treatment of "Symbol",
93 // "Wingdings", etc.) should be applied.
94 PRPackedBool familyNameQuirks
: 1;
96 // The weight of the font. 100, 200, ... 900 are the weights, and
97 // single integer offsets request the next bolder/lighter font
98 // available. For example, for a font available in weights 200,
99 // 400, 700, and 900, a weight of 898 should lead to the weight 400
100 // font being used, since it is two weights lighter than 900.
103 // The logical size of the font, in pixels
106 // the language group
109 // The aspect-value (ie., the ratio actualsize:actualxheight) that any
110 // actual physical font created from this font structure must have when
111 // rendering or measuring a string. A value of 0 means no adjustment
115 // Return the final adjusted font size for the given aspect ratio.
116 // Not meant to be called when sizeAdjust = 0.
117 gfxFloat
GetAdjustedSize(gfxFloat aspect
) const {
118 NS_ASSERTION(sizeAdjust
!= 0.0, "Not meant to be called when sizeAdjust = 0");
119 gfxFloat adjustedSize
= PR_MAX(NS_round(size
*(sizeAdjust
/aspect
)), 1.0);
120 return PR_MIN(adjustedSize
, FONT_MAX_SIZE
);
123 PLDHashNumber
Hash() const {
124 return ((style
+ (systemFont
<< 7) + (familyNameQuirks
<< 8) +
125 (weight
<< 9)) + PRUint32(size
*1000) + PRUint32(sizeAdjust
*1000)) ^
126 HashString(langGroup
);
129 void ComputeWeightAndOffset(PRInt8
*outBaseWeight
,
130 PRInt8
*outOffset
) const;
132 PRBool
Equals(const gfxFontStyle
& other
) const {
133 return (size
== other
.size
) &&
134 (style
== other
.style
) &&
135 (systemFont
== other
.systemFont
) &&
136 (familyNameQuirks
== other
.familyNameQuirks
) &&
137 (weight
== other
.weight
) &&
138 (langGroup
.Equals(other
.langGroup
)) &&
139 (sizeAdjust
== other
.sizeAdjust
);
145 THEBES_INLINE_DECL_REFCOUNTING(gfxFontEntry
)
147 gfxFontEntry(const nsAString
& aName
) :
148 mName(aName
), mIsProxy(PR_FALSE
), mIsValid(PR_TRUE
),
149 mIsBadUnderlineFont(PR_FALSE
),
150 mCmapInitialized(PR_FALSE
), mUserFontData(nsnull
)
153 gfxFontEntry(const gfxFontEntry
& aEntry
) :
154 mName(aEntry
.mName
), mItalic(aEntry
.mItalic
),
155 mFixedPitch(aEntry
.mFixedPitch
), mUnicodeFont(aEntry
.mUnicodeFont
),
156 mSymbolFont(aEntry
.mSymbolFont
), mTrueType(aEntry
.mTrueType
),
157 mIsType1(aEntry
.mIsType1
), mIsProxy(aEntry
.mIsProxy
),
158 mIsValid(aEntry
.mIsValid
), mIsBadUnderlineFont(aEntry
.mIsBadUnderlineFont
),
159 mWeight(aEntry
.mWeight
), mCmapInitialized(aEntry
.mCmapInitialized
),
160 mCharacterMap(aEntry
.mCharacterMap
), mUserFontData(aEntry
.mUserFontData
)
163 virtual ~gfxFontEntry();
165 // unique name for the face, *not* the family
166 const nsString
& Name() const { return mName
; }
168 PRInt32
Weight() { return mWeight
; }
170 PRBool
IsFixedPitch() { return mFixedPitch
; }
171 PRBool
IsItalic() { return mItalic
; }
172 PRBool
IsBold() { return mWeight
>= 600; } // bold == weights 600 and above
174 inline PRBool
HasCharacter(PRUint32 ch
) {
175 if (mCharacterMap
.test(ch
))
178 return TestCharacterMap(ch
);
181 virtual PRBool
TestCharacterMap(PRUint32 aCh
);
182 virtual nsresult
ReadCMAP() { return 0; }
186 PRPackedBool mItalic
: 1;
187 PRPackedBool mFixedPitch
: 1;
189 PRPackedBool mUnicodeFont
: 1;
190 PRPackedBool mSymbolFont
: 1;
191 PRPackedBool mTrueType
: 1;
192 PRPackedBool mIsType1
: 1;
193 PRPackedBool mIsProxy
: 1;
194 PRPackedBool mIsValid
: 1;
196 PRPackedBool mIsBadUnderlineFont
: 1;
201 PRPackedBool mCmapInitialized
;
202 gfxSparseBitSet mCharacterMap
;
203 gfxUserFontData
* mUserFontData
;
207 mIsProxy(PR_FALSE
), mIsValid(PR_TRUE
),
208 mCmapInitialized(PR_FALSE
), mUserFontData(nsnull
)
213 class gfxFontFamily
{
215 THEBES_INLINE_DECL_REFCOUNTING(gfxFontFamily
)
217 gfxFontFamily(const nsAString
& aName
) :
220 virtual ~gfxFontFamily() { }
222 const nsString
& Name() { return mName
; }
224 // choose a specific face to match a style using CSS font matching
225 // rules (weight matching occurs here)
226 gfxFontEntry
*FindFontForStyle(const gfxFontStyle
& aFontStyle
,
230 // fills in an array with weights of faces that match style, returns
231 // number of weights in array
232 virtual PRBool
FindWeightsForStyle(gfxFontEntry
* aFontsForWeights
[],
233 const gfxFontStyle
& aFontStyle
)
239 struct gfxTextRange
{
240 gfxTextRange(PRUint32 aStart
, PRUint32 aEnd
) : start(aStart
), end(aEnd
) { }
241 PRUint32
Length() const { return end
- start
; }
242 nsRefPtr
<gfxFont
> font
;
250 * The mFonts hashtable contains most fonts, indexed by (name, style).
251 * It does not add a reference to the fonts it contains.
252 * When a font's refcount decreases to zero, instead of deleting it we
253 * add it to our expiration tracker.
254 * The expiration tracker tracks fonts with zero refcount. After a certain
255 * period of time, such fonts expire and are deleted.
257 * We're using 3 generations with a ten-second generation interval, so
258 * zero-refcount fonts will be deleted 20-30 seconds after their refcount
259 * goes to zero, if timer events fire in a timely manner.
261 class THEBES_API gfxFontCache
: public nsExpirationTracker
<gfxFont
,3> {
263 enum { TIMEOUT_SECONDS
= 10 };
265 : nsExpirationTracker
<gfxFont
,3>(TIMEOUT_SECONDS
*1000) { mFonts
.Init(); }
267 // Expire everything that has a zero refcount, so we don't leak them.
269 // All fonts should be gone.
270 NS_WARN_IF_FALSE(mFonts
.Count() == 0,
271 "Fonts still alive while shutting down gfxFontCache");
272 // Note that we have to delete everything through the expiration
273 // tracker, since there might be fonts not in the hashtable but in
278 * Get the global gfxFontCache. You must call Init() before
279 * calling this method --- the result will not be null.
281 static gfxFontCache
* GetCache() {
285 static nsresult
Init();
286 // It's OK to call this even if Init() has not been called.
287 static void Shutdown();
289 // Look up a font in the cache. Returns an addrefed pointer, or null
290 // if there's nothing matching in the cache
291 already_AddRefed
<gfxFont
> Lookup(const nsAString
&aName
,
292 const gfxFontStyle
*aFontGroup
);
293 // We created a new font (presumably because Lookup returned null);
294 // put it in the cache. The font's refcount should be nonzero. It is
295 // allowable to add a new font even if there is one already in the
296 // cache with the same key; we'll forget about the old one.
297 void AddNew(gfxFont
*aFont
);
299 // The font's refcount has gone to zero; give ownership of it to
300 // the cache. We delete it if it's not acquired again after a certain
302 void NotifyReleased(gfxFont
*aFont
);
304 // This gets called when the timeout has expired on a zero-refcount
305 // font; we just delete it.
306 virtual void NotifyExpired(gfxFont
*aFont
);
309 void DestroyFont(gfxFont
*aFont
);
311 static gfxFontCache
*gGlobalCache
;
314 const nsAString
& mString
;
315 const gfxFontStyle
* mStyle
;
316 Key(const nsAString
& aString
, const gfxFontStyle
* aStyle
)
317 : mString(aString
), mStyle(aStyle
) {}
320 class HashEntry
: public PLDHashEntryHdr
{
322 typedef const Key
& KeyType
;
323 typedef const Key
* KeyTypePointer
;
325 // When constructing a new entry in the hashtable, we'll leave this
326 // blank. The caller of Put() will fill this in.
327 HashEntry(KeyTypePointer aStr
) : mFont(nsnull
) { }
328 HashEntry(const HashEntry
& toCopy
) : mFont(toCopy
.mFont
) { }
331 PRBool
KeyEquals(const KeyTypePointer aKey
) const;
332 static KeyTypePointer
KeyToPointer(KeyType aKey
) { return &aKey
; }
333 static PLDHashNumber
HashKey(const KeyTypePointer aKey
) {
334 return HashString(aKey
->mString
) ^ aKey
->mStyle
->Hash();
336 enum { ALLOW_MEMMOVE
= PR_TRUE
};
341 nsTHashtable
<HashEntry
> mFonts
;
345 * This stores glyph bounds information for a particular gfxFont, at
346 * a particular appunits-per-dev-pixel ratio (because the compressed glyph
347 * width array is stored in appunits).
349 * We store a hashtable from glyph IDs to float bounding rects. For the
350 * common case where the glyph has no horizontal left bearing, and no
351 * y overflow above the font ascent or below the font descent, and tight
352 * bounding boxes are not required, we avoid storing the glyph ID in the hashtable
353 * and instead consult an array of 16-bit glyph XMost values (in appunits).
354 * This array always has an entry for the font's space glyph --- the width is
355 * assumed to be zero.
357 class THEBES_API gfxGlyphExtents
{
359 gfxGlyphExtents(PRUint32 aAppUnitsPerDevUnit
) :
360 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit
) {
361 MOZ_COUNT_CTOR(gfxGlyphExtents
);
362 mTightGlyphExtents
.Init();
366 enum { INVALID_WIDTH
= 0xFFFF };
368 // returns INVALID_WIDTH => not a contained glyph
369 // Otherwise the glyph has no before-bearing or vertical bearings,
370 // and the result is its width measured from the baseline origin, in
372 PRUint16
GetContainedGlyphWidthAppUnits(PRUint32 aGlyphID
) const {
373 return mContainedGlyphWidths
.Get(aGlyphID
);
376 PRBool
IsGlyphKnown(PRUint32 aGlyphID
) const {
377 return mContainedGlyphWidths
.Get(aGlyphID
) != INVALID_WIDTH
||
378 mTightGlyphExtents
.GetEntry(aGlyphID
) != nsnull
;
381 PRBool
IsGlyphKnownWithTightExtents(PRUint32 aGlyphID
) const {
382 return mTightGlyphExtents
.GetEntry(aGlyphID
) != nsnull
;
385 // Get glyph extents; a rectangle relative to the left baseline origin
386 // Returns true on success. Can fail on OOM or when aContext is null
387 // and extents were not (successfully) prefetched.
388 PRBool
GetTightGlyphExtentsAppUnits(gfxFont
*aFont
, gfxContext
*aContext
,
389 PRUint32 aGlyphID
, gfxRect
*aExtents
);
391 void SetContainedGlyphWidthAppUnits(PRUint32 aGlyphID
, PRUint16 aWidth
) {
392 mContainedGlyphWidths
.Set(aGlyphID
, aWidth
);
394 void SetTightGlyphExtents(PRUint32 aGlyphID
, const gfxRect
& aExtentsAppUnits
);
396 PRUint32
GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit
; }
399 class HashEntry
: public nsUint32HashKey
{
401 // When constructing a new entry in the hashtable, we'll leave this
402 // blank. The caller of Put() will fill this in.
403 HashEntry(KeyTypePointer aPtr
) : nsUint32HashKey(aPtr
) {}
404 HashEntry(const HashEntry
& toCopy
) : nsUint32HashKey(toCopy
) {
405 x
= toCopy
.x
; y
= toCopy
.y
; width
= toCopy
.width
; height
= toCopy
.height
;
408 float x
, y
, width
, height
;
411 typedef unsigned long PtrBits
;
412 enum { BLOCK_SIZE_BITS
= 7, BLOCK_SIZE
= 1 << BLOCK_SIZE_BITS
}; // 128-glyph blocks
416 void Set(PRUint32 aIndex
, PRUint16 aValue
);
417 PRUint16
Get(PRUint32 aIndex
) const {
418 PRUint32 block
= aIndex
>> BLOCK_SIZE_BITS
;
419 if (block
>= mBlocks
.Length())
420 return INVALID_WIDTH
;
421 PtrBits bits
= mBlocks
[block
];
423 return INVALID_WIDTH
;
424 PRUint32 indexInBlock
= aIndex
& (BLOCK_SIZE
- 1);
426 if (GetGlyphOffset(bits
) != indexInBlock
)
427 return INVALID_WIDTH
;
428 return GetWidth(bits
);
430 PRUint16
*widths
= reinterpret_cast<PRUint16
*>(bits
);
431 return widths
[indexInBlock
];
435 PRUint32
ComputeSize();
441 static PRUint32
GetGlyphOffset(PtrBits aBits
) {
442 NS_ASSERTION(aBits
& 0x1, "This is really a pointer...");
443 return (aBits
>> 1) & ((1 << BLOCK_SIZE_BITS
) - 1);
445 static PRUint32
GetWidth(PtrBits aBits
) {
446 NS_ASSERTION(aBits
& 0x1, "This is really a pointer...");
447 return aBits
>> (1 + BLOCK_SIZE_BITS
);
449 static PtrBits
MakeSingle(PRUint32 aGlyphOffset
, PRUint16 aWidth
) {
450 return (aWidth
<< (1 + BLOCK_SIZE_BITS
)) + (aGlyphOffset
<< 1) + 1;
453 nsTArray
<PtrBits
> mBlocks
;
456 GlyphWidths mContainedGlyphWidths
;
457 nsTHashtable
<HashEntry
> mTightGlyphExtents
;
458 PRUint32 mAppUnitsPerDevUnit
;
461 /* a SPECIFIC single font family */
462 class THEBES_API gfxFont
{
464 nsrefcnt
AddRef(void) {
465 NS_PRECONDITION(PRInt32(mRefCnt
) >= 0, "illegal refcnt");
466 if (mExpirationState
.IsTracked()) {
467 gfxFontCache::GetCache()->RemoveObject(this);
470 NS_LOG_ADDREF(this, mRefCnt
, "gfxFont", sizeof(*this));
473 nsrefcnt
Release(void) {
474 NS_PRECONDITION(0 != mRefCnt
, "dup release");
476 NS_LOG_RELEASE(this, mRefCnt
, "gfxFont");
479 // |this| may have been deleted.
485 PRInt32
GetRefCount() { return mRefCnt
; }
488 nsAutoRefCnt mRefCnt
;
490 void NotifyReleased() {
491 gfxFontCache
*cache
= gfxFontCache::GetCache();
493 // Don't delete just yet; return the object to the cache for
494 // possibly recycling within some time limit
495 cache
->NotifyReleased(this);
497 // The cache may have already been shut down.
502 gfxFont(gfxFontEntry
*aFontEntry
, const gfxFontStyle
*aFontStyle
);
507 const nsString
& GetName() const { return mFontEntry
->Name(); }
508 const gfxFontStyle
*GetStyle() const { return &mStyle
; }
510 virtual nsString
GetUniqueName() = 0;
515 gfxFloat superscriptOffset
;
516 gfxFloat subscriptOffset
;
517 gfxFloat strikeoutSize
;
518 gfxFloat strikeoutOffset
;
519 gfxFloat underlineSize
;
520 gfxFloat underlineOffset
;
523 gfxFloat internalLeading
;
524 gfxFloat externalLeading
;
534 gfxFloat aveCharWidth
;
536 gfxFloat zeroOrAveCharWidth
; // width of '0', or if there is
537 // no '0' glyph in this font,
538 // equal to .aveCharWidth
540 virtual const gfxFont::Metrics
& GetMetrics() = 0;
543 * We let layout specify spacing on either side of any
544 * character. We need to specify both before and after
545 * spacing so that substring measurement can do the right things.
546 * These values are in appunits. They're always an integral number of
547 * appunits, but we specify them in floats in case very large spacing
548 * values are required.
555 * Metrics for a particular string
557 struct THEBES_API RunMetrics
{
559 mAdvanceWidth
= mAscent
= mDescent
= 0.0;
560 mBoundingBox
= gfxRect(0,0,0,0);
563 void CombineWith(const RunMetrics
& aOther
, PRBool aOtherIsOnLeft
);
565 // can be negative (partly due to negative spacing).
566 // Advance widths should be additive: the advance width of the
567 // (offset1, length1) plus the advance width of (offset1 + length1,
568 // length2) should be the advance width of (offset1, length1 + length2)
569 gfxFloat mAdvanceWidth
;
571 // For zero-width substrings, these must be zero!
572 gfxFloat mAscent
; // always non-negative
573 gfxFloat mDescent
; // always non-negative
575 // Bounding box that is guaranteed to include everything drawn.
576 // If aTightBoundingBox was set to true when these metrics were
577 // generated, this will tightly wrap the glyphs, otherwise it is
578 // "loose" and may be larger than the true bounding box.
579 // Coordinates are relative to the baseline left origin, so typically
580 // mBoundingBox.y == -mAscent
581 gfxRect mBoundingBox
;
585 * Draw a series of glyphs to aContext. The direction of aTextRun must
587 * @param aStart the first character to draw
588 * @param aEnd draw characters up to here
589 * @param aBaselineOrigin the baseline origin; the left end of the baseline
590 * for LTR textruns, the right end of the baseline for RTL textruns. On return,
591 * this should be updated to the other end of the baseline. In application
593 * @param aSpacing spacing to insert before and after characters (for RTL
594 * glyphs, before-spacing is inserted to the right of characters). There
595 * are aEnd - aStart elements in this array, unless it's null to indicate
596 * that there is no spacing.
597 * @param aDrawToPath when true, add the glyph outlines to the current path
598 * instead of drawing the glyphs
601 * -- aStart and aEnd are aligned to cluster and ligature boundaries
602 * -- all glyphs use this font
604 * The default implementation builds a cairo glyph array and
605 * calls cairo_show_glyphs or cairo_glyph_path.
607 virtual void Draw(gfxTextRun
*aTextRun
, PRUint32 aStart
, PRUint32 aEnd
,
608 gfxContext
*aContext
, PRBool aDrawToPath
, gfxPoint
*aBaselineOrigin
,
611 * Measure a run of characters. See gfxTextRun::Metrics.
612 * @param aTight if false, then return the union of the glyph extents
613 * with the font-box for the characters (the rectangle with x=0,width=
614 * the advance width for the character run,y=-(font ascent), and height=
615 * font ascent + font descent). Otherwise, we must return as tight as possible
616 * an approximation to the area actually painted by glyphs.
617 * @param aContextForTightBoundingBox when aTight is true, this must
619 * @param aSpacing spacing to insert before and after glyphs. The bounding box
620 * need not include the spacing itself, but the spacing affects the glyph
621 * positions. null if there is no spacing.
624 * -- aStart and aEnd are aligned to cluster and ligature boundaries
625 * -- all glyphs use this font
627 * The default implementation just uses font metrics and aTextRun's
628 * advances, and assumes no characters fall outside the font box. In
629 * general this is insufficient, because that assumption is not always true.
631 virtual RunMetrics
Measure(gfxTextRun
*aTextRun
,
632 PRUint32 aStart
, PRUint32 aEnd
,
633 PRBool aTightBoundingBox
,
634 gfxContext
*aContextForTightBoundingBox
,
637 * Line breaks have been changed at the beginning and/or end of a substring
638 * of the text. Reshaping may be required; glyph updating is permitted.
639 * @return true if anything was changed, false otherwise
641 PRBool
NotifyLineBreaksChanged(gfxTextRun
*aTextRun
,
642 PRUint32 aStart
, PRUint32 aLength
)
645 // Expiration tracking
646 nsExpirationState
*GetExpirationState() { return &mExpirationState
; }
648 // Get the glyphID of a space
649 virtual PRUint32
GetSpaceGlyph() = 0;
651 gfxGlyphExtents
*GetOrCreateGlyphExtents(PRUint32 aAppUnitsPerDevUnit
);
653 // You need to call SetupCairoFont on the aCR just before calling this
654 virtual void SetupGlyphExtents(gfxContext
*aContext
, PRUint32 aGlyphID
,
655 PRBool aNeedTight
, gfxGlyphExtents
*aExtents
);
657 // This is called by the default Draw() implementation above.
658 virtual PRBool
SetupCairoFont(gfxContext
*aContext
) = 0;
660 PRBool
IsSyntheticBold() { return mSyntheticBoldOffset
!= 0; }
661 PRUint32
GetSyntheticBoldOffset() { return mSyntheticBoldOffset
; }
663 gfxFontEntry
*GetFontEntry() { return mFontEntry
.get(); }
664 PRBool
HasCharacter(PRUint32 ch
) {
667 return mFontEntry
->HasCharacter(ch
);
671 nsRefPtr
<gfxFontEntry
> mFontEntry
;
673 PRPackedBool mIsValid
;
674 nsExpirationState mExpirationState
;
676 nsAutoTArray
<gfxGlyphExtents
*,1> mGlyphExtentsArray
;
678 // synthetic bolding for environments where this is not supported by the platform
679 PRUint32 mSyntheticBoldOffset
; // number of devunit pixels to offset double-strike, 0 ==> no bolding
681 // some fonts have bad metrics, this method sanitize them.
682 // if this font has bad underline offset, aIsBadUnderlineFont should be true.
683 void SanitizeMetrics(gfxFont::Metrics
*aMetrics
, PRBool aIsBadUnderlineFont
);
686 class THEBES_API gfxTextRunFactory
{
687 THEBES_INLINE_DECL_REFCOUNTING(gfxTextRunFactory
)
690 // Flags in the mask 0xFFFF0000 are reserved for textrun clients
691 // Flags in the mask 0x0000F000 are reserved for per-platform fonts
692 // Flags in the mask 0x00000FFF are set by the textrun creator.
694 CACHE_TEXT_FLAGS
= 0xF0000000,
695 USER_TEXT_FLAGS
= 0x0FFF0000,
696 PLATFORM_TEXT_FLAGS
= 0x0000F000,
697 TEXTRUN_TEXT_FLAGS
= 0x00000FFF,
698 SETTABLE_FLAGS
= CACHE_TEXT_FLAGS
| USER_TEXT_FLAGS
,
701 * When set, the text string pointer used to create the text run
702 * is guaranteed to be available during the lifetime of the text run.
704 TEXT_IS_PERSISTENT
= 0x0001,
706 * When set, the text is known to be all-ASCII (< 128).
708 TEXT_IS_ASCII
= 0x0002,
710 * When set, the text is RTL.
712 TEXT_IS_RTL
= 0x0004,
714 * When set, spacing is enabled and the textrun needs to call GetSpacing
715 * on the spacing provider.
717 TEXT_ENABLE_SPACING
= 0x0008,
719 * When set, GetSpacing can return negative spacing.
721 TEXT_ENABLE_NEGATIVE_SPACING
= 0x0010,
723 * When set, GetHyphenationBreaks may return true for some character
724 * positions, otherwise it will always return false for all characters.
726 TEXT_ENABLE_HYPHEN_BREAKS
= 0x0040,
728 * When set, the text has no characters above 255 and it is stored
729 * in the textrun in 8-bit format.
731 TEXT_IS_8BIT
= 0x0080,
733 * When set, the text may have UTF16 surrogate pairs, otherwise it
736 TEXT_HAS_SURROGATES
= 0x0100,
738 * When set, the RunMetrics::mBoundingBox field will be initialized
739 * properly based on glyph extents, in particular, glyph extents that
740 * overflow the standard font-box (the box defined by the ascent, descent
741 * and advance width of the glyph). When not set, it may just be the
742 * standard font-box even if glyphs overflow.
744 TEXT_NEED_BOUNDING_BOX
= 0x0200,
746 * When set, optional ligatures are disabled. Ligatures that are
747 * required for legible text should still be enabled.
749 TEXT_DISABLE_OPTIONAL_LIGATURES
= 0x0400,
751 * When set, the textrun should favour speed of construction over
752 * quality. This may involve disabling ligatures and/or kerning or
755 TEXT_OPTIMIZE_SPEED
= 0x0800
759 * This record contains all the parameters needed to initialize a textrun.
762 // A reference context suggesting where the textrun will be rendered
763 gfxContext
*mContext
;
764 // Pointer to arbitrary user data (which should outlive the textrun)
766 // A description of which characters have been stripped from the original
767 // DOM string to produce the characters in the textrun. May be null
768 // if that information is not relevant.
769 gfxSkipChars
*mSkipChars
;
770 // A list of where linebreaks are currently placed in the textrun. May
771 // be null if mInitialBreakCount is zero.
772 PRUint32
*mInitialBreaks
;
773 PRUint32 mInitialBreakCount
;
774 // The ratio to use to convert device pixels to application layout units
775 PRUint32 mAppUnitsPerDevUnit
;
778 virtual ~gfxTextRunFactory() {}
782 * gfxTextRun is an abstraction for drawing and measuring substrings of a run
783 * of text. It stores runs of positioned glyph data, each run having a single
784 * gfxFont. The glyphs are associated with a string of source text, and the
785 * gfxTextRun APIs take parameters that are offsets into that source text.
787 * gfxTextRuns are not refcounted. They should be deleted when no longer required.
789 * gfxTextRuns are mostly immutable. The only things that can change are
790 * inter-cluster spacing and line break placement. Spacing is always obtained
791 * lazily by methods that need it, it is not cached. Line breaks are stored
792 * persistently (insofar as they affect the shaping of glyphs; gfxTextRun does
793 * not actually do anything to explicitly account for line breaks). Initially
794 * there are no line breaks. The textrun can record line breaks before or after
795 * any given cluster. (Line breaks specified inside clusters are ignored.)
797 * It is important that zero-length substrings are handled correctly. This will
800 * gfxTextRun stores a list of zero or more glyphs for each character. For each
801 * glyph we store the glyph ID, the advance, and possibly an xoffset and yoffset.
802 * The idea is that a string is rendered by a loop that draws each glyph
803 * at its designated offset from the current point, then advances the current
804 * point by the glyph's advance in the direction of the textrun (LTR or RTL).
805 * Each glyph advance is always rounded to the nearest appunit; this ensures
806 * consistent results when dividing the text in a textrun into multiple text
807 * frames (frame boundaries are always aligned to appunits). We optimize
808 * for the case where a character has a single glyph and zero xoffset and yoffset,
809 * and the glyph ID and advance are in a reasonable range so we can pack all
810 * necessary data into 32 bits.
812 * gfxTextRun methods that measure or draw substrings will associate all the
813 * glyphs in a cluster with the first character of the cluster; if that character
814 * is in the substring, the glyphs will be measured or drawn, otherwise they
817 class THEBES_API gfxTextRun
{
819 // Override operator delete because we used custom allocation
820 void operator delete(void* aPtr
);
821 virtual ~gfxTextRun();
823 typedef gfxFont::RunMetrics Metrics
;
825 // Public textrun API for general use
827 PRBool
IsClusterStart(PRUint32 aPos
) {
828 NS_ASSERTION(0 <= aPos
&& aPos
< mCharacterCount
, "aPos out of range");
829 return mCharacterGlyphs
[aPos
].IsClusterStart();
831 PRBool
IsLigatureGroupStart(PRUint32 aPos
) {
832 NS_ASSERTION(0 <= aPos
&& aPos
< mCharacterCount
, "aPos out of range");
833 return mCharacterGlyphs
[aPos
].IsLigatureGroupStart();
835 PRBool
CanBreakLineBefore(PRUint32 aPos
) {
836 NS_ASSERTION(0 <= aPos
&& aPos
< mCharacterCount
, "aPos out of range");
837 return mCharacterGlyphs
[aPos
].CanBreakBefore();
840 PRUint32
GetLength() { return mCharacterCount
; }
842 // All PRUint32 aStart, PRUint32 aLength ranges below are restricted to
843 // grapheme cluster boundaries! All offsets are in terms of the string
844 // passed into MakeTextRun.
846 // All coordinates are in layout/app units
849 * Set the potential linebreaks for a substring of the textrun. These are
850 * the "allow break before" points. Initially, there are no potential
853 * This can change glyphs and/or geometry! Some textruns' shapes
854 * depend on potential line breaks (e.g., title-case-converting textruns).
855 * This function is virtual so that those textruns can reshape themselves.
857 * @return true if this changed the linebreaks, false if the new line
858 * breaks are the same as the old
860 virtual PRBool
SetPotentialLineBreaks(PRUint32 aStart
, PRUint32 aLength
,
861 PRPackedBool
*aBreakBefore
,
862 gfxContext
*aRefContext
);
865 * Layout provides PropertyProvider objects. These allow detection of
866 * potential line break points and computation of spacing. We pass the data
867 * this way to allow lazy data acquisition; for example BreakAndMeasureText
868 * will want to only ask for properties of text it's actually looking at.
870 * NOTE that requested spacing may not actually be applied, if the textrun
871 * is unable to apply it in some context. Exception: spacing around a
872 * whitespace character MUST always be applied.
874 class PropertyProvider
{
876 // Detect hyphenation break opportunities in the given range; breaks
877 // not at cluster boundaries will be ignored.
878 virtual void GetHyphenationBreaks(PRUint32 aStart
, PRUint32 aLength
,
879 PRPackedBool
*aBreakBefore
) = 0;
881 // Returns the extra width that will be consumed by a hyphen. This should
882 // be constant for a given textrun.
883 virtual gfxFloat
GetHyphenWidth() = 0;
885 typedef gfxFont::Spacing Spacing
;
888 * Get the spacing around the indicated characters. Spacing must be zero
889 * inside clusters. In other words, if character i is not
890 * CLUSTER_START, then character i-1 must have zero after-spacing and
891 * character i must have zero before-spacing.
893 virtual void GetSpacing(PRUint32 aStart
, PRUint32 aLength
,
894 Spacing
*aSpacing
) = 0;
898 * Draws a substring. Uses only GetSpacing from aBreakProvider.
899 * The provided point is the baseline origin on the left of the string
900 * for LTR, on the right of the string for RTL.
901 * @param aDirtyRect if non-null, drawing outside of the rectangle can be
902 * (but does not need to be) dropped. Note that if this is null, we cannot
903 * draw partial ligatures and we will assert if partial ligatures
905 * @param aAdvanceWidth if non-null, the advance width of the substring
908 * Drawing should respect advance widths in the sense that for LTR runs,
909 * Draw(ctx, pt, offset1, length1, dirty, &provider, &advance) followed by
910 * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1 + length1, length2,
911 * dirty, &provider, nsnull) should have the same effect as
912 * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nsnull).
913 * For RTL runs the rule is:
914 * Draw(ctx, pt, offset1 + length1, length2, dirty, &provider, &advance) followed by
915 * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1, length1,
916 * dirty, &provider, nsnull) should have the same effect as
917 * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nsnull).
919 * Glyphs should be drawn in logical content order, which can be significant
920 * if they overlap (perhaps due to negative spacing).
922 void Draw(gfxContext
*aContext
, gfxPoint aPt
,
923 PRUint32 aStart
, PRUint32 aLength
,
924 const gfxRect
*aDirtyRect
,
925 PropertyProvider
*aProvider
,
926 gfxFloat
*aAdvanceWidth
);
929 * Renders a substring to a path. Uses only GetSpacing from aBreakProvider.
930 * The provided point is the baseline origin on the left of the string
931 * for LTR, on the right of the string for RTL.
932 * @param aAdvanceWidth if non-null, the advance width of the substring
935 * Drawing should respect advance widths in the way that Draw above does.
937 * Glyphs should be drawn in logical content order.
939 * UNLIKE Draw above, this cannot be used to render substrings that start or
940 * end inside a ligature.
942 void DrawToPath(gfxContext
*aContext
, gfxPoint aPt
,
943 PRUint32 aStart
, PRUint32 aLength
,
944 PropertyProvider
*aBreakProvider
,
945 gfxFloat
*aAdvanceWidth
);
948 * Computes the ReflowMetrics for a substring.
949 * Uses GetSpacing from aBreakProvider.
950 * @param aTightBoundingBox if true, we make the bounding box tight
952 Metrics
MeasureText(PRUint32 aStart
, PRUint32 aLength
,
953 PRBool aTightBoundingBox
,
954 gfxContext
*aRefContextForTightBoundingBox
,
955 PropertyProvider
*aProvider
);
958 * Computes just the advance width for a substring.
959 * Uses GetSpacing from aBreakProvider.
961 gfxFloat
GetAdvanceWidth(PRUint32 aStart
, PRUint32 aLength
,
962 PropertyProvider
*aProvider
);
965 * Clear all stored line breaks for the given range (both before and after),
966 * and then set the line-break state before aStart to aBreakBefore and
967 * after the last cluster to aBreakAfter.
969 * We require that before and after line breaks be consistent. For clusters
970 * i and i+1, we require that if there is a break after cluster i, a break
971 * will be specified before cluster i+1. This may be temporarily violated
972 * (e.g. after reflowing line L and before reflowing line L+1); to handle
973 * these temporary violations, we say that there is a break betwen i and i+1
974 * if a break is specified after i OR a break is specified before i+1.
976 * This can change textrun geometry! The existence of a linebreak can affect
977 * the advance width of the cluster before the break (when kerning) or the
978 * geometry of one cluster before the break or any number of clusters
979 * after the break. (The one-cluster-before-the-break limit is somewhat
980 * arbitrary; if some scripts require breaking it, then we need to
981 * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase
982 * it could affect the layout of frames before it...)
984 * We return true if glyphs or geometry changed, false otherwise. This
985 * function is virtual so that gfxTextRun subclasses can reshape
988 * @param aAdvanceWidthDelta if non-null, returns the change in advance
989 * width of the given range.
991 virtual PRBool
SetLineBreaks(PRUint32 aStart
, PRUint32 aLength
,
992 PRBool aLineBreakBefore
, PRBool aLineBreakAfter
,
993 gfxFloat
*aAdvanceWidthDelta
,
994 gfxContext
*aRefContext
);
997 * Finds the longest substring that will fit into the given width.
998 * Uses GetHyphenationBreaks and GetSpacing from aBreakProvider.
999 * Guarantees the following:
1000 * -- 0 <= result <= aMaxLength
1001 * -- result is the maximal value of N such that either
1002 * N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
1003 * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
1004 * OR N == aMaxLength && GetAdvanceWidth(aStart, N) <= aWidth
1005 * where GetAdvanceWidth assumes the effect of
1006 * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
1007 * -- if no such N exists, then result is the smallest N such that
1008 * N < aMaxLength && line break at N
1009 * OR N < aMaxLength && hyphen break at N
1010 * OR N == aMaxLength
1012 * The call has the effect of
1013 * SetLineBreaks(aStart, result, aLineBreakBefore, result < aMaxLength, aProvider)
1014 * and the returned metrics and the invariants above reflect this.
1016 * @param aMaxLength this can be PR_UINT32_MAX, in which case the length used
1017 * is up to the end of the string
1018 * @param aLineBreakBefore set to true if and only if there is an actual
1019 * line break at the start of this string.
1020 * @param aSuppressInitialBreak if true, then we assume there is no possible
1021 * linebreak before aStart. If false, then we will check the internal
1022 * line break opportunity state before deciding whether to return 0 as the
1023 * character to break before.
1024 * @param aTrimWhitespace if non-null, then we allow a trailing run of
1025 * spaces to be trimmed; the width of the space(s) will not be included in
1026 * the measured string width for comparison with the limit aWidth, and
1027 * trimmed spaces will not be included in returned metrics. The width
1028 * of the trimmed spaces will be returned in aTrimWhitespace.
1029 * Trimmed spaces are still counted in the "characters fit" result.
1030 * @param aMetrics if non-null, we fill this in for the returned substring.
1031 * If a hyphenation break was used, the hyphen is NOT included in the returned metrics.
1032 * @param aTightBoundingBox if true, we make the bounding box in aMetrics tight
1033 * @param aRefContextForTightBoundingBox a reference context to get the
1034 * tight bounding box, if aTightBoundingBox is true
1035 * @param aUsedHyphenation if non-null, records if we selected a hyphenation break
1036 * @param aLastBreak if non-null and result is aMaxLength, we set this to
1037 * the maximal N such that
1038 * N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
1039 * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
1040 * or PR_UINT32_MAX if no such N exists, where GetAdvanceWidth assumes
1042 * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
1044 * @param aCanWordWrap true if we can break between any two grapheme
1045 * clusters. This is set by word-wrap: break-word
1047 * @param aBreakPriority in/out the priority of the break opportunity
1048 * saved in the line. If we are prioritizing break opportunities, we will
1049 * not set a break with a lower priority. @see gfxBreakPriority.
1051 * Note that negative advance widths are possible especially if negative
1052 * spacing is provided.
1054 PRUint32
BreakAndMeasureText(PRUint32 aStart
, PRUint32 aMaxLength
,
1055 PRBool aLineBreakBefore
, gfxFloat aWidth
,
1056 PropertyProvider
*aProvider
,
1057 PRBool aSuppressInitialBreak
,
1058 gfxFloat
*aTrimWhitespace
,
1059 Metrics
*aMetrics
, PRBool aTightBoundingBox
,
1060 gfxContext
*aRefContextForTightBoundingBox
,
1061 PRBool
*aUsedHyphenation
,
1062 PRUint32
*aLastBreak
,
1063 PRBool aCanWordWrap
,
1064 gfxBreakPriority
*aBreakPriority
);
1067 * Update the reference context.
1068 * XXX this is a hack. New text frame does not call this. Use only
1069 * temporarily for old text frame.
1071 void SetContext(gfxContext
*aContext
) {}
1075 PRBool
IsRightToLeft() const { return (mFlags
& gfxTextRunFactory::TEXT_IS_RTL
) != 0; }
1076 gfxFloat
GetDirection() const { return (mFlags
& gfxTextRunFactory::TEXT_IS_RTL
) ? -1.0 : 1.0; }
1077 void *GetUserData() const { return mUserData
; }
1078 void SetUserData(void *aUserData
) { mUserData
= aUserData
; }
1079 PRUint32
GetFlags() const { return mFlags
; }
1080 void SetFlagBits(PRUint32 aFlags
) {
1081 NS_ASSERTION(!(aFlags
& ~gfxTextRunFactory::SETTABLE_FLAGS
),
1082 "Only user flags should be mutable");
1085 void ClearFlagBits(PRUint32 aFlags
) {
1086 NS_ASSERTION(!(aFlags
& ~gfxTextRunFactory::SETTABLE_FLAGS
),
1087 "Only user flags should be mutable");
1090 const gfxSkipChars
& GetSkipChars() const { return mSkipChars
; }
1091 PRUint32
GetAppUnitsPerDevUnit() const { return mAppUnitsPerDevUnit
; }
1092 gfxFontGroup
*GetFontGroup() const { return mFontGroup
; }
1093 const PRUint8
*GetText8Bit() const
1094 { return (mFlags
& gfxTextRunFactory::TEXT_IS_8BIT
) ? mText
.mSingle
: nsnull
; }
1095 const PRUnichar
*GetTextUnicode() const
1096 { return (mFlags
& gfxTextRunFactory::TEXT_IS_8BIT
) ? nsnull
: mText
.mDouble
; }
1097 const void *GetTextAt(PRUint32 aIndex
) {
1098 return (mFlags
& gfxTextRunFactory::TEXT_IS_8BIT
)
1099 ? static_cast<const void *>(mText
.mSingle
+ aIndex
)
1100 : static_cast<const void *>(mText
.mDouble
+ aIndex
);
1102 const PRUnichar
GetChar(PRUint32 i
) const
1103 { return (mFlags
& gfxTextRunFactory::TEXT_IS_8BIT
) ? mText
.mSingle
[i
] : mText
.mDouble
[i
]; }
1104 PRUint32
GetHashCode() const { return mHashCode
; }
1105 void SetHashCode(PRUint32 aHash
) { mHashCode
= aHash
; }
1107 // Call this, don't call "new gfxTextRun" directly. This does custom
1108 // allocation and initialization
1109 static gfxTextRun
*Create(const gfxTextRunFactory::Parameters
*aParams
,
1110 const void *aText
, PRUint32 aLength
, gfxFontGroup
*aFontGroup
, PRUint32 aFlags
);
1112 // Clone this textrun, according to the given parameters. This textrun's
1113 // glyph data is copied, so the text and length must be the same as this
1114 // textrun's. If there's a problem, return null. Actual linebreaks will
1115 // be set as per aParams; there will be no potential linebreaks.
1116 // If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
1117 // textrun will copy it.
1118 virtual gfxTextRun
*Clone(const gfxTextRunFactory::Parameters
*aParams
, const void *aText
,
1119 PRUint32 aLength
, gfxFontGroup
*aFontGroup
, PRUint32 aFlags
);
1122 * This class records the information associated with a character in the
1123 * input string. It's optimized for the case where there is one glyph
1124 * representing that character alone.
1126 * A character can have zero or more associated glyphs. Each glyph
1127 * has an advance width and an x and y offset.
1128 * A character may be the start of a cluster.
1129 * A character may be the start of a ligature group.
1130 * A character can be "missing", indicating that the system is unable
1131 * to render the character.
1133 * All characters in a ligature group conceptually share all the glyphs
1134 * associated with the characters in a group.
1136 class CompressedGlyph
{
1138 CompressedGlyph() { mValue
= 0; }
1141 // Indicates that a cluster and ligature group starts at this
1142 // character; this character has a single glyph with a reasonable
1143 // advance and zero offsets. A "reasonable" advance
1144 // is one that fits in the available bits (currently 14) (specified
1146 FLAG_IS_SIMPLE_GLYPH
= 0x80000000U
,
1147 // Indicates that a linebreak is allowed before this character
1148 FLAG_CAN_BREAK_BEFORE
= 0x40000000U
,
1150 // The advance is stored in appunits
1151 ADVANCE_MASK
= 0x3FFF0000U
,
1154 GLYPH_MASK
= 0x0000FFFFU
,
1156 // Non-simple glyphs may or may not have glyph data in the
1157 // corresponding mDetailedGlyphs entry. They have the following
1160 // When NOT set, indicates that this character corresponds to a
1161 // missing glyph and should be skipped (or possibly, render the character
1162 // Unicode value in some special way). If there are glyphs,
1163 // the mGlyphID is actually the UTF16 character code. The bit is
1164 // inverted so we can memset the array to zero to indicate all missing.
1165 FLAG_NOT_MISSING
= 0x01,
1166 FLAG_NOT_CLUSTER_START
= 0x02,
1167 FLAG_NOT_LIGATURE_GROUP_START
= 0x04,
1168 FLAG_LOW_SURROGATE
= 0x08,
1170 GLYPH_COUNT_MASK
= 0x00FFFF00U
,
1171 GLYPH_COUNT_SHIFT
= 8
1174 // "Simple glyphs" have a simple glyph ID, simple advance and their
1175 // x and y offsets are zero. Also the glyph extents do not overflow
1176 // the font-box defined by the font ascent, descent and glyph advance width.
1177 // These case is optimized to avoid storing DetailedGlyphs.
1179 // Returns true if the glyph ID aGlyph fits into the compressed representation
1180 static PRBool
IsSimpleGlyphID(PRUint32 aGlyph
) {
1181 return (aGlyph
& GLYPH_MASK
) == aGlyph
;
1183 // Returns true if the advance aAdvance fits into the compressed representation.
1184 // aAdvance is in appunits.
1185 static PRBool
IsSimpleAdvance(PRUint32 aAdvance
) {
1186 return (aAdvance
& (ADVANCE_MASK
>> ADVANCE_SHIFT
)) == aAdvance
;
1189 PRBool
IsSimpleGlyph() const { return (mValue
& FLAG_IS_SIMPLE_GLYPH
) != 0; }
1190 PRUint32
GetSimpleAdvance() const { return (mValue
& ADVANCE_MASK
) >> ADVANCE_SHIFT
; }
1191 PRUint32
GetSimpleGlyph() const { return mValue
& GLYPH_MASK
; }
1193 PRBool
IsMissing() const { return (mValue
& (FLAG_NOT_MISSING
|FLAG_IS_SIMPLE_GLYPH
)) == 0; }
1194 PRBool
IsLowSurrogate() const {
1195 return (mValue
& (FLAG_LOW_SURROGATE
|FLAG_IS_SIMPLE_GLYPH
)) == FLAG_LOW_SURROGATE
;
1197 PRBool
IsClusterStart() const {
1198 return (mValue
& FLAG_IS_SIMPLE_GLYPH
) || !(mValue
& FLAG_NOT_CLUSTER_START
);
1200 PRBool
IsLigatureGroupStart() const {
1201 return (mValue
& FLAG_IS_SIMPLE_GLYPH
) || !(mValue
& FLAG_NOT_LIGATURE_GROUP_START
);
1204 PRBool
CanBreakBefore() const { return (mValue
& FLAG_CAN_BREAK_BEFORE
) != 0; }
1205 // Returns FLAG_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
1206 PRUint32
SetCanBreakBefore(PRBool aCanBreakBefore
) {
1207 NS_ASSERTION(aCanBreakBefore
== PR_FALSE
|| aCanBreakBefore
== PR_TRUE
,
1208 "Bogus break-before value!");
1209 PRUint32 breakMask
= aCanBreakBefore
*FLAG_CAN_BREAK_BEFORE
;
1210 PRUint32 toggle
= breakMask
^ (mValue
& FLAG_CAN_BREAK_BEFORE
);
1215 CompressedGlyph
& SetSimpleGlyph(PRUint32 aAdvanceAppUnits
, PRUint32 aGlyph
) {
1216 NS_ASSERTION(IsSimpleAdvance(aAdvanceAppUnits
), "Advance overflow");
1217 NS_ASSERTION(IsSimpleGlyphID(aGlyph
), "Glyph overflow");
1218 mValue
= (mValue
& FLAG_CAN_BREAK_BEFORE
) | FLAG_IS_SIMPLE_GLYPH
|
1219 (aAdvanceAppUnits
<< ADVANCE_SHIFT
) | aGlyph
;
1222 CompressedGlyph
& SetComplex(PRBool aClusterStart
, PRBool aLigatureStart
,
1223 PRUint32 aGlyphCount
) {
1224 mValue
= (mValue
& FLAG_CAN_BREAK_BEFORE
) | FLAG_NOT_MISSING
|
1225 (aClusterStart
? 0 : FLAG_NOT_CLUSTER_START
) |
1226 (aLigatureStart
? 0 : FLAG_NOT_LIGATURE_GROUP_START
) |
1227 (aGlyphCount
<< GLYPH_COUNT_SHIFT
);
1231 * Missing glyphs are treated as cluster and ligature group starts.
1233 CompressedGlyph
& SetMissing(PRUint32 aGlyphCount
) {
1234 mValue
= (mValue
& FLAG_CAN_BREAK_BEFORE
) |
1235 (aGlyphCount
<< GLYPH_COUNT_SHIFT
);
1239 * Low surrogates don't have any glyphs and are not the start of
1240 * a cluster or ligature group.
1242 CompressedGlyph
& SetLowSurrogate() {
1243 mValue
= (mValue
& FLAG_CAN_BREAK_BEFORE
) | FLAG_NOT_MISSING
|
1247 PRUint32
GetGlyphCount() const {
1248 NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
1249 return (mValue
& GLYPH_COUNT_MASK
) >> GLYPH_COUNT_SHIFT
;
1257 * When the glyphs for a character don't fit into a CompressedGlyph record
1258 * in SimpleGlyph format, we use an array of DetailedGlyphs instead.
1260 struct DetailedGlyph
{
1261 /** The glyphID, or the Unicode character
1262 * if this is a missing glyph */
1264 /** The advance, x-offset and y-offset of the glyph, in appunits
1265 * mAdvance is in the text direction (RTL or LTR)
1266 * mXOffset is always from left to right
1267 * mYOffset is always from bottom to top */
1269 float mXOffset
, mYOffset
;
1272 // The text is divided into GlyphRuns as necessary
1274 nsRefPtr
<gfxFont
> mFont
; // never null
1275 PRUint32 mCharacterOffset
; // into original UTF16 string
1278 class THEBES_API GlyphRunIterator
{
1280 GlyphRunIterator(gfxTextRun
*aTextRun
, PRUint32 aStart
, PRUint32 aLength
)
1281 : mTextRun(aTextRun
), mStartOffset(aStart
), mEndOffset(aStart
+ aLength
) {
1282 mNextIndex
= mTextRun
->FindFirstGlyphRunContaining(aStart
);
1285 GlyphRun
*GetGlyphRun() { return mGlyphRun
; }
1286 PRUint32
GetStringStart() { return mStringStart
; }
1287 PRUint32
GetStringEnd() { return mStringEnd
; }
1289 gfxTextRun
*mTextRun
;
1290 GlyphRun
*mGlyphRun
;
1291 PRUint32 mStringStart
;
1292 PRUint32 mStringEnd
;
1293 PRUint32 mNextIndex
;
1294 PRUint32 mStartOffset
;
1295 PRUint32 mEndOffset
;
1298 class GlyphRunOffsetComparator
{
1300 PRBool
Equals(const GlyphRun
& a
,
1301 const GlyphRun
& b
) const
1303 return a
.mCharacterOffset
== b
.mCharacterOffset
;
1306 PRBool
LessThan(const GlyphRun
& a
,
1307 const GlyphRun
& b
) const
1309 return a
.mCharacterOffset
< b
.mCharacterOffset
;
1313 friend class GlyphRunIterator
;
1314 friend class FontSelector
;
1316 // API for setting up the textrun glyphs. Should only be called by
1317 // things that construct textruns.
1319 * Record every character that is the second half of a surrogate pair.
1320 * This should be called after creating a Unicode textrun.
1322 void RecordSurrogates(const PRUnichar
*aString
);
1324 * We've found a run of text that should use a particular font. Call this
1325 * only during initialization when font substitution has been computed.
1326 * Call it before setting up the glyphs for the characters in this run;
1327 * SetMissingGlyph requires that the correct glyphrun be installed.
1329 * If aForceNewRun, a new glyph run will be added, even if the
1330 * previously added run uses the same font. If glyph runs are
1331 * added out of strictly increasing aStartCharIndex order (via
1332 * force), then SortGlyphRuns must be called after all glyph runs
1333 * are added before any further operations are performed with this
1336 nsresult
AddGlyphRun(gfxFont
*aFont
, PRUint32 aStartCharIndex
, PRBool aForceNewRun
= PR_FALSE
);
1337 void ResetGlyphRuns() { mGlyphRuns
.Clear(); }
1338 void SortGlyphRuns();
1340 // Call the following glyph-setters during initialization or during reshaping
1341 // only. It is OK to overwrite existing data for a character.
1343 * Set the glyph data for a character. aGlyphs may be null if aGlyph is a
1344 * simple glyph or has no associated glyphs. If non-null the data is copied,
1345 * the caller retains ownership.
1347 void SetSimpleGlyph(PRUint32 aCharIndex
, CompressedGlyph aGlyph
) {
1348 NS_ASSERTION(aGlyph
.IsSimpleGlyph(), "Should be a simple glyph here");
1349 if (mCharacterGlyphs
) {
1350 mCharacterGlyphs
[aCharIndex
] = aGlyph
;
1352 if (mDetailedGlyphs
) {
1353 mDetailedGlyphs
[aCharIndex
] = nsnull
;
1356 void SetGlyphs(PRUint32 aCharIndex
, CompressedGlyph aGlyph
,
1357 const DetailedGlyph
*aGlyphs
);
1358 void SetMissingGlyph(PRUint32 aCharIndex
, PRUint32 aUnicodeChar
);
1359 void SetSpaceGlyph(gfxFont
*aFont
, gfxContext
*aContext
, PRUint32 aCharIndex
);
1362 * Prefetch all the glyph extents needed to ensure that Measure calls
1363 * on this textrun with aTightBoundingBox false will succeed. Note
1364 * that some glyph extents might not be fetched due to OOM or other
1367 void FetchGlyphExtents(gfxContext
*aRefContext
);
1369 // API for access to the raw glyph data, needed by gfxFont::Draw
1370 // and gfxFont::GetBoundingBox
1371 const CompressedGlyph
*GetCharacterGlyphs() { return mCharacterGlyphs
; }
1372 const DetailedGlyph
*GetDetailedGlyphs(PRUint32 aCharIndex
) {
1373 return mDetailedGlyphs
? mDetailedGlyphs
[aCharIndex
].get() : nsnull
;
1375 PRBool
HasDetailedGlyphs() { return mDetailedGlyphs
.get() != nsnull
; }
1376 PRUint32
CountMissingGlyphs();
1377 const GlyphRun
*GetGlyphRuns(PRUint32
*aNumGlyphRuns
) {
1378 *aNumGlyphRuns
= mGlyphRuns
.Length();
1379 return mGlyphRuns
.Elements();
1381 // Returns the index of the GlyphRun containing the given offset.
1382 // Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
1383 PRUint32
FindFirstGlyphRunContaining(PRUint32 aOffset
);
1384 // Copy glyph data for a range of characters from aSource to this
1385 // textrun. If aStealData is true then we actually steal the glyph data,
1386 // setting the data in aSource to "missing". aDest should be in the last
1388 virtual void CopyGlyphDataFrom(gfxTextRun
*aSource
, PRUint32 aStart
,
1389 PRUint32 aLength
, PRUint32 aDest
,
1392 nsExpirationState
*GetExpirationState() { return &mExpirationState
; }
1394 struct LigatureData
{
1395 // textrun offsets of the start and end of the containing ligature
1396 PRUint32 mLigatureStart
;
1397 PRUint32 mLigatureEnd
;
1398 // appunits advance to the start of the ligature part within the ligature;
1399 // never includes any spacing
1400 gfxFloat mPartAdvance
;
1401 // appunits width of the ligature part; includes before-spacing
1402 // when the part is at the start of the ligature, and after-spacing
1403 // when the part is as the end of the ligature
1404 gfxFloat mPartWidth
;
1406 PRPackedBool mClipBeforePart
;
1407 PRPackedBool mClipAfterPart
;
1410 // user font set generation when text run was created
1411 PRUint64
GetUserFontSetGeneration() { return mUserFontSetGeneration
; }
1414 // number of entries referencing this textrun in the gfxTextRunWordCache
1415 PRUint32 mCachedWords
;
1417 void Dump(FILE* aOutput
);
1420 // post-process glyph advances to deal with synthetic bolding
1421 void AdjustAdvancesForSyntheticBold(PRUint32 aStart
, PRUint32 aLength
);
1424 // Allocates extra space for the CompressedGlyph array and the text
1426 void *operator new(size_t aSize
, PRUint32 aLength
, PRUint32 aFlags
);
1429 * Initializes the textrun to blank.
1430 * @param aObjectSize the size of the object; this lets us fine
1431 * where our CompressedGlyph array and string have been allocated
1433 gfxTextRun(const gfxTextRunFactory::Parameters
*aParams
, const void *aText
,
1434 PRUint32 aLength
, gfxFontGroup
*aFontGroup
, PRUint32 aFlags
,
1435 PRUint32 aObjectSize
);
1438 // **** general helpers ****
1440 // Allocate aCount DetailedGlyphs for the given index
1441 DetailedGlyph
*AllocateDetailedGlyphs(PRUint32 aCharIndex
, PRUint32 aCount
);
1443 // Spacing for characters outside the range aSpacingStart/aSpacingEnd
1444 // is assumed to be zero; such characters are not passed to aProvider.
1445 // This is useful to protect aProvider from being passed character indices
1446 // it is not currently able to handle.
1447 PRBool
GetAdjustedSpacingArray(PRUint32 aStart
, PRUint32 aEnd
,
1448 PropertyProvider
*aProvider
,
1449 PRUint32 aSpacingStart
, PRUint32 aSpacingEnd
,
1450 nsTArray
<PropertyProvider::Spacing
> *aSpacing
);
1452 // **** ligature helpers ****
1453 // (Platforms do the actual ligaturization, but we need to do a bunch of stuff
1454 // to handle requests that begin or end inside a ligature)
1456 // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
1457 LigatureData
ComputeLigatureData(PRUint32 aPartStart
, PRUint32 aPartEnd
,
1458 PropertyProvider
*aProvider
);
1459 gfxFloat
ComputePartialLigatureWidth(PRUint32 aPartStart
, PRUint32 aPartEnd
,
1460 PropertyProvider
*aProvider
);
1461 void DrawPartialLigature(gfxFont
*aFont
, gfxContext
*aCtx
, PRUint32 aStart
,
1462 PRUint32 aEnd
, const gfxRect
*aDirtyRect
, gfxPoint
*aPt
,
1463 PropertyProvider
*aProvider
);
1464 // Advance aStart to the start of the nearest ligature; back up aEnd
1465 // to the nearest ligature end; may result in *aStart == *aEnd
1466 void ShrinkToLigatureBoundaries(PRUint32
*aStart
, PRUint32
*aEnd
);
1467 // result in appunits
1468 gfxFloat
GetPartialLigatureWidth(PRUint32 aStart
, PRUint32 aEnd
, PropertyProvider
*aProvider
);
1469 void AccumulatePartialLigatureMetrics(gfxFont
*aFont
,
1470 PRUint32 aStart
, PRUint32 aEnd
, PRBool aTight
,
1471 gfxContext
*aRefContext
,
1472 PropertyProvider
*aProvider
,
1475 // **** measurement helper ****
1476 void AccumulateMetricsForRun(gfxFont
*aFont
, PRUint32 aStart
,
1477 PRUint32 aEnd
, PRBool aTight
,
1478 gfxContext
*aRefContext
,
1479 PropertyProvider
*aProvider
,
1480 PRUint32 aSpacingStart
, PRUint32 aSpacingEnd
,
1483 // **** drawing helper ****
1484 void DrawGlyphs(gfxFont
*aFont
, gfxContext
*aContext
, PRBool aDrawToPath
,
1485 gfxPoint
*aPt
, PRUint32 aStart
, PRUint32 aEnd
,
1486 PropertyProvider
*aProvider
,
1487 PRUint32 aSpacingStart
, PRUint32 aSpacingEnd
);
1489 // All our glyph data is in logical order, not visual.
1490 // mCharacterGlyphs is allocated fused with this object. We need a pointer
1491 // to it because gfxTextRun subclasses exist with extra fields, so we don't
1492 // know where it starts without a virtual method call or an explicit pointer.
1493 CompressedGlyph
* mCharacterGlyphs
;
1494 nsAutoArrayPtr
<nsAutoArrayPtr
<DetailedGlyph
> > mDetailedGlyphs
; // only non-null if needed
1495 // XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
1496 // for smaller size especially in the super-common one-glyphrun case
1497 nsAutoTArray
<GlyphRun
,1> mGlyphRuns
;
1498 // When TEXT_IS_8BIT is set, we use mSingle, otherwise we use mDouble.
1499 // When TEXT_IS_PERSISTENT is set, we don't own the text, otherwise we
1500 // own the text. When we own the text, it's allocated fused with this
1501 // object, so it need not be deleted.
1502 // This text is not null-terminated.
1504 const PRUint8
*mSingle
;
1505 const PRUnichar
*mDouble
;
1508 gfxFontGroup
*mFontGroup
; // addrefed
1509 gfxSkipChars mSkipChars
;
1510 nsExpirationState mExpirationState
;
1511 PRUint32 mAppUnitsPerDevUnit
;
1513 PRUint32 mCharacterCount
;
1515 PRUint64 mUserFontSetGeneration
; // user font set generation when text run created
1518 class THEBES_API gfxFontGroup
: public gfxTextRunFactory
{
1520 gfxFontGroup(const nsAString
& aFamilies
, const gfxFontStyle
*aStyle
, gfxUserFontSet
*aUserFontSet
= nsnull
);
1523 virtual ~gfxFontGroup();
1525 virtual gfxFont
*GetFontAt(PRInt32 i
) {
1526 // If it turns out to be hard for all clients that cache font
1527 // groups to call UpdateFontList at appropriate times, we could
1528 // instead consider just calling UpdateFontList from someplace
1529 // more central (such as here).
1530 NS_ASSERTION(!mUserFontSet
|| mCurrGeneration
== GetGeneration(),
1531 "Whoever was caching this font group should have "
1532 "called UpdateFontList on it");
1534 return static_cast<gfxFont
*>(mFonts
[i
]);
1536 virtual PRUint32
FontListLength() const {
1537 return mFonts
.Length();
1540 PRBool
Equals(const gfxFontGroup
& other
) const {
1541 return mFamilies
.Equals(other
.mFamilies
) &&
1542 mStyle
.Equals(other
.mStyle
);
1545 const gfxFontStyle
*GetStyle() const { return &mStyle
; }
1547 virtual gfxFontGroup
*Copy(const gfxFontStyle
*aStyle
) = 0;
1550 * The listed characters should not be passed in to MakeTextRun and should
1551 * be treated as invisible and zero-width.
1553 static PRBool
IsInvalidChar(PRUnichar ch
);
1556 * Make a textrun for an empty string. This is fast; if you call it,
1557 * don't bother caching the result.
1559 gfxTextRun
*MakeEmptyTextRun(const Parameters
*aParams
, PRUint32 aFlags
);
1561 * Make a textrun for a single ASCII space. This is fast; if you call it,
1562 * don't bother caching the result.
1564 gfxTextRun
*MakeSpaceTextRun(const Parameters
*aParams
, PRUint32 aFlags
);
1567 * Make a textrun for a given string.
1568 * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
1569 * textrun will copy it.
1570 * This calls FetchGlyphExtents on the textrun.
1572 virtual gfxTextRun
*MakeTextRun(const PRUnichar
*aString
, PRUint32 aLength
,
1573 const Parameters
*aParams
, PRUint32 aFlags
) = 0;
1575 * Make a textrun for a given string.
1576 * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
1577 * textrun will copy it.
1578 * This calls FetchGlyphExtents on the textrun.
1580 virtual gfxTextRun
*MakeTextRun(const PRUint8
*aString
, PRUint32 aLength
,
1581 const Parameters
*aParams
, PRUint32 aFlags
) = 0;
1583 /* helper function for splitting font families on commas and
1584 * calling a function for each family to fill the mFonts array
1586 typedef PRBool (*FontCreationCallback
) (const nsAString
& aName
,
1587 const nsACString
& aGenericName
,
1589 /*static*/ PRBool
ForEachFont(const nsAString
& aFamilies
,
1590 const nsACString
& aLangGroup
,
1591 FontCreationCallback fc
,
1593 PRBool
ForEachFont(FontCreationCallback fc
, void *closure
);
1595 const nsString
& GetFamilies() { return mFamilies
; }
1597 // This returns the preferred underline for this font group.
1598 // Some CJK fonts have wrong underline offset in its metrics.
1599 // If this group has such "bad" font, each platform's gfxFontGroup initialized mUnderlineOffset.
1600 // The value should be lower value of first font's metrics and the bad font's metrics.
1601 // Otherwise, this returns from first font's metrics.
1602 enum { UNDERLINE_OFFSET_NOT_SET
= PR_INT16_MAX
};
1603 gfxFloat
GetUnderlineOffset() {
1604 if (mUnderlineOffset
== UNDERLINE_OFFSET_NOT_SET
)
1605 mUnderlineOffset
= GetFontAt(0)->GetMetrics().underlineOffset
;
1606 return mUnderlineOffset
;
1609 already_AddRefed
<gfxFont
> FindFontForChar(PRUint32 ch
, PRUint32 prevCh
, PRUint32 nextCh
, gfxFont
*aPrevMatchedFont
);
1611 virtual already_AddRefed
<gfxFont
> WhichPrefFontSupportsChar(PRUint32 aCh
) { return nsnull
; }
1613 virtual already_AddRefed
<gfxFont
> WhichSystemFontSupportsChar(PRUint32 aCh
) { return nsnull
; }
1615 void ComputeRanges(nsTArray
<gfxTextRange
>& mRanges
, const PRUnichar
*aString
, PRUint32 begin
, PRUint32 end
);
1617 gfxUserFontSet
* GetUserFontSet();
1619 // With downloadable fonts, the composition of the font group can change as fonts are downloaded
1620 // for each change in state of the user font set, the generation value is bumped to avoid picking up
1621 // previously created text runs in the text run word cache. For font groups based on stylesheets
1622 // with no @font-face rule, this always returns 0.
1623 PRUint64
GetGeneration();
1625 // If there is a user font set, check to see whether the font list or any
1626 // caches need updating.
1627 virtual void UpdateFontList() { }
1631 gfxFontStyle mStyle
;
1632 nsTArray
< nsRefPtr
<gfxFont
> > mFonts
;
1633 gfxFloat mUnderlineOffset
;
1635 gfxUserFontSet
* mUserFontSet
;
1636 PRUint64 mCurrGeneration
; // track the current user font set generation, rebuild font list if needed
1638 // Used for construction/destruction. Not intended to change the font set
1639 // as invalidation of font lists and caches is not considered.
1640 void SetUserFontSet(gfxUserFontSet
*aUserFontSet
);
1642 // Init this font group's font metrics. If there no bad fonts, you don't need to call this.
1643 // But if there are one or more bad fonts which have bad underline offset,
1644 // you should call this with the *first* bad font.
1645 void InitMetricsForBadFont(gfxFont
* aBadFont
);
1647 /* If aResolveGeneric is true, then CSS/Gecko generic family names are
1648 * replaced with preferred fonts.
1650 * If aResolveFontName is true then fc() is called only for existing fonts
1651 * and with actual font names. If false then fc() is called with each
1652 * family name in aFamilies (after resolving CSS/Gecko generic family names
1653 * if aResolveGeneric).
1655 /*static*/ PRBool
ForEachFontInternal(const nsAString
& aFamilies
,
1656 const nsACString
& aLangGroup
,
1657 PRBool aResolveGeneric
,
1658 PRBool aResolveFontName
,
1659 FontCreationCallback fc
,
1662 static PRBool
FontResolverProc(const nsAString
& aName
, void *aClosure
);
1664 inline gfxFont
* WhichFontSupportsChar(nsTArray
< nsRefPtr
<gfxFont
> >& aFontList
, PRUint32 aCh
) {
1665 PRUint32 len
= aFontList
.Length();
1666 for (PRUint32 i
= 0; i
< len
; i
++) {
1667 gfxFont
* font
= aFontList
.ElementAt(i
).get();
1668 if (font
&& font
->HasCharacter(aCh
))