TextTTF.cxx
Go to the documentation of this file.
1 
2 //
3 // Code extracted from freetype-1.3.1/test/ftview.c, ftstring.c.
4 //
6 
7 // this :
8 #include "TextTTF.h"
9 
10 #include "OpenGL.h"
11 
12 #include <iostream>
13 
14 #ifdef HAVE_TTF
15 #include <freetype.h>
16 
17 #define MAXIMUM(a,b) ((a)>(b)?a:b)
18 #define MINIMUM(a,b) ((a)<(b)?a:b)
19 
20 class TextTTF_Internal {
21 public:
22  TT_Error loadTrueTypeChar(int);
23  bool fOpened;
24  TT_Face fFace;
25  TT_CharMap fCharMap;
26  TT_Instance fInstance;
27  TT_Instance_Metrics fInstanceMetrics;
28  TT_Glyph fGlyph;
29  TT_Raster_Map fBitmap;
30  int fNumGlyphs;
31  bool fHinted;
32  bool fNewLine;
33  TT_UShort fWidth;
34  TT_UShort fTextWidth;
35  TT_UShort fTextHeight;
36  float fXJustifyTranslation;
37  float fYJustifyTranslation;
38 };
39 
40 static TT_Engine* fEngine = 0;
41 
43 TT_Error TextTTF_Internal::loadTrueTypeChar(
44  int aIndex
45 )
48 {
49  //int flags = TTLOAD_SCALE_GLYPH;
50  //if (fHinted==true) flags |= TTLOAD_HINT_GLYPH;
51  int flags = TTLOAD_DEFAULT;
52  return TT_Load_Glyph( fInstance, fGlyph, aIndex, flags );
53 }
54 #endif
55 
58 )
59 :fStatus(false)
60 ,fInitFont(true)
61 ,fPointSize(0)
62 ,fViewportWidth(0)
63 ,fViewportHeight(0)
64 ,fRotated(false)
67 {
68 #ifdef HAVE_TTF
69  if(!fEngine) {
70  fEngine = new TT_Engine;
71  TT_Error error = TT_Init_FreeType(fEngine);
72  if(error) {
73  std::cout << "TextTTF : could not initialise FreeType." << std::endl;
74  return;
75  }
76  // When finished , should do a : TT_Done_FreeType(fEngine);
77  }
78 #else
79  std::cout << "TextTTF : compiled without HAVE_TTF CPP macro" << std::endl;
80 #endif
81 
82  //m_fileName = "times";
83  m_fileName = "helvetica";
84  m_size = 64;
88 #ifdef HAVE_TTF
89  fTTF = new TextTTF_Internal;
90  fTTF->fOpened = false;
91  fTTF->fBitmap.bitmap = 0;
92 #else
93  fTTF = 0;
94 #endif
95 
96  fPointSize = (int)m_size;
97  initFont();
98  fInitFont = false;
99 }
102 )
105 {
106  fStatus = false;
107 #ifdef HAVE_TTF
108  if(fTTF->fOpened==true) {
109  free(fTTF->fBitmap.bitmap);
110  TT_Done_Glyph(fTTF->fGlyph);
111  TT_Done_Instance(fTTF->fInstance);
112  TT_Close_Face(fTTF->fFace);
113  fTTF->fOpened = false;
114  }
115  delete fTTF;
116 #endif
117 }
118 void hippodraw::TextTTF::setFileName(const std::string& aFileName){
119  m_fileName = aFileName;
120  fInitFont = true;
121 }
122 void hippodraw::TextTTF::setString(const std::string& aString) {
123  m_strings.clear();
124  m_strings.push_back(aString);
125  fInitFont = true;
126 }
127 void hippodraw::TextTTF::setStrings(const std::vector<std::string>& aStrings) {
128  m_strings = aStrings;
129  fInitFont = true;
130 }
131 void hippodraw::TextTTF::setSize(float aSize){
132  m_size = aSize;
133  fInitFont = true;
134 }
138  fInitFont = true;
139 }
141  fRotated = aYesNo;
142 }
145 )
148 {
149 #ifdef HAVE_TTF
151  if(fInitFont) {
152  fPointSize = (int)m_size;
153  initFont();
154  fInitFont = false;
155  }
156  } /*
157  else if(m_viewportMapping==TextTTF::RESCALE) {
158  SbViewportRegion vpr = SoViewportRegionElement::get(aAction->getState());
159  const SbVec2s& win = vpr.getViewportSizePixels();
160  if( fInitFont || (win[0]!=fViewportWidth) || (win[1]!=fViewportHeight) ) {
161  if(win[0]<=win[1]) {
162  fPointSize = (int)(m_size * win[0]);
163  } else {
164  fPointSize = (int)(m_size * win[1]);
165  }
166  initFont();
167  fInitFont = false;
168  fViewportWidth = win[0];
169  fViewportHeight = win[1];
170  }
171  } else if(m_viewportMapping==TextTTF::ADJUST) {
172  SbViewportRegion vpr = SoViewportRegionElement::get(aAction->getState());
173  const SbVec2s& win = vpr.getViewportSizePixels();
174  if( fInitFont || (win[0]!=fViewportWidth) || (fViewportHeight!=win[1]) ) {
175  // Get size with current point size;
176  SbVec2s sz = getTextSizePixels();
177  //printf("debug : sz : %d %d : %d %d\n",win[0],win[1],sz[0],sz[1]);
178  if( (sz[0]>0) && (sz[1]>0)) {
179  if(win[0]<=win[1]) {
180  if(sz[0]<=sz[1]) {
181  fPointSize =
182  (int)(((float)fPointSize) * ((float)win[1])/((float)sz[1]));
183  } else {
184  fPointSize = (int)(fPointSize * win[0]/((float)sz[0]));
185  }
186  } else {
187  if(sz[0]<=sz[1]) {
188  fPointSize = (int)(fPointSize * win[1]/((float)sz[1]));
189  } else {
190  fPointSize = (int)(fPointSize * win[0]/((float)sz[0]));
191  }
192  }
193  initFont();
194  //sz = getTextSizePixels();
195  //printf("debug : new : sz : %d %d : %d %d\n",win[0],win[1],sz[0],sz[1]);
196  }
197  fInitFont = false;
198  fViewportWidth = win[0];
199  fViewportHeight = win[1];
200  }
201  }
202  */
203 
204  if(fStatus==false) return;
205 
206  float red = 0;
207  float green = 0;
208  float blue = 0;
209  glPushAttrib( (GLbitfield)(GL_CURRENT_BIT | GL_ENABLE_BIT));
210 #ifdef WIN32
211  // Pb on Windows : depth test is out over bitmap !
212  glDisable(GL_DEPTH_TEST);
213 #endif
214  glDisable(GL_LIGHTING);
215  glColor3f(red,green,blue);
216 #endif
217 
218 #ifdef HAVE_TTF
219  fTTF->fXJustifyTranslation = 0;
220  fTTF->fYJustifyTranslation = 0;
221  short w,h;
223  } else if(m_horizontalJustification==CENTER) {
224  getTextSizePixels(w,h);
225  fTTF->fXJustifyTranslation = 0.5F * w;
226  } else if(m_horizontalJustification==RIGHT) {
227  getTextSizePixels(w,h);
228  fTTF->fXJustifyTranslation = w;
229  }
230 
232  } else if(m_verticalJustification==MIDDLE) {
233  getTextSizePixels(w,h);
234  fTTF->fYJustifyTranslation = 0.5F * h;
235  } else if(m_verticalJustification==TOP) {
236  getTextSizePixels(w,h);
237  fTTF->fYJustifyTranslation = h;
238  }
239 #endif
240 
241  // glRasterPos3f fixes also
242  // the color for rasterisation. Then
243  // glColor3f should be done before it.
244  //glRasterPos3f(0,0,0);
245 
246  glPixelStorei(GL_UNPACK_ALIGNMENT,1);
247  // Do a push, pop to correct a deffect of Mesa-3.1.
248  // If not, further line drawing will have bad colors.
249  // The glPopAttrib will compell a reinitialisation of
250  // some internal Mesa state.
251  //glPushAttrib(GL_ALL_ATTRIB_BITS);
252  //glPopAttrib();
253 
254  int linen = m_strings.size();
255  for(int count=0;count<linen;count++) {
256  renderString(m_strings[count]);
257  }
258 
259  glPopAttrib();
260 
261 }
265 )
268 {
269  fStatus = false;
270 #ifdef HAVE_TTF
271  if(fPointSize<=0) return;
272 
273  if(fTTF->fOpened==true) {
274  free(fTTF->fBitmap.bitmap);
275  TT_Done_Glyph(fTTF->fGlyph);
276  TT_Done_Instance(fTTF->fInstance);
277  TT_Close_Face(fTTF->fFace);
278  fTTF->fOpened = false;
279  }
280 
281  char* ttf_path = ::getenv("TTFPATH");
282  std::string ttfpath = (!ttf_path ? "" : ttf_path);
283  if(ttfpath=="") {
284  std::string fullName = m_fileName;
285  if(m_fileName.find(".ttf")==std::string::npos) fullName += ".ttf";
286  TT_Error error = TT_Open_Face(*fEngine,fullName.c_str(),&(fTTF->fFace));
287  if(error) {
288  std::cout << "TextTTF::initFont : could not find or open file "
289  << m_fileName << std::endl;
290  return;
291  }
292  } else {
293 
294  char* path = (char*)ttfpath.c_str();
295  std::vector<std::string> paths;
296  char* token = strtok(path," ");
297  do {
298  paths.push_back(std::string(token));
299  } while( (token = strtok(NULL," "))!=NULL);
300 
301  bool found = false;
302  unsigned int index;
303  for(index=0;index<paths.size();index++) {
304  std::string fullName = paths[index];
305 #ifdef WIN32
306  fullName += "\\";
307 #else
308  fullName += "/";
309 #endif
310  fullName += m_fileName;
311  if(m_fileName.find(".ttf")==std::string::npos) fullName += ".ttf";
312  TT_Error error =
313  TT_Open_Face(*fEngine,fullName.c_str(),&(fTTF->fFace));
314  if(error) continue;
315  found = true;
316  break;
317  }
318 
319  if(found==false) {
320  std::cout << "TextTTF::initFont : could not find or open file "
321  << m_fileName << std::endl;
322  return;
323  }
324  }
325 
326 
327  TT_Face_Properties properties;
328  TT_Error error = TT_Get_Face_Properties(fTTF->fFace, &properties );
329  if(error) {
330  std::cout << "TextTTF::initFont : could not get face properties" << std::endl;
331  return;
332  }
333 
334  // Look for a Unicode charmap :
335  unsigned short n = properties.num_CharMaps;
336  unsigned short i;
337  for ( i = 0; i < n; i++ ) {
338  unsigned short platform, encoding;
339  TT_Get_CharMap_ID( fTTF->fFace, i, &platform, &encoding );
340  if ( (platform == 3 && encoding == 1 ) ||
341  (platform == 0 && encoding == 0 ) ) {
342  TT_Get_CharMap( fTTF->fFace, i, &(fTTF->fCharMap) );
343  i = n + 1;
344  }
345  }
346  if ( i == n ) {
347  std::cout << "TextTTF::initFont : this font doesn't contain any Unicode mapping table" << std::endl;
348  return;
349  }
350  //printf("debug : asc %d\n",properties.vertical->Ascender);
351 
352  fTTF->fNumGlyphs = properties.num_Glyphs;
353 
354  error = TT_New_Glyph( fTTF->fFace, &(fTTF->fGlyph) );
355  if(error) {
356  std::cout << "TextTTF::initFont : could not create glyph container" << std::endl;
357  return;
358  }
359 
360  error = TT_New_Instance( fTTF->fFace, &(fTTF->fInstance) );
361  if(error) {
362  std::cout << "TextTTF::initFont : could not create instance" << std::endl;
363  return;
364  }
365 
366  // Give screen resolution.
367  // Device resolution = # of pixels/inch.
368  // Around 96 for screen (300 for printer).
369  error = TT_Set_Instance_Resolutions(fTTF->fInstance, 96, 96 );
370  if (error) {
371  std::cout << "TextTTF::initFont : Could not set instance resolution" << std::endl;
372  return;
373  }
374 
375  // Give size of a character in "pt" :
376  // 1 pt = 1/72 inch.
377  // Si n pt the char will do : n * 96 /72 pixels on screen.
378  // Exa : 64 pt = 64 * 96 /72 = 85 pixels on screen.
379  error = TT_Set_Instance_PointSize(fTTF->fInstance,fPointSize);
380  //error = TT_Set_Instance_CharSize(fTTF->fInstance,fPointSize * 64);
381  if (error) {
382  std::cout << "TextTTF::initFont : Could not set instance point size" << std::endl;
383  return;
384  }
385 
386  error = TT_Get_Instance_Metrics(fTTF->fInstance,
387  &(fTTF->fInstanceMetrics));
388  if (error) {
389  std::cout << "TextTTF::initFont : could not get instance metric" << std::endl;
390  return;
391  }
392 
393  // fInstanceMetrics.y_ppem, x_ppem # of screen pixels.
394  fTTF->fBitmap.rows = fTTF->fInstanceMetrics.y_ppem;
395  fTTF->fBitmap.width = fTTF->fInstanceMetrics.x_ppem;
396  // # of bytes that contains 'width'.
397  fTTF->fBitmap.cols = (fTTF->fBitmap.width + 7)/8;
398  fTTF->fBitmap.flow = TT_Flow_Up;
399  fTTF->fBitmap.size = (long)(fTTF->fBitmap.rows * fTTF->fBitmap.cols);
400  fTTF->fBitmap.bitmap = malloc( (int)fTTF->fBitmap.size );
401  if(!fTTF->fBitmap.bitmap) return;
402 
403  fTTF->fHinted = true;
404 
405  /* printf("debug : i char size %d pt ; ppem %d %d ; res %d %d\n",
406  fInstanceMetrics.pointSize,
407  fInstanceMetrics.x_ppem,fInstanceMetrics.y_ppem,
408  fInstanceMetrics.x_resolution,fInstanceMetrics.y_resolution);
409  */
410 
411  //printf("debug : size rows %d cols %d\n",fBitmap.rows,fBitmap.cols);
412 
413  //printf("debug : TextTTF : update\n");
414 
415  fTTF->fOpened = true;
416 
417  fStatus = true;
418 #endif
419 }
422  const std::string& aString
423 )
426 {
427  if(aString=="") return;
428 #ifdef HAVE_TTF
429  fTTF->fNewLine = false;
430  fTTF->fWidth = 0;
431  int l = aString.size();
432  for(int count=0;count<l;count++) {
433  if(count==l-1) fTTF->fNewLine = true;
434  renderCharacter(aString[count]);
435  }
436 #endif
437 }
440  char aChar
441 )
443 /* Convert an ASCII string to a string of glyph indexes. */
444 /* */
445 /* IMPORTANT NOTE: */
446 /* */
447 /* There is no portable way to convert from any system's char. code */
448 /* to Unicode. This function simply takes a char. string as argument */
449 /* and "interprets" each character as a Unicode char. index with no */
450 /* further check. */
451 /* */
452 /* This mapping is only valid for the ASCII character set (i.e., */
453 /* codes 32 to 127); all other codes (like accentuated characters) */
454 /* will produce more or less random results, depending on the system */
455 /* being run. */
456 
457 
458 {
459 #ifdef HAVE_TTF
460  short index = TT_Char_Index( fTTF->fCharMap, (short)aChar);
461 
462  if((index<0)||(index>=fTTF->fNumGlyphs)) return;
463 
464  //postInfo("TextTTF::renderCharacter","debug 001");
465 
466  TT_Error error = fTTF->loadTrueTypeChar(index);
467  if (error) {
468  std::cout << "TextTTF::renderCharacter." << std::endl;
469  return;
470  }
471 
472  // Metric infos are given in "Char_PointSize * 64 units".
473  TT_Big_Glyph_Metrics metrics;
474  error = TT_Get_Glyph_Big_Metrics( fTTF->fGlyph, &metrics );
475  if (error) {
476  std::cout << "TextTTF::renderCharacter : could not get glyph metrics"
477  << std::endl;
478  return;
479  }
480 
481  /* printf("debug : bb xmn %d ymn %d xmx %d ymx %d ; bX %d bY %d ; adv %d %d\n",
482  metrics.bbox.xMin,metrics.bbox.yMin,
483  metrics.bbox.xMax,metrics.bbox.yMax,
484  metrics.horiBearingX,metrics.horiBearingY,
485  metrics.horiAdvance,metrics.vertAdvance);
486  */
487 
488  // To bring the whole glyph in the bitmap.
489  TT_F26Dot6 xmin, ymin;
490  xmin = metrics.bbox.xMin & -64;
491  ymin = metrics.bbox.yMin & -64;
492 
493  //printf("debug : xx %d %d\n",xmin,ymin);
494 
495  memset( fTTF->fBitmap.bitmap, 0, fTTF->fBitmap.size );
496  error = TT_Get_Glyph_Bitmap( fTTF->fGlyph,
497  &(fTTF->fBitmap),
498  -xmin, -ymin);
499  if (error) {
500  std::cout << "TextTTF::renderCharacter : could not get glyph bitmap"
501  << std::endl;
502  } else {
503 
504  TT_F26Dot6 xmove,ymove;
505  if(fTTF->fNewLine==true) {
506  xmove = -fTTF->fWidth;
507  //ymove = -(fTTF->fInstanceMetrics.y_ppem + 10);
508  ymove = - (metrics.vertAdvance/64);
509  fTTF->fNewLine = false;
510  } else {
511  //xmove = fInstanceMetrics.x_ppem + 3;
512  xmove = metrics.horiAdvance/64;
513  ymove = 0;
514  fTTF->fWidth += (TT_UShort)xmove;
515  }
516 
517  float xorig = fTTF->fXJustifyTranslation;
518  float yorig = (float)(-ymin/64)+fTTF->fYJustifyTranslation;
519 
520  if(fRotated) {
521  GLubyte* pfrom = (GLubyte*)fTTF->fBitmap.bitmap;
522  GLsizei bwidth = fTTF->fBitmap.rows;
523  GLsizei bheight = fTTF->fBitmap.width;
524  GLubyte* bptr = new GLubyte[bwidth * bheight];
525  int irow;
526  for(irow=0;irow<fTTF->fBitmap.rows;irow++) {
527  int icol = 0;
528  for(int ibyte=0;ibyte<fTTF->fBitmap.cols;ibyte++) {
529  GLubyte byte = *pfrom; //Contains 8 pixels.
530  pfrom++;
531  GLubyte pixel8 = (byte >> 0) & 0x1;
532  GLubyte pixel7 = (byte >> 1) & 0x1;
533  GLubyte pixel6 = (byte >> 2) & 0x1;
534  GLubyte pixel5 = (byte >> 3) & 0x1;
535  GLubyte pixel4 = (byte >> 4) & 0x1;
536  GLubyte pixel3 = (byte >> 5) & 0x1;
537  GLubyte pixel2 = (byte >> 6) & 0x1;
538  GLubyte pixel1 = (byte >> 7) & 0x1;
539 
540  int bicol = fTTF->fBitmap.rows-irow-1; // To have + 90 deg.
541 
542  int birow = icol;
543  if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel1;
544  icol++;
545 
546  birow = icol;
547  if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel2;
548  icol++;
549 
550  birow = icol;
551  if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel3;
552  icol++;
553 
554  birow = icol;
555  if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel4;
556  icol++;
557 
558  birow = icol;
559  if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel5;
560  icol++;
561 
562  birow = icol;
563  if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel6;
564  icol++;
565 
566  birow = icol;
567  if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel7;
568  icol++;
569 
570  birow = icol;
571  if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel8;
572  icol++;
573  }
574  }
575  GLubyte* ptr = bptr;
576  int bcols = (bwidth + 7)/8;
577  GLubyte* bptr2 = new GLubyte[bheight * bcols];
578  GLubyte* ptr2 = bptr2;
579  for(irow=0;irow<bheight;irow++) {
580  int icol = 0;
581  for(int ibyte=0;ibyte<bcols;ibyte++) {
582  GLubyte byte = 0;
583  if(icol<bwidth) {
584  byte = byte | ((*ptr) << 7);
585  ptr++;icol++;
586  }
587  if(icol<bwidth) {
588  byte = byte | ((*ptr) << 6);
589  ptr++;icol++;
590  }
591  if(icol<bwidth) {
592  byte = byte | ((*ptr) << 5);
593  ptr++;icol++;
594  }
595  if(icol<bwidth) {
596  byte = byte | ((*ptr) << 4);
597  ptr++;icol++;
598  }
599  if(icol<bwidth) {
600  byte = byte | ((*ptr) << 3);
601  ptr++;icol++;
602  }
603  if(icol<bwidth) {
604  byte = byte | ((*ptr) << 2);
605  ptr++;icol++;
606  }
607  if(icol<bwidth) {
608  byte = byte | ((*ptr) << 1);
609  ptr++;icol++;
610  }
611  if(icol<bwidth) {
612  byte = byte | ((*ptr) << 0);
613  ptr++;icol++;
614  }
615  *ptr2 = byte;ptr2++;
616  }
617  }
618  glBitmap(bwidth,bheight,xorig+bwidth,yorig,(float)ymove,(float)xmove,
619  (GLubyte*)bptr2);
620  delete [] bptr;
621  delete [] bptr2;
622  } else {
623  glBitmap(fTTF->fBitmap.width,fTTF->fBitmap.rows,
624  xorig,yorig,(float)xmove,(float)ymove,
625  (GLubyte*)fTTF->fBitmap.bitmap);
626  }
627  }
628 #else
629  aChar = 0;
630 #endif
631 }
634  short& aWidth
635 ,short& aHeight
636 )
639 {
640  aWidth = 0;
641  aHeight = 0;
642  if(fStatus==false) return false;
643 #ifdef HAVE_TTF
644  int linen = m_strings.size();
645  fTTF->fTextWidth = 0;
646  fTTF->fTextHeight = 0;
647  for(int count=0;count<linen;count++) {
648  const std::string& s = m_strings[count];
649  if(s=="") continue; // Must be coherent with GLRender.
650  fTTF->fNewLine = false;
651  fTTF->fWidth = 0;
652  int l = s.size();
653  TT_F26Dot6 yMax = 0;
654  TT_F26Dot6 yMin = 0;
655  for(int i=0;i<l;i++) {
656  if(i==l-1) fTTF->fNewLine = true;
657  char c = s[i];
658  short index = TT_Char_Index(fTTF->fCharMap,(short)c);
659  if((index<0)||(index>=fTTF->fNumGlyphs)) continue; //?
660  TT_Error error = fTTF->loadTrueTypeChar(index);
661  if (error) {
662  std::cout << "TextTTF::getTextSizePixels" << std::endl;
663  continue; // Same as GLRender.
664  }
665  // Metric infos are given in "Char_PointSize * 64 units".
666  TT_Big_Glyph_Metrics metrics;
667  error = TT_Get_Glyph_Big_Metrics( fTTF->fGlyph, &metrics );
668  if (error) {
669  std::cout << "TextTTF::getTextSizePixels : could not get glyph metrics"
670  << std::endl;
671  continue; //Same as GLRender.
672  }
673  //TT_F26Dot6 xmin, ymin;
674  //xmin = metrics.bbox.xMin & -64;
675  //ymin = metrics.bbox.yMin & -64;
676  TT_F26Dot6 xmove,ymove;
677  if(fTTF->fNewLine==true) {
678  fTTF->fWidth += (TT_UShort)metrics.horiAdvance/64;
679  xmove = -fTTF->fWidth;
680  //ymove = -(fTTF->fInstanceMetrics.y_ppem + 10);
681  ymove = - (metrics.vertAdvance/64);
682  fTTF->fNewLine = false;
683  //
684  fTTF->fTextWidth = MAXIMUM(fTTF->fTextWidth,fTTF->fWidth);
685  if(count==0) fTTF->fTextHeight += yMax; // First line.
686  if(count!=linen-1) fTTF->fTextHeight += (TT_UShort)-ymove;
687  if(count==linen-1) fTTF->fTextHeight += -yMin; // Last line.
688  } else {
689  //xmove = fInstanceMetrics.x_ppem + 3;
690  xmove = metrics.horiAdvance/64;
691  ymove = 0;
692  fTTF->fWidth += (TT_UShort)xmove;
693  }
694  yMax = MAXIMUM(yMax,(metrics.bbox.yMax & -64)/64);
695  yMin = MINIMUM(yMin,(metrics.bbox.yMin & -64)/64);
696  }
697  }
698  aWidth = fTTF->fTextWidth;
699  aHeight = fTTF->fTextHeight;
700  return true;
701 #else
702  return false;
703 #endif
704 }

Generated for HippoDraw Class Library by doxygen