Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / gfx / thebes / public / gfxFont.h
blobf4b10be6af64295d7bcde96fd277c25d42504bf0
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
13 * License.
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.
21 * Contributor(s):
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 ***** */
40 #ifndef GFX_FONT_H
41 #define GFX_FONT_H
43 #include "prtypes.h"
44 #include "gfxTypes.h"
45 #include "nsString.h"
46 #include "gfxPoint.h"
47 #include "gfxFontUtils.h"
48 #include "nsTArray.h"
49 #include "nsTHashtable.h"
50 #include "nsHashKeys.h"
51 #include "gfxSkipChars.h"
52 #include "gfxRect.h"
53 #include "nsExpirationTracker.h"
55 #ifdef DEBUG
56 #include <stdio.h>
57 #endif
59 class gfxContext;
60 class gfxTextRun;
61 class nsIAtom;
62 class gfxFont;
63 class gfxFontGroup;
64 class gfxUserFontSet;
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 {
77 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)
85 PRUint8 style : 7;
87 // Say that this font is a system font and therefore does not
88 // require certain fixup that we do for fonts from untrusted
89 // sources.
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.
101 PRUint16 weight;
103 // The logical size of the font, in pixels
104 gfxFloat size;
106 // the language group
107 nsCString langGroup;
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
112 // needs to be done.
113 float sizeAdjust;
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);
143 class gfxFontEntry {
144 public:
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))
176 return PR_TRUE;
178 return TestCharacterMap(ch);
181 virtual PRBool TestCharacterMap(PRUint32 aCh);
182 virtual nsresult ReadCMAP() { return 0; }
184 nsString mName;
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;
198 PRUint16 mWeight;
199 PRUint16 mStretch;
201 PRPackedBool mCmapInitialized;
202 gfxSparseBitSet mCharacterMap;
203 gfxUserFontData* mUserFontData;
205 protected:
206 gfxFontEntry() :
207 mIsProxy(PR_FALSE), mIsValid(PR_TRUE),
208 mCmapInitialized(PR_FALSE), mUserFontData(nsnull)
213 class gfxFontFamily {
214 public:
215 THEBES_INLINE_DECL_REFCOUNTING(gfxFontFamily)
217 gfxFontFamily(const nsAString& aName) :
218 mName(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,
227 PRBool& aNeedsBold);
229 protected:
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)
234 { return PR_FALSE; }
236 nsString mName;
239 struct gfxTextRange {
240 gfxTextRange(PRUint32 aStart, PRUint32 aEnd) : start(aStart), end(aEnd) { }
241 PRUint32 Length() const { return end - start; }
242 nsRefPtr<gfxFont> font;
243 PRUint32 start, end;
248 * Font cache design:
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> {
262 public:
263 enum { TIMEOUT_SECONDS = 10 };
264 gfxFontCache()
265 : nsExpirationTracker<gfxFont,3>(TIMEOUT_SECONDS*1000) { mFonts.Init(); }
266 ~gfxFontCache() {
267 // Expire everything that has a zero refcount, so we don't leak them.
268 AgeAllGenerations();
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
274 // the tracker.
278 * Get the global gfxFontCache. You must call Init() before
279 * calling this method --- the result will not be null.
281 static gfxFontCache* GetCache() {
282 return gGlobalCache;
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
301 // amount of time.
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);
308 protected:
309 void DestroyFont(gfxFont *aFont);
311 static gfxFontCache *gGlobalCache;
313 struct Key {
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 {
321 public:
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) { }
329 ~HashEntry() { }
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 };
338 gfxFont* mFont;
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 {
358 public:
359 gfxGlyphExtents(PRUint32 aAppUnitsPerDevUnit) :
360 mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) {
361 MOZ_COUNT_CTOR(gfxGlyphExtents);
362 mTightGlyphExtents.Init();
364 ~gfxGlyphExtents();
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
371 // appunits.
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; }
398 private:
399 class HashEntry : public nsUint32HashKey {
400 public:
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
414 class GlyphWidths {
415 public:
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];
422 if (!bits)
423 return INVALID_WIDTH;
424 PRUint32 indexInBlock = aIndex & (BLOCK_SIZE - 1);
425 if (bits & 0x1) {
426 if (GetGlyphOffset(bits) != indexInBlock)
427 return INVALID_WIDTH;
428 return GetWidth(bits);
430 PRUint16 *widths = reinterpret_cast<PRUint16 *>(bits);
431 return widths[indexInBlock];
434 #ifdef DEBUG
435 PRUint32 ComputeSize();
436 #endif
438 ~GlyphWidths();
440 private:
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 {
463 public:
464 nsrefcnt AddRef(void) {
465 NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
466 if (mExpirationState.IsTracked()) {
467 gfxFontCache::GetCache()->RemoveObject(this);
469 ++mRefCnt;
470 NS_LOG_ADDREF(this, mRefCnt, "gfxFont", sizeof(*this));
471 return mRefCnt;
473 nsrefcnt Release(void) {
474 NS_PRECONDITION(0 != mRefCnt, "dup release");
475 --mRefCnt;
476 NS_LOG_RELEASE(this, mRefCnt, "gfxFont");
477 if (mRefCnt == 0) {
478 NotifyReleased();
479 // |this| may have been deleted.
480 return 0;
482 return mRefCnt;
485 PRInt32 GetRefCount() { return mRefCnt; }
487 protected:
488 nsAutoRefCnt mRefCnt;
490 void NotifyReleased() {
491 gfxFontCache *cache = gfxFontCache::GetCache();
492 if (cache) {
493 // Don't delete just yet; return the object to the cache for
494 // possibly recycling within some time limit
495 cache->NotifyReleased(this);
496 } else {
497 // The cache may have already been shut down.
498 delete this;
502 gfxFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle);
504 public:
505 virtual ~gfxFont();
507 const nsString& GetName() const { return mFontEntry->Name(); }
508 const gfxFontStyle *GetStyle() const { return &mStyle; }
510 virtual nsString GetUniqueName() = 0;
512 // Font metrics
513 struct Metrics {
514 gfxFloat xHeight;
515 gfxFloat superscriptOffset;
516 gfxFloat subscriptOffset;
517 gfxFloat strikeoutSize;
518 gfxFloat strikeoutOffset;
519 gfxFloat underlineSize;
520 gfxFloat underlineOffset;
521 gfxFloat height;
523 gfxFloat internalLeading;
524 gfxFloat externalLeading;
526 gfxFloat emHeight;
527 gfxFloat emAscent;
528 gfxFloat emDescent;
529 gfxFloat maxHeight;
530 gfxFloat maxAscent;
531 gfxFloat maxDescent;
532 gfxFloat maxAdvance;
534 gfxFloat aveCharWidth;
535 gfxFloat spaceWidth;
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.
550 struct Spacing {
551 gfxFloat mBefore;
552 gfxFloat mAfter;
555 * Metrics for a particular string
557 struct THEBES_API RunMetrics {
558 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
586 * be honoured.
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
592 * units, really!
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
600 * Callers guarantee:
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,
609 Spacing *aSpacing);
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
618 * be non-null.
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.
623 * Callers guarantee:
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,
635 Spacing *aSpacing);
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)
643 { return PR_FALSE; }
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) {
665 if (!mIsValid)
666 return PR_FALSE;
667 return mFontEntry->HasCharacter(ch);
670 protected:
671 nsRefPtr<gfxFontEntry> mFontEntry;
673 PRPackedBool mIsValid;
674 nsExpirationState mExpirationState;
675 gfxFontStyle mStyle;
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)
689 public:
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.
693 enum {
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
734 * doesn't.
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
753 * other effects.
755 TEXT_OPTIMIZE_SPEED = 0x0800
759 * This record contains all the parameters needed to initialize a textrun.
761 struct Parameters {
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)
765 void *mUserData;
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
798 * be on the test!
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
815 * won't.
817 class THEBES_API gfxTextRun {
818 public:
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
851 * linebreaks.
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 {
875 public:
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
904 * are detected.
905 * @param aAdvanceWidth if non-null, the advance width of the substring
906 * is returned here.
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
933 * is returned here.
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
986 * properly.
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
1041 * the effect of
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) {}
1073 // Utility getters
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");
1083 mFlags |= aFlags;
1085 void ClearFlagBits(PRUint32 aFlags) {
1086 NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS),
1087 "Only user flags should be mutable");
1088 mFlags &= ~aFlags;
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 {
1137 public:
1138 CompressedGlyph() { mValue = 0; }
1140 enum {
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
1145 // in appunits).
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,
1152 ADVANCE_SHIFT = 16,
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
1158 // flag bits:
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);
1211 mValue ^= toggle;
1212 return toggle;
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;
1220 return *this;
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);
1228 return *this;
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);
1236 return *this;
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 |
1244 FLAG_LOW_SURROGATE;
1245 return *this;
1247 PRUint32 GetGlyphCount() const {
1248 NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
1249 return (mValue & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT;
1252 private:
1253 PRUint32 mValue;
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 */
1263 PRUint32 mGlyphID;
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 */
1268 PRInt32 mAdvance;
1269 float mXOffset, mYOffset;
1272 // The text is divided into GlyphRuns as necessary
1273 struct GlyphRun {
1274 nsRefPtr<gfxFont> mFont; // never null
1275 PRUint32 mCharacterOffset; // into original UTF16 string
1278 class THEBES_API GlyphRunIterator {
1279 public:
1280 GlyphRunIterator(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aLength)
1281 : mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) {
1282 mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart);
1284 PRBool NextRun();
1285 GlyphRun *GetGlyphRun() { return mGlyphRun; }
1286 PRUint32 GetStringStart() { return mStringStart; }
1287 PRUint32 GetStringEnd() { return mStringEnd; }
1288 private:
1289 gfxTextRun *mTextRun;
1290 GlyphRun *mGlyphRun;
1291 PRUint32 mStringStart;
1292 PRUint32 mStringEnd;
1293 PRUint32 mNextIndex;
1294 PRUint32 mStartOffset;
1295 PRUint32 mEndOffset;
1298 class GlyphRunOffsetComparator {
1299 public:
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
1334 * TextRun.
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
1365 * errors.
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
1387 // glyphrun.
1388 virtual void CopyGlyphDataFrom(gfxTextRun *aSource, PRUint32 aStart,
1389 PRUint32 aLength, PRUint32 aDest,
1390 PRBool aStealData);
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; }
1413 #ifdef DEBUG
1414 // number of entries referencing this textrun in the gfxTextRunWordCache
1415 PRUint32 mCachedWords;
1417 void Dump(FILE* aOutput);
1418 #endif
1420 // post-process glyph advances to deal with synthetic bolding
1421 void AdjustAdvancesForSyntheticBold(PRUint32 aStart, PRUint32 aLength);
1423 protected:
1424 // Allocates extra space for the CompressedGlyph array and the text
1425 // (if needed)
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);
1437 private:
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,
1473 Metrics *aMetrics);
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,
1481 Metrics *aMetrics);
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.
1503 union {
1504 const PRUint8 *mSingle;
1505 const PRUnichar *mDouble;
1506 } mText;
1507 void *mUserData;
1508 gfxFontGroup *mFontGroup; // addrefed
1509 gfxSkipChars mSkipChars;
1510 nsExpirationState mExpirationState;
1511 PRUint32 mAppUnitsPerDevUnit;
1512 PRUint32 mFlags;
1513 PRUint32 mCharacterCount;
1514 PRUint32 mHashCode;
1515 PRUint64 mUserFontSetGeneration; // user font set generation when text run created
1518 class THEBES_API gfxFontGroup : public gfxTextRunFactory {
1519 protected:
1520 gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet = nsnull);
1522 public:
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,
1588 void *closure);
1589 /*static*/ PRBool ForEachFont(const nsAString& aFamilies,
1590 const nsACString& aLangGroup,
1591 FontCreationCallback fc,
1592 void *closure);
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() { }
1629 protected:
1630 nsString mFamilies;
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,
1660 void *closure);
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))
1669 return font;
1671 return nsnull;
1675 #endif