--- a/gfx/thebes/public/gfxFont.h
+++ b/gfx/thebes/public/gfxFont.h
@@ -665,16 +665,18 @@ public:
*
* gfxTextRun methods that measure or draw substrings will associate all the
* glyphs in a cluster with the first character of the cluster; if that character
* is in the substring, the glyphs will be measured or drawn, otherwise they
* won't.
*/
class THEBES_API gfxTextRun {
public:
+ // Override operator delete because we used custom allocation
+ void operator delete(void* aPtr);
virtual ~gfxTextRun();
typedef gfxFont::RunMetrics Metrics;
// Public textrun API for general use
PRBool IsClusterStart(PRUint32 aPos) {
NS_ASSERTION(0 <= aPos && aPos < mCharacterCount, "aPos out of range");
@@ -942,22 +944,20 @@ public:
? static_cast<const void *>(mText.mSingle + aIndex)
: static_cast<const void *>(mText.mDouble + aIndex);
}
const PRUnichar GetChar(PRUint32 i) const
{ return (mFlags & gfxTextRunFactory::TEXT_IS_8BIT) ? mText.mSingle[i] : mText.mDouble[i]; }
PRUint32 GetHashCode() const { return mHashCode; }
void SetHashCode(PRUint32 aHash) { mHashCode = aHash; }
- // The caller is responsible for initializing our glyphs after construction.
- // Initially all glyphs are such that GetCharacterGlyphs()[i].IsMissing() is true.
- // If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
- // textrun will copy it.
- gfxTextRun(const gfxTextRunFactory::Parameters *aParams, const void *aText,
- PRUint32 aLength, gfxFontGroup *aFontGroup, PRUint32 aFlags);
+ // Call this, don't call "new gfxTextRun" directly. This does custom
+ // allocation and initialization
+ static gfxTextRun *Create(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 aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
// textrun will copy it.
virtual gfxTextRun *Clone(const gfxTextRunFactory::Parameters *aParams, const void *aText,
@@ -1246,16 +1246,30 @@ public:
PRPackedBool mPartIsEndOfLigature;
};
#ifdef DEBUG
// number of entries referencing this textrun in the gfxTextRunWordCache
PRUint32 mCachedWords;
#endif
+protected:
+ // Allocates extra space for the CompressedGlyph array and the text
+ // (if needed)
+ void *operator new(size_t aSize, PRUint32 aLength, PRUint32 aFlags);
+
+ /**
+ * Initializes the textrun to blank.
+ * @param aObjectSize the size of the object; this lets us fine
+ * where our CompressedGlyph array and string have been allocated
+ */
+ gfxTextRun(const gfxTextRunFactory::Parameters *aParams, const void *aText,
+ PRUint32 aLength, gfxFontGroup *aFontGroup, PRUint32 aFlags,
+ PRUint32 aObjectSize);
+
private:
// **** general helpers ****
// Allocate aCount DetailedGlyphs for the given index
DetailedGlyph *AllocateDetailedGlyphs(PRUint32 aCharIndex, PRUint32 aCount);
// Spacing for characters outside the range aSpacingStart/aSpacingEnd
// is assumed to be zero; such characters are not passed to aProvider.
@@ -1298,25 +1312,29 @@ private:
Metrics *aMetrics);
// **** drawing helper ****
void DrawGlyphs(gfxFont *aFont, gfxContext *aContext, PRBool aDrawToPath,
gfxPoint *aPt, PRUint32 aStart, PRUint32 aEnd,
PropertyProvider *aProvider,
PRUint32 aSpacingStart, PRUint32 aSpacingEnd);
- // All our glyph data is in logical order, not visual
- nsAutoArrayPtr<CompressedGlyph> mCharacterGlyphs;
+ // All our glyph data is in logical order, not visual.
+ // mCharacterGlyphs is allocated fused with this object. We need a pointer
+ // to it because gfxTextRun subclasses exist with extra fields, so we don't
+ // know where it starts without a virtual method call or an explicit pointer.
+ 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;
// 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.
+ // own the text. When we own the text, it's allocated fused with this
+ // object, so it need not be deleted.
// This text is not null-terminated.
union {
const PRUint8 *mSingle;
const PRUnichar *mDouble;
} mText;
void *mUserData;
gfxFontGroup *mFontGroup; // addrefed
gfxSkipChars mSkipChars;
--- a/gfx/thebes/src/gfxAtsuiFonts.cpp
+++ b/gfx/thebes/src/gfxAtsuiFonts.cpp
@@ -575,17 +575,17 @@ gfxAtsuiFontGroup::GuessMaximumStringLen
* If the font size is incredibly huge and/or clusters are very large, this
* could mean that we actually put more than 'maxLen' characters in a chunk.
*/
gfxTextRun *
gfxAtsuiFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
const Parameters *aParams, PRUint32 aFlags)
{
- gfxTextRun *textRun = new gfxTextRun(aParams, aString, aLength, this, aFlags);
+ gfxTextRun *textRun = gfxTextRun::Create(aParams, aString, aLength, this, aFlags);
if (!textRun)
return nsnull;
textRun->RecordSurrogates(aString);
SetupClusterBoundaries(textRun, aString);
PRUint32 maxLen;
nsAutoString utf16;
@@ -616,17 +616,17 @@ gfxAtsuiFontGroup::MakeTextRun(const PRU
return textRun;
}
gfxTextRun *
gfxAtsuiFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
const Parameters *aParams, PRUint32 aFlags)
{
NS_ASSERTION(aFlags & TEXT_IS_8BIT, "should be marked 8bit");
- gfxTextRun *textRun = new gfxTextRun(aParams, aString, aLength, this, aFlags);
+ gfxTextRun *textRun = gfxTextRun::Create(aParams, aString, aLength, this, aFlags);
if (!textRun)
return nsnull;
PRUint32 maxLen;
nsAutoString utf16;
for (maxLen = GuessMaximumStringLength(); maxLen > 0; maxLen /= 2) {
PRUint32 start = 0;
while (start < aLength) {
--- a/gfx/thebes/src/gfxFont.cpp
+++ b/gfx/thebes/src/gfxFont.cpp
@@ -822,28 +822,28 @@ gfxFontGroup::FindGenericFontFromStyle(F
}
}
}
gfxTextRun *
gfxFontGroup::MakeEmptyTextRun(const Parameters *aParams, PRUint32 aFlags)
{
aFlags |= TEXT_IS_8BIT | TEXT_IS_ASCII | TEXT_IS_PERSISTENT;
- return new gfxTextRun(aParams, nsnull, 0, this, aFlags);
+ return gfxTextRun::Create(aParams, nsnull, 0, this, aFlags);
}
gfxTextRun *
gfxFontGroup::MakeSpaceTextRun(const Parameters *aParams, PRUint32 aFlags)
{
aFlags |= TEXT_IS_8BIT | TEXT_IS_ASCII | TEXT_IS_PERSISTENT;
static const PRUint8 space = ' ';
nsAutoPtr<gfxTextRun> textRun;
- textRun = new gfxTextRun(aParams, &space, 1, this, aFlags);
- if (!textRun || !textRun->GetCharacterGlyphs())
+ textRun = gfxTextRun::Create(aParams, &space, 1, this, aFlags);
+ if (!textRun)
return nsnull;
gfxFont *font = GetFontAt(0);
textRun->SetSpaceGlyph(font, aParams->mContext, 0);
// Note that the gfxGlyphExtents glyph bounds storage for the font will
// always contain an entry for the font's space glyph, so we don't have
// to call FetchGlyphExtents here.
return textRun.forget();
@@ -933,91 +933,100 @@ AccountStorageForTextRun(gfxTextRun *aTe
bytesPerChar += (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) ? 1 : 2;
}
PRInt32 bytes = sizeof(gfxTextRun) + aTextRun->GetLength()*bytesPerChar;
gTextRunStorage += bytes*aSign;
gTextRunStorageHighWaterMark = PR_MAX(gTextRunStorageHighWaterMark, gTextRunStorage);
}
#endif
+gfxTextRun *
+gfxTextRun::Create(const gfxTextRunFactory::Parameters *aParams, const void *aText,
+ PRUint32 aLength, gfxFontGroup *aFontGroup, PRUint32 aFlags)
+{
+ return new (aLength, aFlags)
+ gfxTextRun(aParams, aText, aLength, aFontGroup, aFlags, sizeof(gfxTextRun));
+}
+
+void *
+gfxTextRun::operator new(size_t aSize, PRUint32 aLength, PRUint32 aFlags)
+{
+ NS_ASSERTION(aSize % sizeof(CompressedGlyph) == 0, "Alignment broken!");
+ aSize += sizeof(CompressedGlyph)*aLength;
+ if (!(aFlags & gfxTextRunFactory::TEXT_IS_PERSISTENT)) {
+ NS_ASSERTION(aSize % 2 == 0, "Alignment broken!");
+ aSize += ((aFlags & gfxTextRunFactory::TEXT_IS_8BIT) ? 1 : 2)*aLength;
+ }
+
+ return new PRUint8[aSize];
+}
+
+void gfxTextRun::operator delete(void *p)
+{
+ delete[] static_cast<PRUint8*>(p);
+}
+
gfxTextRun::gfxTextRun(const gfxTextRunFactory::Parameters *aParams, const void *aText,
- PRUint32 aLength, gfxFontGroup *aFontGroup, PRUint32 aFlags)
+ PRUint32 aLength, gfxFontGroup *aFontGroup, PRUint32 aFlags,
+ PRUint32 aObjectSize)
: mUserData(aParams->mUserData),
mFontGroup(aFontGroup),
mAppUnitsPerDevUnit(aParams->mAppUnitsPerDevUnit),
mFlags(aFlags), mCharacterCount(aLength), mHashCode(0)
{
NS_ASSERTION(mAppUnitsPerDevUnit != 0, "Invalid app unit scale");
MOZ_COUNT_CTOR(gfxTextRun);
NS_ADDREF(mFontGroup);
if (aParams->mSkipChars) {
mSkipChars.TakeFrom(aParams->mSkipChars);
}
- if (aLength > 0) {
- mCharacterGlyphs = new CompressedGlyph[aLength];
- if (mCharacterGlyphs) {
- memset(mCharacterGlyphs, 0, sizeof(CompressedGlyph)*aLength);
- }
- }
+
+ mCharacterGlyphs = reinterpret_cast<CompressedGlyph*>
+ (reinterpret_cast<PRUint8*>(this) + aObjectSize);
+ memset(mCharacterGlyphs, 0, sizeof(CompressedGlyph)*aLength);
+
if (mFlags & gfxTextRunFactory::TEXT_IS_8BIT) {
mText.mSingle = static_cast<const PRUint8 *>(aText);
if (!(mFlags & gfxTextRunFactory::TEXT_IS_PERSISTENT)) {
- PRUint8 *newText = new PRUint8[aLength];
- if (!newText) {
- // indicate textrun failure
- mCharacterGlyphs = nsnull;
- } else {
- memcpy(newText, aText, aLength);
- }
+ PRUint8 *newText = reinterpret_cast<PRUint8*>(mCharacterGlyphs + aLength);
+ memcpy(newText, aText, aLength);
mText.mSingle = newText;
}
} else {
mText.mDouble = static_cast<const PRUnichar *>(aText);
if (!(mFlags & gfxTextRunFactory::TEXT_IS_PERSISTENT)) {
- PRUnichar *newText = new PRUnichar[aLength];
- if (!newText) {
- // indicate textrun failure
- mCharacterGlyphs = nsnull;
- } else {
- memcpy(newText, aText, aLength*sizeof(PRUnichar));
- }
+ PRUnichar *newText = reinterpret_cast<PRUnichar*>(mCharacterGlyphs + aLength);
+ memcpy(newText, aText, aLength*sizeof(PRUnichar));
mText.mDouble = newText;
}
}
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
AccountStorageForTextRun(this, 1);
#endif
}
gfxTextRun::~gfxTextRun()
{
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
AccountStorageForTextRun(this, -1);
#endif
- if (!(mFlags & gfxTextRunFactory::TEXT_IS_PERSISTENT)) {
- if (mFlags & gfxTextRunFactory::TEXT_IS_8BIT) {
- delete[] mText.mSingle;
- } else {
- delete[] mText.mDouble;
- }
- }
NS_RELEASE(mFontGroup);
MOZ_COUNT_DTOR(gfxTextRun);
}
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)
+ textRun = gfxTextRun::Create(aParams, aText, aLength, aFontGroup, aFlags);
+ if (!textRun)
return nsnull;
textRun->CopyGlyphDataFrom(this, 0, mCharacterCount, 0, PR_FALSE);
return textRun.forget();
}
PRBool
gfxTextRun::SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
--- a/gfx/thebes/src/gfxTextRunWordCache.cpp
+++ b/gfx/thebes/src/gfxTextRunWordCache.cpp
@@ -364,17 +364,17 @@ TextRunWordCache::FinishTextRun(gfxTextR
static gfxTextRun *
MakeBlankTextRun(const void* aText, PRUint32 aLength,
gfxFontGroup *aFontGroup,
const gfxFontGroup::Parameters *aParams,
PRUint32 aFlags)
{
nsAutoPtr<gfxTextRun> textRun;
- textRun = new gfxTextRun(aParams, aText, aLength, aFontGroup, aFlags);
+ textRun = gfxTextRun::Create(aParams, aText, aLength, aFontGroup, aFlags);
if (!textRun || !textRun->GetCharacterGlyphs())
return nsnull;
gfxFont *font = aFontGroup->GetFontAt(0);
textRun->AddGlyphRun(font, 0);
return textRun.forget();
}
gfxTextRun *
@@ -386,17 +386,17 @@ TextRunWordCache::MakeTextRun(const PRUn
if (aFontGroup->GetStyle()->size == 0) {
// Short-circuit for size-0 fonts, as Windows and ATSUI can't handle
// them, and always create at least size 1 fonts, i.e. they still
// render something for size 0 fonts.
return MakeBlankTextRun(aText, aLength, aFontGroup, aParams, aFlags);
}
nsAutoPtr<gfxTextRun> textRun;
- textRun = new gfxTextRun(aParams, aText, aLength, aFontGroup, aFlags);
+ textRun = gfxTextRun::Create(aParams, aText, aLength, aFontGroup, aFlags);
if (!textRun || !textRun->GetCharacterGlyphs())
return nsnull;
#ifdef DEBUG
textRun->mCachedWords = 0;
#endif
gfxFont *font = aFontGroup->GetFontAt(0);
nsresult rv = textRun->AddGlyphRun(font, 0);
@@ -469,17 +469,17 @@ TextRunWordCache::MakeTextRun(const PRUi
// Short-circuit for size-0 fonts, as Windows and ATSUI can't handle
// them, and always create at least size 1 fonts, i.e. they still
// render something for size 0 fonts.
return MakeBlankTextRun(aText, aLength, aFontGroup, aParams, aFlags);
}
aFlags |= gfxTextRunFactory::TEXT_IS_8BIT;
nsAutoPtr<gfxTextRun> textRun;
- textRun = new gfxTextRun(aParams, aText, aLength, aFontGroup, aFlags);
+ textRun = gfxTextRun::Create(aParams, aText, aLength, aFontGroup, aFlags);
if (!textRun || !textRun->GetCharacterGlyphs())
return nsnull;
#ifdef DEBUG
textRun->mCachedWords = 0;
#endif
gfxFont *font = aFontGroup->GetFontAt(0);
nsresult rv = textRun->AddGlyphRun(font, 0);
--- a/layout/generic/nsTextRunTransformations.cpp
+++ b/layout/generic/nsTextRunTransformations.cpp
@@ -43,16 +43,29 @@
#include "nsICaseConversion.h"
#include "nsStyleConsts.h"
#include "nsStyleContext.h"
#include "gfxContext.h"
#include "nsContentUtils.h"
#define SZLIG 0x00DF
+nsTransformedTextRun *
+nsTransformedTextRun::Create(const gfxTextRunFactory::Parameters* aParams,
+ nsTransformingTextRunFactory* aFactory,
+ gfxFontGroup* aFontGroup,
+ const PRUnichar* aString, PRUint32 aLength,
+ const PRUint32 aFlags, nsStyleContext** aStyles,
+ PRBool aOwnsFactory)
+{
+ return new (aLength, aFlags)
+ nsTransformedTextRun(aParams, aFactory, aFontGroup, aString, aLength,
+ aFlags, aStyles, aOwnsFactory);
+}
+
void
nsTransformedTextRun::SetCapitalization(PRUint32 aStart, PRUint32 aLength,
PRPackedBool* aCapitalization,
gfxContext* aRefContext)
{
if (mCapitalize.IsEmpty()) {
if (!mCapitalize.AppendElements(GetLength()))
return;
@@ -127,18 +140,18 @@ nsTransformedTextRun::SetLineBreaks(PRUi
gfxTextRun*
nsTransformingTextRunFactory::MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
const gfxTextRunFactory::Parameters* aParams,
gfxFontGroup* aFontGroup, PRUint32 aFlags,
nsStyleContext** aStyles, PRBool aOwnsFactory)
{
nsTransformedTextRun* textRun =
- new nsTransformedTextRun(aParams, this, aFontGroup,
- aString, aLength, aFlags, aStyles, aOwnsFactory);
+ nsTransformedTextRun::Create(aParams, this, aFontGroup,
+ aString, aLength, aFlags, aStyles, aOwnsFactory);
if (!textRun)
return nsnull;
RebuildTextRun(textRun, aParams->mContext);
return textRun;
}
gfxTextRun*
--- a/layout/generic/nsTextRunTransformations.h
+++ b/layout/generic/nsTextRunTransformations.h
@@ -95,34 +95,23 @@ protected:
};
/**
* So that we can reshape as necessary, we store enough information
* to fully rebuild the textrun contents.
*/
class nsTransformedTextRun : public gfxTextRun {
public:
- nsTransformedTextRun(const gfxTextRunFactory::Parameters* aParams,
- nsTransformingTextRunFactory* aFactory,
- gfxFontGroup* aFontGroup,
- const PRUnichar* aString, PRUint32 aLength,
- const PRUint32 aFlags, nsStyleContext** aStyles,
- PRBool aOwnsFactory)
- : gfxTextRun(aParams, aString, aLength, aFontGroup, aFlags),
- mFactory(aFactory), mOwnsFactory(aOwnsFactory)
- {
- PRUint32 i;
- for (i = 0; i < aLength; ++i) {
- mStyles.AppendElement(aStyles[i]);
- }
- for (i = 0; i < aParams->mInitialBreakCount; ++i) {
- mLineBreaks.AppendElement(aParams->mInitialBreaks[i]);
- }
- }
-
+ static nsTransformedTextRun *Create(const gfxTextRunFactory::Parameters* aParams,
+ nsTransformingTextRunFactory* aFactory,
+ gfxFontGroup* aFontGroup,
+ const PRUnichar* aString, PRUint32 aLength,
+ const PRUint32 aFlags, nsStyleContext** aStyles,
+ PRBool aOwnsFactory);
+
~nsTransformedTextRun() {
if (mOwnsFactory) {
delete mFactory;
}
}
virtual void SetCapitalization(PRUint32 aStart, PRUint32 aLength,
PRPackedBool* aCapitalization,
@@ -135,11 +124,30 @@ public:
gfxFloat* aAdvanceWidthDelta,
gfxContext* aRefContext);
nsTransformingTextRunFactory *mFactory;
nsTArray<PRUint32> mLineBreaks;
nsTArray<nsRefPtr<nsStyleContext> > mStyles;
nsTArray<PRPackedBool> mCapitalize;
PRPackedBool mOwnsFactory;
+
+private:
+ nsTransformedTextRun(const gfxTextRunFactory::Parameters* aParams,
+ nsTransformingTextRunFactory* aFactory,
+ gfxFontGroup* aFontGroup,
+ const PRUnichar* aString, PRUint32 aLength,
+ const PRUint32 aFlags, nsStyleContext** aStyles,
+ PRBool aOwnsFactory)
+ : gfxTextRun(aParams, aString, aLength, aFontGroup, aFlags, sizeof(nsTransformedTextRun)),
+ mFactory(aFactory), mOwnsFactory(aOwnsFactory)
+ {
+ PRUint32 i;
+ for (i = 0; i < aLength; ++i) {
+ mStyles.AppendElement(aStyles[i]);
+ }
+ for (i = 0; i < aParams->mInitialBreakCount; ++i) {
+ mLineBreaks.AppendElement(aParams->mInitialBreaks[i]);
+ }
+ }
};
#endif /*NSTEXTRUNTRANSFORMATIONS_H_*/