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