# This is a shell script that calls functions and scripts from # tml@iki.fi's personal work environment. It is not expected to be # usable unmodified by others, and is included only for reference. MOD=pango VER=1.28.1 REV=2 ARCH=win32 THIS=${MOD}_${VER}-${REV}_${ARCH} RUNZIP=${MOD}_${VER}-${REV}_${ARCH}.zip DEVZIP=${MOD}-dev_${VER}-${REV}_${ARCH}.zip HEX=`echo $THIS | md5sum | cut -d' ' -f1` TARGET=c:/devel/target/$HEX usedev usemsvs6 ( set -x patch --verbose --fuzz=0 -p1 <<'EOF' commit ed4732969da2219e36c5c74193886637439bb2e9 Author: Tor Lillqvist Date: Sat Sep 11 15:17:19 2010 +0300 Improve performance on Windows especially for non-Latin scripts The use of Uniscribe script caches was decidedly suboptimal. Use one persistent SCRIPT_CACHE per Win32 font and script. Patch by by David E. Hollingsworth and Fredrik Corneliusson, from bug #621869. diff --git a/modules/basic/basic-win32.c b/modules/basic/basic-win32.c index ecb139e..e1ef376 100644 --- a/modules/basic/basic-win32.c +++ b/modules/basic/basic-win32.c @@ -33,6 +33,8 @@ #include "pango-engine.h" #include "pango-utils.h" +extern HFONT _pango_win32_font_get_hfont (PangoFont *font); + /* No extra fields needed */ typedef PangoEngineShape BasicEngineWin32; typedef PangoEngineShapeClass BasicEngineWin32Class ; @@ -495,8 +497,7 @@ itemize_shape_and_place (PangoFont *font, wchar_t *wtext, int wlen, const PangoAnalysis *analysis, - PangoGlyphString *glyphs, - SCRIPT_CACHE *script_cache) + PangoGlyphString *glyphs) { int i; int item, nitems, item_step; @@ -505,6 +506,11 @@ itemize_shape_and_place (PangoFont *font, SCRIPT_STATE state; SCRIPT_ITEM items[100]; double scale = pango_win32_font_get_metrics_factor (font); + HFONT hfont = _pango_win32_font_get_hfont (font); + static GHashTable *script_cache_hash = NULL; + + if (!script_cache_hash) + script_cache_hash = g_hash_table_new (g_int64_hash, g_int64_equal); memset (&control, 0, sizeof (control)); memset (&state, 0, sizeof (state)); @@ -551,9 +557,11 @@ itemize_shape_and_place (PangoFont *font, int advances[1000]; GOFFSET offsets[1000]; ABC abc; - int script = items[item].a.eScript; + gint32 script = items[item].a.eScript; int ng; int char_offset; + SCRIPT_CACHE *script_cache; + gint64 font_and_script_key; memset (advances, 0, sizeof (advances)); memset (offsets, 0, sizeof (offsets)); @@ -579,9 +587,33 @@ itemize_shape_and_place (PangoFont *font, items[item].a.fNoGlyphIndex ? " fNoGlyphIndex" : "", items[item].iCharPos, items[item+1].iCharPos-1, itemlen); #endif + /* Create a hash key based on hfont and script engine */ + font_and_script_key = (((gint64) ((gint32) hfont)) << 32) | script; + + /* Get the script cache for this hfont and script */ + script_cache = g_hash_table_lookup (script_cache_hash, &font_and_script_key); + if (!script_cache) + { + gint64 *key_n; + SCRIPT_CACHE *new_script_cache; + + key_n = g_new (gint64, 1); + *key_n = font_and_script_key; + + new_script_cache = g_new0 (SCRIPT_CACHE, 1); + script_cache = new_script_cache; + + /* Insert the new value */ + g_hash_table_insert (script_cache_hash, key_n, new_script_cache); + +#ifdef BASIC_WIN32_DEBUGGING + if (pango_win32_debug) + g_print (" New SCRIPT_CACHE for font %p and script %d\n", hfont, script); +#endif + } items[item].a.fRTL = analysis->level % 2; - if ((*script_shape) (hdc, &script_cache[script], + if ((*script_shape) (hdc, script_cache, wtext + items[item].iCharPos, itemlen, G_N_ELEMENTS (iglyphs), &items[item].a, @@ -611,7 +643,7 @@ itemize_shape_and_place (PangoFont *font, nglyphs, glyphs->log_clusters + ng, char_offset); - if ((*script_place) (hdc, &script_cache[script], iglyphs, nglyphs, + if ((*script_place) (hdc, script_cache, iglyphs, nglyphs, visattrs, &items[item].a, advances, offsets, &abc)) { @@ -671,9 +703,7 @@ uniscribe_shape (PangoFont *font, { wchar_t *wtext; long wlen; - int i; gboolean retval = TRUE; - SCRIPT_CACHE script_cache[100]; if (!pango_win32_font_select_font (font, hdc)) return FALSE; @@ -684,11 +714,7 @@ uniscribe_shape (PangoFont *font, if (retval) { - memset (script_cache, 0, sizeof (script_cache)); - retval = itemize_shape_and_place (font, hdc, wtext, wlen, analysis, glyphs, script_cache); - for (i = 0; i < G_N_ELEMENTS (script_cache); i++) - if (script_cache[i]) - (*script_free_cache)(&script_cache[i]); + retval = itemize_shape_and_place (font, hdc, wtext, wlen, analysis, glyphs); } if (retval) diff --git a/pango/pangowin32-private.h b/pango/pangowin32-private.h index 9f35823..73df2e9 100644 --- a/pango/pangowin32-private.h +++ b/pango/pangowin32-private.h @@ -129,11 +129,8 @@ struct _PangoWin32Font PangoFontMap *fontmap; - /* Written by pango_win32_get_hfont: */ + /* Written by _pango_win32_font_get_hfont: */ HFONT hfont; - gint tm_ascent; - gint tm_descent; - gint tm_overhang; PangoWin32Face *win32face; @@ -275,6 +272,8 @@ gboolean _pango_win32_get_name_record (HDC hdc, gint i, struct name_record *record); +HFONT _pango_win32_font_get_hfont (PangoFont *font); + extern HDC _pango_win32_hdc; extern OSVERSIONINFO _pango_win32_os_version_info; extern gboolean _pango_win32_debug; diff --git a/pango/pangowin32.c b/pango/pangowin32.c index 1f8c1d2..30ec8b6 100644 --- a/pango/pangowin32.c +++ b/pango/pangowin32.c @@ -74,7 +74,6 @@ static gboolean pango_win32_font_real_select_font (PangoFont *font, static void pango_win32_font_real_done_font (PangoFont *font); static double pango_win32_font_real_get_metrics_factor (PangoFont *font); -static HFONT pango_win32_get_hfont (PangoFont *font); static void pango_win32_get_item_properties (PangoItem *item, PangoUnderline *uline, PangoAttrColor *fg_color, @@ -82,12 +81,11 @@ static void pango_win32_get_item_properties (PangoItem PangoAttrColor *bg_color, gboolean *bg_set); -static HFONT -pango_win32_get_hfont (PangoFont *font) +HFONT +_pango_win32_font_get_hfont (PangoFont *font) { PangoWin32Font *win32font = (PangoWin32Font *)font; PangoWin32FontCache *cache; - TEXTMETRIC tm; if (!win32font) return NULL; @@ -105,13 +103,6 @@ pango_win32_get_hfont (PangoFont *font) g_free (face_utf8); return NULL; } - - SelectObject (_pango_win32_hdc, win32font->hfont); - GetTextMetrics (_pango_win32_hdc, &tm); - - win32font->tm_overhang = tm.tmOverhang; - win32font->tm_descent = tm.tmDescent; - win32font->tm_ascent = tm.tmAscent; } return win32font->hfont; @@ -261,7 +252,7 @@ pango_win32_render (HDC hdc, if (glyphs->num_glyphs == 0) return; - hfont = pango_win32_get_hfont (font); + hfont = _pango_win32_font_get_hfont (font); if (!hfont) return; @@ -440,6 +431,7 @@ pango_win32_font_get_glyph_extents (PangoFont *font, PangoWin32Font *win32font = (PangoWin32Font *)font; guint16 glyph_index = glyph; GLYPHMETRICS gm; + TEXTMETRIC tm; guint32 res; HFONT hfont; MAT2 m = {{0,1}, {0,0}, {0,0}, {0,1}}; @@ -465,7 +457,7 @@ pango_win32_font_get_glyph_extents (PangoFont *font, memset (&gm, 0, sizeof (gm)); - hfont = pango_win32_get_hfont (font); + hfont = _pango_win32_font_get_hfont (font); SelectObject (_pango_win32_hdc, hfont); /* FIXME: (Alex) This constant reuse of _pango_win32_hdc is not thread-safe */ @@ -491,10 +483,11 @@ pango_win32_font_get_glyph_extents (PangoFont *font, info->ink_rect.y = - PANGO_SCALE * gm.gmptGlyphOrigin.y; info->ink_rect.height = PANGO_SCALE * gm.gmBlackBoxY; + GetTextMetrics (_pango_win32_hdc, &tm); info->logical_rect.x = 0; info->logical_rect.width = PANGO_SCALE * gm.gmCellIncX; - info->logical_rect.y = - PANGO_SCALE * win32font->tm_ascent; - info->logical_rect.height = PANGO_SCALE * (win32font->tm_ascent + win32font->tm_descent); + info->logical_rect.y = - PANGO_SCALE * tm.tmAscent; + info->logical_rect.height = PANGO_SCALE * (tm.tmAscent + tm.tmDescent); g_hash_table_insert (win32font->glyph_info, GUINT_TO_POINTER(glyph), info); } @@ -562,7 +555,7 @@ pango_win32_font_get_metrics (PangoFont *font, info->sample_str = sample_str; info->metrics = metrics = pango_font_metrics_new (); - hfont = pango_win32_get_hfont (font); + hfont = _pango_win32_font_get_hfont (font); if (hfont != NULL) { PangoCoverage *coverage; @@ -626,7 +619,7 @@ static gboolean pango_win32_font_real_select_font (PangoFont *font, HDC hdc) { - HFONT hfont = pango_win32_get_hfont (font); + HFONT hfont = _pango_win32_font_get_hfont (font); if (!hfont) return FALSE; @@ -1611,7 +1604,7 @@ font_has_name_in (PangoFont *font, if (cjkv == PANGO_WIN32_COVERAGE_UNSPEC) return TRUE; - hfont = pango_win32_get_hfont (font); + hfont = _pango_win32_font_get_hfont (font); oldhfont = SelectObject (_pango_win32_hdc, hfont); if (!_pango_win32_get_name_header (_pango_win32_hdc, &header)) diff --git a/pango/pangowin32.def b/pango/pangowin32.def index 13b6e8b..ec8e8b2 100644 --- a/pango/pangowin32.def +++ b/pango/pangowin32.def @@ -3,6 +3,7 @@ EXPORTS _pango_win32_make_matching_logfontw _pango_win32_font_get_type _pango_win32_font_map_get_type + _pango_win32_font_get_hfont pango_win32_font_cache_free pango_win32_font_cache_load pango_win32_font_cache_loadw commit 75f0db89f7a4d0bd2948d27134913b9f2af02533 Author: Tor Lillqvist Date: Sat Sep 11 14:52:28 2010 +0300 Reduce DLL hijack risk and simplify code in basic-win32 module Dont load usp10.dll dynamically with LoadLibrary(). Just link to the Uniscribe API directly. MinGW comes with an import library so no problem with that either. The Uniscribe DLL is present on all versions of Windows we care for. diff --git a/modules/basic/Makefile.am b/modules/basic/Makefile.am index acd0c4d..93604c9 100644 --- a/modules/basic/Makefile.am +++ b/modules/basic/Makefile.am @@ -47,7 +47,8 @@ endif endif pango_basic_win32_la_LDFLAGS = -module $(MODULE_LIBTOOL_OPTIONS) -pango_basic_win32_la_LIBADD = $(pangowin32libs) -lgdi32 +pango_basic_win32_la_LIBADD = $(pangowin32libs) -lgdi32 -lusp10 +libpango_basic_win32_la_LIBADD = -lgdi32 -lusp10 pango_basic_win32_la_SOURCES = basic-win32.c libpango_basic_win32_la_SOURCES = basic-win32.c libpango_basic_win32_la_CFLAGS = -DPANGO_MODULE_PREFIX=_pango_basic_win32 diff --git a/modules/basic/basic-win32.c b/modules/basic/basic-win32.c index e1ef376..a7f1c90 100644 --- a/modules/basic/basic-win32.c +++ b/modules/basic/basic-win32.c @@ -45,55 +45,8 @@ static gboolean pango_win32_debug = FALSE; #include -static gboolean have_uniscribe = FALSE; - static HDC hdc; -typedef HRESULT (WINAPI *pScriptGetProperties) (const SCRIPT_PROPERTIES ***, - int *); - -typedef HRESULT (WINAPI *pScriptItemize) (const WCHAR *, - int, - int, - const SCRIPT_CONTROL *, - const SCRIPT_STATE *, - SCRIPT_ITEM *, - int *); - -typedef HRESULT (WINAPI *pScriptShape) (HDC, - SCRIPT_CACHE *, - const WCHAR *, - int, - int, - SCRIPT_ANALYSIS *, - WORD *, - WORD *, - SCRIPT_VISATTR *, - int *); - -typedef HRESULT (WINAPI *pScriptPlace) (HDC, - SCRIPT_CACHE *, - const WORD *, - int, - const SCRIPT_VISATTR *, - SCRIPT_ANALYSIS *, - int *, - GOFFSET *, - ABC *); - -typedef HRESULT (WINAPI *pScriptFreeCache) (SCRIPT_CACHE *); - -typedef HRESULT (WINAPI *pScriptIsComplex) (WCHAR *, - int, - DWORD); - -static pScriptGetProperties script_get_properties; -static pScriptItemize script_itemize; -static pScriptShape script_shape; -static pScriptPlace script_place; -static pScriptFreeCache script_free_cache; -static pScriptIsComplex script_is_complex; - #ifdef BASIC_WIN32_DEBUGGING static const SCRIPT_PROPERTIES **scripts; static int nscripts; @@ -523,8 +476,8 @@ itemize_shape_and_place (PangoFont *font, g_print (G_STRLOC ": ScriptItemize: uDefaultLanguage:%04x uBidiLevel:%d\n", control.uDefaultLanguage, state.uBidiLevel); #endif - if ((*script_itemize) (wtext, wlen, G_N_ELEMENTS (items), &control, NULL, - items, &nitems)) + if (ScriptItemize (wtext, wlen, G_N_ELEMENTS (items), &control, NULL, + items, &nitems)) { #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) @@ -613,14 +566,14 @@ itemize_shape_and_place (PangoFont *font, } items[item].a.fRTL = analysis->level % 2; - if ((*script_shape) (hdc, script_cache, - wtext + items[item].iCharPos, itemlen, - G_N_ELEMENTS (iglyphs), - &items[item].a, - iglyphs, - log_clusters, - visattrs, - &nglyphs)) + if (ScriptShape (hdc, script_cache, + wtext + items[item].iCharPos, itemlen, + G_N_ELEMENTS (iglyphs), + &items[item].a, + iglyphs, + log_clusters, + visattrs, + &nglyphs)) { #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) @@ -643,9 +596,9 @@ itemize_shape_and_place (PangoFont *font, nglyphs, glyphs->log_clusters + ng, char_offset); - if ((*script_place) (hdc, script_cache, iglyphs, nglyphs, - visattrs, &items[item].a, - advances, offsets, &abc)) + if (ScriptPlace (hdc, script_cache, iglyphs, nglyphs, + visattrs, &items[item].a, + advances, offsets, &abc)) { #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) @@ -752,7 +705,7 @@ text_is_simple (const char *text, if (wtext == NULL) return TRUE; - retval = ((*script_is_complex) (wtext, wlen, SIC_COMPLEX) == S_FALSE); + retval = (ScriptIsComplex (wtext, wlen, SIC_COMPLEX) == S_FALSE); g_free (wtext); @@ -782,8 +735,7 @@ basic_engine_shape (PangoEngineShape *engine, g_return_if_fail (length >= 0); g_return_if_fail (analysis != NULL); - if (have_uniscribe && - !text_is_simple (text, length) && + if (!text_is_simple (text, length) && uniscribe_shape (font, text, length, analysis, glyphs)) return; @@ -872,33 +824,10 @@ basic_engine_shape (PangoEngineShape *engine, static void init_uniscribe (void) { - HMODULE usp10_dll; - - have_uniscribe = FALSE; - - if ((usp10_dll = LoadLibrary ("usp10.dll")) != NULL) - { - (script_get_properties = (pScriptGetProperties) - GetProcAddress (usp10_dll, "ScriptGetProperties")) && - (script_itemize = (pScriptItemize) - GetProcAddress (usp10_dll, "ScriptItemize")) && - (script_shape = (pScriptShape) - GetProcAddress (usp10_dll, "ScriptShape")) && - (script_place = (pScriptPlace) - GetProcAddress (usp10_dll, "ScriptPlace")) && - (script_free_cache = (pScriptFreeCache) - GetProcAddress (usp10_dll, "ScriptFreeCache")) && - (script_is_complex = (pScriptIsComplex) - GetProcAddress (usp10_dll, "ScriptIsComplex")) && - (have_uniscribe = TRUE); - } - if (have_uniscribe) - { #ifdef BASIC_WIN32_DEBUGGING - (*script_get_properties) (&scripts, &nscripts); + ScriptGetProperties (&scripts, &nscripts); #endif - hdc = pango_win32_get_dc (); - } + hdc = pango_win32_get_dc (); } static void @@ -935,28 +864,25 @@ PANGO_MODULE_ENTRY(list) (PangoEngineInfo **engines, script_engines[0].scripts = basic_scripts; script_engines[0].n_scripts = G_N_ELEMENTS (basic_scripts); - if (have_uniscribe) - { #if 0 - int i; - GArray *ranges = g_array_new (FALSE, FALSE, sizeof (PangoEngineRange)); + int i; + GArray *ranges = g_array_new (FALSE, FALSE, sizeof (PangoEngineRange)); - /* Walk through scripts supported by the Uniscribe implementation on this - * machine, and mark corresponding Unicode ranges. - */ - for (i = 0; i < nscripts; i++) - { - } + /* Walk through scripts supported by the Uniscribe implementation on this + * machine, and mark corresponding Unicode ranges. + */ + for (i = 0; i < nscripts; i++) + { + } - /* Sort range array */ - g_array_sort (ranges, compare_range); - script_engines[0].ranges = ranges; - script_engines[0].n_ranges = ranges->len; + /* Sort range array */ + g_array_sort (ranges, compare_range); + script_engines[0].ranges = ranges; + script_engines[0].n_ranges = ranges->len; #else - script_engines[0].scripts = uniscribe_scripts; - script_engines[0].n_scripts = G_N_ELEMENTS (uniscribe_scripts); + script_engines[0].scripts = uniscribe_scripts; + script_engines[0].n_scripts = G_N_ELEMENTS (uniscribe_scripts); #endif - } *engines = script_engines; *n_engines = G_N_ELEMENTS (script_engines); EOF patch -p0 --verbose <<'EOF' --- modules/basic/Makefile.in +++ modules/basic/Makefile.in @@ -101,7 +101,7 @@ $(libpango_basic_fc_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ @HAVE_FREETYPE_TRUE@@INCLUDE_BASIC_FC_TRUE@am_libpango_basic_fc_la_rpath = -libpango_basic_win32_la_LIBADD = +libpango_basic_win32_la_LIBADD = -lgdi32 -lusp10 am_libpango_basic_win32_la_OBJECTS = \ libpango_basic_win32_la-basic-win32.lo libpango_basic_win32_la_OBJECTS = \ EOF DEPS=`latest --arch=${ARCH} glib pkg-config zlib libpng pixman cairo expat fontconfig freetype` PROXY_LIBINTL=`latest --arch=${ARCH} proxy-libintl` PKG_CONFIG_PATH=/dummy for D in $DEPS; do PKG_CONFIG_PATH=/devel/dist/${ARCH}/$D/lib/pkgconfig:$PKG_CONFIG_PATH PATH=/devel/dist/${ARCH}/$D/bin:$PATH done patch -p0 <<\EOF EOF lt_cv_deplibs_check_method='pass_all' \ CC='gcc -mtune=pentium3 -mthreads' \ LDFLAGS="-L/devel/dist/${ARCH}/${PROXY_LIBINTL}/lib -Wl,--exclude-libs=libintl.a -Wl,--enable-auto-image-base" \ CFLAGS=-O2 \ ./configure --enable-debug=yes --disable-gtk-doc --without-x --prefix=c:/devel/target/$HEX --enable-explicit-deps=no --with-included-modules=yes && PATH=/devel/target/$HEX/bin:.libs:$PATH make install && ./pango-zip.sh && cd $TARGET zip /tmp/${MOD}-dev-${VER}.zip bin/pango-view.exe zip /tmp/${MOD}-dev-${VER}.zip share/man/man1/*.1 mv /tmp/${MOD}-${VER}.zip /tmp/$RUNZIP && mv /tmp/${MOD}-dev-${VER}.zip /tmp/$DEVZIP ) 2>&1 | tee /devel/src/tml/packaging/$THIS.log (cd /devel && zip /tmp/$DEVZIP src/tml/packaging/$THIS.{sh,log}) && manifestify /tmp/$RUNZIP /tmp/$DEVZIP