Anti-Grain Geometry Tutorial
agg_font_win32_tt.cpp
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 // mcseemagg@yahoo.com
13 // http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 
16 #include <cstdio>
17 #include <cstring>
18 #include "agg_font_win32_tt.h"
19 #include "agg_bitset_iterator.h"
20 #include "agg_renderer_scanline.h"
21 
22 #ifdef AGG_WIN9X_COMPLIANT
23 #define GetGlyphOutlineX GetGlyphOutline
24 #else
25 #define GetGlyphOutlineX GetGlyphOutlineW
26 #endif
27 
28 namespace agg
29 {
30 
31  //------------------------------------------------------------------------------
32  //
33  // This code implements the AUTODIN II polynomial
34  // The variable corresponding to the macro argument "crc" should
35  // be an unsigned long.
36  // Oroginal code by Spencer Garrett <srg@quick.com>
37  //
38 
39  // generated using the AUTODIN II polynomial
40  // x^32 + x^26 + x^23 + x^22 + x^16 +
41  // x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
42  //
43  //------------------------------------------------------------------------------
44 
45  static const unsigned crc32tab[256] =
46  {
47  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
48  0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
49  0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
50  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
51  0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
52  0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
53  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
54  0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
55  0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
56  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
57  0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
58  0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
59  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
60  0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
61  0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
62  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
63  0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
64  0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
65  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
66  0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
67  0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
68  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
69  0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
70  0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
71  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
72  0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
73  0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
74  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
75  0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
76  0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
77  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
78  0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
79  0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
80  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
81  0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
82  0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
83  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
84  0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
85  0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
86  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
87  0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
88  0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
89  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
90  0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
91  0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
92  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
93  0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
94  0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
95  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
96  0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
97  0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
98  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
99  0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
100  0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
101  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
102  0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
103  0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
104  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
105  0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
106  0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
107  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
108  0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
109  0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
110  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
111  };
112 
113  //------------------------------------------------------------------------------
114  static unsigned calc_crc32(const unsigned char* buf, unsigned size)
115  {
116  unsigned crc = (unsigned)~0;
117  const unsigned char* p;
118  unsigned len = 0;
119  unsigned nr = size;
120 
121  for (len += nr, p = buf; nr--; ++p)
122  {
123  crc = (crc >> 8) ^ crc32tab[(crc ^ *p) & 0xff];
124  }
125  return ~crc;
126  }
127 
128  //------------------------------------------------------------------------
129  static inline FIXED dbl_to_fx(double d)
130  {
131  int l;
132  l = int(d * 65536.0);
133  return *(FIXED*)&l;
134  }
135 
136  //------------------------------------------------------------------------
137  static inline int dbl_to_plain_fx(double d)
138  {
139  return int(d * 65536.0);
140  }
141 
142  //------------------------------------------------------------------------
143  static inline FIXED negate_fx(const FIXED& fx)
144  {
145  int l = -(*(int*)(&fx));
146  return *(FIXED*)&l;
147  }
148 
149  //------------------------------------------------------------------------
150  static inline double fx_to_dbl(const FIXED& p)
151  {
152  return double(p.value) + double(p.fract) * (1.0 / 65536.0);
153  }
154 
155  //------------------------------------------------------------------------
156  static inline int fx_to_plain_int(const FIXED& fx)
157  {
158  return *(int*)(&fx);
159  }
160 
161  //------------------------------------------------------------------------
162  static inline int fx_to_int26p6(const FIXED& p)
163  {
164  return (int(p.value) << 6) + (int(p.fract) >> 10);
165  }
166 
167  //------------------------------------------------------------------------
168  static inline int dbl_to_int26p6(double p)
169  {
170  return int(p * 64.0 + 0.5);
171  }
172 
173  //------------------------------------------------------------------------
174  template<class Scanline, class ScanlineStorage>
175  void decompose_win32_glyph_bitmap_mono(const char* gbuf,
176  int w, int h,
177  int x, int y,
178  bool flip_y,
179  Scanline& sl,
180  ScanlineStorage& storage)
181  {
182  int i;
183  int pitch = ((w + 31) >> 5) << 2;
184  const int8u* buf = (const int8u*)gbuf;
185  sl.reset(x, x + w);
186  storage.prepare();
187  if(flip_y)
188  {
189  buf += pitch * (h - 1);
190  y += h;
191  pitch = -pitch;
192  }
193  for(i = 0; i < h; i++)
194  {
195  sl.reset_spans();
196  bitset_iterator bits(buf, 0);
197  int j;
198  for(j = 0; j < w; j++)
199  {
200  if(bits.bit()) sl.add_cell(x + j, cover_full);
201  ++bits;
202  }
203  buf += pitch;
204  if(sl.num_spans())
205  {
206  sl.finalize(y - i - 1);
207  storage.render(sl);
208  }
209  }
210  }
211 
212 
213 
214  //------------------------------------------------------------------------
215  template<class Rasterizer, class Scanline, class ScanlineStorage>
216  void decompose_win32_glyph_bitmap_gray8(const char* gbuf,
217  int w, int h,
218  int x, int y,
219  bool flip_y,
220  Rasterizer& ras,
221  Scanline& sl,
222  ScanlineStorage& storage)
223  {
224  int i, j;
225  int pitch = ((w + 3) >> 2) << 2;
226  const int8u* buf = (const int8u*)gbuf;
227  sl.reset(x, x + w);
228  storage.prepare();
229  if(flip_y)
230  {
231  buf += pitch * (h - 1);
232  y += h;
233  pitch = -pitch;
234  }
235  for(i = 0; i < h; i++)
236  {
237  sl.reset_spans();
238  const int8u* p = buf;
239  for(j = 0; j < w; j++)
240  {
241  if(*p)
242  {
243  unsigned v = *p;
244  if(v == 64) v = 255;
245  else v <<= 2;
246  sl.add_cell(x + j, ras.apply_gamma(v));
247  }
248  ++p;
249  }
250  buf += pitch;
251  if(sl.num_spans())
252  {
253  sl.finalize(y - i - 1);
254  storage.render(sl);
255  }
256  }
257  }
258 
259 
260 
261  //------------------------------------------------------------------------
262  template<class PathStorage>
263  bool decompose_win32_glyph_outline(const char* gbuf,
264  unsigned total_size,
265  bool flip_y,
266  const trans_affine& mtx,
267  PathStorage& path)
268  {
269  const char* cur_glyph = gbuf;
270  const char* end_glyph = gbuf + total_size;
271  double x, y;
272  typedef typename PathStorage::value_type value_type;
273 
274  while(cur_glyph < end_glyph)
275  {
276  const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
277 
278  const char* end_poly = cur_glyph + th->cb;
279  const char* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
280 
281  x = fx_to_dbl(th->pfxStart.x);
282  y = fx_to_dbl(th->pfxStart.y);
283  if(flip_y) y = -y;
284  mtx.transform(&x, &y);
285  path.move_to(value_type(dbl_to_int26p6(x)),
286  value_type(dbl_to_int26p6(y)));
287 
288  while(cur_poly < end_poly)
289  {
290  const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
291 
292  if (pc->wType == TT_PRIM_LINE)
293  {
294  int i;
295  for (i = 0; i < pc->cpfx; i++)
296  {
297  x = fx_to_dbl(pc->apfx[i].x);
298  y = fx_to_dbl(pc->apfx[i].y);
299  if(flip_y) y = -y;
300  mtx.transform(&x, &y);
301  path.line_to(value_type(dbl_to_int26p6(x)),
302  value_type(dbl_to_int26p6(y)));
303  }
304  }
305 
306  if (pc->wType == TT_PRIM_QSPLINE)
307  {
308  int u;
309  for (u = 0; u < pc->cpfx - 1; u++) // Walk through points in spline
310  {
311  POINTFX pnt_b = pc->apfx[u]; // B is always the current point
312  POINTFX pnt_c = pc->apfx[u+1];
313 
314  if (u < pc->cpfx - 2) // If not on last spline, compute C
315  {
316  // midpoint (x,y)
317  *(int*)&pnt_c.x = (*(int*)&pnt_b.x + *(int*)&pnt_c.x) / 2;
318  *(int*)&pnt_c.y = (*(int*)&pnt_b.y + *(int*)&pnt_c.y) / 2;
319  }
320 
321  double x2, y2;
322  x = fx_to_dbl(pnt_b.x);
323  y = fx_to_dbl(pnt_b.y);
324  x2 = fx_to_dbl(pnt_c.x);
325  y2 = fx_to_dbl(pnt_c.y);
326  if(flip_y) { y = -y; y2 = -y2; }
327  mtx.transform(&x, &y);
328  mtx.transform(&x2, &y2);
329  path.curve3(value_type(dbl_to_int26p6(x)),
330  value_type(dbl_to_int26p6(y)),
331  value_type(dbl_to_int26p6(x2)),
332  value_type(dbl_to_int26p6(y2)));
333  }
334  }
335  cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
336  }
337  cur_glyph += th->cb;
338  }
339  return true;
340  }
341 
342 
343 
344 
345  //------------------------------------------------------------------------
346  font_engine_win32_tt_base::~font_engine_win32_tt_base()
347  {
348  delete [] m_kerning_pairs;
349  delete [] m_gbuf;
350  delete [] m_signature;
351  delete [] m_typeface;
352  if(m_dc && m_old_font) ::SelectObject(m_dc, m_old_font);
353  unsigned i;
354  for(i = 0; i < m_num_fonts; ++i)
355  {
356  delete [] m_font_names[i];
357  ::DeleteObject(m_fonts[i]);
358  }
359  delete [] m_font_names;
360  delete [] m_fonts;
361  }
362 
363 
364 
365  //------------------------------------------------------------------------
366  font_engine_win32_tt_base::font_engine_win32_tt_base(bool flag32,
367  HDC dc,
368  unsigned max_fonts) :
369  m_flag32(flag32),
370  m_dc(dc),
371  m_old_font(m_dc ? (HFONT)::GetCurrentObject(m_dc, OBJ_FONT) : 0),
372  m_fonts(new HFONT [max_fonts]),
373  m_num_fonts(0),
374  m_max_fonts(max_fonts),
375  m_font_names(new char* [max_fonts]),
376  m_cur_font(0),
377 
378  m_change_stamp(0),
379  m_typeface(new char [256-16]),
380  m_typeface_len(256-16-1),
381  m_signature(new char [256+256-16]),
382  m_height(0),
383  m_width(0),
384  m_weight(FW_REGULAR),
385  m_italic(false),
386  m_char_set(DEFAULT_CHARSET),
387  m_pitch_and_family(FF_DONTCARE),
388  m_hinting(true),
389  m_flip_y(false),
390  m_font_created(false),
391  m_resolution(0),
392  m_glyph_rendering(glyph_ren_native_gray8),
393  m_glyph_index(0),
394  m_data_size(0),
395  m_data_type(glyph_data_invalid),
396  m_bounds(1,1,0,0),
397  m_advance_x(0.0),
398  m_advance_y(0.0),
399  m_gbuf(new char [buf_size]),
400  m_kerning_pairs(0),
401  m_num_kerning_pairs(0),
402  m_max_kerning_pairs(0),
403 
404  m_path16(),
405  m_path32(),
406  m_curves16(m_path16),
407  m_curves32(m_path32),
408  m_scanline_aa(),
409  m_scanline_bin(),
410  m_scanlines_aa(),
411  m_scanlines_bin(),
412  m_rasterizer()
413  {
414  m_curves16.approximation_scale(4.0);
415  m_curves32.approximation_scale(4.0);
416  std::memset(&m_matrix, 0, sizeof(m_matrix));
417  m_matrix.eM11.value = 1;
418  m_matrix.eM22.value = 1;
419  }
420 
421 
422 
423  //------------------------------------------------------------------------
424  int font_engine_win32_tt_base::find_font(const char* name) const
425  {
426  unsigned i;
427  for(i = 0; i < m_num_fonts; ++i)
428  {
429  if(std::strcmp(name, m_font_names[i]) == 0) return i;
430  }
431  return -1;
432  }
433 
434  //------------------------------------------------------------------------
435  bool font_engine_win32_tt_base::create_font(const char* typeface_,
436  glyph_rendering ren_type)
437  {
438  if(m_dc)
439  {
440  unsigned len = strlen(typeface_);
441  if(len > m_typeface_len)
442  {
443  delete [] m_signature;
444  delete [] m_typeface;
445  m_typeface = new char [len + 32];
446  m_signature = new char [len + 32 + 256];
447  m_typeface_len = len + 32 - 1;
448  }
449 
450  strcpy(m_typeface, typeface_);
451 
452  int h = m_height;
453  int w = m_width;
454 
455  if(m_resolution)
456  {
457  h = ::MulDiv(m_height, m_resolution, 72);
458  w = ::MulDiv(m_width, m_resolution, 72);
459  }
460 
461  m_glyph_rendering = ren_type;
462  update_signature();
463  int idx = find_font(m_signature);
464  if(idx >= 0)
465  {
466  m_cur_font = m_fonts[idx];
467  ::SelectObject(m_dc, m_cur_font);
468  m_num_kerning_pairs = 0;
469  return true;
470  }
471  else
472  {
473  m_cur_font = ::CreateFont(-h, // height of font
474  w, // average character width
475  0, // angle of escapement
476  0, // base-line orientation angle
477  m_weight, // font weight
478  m_italic, // italic attribute option
479  0, // underline attribute option
480  0, // strikeout attribute option
481  m_char_set, // character set identifier
482  OUT_DEFAULT_PRECIS, // output precision
483  CLIP_DEFAULT_PRECIS, // clipping precision
484  ANTIALIASED_QUALITY, // output quality
485  m_pitch_and_family, // pitch and family
486  m_typeface); // typeface name
487  if(m_cur_font)
488  {
489  if(m_num_fonts >= m_max_fonts)
490  {
491  delete [] m_font_names[0];
492  if(m_old_font) ::SelectObject(m_dc, m_old_font);
493  ::DeleteObject(m_fonts[0]);
494  std::memcpy(m_fonts,
495  m_fonts + 1,
496  (m_max_fonts - 1) * sizeof(HFONT));
497  std::memcpy(m_font_names,
498  m_font_names + 1,
499  (m_max_fonts - 1) * sizeof(char*));
500  m_num_fonts = m_max_fonts - 1;
501  }
502 
503  update_signature();
504  m_font_names[m_num_fonts] = new char[std::strlen(m_signature) + 1];
505  std::strcpy(m_font_names[m_num_fonts], m_signature);
506  m_fonts[m_num_fonts] = m_cur_font;
507  ++m_num_fonts;
508  ::SelectObject(m_dc, m_cur_font);
509  m_num_kerning_pairs = 0;
510  return true;
511  }
512  }
513  }
514  return false;
515  }
516 
517 
518 
519 
520 
521  //------------------------------------------------------------------------
522  bool font_engine_win32_tt_base::create_font(const char* typeface_,
523  glyph_rendering ren_type,
524  double height_,
525  double width_,
526  int weight_,
527  bool italic_,
528  DWORD char_set_,
529  DWORD pitch_and_family_)
530  {
531  height(height_);
532  width(width_);
533  weight(weight_);
534  italic(italic_);
535  char_set(char_set_);
536  pitch_and_family(pitch_and_family_);
537  return create_font(typeface_, ren_type);
538  }
539 
540 
541 
542 
543  //------------------------------------------------------------------------
544  void font_engine_win32_tt_base::update_signature()
545  {
546  m_signature[0] = 0;
547  if(m_dc && m_cur_font)
548  {
549  unsigned gamma_hash = 0;
550  if(m_glyph_rendering == glyph_ren_native_gray8 ||
551  m_glyph_rendering == glyph_ren_agg_mono ||
552  m_glyph_rendering == glyph_ren_agg_gray8)
553  {
554  unsigned char gamma_table[rasterizer_scanline_aa<>::aa_scale];
555  unsigned i;
556  for(i = 0; i < rasterizer_scanline_aa<>::aa_scale; ++i)
557  {
558  gamma_table[i] = m_rasterizer.apply_gamma(i);
559  }
560  gamma_hash = calc_crc32(gamma_table, sizeof(gamma_table));
561  }
562 
563  sprintf(m_signature,
564  "%s,%u,%d,%d:%dx%d,%d,%d,%d,%d,%d,%08X",
565  m_typeface,
566  m_char_set,
567  int(m_glyph_rendering),
568  m_resolution,
569  m_height,
570  m_width,
571  m_weight,
572  int(m_italic),
573  int(m_hinting),
574  int(m_flip_y),
575  int(m_pitch_and_family),
576  gamma_hash);
577 
578  if(m_glyph_rendering == glyph_ren_outline ||
579  m_glyph_rendering == glyph_ren_agg_mono ||
580  m_glyph_rendering == glyph_ren_agg_gray8)
581  {
582  double mtx[6];
583  char buf[100];
584  m_affine.store_to(mtx);
585  std::sprintf(buf, ",%08X%08X%08X%08X%08X%08X",
586  dbl_to_plain_fx(mtx[0]),
587  dbl_to_plain_fx(mtx[1]),
588  dbl_to_plain_fx(mtx[2]),
589  dbl_to_plain_fx(mtx[3]),
590  dbl_to_plain_fx(mtx[4]),
591  dbl_to_plain_fx(mtx[5]));
592  std::strcat(m_signature, buf);
593  }
594  ++m_change_stamp;
595  }
596  }
597 
598 
599 
600  //------------------------------------------------------------------------
601  bool font_engine_win32_tt_base::prepare_glyph(unsigned glyph_code)
602  {
603  if(m_dc && m_cur_font)
604  {
605  int format = GGO_BITMAP;
606 
607  switch(m_glyph_rendering)
608  {
609  case glyph_ren_native_gray8:
610  format = GGO_GRAY8_BITMAP;
611  break;
612 
613  case glyph_ren_outline:
614  case glyph_ren_agg_mono:
615  case glyph_ren_agg_gray8:
616  format = GGO_NATIVE;
617  break;
618  }
619 
620 #ifndef GGO_UNHINTED // For compatibility with old SDKs.
621 #define GGO_UNHINTED 0x0100
622 #endif
623  if(!m_hinting) format |= GGO_UNHINTED;
624 
625  GLYPHMETRICS gm;
626  int total_size = GetGlyphOutlineX(m_dc,
627  glyph_code,
628  format,
629  &gm,
630  buf_size,
631  (void*)m_gbuf,
632  &m_matrix);
633 
634  if(total_size < 0)
635  {
636  // GetGlyphOutline() fails when being called for
637  // GGO_GRAY8_BITMAP and white space (stupid Microsoft).
638  // It doesn't even initialize the glyph metrics
639  // structure. So, we have to query the metrics
640  // separately (basically we need gmCellIncX).
641  int total_size = GetGlyphOutlineX(m_dc,
642  glyph_code,
643  GGO_METRICS,
644  &gm,
645  buf_size,
646  (void*)m_gbuf,
647  &m_matrix);
648 
649  if(total_size < 0) return false;
650  gm.gmBlackBoxX = gm.gmBlackBoxY = 0;
651  total_size = 0;
652  }
653 
654  m_glyph_index = glyph_code;
655  m_advance_x = gm.gmCellIncX;
656  m_advance_y = -gm.gmCellIncY;
657 
658  switch(m_glyph_rendering)
659  {
660  case glyph_ren_native_mono:
661  decompose_win32_glyph_bitmap_mono(m_gbuf,
662  gm.gmBlackBoxX,
663  gm.gmBlackBoxY,
664  gm.gmptGlyphOrigin.x,
665  m_flip_y ? -gm.gmptGlyphOrigin.y :
666  gm.gmptGlyphOrigin.y,
667  m_flip_y,
668  m_scanline_bin,
669  m_scanlines_bin);
670  m_bounds.x1 = m_scanlines_bin.min_x();
671  m_bounds.y1 = m_scanlines_bin.min_y();
672  m_bounds.x2 = m_scanlines_bin.max_x() + 1;
673  m_bounds.y2 = m_scanlines_bin.max_y() + 1;
674  m_data_size = m_scanlines_bin.byte_size();
675  m_data_type = glyph_data_mono;
676  return true;
677 
678  case glyph_ren_native_gray8:
679  decompose_win32_glyph_bitmap_gray8(m_gbuf,
680  gm.gmBlackBoxX,
681  gm.gmBlackBoxY,
682  gm.gmptGlyphOrigin.x,
683  m_flip_y ? -gm.gmptGlyphOrigin.y :
684  gm.gmptGlyphOrigin.y,
685  m_flip_y,
686  m_rasterizer,
687  m_scanline_aa,
688  m_scanlines_aa);
689  m_bounds.x1 = m_scanlines_aa.min_x();
690  m_bounds.y1 = m_scanlines_aa.min_y();
691  m_bounds.x2 = m_scanlines_aa.max_x() + 1;
692  m_bounds.y2 = m_scanlines_aa.max_y() + 1;
693  m_data_size = m_scanlines_aa.byte_size();
694  m_data_type = glyph_data_gray8;
695  return true;
696 
697  case glyph_ren_outline:
698  m_affine.transform(&m_advance_x, &m_advance_y);
699  if(m_flag32)
700  {
701  m_path32.remove_all();
702  if(decompose_win32_glyph_outline(m_gbuf,
703  total_size,
704  m_flip_y,
705  m_affine,
706  m_path32))
707  {
708  rect_d bnd = m_path32.bounding_rect();
709  m_data_size = m_path32.byte_size();
710  m_data_type = glyph_data_outline;
711  m_bounds.x1 = int(floor(bnd.x1));
712  m_bounds.y1 = int(floor(bnd.y1));
713  m_bounds.x2 = int(ceil(bnd.x2));
714  m_bounds.y2 = int(ceil(bnd.y2));
715  return true;
716  }
717  }
718  else
719  {
720  m_path16.remove_all();
721  if(decompose_win32_glyph_outline(m_gbuf,
722  total_size,
723  m_flip_y,
724  m_affine,
725  m_path16))
726  {
727  rect_d bnd = m_path16.bounding_rect();
728  m_data_size = m_path16.byte_size();
729  m_data_type = glyph_data_outline;
730  m_bounds.x1 = int(floor(bnd.x1));
731  m_bounds.y1 = int(floor(bnd.y1));
732  m_bounds.x2 = int(ceil(bnd.x2));
733  m_bounds.y2 = int(ceil(bnd.y2));
734  return true;
735  }
736  }
737  break;
738 
739  case glyph_ren_agg_mono:
740  m_rasterizer.reset();
741  m_affine.transform(&m_advance_x, &m_advance_y);
742  if(m_flag32)
743  {
744  m_path32.remove_all();
745  decompose_win32_glyph_outline(m_gbuf,
746  total_size,
747  m_flip_y,
748  m_affine,
749  m_path32);
750  m_rasterizer.add_path(m_curves32);
751  }
752  else
753  {
754  m_path16.remove_all();
755  decompose_win32_glyph_outline(m_gbuf,
756  total_size,
757  m_flip_y,
758  m_affine,
759  m_path16);
760  m_rasterizer.add_path(m_curves16);
761  }
762  m_scanlines_bin.prepare(); // Remove all
763  render_scanlines(m_rasterizer, m_scanline_bin, m_scanlines_bin);
764  m_bounds.x1 = m_scanlines_bin.min_x();
765  m_bounds.y1 = m_scanlines_bin.min_y();
766  m_bounds.x2 = m_scanlines_bin.max_x() + 1;
767  m_bounds.y2 = m_scanlines_bin.max_y() + 1;
768  m_data_size = m_scanlines_bin.byte_size();
769  m_data_type = glyph_data_mono;
770  return true;
771 
772  case glyph_ren_agg_gray8:
773  m_rasterizer.reset();
774  m_affine.transform(&m_advance_x, &m_advance_y);
775  if(m_flag32)
776  {
777  m_path32.remove_all();
778  decompose_win32_glyph_outline(m_gbuf,
779  total_size,
780  m_flip_y,
781  m_affine,
782  m_path32);
783  m_rasterizer.add_path(m_curves32);
784  }
785  else
786  {
787  m_path16.remove_all();
788  decompose_win32_glyph_outline(m_gbuf,
789  total_size,
790  m_flip_y,
791  m_affine,
792  m_path16);
793  m_rasterizer.add_path(m_curves16);
794  }
795  m_scanlines_aa.prepare(); // Remove all
796  render_scanlines(m_rasterizer, m_scanline_aa, m_scanlines_aa);
797  m_bounds.x1 = m_scanlines_aa.min_x();
798  m_bounds.y1 = m_scanlines_aa.min_y();
799  m_bounds.x2 = m_scanlines_aa.max_x() + 1;
800  m_bounds.y2 = m_scanlines_aa.max_y() + 1;
801  m_data_size = m_scanlines_aa.byte_size();
802  m_data_type = glyph_data_gray8;
803  return true;
804  }
805  }
806  return false;
807  }
808 
809 
810 
811  //------------------------------------------------------------------------
812  void font_engine_win32_tt_base::write_glyph_to(int8u* data) const
813  {
814  if(data && m_data_size)
815  {
816  switch(m_data_type)
817  {
818  case glyph_data_mono: m_scanlines_bin.serialize(data); break;
819  case glyph_data_gray8: m_scanlines_aa.serialize(data); break;
820  case glyph_data_outline:
821  if(m_flag32)
822  {
823  m_path32.serialize(data);
824  }
825  else
826  {
827  m_path16.serialize(data);
828  }
829  break;
830  }
831  }
832  }
833 
834 
835 
836  //------------------------------------------------------------------------
837  static bool pair_less(const KERNINGPAIR& v1, const KERNINGPAIR& v2)
838  {
839  if(v1.wFirst != v2.wFirst) return v1.wFirst < v2.wFirst;
840  return v1.wSecond < v2.wSecond;
841  }
842 
843 
844  //------------------------------------------------------------------------
845  void font_engine_win32_tt_base::sort_kerning_pairs()
846  {
847  pod_array_adaptor<KERNINGPAIR> pairs(m_kerning_pairs, m_num_kerning_pairs);
848  quick_sort(pairs, pair_less);
849  }
850 
851 
852 
853  //------------------------------------------------------------------------
854  void font_engine_win32_tt_base::load_kerning_pairs()
855  {
856  if(m_dc && m_cur_font)
857  {
858  if(m_kerning_pairs == 0)
859  {
860  m_kerning_pairs = new KERNINGPAIR [16384-16];
861  m_max_kerning_pairs = 16384-16;
862  }
863  m_num_kerning_pairs = ::GetKerningPairs(m_dc,
864  m_max_kerning_pairs,
865  m_kerning_pairs);
866 
867  if(m_num_kerning_pairs)
868  {
869  // Check to see if the kerning pairs are sorted and
870  // sort them if they are not.
871  //----------------
872  unsigned i;
873  for(i = 1; i < m_num_kerning_pairs; ++i)
874  {
875  if(!pair_less(m_kerning_pairs[i - 1], m_kerning_pairs[i]))
876  {
877  sort_kerning_pairs();
878  break;
879  }
880  }
881  }
882  }
883  }
884 
885 
886  //------------------------------------------------------------------------
887  bool font_engine_win32_tt_base::add_kerning(unsigned first, unsigned second,
888  double* x, double* y)
889  {
890  if(m_dc && m_cur_font)
891  {
892  if(m_num_kerning_pairs == 0)
893  {
894  load_kerning_pairs();
895  }
896 
897  int end = m_num_kerning_pairs - 1;
898  int beg = 0;
899  KERNINGPAIR t;
900  t.wFirst = (WORD)first;
901  t.wSecond = (WORD)second;
902  while(beg <= end)
903  {
904  int mid = (end + beg) / 2;
905  if(m_kerning_pairs[mid].wFirst == t.wFirst &&
906  m_kerning_pairs[mid].wSecond == t.wSecond)
907  {
908  double dx = m_kerning_pairs[mid].iKernAmount;
909  double dy = 0.0;
910  if(m_glyph_rendering == glyph_ren_outline ||
911  m_glyph_rendering == glyph_ren_agg_mono ||
912  m_glyph_rendering == glyph_ren_agg_gray8)
913  {
914  m_affine.transform_2x2(&dx, &dy);
915  }
916  *x += dx;
917  *y += dy;
918  return true;
919  }
920  else
921  if(pair_less(t, m_kerning_pairs[mid]))
922  {
923  end = mid - 1;
924  }
925  else
926  {
927  beg = mid + 1;
928  }
929  }
930  return false;
931  }
932  return false;
933  }
934 
935 
936 
937 }
938 
Definition: agg_arc.cpp:24