Bug 370588. Make gfxTextRun be a single shared class for all platforms. Move all platform-specific code to gfxFontGroup and gfxFont implementations. Actually implement textruns properly on Mac and Windows. r=vlad,pavlov

This commit is contained in:
roc+%cs.cmu.edu 2007-03-04 21:05:10 +00:00
parent 1723cb6673
commit 807c3d9076
12 changed files with 2407 additions and 2617 deletions

View File

@ -424,11 +424,9 @@ nsThebesFontMetrics::DrawString(const char *aString, PRUint32 aLength,
if (!textRun.get())
return NS_ERROR_FAILURE;
gfxPoint pt(aX, aY);
#ifdef MOZ_X11
if (mTextRunRTL) {
pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
}
#endif
textRun->Draw(aContext->Thebes(), pt, 0, aLength,
nsnull, &provider, nsnull);
return NS_OK;
@ -450,11 +448,9 @@ nsThebesFontMetrics::DrawString(const PRUnichar* aString, PRUint32 aLength,
if (!textRun.get())
return NS_ERROR_FAILURE;
gfxPoint pt(aX, aY);
#ifdef MOZ_X11
if (mTextRunRTL) {
pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
}
#endif
textRun->Draw(aContext->Thebes(), pt, 0, aLength,
nsnull, &provider, nsnull);
return NS_OK;

View File

@ -148,11 +148,7 @@ public:
virtual gfxFontGroup* GetThebesFontGroup() { return mFontGroup; }
PRBool GetRightToLeftTextRunMode() {
#ifdef MOZ_X11
return mTextRunRTL;
#else
return mIsRightToLeft;
#endif
}
protected:

View File

@ -247,11 +247,8 @@ nsThebesRenderingContext::GetHints(PRUint32& aResult)
aResult |= (NS_RENDERING_HINT_BIDI_REORDERING |
NS_RENDERING_HINT_ARABIC_SHAPING |
NS_RENDERING_HINT_REORDER_SPACED_TEXT);
#ifdef MOZ_X11
aResult |= NS_RENDERING_HINT_NEW_TEXT_RUNS;
#endif
NS_RENDERING_HINT_REORDER_SPACED_TEXT |
NS_RENDERING_HINT_NEW_TEXT_RUNS);
return NS_OK;
}

View File

@ -82,6 +82,11 @@ protected:
gfxFloat mAdjustedSize;
void InitMetrics(ATSUFontID aFontID, ATSFontRef aFontRef);
virtual void SetupCairoFont(cairo_t *aCR)
{
cairo_set_scaled_font (aCR, CairoScaledFont());
}
};
class THEBES_API gfxAtsuiFontGroup : public gfxFontGroup {
@ -98,6 +103,11 @@ public:
Parameters* aParams);
virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams);
// Here, aString is actually aLength + 1 chars long; the first char
// is an LRO or RLO bidi control character to force setting the direction
// for all characters
gfxTextRun *MakeTextRunInternal(const PRUnichar *aString, PRUint32 aLength,
Parameters *aParams);
ATSUFontFallbacks *GetATSUFontFallbacksPtr() { return &mFallbacks; }
@ -112,32 +122,8 @@ protected:
const nsACString& aGenericName,
void *closure);
void InitTextRun(gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength);
ATSUFontFallbacks mFallbacks;
};
class THEBES_API gfxAtsuiTextRun {
public:
gfxAtsuiTextRun(const nsAString& aString, gfxAtsuiFontGroup *aFontGroup);
~gfxAtsuiTextRun();
virtual void Draw(gfxContext *aContext, gfxPoint pt);
virtual gfxFloat Measure(gfxContext *aContext);
virtual void SetSpacing(const nsTArray<gfxFloat>& spacingArray);
virtual const nsTArray<gfxFloat> *const GetSpacing() const;
void SetRightToLeft(PRBool aIsRTL) { mIsRTL = aIsRTL; }
PRBool IsRightToLeft() { return mIsRTL; }
private:
nsString mString;
gfxAtsuiFontGroup *mGroup;
ATSUTextLayout mATSULayout;
nsTArray<ATSUStyle> mStylesToDispose;
PRPackedBool mIsRTL;
};
#endif /* GFX_ATSUIFONTS_H */

View File

@ -50,6 +50,8 @@
class gfxContext;
class gfxTextRun;
class nsIAtom;
class gfxFontGroup;
typedef struct _cairo cairo_t;
#define FONT_STYLE_NORMAL 0
#define FONT_STYLE_ITALIC 1
@ -66,8 +68,6 @@ class nsIAtom;
#define FONT_WEIGHT_NORMAL 400
#define FONT_WEIGHT_BOLD 700
class gfxFontGroup;
struct THEBES_API gfxFontStyle {
gfxFontStyle(PRUint8 aStyle, PRUint8 aVariant,
PRUint16 aWeight, PRUint8 aDecoration, gfxFloat aSize,
@ -144,6 +144,7 @@ public:
virtual nsString GetUniqueName() { return GetName(); }
// Font metrics
struct Metrics {
gfxFloat xHeight;
gfxFloat superscriptOffset;
@ -170,10 +171,121 @@ public:
};
virtual const gfxFont::Metrics& GetMetrics() = 0;
/**
* We let layout specify spacing on either side of any
* character. We need to specify both before and after
* spacing so that substring measurement can do the right things.
*/
struct Spacing {
gfxFloat mBefore;
gfxFloat mAfter;
};
/**
* Metrics for a particular string
*/
struct RunMetrics {
RunMetrics() {
mAdvanceWidth = mAscent = mDescent = 0.0;
mBoundingBox = gfxRect(0,0,0,0);
mClusterCount = 0;
}
void CombineWith(const RunMetrics& aOtherOnRight) {
mAscent = PR_MAX(mAscent, aOtherOnRight.mAscent);
mDescent = PR_MAX(mDescent, aOtherOnRight.mDescent);
mBoundingBox =
mBoundingBox.Union(aOtherOnRight.mBoundingBox + gfxPoint(mAdvanceWidth, 0));
mAdvanceWidth += aOtherOnRight.mAdvanceWidth;
mClusterCount += aOtherOnRight.mClusterCount;
}
// can be negative (partly due to negative spacing).
// Advance widths should be additive: the advance width of the
// (offset1, length1) plus the advance width of (offset1 + length1,
// length2) should be the advance width of (offset1, length1 + length2)
gfxFloat mAdvanceWidth;
// For zero-width substrings, these must be zero!
gfxFloat mAscent; // always non-negative
gfxFloat mDescent; // always non-negative
// Bounding box that is guaranteed to include everything drawn.
// If aTightBoundingBox was set to true when these metrics were
// generated, this will tightly wrap the glyphs, otherwise it is
// "loose" and may be larger than the true bounding box.
// Coordinates are relative to the baseline left origin, so typically
// mBoundingBox.y == -mAscent
gfxRect mBoundingBox;
// Count of the number of grapheme clusters. Layout needs
// this to compute tab offsets. For SpecialStrings, this is always 1.
PRInt32 mClusterCount;
};
/**
* Draw a series of glyphs to aContext. The direction of aTextRun must
* be honoured.
* @param aStart the first character to draw
* @param aEnd draw characters up to here
* @param aBaselineOrigin the baseline origin; the left end of the baseline
* for LTR textruns, the right end of the baseline for RTL textruns. On return,
* this should be updated to the other end of the baseline. In application units.
* @param aSpacing spacing to insert before and after characters (for RTL
* glyphs, before-spacing is inserted to the right of characters). There
* are aEnd - aStart elements in this array, unless it's null to indicate
* that there is no spacing.
* @param aDrawToPath when true, add the glyph outlines to the current path
* instead of drawing the glyphs
*
* Callers guarantee:
* -- aStart and aEnd are aligned to cluster and ligature boundaries
* -- all glyphs use this font
*
* The default implementation builds a cairo glyph array and
* calls cairo_show_glyphs or cairo_glyph_path.
*/
virtual void Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
gfxContext *aContext, PRBool aDrawToPath, gfxPoint *aBaselineOrigin,
Spacing *aSpacing);
/**
* Measure a run of characters. See gfxTextRun::Metrics.
* @param aTight if false, then return the union of the glyph extents
* with the font-box for the characters (the rectangle with x=0,width=
* the advance width for the character run,y=-(font ascent), and height=
* font ascent + font descent). Otherwise, we must return as tight as possible
* an approximation to the area actually painted by glyphs.
* @param aSpacing spacing to insert before and after glyphs. The bounding box
* need not include the spacing itself, but the spacing affects the glyph
* positions. null if there is no spacing.
*
* Callers guarantee:
* -- aStart and aEnd are aligned to cluster and ligature boundaries
* -- all glyphs use this font
*
* The default implementation just uses font metrics and aTextRun's
* advances, and assumes no characters fall outside the font box. In
* general this is insufficient, because that assumption is not always true.
*/
virtual RunMetrics Measure(gfxTextRun *aTextRun,
PRUint32 aStart, PRUint32 aEnd,
PRBool aTightBoundingBox,
Spacing *aSpacing);
/**
* Line breaks have been changed at the beginning and/or end of a substring
* of the text. Reshaping may be required; glyph updating is permitted.
* @return true if anything was changed, false otherwise
*/
PRBool NotifyLineBreaksChanged(gfxTextRun *aTextRun,
PRUint32 aStart, PRUint32 aLength)
{ return PR_FALSE; }
protected:
// The family name of the font
nsString mName;
// This is called by the default Draw() implementation above.
virtual void SetupCairoFont(cairo_t *aCR) = 0;
const gfxFontStyle *mStyle;
};
@ -225,7 +337,15 @@ public:
* When set, the text may have UTF16 surrogate pairs, otherwise it
* doesn't.
*/
TEXT_HAS_SURROGATES = 0x0100
TEXT_HAS_SURROGATES = 0x0100,
/**
* When set, the RunMetrics::mBoundingBox field will be initialized
* properly based on glyph extents, in particular, glyph extents that
* overflow the standard font-box (the box defined by the ascent, descent
* and advance width of the glyph). When not set, it may just be the
* standard font-box even if glyphs overflow.
*/
TEXT_NEED_BOUNDING_BOX = 0x0200
};
/**
@ -268,92 +388,11 @@ public:
Parameters *aParams) = 0;
};
class THEBES_API gfxFontGroup : public gfxTextRunFactory {
public:
gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle);
virtual ~gfxFontGroup() {
mFonts.Clear();
}
gfxFont *GetFontAt(PRInt32 i) {
return NS_STATIC_CAST(gfxFont*, mFonts[i]);
}
PRUint32 FontListLength() const {
return mFonts.Length();
}
PRBool Equals(const gfxFontGroup& other) const {
return mFamilies.Equals(other.mFamilies) &&
mStyle.Equals(other.mStyle);
}
const gfxFontStyle *GetStyle() const { return &mStyle; }
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle) = 0;
// These need to be repeated from gfxTextRunFactory because of C++'s
// hiding rules!
virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
Parameters* aParams) = 0;
virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams) = 0;
/* helper function for splitting font families on commas and
* calling a function for each family to fill the mFonts array
*/
typedef PRBool (*FontCreationCallback) (const nsAString& aName,
const nsACString& aGenericName,
void *closure);
static PRBool ForEachFont(const nsAString& aFamilies,
const nsACString& aLangGroup,
FontCreationCallback fc,
void *closure);
PRBool ForEachFont(FontCreationCallback fc, void *closure);
/* this will call back fc with the a generic font based on the style's langgroup */
void FindGenericFontFromStyle(FontCreationCallback fc, void *closure);
const nsString& GetFamilies() { return mFamilies; }
/**
* Special strings are strings that we might need to draw/measure but aren't
* actually substrings of DOM text. They never have extra spacing and
* aren't involved in breaking.
*/
enum SpecialString {
STRING_ELLIPSIS,
STRING_HYPHEN,
STRING_SPACE,
STRING_MAX = STRING_SPACE
};
// Get the textrun for the given special string. Ownership remains
// with this gfxFontGroup. Copy relevant parameters from the template textrun.
// SpecialString textruns do not use spacing and it's fine to pass null
// as the PropertyProvider* in their methods.
// This is stubbed out until we have full textrun support on all platforms.
virtual gfxTextRun *GetSpecialStringTextRun(SpecialString aString,
gfxTextRun *aTemplate)
{ return nsnull; }
protected:
nsString mFamilies;
gfxFontStyle mStyle;
nsTArray< nsRefPtr<gfxFont> > mFonts;
static PRBool ForEachFontInternal(const nsAString& aFamilies,
const nsACString& aLangGroup,
PRBool aResolveGeneric,
FontCreationCallback fc,
void *closure);
static PRBool FontResolverProc(const nsAString& aName, void *aClosure);
};
/**
* gfxTextRun is an abstraction for drawing and measuring substrings of a run
* of text.
* of text. It stores runs of positioned glyph data, each run having a single
* gfxFont. The glyphs are associated with a string of source text, and the
* gfxTextRun APIs take parameters that are offsets into that source text.
*
* \r and \n characters must be ignored completely. Substring operations
* will not normally include these characters.
@ -379,25 +418,31 @@ protected:
*
* It is important that zero-length substrings are handled correctly. This will
* be on the test!
*
* This class should not be subclassed.
*/
class THEBES_API gfxTextRun {
public:
virtual ~gfxTextRun() {}
~gfxTextRun() {}
enum {
// character is the start of a grapheme cluster
CLUSTER_START = 0x01,
// character is a cluster start but is part of a ligature started
// in a previous cluster.
CONTINUES_LIGATURE = 0x02,
// line break opportunity before this character
LINE_BREAK_BEFORE = 0x04
};
virtual void GetCharFlags(PRUint32 aStart, PRUint32 aLength,
PRUint8 *aFlags) = 0;
virtual PRUint8 GetCharFlags(PRUint32 aStart) = 0;
typedef gfxFont::RunMetrics Metrics;
virtual PRUint32 GetLength() = 0;
// Public textrun API for general use
PRBool IsClusterStart(PRUint32 aPos) {
NS_ASSERTION(0 <= aPos && aPos < mCharacterCount, "aPos out of range");
return mCharacterGlyphs[aPos].IsClusterStart();
}
PRBool IsLigatureContinuation(PRUint32 aPos) {
NS_ASSERTION(0 <= aPos && aPos < mCharacterCount, "aPos out of range");
return mCharacterGlyphs[aPos].IsLigatureContinuation();
}
PRBool CanBreakLineBefore(PRUint32 aPos) {
NS_ASSERTION(0 <= aPos && aPos < mCharacterCount, "aPos out of range");
return mCharacterGlyphs[aPos].CanBreakBefore();
}
PRUint32 GetLength() { return mCharacterCount; }
// All PRUint32 aStart, PRUint32 aLength ranges below are restricted to
// grapheme cluster boundaries! All offsets are in terms of the string
@ -409,12 +454,10 @@ public:
* This can be called to force gfxTextRun to remember the text used
* to create it and *never* call TextProvider::GetText again.
*
* The default implementation is to not remember anything. If you want
* to be able to recover text from the gfxTextRun user you need to override
* these.
* Right now we don't implement these.
*/
virtual void RememberText(const PRUnichar *aText, PRUint32 aLength) {}
virtual void RememberText(const PRUint8 *aText, PRUint32 aLength) {}
void RememberText(const PRUnichar *aText, PRUint32 aLength) {}
void RememberText(const PRUint8 *aText, PRUint32 aLength) {}
/**
* Set the potential linebreaks for a substring of the textrun. These are
@ -424,8 +467,8 @@ public:
* @return true if this changed the linebreaks, false if the new line
* breaks are the same as the old
*/
virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRPackedBool *aBreakBefore) = 0;
PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRPackedBool *aBreakBefore);
/**
* This is provided so a textrun can (re)obtain the original text used to
@ -465,15 +508,8 @@ public:
// be constant for a given textrun.
virtual gfxFloat GetHyphenWidth() = 0;
/**
* We let the property provider specify spacing on either side of any
* character. We need to specify both before and after
* spacing so that substring measurement can do the right things.
*/
struct Spacing {
gfxFloat mBefore;
gfxFloat mAfter;
};
typedef gfxFont::Spacing Spacing;
/**
* Get the spacing around the indicated characters. Spacing must be zero
* inside clusters. In other words, if character i is not
@ -509,11 +545,11 @@ public:
* Glyphs should be drawn in logical content order, which can be significant
* if they overlap (perhaps due to negative spacing).
*/
virtual void Draw(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
const gfxRect *aDirtyRect,
PropertyProvider *aProvider,
gfxFloat *aAdvanceWidth) = 0;
void Draw(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
const gfxRect *aDirtyRect,
PropertyProvider *aProvider,
gfxFloat *aAdvanceWidth);
/**
* Renders a substring to a path. Uses only GetSpacing from aBreakProvider.
@ -529,66 +565,26 @@ public:
* UNLIKE Draw above, this cannot be used to render substrings that start or
* end inside a ligature.
*/
virtual void DrawToPath(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
PropertyProvider *aBreakProvider,
gfxFloat *aAdvanceWidth) = 0;
// Metrics needed by reflow
struct Metrics {
Metrics() {
mAdvanceWidth = mAscent = mDescent = 0.0;
mBoundingBox = gfxRect(0,0,0,0);
mClusterCount = 0;
}
void CombineWith(const Metrics& aOtherOnRight) {
mAscent = PR_MAX(mAscent, aOtherOnRight.mAscent);
mDescent = PR_MAX(mDescent, aOtherOnRight.mDescent);
mBoundingBox =
mBoundingBox.Union(aOtherOnRight.mBoundingBox + gfxPoint(mAdvanceWidth, 0));
mAdvanceWidth += aOtherOnRight.mAdvanceWidth;
mClusterCount += aOtherOnRight.mClusterCount;
}
// can be negative (partly due to negative spacing).
// Advance widths should be additive: the advance width of the
// (offset1, length1) plus the advance width of (offset1 + length1,
// length2) should be the advance width of (offset1, length1 + length2)
gfxFloat mAdvanceWidth;
// For zero-width substrings, these must be zero!
gfxFloat mAscent; // always non-negative
gfxFloat mDescent; // always non-negative
// Bounding box that is guaranteed to include everything drawn.
// If aTightBoundingBox was set to true when these metrics were
// generated, this will tightly wrap the glyphs, otherwise it is
// "loose" and may be larger than the true bounding box.
// Coordinates are relative to the baseline left origin, so typically
// mBoundingBox.y == -mAscent
gfxRect mBoundingBox;
// Count of the number of grapheme clusters. Layout needs
// this to compute tab offsets. For SpecialStrings, this is always 1.
PRInt32 mClusterCount;
};
void DrawToPath(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
PropertyProvider *aBreakProvider,
gfxFloat *aAdvanceWidth);
/**
* Computes the ReflowMetrics for a substring.
* Uses GetSpacing from aBreakProvider.
* @param aTightBoundingBox if true, we make the bounding box tight
*/
virtual Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
PRBool aTightBoundingBox,
PropertyProvider *aProvider) = 0;
Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
PRBool aTightBoundingBox,
PropertyProvider *aProvider);
/**
* Computes just the advance width for a substring.
* Uses GetSpacing from aBreakProvider.
*/
virtual gfxFloat GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PropertyProvider *aProvider) = 0;
gfxFloat GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PropertyProvider *aProvider);
/**
* Clear all stored line breaks for the given range (both before and after),
@ -613,10 +609,10 @@ public:
* @param aAdvanceWidthDelta if non-null, returns the change in advance
* width of the given range.
*/
virtual void SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
TextProvider *aProvider,
gfxFloat *aAdvanceWidthDelta) = 0;
void SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
TextProvider *aProvider,
gfxFloat *aAdvanceWidthDelta);
/**
* Finds the longest substring that will fit into the given width.
@ -661,20 +657,20 @@ public:
* Note that negative advance widths are possible especially if negative
* spacing is provided.
*/
virtual PRUint32 BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
PRBool aLineBreakBefore, gfxFloat aWidth,
PropertyProvider *aProvider,
PRBool aSuppressInitialBreak,
Metrics *aMetrics, PRBool aTightBoundingBox,
PRBool *aUsedHyphenation,
PRUint32 *aLastBreak) = 0;
PRUint32 BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
PRBool aLineBreakBefore, gfxFloat aWidth,
PropertyProvider *aProvider,
PRBool aSuppressInitialBreak,
Metrics *aMetrics, PRBool aTightBoundingBox,
PRBool *aUsedHyphenation,
PRUint32 *aLastBreak);
/**
* Update the reference context.
* XXX this is a hack. New text frame does not call this. Use only
* temporarily for old text frame.
*/
virtual void SetContext(gfxContext *aContext) {}
void SetContext(gfxContext *aContext) {}
// Utility getters
@ -685,22 +681,360 @@ public:
const gfxSkipChars& GetSkipChars() const { return mSkipChars; }
float GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; }
protected:
gfxTextRun(gfxTextRunFactory::Parameters *aParams)
: mUserData(aParams->mUserData),
mAppUnitsPerDevUnit(aParams->mAppUnitsPerDevUnit),
mFlags(aParams->mFlags)
{
if (aParams->mSkipChars) {
mSkipChars.TakeFrom(aParams->mSkipChars);
// The caller is responsible for initializing our glyphs after construction.
// Initially all glyphs are such that GetCharacterGlyphs()[i].IsMissing() is true.
gfxTextRun(gfxTextRunFactory::Parameters *aParams, PRUint32 aLength);
/**
* This class records the information associated with a character in the
* input string. It's optimized for the case where there is one glyph
* representing that character alone.
*/
class CompressedGlyph {
public:
CompressedGlyph() { mValue = 0; }
enum {
// Indicates that a cluster starts at this character and can be
// rendered using a single glyph with a reasonable advance offset
// and no special glyph offset. A "reasonable" advance offset is
// one that is a) a multiple of a pixel and b) fits in the available
// bits (currently 14). We should revisit this, especially a),
// if we want to support subpixel-aligned text.
FLAG_IS_SIMPLE_GLYPH = 0x80000000U,
// Indicates that a linebreak is allowed before this character
FLAG_CAN_BREAK_BEFORE = 0x40000000U,
ADVANCE_MASK = 0x3FFF0000U,
ADVANCE_SHIFT = 16,
GLYPH_MASK = 0x0000FFFFU,
// Non-simple glyphs have the following tags
TAG_MASK = 0x000000FFU,
// Indicates that this character corresponds to a missing glyph
// and should be skipped (or possibly, render the character
// Unicode value in some special way)
TAG_MISSING = 0x00U,
// Indicates that a cluster starts at this character and is rendered
// using one or more glyphs which cannot be represented here.
// Look up the DetailedGlyph table instead.
TAG_COMPLEX_CLUSTER = 0x01U,
// Indicates that a cluster starts at this character but is rendered
// as part of a ligature starting in a previous cluster.
// NOTE: we divide up the ligature's width by the number of clusters
// to get the width assigned to each cluster.
TAG_LIGATURE_CONTINUATION = 0x21U,
// Values where the upper 28 bits equal 0x80 are reserved for
// non-cluster-start characters (see IsClusterStart below)
// Indicates that a cluster does not start at this character, this is
// a low UTF16 surrogate
TAG_LOW_SURROGATE = 0x80U,
// Indicates that a cluster does not start at this character, this is
// part of a cluster starting with an earlier character (but not
// a low surrogate).
TAG_CLUSTER_CONTINUATION = 0x81U
};
// "Simple glyphs" have a simple glyph ID, simple advance and their
// x and y offsets are zero. Also the glyph extents do not overflow
// the font-box defined by the font ascent, descent and glyph advance width.
// These case is optimized to avoid storing DetailedGlyphs.
// Returns true if the glyph ID aGlyph fits into the compressed representation
static PRBool IsSimpleGlyphID(PRUint32 aGlyph) {
return (aGlyph & GLYPH_MASK) == aGlyph;
}
// Returns true if the advance aAdvance fits into the compressed representation.
// aAdvance is in pixels.
static PRBool IsSimpleAdvancePixels(PRUint32 aAdvance) {
return (aAdvance & (ADVANCE_MASK >> ADVANCE_SHIFT)) == aAdvance;
}
PRBool IsSimpleGlyph() const { return (mValue & FLAG_IS_SIMPLE_GLYPH) != 0; }
PRBool IsComplex(PRUint32 aTag) const { return (mValue & (FLAG_IS_SIMPLE_GLYPH|TAG_MASK)) == aTag; }
PRBool IsMissing() const { return IsComplex(TAG_MISSING); }
PRBool IsComplexCluster() const { return IsComplex(TAG_COMPLEX_CLUSTER); }
PRBool IsLigatureContinuation() const { return IsComplex(TAG_LIGATURE_CONTINUATION); }
PRBool IsClusterContinuation() const { return IsComplex(TAG_CLUSTER_CONTINUATION); }
PRBool IsLowSurrogate() const { return IsComplex(TAG_LOW_SURROGATE); }
PRBool IsClusterStart() const { return (mValue & (FLAG_IS_SIMPLE_GLYPH|0x80U)) != 0x80U; }
PRUint32 GetSimpleAdvance() const { return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT; }
PRUint32 GetSimpleGlyph() const { return mValue & GLYPH_MASK; }
PRUint32 GetComplexTag() const { return mValue & TAG_MASK; }
PRBool CanBreakBefore() const { return (mValue & FLAG_CAN_BREAK_BEFORE) != 0; }
// Returns FLAG_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
PRUint32 SetCanBreakBefore(PRBool aCanBreakBefore) {
PRUint32 breakMask = aCanBreakBefore*FLAG_CAN_BREAK_BEFORE;
PRUint32 toggle = breakMask ^ (mValue & FLAG_CAN_BREAK_BEFORE);
mValue ^= toggle;
return toggle;
}
CompressedGlyph& SetSimpleGlyph(PRUint32 aAdvancePixels, PRUint32 aGlyph) {
NS_ASSERTION(IsSimpleAdvancePixels(aAdvancePixels), "Advance overflow");
NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow");
mValue = (mValue & FLAG_CAN_BREAK_BEFORE) | FLAG_IS_SIMPLE_GLYPH |
(aAdvancePixels << ADVANCE_SHIFT) | aGlyph;
return *this;
}
CompressedGlyph& SetComplex(PRUint32 aTag) {
mValue = (mValue & FLAG_CAN_BREAK_BEFORE) | aTag;
return *this;
}
CompressedGlyph& SetMissing() { return SetComplex(TAG_MISSING); }
CompressedGlyph& SetComplexCluster() { return SetComplex(TAG_COMPLEX_CLUSTER); }
CompressedGlyph& SetLowSurrogate() { return SetComplex(TAG_LOW_SURROGATE); }
CompressedGlyph& SetLigatureContinuation() { return SetComplex(TAG_LIGATURE_CONTINUATION); }
CompressedGlyph& SetClusterContinuation() { return SetComplex(TAG_CLUSTER_CONTINUATION); }
private:
PRUint32 mValue;
};
/**
* When the glyphs for a character don't fit into a CompressedGlyph record
* in SimpleGlyph format, we use an array of DetailedGlyphs instead.
*/
struct DetailedGlyph {
/** This is true for the last DetailedGlyph in the array. This lets
* us track the length of the array. */
PRUint32 mIsLastGlyph:1;
PRUint32 mGlyphID:31;
// The advance, x-offset and y-offset of the glyph, in pixels
float mAdvance, mXOffset, mYOffset;
};
// The text is divided into GlyphRuns as necessary
struct GlyphRun {
nsRefPtr<gfxFont> mFont; // never null
PRUint32 mCharacterOffset; // into original UTF16 string
};
class GlyphRunIterator {
public:
GlyphRunIterator(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aLength)
: mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) {
mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart);
}
PRBool NextRun();
GlyphRun *GetGlyphRun() { return mGlyphRun; }
PRUint32 GetStringStart() { return mStringStart; }
PRUint32 GetStringEnd() { return mStringEnd; }
private:
gfxTextRun *mTextRun;
GlyphRun *mGlyphRun;
PRUint32 mStringStart;
PRUint32 mStringEnd;
PRUint32 mNextIndex;
PRUint32 mStartOffset;
PRUint32 mEndOffset;
};
friend class GlyphRunIterator;
friend class FontSelector;
// API for setting up the textrun glyphs. Should only be called by
// things that construct textruns.
/**
* Record every character that is the second half of a surrogate pair.
* This should be called after creating a Unicode textrun.
*/
void RecordSurrogates(const PRUnichar *aString);
/**
* We've found a run of text that should use a particular font. Call this
* only during initialization when font substitution has been computed.
*/
nsresult AddGlyphRun(gfxFont *aFont, PRUint32 aStartCharIndex);
// Call the following glyph-setters during initialization or during reshaping
// only. It is OK to overwrite existing data for a character.
/**
* Set the glyph for a character. Also allows you to set low surrogates,
* cluster and ligature continuations.
*/
void SetCharacterGlyph(PRUint32 aCharIndex, CompressedGlyph aGlyph) {
NS_ASSERTION(aCharIndex > 0 ||
(aGlyph.IsClusterStart() && !aGlyph.IsLigatureContinuation()),
"First character must be the start of a cluster and can't be a ligature continuation!");
if (mCharacterGlyphs) {
mCharacterGlyphs[aCharIndex] = aGlyph;
}
if (mDetailedGlyphs) {
mDetailedGlyphs[aCharIndex] = nsnull;
}
}
/**
* Set some detailed glyphs for a character. The data is copied from aGlyphs,
* the caller retains ownership.
*/
void SetDetailedGlyphs(PRUint32 aCharIndex, DetailedGlyph *aGlyphs,
PRUint32 aNumGlyphs);
void * mUserData;
// API for access to the raw glyph data, needed by gfxFont::Draw
// and gfxFont::GetBoundingBox
const CompressedGlyph *GetCharacterGlyphs() { return mCharacterGlyphs; }
const DetailedGlyph *GetDetailedGlyphs(PRUint32 aCharIndex) {
NS_ASSERTION(mDetailedGlyphs && mDetailedGlyphs[aCharIndex],
"Requested detailed glyphs when there aren't any, "
"I think I'll go and have a lie down...");
return mDetailedGlyphs[aCharIndex];
}
PRUint32 CountMissingGlyphs();
private:
// **** general helpers ****
// Returns the index of the GlyphRun containing the given offset.
// Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
PRUint32 FindFirstGlyphRunContaining(PRUint32 aOffset);
// Computes the x-advance for a given cluster starting at aClusterOffset. Does
// not include any spacing. Result is in device pixels.
gfxFloat ComputeClusterAdvance(PRUint32 aClusterOffset);
// **** ligature helpers ****
// (Platforms do the actual ligaturization, but we need to do a bunch of stuff
// to handle requests that begin or end inside a ligature)
struct LigatureData {
PRUint32 mStartOffset;
PRUint32 mEndOffset;
PRUint32 mClusterCount;
PRUint32 mPartClusterIndex;
gfxFloat mLigatureWidth; // appunits
gfxFloat mBeforeSpacing; // appunits
gfxFloat mAfterSpacing; // appunits
};
// if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
LigatureData ComputeLigatureData(PRUint32 aPartOffset, PropertyProvider *aProvider);
void GetAdjustedSpacing(PRUint32 aStart, PRUint32 aEnd,
PropertyProvider *aProvider, PropertyProvider::Spacing *aSpacing);
PRBool GetAdjustedSpacingArray(PRUint32 aStart, PRUint32 aEnd,
PropertyProvider *aProvider,
nsTArray<PropertyProvider::Spacing> *aSpacing);
void DrawPartialLigature(gfxFont *aFont, gfxContext *aCtx, PRUint32 aOffset,
const gfxRect *aDirtyRect, gfxPoint *aPt,
PropertyProvider *aProvider);
// result in appunits
void ShrinkToLigatureBoundaries(PRUint32 *aStart, PRUint32 *aEnd);
gfxFloat GetPartialLigatureWidth(PRUint32 aStart, PRUint32 aEnd, PropertyProvider *aProvider);
void AccumulatePartialLigatureMetrics(gfxFont *aFont,
PRUint32 aOffset, PRBool aTight,
PropertyProvider *aProvider,
Metrics *aMetrics);
// **** measurement helper ****
void AccumulateMetricsForRun(gfxFont *aFont, PRUint32 aStart,
PRUint32 aEnd, PRBool aTight,
PropertyProvider *aProvider,
Metrics *aMetrics);
// **** drawing helper ****
void DrawGlyphs(gfxFont *aFont, gfxContext *aContext, PRBool aDrawToPath,
gfxPoint *aPt, PRUint32 aStart, PRUint32 aEnd,
PropertyProvider *aProvider);
// All our glyph data is in logical order, not visual
nsAutoArrayPtr<CompressedGlyph> mCharacterGlyphs;
nsAutoArrayPtr<nsAutoArrayPtr<DetailedGlyph> > mDetailedGlyphs; // only non-null if needed
// XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
// for smaller size especially in the super-common one-glyphrun case
nsAutoTArray<GlyphRun,1> mGlyphRuns;
void *mUserData;
gfxSkipChars mSkipChars;
// This is actually an integer, but we keep it in float form to reduce
// the conversions required
float mAppUnitsPerDevUnit;
PRUint32 mFlags;
PRUint32 mCharacterCount;
};
class THEBES_API gfxFontGroup : public gfxTextRunFactory {
public:
gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle);
virtual ~gfxFontGroup() {
mFonts.Clear();
}
gfxFont *GetFontAt(PRInt32 i) {
return NS_STATIC_CAST(gfxFont*, mFonts[i]);
}
PRUint32 FontListLength() const {
return mFonts.Length();
}
PRBool Equals(const gfxFontGroup& other) const {
return mFamilies.Equals(other.mFamilies) &&
mStyle.Equals(other.mStyle);
}
const gfxFontStyle *GetStyle() const { return &mStyle; }
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle) = 0;
// These need to be repeated from gfxTextRunFactory because of C++'s
// hiding rules!
virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
Parameters* aParams) = 0;
// This function should set TEXT_IS_8BIT in aParams->mFlags.
virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams) = 0;
/* helper function for splitting font families on commas and
* calling a function for each family to fill the mFonts array
*/
typedef PRBool (*FontCreationCallback) (const nsAString& aName,
const nsACString& aGenericName,
void *closure);
static PRBool ForEachFont(const nsAString& aFamilies,
const nsACString& aLangGroup,
FontCreationCallback fc,
void *closure);
PRBool ForEachFont(FontCreationCallback fc, void *closure);
/* this will call back fc with the a generic font based on the style's langgroup */
void FindGenericFontFromStyle(FontCreationCallback fc, void *closure);
const nsString& GetFamilies() { return mFamilies; }
/**
* Special strings are strings that we might need to draw/measure but aren't
* actually substrings of DOM text. They never have extra spacing and
* aren't involved in breaking.
*/
enum SpecialString {
STRING_ELLIPSIS,
STRING_HYPHEN,
STRING_SPACE,
STRING_MAX = STRING_SPACE
};
// Get the textrun for the given special string. Ownership remains
// with this gfxFontGroup. Copy relevant parameters from the template textrun.
// SpecialString textruns do not use spacing and it's fine to pass null
// as the PropertyProvider* in their methods.
// This is stubbed out until we have full textrun support on all platforms.
gfxTextRun *GetSpecialStringTextRun(SpecialString aString,
gfxTextRun *aTemplate);
protected:
nsString mFamilies;
gfxFontStyle mStyle;
nsTArray< nsRefPtr<gfxFont> > mFonts;
nsAutoPtr<gfxTextRun> mSpecialStrings[STRING_MAX + 1];
static PRBool ForEachFontInternal(const nsAString& aFamilies,
const nsACString& aLangGroup,
PRBool aResolveGeneric,
FontCreationCallback fc,
void *closure);
static PRBool FontResolverProc(const nsAString& aName, void *aClosure);
};
#endif

View File

@ -77,57 +77,10 @@ public:
XftFont *GetXftFont () { RealizeXftFont (); return mXftFont; }
gfxFloat GetAdjustedSize() { RealizeFont(); return mAdjustedSize; }
// These APIs need to be moved up to gfxFont with gfxPangoTextRun switched
// to gfxTextRun
/**
* Draw a series of glyphs to aContext. The direction of aTextRun must
* be honoured.
* @param aStart the first character to draw
* @param aEnd draw characters up to here
* @param aBaselineOrigin the baseline origin; the left end of the baseline
* for LTR textruns, the right end of the baseline for RTL textruns. On return,
* this should be updated to the other end of the baseline. In application units.
* @param aSpacing spacing to insert before and after characters (for RTL
* glyphs, before-spacing is inserted to the right of characters). There
* are aEnd - aStart elements in this array, unless it's null to indicate
* that there is no spacing.
* @param aDrawToPath when true, add the glyph outlines to the current path
* instead of drawing the glyphs
*
* Callers guarantee:
* -- aStart and aEnd are aligned to cluster and ligature boundaries
* -- all glyphs use this font
*/
void Draw(gfxPangoTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
gfxContext *aContext, PRBool aDrawToPath, gfxPoint *aBaselineOrigin,
gfxTextRun::PropertyProvider::Spacing *aSpacing);
/**
* Measure a run of characters. See gfxTextRun::Metrics.
* @param aTight if false, then return the union of the glyph extents
* with the font-box for the characters (the rectangle with x=0,width=
* the advance width for the character run,y=-(font ascent), and height=
* font ascent + font descent). Otherwise, we must return as tight as possible
* an approximation to the area actually painted by glyphs.
* @param aSpacing spacing to insert before and after glyphs. The bounding box
* need not include the spacing itself, but the spacing affects the glyph
* positions. null if there is no spacing.
*
* Callers guarantee:
* -- aStart and aEnd are aligned to cluster and ligature boundaries
* -- all glyphs use this font
*/
gfxTextRun::Metrics Measure(gfxPangoTextRun *aTextRun,
PRUint32 aStart, PRUint32 aEnd,
PRBool aTightBoundingBox,
gfxTextRun::PropertyProvider::Spacing *aSpacing);
/**
* Line breaks have been changed at the beginning and/or end of a substring
* of the text. Reshaping may be required; glyph updating is permitted.
* @return true if anything was changed, false otherwise
*/
PRBool NotifyLineBreaksChanged(gfxPangoTextRun *aTextRun,
PRUint32 aStart, PRUint32 aLength)
{ return PR_FALSE; }
virtual gfxTextRun::Metrics Measure(gfxTextRun *aTextRun,
PRUint32 aStart, PRUint32 aEnd,
PRBool aTightBoundingBox,
Spacing *aSpacing);
protected:
PangoFontDescription *mPangoFontDesc;
@ -143,7 +96,8 @@ protected:
void RealizeFont(PRBool force = PR_FALSE);
void RealizeXftFont(PRBool force = PR_FALSE);
void GetSize(const char *aString, PRUint32 aLength, gfxSize& inkSize, gfxSize& logSize);
void SetupCairoFont(cairo_t *aCR);
virtual void SetupCairoFont(cairo_t *aCR);
};
class FontSelector;
@ -178,39 +132,33 @@ public:
mFontCache.Put(aName, aFont);
}
virtual gfxTextRun *GetSpecialStringTextRun(SpecialString aString,
gfxTextRun *aTemplate);
protected:
friend class FontSelector;
// ****** Textrun glyph conversion helpers ******
// If aUTF16Text is null, then the string contains no characters >= 0x100
void InitTextRun(gfxPangoTextRun *aTextRun, const gchar *aUTF8Text,
void InitTextRun(gfxTextRun *aTextRun, const gchar *aUTF8Text,
PRUint32 aUTF8Length, PRUint32 aUTF8HeaderLength,
const PRUnichar *aUTF16Text, PRUint32 aUTF16Length);
// Returns NS_ERROR_FAILURE if there's a missing glyph
nsresult SetGlyphs(gfxPangoTextRun *aTextRun, const gchar *aUTF8,
nsresult SetGlyphs(gfxTextRun *aTextRun, const gchar *aUTF8,
PRUint32 aUTF8Length,
PRUint32 *aUTF16Offset, PangoGlyphString *aGlyphs,
PangoGlyphUnit aOverrideSpaceWidth,
PRBool aAbortOnMissingGlyph);
// If aUTF16Text is null, then the string contains no characters >= 0x100.
// Returns NS_ERROR_FAILURE if we require the itemizing path
nsresult CreateGlyphRunsFast(gfxPangoTextRun *aTextRun,
nsresult CreateGlyphRunsFast(gfxTextRun *aTextRun,
const gchar *aUTF8, PRUint32 aUTF8Length,
const PRUnichar *aUTF16Text, PRUint32 aUTF16Length);
void CreateGlyphRunsItemizing(gfxPangoTextRun *aTextRun,
void CreateGlyphRunsItemizing(gfxTextRun *aTextRun,
const gchar *aUTF8, PRUint32 aUTF8Length,
PRUint32 aUTF8HeaderLength);
#if defined(ENABLE_XFT_FAST_PATH_8BIT) || defined(ENABLE_XFT_FAST_PATH_ALWAYS)
void CreateGlyphRunsXft(gfxPangoTextRun *aTextRun,
void CreateGlyphRunsXft(gfxTextRun *aTextRun,
const gchar *aUTF8, PRUint32 aUTF8Length);
#endif
void SetupClusterBoundaries(gfxPangoTextRun *aTextRun,
const gchar *aUTF8, PRUint32 aUTF8Length,
PRUint32 aUTF16Offset, PangoAnalysis *aAnalysis);
static PRBool FontCallback (const nsAString& fontName,
const nsACString& genericName,
@ -219,294 +167,6 @@ protected:
private:
nsDataHashtable<nsStringHashKey, nsRefPtr<gfxPangoFont> > mFontCache;
nsTArray<gfxFontStyle> mAdditionalStyles;
nsAutoPtr<gfxTextRun> mSpecialStrings[STRING_MAX + 1];
};
/**
* This is not really Pango-specific anymore. We'll merge this into gfxTextRun
* soon. At that point uses of gfxPangoFontGroup, gfxPangoFont and gfxPangoTextRun
* will be converted to use the cross-platform superclasses.
*/
class THEBES_API gfxPangoTextRun : public gfxTextRun {
public:
gfxPangoTextRun(gfxTextRunFactory::Parameters *aParams, PRUint32 aLength);
// The caller is responsible for initializing our glyphs. Initially
// all glyphs are such that GetCharacterGlyphs()[i].IsMissing() is true.
// gfxTextRun public API
virtual void GetCharFlags(PRUint32 aStart, PRUint32 aLength,
PRUint8 *aFlags);
virtual PRUint8 GetCharFlags(PRUint32 aOffset);
virtual PRUint32 GetLength();
virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRPackedBool *aBreakBefore);
virtual void Draw(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
const gfxRect *aDirtyRect,
PropertyProvider *aBreakProvider,
gfxFloat *aAdvanceWidth);
virtual void DrawToPath(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
PropertyProvider *aBreakProvider,
gfxFloat *aAdvanceWidth);
virtual Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
PRBool aTightBoundingBox,
PropertyProvider *aBreakProvider);
virtual void SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
TextProvider *aProvider,
gfxFloat *aAdvanceWidthDelta);
virtual gfxFloat GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PropertyProvider *aBreakProvider);
virtual PRUint32 BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
PRBool aLineBreakBefore, gfxFloat aWidth,
PropertyProvider *aBreakProvider,
PRBool aSuppressInitialBreak,
Metrics *aMetrics, PRBool aTightBoundingBox,
PRBool *aUsedHyphenation,
PRUint32 *aLastBreak);
/**
* This class records the information associated with a character in the
* input string. It's optimized for the case where there is one glyph
* representing that character alone.
*/
class CompressedGlyph {
public:
CompressedGlyph() { mValue = 0; }
enum {
// Indicates that a cluster starts at this character and can be
// rendered using a single glyph with a reasonable advance offset
// and no special glyph offset. A "reasonable" advance offset is
// one that is a) a multiple of a pixel and b) fits in the available
// bits (currently 14). We should revisit this, especially a),
// if we want to support subpixel-aligned text.
FLAG_IS_SIMPLE_GLYPH = 0x80000000U,
// Indicates that a linebreak is allowed before this character
FLAG_CAN_BREAK_BEFORE = 0x40000000U,
ADVANCE_MASK = 0x3FFF0000U,
ADVANCE_SHIFT = 16,
GLYPH_MASK = 0x0000FFFFU,
// Non-simple glyphs have the following tags
TAG_MASK = 0x000000FFU,
// Indicates that this character corresponds to a missing glyph
// and should be skipped (or possibly, render the character
// Unicode value in some special way)
TAG_MISSING = 0x00U,
// Indicates that a cluster starts at this character and is rendered
// using one or more glyphs which cannot be represented here.
// Look up the DetailedGlyph table instead.
TAG_COMPLEX_CLUSTER = 0x01U,
// Indicates that a cluster starts at this character but is rendered
// as part of a ligature starting in a previous cluster.
// NOTE: we divide up the ligature's width by the number of clusters
// to get the width assigned to each cluster.
TAG_LIGATURE_CONTINUATION = 0x21U,
// Values where the upper 28 bits equal 0x80 are reserved for
// non-cluster-start characters (see IsClusterStart below)
// Indicates that a cluster does not start at this character, this is
// a low UTF16 surrogate
TAG_LOW_SURROGATE = 0x80U,
// Indicates that a cluster does not start at this character, this is
// part of a cluster starting with an earlier character (but not
// a low surrogate).
TAG_CLUSTER_CONTINUATION = 0x81U
};
// "Simple glyphs" have a simple glyph ID, simple advance and their
// x and y offsets are zero. These cases are optimized to avoid storing
// DetailedGlyphs.
// Returns true if the glyph ID aGlyph fits into the compressed representation
static PRBool IsSimpleGlyphID(PRUint32 aGlyph) {
return (aGlyph & GLYPH_MASK) == aGlyph;
}
// Returns true if the advance aAdvance fits into the compressed representation.
// aAdvance is in pixels.
static PRBool IsSimpleAdvancePixels(PRUint32 aAdvance) {
return (aAdvance & (ADVANCE_MASK >> ADVANCE_SHIFT)) == aAdvance;
}
PRBool IsSimpleGlyph() const { return (mValue & FLAG_IS_SIMPLE_GLYPH) != 0; }
PRBool IsComplex(PRUint32 aTag) const { return (mValue & (FLAG_IS_SIMPLE_GLYPH|TAG_MASK)) == aTag; }
PRBool IsMissing() const { return IsComplex(TAG_MISSING); }
PRBool IsComplexCluster() const { return IsComplex(TAG_COMPLEX_CLUSTER); }
PRBool IsLigatureContinuation() const { return IsComplex(TAG_LIGATURE_CONTINUATION); }
PRBool IsLowSurrogate() const { return IsComplex(TAG_LOW_SURROGATE); }
PRBool IsClusterStart() const { return (mValue & (FLAG_IS_SIMPLE_GLYPH|0x80U)) != 0x80U; }
PRUint32 GetSimpleAdvance() const { return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT; }
PRUint32 GetSimpleGlyph() const { return mValue & GLYPH_MASK; }
PRUint32 GetComplexTag() const { return mValue & TAG_MASK; }
PRBool CanBreakBefore() const { return (mValue & FLAG_CAN_BREAK_BEFORE) != 0; }
// Returns FLAG_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
PRUint32 SetCanBreakBefore(PRBool aCanBreakBefore) {
PRUint32 breakMask = aCanBreakBefore*FLAG_CAN_BREAK_BEFORE;
PRUint32 toggle = breakMask ^ (mValue & FLAG_CAN_BREAK_BEFORE);
mValue ^= toggle;
return toggle;
}
CompressedGlyph& SetSimpleGlyph(PRUint32 aAdvancePixels, PRUint32 aGlyph) {
NS_ASSERTION(IsSimpleAdvancePixels(aAdvancePixels), "Advance overflow");
NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow");
mValue = (mValue & FLAG_CAN_BREAK_BEFORE) | FLAG_IS_SIMPLE_GLYPH |
(aAdvancePixels << ADVANCE_SHIFT) | aGlyph;
return *this;
}
CompressedGlyph& SetComplex(PRUint32 aTag) {
mValue = (mValue & FLAG_CAN_BREAK_BEFORE) | aTag;
return *this;
}
CompressedGlyph& SetMissing() { return SetComplex(TAG_MISSING); }
CompressedGlyph& SetComplexCluster() { return SetComplex(TAG_COMPLEX_CLUSTER); }
CompressedGlyph& SetLowSurrogate() { return SetComplex(TAG_LOW_SURROGATE); }
CompressedGlyph& SetLigatureContinuation() { return SetComplex(TAG_LIGATURE_CONTINUATION); }
CompressedGlyph& SetClusterContinuation() { return SetComplex(TAG_CLUSTER_CONTINUATION); }
private:
PRUint32 mValue;
};
struct DetailedGlyph {
PRUint32 mIsLastGlyph:1;
PRUint32 mGlyphID:31;
float mAdvance, mXOffset, mYOffset;
};
// The text is divided into GlyphRuns at Pango item and text segment boundaries
struct GlyphRun {
nsRefPtr<gfxPangoFont> mFont; // never null
PRUint32 mCharacterOffset; // into original UTF16 string
};
class GlyphRunIterator {
public:
GlyphRunIterator(gfxPangoTextRun *aTextRun, PRUint32 aStart, PRUint32 aLength)
: mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) {
mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart);
}
PRBool NextRun();
GlyphRun *GetGlyphRun() { return mGlyphRun; }
PRUint32 GetStringStart() { return mStringStart; }
PRUint32 GetStringEnd() { return mStringEnd; }
private:
gfxPangoTextRun *mTextRun;
GlyphRun *mGlyphRun;
PRUint32 mStringStart;
PRUint32 mStringEnd;
PRUint32 mNextIndex;
PRUint32 mStartOffset;
PRUint32 mEndOffset;
};
friend class GlyphRunIterator;
friend class FontSelector;
// API for setting up the textrun glyphs
/**
* We've found a run of text that should use a particular font. Call this
* only during initialization when font substitution has been computed.
*/
nsresult AddGlyphRun(gfxPangoFont *aFont, PRUint32 aStartCharIndex);
// Call the following glyph-setters during initialization or during reshaping
// only. It is OK to overwrite existing data for a character.
/**
* Set the glyph for a character. Also allows you to set low surrogates,
* cluster and ligature continuations.
*/
void SetCharacterGlyph(PRUint32 aCharIndex, CompressedGlyph aGlyph) {
if (mCharacterGlyphs) {
mCharacterGlyphs[aCharIndex] = aGlyph;
}
if (mDetailedGlyphs) {
mDetailedGlyphs[aCharIndex] = nsnull;
}
}
/**
* Set some detailed glyphs for a character. The data is copied from aGlyphs,
* the caller retains ownership.
*/
void SetDetailedGlyphs(PRUint32 aCharIndex, DetailedGlyph *aGlyphs,
PRUint32 aNumGlyphs);
// API for access to the raw glyph data, needed by gfxPangoFont::Draw
// and gfxPangoFont::GetBoundingBox
const CompressedGlyph *GetCharacterGlyphs() { return mCharacterGlyphs; }
const DetailedGlyph *GetDetailedGlyphs(PRUint32 aCharIndex) {
NS_ASSERTION(mDetailedGlyphs && mDetailedGlyphs[aCharIndex],
"Requested detailed glyphs when there aren't any, "
"I think I'll go and have a lie down...");
return mDetailedGlyphs[aCharIndex];
}
PRUint32 CountMissingGlyphs();
private:
// **** general helpers ****
// Returns the index of the GlyphRun containing the given offset.
// Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
PRUint32 FindFirstGlyphRunContaining(PRUint32 aOffset);
// Computes the x-advance for a given cluster starting at aClusterOffset. Does
// not include any spacing. Result is in device pixels.
gfxFloat ComputeClusterAdvance(PRUint32 aClusterOffset);
// **** ligature helpers ****
// (Platforms do the actual ligaturization, but we need to do a bunch of stuff
// to handle requests that begin or end inside a ligature)
struct LigatureData {
PRUint32 mStartOffset;
PRUint32 mEndOffset;
PRUint32 mClusterCount;
PRUint32 mPartClusterIndex;
gfxFloat mLigatureWidth; // appunits
gfxFloat mBeforeSpacing; // appunits
gfxFloat mAfterSpacing; // appunits
};
// if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
LigatureData ComputeLigatureData(PRUint32 aPartOffset, PropertyProvider *aProvider);
void GetAdjustedSpacing(PRUint32 aStart, PRUint32 aEnd,
PropertyProvider *aProvider, PropertyProvider::Spacing *aSpacing);
PRBool GetAdjustedSpacingArray(PRUint32 aStart, PRUint32 aEnd,
PropertyProvider *aProvider,
nsTArray<PropertyProvider::Spacing> *aSpacing);
void DrawPartialLigature(gfxPangoFont *aFont, gfxContext *aCtx, PRUint32 aOffset,
const gfxRect *aDirtyRect, gfxPoint *aPt,
PropertyProvider *aProvider);
// result in appunits
void ShrinkToLigatureBoundaries(PRUint32 *aStart, PRUint32 *aEnd);
gfxFloat GetPartialLigatureWidth(PRUint32 aStart, PRUint32 aEnd, PropertyProvider *aProvider);
void AccumulatePartialLigatureMetrics(gfxPangoFont *aFont,
PRUint32 aOffset, PRBool aTight,
PropertyProvider *aProvider,
Metrics *aMetrics);
// **** measurement helper ****
void AccumulateMetricsForRun(gfxPangoFont *aFont, PRUint32 aStart,
PRUint32 aEnd, PRBool aTight,
PropertyProvider *aProvider,
Metrics *aMetrics);
// **** drawing helper ****
void DrawGlyphs(gfxPangoFont *aFont, gfxContext *aContext, PRBool aDrawToPath,
gfxPoint *aPt, PRUint32 aStart, PRUint32 aEnd,
PropertyProvider *aProvider);
// All our glyph data is in logical order, not visual
nsAutoArrayPtr<CompressedGlyph> mCharacterGlyphs;
nsAutoArrayPtr<nsAutoArrayPtr<DetailedGlyph> > mDetailedGlyphs; // only non-null if needed
// XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
// for smaller size especially in the super-common one-glyphrun case
nsAutoTArray<GlyphRun,1> mGlyphRuns;
PRUint32 mCharacterCount;
};
#endif /* GFX_PANGOFONTS_H */

View File

@ -382,6 +382,10 @@ public:
virtual nsString GetUniqueName();
virtual void Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
gfxContext *aContext, PRBool aDrawToPath, gfxPoint *aBaselineOrigin,
Spacing *aSpacing);
protected:
HFONT MakeHFONT();
cairo_font_face_t *MakeCairoFontFace();
@ -406,6 +410,8 @@ private:
LOGFONTW mLogFont;
nsRefPtr<WeightTable> mWeightTable;
virtual void SetupCairoFont(cairo_t *aCR);
};
/**********************************************************************
@ -469,6 +475,11 @@ protected:
const nsACString& genericName,
void *closure);
void InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun, const char *aString, PRUint32 aLength);
void InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength);
void InitTextRunUniscribe(gfxContext *aContext, gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength);
private:
friend class gfxWindowsTextRun;
@ -477,47 +488,4 @@ private:
nsDataHashtable<nsStringHashKey, nsRefPtr<gfxWindowsFont> > mFontCache;
};
/**********************************************************************
*
* class gfxWindowsTextRun
*
**********************************************************************/
class THEBES_API gfxWindowsTextRun {
public:
gfxWindowsTextRun(const nsAString& aString, gfxWindowsFontGroup *aFontGroup);
gfxWindowsTextRun(const nsACString& aString, gfxWindowsFontGroup *aFontGroup);
~gfxWindowsTextRun();
virtual void Draw(gfxContext *aContext, gfxPoint pt);
virtual gfxFloat Measure(gfxContext *aContext);
virtual void SetSpacing(const nsTArray<gfxFloat>& spacingArray);
virtual const nsTArray<gfxFloat> *const GetSpacing() const;
void SetRightToLeft(PRBool aIsRTL) { mIsRTL = aIsRTL; }
PRBool IsRightToLeft() { return mIsRTL; }
private:
double MeasureOrDrawFast(gfxContext *aContext, PRBool aDraw, gfxPoint pt);
double MeasureOrDrawReallyFast(gfxContext *aContext, PRBool aDraw, gfxPoint pt, gfxRGBA color);
double MeasureOrDrawUniscribe(gfxContext *aContext, PRBool aDraw, gfxPoint pt);
gfxWindowsFontGroup *mGroup;
nsTArray<gfxFloat> mSpacing;
// These should probably be in a union
nsString mString;
nsCString mCString;
const PRPackedBool mIsASCII;
PRPackedBool mIsRTL;
nsRefPtr<gfxWindowsFont> mFallbackFont;
/* cached values */
double mLength;
};
#endif /* GFX_WINDOWSFONTS_H */

View File

@ -339,145 +339,96 @@ gfxAtsuiFontGroup::~gfxAtsuiFontGroup()
ATSUDisposeFontFallbacks(mFallbacks);
}
class gfxWrapperTextRun : public gfxTextRun {
public:
gfxWrapperTextRun(gfxAtsuiFontGroup *aGroup,
const PRUint8* aString, PRUint32 aLength,
gfxTextRunFactory::Parameters* aParams)
: gfxTextRun(aParams),
mContext(aParams->mContext),
mInner(NS_ConvertASCIItoUTF16(nsDependentCSubstring(reinterpret_cast<const char*>(aString),
reinterpret_cast<const char*>(aString + aLength))),
aGroup),
mLength(aLength)
{
mInner.SetRightToLeft(IsRightToLeft());
}
gfxWrapperTextRun(gfxAtsuiFontGroup *aGroup,
const PRUnichar* aString, PRUint32 aLength,
gfxTextRunFactory::Parameters* aParams)
: gfxTextRun(aParams), mContext(aParams->mContext),
mInner(nsDependentSubstring(aString, aString + aLength), aGroup),
mLength(aLength)
{
mInner.SetRightToLeft(IsRightToLeft());
}
~gfxWrapperTextRun() {}
virtual void GetCharFlags(PRUint32 aStart, PRUint32 aLength,
PRUint8* aFlags)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual PRUint8 GetCharFlags(PRUint32 aOffset)
{ NS_ERROR("NOT IMPLEMENTED"); return 0; }
virtual PRUint32 GetLength()
{ NS_ERROR("NOT IMPLEMENTED"); return 0; }
virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRPackedBool* aBreakBefore)
{ NS_ERROR("NOT IMPLEMENTED"); return PR_FALSE; }
virtual void DrawToPath(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
PRBool aTightBoundingBox,
PropertyProvider* aBreakProvider)
{ NS_ERROR("NOT IMPLEMENTED"); return Metrics(); }
virtual void SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
TextProvider* aProvider,
gfxFloat* aAdvanceWidthDelta)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual PRUint32 BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
PRBool aLineBreakBefore, gfxFloat aWidth,
PropertyProvider* aProvider,
PRBool aSuppressInitialBreak,
Metrics* aMetrics, PRBool aTightBoundingBox,
PRBool* aUsedHyphenation,
PRUint32* aLastBreak)
{ NS_ERROR("NOT IMPLEMENTED"); return 0; }
virtual void Draw(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
const gfxRect* aDirtyRect,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth);
virtual gfxFloat GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider);
virtual void SetContext(gfxContext* aContext) { mContext = aContext; }
private:
gfxContext* mContext;
gfxAtsuiTextRun mInner;
PRUint32 mLength;
void SetupSpacingFromProvider(PropertyProvider* aProvider);
};
#define ROUND(x) floor((x) + 0.5)
void
gfxWrapperTextRun::SetupSpacingFromProvider(PropertyProvider* aProvider)
static void
SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString, PRUint32 aLength)
{
if (!(mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING))
TextBreakLocatorRef locator;
OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakClusterMask,
&locator);
if (status != noErr)
return;
UniCharArrayOffset breakOffset;
status = UCFindTextBreak(locator, kUCTextBreakClusterMask, 0, aString, aLength,
0, &breakOffset);
if (status != noErr) {
UCDisposeTextBreakLocator(&locator);
return;
NS_ASSERTION(mFlags & gfxTextRunFactory::TEXT_ABSOLUTE_SPACING,
"Can't handle relative spacing");
nsAutoTArray<PropertyProvider::Spacing,200> spacing;
spacing.AppendElements(mLength);
aProvider->GetSpacing(0, mLength, spacing.Elements());
nsTArray<gfxFloat> spaceArray;
PRUint32 i;
gfxFloat offset = 0; // in device pixels
for (i = 0; i < mLength; ++i) {
NS_ASSERTION(spacing.Elements()[i].mBefore == 0,
"Can't handle before-spacing!");
gfxFloat nextOffset = offset + spacing.Elements()[i].mAfter/mAppUnitsPerDevUnit;
spaceArray.AppendElement(ROUND(nextOffset) - ROUND(offset));
offset = nextOffset;
}
mInner.SetSpacing(spaceArray);
}
void
gfxWrapperTextRun::Draw(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
const gfxRect* aDirtyRect,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth)
{
NS_ASSERTION(aStart == 0 && aLength == mLength, "Can't handle substrings");
SetupSpacingFromProvider(aBreakProvider);
gfxPoint pt(aPt.x/mAppUnitsPerDevUnit, aPt.y/mAppUnitsPerDevUnit);
return mInner.Draw(mContext, pt);
}
gfxFloat
gfxWrapperTextRun::GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider)
{
NS_ASSERTION(aStart == 0 && aLength == mLength, "Can't handle substrings");
SetupSpacingFromProvider(aBreakProvider);
return mInner.Measure(mContext)*mAppUnitsPerDevUnit;
NS_ASSERTION(breakOffset == 0, "Cluster should start at offset zero");
gfxTextRun::CompressedGlyph g;
while (breakOffset < aLength) {
PRUint32 curOffset = breakOffset;
status = UCFindTextBreak(locator, kUCTextBreakClusterMask,
kUCTextBreakIterateMask,
aString, aLength, curOffset, &breakOffset);
if (status != noErr) {
UCDisposeTextBreakLocator(&locator);
return;
}
PRUint32 j;
for (j = curOffset + 1; j < breakOffset; ++j) {
aTextRun->SetCharacterGlyph(j, g.SetClusterContinuation());
}
}
NS_ASSERTION(breakOffset == aLength, "Should have found a final break");
UCDisposeTextBreakLocator(&locator);
}
gfxTextRun *
gfxAtsuiFontGroup::MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
Parameters* aParams)
gfxAtsuiFontGroup::MakeTextRunInternal(const PRUnichar *aString, PRUint32 aLength,
Parameters *aParams)
{
return new gfxWrapperTextRun(this, aString, aLength, aParams);
// NS_ASSERTION(!(aParams->mFlags & TEXT_NEED_BOUNDING_BOX),
// "Glyph extents not yet supported");
gfxTextRun *textRun = new gfxTextRun(aParams, aLength);
if (!textRun)
return nsnull;
// There's a one-char header in the string and a one-char trailer
textRun->RecordSurrogates(aString + 1);
if (!(aParams->mFlags & TEXT_IS_8BIT)) {
SetupClusterBoundaries(textRun, aString + 1, aLength);
}
InitTextRun(textRun, aString, aLength);
return textRun;
}
#define UNICODE_LRO 0x202d
#define UNICODE_RLO 0x202e
#define UNICODE_PDF 0x202c
static void
AppendDirectionalIndicator(PRUint32 aFlags, nsAString& aString)
{
static const PRUnichar overrides[2] = { UNICODE_LRO, UNICODE_RLO };
aString.Append(overrides[(aFlags & gfxTextRunFactory::TEXT_IS_RTL) != 0]);
}
gfxTextRun *
gfxAtsuiFontGroup::MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams)
gfxAtsuiFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
Parameters *aParams)
{
nsAutoString utf16;
AppendDirectionalIndicator(aParams->mFlags, utf16);
utf16.Append(aString, aLength);
utf16.Append(UNICODE_PDF);
return MakeTextRunInternal(utf16.get(), aLength, aParams);
}
gfxTextRun *
gfxAtsuiFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
Parameters *aParams)
{
aParams->mFlags |= TEXT_IS_8BIT;
return new gfxWrapperTextRun(this, aString, aLength, aParams);
nsDependentCSubstring cString(reinterpret_cast<const char*>(aString),
reinterpret_cast<const char*>(aString + aLength));
nsAutoString utf16;
AppendDirectionalIndicator(aParams->mFlags, utf16);
AppendASCIItoUTF16(cString, utf16);
utf16.Append(UNICODE_PDF);
return MakeTextRunInternal(utf16.get(), aLength, aParams);
}
gfxAtsuiFont*
@ -488,7 +439,7 @@ gfxAtsuiFontGroup::FindFontFor(ATSUFontID fid)
// In most cases, this will just be 1 -- maybe a
// small number, so no need for any more complex
// lookup
for (int i = 0; i < FontListLength(); i++) {
for (PRUint32 i = 0; i < FontListLength(); i++) {
font = GetFontAt(i);
if (font->GetATSUFontID() == fid)
return font;
@ -501,43 +452,325 @@ gfxAtsuiFontGroup::FindFontFor(ATSUFontID fid)
}
/**
** gfxAtsuiTextRun
**/
* Simple wrapper for ATSU "direct data arrays"
*/
class AutoLayoutDataArrayPtr {
public:
AutoLayoutDataArrayPtr(ATSULineRef aLineRef,
ATSUDirectDataSelector aSelector)
: mLineRef(aLineRef), mSelector(aSelector)
{
OSStatus status =
ATSUDirectGetLayoutDataArrayPtrFromLineRef(aLineRef,
aSelector, PR_FALSE, &mArray, &mItemCount);
if (status != noErr) {
mArray = NULL;
mItemCount = 0;
}
}
~AutoLayoutDataArrayPtr() {
if (mArray) {
ATSUDirectReleaseLayoutDataArrayPtr(mLineRef, mSelector, &mArray);
}
}
gfxAtsuiTextRun::gfxAtsuiTextRun(const nsAString& aString, gfxAtsuiFontGroup *aGroup)
: mString(aString), mGroup(aGroup)
void *mArray;
ItemCount mItemCount;
private:
ATSULineRef mLineRef;
ATSUDirectDataSelector mSelector;
};
/**
* Abstraction to iterate through an array in strange order. It just remaps
* array indices. Tragically we mainly need this because of ATSUI bugs.
* There are four cases we need to handle. Note that 0 <= i < L in all cases.
* 1) f(i) = i (LTR, no bug, most common)
* 2) f(i) = L - 1 - i (RTL, no bug, next most common)
* 3) f(i) = i < N ? N - 1 - i : i; (compensate for ATSUI bug in RTL mode)
* 4) f(i) = i < N ? i + L - N : L - 1 - i (compensate for ATSUI bug in LTR mode)
* We collapse 2) into 3) by setting N=L.
* We collapse 1) into 4) by setting N=L.
*/
class GlyphMapper {
public:
GlyphMapper(PRBool aIsRTL, PRUint32 aL, PRUint32 aN)
: mL(aL), mN(aN), mRTL(aIsRTL) {}
PRUint32 MapIndex(PRUint32 aIndex)
{
if (mRTL) {
return aIndex < mN ? mN - 1 - aIndex : aIndex;
} else {
return aIndex < mN ? aIndex + mL - mN : mL - 1 - aIndex;
}
}
private:
PRUint32 mL, mN;
PRBool mRTL;
};
static void
PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
const PRUnichar *aString)
{
AutoLayoutDataArrayPtr advanceDeltasArray(aLine, kATSUDirectDataAdvanceDeltaFixedArray);
AutoLayoutDataArrayPtr baselineDeltasArray(aLine, kATSUDirectDataBaselineDeltaFixedArray);
AutoLayoutDataArrayPtr deviceDeltasArray(aLine, kATSUDirectDataDeviceDeltaSInt16Array);
AutoLayoutDataArrayPtr glyphRecordsArray(aLine, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent);
PRUint32 numGlyphs = glyphRecordsArray.mItemCount;
if (numGlyphs == 0 || !glyphRecordsArray.mArray) {
NS_WARNING("Failed to retrieve key glyph data");
return;
}
Fixed *advanceDeltas = NS_STATIC_CAST(Fixed *, advanceDeltasArray.mArray);
Fixed *baselineDeltas = NS_STATIC_CAST(Fixed *, baselineDeltasArray.mArray);
ATSLayoutRecord *glyphRecords = NS_STATIC_CAST(ATSLayoutRecord *, glyphRecordsArray.mArray);
NS_ASSERTION((!advanceDeltas || advanceDeltasArray.mItemCount == numGlyphs) &&
(!baselineDeltas || baselineDeltasArray.mItemCount == numGlyphs),
"Mismatched glyph counts");
NS_ASSERTION(glyphRecords[numGlyphs - 1].flags & kATSGlyphInfoTerminatorGlyph,
"Last glyph should be a terminator glyph");
--numGlyphs;
if (numGlyphs == 0)
return;
PRUint32 index = 0;
ItemCount k = 0;
PRUint32 length = aRun->GetLength();
// ATSUI seems to have a bug where trailing whitespace in a run,
// even after we've forced the direction with LRO/RLO/PDF, does not
// necessarily get the required direction.
// A specific testcase is "RLO space space PDF"; we get
// glyphRecords[0] = { originalOffset:0, realPos:0; }
// glyphRecords[1] = { originalOffset:2, realPos:>0 }
// We count the number of glyphs that appear to be this sort of erroneous
// whitespace.
// In RTL situations, the bug manifests as the trailing whitespace characters
// being rendered in LTR order at the end of the glyph array.
// In LTR situations, the bug manifests as the trailing whitespace characters
// being rendered in RTL order at the start of the glyph array.
PRUint32 incorrectDirectionGlyphCount = 0;
PRUint32 stringTailOffset = length - 1;
while (glyphRecords[aRun->IsRightToLeft() ? numGlyphs - 1 - incorrectDirectionGlyphCount
: incorrectDirectionGlyphCount].originalOffset == stringTailOffset*2 &&
aString[stringTailOffset] == ' ') {
++incorrectDirectionGlyphCount;
stringTailOffset--;
if (incorrectDirectionGlyphCount == numGlyphs)
break;
}
GlyphMapper mapper(aRun->IsRightToLeft(), numGlyphs,
numGlyphs - incorrectDirectionGlyphCount);
gfxTextRun::CompressedGlyph g;
nsAutoTArray<gfxTextRun::DetailedGlyph,1> detailedGlyphs;
PRBool gotRealCharacter = PR_FALSE;
while (index < length) {
ATSLayoutRecord *glyph = nsnull;
// ATSUI sometimes moves glyphs around in visual order to handle
// situations such as DEVANAGARI VOWEL I appearing before its base
// character (even though it follows the base character in the text).
// To handle this we make the reordered glyph(s) and the characters
// they're reordered around into a single cluster.
PRUint32 forceClusterGlyphs = 0;
PRUint32 nextIndex = index + 1;
if (k < numGlyphs) {
glyph = &glyphRecords[mapper.MapIndex(k)];
// originalOffset is in bytes, so we need to adjust index by 2 for comparisons
if (glyph->originalOffset > 2*index) {
// Detect the situation above. We assume that at most
// two glyphs have been moved from after a run of characters
// to visually before the run of characters, so the following glyph
// or the next glyph is a glyph for the current character.
// We can tweak this up if necessary...
const PRUint32 MAX_GLYPHS_REORDERED = 10;
PRUint32 reorderedGlyphs = 0;
PRUint32 i;
PRUint32 maxOffset = glyph->originalOffset;
for (i = 1; k + i < numGlyphs; ++i) {
ATSLayoutRecord *nextGlyph = &glyphRecords[mapper.MapIndex(k + i)];
if (i == MAX_GLYPHS_REORDERED || nextGlyph->originalOffset == 2*index) {
reorderedGlyphs = i;
break;
}
maxOffset = PR_MAX(maxOffset, nextGlyph->originalOffset);
}
if (reorderedGlyphs > 0) {
forceClusterGlyphs = reorderedGlyphs;
while (k + forceClusterGlyphs < numGlyphs) {
ATSLayoutRecord *nextGlyph = &glyphRecords[mapper.MapIndex(k + forceClusterGlyphs)];
if (nextGlyph->originalOffset > maxOffset)
break;
++forceClusterGlyphs;
}
nextIndex = maxOffset/2 + 1;
}
}
}
if (k == numGlyphs ||
(glyph->originalOffset > 2*index && !forceClusterGlyphs)) {
NS_ASSERTION(index > 0, "Continuation at the start of a run??");
if (!aRun->GetCharacterGlyphs()[index].IsClusterContinuation()) {
if (gotRealCharacter) {
// No glyphs for character 'index', it must be a ligature continuation
aRun->SetCharacterGlyph(index, g.SetLigatureContinuation());
} else {
// Don't allow ligature continuations until we've actually
// got something for them to be a continuation of
aRun->SetCharacterGlyph(index, g.SetMissing());
}
}
} else {
NS_ASSERTION(glyph->originalOffset >= 2*index, "Lost some glyphs");
PRUint32 glyphCount = 1;
if (forceClusterGlyphs) {
glyphCount = forceClusterGlyphs;
PRUint32 i;
// Mark all the characters that we forced to cluster, other
// than this leading character, as cluster continuations.
for (i = 0; i < forceClusterGlyphs; ++i) {
PRUint32 offset = glyphRecords[mapper.MapIndex(k + i)].originalOffset;
if (offset != 2*index) {
aRun->SetCharacterGlyph(offset/2, g.SetClusterContinuation());
}
}
} else {
// Find all the glyphs associated with this character
while (k + glyphCount < numGlyphs &&
glyphRecords[mapper.MapIndex(k + glyphCount)].originalOffset == 2*index) {
++glyphCount;
}
}
Fixed advance = glyph[1].realPos - glyph->realPos;
PRUint32 advancePixels = advance >> 16;
// "Fixed" values have their fraction in the low 16 bits
if (glyphCount == 1 && advance >= 0 && (advance & 0xFFFF) == 0 &&
(!baselineDeltas || baselineDeltas[mapper.MapIndex(k)] == 0) &&
gfxTextRun::CompressedGlyph::IsSimpleAdvancePixels(advancePixels) &&
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph->glyphID)) {
aRun->SetCharacterGlyph(index, g.SetSimpleGlyph(advancePixels, glyph->glyphID));
} else {
if (detailedGlyphs.Length() < glyphCount) {
if (!detailedGlyphs.AppendElements(glyphCount - detailedGlyphs.Length()))
return;
}
PRUint32 i;
float appUnitsPerDevUnit = aRun->GetAppUnitsPerDevUnit();
for (i = 0; i < glyphCount; ++i) {
gfxTextRun::DetailedGlyph *details = &detailedGlyphs[i];
glyph = &glyphRecords[mapper.MapIndex(k + i)];
details->mIsLastGlyph = i == glyphCount - 1;
details->mGlyphID = glyph->glyphID;
float advanceAppUnits =
FixedToFloat(glyph[1].realPos - glyph->realPos)*appUnitsPerDevUnit;
details->mAdvance = ceilf(advanceAppUnits)/appUnitsPerDevUnit;
details->mXOffset = 0;
details->mYOffset = !baselineDeltas ? 0.0f
: FixedToFloat(baselineDeltas[mapper.MapIndex(k + i)]);
}
aRun->SetDetailedGlyphs(index, detailedGlyphs.Elements(), glyphCount);
}
gotRealCharacter = PR_TRUE;
k += glyphCount;
}
index = nextIndex;
if (index + 1 < length && NS_IS_HIGH_SURROGATE(aString[index])) {
++index;
}
}
}
struct PostLayoutCallbackClosure {
gfxTextRun *mTextRun;
const PRUnichar *mString;
};
// This is really disgusting, but the ATSUI refCon thing is also disgusting
static PostLayoutCallbackClosure *gCallbackClosure = nsnull;
static OSStatus
PostLayoutOperationCallback(ATSULayoutOperationSelector iCurrentOperation,
ATSULineRef iLineRef,
UInt32 iRefCon,
void *iOperationCallbackParameterPtr,
ATSULayoutOperationCallbackStatus *oCallbackStatus)
{
PostLayoutCallback(iLineRef, gCallbackClosure->mTextRun,
gCallbackClosure->mString);
*oCallbackStatus = kATSULayoutOperationCallbackStatusContinue;
return noErr;
}
void
gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
const PRUnichar *aString, PRUint32 aLength)
{
OSStatus status;
gfxAtsuiFont *atsuiFont = mGroup->GetFontAt(0);
gfxAtsuiFont *atsuiFont = GetFontAt(0);
ATSUStyle mainStyle = atsuiFont->GetATSUStyle();
nsTArray<ATSUStyle> stylesToDispose;
UniCharCount runLengths = mString.Length();
UniCharCount runLengths = aLength;
ATSUTextLayout layout;
// The string is actually aLength + 2 chars, with a header char to set
// the direction and a trailer char to pop it. So create the text layout
// giving the whole string as context, although we only want glyphs for
// the inner substring.
status = ATSUCreateTextLayoutWithTextPtr
(nsPromiseFlatString(mString).get(),
0,
mString.Length(),
mString.Length(),
(aString,
1,
aLength,
aLength + 2,
1,
&runLengths,
&mainStyle,
&mATSULayout);
&layout);
// XXX error check here?
PostLayoutCallbackClosure closure;
closure.mTextRun = aRun;
// Pass the real string to the closure, ignoring the header
closure.mString = aString + 1;
NS_ASSERTION(!gCallbackClosure, "Reentering InitTextRun? Expect disaster!");
gCallbackClosure = &closure;
ATSULayoutOperationOverrideSpecifier override;
override.operationSelector = kATSULayoutOperationPostLayoutAdjustment;
override.overrideUPP = PostLayoutOperationCallback;
// Set up our layout attributes
ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers;
ATSUAttributeTag layoutTags[] = { kATSULineLayoutOptionsTag, kATSULineFontFallbacksTag };
ByteCount layoutArgSizes[] = { sizeof(ATSLineLayoutOptions), sizeof(ATSUFontFallbacks) };
ATSUAttributeValuePtr layoutArgs[] = { &lineLayoutOptions, mGroup->GetATSUFontFallbacksPtr() };
ATSUSetLayoutControls(mATSULayout,
sizeof(layoutTags) / sizeof(ATSUAttributeTag),
static ATSUAttributeTag layoutTags[] = {
kATSULineLayoutOptionsTag,
kATSULineFontFallbacksTag,
kATSULayoutOperationOverrideTag
};
static ByteCount layoutArgSizes[] = {
sizeof(ATSLineLayoutOptions),
sizeof(ATSUFontFallbacks),
sizeof(ATSULayoutOperationOverrideSpecifier)
};
ATSUAttributeValuePtr layoutArgs[] = {
&lineLayoutOptions,
GetATSUFontFallbacksPtr(),
&override
};
ATSUSetLayoutControls(layout,
NS_ARRAY_LENGTH(layoutTags),
layoutTags,
layoutArgSizes,
layoutArgs);
/* Now go through and update the styles for the text, based on font matching. */
UniCharArrayOffset runStart = 0;
UniCharCount totalLength = mString.Length();
UniCharCount runLength = totalLength;
UniCharArrayOffset runStart = 1;
UniCharCount totalLength = aLength + 1;
UniCharCount runLength = aLength;
//fprintf (stderr, "==== Starting font maching [string length: %d]\n", totalLength);
while (runStart < totalLength) {
@ -545,11 +778,12 @@ gfxAtsuiTextRun::gfxAtsuiTextRun(const nsAString& aString, gfxAtsuiFontGroup *aG
UniCharArrayOffset changedOffset;
UniCharCount changedLength;
OSStatus status = ATSUMatchFontsToText (mATSULayout, runStart, runLength,
OSStatus status = ATSUMatchFontsToText (layout, runStart, runLength,
&substituteFontID, &changedOffset, &changedLength);
if (status == noErr) {
//fprintf (stderr, "ATSUMatchFontsToText returned noErr\n");
// everything's good, finish up
aRun->AddGlyphRun(atsuiFont, runStart - 1);
break;
} else if (status == kATSUFontsMatched) {
//fprintf (stderr, "ATSUMatchFontsToText returned kATSUFontsMatched: FID %d\n", substituteFontID);
@ -564,188 +798,43 @@ gfxAtsuiTextRun::gfxAtsuiTextRun(const nsAString& aString, gfxAtsuiFontGroup *aG
ATSUSetAttributes (subStyle, 1, fontTags, fontArgSizes, fontArgs);
ATSUSetRunStyle (mATSULayout, subStyle, changedOffset, changedLength);
if (changedOffset > runStart) {
aRun->AddGlyphRun(atsuiFont, runStart - 1);
}
mStylesToDispose.AppendElement(subStyle);
ATSUSetRunStyle (layout, subStyle, changedOffset, changedLength);
gfxAtsuiFont *font = FindFontFor(substituteFontID);
if (font) {
aRun->AddGlyphRun(font, changedOffset - 1);
}
stylesToDispose.AppendElement(subStyle);
} else if (status == kATSUFontsNotMatched) {
//fprintf (stderr, "ATSUMatchFontsToText returned kATSUFontsNotMatched\n");
/* I need to select the last resort font; how the heck do I do that? */
// Record which font is associated with these glyphs, anyway
aRun->AddGlyphRun(atsuiFont, runStart - 1);
}
//fprintf (stderr, "total length: %d changedOffset: %d changedLength: %d\n", runLength, changedOffset, changedLength);
//fprintf (stderr, "total length: %d changedOffset: %d changedLength: %d\p=n", runLength, changedOffset, changedLength);
runStart = changedOffset + changedLength;
runLength = totalLength - runStart;
}
//fprintf (stderr, "==== End font matching\n");
}
gfxAtsuiTextRun::~gfxAtsuiTextRun()
{
if (mATSULayout)
ATSUDisposeTextLayout(mATSULayout);
for (PRUint32 i = 0; i < mStylesToDispose.Length(); i++) {
ATSUStyle s = mStylesToDispose[i];
ATSUDisposeStyle(s);
}
}
struct CairoGlyphBuffer {
CairoGlyphBuffer() {
size = 128;
glyphs = staticGlyphBuf;
}
~CairoGlyphBuffer() {
if (glyphs != staticGlyphBuf)
PR_Free(glyphs);
}
void EnsureSize(PRUint32 numGlyphs) {
if (size < numGlyphs) {
if (glyphs != staticGlyphBuf)
PR_Free(glyphs);
glyphs = (cairo_glyph_t*) PR_Malloc(sizeof(cairo_glyph_t) * numGlyphs);
size = numGlyphs;
}
}
PRUint32 size;
cairo_glyph_t *glyphs;
private:
cairo_glyph_t staticGlyphBuf[128];
};
void
gfxAtsuiTextRun::Draw(gfxContext *aContext, gfxPoint pt)
{
gfxFloat offsetX, offsetY;
nsRefPtr<gfxASurface> surf = aContext->CurrentSurface (&offsetX, &offsetY);
cairo_t *cr = aContext->GetCairo();
double fontSize = mGroup->GetStyle()->size;
cairo_save (cr);
cairo_translate (cr, pt.x, pt.y);
OSStatus status;
ByteCount bufferSize = 4096;
ATSUGlyphInfoArray *glyphInfo = (ATSUGlyphInfoArray*) PR_Malloc (bufferSize);
status = ATSUGetGlyphInfo (mATSULayout, kATSUFromTextBeginning, kATSUToTextEnd, &bufferSize, glyphInfo);
if (status == buffersTooSmall) {
ATSUGetGlyphInfo (mATSULayout, kATSUFromTextBeginning, kATSUToTextEnd, &bufferSize, NULL);
PR_Free(glyphInfo);
glyphInfo = (ATSUGlyphInfoArray*) PR_Malloc (bufferSize);
status = ATSUGetGlyphInfo (mATSULayout, kATSUFromTextBeginning, kATSUToTextEnd, &bufferSize, glyphInfo);
}
if (status != noErr) {
fprintf (stderr, "ATSUGetGlyphInfo returned error %d\n", (int) status);
PR_Free (glyphInfo);
return;
}
CairoGlyphBuffer cairoGlyphs;
ItemCount i = 0;
while (i < glyphInfo->numGlyphs) {
ATSUStyle runStyle = glyphInfo->glyphs[i].style;
ItemCount lastRunGlyph;
for (lastRunGlyph = i+1; lastRunGlyph < glyphInfo->numGlyphs; lastRunGlyph++) {
if (glyphInfo->glyphs[lastRunGlyph].style != runStyle)
break;
}
ItemCount numGlyphs = lastRunGlyph-i;
ATSUFontID runFontID;
ByteCount unused;
status = ATSUGetAttribute (runStyle, kATSUFontTag, sizeof(ATSUFontID), &runFontID, &unused);
if (status != noErr || runFontID == kATSUInvalidFontID) {
i += numGlyphs;
continue;
}
cairoGlyphs.EnsureSize(numGlyphs);
cairo_glyph_t *runGlyphs = cairoGlyphs.glyphs;
for (ItemCount k = i; k < lastRunGlyph; k++) {
runGlyphs->index = glyphInfo->glyphs[k].glyphID;
runGlyphs->x = glyphInfo->glyphs[k].idealX; /* screenX */
runGlyphs->y = glyphInfo->glyphs[k].deltaY;
runGlyphs++;
}
gfxAtsuiFont *font = mGroup->FindFontFor(runFontID);
if (gfxFontTestStore::CurrentStore()) {
gfxFontTestStore::CurrentStore()->AddItem(font->GetUniqueName(),
cairoGlyphs.glyphs, numGlyphs);
}
cairo_set_scaled_font (cr, font->CairoScaledFont());
cairo_show_glyphs (cr, cairoGlyphs.glyphs, numGlyphs);
i += numGlyphs;
}
PR_Free (glyphInfo);
cairo_restore (cr);
}
gfxFloat
gfxAtsuiTextRun::Measure(gfxContext *aContext)
{
OSStatus status;
// Trigger layout so that our callback fires. We don't actually care about
// the result of this call.
ATSTrapezoid trap;
ItemCount numBounds;
ItemCount trapCount;
ATSUGetGlyphBounds(layout, 0, 0, 1, aLength, kATSUseDeviceOrigins, 1, &trap, &trapCount);
status = ATSUGetGlyphBounds(mATSULayout,
FloatToFixed(0.0),
FloatToFixed(0.0),
kATSUFromTextBeginning,
kATSUToTextEnd,
kATSUseFractionalOrigins,
1,
&trap,
&numBounds);
if (status != noErr) {
fprintf(stderr, "ATSUGetGlyphBounds returned error %d!\n", (int) status);
return 0.0;
ATSUDisposeTextLayout(layout);
//fprintf (stderr, "==== End font matching\n");
PRUint32 i;
for (i = 0; i < stylesToDispose.Length(); ++i) {
ATSUDisposeStyle(stylesToDispose[i]);
}
#if 0
printf ("Measure: '%s' trap: %f %f %f %f\n",
NS_ConvertUTF16toUTF8(mString).get(),
FixedToFloat(trap.upperLeft.x), FixedToFloat(trap.lowerLeft.x),
FixedToFloat(trap.upperRight.x), FixedToFloat(trap.lowerRight.x));
#endif
float f =
FixedToFloat(PR_MAX(trap.upperRight.x, trap.lowerRight.x)) -
FixedToFloat(PR_MIN(trap.upperLeft.x, trap.lowerLeft.x));
return f;
gCallbackClosure = nsnull;
}
void
gfxAtsuiTextRun::SetSpacing(const nsTArray<gfxFloat> &spacingArray)
{
// We can implement this, but there's really a mismatch between
// the spacings given here and cluster spacings. So we're
// going to do nothing until we figure out what the layout API
// will look like for this.
}
const nsTArray<gfxFloat> *const
gfxAtsuiTextRun::GetSpacing() const
{
return nsnull;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,42 @@
#include "gfxTextRunCache.h"
static inline PRBool
IsAscii(const char *aString, PRUint32 aLength)
{
const char *end = aString + aLength;
while (aString < end) {
if (0x80 & *aString)
return PR_FALSE;
++aString;
}
return PR_TRUE;
}
static inline PRBool
IsAscii(const PRUnichar *aString, PRUint32 aLength)
{
const PRUnichar *end = aString + aLength;
while (aString < end) {
if (0x0080 <= *aString)
return PR_FALSE;
++aString;
}
return PR_TRUE;
}
static inline PRBool
Is8Bit(const PRUnichar *aString, PRUint32 aLength)
{
const PRUnichar *end = aString + aLength;
while (aString < end) {
if (0x0100 <= *aString)
return PR_FALSE;
++aString;
}
return PR_TRUE;
}
gfxTextRunCache* gfxTextRunCache::mGlobalCache = nsnull;
PRInt32 gfxTextRunCache::mGlobalCacheRefCount = 0;
@ -85,7 +121,8 @@ gfxTextRunCache::Shutdown()
}
}
static PRUint32 ComputeFlags(PRBool aIsRTL, PRBool aEnableSpacing)
static PRUint32
ComputeFlags(PRBool aIsRTL, PRBool aEnableSpacing)
{
PRUint32 flags = gfxTextRunFactory::TEXT_HAS_SURROGATES;
if (aIsRTL) {
@ -100,18 +137,23 @@ static PRUint32 ComputeFlags(PRBool aIsRTL, PRBool aEnableSpacing)
}
gfxTextRun*
gfxTextRunCache::GetOrMakeTextRun (gfxContext* aContext, gfxFontGroup *aFontGroup,
const PRUnichar *aString, PRUint32 aLength,
PRUint32 aAppUnitsPerDevUnit, PRBool aIsRTL,
PRBool aEnableSpacing, PRBool *aCallerOwns)
gfxTextRunCache::GetOrMakeTextRun(gfxContext *aContext, gfxFontGroup *aFontGroup,
const PRUnichar *aString, PRUint32 aLength,
PRUint32 aAppUnitsPerDevUnit, PRBool aIsRTL,
PRBool aEnableSpacing, PRBool *aCallerOwns)
{
gfxSkipChars skipChars;
// Choose pessimistic flags since we don't want to bother analyzing the string
gfxTextRunFactory::Parameters params =
{ aContext, nsnull, nsnull, &skipChars, nsnull, 0, aAppUnitsPerDevUnit,
ComputeFlags(aIsRTL, aEnableSpacing) };
gfxTextRunFactory::Parameters params = {
aContext, nsnull, nsnull, &skipChars, nsnull, 0, aAppUnitsPerDevUnit,
ComputeFlags(aIsRTL, aEnableSpacing)
};
if (IsAscii(aString, aLength))
params.mFlags |= gfxTextRunFactory::TEXT_IS_ASCII;
// else if (Is8Bit(aString, aLength))
// params.mFlags |= gfxTextRunFactory::TEXT_IS_8BIT;
gfxTextRun* tr = nsnull;
gfxTextRun *tr = nsnull;
// Don't cache textruns that use spacing
if (!gDisableCache && !aEnableSpacing) {
// Evict first, to make sure that the textrun we return is live.
@ -156,19 +198,25 @@ gfxTextRunCache::GetOrMakeTextRun (gfxContext* aContext, gfxFontGroup *aFontGrou
}
gfxTextRun*
gfxTextRunCache::GetOrMakeTextRun (gfxContext* aContext, gfxFontGroup *aFontGroup,
const char *aString, PRUint32 aLength,
PRUint32 aAppUnitsPerDevUnit, PRBool aIsRTL,
PRBool aEnableSpacing, PRBool *aCallerOwns)
gfxTextRunCache::GetOrMakeTextRun(gfxContext *aContext, gfxFontGroup *aFontGroup,
const char *aString, PRUint32 aLength,
PRUint32 aAppUnitsPerDevUnit, PRBool aIsRTL,
PRBool aEnableSpacing, PRBool *aCallerOwns)
{
gfxSkipChars skipChars;
// Choose pessimistic flags since we don't want to bother analyzing the string
gfxTextRunFactory::Parameters params =
{ aContext, nsnull, nsnull, &skipChars, nsnull, 0, aAppUnitsPerDevUnit,
ComputeFlags(aIsRTL, aEnableSpacing) };
const PRUint8* str = NS_REINTERPRET_CAST(const PRUint8*, aString);
gfxTextRunFactory::Parameters params = {
aContext, nsnull, nsnull, &skipChars, nsnull, 0, aAppUnitsPerDevUnit,
ComputeFlags(aIsRTL, aEnableSpacing)
};
if (IsAscii(aString, aLength))
params.mFlags |= gfxTextRunFactory::TEXT_IS_ASCII;
else
params.mFlags |= gfxTextRunFactory::TEXT_IS_8BIT;
gfxTextRun* tr = nsnull;
const PRUint8 *str = reinterpret_cast<const PRUint8*>(aString);
gfxTextRun *tr = nsnull;
// Don't cache textruns that use spacing
if (!gDisableCache && !aEnableSpacing) {
// Evict first, to make sure that the textrun we return is live.

File diff suppressed because it is too large Load Diff