diff options
| author | Ian MacArthur <imacarthur@gmail.com> | 2011-04-17 21:19:14 +0000 |
|---|---|---|
| committer | Ian MacArthur <imacarthur@gmail.com> | 2011-04-17 21:19:14 +0000 |
| commit | ac5d865986f19350ff275b09f7ceebbb9df02566 (patch) | |
| tree | c0e5e65dab6b310e09781e4a563a1a1676cad526 | |
| parent | 8f59684c0f3efa778a6ca12be091626f507c6eec (diff) | |
This WIN32 patch introduces a credible (though far from ideal)
workaround for text_extents being measured on glyphs from
supplementary Unicode planes.
It has no effect on glyphs from the Basic plane, so should not
be visible at all to most code.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@8600 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
| -rw-r--r-- | src/fl_font_win32.cxx | 68 |
1 files changed, 56 insertions, 12 deletions
diff --git a/src/fl_font_win32.cxx b/src/fl_font_win32.cxx index 162434798..fd57da6b8 100644 --- a/src/fl_font_win32.cxx +++ b/src/fl_font_win32.cxx @@ -271,24 +271,29 @@ static void on_printer_extents_update(int &dx, int &dy, int &w, int &h) #define EXTENTS_UPDATE(x,y,w,h) \ if (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) { on_printer_extents_update(x,y,w,h); } -static unsigned short *ext_buff = NULL; // UTF-16 converted version of input UTF-8 string -static unsigned wc_len = 0; // current string buffer dimension -static WORD *gi = NULL; // glyph indices array // Function to determine the extent of the "inked" area of the glyphs in a string void Fl_GDI_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) { + Fl_Font_Descriptor *fl_fontsize = font_descriptor(); - if (!fl_fontsize) { + if (!fl_fontsize) { // no valid font, nothing to measure w = 0; h = 0; dx = dy = 0; return; } - static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; + + static unsigned short *ext_buff = NULL; // UTF-16 converted version of input UTF-8 string + static unsigned *ucs_buff = NULL; // UCS converted version of input UTF8 string + static WORD *w_buff = NULL; // glyph or class indices array + static unsigned wc_len = 0; // current string buffer dimensions + static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; // identity mat for GetGlyphOutlineW GLYPHMETRICS metrics; int maxw = 0, maxh = 0, dh; int minx = 0, miny = -999999; unsigned len = 0, idx = 0; + unsigned gcp_w = 0x7FFFFFFF, gcp_h; HWND hWnd = 0; HDC gc = fl_gc; // local copy of current gc - make a copy in case we change it... + int has_surrogates; // will be set if the string contains surrogate pairs // Have we loaded the GetGlyphIndicesW function yet? if (have_loaded_GetGlyphIndices == 0) { @@ -310,21 +315,57 @@ void Fl_GDI_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy len = fl_utf8toUtf16(c, n, ext_buff, wc_len); if(len >= wc_len) { if(ext_buff) {delete [] ext_buff;} - if(gi) {delete [] gi;} + if(w_buff) {delete [] w_buff;} + if(ucs_buff) {delete [] ucs_buff;} wc_len = len + 64; ext_buff = new unsigned short[wc_len]; - gi = new WORD[wc_len]; + w_buff = new WORD[wc_len]; + ucs_buff = new unsigned[wc_len]; len = fl_utf8toUtf16(c, n, ext_buff, wc_len); } SelectObject(gc, fl_fontsize->fid); - if (fl_GetGlyphIndices(gc, (WCHAR*)ext_buff, len, gi, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) { - // some error occured here - just return fl_measure values - goto exit_error; + // Are there surrogate-pairs in this string? If so GetGlyphIndicesW will fail + // since it can only handle the BMP range. + // We ideally want to use GetGlyphIndicesW, as it is the Right Thing, but it + // only works for the BMP, so we leverage GetCharacterPlacementW instead, which + // is not ideal, but works adequately well, and does handle surrogate pairs. + has_surrogates = 0; + for(unsigned ll = 0; ll < len; ll++) { + if((ext_buff[ll] >= 0xD800) && (ext_buff[ll] < 0xE000)) { + has_surrogates = -1; + break; + } + } + if (has_surrogates) { + // GetGlyphIndices will not work - use GetCharacterPlacementW() instead + GCP_RESULTSW gcp_res; + memset(ucs_buff, 0, (sizeof(unsigned) * wc_len)); + memset(w_buff, 0, (sizeof(WCHAR) * wc_len)); + memset(&gcp_res, 0, sizeof(GCP_RESULTSW)); + gcp_res.lpClass = (WCHAR *)w_buff; + gcp_res.lpGlyphs = (LPWSTR)ucs_buff; + gcp_res.nGlyphs = wc_len; + gcp_res.lStructSize = sizeof(gcp_res); + + DWORD dr = GetCharacterPlacementW(gc, (WCHAR*)ext_buff, len, 0, &gcp_res, GCP_GLYPHSHAPE); + gcp_w = dr & 0xFFFF; + if(gcp_w == 0) gcp_w = 0x7FFFFFFF; + gcp_h = (dr >> 16) & 0xFFFF; + len = gcp_res.nGlyphs; + } else { + if (fl_GetGlyphIndices(gc, (WCHAR*)ext_buff, len, w_buff, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) { + // some error occured here - just return fl_measure values + goto exit_error; + } + for(unsigned ll = 0; ll < len; ll++) { + ucs_buff[ll] = w_buff[ll]; + } } + // now we have the glyph array we measure each glyph in turn... for(idx = 0; idx < len; idx++){ - if (GetGlyphOutlineW (gc, gi[idx], GGO_METRICS | GGO_GLYPH_INDEX, + if (GetGlyphOutlineW (gc, ucs_buff[idx], GGO_METRICS | GGO_GLYPH_INDEX, &metrics, 0, NULL, &matrix) == GDI_ERROR) { goto exit_error; } @@ -334,13 +375,16 @@ void Fl_GDI_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy if(dh > maxh) maxh = dh; if(miny < metrics.gmptGlyphOrigin.y) miny = metrics.gmptGlyphOrigin.y; } - // for the last cell, we only want the bounding X-extent, not the glyphs increment step maxw = maxw - metrics.gmCellIncX + metrics.gmBlackBoxX + metrics.gmptGlyphOrigin.x; w = maxw - minx; h = maxh + miny; dx = minx; dy = -miny; + // This next line traps for a specific (probably font related) issue with measuring + // the width of strings that sometimes happens if using GetCharacterPlacementW() + // it is a workaround, not good code... + if((has_surrogates) && (w > (int)gcp_w)) {w = (int)gcp_w;} EXTENTS_UPDATE(dx, dy, w, h); return; // normal exit |
