зеркало из https://github.com/mozilla/pjs.git
Bug 96041. Compute precise glyph extents for high-quality text, and when requested. r=vlad,r+sr=dbaron
This commit is contained in:
Родитель
d503c88193
Коммит
dcd17482e7
|
@ -1589,8 +1589,8 @@ nsCanvasRenderingContext2D::MozMeasureText(const nsAString& textToMeasure, float
|
||||||
|
|
||||||
PRBool tightBoundingBox = PR_FALSE;
|
PRBool tightBoundingBox = PR_FALSE;
|
||||||
gfxTextRun::Metrics metrics = textRun->MeasureText(/* offset = */ 0, textToMeasure.Length(),
|
gfxTextRun::Metrics metrics = textRun->MeasureText(/* offset = */ 0, textToMeasure.Length(),
|
||||||
tightBoundingBox,
|
tightBoundingBox, mThebesContext,
|
||||||
nsnull);
|
nsnull);
|
||||||
*retVal = metrics.mAdvanceWidth/gfxFloat(elemDocument->GetPrimaryShell()->GetPresContext()->AppUnitsPerCSSPixel());
|
*retVal = metrics.mAdvanceWidth/gfxFloat(elemDocument->GetPrimaryShell()->GetPresContext()->AppUnitsPerCSSPixel());
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,6 +99,7 @@ typedef struct {
|
||||||
HFONT scaled_hfont;
|
HFONT scaled_hfont;
|
||||||
HFONT unscaled_hfont;
|
HFONT unscaled_hfont;
|
||||||
|
|
||||||
|
cairo_bool_t is_truetype;
|
||||||
cairo_bool_t glyph_indexing;
|
cairo_bool_t glyph_indexing;
|
||||||
|
|
||||||
cairo_bool_t delete_scaled_hfont;
|
cairo_bool_t delete_scaled_hfont;
|
||||||
|
@ -744,11 +745,11 @@ _cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((metrics.tmPitchAndFamily & TMPF_TRUETYPE) ||
|
scaled_font->is_truetype = (metrics.tmPitchAndFamily & TMPF_TRUETYPE) != 0;
|
||||||
(GetFontData (hdc, OPENTYPE_CFF_TAG, 0, NULL, 0) != GDI_ERROR))
|
scaled_font->glyph_indexing = scaled_font->is_truetype ||
|
||||||
scaled_font->glyph_indexing = TRUE;
|
(GetFontData (hdc, OPENTYPE_CFF_TAG, 0, NULL, 0) != GDI_ERROR);
|
||||||
else
|
// XXX in what situations does this OPENTYPE_CFF thing not have the
|
||||||
scaled_font->glyph_indexing = FALSE;
|
// TMPF_TRUETYPE flag? GetFontData says it only works on Truetype fonts...
|
||||||
|
|
||||||
_cairo_scaled_font_set_metrics (&scaled_font->base, &extents);
|
_cairo_scaled_font_set_metrics (&scaled_font->base, &extents);
|
||||||
|
|
||||||
|
@ -764,18 +765,35 @@ _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_f
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
cairo_text_extents_t extents;
|
cairo_text_extents_t extents;
|
||||||
HDC hdc;
|
HDC hdc;
|
||||||
UINT glyph_index_option;
|
|
||||||
|
|
||||||
hdc = _get_global_font_dc ();
|
hdc = _get_global_font_dc ();
|
||||||
if (!hdc)
|
if (!hdc)
|
||||||
return CAIRO_STATUS_NO_MEMORY;
|
return CAIRO_STATUS_NO_MEMORY;
|
||||||
|
|
||||||
if (scaled_font->glyph_indexing)
|
if (!scaled_font->is_truetype) {
|
||||||
glyph_index_option = GGO_GLYPH_INDEX;
|
/* GetGlyphOutline will not work. Assume that the glyph does not extend outside the font box. */
|
||||||
else
|
cairo_font_extents_t font_extents;
|
||||||
glyph_index_option = 0;
|
INT width = 0;
|
||||||
|
UINT charIndex = _cairo_scaled_glyph_index (scaled_glyph);
|
||||||
|
|
||||||
if (scaled_font->preserve_axes && scaled_font->base.options.hint_style != CAIRO_HINT_METRICS_OFF) {
|
cairo_scaled_font_extents (&scaled_font->base, &font_extents);
|
||||||
|
|
||||||
|
status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
|
||||||
|
if (!status) {
|
||||||
|
if (!GetCharWidth32(hdc, charIndex, charIndex, &width)) {
|
||||||
|
status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetCharWidth32");
|
||||||
|
width = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cairo_win32_scaled_font_done_font (&scaled_font->base);
|
||||||
|
|
||||||
|
extents.x_bearing = 0;
|
||||||
|
extents.y_bearing = -font_extents.ascent / scaled_font->y_scale;
|
||||||
|
extents.width = width / scaled_font->x_scale;
|
||||||
|
extents.height = (font_extents.ascent + font_extents.descent) / scaled_font->y_scale;
|
||||||
|
extents.x_advance = extents.width;
|
||||||
|
extents.y_advance = 0;
|
||||||
|
} else if (scaled_font->preserve_axes && scaled_font->base.options.hint_style != CAIRO_HINT_METRICS_OFF) {
|
||||||
/* If we aren't rotating / skewing the axes, then we get the metrics
|
/* If we aren't rotating / skewing the axes, then we get the metrics
|
||||||
* from the GDI in device space and convert to font space.
|
* from the GDI in device space and convert to font space.
|
||||||
*/
|
*/
|
||||||
|
@ -783,7 +801,7 @@ _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_f
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
|
if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
|
||||||
GGO_METRICS | glyph_index_option,
|
GGO_METRICS | GGO_GLYPH_INDEX,
|
||||||
&metrics, 0, NULL, &matrix) == GDI_ERROR) {
|
&metrics, 0, NULL, &matrix) == GDI_ERROR) {
|
||||||
status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetGlyphOutlineW");
|
status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetGlyphOutlineW");
|
||||||
memset (&metrics, 0, sizeof (GLYPHMETRICS));
|
memset (&metrics, 0, sizeof (GLYPHMETRICS));
|
||||||
|
@ -822,7 +840,7 @@ _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_f
|
||||||
*/
|
*/
|
||||||
status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
|
status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
|
||||||
if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
|
if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
|
||||||
GGO_METRICS | glyph_index_option,
|
GGO_METRICS | GGO_GLYPH_INDEX,
|
||||||
&metrics, 0, NULL, &matrix) == GDI_ERROR) {
|
&metrics, 0, NULL, &matrix) == GDI_ERROR) {
|
||||||
status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetGlyphOutlineW");
|
status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetGlyphOutlineW");
|
||||||
memset (&metrics, 0, sizeof (GLYPHMETRICS));
|
memset (&metrics, 0, sizeof (GLYPHMETRICS));
|
||||||
|
|
|
@ -72,6 +72,9 @@ public:
|
||||||
|
|
||||||
PRBool HasMirroringInfo();
|
PRBool HasMirroringInfo();
|
||||||
|
|
||||||
|
virtual void SetupGlyphExtents(gfxContext *aContext, PRUint32 aGlyphID,
|
||||||
|
PRBool aNeedTight, gfxGlyphExtents *aExtents);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const gfxFontStyle *mFontStyle;
|
const gfxFontStyle *mFontStyle;
|
||||||
|
|
||||||
|
@ -93,7 +96,7 @@ protected:
|
||||||
|
|
||||||
void InitMetrics(ATSUFontID aFontID, ATSFontRef aFontRef);
|
void InitMetrics(ATSUFontID aFontID, ATSFontRef aFontRef);
|
||||||
|
|
||||||
virtual PRBool SetupCairoFont(cairo_t *aCR);
|
virtual PRBool SetupCairoFont(gfxContext *aContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
class THEBES_API gfxAtsuiFontGroup : public gfxFontGroup {
|
class THEBES_API gfxAtsuiFontGroup : public gfxFontGroup {
|
||||||
|
|
|
@ -56,7 +56,6 @@ class gfxTextRun;
|
||||||
class nsIAtom;
|
class nsIAtom;
|
||||||
class gfxFont;
|
class gfxFont;
|
||||||
class gfxFontGroup;
|
class gfxFontGroup;
|
||||||
typedef struct _cairo cairo_t;
|
|
||||||
|
|
||||||
#define FONT_STYLE_NORMAL 0
|
#define FONT_STYLE_NORMAL 0
|
||||||
#define FONT_STYLE_ITALIC 1
|
#define FONT_STYLE_ITALIC 1
|
||||||
|
@ -230,6 +229,75 @@ protected:
|
||||||
nsTHashtable<HashEntry> mFonts;
|
nsTHashtable<HashEntry> mFonts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This stores glyph bounds information for a particular gfxFont, at
|
||||||
|
* a particular appunits-per-dev-pixel ratio (because the compressed glyph
|
||||||
|
* width array is stored in appunits).
|
||||||
|
*
|
||||||
|
* We store a hashtable from glyph IDs to float bounding rects. For the
|
||||||
|
* common case where the glyph has no horizontal left bearing, and no
|
||||||
|
* y overflow above the font ascent or below the font descent, and tight
|
||||||
|
* bounding boxes are not required, we avoid storing the glyph ID in the hashtable
|
||||||
|
* and instead consult an array of 16-bit glyph XMost values (in appunits).
|
||||||
|
* This array always has an entry for the font's space glyph --- the width is
|
||||||
|
* assumed to be zero.
|
||||||
|
*/
|
||||||
|
class THEBES_API gfxGlyphExtents {
|
||||||
|
public:
|
||||||
|
gfxGlyphExtents(PRUint32 aAppUnitsPerDevUnit) :
|
||||||
|
mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) {
|
||||||
|
mTightGlyphExtents.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { INVALID_WIDTH = 0xFFFF };
|
||||||
|
|
||||||
|
// returns INVALID_WIDTH => not a contained glyph
|
||||||
|
// Otherwise the glyph has no before-bearing or vertical bearings,
|
||||||
|
// and the result is its width measured from the baseline origin, in
|
||||||
|
// appunits.
|
||||||
|
PRUint16 GetContainedGlyphWidthAppUnits(PRUint32 aGlyphID) const {
|
||||||
|
if (aGlyphID >= mWidthsForContainedGlyphsAppUnits.Length())
|
||||||
|
return INVALID_WIDTH;
|
||||||
|
return mWidthsForContainedGlyphsAppUnits[aGlyphID];
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool IsGlyphKnown(PRUint32 aGlyphID) const {
|
||||||
|
if (aGlyphID < mWidthsForContainedGlyphsAppUnits.Length() &&
|
||||||
|
mWidthsForContainedGlyphsAppUnits[aGlyphID] != INVALID_WIDTH)
|
||||||
|
return PR_TRUE;
|
||||||
|
return mTightGlyphExtents.GetEntry(aGlyphID) != nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool IsGlyphKnownWithTightExtents(PRUint32 aGlyphID) const {
|
||||||
|
return mTightGlyphExtents.GetEntry(aGlyphID) != nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get glyph extents; a rectangle relative to the left baseline origin
|
||||||
|
gfxRect GetTightGlyphExtentsAppUnits(gfxFont *aFont, gfxContext *aContext, PRUint32 aGlyphID);
|
||||||
|
|
||||||
|
void SetContainedGlyphWidthAppUnits(PRUint32 aGlyphID, PRUint16 aWidth);
|
||||||
|
void SetTightGlyphExtents(PRUint32 aGlyphID, const gfxRect& aExtentsAppUnits);
|
||||||
|
|
||||||
|
PRUint32 GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
class HashEntry : public nsUint32HashKey {
|
||||||
|
public:
|
||||||
|
// When constructing a new entry in the hashtable, we'll leave this
|
||||||
|
// blank. The caller of Put() will fill this in.
|
||||||
|
HashEntry(KeyTypePointer aPtr) : nsUint32HashKey(aPtr) {}
|
||||||
|
HashEntry(const HashEntry& toCopy) : nsUint32HashKey(toCopy) {
|
||||||
|
x = toCopy.x; y = toCopy.y; width = toCopy.width; height = toCopy.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
float x, y, width, height;
|
||||||
|
};
|
||||||
|
|
||||||
|
nsTArray<PRUint16> mWidthsForContainedGlyphsAppUnits;
|
||||||
|
nsTHashtable<HashEntry> mTightGlyphExtents;
|
||||||
|
PRUint32 mAppUnitsPerDevUnit;
|
||||||
|
};
|
||||||
|
|
||||||
/* a SPECIFIC single font family */
|
/* a SPECIFIC single font family */
|
||||||
class THEBES_API gfxFont {
|
class THEBES_API gfxFont {
|
||||||
public:
|
public:
|
||||||
|
@ -259,7 +327,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
gfxFont(const nsAString &aName, const gfxFontStyle *aFontGroup);
|
gfxFont(const nsAString &aName, const gfxFontStyle *aFontGroup);
|
||||||
virtual ~gfxFont() {}
|
virtual ~gfxFont();
|
||||||
|
|
||||||
const nsString& GetName() const { return mName; }
|
const nsString& GetName() const { return mName; }
|
||||||
const gfxFontStyle *GetStyle() const { return &mStyle; }
|
const gfxFontStyle *GetStyle() const { return &mStyle; }
|
||||||
|
@ -389,6 +457,7 @@ public:
|
||||||
virtual RunMetrics Measure(gfxTextRun *aTextRun,
|
virtual RunMetrics Measure(gfxTextRun *aTextRun,
|
||||||
PRUint32 aStart, PRUint32 aEnd,
|
PRUint32 aStart, PRUint32 aEnd,
|
||||||
PRBool aTightBoundingBox,
|
PRBool aTightBoundingBox,
|
||||||
|
gfxContext *aContextForTightBoundingBox,
|
||||||
Spacing *aSpacing);
|
Spacing *aSpacing);
|
||||||
/**
|
/**
|
||||||
* Line breaks have been changed at the beginning and/or end of a substring
|
* Line breaks have been changed at the beginning and/or end of a substring
|
||||||
|
@ -405,14 +474,21 @@ public:
|
||||||
// Get the glyphID of a space
|
// Get the glyphID of a space
|
||||||
virtual PRUint32 GetSpaceGlyph() = 0;
|
virtual PRUint32 GetSpaceGlyph() = 0;
|
||||||
|
|
||||||
protected:
|
gfxGlyphExtents *GetOrCreateGlyphExtents(PRUint32 aAppUnitsPerDevUnit);
|
||||||
// The family name of the font
|
|
||||||
nsString mName;
|
// You need to call SetupCairoFont on the aCR just before calling this
|
||||||
nsExpirationState mExpirationState;
|
virtual void SetupGlyphExtents(gfxContext *aContext, PRUint32 aGlyphID,
|
||||||
gfxFontStyle mStyle;
|
PRBool aNeedTight, gfxGlyphExtents *aExtents);
|
||||||
|
|
||||||
// This is called by the default Draw() implementation above.
|
// This is called by the default Draw() implementation above.
|
||||||
virtual PRBool SetupCairoFont(cairo_t *aCR) = 0;
|
virtual PRBool SetupCairoFont(gfxContext *aContext) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// The family name of the font
|
||||||
|
nsString mName;
|
||||||
|
nsExpirationState mExpirationState;
|
||||||
|
gfxFontStyle mStyle;
|
||||||
|
nsAutoTArray<gfxGlyphExtents*,1> mGlyphExtentsArray;
|
||||||
};
|
};
|
||||||
|
|
||||||
class THEBES_API gfxTextRunFactory {
|
class THEBES_API gfxTextRunFactory {
|
||||||
|
@ -686,6 +762,7 @@ public:
|
||||||
*/
|
*/
|
||||||
Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
|
Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
|
||||||
PRBool aTightBoundingBox,
|
PRBool aTightBoundingBox,
|
||||||
|
gfxContext *aRefContextForTightBoundingBox,
|
||||||
PropertyProvider *aProvider);
|
PropertyProvider *aProvider);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -764,6 +841,8 @@ public:
|
||||||
* @param aMetrics if non-null, we fill this in for the returned substring.
|
* @param aMetrics if non-null, we fill this in for the returned substring.
|
||||||
* If a hyphenation break was used, the hyphen is NOT included in the returned metrics.
|
* If a hyphenation break was used, the hyphen is NOT included in the returned metrics.
|
||||||
* @param aTightBoundingBox if true, we make the bounding box in aMetrics tight
|
* @param aTightBoundingBox if true, we make the bounding box in aMetrics tight
|
||||||
|
* @param aRefContextForTightBoundingBox a reference context to get the
|
||||||
|
* tight bounding box, if aTightBoundingBox is true
|
||||||
* @param aUsedHyphenation if non-null, records if we selected a hyphenation break
|
* @param aUsedHyphenation if non-null, records if we selected a hyphenation break
|
||||||
* @param aLastBreak if non-null and result is aMaxLength, we set this to
|
* @param aLastBreak if non-null and result is aMaxLength, we set this to
|
||||||
* the maximal N such that
|
* the maximal N such that
|
||||||
|
@ -782,6 +861,7 @@ public:
|
||||||
PRBool aSuppressInitialBreak,
|
PRBool aSuppressInitialBreak,
|
||||||
gfxFloat *aTrimWhitespace,
|
gfxFloat *aTrimWhitespace,
|
||||||
Metrics *aMetrics, PRBool aTightBoundingBox,
|
Metrics *aMetrics, PRBool aTightBoundingBox,
|
||||||
|
gfxContext *aRefContextForTightBoundingBox,
|
||||||
PRBool *aUsedHyphenation,
|
PRBool *aUsedHyphenation,
|
||||||
PRUint32 *aLastBreak);
|
PRUint32 *aLastBreak);
|
||||||
|
|
||||||
|
@ -932,6 +1012,8 @@ public:
|
||||||
PRBool CanBreakBefore() const { return (mValue & FLAG_CAN_BREAK_BEFORE) != 0; }
|
PRBool CanBreakBefore() const { return (mValue & FLAG_CAN_BREAK_BEFORE) != 0; }
|
||||||
// Returns FLAG_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
|
// Returns FLAG_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
|
||||||
PRUint32 SetCanBreakBefore(PRBool aCanBreakBefore) {
|
PRUint32 SetCanBreakBefore(PRBool aCanBreakBefore) {
|
||||||
|
NS_ASSERTION(aCanBreakBefore == PR_FALSE || aCanBreakBefore == PR_TRUE,
|
||||||
|
"Bogus break-before value!");
|
||||||
PRUint32 breakMask = aCanBreakBefore*FLAG_CAN_BREAK_BEFORE;
|
PRUint32 breakMask = aCanBreakBefore*FLAG_CAN_BREAK_BEFORE;
|
||||||
PRUint32 toggle = breakMask ^ (mValue & FLAG_CAN_BREAK_BEFORE);
|
PRUint32 toggle = breakMask ^ (mValue & FLAG_CAN_BREAK_BEFORE);
|
||||||
mValue ^= toggle;
|
mValue ^= toggle;
|
||||||
|
@ -1070,6 +1152,8 @@ public:
|
||||||
PRUint32 aNumGlyphs);
|
PRUint32 aNumGlyphs);
|
||||||
void SetMissingGlyph(PRUint32 aCharIndex, PRUint32 aChar);
|
void SetMissingGlyph(PRUint32 aCharIndex, PRUint32 aChar);
|
||||||
void SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, PRUint32 aCharIndex);
|
void SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, PRUint32 aCharIndex);
|
||||||
|
|
||||||
|
void FetchGlyphExtents(gfxContext *aRefContext);
|
||||||
|
|
||||||
// API for access to the raw glyph data, needed by gfxFont::Draw
|
// API for access to the raw glyph data, needed by gfxFont::Draw
|
||||||
// and gfxFont::GetBoundingBox
|
// and gfxFont::GetBoundingBox
|
||||||
|
@ -1079,6 +1163,7 @@ public:
|
||||||
// Missing glyphs need not have details.
|
// Missing glyphs need not have details.
|
||||||
return mDetailedGlyphs ? mDetailedGlyphs[aCharIndex].get() : nsnull;
|
return mDetailedGlyphs ? mDetailedGlyphs[aCharIndex].get() : nsnull;
|
||||||
}
|
}
|
||||||
|
PRBool HasDetailedGlyphs() { return mDetailedGlyphs.get() != nsnull; }
|
||||||
PRUint32 CountMissingGlyphs();
|
PRUint32 CountMissingGlyphs();
|
||||||
const GlyphRun *GetGlyphRuns(PRUint32 *aNumGlyphRuns) {
|
const GlyphRun *GetGlyphRuns(PRUint32 *aNumGlyphRuns) {
|
||||||
*aNumGlyphRuns = mGlyphRuns.Length();
|
*aNumGlyphRuns = mGlyphRuns.Length();
|
||||||
|
@ -1157,12 +1242,14 @@ private:
|
||||||
gfxFloat GetPartialLigatureWidth(PRUint32 aStart, PRUint32 aEnd, PropertyProvider *aProvider);
|
gfxFloat GetPartialLigatureWidth(PRUint32 aStart, PRUint32 aEnd, PropertyProvider *aProvider);
|
||||||
void AccumulatePartialLigatureMetrics(gfxFont *aFont,
|
void AccumulatePartialLigatureMetrics(gfxFont *aFont,
|
||||||
PRUint32 aStart, PRUint32 aEnd, PRBool aTight,
|
PRUint32 aStart, PRUint32 aEnd, PRBool aTight,
|
||||||
|
gfxContext *aRefContext,
|
||||||
PropertyProvider *aProvider,
|
PropertyProvider *aProvider,
|
||||||
Metrics *aMetrics);
|
Metrics *aMetrics);
|
||||||
|
|
||||||
// **** measurement helper ****
|
// **** measurement helper ****
|
||||||
void AccumulateMetricsForRun(gfxFont *aFont, PRUint32 aStart,
|
void AccumulateMetricsForRun(gfxFont *aFont, PRUint32 aStart,
|
||||||
PRUint32 aEnd, PRBool aTight,
|
PRUint32 aEnd, PRBool aTight,
|
||||||
|
gfxContext *aRefContext,
|
||||||
PropertyProvider *aProvider,
|
PropertyProvider *aProvider,
|
||||||
PRUint32 aSpacingStart, PRUint32 aSpacingEnd,
|
PRUint32 aSpacingStart, PRUint32 aSpacingEnd,
|
||||||
Metrics *aMetrics);
|
Metrics *aMetrics);
|
||||||
|
|
|
@ -111,7 +111,7 @@ protected:
|
||||||
void GetCharSize(const char aChar, gfxSize& aInkSize, gfxSize& aLogSize,
|
void GetCharSize(const char aChar, gfxSize& aInkSize, gfxSize& aLogSize,
|
||||||
PRUint32 *aGlyphID = nsnull);
|
PRUint32 *aGlyphID = nsnull);
|
||||||
|
|
||||||
virtual PRBool SetupCairoFont(cairo_t *aCR);
|
virtual PRBool SetupCairoFont(gfxContext *aContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
class FontSelector;
|
class FontSelector;
|
||||||
|
|
|
@ -533,7 +533,7 @@ private:
|
||||||
|
|
||||||
nsRefPtr<FontEntry> mFontEntry;
|
nsRefPtr<FontEntry> mFontEntry;
|
||||||
|
|
||||||
virtual PRBool SetupCairoFont(cairo_t *aCR);
|
virtual PRBool SetupCairoFont(gfxContext *aContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
|
|
@ -171,8 +171,8 @@ gfxAtsuiFont::InitMetrics(ATSUFontID aFontID, ATSFontRef aFontRef)
|
||||||
|
|
||||||
mMetrics.emHeight = size;
|
mMetrics.emHeight = size;
|
||||||
|
|
||||||
mMetrics.maxAscent = atsMetrics.ascent * size;
|
mMetrics.maxAscent = NS_ceil(atsMetrics.ascent * size);
|
||||||
mMetrics.maxDescent = - (atsMetrics.descent * size);
|
mMetrics.maxDescent = NS_ceil(- (atsMetrics.descent * size));
|
||||||
|
|
||||||
mMetrics.maxHeight = mMetrics.maxAscent + mMetrics.maxDescent;
|
mMetrics.maxHeight = mMetrics.maxAscent + mMetrics.maxDescent;
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ gfxAtsuiFont::InitMetrics(ATSUFontID aFontID, ATSFontRef aFontRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
PRBool
|
PRBool
|
||||||
gfxAtsuiFont::SetupCairoFont(cairo_t *aCR)
|
gfxAtsuiFont::SetupCairoFont(gfxContext *aContext)
|
||||||
{
|
{
|
||||||
cairo_scaled_font_t *scaledFont = CairoScaledFont();
|
cairo_scaled_font_t *scaledFont = CairoScaledFont();
|
||||||
if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
|
if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
|
||||||
|
@ -234,7 +234,7 @@ gfxAtsuiFont::SetupCairoFont(cairo_t *aCR)
|
||||||
// the cairo_t, precluding any further drawing.
|
// the cairo_t, precluding any further drawing.
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
cairo_set_scaled_font(aCR, scaledFont);
|
cairo_set_scaled_font(aContext->GetCairo(), scaledFont);
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,6 +329,35 @@ CreateFontFallbacksFromFontList(nsTArray< nsRefPtr<gfxFont> > *aFonts,
|
||||||
return status == noErr ? NS_OK : NS_ERROR_FAILURE;
|
return status == noErr ? NS_OK : NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gfxAtsuiFont::SetupGlyphExtents(gfxContext *aContext, PRUint32 aGlyphID,
|
||||||
|
PRBool aNeedTight, gfxGlyphExtents *aExtents)
|
||||||
|
{
|
||||||
|
ATSGlyphScreenMetrics metrics;
|
||||||
|
GlyphID glyph = aGlyphID;
|
||||||
|
OSStatus err = ATSUGlyphGetScreenMetrics(mATSUStyle, 1, &glyph, 0, false, false,
|
||||||
|
&metrics);
|
||||||
|
if (err != noErr)
|
||||||
|
return;
|
||||||
|
PRUint32 appUnitsPerDevUnit = aExtents->GetAppUnitsPerDevUnit();
|
||||||
|
|
||||||
|
if (!aNeedTight && metrics.topLeft.x >= 0 &&
|
||||||
|
-metrics.topLeft.y + metrics.height <= mMetrics.maxAscent &&
|
||||||
|
metrics.topLeft.y <= mMetrics.maxDescent) {
|
||||||
|
PRUint32 appUnitsWidth =
|
||||||
|
PRUint32(NS_ceil((metrics.topLeft.x + metrics.width)*appUnitsPerDevUnit));
|
||||||
|
if (appUnitsWidth < gfxGlyphExtents::INVALID_WIDTH) {
|
||||||
|
aExtents->SetContainedGlyphWidthAppUnits(aGlyphID, PRUint16(appUnitsWidth));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double d2a = appUnitsPerDevUnit;
|
||||||
|
gfxRect bounds(metrics.topLeft.x*d2a, (metrics.topLeft.y - metrics.height)*d2a,
|
||||||
|
metrics.width*d2a, metrics.height*d2a);
|
||||||
|
aExtents->SetTightGlyphExtents(aGlyphID, bounds);
|
||||||
|
}
|
||||||
|
|
||||||
PRBool
|
PRBool
|
||||||
gfxAtsuiFont::HasMirroringInfo()
|
gfxAtsuiFont::HasMirroringInfo()
|
||||||
{
|
{
|
||||||
|
@ -572,6 +601,8 @@ gfxAtsuiFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
|
||||||
break;
|
break;
|
||||||
textRun->ResetGlyphRuns();
|
textRun->ResetGlyphRuns();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textRun->FetchGlyphExtents(aParams->mContext);
|
||||||
|
|
||||||
return textRun;
|
return textRun;
|
||||||
}
|
}
|
||||||
|
@ -614,6 +645,8 @@ gfxAtsuiFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
|
||||||
textRun->ResetGlyphRuns();
|
textRun->ResetGlyphRuns();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textRun->FetchGlyphExtents(aParams->mContext);
|
||||||
|
|
||||||
return textRun;
|
return textRun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,6 +162,17 @@ gfxFont::gfxFont(const nsAString &aName, const gfxFontStyle *aFontStyle) :
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gfxFont::~gfxFont()
|
||||||
|
{
|
||||||
|
PRUint32 i;
|
||||||
|
// We destroy the contents of mGlyphExtentsArray explicitly instead of
|
||||||
|
// using nsAutoPtr because VC++ can't deal with nsTArrays of nsAutoPtrs
|
||||||
|
// of classes that lack a proper copy constructor
|
||||||
|
for (i = 0; i < mGlyphExtentsArray.Length(); ++i) {
|
||||||
|
delete mGlyphExtentsArray[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper function in case we need to do any rounding or other
|
* A helper function in case we need to do any rounding or other
|
||||||
* processing here.
|
* processing here.
|
||||||
|
@ -213,13 +224,13 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||||
double x = aPt->x;
|
double x = aPt->x;
|
||||||
double y = aPt->y;
|
double y = aPt->y;
|
||||||
|
|
||||||
cairo_t *cr = aContext->GetCairo();
|
PRBool success = SetupCairoFont(aContext);
|
||||||
PRBool success = SetupCairoFont(cr);
|
|
||||||
if (NS_UNLIKELY(!success))
|
if (NS_UNLIKELY(!success))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GlyphBuffer glyphs;
|
GlyphBuffer glyphs;
|
||||||
cairo_glyph_t *glyph;
|
cairo_glyph_t *glyph;
|
||||||
|
cairo_t *cr = aContext->GetCairo();
|
||||||
|
|
||||||
if (aSpacing) {
|
if (aSpacing) {
|
||||||
x += direction*aSpacing[0].mBefore;
|
x += direction*aSpacing[0].mBefore;
|
||||||
|
@ -306,53 +317,220 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||||
*aPt = gfxPoint(x, y);
|
*aPt = gfxPoint(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
UnionWithXPoint(gfxRect *aRect, double aX)
|
||||||
|
{
|
||||||
|
if (aX < aRect->pos.x) {
|
||||||
|
aRect->size.width += aRect->pos.x - aX;
|
||||||
|
aRect->pos.x = aX;
|
||||||
|
} else if (aX > aRect->XMost()) {
|
||||||
|
aRect->size.width = aX - aRect->pos.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PRBool
|
||||||
|
NeedsGlyphExtents(gfxTextRun *aTextRun)
|
||||||
|
{
|
||||||
|
return (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED) == 0;
|
||||||
|
// return PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
gfxFont::RunMetrics
|
gfxFont::RunMetrics
|
||||||
gfxFont::Measure(gfxTextRun *aTextRun,
|
gfxFont::Measure(gfxTextRun *aTextRun,
|
||||||
PRUint32 aStart, PRUint32 aEnd,
|
PRUint32 aStart, PRUint32 aEnd,
|
||||||
PRBool aTightBoundingBox,
|
PRBool aTightBoundingBox, gfxContext *aRefContext,
|
||||||
Spacing *aSpacing)
|
Spacing *aSpacing)
|
||||||
{
|
{
|
||||||
// XXX temporary code, does not handle glyphs outside the font-box
|
|
||||||
// XXX comment out the assertion for now since it fires too much
|
|
||||||
// NS_ASSERTION(!(aTextRun->GetFlags() & gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX),
|
|
||||||
// "Glyph extents not yet supported");
|
|
||||||
PRInt32 advance = 0;
|
|
||||||
PRUint32 i;
|
|
||||||
const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs();
|
const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs();
|
||||||
|
const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
|
||||||
|
PRBool isRTL = aTextRun->IsRightToLeft();
|
||||||
|
double direction = aTextRun->GetDirection();
|
||||||
|
// Current position in appunits
|
||||||
|
const gfxFont::Metrics& fontMetrics = GetMetrics();
|
||||||
|
|
||||||
|
RunMetrics metrics;
|
||||||
|
metrics.mAscent = fontMetrics.maxAscent*appUnitsPerDevUnit;
|
||||||
|
metrics.mDescent = fontMetrics.maxDescent*appUnitsPerDevUnit;
|
||||||
|
metrics.mAdvanceWidth = 0;
|
||||||
|
if (aTightBoundingBox) {
|
||||||
|
metrics.mBoundingBox = gfxRect(0, 0, 0, 0);
|
||||||
|
} else {
|
||||||
|
metrics.mBoundingBox = gfxRect(0, -metrics.mAscent, 0, metrics.mAscent + metrics.mDescent);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfxGlyphExtents *extents =
|
||||||
|
(!aTightBoundingBox && !NeedsGlyphExtents(aTextRun) && !aTextRun->HasDetailedGlyphs()) ? nsnull
|
||||||
|
: GetOrCreateGlyphExtents(aTextRun->GetAppUnitsPerDevUnit());
|
||||||
|
double x = 0;
|
||||||
|
if (aSpacing) {
|
||||||
|
x += direction*aSpacing[0].mBefore;
|
||||||
|
}
|
||||||
|
PRUint32 i;
|
||||||
for (i = aStart; i < aEnd; ++i) {
|
for (i = aStart; i < aEnd; ++i) {
|
||||||
gfxTextRun::CompressedGlyph g = charGlyphs[i];
|
const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[i];
|
||||||
if (g.IsClusterStart()) {
|
if (glyphData->IsSimpleGlyph()) {
|
||||||
if (g.IsSimpleGlyph()) {
|
double advance = glyphData->GetSimpleAdvance();
|
||||||
advance += charGlyphs[i].GetSimpleAdvance();
|
// Only get the real glyph horizontal extent if we were asked
|
||||||
} else if (g.IsComplexOrMissing()) {
|
// for the tight bounding box or we're in quality mode
|
||||||
const gfxTextRun::DetailedGlyph *details = aTextRun->GetDetailedGlyphs(i);
|
if (aTightBoundingBox || NeedsGlyphExtents(aTextRun)) {
|
||||||
while (details) {
|
PRUint32 glyphIndex = glyphData->GetSimpleGlyph();
|
||||||
advance += details->mAdvance;
|
PRUint16 extentsWidth = extents->GetContainedGlyphWidthAppUnits(glyphIndex);
|
||||||
if (details->mIsLastGlyph)
|
if (extentsWidth != gfxGlyphExtents::INVALID_WIDTH && !aTightBoundingBox) {
|
||||||
break;
|
UnionWithXPoint(&metrics.mBoundingBox, x + direction*extentsWidth);
|
||||||
++details;
|
} else {
|
||||||
|
gfxRect glyphRect =
|
||||||
|
extents->GetTightGlyphExtentsAppUnits(this, aRefContext, glyphIndex);
|
||||||
|
if (isRTL) {
|
||||||
|
glyphRect.pos.x -= advance;
|
||||||
|
}
|
||||||
|
glyphRect.pos.x += x;
|
||||||
|
metrics.mBoundingBox = metrics.mBoundingBox.Union(glyphRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
x += direction*advance;
|
||||||
|
} else if (glyphData->IsComplexCluster()) {
|
||||||
|
const gfxTextRun::DetailedGlyph *details = aTextRun->GetDetailedGlyphs(i);
|
||||||
|
for (;;) {
|
||||||
|
PRUint32 glyphIndex = details->mGlyphID;
|
||||||
|
gfxPoint glyphPt(x + details->mXOffset, details->mYOffset);
|
||||||
|
double advance = details->mAdvance;
|
||||||
|
gfxRect glyphRect =
|
||||||
|
extents->GetTightGlyphExtentsAppUnits(this, aRefContext, glyphIndex);
|
||||||
|
if (isRTL) {
|
||||||
|
glyphRect.pos.x -= advance;
|
||||||
|
}
|
||||||
|
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
|
||||||
|
if (aSpacing) {
|
||||||
|
double space = aSpacing[i - aStart].mAfter;
|
||||||
|
if (i + 1 < aEnd) {
|
||||||
|
space += aSpacing[i + 1 - aStart].mBefore;
|
||||||
|
}
|
||||||
|
x += direction*space;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxFloat floatAdvance = advance;
|
if (!aTightBoundingBox) {
|
||||||
if (aSpacing) {
|
// Make sure the non-tight bounding box includes the entire advance
|
||||||
for (i = 0; i < aEnd - aStart; ++i) {
|
UnionWithXPoint(&metrics.mBoundingBox, x);
|
||||||
floatAdvance += aSpacing[i].mBefore + aSpacing[i].mAfter;
|
}
|
||||||
|
if (isRTL) {
|
||||||
|
metrics.mBoundingBox.pos.x -= x;
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics.mAdvanceWidth = x*direction;
|
||||||
|
return metrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfxGlyphExtents *
|
||||||
|
gfxFont::GetOrCreateGlyphExtents(PRUint32 aAppUnitsPerDevUnit) {
|
||||||
|
PRUint32 i;
|
||||||
|
for (i = 0; i < mGlyphExtentsArray.Length(); ++i) {
|
||||||
|
if (mGlyphExtentsArray[i]->GetAppUnitsPerDevUnit() == aAppUnitsPerDevUnit)
|
||||||
|
return mGlyphExtentsArray[i];
|
||||||
|
}
|
||||||
|
gfxGlyphExtents *glyphExtents = new gfxGlyphExtents(aAppUnitsPerDevUnit);
|
||||||
|
if (glyphExtents) {
|
||||||
|
mGlyphExtentsArray.AppendElement(glyphExtents);
|
||||||
|
// Initialize the extents of a space glyph, assuming that spaces don't
|
||||||
|
// render anything!
|
||||||
|
glyphExtents->SetContainedGlyphWidthAppUnits(GetSpaceGlyph(), 0);
|
||||||
|
}
|
||||||
|
return glyphExtents;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gfxFont::SetupGlyphExtents(gfxContext *aContext, PRUint32 aGlyphID, PRBool aNeedTight,
|
||||||
|
gfxGlyphExtents *aExtents)
|
||||||
|
{
|
||||||
|
cairo_glyph_t glyph;
|
||||||
|
glyph.index = aGlyphID;
|
||||||
|
glyph.x = 0;
|
||||||
|
glyph.y = 0;
|
||||||
|
cairo_text_extents_t extents;
|
||||||
|
cairo_glyph_extents(aContext->GetCairo(), &glyph, 1, &extents);
|
||||||
|
|
||||||
|
const Metrics& fontMetrics = GetMetrics();
|
||||||
|
PRUint32 appUnitsPerDevUnit = aExtents->GetAppUnitsPerDevUnit();
|
||||||
|
if (!aNeedTight && extents.x_bearing >= 0 &&
|
||||||
|
extents.y_bearing >= -fontMetrics.maxAscent &&
|
||||||
|
extents.height + extents.y_bearing <= fontMetrics.maxDescent) {
|
||||||
|
PRUint32 appUnitsWidth =
|
||||||
|
PRUint32(NS_ceil((extents.x_bearing + extents.width)*appUnitsPerDevUnit));
|
||||||
|
if (appUnitsWidth < gfxGlyphExtents::INVALID_WIDTH) {
|
||||||
|
aExtents->SetContainedGlyphWidthAppUnits(aGlyphID, PRUint16(appUnitsWidth));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RunMetrics metrics;
|
|
||||||
const gfxFont::Metrics& fontMetrics = GetMetrics();
|
double d2a = appUnitsPerDevUnit;
|
||||||
metrics.mAdvanceWidth = floatAdvance;
|
gfxRect bounds(extents.x_bearing*d2a, extents.y_bearing*d2a,
|
||||||
const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
|
extents.width*d2a, extents.height*d2a);
|
||||||
metrics.mAscent = fontMetrics.maxAscent*appUnitsPerDevUnit;
|
aExtents->SetTightGlyphExtents(aGlyphID, bounds);
|
||||||
gfxFloat descentForUnderline =
|
}
|
||||||
NS_round(fontMetrics.underlineSize) + NS_round(metrics.mAscent - fontMetrics.underlineOffset) - metrics.mAscent;
|
|
||||||
metrics.mDescent = PR_MAX(fontMetrics.maxDescent, descentForUnderline)*appUnitsPerDevUnit;
|
gfxRect
|
||||||
metrics.mBoundingBox =
|
gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont,
|
||||||
gfxRect(0, -metrics.mAscent, floatAdvance, metrics.mAscent + metrics.mDescent);
|
gfxContext *aContext, PRUint32 aGlyphID)
|
||||||
return metrics;
|
{
|
||||||
|
HashEntry *entry = mTightGlyphExtents.GetEntry(aGlyphID);
|
||||||
|
if (!entry) {
|
||||||
|
aFont->SetupCairoFont(aContext);
|
||||||
|
aFont->SetupGlyphExtents(aContext, aGlyphID, PR_TRUE, this);
|
||||||
|
entry = mTightGlyphExtents.GetEntry(aGlyphID);
|
||||||
|
if (!entry) {
|
||||||
|
NS_WARNING("Could not get glyph extents");
|
||||||
|
return gfxRect(0,0,0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gfxRect(entry->x, entry->y, entry->width, entry->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gfxGlyphExtents::SetContainedGlyphWidthAppUnits(PRUint32 aGlyphID, PRUint16 aWidth)
|
||||||
|
{
|
||||||
|
PRUint32 len = mWidthsForContainedGlyphsAppUnits.Length();
|
||||||
|
if (aGlyphID >= len) {
|
||||||
|
PRUint16 *elems = mWidthsForContainedGlyphsAppUnits.AppendElements(aGlyphID + 1 - len);
|
||||||
|
if (!elems)
|
||||||
|
return;
|
||||||
|
PRUint32 i;
|
||||||
|
for (i = len; i < aGlyphID; ++i) {
|
||||||
|
mWidthsForContainedGlyphsAppUnits[i] = INVALID_WIDTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mWidthsForContainedGlyphsAppUnits[aGlyphID] = aWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gfxGlyphExtents::SetTightGlyphExtents(PRUint32 aGlyphID, const gfxRect& aExtentsAppUnits)
|
||||||
|
{
|
||||||
|
HashEntry *entry = mTightGlyphExtents.PutEntry(aGlyphID);
|
||||||
|
if (!entry)
|
||||||
|
return;
|
||||||
|
entry->x = aExtentsAppUnits.pos.x;
|
||||||
|
entry->y = aExtentsAppUnits.pos.y;
|
||||||
|
entry->width = aExtentsAppUnits.size.width;
|
||||||
|
entry->height = aExtentsAppUnits.size.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxFontGroup::gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle)
|
gfxFontGroup::gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle)
|
||||||
|
@ -579,6 +757,9 @@ gfxFontGroup::MakeSpaceTextRun(const Parameters *aParams, PRUint32 aFlags)
|
||||||
|
|
||||||
gfxFont *font = GetFontAt(0);
|
gfxFont *font = GetFontAt(0);
|
||||||
textRun->SetSpaceGlyph(font, aParams->mContext, 0);
|
textRun->SetSpaceGlyph(font, aParams->mContext, 0);
|
||||||
|
// Note that the gfxGlyphExtents glyph bounds storage for the font will
|
||||||
|
// always contain an entry for the font's space glyph, so we don't have
|
||||||
|
// to call FetchGlyphExtents here.
|
||||||
return textRun.forget();
|
return textRun.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1103,14 +1284,15 @@ gfxTextRun::DrawToPath(gfxContext *aContext, gfxPoint aPt,
|
||||||
void
|
void
|
||||||
gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont,
|
gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont,
|
||||||
PRUint32 aStart, PRUint32 aEnd,
|
PRUint32 aStart, PRUint32 aEnd,
|
||||||
PRBool aTight, PropertyProvider *aProvider,
|
PRBool aTight, gfxContext *aRefContext,
|
||||||
|
PropertyProvider *aProvider,
|
||||||
PRUint32 aSpacingStart, PRUint32 aSpacingEnd,
|
PRUint32 aSpacingStart, PRUint32 aSpacingEnd,
|
||||||
Metrics *aMetrics)
|
Metrics *aMetrics)
|
||||||
{
|
{
|
||||||
nsAutoTArray<PropertyProvider::Spacing,200> spacingBuffer;
|
nsAutoTArray<PropertyProvider::Spacing,200> spacingBuffer;
|
||||||
PRBool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider,
|
PRBool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider,
|
||||||
aSpacingStart, aSpacingEnd, &spacingBuffer);
|
aSpacingStart, aSpacingEnd, &spacingBuffer);
|
||||||
Metrics metrics = aFont->Measure(this, aStart, aEnd, aTight,
|
Metrics metrics = aFont->Measure(this, aStart, aEnd, aTight, aRefContext,
|
||||||
haveSpacing ? spacingBuffer.Elements() : nsnull);
|
haveSpacing ? spacingBuffer.Elements() : nsnull);
|
||||||
|
|
||||||
if (IsRightToLeft()) {
|
if (IsRightToLeft()) {
|
||||||
|
@ -1123,7 +1305,7 @@ gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont,
|
||||||
|
|
||||||
void
|
void
|
||||||
gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont,
|
gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont,
|
||||||
PRUint32 aStart, PRUint32 aEnd, PRBool aTight,
|
PRUint32 aStart, PRUint32 aEnd, PRBool aTight, gfxContext *aRefContext,
|
||||||
PropertyProvider *aProvider, Metrics *aMetrics)
|
PropertyProvider *aProvider, Metrics *aMetrics)
|
||||||
{
|
{
|
||||||
if (aStart >= aEnd)
|
if (aStart >= aEnd)
|
||||||
|
@ -1136,7 +1318,7 @@ gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont,
|
||||||
// First measure the complete ligature
|
// First measure the complete ligature
|
||||||
Metrics metrics;
|
Metrics metrics;
|
||||||
AccumulateMetricsForRun(aFont, data.mLigatureStart, data.mLigatureEnd,
|
AccumulateMetricsForRun(aFont, data.mLigatureStart, data.mLigatureEnd,
|
||||||
aTight, aProvider, aStart, aEnd, &metrics);
|
aTight, aRefContext, aProvider, aStart, aEnd, &metrics);
|
||||||
|
|
||||||
// Clip the bounding box to the ligature part
|
// Clip the bounding box to the ligature part
|
||||||
gfxFloat bboxLeft = metrics.mBoundingBox.X();
|
gfxFloat bboxLeft = metrics.mBoundingBox.X();
|
||||||
|
@ -1164,7 +1346,7 @@ gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont,
|
||||||
|
|
||||||
gfxTextRun::Metrics
|
gfxTextRun::Metrics
|
||||||
gfxTextRun::MeasureText(PRUint32 aStart, PRUint32 aLength,
|
gfxTextRun::MeasureText(PRUint32 aStart, PRUint32 aLength,
|
||||||
PRBool aTightBoundingBox,
|
PRBool aTightBoundingBox, gfxContext *aRefContext,
|
||||||
PropertyProvider *aProvider)
|
PropertyProvider *aProvider)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(aStart + aLength <= mCharacterCount, "Substring out of range");
|
NS_ASSERTION(aStart + aLength <= mCharacterCount, "Substring out of range");
|
||||||
|
@ -1180,7 +1362,7 @@ gfxTextRun::MeasureText(PRUint32 aStart, PRUint32 aLength,
|
||||||
ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
|
ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
|
||||||
|
|
||||||
AccumulatePartialLigatureMetrics(font, start, ligatureRunStart,
|
AccumulatePartialLigatureMetrics(font, start, ligatureRunStart,
|
||||||
aTightBoundingBox, aProvider, &accumulatedMetrics);
|
aTightBoundingBox, aRefContext, aProvider, &accumulatedMetrics);
|
||||||
|
|
||||||
// XXX This sucks. We have to get glyph extents just so we can detect
|
// XXX This sucks. We have to get glyph extents just so we can detect
|
||||||
// glyphs outside the font box, even when aTightBoundingBox is false,
|
// glyphs outside the font box, even when aTightBoundingBox is false,
|
||||||
|
@ -1188,12 +1370,12 @@ gfxTextRun::MeasureText(PRUint32 aStart, PRUint32 aLength,
|
||||||
// by getting some ascent/descent from the font and using our stored
|
// by getting some ascent/descent from the font and using our stored
|
||||||
// advance widths.
|
// advance widths.
|
||||||
AccumulateMetricsForRun(font,
|
AccumulateMetricsForRun(font,
|
||||||
ligatureRunStart, ligatureRunEnd, aTightBoundingBox, aProvider,
|
ligatureRunStart, ligatureRunEnd, aTightBoundingBox,
|
||||||
ligatureRunStart, ligatureRunEnd,
|
aRefContext, aProvider, ligatureRunStart, ligatureRunEnd,
|
||||||
&accumulatedMetrics);
|
&accumulatedMetrics);
|
||||||
|
|
||||||
AccumulatePartialLigatureMetrics(font, ligatureRunEnd, end,
|
AccumulatePartialLigatureMetrics(font, ligatureRunEnd, end,
|
||||||
aTightBoundingBox, aProvider, &accumulatedMetrics);
|
aTightBoundingBox, aRefContext, aProvider, &accumulatedMetrics);
|
||||||
}
|
}
|
||||||
|
|
||||||
return accumulatedMetrics;
|
return accumulatedMetrics;
|
||||||
|
@ -1208,6 +1390,7 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
||||||
PRBool aSuppressInitialBreak,
|
PRBool aSuppressInitialBreak,
|
||||||
gfxFloat *aTrimWhitespace,
|
gfxFloat *aTrimWhitespace,
|
||||||
Metrics *aMetrics, PRBool aTightBoundingBox,
|
Metrics *aMetrics, PRBool aTightBoundingBox,
|
||||||
|
gfxContext *aRefContext,
|
||||||
PRBool *aUsedHyphenation,
|
PRBool *aUsedHyphenation,
|
||||||
PRUint32 *aLastBreak)
|
PRUint32 *aLastBreak)
|
||||||
{
|
{
|
||||||
|
@ -1349,7 +1532,8 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aMetrics) {
|
if (aMetrics) {
|
||||||
*aMetrics = MeasureText(aStart, charsFit - trimmableChars, aTightBoundingBox, aProvider);
|
*aMetrics = MeasureText(aStart, charsFit - trimmableChars,
|
||||||
|
aTightBoundingBox, aRefContext, aProvider);
|
||||||
}
|
}
|
||||||
if (aTrimWhitespace) {
|
if (aTrimWhitespace) {
|
||||||
*aTrimWhitespace = trimmableAdvance;
|
*aTrimWhitespace = trimmableAdvance;
|
||||||
|
@ -1718,3 +1902,55 @@ gfxTextRun::SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, PRUint32 aCharIn
|
||||||
g.SetSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
|
g.SetSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
|
||||||
SetCharacterGlyph(aCharIndex, g);
|
SetCharacterGlyph(aCharIndex, g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext)
|
||||||
|
{
|
||||||
|
if (!NeedsGlyphExtents(this) && !mDetailedGlyphs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PRUint32 i;
|
||||||
|
CompressedGlyph *charGlyphs = mCharacterGlyphs;
|
||||||
|
for (i = 0; i < mGlyphRuns.Length(); ++i) {
|
||||||
|
gfxFont *font = mGlyphRuns[i].mFont;
|
||||||
|
PRUint32 start = mGlyphRuns[i].mCharacterOffset;
|
||||||
|
PRUint32 end = i + 1 < mGlyphRuns.Length()
|
||||||
|
? mGlyphRuns[i + 1].mCharacterOffset : GetLength();
|
||||||
|
PRBool fontIsSetup = PR_FALSE;
|
||||||
|
PRUint32 j;
|
||||||
|
gfxGlyphExtents *extents = font->GetOrCreateGlyphExtents(mAppUnitsPerDevUnit);
|
||||||
|
|
||||||
|
for (j = start; j < end; ++j) {
|
||||||
|
const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[j];
|
||||||
|
if (glyphData->IsSimpleGlyph()) {
|
||||||
|
// If we're in speed mode, don't set up glyph extents here; we'll
|
||||||
|
// just return "optimistic" glyph bounds later
|
||||||
|
if (NeedsGlyphExtents(this)) {
|
||||||
|
PRUint32 glyphIndex = glyphData->GetSimpleGlyph();
|
||||||
|
if (!extents->IsGlyphKnown(glyphIndex)) {
|
||||||
|
if (!fontIsSetup) {
|
||||||
|
font->SetupCairoFont(aRefContext);
|
||||||
|
fontIsSetup = PR_TRUE;
|
||||||
|
}
|
||||||
|
font->SetupGlyphExtents(aRefContext, glyphIndex, PR_FALSE, extents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (glyphData->IsComplexCluster()) {
|
||||||
|
const gfxTextRun::DetailedGlyph *details = GetDetailedGlyphs(j);
|
||||||
|
for (;;) {
|
||||||
|
PRUint32 glyphIndex = details->mGlyphID;
|
||||||
|
if (!extents->IsGlyphKnownWithTightExtents(glyphIndex)) {
|
||||||
|
if (!fontIsSetup) {
|
||||||
|
font->SetupCairoFont(aRefContext);
|
||||||
|
fontIsSetup = PR_TRUE;
|
||||||
|
}
|
||||||
|
font->SetupGlyphExtents(aRefContext, glyphIndex, PR_TRUE, extents);
|
||||||
|
}
|
||||||
|
if (details->mIsLastGlyph)
|
||||||
|
break;
|
||||||
|
++details;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -828,6 +828,7 @@ gfxPangoFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
|
||||||
AppendUTF16toUTF8(unicodeString, utf8);
|
AppendUTF16toUTF8(unicodeString, utf8);
|
||||||
InitTextRun(run, utf8.get(), utf8.Length(), headerLen, PR_TRUE);
|
InitTextRun(run, utf8.get(), utf8.Length(), headerLen, PR_TRUE);
|
||||||
}
|
}
|
||||||
|
run->FetchGlyphExtents(aParams->mContext);
|
||||||
return run;
|
return run;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -866,6 +867,7 @@ gfxPangoFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
InitTextRun(run, utf8.get(), utf8.Length(), headerLen, is8Bit);
|
InitTextRun(run, utf8.get(), utf8.Length(), headerLen, is8Bit);
|
||||||
|
run->FetchGlyphExtents(aParams->mContext);
|
||||||
return run;
|
return run;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -916,10 +918,11 @@ CreateScaledFont(cairo_t *aCR, cairo_matrix_t *aCTM, PangoFont *aPangoFont)
|
||||||
}
|
}
|
||||||
|
|
||||||
PRBool
|
PRBool
|
||||||
gfxPangoFont::SetupCairoFont(cairo_t *aCR)
|
gfxPangoFont::SetupCairoFont(gfxContext *aContext)
|
||||||
{
|
{
|
||||||
|
cairo_t *cr = aContext->GetCairo();
|
||||||
cairo_matrix_t currentCTM;
|
cairo_matrix_t currentCTM;
|
||||||
cairo_get_matrix(aCR, ¤tCTM);
|
cairo_get_matrix(cr, ¤tCTM);
|
||||||
|
|
||||||
if (mCairoFont) {
|
if (mCairoFont) {
|
||||||
// Need to validate that its CTM is OK
|
// Need to validate that its CTM is OK
|
||||||
|
@ -933,14 +936,14 @@ gfxPangoFont::SetupCairoFont(cairo_t *aCR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!mCairoFont) {
|
if (!mCairoFont) {
|
||||||
mCairoFont = CreateScaledFont(aCR, ¤tCTM, GetPangoFont());
|
mCairoFont = CreateScaledFont(cr, ¤tCTM, GetPangoFont());
|
||||||
}
|
}
|
||||||
if (cairo_scaled_font_status(mCairoFont) != CAIRO_STATUS_SUCCESS) {
|
if (cairo_scaled_font_status(mCairoFont) != CAIRO_STATUS_SUCCESS) {
|
||||||
// Don't cairo_set_scaled_font as that would propagate the error to
|
// Don't cairo_set_scaled_font as that would propagate the error to
|
||||||
// the cairo_t, precluding any further drawing.
|
// the cairo_t, precluding any further drawing.
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
cairo_set_scaled_font(aCR, mCairoFont);
|
cairo_set_scaled_font(cr, mCairoFont);
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -434,7 +434,7 @@ gfxWindowsFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
||||||
}
|
}
|
||||||
|
|
||||||
PRBool
|
PRBool
|
||||||
gfxWindowsFont::SetupCairoFont(cairo_t *aCR)
|
gfxWindowsFont::SetupCairoFont(gfxContext *aContext)
|
||||||
{
|
{
|
||||||
cairo_scaled_font_t *scaledFont = CairoScaledFont();
|
cairo_scaled_font_t *scaledFont = CairoScaledFont();
|
||||||
if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
|
if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
|
||||||
|
@ -442,7 +442,7 @@ gfxWindowsFont::SetupCairoFont(cairo_t *aCR)
|
||||||
// the cairo_t, precluding any further drawing.
|
// the cairo_t, precluding any further drawing.
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
cairo_set_scaled_font(aCR, scaledFont);
|
cairo_set_scaled_font(aContext->GetCairo(), scaledFont);
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,6 +566,8 @@ gfxWindowsFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
|
||||||
else
|
else
|
||||||
InitTextRunGDI(aParams->mContext, textRun, aString, aLength);
|
InitTextRunGDI(aParams->mContext, textRun, aString, aLength);
|
||||||
|
|
||||||
|
textRun->FetchGlyphExtents(aParams->mContext);
|
||||||
|
|
||||||
return textRun;
|
return textRun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,6 +607,8 @@ gfxWindowsFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textRun->FetchGlyphExtents(aParams->mContext);
|
||||||
|
|
||||||
return textRun;
|
return textRun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -184,6 +184,8 @@ BRFrame::Reflow(nsPresContext* aPresContext,
|
||||||
else {
|
else {
|
||||||
aStatus = NS_FRAME_COMPLETE;
|
aStatus = NS_FRAME_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aMetrics.mOverflowArea = nsRect(0, 0, aMetrics.width, aMetrics.height);
|
||||||
|
|
||||||
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
|
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
@ -1562,6 +1562,12 @@ nsBulletFrame::Reflow(nsPresContext* aPresContext,
|
||||||
aMetrics.height += borderPadding.top + borderPadding.bottom;
|
aMetrics.height += borderPadding.top + borderPadding.bottom;
|
||||||
aMetrics.ascent += borderPadding.top;
|
aMetrics.ascent += borderPadding.top;
|
||||||
|
|
||||||
|
// XXX this is a bit of a hack, we're assuming that no glyphs used for bullets
|
||||||
|
// overflow their font-boxes. It'll do for now; to fix it for real, we really
|
||||||
|
// should rewrite all the text-handling code here to use gfxTextRun (bug
|
||||||
|
// 397294).
|
||||||
|
aMetrics.mOverflowArea.SetRect(0, 0, aMetrics.width, aMetrics.height);
|
||||||
|
|
||||||
aStatus = NS_FRAME_COMPLETE;
|
aStatus = NS_FRAME_COMPLETE;
|
||||||
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
|
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
#include "nsTextFragment.h"
|
#include "nsTextFragment.h"
|
||||||
#include "nsBidiUtils.h"
|
#include "nsBidiUtils.h"
|
||||||
#include "nsLayoutUtils.h"
|
#include "nsLayoutUtils.h"
|
||||||
|
#include "nsTextFrame.h"
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#undef NOISY_HORIZONTAL_ALIGN
|
#undef NOISY_HORIZONTAL_ALIGN
|
||||||
|
@ -2420,6 +2421,10 @@ nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD, FrameJustificationState
|
||||||
|
|
||||||
aState->mWidthForLettersProcessed = newAllocatedWidthForLetters;
|
aState->mWidthForLettersProcessed = newAllocatedWidthForLetters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dw) {
|
||||||
|
pfd->SetFlag(PFD_RECOMPUTEOVERFLOW, PR_TRUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (nsnull != pfd->mSpan) {
|
if (nsnull != pfd->mSpan) {
|
||||||
|
@ -2643,11 +2648,12 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea)
|
||||||
// aggregating it into our combined area.
|
// aggregating it into our combined area.
|
||||||
RelativePositionFrames(pfd->mSpan, r);
|
RelativePositionFrames(pfd->mSpan, r);
|
||||||
} else {
|
} else {
|
||||||
// For simple text frames we take the union of the combined area
|
r = pfd->mCombinedArea;
|
||||||
// and the width/height. I think the combined area should always
|
if (pfd->GetFlag(PFD_RECOMPUTEOVERFLOW)) {
|
||||||
// equal the bounds in this case, but this is safe.
|
nsTextFrame* f = static_cast<nsTextFrame*>(frame);
|
||||||
nsRect adjustedBounds(0, 0, pfd->mBounds.width, pfd->mBounds.height);
|
r = f->RecomputeOverflowRect();
|
||||||
r.UnionRect(pfd->mCombinedArea, adjustedBounds);
|
}
|
||||||
|
frame->FinishAndStoreOverflow(&r, frame->GetSize());
|
||||||
|
|
||||||
// If we have something that's not an inline but with a complex frame
|
// If we have something that's not an inline but with a complex frame
|
||||||
// hierarchy inside that contains views, they need to be
|
// hierarchy inside that contains views, they need to be
|
||||||
|
|
|
@ -502,6 +502,7 @@ protected:
|
||||||
#define PFD_ISNONEMPTYTEXTFRAME 0x00000004
|
#define PFD_ISNONEMPTYTEXTFRAME 0x00000004
|
||||||
#define PFD_ISNONWHITESPACETEXTFRAME 0x00000008
|
#define PFD_ISNONWHITESPACETEXTFRAME 0x00000008
|
||||||
#define PFD_ISLETTERFRAME 0x00000010
|
#define PFD_ISLETTERFRAME 0x00000010
|
||||||
|
#define PFD_RECOMPUTEOVERFLOW 0x00000020
|
||||||
#define PFD_ISBULLET 0x00000040
|
#define PFD_ISBULLET 0x00000040
|
||||||
#define PFD_SKIPWHENTRIMMINGWHITESPACE 0x00000080
|
#define PFD_SKIPWHENTRIMMINGWHITESPACE 0x00000080
|
||||||
#define PFD_LASTFLAG PFD_SKIPWHENTRIMMINGWHITESPACE
|
#define PFD_LASTFLAG PFD_SKIPWHENTRIMMINGWHITESPACE
|
||||||
|
|
|
@ -0,0 +1,346 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Netscape Communications Corporation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Robert O'Callahan <robert@ocallahan.org>
|
||||||
|
* Roger B. Sidje <rbs@maths.uq.edu.au>
|
||||||
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||||
|
* Prabhat Hegde <prabhat.hegde@sun.com>
|
||||||
|
* Tomi Leppikangas <tomi.leppikangas@oulu.fi>
|
||||||
|
* Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
|
||||||
|
* Daniel Glazman <glazman@netscape.com>
|
||||||
|
* Neil Deakin <neil@mozdevgroup.com>
|
||||||
|
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||||
|
* Mats Palmgren <mats.palmgren@bredband.net>
|
||||||
|
* Uri Bernstein <uriber@gmail.com>
|
||||||
|
* Stephen Blackheath <entangled.mooched.stephen@blacksapphire.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#ifndef nsTextFrame_h__
|
||||||
|
#define nsTextFrame_h__
|
||||||
|
|
||||||
|
#include "nsFrame.h"
|
||||||
|
#include "nsLineBox.h"
|
||||||
|
#include "gfxFont.h"
|
||||||
|
#include "gfxSkipChars.h"
|
||||||
|
|
||||||
|
class nsTextPaintStyle;
|
||||||
|
class PropertyProvider;
|
||||||
|
|
||||||
|
class nsTextFrame : public nsFrame {
|
||||||
|
public:
|
||||||
|
nsTextFrame(nsStyleContext* aContext) : nsFrame(aContext)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(mContentOffset == 0, "Bogus content offset");
|
||||||
|
}
|
||||||
|
|
||||||
|
// nsIFrame
|
||||||
|
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||||
|
const nsRect& aDirtyRect,
|
||||||
|
const nsDisplayListSet& aLists);
|
||||||
|
|
||||||
|
NS_IMETHOD Init(nsIContent* aContent,
|
||||||
|
nsIFrame* aParent,
|
||||||
|
nsIFrame* aPrevInFlow);
|
||||||
|
|
||||||
|
virtual void Destroy();
|
||||||
|
|
||||||
|
NS_IMETHOD GetCursor(const nsPoint& aPoint,
|
||||||
|
nsIFrame::Cursor& aCursor);
|
||||||
|
|
||||||
|
NS_IMETHOD CharacterDataChanged(nsPresContext* aPresContext,
|
||||||
|
nsIContent* aChild,
|
||||||
|
PRBool aAppend);
|
||||||
|
|
||||||
|
NS_IMETHOD DidSetStyleContext();
|
||||||
|
|
||||||
|
virtual nsIFrame* GetNextContinuation() const {
|
||||||
|
return mNextContinuation;
|
||||||
|
}
|
||||||
|
NS_IMETHOD SetNextContinuation(nsIFrame* aNextContinuation) {
|
||||||
|
NS_ASSERTION (!aNextContinuation || GetType() == aNextContinuation->GetType(),
|
||||||
|
"setting a next continuation with incorrect type!");
|
||||||
|
NS_ASSERTION (!nsSplittableFrame::IsInNextContinuationChain(aNextContinuation, this),
|
||||||
|
"creating a loop in continuation chain!");
|
||||||
|
mNextContinuation = aNextContinuation;
|
||||||
|
if (aNextContinuation)
|
||||||
|
aNextContinuation->RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
virtual nsIFrame* GetNextInFlowVirtual() const { return GetNextInFlow(); }
|
||||||
|
nsIFrame* GetNextInFlow() const {
|
||||||
|
return mNextContinuation && (mNextContinuation->GetStateBits() & NS_FRAME_IS_FLUID_CONTINUATION) ?
|
||||||
|
mNextContinuation : nsnull;
|
||||||
|
}
|
||||||
|
NS_IMETHOD SetNextInFlow(nsIFrame* aNextInFlow) {
|
||||||
|
NS_ASSERTION (!aNextInFlow || GetType() == aNextInFlow->GetType(),
|
||||||
|
"setting a next in flow with incorrect type!");
|
||||||
|
NS_ASSERTION (!nsSplittableFrame::IsInNextContinuationChain(aNextInFlow, this),
|
||||||
|
"creating a loop in continuation chain!");
|
||||||
|
mNextContinuation = aNextInFlow;
|
||||||
|
if (aNextInFlow)
|
||||||
|
aNextInFlow->AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
virtual nsIFrame* GetLastInFlow() const;
|
||||||
|
virtual nsIFrame* GetLastContinuation() const;
|
||||||
|
|
||||||
|
virtual nsSplittableType GetSplittableType() const {
|
||||||
|
return NS_FRAME_SPLITTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the "type" of the frame
|
||||||
|
*
|
||||||
|
* @see nsGkAtoms::textFrame
|
||||||
|
*/
|
||||||
|
virtual nsIAtom* GetType() const;
|
||||||
|
|
||||||
|
virtual PRBool IsFrameOfType(PRUint32 aFlags) const
|
||||||
|
{
|
||||||
|
// Set the frame state bit for text frames to mark them as replaced.
|
||||||
|
// XXX kipp: temporary
|
||||||
|
return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced |
|
||||||
|
nsIFrame::eLineParticipant));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
|
||||||
|
NS_IMETHOD GetFrameName(nsAString& aResult) const;
|
||||||
|
NS_IMETHOD_(nsFrameState) GetDebugStateBits() const ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
virtual ContentOffsets CalcContentOffsetsFromFramePoint(nsPoint aPoint);
|
||||||
|
|
||||||
|
NS_IMETHOD SetSelected(nsPresContext* aPresContext,
|
||||||
|
nsIDOMRange *aRange,
|
||||||
|
PRBool aSelected,
|
||||||
|
nsSpread aSpread);
|
||||||
|
|
||||||
|
virtual PRBool PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset);
|
||||||
|
virtual PRBool PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset);
|
||||||
|
virtual PRBool PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsKeyboardSelect,
|
||||||
|
PRInt32* aOffset, PeekWordState* aState);
|
||||||
|
|
||||||
|
NS_IMETHOD CheckVisibility(nsPresContext* aContext, PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aRecurse, PRBool *aFinished, PRBool *_retval);
|
||||||
|
|
||||||
|
// Update offsets to account for new length. This may clear mTextRun.
|
||||||
|
void SetLength(PRInt32 aLength);
|
||||||
|
|
||||||
|
NS_IMETHOD GetOffsets(PRInt32 &start, PRInt32 &end)const;
|
||||||
|
|
||||||
|
virtual void AdjustOffsetsForBidi(PRInt32 start, PRInt32 end);
|
||||||
|
|
||||||
|
NS_IMETHOD GetPointFromOffset(PRInt32 inOffset,
|
||||||
|
nsPoint* outPoint);
|
||||||
|
|
||||||
|
NS_IMETHOD GetChildFrameContainingOffset(PRInt32 inContentOffset,
|
||||||
|
PRBool inHint,
|
||||||
|
PRInt32* outFrameContentOffset,
|
||||||
|
nsIFrame* *outChildFrame);
|
||||||
|
|
||||||
|
virtual PRBool IsVisibleInSelection(nsISelection* aSelection);
|
||||||
|
|
||||||
|
virtual PRBool IsEmpty();
|
||||||
|
virtual PRBool IsSelfEmpty() { return IsEmpty(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return PR_TRUE if this text frame ends with a newline character. It
|
||||||
|
* should return PR_FALSE if this is not a text frame.
|
||||||
|
*/
|
||||||
|
virtual PRBool HasTerminalNewline() const;
|
||||||
|
|
||||||
|
#ifdef ACCESSIBILITY
|
||||||
|
NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
virtual void MarkIntrinsicWidthsDirty();
|
||||||
|
virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext);
|
||||||
|
virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext);
|
||||||
|
virtual void AddInlineMinWidth(nsIRenderingContext *aRenderingContext,
|
||||||
|
InlineMinWidthData *aData);
|
||||||
|
virtual void AddInlinePrefWidth(nsIRenderingContext *aRenderingContext,
|
||||||
|
InlinePrefWidthData *aData);
|
||||||
|
virtual nsSize ComputeSize(nsIRenderingContext *aRenderingContext,
|
||||||
|
nsSize aCBSize, nscoord aAvailableWidth,
|
||||||
|
nsSize aMargin, nsSize aBorder, nsSize aPadding,
|
||||||
|
PRBool aShrinkWrap);
|
||||||
|
NS_IMETHOD Reflow(nsPresContext* aPresContext,
|
||||||
|
nsHTMLReflowMetrics& aMetrics,
|
||||||
|
const nsHTMLReflowState& aReflowState,
|
||||||
|
nsReflowStatus& aStatus);
|
||||||
|
virtual PRBool CanContinueTextRun() const;
|
||||||
|
NS_IMETHOD TrimTrailingWhiteSpace(nsPresContext* aPresContext,
|
||||||
|
nsIRenderingContext& aRC,
|
||||||
|
nscoord& aDeltaWidth,
|
||||||
|
PRBool& aLastCharIsJustifiable);
|
||||||
|
virtual nsresult GetRenderedText(nsAString* aString = nsnull,
|
||||||
|
gfxSkipChars* aSkipChars = nsnull,
|
||||||
|
gfxSkipCharsIterator* aSkipIter = nsnull,
|
||||||
|
PRUint32 aSkippedStartOffset = 0,
|
||||||
|
PRUint32 aSkippedMaxLength = PR_UINT32_MAX);
|
||||||
|
|
||||||
|
nsRect RecomputeOverflowRect();
|
||||||
|
|
||||||
|
void AddInlineMinWidthForFlow(nsIRenderingContext *aRenderingContext,
|
||||||
|
nsIFrame::InlineMinWidthData *aData);
|
||||||
|
void AddInlinePrefWidthForFlow(nsIRenderingContext *aRenderingContext,
|
||||||
|
InlinePrefWidthData *aData);
|
||||||
|
|
||||||
|
gfxFloat GetSnappedBaselineY(gfxContext* aContext, gfxFloat aY);
|
||||||
|
|
||||||
|
// primary frame paint method called from nsDisplayText
|
||||||
|
void PaintText(nsIRenderingContext* aRenderingContext, nsPoint aPt,
|
||||||
|
const nsRect& aDirtyRect);
|
||||||
|
// helper: paint quirks-mode CSS text decorations
|
||||||
|
void PaintTextDecorations(gfxContext* aCtx, const gfxRect& aDirtyRect,
|
||||||
|
const gfxPoint& aFramePt,
|
||||||
|
const gfxPoint& aTextBaselinePt,
|
||||||
|
nsTextPaintStyle& aTextStyle,
|
||||||
|
PropertyProvider& aProvider);
|
||||||
|
// helper: paint text frame when we're impacted by at least one selection.
|
||||||
|
// Return PR_FALSE if the text was not painted and we should continue with
|
||||||
|
// the fast path.
|
||||||
|
PRBool PaintTextWithSelection(gfxContext* aCtx,
|
||||||
|
const gfxPoint& aFramePt,
|
||||||
|
const gfxPoint& aTextBaselinePt,
|
||||||
|
const gfxRect& aDirtyRect,
|
||||||
|
PropertyProvider& aProvider,
|
||||||
|
nsTextPaintStyle& aTextPaintStyle);
|
||||||
|
// helper: paint text with foreground and background colors determined
|
||||||
|
// by selection(s). Also computes a mask of all selection types applying to
|
||||||
|
// our text, returned in aAllTypes.
|
||||||
|
void PaintTextWithSelectionColors(gfxContext* aCtx,
|
||||||
|
const gfxPoint& aFramePt,
|
||||||
|
const gfxPoint& aTextBaselinePt,
|
||||||
|
const gfxRect& aDirtyRect,
|
||||||
|
PropertyProvider& aProvider,
|
||||||
|
nsTextPaintStyle& aTextPaintStyle,
|
||||||
|
SelectionDetails* aDetails,
|
||||||
|
SelectionType* aAllTypes);
|
||||||
|
// helper: paint text decorations for text selected by aSelectionType
|
||||||
|
void PaintTextSelectionDecorations(gfxContext* aCtx,
|
||||||
|
const gfxPoint& aFramePt,
|
||||||
|
const gfxPoint& aTextBaselinePt,
|
||||||
|
const gfxRect& aDirtyRect,
|
||||||
|
PropertyProvider& aProvider,
|
||||||
|
nsTextPaintStyle& aTextPaintStyle,
|
||||||
|
SelectionDetails* aDetails,
|
||||||
|
SelectionType aSelectionType);
|
||||||
|
|
||||||
|
PRInt16 GetSelectionStatus(PRInt16* aSelectionFlags);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
void ToCString(nsString& aBuf, PRInt32* aTotalContentLength) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PRInt32 GetContentOffset() const { return mContentOffset; }
|
||||||
|
PRInt32 GetContentLength() const { return GetContentEnd() - mContentOffset; }
|
||||||
|
PRInt32 GetContentEnd() const;
|
||||||
|
// This returns the length the frame thinks it *should* have after it was
|
||||||
|
// last reflowed (0 if it hasn't been reflowed yet). This should be used only
|
||||||
|
// when setting up the text offsets for a new continuation frame.
|
||||||
|
PRInt32 GetContentLengthHint() const { return mContentLengthHint; }
|
||||||
|
|
||||||
|
// Compute the length of the content mapped by this frame
|
||||||
|
// and all its in-flow siblings. Basically this means starting at mContentOffset
|
||||||
|
// and going to the end of the text node or the next bidi continuation
|
||||||
|
// boundary.
|
||||||
|
PRInt32 GetInFlowContentLength();
|
||||||
|
|
||||||
|
// Clears out mTextRun from this frame and all other frames that hold a reference
|
||||||
|
// to it, then deletes the textrun.
|
||||||
|
void ClearTextRun();
|
||||||
|
/**
|
||||||
|
* Acquires the text run for this content, if necessary.
|
||||||
|
* @param aRC the rendering context to use as a reference for creating
|
||||||
|
* the textrun, if available (if not, we'll create one which will just be slower)
|
||||||
|
* @param aBlock the block ancestor for this frame, or nsnull if unknown
|
||||||
|
* @param aLine the line that this frame is on, if any, or nsnull if unknown
|
||||||
|
* @param aFlowEndInTextRun if non-null, this returns the textrun offset of
|
||||||
|
* end of the text associated with this frame and its in-flow siblings
|
||||||
|
* @return a gfxSkipCharsIterator set up to map DOM offsets for this frame
|
||||||
|
* to offsets into the textrun; its initial offset is set to this frame's
|
||||||
|
* content offset
|
||||||
|
*/
|
||||||
|
gfxSkipCharsIterator EnsureTextRun(nsIRenderingContext* aRC = nsnull,
|
||||||
|
nsIFrame* aLineContainer = nsnull,
|
||||||
|
const nsLineList::iterator* aLine = nsnull,
|
||||||
|
PRUint32* aFlowEndInTextRun = nsnull);
|
||||||
|
|
||||||
|
gfxTextRun* GetTextRun() { return mTextRun; }
|
||||||
|
void SetTextRun(gfxTextRun* aTextRun) { mTextRun = aTextRun; }
|
||||||
|
|
||||||
|
// Get the DOM content range mapped by this frame after excluding
|
||||||
|
// whitespace subject to start-of-line and end-of-line trimming.
|
||||||
|
// The textrun must have been created before calling this.
|
||||||
|
struct TrimmedOffsets {
|
||||||
|
PRInt32 mStart;
|
||||||
|
PRInt32 mLength;
|
||||||
|
PRInt32 GetEnd() { return mStart + mLength; }
|
||||||
|
};
|
||||||
|
TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag,
|
||||||
|
PRBool aTrimAfter);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~nsTextFrame();
|
||||||
|
|
||||||
|
nsIFrame* mNextContinuation;
|
||||||
|
// The key invariant here is that mContentOffset never decreases along
|
||||||
|
// a next-continuation chain. And of course mContentOffset is always <= the
|
||||||
|
// the text node's content length, and the mContentOffset for the first frame
|
||||||
|
// is always 0. Furthermore the text mapped by a frame is determined by
|
||||||
|
// GetContentOffset() and GetContentLength()/GetContentEnd(), which get
|
||||||
|
// the length from the difference between this frame's offset and the next
|
||||||
|
// frame's offset, or the text length if there is no next frame. This means
|
||||||
|
// the frames always map the text node without overlapping or leaving any gaps.
|
||||||
|
PRInt32 mContentOffset;
|
||||||
|
// This does *not* indicate the length of text currently mapped by the frame;
|
||||||
|
// instead it's a hint saying that this frame *wants* to map this much text
|
||||||
|
// so if we create a new continuation, this is where that continuation should
|
||||||
|
// start.
|
||||||
|
PRInt32 mContentLengthHint;
|
||||||
|
nscoord mAscent;
|
||||||
|
gfxTextRun* mTextRun;
|
||||||
|
|
||||||
|
SelectionDetails* GetSelectionDetails();
|
||||||
|
|
||||||
|
void AdjustSelectionPointsForBidi(SelectionDetails *sdptr,
|
||||||
|
PRInt32 textLength,
|
||||||
|
PRBool isRTLChars,
|
||||||
|
PRBool isOddLevel,
|
||||||
|
PRBool isBidiSystem);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -81,6 +81,7 @@
|
||||||
#include "nsFrameManager.h"
|
#include "nsFrameManager.h"
|
||||||
#include "nsTextFrameTextRunCache.h"
|
#include "nsTextFrameTextRunCache.h"
|
||||||
#include "nsExpirationTracker.h"
|
#include "nsExpirationTracker.h"
|
||||||
|
#include "nsTextFrame.h"
|
||||||
#include "nsICaseConversion.h"
|
#include "nsICaseConversion.h"
|
||||||
#include "nsIUGenCategory.h"
|
#include "nsIUGenCategory.h"
|
||||||
#include "nsUnicharUtilCIID.h"
|
#include "nsUnicharUtilCIID.h"
|
||||||
|
@ -182,9 +183,6 @@
|
||||||
* <b>Kit­</b>ty
|
* <b>Kit­</b>ty
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class nsTextFrame;
|
|
||||||
class PropertyProvider;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We use an array of these objects to record which text frames
|
* We use an array of these objects to record which text frames
|
||||||
* are associated with the textrun. mStartFrame is the start of a list of
|
* are associated with the textrun. mStartFrame is the start of a list of
|
||||||
|
@ -295,289 +293,6 @@ protected:
|
||||||
nscolor aBackColor);
|
nscolor aBackColor);
|
||||||
};
|
};
|
||||||
|
|
||||||
class nsTextFrame : public nsFrame {
|
|
||||||
public:
|
|
||||||
nsTextFrame(nsStyleContext* aContext) : nsFrame(aContext)
|
|
||||||
{
|
|
||||||
NS_ASSERTION(mContentOffset == 0, "Bogus content offset");
|
|
||||||
}
|
|
||||||
|
|
||||||
// nsIFrame
|
|
||||||
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|
||||||
const nsRect& aDirtyRect,
|
|
||||||
const nsDisplayListSet& aLists);
|
|
||||||
|
|
||||||
NS_IMETHOD Init(nsIContent* aContent,
|
|
||||||
nsIFrame* aParent,
|
|
||||||
nsIFrame* aPrevInFlow);
|
|
||||||
|
|
||||||
virtual void Destroy();
|
|
||||||
|
|
||||||
NS_IMETHOD GetCursor(const nsPoint& aPoint,
|
|
||||||
nsIFrame::Cursor& aCursor);
|
|
||||||
|
|
||||||
NS_IMETHOD CharacterDataChanged(nsPresContext* aPresContext,
|
|
||||||
nsIContent* aChild,
|
|
||||||
PRBool aAppend);
|
|
||||||
|
|
||||||
NS_IMETHOD DidSetStyleContext();
|
|
||||||
|
|
||||||
virtual nsIFrame* GetNextContinuation() const {
|
|
||||||
return mNextContinuation;
|
|
||||||
}
|
|
||||||
NS_IMETHOD SetNextContinuation(nsIFrame* aNextContinuation) {
|
|
||||||
NS_ASSERTION (!aNextContinuation || GetType() == aNextContinuation->GetType(),
|
|
||||||
"setting a next continuation with incorrect type!");
|
|
||||||
NS_ASSERTION (!nsSplittableFrame::IsInNextContinuationChain(aNextContinuation, this),
|
|
||||||
"creating a loop in continuation chain!");
|
|
||||||
mNextContinuation = aNextContinuation;
|
|
||||||
if (aNextContinuation)
|
|
||||||
aNextContinuation->RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
virtual nsIFrame* GetNextInFlowVirtual() const { return GetNextInFlow(); }
|
|
||||||
nsIFrame* GetNextInFlow() const {
|
|
||||||
return mNextContinuation && (mNextContinuation->GetStateBits() & NS_FRAME_IS_FLUID_CONTINUATION) ?
|
|
||||||
mNextContinuation : nsnull;
|
|
||||||
}
|
|
||||||
NS_IMETHOD SetNextInFlow(nsIFrame* aNextInFlow) {
|
|
||||||
NS_ASSERTION (!aNextInFlow || GetType() == aNextInFlow->GetType(),
|
|
||||||
"setting a next in flow with incorrect type!");
|
|
||||||
NS_ASSERTION (!nsSplittableFrame::IsInNextContinuationChain(aNextInFlow, this),
|
|
||||||
"creating a loop in continuation chain!");
|
|
||||||
mNextContinuation = aNextInFlow;
|
|
||||||
if (aNextInFlow)
|
|
||||||
aNextInFlow->AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
virtual nsIFrame* GetLastInFlow() const;
|
|
||||||
virtual nsIFrame* GetLastContinuation() const;
|
|
||||||
|
|
||||||
virtual nsSplittableType GetSplittableType() const {
|
|
||||||
return NS_FRAME_SPLITTABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the "type" of the frame
|
|
||||||
*
|
|
||||||
* @see nsGkAtoms::textFrame
|
|
||||||
*/
|
|
||||||
virtual nsIAtom* GetType() const;
|
|
||||||
|
|
||||||
virtual PRBool IsFrameOfType(PRUint32 aFlags) const
|
|
||||||
{
|
|
||||||
// Set the frame state bit for text frames to mark them as replaced.
|
|
||||||
// XXX kipp: temporary
|
|
||||||
return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced |
|
|
||||||
nsIFrame::eLineParticipant));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
|
|
||||||
NS_IMETHOD GetFrameName(nsAString& aResult) const;
|
|
||||||
NS_IMETHOD_(nsFrameState) GetDebugStateBits() const ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
virtual ContentOffsets CalcContentOffsetsFromFramePoint(nsPoint aPoint);
|
|
||||||
|
|
||||||
NS_IMETHOD SetSelected(nsPresContext* aPresContext,
|
|
||||||
nsIDOMRange *aRange,
|
|
||||||
PRBool aSelected,
|
|
||||||
nsSpread aSpread);
|
|
||||||
|
|
||||||
virtual PRBool PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset);
|
|
||||||
virtual PRBool PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset);
|
|
||||||
virtual PRBool PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsKeyboardSelect,
|
|
||||||
PRInt32* aOffset, PeekWordState* aState);
|
|
||||||
|
|
||||||
NS_IMETHOD CheckVisibility(nsPresContext* aContext, PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aRecurse, PRBool *aFinished, PRBool *_retval);
|
|
||||||
|
|
||||||
// Update offsets to account for new length. This may clear mTextRun.
|
|
||||||
void SetLength(PRInt32 aLength);
|
|
||||||
|
|
||||||
NS_IMETHOD GetOffsets(PRInt32 &start, PRInt32 &end)const;
|
|
||||||
|
|
||||||
virtual void AdjustOffsetsForBidi(PRInt32 start, PRInt32 end);
|
|
||||||
|
|
||||||
NS_IMETHOD GetPointFromOffset(PRInt32 inOffset,
|
|
||||||
nsPoint* outPoint);
|
|
||||||
|
|
||||||
NS_IMETHOD GetChildFrameContainingOffset(PRInt32 inContentOffset,
|
|
||||||
PRBool inHint,
|
|
||||||
PRInt32* outFrameContentOffset,
|
|
||||||
nsIFrame* *outChildFrame);
|
|
||||||
|
|
||||||
virtual PRBool IsVisibleInSelection(nsISelection* aSelection);
|
|
||||||
|
|
||||||
virtual PRBool IsEmpty();
|
|
||||||
virtual PRBool IsSelfEmpty() { return IsEmpty(); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return PR_TRUE if this text frame ends with a newline character. It
|
|
||||||
* should return PR_FALSE if this is not a text frame.
|
|
||||||
*/
|
|
||||||
virtual PRBool HasTerminalNewline() const;
|
|
||||||
|
|
||||||
#ifdef ACCESSIBILITY
|
|
||||||
NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
virtual void MarkIntrinsicWidthsDirty();
|
|
||||||
virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext);
|
|
||||||
virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext);
|
|
||||||
virtual void AddInlineMinWidth(nsIRenderingContext *aRenderingContext,
|
|
||||||
InlineMinWidthData *aData);
|
|
||||||
virtual void AddInlinePrefWidth(nsIRenderingContext *aRenderingContext,
|
|
||||||
InlinePrefWidthData *aData);
|
|
||||||
virtual nsSize ComputeSize(nsIRenderingContext *aRenderingContext,
|
|
||||||
nsSize aCBSize, nscoord aAvailableWidth,
|
|
||||||
nsSize aMargin, nsSize aBorder, nsSize aPadding,
|
|
||||||
PRBool aShrinkWrap);
|
|
||||||
NS_IMETHOD Reflow(nsPresContext* aPresContext,
|
|
||||||
nsHTMLReflowMetrics& aMetrics,
|
|
||||||
const nsHTMLReflowState& aReflowState,
|
|
||||||
nsReflowStatus& aStatus);
|
|
||||||
virtual PRBool CanContinueTextRun() const;
|
|
||||||
NS_IMETHOD TrimTrailingWhiteSpace(nsPresContext* aPresContext,
|
|
||||||
nsIRenderingContext& aRC,
|
|
||||||
nscoord& aDeltaWidth,
|
|
||||||
PRBool& aLastCharIsJustifiable);
|
|
||||||
virtual nsresult GetRenderedText(nsAString* aString = nsnull,
|
|
||||||
gfxSkipChars* aSkipChars = nsnull,
|
|
||||||
gfxSkipCharsIterator* aSkipIter = nsnull,
|
|
||||||
PRUint32 aSkippedStartOffset = 0,
|
|
||||||
PRUint32 aSkippedMaxLength = PR_UINT32_MAX);
|
|
||||||
|
|
||||||
void AddInlineMinWidthForFlow(nsIRenderingContext *aRenderingContext,
|
|
||||||
nsIFrame::InlineMinWidthData *aData);
|
|
||||||
void AddInlinePrefWidthForFlow(nsIRenderingContext *aRenderingContext,
|
|
||||||
InlinePrefWidthData *aData);
|
|
||||||
|
|
||||||
gfxFloat GetSnappedBaselineY(gfxContext* aContext, gfxFloat aY);
|
|
||||||
|
|
||||||
// primary frame paint method called from nsDisplayText
|
|
||||||
void PaintText(nsIRenderingContext* aRenderingContext, nsPoint aPt,
|
|
||||||
const nsRect& aDirtyRect);
|
|
||||||
// helper: paint quirks-mode CSS text decorations
|
|
||||||
void PaintTextDecorations(gfxContext* aCtx, const gfxRect& aDirtyRect,
|
|
||||||
const gfxPoint& aFramePt,
|
|
||||||
const gfxPoint& aTextBaselinePt,
|
|
||||||
nsTextPaintStyle& aTextStyle,
|
|
||||||
PropertyProvider& aProvider);
|
|
||||||
// helper: paint text frame when we're impacted by at least one selection.
|
|
||||||
// Return PR_FALSE if the text was not painted and we should continue with
|
|
||||||
// the fast path.
|
|
||||||
PRBool PaintTextWithSelection(gfxContext* aCtx,
|
|
||||||
const gfxPoint& aFramePt,
|
|
||||||
const gfxPoint& aTextBaselinePt,
|
|
||||||
const gfxRect& aDirtyRect,
|
|
||||||
PropertyProvider& aProvider,
|
|
||||||
nsTextPaintStyle& aTextPaintStyle);
|
|
||||||
// helper: paint text with foreground and background colors determined
|
|
||||||
// by selection(s). Also computes a mask of all selection types applying to
|
|
||||||
// our text, returned in aAllTypes.
|
|
||||||
void PaintTextWithSelectionColors(gfxContext* aCtx,
|
|
||||||
const gfxPoint& aFramePt,
|
|
||||||
const gfxPoint& aTextBaselinePt,
|
|
||||||
const gfxRect& aDirtyRect,
|
|
||||||
PropertyProvider& aProvider,
|
|
||||||
nsTextPaintStyle& aTextPaintStyle,
|
|
||||||
SelectionDetails* aDetails,
|
|
||||||
SelectionType* aAllTypes);
|
|
||||||
// helper: paint text decorations for text selected by aSelectionType
|
|
||||||
void PaintTextSelectionDecorations(gfxContext* aCtx,
|
|
||||||
const gfxPoint& aFramePt,
|
|
||||||
const gfxPoint& aTextBaselinePt,
|
|
||||||
const gfxRect& aDirtyRect,
|
|
||||||
PropertyProvider& aProvider,
|
|
||||||
nsTextPaintStyle& aTextPaintStyle,
|
|
||||||
SelectionDetails* aDetails,
|
|
||||||
SelectionType aSelectionType);
|
|
||||||
|
|
||||||
PRInt16 GetSelectionStatus(PRInt16* aSelectionFlags);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
void ToCString(nsString& aBuf, PRInt32* aTotalContentLength) const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PRInt32 GetContentOffset() const { return mContentOffset; }
|
|
||||||
PRInt32 GetContentLength() const { return GetContentEnd() - mContentOffset; }
|
|
||||||
PRInt32 GetContentEnd() const;
|
|
||||||
// This returns the length the frame thinks it *should* have after it was
|
|
||||||
// last reflowed (0 if it hasn't been reflowed yet). This should be used only
|
|
||||||
// when setting up the text offsets for a new continuation frame.
|
|
||||||
PRInt32 GetContentLengthHint() const { return mContentLengthHint; }
|
|
||||||
|
|
||||||
// Compute the length of the content mapped by this frame
|
|
||||||
// and all its in-flow siblings. Basically this means starting at mContentOffset
|
|
||||||
// and going to the end of the text node or the next bidi continuation
|
|
||||||
// boundary.
|
|
||||||
PRInt32 GetInFlowContentLength();
|
|
||||||
|
|
||||||
// Clears out mTextRun from this frame and all other frames that hold a reference
|
|
||||||
// to it, then deletes the textrun.
|
|
||||||
void ClearTextRun();
|
|
||||||
/**
|
|
||||||
* Acquires the text run for this content, if necessary.
|
|
||||||
* @param aRC the rendering context to use as a reference for creating
|
|
||||||
* the textrun, if available (if not, we'll create one which will just be slower)
|
|
||||||
* @param aBlock the block ancestor for this frame, or nsnull if unknown
|
|
||||||
* @param aLine the line that this frame is on, if any, or nsnull if unknown
|
|
||||||
* @param aFlowEndInTextRun if non-null, this returns the textrun offset of
|
|
||||||
* end of the text associated with this frame and its in-flow siblings
|
|
||||||
* @return a gfxSkipCharsIterator set up to map DOM offsets for this frame
|
|
||||||
* to offsets into the textrun; its initial offset is set to this frame's
|
|
||||||
* content offset
|
|
||||||
*/
|
|
||||||
gfxSkipCharsIterator EnsureTextRun(nsIRenderingContext* aRC = nsnull,
|
|
||||||
nsIFrame* aLineContainer = nsnull,
|
|
||||||
const nsLineList::iterator* aLine = nsnull,
|
|
||||||
PRUint32* aFlowEndInTextRun = nsnull);
|
|
||||||
|
|
||||||
gfxTextRun* GetTextRun() { return mTextRun; }
|
|
||||||
void SetTextRun(gfxTextRun* aTextRun) { mTextRun = aTextRun; }
|
|
||||||
|
|
||||||
// Get the DOM content range mapped by this frame after excluding
|
|
||||||
// whitespace subject to start-of-line and end-of-line trimming.
|
|
||||||
// The textrun must have been created before calling this.
|
|
||||||
struct TrimmedOffsets {
|
|
||||||
PRInt32 mStart;
|
|
||||||
PRInt32 mLength;
|
|
||||||
PRInt32 GetEnd() { return mStart + mLength; }
|
|
||||||
};
|
|
||||||
TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag,
|
|
||||||
PRBool aTrimAfter);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~nsTextFrame();
|
|
||||||
|
|
||||||
nsIFrame* mNextContinuation;
|
|
||||||
// The key invariant here is that mContentOffset never decreases along
|
|
||||||
// a next-continuation chain. And of course mContentOffset is always <= the
|
|
||||||
// the text node's content length, and the mContentOffset for the first frame
|
|
||||||
// is always 0. Furthermore the text mapped by a frame is determined by
|
|
||||||
// GetContentOffset() and GetContentLength()/GetContentEnd(), which get
|
|
||||||
// the length from the difference between this frame's offset and the next
|
|
||||||
// frame's offset, or the text length if there is no next frame. This means
|
|
||||||
// the frames always map the text node without overlapping or leaving any gaps.
|
|
||||||
PRInt32 mContentOffset;
|
|
||||||
// This does *not* indicate the length of text currently mapped by the frame;
|
|
||||||
// instead it's a hint saying that this frame *wants* to map this much text
|
|
||||||
// so if we create a new continuation, this is where that continuation should
|
|
||||||
// start.
|
|
||||||
PRInt32 mContentLengthHint;
|
|
||||||
nscoord mAscent;
|
|
||||||
gfxTextRun* mTextRun;
|
|
||||||
|
|
||||||
SelectionDetails* GetSelectionDetails();
|
|
||||||
|
|
||||||
void AdjustSelectionPointsForBidi(SelectionDetails *sdptr,
|
|
||||||
PRInt32 textLength,
|
|
||||||
PRBool isRTLChars,
|
|
||||||
PRBool isOddLevel,
|
|
||||||
PRBool isBidiSystem);
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DestroyUserData(void* aUserData)
|
DestroyUserData(void* aUserData)
|
||||||
{
|
{
|
||||||
|
@ -1483,6 +1198,10 @@ GetFontGroupForFrame(nsIFrame* aFrame)
|
||||||
|
|
||||||
nsIFontMetrics* metricsRaw = metrics;
|
nsIFontMetrics* metricsRaw = metrics;
|
||||||
nsIThebesFontMetrics* fm = static_cast<nsIThebesFontMetrics*>(metricsRaw);
|
nsIThebesFontMetrics* fm = static_cast<nsIThebesFontMetrics*>(metricsRaw);
|
||||||
|
// XXX this is a bit bogus, we're releasing 'metrics' so the returned font-group
|
||||||
|
// might actually be torn down, although because of the way the device context
|
||||||
|
// caches font metrics, this seems to not actually happen. But we should fix
|
||||||
|
// this.
|
||||||
return fm->GetThebesFontGroup();
|
return fm->GetThebesFontGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3645,7 +3364,9 @@ public:
|
||||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
|
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
|
||||||
return mFrame->GetOverflowRect() + aBuilder->ToReferenceFrame(mFrame);
|
return mFrame->GetOverflowRect() + aBuilder->ToReferenceFrame(mFrame);
|
||||||
}
|
}
|
||||||
virtual nsIFrame* HitTest(nsDisplayListBuilder* aBuilder, nsPoint aPt) { return mFrame; }
|
virtual nsIFrame* HitTest(nsDisplayListBuilder* aBuilder, nsPoint aPt) {
|
||||||
|
return nsRect(aBuilder->ToReferenceFrame(mFrame), mFrame->GetSize()).Contains(aPt) ? mFrame : nsnull;
|
||||||
|
}
|
||||||
virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
|
virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
|
||||||
const nsRect& aDirtyRect);
|
const nsRect& aDirtyRect);
|
||||||
NS_DISPLAY_DECL_NAME("Text")
|
NS_DISPLAY_DECL_NAME("Text")
|
||||||
|
@ -5200,14 +4921,15 @@ nsTextFrame::ComputeSize(nsIRenderingContext *aRenderingContext,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
AddCharToMetrics(gfxTextRun* aCharTextRun, gfxTextRun* aBaseTextRun,
|
AddCharToMetrics(gfxTextRun* aCharTextRun, gfxTextRun* aBaseTextRun,
|
||||||
gfxTextRun::Metrics* aMetrics, PRBool aTightBoundingBox)
|
gfxTextRun::Metrics* aMetrics, PRBool aTightBoundingBox,
|
||||||
|
gfxContext* aContext)
|
||||||
{
|
{
|
||||||
gfxRect charRect;
|
gfxRect charRect;
|
||||||
// assume char does not overflow font metrics!!!
|
// assume char does not overflow font metrics!!!
|
||||||
gfxFloat width = aCharTextRun->GetAdvanceWidth(0, aCharTextRun->GetLength(), nsnull);
|
gfxFloat width = aCharTextRun->GetAdvanceWidth(0, aCharTextRun->GetLength(), nsnull);
|
||||||
if (aTightBoundingBox) {
|
if (aTightBoundingBox) {
|
||||||
gfxTextRun::Metrics charMetrics =
|
gfxTextRun::Metrics charMetrics =
|
||||||
aCharTextRun->MeasureText(0, aCharTextRun->GetLength(), PR_TRUE, nsnull);
|
aCharTextRun->MeasureText(0, aCharTextRun->GetLength(), PR_TRUE, aContext, nsnull);
|
||||||
charRect = charMetrics.mBoundingBox;
|
charRect = charMetrics.mBoundingBox;
|
||||||
} else {
|
} else {
|
||||||
charRect = gfxRect(0, -aMetrics->mAscent, width,
|
charRect = gfxRect(0, -aMetrics->mAscent, width,
|
||||||
|
@ -5452,13 +5174,15 @@ nsTextFrame::Reflow(nsPresContext* aPresContext,
|
||||||
gfxFloat availWidth = aReflowState.availableWidth;
|
gfxFloat availWidth = aReflowState.availableWidth;
|
||||||
PRBool canTrimTrailingWhitespace = !textStyle->WhiteSpaceIsSignificant() &&
|
PRBool canTrimTrailingWhitespace = !textStyle->WhiteSpaceIsSignificant() &&
|
||||||
textStyle->WhiteSpaceCanWrap();
|
textStyle->WhiteSpaceCanWrap();
|
||||||
|
gfxContext* ctx = static_cast<gfxContext*>
|
||||||
|
(aReflowState.rendContext->GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT));
|
||||||
PRUint32 transformedCharsFit =
|
PRUint32 transformedCharsFit =
|
||||||
mTextRun->BreakAndMeasureText(transformedOffset, transformedLength,
|
mTextRun->BreakAndMeasureText(transformedOffset, transformedLength,
|
||||||
(GetStateBits() & TEXT_START_OF_LINE) != 0,
|
(GetStateBits() & TEXT_START_OF_LINE) != 0,
|
||||||
availWidth,
|
availWidth,
|
||||||
&provider, suppressInitialBreak,
|
&provider, suppressInitialBreak,
|
||||||
canTrimTrailingWhitespace ? &trimmedWidth : nsnull,
|
canTrimTrailingWhitespace ? &trimmedWidth : nsnull,
|
||||||
&textMetrics, needTightBoundingBox,
|
&textMetrics, needTightBoundingBox, ctx,
|
||||||
&usedHyphenation, &transformedLastBreak);
|
&usedHyphenation, &transformedLastBreak);
|
||||||
// The "end" iterator points to the first character after the string mapped
|
// The "end" iterator points to the first character after the string mapped
|
||||||
// by this frame. Basically, its original-string offset is offset+charsFit
|
// by this frame. Basically, its original-string offset is offset+charsFit
|
||||||
|
@ -5489,7 +5213,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext,
|
||||||
gfxTextRunCache::AutoTextRun hyphenTextRun(GetHyphenTextRun(mTextRun, aReflowState.rendContext));
|
gfxTextRunCache::AutoTextRun hyphenTextRun(GetHyphenTextRun(mTextRun, aReflowState.rendContext));
|
||||||
if (hyphenTextRun.get()) {
|
if (hyphenTextRun.get()) {
|
||||||
AddCharToMetrics(hyphenTextRun.get(),
|
AddCharToMetrics(hyphenTextRun.get(),
|
||||||
mTextRun, &textMetrics, needTightBoundingBox);
|
mTextRun, &textMetrics, needTightBoundingBox, ctx);
|
||||||
}
|
}
|
||||||
AddStateBits(TEXT_HYPHEN_BREAK);
|
AddStateBits(TEXT_HYPHEN_BREAK);
|
||||||
}
|
}
|
||||||
|
@ -5526,7 +5250,6 @@ nsTextFrame::Reflow(nsPresContext* aPresContext,
|
||||||
if (GetStateBits() & TEXT_FIRST_LETTER) {
|
if (GetStateBits() & TEXT_FIRST_LETTER) {
|
||||||
textMetrics.mAscent = PR_MAX(0, -textMetrics.mBoundingBox.Y());
|
textMetrics.mAscent = PR_MAX(0, -textMetrics.mBoundingBox.Y());
|
||||||
textMetrics.mDescent = PR_MAX(0, textMetrics.mBoundingBox.YMost());
|
textMetrics.mDescent = PR_MAX(0, textMetrics.mBoundingBox.YMost());
|
||||||
textMetrics.mAdvanceWidth = textMetrics.mBoundingBox.XMost();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup metrics for caller
|
// Setup metrics for caller
|
||||||
|
@ -5736,6 +5459,28 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsRect
|
||||||
|
nsTextFrame::RecomputeOverflowRect()
|
||||||
|
{
|
||||||
|
gfxSkipCharsIterator iter = EnsureTextRun();
|
||||||
|
if (!mTextRun)
|
||||||
|
return nsRect(nsPoint(0,0), GetSize());
|
||||||
|
|
||||||
|
PropertyProvider provider(this, iter);
|
||||||
|
provider.InitializeForDisplay(PR_TRUE);
|
||||||
|
|
||||||
|
gfxTextRun::Metrics textMetrics =
|
||||||
|
mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(),
|
||||||
|
ComputeTransformedLength(provider), PR_FALSE, nsnull,
|
||||||
|
&provider);
|
||||||
|
|
||||||
|
nsRect boundingBox =
|
||||||
|
ConvertGfxRectOutward(textMetrics.mBoundingBox + gfxPoint(0, textMetrics.mAscent));
|
||||||
|
boundingBox.UnionRect(boundingBox,
|
||||||
|
nsRect(nsPoint(0,0), GetSize()));
|
||||||
|
return boundingBox;
|
||||||
|
}
|
||||||
|
|
||||||
static PRUnichar TransformChar(const nsStyleText* aStyle, gfxTextRun* aTextRun,
|
static PRUnichar TransformChar(const nsStyleText* aStyle, gfxTextRun* aTextRun,
|
||||||
PRUint32 aSkippedOffset, PRUnichar aChar)
|
PRUint32 aSkippedOffset, PRUnichar aChar)
|
||||||
{
|
{
|
||||||
|
@ -5957,6 +5702,11 @@ nsTextFrame::List(FILE* out, PRInt32 aIndent) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(out, " [content=%p]", static_cast<void*>(mContent));
|
fprintf(out, " [content=%p]", static_cast<void*>(mContent));
|
||||||
|
nsRect* overflowArea = const_cast<nsTextFrame*>(this)->GetOverflowAreaProperty(PR_FALSE);
|
||||||
|
if (overflowArea) {
|
||||||
|
fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea->x, overflowArea->y,
|
||||||
|
overflowArea->width, overflowArea->height);
|
||||||
|
}
|
||||||
fprintf(out, " sc=%p", static_cast<void*>(mStyleContext));
|
fprintf(out, " sc=%p", static_cast<void*>(mStyleContext));
|
||||||
nsIAtom* pseudoTag = mStyleContext->GetPseudoType();
|
nsIAtom* pseudoTag = mStyleContext->GetPseudoType();
|
||||||
if (pseudoTag) {
|
if (pseudoTag) {
|
||||||
|
|
|
@ -8,13 +8,16 @@ span {
|
||||||
font-size: 200%;
|
font-size: 200%;
|
||||||
font-variant: small-caps;
|
font-variant: small-caps;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
|
color:red;
|
||||||
|
}
|
||||||
|
span.line {
|
||||||
|
background: yellow;
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
color:red; background: yellow;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<p><span>H</span>ello
|
<p><span>H</span>ello
|
||||||
<div><span>Hello</span><br>Kitty</div>
|
<div><span class="line">Hello</span><br>Kitty</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -8,8 +8,11 @@ span, p:first-letter, div:first-line {
|
||||||
font-size: 200%;
|
font-size: 200%;
|
||||||
font-variant: small-caps;
|
font-variant: small-caps;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
|
color:red;
|
||||||
|
}
|
||||||
|
span, div:first-line {
|
||||||
|
background: yellow;
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
color:red; background: yellow;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -409,7 +409,7 @@ nsSVGGlyphFrame::UpdateCoveredRegion()
|
||||||
textRun->DrawToPath(gfx, mPosition, 0, text.Length(), nsnull, nsnull);
|
textRun->DrawToPath(gfx, mPosition, 0, text.Length(), nsnull, nsnull);
|
||||||
} else {
|
} else {
|
||||||
gfxTextRun::Metrics metrics =
|
gfxTextRun::Metrics metrics =
|
||||||
textRun->MeasureText(0, text.Length(), PR_FALSE, nsnull);
|
textRun->MeasureText(0, text.Length(), PR_FALSE, nsnull, nsnull);
|
||||||
gfx->Rectangle(metrics.mBoundingBox + mPosition);
|
gfx->Rectangle(metrics.mBoundingBox + mPosition);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -434,7 +434,7 @@ nsSVGGlyphFrame::UpdateCoveredRegion()
|
||||||
gfx->Rotate(cp[i].angle);
|
gfx->Rotate(cp[i].angle);
|
||||||
|
|
||||||
gfxTextRun::Metrics metrics =
|
gfxTextRun::Metrics metrics =
|
||||||
textRun->MeasureText(i, 1, PR_FALSE, nsnull);
|
textRun->MeasureText(i, 1, PR_FALSE, nsnull, nsnull);
|
||||||
|
|
||||||
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
|
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
|
||||||
}
|
}
|
||||||
|
@ -867,7 +867,7 @@ nsSVGGlyphFrame::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
gfxTextRun::Metrics metrics =
|
gfxTextRun::Metrics metrics =
|
||||||
textRun->MeasureText(charnum, 1, PR_FALSE, nsnull);
|
textRun->MeasureText(charnum, 1, PR_FALSE, nsnull, nsnull);
|
||||||
|
|
||||||
if (cp) {
|
if (cp) {
|
||||||
if (cp[charnum].draw == PR_FALSE) {
|
if (cp[charnum].draw == PR_FALSE) {
|
||||||
|
@ -943,7 +943,7 @@ nsSVGGlyphFrame::GetBaselineOffset(PRUint16 baselineIdentifier)
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|
||||||
gfxTextRun::Metrics metrics =
|
gfxTextRun::Metrics metrics =
|
||||||
textRun->MeasureText(0, text.Length(), PR_FALSE, nsnull);
|
textRun->MeasureText(0, text.Length(), PR_FALSE, nsnull, nsnull);
|
||||||
|
|
||||||
switch (baselineIdentifier) {
|
switch (baselineIdentifier) {
|
||||||
case BASELINE_HANGING:
|
case BASELINE_HANGING:
|
||||||
|
@ -1171,7 +1171,7 @@ nsSVGGlyphFrame::GetCharNumAtPosition(nsIDOMSVGPoint *point)
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxTextRun::Metrics metrics =
|
gfxTextRun::Metrics metrics =
|
||||||
textRun->MeasureText(charnum, 1, PR_FALSE, nsnull);
|
textRun->MeasureText(charnum, 1, PR_FALSE, nsnull, nsnull);
|
||||||
|
|
||||||
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
|
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
|
||||||
|
|
||||||
|
@ -1293,7 +1293,7 @@ nsSVGGlyphFrame::ContainsPoint(float x, float y)
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxTextRun::Metrics metrics =
|
gfxTextRun::Metrics metrics =
|
||||||
textRun->MeasureText(i, 1, PR_FALSE, nsnull);
|
textRun->MeasureText(i, 1, PR_FALSE, nsnull, nsnull);
|
||||||
|
|
||||||
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
|
gfx->Rectangle(metrics.mBoundingBox + gfx->CurrentPoint());
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче