зеркало из https://github.com/mozilla/pjs.git
Bug 368799. Refactor gfxPangoTextRun so that the platform-dependent parts are all in gfxPangoFont/gfxPangoFontGroup. Also, remove special-string APIs, FlushSpacingCache and GetDecorationMetrics APIs from gfxTextRun. This will allow us to merge gfxPangoTextRun up to gfxTextRun and use that code on all platforms. r=pavlov
This commit is contained in:
Родитель
13f55f415d
Коммит
8841c2301a
|
@ -181,7 +181,9 @@ class THEBES_API gfxTextRunFactory {
|
|||
THEBES_INLINE_DECL_REFCOUNTING(gfxTextRunFactory)
|
||||
|
||||
public:
|
||||
// Flags >= 0x10000 are reserved for textrun clients
|
||||
// Flags in the mask 0xFFFF0000 are reserved for textrun clients
|
||||
// Flags in the mask 0x0000F000 are reserved for per-platform fonts
|
||||
// Flags in the mask 0x00000FFF are set by the textrun creator.
|
||||
enum {
|
||||
/**
|
||||
* When set, the text string pointer used to create the text run
|
||||
|
@ -237,9 +239,11 @@ public:
|
|||
// The language of the text, or null if not known
|
||||
nsIAtom *mLangGroup;
|
||||
// A description of which characters have been stripped from the original
|
||||
// DOM string to produce the characters in the textrun
|
||||
// DOM string to produce the characters in the textrun. May be null
|
||||
// if that information is not relevant.
|
||||
gfxSkipChars *mSkipChars;
|
||||
// A list of where linebreaks are currently placed in the textrun
|
||||
// A list of where linebreaks are currently placed in the textrun. May
|
||||
// be null if mInitialBreakCount is zero.
|
||||
PRUint32 *mInitialBreaks;
|
||||
PRUint32 mInitialBreakCount;
|
||||
// The ratio to use to convert device pixels to application layout units
|
||||
|
@ -312,6 +316,27 @@ public:
|
|||
|
||||
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;
|
||||
|
@ -337,12 +362,11 @@ protected:
|
|||
*
|
||||
* gfxTextRuns are mostly immutable. The only things that can change are
|
||||
* inter-cluster spacing and line break placement. Spacing is always obtained
|
||||
* lazily by methods that need it; cached spacing is flushed via
|
||||
* FlushSpacingCache(). Line breaks are stored persistently (insofar
|
||||
* as they affect the shaping of glyphs; gfxTextRun does not actually do anything
|
||||
* to explicitly account for line breaks). Initially there are no line breaks.
|
||||
* The textrun can record line breaks before or after any given cluster. (Line
|
||||
* breaks specified inside clusters are ignored.)
|
||||
* lazily by methods that need it, it is not cached. Line breaks are stored
|
||||
* persistently (insofar as they affect the shaping of glyphs; gfxTextRun does
|
||||
* not actually do anything to explicitly account for line breaks). Initially
|
||||
* there are no line breaks. The textrun can record line breaks before or after
|
||||
* any given cluster. (Line breaks specified inside clusters are ignored.)
|
||||
*
|
||||
* gfxTextRuns don't need to remember their text ... often it's enough just to
|
||||
* convert text to glyphs and store glyphs plus some geometry data in packed
|
||||
|
@ -510,25 +534,6 @@ public:
|
|||
PropertyProvider *aBreakProvider,
|
||||
gfxFloat *aAdvanceWidth) = 0;
|
||||
|
||||
/**
|
||||
* Special strings are strings that we might need to draw/measure but aren't
|
||||
* actually substrings of the given text. They never have extra spacing and
|
||||
* aren't involved in breaking.
|
||||
*/
|
||||
enum SpecialString {
|
||||
STRING_ELLIPSIS,
|
||||
STRING_HYPHEN,
|
||||
STRING_SPACE,
|
||||
STRING_MAX = STRING_SPACE
|
||||
};
|
||||
/**
|
||||
* Draw special string.
|
||||
* The provided point is the baseline origin on the left of the string
|
||||
* for LTR, on the right of the string for RTL.
|
||||
*/
|
||||
virtual void DrawSpecialString(gfxContext *aContext, gfxPoint aPt,
|
||||
SpecialString aString) = 0;
|
||||
|
||||
// Metrics needed by reflow
|
||||
struct Metrics {
|
||||
Metrics() {
|
||||
|
@ -578,14 +583,6 @@ public:
|
|||
PRBool aTightBoundingBox,
|
||||
PropertyProvider *aProvider) = 0;
|
||||
|
||||
/**
|
||||
* Computes the ReflowMetrics for a special string.
|
||||
* Uses GetSpacing from aBreakProvider.
|
||||
* @param aTightBoundingBox if true, we make the bounding box tight
|
||||
*/
|
||||
virtual Metrics MeasureTextSpecialString(SpecialString aString,
|
||||
PRBool aTightBoundingBox) = 0;
|
||||
|
||||
/**
|
||||
* Computes just the advance width for a substring.
|
||||
* Uses GetSpacing from aBreakProvider.
|
||||
|
@ -593,18 +590,6 @@ public:
|
|||
virtual gfxFloat GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
|
||||
PropertyProvider *aProvider) = 0;
|
||||
|
||||
/**
|
||||
* Computes the advance width for a special string.
|
||||
*/
|
||||
virtual gfxFloat GetAdvanceWidthSpecialString(SpecialString aString) = 0;
|
||||
|
||||
/**
|
||||
* Get the font metrics that we should use for drawing text decorations.
|
||||
* Overriden here so that transforming gfxTextRuns such as smallcaps
|
||||
* can do something special if they want to.
|
||||
*/
|
||||
virtual gfxFont::Metrics GetDecorationMetrics() = 0;
|
||||
|
||||
/**
|
||||
* Clear all stored line breaks for the given range (both before and after),
|
||||
* and then set the line-break state before aStart to aBreakBefore and
|
||||
|
@ -691,11 +676,6 @@ public:
|
|||
*/
|
||||
virtual void SetContext(gfxContext *aContext) {}
|
||||
|
||||
/**
|
||||
* Flush cached spacing data for the characters at and after aStart.
|
||||
*/
|
||||
virtual void FlushSpacingCache(PRUint32 aStart) = 0;
|
||||
|
||||
// Utility getters
|
||||
|
||||
PRBool IsRightToLeft() const { return (mFlags & gfxTextRunFactory::TEXT_IS_RTL) != 0; }
|
||||
|
@ -706,14 +686,13 @@ public:
|
|||
float GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; }
|
||||
|
||||
protected:
|
||||
gfxTextRun(gfxTextRunFactory::Parameters *aParams, PRBool aIs8Bit)
|
||||
gfxTextRun(gfxTextRunFactory::Parameters *aParams)
|
||||
: mUserData(aParams->mUserData),
|
||||
mAppUnitsPerDevUnit(aParams->mAppUnitsPerDevUnit),
|
||||
mFlags(aParams->mFlags)
|
||||
{
|
||||
mSkipChars.TakeFrom(aParams->mSkipChars);
|
||||
if (aIs8Bit) {
|
||||
mFlags |= gfxTextRunFactory::TEXT_IS_8BIT;
|
||||
if (aParams->mSkipChars) {
|
||||
mSkipChars.TakeFrom(aParams->mSkipChars);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,8 @@
|
|||
|
||||
class FontSelector;
|
||||
|
||||
class gfxPangoTextRun;
|
||||
|
||||
class gfxPangoFont : public gfxFont {
|
||||
public:
|
||||
gfxPangoFont (const nsAString& aName,
|
||||
|
@ -75,11 +77,64 @@ 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; }
|
||||
|
||||
protected:
|
||||
PangoFontDescription *mPangoFontDesc;
|
||||
PangoContext *mPangoCtx;
|
||||
|
||||
XftFont *mXftFont;
|
||||
cairo_scaled_font_t *mCairoFont;
|
||||
|
||||
PRBool mHasMetrics;
|
||||
Metrics mMetrics;
|
||||
|
@ -88,8 +143,11 @@ 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);
|
||||
};
|
||||
|
||||
class FontSelector;
|
||||
|
||||
class THEBES_API gfxPangoFontGroup : public gfxFontGroup {
|
||||
public:
|
||||
gfxPangoFontGroup (const nsAString& families,
|
||||
|
@ -98,6 +156,7 @@ public:
|
|||
|
||||
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
|
||||
|
||||
// Create and initialize a textrun using Pango (or Xft)
|
||||
virtual gfxTextRun *MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
|
||||
Parameters *aParams);
|
||||
virtual gfxTextRun *MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
|
||||
|
@ -119,16 +178,40 @@ public:
|
|||
mFontCache.Put(aName, aFont);
|
||||
}
|
||||
|
||||
struct SpecialStringData {
|
||||
PangoGlyphString* mGlyphs;
|
||||
gfxFloat mAdvance;
|
||||
|
||||
SpecialStringData() { mGlyphs = nsnull; }
|
||||
~SpecialStringData() { if (mGlyphs) pango_glyph_string_free(mGlyphs); }
|
||||
};
|
||||
SpecialStringData mSpecialStrings[gfxTextRun::STRING_MAX + 1];
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
const gchar *aUTF8, PRUint32 aUTF8Length,
|
||||
const PRUnichar *aUTF16Text, PRUint32 aUTF16Length);
|
||||
void CreateGlyphRunsItemizing(gfxPangoTextRun *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,
|
||||
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,
|
||||
void *closure);
|
||||
|
@ -136,20 +219,21 @@ protected:
|
|||
private:
|
||||
nsDataHashtable<nsStringHashKey, nsRefPtr<gfxPangoFont> > mFontCache;
|
||||
nsTArray<gfxFontStyle> mAdditionalStyles;
|
||||
nsAutoPtr<gfxTextRun> mSpecialStrings[STRING_MAX + 1];
|
||||
};
|
||||
|
||||
struct TextSegment;
|
||||
|
||||
/**
|
||||
* 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(gfxPangoFontGroup *aGroup,
|
||||
const PRUint8 *aString, PRUint32 aLength,
|
||||
gfxTextRunFactory::Parameters *aParams);
|
||||
gfxPangoTextRun(gfxPangoFontGroup *aGroup,
|
||||
const PRUnichar *aString, PRUint32 aLength,
|
||||
gfxTextRunFactory::Parameters *aParams);
|
||||
~gfxPangoTextRun();
|
||||
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);
|
||||
|
@ -165,8 +249,6 @@ public:
|
|||
PRUint32 aStart, PRUint32 aLength,
|
||||
PropertyProvider *aBreakProvider,
|
||||
gfxFloat *aAdvanceWidth);
|
||||
virtual void DrawSpecialString(gfxContext *aContext, gfxPoint aPt,
|
||||
SpecialString aString);
|
||||
virtual Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
|
||||
PRBool aTightBoundingBox,
|
||||
PropertyProvider *aBreakProvider);
|
||||
|
@ -174,12 +256,8 @@ public:
|
|||
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
|
||||
TextProvider *aProvider,
|
||||
gfxFloat *aAdvanceWidthDelta);
|
||||
virtual Metrics MeasureTextSpecialString(SpecialString aString,
|
||||
PRBool aTightBoundingBox);
|
||||
virtual gfxFloat GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
|
||||
PropertyProvider *aBreakProvider);
|
||||
virtual gfxFloat GetAdvanceWidthSpecialString(SpecialString aString);
|
||||
virtual gfxFont::Metrics GetDecorationMetrics();
|
||||
virtual PRUint32 BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
||||
PRBool aLineBreakBefore, gfxFloat aWidth,
|
||||
PropertyProvider *aBreakProvider,
|
||||
|
@ -187,7 +265,6 @@ public:
|
|||
Metrics *aMetrics, PRBool aTightBoundingBox,
|
||||
PRBool *aUsedHyphenation,
|
||||
PRUint32 *aLastBreak);
|
||||
virtual void FlushSpacingCache(PRUint32 aStart);
|
||||
|
||||
/**
|
||||
* This class records the information associated with a character in the
|
||||
|
@ -217,15 +294,19 @@ public:
|
|||
// 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 = 0x00U,
|
||||
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 = 0x01U,
|
||||
TAG_LIGATURE_CONTINUATION = 0x21U,
|
||||
|
||||
// Values where the upper 28 bits equal 0x80 are reserved for
|
||||
// non-cluster-start characters (see IsClusterStart below)
|
||||
|
@ -239,28 +320,34 @@ public:
|
|||
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
|
||||
static PRBool IsSimpleAdvance(PRUint32 aAdvance) {
|
||||
// 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() { return (mValue & FLAG_IS_SIMPLE_GLYPH) != 0; }
|
||||
PRBool IsComplex(PRUint32 aTag) { return (mValue & (FLAG_IS_SIMPLE_GLYPH|TAG_MASK)) == aTag; }
|
||||
PRBool IsComplexCluster() { return IsComplex(TAG_COMPLEX_CLUSTER); }
|
||||
PRBool IsLigatureContinuation() { return IsComplex(TAG_LIGATURE_CONTINUATION); }
|
||||
PRBool IsLowSurrogate() { return IsComplex(TAG_LOW_SURROGATE); }
|
||||
PRBool IsClusterStart() { return (mValue & (FLAG_IS_SIMPLE_GLYPH|0x80U)) != 0x80U; }
|
||||
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() { return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT; }
|
||||
PRUint32 GetSimpleGlyph() { return mValue & GLYPH_MASK; }
|
||||
PRUint32 GetSimpleAdvance() const { return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT; }
|
||||
PRUint32 GetSimpleGlyph() const { return mValue & GLYPH_MASK; }
|
||||
|
||||
PRUint32 GetComplexTag() { return mValue & TAG_MASK; }
|
||||
PRUint32 GetComplexTag() const { return mValue & TAG_MASK; }
|
||||
|
||||
PRBool CanBreakBefore() { return (mValue & FLAG_CAN_BREAK_BEFORE) != 0; }
|
||||
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;
|
||||
|
@ -269,46 +356,34 @@ public:
|
|||
return toggle;
|
||||
}
|
||||
|
||||
void SetSimpleGlyph(PRUint32 aAdvance, PRUint32 aGlyph) {
|
||||
NS_ASSERTION(IsSimpleAdvance(aAdvance), "Advance overflow");
|
||||
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 |
|
||||
(aAdvance << ADVANCE_SHIFT) | aGlyph;
|
||||
(aAdvancePixels << ADVANCE_SHIFT) | aGlyph;
|
||||
return *this;
|
||||
}
|
||||
void SetComplex(PRUint32 aTag) { mValue = (mValue & FLAG_CAN_BREAK_BEFORE) | aTag; }
|
||||
void SetComplexCluster() { SetComplex(TAG_COMPLEX_CLUSTER); }
|
||||
void SetLowSurrogate() { SetComplex(TAG_LOW_SURROGATE); }
|
||||
void SetLigatureContinuation() { SetComplex(TAG_LIGATURE_CONTINUATION); }
|
||||
void SetClusterContinuation() { SetComplex(TAG_CLUSTER_CONTINUATION); }
|
||||
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;
|
||||
// mGlyphID == 2^31 means "missing glyph"
|
||||
PRUint32 mGlyphID:31;
|
||||
float mAdvance, mXOffset, mYOffset;
|
||||
|
||||
// This is the ID of a missing glyph in a details record. All "missing" glyphs
|
||||
// are converted to a detailed glyph record with this glyph ID.
|
||||
enum {
|
||||
DETAILED_MISSING_GLYPH = 1U << 30
|
||||
};
|
||||
};
|
||||
// The text is divided into GlyphRuns at Pango item and text segment boundaries
|
||||
struct GlyphRun {
|
||||
PangoFont *mPangoFont; // strong ref; can't be null
|
||||
cairo_scaled_font_t *mCairoFont; // could be null
|
||||
PRUint32 mCharacterOffset; // into original UTF16 string
|
||||
|
||||
~GlyphRun() {
|
||||
if (mCairoFont) {
|
||||
cairo_scaled_font_destroy(mCairoFont);
|
||||
}
|
||||
if (mPangoFont) {
|
||||
g_object_unref(mPangoFont);
|
||||
}
|
||||
}
|
||||
nsRefPtr<gfxPangoFont> mFont; // never null
|
||||
PRUint32 mCharacterOffset; // into original UTF16 string
|
||||
};
|
||||
|
||||
class GlyphRunIterator {
|
||||
|
@ -334,35 +409,48 @@ public:
|
|||
friend class GlyphRunIterator;
|
||||
friend class FontSelector;
|
||||
|
||||
// **** Initialization helpers ****
|
||||
// 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:
|
||||
// If aUTF16Text is null, then the string contains no characters >= 0x100
|
||||
void Init(gfxTextRunFactory::Parameters *aParams, const gchar *aUTF8Text,
|
||||
PRUint32 aUTF8Length, PRUint32 aUTF8HeaderLength, const PRUnichar *aUTF16Text,
|
||||
PRUint32 aUTF16Length);
|
||||
void SetupClusterBoundaries(const gchar *aUTF8, PRUint32 aUTF8Length,
|
||||
PRUint32 aUTF16Offset, PangoAnalysis *aAnalysis);
|
||||
nsresult AddGlyphRun(PangoFont *aFont, PRUint32 aUTF16Offset);
|
||||
DetailedGlyph *AllocateDetailedGlyphs(PRUint32 aIndex, PRUint32 aCount);
|
||||
// Returns NS_ERROR_FAILURE if there's a missing glyph
|
||||
nsresult SetGlyphs(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(const gchar *aUTF8, PRUint32 aUTF8Length,
|
||||
const PRUnichar *aUTF16Text, PRUint32 aUTF16Length);
|
||||
void CreateGlyphRunsItemizing(const gchar *aUTF8, PRUint32 aUTF8Length,
|
||||
PRUint32 aUTF8HeaderLength);
|
||||
#if defined(ENABLE_XFT_FAST_PATH_8BIT) || defined(ENABLE_XFT_FAST_PATH_ALWAYS)
|
||||
void CreateGlyphRunsXft(const gchar *aUTF8, PRUint32 aUTF8Length);
|
||||
#endif
|
||||
// **** general helpers ****
|
||||
|
||||
void SetupPangoContextDirection();
|
||||
static void SetupCairoFont(cairo_t *aCR, GlyphRun *aGlyphRun);
|
||||
// Returns the index of the GlyphRun containing the given offset.
|
||||
// Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
|
||||
PRUint32 FindFirstGlyphRunContaining(PRUint32 aOffset);
|
||||
|
@ -371,7 +459,7 @@ private:
|
|||
gfxFloat ComputeClusterAdvance(PRUint32 aClusterOffset);
|
||||
|
||||
// **** ligature helpers ****
|
||||
// (Pango does the actual ligaturization, but we need to do a bunch of stuff
|
||||
// (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 {
|
||||
|
@ -390,38 +478,33 @@ private:
|
|||
PRBool GetAdjustedSpacingArray(PRUint32 aStart, PRUint32 aEnd,
|
||||
PropertyProvider *aProvider,
|
||||
nsTArray<PropertyProvider::Spacing> *aSpacing);
|
||||
void DrawPartialLigature(gfxContext *aCtx, PRUint32 aOffset,
|
||||
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(PangoFont *aPangoFont,
|
||||
PRUint32 aOffset, PropertyProvider *aProvider,
|
||||
void AccumulatePartialLigatureMetrics(gfxPangoFont *aFont,
|
||||
PRUint32 aOffset, PRBool aTight,
|
||||
PropertyProvider *aProvider,
|
||||
Metrics *aMetrics);
|
||||
|
||||
// **** measurement helper ****
|
||||
void AccumulatePangoMetricsForRun(PangoFont *aPangoFont, PRUint32 aStart,
|
||||
PRUint32 aEnd, PropertyProvider *aProvider,
|
||||
Metrics *aMetrics);
|
||||
void AccumulateMetricsForRun(gfxPangoFont *aFont, PRUint32 aStart,
|
||||
PRUint32 aEnd, PRBool aTight,
|
||||
PropertyProvider *aProvider,
|
||||
Metrics *aMetrics);
|
||||
|
||||
// **** drawing helpers ****
|
||||
// **** drawing helper ****
|
||||
void DrawGlyphs(gfxPangoFont *aFont, gfxContext *aContext, PRBool aDrawToPath,
|
||||
gfxPoint *aPt, PRUint32 aStart, PRUint32 aEnd,
|
||||
PropertyProvider *aProvider);
|
||||
|
||||
typedef void (* CairoGlyphProcessorCallback)
|
||||
(void *aClosure, cairo_glyph_t *aGlyphs, int aNumGlyphs);
|
||||
void ProcessCairoGlyphsWithSpacing(CairoGlyphProcessorCallback aCB, void *aClosure,
|
||||
gfxPoint *aPt, PRUint32 aStart, PRUint32 aEnd,
|
||||
PropertyProvider::Spacing *aSpacing);
|
||||
void ProcessCairoGlyphs(CairoGlyphProcessorCallback aCB, void *aClosure,
|
||||
gfxPoint *aPt, PRUint32 aStart, PRUint32 aEnd,
|
||||
PropertyProvider *aProvider);
|
||||
static void CairoShowGlyphs(void *aClosure, cairo_glyph_t *aGlyphs, int aNumGlyphs);
|
||||
static void CairoGlyphsToPath(void *aClosure, cairo_glyph_t *aGlyphs, int aNumGlyphs);
|
||||
|
||||
nsRefPtr<gfxPangoFontGroup> mFontGroup;
|
||||
// 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;
|
||||
};
|
||||
|
|
|
@ -379,20 +379,10 @@ public:
|
|||
PropertyProvider* aBreakProvider,
|
||||
gfxFloat* aAdvanceWidth)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); }
|
||||
virtual void DrawSpecialString(gfxContext* aContext, gfxPoint aPt,
|
||||
SpecialString aString)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); }
|
||||
virtual Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
|
||||
PRBool aTightBoundingBox,
|
||||
PropertyProvider* aBreakProvider)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); return Metrics(); }
|
||||
virtual Metrics MeasureTextSpecialString(SpecialString aString,
|
||||
PRBool aTightBoundingBox)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); return Metrics(); }
|
||||
virtual gfxFloat GetAdvanceWidthSpecialString(SpecialString aString)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); return 0; }
|
||||
virtual gfxFont::Metrics GetDecorationMetrics()
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); return gfxFont::Metrics(); }
|
||||
virtual void SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
|
||||
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
|
||||
TextProvider* aProvider,
|
||||
|
@ -406,8 +396,6 @@ public:
|
|||
PRBool* aUsedHyphenation,
|
||||
PRUint32* aLastBreak)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); return 0; }
|
||||
virtual void FlushSpacingCache(PRUint32 aStart)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); }
|
||||
|
||||
virtual void Draw(gfxContext *aContext, gfxPoint aPt,
|
||||
PRUint32 aStart, PRUint32 aLength,
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -559,20 +559,10 @@ public:
|
|||
PropertyProvider* aBreakProvider,
|
||||
gfxFloat* aAdvanceWidth)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); }
|
||||
virtual void DrawSpecialString(gfxContext* aContext, gfxPoint aPt,
|
||||
SpecialString aString)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); }
|
||||
virtual Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
|
||||
PRBool aTightBoundingBox,
|
||||
PropertyProvider* aBreakProvider)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
|
||||
virtual Metrics MeasureTextSpecialString(SpecialString aString,
|
||||
PRBool aTightBoundingBox)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
|
||||
virtual gfxFloat GetAdvanceWidthSpecialString(SpecialString aString)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
|
||||
virtual gfxFont::Metrics GetDecorationMetrics()
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
|
||||
virtual void SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
|
||||
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
|
||||
TextProvider* aProvider,
|
||||
|
@ -586,8 +576,6 @@ public:
|
|||
PRBool* aUsedHyphenation,
|
||||
PRUint32* aLastBreak)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
|
||||
virtual void FlushSpacingCache(PRUint32 aStart)
|
||||
{ NS_ERROR("NOT IMPLEMENTED"); }
|
||||
|
||||
virtual void Draw(gfxContext *aContext, gfxPoint aPt,
|
||||
PRUint32 aStart, PRUint32 aLength,
|
||||
|
|
Загрузка…
Ссылка в новой задаче