|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: fl_font_win32.cxx 8213 2011-01-07 16:19:30Z manolo $" 00003 // 00004 // WIN32 font selection routines for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00028 #include <FL/Fl_Printer.H> 00029 00030 static int fl_angle_ = 0; 00031 00032 #ifndef FL_DOXYGEN 00033 Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize size) { 00034 int weight = FW_NORMAL; 00035 int italic = 0; 00036 switch (*name++) { 00037 case 'I': italic = 1; break; 00038 case 'P': italic = 1; 00039 case 'B': weight = FW_BOLD; break; 00040 case ' ': break; 00041 default: name--; 00042 } 00043 fid = CreateFont( 00044 -size, // negative makes it use "char size" 00045 0, // logical average character width 00046 fl_angle_*10, // angle of escapement 00047 fl_angle_*10, // base-line orientation angle 00048 weight, 00049 italic, 00050 FALSE, // underline attribute flag 00051 FALSE, // strikeout attribute flag 00052 DEFAULT_CHARSET, // character set identifier 00053 OUT_DEFAULT_PRECIS, // output precision 00054 CLIP_DEFAULT_PRECIS,// clipping precision 00055 DEFAULT_QUALITY, // output quality 00056 DEFAULT_PITCH, // pitch and family 00057 name // pointer to typeface name string 00058 ); 00059 angle = fl_angle_; 00060 if (!fl_gc) fl_GetDC(0); 00061 SelectObject(fl_gc, fid); 00062 GetTextMetrics(fl_gc, &metr); 00063 // BOOL ret = GetCharWidthFloat(fl_gc, metr.tmFirstChar, metr.tmLastChar, font->width+metr.tmFirstChar); 00064 // ...would be the right call, but is not implemented into Window95! (WinNT?) 00065 //GetCharWidth(fl_gc, 0, 255, width); 00066 int i; 00067 for (i = 0; i < 64; i++) width[i] = NULL; 00068 #if HAVE_GL 00069 listbase = 0; 00070 for (i = 0; i < 64; i++) glok[i] = 0; 00071 #endif 00072 minsize = maxsize = size; 00073 } 00074 00075 Fl_Font_Descriptor* fl_fontsize; 00076 00077 Fl_Font_Descriptor::~Fl_Font_Descriptor() { 00078 #if HAVE_GL 00079 // Delete list created by gl_draw(). This is not done by this code 00080 // as it will link in GL unnecessarily. There should be some kind 00081 // of "free" routine pointer, or a subclass? 00082 // if (listbase) { 00083 // int base = font->min_char_or_byte2; 00084 // int size = font->max_char_or_byte2-base+1; 00085 // int base = 0; int size = 256; 00086 // glDeleteLists(listbase+base,size); 00087 // } 00088 #endif 00089 if (this == fl_fontsize) fl_fontsize = 0; 00090 DeleteObject(fid); 00091 int i; 00092 for (i = 0; i < 64; i++) free(width[i]); 00093 } 00094 00096 00097 // WARNING: if you add to this table, you must redefine FL_FREE_FONT 00098 // in Enumerations.H & recompile!! 00099 static Fl_Fontdesc built_in_table[] = { 00100 {" Arial"}, 00101 {"BArial"}, 00102 {"IArial"}, 00103 {"PArial"}, 00104 {" Courier New"}, 00105 {"BCourier New"}, 00106 {"ICourier New"}, 00107 {"PCourier New"}, 00108 {" Times New Roman"}, 00109 {"BTimes New Roman"}, 00110 {"ITimes New Roman"}, 00111 {"PTimes New Roman"}, 00112 {" Symbol"}, 00113 {" Terminal"}, 00114 {"BTerminal"}, 00115 {" Wingdings"}, 00116 }; 00117 00118 Fl_Fontdesc* fl_fonts = built_in_table; 00119 00120 static Fl_Font_Descriptor* find(Fl_Font fnum, Fl_Fontsize size, int angle) { 00121 Fl_Fontdesc* s = fl_fonts+fnum; 00122 if (!s->name) s = fl_fonts; // use 0 if fnum undefined 00123 Fl_Font_Descriptor* f; 00124 for (f = s->first; f; f = f->next) 00125 if (f->minsize <= size && f->maxsize >= size && f->angle == angle) return f; 00126 f = new Fl_Font_Descriptor(s->name, size); 00127 f->next = s->first; 00128 s->first = f; 00129 return f; 00130 } 00131 00133 // Public interface: 00134 00135 Fl_Font fl_font_ = 0; 00136 Fl_Fontsize fl_size_ = 0; 00137 //static HDC font_gc; 00138 00139 void fl_font(Fl_Font fnum, Fl_Fontsize size, int angle) { 00140 if (fnum==-1) { // just make sure that we will load a new font next time 00141 fl_font_ = 0; fl_size_ = 0; fl_angle_ = 0; 00142 return; 00143 } 00144 if (fnum == fl_font_ && size == fl_size_ && angle == fl_angle_) return; 00145 fl_font_ = fnum; fl_size_ = size; fl_angle_ = angle; 00146 fl_fontsize = find(fnum, size, angle); 00147 } 00148 00149 void Fl_GDI_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) { 00150 fl_font(fnum, size, 0); 00151 } 00152 00153 int fl_height() { 00154 if (fl_fontsize) return (fl_fontsize->metr.tmAscent + fl_fontsize->metr.tmDescent); 00155 else return -1; 00156 } 00157 00158 int fl_descent() { 00159 if (fl_fontsize) return fl_fontsize->metr.tmDescent; 00160 else return -1; 00161 } 00162 00163 // Unicode string buffer 00164 static xchar *wstr = NULL; 00165 static int wstr_len = 0; 00166 00167 00168 double fl_width(const char* c, int n) { 00169 int i = 0; 00170 if (!fl_fontsize) return -1.0; 00171 double w = 0.0; 00172 char *end = (char *)&c[n]; 00173 while (i < n) { 00174 unsigned int ucs; 00175 // int l = fl_utf2ucs((const unsigned char*)c + i, n - i, &ucs); 00176 int l; 00177 ucs = fl_utf8decode((const char*)(c + i), end, &l); 00178 // if (l < 1) l = 1; 00179 i += l; 00180 if (!fl_nonspacing(ucs)) { 00181 w += fl_width(ucs); 00182 } 00183 } 00184 return w; 00185 } 00186 00187 double fl_width(unsigned int c) { 00188 unsigned int r; 00189 r = (c & 0xFC00) >> 10; 00190 if (!fl_fontsize->width[r]) { 00191 SelectObject(fl_gc, fl_fontsize->fid); 00192 fl_fontsize->width[r] = (int*) malloc(sizeof(int) * 0x0400); 00193 SIZE s; 00194 unsigned short i = 0, ii = r * 0x400; 00195 // The following code makes a best effort attempt to obtain a valid fl_gc. 00196 // If no fl_gc is available at the time we call fl_width(), then we first 00197 // try to obtain a gc from the first fltk window. 00198 // If that is null then we attempt to obtain the gc from the current screen 00199 // using (GetDC(NULL)). 00200 // This should resolve STR #2086 00201 HDC gc = fl_gc; 00202 HWND hWnd = 0; 00203 if (!gc) { // We have no valid gc, try and obtain one 00204 // Use our first fltk window, or fallback to using the screen via GetDC(NULL) 00205 hWnd = Fl::first_window() ? fl_xid(Fl::first_window()) : NULL; 00206 gc = GetDC(hWnd); 00207 } 00208 if (!gc) 00209 Fl::fatal("Invalid graphic context: fl_width() failed because no valid HDC was found!"); 00210 for (; i < 0x400; i++) { 00211 GetTextExtentPoint32W(gc, (WCHAR*)&ii, 1, &s); 00212 fl_fontsize->width[r][i] = s.cx; 00213 ii++; 00214 } 00215 if (gc && gc!=fl_gc) ReleaseDC(hWnd, gc); 00216 } 00217 return (double) fl_fontsize->width[r][c & 0x03FF]; 00218 } 00219 00220 /* Add function pointer to allow us to access GetGlyphIndicesW on systems that have it, 00221 * without crashing on systems that do not. */ 00222 /* DWORD WINAPI GetGlyphIndicesW(HDC,LPCWSTR,int,LPWORD,DWORD) */ 00223 typedef DWORD (WINAPI* fl_GetGlyphIndices_func)(HDC,LPCWSTR,int,LPWORD,DWORD); 00224 00225 static fl_GetGlyphIndices_func fl_GetGlyphIndices = NULL; // used to hold a proc pointer for GetGlyphIndicesW 00226 static int have_loaded_GetGlyphIndices = 0; // Set this non-zero once we have tried to load GetGlyphIndices 00227 00228 // Function that tries to dynamically load GetGlyphIndicesW at runtime 00229 static void GetGlyphIndices_init() { 00230 // Since not all versions of Windows include GetGlyphIndicesW support, 00231 // we do a run-time check for the required function. 00232 HMODULE hMod = GetModuleHandle("GDI32.DLL"); 00233 if (hMod) { 00234 // check that GetGlyphIndicesW is available 00235 fl_GetGlyphIndices = (fl_GetGlyphIndices_func)GetProcAddress(hMod, "GetGlyphIndicesW"); 00236 } 00237 have_loaded_GetGlyphIndices = -1; // set this non-zero when we have attempted to load GetGlyphIndicesW 00238 } // GetGlyphIndices_init function 00239 00240 static void on_printer_extents_update(int &dx, int &dy, int &w, int &h) 00241 // converts text extents from device coords to logical coords 00242 { 00243 POINT pt[3] = { {0, 0}, {dx, dy}, {dx+w, dy+h} }; 00244 DPtoLP(fl_gc, pt, 3); 00245 w = pt[2].x - pt[1].x; 00246 h = pt[2].y - pt[1].y; 00247 dx = pt[1].x - pt[0].x; 00248 dy = pt[1].y - pt[0].y; 00249 } 00250 00251 // if printer context, extents shd be converted to logical coords 00252 #define EXTENTS_UPDATE(x,y,w,h) \ 00253 if (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) { on_printer_extents_update(x,y,w,h); } 00254 00255 static unsigned short *ext_buff = NULL; // UTF-16 converted version of input UTF-8 string 00256 static unsigned wc_len = 0; // current string buffer dimension 00257 static WORD *gi = NULL; // glyph indices array 00258 // Function to determine the extent of the "inked" area of the glyphs in a string 00259 void fl_text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) { 00260 if (!fl_fontsize) { 00261 w = 0; h = 0; 00262 dx = dy = 0; 00263 return; 00264 } 00265 static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; 00266 GLYPHMETRICS metrics; 00267 int maxw = 0, maxh = 0, dh; 00268 int minx = 0, miny = -999999; 00269 unsigned len = 0, idx = 0; 00270 HWND hWnd = 0; 00271 00272 // Have we loaded the GetGlyphIndicesW function yet? 00273 if (have_loaded_GetGlyphIndices == 0) { 00274 GetGlyphIndices_init(); 00275 } 00276 // Do we have a usable GetGlyphIndices function? 00277 if(!fl_GetGlyphIndices) goto exit_error; // No GetGlyphIndices function, use fallback mechanism instead 00278 00279 // The following code makes a best effort attempt to obtain a valid fl_gc. 00280 // See description in fl_width() above for an explanation. 00281 if (!fl_gc) { // We have no valid gc, try and obtain one 00282 // Use our first fltk window, or fallback to using the screen via GetDC(NULL) 00283 hWnd = Fl::first_window() ? fl_xid(Fl::first_window()) : NULL; 00284 fl_gc = GetDC(hWnd); 00285 } 00286 if (!fl_gc)goto exit_error; // no valid gc, attempt to use fallback measure 00287 00288 // now convert the string to WCHAR and measure it 00289 len = fl_utf8toUtf16(c, n, ext_buff, wc_len); 00290 if(len >= wc_len) { 00291 if(ext_buff) {delete [] ext_buff;} 00292 if(gi) {delete [] gi;} 00293 wc_len = len + 64; 00294 ext_buff = new unsigned short[wc_len]; 00295 gi = new WORD[wc_len]; 00296 len = fl_utf8toUtf16(c, n, ext_buff, wc_len); 00297 } 00298 SelectObject(fl_gc, fl_fontsize->fid); 00299 00300 if (fl_GetGlyphIndices(fl_gc, (WCHAR*)ext_buff, len, gi, 0) == GDI_ERROR) { 00301 // some error occured here - just return fl_measure values? 00302 goto exit_error; 00303 } 00304 00305 // now we have the glyph array we measure each glyph in turn... 00306 for(idx = 0; idx < len; idx++){ 00307 if (GetGlyphOutlineW (fl_gc, gi[idx], GGO_METRICS | GGO_GLYPH_INDEX, 00308 &metrics, 0, NULL, &matrix) == GDI_ERROR) { 00309 goto exit_error; 00310 } 00311 maxw += metrics.gmCellIncX; 00312 if(idx == 0) minx = metrics.gmptGlyphOrigin.x; 00313 dh = metrics.gmBlackBoxY - metrics.gmptGlyphOrigin.y; 00314 if(dh > maxh) maxh = dh; 00315 if(miny < metrics.gmptGlyphOrigin.y) miny = metrics.gmptGlyphOrigin.y; 00316 } 00317 00318 // for the last cell, we only want the bounding X-extent, not the glyphs increment step 00319 maxw = maxw - metrics.gmCellIncX + metrics.gmBlackBoxX + metrics.gmptGlyphOrigin.x; 00320 w = maxw - minx; 00321 h = maxh + miny; 00322 dx = minx; 00323 dy = -miny; 00324 EXTENTS_UPDATE(dx, dy, w, h); 00325 return; // normal exit 00326 00327 exit_error: 00328 // some error here - just return fl_measure values 00329 w = (int)fl_width(c, n); 00330 h = fl_height(); 00331 dx = 0; 00332 dy = fl_descent() - h; 00333 EXTENTS_UPDATE(dx, dy, w, h); 00334 return; 00335 } // fl_text_extents 00336 00337 void Fl_GDI_Graphics_Driver::draw(const char* str, int n, int x, int y) { 00338 int i = 0; 00339 int lx = 0; 00340 char *end = (char *)&str[n]; 00341 COLORREF oldColor = SetTextColor(fl_gc, fl_RGB()); 00342 SelectObject(fl_gc, fl_fontsize->fid); 00343 while (i < n) { 00344 unsigned int u; 00345 unsigned int u1; 00346 unsigned short ucs; 00347 // int l = fl_utf2ucs((const unsigned char*)str + i, n - i, &u); 00348 int l; 00349 u = fl_utf8decode((const char*)(str + i), end, &l); 00350 if ( (u1 = fl_nonspacing(u)) ) { 00351 x -= lx; 00352 u = u1; 00353 } else { 00354 lx = (int) fl_width(u); 00355 } 00356 ucs = u; 00357 if (l < 1) l = 1; 00358 i += l; 00359 TextOutW(fl_gc, x, y, (WCHAR*)&ucs, 1); 00360 x += lx; 00361 } 00362 SetTextColor(fl_gc, oldColor); 00363 } 00364 00365 void Fl_GDI_Graphics_Driver::draw(int angle, const char* str, int n, int x, int y) { 00366 fl_font(fl_font_, fl_size_, angle); 00367 // fl_draw(str, n, (int)x, (int)y); 00368 int i = 0, i2=0; 00369 char *end = (char *)&str[n]; 00370 COLORREF oldColor = SetTextColor(fl_gc, fl_RGB()); 00371 SelectObject(fl_gc, fl_fontsize->fid); 00372 //unsigned short ucs[n]; //only GCC, but not MSVC 00373 unsigned short* ucs = new unsigned short[n]; 00374 while (i < n) { 00375 unsigned int u; 00376 int l; 00377 u = fl_utf8decode((const char*)(str + i), end, &l); 00378 ucs[i2] = u; 00379 if (l < 1) l = 1; 00380 i += l; 00381 ++i2; 00382 } 00383 TextOutW(fl_gc, x, y, (WCHAR*)ucs, i2); 00384 delete[] ucs; 00385 SetTextColor(fl_gc, oldColor); 00386 fl_font(fl_font_, fl_size_); 00387 } 00388 00389 void Fl_GDI_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { 00390 int wn; 00391 wn = fl_utf8toUtf16(c, n, (unsigned short*)wstr, wstr_len); 00392 if(wn >= wstr_len) { 00393 wstr = (xchar*) realloc(wstr, sizeof(xchar) * (wn + 1)); 00394 wstr_len = wn + 1; 00395 wn = fl_utf8toUtf16(c, n, (unsigned short*)wstr, wstr_len); 00396 } 00397 00398 COLORREF oldColor = SetTextColor(fl_gc, fl_RGB()); 00399 SelectObject(fl_gc, fl_fontsize->fid); 00400 #ifdef RTL_CHAR_BY_CHAR 00401 int i = 0; 00402 int lx = 0; 00403 while (i < wn) { // output char by char is very bad for Arabic but coherent with fl_width() 00404 lx = (int) fl_width(wstr[i]); 00405 x -= lx; 00406 TextOutW(fl_gc, x, y, (WCHAR*)wstr + i, 1); 00407 if (fl_nonspacing(wstr[i])) { 00408 x += lx; 00409 } 00410 i++; 00411 } 00412 #else 00413 UINT old_align = SetTextAlign(fl_gc, TA_RIGHT | TA_RTLREADING); 00414 TextOutW(fl_gc, x, y - fl_height() + fl_descent(), (WCHAR*)wstr, wn); 00415 SetTextAlign(fl_gc, old_align); 00416 #endif 00417 SetTextColor(fl_gc, oldColor); 00418 } 00419 #endif 00420 // 00421 // End of "$Id: fl_font_win32.cxx 8213 2011-01-07 16:19:30Z manolo $". 00422 //