PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plfreetype.c
Go to the documentation of this file.
1 // $Id: plfreetype.c 12661 2013-11-05 16:24:11Z airwin $
2 //
3 // Copyright (C) 2002, 2004, 2005 Andrew Roach
4 // Copyright (C) 2002 Maurice LeBrun
5 // Copyright (C) 2002-2012 Alan W. Irwin
6 // Copyright (C) 2003, 2004 Joao Cardoso
7 // Copyright (C) 2003, 2004, 2005 Rafael Laboissiere
8 // Copyright (C) 2004 Andrew Ross
9 //
10 // This file is part of PLplot.
11 //
12 // PLplot is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU Library General Public License as published
14 // by the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
16 //
17 // PLplot is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU Library General Public License for more details.
21 //
22 // You should have received a copy of the GNU Library General Public License
23 // along with PLplot; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 //
26 //
27 // Support routines for freetype font engine
28 //
29 // This file contains a series of support routines for drivers interested
30 // in using freetype rendered fonts instead of plplot plotter fonts.
31 // Freetype supports a gerth of font formats including TrueType, OpenType,
32 // Adobe Type1, Type42 etc... the list seems almost endless. Any bitmap
33 // driver should be able to use any of these freetype fonts from plplot if
34 // these routines are properly initialised.
35 //
36 // Freetype support is not intended to be a "feature" of the common API,
37 // but is implemented as a driver-specific optional extra invoked via the
38 // -drvopt command line toggle. It is intended to be used in the context of
39 // "PLESC_HAS_TEXT" for any bitmap drivers without native font support.
40 // Implementing freetype in this manner minimise changes to the overall
41 // API. Because of this approach, there is not a "wealth" of font options
42 // available to the programmer. You can not do anything you can't do for a
43 // normal freetype plotter font like boldface. You can do most of the
44 // things that you can do with a plotter font however, like greek
45 // characters superscripting, and selecting one of the four "pre-defined"
46 // plplot font types. At present underlining and overlining are not
47 // supported.
48 //
49 // To give the user some level of control over the fonts that are used,
50 // environmental variables can be set to over-ride the definitions used by
51 // the five default plplot fonts.
52 //
53 // The exact syntax for evoking freetype fonts is dependant on each
54 // driver, but for the GD and GNUSVGA drivers I have followed the syntax of
55 // the PS driver and use the command-line switch of "-drvopt text" to
56 // activate the feature, and suggest other programmers do the same for
57 // commonality.
58 //
59 // Both anti-aliased and monochrome font rendering is supported by these
60 // routines. How these are evoked depends on the programmer, but with the
61 // GD and GNUSVGA driver families I have used the command-line switch
62 // "-drvopt smooth" to activate the feature; but, considering you also need
63 // to turn freetype on, it would probably really be more like "-drvopt
64 // text,smooth".
65 //
66 //
67 
68 #if !defined ( WIN32 ) || defined ( __GNUC__ )
69  #include <unistd.h>
70 #else
71  #define F_OK 1
72  #include <stdio.h>
73 int access( char *filename, int flag )
74 {
75  FILE *infile;
76  infile = fopen( filename, "r" );
77  if ( infile != NULL )
78  {
79  fclose( infile );
80  return 0;
81  }
82  else
83  {
84  return 1;
85  }
86 }
87 #endif
88 
89 #define makeunixslash( b ) do { char *I; for ( I = b; *I != 0; *I++ ) if ( *I == '\\' ) *I = '/';} while ( 0 )
90 
91 #include "plDevs.h"
92 #include "plplotP.h"
93 #include "drivers.h"
94 #ifdef PL_HAVE_FREETYPE
95 #include "plfreetype.h"
96 #include "plfci-truetype.h"
97 
98 #define FT_Data _FT_Data_
99 
100 // Font lookup table that is constructed in plD_FreeType_init
102 // TOP LEVEL DEFINES
103 
104 // Freetype lets you set the text size absolutely. It also takes into
105 // account the DPI when doing so. So does plplot. Why, then, is it that the
106 // size of the text drawn by plplot is bigger than the text drawn by
107 // freetype when given IDENTICAL parameters ? Perhaps I am missing
108 // something somewhere, but to fix this up we use TEXT_SCALING_FACTOR to
109 // set a scaling factor to try and square things up a bit.
110 //
111 
112 #define TEXT_SCALING_FACTOR .7
113 
114 // default size of temporary text buffer
115 // If we wanted to be fancy we could add sizing, but this should be big enough
116 
117 #define NTEXT_ALLOC 1024
118 
119 //--------------------------------------------------------------------------
120 // Some debugging macros
121 //--------------------------------------------------------------------------
122 
123 #define Debug6( a, b, c, d, e, f ) do { if ( pls->debug ) { fprintf( stderr, a, b, c, d, e, f ); } } while ( 0 )
124 
125 
126 // FUNCTION PROTOTYPES
127 
128 // Public prototypes, generally available to the API
129 
130 void plD_FreeType_init( PLStream *pls );
131 void plD_render_freetype_text( PLStream *pls, EscText *args );
132 void plD_FreeType_Destroy( PLStream *pls );
133 void pl_set_extended_cmap0( PLStream *pls, int ncol0_width, int ncol0_org );
134 void pl_RemakeFreeType_text_from_buffer( PLStream *pls );
135 void plD_render_freetype_sym( PLStream *pls, EscText *args );
136 
137 // Private prototypes for use in this file only
138 
139 static void FT_PlotChar( PLStream *pls, FT_Data *FT, FT_GlyphSlot slot, int x, int y );
140 static void FT_SetFace( PLStream *pls, PLUNICODE fci );
141 static PLFLT CalculateIncrement( int bg, int fg, int levels );
142 
143 // These are never defined, maybe they will be used in the future?
144 //
145 // static void pl_save_FreeType_text_to_buffer (PLStream *pls, EscText *args);
146 // static FT_ULong hershey_to_unicode (char in);
147 //
148 //
149 
150 static void FT_WriteStrW( PLStream *pls, const PLUNICODE *text, short len, int x, int y );
151 static void FT_StrX_YW( PLStream *pls, const PLUNICODE *text, short len, int *xx, int *yy, int *overyy, int *underyy );
152 
153 //--------------------------------------------------------------------------
154 // FT_StrX_YW()
155 //
156 // Returns the dimensions of the text box. It does this by fully parsing
157 // the supplied text through the rendering engine. It does everything
158 // but draw the text. This seems, to me, the easiest and most accurate
159 // way of determining the text's dimensions. If/when caching is added,
160 // the CPU hit for this "double processing" will be minimal.
161 //--------------------------------------------------------------------------
162 
163 void
164 FT_StrX_YW( PLStream *pls, const PLUNICODE *text, short len, int *xx, int *yy, int *overyy, int *underyy )
165 {
166  FT_Data *FT = (FT_Data *) pls->FT;
167  short i = 0;
168  FT_Vector akerning, adjust;
169  int x = 0, y = 0, startingy;
170  char esc;
171 
172  plgesc( &esc );
173 
174 //
175 // Things seems to work better with this line than without it;
176 // I guess because there is no vertical kerning or advancement for most
177 // non-transformed fonts, so we need to define *something* for the y height,
178 // and this is the best thing I could think of.
179 //
180 
181  y -= (int) FT->face->size->metrics.height;
182  startingy = y;
183  *yy = y; //note height is negative!
184  *overyy = 0;
185  *underyy = 0;
186  adjust.x = 0;
187  adjust.y = 0;
188 
189 // walk through the text character by character
190  for ( i = 0; i < len; i++ )
191  {
192  if ( ( text[i] == (PLUNICODE) esc ) && ( text[i - 1] != (PLUNICODE) esc ) )
193  {
194  if ( text[i + 1] == (PLUNICODE) esc )
195  continue;
196 
197  switch ( text[i + 1] )
198  {
199  case 'u': // super script
200  case 'U': // super script
201  adjust.y = FT->face->size->metrics.height / 2;
202  adjust.x = 0;
203  FT_Vector_Transform( &adjust, &FT->matrix );
204  x += (int) adjust.x;
205  y -= (int) adjust.y;
206  //calculate excess height from superscripts, this will need changing if scale of sub/superscripts changes
207  *overyy = y - startingy < *overyy ? y - startingy : *overyy;
208  i++;
209  break;
210 
211  case 'd': // subscript
212  case 'D': // subscript
213  adjust.y = -FT->face->size->metrics.height / 2;
214  adjust.x = 0;
215  FT_Vector_Transform( &adjust, &FT->matrix );
216  x += (int) adjust.x;
217  y -= (int) adjust.y;
218  //calculate excess depth from subscripts, this will need changing if scale of sub/superscripts changes
219  *underyy = startingy - y < *underyy ? startingy - y : *underyy;
220  i++;
221  break;
222  }
223  }
224  else if ( text[i] & PL_FCI_MARK )
225  {
226  // FCI in text stream; change font accordingly.
227  FT_SetFace( pls, text[i] );
228  *yy = (int) ( FT->face->size->metrics.height > -*yy ? -FT->face->size->metrics.height : *yy );
229  }
230  else
231  {
232  // see if we have kerning for the particular character pair
233  if ( ( i > 0 ) && FT_HAS_KERNING( FT->face ) )
234  {
235  FT_Get_Kerning( FT->face,
236  text[i - 1],
237  text[i],
238  ft_kerning_default,
239  &akerning );
240  x += (int) ( akerning.x >> 6 ); // add (or subtract) the kerning
241  }
242 
243  //
244  // Next we load the char. This also draws the char, transforms it, and
245  // converts it to a bitmap. At present this is a bit wasteful, but
246  // if/when I add cache support, then this data won't go to waste.
247  // Since there is no sense in going to the trouble of doing anti-aliasing
248  // calculations since we aren't REALLY plotting anything, we will render
249  // this as monochrome since it is probably marginally quicker. If/when
250  // cache support is added, naturally this will have to change.
251  //
252 
253  FT_Load_Char( FT->face, text[i], FT_LOAD_MONOCHROME + FT_LOAD_RENDER );
254 
255  //
256  // Add in the "advancement" needed to position the cursor for the next
257  // character. Unless the text is transformed, "y" will always be zero.
258  // Y is negative because freetype does things upside down
259  //
260 
261  x += (int) ( FT->face->glyph->advance.x );
262  y -= (int) ( FT->face->glyph->advance.y );
263  }
264  }
265 
266 //
267 // Convert from unit of 1/64 of a pixel to pixels, and do it real fast with
268 // a bitwise shift (mind you, any decent compiler SHOULD optimise /64 this way
269 // anyway...)
270 //
271 
272 // (RL, on 2005-01-23) Removed the shift bellow to avoid truncation errors
273 // later.
274 //yy=y>> 6;
275 //xx=x>> 6;
276 //
277  *xx = x;
278 }
279 
280 //--------------------------------------------------------------------------
281 // FT_WriteStrW()
282 //
283 // Writes a string of FT text at the current cursor location.
284 // most of the code here is identical to "FT_StrX_Y" and I will probably
285 // collapse the two into some more efficient code eventually.
286 //--------------------------------------------------------------------------
287 
288 void
289 FT_WriteStrW( PLStream *pls, const PLUNICODE *text, short len, int x, int y )
290 {
291  FT_Data *FT = (FT_Data *) pls->FT;
292  short i = 0, last_char = -1;
293  FT_Vector akerning, adjust;
294  char esc;
295 
296  plgesc( &esc );
297 
298 
299 //
300 // Adjust for the descender - make sure the font is nice and centred
301 // vertically. Freetype assumes we have a base-line, but plplot thinks of
302 // centre-lines, so that's why we have to do this. Since this is one of our
303 // own adjustments, rather than a freetype one, we have to run it through
304 // the transform matrix manually.
305 //
306 // For some odd reason, this works best if we triple the
307 // descender's height and then adjust the height later on...
308 // Don't ask me why, 'cause I don't know. But it does seem to work.
309 //
310 // I really wish I knew *why* it worked better though...
311 //
312 // y-=FT->face->descender >> 6;
313 //
314 
315 #ifdef DODGIE_DECENDER_HACK
316  adjust.y = ( FT->face->descender >> 6 ) * 3;
317 #else
318  adjust.y = ( FT->face->descender >> 6 );
319 #endif
320 
321 // (RL) adjust.y is zeroed below,, making the code above (around
322 // DODGIE_DECENDER_HACK) completely useless. This is necessary for
323 // getting the vertical alignment of text right, which is coped with
324 // in function plD_render_freetype_text now.
325 //
326 
327  adjust.x = 0;
328  adjust.y = 0;
329  FT_Vector_Transform( &adjust, &FT->matrix );
330  x += (int) adjust.x;
331  y -= (int) adjust.y;
332 
333 // (RL, on 2005-01-25) The computation of cumulated glyph width within
334 // the text is done now with full precision, using 26.6 Freetype
335 // arithmetics. We should then shift the x and y variables by 6 bits,
336 // as below. Inside the character for loop, all operations regarding
337 // x and y will be done in 26.6 mode and these variables will be
338 // converted to integers when passed to FT_PlotChar. Notrice that we
339 // are using ROUND and float division instead of ">> 6" now. This
340 // minimizes truncation errors.
341 //
342 
343  x <<= 6;
344  y <<= 6;
345 
346 // walk through the text character by character
347 
348  for ( i = 0; i < len; i++ )
349  {
350  if ( ( text[i] == (PLUNICODE) esc ) && ( text[i - 1] != (PLUNICODE) esc ) )
351  {
352  if ( text[i + 1] == (PLUNICODE) esc )
353  continue;
354 
355  switch ( text[i + 1] )
356  {
357  //
358  // We run the OFFSET for the super-script and sub-script through the
359  // transformation matrix so we can calculate nice and easy the required
360  // offset no matter what's happened rotation wise. Everything else, like
361  // kerning and advancing from character to character is transformed
362  // automatically by freetype, but since the superscript/subscript is a
363  // feature of plplot, and not freetype, we have to make allowances.
364  //
365 
366  case 'u': // super script
367  case 'U': // super script
368  adjust.y = FT->face->size->metrics.height / 2;
369  adjust.x = 0;
370  FT_Vector_Transform( &adjust, &FT->matrix );
371  x += (int) adjust.x;
372  y -= (int) adjust.y;
373  i++;
374  break;
375 
376  case 'd': // subscript
377  case 'D': // subscript
378  adjust.y = -FT->face->size->metrics.height / 2;
379  adjust.x = 0;
380  FT_Vector_Transform( &adjust, &FT->matrix );
381  x += (int) adjust.x;
382  y -= (int) adjust.y;
383  i++;
384  break;
385  }
386  }
387  else if ( text[i] & PL_FCI_MARK )
388  {
389  // FCI in text stream; change font accordingly.
390  FT_SetFace( pls, text[i] );
391  FT = (FT_Data *) pls->FT;
392  FT_Set_Transform( FT->face, &FT->matrix, &FT->pos );
393  }
394  else
395  {
396  // see if we have kerning for the particular character pair
397  if ( ( last_char != -1 ) && ( i > 0 ) && FT_HAS_KERNING( FT->face ) )
398  {
399  FT_Get_Kerning( FT->face,
400  text[last_char],
401  text[i],
402  ft_kerning_default, &akerning );
403  x += (int) akerning.x; // add (or subtract) the kerning
404  y -= (int) akerning.y; // Do I need this in case of rotation ?
405  }
406 
407 
408  FT_Load_Char( FT->face, text[i], ( FT->smooth_text == 0 ) ? FT_LOAD_MONOCHROME + FT_LOAD_RENDER : FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT );
409  FT_PlotChar( pls, FT, FT->face->glyph,
410  ROUND( x / 64.0 ), ROUND( y / 64.0 ) ); // render the text
411 
412  x += (int) FT->face->glyph->advance.x;
413  y -= (int) FT->face->glyph->advance.y;
414 
415  last_char = i;
416  }
417  } // end for
418 }
419 
420 //--------------------------------------------------------------------------
421 // FT_PlotChar()
422 //
423 // Plots an individual character. I know some of this stuff, like colour
424 // could be parsed from plstream, but it was just quicker this way.
425 //--------------------------------------------------------------------------
426 
427 void
428 FT_PlotChar( PLStream *pls, FT_Data *FT, FT_GlyphSlot slot,
429  int x, int y )
430 {
431  unsigned char bittest;
432  short i, k, j;
433  int n = slot->bitmap.pitch;
434  int current_pixel_colour;
435  int R, G, B;
436  PLFLT alpha_a;
437  //PLFLT alpha_b;
438  int xx;
439  short imin, imax, kmin, kmax;
440 
441  // Corners of the clipping rectangle
442  PLINT clipxmin, clipymin, clipxmax, clipymax, tmp;
443  PLINT clpxmi, clpxma, clpymi, clpyma;
444 
445  // Convert clipping box into normal coordinates
446  clipxmin = pls->clpxmi;
447  clipxmax = pls->clpxma;
448  clipymin = pls->clpymi;
449  clipymax = pls->clpyma;
450 
451  if ( plsc->difilt )
452  {
453  difilt( &clipxmin, &clipymin, 1, &clpxmi, &clpxma, &clpymi, &clpyma );
454  difilt( &clipxmax, &clipymax, 1, &clpxmi, &clpxma, &clpymi, &clpyma );
455  }
456 
457 
458  if ( FT->scale != 0.0 ) // scale was set
459  {
460  clipxmin = (PLINT) ( clipxmin / FT->scale );
461  clipxmax = (PLINT) ( clipxmax / FT->scale );
462  if ( FT->invert_y == 1 )
463  {
464  clipymin = (PLINT) ( FT->ymax - ( clipymin / FT->scale ) );
465  clipymax = (PLINT) ( FT->ymax - ( clipymax / FT->scale ) );
466  }
467  else
468  {
469  clipymin = (PLINT) ( clipymin / FT->scale );
470  clipymax = (PLINT) ( clipymax / FT->scale );
471  }
472  }
473  else
474  {
475  clipxmin = (PLINT) ( clipxmin / FT->scalex );
476  clipxmax = (PLINT) ( clipxmax / FT->scalex );
477 
478  if ( FT->invert_y == 1 )
479  {
480  clipymin = (PLINT) ( FT->ymax - ( clipymin / FT->scaley ) );
481  clipymax = (PLINT) ( FT->ymax - ( clipymax / FT->scaley ) );
482  }
483  else
484  {
485  clipymin = (PLINT) ( clipymin / FT->scaley );
486  clipymax = (PLINT) ( clipymax / FT->scaley );
487  }
488  }
489  if ( clipxmin > clipxmax )
490  {
491  tmp = clipxmax;
492  clipxmax = clipxmin;
493  clipxmin = tmp;
494  }
495  if ( clipymin > clipymax )
496  {
497  tmp = clipymax;
498  clipymax = clipymin;
499  clipymin = tmp;
500  }
501 
502  // Comment this out as it fails for cases where we want to plot text
503  // in the background font, i.e. example 24.
504  //
505  //if ((slot->bitmap.pixel_mode==ft_pixel_mode_mono)||(pls->icol0==0)) {
506  if ( slot->bitmap.pixel_mode == ft_pixel_mode_mono )
507  {
508  x += slot->bitmap_left;
509  y -= slot->bitmap_top;
510 
511  imin = (short) MAX( 0, clipymin - y );
512  imax = (short) MIN( slot->bitmap.rows, clipymax - y );
513  for ( i = imin; i < imax; i++ )
514  {
515  for ( k = 0; k < n; k++ )
516  {
517  bittest = 128;
518  for ( j = 0; j < 8; j++ )
519  {
520  if ( ( bittest & (unsigned char) slot->bitmap.buffer[( i * n ) + k] ) == bittest )
521  {
522  xx = x + ( k * 8 ) + j;
523  if ( ( xx >= clipxmin ) && ( xx <= clipxmax ) )
524  FT->pixel( pls, xx, y + i );
525  }
526  bittest >>= 1;
527  }
528  }
529  }
530  }
531 
532 // this is the anti-aliased stuff
533 
534  else
535  {
536  x += slot->bitmap_left;
537  y -= slot->bitmap_top;
538 
539  imin = (short) MAX( 0, clipymin - y );
540  imax = (short) MIN( slot->bitmap.rows, clipymax - y );
541  kmin = (short) MAX( 0, clipxmin - x );
542  kmax = (short) MIN( slot->bitmap.width, clipxmax - x );
543  for ( i = imin; i < imax; i++ )
544  {
545  for ( k = kmin; k < kmax; k++ )
546  {
547  FT->shade = ( slot->bitmap.buffer[( i * slot->bitmap.width ) + k] );
548  if ( FT->shade > 0 )
549  {
550  if ( ( FT->BLENDED_ANTIALIASING == 1 ) && ( FT->read_pixel != NULL ) )
551  // The New anti-aliasing technique
552  {
553  if ( FT->shade == 255 )
554  {
555  FT->pixel( pls, x + k, y + i );
556  }
557  else
558  {
559  current_pixel_colour = FT->read_pixel( pls, x + k, y + i );
560 
561  G = GetGValue( current_pixel_colour );
562  R = GetRValue( current_pixel_colour );
563  B = GetBValue( current_pixel_colour );
564  alpha_a = (float) FT->shade / 255.0;
565 
566  // alpha_b=1.0-alpha_a;
567  // R=(plsc->curcolor.r*alpha_a)+(R*alpha_b);
568  // G=(plsc->curcolor.g*alpha_a)+(G*alpha_b);
569  // B=(plsc->curcolor.b*alpha_a)+(B*alpha_b);
570  //
571 
572  // This next bit of code is, I *think*, computationally
573  // more efficient than the bit above. It results in
574  // an indistinguishable plot, but file sizes are different
575  // suggesting subtle variations doubtless caused by rounding
576  // and/or floating point conversions. Questions are - which is
577  // better ? Which is more "correct" ? Does it make a difference ?
578  // Is one faster than the other so that you'd ever notice ?
579  //
580 
581  R = (int) ( ( ( plsc->curcolor.r - R ) * alpha_a ) + R );
582  G = (int) ( ( ( plsc->curcolor.g - G ) * alpha_a ) + G );
583  B = (int) ( ( ( plsc->curcolor.b - B ) * alpha_a ) + B );
584 
585  FT->set_pixel( pls, x + k, y + i, RGB( R > 255 ? 255 : R, G > 255 ? 255 : G, B > 255 ? 255 : B ) );
586  }
587  }
588  else // The old anti-aliasing technique
589  {
590  FT->col_idx = FT->ncol0_width - ( ( FT->ncol0_width * FT->shade ) / 255 );
591  FT->last_icol0 = pls->icol0;
592  plcol0( pls->icol0 + ( FT->col_idx * ( FT->ncol0_org - 1 ) ) );
593  FT->pixel( pls, x + k, y + i );
594  plcol0( FT->last_icol0 );
595  }
596  }
597  }
598  }
599  }
600 }
601 
602 //--------------------------------------------------------------------------
603 // plD_FreeType_init()
604 //
605 // Allocates memory to Freetype structure
606 // Initialises the freetype library.
607 // Initialises freetype structure
608 //--------------------------------------------------------------------------
609 
610 void plD_FreeType_init( PLStream *pls )
611 {
612  FT_Data *FT;
613  char *a;
614 // font paths and file names can be long so leave generous (1024) room
615  char font_dir[PLPLOT_MAX_PATH];
616  // N.B. must be in exactly same order as TrueTypeLookup
617  const char *env_font_names[N_TrueTypeLookup] = {
618  "PLPLOT_FREETYPE_SANS_FONT",
619  "PLPLOT_FREETYPE_SERIF_FONT",
620  "PLPLOT_FREETYPE_MONO_FONT",
621  "PLPLOT_FREETYPE_SCRIPT_FONT",
622  "PLPLOT_FREETYPE_SYMBOL_FONT",
623  "PLPLOT_FREETYPE_SANS_ITALIC_FONT",
624  "PLPLOT_FREETYPE_SERIF_ITALIC_FONT",
625  "PLPLOT_FREETYPE_MONO_ITALIC_FONT",
626  "PLPLOT_FREETYPE_SCRIPT_ITALIC_FONT",
627  "PLPLOT_FREETYPE_SYMBOL_ITALIC_FONT",
628  "PLPLOT_FREETYPE_SANS_OBLIQUE_FONT",
629  "PLPLOT_FREETYPE_SERIF_OBLIQUE_FONT",
630  "PLPLOT_FREETYPE_MONO_OBLIQUE_FONT",
631  "PLPLOT_FREETYPE_SCRIPT_OBLIQUE_FONT",
632  "PLPLOT_FREETYPE_SYMBOL_OBLIQUE_FONT",
633  "PLPLOT_FREETYPE_SANS_BOLD_FONT",
634  "PLPLOT_FREETYPE_SERIF_BOLD_FONT",
635  "PLPLOT_FREETYPE_MONO_BOLD_FONT",
636  "PLPLOT_FREETYPE_SCRIPT_BOLD_FONT",
637  "PLPLOT_FREETYPE_SYMBOL_BOLD_FONT",
638  "PLPLOT_FREETYPE_SANS_BOLD_ITALIC_FONT",
639  "PLPLOT_FREETYPE_SERIF_BOLD_ITALIC_FONT",
640  "PLPLOT_FREETYPE_MONO_BOLD_ITALIC_FONT",
641  "PLPLOT_FREETYPE_SCRIPT_BOLD_ITALIC_FONT",
642  "PLPLOT_FREETYPE_SYMBOL_BOLD_ITALIC_FONT",
643  "PLPLOT_FREETYPE_SANS_BOLD_OBLIQUE_FONT",
644  "PLPLOT_FREETYPE_SERIF_BOLD_OBLIQUE_FONT",
645  "PLPLOT_FREETYPE_MONO_BOLD_OBLIQUE_FONT",
646  "PLPLOT_FREETYPE_SCRIPT_BOLD_OBLIQUE_FONT",
647  "PLPLOT_FREETYPE_SYMBOL_BOLD_OBLIQUE_FONT"
648  };
649  short i;
650 
651 #if defined ( MSDOS ) || defined ( WIN32 )
652  static char *default_font_names[] = { "arial.ttf", "times.ttf", "timesi.ttf", "arial.ttf",
653  "symbol.ttf" };
654  char WINDIR_PATH[PLPLOT_MAX_PATH];
655  char *b;
656  b = getenv( "WINDIR" );
657  strncpy( WINDIR_PATH, b, PLPLOT_MAX_PATH - 1 );
658  WINDIR_PATH[PLPLOT_MAX_PATH - 1] = '\0';
659 #else
660  const char *default_unix_font_dir = PL_FREETYPE_FONT_DIR;
661 #endif
662 
663 
664  if ( pls->FT )
665  {
666  plwarn( "Freetype seems already to have been initialised!" );
667  return;
668  }
669 
670  if ( ( pls->FT = calloc( 1, (size_t) sizeof ( FT_Data ) ) ) == NULL )
671  plexit( "Could not allocate memory for Freetype" );
672 
673  FT = (FT_Data *) pls->FT;
674 
675  if ( ( FT->textbuf = calloc( NTEXT_ALLOC, 1 ) ) == NULL )
676  plexit( "Could not allocate memory for Freetype text buffer" );
677 
678  if ( FT_Init_FreeType( &FT->library ) )
679  plexit( "Could not initialise Freetype library" );
680 
681  // set to an impossible value for an FCI
682  FT->fci = PL_FCI_IMPOSSIBLE;
683 
684 #if defined ( MSDOS ) || defined ( WIN32 )
685 
686 // First check for a user customised location and if
687 // the fonts aren't found there try the default Windows
688 // locations
689  if ( ( a = getenv( "PLPLOT_FREETYPE_FONT_DIR" ) ) != NULL )
690  strncpy( font_dir, a, PLPLOT_MAX_PATH - 1 );
691  else if ( strlen( PL_FREETYPE_FONT_DIR ) > 0 )
692  strncpy( font_dir, PL_FREETYPE_FONT_DIR, PLPLOT_MAX_PATH - 1 );
693  else if ( WINDIR_PATH == NULL )
694  {
695  //try to guess the font location by looking for arial font on C:
696  if ( access( "c:\\windows\\fonts\\arial.ttf", F_OK ) == 0 )
697  {
698  strcpy( font_dir, "c:/windows/fonts/" );
699  }
700  else if ( access( "c:\\windows\\system\\arial.ttf", F_OK ) == 0 )
701  {
702  strcpy( font_dir, "c:/windows/system/" );
703  }
704  else
705  plwarn( "Could not find font path; I sure hope you have defined fonts manually !" );
706  }
707  else
708  {
709  //Try to guess the font location by looking for Arial font in the Windows Path
710  strncat( WINDIR_PATH, "\\fonts\\arial.ttf", PLPLOT_MAX_PATH - 1 - strlen( WINDIR_PATH ) );
711  if ( access( WINDIR_PATH, F_OK ) == 0 )
712  {
713  b = strrchr( WINDIR_PATH, '\\' );
714  b++;
715  *b = 0;
716  makeunixslash( WINDIR_PATH );
717  strcpy( font_dir, WINDIR_PATH );
718  }
719  else
720  plwarn( "Could not find font path; I sure hope you have defined fonts manually !" );
721  }
722  font_dir[PLPLOT_MAX_PATH - 1] = '\0';
723 
724  if ( pls->debug )
725  fprintf( stderr, "%s\n", font_dir );
726 #else
727 
728 //
729 // For Unix systems, we will set the font path up a little differently in
730 // that the configured PL_FREETYPE_FONT_DIR has been set as the default path,
731 // but the user can override this by setting the environmental variable
732 // "PLPLOT_FREETYPE_FONT_DIR" to something else.
733 // NOTE WELL - the trailing slash must be added for now !
734 //
735 
736  if ( ( a = getenv( "PLPLOT_FREETYPE_FONT_DIR" ) ) != NULL )
737  strncpy( font_dir, a, PLPLOT_MAX_PATH - 1 );
738  else
739  strncpy( font_dir, default_unix_font_dir, PLPLOT_MAX_PATH - 1 );
740 
741  font_dir[PLPLOT_MAX_PATH - 1] = '\0';
742 #endif
743 
744 //
745 // The driver looks for N_TrueTypeLookup environmental variables
746 // where the path and name of these fonts can be OPTIONALLY set,
747 // overriding the configured default values.
748 //
749 
750  for ( i = 0; i < N_TrueTypeLookup; i++ )
751  {
752  if ( ( a = getenv( env_font_names[i] ) ) != NULL )
753  {
754 //
755 // Work out if we have been given an absolute path to a font name, or just
756 // a font name sans-path. To do this we will look for a directory separator
757 // character, which means some system specific junk. DJGPP is all wise, and
758 // understands both Unix and DOS conventions. DOS only knows DOS, and
759 // I assume everything else knows Unix-speak. (Why Bill, didn't you just
760 // pay the extra 15c and get a REAL separator???)
761 //
762 
763 #ifdef MSDOS
764  if ( a[1] == ':' ) // check for MS-DOS absolute path
765 #else
766  if ( ( a[0] == '/' ) || ( a[0] == '~' ) ) // check for unix abs path
767 #endif
768  strncpy( FT->font_name[i], a, PLPLOT_MAX_PATH - 1 );
769 
770  else
771  {
772  strncpy( FT->font_name[i], font_dir, PLPLOT_MAX_PATH - 1 );
773  strncat( FT->font_name[i], a, PLPLOT_MAX_PATH - 1 - strlen( FT->font_name[i] ) );
774  }
775  }
776  else
777  {
778  strncpy( FT->font_name[i], font_dir, PLPLOT_MAX_PATH - 1 );
779  strncat( FT->font_name[i], (const char *) TrueTypeLookup[i].pfont, PLPLOT_MAX_PATH - 1 - strlen( FT->font_name[i] ) );
780  }
781  FT->font_name[i][PLPLOT_MAX_PATH - 1] = '\0';
782 
783  {
784  FILE *infile;
785  if ( ( infile = fopen( FT->font_name[i], "r" ) ) == NULL )
786  {
787  char msgbuf[1024];
788  snprintf( msgbuf, 1024,
789  "plD_FreeType_init: Could not find the freetype compatible font:\n %s",
790  FT->font_name[i] );
791  plwarn( msgbuf );
792  }
793  else
794  {
795  fclose( infile );
796  }
797  }
798  FontLookup[i].fci = TrueTypeLookup[i].fci;
799  if ( FT->font_name[i][0] == '\0' )
800  FontLookup[i].pfont = NULL;
801  else
802  FontLookup[i].pfont = (unsigned char *) FT->font_name[i];
803  }
804 //
805 // Next, we check to see if -drvopt has been used on the command line to
806 // over-ride any settings
807 //
808 }
809 
810 
811 //--------------------------------------------------------------------------
812 // FT_SetFace( PLStream *pls, PLUNICODE fci )
813 //
814 // Sets up the font face and size
815 //--------------------------------------------------------------------------
816 
817 void FT_SetFace( PLStream *pls, PLUNICODE fci )
818 {
819  FT_Data *FT = (FT_Data *) pls->FT;
820  double font_size = pls->chrht * 72 / 25.4; // font_size in points, chrht is in mm
821 
822  // save a copy of character height and resolution
823  FT->chrht = pls->chrht;
824  FT->xdpi = pls->xdpi;
825  FT->ydpi = pls->ydpi;
826 
827  if ( fci != FT->fci )
828  {
829  const char *font_name = plP_FCI2FontName( fci, FontLookup, N_TrueTypeLookup );
830  if ( font_name == NULL )
831  {
832  if ( FT->fci == PL_FCI_IMPOSSIBLE )
833  plexit( "FT_SetFace: Bad FCI and no previous valid font to fall back on" );
834  else
835  plwarn( "FT_SetFace: Bad FCI. Falling back to previous font." );
836  }
837  else
838  {
839  FT->fci = fci;
840 
841  if ( FT->face != NULL )
842  {
843  FT_Done_Face( FT->face );
844  FT->face = NULL;
845  }
846 
847  if ( FT->face == NULL )
848  {
849  if ( FT_New_Face( FT->library, font_name, 0, &FT->face ) )
850  plexit( "FT_SetFace: Error loading a font in freetype" );
851  }
852 
853  //check if the charmap was loaded correctly - freetype only checks for a unicode charmap
854  //if it is not set then use the first found charmap in the font
855  if ( FT->face->charmap == NULL )
856  FT_Select_Charmap( FT->face, FT->face->charmaps[0]->encoding );
857  }
858  }
859  FT_Set_Char_Size( FT->face, 0,
860  (FT_F26Dot6) ( font_size * 64 / TEXT_SCALING_FACTOR ), (FT_UInt) pls->xdpi,
861  (FT_UInt) pls->ydpi );
862 }
863 
864 //--------------------------------------------------------------------------
865 // plD_render_freetype_text()
866 //
867 // Transforms the font
868 // calculates real-world bitmap coordinates from plplot ones
869 // renders text using freetype
870 //--------------------------------------------------------------------------
871 
872 void plD_render_freetype_text( PLStream *pls, EscText *args )
873 {
874  FT_Data *FT = (FT_Data *) pls->FT;
875  int x, y;
876  int w = 0, h = 0, overh = 0, underh = 0;
877  PLFLT *t = args->xform;
878  FT_Matrix matrix;
879  PLFLT angle = PI * pls->diorot / 2;
880  PLUNICODE *line = args->unicode_array;
881  int linelen;
882  int prevlineheights = 0;
883 
884 // Used later in a commented out section (See Rotate The Page), if that
885 // section will never be used again, remove these as well.
886 // PLINT clxmin, clxmax, clymin, clymax;
887 //
888  PLFLT Sin_A, Cos_A;
889  FT_Vector adjust;
890  PLUNICODE fci;
891  FT_Fixed height;
892  PLFLT height_factor;
893 
894  if ( ( args->unicode_array_len > 0 ) )
895  {
896 //
897 // Work out if either the font size, the font face or the
898 // resolution has changed.
899 // If either has, then we will reload the font face.
900 //
901  plgfci( &fci );
902  if ( ( FT->fci != fci ) || ( FT->chrht != pls->chrht ) || ( FT->xdpi != pls->xdpi ) || ( FT->ydpi != pls->ydpi ) )
903  FT_SetFace( pls, fci );
904 
905 
906 // this will help work out underlining and overlining
907 
908  Debug6( "%s %d %d %d %d\n", "plD_render_freetype_text:",
909  FT->face->underline_position >> 6,
910  FT->face->descender >> 6,
911  FT->face->ascender >> 6,
912  ( ( FT->face->underline_position * -1 ) + FT->face->ascender ) >> 6 );
913 
914 
915 
916 //
917 // Split the text into lines based on the newline character
918 //
919  while ( line < args->unicode_array + args->unicode_array_len )
920  {
921  linelen = 0;
922  while ( line[linelen] != '\n' && line + linelen < args->unicode_array + args->unicode_array_len )
923  ++linelen;
924 
925 //
926 // Now we work out how long the text is (for justification etc...) and how
927 // high the text is. This is done on UN-TRANSFORMED text, since we will
928 // apply our own transformations on it later, so it's necessary for us
929 // to to turn all transformations off first, before calling the function
930 // that calculates the text size.
931 //
932 
933  FT->matrix.xx = 0x10000;
934  FT->matrix.xy = 0x00000;
935  FT->matrix.yx = 0x00000;
936  FT->matrix.yy = 0x10000;
937 
938  FT_Vector_Transform( &FT->pos, &FT->matrix );
939  FT_Set_Transform( FT->face, &FT->matrix, &FT->pos );
940 
941  FT_StrX_YW( pls, line, (short) linelen, &w, &h, &overh, &underh );
942 
943 //
944 // Set up the transformation Matrix
945 //
946 // Fortunately this is almost identical to plplot's own transformation matrix;
947 // you have NO idea how much effort that saves ! Some params are in a
948 // different order, and Freetype wants integers whereas plplot likes floats,
949 // but such differences are quite trivial.
950 //
951 // For some odd reason, this needs to be set a different way for DJGPP. Why ?
952 // I wish I knew.
953 //
954 
955 // (RL, on 2005-01-21) The height_factor variable is introduced below.
956 // It is used here and farther below when computing the vertical
957 // adjustment. The rationale for its introduction is as follow: up to
958 // now, the text produced with Hershey fonts was systematically taller
959 // than the same text produced with TT fonts, and tha by a factor of
960 // around 1.125 (I discovered this empirically). This corresponds
961 // roughly to the ratio between total height and the ascender of some
962 // TT faces. Hence the computation below. Remember that descender is
963 // always a negative quantity.
964 //
965 
966  height_factor = (PLFLT) ( FT->face->ascender - FT->face->descender )
967  / FT->face->ascender;
968  height = (FT_Fixed) ( 0x10000 * height_factor );
969 
970 #ifdef DJGPP
971  FT->matrix.xx = (FT_Fixed) ( (PLFLT) height * t[0] );
972  FT->matrix.xy = (FT_Fixed) ( (PLFLT) height * t[2] );
973  FT->matrix.yx = (FT_Fixed) ( (PLFLT) height * t[1] );
974  FT->matrix.yy = (FT_Fixed) ( (PLFLT) height * t[3] );
975 #else
976  FT->matrix.xx = (FT_Fixed) ( (PLFLT) height * t[0] );
977  FT->matrix.xy = (FT_Fixed) ( (PLFLT) height * t[1] );
978  FT->matrix.yx = (FT_Fixed) ( (PLFLT) height * t[2] );
979  FT->matrix.yy = (FT_Fixed) ( (PLFLT) height * t[3] );
980 #endif
981 
982 
983 // Rotate the Font
984 //
985 // If the page has been rotated using -ori, this is where we rotate the
986 // font to point in the right direction. To make things nice and easy, we
987 // will use freetypes matrix math stuff to do this for us.
988 //
989 
990  Cos_A = cos( angle );
991  Sin_A = sin( angle );
992 
993  matrix.xx = (FT_Fixed) ( (PLFLT) 0x10000 * Cos_A );
994 
995 #ifdef DJGPP
996  matrix.xy = (FT_Fixed) ( (PLFLT) 0x10000 * Sin_A * -1.0 );
997  matrix.yx = (FT_Fixed) ( (PLFLT) 0x10000 * Sin_A );
998 #else
999  matrix.xy = (FT_Fixed) ( (PLFLT) 0x10000 * Sin_A );
1000  matrix.yx = (FT_Fixed) ( (PLFLT) 0x10000 * Sin_A * -1.0 );
1001 #endif
1002 
1003  matrix.yy = (FT_Fixed) ( (PLFLT) 0x10000 * Cos_A );
1004 
1005  FT_Matrix_Multiply( &matrix, &FT->matrix );
1006 
1007 
1008 // Calculate a Vector from the matrix
1009 //
1010 // This is closely related to the "transform matrix".
1011 // The matrix is used for rendering the glyph, while the vector is used for
1012 // calculating offsets of the text box, so we need both. Why ? I dunno, but
1013 // we have to live with it, and it works...
1014 //
1015 
1016 
1017  FT_Vector_Transform( &FT->pos, &FT->matrix );
1018 
1019 
1020 // Transform the font face
1021 //
1022 // This is where our matrix transformation is calculated for the font face.
1023 // This is only done once for each unique transformation since it is "sticky"
1024 // within the font. Font rendering is done later, using the supplied matrix,
1025 // but invisibly to us from here on. I don't believe the vector is used, but
1026 // it is asked for.
1027 //
1028 
1029  FT_Set_Transform( FT->face, &FT->matrix, &FT->pos );
1030 
1031 
1032 // Rotate the Page
1033 //
1034 // If the page has been rotated using -ori, this is we recalculate the
1035 // reference point for the text using plplot functions.
1036 //
1037 
1038 // difilt(&args->x, &args->y, 1, &clxmin, &clxmax, &clymin, &clymax);
1039 
1040 
1041 //
1042 // Convert into normal coordinates from virtual coordinates
1043 //
1044 
1045  if ( FT->scale != 0.0 ) // scale was set
1046  {
1047  x = (int) ( args->x / FT->scale );
1048 
1049  if ( FT->invert_y == 1 )
1050  y = (int) ( FT->ymax - ( args->y / FT->scale ) );
1051  else
1052  y = (int) ( args->y / FT->scale );
1053  }
1054  else
1055  {
1056  x = (int) ( args->x / FT->scalex );
1057 
1058  if ( FT->invert_y == 1 )
1059  y = (int) ( FT->ymax - ( args->y / FT->scaley ) );
1060  else
1061  y = (int) ( args->y / FT->scaley );
1062  }
1063 
1064  // Adjust for the justification and character height
1065  //
1066  // Eeeksss... this wasn't a nice bit of code to work out, let me tell you.
1067  // I could not work out an entirely satisfactory solution that made
1068  // logical sense, so came up with an "illogical" one as well.
1069  // The logical one works fine for text in the normal "portrait"
1070  // orientation, and does so for reasons you might expect it to work; But
1071  // for all other orientations, the text's base line is either a little
1072  // high, or a little low. This is because of the way the base-line pos
1073  // is calculated from the decender height. The "dodgie" way of calculating
1074  // the position is to use the character height here, then adjust for the
1075  // decender height by a three-fold factor later on. That approach seems to
1076  // work a little better for rotated pages, but why it should be so, I
1077  // don't understand. You can compile in or out which way you want it by
1078  // defining "DODGIE_DECENDER_HACK".
1079  //
1080  // note: the logic of the page rotation coming up next is that we pump in
1081  // the justification factor and then use freetype to rotate and transform
1082  // the values, which we then use to change the plotting location.
1083  //
1084 
1085 
1086 #ifdef DODGIE_DECENDER_HACK
1087  adjust.y = h;
1088 #else
1089  adjust.y = 0;
1090 #endif
1091 
1092 // (RL, on 2005-01-24) The code below uses floating point and division
1093 // operations instead of integer shift used before. This is slower but
1094 // gives accurate placement of text in plots.
1095 //
1096 
1097 // (RL, on 2005-01-21) The hack below is intended to align single
1098 // glyphs being generated via plpoin. The way to detect this
1099 // situation is completely hackish, I must admit, by checking whether the
1100 // length of the Unicode array is equal 2 and whether the first
1101 // character is actually a font-changing command to font number 4 (for
1102 // symbols). This is ugly because it depends on definitions set
1103 // elsewhere, but it works.
1104 //
1105 // The computation of the vertical and horizontal adjustments are
1106 // based on the bouding box of the glyph being loaded (since there is
1107 // only one glyph in the string in this case, we are okay here).
1108 //
1109 
1110  if ( ( args->unicode_array_len == 2 )
1111  && ( args->unicode_array[0] == ( PL_FCI_MARK | 0x004 ) ) )
1112  {
1113  adjust.x = (FT_Pos) ( args->just * ROUND( (PLFLT) FT->face->glyph->metrics.width / 64.0 ) );
1114  adjust.y = (FT_Pos) ROUND( (PLFLT) FT->face->glyph->metrics.height / 128.0 );
1115  }
1116  else
1117  {
1118 // (RL, on 2005-01-21) The vertical adjustment is set below, making
1119 // the DODGIE conditional moot. I use the value of h as return by FT_StrX_YW,
1120 // which should correspond to the total height of the text being
1121 // drawn. Freetype aligns text around the baseline, while PLplot
1122 // aligns to the center of the ascender portion. We must then adjust
1123 // by half of the ascender and this is why there is a division by
1124 // height_factor below.
1125 //
1126 
1127  adjust.y = (FT_Pos)
1128  ROUND( (PLFLT) FT->face->size->metrics.height / height_factor / 128.0 - ( prevlineheights + overh ) / 64.0 );
1129  adjust.x = (FT_Pos) ( args->just * ROUND( w / 64.0 ) );
1130  }
1131 
1132  FT_Vector_Transform( &adjust, &FT->matrix ); // was /&matrix); - was I using the wrong matrix all this time ?
1133 
1134  x -= (int) adjust.x;
1135  y += (int) adjust.y;
1136 
1137  FT_WriteStrW( pls, line, (short) linelen, x, y ); // write it out
1138 
1139 //
1140 // Move to the next line
1141 //
1142  line += linelen + 1;
1143  prevlineheights += h + overh + underh;
1144  }
1145  }
1146  else
1147  {
1148  plD_render_freetype_sym( pls, args );
1149  }
1150 }
1151 
1152 //--------------------------------------------------------------------------
1153 // plD_FreeType_Destroy()
1154 //
1155 // Restores cmap0 if it had been modifed for anti-aliasing
1156 // closes the freetype library.
1157 // Deallocates memory to the Freetype structure
1158 //--------------------------------------------------------------------------
1159 
1160 void plD_FreeType_Destroy( PLStream *pls )
1161 {
1162  FT_Data *FT = (FT_Data *) pls->FT;
1163  //extern int FT_Done_Library( FT_Library library );
1164 
1165  if ( FT )
1166  {
1167  if ( ( FT->smooth_text == 1 ) && ( FT->BLENDED_ANTIALIASING == 0 ) )
1168  plscmap0n( FT->ncol0_org );
1169  if ( FT->textbuf )
1170  free( FT->textbuf );
1171  FT_Done_Library( FT->library );
1172  free( pls->FT );
1173  pls->FT = NULL;
1174  }
1175 }
1176 
1177 //--------------------------------------------------------------------------
1178 // PLFLT CalculateIncrement( int bg, int fg, int levels)
1179 //
1180 // Takes the value of the foreground, and the background, and when
1181 // given the number of desired steps, calculates how much to incriment
1182 // a value to transition from fg to bg.
1183 // This function only does it for one colour channel at a time.
1184 //--------------------------------------------------------------------------
1185 
1186 static PLFLT CalculateIncrement( int bg, int fg, int levels )
1187 {
1188  PLFLT ret = 0;
1189 
1190  if ( levels > 1 )
1191  {
1192  if ( fg > bg )
1193  ret = ( ( fg + 1 ) - bg ) / levels;
1194  else if ( fg < bg )
1195  ret = ( ( ( fg - 1 ) - bg ) / levels );
1196  }
1197  return ( ret );
1198 }
1199 
1200 //--------------------------------------------------------------------------
1201 // void pl_set_extended_cmap0(PLStream *pls, int ncol0_width, int ncol0_org)
1202 //
1203 // ncol0_width - how many greyscale levels to accolate to each CMAP0 entry
1204 // ncol0_org - the originl number of CMAP0 entries.
1205 //
1206 // This function calcualtes and sets an extended CMAP0 entry for the
1207 // driver. It is assumed that the caller has checked to make sure there is
1208 // room for extending CMAP0 already.
1209 //
1210 // NOTES
1211 // We don't bother calculating an entry for CMAP[0], the background.
1212 // It is assumed the caller has already expanded the size of CMAP[0]
1213 //--------------------------------------------------------------------------
1214 
1215 void pl_set_extended_cmap0( PLStream *pls, int ncol0_width, int ncol0_org )
1216 {
1217  int i, j, k;
1218  int r, g, b;
1219  PLFLT r_inc, g_inc, b_inc;
1220 
1221  for ( i = 1; i < ncol0_org; i++ )
1222  {
1223  r = pls->cmap0[i].r;
1224  g = pls->cmap0[i].g;
1225  b = pls->cmap0[i].b;
1226 
1227  r_inc = CalculateIncrement( pls->cmap0[0].r, r, ncol0_width );
1228  g_inc = CalculateIncrement( pls->cmap0[0].g, g, ncol0_width );
1229  b_inc = CalculateIncrement( pls->cmap0[0].b, b, ncol0_width );
1230 
1231  for ( j = 0, k = ncol0_org + i - 1; j < ncol0_width; j++, k += ( ncol0_org - 1 ) )
1232  {
1233  r -= (int) r_inc;
1234  g -= (int) g_inc;
1235  b -= (int) b_inc;
1236  if ( ( r < 0 ) || ( g < 0 ) || ( b < 0 ) )
1237  plscol0( k, 0, 0, 0 );
1238  else
1239  plscol0( k, ( r > 0xff ? 0xff : r ), ( g > 0xff ? 0xff : g ), ( b > 0xff ? 0xff : b ) );
1240  }
1241  }
1242 }
1243 
1244 
1245 //--------------------------------------------------------------------------
1246 // plD_render_freetype_sym( PLStream *pls, EscText *args )
1247 // PLStream *pls - pointer to plot stream
1248 // EscText *args - pointer to standard "string" object.
1249 //
1250 // This function is a simple rendering function which draws a single
1251 // character at a time. The function is an alternative to the text
1252 // functions which are considerably, and needlessly, more complicated
1253 // than what we need here.
1254 //--------------------------------------------------------------------------
1255 
1256 
1257 void plD_render_freetype_sym( PLStream *pls, EscText *args )
1258 {
1259  FT_Data *FT = (FT_Data *) pls->FT;
1260  int x, y;
1261  FT_Vector adjust;
1262  PLUNICODE fci;
1263 
1264  if ( FT->scale != 0.0 ) // scale was set
1265  {
1266  x = (int) ( args->x / FT->scale );
1267 
1268  if ( FT->invert_y == 1 )
1269  y = (int) ( FT->ymax - ( args->y / FT->scale ) );
1270  else
1271  y = (int) ( args->y / FT->scale );
1272  }
1273  else
1274  {
1275  x = (int) ( args->x / FT->scalex );
1276 
1277  if ( FT->invert_y == 1 )
1278  y = (int) ( FT->ymax - ( args->y / FT->scaley ) );
1279  else
1280  y = (int) ( args->y / FT->scaley );
1281  }
1282 
1283 
1284 //
1285 // Adjust for the descender - make sure the font is nice and centred
1286 // vertically. Freetype assumes we have a base-line, but plplot thinks of
1287 // centre-lines, so that's why we have to do this. Since this is one of our
1288 // own adjustments, rather than a freetype one, we have to run it through
1289 // the transform matrix manually.
1290 //
1291 // For some odd reason, this works best if we triple the
1292 // descender's height and then adjust the height later on...
1293 // Don't ask me why, 'cause I don't know. But it does seem to work.
1294 //
1295 // I really wish I knew *why* it worked better though...
1296 //
1297 // y-=FT->face->descender >> 6;
1298 //
1299 
1300 #ifdef DODGIE_DECENDER_HACK
1301  adjust.y = ( FT->face->descender >> 6 ) * 3;
1302 #else
1303  adjust.y = ( FT->face->descender >> 6 );
1304 #endif
1305 
1306  adjust.x = 0;
1307  FT_Vector_Transform( &adjust, &FT->matrix );
1308  x += (int) adjust.x;
1309  y -= (int) adjust.y;
1310 
1311  plgfci( &fci );
1312  FT_SetFace( pls, fci );
1313 
1314  FT = (FT_Data *) pls->FT;
1315  FT_Set_Transform( FT->face, &FT->matrix, &FT->pos );
1316 
1317  FT_Load_Char( FT->face, args->unicode_char, ( FT->smooth_text == 0 ) ? FT_LOAD_MONOCHROME + FT_LOAD_RENDER : FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT );
1318 
1319 //
1320 // Now we have to try and componsate for the fact that the freetype glyphs are left
1321 // justified, and plplot's glyphs are centred. To do this, we will just work out the
1322 // advancment, halve it, and take it away from the x position. This wont be 100%
1323 // accurate because "spacing" is factored into the right hand side of the glyph,
1324 // but it is as good a way as I can think of.
1325 //
1326 
1327  x -= (int) ( ( FT->face->glyph->advance.x >> 6 ) / 2 );
1328  FT_PlotChar( pls, FT, FT->face->glyph, x, y ); // render the text
1329 }
1330 
1331 
1332 
1333 
1334 #else
1335 int
1337 {
1338  return 0;
1339 }
1340 
1341 #endif