summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIan MacArthur <imacarthur@gmail.com>2011-04-17 21:19:14 +0000
committerIan MacArthur <imacarthur@gmail.com>2011-04-17 21:19:14 +0000
commitac5d865986f19350ff275b09f7ceebbb9df02566 (patch)
treec0e5e65dab6b310e09781e4a563a1a1676cad526 /src
parent8f59684c0f3efa778a6ca12be091626f507c6eec (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
Diffstat (limited to 'src')
-rw-r--r--src/fl_font_win32.cxx68
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