From 5331bc3fe6066b0c177c054a711c5b2d1f9167c9 Mon Sep 17 00:00:00 2001 From: "pavlov@pavlov.net" Date: Wed, 19 Sep 2007 15:18:42 -0700 Subject: [PATCH] bug 362682. fix missing glyphs on linux. patch by myself and Behdad Esfahbod . r=vlad --- config/system-headers | 3 + configure.in | 22 +- gfx/cairo/cairo/src/cairo-ft-font.c | 14 +- gfx/thebes/public/gfxPangoFonts.h | 68 +- gfx/thebes/public/gfxPlatformGtk.h | 2 +- gfx/thebes/src/cairo-xlib-utils.c | 1 + gfx/thebes/src/gfxPangoFonts.cpp | 919 ++++++---------------------- gfx/thebes/src/gfxPlatformGtk.cpp | 100 +-- 8 files changed, 230 insertions(+), 899 deletions(-) diff --git a/config/system-headers b/config/system-headers index c40e1dcae15..b19546916c7 100644 --- a/config/system-headers +++ b/config/system-headers @@ -213,6 +213,7 @@ Gdiplus.h gdk/gdkevents.h gdk/gdk.h gdk/gdkkeysyms.h +gdk/gdkpango.h gdk/gdkprivate.h gdk/gdkregion.h gdk/gdkwindow.h @@ -505,6 +506,7 @@ PALM_CMN.H pango-engine.h pango-glyph.h pango-modules.h +pango/pangocairo.h pango/pangofc-decoder.h pango/pangofc-font.h pango/pangofc-fontmap.h @@ -513,6 +515,7 @@ pango/pango-fontmap.h pango/pango.h pango/pangoxft.h pango/pangox.h +pango/pango-utils.h pango-types.h pascal.h Patches.h diff --git a/configure.in b/configure.in index 32785ef6974..692de86428d 100644 --- a/configure.in +++ b/configure.in @@ -116,7 +116,8 @@ PERL_VERSION=5.006 LIBART_VERSION=2.3.4 CAIRO_VERSION=1.4.2 GLITZ_VERSION=0.4.0 -GTK2_VERSION=1.3.7 +PANGO_VERSION=1.10.0 +GTK2_VERSION=1.8.0 MAKE_VERSION=3.78 WINDRES_VERSION=2.14.90 W32API_VERSION=3.8 @@ -4567,7 +4568,7 @@ fi if test "$COMPILE_ENVIRONMENT"; then if test "$MOZ_ENABLE_GTK2" then - PKG_CHECK_MODULES(MOZ_GTK2, gtk+-2.0 >= 1.3.7 gdk-x11-2.0 glib-2.0 gobject-2.0) + PKG_CHECK_MODULES(MOZ_GTK2, gtk+-2.0 >= $GTK2_VERSION gdk-x11-2.0 glib-2.0 gobject-2.0) fi fi # COMPILE_ENVIRONMENT @@ -4806,7 +4807,7 @@ if test "$MOZ_ENABLE_XFT" then AC_DEFINE(MOZ_ENABLE_XFT) PKG_CHECK_MODULES(MOZ_XFT, xft) - PKG_CHECK_MODULES(_PANGOCHK, pango >= 1.1.0) + PKG_CHECK_MODULES(_PANGOCHK, pango >= $PANGO_VERSION) fi AC_SUBST(MOZ_ENABLE_XFT) @@ -4823,12 +4824,7 @@ MOZ_ARG_ENABLE_BOOL(pango, if test "$MOZ_ENABLE_PANGO" && test -z "$MOZ_ENABLE_CAIRO_GFX" then - AC_DEFINE(MOZ_ENABLE_PANGO) - PKG_CHECK_MODULES(MOZ_PANGO, pangoxft >= 1.6.0) - - AC_SUBST(MOZ_ENABLE_PANGO) - AC_SUBST(MOZ_PANGO_CFLAGS) - AC_SUBST(MOZ_PANGO_LIBS) + AC_MSG_ERROR([Cairo gfx is required for Pango font rendering]) fi if test "$MOZ_ENABLE_GTK2" && test "$MOZ_ENABLE_CAIRO_GFX" @@ -4844,13 +4840,7 @@ fi if test "$MOZ_ENABLE_PANGO" && test "$MOZ_ENABLE_CAIRO_GFX" then AC_DEFINE(MOZ_ENABLE_PANGO) - dnl PKG_CHECK_MODULES(MOZ_PANGO, pango >= 1.10.0 pangocairo >= 1.10.0) - if test "$MOZ_X11"; then - PKG_CHECK_MODULES(MOZ_PANGO, pango >= 1.6.0 pangoft2 >= 1.6.0 pangoxft >= 1.6.0) - else - PKG_CHECK_MODULES(MOZ_PANGO, pango >= 1.6.0 pangoft2 >= 1.6.0) - fi - + PKG_CHECK_MODULES(MOZ_PANGO, pango >= $PANGO_VERSION pangocairo >= $PANGO_VERSION) AC_SUBST(MOZ_ENABLE_PANGO) AC_SUBST(MOZ_PANGO_CFLAGS) AC_SUBST(MOZ_PANGO_LIBS) diff --git a/gfx/cairo/cairo/src/cairo-ft-font.c b/gfx/cairo/cairo/src/cairo-ft-font.c index 8fb413743d1..8695ea119ed 100644 --- a/gfx/cairo/cairo/src/cairo-ft-font.c +++ b/gfx/cairo/cairo/src/cairo-ft-font.c @@ -1097,7 +1097,9 @@ _render_glyph_bitmap (FT_Face face, * we avoid the FT_LOAD_NO_RECURSE flag. */ error = FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL); - if (error) { + /* XXX ignoring all other errors for now. They are not fatal, typically + * just a glyph-not-found. */ + if (error == FT_Err_Out_Of_Memory) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; } @@ -1891,8 +1893,9 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, error = FT_Load_Glyph (scaled_font->unscaled->face, _cairo_scaled_glyph_index(scaled_glyph), load_flags); - - if (error) { + /* XXX ignoring all other errors for now. They are not fatal, typically + * just a glyph-not-found. */ + if (error == FT_Err_Out_Of_Memory) { status = CAIRO_STATUS_NO_MEMORY; goto FAIL; } @@ -2042,8 +2045,9 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, error = FT_Load_Glyph (face, _cairo_scaled_glyph_index(scaled_glyph), load_flags | FT_LOAD_NO_BITMAP); - - if (error) { + /* XXX ignoring all other errors for now. They are not fatal, typically + * just a glyph-not-found. */ + if (error == FT_Err_Out_Of_Memory) { _cairo_ft_unscaled_font_unlock_face (unscaled); _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_NO_MEMORY; diff --git a/gfx/thebes/public/gfxPangoFonts.h b/gfx/thebes/public/gfxPangoFonts.h index 54dc20b3a88..2e6dbb7ebb6 100644 --- a/gfx/thebes/public/gfxPangoFonts.h +++ b/gfx/thebes/public/gfxPangoFonts.h @@ -44,14 +44,15 @@ #include "gfxFont.h" #include -#include -// Control when we use Xft directly, bypassing Pango -// Enable this to use Xft to glyph-convert 8bit-only textruns, but use Pango +// Control when we bypass Pango +// Enable this to use FreeType to glyph-convert 8bit-only textruns, but use Pango // to shape any textruns with non-8bit characters -#define ENABLE_XFT_FAST_PATH_8BIT -// Enable this to use Xft to glyph-convert all textruns -// #define ENABLE_XFT_FAST_PATH_ALWAYS +// XXX +#define ENABLE_FAST_PATH_8BIT +// Enable this to bypass Pango shaping for all textruns. Don't expect +// anything other than simple Latin work though! +//#define ENABLE_FAST_PATH_ALWAYS #include "nsDataHashtable.h" #include "nsClassHashtable.h" @@ -70,17 +71,15 @@ public: virtual const gfxFont::Metrics& GetMetrics(); - PangoFontDescription *GetPangoFontDescription() { RealizeFont(); return mPangoFontDesc; } - PangoContext *GetPangoContext() { RealizeFont(); return mPangoCtx; } + PangoFontDescription *GetPangoFontDescription() { if (!mPangoFontDesc) RealizeFont(); return mPangoFontDesc; } + PangoContext *GetPangoContext() { if (!mPangoFontDesc) RealizeFont(); return mPangoCtx; } void GetMozLang(nsACString &aMozLang); void GetActualFontFamily(nsACString &aFamily); - XftFont *GetXftFont () { RealizeXftFont (); return mXftFont; } - PangoFont *GetPangoFont() { RealizePangoFont(); return mPangoFont; } - gfxFloat GetAdjustedSize() { RealizeFont(); return mAdjustedSize; } + PangoFont *GetPangoFont() { if (!mPangoFont) RealizePangoFont(); return mPangoFont; } + gfxFloat GetAdjustedSize() { if (!mPangoFontDesc) RealizeFont(); return mAdjustedSize; } - PRBool HasGlyph(const PRUint32 aChar); PRUint32 GetGlyph(const PRUint32 aChar); virtual nsString GetUniqueName(); @@ -95,9 +94,7 @@ protected: PangoFontDescription *mPangoFontDesc; PangoContext *mPangoCtx; - XftFont *mXftFont; PangoFont *mPangoFont; - PangoFont *mGlyphTestingFont; cairo_scaled_font_t *mCairoFont; PRBool mHasMetrics; @@ -106,7 +103,6 @@ protected: gfxFloat mAdjustedSize; void RealizeFont(PRBool force = PR_FALSE); - void RealizeXftFont(PRBool force = PR_FALSE); void RealizePangoFont(PRBool aForce = PR_FALSE); void GetCharSize(const char aChar, gfxSize& aInkSize, gfxSize& aLogSize, PRUint32 *aGlyphID = nsnull); @@ -124,7 +120,7 @@ public: virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle); - // Create and initialize a textrun using Pango (or Xft) + // Create and initialize a textrun using Pango virtual gfxTextRun *MakeTextRun(const PRUnichar *aString, PRUint32 aLength, const Parameters *aParams, PRUint32 aFlags); virtual gfxTextRun *MakeTextRun(const PRUint8 *aString, PRUint32 aLength, @@ -146,8 +142,8 @@ protected: * but stored in UTF16 format) */ void InitTextRun(gfxTextRun *aTextRun, const gchar *aUTF8Text, - PRUint32 aUTF8Length, PRUint32 aUTF8HeaderLength, - PRBool aTake8BitPath); + PRUint32 aUTF8Length, PRBool aTake8BitPath); + // Returns NS_ERROR_FAILURE if there's a missing glyph nsresult SetGlyphs(gfxTextRun *aTextRun, gfxPangoFont *aFont, const gchar *aUTF8, PRUint32 aUTF8Length, @@ -158,11 +154,11 @@ protected: const gchar *aUTF8, PRUint32 aUTF8Length, PRUint32 *aUTF16Offset); void CreateGlyphRunsItemizing(gfxTextRun *aTextRun, - const gchar *aUTF8, PRUint32 aUTF8Length, - PRUint32 aUTF8HeaderLength); -#if defined(ENABLE_XFT_FAST_PATH_8BIT) || defined(ENABLE_XFT_FAST_PATH_ALWAYS) - void CreateGlyphRunsXft(gfxTextRun *aTextRun, - const gchar *aUTF8, PRUint32 aUTF8Length); + const gchar *aUTF8, PRUint32 aUTF8Length); +#if defined(ENABLE_FAST_PATH_8BIT) || defined(ENABLE_FAST_PATH_ALWAYS) + PRBool CanTakeFastPath(PRUint32 aFlags); + void CreateGlyphRunsFast(gfxTextRun *aTextRun, + const gchar *aUTF8, PRUint32 aUTF8Length); #endif static PRBool FontCallback (const nsAString& fontName, @@ -212,30 +208,4 @@ private: nsClassHashtable 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 mPangoFonts; -}; #endif /* GFX_PANGOFONTS_H */ diff --git a/gfx/thebes/public/gfxPlatformGtk.h b/gfx/thebes/public/gfxPlatformGtk.h index 01773046f86..4c7eafd0fbb 100644 --- a/gfx/thebes/public/gfxPlatformGtk.h +++ b/gfx/thebes/public/gfxPlatformGtk.h @@ -79,7 +79,7 @@ public: if (sDPI == -1) { InitDPI(); } - NS_ASSERTION(sDPI != 0, "Something is wrong"); + NS_ASSERTION(sDPI > 0, "Something is wrong"); return sDPI; } diff --git a/gfx/thebes/src/cairo-xlib-utils.c b/gfx/thebes/src/cairo-xlib-utils.c index 69cccf2f483..a7d9333ba1c 100644 --- a/gfx/thebes/src/cairo-xlib-utils.c +++ b/gfx/thebes/src/cairo-xlib-utils.c @@ -40,6 +40,7 @@ #include "cairo-xlib.h" #include +#include #if HAVE_STDINT_H #include #elif HAVE_INTTYPES_H diff --git a/gfx/thebes/src/gfxPangoFonts.cpp b/gfx/thebes/src/gfxPangoFonts.cpp index 89e886ddbcb..db95d9fb12d 100644 --- a/gfx/thebes/src/gfxPangoFonts.cpp +++ b/gfx/thebes/src/gfxPangoFonts.cpp @@ -21,6 +21,7 @@ * Contributor(s): * Vladimir Vukicevic * Masayuki Nakano + * Behdad Esfahbod * * based on nsFontMetricsPango.cpp by * Christopher Blizzard @@ -39,11 +40,6 @@ * * ***** END LICENSE BLOCK ***** */ -#ifdef XP_BEOS -#define THEBES_USE_PANGO_CAIRO -#endif - -#define PANGO_ENABLE_ENGINE #define PANGO_ENABLE_BACKEND #include "prtypes.h" @@ -62,45 +58,38 @@ #include "nsPromiseFlatString.h" #include "gfxContext.h" +#include "gfxPlatformGtk.h" #include "gfxPangoFonts.h" #include "nsCRT.h" -#include "cairo.h" - -#ifndef THEBES_USE_PANGO_CAIRO -#include -#include -#include - - #include -#include -#include -#include - -#include "cairo-ft.h" - -#include "gfxPlatformGtk.h" - -#else // THEBES_USE_PANGO_CAIRO +#include +#include +#include +#include #include +#include -#endif // THEBES_USE_PANGO_CAIRO +#include #include #define FLOAT_PANGO_SCALE ((gfxFloat)PANGO_SCALE) -#define IS_MISSING_GLYPH(g) (((g) & 0x10000000) || (g) == 0x0FFFFFFF) +#ifndef PANGO_GLYPH_UNKNOWN_FLAG +#define PANGO_GLYPH_UNKNOWN_FLAG ((PangoGlyph)0x10000000) +#endif +#ifndef PANGO_GLYPH_EMPTY +#define PANGO_GLYPH_EMPTY ((PangoGlyph)0) +#endif +#define IS_MISSING_GLYPH(g) (((g) & PANGO_GLYPH_UNKNOWN_FLAG) || (g) == PANGO_GLYPH_EMPTY) static PangoLanguage *GetPangoLanguage(const nsACString& aLangGroup); -static void GetMozLanguage(const PangoLanguage *aLang, nsACString &aMozLang); /* static */ gfxPangoFontCache* gfxPangoFontCache::sPangoFontCache = nsnull; -/* static */ gfxPangoFontNameMap* gfxPangoFontNameMap::sPangoFontNameMap = nsnull; /** ** gfxPangoFontGroup @@ -166,6 +155,7 @@ gfxPangoFontGroup::gfxPangoFontGroup (const nsAString& families, // XXX If there are no actual fonts, we should use dummy family. // Pango will resolve from this. + // behdad: yep, looks good. if (familyArray.Count() == 0) { // printf("%s(%s)\n", NS_ConvertUTF16toUTF8(families).get(), // aStyle->langGroup.get()); @@ -194,82 +184,12 @@ gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle) ** gfxPangoFont **/ -// Glue to avoid build/runtime dependencies on Pango > 1.6, -// because we like living in 1999 - -#ifndef THEBES_USE_PANGO_CAIRO -static void -(* PTR_pango_font_description_set_absolute_size)(PangoFontDescription*, double) - = nsnull; - -static void InitPangoLib() -{ - static PRBool initialized = PR_FALSE; - if (initialized) - return; - initialized = PR_TRUE; - - g_type_init(); - - PRLibrary *pangoLib = nsnull; - PTR_pango_font_description_set_absolute_size = - (void (*)(PangoFontDescription*, double)) - PR_FindFunctionSymbolAndLibrary("pango_font_description_set_absolute_size", - &pangoLib); - if (pangoLib) - PR_UnloadLibrary(pangoLib); - - PRLibrary *xftLib = nsnull; - int *xft_max_freetype_files_ptr = nsnull; - xft_max_freetype_files_ptr = (int*) PR_FindSymbolAndLibrary("XftMaxFreeTypeFiles", &xftLib); - if (xft_max_freetype_files_ptr && *xft_max_freetype_files_ptr < 50) - *xft_max_freetype_files_ptr = 50; - if (xftLib) - PR_UnloadLibrary(xftLib); -} - -static void -ShutdownPangoLib() -{ -} - -static void -MOZ_pango_font_description_set_absolute_size(PangoFontDescription *desc, - double size) -{ - if (PTR_pango_font_description_set_absolute_size) { - PTR_pango_font_description_set_absolute_size(desc, size); - } else { - pango_font_description_set_size(desc, - (gint)(size * 72.0 / - gfxPlatformGtk::DPI())); - } -} -#else -static inline void InitPangoLib() -{ -} - -static inline void ShutdownPangoLib() -{ -} - -static inline void -MOZ_pango_font_description_set_absolute_size(PangoFontDescription *desc, double size) -{ - pango_font_description_set_absolute_size(desc, size); -} -#endif - gfxPangoFont::gfxPangoFont(const nsAString &aName, const gfxFontStyle *aFontStyle) : gfxFont(aName, aFontStyle), - mPangoFontDesc(nsnull), mPangoCtx(nsnull), - mXftFont(nsnull), mPangoFont(nsnull), mGlyphTestingFont(nsnull), - mCairoFont(nsnull), mHasMetrics(PR_FALSE), - mAdjustedSize(0) + mPangoFontDesc(nsnull), mPangoCtx(nsnull), mPangoFont(nsnull), + mCairoFont(nsnull), mHasMetrics(PR_FALSE), mAdjustedSize(0) { - InitPangoLib(); } gfxPangoFont::~gfxPangoFont() @@ -280,9 +200,6 @@ gfxPangoFont::~gfxPangoFont() if (mPangoFont) g_object_unref(mPangoFont); - if (mGlyphTestingFont) - g_object_unref(mGlyphTestingFont); - if (mPangoFontDesc) pango_font_description_free(mPangoFontDesc); @@ -293,9 +210,12 @@ gfxPangoFont::~gfxPangoFont() /* static */ void gfxPangoFont::Shutdown() { - ShutdownPangoLib(); gfxPangoFontCache::Shutdown(); - gfxPangoFontNameMap::Shutdown(); + + PangoFontMap *fontmap = pango_cairo_font_map_get_default (); + if (PANGO_IS_FC_FONT_MAP (fontmap)) + pango_fc_font_map_shutdown (PANGO_FC_FONT_MAP (fontmap)); + } static PangoStyle @@ -375,28 +295,24 @@ gfxPangoFont::RealizeFont(PRBool force) if (mPangoFont) { g_object_unref(mPangoFont); mPangoFont = nsnull; - mXftFont = nsnull; - // XXX we don't need to reset mGlyphTestingFont } mPangoFontDesc = pango_font_description_new(); pango_font_description_set_family(mPangoFontDesc, NS_ConvertUTF16toUTF8(mName).get()); gfxFloat size = mAdjustedSize ? mAdjustedSize : GetStyle()->size; - MOZ_pango_font_description_set_absolute_size(mPangoFontDesc, size * PANGO_SCALE); + pango_font_description_set_absolute_size(mPangoFontDesc, size * PANGO_SCALE); pango_font_description_set_style(mPangoFontDesc, ThebesStyleToPangoStyle(GetStyle())); pango_font_description_set_weight(mPangoFontDesc, ThebesStyleToPangoWeight(GetStyle())); //printf ("%s, %f, %d, %d\n", NS_ConvertUTF16toUTF8(mName).get(), GetStyle()->size, ThebesStyleToPangoStyle(GetStyle()), ThebesStyleToPangoWeight(GetStyle())); -#ifndef THEBES_USE_PANGO_CAIRO - mPangoCtx = pango_xft_get_context(GDK_DISPLAY(), 0); - gdk_pango_context_set_colormap(mPangoCtx, gdk_rgb_get_cmap()); -#else - mPangoCtx = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(pango_cairo_font_map_get_default())); -#endif + mPangoCtx = gdk_pango_context_get (); - if (!GetStyle()->langGroup.IsEmpty()) - pango_context_set_language(mPangoCtx, GetPangoLanguage(GetStyle()->langGroup)); + if (!GetStyle()->langGroup.IsEmpty()) { + PangoLanguage *lang = GetPangoLanguage(GetStyle()->langGroup); + if (lang) + pango_context_set_language(mPangoCtx, lang); + } pango_context_set_font_description(mPangoCtx, mPangoFontDesc); @@ -416,20 +332,6 @@ gfxPangoFont::RealizeFont(PRBool force) RealizeFont(PR_TRUE); } -void -gfxPangoFont::RealizeXftFont(PRBool force) -{ - // already realized? - if (!force && mXftFont) - return; - if (GDK_DISPLAY() == 0) { - mXftFont = nsnull; - return; - } - - mXftFont = pango_xft_font_get_font(GetPangoFont()); -} - void gfxPangoFont::RealizePangoFont(PRBool aForce) { @@ -438,7 +340,6 @@ gfxPangoFont::RealizePangoFont(PRBool aForce) if (mPangoFont) { g_object_unref(mPangoFont); mPangoFont = nsnull; - mXftFont = nsnull; } RealizeFont(); gfxPangoFontCache *cache = gfxPangoFontCache::GetPangoFontCache(); @@ -451,19 +352,6 @@ gfxPangoFont::RealizePangoFont(PRBool aForce) if (!mPangoFont) return; // Error cache->Put(mPangoFontDesc, mPangoFont); - - if (mGlyphTestingFont) - return; - - // 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 @@ -520,89 +408,6 @@ gfxPangoFont::GetMetrics() if (mHasMetrics) return mMetrics; -#ifndef THEBES_USE_PANGO_CAIRO - float val; - - XftFont *xftFont = GetXftFont(); // RealizeFont is called here. - if (!xftFont) - return mMetrics; // XXX error - - FT_Face face = XftLockFace(xftFont); - if (!face) - return mMetrics; // XXX error - - int size; - PangoFcFont *fcfont = PANGO_FC_FONT(mPangoFont); - if (FcPatternGetInteger(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch) - size = 12; - mMetrics.emHeight = PR_MAX(1, size); - - mMetrics.maxAscent = xftFont->ascent; - mMetrics.maxDescent = xftFont->descent; - - double lineHeight = mMetrics.maxAscent + mMetrics.maxDescent; - - if (lineHeight > mMetrics.emHeight) - mMetrics.internalLeading = lineHeight - mMetrics.emHeight; - else - mMetrics.internalLeading = 0; - mMetrics.externalLeading = 0; - - mMetrics.maxHeight = lineHeight; - mMetrics.emAscent = mMetrics.maxAscent * mMetrics.emHeight / lineHeight; - mMetrics.emDescent = mMetrics.emHeight - mMetrics.emAscent; - mMetrics.maxAdvance = xftFont->max_advance_width; - - gfxSize isz, lsz; - GetCharSize(' ', isz, lsz, &mSpaceGlyph); - mMetrics.spaceWidth = lsz.width; - - // XXX do some FcCharSetHasChar work here to make sure - // we have an "x" - GetCharSize('x', isz, lsz); - mMetrics.xHeight = isz.height; - mMetrics.aveCharWidth = isz.width; - - val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_position, - face->size->metrics.y_scale); - if (!val) - val = - PR_MAX(1, floor(0.1 * xftFont->height + 0.5)); - - mMetrics.underlineOffset = val; - - val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_thickness, - face->size->metrics.y_scale); - if (!val) - val = floor(0.05 * xftFont->height + 0.5); - - mMetrics.underlineSize = PR_MAX(1, val); - - TT_OS2 *os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2); - - if (os2 && os2->ySuperscriptYOffset) { - val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySuperscriptYOffset, - face->size->metrics.y_scale); - mMetrics.superscriptOffset = PR_MAX(1, val); - } else { - mMetrics.superscriptOffset = mMetrics.xHeight; - } - - // mSubscriptOffset - if (os2 && os2->ySubscriptYOffset) { - val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySubscriptYOffset, - face->size->metrics.y_scale); - // some fonts have the incorrect sign. - val = (val < 0) ? -val : val; - mMetrics.subscriptOffset = PR_MAX(1, val); - } else { - mMetrics.subscriptOffset = mMetrics.xHeight; - } - - mMetrics.strikeoutOffset = mMetrics.xHeight / 2.0; - mMetrics.strikeoutSize = mMetrics.underlineSize; - - XftUnlockFace(xftFont); -#else /* pango_cairo case; try to get all the metrics from pango itself */ PangoFont *font = GetPangoFont(); // RealizeFont is called here. @@ -627,7 +432,8 @@ gfxPangoFont::GetMetrics() mMetrics.emAscent = mMetrics.maxAscent * mMetrics.emHeight / lineHeight; mMetrics.emDescent = mMetrics.emHeight - mMetrics.emAscent; - mMetrics.maxAdvance = pango_font_metrics_get_approximate_char_width(pfm) / FLOAT_PANGO_SCALE; // XXX + // XXX should we move this down, get max-advance from FT_Face? + mMetrics.maxAdvance = pango_font_metrics_get_approximate_char_width(pfm) / FLOAT_PANGO_SCALE; gfxSize isz, lsz; GetCharSize(' ', isz, lsz, &mSpaceGlyph); @@ -643,14 +449,43 @@ gfxPangoFont::GetMetrics() mMetrics.strikeoutOffset = pango_font_metrics_get_strikethrough_position(pfm) / FLOAT_PANGO_SCALE; mMetrics.strikeoutSize = pango_font_metrics_get_strikethrough_thickness(pfm) / FLOAT_PANGO_SCALE; - // these are specified by the so-called OS2 SFNT info, but - // pango doesn't expose this to us. This really sucks, - // so we just assume it's the xHeight - mMetrics.superscriptOffset = mMetrics.xHeight; - mMetrics.subscriptOffset = mMetrics.xHeight; + FT_Face face = NULL; + if (PANGO_IS_FC_FONT (font)) + face = pango_fc_font_lock_face (PANGO_FC_FONT (font)); + + if (face) { + + float val; + + TT_OS2 *os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2); + + if (os2 && os2->ySuperscriptYOffset) { + val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySuperscriptYOffset, + face->size->metrics.y_scale); + mMetrics.superscriptOffset = PR_MAX(1, val); + } else { + mMetrics.superscriptOffset = mMetrics.xHeight; + } + + // mSubscriptOffset + if (os2 && os2->ySubscriptYOffset) { + val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySubscriptYOffset, + face->size->metrics.y_scale); + // some fonts have the incorrect sign. + val = (val < 0) ? -val : val; + mMetrics.subscriptOffset = PR_MAX(1, val); + } else { + mMetrics.subscriptOffset = mMetrics.xHeight; + } + + } else { + + mMetrics.superscriptOffset = mMetrics.xHeight; + mMetrics.subscriptOffset = mMetrics.xHeight; + } + pango_font_metrics_unref (pfm); -#endif #if 0 fprintf (stderr, "Font: %s\n", NS_ConvertUTF16toUTF8(mName).get()); @@ -665,66 +500,13 @@ gfxPangoFont::GetMetrics() return mMetrics; } -// XXX we should replace this to |pango_is_zero_width| after we don't support pre pango 1.10 -static PRBool MOZ_pango_is_zero_width(PRUint32 aChar) -{ - if (aChar == 0x00AD) - return PR_TRUE; - if (aChar < 0x200B) - return PR_FALSE; - if (aChar <= 0x200F || aChar == 0x2028) - return PR_TRUE; - if (aChar < 0x202A) - return PR_FALSE; - if (aChar <= 0x202E) - return PR_TRUE; - if (aChar < 0x2060) - return PR_FALSE; - if (aChar <= 0x2063 || aChar == 0xFEFF) - return PR_TRUE; - return PR_FALSE; -} -PRBool -gfxPangoFont::HasGlyph(PRUint32 aChar) -{ - // Ensure that null character should be missing. - if (aChar == 0) - return PR_FALSE; - - if (MOZ_pango_is_zero_width(aChar)) - return PR_TRUE; - - 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; -} - PRUint32 gfxPangoFont::GetGlyph(const PRUint32 aChar) { // Ensure that null character should be missing. if (aChar == 0) return 0; - RealizePangoFont(); - return pango_fc_font_get_glyph(PANGO_FC_FONT(mPangoFont), aChar); + return pango_fc_font_get_glyph(PANGO_FC_FONT(GetPangoFont()), aChar); } nsString @@ -732,16 +514,9 @@ gfxPangoFont::GetUniqueName() { PangoFont *font = GetPangoFont(); PangoFontDescription *desc = pango_font_describe(font); + pango_font_description_unset_fields (desc, PANGO_FONT_MASK_SIZE); char *str = pango_font_description_to_string(desc); - - // chop off the trailing size, e.g. "Albany AMT 15.359375" -> "Albany AMT" - PRUint32 end = strlen(str); - while (end > 0) { - --end; - if (str[end] == ' ') - break; - } - str[end] = 0; + pango_font_description_free (desc); nsString result; CopyUTF8toUTF16(str, result); @@ -749,32 +524,6 @@ gfxPangoFont::GetUniqueName() return result; } -static const char *sCJKLangGroup[] = { - "ja", - "ko", - "zh-CN", - "zh-HK", - "zh-TW" -}; - -#define COUNT_OF_CJK_LANG_GROUP 5 -#define CJK_LANG_JA sCJKLangGroup[0] -#define CJK_LANG_KO sCJKLangGroup[1] -#define CJK_LANG_ZH_CN sCJKLangGroup[2] -#define CJK_LANG_ZH_HK sCJKLangGroup[3] -#define CJK_LANG_ZH_TW sCJKLangGroup[4] - -static PRInt32 -GetCJKLangGroupIndex(const char *aLangGroup) -{ - PRInt32 i; - for (i = 0; i < COUNT_OF_CJK_LANG_GROUP; i++) { - if (!PL_strcasecmp(aLangGroup, sCJKLangGroup[i])) - return i; - } - return -1; -} - /** ** gfxTextRun * @@ -788,19 +537,6 @@ GetCJKLangGroupIndex(const char *aLangGroup) * **/ -/** - * We use this to append an LTR or RTL Override character to the start of the - * string. This forces Pango to honour our direction even if there are neutral characters - * in the string. - */ -static PRInt32 AppendDirectionalIndicatorUTF8(PRBool aIsRTL, nsACString& aString) -{ - static const PRUnichar overrides[2][2] = - { { 0x202d, 0 }, { 0x202e, 0 }}; // LRO, RLO - AppendUTF16toUTF8(overrides[aIsRTL], aString); - return 3; // both overrides map to 3 bytes in UTF8 -} - gfxTextRun * gfxPangoFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength, const Parameters *aParams, PRUint32 aFlags) @@ -812,34 +548,33 @@ gfxPangoFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength, PRBool isRTL = run->IsRightToLeft(); if ((aFlags & TEXT_IS_ASCII) && !isRTL) { - // We don't need to send an override character here, the characters must be all - // LTR const gchar *utf8Chars = reinterpret_cast(aString); - InitTextRun(run, utf8Chars, aLength, 0, PR_TRUE); + InitTextRun(run, utf8Chars, aLength, PR_TRUE); } else { + // this is really gross... const char *chars = reinterpret_cast(aString); - // XXX this could be more efficient. - // Although chars in not necessarily ASCII (as it may point to the low - // bytes of any UCS-2 characters < 256), NS_ConvertASCIItoUTF16 seems - // to DTRT. NS_ConvertASCIItoUTF16 unicodeString(chars, aLength); - nsCAutoString utf8; - PRInt32 headerLen = AppendDirectionalIndicatorUTF8(isRTL, utf8); - AppendUTF16toUTF8(unicodeString, utf8); - InitTextRun(run, utf8.get(), utf8.Length(), headerLen, PR_TRUE); + NS_ConvertUTF16toUTF8 utf8String(unicodeString); + InitTextRun(run, utf8String.get(), utf8String.Length(), PR_TRUE); } + return run; } -static PRBool -CanTakeFastPath(PRUint32 aFlags) +#if defined(ENABLE_FAST_PATH_8BIT) +PRBool +gfxPangoFontGroup::CanTakeFastPath(PRUint32 aFlags) { + if (!PANGO_IS_FC_FONT (GetFontAt(0)->GetPangoFont ())) + return FALSE; + // Can take fast path only if OPTIMIZE_SPEED is set and IS_RTL isn't // We need to always use Pango for RTL text, in case glyph mirroring is required return (aFlags & (gfxTextRunFactory::TEXT_OPTIMIZE_SPEED | gfxTextRunFactory::TEXT_IS_RTL)) == gfxTextRunFactory::TEXT_OPTIMIZE_SPEED; } +#endif gfxTextRun * gfxPangoFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength, @@ -851,11 +586,10 @@ gfxPangoFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength, run->RecordSurrogates(aString); - nsCAutoString utf8; - PRInt32 headerLen = AppendDirectionalIndicatorUTF8(run->IsRightToLeft(), utf8); - AppendUTF16toUTF8(Substring(aString, aString + aLength), utf8); + NS_ConvertUTF16toUTF8 utf8(aString, aLength); PRBool is8Bit = PR_FALSE; -#if defined(ENABLE_XFT_FAST_PATH_8BIT) + +#if defined(ENABLE_FAST_PATH_8BIT) if (CanTakeFastPath(aFlags)) { PRUint32 allBits = 0; PRUint32 i; @@ -865,21 +599,20 @@ gfxPangoFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength, is8Bit = (allBits & 0xFF00) == 0; } #endif - InitTextRun(run, utf8.get(), utf8.Length(), headerLen, is8Bit); + InitTextRun(run, utf8.get(), utf8.Length(), is8Bit); return run; } void gfxPangoFontGroup::InitTextRun(gfxTextRun *aTextRun, const gchar *aUTF8Text, - PRUint32 aUTF8Length, PRUint32 aUTF8HeaderLength, - PRBool aTake8BitPath) + PRUint32 aUTF8Length, PRBool aTake8BitPath) { -#if defined(ENABLE_XFT_FAST_PATH_ALWAYS) - CreateGlyphRunsXft(aTextRun, aUTF8Text + aUTF8HeaderLength, aUTF8Length - aUTF8HeaderLength); +#if defined(ENABLE_FAST_PATH_ALWAYS) + CreateGlyphRunsFast(aTextRun, aUTF8Text, aUTF8Length); #else -#if defined(ENABLE_XFT_FAST_PATH_8BIT) +#if defined(ENABLE_FAST_PATH_8BIT) if (aTake8BitPath && CanTakeFastPath(aTextRun->GetFlags())) { - CreateGlyphRunsXft(aTextRun, aUTF8Text + aUTF8HeaderLength, aUTF8Length - aUTF8HeaderLength); + CreateGlyphRunsFast(aTextRun, aUTF8Text, aUTF8Length); return; } #endif @@ -888,13 +621,20 @@ gfxPangoFontGroup::InitTextRun(gfxTextRun *aTextRun, const gchar *aUTF8Text, (aTextRun->IsRightToLeft() ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR)); - CreateGlyphRunsItemizing(aTextRun, aUTF8Text, aUTF8Length, aUTF8HeaderLength); + CreateGlyphRunsItemizing(aTextRun, aUTF8Text, aUTF8Length); #endif } static cairo_scaled_font_t* CreateScaledFont(cairo_t *aCR, cairo_matrix_t *aCTM, PangoFont *aPangoFont) { +#if 0 +//XXX enalbe this #if defined(PANGO_VERSION_CHECK) && PANGO_VERSION_CHECK(1,17,5) + // Lets just use pango_cairo_font_get_scaled_font() for now. it's only + // available in pango 1.17.x though :( + return cairo_scaled_font_reference (pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (aPangoFont))); +#else + // XXX is this safe really? We should probably check the font type or something. // XXX does this really create the same font that Pango used for measurement? // We probably need to work harder here. We should pay particular attention @@ -913,6 +653,7 @@ CreateScaledFont(cairo_t *aCR, cairo_matrix_t *aCTM, PangoFont *aPangoFont) cairo_font_options_destroy(fontOptions); cairo_font_face_destroy(face); return scaledFont; +#endif } PRBool @@ -951,6 +692,8 @@ SetupClusterBoundaries(gfxTextRun* aTextRun, const gchar *aUTF8, PRUint32 aUTF8L if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) { // 8-bit text doesn't have clusters. // XXX is this true in all languages??? + // behdad: don't think so. Czech for example IIRC has a + // 'ch' grapheme. return; } @@ -1195,8 +938,9 @@ gfxPangoFontGroup::SetGlyphs(gfxTextRun *aTextRun, gfxPangoFont *aFont, gunichar ch = g_utf8_get_char(clusterUTF8); do { // Does pango ever provide more than one glyph in the cluster // if there is a missing glyph? + // behdad: yes if (IS_MISSING_GLYPH(glyphs[glyphIndex].glyph)) { - if (MOZ_pango_is_zero_width(ch)) { + if (pango_is_zero_width(ch)) { // the zero width characters returns empty glyph ID at shaping, // we should override it if the font has the character. glyphs[glyphIndex].glyph = aFont->GetGlyph(' '); @@ -1256,15 +1000,15 @@ gfxPangoFontGroup::SetMissingGlyphs(gfxTextRun *aTextRun, return NS_OK; } -#if defined(ENABLE_XFT_FAST_PATH_8BIT) || defined(ENABLE_XFT_FAST_PATH_ALWAYS) +#if defined(ENABLE_FAST_PATH_8BIT) || defined(ENABLE_FAST_PATH_ALWAYS) void -gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun, - const gchar *aUTF8, PRUint32 aUTF8Length) +gfxPangoFontGroup::CreateGlyphRunsFast(gfxTextRun *aTextRun, + const gchar *aUTF8, PRUint32 aUTF8Length) { const gchar *p = aUTF8; - Display *dpy = GDK_DISPLAY(); gfxPangoFont *font = GetFontAt(0); - XftFont *xfont = font->GetXftFont(); + PangoFont *pangofont = font->GetPangoFont(); + PangoFcFont *fcfont = PANGO_FC_FONT (pangofont); PRUint32 utf16Offset = 0; gfxTextRun::CompressedGlyph g; const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit(); @@ -1285,14 +1029,11 @@ gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun, aTextRun->SetMissingGlyph(utf16Offset, 0); } else { NS_ASSERTION(!IsInvalidChar(ch), "Invalid char detected"); - FT_UInt glyph = XftCharIndex(dpy, xfont, ch); - XGlyphInfo info; - XftGlyphExtents(dpy, xfont, &glyph, 1, &info); - if (info.yOff > 0) { - NS_WARNING("vertical offsets not supported"); - } + FT_UInt glyph = pango_fc_font_get_glyph (fcfont, ch); + PangoRectangle rect; + pango_font_get_glyph_extents (pangofont, glyph, NULL, &rect); - PRInt32 advance = info.xOff*appUnitsPerDevUnit; + PRInt32 advance = PANGO_PIXELS (rect.width * appUnitsPerDevUnit); if (advance >= 0 && gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) && gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph)) { @@ -1326,288 +1067,39 @@ gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun, } #endif -class FontSelector -{ -public: - FontSelector(const gchar *aString, PRInt32 aLength, - gfxPangoFontGroup *aGroup, gfxTextRun *aTextRun, - PangoItem *aItem, PRUint32 aUTF16Offset, PRPackedBool aIsRTL) : - mItem(aItem), - mGroup(aGroup), mTextRun(aTextRun), mString(aString), - mFontIndex(0), mLength(aLength), mUTF16Offset(aUTF16Offset), - mTriedPrefFonts(0), mTriedOtherFonts(0), mIsRTL(aIsRTL) - { - for (PRUint32 i = 0; i < mGroup->FontListLength(); ++i) - mFonts.AppendElement(mGroup->GetFontAt(i)); - mSpaceWidth = NS_lround(mGroup->GetFontAt(0)->GetMetrics().spaceWidth * FLOAT_PANGO_SCALE); - } - - nsresult Run() - { - return InitSegments(mString, mLength); - } - - PRUint32 GetUTF16Offset() { return mUTF16Offset; } - - static PRBool ExistsFont(FontSelector *aFs, - const nsAString &aName) { - PRUint32 len = aFs->mFonts.Length(); - for (PRUint32 i = 0; i < len; ++i) { - if (aName.Equals(aFs->mFonts[i]->GetName())) - return PR_TRUE; - } - return PR_FALSE; - } - - static PRBool AddFontCallback(const nsAString &aName, - const nsACString &aGenericName, - void *closure) { - if (aName.IsEmpty()) - return PR_TRUE; - - FontSelector *fs = static_cast(closure); - - // XXX do something better than this to remove dups - if (ExistsFont(fs, aName)) - return PR_TRUE; - - nsRefPtr font = GetOrMakeFont(aName, fs->mGroup->GetStyle()); - if (font) { - fs->mFonts.AppendElement(font); - } - - return PR_TRUE; - } - -private: - PangoItem *mItem; - - nsTArray< nsRefPtr > mFonts; - - gfxPangoFontGroup *mGroup; - gfxTextRun *mTextRun; - const char *mString; // UTF-8 - PRUint32 mFontIndex; - PRInt32 mLength; - PRUint32 mUTF16Offset; - PRUint32 mSpaceWidth; - - PRPackedBool mTriedPrefFonts; - PRPackedBool mTriedOtherFonts; - PRPackedBool mIsRTL; - - nsresult InitSegments(const gchar *aUTF8, PRUint32 aLength) { - if (aLength == 0) - return NS_OK; - const gchar *start = aUTF8; - const gchar *last = start + aLength; - -RetryNextFont: - nsRefPtr font = GetNextFont(); - - // If we cannot found the font that has the current character glyph, - // we should return default font's missing data. - if (!font) - return AppendMissingSegment(start, last - start); - - 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; - } - - 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; - mItem->analysis.font = pf; - pango_shape(aUTF8, aLength, &mItem->analysis, glyphString); - mItem->analysis.font = tmpFont; - - nsresult rv = mTextRun->AddGlyphRun(aFont, mUTF16Offset); - if (NS_FAILED(rv)) { - NS_ERROR("AddGlyphRun Failed"); - pango_glyph_string_free(glyphString); - return rv; - } - PRUint32 utf16Offset = mUTF16Offset; - rv = mGroup->SetGlyphs(mTextRun, aFont, aUTF8, aLength, - &utf16Offset, glyphString, mSpaceWidth, PR_FALSE); - 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() { -TRY_AGAIN_HOPE_FOR_THE_BEST_2: - if (mFontIndex < mFonts.Length()) { - return mFonts[mFontIndex++]; - } else if (!mTriedPrefFonts) { - mTriedPrefFonts = PR_TRUE; - nsCAutoString mozLang; - GetMozLanguage(mItem->analysis.language, mozLang); - if (!mozLang.IsEmpty()) { - PRInt32 index = GetCJKLangGroupIndex(mozLang.get()); - if (index >= 0) - AppendCJKPrefFonts(); - else - AppendPrefFonts(mozLang.get()); - } else { - NS_ConvertUTF8toUTF16 str(mString); - PRBool appenedCJKFonts = PR_FALSE; - for (PRUint32 i = 0; i < str.Length(); ++i) { - const PRUnichar ch = str[i]; - PRUint32 unicodeRange = FindCharUnicodeRange(ch); - - /* special case CJK */ - if (unicodeRange == kRangeSetCJK) { - if (!appenedCJKFonts) { - appenedCJKFonts = PR_TRUE; - AppendCJKPrefFonts(); - } - } else { - const char *langGroup = - LangGroupFromUnicodeRange(unicodeRange); - if (langGroup) - AppendPrefFonts(langGroup); - } - } - } - goto TRY_AGAIN_HOPE_FOR_THE_BEST_2; - } else if (!mTriedOtherFonts) { - mTriedOtherFonts = PR_TRUE; - // XXX we should try by all system fonts - goto TRY_AGAIN_HOPE_FOR_THE_BEST_2; - } - return nsnull; - } - - void AppendPrefFonts(const char *aLangGroup) { - NS_ASSERTION(aLangGroup, "aLangGroup is null"); - gfxPlatform *platform = gfxPlatform::GetPlatform(); - nsString fonts; - platform->GetPrefFonts(aLangGroup, fonts); - if (fonts.IsEmpty()) - return; - gfxFontGroup::ForEachFont(fonts, nsDependentCString(aLangGroup), - FontSelector::AddFontCallback, this); - return; - } - - void AppendCJKPrefFonts() { - nsCOMPtr prefs = - do_GetService(NS_PREFSERVICE_CONTRACTID); - if (!prefs) - return; - - nsCOMPtr prefBranch; - prefs->GetBranch(0, getter_AddRefs(prefBranch)); - if (!prefBranch) - return; - - // Add the accept languages. - nsXPIDLCString list; - nsresult rv = prefBranch->GetCharPref("intl.accept_languages", - getter_Copies(list)); - if (NS_SUCCEEDED(rv) && !list.IsEmpty()) { - const char kComma = ','; - const char *p, *p_end; - list.BeginReading(p); - list.EndReading(p_end); - while (p < p_end) { - while (nsCRT::IsAsciiSpace(*p)) { - if (++p == p_end) - break; - } - if (p == p_end) - break; - const char *start = p; - while (++p != p_end && *p != kComma) - /* nothing */ ; - nsCAutoString lang(Substring(start, p)); - lang.CompressWhitespace(PR_FALSE, PR_TRUE); - PRInt32 index = GetCJKLangGroupIndex(lang.get()); - if (index >= 0) - AppendPrefFonts(sCJKLangGroup[index]); - p++; - } - } - - // XXX I think that we should append system locale here if it is CJK. - - // last resort... - AppendPrefFonts(CJK_LANG_JA); - AppendPrefFonts(CJK_LANG_KO); - AppendPrefFonts(CJK_LANG_ZH_CN); - AppendPrefFonts(CJK_LANG_ZH_HK); - AppendPrefFonts(CJK_LANG_ZH_TW); - } -}; - void gfxPangoFontGroup::CreateGlyphRunsItemizing(gfxTextRun *aTextRun, - const gchar *aUTF8, PRUint32 aUTF8Length, - PRUint32 aUTF8HeaderLen) + const gchar *aUTF8, PRUint32 aUTF8Length) { - GList *items = pango_itemize(GetFontAt(0)->GetPangoContext(), aUTF8, 0, - aUTF8Length, nsnull, nsnull); - + + PangoContext *context = gdk_pango_context_get (); + + PangoFontDescription *fontDesc = pango_font_description_new(); + + // these should be FontEntries or something similar rather than gfxPangoFonts... + nsString fontList; + + for (PRUint32 i = 0; i < mFonts.Length(); i++) { + fontList.Append(mFonts[i]->GetName()); + fontList.Append(NS_LITERAL_STRING(", ")); + } + + PangoLanguage *lang = GetPangoLanguage(GetStyle()->langGroup); + + pango_font_description_set_family(fontDesc, NS_ConvertUTF16toUTF8(fontList).get()); + pango_font_description_set_absolute_size(fontDesc, GetStyle()->size * PANGO_SCALE); + pango_font_description_set_style(fontDesc, ThebesStyleToPangoStyle(GetStyle())); + pango_font_description_set_weight(fontDesc, ThebesStyleToPangoWeight(GetStyle())); + + pango_context_set_font_description(context, fontDesc); + + // we should set this to null if we don't have a text language from the page... + // except that we almost always have something... + pango_context_set_language(context, lang); + + PangoDirection dir = aTextRun->IsRightToLeft() ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; + GList *items = pango_itemize_with_base_dir(context, dir, aUTF8, 0, aUTF8Length, nsnull, nsnull); + PRUint32 utf16Offset = 0; PRBool isRTL = aTextRun->IsRightToLeft(); GList *pos = items; @@ -1617,29 +1109,51 @@ gfxPangoFontGroup::CreateGlyphRunsItemizing(gfxTextRun *aTextRun, PRUint32 offset = item->offset; PRUint32 length = item->length; - if (offset < aUTF8HeaderLen) { - if (offset + length <= aUTF8HeaderLen) { - pango_item_free(item); - continue; - } - length -= aUTF8HeaderLen - offset; - offset = aUTF8HeaderLen; - } - + + // need to append glyph runs here. + PangoGlyphString *glyphString = pango_glyph_string_new(); + if (!glyphString) + return; // OOM + + pango_shape(aUTF8 + offset, length, &item->analysis, glyphString); + + /* look up the gfxPangoFont from the PangoFont */ + // XXX we need a function to do this.. until then do this + // behdad: use g_object_[sg]et_qdata() for it. + PangoFontDescription *d = pango_font_describe(item->analysis.font); + nsRefPtr font = GetOrMakeFont(NS_ConvertUTF8toUTF16(pango_font_description_get_family(d)), GetStyle()); + + //printf("Using %s\n", pango_font_description_get_family(d)); + + pango_font_description_free(d); SetupClusterBoundaries(aTextRun, aUTF8 + offset, length, utf16Offset, &item->analysis); - FontSelector fs(aUTF8 + offset, length, this, aTextRun, item, utf16Offset, isRTL); - fs.Run(); // appends GlyphRuns - utf16Offset = fs.GetUTF16Offset(); - pango_item_free(item); + + nsresult rv = aTextRun->AddGlyphRun(font, utf16Offset, PR_TRUE); + if (NS_FAILED(rv)) { + NS_ERROR("AddGlyphRun Failed"); + pango_glyph_string_free(glyphString); + return; + } + + PRUint32 spaceWidth = NS_lround(font->GetMetrics().spaceWidth * FLOAT_PANGO_SCALE); + + rv = SetGlyphs(aTextRun, font, aUTF8 + offset, length, &utf16Offset, glyphString, spaceWidth, PR_FALSE); + + pango_glyph_string_free(glyphString); } - NS_ASSERTION(utf16Offset == aTextRun->GetLength(), - "Didn't resolve all characters"); - if (items) g_list_free(items); + + pango_font_description_free(fontDesc); + + g_object_unref(context); + + aTextRun->SortGlyphRuns(); } + + /** ** language group helpers **/ @@ -1708,7 +1222,7 @@ GetPangoLanguage(const nsACString& cname) else if (langGroup->PangoLang) return pango_language_from_string(langGroup->PangoLang); - return pango_language_from_string("en"); + return nsnull; } // See pango-script-lang-table.h in pango. @@ -1892,38 +1406,7 @@ static const MozPangoLangGroup PangoAllLangGroup[] = { { "x-western", "zu" }, }; -#define NUM_PANGO_ALL_LANG_GROUPS (sizeof (PangoAllLangGroup) / \ - sizeof (PangoAllLangGroup[0])) - -/* static */ -void -GetMozLanguage(const PangoLanguage *aLang, nsACString &aMozLang) -{ - aMozLang.Truncate(); - if (!aLang) - return; - - nsCAutoString lang(pango_language_to_string(aLang)); - if (lang.IsEmpty() || lang.Equals("xx")) - return; - - while (1) { - for (PRUint32 i = 0; i < NUM_PANGO_ALL_LANG_GROUPS; ++i) { - if (lang.Equals(PangoAllLangGroup[i].PangoLang)) { - if (PangoAllLangGroup[i].mozLangGroup) - aMozLang.Assign(PangoAllLangGroup[i].mozLangGroup); - return; - } - } - - PRInt32 hyphen = lang.FindChar('-'); - if (hyphen != kNotFound) { - lang.Cut(hyphen, lang.Length()); - continue; - } - break; - } -} +#define NUM_PANGO_ALL_LANG_GROUPS (G_N_ELEMENTS (PangoAllLangGroup)) gfxPangoFontCache::gfxPangoFontCache() { @@ -1957,39 +1440,3 @@ gfxPangoFontCache::Get(const PangoFontDescription *aFontDesc) 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; -} diff --git a/gfx/thebes/src/gfxPlatformGtk.cpp b/gfx/thebes/src/gfxPlatformGtk.cpp index 4d5f4e06e3d..826f997094e 100644 --- a/gfx/thebes/src/gfxPlatformGtk.cpp +++ b/gfx/thebes/src/gfxPlatformGtk.cpp @@ -60,12 +60,6 @@ #include -#ifndef THEBES_USE_PANGO_CAIRO -#include -#endif // THEBES_USE_PANGO_CAIRO - -#include - #include "nsMathUtils.h" #include "lcms.h" @@ -89,6 +83,8 @@ gfxPlatformGtk::gfxPlatformGtk() #endif if (!sFontconfigUtils) sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils(); + + InitDPI(); } gfxPlatformGtk::~gfxPlatformGtk() @@ -98,10 +94,6 @@ gfxPlatformGtk::~gfxPlatformGtk() gfxPangoFont::Shutdown(); -#ifndef THEBES_USE_PANGO_CAIRO - pango_xft_shutdown_display(GDK_DISPLAY(), 0); -#endif - #if 0 // It would be nice to do this (although it might need to be after // the cairo shutdown that happens in ~gfxPlatform). It even looks @@ -278,93 +270,17 @@ gfxPlatformGtk::CreateFontGroup(const nsAString &aFamilies, return new gfxPangoFontGroup(aFamilies, aStyle); } -static PRInt32 -GetXftDPI() -{ - char *val = XGetDefault(GDK_DISPLAY(), "Xft", "dpi"); - if (val) { - char *e; - double d = strtod(val, &e); - - if (e != val) - return NS_lround(d); - } - - return -1; -} - -static PRInt32 -GetDPIFromPangoFont() -{ -#ifndef THEBES_USE_PANGO_CAIRO - PangoContext* ctx = pango_xft_get_context(GDK_DISPLAY(), 0); - gdk_pango_context_set_colormap(ctx, gdk_rgb_get_cmap()); -#else - PangoContext* ctx = - pango_cairo_font_map_create_context( - PANGO_CAIRO_FONT_MAP(pango_cairo_font_map_get_default())); -#endif - - if (!ctx) { - return 0; - } - - double dblDPI = 0.0f; - GList *items = nsnull; - PangoItem *item = nsnull; - PangoFcFont *fcfont = nsnull; - - PangoAttrList *al = pango_attr_list_new(); - - if (!al) { - goto cleanup; - } - - // Just using the string "a" because we need _some_ text. - items = pango_itemize(ctx, "a", 0, 1, al, NULL); - - if (!items) { - goto cleanup; - } - - item = (PangoItem*)items->data; - - if (!item) { - goto cleanup; - } - - fcfont = PANGO_FC_FONT(item->analysis.font); - - if (!fcfont) { - goto cleanup; - } - - FcPatternGetDouble(fcfont->font_pattern, FC_DPI, 0, &dblDPI); - - cleanup: - if (al) - pango_attr_list_unref(al); - if (item) - pango_item_free(item); - if (items) - g_list_free(items); - if (ctx) - g_object_unref(ctx); - - return NS_lround(dblDPI); -} - /* static */ void gfxPlatformGtk::InitDPI() { - sDPI = GetXftDPI(); + PangoContext *context = gdk_pango_context_get (); + sDPI = pango_cairo_context_get_resolution (context); + g_object_unref (context); + if (sDPI <= 0) { - sDPI = GetDPIFromPangoFont(); - if (sDPI <= 0) { - // Fall back to something sane - sDPI = 96; - } + // Fall back to something sane + sDPI = 96; } }