Bug 375760. Make a number of small changes to the gfxTextRun/gfxFont/gfxFontGroup APIs. r=vlad

This commit is contained in:
roc+@cs.cmu.edu 2007-05-04 19:16:16 -07:00
parent bb057f50e6
commit 2898af075d
14 changed files with 326 additions and 249 deletions

View File

@ -275,9 +275,6 @@ public:
StubPropertyProvider(const nscoord* aSpacing = nsnull)
: mSpacing(aSpacing) {}
virtual void ForceRememberText() {
NS_ERROR("This shouldn't be called because we already asked the textrun to remember");
}
virtual void GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength,
PRPackedBool* aBreakBefore) {
NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");

View File

@ -56,7 +56,7 @@ public:
virtual const gfxFont::Metrics& GetMetrics();
float GetCharWidth(PRUnichar c);
float GetCharWidth(PRUnichar c, PRUint32 *aGlyphID = nsnull);
float GetCharHeight(PRUnichar c);
ATSUFontID GetATSUFontID() { return mATSUFontID; }
@ -68,6 +68,8 @@ public:
virtual nsString GetUniqueName();
virtual PRUint32 GetSpaceGlyph() { return mSpaceGlyph; }
protected:
const gfxFontStyle *mFontStyle;
@ -82,6 +84,8 @@ protected:
gfxFont::Metrics mMetrics;
gfxFloat mAdjustedSize;
PRUint32 mSpaceGlyph;
void InitMetrics(ATSUFontID aFontID, ATSFontRef aFontRef);
virtual void SetupCairoFont(cairo_t *aCR)
@ -99,17 +103,17 @@ public:
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
Parameters* aParams);
const Parameters* aParams, PRUint32 aFlags);
virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams);
const Parameters* aParams, PRUint32 aFlags);
// When aWrapped is true, the string includes bidi control
// characters. The first character will be LRO or LRO to force setting the
// direction for all characters, the last character is PDF, and the
// second to last character is a non-whitespace character --- to ensure
// that there is no "trailing whitespace" in the string, see
// http://weblogs.mozillazine.org/roc/archives/2007/02/superlaser_targ.html#comments
gfxTextRun *MakeTextRunInternal(const PRUnichar *aString, PRUint32 aLength,
PRBool aWrapped, Parameters *aParams);
void MakeTextRunInternal(const PRUnichar *aString, PRUint32 aLength,
PRBool aWrapped, gfxTextRun *aTextRun);
ATSUFontFallbacks *GetATSUFontFallbacksPtr() { return &mFallbacks; }

View File

@ -414,6 +414,9 @@ public:
// Expiration tracking
nsExpirationState *GetExpirationState() { return &mExpirationState; }
// Get the glyphID of a space
virtual PRUint32 GetSpaceGlyph() = 0;
protected:
// The family name of the font
nsString mName;
@ -491,8 +494,6 @@ public:
gfxContext *mContext;
// Pointer to arbitrary user data (which should outlive the textrun)
void *mUserData;
// 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. May be null
// if that information is not relevant.
@ -503,24 +504,9 @@ public:
PRUint32 mInitialBreakCount;
// The ratio to use to convert device pixels to application layout units
PRUint32 mAppUnitsPerDevUnit;
// Flags --- see above
PRUint32 mFlags;
};
virtual ~gfxTextRunFactory() {}
/**
* Create a gfxTextRun from Unicode text. The length is obtained from
* aParams->mSkipChars->GetCharCount().
*/
virtual gfxTextRun *MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
Parameters *aParams) = 0;
/**
* Create a gfxTextRun from 8-bit Unicode (UCS1?) text. The length is
* obtained from aParams->mSkipChars->GetCharCount().
*/
virtual gfxTextRun *MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
Parameters *aParams) = 0;
};
/**
@ -542,15 +528,6 @@ public:
* 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
* form. However sometimes gfxTextRuns will want to get the original text back
* to handle some unusual situation. So gfxTextRuns have two modes: "not
* remembering text" (initial state) and "remembering text". A call to
* gfxTextRun::RememberText forces a transition from the former to latter state.
* The text is never forgotten. A gfxTextRun call that receives a PropertyProvider
* object may call ForceRememberText to request a transition to "remembering text".
*
* It is important that zero-length substrings are handled correctly. This will
* be on the test!
*
@ -568,7 +545,7 @@ public:
*/
class THEBES_API gfxTextRun {
public:
~gfxTextRun() {}
virtual ~gfxTextRun();
typedef gfxFont::RunMetrics Metrics;
@ -595,15 +572,6 @@ public:
// All coordinates are in layout/app units
/**
* This can be called to force gfxTextRun to remember the text used
* to create it and *never* call PropertyProvider::GetText again.
*
* Right now we don't implement these.
*/
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
* the "allow break before" points. Initially, there are no potential
@ -631,16 +599,6 @@ public:
*/
class PropertyProvider {
public:
/**
* Recover the text originally used to build the textrun. This should
* only be requested infrequently as it may be slow. If you need to
* call it a lot you should probably be saving the text in the text run
* itself. It just forces the textrun user to call RememberText on the
* text run. If you call this and RememberText doesn't get called,
* then something has failed and you should handle it.
*/
virtual void ForceRememberText() = 0;
// Detect hyphenation break opportunities in the given range; breaks
// not at cluster boundaries will be ignored.
virtual void GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength,
@ -757,7 +715,6 @@ public:
*/
virtual PRBool SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
PropertyProvider *aProvider,
gfxFloat *aAdvanceWidthDelta);
/**
@ -823,13 +780,30 @@ public:
PRBool IsRightToLeft() const { return (mFlags & gfxTextRunFactory::TEXT_IS_RTL) != 0; }
gfxFloat GetDirection() const { return (mFlags & gfxTextRunFactory::TEXT_IS_RTL) ? -1.0 : 1.0; }
void *GetUserData() const { return mUserData; }
void SetUserData(void *aUserData) { mUserData = aUserData; }
PRUint32 GetFlags() const { return mFlags; }
const gfxSkipChars& GetSkipChars() const { return mSkipChars; }
PRUint32 GetAppUnitsPerDevUnit() const { return mAppUnitsPerDevUnit; }
gfxFontGroup *GetFontGroup() const { return mFontGroup; }
const PRUint8 *GetText8Bit() const
{ return (mFlags & gfxTextRunFactory::TEXT_IS_8BIT) ? mText.mSingle : nsnull; }
const PRUnichar *GetTextUnicode() const
{ return (mFlags & gfxTextRunFactory::TEXT_IS_8BIT) ? nsnull : mText.mDouble; }
// 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);
// We take ownership of aText, which must have been allocated by new[] (it
// may be null if aLength is zero).
gfxTextRun(const gfxTextRunFactory::Parameters *aParams, const void *aText,
PRUint32 aLength, gfxFontGroup *aFontGroup, PRUint32 aFlags);
// Clone this textrun, according to the given parameters. This textrun's
// glyph data is copied, so the text and length must be the same as this
// textrun's. If there's a problem, return null. Actual linebreaks will
// be set as per aParams; there will be no potential linebreaks.
// If successful, we take ownership of aText, which must have been allocated by new[].
virtual gfxTextRun *Clone(const gfxTextRunFactory::Parameters *aParams, const void *aText,
PRUint32 aLength, gfxFontGroup *aFontGroup, PRUint32 aFlags);
/**
* This class records the information associated with a character in the
@ -1050,6 +1024,8 @@ public:
return mGlyphRuns.Elements();
}
nsExpirationState *GetExpirationState() { return &mExpirationState; }
private:
// **** general helpers ****
@ -1110,14 +1086,21 @@ private:
// 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
PRUint32 mAppUnitsPerDevUnit;
PRUint32 mFlags;
PRUint32 mCharacterCount;
// When TEXT_IS_8BIT is set, we use mSingle, otherwise we use mDouble.
// When TEXT_IS_PERSISTENT is set, we don't own the text, otherwise we
// own the text and should delete it when we go away.
// This text is not null-terminated.
union {
const PRUint8 *mSingle;
const PRUnichar *mDouble;
} mText;
void *mUserData;
gfxFontGroup *mFontGroup; // addrefed
gfxSkipChars mSkipChars;
nsExpirationState mExpirationState;
PRUint32 mAppUnitsPerDevUnit;
PRUint32 mFlags;
PRUint32 mCharacterCount;
};
class THEBES_API gfxFontGroup : public gfxTextRunFactory {
@ -1144,13 +1127,31 @@ public:
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;
/**
* Make a textrun for an empty string. This is fast; if you call it,
* don't bother caching the result.
*/
gfxTextRun *MakeEmptyTextRun(const Parameters *aParams, PRUint32 aFlags);
/**
* Make a textrun for a single ASCII space. This is fast; if you call it,
* don't bother caching the result.
*/
gfxTextRun *MakeSpaceTextRun(const Parameters *aParams, PRUint32 aFlags);
/**
* Make a textrun for a given string. Takes ownership of aString unless
* aFlags & TEXT_IS_PERSISTENT --- in that case, the caller must destroy
* the textrun before aString dies.
*/
virtual gfxTextRun *MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
const Parameters *aParams, PRUint32 aFlags) = 0;
/**
* Make a textrun for a given string. Takes ownership of aString unless
* aFlags & TEXT_IS_PERSISTENT --- in that case, the caller must destroy
* the textrun before aString dies.
*/
virtual gfxTextRun *MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
const Parameters *aParams, PRUint32 aFlags) = 0;
/* helper function for splitting font families on commas and
* calling a function for each family to fill the mFonts array
@ -1169,31 +1170,10 @@ 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.
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,

View File

@ -86,6 +86,12 @@ public:
virtual nsString GetUniqueName();
// Get the glyphID of a space
virtual PRUint32 GetSpaceGlyph() {
GetMetrics();
return mSpaceGlyph;
}
protected:
PangoFontDescription *mPangoFontDesc;
PangoContext *mPangoCtx;
@ -93,13 +99,15 @@ protected:
XftFont *mXftFont;
cairo_scaled_font_t *mCairoFont;
PRBool mHasMetrics;
Metrics mMetrics;
PRBool mHasMetrics;
PRUint32 mSpaceGlyph;
Metrics mMetrics;
gfxFloat mAdjustedSize;
void RealizeFont(PRBool force = PR_FALSE);
void RealizeXftFont(PRBool force = PR_FALSE);
void GetSize(const char *aString, PRUint32 aLength, gfxSize& inkSize, gfxSize& logSize);
void GetSize(char aChar, gfxSize& inkSize, gfxSize& logSize,
PRUint32 *aGlyphID = nsnull);
virtual void SetupCairoFont(cairo_t *aCR);
};
@ -116,9 +124,9 @@ public:
// Create and initialize a textrun using Pango (or Xft)
virtual gfxTextRun *MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
Parameters *aParams);
const Parameters *aParams, PRUint32 aFlags);
virtual gfxTextRun *MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
Parameters *aParams);
const Parameters *aParams, PRUint32 aFlags);
gfxPangoFont *GetFontAt(PRInt32 i) {
return NS_STATIC_CAST(gfxPangoFont*,

View File

@ -91,6 +91,8 @@ protected:
FontGroupAndStringT(gfxFontGroup *fg, const GenericString* str)
: mFontGroup(fg), mString(str) { }
typedef typename RealString::char_type char_type;
FontGroupAndStringT(const FontGroupAndStringT<GenericString,RealString>& other)
: mFontGroup(other.mFontGroup), mString(&mRealString)
{
@ -101,6 +103,9 @@ protected:
mRealString.Assign(*mString);
mString = &mRealString;
}
const char_type *GetRealString() {
return mRealString.get();
}
nsRefPtr<gfxFontGroup> mFontGroup;
RealString mRealString;

View File

@ -424,14 +424,20 @@ public:
gfxContext *aContext, PRBool aDrawToPath, gfxPoint *aBaselineOrigin,
Spacing *aSpacing);
virtual PRUint32 GetSpaceGlyph() {
ComputeMetrics();
return mSpaceGlyph;
};
protected:
HFONT MakeHFONT();
cairo_font_face_t *MakeCairoFontFace();
cairo_scaled_font_t *MakeCairoScaledFont();
void FillLogFont(gfxFloat aSize, PRInt16 aWeight);
HFONT mFont;
HFONT mFont;
gfxFloat mAdjustedSize;
PRUint32 mSpaceGlyph;
private:
void Destroy();
@ -466,9 +472,9 @@ public:
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
Parameters* aParams);
const Parameters* aParams, PRUint32 aFlags);
virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams);
const Parameters* aParams, PRUint32 aFlags);
const nsACString& GetGenericFamily() const {
return mGenericFamily;

View File

@ -182,11 +182,12 @@ gfxAtsuiFont::InitMetrics(ATSUFontID aFontID, ATSFontRef aFontRef)
mMetrics.maxAdvance = atsMetrics.maxAdvanceWidth * size;
float xWidth = GetCharWidth('x');
if (atsMetrics.avgAdvanceWidth != 0.0)
mMetrics.aveCharWidth =
PR_MIN(atsMetrics.avgAdvanceWidth * size, GetCharWidth('x'));
PR_MIN(atsMetrics.avgAdvanceWidth * size, xWidth);
else
mMetrics.aveCharWidth = GetCharWidth('x');
mMetrics.aveCharWidth = xWidth;
mMetrics.underlineOffset = atsMetrics.underlinePosition * size;
// ATSUI sometimes returns 0 for underline thickness, see bug 361576.
@ -198,7 +199,9 @@ gfxAtsuiFont::InitMetrics(ATSUFontID aFontID, ATSFontRef aFontRef)
mMetrics.strikeoutOffset = mMetrics.xHeight / 2.0;
mMetrics.strikeoutSize = mMetrics.underlineSize;
mMetrics.spaceWidth = GetCharWidth(' ');
PRUint32 glyphID;
mMetrics.spaceWidth = GetCharWidth(' ', &glyphID);
mSpaceGlyph = glyphID;
#if 0
fprintf (stderr, "Font: %p size: %f", this, size);
@ -217,7 +220,7 @@ gfxAtsuiFont::GetUniqueName()
}
float
gfxAtsuiFont::GetCharWidth(PRUnichar c)
gfxAtsuiFont::GetCharWidth(PRUnichar c, PRUint32 *aGlyphID)
{
// this sucks. There is a faster way to go from a char -> glyphs, but it
// requires using oodles of apple private interfaces. If we start caching
@ -236,6 +239,13 @@ gfxAtsuiFont::GetCharWidth(PRUnichar c)
FixedToFloat(PR_MAX(trap.upperRight.x, trap.lowerRight.x)) -
FixedToFloat(PR_MIN(trap.upperLeft.x, trap.lowerLeft.x));
if (aGlyphID) {
ATSUGlyphInfoArray glyphInfo;
ByteCount bytes = sizeof(glyphInfo);
ATSUGetGlyphInfo(layout, 0, 1, &bytes, &glyphInfo);
*aGlyphID = glyphInfo.glyphs[0].glyphID;
}
ATSUDisposeTextLayout(layout);
return f;
@ -412,25 +422,19 @@ SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString)
UCDisposeTextBreakLocator(&locator);
}
gfxTextRun *
void
gfxAtsuiFontGroup::MakeTextRunInternal(const PRUnichar *aString, PRUint32 aLength,
PRBool aWrapped, Parameters *aParams)
PRBool aWrapped, gfxTextRun *aTextRun)
{
// NS_ASSERTION(!(aParams->mFlags & TEXT_NEED_BOUNDING_BOX),
// "Glyph extents not yet supported");
gfxTextRun *textRun = new gfxTextRun(aParams, aLength - (aWrapped ? 3 : 0));
if (!textRun)
return nsnull;
const PRUnichar *realString = aString + (aWrapped ? 1 : 0);
textRun->RecordSurrogates(realString);
if (!(aParams->mFlags & TEXT_IS_8BIT)) {
SetupClusterBoundaries(textRun, realString);
aTextRun->RecordSurrogates(realString);
if (!(aTextRun->GetFlags() & TEXT_IS_8BIT)) {
SetupClusterBoundaries(aTextRun, realString);
}
InitTextRun(textRun, aString, aLength, aWrapped);
return textRun;
InitTextRun(aTextRun, aString, aLength, aWrapped);
}
#define UNICODE_LRO 0x202d
@ -446,36 +450,46 @@ AppendDirectionalIndicator(PRUint32 aFlags, nsAString& aString)
gfxTextRun *
gfxAtsuiFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
Parameters *aParams)
const Parameters *aParams, PRUint32 aFlags)
{
gfxTextRun *textRun = new gfxTextRun(aParams, aString, aLength, this, aFlags);
if (!textRun)
return nsnull;
nsAutoString utf16;
AppendDirectionalIndicator(aParams->mFlags, utf16);
AppendDirectionalIndicator(aFlags, utf16);
utf16.Append(aString, aLength);
// Ensure that none of the whitespace in the run is considered "trailing"
// by ATSUI's bidi algorithm
utf16.Append('.');
utf16.Append(UNICODE_PDF);
return MakeTextRunInternal(utf16.get(), utf16.Length(), PR_TRUE, aParams);
MakeTextRunInternal(utf16.get(), utf16.Length(), PR_TRUE, textRun);
return textRun;
}
gfxTextRun *
gfxAtsuiFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
Parameters *aParams)
const Parameters *aParams, PRUint32 aFlags)
{
aParams->mFlags |= TEXT_IS_8BIT;
NS_ASSERTION(aFlags & TEXT_IS_8BIT, "should be marked 8bit");
gfxTextRun *textRun = new gfxTextRun(aParams, aString, aLength, this, aFlags);
if (!textRun)
return nsnull;
nsDependentCSubstring cString(reinterpret_cast<const char*>(aString),
reinterpret_cast<const char*>(aString + aLength));
nsAutoString utf16;
PRBool wrapBidi = (aParams->mFlags & TEXT_IS_RTL) != 0;
PRBool wrapBidi = (aFlags & TEXT_IS_RTL) != 0;
if (wrapBidi) {
AppendDirectionalIndicator(aParams->mFlags, utf16);
AppendDirectionalIndicator(aFlags, utf16);
}
AppendASCIItoUTF16(cString, utf16);
if (wrapBidi) {
utf16.Append('.');
utf16.Append(UNICODE_PDF);
}
return MakeTextRunInternal(utf16.get(), utf16.Length(), wrapBidi, aParams);
MakeTextRunInternal(utf16.get(), utf16.Length(), wrapBidi, textRun);
return textRun;
}
gfxAtsuiFont*

View File

@ -48,6 +48,7 @@
#include "gfxTypes.h"
#include "gfxContext.h"
#include "gfxFontMissingGlyphs.h"
#include "nsMathUtils.h"
#include "cairo.h"
#include "gfxFontTest.h"
@ -518,61 +519,37 @@ gfxFontGroup::FindGenericFontFromStyle(FontCreationCallback fc,
}
gfxTextRun *
gfxFontGroup::GetSpecialStringTextRun(SpecialString aString,
gfxTextRun *aTemplate)
gfxFontGroup::MakeEmptyTextRun(const Parameters *aParams, PRUint32 aFlags)
{
NS_ASSERTION(aString <= gfxFontGroup::STRING_MAX,
"Bad special string index");
aFlags |= TEXT_IS_8BIT | TEXT_IS_ASCII | TEXT_IS_PERSISTENT;
return new gfxTextRun(aParams, nsnull, 0, this, aFlags);
}
if (mSpecialStrings[aString] &&
mSpecialStrings[aString]->GetAppUnitsPerDevUnit() ==
aTemplate->GetAppUnitsPerDevUnit())
return mSpecialStrings[aString];
static const PRUnichar unicodeHyphen = 0x2010;
static const PRUnichar unicodeEllipsis = 0x2026;
gfxTextRun *
gfxFontGroup::MakeSpaceTextRun(const Parameters *aParams, PRUint32 aFlags)
{
aFlags |= TEXT_IS_8BIT | TEXT_IS_ASCII | TEXT_IS_PERSISTENT;
static const PRUint8 space = ' ';
gfxTextRunFactory::Parameters params = {
nsnull, nsnull, nsnull, nsnull, nsnull, 0,
aTemplate->GetAppUnitsPerDevUnit(), TEXT_IS_PERSISTENT
};
gfxTextRun* textRun;
gfxFont *font = GetFontAt(0);
PRUint32 spaceGlyph = font->GetSpaceGlyph();
float spaceWidth = font->GetMetrics().spaceWidth;
PRUint32 spaceWidthAppUnits = NS_lroundf(spaceWidth*aParams->mAppUnitsPerDevUnit);
if (!spaceGlyph ||
!gfxTextRun::CompressedGlyph::IsSimpleGlyphID(spaceGlyph) ||
!gfxTextRun::CompressedGlyph::IsSimpleAdvance(spaceWidthAppUnits))
return MakeTextRun(&space, 1, aParams, aFlags);
switch (aString) {
case STRING_HYPHEN:
textRun = MakeTextRun(&unicodeHyphen, 1, &params);
break;
case STRING_ELLIPSIS:
textRun = MakeTextRun(&unicodeEllipsis, 1, &params);
break;
default:
case STRING_SPACE:
textRun = MakeTextRun(&space, 1, &params);
break;
}
nsAutoPtr<gfxTextRun> textRun;
textRun = new gfxTextRun(aParams, &space, 1, this, aFlags);
if (!textRun)
return nsnull;
if (textRun->CountMissingGlyphs() > 0) {
static const PRUint8 ASCIIEllipsis[] = {'.', '.', '.'};
static const PRUint8 ASCIIHyphen = '-';
switch (aString) {
case STRING_ELLIPSIS:
textRun = MakeTextRun(ASCIIEllipsis, NS_ARRAY_LENGTH(ASCIIEllipsis), &params);
break;
case STRING_HYPHEN:
textRun = MakeTextRun(&ASCIIHyphen, 1, &params);
break;
default:
NS_WARNING("This font doesn't support the space character? That's messed up");
break;
}
}
mSpecialStrings[aString] = textRun;
return textRun;
if (NS_FAILED(textRun->AddGlyphRun(font, 0)))
return nsnull;
gfxTextRun::CompressedGlyph g;
g.SetSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
textRun->SetCharacterGlyph(0, g);
return textRun.forget();
}
gfxFontStyle::gfxFontStyle(PRUint8 aStyle, PRUint8 aVariant,
@ -637,20 +614,84 @@ gfxTextRun::GlyphRunIterator::NextRun() {
return PR_TRUE;
}
gfxTextRun::gfxTextRun(gfxTextRunFactory::Parameters *aParams,
PRUint32 aLength)
gfxTextRun::gfxTextRun(const gfxTextRunFactory::Parameters *aParams, const void *aText,
PRUint32 aLength, gfxFontGroup *aFontGroup, PRUint32 aFlags)
: mUserData(aParams->mUserData),
mFontGroup(aFontGroup),
mAppUnitsPerDevUnit(aParams->mAppUnitsPerDevUnit),
mFlags(aParams->mFlags),
mCharacterCount(aLength)
mFlags(aFlags), mCharacterCount(aLength)
{
NS_ADDREF(mFontGroup);
if (aParams->mSkipChars) {
mSkipChars.TakeFrom(aParams->mSkipChars);
}
mCharacterGlyphs = new CompressedGlyph[aLength];
if (mCharacterGlyphs) {
memset(mCharacterGlyphs, 0, sizeof(CompressedGlyph)*aLength);
if (aLength > 0) {
mCharacterGlyphs = new CompressedGlyph[aLength];
if (mCharacterGlyphs) {
memset(mCharacterGlyphs, 0, sizeof(CompressedGlyph)*aLength);
}
}
if (mFlags & gfxTextRunFactory::TEXT_IS_8BIT) {
mText.mSingle = NS_STATIC_CAST(const PRUint8 *, aText);
} else {
mText.mDouble = NS_STATIC_CAST(const PRUnichar *, aText);
}
}
gfxTextRun::~gfxTextRun()
{
if (!(mFlags & gfxTextRunFactory::TEXT_IS_PERSISTENT)) {
if (mFlags & gfxTextRunFactory::TEXT_IS_8BIT) {
delete[] mText.mSingle;
} else {
delete[] mText.mDouble;
}
}
NS_RELEASE(mFontGroup);
}
gfxTextRun *
gfxTextRun::Clone(const gfxTextRunFactory::Parameters *aParams, const void *aText,
PRUint32 aLength, gfxFontGroup *aFontGroup, PRUint32 aFlags)
{
if (!mCharacterGlyphs)
return nsnull;
nsAutoPtr<gfxTextRun> textRun;
textRun = new gfxTextRun(aParams, aText, aLength, aFontGroup, aFlags);
if (!textRun || !textRun->mCharacterGlyphs)
return nsnull;
PRUint32 i;
for (i = 0; i < mGlyphRuns.Length(); ++i) {
if (NS_FAILED(textRun->AddGlyphRun(mGlyphRuns[i].mFont,
mGlyphRuns[i].mCharacterOffset)))
return nsnull;
}
for (i = 0; i < aLength; ++i) {
CompressedGlyph g = mCharacterGlyphs[i];
g.SetCanBreakBefore(PR_FALSE);
textRun->mCharacterGlyphs[i] = g;
}
if (mDetailedGlyphs) {
for (i = 0; i < aLength; ++i) {
DetailedGlyph *details = mDetailedGlyphs[i];
if (details) {
PRUint32 glyphCount = 1;
while (!details[glyphCount - 1].mIsLastGlyph) {
++glyphCount;
}
DetailedGlyph *dest = textRun->AllocateDetailedGlyphs(i, glyphCount);
if (!dest)
return nsnull;
memcpy(dest, details, sizeof(DetailedGlyph)*glyphCount);
}
}
}
return textRun.forget();
}
PRBool
@ -1368,7 +1409,6 @@ gfxTextRun::GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PRBool
gfxTextRun::SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
PropertyProvider *aProvider,
gfxFloat *aAdvanceWidthDelta)
{
// Do nothing because our shaping does not currently take linebreaks into

View File

@ -94,6 +94,8 @@
#define FLOAT_PANGO_SCALE ((gfxFloat)PANGO_SCALE)
#define IS_MISSING_GLYPH(g) (((g) & 0x10000000) || (g) == 0x0FFFFFFF)
static PangoLanguage *GetPangoLanguage(const nsACString& aLangGroup);
static void GetMozLanguage(const PangoLanguage *aLang, nsACString &aMozLang);
@ -396,7 +398,7 @@ gfxPangoFont::RealizeFont(PRBool force)
return;
gfxSize isz, lsz;
GetSize("x", 1, isz, lsz);
GetSize('x', isz, lsz);
gfxFloat aspect = isz.height / GetStyle()->size;
mAdjustedSize =
PR_MAX(NS_round(GetStyle()->size*(GetStyle()->sizeAdjust/aspect)), 1.0);
@ -419,12 +421,13 @@ gfxPangoFont::RealizeXftFont(PRBool force)
}
void
gfxPangoFont::GetSize(const char *aCharString, PRUint32 aLength, gfxSize& inkSize, gfxSize& logSize)
gfxPangoFont::GetSize(char aChar, gfxSize& inkSize, gfxSize& logSize,
PRUint32 *aGlyphID)
{
RealizeFont();
PangoAttrList *al = pango_attr_list_new();
GList *items = pango_itemize(mPangoCtx, aCharString, 0, aLength, al, NULL);
GList *items = pango_itemize(mPangoCtx, &aChar, 0, 1, al, NULL);
pango_attr_list_unref(al);
if (!items || g_list_length(items) != 1)
@ -433,7 +436,17 @@ gfxPangoFont::GetSize(const char *aCharString, PRUint32 aLength, gfxSize& inkSiz
PangoItem *item = (PangoItem*) items->data;
PangoGlyphString *glstr = pango_glyph_string_new();
pango_shape (aCharString, aLength, &(item->analysis), glstr);
pango_shape (&aChar, 1, &(item->analysis), glstr);
if (aGlyphID) {
*aGlyphID = 0;
if (glstr->num_glyphs == 1) {
PangoGlyph glyph = glstr->glyphs[0].glyph;
if (!IS_MISSING_GLYPH(glyph)) {
*aGlyphID = glyph;
}
}
}
PangoRectangle ink_rect, log_rect;
pango_glyph_string_extents (glstr, item->analysis.font, &ink_rect, &log_rect);
@ -464,6 +477,7 @@ gfxPangoFont::GetMetrics()
return mMetrics;
RealizeFont();
mSpaceGlyph = 0; // in case we error out below
PangoAttrList *al = pango_attr_list_new();
GList *items = pango_itemize(mPangoCtx, "a", 0, 1, al, NULL);
@ -508,12 +522,12 @@ gfxPangoFont::GetMetrics()
mMetrics.maxAdvance = xftFont->max_advance_width;
gfxSize isz, lsz;
GetSize(" ", 1, isz, lsz);
GetSize(' ', isz, lsz, &mSpaceGlyph);
mMetrics.spaceWidth = lsz.width;
// XXX do some FcCharSetHasChar work here to make sure
// we have an "x"
GetSize("x", 1, isz, lsz);
GetSize('x', isz, lsz);
mMetrics.xHeight = isz.height;
mMetrics.aveCharWidth = isz.width;
@ -585,9 +599,9 @@ gfxPangoFont::GetMetrics()
mMetrics.maxAdvance = pango_font_metrics_get_approximate_char_width(pfm) / FLOAT_PANGO_SCALE; // XXX
gfxSize isz, lsz;
GetSize(" ", 1, isz, lsz);
GetSize(' ', isz, lsz, &mSpaceGlyph);
mMetrics.spaceWidth = lsz.width;
GetSize("x", 1, isz, lsz);
GetSize('x', isz, lsz);
mMetrics.xHeight = isz.height;
mMetrics.aveCharWidth = pango_font_metrics_get_approximate_char_width(pfm) / FLOAT_PANGO_SCALE;
@ -709,15 +723,15 @@ static PRInt32 AppendDirectionalIndicatorUTF8(PRBool aIsRTL, nsACString& aString
gfxTextRun *
gfxPangoFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
Parameters *aParams)
const Parameters *aParams, PRUint32 aFlags)
{
aParams->mFlags |= TEXT_IS_8BIT;
gfxTextRun *run = new gfxTextRun(aParams, aLength);
NS_ASSERTION(aFlags & TEXT_IS_8BIT, "8bit should have been set");
gfxTextRun *run = new gfxTextRun(aParams, aString, aLength, this, aFlags);
if (!run)
return nsnull;
PRBool isRTL = run->IsRightToLeft();
if ((aParams->mFlags & TEXT_IS_ASCII) && !isRTL) {
if ((aFlags & TEXT_IS_ASCII) && !isRTL) {
// We don't need to send an override character here, the characters must be all
// LTR
const gchar *utf8Chars = NS_REINTERPRET_CAST(const gchar*, aString);
@ -739,9 +753,9 @@ gfxPangoFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
gfxTextRun *
gfxPangoFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
Parameters *aParams)
const Parameters *aParams, PRUint32 aFlags)
{
gfxTextRun *run = new gfxTextRun(aParams, aLength);
gfxTextRun *run = new gfxTextRun(aParams, aString, aLength, this, aFlags);
if (!run)
return nsnull;
@ -891,8 +905,6 @@ gfxPangoFont::Measure(gfxTextRun *aTextRun,
return GetPangoMetrics(&glyphs, GetPangoFont(), aTextRun->GetAppUnitsPerDevUnit(), clusterCount);
}
#define IS_MISSING_GLYPH(g) (((g) & 0x10000000) || (g) == 0x0FFFFFFF)
static cairo_scaled_font_t*
CreateScaledFont(cairo_t *aCR, cairo_matrix_t *aCTM, PangoFont *aPangoFont)
{

View File

@ -133,22 +133,17 @@ gfxTextRunCache::GetOrMakeTextRun(gfxContext *aContext, gfxFontGroup *aFontGroup
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)
aContext, nsnull, nsnull, nsnull, 0, aAppUnitsPerDevUnit
};
if (IsAscii(aString, aLength))
params.mFlags |= gfxTextRunFactory::TEXT_IS_ASCII;
// else if (Is8Bit(aString, aLength))
// params.mFlags |= gfxTextRunFactory::TEXT_IS_8BIT;
if (!(params.mFlags & gfxTextRunFactory::TEXT_IS_ASCII)) {
PRUint32 flags = ComputeFlags(aIsRTL, aEnableSpacing);
if (IsAscii(aString, aLength)) {
flags |= gfxTextRunFactory::TEXT_IS_ASCII;
} else {
for (PRUint32 i = 0; i < aLength; ++i) {
if (NS_IS_HIGH_SURROGATE(aString[i])) {
params.mFlags |= gfxTextRunFactory::TEXT_HAS_SURROGATES;
flags |= gfxTextRunFactory::TEXT_HAS_SURROGATES;
break;
}
}
@ -176,9 +171,12 @@ gfxTextRunCache::GetOrMakeTextRun(gfxContext *aContext, gfxFontGroup *aFontGroup
tr->SetContext(aContext);
}
} else {
tr = aFontGroup->MakeTextRun(aString, aLength, &params);
entry = new TextRunEntry(tr);
key.Realize();
// Text is persistent since it's in the key, which will live as
// long as this textrun.
tr = aFontGroup->MakeTextRun(key.GetRealString(), aLength, &params,
flags | gfxTextRunFactory::TEXT_IS_PERSISTENT);
entry = new TextRunEntry(tr);
mHashTableUTF16.Put(key, entry);
}
}
@ -188,11 +186,11 @@ gfxTextRunCache::GetOrMakeTextRun(gfxContext *aContext, gfxFontGroup *aFontGroup
} else {
// Textrun is not in the cache for some reason.
*aCallerOwns = PR_TRUE;
tr = aFontGroup->MakeTextRun(aString, aLength, &params);
}
if (tr) {
// We don't want to have to reconstruct the string
tr->RememberText(aString, aLength);
PRUnichar *newStr = new PRUnichar[aLength];
if (newStr) {
memcpy(newStr, aString, sizeof(PRUnichar)*aLength);
tr = aFontGroup->MakeTextRun(aString, aLength, &params, flags);
}
}
return tr;
@ -204,16 +202,13 @@ gfxTextRunCache::GetOrMakeTextRun(gfxContext *aContext, gfxFontGroup *aFontGroup
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)
aContext, nsnull, nsnull, nsnull, 0, aAppUnitsPerDevUnit
};
PRUint32 flags = ComputeFlags(aIsRTL, aEnableSpacing) | gfxTextRunFactory::TEXT_IS_8BIT;
if (IsAscii(aString, aLength))
params.mFlags |= gfxTextRunFactory::TEXT_IS_ASCII;
else
params.mFlags |= gfxTextRunFactory::TEXT_IS_8BIT;
flags |= gfxTextRunFactory::TEXT_IS_ASCII;
const PRUint8 *str = reinterpret_cast<const PRUint8*>(aString);
@ -239,9 +234,13 @@ gfxTextRunCache::GetOrMakeTextRun(gfxContext *aContext, gfxFontGroup *aFontGroup
tr->SetContext(aContext);
}
} else {
tr = aFontGroup->MakeTextRun(str, aLength, &params);
entry = new TextRunEntry(tr);
key.Realize();
// Text is persistent since it's in the key, which will live as
// long as this textrun.
tr = aFontGroup->MakeTextRun(reinterpret_cast<const PRUint8 *>(key.GetRealString()),
aLength, &params,
flags | gfxTextRunFactory::TEXT_IS_PERSISTENT);
entry = new TextRunEntry(tr);
mHashTableASCII.Put(key, entry);
}
}
@ -251,11 +250,11 @@ gfxTextRunCache::GetOrMakeTextRun(gfxContext *aContext, gfxFontGroup *aFontGroup
} else {
// Textrun is not in the cache for some reason.
*aCallerOwns = PR_TRUE;
tr = aFontGroup->MakeTextRun(str, aLength, &params);
}
if (tr) {
// We don't want to have to reconstruct the string
tr->RememberText(str, aLength);
PRUint8 *newStr = new PRUint8[aLength];
if (newStr) {
memcpy(newStr, str, aLength);
tr = aFontGroup->MakeTextRun(newStr, aLength, &params, flags);
}
}
return tr;

View File

@ -382,6 +382,16 @@ gfxWindowsFont::ComputeMetrics()
GetTextExtentPoint32(dc, " ", 1, &size);
mMetrics->spaceWidth = ROUND(size.cx);
mSpaceGlyph = 0;
if (metrics.tmPitchAndFamily & TMPF_TRUETYPE) {
WORD glyph;
DWORD ret = GetGlyphIndicesA(dc, " ", 1, &glyph,
GGI_MARK_NONEXISTING_GLYPHS);
if (ret != GDI_ERROR && glyph != 0xFFFF) {
mSpaceGlyph = glyph;
}
}
SelectObject(dc, oldFont);
ReleaseDC((HWND)nsnull, dc);
@ -551,13 +561,13 @@ gfxWindowsFontGroup::Copy(const gfxFontStyle *aStyle)
gfxTextRun *
gfxWindowsFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
Parameters *aParams)
const Parameters *aParams, PRUint32 aFlags)
{
// XXX comment out the assertion for now since it fires too much
// NS_ASSERTION(!(aParams->mFlags & TEXT_NEED_BOUNDING_BOX),
// "Glyph extents not yet supported");
gfxTextRun *textRun = new gfxTextRun(aParams, aLength);
gfxTextRun *textRun = new gfxTextRun(aParams, aString, aLength, this, aFlags);
if (!textRun)
return nsnull;
@ -579,10 +589,11 @@ gfxWindowsFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
gfxTextRun *
gfxWindowsFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
Parameters *aParams)
const Parameters *aParams, PRUint32 aFlags)
{
aParams->mFlags |= TEXT_IS_8BIT;
gfxTextRun *textRun = new gfxTextRun(aParams, aLength);
NS_ASSERTION(aFlags & TEXT_IS_8BIT, "should be marked 8bit");
gfxTextRun *textRun = new gfxTextRun(aParams, aString, aLength, this, aFlags);
if (!textRun)
return nsnull;

View File

@ -287,22 +287,22 @@ RunTest (TestEntry *test, gfxContext *ctx) {
nsAutoPtr<gfxTextRun> textRun;
gfxTextRunFactory::Parameters params = {
ctx, nsnull, nsnull, nsnull, nsnull, 0, 60,
gfxTextRunFactory::TEXT_IS_ASCII
ctx, nsnull, nsnull, nsnull, 0, 60
};
PRUint32 flags = gfxTextRunFactory::TEXT_IS_PERSISTENT;
if (test->isRTL) {
params.mFlags |= gfxTextRunFactory::TEXT_IS_RTL;
flags |= gfxTextRunFactory::TEXT_IS_RTL;
}
PRUint32 length;
if (test->stringType == S_ASCII) {
params.mFlags |= gfxTextRunFactory::TEXT_IS_ASCII;
flags |= gfxTextRunFactory::TEXT_IS_ASCII | gfxTextRunFactory::TEXT_IS_8BIT;
length = strlen(test->string);
textRun = fontGroup->MakeTextRun(NS_REINTERPRET_CAST(PRUint8*, test->string), length, &params);
textRun = fontGroup->MakeTextRun(NS_REINTERPRET_CAST(PRUint8*, test->string), length, &params, flags);
} else {
params.mFlags |= gfxTextRunFactory::TEXT_HAS_SURROGATES; // just in case
flags |= gfxTextRunFactory::TEXT_HAS_SURROGATES; // just in case
NS_ConvertUTF8toUTF16 str(nsDependentCString(test->string));
length = str.Length();
textRun = fontGroup->MakeTextRun(str.get(), length, &params);
textRun = fontGroup->MakeTextRun(str.get(), length, &params, flags);
}
gfxFontTestStore::NewStore();

View File

@ -110,19 +110,20 @@ RunTest (TestEntry *test, gfxContext *ctx) {
}
}
gfxTextRunFactory::Parameters params = {
ctx, nsnull, nsnull, nsnull, nsnull, 0, 60, 0
ctx, nsnull, nsnull, nsnull, 0, 60
};
PRUint32 flags = gfxTextRunFactory::TEXT_IS_PERSISTENT;
PRUint32 length;
if (isASCII) {
params.mFlags |= gfxTextRunFactory::TEXT_IS_ASCII |
gfxTextRunFactory::TEXT_IS_8BIT;
flags |= gfxTextRunFactory::TEXT_IS_ASCII |
gfxTextRunFactory::TEXT_IS_8BIT;
length = strlen(test->mString);
textRun = fontGroup->MakeTextRun(NS_REINTERPRET_CAST(const PRUint8*, test->mString), length, &params);
textRun = fontGroup->MakeTextRun(NS_REINTERPRET_CAST(const PRUint8*, test->mString), length, &params, flags);
} else {
params.mFlags |= gfxTextRunFactory::TEXT_HAS_SURROGATES; // just in case
flags |= gfxTextRunFactory::TEXT_HAS_SURROGATES; // just in case
NS_ConvertUTF8toUTF16 str(nsDependentCString(test->mString));
length = str.Length();
textRun = fontGroup->MakeTextRun(str.get(), length, &params);
textRun = fontGroup->MakeTextRun(str.get(), length, &params, flags);
}
// Should we test drawing?

View File

@ -1352,14 +1352,14 @@ nsSVGGlyphFrame::GetTextRun(gfxContext *aCtx, const nsString &aText)
gfxTextRunFactory::Parameters params =
{ aCtx, nsnull, nsnull,
nsnull, nsnull, nsnull,
1, // see note above
0 };
nsnull, nsnull,
1 // see note above
};
if (!mFontGroup)
return nsnull;
return mFontGroup->MakeTextRun(aText.get(), aText.Length(), &params);
return mFontGroup->MakeTextRun(aText.get(), aText.Length(), &params, 0);
}
//----------------------------------------------------------------------