mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 385417 - Rework textrun glyph representation so we can handle clusters containing glyphs in different fonts [p=roc r=stuart r=smontagu a=blocking1.9+]
This commit is contained in:
parent
502c4c7607
commit
6adc9d9130
@ -271,37 +271,19 @@ nsThebesFontMetrics::GetMaxStringLength()
|
||||
|
||||
class StubPropertyProvider : public gfxTextRun::PropertyProvider {
|
||||
public:
|
||||
StubPropertyProvider(const nscoord* aSpacing = nsnull)
|
||||
: mSpacing(aSpacing) {}
|
||||
|
||||
virtual void GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore) {
|
||||
NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
|
||||
}
|
||||
virtual gfxFloat GetHyphenWidth() {
|
||||
NS_ERROR("This shouldn't be called because we never specify hyphen breaks");
|
||||
NS_ERROR("This shouldn't be called because we never enable hyphens");
|
||||
return 0;
|
||||
}
|
||||
virtual void GetSpacing(PRUint32 aStart, PRUint32 aLength,
|
||||
Spacing* aSpacing);
|
||||
|
||||
private:
|
||||
const nscoord* mSpacing;
|
||||
};
|
||||
|
||||
void
|
||||
StubPropertyProvider::GetSpacing(PRUint32 aStart, PRUint32 aLength,
|
||||
Spacing* aSpacing)
|
||||
{
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aLength; ++i) {
|
||||
aSpacing[i].mBefore = 0;
|
||||
// mSpacing is absolute (already includes the character width). This is OK
|
||||
// because gfxTextRunCache sets TEXT_ABSOLUTE_SPACING when it creates
|
||||
// the textrun.
|
||||
aSpacing[i].mAfter = mSpacing ? mSpacing[aStart + i] : 0;
|
||||
Spacing* aSpacing) {
|
||||
NS_ERROR("This shouldn't be called because we never enable spacing");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
nsresult
|
||||
nsThebesFontMetrics::GetWidth(const char* aString, PRUint32 aLength, nscoord& aWidth,
|
||||
@ -317,7 +299,7 @@ nsThebesFontMetrics::GetWidth(const char* aString, PRUint32 aLength, nscoord& aW
|
||||
return GetSpaceWidth(aWidth);
|
||||
|
||||
StubPropertyProvider provider;
|
||||
AutoTextRun textRun(this, aContext, aString, aLength, PR_FALSE);
|
||||
AutoTextRun textRun(this, aContext, aString, aLength);
|
||||
if (!textRun.get())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@ -341,7 +323,7 @@ nsThebesFontMetrics::GetWidth(const PRUnichar* aString, PRUint32 aLength,
|
||||
return GetSpaceWidth(aWidth);
|
||||
|
||||
StubPropertyProvider provider;
|
||||
AutoTextRun textRun(this, aContext, aString, aLength, PR_FALSE);
|
||||
AutoTextRun textRun(this, aContext, aString, aLength);
|
||||
if (!textRun.get())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@ -397,8 +379,9 @@ nsThebesFontMetrics::DrawString(const char *aString, PRUint32 aLength,
|
||||
if (aLength == 0)
|
||||
return NS_OK;
|
||||
|
||||
StubPropertyProvider provider(aSpacing);
|
||||
AutoTextRun textRun(this, aContext, aString, aLength, aSpacing != nsnull);
|
||||
NS_ASSERTION(!aSpacing, "Spacing not supported here");
|
||||
StubPropertyProvider provider;
|
||||
AutoTextRun textRun(this, aContext, aString, aLength);
|
||||
if (!textRun.get())
|
||||
return NS_ERROR_FAILURE;
|
||||
gfxPoint pt(aX, aY);
|
||||
@ -421,8 +404,9 @@ nsThebesFontMetrics::DrawString(const PRUnichar* aString, PRUint32 aLength,
|
||||
if (aLength == 0)
|
||||
return NS_OK;
|
||||
|
||||
StubPropertyProvider provider(aSpacing);
|
||||
AutoTextRun textRun(this, aContext, aString, aLength, aSpacing != nsnull);
|
||||
NS_ASSERTION(!aSpacing, "Spacing not supported here");
|
||||
StubPropertyProvider provider;
|
||||
AutoTextRun textRun(this, aContext, aString, aLength);
|
||||
if (!textRun.get())
|
||||
return NS_ERROR_FAILURE;
|
||||
gfxPoint pt(aX, aY);
|
||||
|
@ -158,21 +158,21 @@ protected:
|
||||
class AutoTextRun {
|
||||
public:
|
||||
AutoTextRun(nsThebesFontMetrics* aMetrics, nsIRenderingContext* aRC,
|
||||
const char* aString, PRInt32 aLength, PRBool aEnableSpacing) {
|
||||
const char* aString, PRInt32 aLength) {
|
||||
mTextRun = gfxTextRunCache::MakeTextRun(
|
||||
reinterpret_cast<const PRUint8*>(aString), aLength,
|
||||
aMetrics->mFontGroup,
|
||||
static_cast<gfxContext*>(aRC->GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT)),
|
||||
aMetrics->mP2A,
|
||||
ComputeFlags(aMetrics, aEnableSpacing));
|
||||
ComputeFlags(aMetrics));
|
||||
}
|
||||
AutoTextRun(nsThebesFontMetrics* aMetrics, nsIRenderingContext* aRC,
|
||||
const PRUnichar* aString, PRInt32 aLength, PRBool aEnableSpacing) {
|
||||
const PRUnichar* aString, PRInt32 aLength) {
|
||||
mTextRun = gfxTextRunCache::MakeTextRun(
|
||||
aString, aLength, aMetrics->mFontGroup,
|
||||
static_cast<gfxContext*>(aRC->GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT)),
|
||||
aMetrics->mP2A,
|
||||
ComputeFlags(aMetrics, aEnableSpacing));
|
||||
ComputeFlags(aMetrics));
|
||||
}
|
||||
gfxTextRun* operator->() { return mTextRun.get(); }
|
||||
gfxTextRun* get() { return mTextRun.get(); }
|
||||
@ -180,17 +180,11 @@ protected:
|
||||
private:
|
||||
gfxTextRunCache::AutoTextRun mTextRun;
|
||||
|
||||
static PRUint32 ComputeFlags(nsThebesFontMetrics* aMetrics,
|
||||
PRBool aEnableSpacing) {
|
||||
static PRUint32 ComputeFlags(nsThebesFontMetrics* aMetrics) {
|
||||
PRUint32 flags = 0;
|
||||
if (aMetrics->GetRightToLeftTextRunMode()) {
|
||||
flags |= gfxTextRunFactory::TEXT_IS_RTL;
|
||||
}
|
||||
if (aEnableSpacing) {
|
||||
flags |= gfxTextRunFactory::TEXT_ENABLE_SPACING |
|
||||
gfxTextRunFactory::TEXT_ABSOLUTE_SPACING |
|
||||
gfxTextRunFactory::TEXT_ENABLE_NEGATIVE_SPACING;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
};
|
||||
|
@ -573,11 +573,6 @@ public:
|
||||
* When set, GetSpacing can return negative spacing.
|
||||
*/
|
||||
TEXT_ENABLE_NEGATIVE_SPACING = 0x0010,
|
||||
/**
|
||||
* When set, mAfter spacing for a character already includes the character
|
||||
* width. Otherwise, it does not include the character width.
|
||||
*/
|
||||
TEXT_ABSOLUTE_SPACING = 0x0020,
|
||||
/**
|
||||
* When set, GetHyphenationBreaks may return true for some character
|
||||
* positions, otherwise it will always return false for all characters.
|
||||
@ -685,9 +680,9 @@ public:
|
||||
NS_ASSERTION(0 <= aPos && aPos < mCharacterCount, "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].IsClusterStart();
|
||||
}
|
||||
PRBool IsLigatureContinuation(PRUint32 aPos) {
|
||||
PRBool IsLigatureGroupStart(PRUint32 aPos) {
|
||||
NS_ASSERTION(0 <= aPos && aPos < mCharacterCount, "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].IsLigatureContinuation();
|
||||
return mCharacterGlyphs[aPos].IsLigatureGroupStart();
|
||||
}
|
||||
PRBool CanBreakLineBefore(PRUint32 aPos) {
|
||||
NS_ASSERTION(0 <= aPos && aPos < mCharacterCount, "aPos out of range");
|
||||
@ -972,18 +967,27 @@ public:
|
||||
* 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.
|
||||
*
|
||||
* A character can have zero or more associated glyphs. Each glyph
|
||||
* has an advance width and an x and y offset.
|
||||
* A character may be the start of a cluster.
|
||||
* A character may be the start of a ligature group.
|
||||
* A character can be "missing", indicating that the system is unable
|
||||
* to render the character.
|
||||
*
|
||||
* All characters in a ligature group conceptually share all the glyphs
|
||||
* associated with the characters in a group.
|
||||
*/
|
||||
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.
|
||||
// Indicates that a cluster and ligature group starts at this
|
||||
// character; this character has a single glyph with a reasonable
|
||||
// advance and zero offsets. A "reasonable" advance
|
||||
// is one that fits in the available bits (currently 14) (specified
|
||||
// in appunits).
|
||||
FLAG_IS_SIMPLE_GLYPH = 0x80000000U,
|
||||
// Indicates that a linebreak is allowed before this character
|
||||
FLAG_CAN_BREAK_BEFORE = 0x40000000U,
|
||||
@ -994,33 +998,22 @@ public:
|
||||
|
||||
GLYPH_MASK = 0x0000FFFFU,
|
||||
|
||||
// Non-simple glyphs have the following tags
|
||||
// Non-simple glyphs may or may not have glyph data in the
|
||||
// corresponding mDetailedGlyphs entry. They have the following
|
||||
// flag bits:
|
||||
|
||||
// When NOT set, indicates that this character corresponds to a
|
||||
// missing glyph and should be skipped (or possibly, render the character
|
||||
// Unicode value in some special way). If there are glyphs,
|
||||
// the mGlyphID is actually the UTF16 character code. The bit is
|
||||
// inverted so we can memset the array to zero to indicate all missing.
|
||||
FLAG_NOT_MISSING = 0x01,
|
||||
FLAG_NOT_CLUSTER_START = 0x02,
|
||||
FLAG_NOT_LIGATURE_GROUP_START = 0x04,
|
||||
FLAG_LOW_SURROGATE = 0x08,
|
||||
|
||||
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
|
||||
GLYPH_COUNT_MASK = 0x00FFFF00U,
|
||||
GLYPH_COUNT_SHIFT = 8
|
||||
};
|
||||
|
||||
// "Simple glyphs" have a simple glyph ID, simple advance and their
|
||||
@ -1039,21 +1032,19 @@ public:
|
||||
}
|
||||
|
||||
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 IsComplexOrMissing() const {
|
||||
return IsComplex(TAG_COMPLEX_CLUSTER) || IsComplex(TAG_MISSING);
|
||||
}
|
||||
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 IsMissing() const { return (mValue & (FLAG_NOT_MISSING|FLAG_IS_SIMPLE_GLYPH)) == 0; }
|
||||
PRBool IsLowSurrogate() const {
|
||||
return (mValue & (FLAG_LOW_SURROGATE|FLAG_IS_SIMPLE_GLYPH)) == FLAG_LOW_SURROGATE;
|
||||
}
|
||||
PRBool IsClusterStart() const {
|
||||
return (mValue & FLAG_IS_SIMPLE_GLYPH) || !(mValue & FLAG_NOT_CLUSTER_START);
|
||||
}
|
||||
PRBool IsLigatureGroupStart() const {
|
||||
return (mValue & FLAG_IS_SIMPLE_GLYPH) || !(mValue & FLAG_NOT_LIGATURE_GROUP_START);
|
||||
}
|
||||
|
||||
PRBool CanBreakBefore() const { return (mValue & FLAG_CAN_BREAK_BEFORE) != 0; }
|
||||
// Returns FLAG_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
|
||||
@ -1073,15 +1064,36 @@ public:
|
||||
(aAdvanceAppUnits << ADVANCE_SHIFT) | aGlyph;
|
||||
return *this;
|
||||
}
|
||||
CompressedGlyph& SetComplex(PRUint32 aTag) {
|
||||
mValue = (mValue & FLAG_CAN_BREAK_BEFORE) | aTag;
|
||||
CompressedGlyph& SetComplex(PRBool aClusterStart, PRBool aLigatureStart,
|
||||
PRUint32 aGlyphCount) {
|
||||
mValue = (mValue & FLAG_CAN_BREAK_BEFORE) | FLAG_NOT_MISSING |
|
||||
(aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) |
|
||||
(aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) |
|
||||
(aGlyphCount << GLYPH_COUNT_SHIFT);
|
||||
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); }
|
||||
/**
|
||||
* Missing glyphs are treated as cluster and ligature group starts.
|
||||
*/
|
||||
CompressedGlyph& SetMissing(PRUint32 aGlyphCount) {
|
||||
mValue = (mValue & FLAG_CAN_BREAK_BEFORE) |
|
||||
(aGlyphCount << GLYPH_COUNT_SHIFT);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Low surrogates don't have any glyphs and are not the start of
|
||||
* a cluster or ligature group.
|
||||
*/
|
||||
CompressedGlyph& SetLowSurrogate() {
|
||||
mValue = (mValue & FLAG_CAN_BREAK_BEFORE) | FLAG_NOT_MISSING |
|
||||
FLAG_LOW_SURROGATE;
|
||||
return *this;
|
||||
}
|
||||
PRUint32 GetGlyphCount() const {
|
||||
NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
|
||||
return (mValue & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT;
|
||||
}
|
||||
|
||||
private:
|
||||
PRUint32 mValue;
|
||||
};
|
||||
@ -1091,12 +1103,9 @@ public:
|
||||
* 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;
|
||||
/** The glyphID if this is a ComplexCluster, or the Unicode character
|
||||
* if this is a Missing glyph */
|
||||
PRUint32 mGlyphID:31;
|
||||
/** The glyphID, or the Unicode character
|
||||
* if this is a missing glyph */
|
||||
PRUint32 mGlyphID;
|
||||
/** The advance, x-offset and y-offset of the glyph, in appunits
|
||||
* mAdvance is in the text direction (RTL or LTR)
|
||||
* mXOffset is always from left to right
|
||||
@ -1111,7 +1120,7 @@ public:
|
||||
PRUint32 mCharacterOffset; // into original UTF16 string
|
||||
};
|
||||
|
||||
class GlyphRunIterator {
|
||||
class THEBES_API GlyphRunIterator {
|
||||
public:
|
||||
GlyphRunIterator(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aLength)
|
||||
: mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) {
|
||||
@ -1176,13 +1185,12 @@ public:
|
||||
// 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.
|
||||
* Set the glyph data for a character. aGlyphs may be null if aGlyph is a
|
||||
* simple glyph or has no associated glyphs. If non-null the data is copied,
|
||||
* the caller retains ownership.
|
||||
*/
|
||||
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!");
|
||||
void SetSimpleGlyph(PRUint32 aCharIndex, CompressedGlyph aGlyph) {
|
||||
NS_ASSERTION(aGlyph.IsSimpleGlyph(), "Should be a simple glyph here");
|
||||
if (mCharacterGlyphs) {
|
||||
mCharacterGlyphs[aCharIndex] = aGlyph;
|
||||
}
|
||||
@ -1190,13 +1198,9 @@ public:
|
||||
mDetailedGlyphs[aCharIndex] = nsnull;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set some detailed glyphs for a character. The data is copied from aGlyphs,
|
||||
* the caller retains ownership.
|
||||
*/
|
||||
void SetDetailedGlyphs(PRUint32 aCharIndex, const DetailedGlyph *aGlyphs,
|
||||
PRUint32 aNumGlyphs);
|
||||
void SetMissingGlyph(PRUint32 aCharIndex, PRUint32 aChar);
|
||||
void SetGlyphs(PRUint32 aCharIndex, CompressedGlyph aGlyph,
|
||||
const DetailedGlyph *aGlyphs);
|
||||
void SetMissingGlyph(PRUint32 aCharIndex, PRUint32 aUnicodeChar);
|
||||
void SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, PRUint32 aCharIndex);
|
||||
|
||||
void FetchGlyphExtents(gfxContext *aRefContext);
|
||||
@ -1205,8 +1209,6 @@ public:
|
||||
// and gfxFont::GetBoundingBox
|
||||
const CompressedGlyph *GetCharacterGlyphs() { return mCharacterGlyphs; }
|
||||
const DetailedGlyph *GetDetailedGlyphs(PRUint32 aCharIndex) {
|
||||
// Although mDetailedGlyphs should be non-NULL when ComplexCluster,
|
||||
// Missing glyphs need not have details.
|
||||
return mDetailedGlyphs ? mDetailedGlyphs[aCharIndex].get() : nsnull;
|
||||
}
|
||||
PRBool HasDetailedGlyphs() { return mDetailedGlyphs.get() != nsnull; }
|
||||
@ -1254,12 +1256,7 @@ private:
|
||||
|
||||
// Allocate aCount DetailedGlyphs for the given index
|
||||
DetailedGlyph *AllocateDetailedGlyphs(PRUint32 aCharIndex, PRUint32 aCount);
|
||||
// Computes the x-advance for a given cluster starting at aClusterOffset. Does
|
||||
// not include any spacing. Result is in appunits.
|
||||
PRInt32 ComputeClusterAdvance(PRUint32 aClusterOffset);
|
||||
|
||||
void GetAdjustedSpacing(PRUint32 aStart, PRUint32 aEnd,
|
||||
PropertyProvider *aProvider, PropertyProvider::Spacing *aSpacing);
|
||||
// Spacing for characters outside the range aSpacingStart/aSpacingEnd
|
||||
// is assumed to be zero; such characters are not passed to aProvider.
|
||||
// This is useful to protect aProvider from being passed character indices
|
||||
|
@ -483,7 +483,10 @@ SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString)
|
||||
PRUint32 i;
|
||||
for (i = breakOffset + 1; i < next; ++i) {
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
aTextRun->SetCharacterGlyph(i, g.SetClusterContinuation());
|
||||
// Remember that this character is not the start of a cluster by
|
||||
// setting its glyph data to "not a cluster start", "is a
|
||||
// ligature start", with no glyphs.
|
||||
aTextRun->SetGlyphs(i, g.SetComplex(PR_FALSE, PR_TRUE, 0), nsnull);
|
||||
}
|
||||
breakOffset = next;
|
||||
}
|
||||
@ -736,7 +739,7 @@ GetAdvanceAppUnits(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||
* Given a run of ATSUI glyphs that should be treated as a single cluster/ligature,
|
||||
* store them in the textrun at the appropriate character and set the
|
||||
* other characters involved to be ligature/cluster continuations as appropriate.
|
||||
*/
|
||||
*/
|
||||
static void
|
||||
SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||
Fixed *aBaselineDeltas, PRUint32 aAppUnitsPerDevUnit,
|
||||
@ -792,26 +795,26 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
PRUint32 offset;
|
||||
// Make all but the first character in the group NOT be a ligature boundary,
|
||||
// i.e. fuse the group into a ligature.
|
||||
// Also make them not be cluster boundaries, i.e., fuse them into a cluster,
|
||||
// if the glyphs are out of character order.
|
||||
for (offset = firstOffset + 2; offset <= lastOffset; offset += 2) {
|
||||
PRUint32 index = offset/2;
|
||||
if (!inOrder) {
|
||||
// Because the characters in this group were not in the textrun's
|
||||
// required order, we must make the entire group an indivisible cluster
|
||||
aRun->SetCharacterGlyph(aSegmentStart + index, g.SetClusterContinuation());
|
||||
} else if (!aRun->GetCharacterGlyphs()[index].IsClusterContinuation()) {
|
||||
aRun->SetCharacterGlyph(aSegmentStart + index, g.SetLigatureContinuation());
|
||||
}
|
||||
PRUint32 index = offset/2;
|
||||
PRBool makeClusterStart = inOrder && aRun->IsClusterStart(index);
|
||||
g.SetComplex(makeClusterStart, PR_FALSE, 0);
|
||||
aRun->SetGlyphs(aSegmentStart + index, g, nsnull);
|
||||
}
|
||||
|
||||
// Grab total advance for all glyphs
|
||||
PRInt32 advance = GetAdvanceAppUnits(aGlyphs, aGlyphCount, aAppUnitsPerDevUnit);
|
||||
PRUint32 index = firstOffset/2;
|
||||
PRUint32 charIndex = aSegmentStart + firstOffset/2;
|
||||
if (regularGlyphCount == 1) {
|
||||
if (advance >= 0 &&
|
||||
(!aBaselineDeltas || aBaselineDeltas[displayGlyph - aGlyphs] == 0) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(displayGlyph->glyphID)) {
|
||||
aRun->SetCharacterGlyph(aSegmentStart + index, g.SetSimpleGlyph(advance, displayGlyph->glyphID));
|
||||
aRun->SetSimpleGlyph(charIndex, g.SetSimpleGlyph(advance, displayGlyph->glyphID));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -821,11 +824,37 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||
for (i = 0; i < aGlyphCount; ++i) {
|
||||
ATSLayoutRecord *glyph = &aGlyphs[i];
|
||||
if (glyph->glyphID != ATSUI_SPECIAL_GLYPH_ID) {
|
||||
if (glyph->originalOffset > firstOffset) {
|
||||
PRUint32 glyphCharIndex = aSegmentStart + glyph->originalOffset/2;
|
||||
PRUint32 glyphRunIndex = aRun->FindFirstGlyphRunContaining(glyphCharIndex);
|
||||
PRUint32 numGlyphRuns;
|
||||
const gfxTextRun::GlyphRun *glyphRun = aRun->GetGlyphRuns(&numGlyphRuns) + glyphRunIndex;
|
||||
|
||||
if (glyphRun->mCharacterOffset > charIndex) {
|
||||
// The font has changed inside the character group. This might
|
||||
// happen in some weird situations, e.g. if
|
||||
// ATSUI decides in LTR text to put the glyph for character
|
||||
// 1 before the glyph for character 0, AND decides to
|
||||
// give character 1's glyph a different font from character
|
||||
// 0. This sucks because we can't then safely move this
|
||||
// glyph to be associated with our first character.
|
||||
// To handle this we'd have to do some funky hacking with
|
||||
// glyph advances and offsets so that the glyphs stay
|
||||
// associated with the right characters but they are
|
||||
// displayed out of order. Let's not do this for now,
|
||||
// in the hope that it doesn't come up. If it does come up,
|
||||
// at least we can fix it right here without changing
|
||||
// any other code.
|
||||
NS_ERROR("Font change inside character group!");
|
||||
// Be safe, just throw out this glyph
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
gfxTextRun::DetailedGlyph *details = detailedGlyphs.AppendElement();
|
||||
if (!details)
|
||||
return;
|
||||
details->mAdvance = 0;
|
||||
details->mIsLastGlyph = PR_FALSE;
|
||||
details->mGlyphID = glyph->glyphID;
|
||||
details->mXOffset = 0;
|
||||
if (detailedGlyphs.Length() > 1) {
|
||||
@ -839,18 +868,18 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||
}
|
||||
if (detailedGlyphs.Length() == 0) {
|
||||
NS_WARNING("No glyphs visible at all!");
|
||||
aRun->SetCharacterGlyph(aSegmentStart + index, g.SetMissing());
|
||||
aRun->SetGlyphs(aSegmentStart + charIndex, g.SetMissing(0), nsnull);
|
||||
return;
|
||||
}
|
||||
|
||||
// The advance width for the whole cluster
|
||||
PRInt32 clusterAdvance = GetAdvanceAppUnits(aGlyphs, aGlyphCount, aAppUnitsPerDevUnit);
|
||||
detailedGlyphs[detailedGlyphs.Length() - 1].mIsLastGlyph = PR_TRUE;
|
||||
if (aRun->IsRightToLeft())
|
||||
detailedGlyphs[0].mAdvance = clusterAdvance;
|
||||
else
|
||||
detailedGlyphs[detailedGlyphs.Length() - 1].mAdvance = clusterAdvance;
|
||||
aRun->SetDetailedGlyphs(aSegmentStart + index, detailedGlyphs.Elements(), detailedGlyphs.Length());
|
||||
g.SetComplex(aRun->IsClusterStart(charIndex), PR_TRUE, detailedGlyphs.Length());
|
||||
aRun->SetGlyphs(charIndex, g, detailedGlyphs.Elements());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -910,26 +939,21 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
||||
PRUint32 glyphIndex = isRTL ? numGlyphs - 1 : 0;
|
||||
PRUint32 lastOffset = glyphRecords[glyphIndex].originalOffset;
|
||||
PRUint32 glyphCount = 1;
|
||||
// Determine the glyphs for this group
|
||||
// Determine the glyphs for this ligature group
|
||||
while (glyphCount < numGlyphs) {
|
||||
ATSLayoutRecord *glyph = &glyphRecords[glyphIndex + direction*glyphCount];
|
||||
PRUint32 glyphOffset = glyph->originalOffset;
|
||||
allFlags |= glyph->flags;
|
||||
// Always add the current glyph to the group if it's for the same
|
||||
// character as a character whose glyph is already in the group,
|
||||
// or an earlier character. The latter can happen because ATSUI
|
||||
// sometimes visually reorders glyphs; e.g. DEVANAGARI VOWEL I
|
||||
// can have its glyph displayed before the glyph for the consonant that's
|
||||
// it's logically after (even though this is all left-to-right text).
|
||||
// In this case we need to make sure the glyph for the consonant
|
||||
// is added to the group containing the vowel.
|
||||
if (lastOffset < glyphOffset) {
|
||||
if (!aRun->IsClusterStart(aSegmentStart + glyphOffset/2)) {
|
||||
// next character is a cluster continuation,
|
||||
// add it to the current group
|
||||
lastOffset = glyphOffset;
|
||||
continue;
|
||||
}
|
||||
if (glyphOffset <= lastOffset) {
|
||||
// Always add the current glyph to the ligature group if it's for the same
|
||||
// character as a character whose glyph is already in the group,
|
||||
// or an earlier character. The latter can happen because ATSUI
|
||||
// sometimes visually reorders glyphs; e.g. DEVANAGARI VOWEL I
|
||||
// can have its glyph displayed before the glyph for the consonant that's
|
||||
// it's logically after (even though this is all left-to-right text).
|
||||
// In this case we need to make sure the glyph for the consonant
|
||||
// is added to the group containing the vowel.
|
||||
} else {
|
||||
// We could be at the end of a character group
|
||||
if (glyph->glyphID != ATSUI_SPECIAL_GLYPH_ID) {
|
||||
// Next character is a normal character, stop the group here
|
||||
@ -1247,22 +1271,6 @@ AppendCJKPrefFonts(nsTArray<nsRefPtr<gfxFont> > *aFonts,
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void
|
||||
AddGlyphRun(gfxTextRun *aRun, gfxAtsuiFont *aFont, PRUint32 aOffset)
|
||||
{
|
||||
//fprintf (stderr, "+ AddGlyphRun: %d %s\n", aOffset, NS_ConvertUTF16toUTF8(aFont->GetUniqueName()).get());
|
||||
aRun->AddGlyphRun(aFont, aOffset, PR_TRUE);
|
||||
if (!aRun->IsClusterStart(aOffset)) {
|
||||
// Glyph runs must start at cluster boundaries. However, sometimes
|
||||
// ATSUI matches different fonts for characters in the same cluster.
|
||||
// If this happens, break up the cluster. It's not clear what else
|
||||
// we can do.
|
||||
NS_WARNING("Font mismatch inside cluster");
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
aRun->SetCharacterGlyph(aOffset, g.SetMissing());
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
DisableOptionalLigaturesInStyle(ATSUStyle aStyle)
|
||||
{
|
||||
@ -1526,7 +1534,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||
}
|
||||
|
||||
// add a glyph run for the entire substring
|
||||
AddGlyphRun(aRun, firstFont, aSegmentStart + runStart - headerChars);
|
||||
aRun->AddGlyphRun(firstFont, aSegmentStart + runStart - headerChars, PR_TRUE);
|
||||
|
||||
// do we have any more work to do?
|
||||
if (status == noErr)
|
||||
@ -1572,7 +1580,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||
changedLength);
|
||||
}
|
||||
|
||||
AddGlyphRun(aRun, font, aSegmentStart + changedOffset - headerChars);
|
||||
aRun->AddGlyphRun(font, aSegmentStart + changedOffset - headerChars, PR_TRUE);
|
||||
} else {
|
||||
// We could hit this case if we decided to ignore the
|
||||
// font when enumerating at startup; pretend that these are
|
||||
@ -1597,7 +1605,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||
missingOffsetsAndLengths.AppendElement(changedOffset);
|
||||
missingOffsetsAndLengths.AppendElement(changedLength);
|
||||
} else {
|
||||
AddGlyphRun(aRun, firstFont, aSegmentStart + changedOffset - headerChars);
|
||||
aRun->AddGlyphRun(firstFont, aSegmentStart + changedOffset - headerChars, PR_TRUE);
|
||||
|
||||
if (!closure.mUnmatchedChars) {
|
||||
closure.mUnmatchedChars = new PRPackedBool[aLength];
|
||||
|
@ -273,44 +273,38 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
x += advance;
|
||||
}
|
||||
glyphs.Flush(cr, aDrawToPath);
|
||||
} else if (glyphData->IsComplexCluster()) {
|
||||
} else {
|
||||
PRUint32 j;
|
||||
PRUint32 glyphCount = glyphData->GetGlyphCount();
|
||||
const gfxTextRun::DetailedGlyph *details = aTextRun->GetDetailedGlyphs(i);
|
||||
for (;;) {
|
||||
glyph = glyphs.AppendGlyph();
|
||||
glyph->index = details->mGlyphID;
|
||||
glyph->x = ToDeviceUnits(x + details->mXOffset, devUnitsPerAppUnit);
|
||||
glyph->y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
|
||||
for (j = 0; j < glyphCount; ++j, ++details) {
|
||||
double advance = details->mAdvance;
|
||||
if (isRTL) {
|
||||
glyph->x -= ToDeviceUnits(advance, devUnitsPerAppUnit);
|
||||
}
|
||||
x += direction*advance;
|
||||
|
||||
glyphs.Flush(cr, aDrawToPath);
|
||||
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
++details;
|
||||
}
|
||||
} else if (glyphData->IsMissing()) {
|
||||
const gfxTextRun::DetailedGlyph *details = aTextRun->GetDetailedGlyphs(i);
|
||||
if (details) {
|
||||
double advance = details->mAdvance;
|
||||
if (!aDrawToPath) {
|
||||
gfxPoint pt(ToDeviceUnits(x, devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y, devUnitsPerAppUnit));
|
||||
gfxFloat advanceDevUnits = ToDeviceUnits(advance, devUnitsPerAppUnit);
|
||||
if (isRTL) {
|
||||
pt.x -= advanceDevUnits;
|
||||
if (glyphData->IsMissing()) {
|
||||
if (!aDrawToPath) {
|
||||
gfxPoint pt(ToDeviceUnits(x, devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y, devUnitsPerAppUnit));
|
||||
gfxFloat advanceDevUnits = ToDeviceUnits(advance, devUnitsPerAppUnit);
|
||||
if (isRTL) {
|
||||
pt.x -= advanceDevUnits;
|
||||
}
|
||||
gfxFloat height = GetMetrics().maxAscent;
|
||||
gfxRect glyphRect(pt.x, pt.y - height, advanceDevUnits, height);
|
||||
gfxFontMissingGlyphs::DrawMissingGlyph(aContext, glyphRect, details->mGlyphID);
|
||||
}
|
||||
gfxFloat height = GetMetrics().maxAscent;
|
||||
gfxRect glyphRect(pt.x, pt.y - height, advanceDevUnits, height);
|
||||
gfxFontMissingGlyphs::DrawMissingGlyph(aContext, glyphRect, details->mGlyphID);
|
||||
} else {
|
||||
glyph = glyphs.AppendGlyph();
|
||||
glyph->index = details->mGlyphID;
|
||||
glyph->x = ToDeviceUnits(x + details->mXOffset, devUnitsPerAppUnit);
|
||||
glyph->y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
|
||||
if (isRTL) {
|
||||
glyph->x -= ToDeviceUnits(advance, devUnitsPerAppUnit);
|
||||
}
|
||||
glyphs.Flush(cr, aDrawToPath);
|
||||
}
|
||||
x += direction*advance;
|
||||
}
|
||||
}
|
||||
// Every other glyph type is ignored
|
||||
|
||||
if (aSpacing) {
|
||||
double space = aSpacing[i - aStart].mAfter;
|
||||
if (i + 1 < aEnd) {
|
||||
@ -335,6 +329,27 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
*aPt = gfxPoint(x, y);
|
||||
}
|
||||
|
||||
static PRInt32
|
||||
GetAdvanceForGlyphs(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd)
|
||||
{
|
||||
const gfxTextRun::CompressedGlyph *glyphData = aTextRun->GetCharacterGlyphs() + aStart;
|
||||
PRInt32 advance = 0;
|
||||
PRUint32 i;
|
||||
for (i = aStart; i < aEnd; ++i, ++glyphData) {
|
||||
if (glyphData->IsSimpleGlyph()) {
|
||||
advance += glyphData->GetSimpleAdvance();
|
||||
} else {
|
||||
PRUint32 glyphCount = glyphData->GetGlyphCount();
|
||||
const gfxTextRun::DetailedGlyph *details = aTextRun->GetDetailedGlyphs(i);
|
||||
PRUint32 j;
|
||||
for (j = 0; j < glyphCount; ++j, ++details) {
|
||||
advance += details->mAdvance;
|
||||
}
|
||||
}
|
||||
}
|
||||
return advance;
|
||||
}
|
||||
|
||||
static void
|
||||
UnionWithXPoint(gfxRect *aRect, double aX)
|
||||
{
|
||||
@ -405,9 +420,11 @@ gfxFont::Measure(gfxTextRun *aTextRun,
|
||||
}
|
||||
}
|
||||
x += direction*advance;
|
||||
} else if (glyphData->IsComplexCluster()) {
|
||||
} else {
|
||||
PRUint32 glyphCount = glyphData->GetGlyphCount();
|
||||
const gfxTextRun::DetailedGlyph *details = aTextRun->GetDetailedGlyphs(i);
|
||||
for (;;) {
|
||||
PRUint32 j;
|
||||
for (j = 0; j < glyphCount; ++j, ++details) {
|
||||
PRUint32 glyphIndex = details->mGlyphID;
|
||||
gfxPoint glyphPt(x + details->mXOffset, details->mYOffset);
|
||||
double advance = details->mAdvance;
|
||||
@ -419,20 +436,6 @@ gfxFont::Measure(gfxTextRun *aTextRun,
|
||||
glyphRect.pos.x += x;
|
||||
metrics.mBoundingBox = metrics.mBoundingBox.Union(glyphRect);
|
||||
x += direction*advance;
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
++details;
|
||||
}
|
||||
} else if (glyphData->IsMissing()) {
|
||||
const gfxTextRun::DetailedGlyph *details = aTextRun->GetDetailedGlyphs(i);
|
||||
if (details) {
|
||||
double advance = details->mAdvance;
|
||||
gfxRect glyphRect(x, -metrics.mAscent, advance, metrics.mAscent);
|
||||
if (isRTL) {
|
||||
glyphRect.pos.x -= advance;
|
||||
}
|
||||
metrics.mBoundingBox = metrics.mBoundingBox.Union(glyphRect);
|
||||
x += direction*advance;
|
||||
}
|
||||
}
|
||||
// Every other glyph type is ignored
|
||||
@ -1040,32 +1043,6 @@ gfxTextRun::SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
|
||||
return changed != 0;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
gfxTextRun::ComputeClusterAdvance(PRUint32 aClusterOffset)
|
||||
{
|
||||
CompressedGlyph *glyphData = &mCharacterGlyphs[aClusterOffset];
|
||||
if (glyphData->IsSimpleGlyph())
|
||||
return glyphData->GetSimpleAdvance();
|
||||
|
||||
const DetailedGlyph *details = GetDetailedGlyphs(aClusterOffset);
|
||||
if (!details)
|
||||
return 0;
|
||||
|
||||
PRInt32 advance = 0;
|
||||
while (1) {
|
||||
advance += details->mAdvance;
|
||||
if (details->mIsLastGlyph)
|
||||
return advance;
|
||||
++details;
|
||||
}
|
||||
}
|
||||
|
||||
static PRBool
|
||||
IsLigatureStart(gfxTextRun::CompressedGlyph aGlyph)
|
||||
{
|
||||
return aGlyph.IsClusterStart() && !aGlyph.IsLigatureContinuation();
|
||||
}
|
||||
|
||||
gfxTextRun::LigatureData
|
||||
gfxTextRun::ComputeLigatureData(PRUint32 aPartStart, PRUint32 aPartEnd,
|
||||
PropertyProvider *aProvider)
|
||||
@ -1077,15 +1054,16 @@ gfxTextRun::ComputeLigatureData(PRUint32 aPartStart, PRUint32 aPartEnd,
|
||||
CompressedGlyph *charGlyphs = mCharacterGlyphs;
|
||||
|
||||
PRUint32 i;
|
||||
for (i = aPartStart; !IsLigatureStart(charGlyphs[i]); --i) {
|
||||
for (i = aPartStart; !charGlyphs[i].IsLigatureGroupStart(); --i) {
|
||||
NS_ASSERTION(i > 0, "Ligature at the start of the run??");
|
||||
}
|
||||
result.mLigatureStart = i;
|
||||
for (i = aPartStart + 1; i < mCharacterCount && !IsLigatureStart(charGlyphs[i]); ++i) {
|
||||
for (i = aPartStart + 1; i < mCharacterCount && !charGlyphs[i].IsLigatureGroupStart(); ++i) {
|
||||
}
|
||||
result.mLigatureEnd = i;
|
||||
|
||||
PRInt32 ligatureWidth = ComputeClusterAdvance(result.mLigatureStart);
|
||||
PRInt32 ligatureWidth =
|
||||
GetAdvanceForGlyphs(this, result.mLigatureStart, result.mLigatureEnd);
|
||||
// Count the number of started clusters we have seen
|
||||
PRUint32 totalClusterCount = 0;
|
||||
PRUint32 partClusterIndex = 0;
|
||||
@ -1130,58 +1108,24 @@ gfxTextRun::ComputePartialLigatureWidth(PRUint32 aPartStart, PRUint32 aPartEnd,
|
||||
return data.mPartWidth;
|
||||
}
|
||||
|
||||
void
|
||||
gfxTextRun::GetAdjustedSpacing(PRUint32 aStart, PRUint32 aEnd,
|
||||
PropertyProvider *aProvider,
|
||||
PropertyProvider::Spacing *aSpacing)
|
||||
static void
|
||||
GetAdjustedSpacing(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
gfxTextRun::PropertyProvider *aProvider,
|
||||
gfxTextRun::PropertyProvider::Spacing *aSpacing)
|
||||
{
|
||||
if (aStart >= aEnd)
|
||||
return;
|
||||
|
||||
aProvider->GetSpacing(aStart, aEnd - aStart, aSpacing);
|
||||
|
||||
CompressedGlyph *charGlyphs = mCharacterGlyphs;
|
||||
PRUint32 i;
|
||||
|
||||
if (mFlags & gfxTextRunFactory::TEXT_ABSOLUTE_SPACING) {
|
||||
// Subtract character widths from mAfter at the end of clusters/ligatures to
|
||||
// relativize spacing. This is a bit sad since we're going to add
|
||||
// them in again below when we actually use the spacing, but this
|
||||
// produces simpler code and absolute spacing is rarely required.
|
||||
|
||||
// The width of the last nonligature cluster, in appunits
|
||||
PRInt32 clusterWidth = 0;
|
||||
for (i = aStart; i < aEnd; ++i) {
|
||||
CompressedGlyph *glyphData = &charGlyphs[i];
|
||||
|
||||
if (glyphData->IsSimpleGlyph()) {
|
||||
if (i > aStart) {
|
||||
aSpacing[i - 1 - aStart].mAfter -= clusterWidth;
|
||||
}
|
||||
clusterWidth = glyphData->GetSimpleAdvance();
|
||||
} else if (glyphData->IsComplexOrMissing()) {
|
||||
if (i > aStart) {
|
||||
aSpacing[i - 1 - aStart].mAfter -= clusterWidth;
|
||||
}
|
||||
clusterWidth = 0;
|
||||
const DetailedGlyph *details = GetDetailedGlyphs(i);
|
||||
if (details) {
|
||||
while (1) {
|
||||
clusterWidth += details->mAdvance;
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
++details;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
aSpacing[aEnd - 1 - aStart].mAfter -= clusterWidth;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Check to see if we have spacing inside ligatures
|
||||
|
||||
const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs();
|
||||
PRUint32 i;
|
||||
|
||||
for (i = aStart; i < aEnd; ++i) {
|
||||
if (charGlyphs[i].IsLigatureContinuation()) {
|
||||
if (!charGlyphs[i].IsLigatureGroupStart()) {
|
||||
NS_ASSERTION(i == aStart || aSpacing[i - aStart].mBefore == 0,
|
||||
"Before-spacing inside a ligature!");
|
||||
NS_ASSERTION(i - 1 <= aStart || aSpacing[i - 1 - aStart].mAfter == 0,
|
||||
@ -1202,7 +1146,7 @@ gfxTextRun::GetAdjustedSpacingArray(PRUint32 aStart, PRUint32 aEnd,
|
||||
if (!aSpacing->AppendElements(aEnd - aStart))
|
||||
return PR_FALSE;
|
||||
memset(aSpacing->Elements(), 0, sizeof(gfxFont::Spacing)*(aSpacingStart - aStart));
|
||||
GetAdjustedSpacing(aSpacingStart, aSpacingEnd, aProvider,
|
||||
GetAdjustedSpacing(this, aSpacingStart, aSpacingEnd, aProvider,
|
||||
aSpacing->Elements() + aSpacingStart - aStart);
|
||||
memset(aSpacing->Elements() + aSpacingEnd - aStart, 0, sizeof(gfxFont::Spacing)*(aEnd - aSpacingEnd));
|
||||
return PR_TRUE;
|
||||
@ -1216,11 +1160,11 @@ gfxTextRun::ShrinkToLigatureBoundaries(PRUint32 *aStart, PRUint32 *aEnd)
|
||||
|
||||
CompressedGlyph *charGlyphs = mCharacterGlyphs;
|
||||
|
||||
while (*aStart < *aEnd && !IsLigatureStart(charGlyphs[*aStart])) {
|
||||
while (*aStart < *aEnd && !charGlyphs[*aStart].IsLigatureGroupStart()) {
|
||||
++(*aStart);
|
||||
}
|
||||
if (*aEnd < mCharacterCount) {
|
||||
while (*aEnd > *aStart && !IsLigatureStart(charGlyphs[*aEnd])) {
|
||||
while (*aEnd > *aStart && !charGlyphs[*aEnd].IsLigatureGroupStart()) {
|
||||
--(*aEnd);
|
||||
}
|
||||
}
|
||||
@ -1477,8 +1421,6 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
||||
PRBool *aUsedHyphenation,
|
||||
PRUint32 *aLastBreak)
|
||||
{
|
||||
CompressedGlyph *charGlyphs = mCharacterGlyphs;
|
||||
|
||||
aMaxLength = PR_MIN(aMaxLength, mCharacterCount - aStart);
|
||||
|
||||
NS_ASSERTION(aStart + aMaxLength <= mCharacterCount, "Substring out of range");
|
||||
@ -1488,7 +1430,7 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
||||
PropertyProvider::Spacing spacingBuffer[MEASUREMENT_BUFFER_SIZE];
|
||||
PRBool haveSpacing = aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING) != 0;
|
||||
if (haveSpacing) {
|
||||
GetAdjustedSpacing(bufferStart, bufferStart + bufferLength, aProvider,
|
||||
GetAdjustedSpacing(this, bufferStart, bufferStart + bufferLength, aProvider,
|
||||
spacingBuffer);
|
||||
}
|
||||
PRPackedBool hyphenBuffer[MEASUREMENT_BUFFER_SIZE];
|
||||
@ -1522,7 +1464,7 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
||||
bufferStart = i;
|
||||
bufferLength = PR_MIN(aStart + aMaxLength, i + MEASUREMENT_BUFFER_SIZE) - i;
|
||||
if (haveSpacing) {
|
||||
GetAdjustedSpacing(bufferStart, bufferStart + bufferLength, aProvider,
|
||||
GetAdjustedSpacing(this, bufferStart, bufferStart + bufferLength, aProvider,
|
||||
spacingBuffer);
|
||||
}
|
||||
if (haveHyphenation) {
|
||||
@ -1557,28 +1499,15 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
||||
}
|
||||
}
|
||||
|
||||
gfxFloat charAdvance = 0;
|
||||
gfxFloat charAdvance;
|
||||
if (i >= ligatureRunStart && i < ligatureRunEnd) {
|
||||
CompressedGlyph *glyphData = &charGlyphs[i];
|
||||
if (glyphData->IsSimpleGlyph()) {
|
||||
charAdvance = glyphData->GetSimpleAdvance();
|
||||
} else if (glyphData->IsComplexOrMissing()) {
|
||||
const DetailedGlyph *details = GetDetailedGlyphs(i);
|
||||
if (details) {
|
||||
while (1) {
|
||||
charAdvance += details->mAdvance;
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
++details;
|
||||
}
|
||||
}
|
||||
}
|
||||
charAdvance = GetAdvanceForGlyphs(this, i, i + 1);
|
||||
if (haveSpacing) {
|
||||
PropertyProvider::Spacing *space = &spacingBuffer[i - bufferStart];
|
||||
charAdvance += space->mBefore + space->mAfter;
|
||||
}
|
||||
} else {
|
||||
charAdvance += ComputePartialLigatureWidth(i, i + 1, aProvider);
|
||||
charAdvance = ComputePartialLigatureWidth(i, i + 1, aProvider);
|
||||
}
|
||||
|
||||
advance += charAdvance;
|
||||
@ -1639,8 +1568,6 @@ gfxFloat
|
||||
gfxTextRun::GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
|
||||
PropertyProvider *aProvider)
|
||||
{
|
||||
CompressedGlyph *charGlyphs = mCharacterGlyphs;
|
||||
|
||||
NS_ASSERTION(aStart + aLength <= mCharacterCount, "Substring out of range");
|
||||
|
||||
PRUint32 ligatureRunStart = aStart;
|
||||
@ -1656,7 +1583,7 @@ gfxTextRun::GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
|
||||
PRUint32 i;
|
||||
nsAutoTArray<PropertyProvider::Spacing,200> spacingBuffer;
|
||||
if (spacingBuffer.AppendElements(aLength)) {
|
||||
GetAdjustedSpacing(ligatureRunStart, ligatureRunEnd, aProvider,
|
||||
GetAdjustedSpacing(this, ligatureRunStart, ligatureRunEnd, aProvider,
|
||||
spacingBuffer.Elements());
|
||||
for (i = 0; i < ligatureRunEnd - ligatureRunStart; ++i) {
|
||||
PropertyProvider::Spacing *space = &spacingBuffer[i];
|
||||
@ -1665,25 +1592,7 @@ gfxTextRun::GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 i;
|
||||
for (i = ligatureRunStart; i < ligatureRunEnd; ++i) {
|
||||
CompressedGlyph *glyphData = &charGlyphs[i];
|
||||
if (glyphData->IsSimpleGlyph()) {
|
||||
result += glyphData->GetSimpleAdvance();
|
||||
} else if (glyphData->IsComplexOrMissing()) {
|
||||
const DetailedGlyph *details = GetDetailedGlyphs(i);
|
||||
if (details) {
|
||||
while (1) {
|
||||
result += details->mAdvance;
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
++details;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result + GetAdvanceForGlyphs(this, ligatureRunStart, ligatureRunEnd);
|
||||
}
|
||||
|
||||
PRBool
|
||||
@ -1797,13 +1706,13 @@ gfxTextRun::AllocateDetailedGlyphs(PRUint32 aIndex, PRUint32 aCount)
|
||||
if (!mDetailedGlyphs) {
|
||||
mDetailedGlyphs = new nsAutoArrayPtr<DetailedGlyph>[mCharacterCount];
|
||||
if (!mDetailedGlyphs) {
|
||||
mCharacterGlyphs[aIndex].SetMissing();
|
||||
mCharacterGlyphs[aIndex].SetMissing(0);
|
||||
return nsnull;
|
||||
}
|
||||
}
|
||||
DetailedGlyph *details = new DetailedGlyph[aCount];
|
||||
if (!details) {
|
||||
mCharacterGlyphs[aIndex].SetMissing();
|
||||
mCharacterGlyphs[aIndex].SetMissing(0);
|
||||
return nsnull;
|
||||
}
|
||||
mDetailedGlyphs[aIndex] = details;
|
||||
@ -1811,20 +1720,24 @@ gfxTextRun::AllocateDetailedGlyphs(PRUint32 aIndex, PRUint32 aCount)
|
||||
}
|
||||
|
||||
void
|
||||
gfxTextRun::SetDetailedGlyphs(PRUint32 aIndex, const DetailedGlyph *aGlyphs,
|
||||
PRUint32 aCount)
|
||||
gfxTextRun::SetGlyphs(PRUint32 aIndex, CompressedGlyph aGlyph,
|
||||
const DetailedGlyph *aGlyphs)
|
||||
{
|
||||
NS_ASSERTION(aCount > 0, "Can't set zero detailed glyphs");
|
||||
NS_ASSERTION(aGlyphs[aCount - 1].mIsLastGlyph, "Failed to set last glyph flag");
|
||||
NS_ASSERTION(!aGlyph.IsSimpleGlyph(), "Simple glyphs not handled here");
|
||||
NS_ASSERTION(aIndex > 0 ||
|
||||
(aGlyph.IsClusterStart() && aGlyph.IsLigatureGroupStart()),
|
||||
"First character must be the start of a cluster and can't be a ligature continuation!");
|
||||
|
||||
DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, aCount);
|
||||
if (!details)
|
||||
return;
|
||||
|
||||
memcpy(details, aGlyphs, sizeof(DetailedGlyph)*aCount);
|
||||
mCharacterGlyphs[aIndex].SetComplexCluster();
|
||||
PRUint32 glyphCount = aGlyph.GetGlyphCount();
|
||||
if (glyphCount > 0) {
|
||||
DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, glyphCount);
|
||||
if (!details)
|
||||
return;
|
||||
memcpy(details, aGlyphs, sizeof(DetailedGlyph)*glyphCount);
|
||||
}
|
||||
mCharacterGlyphs[aIndex] = aGlyph;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gfxTextRun::SetMissingGlyph(PRUint32 aIndex, PRUint32 aChar)
|
||||
{
|
||||
@ -1832,7 +1745,6 @@ gfxTextRun::SetMissingGlyph(PRUint32 aIndex, PRUint32 aChar)
|
||||
if (!details)
|
||||
return;
|
||||
|
||||
details->mIsLastGlyph = PR_TRUE;
|
||||
details->mGlyphID = aChar;
|
||||
GlyphRun *glyphRun = &mGlyphRuns[FindFirstGlyphRunContaining(aIndex)];
|
||||
gfxFloat width = PR_MAX(glyphRun->mFont->GetMetrics().aveCharWidth,
|
||||
@ -1840,7 +1752,7 @@ gfxTextRun::SetMissingGlyph(PRUint32 aIndex, PRUint32 aChar)
|
||||
details->mAdvance = PRUint32(width*GetAppUnitsPerDevUnit());
|
||||
details->mXOffset = 0;
|
||||
details->mYOffset = 0;
|
||||
mCharacterGlyphs[aIndex].SetMissing();
|
||||
mCharacterGlyphs[aIndex].SetMissing(1);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1855,30 +1767,15 @@ gfxTextRun::RecordSurrogates(const PRUnichar *aString)
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
for (i = 0; i < mCharacterCount; ++i) {
|
||||
if (NS_IS_LOW_SURROGATE(aString[i])) {
|
||||
SetCharacterGlyph(i, g.SetLowSurrogate());
|
||||
SetGlyphs(i, g.SetLowSurrogate(), nsnull);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static PRUint32
|
||||
CountDetailedGlyphs(gfxTextRun::DetailedGlyph *aGlyphs)
|
||||
{
|
||||
PRUint32 i = 0;
|
||||
while (!aGlyphs[i].mIsLastGlyph) {
|
||||
++i;
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static void
|
||||
ClearCharacters(gfxTextRun::CompressedGlyph *aGlyphs, PRUint32 aLength)
|
||||
{
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
g.SetMissing();
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aLength; ++i) {
|
||||
aGlyphs[i] = g;
|
||||
}
|
||||
memset(aGlyphs, 0, sizeof(gfxTextRun::CompressedGlyph)*aLength);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1892,15 +1789,17 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, PRUint32 aStart,
|
||||
"Destination substring out of range");
|
||||
|
||||
PRUint32 i;
|
||||
// Copy base character data
|
||||
for (i = 0; i < aLength; ++i) {
|
||||
CompressedGlyph g = aSource->mCharacterGlyphs[i + aStart];
|
||||
g.SetCanBreakBefore(mCharacterGlyphs[i + aDest].CanBreakBefore());
|
||||
mCharacterGlyphs[i + aDest] = g;
|
||||
if (aStealData) {
|
||||
aSource->mCharacterGlyphs[i + aStart].SetMissing();
|
||||
aSource->mCharacterGlyphs[i + aStart].SetMissing(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy detailed glyphs
|
||||
if (aSource->mDetailedGlyphs) {
|
||||
for (i = 0; i < aLength; ++i) {
|
||||
DetailedGlyph *details = aSource->mDetailedGlyphs[i + aStart];
|
||||
@ -1916,7 +1815,7 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, PRUint32 aStart,
|
||||
mDetailedGlyphs[i + aDest] = details;
|
||||
aSource->mDetailedGlyphs[i + aStart].forget();
|
||||
} else {
|
||||
PRUint32 glyphCount = CountDetailedGlyphs(details);
|
||||
PRUint32 glyphCount = mCharacterGlyphs[i + aDest].GetGlyphCount();
|
||||
DetailedGlyph *dest = AllocateDetailedGlyphs(i + aDest, glyphCount);
|
||||
if (!dest) {
|
||||
ClearCharacters(&mCharacterGlyphs[aDest], aLength);
|
||||
@ -1934,6 +1833,7 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, PRUint32 aStart,
|
||||
}
|
||||
}
|
||||
|
||||
// Copy glyph runs
|
||||
GlyphRunIterator iter(aSource, aStart, aLength);
|
||||
#ifdef DEBUG
|
||||
gfxFont *lastFont = nsnull;
|
||||
@ -1983,7 +1883,7 @@ gfxTextRun::SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, PRUint32 aCharIn
|
||||
AddGlyphRun(aFont, aCharIndex);
|
||||
CompressedGlyph g;
|
||||
g.SetSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
|
||||
SetCharacterGlyph(aCharIndex, g);
|
||||
SetSimpleGlyph(aCharIndex, g);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2013,7 +1913,7 @@ gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext)
|
||||
if (!extents->IsGlyphKnown(glyphIndex)) {
|
||||
if (!fontIsSetup) {
|
||||
font->SetupCairoFont(aRefContext);
|
||||
fontIsSetup = PR_TRUE;
|
||||
fontIsSetup = PR_TRUE;
|
||||
}
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
++gGlyphExtentsSetupEagerSimple;
|
||||
@ -2021,9 +1921,11 @@ gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext)
|
||||
font->SetupGlyphExtents(aRefContext, glyphIndex, PR_FALSE, extents);
|
||||
}
|
||||
}
|
||||
} else if (glyphData->IsComplexCluster()) {
|
||||
} else {
|
||||
PRUint32 k;
|
||||
PRUint32 glyphCount = glyphData->GetGlyphCount();
|
||||
const gfxTextRun::DetailedGlyph *details = GetDetailedGlyphs(j);
|
||||
for (;;) {
|
||||
for (k = 0; k < glyphCount; ++k, ++details) {
|
||||
PRUint32 glyphIndex = details->mGlyphID;
|
||||
if (!extents->IsGlyphKnownWithTightExtents(glyphIndex)) {
|
||||
if (!fontIsSetup) {
|
||||
@ -2035,9 +1937,6 @@ gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext)
|
||||
#endif
|
||||
font->SetupGlyphExtents(aRefContext, glyphIndex, PR_TRUE, extents);
|
||||
}
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
++details;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -578,20 +578,20 @@ void gfxOS2FontGroup::CreateGlyphRunsFT(gfxTextRun *aTextRun, const PRUint8 *aUT
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(gid))
|
||||
{
|
||||
aTextRun->SetCharacterGlyph(utf16Offset,
|
||||
g.SetSimpleGlyph(advance, gid));
|
||||
aTextRun->SetSimpleGlyph(utf16Offset,
|
||||
g.SetSimpleGlyph(advance, gid));
|
||||
} else if (gid == 0) {
|
||||
// gid = 0 only happens when the glyph is missing from the font
|
||||
aTextRun->SetMissingGlyph(utf16Offset, ch);
|
||||
} else {
|
||||
gfxTextRun::DetailedGlyph details;
|
||||
details.mIsLastGlyph = PR_TRUE;
|
||||
details.mGlyphID = gid;
|
||||
NS_ASSERTION(details.mGlyphID == gid, "Seriously weird glyph ID detected!");
|
||||
details.mAdvance = advance;
|
||||
details.mXOffset = 0;
|
||||
details.mYOffset = 0;
|
||||
aTextRun->SetDetailedGlyphs(utf16Offset, &details, 1);
|
||||
g.SetComplex(aTextRun->IsClusterStart(utf16Offset), PR_TRUE, 1);
|
||||
aTextRun->SetGlyphs(utf16Offset, g, &details);
|
||||
}
|
||||
|
||||
NS_ASSERTION(!IS_SURROGATE(ch), "Surrogates shouldn't appear in UTF8");
|
||||
|
@ -740,7 +740,7 @@ SetupClusterBoundaries(gfxTextRun* aTextRun, const gchar *aUTF8, PRUint32 aUTF8L
|
||||
|
||||
while (p < end) {
|
||||
if (!attr->is_cursor_position) {
|
||||
aTextRun->SetCharacterGlyph(aUTF16Offset, g.SetClusterContinuation());
|
||||
aTextRun->SetGlyphs(aUTF16Offset, g.SetComplex(PR_FALSE, PR_TRUE, 0), nsnull);
|
||||
}
|
||||
++aUTF16Offset;
|
||||
|
||||
@ -799,14 +799,15 @@ SetGlyphsForCharacterGroup(const PangoGlyphInfo *aGlyphs, PRUint32 aGlyphCount,
|
||||
PRInt32 advance = ConvertPangoToAppUnits(width, appUnitsPerDevUnit);
|
||||
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
PRBool atClusterStart = aTextRun->IsClusterStart(utf16Offset);
|
||||
// See if we fit in the compressed area.
|
||||
if (aGlyphCount == 1 && advance >= 0 &&
|
||||
if (aGlyphCount == 1 && advance >= 0 && atClusterStart &&
|
||||
aGlyphs[0].geometry.x_offset == 0 &&
|
||||
aGlyphs[0].geometry.y_offset == 0 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(aGlyphs[0].glyph)) {
|
||||
aTextRun->SetCharacterGlyph(utf16Offset,
|
||||
g.SetSimpleGlyph(advance, aGlyphs[0].glyph));
|
||||
aTextRun->SetSimpleGlyph(utf16Offset,
|
||||
g.SetSimpleGlyph(advance, aGlyphs[0].glyph));
|
||||
} else {
|
||||
nsAutoTArray<gfxTextRun::DetailedGlyph,10> detailedGlyphs;
|
||||
if (!detailedGlyphs.AppendElements(aGlyphCount))
|
||||
@ -817,7 +818,6 @@ SetGlyphsForCharacterGroup(const PangoGlyphInfo *aGlyphs, PRUint32 aGlyphCount,
|
||||
gfxTextRun::DetailedGlyph *details = &detailedGlyphs[i];
|
||||
PRUint32 j = (aTextRun->IsRightToLeft()) ? aGlyphCount - 1 - i : i;
|
||||
const PangoGlyphInfo &glyph = aGlyphs[j];
|
||||
details->mIsLastGlyph = i == aGlyphCount - 1;
|
||||
details->mGlyphID = glyph.glyph;
|
||||
NS_ASSERTION(details->mGlyphID == glyph.glyph,
|
||||
"Seriously weird glyph ID detected!");
|
||||
@ -829,7 +829,8 @@ SetGlyphsForCharacterGroup(const PangoGlyphInfo *aGlyphs, PRUint32 aGlyphCount,
|
||||
details->mYOffset =
|
||||
float(glyph.geometry.y_offset)*appUnitsPerDevUnit/PANGO_SCALE;
|
||||
}
|
||||
aTextRun->SetDetailedGlyphs(utf16Offset, detailedGlyphs.Elements(), aGlyphCount);
|
||||
g.SetComplex(atClusterStart, PR_TRUE, aGlyphCount);
|
||||
aTextRun->SetGlyphs(utf16Offset, g, detailedGlyphs.Elements());
|
||||
}
|
||||
|
||||
// Check for ligatures and set *aUTF16Offset.
|
||||
@ -859,12 +860,8 @@ SetGlyphsForCharacterGroup(const PangoGlyphInfo *aGlyphs, PRUint32 aGlyphCount,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (! charGlyphs[utf16Offset].IsClusterContinuation()) {
|
||||
// This is a separate grapheme cluster but it has no glyphs.
|
||||
// It must be represented by a ligature with the previous
|
||||
// grapheme cluster.
|
||||
aTextRun->SetCharacterGlyph(utf16Offset, g.SetLigatureContinuation());
|
||||
}
|
||||
g.SetComplex(aTextRun->IsClusterStart(utf16Offset), PR_FALSE, 0);
|
||||
aTextRun->SetGlyphs(utf16Offset, g, nsnull);
|
||||
}
|
||||
*aUTF16Offset = utf16Offset;
|
||||
return NS_OK;
|
||||
@ -1050,18 +1047,18 @@ gfxPangoFontGroup::CreateGlyphRunsFast(gfxTextRun *aTextRun,
|
||||
if (advance >= 0 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph)) {
|
||||
aTextRun->SetCharacterGlyph(utf16Offset,
|
||||
g.SetSimpleGlyph(advance, glyph));
|
||||
aTextRun->SetSimpleGlyph(utf16Offset,
|
||||
g.SetSimpleGlyph(advance, glyph));
|
||||
} else {
|
||||
gfxTextRun::DetailedGlyph details;
|
||||
details.mIsLastGlyph = PR_TRUE;
|
||||
details.mGlyphID = glyph;
|
||||
NS_ASSERTION(details.mGlyphID == glyph,
|
||||
"Seriously weird glyph ID detected!");
|
||||
details.mAdvance = advance;
|
||||
details.mXOffset = 0;
|
||||
details.mYOffset = 0;
|
||||
aTextRun->SetDetailedGlyphs(utf16Offset, &details, 1);
|
||||
g.SetComplex(aTextRun->IsClusterStart(utf16Offset), PR_TRUE, 1);
|
||||
aTextRun->SetGlyphs(utf16Offset, g, &details);
|
||||
}
|
||||
|
||||
NS_ASSERTION(!IS_SURROGATE(ch), "Surrogates shouldn't appear in UTF8");
|
||||
|
@ -687,15 +687,14 @@ SetupTextRunFromGlyphs(gfxTextRun *aRun, WCHAR *aGlyphs, HDC aDC,
|
||||
if (advanceAppUnits >= 0 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advanceAppUnits) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph)) {
|
||||
aRun->SetCharacterGlyph(i, g.SetSimpleGlyph(advanceAppUnits, glyph));
|
||||
aRun->SetSimpleGlyph(i, g.SetSimpleGlyph(advanceAppUnits, glyph));
|
||||
} else {
|
||||
gfxTextRun::DetailedGlyph details;
|
||||
details.mIsLastGlyph = PR_TRUE;
|
||||
details.mGlyphID = glyph;
|
||||
details.mAdvance = advanceAppUnits;
|
||||
details.mXOffset = 0;
|
||||
details.mYOffset = 0;
|
||||
aRun->SetDetailedGlyphs(i, &details, 1);
|
||||
aRun->SetGlyphs(i, g.SetComplex(PR_TRUE, PR_TRUE, 1), &details);
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
@ -1064,7 +1063,7 @@ public:
|
||||
// it with so we just can't cluster it. So skip it here.
|
||||
for (PRUint32 i = 1; i < mRangeLength; ++i) {
|
||||
if (!logAttr[i].fCharStop) {
|
||||
aRun->SetCharacterGlyph(i + aOffsetInRun, g.SetClusterContinuation());
|
||||
aRun->SetGlyphs(i + aOffsetInRun, g.SetComplex(PR_FALSE, PR_TRUE, 0), nsnull);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1086,10 +1085,8 @@ public:
|
||||
while (offset < mRangeLength) {
|
||||
PRUint32 runOffset = offsetInRun + offset;
|
||||
if (offset > 0 && mClusters[offset] == mClusters[offset - 1]) {
|
||||
if (!aRun->GetCharacterGlyphs()[runOffset].IsClusterContinuation()) {
|
||||
// No glyphs for character 'index', it must be a ligature continuation
|
||||
aRun->SetCharacterGlyph(runOffset, g.SetLigatureContinuation());
|
||||
}
|
||||
g.SetComplex(aRun->IsClusterStart(runOffset), PR_FALSE, 0);
|
||||
aRun->SetGlyphs(runOffset, g, nsnull);
|
||||
} else {
|
||||
// Count glyphs for this character
|
||||
PRUint32 k = mClusters[offset];
|
||||
@ -1126,7 +1123,7 @@ public:
|
||||
mOffsets[k].dv == 0 && mOffsets[k].du == 0 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph)) {
|
||||
aRun->SetCharacterGlyph(runOffset, g.SetSimpleGlyph(advance, glyph));
|
||||
aRun->SetSimpleGlyph(runOffset, g.SetSimpleGlyph(advance, glyph));
|
||||
} else {
|
||||
if (detailedGlyphs.Length() < glyphCount) {
|
||||
if (!detailedGlyphs.AppendElements(glyphCount - detailedGlyphs.Length()))
|
||||
@ -1135,13 +1132,13 @@ public:
|
||||
PRUint32 i;
|
||||
for (i = 0; i < glyphCount; ++i) {
|
||||
gfxTextRun::DetailedGlyph *details = &detailedGlyphs[i];
|
||||
details->mIsLastGlyph = i == glyphCount - 1;
|
||||
details->mGlyphID = mGlyphs[k + i];
|
||||
details->mAdvance = mAdvances[k + i]*appUnitsPerDevUnit;
|
||||
details->mXOffset = float(mOffsets[k + i].du)*appUnitsPerDevUnit*aRun->GetDirection();
|
||||
details->mYOffset = float(mOffsets[k + i].dv)*appUnitsPerDevUnit;
|
||||
}
|
||||
aRun->SetDetailedGlyphs(runOffset, detailedGlyphs.Elements(), glyphCount);
|
||||
aRun->SetGlyphs(runOffset,
|
||||
g.SetComplex(PR_TRUE, PR_TRUE, glyphCount), detailedGlyphs.Elements());
|
||||
}
|
||||
}
|
||||
++offset;
|
||||
|
@ -2082,7 +2082,7 @@ CanAddSpacingAfter(gfxTextRun* aTextRun, PRUint32 aOffset)
|
||||
if (aOffset + 1 >= aTextRun->GetLength())
|
||||
return PR_TRUE;
|
||||
return aTextRun->IsClusterStart(aOffset + 1) &&
|
||||
!aTextRun->IsLigatureContinuation(aOffset + 1);
|
||||
aTextRun->IsLigatureGroupStart(aOffset + 1);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -180,14 +180,6 @@ nsTransformingTextRunFactory::MakeTextRun(const PRUint8* aString, PRUint32 aLeng
|
||||
aStyles, aOwnsFactory);
|
||||
}
|
||||
|
||||
static PRUint32
|
||||
CountGlyphs(const gfxTextRun::DetailedGlyph* aDetails) {
|
||||
PRUint32 glyphCount;
|
||||
for (glyphCount = 0; !aDetails[glyphCount].mIsLastGlyph; ++glyphCount) {
|
||||
}
|
||||
return glyphCount + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a given textrun, but merge certain characters into a single logical
|
||||
* character. Glyphs for a character are added to the glyph list for the previous
|
||||
@ -201,6 +193,9 @@ CountGlyphs(const gfxTextRun::DetailedGlyph* aDetails) {
|
||||
* glyph runs. It's hard to see how this could happen, but if it does, we just
|
||||
* discard the characters-to-merge.
|
||||
*
|
||||
* For simplicity, this produces a textrun containing all DetailedGlyphs,
|
||||
* no simple glyphs. So don't call it unless you really have merging to do.
|
||||
*
|
||||
* @param aCharsToMerge when aCharsToMerge[i] is true, this character is
|
||||
* merged into the previous character
|
||||
*/
|
||||
@ -210,68 +205,66 @@ MergeCharactersInTextRun(gfxTextRun* aDest, gfxTextRun* aSrc,
|
||||
{
|
||||
aDest->ResetGlyphRuns();
|
||||
|
||||
PRUint32 numGlyphRuns;
|
||||
const gfxTextRun::GlyphRun* glyphRuns = aSrc->GetGlyphRuns(&numGlyphRuns);
|
||||
gfxTextRun::GlyphRunIterator iter(aSrc, 0, aSrc->GetLength());
|
||||
PRUint32 offset = 0;
|
||||
PRUint32 j;
|
||||
for (j = 0; j < numGlyphRuns; ++j) {
|
||||
PRUint32 runOffset = glyphRuns[j].mCharacterOffset;
|
||||
PRUint32 len =
|
||||
(j + 1 < numGlyphRuns ? glyphRuns[j + 1].mCharacterOffset : aSrc->GetLength()) -
|
||||
runOffset;
|
||||
nsresult rv = aDest->AddGlyphRun(glyphRuns[j].mFont, offset);
|
||||
nsAutoTArray<gfxTextRun::DetailedGlyph,2> glyphs;
|
||||
while (iter.NextRun()) {
|
||||
gfxTextRun::GlyphRun* run = iter.GetGlyphRun();
|
||||
nsresult rv = aDest->AddGlyphRun(run->mFont, offset);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
PRBool anyMissing = PR_FALSE;
|
||||
PRUint32 mergeRunStart = iter.GetStringStart();
|
||||
PRUint32 k;
|
||||
for (k = 0; k < len; ++k) {
|
||||
if (aCharsToMerge[runOffset + k])
|
||||
continue;
|
||||
|
||||
gfxTextRun::CompressedGlyph g = aSrc->GetCharacterGlyphs()[runOffset + k];
|
||||
if (g.IsSimpleGlyph() || g.IsComplexCluster()) {
|
||||
PRUint32 mergedCount = 1;
|
||||
PRBool multipleGlyphs = PR_FALSE;
|
||||
while (k + mergedCount < len) {
|
||||
gfxTextRun::CompressedGlyph h = aSrc->GetCharacterGlyphs()[runOffset + k + mergedCount];
|
||||
if (!aCharsToMerge[runOffset + k + mergedCount] &&
|
||||
!h.IsClusterContinuation() && !h.IsLigatureContinuation())
|
||||
break;
|
||||
if (h.IsComplexCluster() || h.IsSimpleGlyph()) {
|
||||
multipleGlyphs = PR_TRUE;
|
||||
}
|
||||
++mergedCount;
|
||||
}
|
||||
if (g.IsSimpleGlyph() && !multipleGlyphs) {
|
||||
aDest->SetCharacterGlyph(offset, g);
|
||||
} else {
|
||||
// We have something complex to do.
|
||||
nsAutoTArray<gfxTextRun::DetailedGlyph,2> detailedGlyphs;
|
||||
PRUint32 m;
|
||||
for (m = 0; m < mergedCount; ++m) {
|
||||
gfxTextRun::CompressedGlyph h = aSrc->GetCharacterGlyphs()[runOffset + k + m];
|
||||
if (h.IsSimpleGlyph()) {
|
||||
gfxTextRun::DetailedGlyph* details = detailedGlyphs.AppendElement();
|
||||
if (!details)
|
||||
return;
|
||||
details->mGlyphID = h.GetSimpleGlyph();
|
||||
details->mAdvance = h.GetSimpleAdvance();
|
||||
details->mXOffset = 0;
|
||||
details->mYOffset = 0;
|
||||
} else if (h.IsComplexCluster()) {
|
||||
const gfxTextRun::DetailedGlyph* srcDetails = aSrc->GetDetailedGlyphs(runOffset + k + m);
|
||||
detailedGlyphs.AppendElements(srcDetails, CountGlyphs(srcDetails));
|
||||
}
|
||||
detailedGlyphs[detailedGlyphs.Length() - 1].mIsLastGlyph = PR_FALSE;
|
||||
}
|
||||
detailedGlyphs[detailedGlyphs.Length() - 1].mIsLastGlyph = PR_TRUE;
|
||||
aDest->SetDetailedGlyphs(offset, detailedGlyphs.Elements(), detailedGlyphs.Length());
|
||||
for (k = iter.GetStringStart(); k < iter.GetStringEnd(); ++k) {
|
||||
gfxTextRun::CompressedGlyph g = aSrc->GetCharacterGlyphs()[k];
|
||||
if (g.IsSimpleGlyph()) {
|
||||
if (!anyMissing) {
|
||||
gfxTextRun::DetailedGlyph details;
|
||||
details.mGlyphID = g.GetSimpleGlyph();
|
||||
details.mAdvance = g.GetSimpleAdvance();
|
||||
details.mXOffset = 0;
|
||||
details.mYOffset = 0;
|
||||
glyphs.AppendElement(details);
|
||||
}
|
||||
} else {
|
||||
aDest->SetCharacterGlyph(offset, g);
|
||||
if (g.IsMissing()) {
|
||||
anyMissing = PR_TRUE;
|
||||
glyphs.Clear();
|
||||
}
|
||||
glyphs.AppendElements(aSrc->GetDetailedGlyphs(k), g.GetGlyphCount());
|
||||
}
|
||||
|
||||
// We could teach this method to handle merging of characters that aren't
|
||||
// cluster starts or ligature group starts, but this is really only used
|
||||
// to merge S's (uppercase ß), so it's not worth it.
|
||||
|
||||
if (k + 1 < iter.GetStringEnd() && aCharsToMerge[k + 1]) {
|
||||
NS_ASSERTION(g.IsClusterStart() && g.IsLigatureGroupStart() &&
|
||||
!g.IsLowSurrogate(),
|
||||
"Don't know how to merge this stuff");
|
||||
continue;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mergeRunStart == k ||
|
||||
(g.IsClusterStart() && g.IsLigatureGroupStart() &&
|
||||
!g.IsLowSurrogate()),
|
||||
"Don't know how to merge this stuff");
|
||||
|
||||
if (anyMissing) {
|
||||
g.SetMissing(glyphs.Length());
|
||||
} else {
|
||||
g.SetComplex(PR_TRUE, PR_TRUE, glyphs.Length());
|
||||
}
|
||||
aDest->SetGlyphs(offset, g, glyphs.Elements());
|
||||
++offset;
|
||||
glyphs.Clear();
|
||||
anyMissing = PR_FALSE;
|
||||
mergeRunStart = k + 1;
|
||||
}
|
||||
NS_ASSERTION(glyphs.Length() == 0,
|
||||
"Leftover glyphs, don't request merging of the last character with its next!");
|
||||
}
|
||||
NS_ASSERTION(offset == aDest->GetLength(), "Bad offset calculations");
|
||||
}
|
||||
@ -510,6 +503,15 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
||||
"Dropped characters or break-before values somewhere!");
|
||||
child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(),
|
||||
canBreakBeforeArray.Elements(), aRefContext);
|
||||
// Now merge multiple characters into one multi-glyph character as required
|
||||
MergeCharactersInTextRun(aTextRun, child, charsToMergeArray.Elements());
|
||||
|
||||
if (extraCharsCount > 0) {
|
||||
// Now merge multiple characters into one multi-glyph character as required
|
||||
MergeCharactersInTextRun(aTextRun, child, charsToMergeArray.Elements());
|
||||
} else {
|
||||
// No merging to do, so just copy; this produces a more optimized textrun.
|
||||
// We can't steal the data because the child may be cached and stealing
|
||||
// the data would break the cache.
|
||||
aTextRun->ResetGlyphRuns();
|
||||
aTextRun->CopyGlyphDataFrom(child, 0, child->GetLength(), 0, PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user