Author: ianmacarthur
Date: 2011-04-17 14:19:14 -0700 (Sun, 17 Apr 2011)
New Revision: 8600
Log:
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.
Modified:
branches/branch-1.3/src/fl_font_win32.cxx
Modified: branches/branch-1.3/src/fl_font_win32.cxx
===================================================================
--- branches/branch-1.3/src/fl_font_win32.cxx 2011-04-17 19:58:31 UTC (rev
8599)
+++ branches/branch-1.3/src/fl_font_win32.cxx 2011-04-17 21:19:14 UTC (rev
8600)
@@ -271,24 +271,29 @@
#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 @@
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 @@
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
_______________________________________________
fltk-commit mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-commit