зеркало из https://github.com/mozilla/pjs.git
Bug 357637 Loading time (Tp) of pages with Chinese text is unbearable r=vlad
This commit is contained in:
Родитель
fb15a2472d
Коммит
55c73aa92a
|
@ -54,6 +54,7 @@
|
||||||
// #define ENABLE_XFT_FAST_PATH_ALWAYS
|
// #define ENABLE_XFT_FAST_PATH_ALWAYS
|
||||||
|
|
||||||
#include "nsDataHashtable.h"
|
#include "nsDataHashtable.h"
|
||||||
|
#include "nsClassHashtable.h"
|
||||||
|
|
||||||
class FontSelector;
|
class FontSelector;
|
||||||
|
|
||||||
|
@ -74,11 +75,14 @@ public:
|
||||||
|
|
||||||
void GetMozLang(nsACString &aMozLang);
|
void GetMozLang(nsACString &aMozLang);
|
||||||
void GetActualFontFamily(nsACString &aFamily);
|
void GetActualFontFamily(nsACString &aFamily);
|
||||||
PangoFont *GetPangoFont();
|
|
||||||
|
|
||||||
XftFont *GetXftFont () { RealizeXftFont (); return mXftFont; }
|
XftFont *GetXftFont () { RealizeXftFont (); return mXftFont; }
|
||||||
|
PangoFont *GetPangoFont() { RealizePangoFont(); return mPangoFont; }
|
||||||
gfxFloat GetAdjustedSize() { RealizeFont(); return mAdjustedSize; }
|
gfxFloat GetAdjustedSize() { RealizeFont(); return mAdjustedSize; }
|
||||||
|
|
||||||
|
PRBool HasGlyph(const PRUint32 aChar);
|
||||||
|
PRUint32 GetGlyph(const PRUint32 aChar);
|
||||||
|
|
||||||
virtual gfxTextRun::Metrics Measure(gfxTextRun *aTextRun,
|
virtual gfxTextRun::Metrics Measure(gfxTextRun *aTextRun,
|
||||||
PRUint32 aStart, PRUint32 aEnd,
|
PRUint32 aStart, PRUint32 aEnd,
|
||||||
PRBool aTightBoundingBox,
|
PRBool aTightBoundingBox,
|
||||||
|
@ -91,6 +95,8 @@ protected:
|
||||||
PangoContext *mPangoCtx;
|
PangoContext *mPangoCtx;
|
||||||
|
|
||||||
XftFont *mXftFont;
|
XftFont *mXftFont;
|
||||||
|
PangoFont *mPangoFont;
|
||||||
|
PangoFont *mGlyphTestingFont;
|
||||||
cairo_scaled_font_t *mCairoFont;
|
cairo_scaled_font_t *mCairoFont;
|
||||||
|
|
||||||
PRBool mHasMetrics;
|
PRBool mHasMetrics;
|
||||||
|
@ -100,6 +106,8 @@ protected:
|
||||||
void RealizeFont(PRBool force = PR_FALSE);
|
void RealizeFont(PRBool force = PR_FALSE);
|
||||||
void RealizeXftFont(PRBool force = PR_FALSE);
|
void RealizeXftFont(PRBool force = PR_FALSE);
|
||||||
void GetSize(const char *aString, PRUint32 aLength, gfxSize& inkSize, gfxSize& logSize);
|
void GetSize(const char *aString, PRUint32 aLength, gfxSize& inkSize, gfxSize& logSize);
|
||||||
|
void RealizePangoFont(PRBool aForce = PR_FALSE);
|
||||||
|
void GetCharSize(const char aChar, gfxSize& aInkSize, gfxSize& aLogSize);
|
||||||
|
|
||||||
virtual void SetupCairoFont(cairo_t *aCR);
|
virtual void SetupCairoFont(cairo_t *aCR);
|
||||||
};
|
};
|
||||||
|
@ -130,21 +138,17 @@ protected:
|
||||||
|
|
||||||
// ****** Textrun glyph conversion helpers ******
|
// ****** Textrun glyph conversion helpers ******
|
||||||
|
|
||||||
// If aUTF16Text is null, then the string contains no characters >= 0x100
|
|
||||||
void InitTextRun(gfxTextRun *aTextRun, const gchar *aUTF8Text,
|
void InitTextRun(gfxTextRun *aTextRun, const gchar *aUTF8Text,
|
||||||
PRUint32 aUTF8Length, PRUint32 aUTF8HeaderLength,
|
PRUint32 aUTF8Length, PRUint32 aUTF8HeaderLength);
|
||||||
const PRUnichar *aUTF16Text, PRUint32 aUTF16Length);
|
|
||||||
// Returns NS_ERROR_FAILURE if there's a missing glyph
|
// Returns NS_ERROR_FAILURE if there's a missing glyph
|
||||||
nsresult SetGlyphs(gfxTextRun *aTextRun, const gchar *aUTF8,
|
nsresult SetGlyphs(gfxTextRun *aTextRun, gfxPangoFont *aFont,
|
||||||
PRUint32 aUTF8Length,
|
const gchar *aUTF8, PRUint32 aUTF8Length,
|
||||||
PRUint32 *aUTF16Offset, PangoGlyphString *aGlyphs,
|
PRUint32 *aUTF16Offset, PangoGlyphString *aGlyphs,
|
||||||
PangoGlyphUnit aOverrideSpaceWidth,
|
PangoGlyphUnit aOverrideSpaceWidth,
|
||||||
PRBool aAbortOnMissingGlyph);
|
PRBool aAbortOnMissingGlyph);
|
||||||
// If aUTF16Text is null, then the string contains no characters >= 0x100.
|
nsresult SetMissingGlyphs(gfxTextRun *aTextRun,
|
||||||
// Returns NS_ERROR_FAILURE if we require the itemizing path
|
const gchar *aUTF8, PRUint32 aUTF8Length,
|
||||||
nsresult CreateGlyphRunsFast(gfxTextRun *aTextRun,
|
PRUint32 *aUTF16Offset);
|
||||||
const gchar *aUTF8, PRUint32 aUTF8Length,
|
|
||||||
const PRUnichar *aUTF16Text, PRUint32 aUTF16Length);
|
|
||||||
void CreateGlyphRunsItemizing(gfxTextRun *aTextRun,
|
void CreateGlyphRunsItemizing(gfxTextRun *aTextRun,
|
||||||
const gchar *aUTF8, PRUint32 aUTF8Length,
|
const gchar *aUTF8, PRUint32 aUTF8Length,
|
||||||
PRUint32 aUTF8HeaderLength);
|
PRUint32 aUTF8HeaderLength);
|
||||||
|
@ -161,4 +165,69 @@ private:
|
||||||
nsTArray<gfxFontStyle> mAdditionalStyles;
|
nsTArray<gfxFontStyle> mAdditionalStyles;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class gfxPangoFontWrapper {
|
||||||
|
public:
|
||||||
|
gfxPangoFontWrapper(PangoFont *aFont) {
|
||||||
|
mFont = aFont;
|
||||||
|
g_object_ref(mFont);
|
||||||
|
}
|
||||||
|
~gfxPangoFontWrapper() {
|
||||||
|
if (mFont)
|
||||||
|
g_object_unref(mFont);
|
||||||
|
}
|
||||||
|
PangoFont* Get() { return mFont; }
|
||||||
|
private:
|
||||||
|
PangoFont *mFont;
|
||||||
|
};
|
||||||
|
|
||||||
|
class gfxPangoFontCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
gfxPangoFontCache();
|
||||||
|
~gfxPangoFontCache();
|
||||||
|
|
||||||
|
static gfxPangoFontCache* GetPangoFontCache() {
|
||||||
|
if (!sPangoFontCache)
|
||||||
|
sPangoFontCache = new gfxPangoFontCache();
|
||||||
|
return sPangoFontCache;
|
||||||
|
}
|
||||||
|
static void Shutdown() {
|
||||||
|
if (sPangoFontCache)
|
||||||
|
delete sPangoFontCache;
|
||||||
|
sPangoFontCache = nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Put(const PangoFontDescription *aFontDesc, PangoFont *aPangoFont);
|
||||||
|
PangoFont* Get(const PangoFontDescription *aFontDesc);
|
||||||
|
private:
|
||||||
|
static gfxPangoFontCache *sPangoFontCache;
|
||||||
|
nsClassHashtable<nsUint32HashKey, gfxPangoFontWrapper> mPangoFonts;
|
||||||
|
};
|
||||||
|
|
||||||
|
// XXX we should remove this class, because this class is used only in |HasGlyph| of gfxPangoFont.
|
||||||
|
// But it can use fontconfig directly after bug 366664.
|
||||||
|
class gfxPangoFontNameMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
gfxPangoFontNameMap();
|
||||||
|
~gfxPangoFontNameMap();
|
||||||
|
|
||||||
|
static gfxPangoFontNameMap* GetPangoFontNameMap() {
|
||||||
|
if (!sPangoFontNameMap)
|
||||||
|
sPangoFontNameMap = new gfxPangoFontNameMap();
|
||||||
|
return sPangoFontNameMap;
|
||||||
|
}
|
||||||
|
static void Shutdown() {
|
||||||
|
if (sPangoFontNameMap)
|
||||||
|
delete sPangoFontNameMap;
|
||||||
|
sPangoFontNameMap = nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Put(const nsACString &aName, PangoFont *aPangoFont);
|
||||||
|
PangoFont* Get(const nsACString &aName);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static gfxPangoFontNameMap *sPangoFontNameMap;
|
||||||
|
nsClassHashtable<nsCStringHashKey, gfxPangoFontWrapper> mPangoFonts;
|
||||||
|
};
|
||||||
#endif /* GFX_PANGOFONTS_H */
|
#endif /* GFX_PANGOFONTS_H */
|
||||||
|
|
|
@ -97,6 +97,9 @@
|
||||||
static PangoLanguage *GetPangoLanguage(const nsACString& aLangGroup);
|
static PangoLanguage *GetPangoLanguage(const nsACString& aLangGroup);
|
||||||
static void GetMozLanguage(const PangoLanguage *aLang, nsACString &aMozLang);
|
static void GetMozLanguage(const PangoLanguage *aLang, nsACString &aMozLang);
|
||||||
|
|
||||||
|
/* static */ gfxPangoFontCache* gfxPangoFontCache::sPangoFontCache = nsnull;
|
||||||
|
/* static */ gfxPangoFontNameMap* gfxPangoFontNameMap::sPangoFontNameMap = nsnull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** gfxPangoFontGroup
|
** gfxPangoFontGroup
|
||||||
**/
|
**/
|
||||||
|
@ -266,7 +269,8 @@ gfxPangoFont::gfxPangoFont(const nsAString &aName,
|
||||||
const gfxFontStyle *aFontStyle)
|
const gfxFontStyle *aFontStyle)
|
||||||
: gfxFont(aName, aFontStyle),
|
: gfxFont(aName, aFontStyle),
|
||||||
mPangoFontDesc(nsnull), mPangoCtx(nsnull),
|
mPangoFontDesc(nsnull), mPangoCtx(nsnull),
|
||||||
mXftFont(nsnull), mCairoFont(nsnull), mHasMetrics(PR_FALSE),
|
mXftFont(nsnull), mPangoFont(nsnull), mGlyphTestingFont(nsnull),
|
||||||
|
mCairoFont(nsnull), mHasMetrics(PR_FALSE),
|
||||||
mAdjustedSize(0)
|
mAdjustedSize(0)
|
||||||
{
|
{
|
||||||
InitPangoLib();
|
InitPangoLib();
|
||||||
|
@ -277,6 +281,12 @@ gfxPangoFont::~gfxPangoFont()
|
||||||
if (mPangoCtx)
|
if (mPangoCtx)
|
||||||
g_object_unref(mPangoCtx);
|
g_object_unref(mPangoCtx);
|
||||||
|
|
||||||
|
if (mPangoFont)
|
||||||
|
g_object_unref(mPangoFont);
|
||||||
|
|
||||||
|
if (mGlyphTestingFont)
|
||||||
|
g_object_unref(mGlyphTestingFont);
|
||||||
|
|
||||||
if (mPangoFontDesc)
|
if (mPangoFontDesc)
|
||||||
pango_font_description_free(mPangoFontDesc);
|
pango_font_description_free(mPangoFontDesc);
|
||||||
|
|
||||||
|
@ -288,6 +298,8 @@ gfxPangoFont::~gfxPangoFont()
|
||||||
gfxPangoFont::Shutdown()
|
gfxPangoFont::Shutdown()
|
||||||
{
|
{
|
||||||
ShutdownPangoLib();
|
ShutdownPangoLib();
|
||||||
|
gfxPangoFontCache::Shutdown();
|
||||||
|
gfxPangoFontNameMap::Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
static PangoStyle
|
static PangoStyle
|
||||||
|
@ -364,6 +376,12 @@ gfxPangoFont::RealizeFont(PRBool force)
|
||||||
g_object_unref(mPangoCtx);
|
g_object_unref(mPangoCtx);
|
||||||
if (mPangoFontDesc)
|
if (mPangoFontDesc)
|
||||||
pango_font_description_free(mPangoFontDesc);
|
pango_font_description_free(mPangoFontDesc);
|
||||||
|
if (mPangoFont) {
|
||||||
|
g_object_unref(mPangoFont);
|
||||||
|
mPangoFont = nsnull;
|
||||||
|
mXftFont = nsnull;
|
||||||
|
// XXX we don't need to reset mGlyphTestingFont
|
||||||
|
}
|
||||||
|
|
||||||
mPangoFontDesc = pango_font_description_new();
|
mPangoFontDesc = pango_font_description_new();
|
||||||
|
|
||||||
|
@ -396,7 +414,7 @@ gfxPangoFont::RealizeFont(PRBool force)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gfxSize isz, lsz;
|
gfxSize isz, lsz;
|
||||||
GetSize("x", 1, isz, lsz);
|
GetCharSize('x', isz, lsz);
|
||||||
gfxFloat aspect = isz.height / GetStyle()->size;
|
gfxFloat aspect = isz.height / GetStyle()->size;
|
||||||
mAdjustedSize =
|
mAdjustedSize =
|
||||||
PR_MAX(NS_round(GetStyle()->size*(GetStyle()->sizeAdjust/aspect)), 1.0);
|
PR_MAX(NS_round(GetStyle()->size*(GetStyle()->sizeAdjust/aspect)), 1.0);
|
||||||
|
@ -414,39 +432,69 @@ gfxPangoFont::RealizeXftFont(PRBool force)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PangoFcFont *fcfont = PANGO_FC_FONT(GetPangoFont());
|
mXftFont = pango_xft_font_get_font(GetPangoFont());
|
||||||
mXftFont = pango_xft_font_get_font(PANGO_FONT(fcfont));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gfxPangoFont::GetSize(const char *aCharString, PRUint32 aLength, gfxSize& inkSize, gfxSize& logSize)
|
gfxPangoFont::RealizePangoFont(PRBool aForce)
|
||||||
{
|
{
|
||||||
|
if (!aForce && mPangoFont)
|
||||||
|
return;
|
||||||
|
if (mPangoFont) {
|
||||||
|
g_object_unref(mPangoFont);
|
||||||
|
mPangoFont = nsnull;
|
||||||
|
mXftFont = nsnull;
|
||||||
|
}
|
||||||
RealizeFont();
|
RealizeFont();
|
||||||
|
gfxPangoFontCache *cache = gfxPangoFontCache::GetPangoFontCache();
|
||||||
|
if (!cache)
|
||||||
|
return; // Error
|
||||||
|
mPangoFont = cache->Get(mPangoFontDesc);
|
||||||
|
if (mPangoFont)
|
||||||
|
return;
|
||||||
|
mPangoFont = pango_context_load_font(mPangoCtx, mPangoFontDesc);
|
||||||
|
if (!mPangoFont)
|
||||||
|
return; // Error
|
||||||
|
cache->Put(mPangoFontDesc, mPangoFont);
|
||||||
|
|
||||||
PangoAttrList *al = pango_attr_list_new();
|
if (mGlyphTestingFont)
|
||||||
GList *items = pango_itemize(mPangoCtx, aCharString, 0, aLength, al, NULL);
|
|
||||||
pango_attr_list_unref(al);
|
|
||||||
|
|
||||||
if (!items || g_list_length(items) != 1)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PangoItem *item = (PangoItem*) items->data;
|
// Append this to font name map
|
||||||
|
gfxPangoFontNameMap *fontNameMap = gfxPangoFontNameMap::GetPangoFontNameMap();
|
||||||
|
if (!fontNameMap)
|
||||||
|
return; // Error
|
||||||
|
NS_ConvertUTF16toUTF8 name(mName);
|
||||||
|
mGlyphTestingFont = fontNameMap->Get(name);
|
||||||
|
if (mGlyphTestingFont)
|
||||||
|
return;
|
||||||
|
fontNameMap->Put(name, mPangoFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gfxPangoFont::GetCharSize(const char aChar, gfxSize& aInkSize, gfxSize& aLogSize)
|
||||||
|
{
|
||||||
|
PangoAnalysis analysis;
|
||||||
|
analysis.font = GetPangoFont();
|
||||||
|
analysis.level = 0;
|
||||||
|
analysis.lang_engine = nsnull;
|
||||||
|
analysis.extra_attrs = nsnull;
|
||||||
|
analysis.language = pango_language_from_string("en");
|
||||||
|
analysis.shape_engine = pango_font_find_shaper(analysis.font, analysis.language, aChar);
|
||||||
|
|
||||||
PangoGlyphString *glstr = pango_glyph_string_new();
|
PangoGlyphString *glstr = pango_glyph_string_new();
|
||||||
pango_shape (aCharString, aLength, &(item->analysis), glstr);
|
pango_shape(&aChar, 1, &analysis, glstr);
|
||||||
|
|
||||||
PangoRectangle ink_rect, log_rect;
|
PangoRectangle ink_rect, log_rect;
|
||||||
pango_glyph_string_extents (glstr, item->analysis.font, &ink_rect, &log_rect);
|
pango_glyph_string_extents(glstr, analysis.font, &ink_rect, &log_rect);
|
||||||
|
|
||||||
inkSize.width = ink_rect.width / FLOAT_PANGO_SCALE;
|
aInkSize.width = ink_rect.width / FLOAT_PANGO_SCALE;
|
||||||
inkSize.height = ink_rect.height / FLOAT_PANGO_SCALE;
|
aInkSize.height = ink_rect.height / FLOAT_PANGO_SCALE;
|
||||||
|
|
||||||
logSize.width = log_rect.width / FLOAT_PANGO_SCALE;
|
aLogSize.width = log_rect.width / FLOAT_PANGO_SCALE;
|
||||||
logSize.height = log_rect.height / FLOAT_PANGO_SCALE;
|
aLogSize.height = log_rect.height / FLOAT_PANGO_SCALE;
|
||||||
|
|
||||||
pango_glyph_string_free(glstr);
|
pango_glyph_string_free(glstr);
|
||||||
pango_item_free(item);
|
|
||||||
g_list_free(items);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// rounding and truncation functions for a Freetype floating point number
|
// rounding and truncation functions for a Freetype floating point number
|
||||||
|
@ -463,22 +511,10 @@ gfxPangoFont::GetMetrics()
|
||||||
if (mHasMetrics)
|
if (mHasMetrics)
|
||||||
return mMetrics;
|
return mMetrics;
|
||||||
|
|
||||||
RealizeFont();
|
|
||||||
|
|
||||||
PangoAttrList *al = pango_attr_list_new();
|
|
||||||
GList *items = pango_itemize(mPangoCtx, "a", 0, 1, al, NULL);
|
|
||||||
pango_attr_list_unref(al);
|
|
||||||
|
|
||||||
if (!items || g_list_length(items) != 1)
|
|
||||||
return mMetrics; // XXX error
|
|
||||||
|
|
||||||
#ifndef THEBES_USE_PANGO_CAIRO
|
#ifndef THEBES_USE_PANGO_CAIRO
|
||||||
float val;
|
float val;
|
||||||
|
|
||||||
PangoItem *item = (PangoItem*)items->data;
|
XftFont *xftFont = GetXftFont(); // RealizeFont is called here.
|
||||||
PangoFcFont *fcfont = PANGO_FC_FONT(item->analysis.font);
|
|
||||||
|
|
||||||
XftFont *xftFont = pango_xft_font_get_font(PANGO_FONT(fcfont));
|
|
||||||
if (!xftFont)
|
if (!xftFont)
|
||||||
return mMetrics; // XXX error
|
return mMetrics; // XXX error
|
||||||
|
|
||||||
|
@ -487,6 +523,7 @@ gfxPangoFont::GetMetrics()
|
||||||
return mMetrics; // XXX error
|
return mMetrics; // XXX error
|
||||||
|
|
||||||
int size;
|
int size;
|
||||||
|
PangoFcFont *fcfont = PANGO_FC_FONT(mPangoFont);
|
||||||
if (FcPatternGetInteger(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch)
|
if (FcPatternGetInteger(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch)
|
||||||
size = 12;
|
size = 12;
|
||||||
mMetrics.emHeight = PR_MAX(1, size);
|
mMetrics.emHeight = PR_MAX(1, size);
|
||||||
|
@ -508,12 +545,12 @@ gfxPangoFont::GetMetrics()
|
||||||
mMetrics.maxAdvance = xftFont->max_advance_width;
|
mMetrics.maxAdvance = xftFont->max_advance_width;
|
||||||
|
|
||||||
gfxSize isz, lsz;
|
gfxSize isz, lsz;
|
||||||
GetSize(" ", 1, isz, lsz);
|
GetCharSize(' ', isz, lsz);
|
||||||
mMetrics.spaceWidth = lsz.width;
|
mMetrics.spaceWidth = lsz.width;
|
||||||
|
|
||||||
// XXX do some FcCharSetHasChar work here to make sure
|
// XXX do some FcCharSetHasChar work here to make sure
|
||||||
// we have an "x"
|
// we have an "x"
|
||||||
GetSize("x", 1, isz, lsz);
|
GetCharSize('x', isz, lsz);
|
||||||
mMetrics.xHeight = isz.height;
|
mMetrics.xHeight = isz.height;
|
||||||
mMetrics.aveCharWidth = isz.width;
|
mMetrics.aveCharWidth = isz.width;
|
||||||
|
|
||||||
|
@ -558,8 +595,7 @@ gfxPangoFont::GetMetrics()
|
||||||
XftUnlockFace(xftFont);
|
XftUnlockFace(xftFont);
|
||||||
#else
|
#else
|
||||||
/* pango_cairo case; try to get all the metrics from pango itself */
|
/* pango_cairo case; try to get all the metrics from pango itself */
|
||||||
PangoItem *item = (PangoItem*)items->data;
|
PangoFont *font = GetPangoFont(); // RealizeFont is called here.
|
||||||
PangoFont *font = item->analysis.font;
|
|
||||||
|
|
||||||
PangoFontMetrics *pfm = pango_font_get_metrics (font, NULL);
|
PangoFontMetrics *pfm = pango_font_get_metrics (font, NULL);
|
||||||
|
|
||||||
|
@ -585,9 +621,9 @@ gfxPangoFont::GetMetrics()
|
||||||
mMetrics.maxAdvance = pango_font_metrics_get_approximate_char_width(pfm) / FLOAT_PANGO_SCALE; // XXX
|
mMetrics.maxAdvance = pango_font_metrics_get_approximate_char_width(pfm) / FLOAT_PANGO_SCALE; // XXX
|
||||||
|
|
||||||
gfxSize isz, lsz;
|
gfxSize isz, lsz;
|
||||||
GetSize(" ", 1, isz, lsz);
|
GetCharSize(' ', isz, lsz);
|
||||||
mMetrics.spaceWidth = lsz.width;
|
mMetrics.spaceWidth = lsz.width;
|
||||||
GetSize("x", 1, isz, lsz);
|
GetCharSize('x', isz, lsz);
|
||||||
mMetrics.xHeight = isz.height;
|
mMetrics.xHeight = isz.height;
|
||||||
|
|
||||||
mMetrics.aveCharWidth = pango_font_metrics_get_approximate_char_width(pfm) / FLOAT_PANGO_SCALE;
|
mMetrics.aveCharWidth = pango_font_metrics_get_approximate_char_width(pfm) / FLOAT_PANGO_SCALE;
|
||||||
|
@ -620,17 +656,44 @@ gfxPangoFont::GetMetrics()
|
||||||
return mMetrics;
|
return mMetrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
PRBool
|
||||||
gfxPangoFont::GetMozLang(nsACString &aMozLang)
|
gfxPangoFont::HasGlyph(PRUint32 aChar)
|
||||||
{
|
{
|
||||||
aMozLang.Assign(GetStyle()->langGroup);
|
// Ensure that null character should be missing.
|
||||||
|
if (aChar == 0)
|
||||||
|
return PR_FALSE;
|
||||||
|
|
||||||
|
PangoFont *font = nsnull;
|
||||||
|
if (mPangoFont)
|
||||||
|
font = mPangoFont;
|
||||||
|
else if (mGlyphTestingFont)
|
||||||
|
font = mGlyphTestingFont;
|
||||||
|
else {
|
||||||
|
gfxPangoFontNameMap *fontNameMap = gfxPangoFontNameMap::GetPangoFontNameMap();
|
||||||
|
NS_ENSURE_TRUE(fontNameMap, PR_FALSE);
|
||||||
|
// XXX in a prinsiple, we need to add weight and style for the key.
|
||||||
|
// But this method should be independent from pango for the performance.
|
||||||
|
// For the temporary, the name is enough for the key. The members of
|
||||||
|
// a font-family should have same glyphs.
|
||||||
|
NS_ConvertUTF16toUTF8 name(mName);
|
||||||
|
mGlyphTestingFont = fontNameMap->Get(name);
|
||||||
|
if (!mGlyphTestingFont) {
|
||||||
|
font = GetPangoFont();
|
||||||
|
NS_ENSURE_TRUE(font, PR_FALSE);
|
||||||
|
} else
|
||||||
|
font = mGlyphTestingFont;
|
||||||
|
}
|
||||||
|
return pango_fc_font_has_char(PANGO_FC_FONT(font), aChar) ? PR_TRUE : PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PangoFont *
|
PRUint32
|
||||||
gfxPangoFont::GetPangoFont()
|
gfxPangoFont::GetGlyph(const PRUint32 aChar)
|
||||||
{
|
{
|
||||||
RealizeFont();
|
// Ensure that null character should be missing.
|
||||||
return pango_context_load_font(mPangoCtx, mPangoFontDesc);
|
if (aChar == 0)
|
||||||
|
return 0;
|
||||||
|
RealizePangoFont();
|
||||||
|
return pango_fc_font_get_glyph(PANGO_FC_FONT(mPangoFont), aChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsString
|
nsString
|
||||||
|
@ -721,7 +784,7 @@ gfxPangoFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
|
||||||
// We don't need to send an override character here, the characters must be all
|
// We don't need to send an override character here, the characters must be all
|
||||||
// LTR
|
// LTR
|
||||||
const gchar *utf8Chars = NS_REINTERPRET_CAST(const gchar*, aString);
|
const gchar *utf8Chars = NS_REINTERPRET_CAST(const gchar*, aString);
|
||||||
InitTextRun(run, utf8Chars, aLength, 0, nsnull, 0);
|
InitTextRun(run, utf8Chars, aLength, 0);
|
||||||
} else {
|
} else {
|
||||||
const char *chars = NS_REINTERPRET_CAST(const char*, aString);
|
const char *chars = NS_REINTERPRET_CAST(const char*, aString);
|
||||||
// XXX this could be more efficient.
|
// XXX this could be more efficient.
|
||||||
|
@ -732,7 +795,7 @@ gfxPangoFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
|
||||||
nsCAutoString utf8;
|
nsCAutoString utf8;
|
||||||
PRInt32 headerLen = AppendDirectionalIndicatorUTF8(isRTL, utf8);
|
PRInt32 headerLen = AppendDirectionalIndicatorUTF8(isRTL, utf8);
|
||||||
AppendUTF16toUTF8(unicodeString, utf8);
|
AppendUTF16toUTF8(unicodeString, utf8);
|
||||||
InitTextRun(run, utf8.get(), utf8.Length(), headerLen, nsnull, 0);
|
InitTextRun(run, utf8.get(), utf8.Length(), headerLen);
|
||||||
}
|
}
|
||||||
return run;
|
return run;
|
||||||
}
|
}
|
||||||
|
@ -750,14 +813,13 @@ gfxPangoFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
|
||||||
nsCAutoString utf8;
|
nsCAutoString utf8;
|
||||||
PRInt32 headerLen = AppendDirectionalIndicatorUTF8(run->IsRightToLeft(), utf8);
|
PRInt32 headerLen = AppendDirectionalIndicatorUTF8(run->IsRightToLeft(), utf8);
|
||||||
AppendUTF16toUTF8(Substring(aString, aString + aLength), utf8);
|
AppendUTF16toUTF8(Substring(aString, aString + aLength), utf8);
|
||||||
InitTextRun(run, utf8.get(), utf8.Length(), headerLen, aString, aLength);
|
InitTextRun(run, utf8.get(), utf8.Length(), headerLen);
|
||||||
return run;
|
return run;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gfxPangoFontGroup::InitTextRun(gfxTextRun *aTextRun, const gchar *aUTF8Text,
|
gfxPangoFontGroup::InitTextRun(gfxTextRun *aTextRun, const gchar *aUTF8Text,
|
||||||
PRUint32 aUTF8Length, PRUint32 aUTF8HeaderLength,
|
PRUint32 aUTF8Length, PRUint32 aUTF8HeaderLength)
|
||||||
const PRUnichar *aUTF16Text, PRUint32 aUTF16Length)
|
|
||||||
{
|
{
|
||||||
#if defined(ENABLE_XFT_FAST_PATH_ALWAYS)
|
#if defined(ENABLE_XFT_FAST_PATH_ALWAYS)
|
||||||
CreateGlyphRunsXft(aTextRun, aUTF8Text + aUTF8HeaderLength, aUTF8Length - aUTF8HeaderLength);
|
CreateGlyphRunsXft(aTextRun, aUTF8Text + aUTF8HeaderLength, aUTF8Length - aUTF8HeaderLength);
|
||||||
|
@ -773,11 +835,7 @@ gfxPangoFontGroup::InitTextRun(gfxTextRun *aTextRun, const gchar *aUTF8Text,
|
||||||
(aTextRun->IsRightToLeft()
|
(aTextRun->IsRightToLeft()
|
||||||
? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR));
|
? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR));
|
||||||
|
|
||||||
nsresult rv = CreateGlyphRunsFast(aTextRun, aUTF8Text + aUTF8HeaderLength,
|
CreateGlyphRunsItemizing(aTextRun, aUTF8Text, aUTF8Length, aUTF8HeaderLength);
|
||||||
aUTF8Length - aUTF8HeaderLength, aUTF16Text, aUTF16Length);
|
|
||||||
if (rv == NS_ERROR_FAILURE) {
|
|
||||||
CreateGlyphRunsItemizing(aTextRun, aUTF8Text, aUTF8Length, aUTF8HeaderLength);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -891,7 +949,8 @@ gfxPangoFont::Measure(gfxTextRun *aTextRun,
|
||||||
return GetPangoMetrics(&glyphs, GetPangoFont(), aTextRun->GetAppUnitsPerDevUnit(), clusterCount);
|
return GetPangoMetrics(&glyphs, GetPangoFont(), aTextRun->GetAppUnitsPerDevUnit(), clusterCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IS_MISSING_GLYPH(g) (((g) & 0x10000000) || (g) == 0x0FFFFFFF)
|
#define EMPTY_GLYPH 0x0FFFFFFF
|
||||||
|
#define IS_MISSING_GLYPH(g) (((g) & 0x10000000) || (g) == EMPTY_GLYPH)
|
||||||
|
|
||||||
static cairo_scaled_font_t*
|
static cairo_scaled_font_t*
|
||||||
CreateScaledFont(cairo_t *aCR, cairo_matrix_t *aCTM, PangoFont *aPangoFont)
|
CreateScaledFont(cairo_t *aCR, cairo_matrix_t *aCTM, PangoFont *aPangoFont)
|
||||||
|
@ -1005,7 +1064,7 @@ SetMissingGlyphForUCS4(gfxTextRun *aTextRun, PRUint32 aIndex, gunichar aCh)
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
gfxPangoFontGroup::SetGlyphs(gfxTextRun *aTextRun,
|
gfxPangoFontGroup::SetGlyphs(gfxTextRun *aTextRun, gfxPangoFont *aFont,
|
||||||
const gchar *aUTF8, PRUint32 aUTF8Length,
|
const gchar *aUTF8, PRUint32 aUTF8Length,
|
||||||
PRUint32 *aUTF16Offset, PangoGlyphString *aGlyphs,
|
PRUint32 *aUTF16Offset, PangoGlyphString *aGlyphs,
|
||||||
PangoGlyphUnit aOverrideSpaceWidth,
|
PangoGlyphUnit aOverrideSpaceWidth,
|
||||||
|
@ -1053,7 +1112,13 @@ gfxPangoFontGroup::SetGlyphs(gfxTextRun *aTextRun,
|
||||||
for (;;) {
|
for (;;) {
|
||||||
++glyphCount;
|
++glyphCount;
|
||||||
if (IS_MISSING_GLYPH(aGlyphs->glyphs[glyphIndex].glyph)) {
|
if (IS_MISSING_GLYPH(aGlyphs->glyphs[glyphIndex].glyph)) {
|
||||||
haveMissingGlyph = PR_TRUE;
|
if (aGlyphs->glyphs[glyphIndex].glyph == EMPTY_GLYPH &&
|
||||||
|
aGlyphs->glyphs[glyphIndex].geometry.width == 0) {
|
||||||
|
// the zero width characters returns empty glyph ID at shaping,
|
||||||
|
// we should override it if the font has the character.
|
||||||
|
aGlyphs->glyphs[glyphIndex].glyph = aFont->GetGlyph(ch);
|
||||||
|
} else
|
||||||
|
haveMissingGlyph = PR_TRUE;
|
||||||
}
|
}
|
||||||
glyphIndex += direction;
|
glyphIndex += direction;
|
||||||
if (glyphCount == numGlyphs ||
|
if (glyphCount == numGlyphs ||
|
||||||
|
@ -1123,6 +1188,33 @@ gfxPangoFontGroup::SetGlyphs(gfxTextRun *aTextRun,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
gfxPangoFontGroup::SetMissingGlyphs(gfxTextRun *aTextRun,
|
||||||
|
const gchar *aUTF8, PRUint32 aUTF8Length,
|
||||||
|
PRUint32 *aUTF16Offset)
|
||||||
|
{
|
||||||
|
PRUint32 utf16Offset = *aUTF16Offset;
|
||||||
|
PRUint32 textRunLength = aTextRun->GetLength();
|
||||||
|
for (PRUint32 index = 0; index < aUTF8Length;) {
|
||||||
|
if (utf16Offset >= textRunLength) {
|
||||||
|
NS_ERROR("Someone has added too many glyphs!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gunichar ch = g_utf8_get_char(aUTF8 + index);
|
||||||
|
SetMissingGlyphForUCS4(aTextRun, utf16Offset, ch);
|
||||||
|
|
||||||
|
++utf16Offset;
|
||||||
|
NS_ASSERTION(!IS_SURROGATE(ch), "surrogates should not appear in UTF8");
|
||||||
|
if (ch >= 0x10000)
|
||||||
|
++utf16Offset;
|
||||||
|
// We produced this UTF8 so we don't need to worry about malformed stuff
|
||||||
|
index = g_utf8_next_char(aUTF8 + index) - aUTF8;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aUTF16Offset = utf16Offset;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(ENABLE_XFT_FAST_PATH_8BIT) || defined(ENABLE_XFT_FAST_PATH_ALWAYS)
|
#if defined(ENABLE_XFT_FAST_PATH_8BIT) || defined(ENABLE_XFT_FAST_PATH_ALWAYS)
|
||||||
void
|
void
|
||||||
gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun,
|
gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun,
|
||||||
|
@ -1192,72 +1284,6 @@ gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nsresult
|
|
||||||
gfxPangoFontGroup::CreateGlyphRunsFast(gfxTextRun *aTextRun,
|
|
||||||
const gchar *aUTF8, PRUint32 aUTF8Length,
|
|
||||||
const PRUnichar *aUTF16, PRUint32 aUTF16Length)
|
|
||||||
{
|
|
||||||
gfxPangoFont *font = GetFontAt(0);
|
|
||||||
PangoAnalysis analysis;
|
|
||||||
analysis.font = font->GetPangoFont();
|
|
||||||
analysis.level = aTextRun->IsRightToLeft() ? 1 : 0;
|
|
||||||
analysis.lang_engine = nsnull;
|
|
||||||
analysis.extra_attrs = nsnull;
|
|
||||||
|
|
||||||
// Find non-ASCII character for finding the language of the script.
|
|
||||||
guint32 ch = 'a';
|
|
||||||
PRUint8 unicharRange = kRangeSetLatin;
|
|
||||||
if (aUTF16) {
|
|
||||||
PRUint32 i;
|
|
||||||
for (i = 0; i < aUTF16Length; ++i) {
|
|
||||||
PRUnichar utf16Char = aUTF16[i];
|
|
||||||
if (utf16Char > 0x100) {
|
|
||||||
ch = utf16Char;
|
|
||||||
unicharRange = FindCharUnicodeRange(utf16Char);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determin the language for finding the shaper.
|
|
||||||
nsCAutoString lang;
|
|
||||||
font->GetMozLang(lang);
|
|
||||||
switch (unicharRange) {
|
|
||||||
case kRangeSetLatin:
|
|
||||||
lang.Assign("x-western");
|
|
||||||
break;
|
|
||||||
case kRangeSetCJK:
|
|
||||||
if (GetCJKLangGroupIndex(lang.get()) < 0)
|
|
||||||
return NS_ERROR_FAILURE; // try with itemizing
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
lang.Assign(LangGroupFromUnicodeRange(unicharRange));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lang.IsEmpty() || lang.Equals("x-unicode") || lang.Equals("x-user-def"))
|
|
||||||
return NS_ERROR_FAILURE; // try with itemizing
|
|
||||||
|
|
||||||
analysis.language = GetPangoLanguage(lang);
|
|
||||||
analysis.shape_engine = pango_font_find_shaper(analysis.font,
|
|
||||||
analysis.language,
|
|
||||||
ch);
|
|
||||||
|
|
||||||
SetupClusterBoundaries(aTextRun, aUTF8, aUTF8Length, 0, &analysis);
|
|
||||||
|
|
||||||
PangoGlyphString *glyphString = pango_glyph_string_new();
|
|
||||||
|
|
||||||
pango_shape(aUTF8, aUTF8Length, &analysis, glyphString);
|
|
||||||
|
|
||||||
PRUint32 utf16Offset = 0;
|
|
||||||
nsresult rv = aTextRun->AddGlyphRun(font, 0);
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
return rv;
|
|
||||||
rv = SetGlyphs(aTextRun, aUTF8, aUTF8Length, &utf16Offset, glyphString, 0, PR_TRUE);
|
|
||||||
pango_glyph_string_free(glyphString);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
class FontSelector
|
class FontSelector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -1266,7 +1292,7 @@ public:
|
||||||
PangoItem *aItem, PRUint32 aUTF16Offset, PRPackedBool aIsRTL) :
|
PangoItem *aItem, PRUint32 aUTF16Offset, PRPackedBool aIsRTL) :
|
||||||
mItem(aItem),
|
mItem(aItem),
|
||||||
mGroup(aGroup), mTextRun(aTextRun), mString(aString),
|
mGroup(aGroup), mTextRun(aTextRun), mString(aString),
|
||||||
mFontIndex(0), mLength(aLength), mSegmentOffset(0), mUTF16Offset(aUTF16Offset),
|
mFontIndex(0), mLength(aLength), mUTF16Offset(aUTF16Offset),
|
||||||
mTriedPrefFonts(0), mTriedOtherFonts(0), mIsRTL(aIsRTL)
|
mTriedPrefFonts(0), mTriedOtherFonts(0), mIsRTL(aIsRTL)
|
||||||
{
|
{
|
||||||
for (PRUint32 i = 0; i < mGroup->FontListLength(); ++i)
|
for (PRUint32 i = 0; i < mGroup->FontListLength(); ++i)
|
||||||
|
@ -1274,9 +1300,9 @@ public:
|
||||||
mSpaceWidth = NS_lround(mGroup->GetFontAt(0)->GetMetrics().spaceWidth * FLOAT_PANGO_SCALE);
|
mSpaceWidth = NS_lround(mGroup->GetFontAt(0)->GetMetrics().spaceWidth * FLOAT_PANGO_SCALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Run()
|
nsresult Run()
|
||||||
{
|
{
|
||||||
InitSegments(0, mLength, mFontIndex);
|
return InitSegments(mString, mLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
PRUint32 GetUTF16Offset() { return mUTF16Offset; }
|
PRUint32 GetUTF16Offset() { return mUTF16Offset; }
|
||||||
|
@ -1311,30 +1337,6 @@ public:
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRBool AppendNextSegment(gfxPangoFont *aFont, PRUint32 aUTF8Length,
|
|
||||||
PangoGlyphString *aGlyphs, PRBool aGotGlyphs)
|
|
||||||
{
|
|
||||||
PangoFont *pf = aFont->GetPangoFont();
|
|
||||||
PRUint32 incomingUTF16Offset = mUTF16Offset;
|
|
||||||
|
|
||||||
if (!aGotGlyphs) {
|
|
||||||
// we can't use the existing glyphstring.
|
|
||||||
PangoFont *tmpFont = mItem->analysis.font;
|
|
||||||
mItem->analysis.font = pf;
|
|
||||||
pango_shape(mString + mSegmentOffset, aUTF8Length, &mItem->analysis, aGlyphs);
|
|
||||||
mItem->analysis.font = tmpFont;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = mTextRun->AddGlyphRun(aFont, incomingUTF16Offset);
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
return rv;
|
|
||||||
mGroup->SetGlyphs(mTextRun, mString + mSegmentOffset, aUTF8Length, &mUTF16Offset,
|
|
||||||
aGlyphs, mSpaceWidth, PR_FALSE);
|
|
||||||
|
|
||||||
mSegmentOffset += aUTF8Length;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PangoItem *mItem;
|
PangoItem *mItem;
|
||||||
|
|
||||||
|
@ -1345,7 +1347,6 @@ private:
|
||||||
const char *mString; // UTF-8
|
const char *mString; // UTF-8
|
||||||
PRUint32 mFontIndex;
|
PRUint32 mFontIndex;
|
||||||
PRInt32 mLength;
|
PRInt32 mLength;
|
||||||
PRUint32 mSegmentOffset;
|
|
||||||
PRUint32 mUTF16Offset;
|
PRUint32 mUTF16Offset;
|
||||||
PRUint32 mSpaceWidth;
|
PRUint32 mSpaceWidth;
|
||||||
|
|
||||||
|
@ -1353,108 +1354,102 @@ private:
|
||||||
PRPackedBool mTriedOtherFonts;
|
PRPackedBool mTriedOtherFonts;
|
||||||
PRPackedBool mIsRTL;
|
PRPackedBool mIsRTL;
|
||||||
|
|
||||||
void InitSegments(const PRUint32 aOffset,
|
nsresult InitSegments(const gchar *aUTF8, PRUint32 aLength) {
|
||||||
const PRUint32 aLength,
|
if (aLength == 0)
|
||||||
const PRUint32 aFontIndex) {
|
return NS_OK;
|
||||||
mFontIndex = aFontIndex;
|
const gchar *start = aUTF8;
|
||||||
|
const gchar *last = start + aLength;
|
||||||
const char *current = mString + aOffset;
|
|
||||||
PRBool checkMissingGlyph = PR_TRUE;
|
|
||||||
|
|
||||||
// for RTL, if we cannot find the font that has all glyphs,
|
|
||||||
// we should use better font.
|
|
||||||
PRUint32 betterFontIndex = 0;
|
|
||||||
PRUint32 foundGlyphs = 0;
|
|
||||||
|
|
||||||
PangoGlyphString *glyphString = pango_glyph_string_new();
|
|
||||||
|
|
||||||
RetryNextFont:
|
RetryNextFont:
|
||||||
nsRefPtr<gfxPangoFont> font = GetNextFont();
|
nsRefPtr<gfxPangoFont> font = GetNextFont();
|
||||||
|
|
||||||
// If we cannot found the font that has the current character glyph,
|
// If we cannot found the font that has the current character glyph,
|
||||||
// we should return default font's missing data.
|
// we should return default font's missing data.
|
||||||
if (!font) {
|
if (!font)
|
||||||
font = mFonts[betterFontIndex];
|
return AppendMissingSegment(start, last - start);
|
||||||
checkMissingGlyph = PR_FALSE;
|
|
||||||
|
nsresult rv;
|
||||||
|
for (const gchar *c = start; c < last;) {
|
||||||
|
// find the first missing glyph
|
||||||
|
gunichar u = g_utf8_get_char(c);
|
||||||
|
if (font->HasGlyph(PRUint32(u))) {
|
||||||
|
c = g_utf8_next_char(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the next point that can be renderd with current font
|
||||||
|
const gchar *missingStart = c;
|
||||||
|
const gchar *next;
|
||||||
|
for (next = g_utf8_next_char(missingStart); next < last; next = g_utf8_next_char(next)) {
|
||||||
|
u = g_utf8_get_char(next);
|
||||||
|
if (font->HasGlyph(PRUint32(u)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// current font has 0 glyphs for current segment, try with next font
|
||||||
|
if (missingStart == start && next == last)
|
||||||
|
goto RetryNextFont;
|
||||||
|
|
||||||
|
// create the segment for found glyphs
|
||||||
|
rv = AppendSegment(font, start, missingStart - start);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// init the missing glyphs with remains fonts.
|
||||||
|
PRUint32 fontIndex = mFontIndex;
|
||||||
|
rv = InitSegments(missingStart, next - missingStart);
|
||||||
|
mFontIndex = fontIndex;
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
start = c = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shaping
|
rv = AppendSegment(font, start, last - start);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult AppendSegment(gfxPangoFont* aFont, const gchar *aUTF8, PRUint32 aLength) {
|
||||||
|
if (aLength == 0)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
PangoFont* pf = aFont->GetPangoFont();
|
||||||
|
|
||||||
|
PangoGlyphString *glyphString = pango_glyph_string_new();
|
||||||
|
if (!glyphString)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
PangoFont *tmpFont = mItem->analysis.font;
|
PangoFont *tmpFont = mItem->analysis.font;
|
||||||
mItem->analysis.font = font->GetPangoFont();
|
mItem->analysis.font = pf;
|
||||||
pango_shape(current, aLength, &mItem->analysis, glyphString);
|
pango_shape(aUTF8, aLength, &mItem->analysis, glyphString);
|
||||||
mItem->analysis.font = tmpFont;
|
mItem->analysis.font = tmpFont;
|
||||||
|
|
||||||
gint num_glyphs = glyphString->num_glyphs;
|
nsresult rv = mTextRun->AddGlyphRun(aFont, mUTF16Offset);
|
||||||
gint *clusters = glyphString->log_clusters;
|
if (NS_FAILED(rv)) {
|
||||||
PRUint32 offset = aOffset;
|
NS_ERROR("AddGlyphRun Failed");
|
||||||
PRUint32 skipLength = 0;
|
pango_glyph_string_free(glyphString);
|
||||||
if (checkMissingGlyph) {
|
return rv;
|
||||||
for (PRInt32 i = 0; i < num_glyphs; ++i) {
|
|
||||||
PangoGlyphInfo *info = &glyphString->glyphs[i];
|
|
||||||
if (IS_MISSING_GLYPH(info->glyph)) {
|
|
||||||
// XXX Note that we don't support the segment separation
|
|
||||||
// in RTL text. Because the Arabic characters changes the
|
|
||||||
// glyphs by the position of the context. I think that the
|
|
||||||
// languages of RTL doesn't have *very *many characters, so,
|
|
||||||
// the Arabic/Hebrew font may have all glyphs in a font.
|
|
||||||
if (mIsRTL) {
|
|
||||||
PRUint32 found = i;
|
|
||||||
for (PRInt32 j = i; j < num_glyphs; ++j) {
|
|
||||||
info = &glyphString->glyphs[j];
|
|
||||||
if (!IS_MISSING_GLYPH(info->glyph))
|
|
||||||
found++;
|
|
||||||
}
|
|
||||||
if (found > foundGlyphs) {
|
|
||||||
// we find better font!
|
|
||||||
foundGlyphs = found;
|
|
||||||
betterFontIndex = mFontIndex - 1;
|
|
||||||
}
|
|
||||||
goto RetryNextFont;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The glyph is missing, separate segment here.
|
|
||||||
PRUint32 missingLength = aLength - clusters[i];
|
|
||||||
PRInt32 j;
|
|
||||||
for (j = i + 1; j < num_glyphs; ++j) {
|
|
||||||
info = &glyphString->glyphs[j];
|
|
||||||
if (!IS_MISSING_GLYPH(info->glyph)) {
|
|
||||||
missingLength = aOffset + clusters[j] - offset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i != 0) {
|
|
||||||
// found glyphs
|
|
||||||
AppendNextSegment(font, offset - (aOffset + skipLength),
|
|
||||||
glyphString, PR_FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// missing glyphs
|
|
||||||
PRUint32 fontIndex = mFontIndex;
|
|
||||||
InitSegments(offset, missingLength, mFontIndex);
|
|
||||||
mFontIndex = fontIndex;
|
|
||||||
|
|
||||||
PRUint32 next = offset + missingLength;
|
|
||||||
if (next >= aLength) {
|
|
||||||
pango_glyph_string_free(glyphString);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remains, continue this loop
|
|
||||||
i = j;
|
|
||||||
skipLength = next - aOffset;
|
|
||||||
}
|
|
||||||
if (i + 1 < num_glyphs)
|
|
||||||
offset = aOffset + clusters[i + 1];
|
|
||||||
else
|
|
||||||
offset = aOffset + aLength;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
offset = aOffset + aLength;
|
|
||||||
}
|
}
|
||||||
|
PRUint32 utf16Offset = mUTF16Offset;
|
||||||
AppendNextSegment(font, aLength - skipLength, glyphString, skipLength == 0);
|
rv = mGroup->SetGlyphs(mTextRun, aFont, aUTF8, aLength,
|
||||||
|
&utf16Offset, glyphString, mSpaceWidth, PR_FALSE);
|
||||||
pango_glyph_string_free(glyphString);
|
pango_glyph_string_free(glyphString);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
mUTF16Offset = utf16Offset;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult AppendMissingSegment(const gchar *aUTF8, PRUint32 aLength) {
|
||||||
|
if (aLength == 0)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
nsresult rv = mTextRun->AddGlyphRun(mFonts[0], mUTF16Offset);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
PRUint32 utf16Offset = mUTF16Offset;
|
||||||
|
rv = mGroup->SetMissingGlyphs(mTextRun, aUTF8, aLength, &utf16Offset);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
mUTF16Offset = utf16Offset;
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxPangoFont *GetNextFont() {
|
gfxPangoFont *GetNextFont() {
|
||||||
|
@ -1524,7 +1519,7 @@ TRY_AGAIN_HOPE_FOR_THE_BEST_2:
|
||||||
if (!prefBranch)
|
if (!prefBranch)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Add by the order of accept languages.
|
// Add the accept languages.
|
||||||
nsXPIDLCString list;
|
nsXPIDLCString list;
|
||||||
nsresult rv = prefBranch->GetCharPref("intl.accept_languages",
|
nsresult rv = prefBranch->GetCharPref("intl.accept_languages",
|
||||||
getter_Copies(list));
|
getter_Copies(list));
|
||||||
|
@ -1887,3 +1882,72 @@ GetMozLanguage(const PangoLanguage *aLang, nsACString &aMozLang)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gfxPangoFontCache::gfxPangoFontCache()
|
||||||
|
{
|
||||||
|
mPangoFonts.Init(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfxPangoFontCache::~gfxPangoFontCache()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gfxPangoFontCache::Put(const PangoFontDescription *aFontDesc, PangoFont *aPangoFont)
|
||||||
|
{
|
||||||
|
if (mPangoFonts.Count() > 5000)
|
||||||
|
mPangoFonts.Clear();
|
||||||
|
PRUint32 key = pango_font_description_hash(aFontDesc);
|
||||||
|
gfxPangoFontWrapper *value = new gfxPangoFontWrapper(aPangoFont);
|
||||||
|
if (!value)
|
||||||
|
return;
|
||||||
|
mPangoFonts.Put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
PangoFont*
|
||||||
|
gfxPangoFontCache::Get(const PangoFontDescription *aFontDesc)
|
||||||
|
{
|
||||||
|
PRUint32 key = pango_font_description_hash(aFontDesc);
|
||||||
|
gfxPangoFontWrapper *value;
|
||||||
|
if (!mPangoFonts.Get(key, &value))
|
||||||
|
return nsnull;
|
||||||
|
PangoFont *font = value->Get();
|
||||||
|
g_object_ref(font);
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfxPangoFontNameMap::gfxPangoFontNameMap()
|
||||||
|
{
|
||||||
|
mPangoFonts.Init(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfxPangoFontNameMap::~gfxPangoFontNameMap()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gfxPangoFontNameMap::Put(const nsACString &aName, PangoFont *aPangoFont)
|
||||||
|
{
|
||||||
|
nsCAutoString key(aName);
|
||||||
|
ToLowerCase(key);
|
||||||
|
gfxPangoFontWrapper *value;
|
||||||
|
if (!mPangoFonts.Get(key, &value)) {
|
||||||
|
value = new gfxPangoFontWrapper(aPangoFont);
|
||||||
|
if (!value)
|
||||||
|
return;
|
||||||
|
mPangoFonts.Put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PangoFont*
|
||||||
|
gfxPangoFontNameMap::Get(const nsACString &aName)
|
||||||
|
{
|
||||||
|
nsCAutoString key(aName);
|
||||||
|
ToLowerCase(key);
|
||||||
|
gfxPangoFontWrapper *value;
|
||||||
|
if (!mPangoFonts.Get(key, &value))
|
||||||
|
return nsnull;
|
||||||
|
PangoFont *font = value->Get();
|
||||||
|
g_object_ref(font);
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче