зеркало из https://github.com/mozilla/gecko-dev.git
Backout the last couple of gfx checkins because the bugs and patches were mixed up. I'll reland.
This commit is contained in:
Родитель
7e6c86eff8
Коммит
5d0896ff66
|
@ -11,7 +11,7 @@ MODULE = thebes
|
|||
DIRS = public src
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
TOOL_DIRS += test
|
||||
# TOOL_DIRS += test
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -103,11 +103,11 @@ public:
|
|||
Parameters* aParams);
|
||||
virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
|
||||
Parameters* aParams);
|
||||
// Here, aString is actually aLength + aHeaderChars*2 chars long; the first char
|
||||
// may be a LRO or RLO bidi control character to force setting the direction
|
||||
// for all characters, and if so the last character will be a PDF
|
||||
// Here, aString is actually aLength + 1 chars long; the first char
|
||||
// is an LRO or RLO bidi control character to force setting the direction
|
||||
// for all characters
|
||||
gfxTextRun *MakeTextRunInternal(const PRUnichar *aString, PRUint32 aLength,
|
||||
Parameters *aParams, PRUint32 aheaderChars);
|
||||
Parameters *aParams);
|
||||
|
||||
ATSUFontFallbacks *GetATSUFontFallbacksPtr() { return &mFallbacks; }
|
||||
|
||||
|
@ -122,8 +122,7 @@ protected:
|
|||
const nsACString& aGenericName,
|
||||
void *closure);
|
||||
|
||||
void InitTextRun(gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength,
|
||||
PRUint32 aHeaderChars);
|
||||
void InitTextRun(gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength);
|
||||
|
||||
ATSUFontFallbacks mFallbacks;
|
||||
};
|
||||
|
|
|
@ -142,7 +142,7 @@ public:
|
|||
const nsString& GetName() const { return mName; }
|
||||
const gfxFontStyle *GetStyle() const { return mStyle; }
|
||||
|
||||
virtual nsString GetUniqueName() = 0;
|
||||
virtual nsString GetUniqueName() { return GetName(); }
|
||||
|
||||
// Font metrics
|
||||
struct Metrics {
|
||||
|
@ -175,9 +175,6 @@ public:
|
|||
* We let layout specify spacing on either side of any
|
||||
* character. We need to specify both before and after
|
||||
* spacing so that substring measurement can do the right things.
|
||||
* These values are in appunits. They're always an integral number of
|
||||
* appunits, but we specify them in floats in case very large spacing
|
||||
* values are required.
|
||||
*/
|
||||
struct Spacing {
|
||||
gfxFloat mBefore;
|
||||
|
@ -232,8 +229,7 @@ public:
|
|||
* @param aEnd draw characters up to here
|
||||
* @param aBaselineOrigin the baseline origin; the left end of the baseline
|
||||
* for LTR textruns, the right end of the baseline for RTL textruns. On return,
|
||||
* this should be updated to the other end of the baseline. In application
|
||||
* units, really!
|
||||
* this should be updated to the other end of the baseline. In application units.
|
||||
* @param aSpacing spacing to insert before and after characters (for RTL
|
||||
* glyphs, before-spacing is inserted to the right of characters). There
|
||||
* are aEnd - aStart elements in this array, unless it's null to indicate
|
||||
|
@ -423,17 +419,7 @@ public:
|
|||
* It is important that zero-length substrings are handled correctly. This will
|
||||
* be on the test!
|
||||
*
|
||||
* gfxTextRun stores a list of zero or more glyphs for each character. For each
|
||||
* glyph we store the glyph ID, the advance, and possibly an xoffset and yoffset.
|
||||
* The idea is that a string is rendered by a loop that draws each glyph
|
||||
* at its designated offset from the current point, then advances the current
|
||||
* point by the glyph's advance in the direction of the textrun (LTR or RTL).
|
||||
* Each glyph advance is always rounded to the nearest appunit; this ensures
|
||||
* consistent results when dividing the text in a textrun into multiple text
|
||||
* frames (frame boundaries are always aligned to appunits). We optimize
|
||||
* for the case where a character has a single glyph and zero xoffset and yoffset,
|
||||
* and the glyph ID and advance are in a reasonable range so we can pack all
|
||||
* necessary data into 32 bits.
|
||||
* This class should not be subclassed.
|
||||
*/
|
||||
class THEBES_API gfxTextRun {
|
||||
public:
|
||||
|
@ -693,7 +679,7 @@ public:
|
|||
void *GetUserData() const { return mUserData; }
|
||||
PRUint32 GetFlags() const { return mFlags; }
|
||||
const gfxSkipChars& GetSkipChars() const { return mSkipChars; }
|
||||
PRUint32 GetAppUnitsPerDevUnit() const { return mAppUnitsPerDevUnit; }
|
||||
float GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; }
|
||||
|
||||
// The caller is responsible for initializing our glyphs after construction.
|
||||
// Initially all glyphs are such that GetCharacterGlyphs()[i].IsMissing() is true.
|
||||
|
@ -719,7 +705,6 @@ public:
|
|||
// Indicates that a linebreak is allowed before this character
|
||||
FLAG_CAN_BREAK_BEFORE = 0x40000000U,
|
||||
|
||||
// The advance is stored in appunits
|
||||
ADVANCE_MASK = 0x3FFF0000U,
|
||||
ADVANCE_SHIFT = 16,
|
||||
|
||||
|
@ -765,7 +750,7 @@ public:
|
|||
}
|
||||
// Returns true if the advance aAdvance fits into the compressed representation.
|
||||
// aAdvance is in pixels.
|
||||
static PRBool IsSimpleAdvance(PRUint32 aAdvance) {
|
||||
static PRBool IsSimpleAdvancePixels(PRUint32 aAdvance) {
|
||||
return (aAdvance & (ADVANCE_MASK >> ADVANCE_SHIFT)) == aAdvance;
|
||||
}
|
||||
|
||||
|
@ -793,7 +778,7 @@ public:
|
|||
}
|
||||
|
||||
CompressedGlyph& SetSimpleGlyph(PRUint32 aAdvancePixels, PRUint32 aGlyph) {
|
||||
NS_ASSERTION(IsSimpleAdvance(aAdvancePixels), "Advance overflow");
|
||||
NS_ASSERTION(IsSimpleAdvancePixels(aAdvancePixels), "Advance overflow");
|
||||
NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow");
|
||||
mValue = (mValue & FLAG_CAN_BREAK_BEFORE) | FLAG_IS_SIMPLE_GLYPH |
|
||||
(aAdvancePixels << ADVANCE_SHIFT) | aGlyph;
|
||||
|
@ -821,9 +806,8 @@ public:
|
|||
* us track the length of the array. */
|
||||
PRUint32 mIsLastGlyph:1;
|
||||
PRUint32 mGlyphID:31;
|
||||
// The advance, x-offset and y-offset of the glyph, in appunits
|
||||
PRInt32 mAdvance;
|
||||
float mXOffset, mYOffset;
|
||||
// The advance, x-offset and y-offset of the glyph, in pixels
|
||||
float mAdvance, mXOffset, mYOffset;
|
||||
};
|
||||
|
||||
// The text is divided into GlyphRuns as necessary
|
||||
|
@ -909,8 +893,8 @@ private:
|
|||
// Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
|
||||
PRUint32 FindFirstGlyphRunContaining(PRUint32 aOffset);
|
||||
// Computes the x-advance for a given cluster starting at aClusterOffset. Does
|
||||
// not include any spacing. Result is in appunits.
|
||||
PRInt32 ComputeClusterAdvance(PRUint32 aClusterOffset);
|
||||
// not include any spacing. Result is in device pixels.
|
||||
gfxFloat ComputeClusterAdvance(PRUint32 aClusterOffset);
|
||||
|
||||
// **** ligature helpers ****
|
||||
// (Platforms do the actual ligaturization, but we need to do a bunch of stuff
|
||||
|
@ -921,7 +905,7 @@ private:
|
|||
PRUint32 mEndOffset;
|
||||
PRUint32 mClusterCount;
|
||||
PRUint32 mPartClusterIndex;
|
||||
PRInt32 mLigatureWidth; // appunits
|
||||
gfxFloat mLigatureWidth; // appunits
|
||||
gfxFloat mBeforeSpacing; // appunits
|
||||
gfxFloat mAfterSpacing; // appunits
|
||||
};
|
||||
|
@ -935,8 +919,8 @@ private:
|
|||
void DrawPartialLigature(gfxFont *aFont, gfxContext *aCtx, PRUint32 aOffset,
|
||||
const gfxRect *aDirtyRect, gfxPoint *aPt,
|
||||
PropertyProvider *aProvider);
|
||||
void ShrinkToLigatureBoundaries(PRUint32 *aStart, PRUint32 *aEnd);
|
||||
// result in appunits
|
||||
void ShrinkToLigatureBoundaries(PRUint32 *aStart, PRUint32 *aEnd);
|
||||
gfxFloat GetPartialLigatureWidth(PRUint32 aStart, PRUint32 aEnd, PropertyProvider *aProvider);
|
||||
void AccumulatePartialLigatureMetrics(gfxFont *aFont,
|
||||
PRUint32 aOffset, PRBool aTight,
|
||||
|
@ -963,7 +947,9 @@ private:
|
|||
|
||||
void *mUserData;
|
||||
gfxSkipChars mSkipChars;
|
||||
PRUint32 mAppUnitsPerDevUnit;
|
||||
// This is actually an integer, but we keep it in float form to reduce
|
||||
// the conversions required
|
||||
float mAppUnitsPerDevUnit;
|
||||
PRUint32 mFlags;
|
||||
PRUint32 mCharacterCount;
|
||||
};
|
||||
|
|
|
@ -82,8 +82,6 @@ public:
|
|||
PRBool aTightBoundingBox,
|
||||
Spacing *aSpacing);
|
||||
|
||||
virtual nsString GetUniqueName();
|
||||
|
||||
protected:
|
||||
PangoFontDescription *mPangoFontDesc;
|
||||
PangoContext *mPangoCtx;
|
||||
|
|
|
@ -376,7 +376,7 @@ SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString, PRUint32
|
|||
|
||||
gfxTextRun *
|
||||
gfxAtsuiFontGroup::MakeTextRunInternal(const PRUnichar *aString, PRUint32 aLength,
|
||||
Parameters *aParams, PRUint32 aHeaderChars)
|
||||
Parameters *aParams)
|
||||
{
|
||||
// NS_ASSERTION(!(aParams->mFlags & TEXT_NEED_BOUNDING_BOX),
|
||||
// "Glyph extents not yet supported");
|
||||
|
@ -386,12 +386,12 @@ gfxAtsuiFontGroup::MakeTextRunInternal(const PRUnichar *aString, PRUint32 aLengt
|
|||
return nsnull;
|
||||
|
||||
// There's a one-char header in the string and a one-char trailer
|
||||
textRun->RecordSurrogates(aString + aHeaderChars);
|
||||
textRun->RecordSurrogates(aString + 1);
|
||||
if (!(aParams->mFlags & TEXT_IS_8BIT)) {
|
||||
SetupClusterBoundaries(textRun, aString + aHeaderChars, aLength);
|
||||
SetupClusterBoundaries(textRun, aString + 1, aLength);
|
||||
}
|
||||
|
||||
InitTextRun(textRun, aString, aLength, aHeaderChars);
|
||||
InitTextRun(textRun, aString, aLength);
|
||||
return textRun;
|
||||
}
|
||||
|
||||
|
@ -414,7 +414,7 @@ gfxAtsuiFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
|
|||
AppendDirectionalIndicator(aParams->mFlags, utf16);
|
||||
utf16.Append(aString, aLength);
|
||||
utf16.Append(UNICODE_PDF);
|
||||
return MakeTextRunInternal(utf16.get(), aLength, aParams, 1);
|
||||
return MakeTextRunInternal(utf16.get(), aLength, aParams);
|
||||
}
|
||||
|
||||
gfxTextRun *
|
||||
|
@ -425,16 +425,10 @@ gfxAtsuiFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
|
|||
nsDependentCSubstring cString(reinterpret_cast<const char*>(aString),
|
||||
reinterpret_cast<const char*>(aString + aLength));
|
||||
nsAutoString utf16;
|
||||
PRUint32 headerChars = 0;
|
||||
if (aParams->mFlags & TEXT_IS_RTL) {
|
||||
AppendDirectionalIndicator(aParams->mFlags, utf16);
|
||||
headerChars = 1;
|
||||
}
|
||||
AppendDirectionalIndicator(aParams->mFlags, utf16);
|
||||
AppendASCIItoUTF16(cString, utf16);
|
||||
if (aParams->mFlags & TEXT_IS_RTL) {
|
||||
utf16.Append(UNICODE_PDF);
|
||||
}
|
||||
return MakeTextRunInternal(utf16.get(), aLength, aParams, headerChars);
|
||||
utf16.Append(UNICODE_PDF);
|
||||
return MakeTextRunInternal(utf16.get(), aLength, aParams);
|
||||
}
|
||||
|
||||
gfxAtsuiFont*
|
||||
|
@ -488,121 +482,41 @@ private:
|
|||
ATSUDirectDataSelector mSelector;
|
||||
};
|
||||
|
||||
#define ATSUI_SPECIAL_GLYPH_ID 0xFFFF
|
||||
|
||||
/**
|
||||
* Calculate the advance in appunits of a run of ATSUI glyphs
|
||||
* Abstraction to iterate through an array in strange order. It just remaps
|
||||
* array indices. Tragically we mainly need this because of ATSUI bugs.
|
||||
* There are four cases we need to handle. Note that 0 <= i < L in all cases.
|
||||
* 1) f(i) = i (LTR, no bug, most common)
|
||||
* 2) f(i) = L - 1 - i (RTL, no bug, next most common)
|
||||
* 3) f(i) = i < N ? N - 1 - i : i; (compensate for ATSUI bug in RTL mode)
|
||||
* 4) f(i) = i < N ? i + L - N : L - 1 - i (compensate for ATSUI bug in LTR mode)
|
||||
* We collapse 2) into 3) by setting N=L.
|
||||
* We collapse 1) into 4) by setting N=L.
|
||||
*/
|
||||
static PRInt32
|
||||
GetAdvanceAppUnits(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||
PRUint32 aAppUnitsPerDevUnit)
|
||||
{
|
||||
Fixed fixedAdvance = aGlyphs[aGlyphCount].realPos - aGlyphs->realPos;
|
||||
return PRInt32((PRInt64(fixedAdvance)*aAppUnitsPerDevUnit + (1 << 15)) >> 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
gfxTextRun *aRun)
|
||||
{
|
||||
NS_ASSERTION(aGlyphCount > 0, "Must set at least one glyph");
|
||||
PRUint32 firstOffset = aGlyphs[0].originalOffset;
|
||||
PRUint32 lastOffset = firstOffset;
|
||||
PRUint32 i;
|
||||
PRUint32 regularGlyphCount = 0;
|
||||
ATSLayoutRecord *displayGlyph = nsnull;
|
||||
PRBool inOrder = PR_TRUE;
|
||||
|
||||
for (i = 0; i < aGlyphCount; ++i) {
|
||||
ATSLayoutRecord *glyph = &aGlyphs[i];
|
||||
PRUint32 offset = glyph->originalOffset;
|
||||
firstOffset = PR_MIN(firstOffset, offset);
|
||||
lastOffset = PR_MAX(lastOffset, offset);
|
||||
if (glyph->glyphID != ATSUI_SPECIAL_GLYPH_ID) {
|
||||
++regularGlyphCount;
|
||||
displayGlyph = glyph;
|
||||
}
|
||||
if (i > 0 && aRun->IsRightToLeft() != (offset < aGlyphs[i - 1].originalOffset)) {
|
||||
inOrder = PR_FALSE;
|
||||
class GlyphMapper {
|
||||
public:
|
||||
GlyphMapper(PRBool aIsRTL, PRUint32 aL, PRUint32 aN)
|
||||
: mL(aL), mN(aN), mRTL(aIsRTL) {}
|
||||
PRUint32 MapIndex(PRUint32 aIndex)
|
||||
{
|
||||
if (mRTL) {
|
||||
return aIndex < mN ? mN - 1 - aIndex : aIndex;
|
||||
} else {
|
||||
return aIndex < mN ? aIndex + mL - mN : mL - 1 - aIndex;
|
||||
}
|
||||
}
|
||||
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
PRUint32 offset;
|
||||
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(index, g.SetClusterContinuation());
|
||||
} else if (!aRun->GetCharacterGlyphs()[index].IsClusterContinuation()) {
|
||||
aRun->SetCharacterGlyph(index, g.SetLigatureContinuation());
|
||||
}
|
||||
}
|
||||
|
||||
// Grab total advance for all glyphs
|
||||
PRInt32 advance = GetAdvanceAppUnits(aGlyphs, aGlyphCount, aAppUnitsPerDevUnit);
|
||||
PRUint32 index = firstOffset/2;
|
||||
if (regularGlyphCount == 1) {
|
||||
if (advance >= 0 &&
|
||||
(!aBaselineDeltas || aBaselineDeltas[displayGlyph - aGlyphs] == 0) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(displayGlyph->glyphID)) {
|
||||
aRun->SetCharacterGlyph(index, g.SetSimpleGlyph(advance, displayGlyph->glyphID));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoTArray<gfxTextRun::DetailedGlyph,10> detailedGlyphs;
|
||||
ATSLayoutRecord *advanceStart = aGlyphs;
|
||||
for (i = 0; i < aGlyphCount; ++i) {
|
||||
ATSLayoutRecord *glyph = &aGlyphs[i];
|
||||
if (glyph->glyphID != ATSUI_SPECIAL_GLYPH_ID || regularGlyphCount == 0) {
|
||||
if (detailedGlyphs.Length() > 0) {
|
||||
detailedGlyphs[detailedGlyphs.Length() - 1].mAdvance =
|
||||
GetAdvanceAppUnits(advanceStart, glyph - advanceStart, aAppUnitsPerDevUnit);
|
||||
advanceStart = glyph;
|
||||
}
|
||||
|
||||
gfxTextRun::DetailedGlyph *details = detailedGlyphs.AppendElement();
|
||||
if (!details)
|
||||
return;
|
||||
details->mIsLastGlyph = PR_FALSE;
|
||||
details->mGlyphID = glyph->glyphID;
|
||||
details->mXOffset = 0;
|
||||
details->mYOffset = !aBaselineDeltas ? 0.0f
|
||||
: FixedToFloat(aBaselineDeltas[i])*aAppUnitsPerDevUnit;
|
||||
}
|
||||
}
|
||||
if (detailedGlyphs.Length() == 0) {
|
||||
NS_WARNING("No glyphs visible at all!");
|
||||
aRun->SetCharacterGlyph(index, g.SetMissing());
|
||||
return;
|
||||
}
|
||||
|
||||
detailedGlyphs[detailedGlyphs.Length() - 1].mIsLastGlyph = PR_TRUE;
|
||||
detailedGlyphs[detailedGlyphs.Length() - 1].mAdvance =
|
||||
GetAdvanceAppUnits(advanceStart, aGlyphs + aGlyphCount - advanceStart, aAppUnitsPerDevUnit);
|
||||
// Should pass unmatchedness here but for now we'll just not tell the textrun
|
||||
// whether these are "missing glyph" glyphs or not
|
||||
aRun->SetDetailedGlyphs(index, detailedGlyphs.Elements(), detailedGlyphs.Length());
|
||||
}
|
||||
private:
|
||||
PRUint32 mL, mN;
|
||||
PRBool mRTL;
|
||||
};
|
||||
|
||||
static void
|
||||
PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
||||
const PRUnichar *aString, const PRPackedBool *aUnmatched)
|
||||
const PRUnichar *aString)
|
||||
{
|
||||
// AutoLayoutDataArrayPtr advanceDeltasArray(aLine, kATSUDirectDataAdvanceDeltaFixedArray);
|
||||
// Fixed *advanceDeltas = NS_STATIC_CAST(Fixed *, advanceDeltasArray.mArray);
|
||||
// AutoLayoutDataArrayPtr deviceDeltasArray(aLine, kATSUDirectDataDeviceDeltaSInt16Array);
|
||||
AutoLayoutDataArrayPtr advanceDeltasArray(aLine, kATSUDirectDataAdvanceDeltaFixedArray);
|
||||
AutoLayoutDataArrayPtr baselineDeltasArray(aLine, kATSUDirectDataBaselineDeltaFixedArray);
|
||||
Fixed *baselineDeltas = NS_STATIC_CAST(Fixed *, baselineDeltasArray.mArray);
|
||||
AutoLayoutDataArrayPtr deviceDeltasArray(aLine, kATSUDirectDataDeviceDeltaSInt16Array);
|
||||
AutoLayoutDataArrayPtr glyphRecordsArray(aLine, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent);
|
||||
|
||||
PRUint32 numGlyphs = glyphRecordsArray.mItemCount;
|
||||
|
@ -610,8 +524,11 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
|||
NS_WARNING("Failed to retrieve key glyph data");
|
||||
return;
|
||||
}
|
||||
Fixed *advanceDeltas = NS_STATIC_CAST(Fixed *, advanceDeltasArray.mArray);
|
||||
Fixed *baselineDeltas = NS_STATIC_CAST(Fixed *, baselineDeltasArray.mArray);
|
||||
ATSLayoutRecord *glyphRecords = NS_STATIC_CAST(ATSLayoutRecord *, glyphRecordsArray.mArray);
|
||||
NS_ASSERTION(!baselineDeltas || baselineDeltasArray.mItemCount == numGlyphs,
|
||||
NS_ASSERTION((!advanceDeltas || advanceDeltasArray.mItemCount == numGlyphs) &&
|
||||
(!baselineDeltas || baselineDeltasArray.mItemCount == numGlyphs),
|
||||
"Mismatched glyph counts");
|
||||
NS_ASSERTION(glyphRecords[numGlyphs - 1].flags & kATSGlyphInfoTerminatorGlyph,
|
||||
"Last glyph should be a terminator glyph");
|
||||
|
@ -619,8 +536,9 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
|||
if (numGlyphs == 0)
|
||||
return;
|
||||
|
||||
const PRUint32 appUnitsPerDevUnit = aRun->GetAppUnitsPerDevUnit();
|
||||
|
||||
PRUint32 index = 0;
|
||||
ItemCount k = 0;
|
||||
PRUint32 length = aRun->GetLength();
|
||||
// ATSUI seems to have a bug where trailing whitespace in a run,
|
||||
// even after we've forced the direction with LRO/RLO/PDF, does not
|
||||
// necessarily get the required direction.
|
||||
|
@ -633,93 +551,141 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
|||
// being rendered in LTR order at the end of the glyph array.
|
||||
// In LTR situations, the bug manifests as the trailing whitespace characters
|
||||
// being rendered in RTL order at the start of the glyph array.
|
||||
// Compensate for this bug now by detecting those characters, setting up
|
||||
// the glyphs for those characters, and then chopping those glyphs off
|
||||
// the glyph array we need to look at.
|
||||
PRUint32 stringTailOffset = aRun->GetLength() - 1;
|
||||
PRBool isRTL = aRun->IsRightToLeft();
|
||||
if (isRTL) {
|
||||
while (numGlyphs > 0 &&
|
||||
glyphRecords[numGlyphs - 1].originalOffset == stringTailOffset*2 &&
|
||||
aString[stringTailOffset] == ' ') {
|
||||
SetGlyphsForCharacterGroup(glyphRecords + numGlyphs - 1, 1,
|
||||
baselineDeltas ? baselineDeltas + numGlyphs - 1 : nsnull,
|
||||
appUnitsPerDevUnit, aRun);
|
||||
--stringTailOffset;
|
||||
--numGlyphs;
|
||||
}
|
||||
} else {
|
||||
while (numGlyphs > 0 &&
|
||||
glyphRecords[0].originalOffset == stringTailOffset*2 &&
|
||||
aString[stringTailOffset] == ' ') {
|
||||
SetGlyphsForCharacterGroup(glyphRecords, 1,
|
||||
baselineDeltas,
|
||||
appUnitsPerDevUnit, aRun);
|
||||
--stringTailOffset;
|
||||
--numGlyphs;
|
||||
++glyphRecords;
|
||||
}
|
||||
PRUint32 incorrectDirectionGlyphCount = 0;
|
||||
PRUint32 stringTailOffset = length - 1;
|
||||
while (glyphRecords[aRun->IsRightToLeft() ? numGlyphs - 1 - incorrectDirectionGlyphCount
|
||||
: incorrectDirectionGlyphCount].originalOffset == stringTailOffset*2 &&
|
||||
aString[stringTailOffset] == ' ') {
|
||||
++incorrectDirectionGlyphCount;
|
||||
stringTailOffset--;
|
||||
if (incorrectDirectionGlyphCount == numGlyphs)
|
||||
break;
|
||||
}
|
||||
GlyphMapper mapper(aRun->IsRightToLeft(), numGlyphs,
|
||||
numGlyphs - incorrectDirectionGlyphCount);
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
nsAutoTArray<gfxTextRun::DetailedGlyph,1> detailedGlyphs;
|
||||
PRBool gotRealCharacter = PR_FALSE;
|
||||
while (index < length) {
|
||||
ATSLayoutRecord *glyph = nsnull;
|
||||
// ATSUI sometimes moves glyphs around in visual order to handle
|
||||
// situations such as DEVANAGARI VOWEL I appearing before its base
|
||||
// character (even though it follows the base character in the text).
|
||||
// To handle this we make the reordered glyph(s) and the characters
|
||||
// they're reordered around into a single cluster.
|
||||
PRUint32 forceClusterGlyphs = 0;
|
||||
PRUint32 nextIndex = index + 1;
|
||||
if (k < numGlyphs) {
|
||||
glyph = &glyphRecords[mapper.MapIndex(k)];
|
||||
// originalOffset is in bytes, so we need to adjust index by 2 for comparisons
|
||||
if (glyph->originalOffset > 2*index) {
|
||||
// Detect the situation above. We assume that at most
|
||||
// two glyphs have been moved from after a run of characters
|
||||
// to visually before the run of characters, so the following glyph
|
||||
// or the next glyph is a glyph for the current character.
|
||||
// We can tweak this up if necessary...
|
||||
const PRUint32 MAX_GLYPHS_REORDERED = 10;
|
||||
PRUint32 reorderedGlyphs = 0;
|
||||
PRUint32 i;
|
||||
PRUint32 maxOffset = glyph->originalOffset;
|
||||
for (i = 1; k + i < numGlyphs; ++i) {
|
||||
ATSLayoutRecord *nextGlyph = &glyphRecords[mapper.MapIndex(k + i)];
|
||||
if (i == MAX_GLYPHS_REORDERED || nextGlyph->originalOffset == 2*index) {
|
||||
reorderedGlyphs = i;
|
||||
break;
|
||||
}
|
||||
maxOffset = PR_MAX(maxOffset, nextGlyph->originalOffset);
|
||||
}
|
||||
if (reorderedGlyphs > 0) {
|
||||
forceClusterGlyphs = reorderedGlyphs;
|
||||
while (k + forceClusterGlyphs < numGlyphs) {
|
||||
ATSLayoutRecord *nextGlyph = &glyphRecords[mapper.MapIndex(k + forceClusterGlyphs)];
|
||||
if (nextGlyph->originalOffset > maxOffset)
|
||||
break;
|
||||
++forceClusterGlyphs;
|
||||
}
|
||||
nextIndex = maxOffset/2 + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now process the rest of the glyphs, which should basically be in
|
||||
// the textrun's desired order, so process them in textrun order
|
||||
PRInt32 direction = PRInt32(aRun->GetDirection());
|
||||
while (numGlyphs > 0) {
|
||||
PRUint32 glyphIndex = isRTL ? numGlyphs - 1 : 0;
|
||||
PRUint32 lastOffset = glyphRecords[glyphIndex].originalOffset;
|
||||
PRUint32 glyphCount = 1;
|
||||
// Determine the glyphs for this group
|
||||
while (glyphCount < numGlyphs) {
|
||||
ATSLayoutRecord *glyph = &glyphRecords[glyphIndex + direction*glyphCount];
|
||||
PRUint32 glyphOffset = glyph->originalOffset;
|
||||
// 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) {
|
||||
// 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
|
||||
break;
|
||||
if (k == numGlyphs ||
|
||||
(glyph->originalOffset > 2*index && !forceClusterGlyphs)) {
|
||||
NS_ASSERTION(index > 0, "Continuation at the start of a run??");
|
||||
if (!aRun->GetCharacterGlyphs()[index].IsClusterContinuation()) {
|
||||
if (gotRealCharacter) {
|
||||
// No glyphs for character 'index', it must be a ligature continuation
|
||||
aRun->SetCharacterGlyph(index, g.SetLigatureContinuation());
|
||||
} else {
|
||||
// Don't allow ligature continuations until we've actually
|
||||
// got something for them to be a continuation of
|
||||
aRun->SetCharacterGlyph(index, g.SetMissing());
|
||||
}
|
||||
if (aUnmatched && aUnmatched[glyphOffset/2]) {
|
||||
// Next character is ummatched, so definitely stop the group here
|
||||
break;
|
||||
}
|
||||
// Otherwise the next glyph is, we assume, a ligature continuation.
|
||||
// Record that this character too is part of the group
|
||||
lastOffset = glyphOffset;
|
||||
}
|
||||
++glyphCount;
|
||||
}
|
||||
if (isRTL) {
|
||||
SetGlyphsForCharacterGroup(glyphRecords + numGlyphs - glyphCount,
|
||||
glyphCount,
|
||||
baselineDeltas ? baselineDeltas + numGlyphs - glyphCount : nsnull,
|
||||
appUnitsPerDevUnit, aRun);
|
||||
} else {
|
||||
SetGlyphsForCharacterGroup(glyphRecords,
|
||||
glyphCount, baselineDeltas,
|
||||
appUnitsPerDevUnit, aRun);
|
||||
glyphRecords += glyphCount;
|
||||
if (baselineDeltas) {
|
||||
baselineDeltas += glyphCount;
|
||||
NS_ASSERTION(glyph->originalOffset >= 2*index, "Lost some glyphs");
|
||||
PRUint32 glyphCount = 1;
|
||||
if (forceClusterGlyphs) {
|
||||
glyphCount = forceClusterGlyphs;
|
||||
PRUint32 i;
|
||||
// Mark all the characters that we forced to cluster, other
|
||||
// than this leading character, as cluster continuations.
|
||||
for (i = 0; i < forceClusterGlyphs; ++i) {
|
||||
PRUint32 offset = glyphRecords[mapper.MapIndex(k + i)].originalOffset;
|
||||
if (offset != 2*index) {
|
||||
aRun->SetCharacterGlyph(offset/2, g.SetClusterContinuation());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Find all the glyphs associated with this character
|
||||
while (k + glyphCount < numGlyphs &&
|
||||
glyphRecords[mapper.MapIndex(k + glyphCount)].originalOffset == 2*index) {
|
||||
++glyphCount;
|
||||
}
|
||||
}
|
||||
Fixed advance = glyph[1].realPos - glyph->realPos;
|
||||
PRUint32 advancePixels = advance >> 16;
|
||||
// "Fixed" values have their fraction in the low 16 bits
|
||||
if (glyphCount == 1 && advance >= 0 && (advance & 0xFFFF) == 0 &&
|
||||
(!baselineDeltas || baselineDeltas[mapper.MapIndex(k)] == 0) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvancePixels(advancePixels) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph->glyphID)) {
|
||||
aRun->SetCharacterGlyph(index, g.SetSimpleGlyph(advancePixels, glyph->glyphID));
|
||||
} else {
|
||||
if (detailedGlyphs.Length() < glyphCount) {
|
||||
if (!detailedGlyphs.AppendElements(glyphCount - detailedGlyphs.Length()))
|
||||
return;
|
||||
}
|
||||
PRUint32 i;
|
||||
float appUnitsPerDevUnit = aRun->GetAppUnitsPerDevUnit();
|
||||
for (i = 0; i < glyphCount; ++i) {
|
||||
gfxTextRun::DetailedGlyph *details = &detailedGlyphs[i];
|
||||
glyph = &glyphRecords[mapper.MapIndex(k + i)];
|
||||
details->mIsLastGlyph = i == glyphCount - 1;
|
||||
details->mGlyphID = glyph->glyphID;
|
||||
float advanceAppUnits =
|
||||
FixedToFloat(glyph[1].realPos - glyph->realPos)*appUnitsPerDevUnit;
|
||||
details->mAdvance = ceilf(advanceAppUnits)/appUnitsPerDevUnit;
|
||||
details->mXOffset = 0;
|
||||
details->mYOffset = !baselineDeltas ? 0.0f
|
||||
: FixedToFloat(baselineDeltas[mapper.MapIndex(k + i)]);
|
||||
}
|
||||
aRun->SetDetailedGlyphs(index, detailedGlyphs.Elements(), glyphCount);
|
||||
}
|
||||
gotRealCharacter = PR_TRUE;
|
||||
k += glyphCount;
|
||||
}
|
||||
|
||||
index = nextIndex;
|
||||
if (index + 1 < length && NS_IS_HIGH_SURROGATE(aString[index])) {
|
||||
++index;
|
||||
}
|
||||
numGlyphs -= glyphCount;
|
||||
}
|
||||
}
|
||||
|
||||
struct PostLayoutCallbackClosure {
|
||||
gfxTextRun *mTextRun;
|
||||
const PRUnichar *mString;
|
||||
// Either null or an array of stringlength booleans set to true for
|
||||
// each character that did not match any fonts
|
||||
nsAutoArrayPtr<PRPackedBool> mUnmatchedChars;
|
||||
gfxTextRun *mTextRun;
|
||||
const PRUnichar *mString;
|
||||
};
|
||||
|
||||
// This is really disgusting, but the ATSUI refCon thing is also disgusting
|
||||
|
@ -733,15 +699,14 @@ PostLayoutOperationCallback(ATSULayoutOperationSelector iCurrentOperation,
|
|||
ATSULayoutOperationCallbackStatus *oCallbackStatus)
|
||||
{
|
||||
PostLayoutCallback(iLineRef, gCallbackClosure->mTextRun,
|
||||
gCallbackClosure->mString, gCallbackClosure->mUnmatchedChars);
|
||||
gCallbackClosure->mString);
|
||||
*oCallbackStatus = kATSULayoutOperationCallbackStatusContinue;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
void
|
||||
gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
||||
const PRUnichar *aString, PRUint32 aLength,
|
||||
PRUint32 aHeaderChars)
|
||||
const PRUnichar *aString, PRUint32 aLength)
|
||||
{
|
||||
OSStatus status;
|
||||
gfxAtsuiFont *atsuiFont = GetFontAt(0);
|
||||
|
@ -750,15 +715,15 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
|||
|
||||
UniCharCount runLengths = aLength;
|
||||
ATSUTextLayout layout;
|
||||
// The string is actually aLength + 2*aHeaderChars chars, with optionally
|
||||
// a header char to set the direction and a trailer char to pop it. So
|
||||
// create the text layout giving the whole string as context, although we
|
||||
// only want glyphs for the inner substring.
|
||||
// The string is actually aLength + 2 chars, with a header char to set
|
||||
// the direction and a trailer char to pop it. So create the text layout
|
||||
// giving the whole string as context, although we only want glyphs for
|
||||
// the inner substring.
|
||||
status = ATSUCreateTextLayoutWithTextPtr
|
||||
(aString,
|
||||
aHeaderChars,
|
||||
1,
|
||||
aLength,
|
||||
aLength + aHeaderChars*2,
|
||||
aLength + 2,
|
||||
1,
|
||||
&runLengths,
|
||||
&mainStyle,
|
||||
|
@ -768,7 +733,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
|||
PostLayoutCallbackClosure closure;
|
||||
closure.mTextRun = aRun;
|
||||
// Pass the real string to the closure, ignoring the header
|
||||
closure.mString = aString + aHeaderChars;
|
||||
closure.mString = aString + 1;
|
||||
NS_ASSERTION(!gCallbackClosure, "Reentering InitTextRun? Expect disaster!");
|
||||
gCallbackClosure = &closure;
|
||||
|
||||
|
@ -803,8 +768,8 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
|||
|
||||
/* Now go through and update the styles for the text, based on font matching. */
|
||||
|
||||
UniCharArrayOffset runStart = aHeaderChars;
|
||||
UniCharCount totalLength = aLength + aHeaderChars;
|
||||
UniCharArrayOffset runStart = 1;
|
||||
UniCharCount totalLength = aLength + 1;
|
||||
UniCharCount runLength = aLength;
|
||||
|
||||
//fprintf (stderr, "==== Starting font maching [string length: %d]\n", totalLength);
|
||||
|
@ -818,7 +783,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
|||
if (status == noErr) {
|
||||
//fprintf (stderr, "ATSUMatchFontsToText returned noErr\n");
|
||||
// everything's good, finish up
|
||||
aRun->AddGlyphRun(atsuiFont, runStart - aHeaderChars);
|
||||
aRun->AddGlyphRun(atsuiFont, runStart - 1);
|
||||
break;
|
||||
} else if (status == kATSUFontsMatched) {
|
||||
//fprintf (stderr, "ATSUMatchFontsToText returned kATSUFontsMatched: FID %d\n", substituteFontID);
|
||||
|
@ -834,14 +799,14 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
|||
ATSUSetAttributes (subStyle, 1, fontTags, fontArgSizes, fontArgs);
|
||||
|
||||
if (changedOffset > runStart) {
|
||||
aRun->AddGlyphRun(atsuiFont, runStart - aHeaderChars);
|
||||
aRun->AddGlyphRun(atsuiFont, runStart - 1);
|
||||
}
|
||||
|
||||
ATSUSetRunStyle (layout, subStyle, changedOffset, changedLength);
|
||||
|
||||
gfxAtsuiFont *font = FindFontFor(substituteFontID);
|
||||
if (font) {
|
||||
aRun->AddGlyphRun(font, changedOffset - aHeaderChars);
|
||||
aRun->AddGlyphRun(font, changedOffset - 1);
|
||||
}
|
||||
|
||||
stylesToDispose.AppendElement(subStyle);
|
||||
|
@ -849,18 +814,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
|||
//fprintf (stderr, "ATSUMatchFontsToText returned kATSUFontsNotMatched\n");
|
||||
/* I need to select the last resort font; how the heck do I do that? */
|
||||
// Record which font is associated with these glyphs, anyway
|
||||
aRun->AddGlyphRun(atsuiFont, runStart - aHeaderChars);
|
||||
|
||||
if (!closure.mUnmatchedChars) {
|
||||
closure.mUnmatchedChars = new PRPackedBool[aLength];
|
||||
if (closure.mUnmatchedChars) {
|
||||
memset(closure.mUnmatchedChars.get(), PR_FALSE, aLength);
|
||||
}
|
||||
}
|
||||
if (closure.mUnmatchedChars) {
|
||||
memset(closure.mUnmatchedChars.get() + changedOffset - aHeaderChars,
|
||||
PR_TRUE, changedLength);
|
||||
}
|
||||
aRun->AddGlyphRun(atsuiFont, runStart - 1);
|
||||
}
|
||||
|
||||
//fprintf (stderr, "total length: %d changedOffset: %d changedLength: %d\p=n", runLength, changedOffset, changedLength);
|
||||
|
@ -873,8 +827,7 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
|
|||
// the result of this call.
|
||||
ATSTrapezoid trap;
|
||||
ItemCount trapCount;
|
||||
ATSUGetGlyphBounds(layout, 0, 0, aHeaderChars, aLength,
|
||||
kATSUseFractionalOrigins, 1, &trap, &trapCount);
|
||||
ATSUGetGlyphBounds(layout, 0, 0, 1, aLength, kATSUseDeviceOrigins, 1, &trap, &trapCount);
|
||||
|
||||
ATSUDisposeTextLayout(layout);
|
||||
|
||||
|
|
|
@ -57,16 +57,6 @@ gfxFont::gfxFont(const nsAString &aName, const gfxFontStyle *aFontStyle) :
|
|||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function in case we need to do any rounding or other
|
||||
* processing here.
|
||||
*/
|
||||
static double
|
||||
ToDeviceUnits(double aAppUnits, double aDevUnitsPerAppUnit)
|
||||
{
|
||||
return aAppUnits*aDevUnitsPerAppUnit;
|
||||
}
|
||||
|
||||
void
|
||||
gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||
gfxContext *aContext, PRBool aDrawToPath, gfxPoint *aPt,
|
||||
|
@ -75,19 +65,19 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
|||
if (aStart >= aEnd)
|
||||
return;
|
||||
|
||||
double appUnitsToPixels = 1.0/aTextRun->GetAppUnitsPerDevUnit();
|
||||
const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs();
|
||||
const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
|
||||
const double devUnitsPerAppUnit = 1/gfxFloat(appUnitsPerDevUnit);
|
||||
PRBool isRTL = aTextRun->IsRightToLeft();
|
||||
double direction = aTextRun->GetDirection();
|
||||
|
||||
nsAutoTArray<cairo_glyph_t,200> glyphBuffer;
|
||||
PRUint32 i;
|
||||
// Current position in appunits
|
||||
double x = aPt->x;
|
||||
double y = aPt->y;
|
||||
|
||||
PRBool isRTL = aTextRun->IsRightToLeft();
|
||||
|
||||
if (aSpacing) {
|
||||
x += direction*aSpacing[0].mBefore;
|
||||
x += direction*aSpacing[0].mBefore*appUnitsToPixels;
|
||||
}
|
||||
for (i = aStart; i < aEnd; ++i) {
|
||||
const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[i];
|
||||
|
@ -97,15 +87,10 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
|||
return;
|
||||
glyph->index = glyphData->GetSimpleGlyph();
|
||||
double advance = glyphData->GetSimpleAdvance();
|
||||
// Perhaps we should put a scale in the cairo context instead of
|
||||
// doing this scaling here...
|
||||
// Multiplying by the reciprocal may introduce tiny error here,
|
||||
// but we assume cairo is going to round coordinates at some stage
|
||||
// and this is faster
|
||||
glyph->x = ToDeviceUnits(x, devUnitsPerAppUnit);
|
||||
glyph->y = ToDeviceUnits(y, devUnitsPerAppUnit);
|
||||
glyph->x = x;
|
||||
glyph->y = y;
|
||||
if (isRTL) {
|
||||
glyph->x -= ToDeviceUnits(advance, devUnitsPerAppUnit);
|
||||
glyph->x -= advance;
|
||||
x -= advance;
|
||||
} else {
|
||||
x += advance;
|
||||
|
@ -117,11 +102,11 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
|||
if (!glyph)
|
||||
return;
|
||||
glyph->index = details->mGlyphID;
|
||||
glyph->x = ToDeviceUnits(x + details->mXOffset, devUnitsPerAppUnit);
|
||||
glyph->y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
|
||||
glyph->x = x + details->mXOffset;
|
||||
glyph->y = y + details->mYOffset;
|
||||
double advance = details->mAdvance;
|
||||
if (isRTL) {
|
||||
glyph->x -= ToDeviceUnits(advance, devUnitsPerAppUnit);
|
||||
glyph->x -= advance;
|
||||
}
|
||||
x += direction*advance;
|
||||
if (details->mIsLastGlyph)
|
||||
|
@ -135,12 +120,16 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
|||
if (i + 1 < aEnd) {
|
||||
space += aSpacing[i + 1 - aStart].mBefore;
|
||||
}
|
||||
x += direction*space;
|
||||
x += direction*space*appUnitsToPixels;
|
||||
}
|
||||
}
|
||||
|
||||
*aPt = gfxPoint(x, y);
|
||||
|
||||
// XXX is this needed? what does it do? Mac code was doing it.
|
||||
// gfxFloat offsetX, offsetY;
|
||||
// nsRefPtr<gfxASurface> surf = aContext->CurrentSurface (&offsetX, &offsetY);
|
||||
|
||||
cairo_t *cr = aContext->GetCairo();
|
||||
SetupCairoFont(cr);
|
||||
if (aDrawToPath) {
|
||||
|
@ -164,7 +153,7 @@ gfxFont::Measure(gfxTextRun *aTextRun,
|
|||
// XXX temporary code, does not handle glyphs outside the font-box
|
||||
NS_ASSERTION(!(aTextRun->GetFlags() & gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX),
|
||||
"Glyph extents not yet supported");
|
||||
PRInt32 advance = 0;
|
||||
gfxFloat advancePixels = 0;
|
||||
PRUint32 i;
|
||||
const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs();
|
||||
PRUint32 clusterCount = 0;
|
||||
|
@ -173,11 +162,11 @@ gfxFont::Measure(gfxTextRun *aTextRun,
|
|||
if (g.IsClusterStart()) {
|
||||
++clusterCount;
|
||||
if (g.IsSimpleGlyph()) {
|
||||
advance += charGlyphs[i].GetSimpleAdvance();
|
||||
advancePixels += charGlyphs[i].GetSimpleAdvance();
|
||||
} else if (g.IsComplexCluster()) {
|
||||
const gfxTextRun::DetailedGlyph *details = aTextRun->GetDetailedGlyphs(i);
|
||||
for (;;) {
|
||||
advance += details->mAdvance;
|
||||
advancePixels += details->mAdvance;
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
++details;
|
||||
|
@ -185,21 +174,20 @@ gfxFont::Measure(gfxTextRun *aTextRun,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
gfxFloat floatAdvance = advance;
|
||||
gfxFloat dev2app = aTextRun->GetAppUnitsPerDevUnit();
|
||||
gfxFloat advance = advancePixels*dev2app;
|
||||
if (aSpacing) {
|
||||
for (i = 0; i < aEnd - aStart; ++i) {
|
||||
floatAdvance += aSpacing[i].mBefore + aSpacing[i].mAfter;
|
||||
advance += aSpacing[i].mBefore + aSpacing[i].mAfter;
|
||||
}
|
||||
}
|
||||
RunMetrics metrics;
|
||||
const gfxFont::Metrics& fontMetrics = GetMetrics();
|
||||
metrics.mAdvanceWidth = floatAdvance;
|
||||
const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
|
||||
metrics.mAscent = fontMetrics.maxAscent*appUnitsPerDevUnit;
|
||||
metrics.mDescent = fontMetrics.maxDescent*appUnitsPerDevUnit;
|
||||
metrics.mAdvanceWidth = advance;
|
||||
metrics.mAscent = fontMetrics.maxAscent*dev2app;
|
||||
metrics.mDescent = fontMetrics.maxDescent*dev2app;
|
||||
metrics.mBoundingBox =
|
||||
gfxRect(0, -metrics.mAscent, floatAdvance, metrics.mAscent + metrics.mDescent);
|
||||
gfxRect(0, -metrics.mAscent, advance, metrics.mAscent + metrics.mDescent);
|
||||
metrics.mClusterCount = clusterCount;
|
||||
return metrics;
|
||||
}
|
||||
|
@ -426,7 +414,7 @@ gfxFontGroup::GetSpecialStringTextRun(SpecialString aString,
|
|||
|
||||
gfxTextRunFactory::Parameters params = {
|
||||
nsnull, nsnull, nsnull, nsnull, nsnull, 0,
|
||||
aTemplate->GetAppUnitsPerDevUnit(), TEXT_IS_PERSISTENT
|
||||
PRUint32(aTemplate->GetAppUnitsPerDevUnit()), TEXT_IS_PERSISTENT
|
||||
};
|
||||
gfxTextRun* textRun;
|
||||
|
||||
|
@ -555,7 +543,7 @@ gfxTextRun::SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
|
|||
return changed != 0;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
gfxFloat
|
||||
gfxTextRun::ComputeClusterAdvance(PRUint32 aClusterOffset)
|
||||
{
|
||||
CompressedGlyph *glyphData = &mCharacterGlyphs[aClusterOffset];
|
||||
|
@ -563,7 +551,7 @@ gfxTextRun::ComputeClusterAdvance(PRUint32 aClusterOffset)
|
|||
return glyphData->GetSimpleAdvance();
|
||||
NS_ASSERTION(glyphData->IsComplexCluster(), "Unknown character type!");
|
||||
NS_ASSERTION(mDetailedGlyphs, "Complex cluster but no details array!");
|
||||
PRInt32 advance = 0;
|
||||
gfxFloat advance = 0;
|
||||
DetailedGlyph *details = mDetailedGlyphs[aClusterOffset];
|
||||
NS_ASSERTION(details, "Complex cluster but no details!");
|
||||
for (;;) {
|
||||
|
@ -588,7 +576,7 @@ gfxTextRun::ComputeLigatureData(PRUint32 aPartOffset, PropertyProvider *aProvide
|
|||
} while (!charGlyphs[ligStart].IsClusterStart());
|
||||
}
|
||||
result.mStartOffset = ligStart;
|
||||
result.mLigatureWidth = ComputeClusterAdvance(ligStart);
|
||||
result.mLigatureWidth = ComputeClusterAdvance(ligStart)*mAppUnitsPerDevUnit;
|
||||
result.mPartClusterIndex = PR_UINT32_MAX;
|
||||
|
||||
PRUint32 charIndex = ligStart;
|
||||
|
@ -633,9 +621,22 @@ gfxTextRun::GetAdjustedSpacing(PRUint32 aStart, PRUint32 aEnd,
|
|||
|
||||
aProvider->GetSpacing(aStart, aEnd - aStart, aSpacing);
|
||||
|
||||
// XXX the following loop could be avoided if we add some kind of
|
||||
// TEXT_HAS_LIGATURES flag
|
||||
CompressedGlyph *charGlyphs = mCharacterGlyphs;
|
||||
PRUint32 i;
|
||||
|
||||
PRUint32 end = PR_MIN(aEnd, mCharacterCount - 1);
|
||||
for (i = aStart; i <= end; ++i) {
|
||||
if (charGlyphs[i].IsLigatureContinuation()) {
|
||||
if (i < aEnd) {
|
||||
aSpacing[i - aStart].mBefore = 0;
|
||||
}
|
||||
if (i > aStart) {
|
||||
aSpacing[i - 1 - aStart].mAfter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -643,7 +644,7 @@ gfxTextRun::GetAdjustedSpacing(PRUint32 aStart, PRUint32 aEnd,
|
|||
// produces simpler code and absolute spacing is rarely required.
|
||||
|
||||
// The width of the last nonligature cluster, in appunits
|
||||
PRInt32 clusterWidth = 0;
|
||||
gfxFloat clusterWidth = 0.0;
|
||||
for (i = aStart; i < aEnd; ++i) {
|
||||
CompressedGlyph *glyphData = &charGlyphs[i];
|
||||
|
||||
|
@ -651,46 +652,25 @@ gfxTextRun::GetAdjustedSpacing(PRUint32 aStart, PRUint32 aEnd,
|
|||
if (i > aStart) {
|
||||
aSpacing[i - 1 - aStart].mAfter -= clusterWidth;
|
||||
}
|
||||
clusterWidth = glyphData->GetSimpleAdvance();
|
||||
clusterWidth = glyphData->GetSimpleAdvance()*mAppUnitsPerDevUnit;
|
||||
} else if (glyphData->IsComplexCluster()) {
|
||||
NS_ASSERTION(mDetailedGlyphs, "No details but we have a complex cluster...");
|
||||
if (i > aStart) {
|
||||
aSpacing[i - 1 - aStart].mAfter -= clusterWidth;
|
||||
}
|
||||
DetailedGlyph *details = mDetailedGlyphs[i];
|
||||
clusterWidth = 0;
|
||||
clusterWidth = 0.0;
|
||||
for (;;) {
|
||||
clusterWidth += details->mAdvance;
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
++details;
|
||||
}
|
||||
clusterWidth *= mAppUnitsPerDevUnit;
|
||||
}
|
||||
}
|
||||
aSpacing[aEnd - 1 - aStart].mAfter -= clusterWidth;
|
||||
}
|
||||
|
||||
// Move spacing inside a ligature to after the ligature.
|
||||
// Do this after adjusting for ABSOLUTE_SPACING above.
|
||||
// XXX we shouldn't really have to do this, textframe users should
|
||||
// not put spacing inside ligatures.
|
||||
// XXX the following loop could be avoided if we add some kind of
|
||||
// TEXT_HAS_LIGATURES flag
|
||||
gfxFloat accumulatedSpace = 0;
|
||||
for (i = aStart; i <= aEnd; ++i) {
|
||||
if (i < aEnd && charGlyphs[i].IsLigatureContinuation()) {
|
||||
accumulatedSpace += aSpacing[i - aStart].mBefore;
|
||||
aSpacing[i - aStart].mBefore = 0;
|
||||
NS_ASSERTION(i > aStart, "Ligature continuation at start of spacing run?");
|
||||
accumulatedSpace += aSpacing[i - 1 - aStart].mAfter;
|
||||
aSpacing[i - 1 - aStart].mAfter = 0;
|
||||
} else {
|
||||
if (i > aStart) {
|
||||
aSpacing[i - 1 - aStart].mAfter += accumulatedSpace;
|
||||
accumulatedSpace = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
|
@ -760,7 +740,7 @@ gfxTextRun::GetPartialLigatureWidth(PRUint32 aStart, PRUint32 aEnd,
|
|||
}
|
||||
}
|
||||
|
||||
gfxFloat result = gfxFloat(data.mLigatureWidth)*clusterCount/data.mClusterCount;
|
||||
gfxFloat result = data.mLigatureWidth*clusterCount/data.mClusterCount;
|
||||
if (aStart == data.mStartOffset) {
|
||||
result += data.mBeforeSpacing;
|
||||
}
|
||||
|
@ -780,17 +760,19 @@ gfxTextRun::DrawPartialLigature(gfxFont *aFont, gfxContext *aCtx, PRUint32 aOffs
|
|||
if (!mCharacterGlyphs[aOffset].IsClusterStart() || !aDirtyRect)
|
||||
return;
|
||||
|
||||
gfxFloat appUnitsToPixels = 1.0/mAppUnitsPerDevUnit;
|
||||
|
||||
// Draw partial ligature. We hack this by clipping the ligature.
|
||||
LigatureData data = ComputeLigatureData(aOffset, aProvider);
|
||||
// Width of a cluster in the ligature, in appunits
|
||||
gfxFloat clusterWidth = data.mLigatureWidth/data.mClusterCount;
|
||||
// Width of a cluster in the ligature, in device pixels
|
||||
gfxFloat clusterWidth = data.mLigatureWidth*appUnitsToPixels/data.mClusterCount;
|
||||
|
||||
gfxFloat direction = GetDirection();
|
||||
gfxFloat left = aDirtyRect->X();
|
||||
gfxFloat right = aDirtyRect->XMost();
|
||||
// The advance to the start of this cluster in the drawn ligature, in appunits
|
||||
gfxFloat left = aDirtyRect->X()*appUnitsToPixels;
|
||||
gfxFloat right = aDirtyRect->XMost()*appUnitsToPixels;
|
||||
// The advance to the start of this cluster in the drawn ligature, in device pixels
|
||||
gfxFloat widthBeforeCluster;
|
||||
// Any spacing that should be included after the cluster, in appunits
|
||||
// Any spacing that should be included after the cluster, in device pixels
|
||||
gfxFloat afterSpace;
|
||||
if (data.mStartOffset < aOffset) {
|
||||
// Not the start of the ligature; need to clip the ligature before the current cluster
|
||||
|
@ -800,7 +782,7 @@ gfxTextRun::DrawPartialLigature(gfxFont *aFont, gfxContext *aCtx, PRUint32 aOffs
|
|||
left = PR_MAX(left, aPt->x);
|
||||
}
|
||||
widthBeforeCluster = clusterWidth*data.mPartClusterIndex +
|
||||
data.mBeforeSpacing;
|
||||
data.mBeforeSpacing*appUnitsToPixels;
|
||||
} else {
|
||||
// We're drawing the start of the ligature, so our cluster includes any
|
||||
// before-spacing.
|
||||
|
@ -816,16 +798,12 @@ gfxTextRun::DrawPartialLigature(gfxFont *aFont, gfxContext *aCtx, PRUint32 aOffs
|
|||
}
|
||||
afterSpace = 0;
|
||||
} else {
|
||||
afterSpace = data.mAfterSpacing;
|
||||
afterSpace = data.mAfterSpacing*appUnitsToPixels;
|
||||
}
|
||||
|
||||
aCtx->Save();
|
||||
// use division here to ensure that when the rect is aligned on multiples
|
||||
// of mAppUnitsPerDevUnit, we clip to true device unit boundaries
|
||||
aCtx->Clip(gfxRect(left/mAppUnitsPerDevUnit,
|
||||
aDirtyRect->Y()/mAppUnitsPerDevUnit,
|
||||
(right - left)/mAppUnitsPerDevUnit,
|
||||
aDirtyRect->Height()/mAppUnitsPerDevUnit));
|
||||
aCtx->Clip(gfxRect(left, aDirtyRect->Y()*appUnitsToPixels, right - left,
|
||||
aDirtyRect->Height()*appUnitsToPixels));
|
||||
gfxPoint pt(aPt->x - direction*widthBeforeCluster, aPt->y);
|
||||
DrawGlyphs(aFont, aCtx, PR_FALSE, &pt, data.mStartOffset,
|
||||
data.mEndOffset, aProvider);
|
||||
|
@ -841,9 +819,12 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt,
|
|||
{
|
||||
NS_ASSERTION(aStart + aLength <= mCharacterCount, "Substring out of range");
|
||||
|
||||
gfxFloat appUnitsToPixels = 1/mAppUnitsPerDevUnit;
|
||||
CompressedGlyph *charGlyphs = mCharacterGlyphs;
|
||||
gfxFloat direction = GetDirection();
|
||||
gfxPoint pt = aPt;
|
||||
|
||||
gfxPoint pt(aPt.x*appUnitsToPixels, aPt.y*appUnitsToPixels);
|
||||
gfxFloat startX = pt.x;
|
||||
|
||||
GlyphRunIterator iter(this, aStart, aLength);
|
||||
while (iter.NextRun()) {
|
||||
|
@ -873,7 +854,7 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt,
|
|||
}
|
||||
|
||||
if (aAdvanceWidth) {
|
||||
*aAdvanceWidth = (pt.x - aPt.x)*direction;
|
||||
*aAdvanceWidth = (pt.x - startX)*direction*mAppUnitsPerDevUnit;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -884,9 +865,12 @@ gfxTextRun::DrawToPath(gfxContext *aContext, gfxPoint aPt,
|
|||
{
|
||||
NS_ASSERTION(aStart + aLength <= mCharacterCount, "Substring out of range");
|
||||
|
||||
gfxFloat appUnitsToPixels = 1/mAppUnitsPerDevUnit;
|
||||
CompressedGlyph *charGlyphs = mCharacterGlyphs;
|
||||
gfxFloat direction = GetDirection();
|
||||
gfxPoint pt = aPt;
|
||||
|
||||
gfxPoint pt(aPt.x*appUnitsToPixels, aPt.y*appUnitsToPixels);
|
||||
gfxFloat startX = pt.x;
|
||||
|
||||
GlyphRunIterator iter(this, aStart, aLength);
|
||||
while (iter.NextRun()) {
|
||||
|
@ -906,7 +890,7 @@ gfxTextRun::DrawToPath(gfxContext *aContext, gfxPoint aPt,
|
|||
}
|
||||
|
||||
if (aAdvanceWidth) {
|
||||
*aAdvanceWidth = (pt.x - aPt.x)*direction;
|
||||
*aAdvanceWidth = (pt.x - startX)*direction*mAppUnitsPerDevUnit;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1080,7 +1064,8 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
|||
}
|
||||
|
||||
gfxFloat width = 0;
|
||||
gfxFloat advance = 0;
|
||||
PRUint32 pixelAdvance = 0;
|
||||
gfxFloat floatAdvanceUnits = 0;
|
||||
PRInt32 lastBreak = -1;
|
||||
PRBool aborted = PR_FALSE;
|
||||
PRUint32 end = aStart + aMaxLength;
|
||||
|
@ -1109,11 +1094,14 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
|||
PRBool lineBreakHere = mCharacterGlyphs[i].CanBreakBefore() &&
|
||||
(!aSuppressInitialBreak || i > aStart);
|
||||
if (lineBreakHere || (haveHyphenation && hyphenBuffer[i - bufferStart])) {
|
||||
gfxFloat advance = gfxFloat(pixelAdvance)*mAppUnitsPerDevUnit + floatAdvanceUnits;
|
||||
gfxFloat hyphenatedAdvance = advance;
|
||||
PRBool hyphenation = !lineBreakHere;
|
||||
if (hyphenation) {
|
||||
hyphenatedAdvance += aProvider->GetHyphenWidth();
|
||||
}
|
||||
pixelAdvance = 0;
|
||||
floatAdvanceUnits = 0;
|
||||
|
||||
if (lastBreak < 0 || width + hyphenatedAdvance <= aWidth) {
|
||||
// We can break here.
|
||||
|
@ -1122,7 +1110,6 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
|||
}
|
||||
|
||||
width += advance;
|
||||
advance = 0;
|
||||
if (width > aWidth) {
|
||||
// No more text fits. Abort
|
||||
aborted = PR_TRUE;
|
||||
|
@ -1133,12 +1120,12 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
|||
if (i >= ligatureRunStart && i < ligatureRunEnd) {
|
||||
CompressedGlyph *glyphData = &charGlyphs[i];
|
||||
if (glyphData->IsSimpleGlyph()) {
|
||||
advance += glyphData->GetSimpleAdvance();
|
||||
pixelAdvance += glyphData->GetSimpleAdvance();
|
||||
} else if (glyphData->IsComplexCluster()) {
|
||||
NS_ASSERTION(mDetailedGlyphs, "No details but we have a complex cluster...");
|
||||
DetailedGlyph *details = mDetailedGlyphs[i];
|
||||
for (;;) {
|
||||
advance += details->mAdvance;
|
||||
floatAdvanceUnits += details->mAdvance*mAppUnitsPerDevUnit;
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
++details;
|
||||
|
@ -1146,14 +1133,15 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
|||
}
|
||||
if (haveSpacing) {
|
||||
PropertyProvider::Spacing *space = &spacingBuffer[i - bufferStart];
|
||||
advance += space->mBefore + space->mAfter;
|
||||
floatAdvanceUnits += space->mBefore + space->mAfter;
|
||||
}
|
||||
} else {
|
||||
advance += GetPartialLigatureWidth(i, i + 1, aProvider);
|
||||
floatAdvanceUnits += GetPartialLigatureWidth(i, i + 1, aProvider);
|
||||
}
|
||||
}
|
||||
|
||||
if (!aborted) {
|
||||
gfxFloat advance = gfxFloat(pixelAdvance)*mAppUnitsPerDevUnit + floatAdvanceUnits;
|
||||
width += advance;
|
||||
}
|
||||
|
||||
|
@ -1217,6 +1205,7 @@ gfxTextRun::GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
|
|||
}
|
||||
}
|
||||
|
||||
PRUint32 pixelAdvance = 0;
|
||||
PRUint32 ligatureRunStart = aStart;
|
||||
PRUint32 ligatureRunEnd = aStart + aLength;
|
||||
ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
|
||||
|
@ -1228,12 +1217,12 @@ gfxTextRun::GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
|
|||
for (i = ligatureRunStart; i < ligatureRunEnd; ++i) {
|
||||
CompressedGlyph *glyphData = &charGlyphs[i];
|
||||
if (glyphData->IsSimpleGlyph()) {
|
||||
result += glyphData->GetSimpleAdvance();
|
||||
pixelAdvance += glyphData->GetSimpleAdvance();
|
||||
} else if (glyphData->IsComplexCluster()) {
|
||||
NS_ASSERTION(mDetailedGlyphs, "No details but we have a complex cluster...");
|
||||
DetailedGlyph *details = mDetailedGlyphs[i];
|
||||
for (;;) {
|
||||
result += details->mAdvance;
|
||||
result += details->mAdvance*mAppUnitsPerDevUnit;
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
++details;
|
||||
|
@ -1241,7 +1230,7 @@ gfxTextRun::GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
|
|||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result + gfxFloat(pixelAdvance)*mAppUnitsPerDevUnit;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1310,9 +1299,6 @@ void
|
|||
gfxTextRun::SetDetailedGlyphs(PRUint32 aIndex, DetailedGlyph *aGlyphs,
|
||||
PRUint32 aCount)
|
||||
{
|
||||
NS_ASSERTION(aCount > 0, "Can't set zero detailed glyphs");
|
||||
NS_ASSERTION(aGlyphs[aCount - 1].mIsLastGlyph, "Failed to set last glyph flag");
|
||||
|
||||
if (!mCharacterGlyphs)
|
||||
return;
|
||||
|
||||
|
@ -1349,4 +1335,4 @@ gfxTextRun::RecordSurrogates(const PRUnichar *aString)
|
|||
SetCharacterGlyph(i, g.SetLowSurrogate());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -592,28 +592,6 @@ gfxPangoFont::GetPangoFont()
|
|||
return pango_context_load_font(mPangoCtx, mPangoFontDesc);
|
||||
}
|
||||
|
||||
nsString
|
||||
gfxPangoFont::GetUniqueName()
|
||||
{
|
||||
PangoFont *font = GetPangoFont();
|
||||
PangoFontDescription *desc = pango_font_describe(font);
|
||||
char *str = pango_font_description_to_string(desc);
|
||||
|
||||
// chop off the trailing size, e.g. "Albany AMT 15.359375" -> "Albany AMT"
|
||||
PRUint32 end = strlen(str);
|
||||
while (end > 0) {
|
||||
--end;
|
||||
if (str[end] == ' ')
|
||||
break;
|
||||
}
|
||||
str[end] = 0;
|
||||
|
||||
nsString result;
|
||||
CopyUTF8toUTF16(str, result);
|
||||
g_free(str);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char *sCJKLangGroup[] = {
|
||||
"ja",
|
||||
"ko",
|
||||
|
@ -739,13 +717,13 @@ gfxPangoFontGroup::InitTextRun(gfxTextRun *aTextRun, const gchar *aUTF8Text,
|
|||
|
||||
static gfxTextRun::Metrics
|
||||
GetPangoMetrics(PangoGlyphString *aGlyphs, PangoFont *aPangoFont,
|
||||
PRUint32 aPixelsToUnits, PRUint32 aClusterCount)
|
||||
gfxFloat aPixelsToUnits, PRUint32 aClusterCount)
|
||||
{
|
||||
PangoRectangle inkRect;
|
||||
PangoRectangle logicalRect;
|
||||
pango_glyph_string_extents(aGlyphs, aPangoFont, &inkRect, &logicalRect);
|
||||
|
||||
gfxFloat scale = aPixelsToUnits/gfxFloat(PANGO_SCALE);
|
||||
gfxFloat scale = aPixelsToUnits/PANGO_SCALE;
|
||||
|
||||
gfxTextRun::Metrics metrics;
|
||||
NS_ASSERTION(logicalRect.x == 0, "Weird logical rect...");
|
||||
|
@ -771,7 +749,7 @@ gfxPangoFont::Measure(gfxTextRun *aTextRun,
|
|||
|
||||
const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs();
|
||||
nsAutoTArray<PangoGlyphInfo,200> glyphBuffer;
|
||||
const gfxFloat appUnitsToPango = gfxFloat(PANGO_SCALE)/aTextRun->GetAppUnitsPerDevUnit();
|
||||
gfxFloat appUnitsToPango = gfxFloat(PANGO_SCALE)/aTextRun->GetAppUnitsPerDevUnit();
|
||||
|
||||
// We start by assuming every character is a cluster and subtract off
|
||||
// characters where that's not true
|
||||
|
@ -844,8 +822,7 @@ gfxPangoFont::Measure(gfxTextRun *aTextRun,
|
|||
glyphs.glyphs = glyphBuffer.Elements();
|
||||
glyphs.log_clusters = nsnull;
|
||||
glyphs.space = glyphBuffer.Length();
|
||||
return GetPangoMetrics(&glyphs, GetPangoFont(),
|
||||
aTextRun->GetAppUnitsPerDevUnit(), clusterCount);
|
||||
return GetPangoMetrics(&glyphs, GetPangoFont(), aTextRun->GetAppUnitsPerDevUnit(), clusterCount);
|
||||
}
|
||||
|
||||
#define IS_MISSING_GLYPH(g) (((g) & 0x10000000) || (g) == 0x0FFFFFFF)
|
||||
|
@ -934,13 +911,6 @@ SetupClusterBoundaries(gfxTextRun* aTextRun, const gchar *aUTF8, PRUint32 aUTF8L
|
|||
}
|
||||
}
|
||||
|
||||
static PRInt32
|
||||
ConvertPangoToAppUnits(PRInt32 aCoordinate, PRUint32 aAppUnitsPerDevUnit)
|
||||
{
|
||||
PRInt64 v = (PRInt64(aCoordinate)*aAppUnitsPerDevUnit + PANGO_SCALE/2)/PANGO_SCALE;
|
||||
return PRInt32(v);
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxPangoFontGroup::SetGlyphs(gfxTextRun* aTextRun,
|
||||
const gchar *aUTF8, PRUint32 aUTF8Length,
|
||||
|
@ -960,7 +930,6 @@ gfxPangoFontGroup::SetGlyphs(gfxTextRun* aTextRun,
|
|||
PRInt32 direction = aTextRun->IsRightToLeft() ? -1 : 1;
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
nsAutoTArray<gfxTextRun::DetailedGlyph,1> detailedGlyphs;
|
||||
const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
|
||||
|
||||
while (index < aUTF8Length) {
|
||||
if (utf16Offset >= textRunLength) {
|
||||
|
@ -1009,13 +978,13 @@ gfxPangoFontGroup::SetGlyphs(gfxTextRun* aTextRun,
|
|||
width = aOverrideSpaceWidth;
|
||||
}
|
||||
|
||||
PRInt32 advance = ConvertPangoToAppUnits(width, appUnitsPerDevUnit);
|
||||
PRInt32 downscaledWidth = width/PANGO_SCALE;
|
||||
if (glyphClusterCount == 1 &&
|
||||
glyph->geometry.x_offset == 0 && glyph->geometry.y_offset == 0 &&
|
||||
advance >= 0 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
width >= 0 && downscaledWidth*PANGO_SCALE == width &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvancePixels(downscaledWidth) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph->glyph)) {
|
||||
aTextRun->SetCharacterGlyph(utf16Offset, g.SetSimpleGlyph(advance, glyph->glyph));
|
||||
aTextRun->SetCharacterGlyph(utf16Offset, g.SetSimpleGlyph(downscaledWidth, glyph->glyph));
|
||||
} else if (haveMissingGlyph) {
|
||||
// Note that missing-glyph IDs are not simple glyph IDs, so we'll
|
||||
// always get here when a glyph is missing
|
||||
|
@ -1032,13 +1001,9 @@ gfxPangoFontGroup::SetGlyphs(gfxTextRun* aTextRun,
|
|||
details->mGlyphID = glyph->glyph;
|
||||
NS_ASSERTION(details->mGlyphID == glyph->glyph,
|
||||
"Seriously weird glyph ID detected!");
|
||||
details->mAdvance =
|
||||
ConvertPangoToAppUnits(glyph->geometry.width,
|
||||
appUnitsPerDevUnit);
|
||||
details->mXOffset =
|
||||
float(glyph->geometry.x_offset)*appUnitsPerDevUnit/PANGO_SCALE;
|
||||
details->mYOffset =
|
||||
float(glyph->geometry.y_offset)*appUnitsPerDevUnit/PANGO_SCALE;
|
||||
details->mAdvance = float(glyph->geometry.width)/PANGO_SCALE;
|
||||
details->mXOffset = float(glyph->geometry.x_offset)/PANGO_SCALE;
|
||||
details->mYOffset = float(glyph->geometry.y_offset)/PANGO_SCALE;
|
||||
glyph += direction;
|
||||
}
|
||||
aTextRun->SetDetailedGlyphs(utf16Offset, detailedGlyphs.Elements(), glyphClusterCount);
|
||||
|
@ -1070,7 +1035,6 @@ gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun,
|
|||
XftFont *xfont = font->GetXftFont();
|
||||
PRUint32 utf16Offset = 0;
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
|
||||
|
||||
while (p < aUTF8 + aUTF8Length) {
|
||||
gunichar ch = g_utf8_get_char(p);
|
||||
|
@ -1086,13 +1050,12 @@ gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun,
|
|||
if (info.yOff > 0) {
|
||||
NS_WARNING("vertical offsets not supported");
|
||||
}
|
||||
|
||||
PRInt32 advance = info.xOff*appUnitsPerDevUnit;
|
||||
if (advance >= 0 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
|
||||
if (info.xOff >= 0 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvancePixels(info.xOff) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph)) {
|
||||
aTextRun->SetCharacterGlyph(utf16Offset,
|
||||
g.SetSimpleGlyph(advance, glyph));
|
||||
g.SetSimpleGlyph(info.xOff, glyph));
|
||||
} else if (IS_MISSING_GLYPH(glyph)) {
|
||||
// Note that missing-glyph IDs are not simple glyph IDs, so we'll
|
||||
// always get here when a glyph is missing
|
||||
|
@ -1103,12 +1066,12 @@ gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun,
|
|||
details.mGlyphID = glyph;
|
||||
NS_ASSERTION(details.mGlyphID == glyph,
|
||||
"Seriously weird glyph ID detected!");
|
||||
details.mAdvance = advance;
|
||||
details.mAdvance = float(info.xOff);
|
||||
details.mXOffset = 0;
|
||||
details.mYOffset = 0;
|
||||
aTextRun->SetDetailedGlyphs(utf16Offset, &details, 1);
|
||||
}
|
||||
|
||||
|
||||
NS_ASSERTION(!IS_SURROGATE(ch), "Surrogates shouldn't appear in UTF8");
|
||||
if (ch >= 0x10000) {
|
||||
// This character is a surrogate pair in UTF16
|
||||
|
|
|
@ -612,25 +612,25 @@ SetupContextFont(gfxContext *aContext, gfxWindowsFont *aFont,
|
|||
}
|
||||
|
||||
static void
|
||||
SetupTextRunFromCharacterPlacement(gfxTextRun *aRun, double aCairoToAppUnits,
|
||||
SetupTextRunFromCharacterPlacement(gfxTextRun *aRun, double aCairoToPixels,
|
||||
int *aDXs, WCHAR *aGlyphs, gfxFont *aFont)
|
||||
{
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
PRUint32 i;
|
||||
PRUint32 length = aRun->GetLength();
|
||||
for (i = 0; i < length; ++i) {
|
||||
double advance = aDXs[i]*aCairoToAppUnits;
|
||||
PRInt32 advanceAppUnits = PRInt32(advance);
|
||||
double advance = aDXs[i]*aCairoToPixels;
|
||||
PRInt32 advancePixels = PRInt32(advance);
|
||||
WCHAR glyph = aGlyphs[i];
|
||||
if (advanceAppUnits >= 0 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advanceAppUnits) &&
|
||||
if (advance >= 0 && advance == advancePixels &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvancePixels(advancePixels) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph)) {
|
||||
aRun->SetCharacterGlyph(i, g.SetSimpleGlyph(advanceAppUnits, glyph));
|
||||
aRun->SetCharacterGlyph(i, g.SetSimpleGlyph(advancePixels, glyph));
|
||||
} else {
|
||||
gfxTextRun::DetailedGlyph details;
|
||||
details.mIsLastGlyph = PR_TRUE;
|
||||
details.mGlyphID = glyph;
|
||||
details.mAdvance = advanceAppUnits;
|
||||
details.mAdvance = float(advance);
|
||||
details.mXOffset = 0;
|
||||
details.mYOffset = 0;
|
||||
aRun->SetDetailedGlyphs(i, &details, 1);
|
||||
|
@ -708,8 +708,7 @@ gfxWindowsFontGroup::InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun,
|
|||
results.lpGlyphs = glyphArray.Elements();
|
||||
GetCharacterPlacementA(dc, aString, aLength, 0, &results, GCP_USEKERNING);
|
||||
|
||||
SetupTextRunFromCharacterPlacement(aRun, cairoToPixels*aRun->GetAppUnitsPerDevUnit(),
|
||||
dxArray.Elements(),
|
||||
SetupTextRunFromCharacterPlacement(aRun, cairoToPixels, dxArray.Elements(),
|
||||
glyphArray.Elements(), font);
|
||||
}
|
||||
|
||||
|
@ -742,8 +741,7 @@ gfxWindowsFontGroup::InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun,
|
|||
results.lpGlyphs = glyphArray.Elements();
|
||||
GetCharacterPlacementW(dc, aString, aLength, 0, &results, GCP_USEKERNING);
|
||||
|
||||
SetupTextRunFromCharacterPlacement(aRun, cairoToPixels*aRun->GetAppUnitsPerDevUnit(),
|
||||
dxArray.Elements(),
|
||||
SetupTextRunFromCharacterPlacement(aRun, cairoToPixels, dxArray.Elements(),
|
||||
glyphArray.Elements(), font);
|
||||
}
|
||||
|
||||
|
@ -1150,7 +1148,6 @@ public:
|
|||
PRUint32 offset = 0;
|
||||
nsAutoTArray<gfxTextRun::DetailedGlyph,1> detailedGlyphs;
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
const PRUint32 appUnitsPerDevUnit = aRun->GetAppUnitsPerDevUnit();
|
||||
while (offset < mLength) {
|
||||
PRUint32 runOffset = offsetInRun + offset;
|
||||
if (offset > 0 && mClusters[offset] == mClusters[offset - 1]) {
|
||||
|
@ -1176,13 +1173,13 @@ public:
|
|||
missing = PR_TRUE;
|
||||
}
|
||||
}
|
||||
PRInt32 advance = mAdvances[k]*appUnitsPerDevUnit;
|
||||
int advance = mAdvances[k];
|
||||
WORD glyph = mGlyphs[k];
|
||||
if (missing) {
|
||||
aRun->SetCharacterGlyph(runOffset, g.SetMissing());
|
||||
} else if (glyphCount == 1 && advance >= 0 &&
|
||||
mOffsets[k].dv == 0 && mOffsets[k].du == 0 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvancePixels(advance) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph)) {
|
||||
aRun->SetCharacterGlyph(runOffset, g.SetSimpleGlyph(advance, glyph));
|
||||
} else {
|
||||
|
@ -1195,9 +1192,9 @@ public:
|
|||
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;
|
||||
details->mYOffset = float(mOffsets[k + i].dv)*appUnitsPerDevUnit;
|
||||
details->mAdvance = float(mAdvances[k + i]);
|
||||
details->mXOffset = float(mOffsets[k + i].du);
|
||||
details->mYOffset = float(mOffsets[k + i].dv);
|
||||
}
|
||||
aRun->SetDetailedGlyphs(runOffset, detailedGlyphs.Elements(), glyphCount);
|
||||
}
|
||||
|
|
|
@ -54,11 +54,17 @@ REQUIRES = \
|
|||
thebes \
|
||||
$(NULL)
|
||||
|
||||
MAIN_CPPSRCS = $(NULL)
|
||||
|
||||
# All platforms
|
||||
CPPSRCS = \
|
||||
gfxSurfaceRefCountTest.cpp \
|
||||
gfxFontSelectionTest.cpp \
|
||||
$(NULL)
|
||||
MAIN_CPPSRCS += gfxSurfaceRefCountTest.cpp
|
||||
|
||||
# mac and win32 for now
|
||||
ifneq (,$(filter windows cocoa,$(MOZ_WIDGET_TOOLKIT)))
|
||||
MAIN_CPPSRCS += gfxFontSelectionTest.cpp
|
||||
endif
|
||||
|
||||
CPPSRCS = $(MAIN_CPPSRCS)
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
|
||||
CMMSRCS = gfxTestCocoaHelper.mm
|
||||
|
@ -88,15 +94,4 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
|
|||
OS_LIBS += -framework Cocoa
|
||||
endif
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
|
||||
OS_LIBS += $(MOZ_PANGO_LIBS) $(MOZ_XFT_LIBS) $(XLIBS)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(TK_CFLAGS)
|
||||
CFLAGS += $(MOZ_CAIRO_CFLAGS) $(TK_CFLAGS)
|
||||
|
||||
ifdef MOZ_ENABLE_PANGO
|
||||
CXXFLAGS += $(MOZ_PANGO_CFLAGS)
|
||||
endif
|
||||
|
|
|
@ -59,10 +59,6 @@
|
|||
#include "gfxTestCocoaHelper.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK2
|
||||
#include "gtk/gtk.h"
|
||||
#endif
|
||||
|
||||
enum {
|
||||
S_UTF8 = 0,
|
||||
S_ASCII = 1
|
||||
|
@ -111,8 +107,7 @@ struct TestEntry {
|
|||
: utf8FamilyString(aUTF8FamilyString),
|
||||
fontStyle(aFontStyle),
|
||||
stringType(S_ASCII),
|
||||
string(aString),
|
||||
isRTL(PR_FALSE)
|
||||
string(aString)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -123,8 +118,7 @@ struct TestEntry {
|
|||
: utf8FamilyString(aUTF8FamilyString),
|
||||
fontStyle(aFontStyle),
|
||||
stringType(stringType),
|
||||
string(aString),
|
||||
isRTL(PR_FALSE)
|
||||
string(aString)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -143,7 +137,7 @@ struct TestEntry {
|
|||
if (/*!fontName.IsEmpty() &&*/ !fontName.Equals(aFontName))
|
||||
return PR_FALSE;
|
||||
|
||||
if (num_glyphs != int(glyphs.data.Length()))
|
||||
if (num_glyphs != glyphs.data.Length())
|
||||
return PR_FALSE;
|
||||
|
||||
for (int j = 0; j < num_glyphs; j++) {
|
||||
|
@ -157,11 +151,6 @@ struct TestEntry {
|
|||
nsCString fontName;
|
||||
LiteralArray glyphs;
|
||||
};
|
||||
|
||||
void SetRTL()
|
||||
{
|
||||
isRTL = PR_TRUE;
|
||||
}
|
||||
|
||||
// empty/NULL fontName means ignore font name
|
||||
void Expect (const char *platform,
|
||||
|
@ -184,9 +173,6 @@ struct TestEntry {
|
|||
#elif defined(XP_MACOSX)
|
||||
if (strcmp(platform, "macosx"))
|
||||
return;
|
||||
#elif defined(MOZ_ENABLE_PANGO)
|
||||
if (strcmp(platform, "gtk2-pango"))
|
||||
return;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
|
@ -216,7 +202,6 @@ struct TestEntry {
|
|||
|
||||
int stringType;
|
||||
char *string;
|
||||
PRPackedBool isRTL;
|
||||
|
||||
nsTArray<ExpectItem> expectItems;
|
||||
};
|
||||
|
@ -230,7 +215,7 @@ MakeContext ()
|
|||
|
||||
nsRefPtr<gfxASurface> surface;
|
||||
|
||||
surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(size, size), gfxASurface::ImageFormatRGB24);
|
||||
surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, size, gfxASurface::ImageFormatRGB24);
|
||||
gfxContext *ctx = new gfxContext(surface);
|
||||
NS_IF_ADDREF(ctx);
|
||||
return ctx;
|
||||
|
@ -267,7 +252,7 @@ DumpStore (gfxFontTestStore *store) {
|
|||
printf ("Run[% 2d]: '%s' ", i, nsPromiseFlatCString(store->items[i].platformFont).get());
|
||||
|
||||
for (int j = 0; j < store->items[i].num_glyphs; j++)
|
||||
printf ("%d ", int(store->items[i].glyphs[j].index));
|
||||
printf ("%d ", store->items[i].glyphs[j].index);
|
||||
|
||||
printf ("\n");
|
||||
}
|
||||
|
@ -278,7 +263,7 @@ DumpTestExpect (TestEntry *test) {
|
|||
for (PRUint32 i = 0; i < test->expectItems.Length(); i++) {
|
||||
printf ("Run[% 2d]: '%s' ", i, nsPromiseFlatCString(test->expectItems[i].fontName).get());
|
||||
for (PRUint32 j = 0; j < test->expectItems[i].glyphs.data.Length(); j++)
|
||||
printf ("%d ", int(test->expectItems[i].glyphs.data[j]));
|
||||
printf ("%d ", test->expectItems[i].glyphs.data[j]);
|
||||
|
||||
printf ("\n");
|
||||
}
|
||||
|
@ -299,28 +284,16 @@ RunTest (TestEntry *test, gfxContext *ctx) {
|
|||
return PR_FALSE;
|
||||
#endif
|
||||
|
||||
nsAutoPtr<gfxTextRun> textRun;
|
||||
gfxTextRunFactory::Parameters params = {
|
||||
ctx, nsnull, nsnull, nsnull, nsnull, 0, 60,
|
||||
gfxTextRunFactory::TEXT_IS_ASCII
|
||||
};
|
||||
if (test->isRTL) {
|
||||
params.mFlags |= gfxTextRunFactory::TEXT_IS_RTL;
|
||||
}
|
||||
PRUint32 length;
|
||||
nsRefPtr<gfxTextRun> textRun;
|
||||
if (test->stringType == S_ASCII) {
|
||||
params.mFlags |= gfxTextRunFactory::TEXT_IS_ASCII;
|
||||
length = strlen(test->string);
|
||||
textRun = fontGroup->MakeTextRun(NS_REINTERPRET_CAST(PRUint8*, test->string), length, ¶ms);
|
||||
textRun = fontGroup->MakeTextRun(nsDependentCString(test->string));
|
||||
} else {
|
||||
params.mFlags |= gfxTextRunFactory::TEXT_HAS_SURROGATES; // just in case
|
||||
NS_ConvertUTF8toUTF16 str(nsDependentCString(test->string));
|
||||
length = str.Length();
|
||||
textRun = fontGroup->MakeTextRun(str.get(), length, ¶ms);
|
||||
textRun = fontGroup->MakeTextRun(NS_ConvertUTF8toUTF16(nsDependentCString(test->string)));
|
||||
}
|
||||
|
||||
|
||||
gfxFontTestStore::NewStore();
|
||||
textRun->Draw(ctx, gfxPoint(0,0), 0, length, nsnull, nsnull, nsnull);
|
||||
textRun->Draw(ctx, gfxPoint(0,0));
|
||||
gfxFontTestStore *s = gfxFontTestStore::CurrentStore();
|
||||
|
||||
if (!test->Check(s)) {
|
||||
|
@ -338,10 +311,6 @@ main (int argc, char **argv) {
|
|||
int passed = 0;
|
||||
int failed = 0;
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK2
|
||||
gtk_init(&argc, &argv);
|
||||
#endif
|
||||
|
||||
// Initialize XPCOM
|
||||
nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
|
||||
if (NS_FAILED(rv))
|
||||
|
|
|
@ -131,7 +131,6 @@ SetupTests()
|
|||
|
||||
t->Expect ("win32", "Arial", GLYPHS(36, 37, 38, 39));
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(36, 37, 38, 39));
|
||||
t->Expect ("gtk2-pango", "Albany AMT", GLYPHS(36, 37, 38, 39));
|
||||
|
||||
/* Test 1 */
|
||||
t = AddTest ("verdana,sans-serif",
|
||||
|
@ -155,61 +154,4 @@ SetupTests()
|
|||
|
||||
t->Expect ("win32", "Arial:700", GLYPHS(36, 37, 38, 39));
|
||||
t->Expect ("macosx", "Helvetica-Bold", GLYPHS(36, 37, 38, 39));
|
||||
t->Expect ("gtk2-pango", "Albany AMT Bold", GLYPHS(36, 37, 38, 39));
|
||||
|
||||
/* Test 3: RTL Arabic with a ligature and leading and trailing whitespace */
|
||||
t = AddTest ("sans-serif",
|
||||
style_western_normal_16,
|
||||
S_UTF8,
|
||||
" \xd8\xaa\xd9\x85 ");
|
||||
t->SetRTL();
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(3));
|
||||
t->Expect ("macosx", "AlBayan", GLYPHS(47));
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(3));
|
||||
|
||||
/* Test 4: LTR Arabic with leading and trailing whitespace */
|
||||
t = AddTest ("sans-serif",
|
||||
style_western_normal_16,
|
||||
S_UTF8,
|
||||
" \xd9\x85\xd8\xaa ");
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(3));
|
||||
t->Expect ("macosx", "AlBayan", GLYPHS(2, 47));
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(3));
|
||||
|
||||
/* Test 5: RTL ASCII with leading whitespace */
|
||||
t = AddTest ("sans-serif",
|
||||
style_western_normal_16,
|
||||
S_ASCII,
|
||||
" ab");
|
||||
t->SetRTL();
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(3, 68, 69));
|
||||
t->Expect ("win32", "Arial", GLYPHS(3, 68, 69));
|
||||
t->Expect ("gtk2-pango", "Albany AMT", GLYPHS(3, 68, 69));
|
||||
|
||||
/* Test 6: RTL ASCII with trailing whitespace */
|
||||
t = AddTest ("sans-serif",
|
||||
style_western_normal_16,
|
||||
S_ASCII,
|
||||
"ab ");
|
||||
t->SetRTL();
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(68, 69, 3));
|
||||
t->Expect ("win32", "Arial", GLYPHS(68, 69, 3));
|
||||
t->Expect ("gtk2-pango", "Albany AMT", GLYPHS(68, 69, 3));
|
||||
|
||||
/* Test 7: Simple ASCII ligature */
|
||||
/* Do we have a Windows font with ligatures? Can we use DejaVu Sans? */
|
||||
t = AddTest ("sans-serif",
|
||||
style_western_normal_16,
|
||||
S_ASCII,
|
||||
"fi");
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(192));
|
||||
|
||||
/* Test 8: DEVANAGARI VOWEL I reordering */
|
||||
/* The glyph for DEVANAGARI VOWEL I 2367 (101) is displayed before the glyph for 2361 (99) */
|
||||
t = AddTest ("sans-serif",
|
||||
style_western_normal_16,
|
||||
S_UTF8,
|
||||
"\xe0\xa4\x9a\xe0\xa4\xbe\xe0\xa4\xb9\xe0\xa4\xbf\xe0\xa4\x8f"); // 2330 2366 2361 2367 2319
|
||||
t->Expect ("macosx", "DevanagariMT", GLYPHS(71, 100, 101, 99, 60));
|
||||
t->Expect ("win32", "Mangal", GLYPHS(133, 545, 465, 161, 102));
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
#include "gfxASurface.h"
|
||||
#include "gfxImageSurface.h"
|
||||
|
||||
#include "cairo.h"
|
||||
|
||||
int
|
||||
GetASurfaceRefCount(gfxASurface *s) {
|
||||
NS_ADDREF(s);
|
||||
|
@ -42,7 +40,7 @@ TestNewSurface () {
|
|||
int failures = 0;
|
||||
int destroyed = 0;
|
||||
|
||||
nsRefPtr<gfxASurface> s = new gfxImageSurface (gfxIntSize(10, 10), gfxASurface::ImageFormatARGB32);
|
||||
nsRefPtr<gfxASurface> s = new gfxImageSurface (gfxASurface::ImageFormatARGB32, 10, 10);
|
||||
cairo_surface_t *cs = s->CairoSurface();
|
||||
|
||||
cairo_surface_set_user_data (cs, &destruction_key, &destroyed, SurfaceDestroyNotifier);
|
||||
|
|
Загрузка…
Ссылка в новой задаче