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

Reply via email to