• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

plfreetype.c

Go to the documentation of this file.
00001 // $Id: plfreetype.c 11680 2011-03-27 17:57:51Z airwin $
00002 //
00003 // Copyright (C) 2002, 2004, 2005  Andrew Roach
00004 // Copyright (C) 2002  Maurice LeBrun
00005 // Copyright (C) 2002, 2004, 2005  Alan W. Irwin
00006 // Copyright (C) 2003, 2004  Joao Cardoso
00007 // Copyright (C) 2003, 2004, 2005  Rafael Laboissiere
00008 // Copyright (C) 2004  Andrew Ross
00009 //
00010 // This file is part of PLplot.
00011 //
00012 // PLplot is free software; you can redistribute it and/or modify
00013 // it under the terms of the GNU Library General Public License as published
00014 // by the Free Software Foundation; either version 2 of the License, or
00015 // (at your option) any later version.
00016 //
00017 // PLplot is distributed in the hope that it will be useful,
00018 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 // GNU Library General Public License for more details.
00021 //
00022 // You should have received a copy of the GNU Library General Public License
00023 // along with PLplot; if not, write to the Free Software
00024 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00025 //
00026 //
00027 //                  Support routines for freetype font engine
00028 //
00029 //  This file contains a series of support routines for drivers interested
00030 //  in using freetype rendered fonts instead of plplot plotter fonts.
00031 //  Freetype supports a gerth of font formats including TrueType, OpenType,
00032 //  Adobe Type1, Type42 etc... the list seems almost endless. Any bitmap
00033 //  driver should be able to use any of these freetype fonts from plplot if
00034 //  these routines are properly initialised.
00035 //
00036 //  Freetype support is not intended to be a "feature" of the common API,
00037 //  but is  implemented as a driver-specific optional extra invoked via the
00038 //  -drvopt command line toggle. It is intended to be used in the context of
00039 //  "PLESC_HAS_TEXT" for any bitmap drivers without native font support.
00040 //  Implementing freetype in this manner minimise changes to the overall
00041 //  API. Because of this approach, there is not a "wealth" of font options
00042 //  available to the programmer. You can not do anything you can't do for a
00043 //  normal freetype plotter font like boldface. You can do most of the
00044 //  things that you can do with a plotter font however, like greek
00045 //  characters superscripting, and selecting one of the four "pre-defined"
00046 //  plplot font types. At present underlining and overlining are not
00047 //  supported.
00048 //
00049 //  To give the user some level of control over the fonts that are used,
00050 //  environmental variables can be set to over-ride the definitions used by
00051 //  the five default plplot fonts.
00052 //
00053 //  The exact syntax for evoking freetype fonts is dependant on each
00054 //  driver, but for the GD and GNUSVGA drivers I have followed the syntax of
00055 //  the PS driver and use the command-line switch of "-drvopt text" to
00056 //  activate the feature, and suggest other programmers do the same for
00057 //  commonality.
00058 //
00059 //  Both anti-aliased and monochrome font rendering is supported by these
00060 //  routines. How these are evoked depends on the programmer, but with the
00061 //  GD and GNUSVGA driver families I have used the command-line switch
00062 //  "-drvopt smooth" to activate the feature; but, considering you also need
00063 //  to turn freetype on, it would probably really be more like "-drvopt
00064 //  text,smooth".
00065 //
00066 //
00067 
00068 #if !defined ( WIN32 ) || defined ( __GNUC__ )
00069   #include <unistd.h>
00070 #else
00071   #define F_OK    1
00072   #include <stdio.h>
00073 int access( char *filename, int flag )
00074 {
00075     FILE *infile;
00076     infile = fopen( filename, "r" );
00077     if ( infile != NULL )
00078     {
00079         fclose( infile );
00080         return 0;
00081     }
00082     else
00083     {
00084         return 1;
00085     }
00086 }
00087 #endif
00088 
00089 #define makeunixslash( b )    do { char *I; for ( I = b; *I != 0; *I++ ) if ( *I == '\\' ) *I = '/';} while ( 0 )
00090 
00091 #include "plDevs.h"
00092 #include "plplotP.h"
00093 #include "drivers.h"
00094 #ifdef HAVE_FREETYPE
00095 #include "plfreetype.h"
00096 #include "plfci-truetype.h"
00097 
00098 #define FT_Data    _FT_Data_
00099 
00100 // Font lookup table that is constructed in plD_FreeType_init
00101 PLDLLIMPEXP_DATA( FCI_to_FontName_Table ) FontLookup[N_TrueTypeLookup];
00102 //              TOP LEVEL DEFINES
00103 
00104 //  Freetype lets you set the text size absolutely. It also takes into
00105 //  account the DPI when doing so. So does plplot. Why, then, is it that the
00106 //  size of the text drawn by plplot is bigger than the text drawn by
00107 //  freetype when given IDENTICAL parameters ? Perhaps I am missing
00108 //  something somewhere, but to fix this up we use TEXT_SCALING_FACTOR to
00109 //  set a scaling factor to try and square things up a bit.
00110 //
00111 
00112 #define TEXT_SCALING_FACTOR    .7
00113 
00114 // default size of temporary text buffer
00115 // If we wanted to be fancy we could add sizing, but this should be big enough
00116 
00117 #define NTEXT_ALLOC    1024
00118 
00119 //--------------------------------------------------------------------------
00120 //  Some debugging macros
00121 //--------------------------------------------------------------------------
00122 
00123 #define Debug6( a, b, c, d, e, f )    do { if ( pls->debug ) { fprintf( stderr, a, b, c, d, e, f ); } } while ( 0 )
00124 
00125 
00126 //              FUNCTION PROTOTYPES
00127 
00128 //  Public prototypes, generally available to the API
00129 
00130 void plD_FreeType_init( PLStream *pls );
00131 void plD_render_freetype_text( PLStream *pls, EscText *args );
00132 void plD_FreeType_Destroy( PLStream *pls );
00133 void pl_set_extended_cmap0( PLStream *pls, int ncol0_width, int ncol0_org );
00134 void pl_RemakeFreeType_text_from_buffer( PLStream *pls );
00135 void plD_render_freetype_sym( PLStream *pls, EscText *args );
00136 
00137 //  Private prototypes for use in this file only
00138 
00139 static void FT_PlotChar( PLStream *pls, FT_Data *FT, FT_GlyphSlot slot, int x, int y, short colour );
00140 static void FT_SetFace( PLStream *pls, PLUNICODE fci );
00141 static PLFLT CalculateIncrement( int bg, int fg, int levels );
00142 
00143 // These are never defined, maybe they will be used in the future?
00144 //
00145 // static void pl_save_FreeType_text_to_buffer (PLStream *pls, EscText *args);
00146 // static FT_ULong hershey_to_unicode (char in);
00147 //
00148 //
00149 
00150 static void FT_WriteStrW( PLStream *pls, const PLUNICODE  *text, short len, int x, int y );
00151 static void FT_StrX_YW( PLStream *pls, const PLUNICODE *text, short len, int *xx, int *yy );
00152 
00153 //--------------------------------------------------------------------------
00154 // FT_StrX_YW()
00155 //
00156 // Returns the dimensions of the text box. It does this by fully parsing
00157 // the supplied text through the rendering engine. It does everything
00158 // but draw the text. This seems, to me, the easiest and most accurate
00159 // way of determining the text's dimensions. If/when caching is added,
00160 // the CPU hit for this "double processing" will be minimal.
00161 //--------------------------------------------------------------------------
00162 
00163 void
00164 FT_StrX_YW( PLStream *pls, const PLUNICODE *text, short len, int *xx, int *yy )
00165 {
00166     FT_Data   *FT = (FT_Data *) pls->FT;
00167     short     i   = 0;
00168     FT_Vector akerning;
00169     int       x = 0, y = 0;
00170     char      esc;
00171 
00172     plgesc( &esc );
00173 
00174 //
00175 // Things seems to work better with this line than without it;
00176 // I guess because there is no vertical kerning or advancement for most
00177 // non-transformed fonts, so we need to define *something* for the y height,
00178 // and this is the best thing I could think of.
00179 //
00180 
00181     y -= FT->face->size->metrics.height;
00182 
00183 // walk through the text character by character
00184     for ( i = 0; i < len; i++ )
00185     {
00186         if ( ( text[i] == esc ) && ( text[i - 1] != esc ) )
00187         {
00188             if ( text[i + 1] == esc )
00189                 continue;
00190 
00191             switch ( text[i + 1] )
00192             {
00193             case 'u': // super script
00194             case 'd': // subscript
00195             case 'U':
00196             case 'D':
00197                 i++;
00198                 break;
00199             }
00200         }
00201         else if ( text[i] & PL_FCI_MARK )
00202         {
00203             // FCI in text stream; change font accordingly.
00204             FT_SetFace( pls, text[i] );
00205         }
00206         else
00207         {
00208             // see if we have kerning for the particular character pair
00209             if ( ( i > 0 ) && FT_HAS_KERNING( FT->face ) )
00210             {
00211                 FT_Get_Kerning( FT->face,
00212                     text[i - 1],
00213                     text[i],
00214                     ft_kerning_default,
00215                     &akerning );
00216                 x += ( akerning.x >> 6 );        // add (or subtract) the kerning
00217             }
00218 
00219             //
00220             // Next we load the char. This also draws the char, transforms it, and
00221             // converts it to a bitmap. At present this is a bit wasteful, but
00222             // if/when I add cache support, then this data won't go to waste.
00223             // Since there is no sense in going to the trouble of doing anti-aliasing
00224             // calculations since we aren't REALLY plotting anything, we will render
00225             // this as monochrome since it is probably marginally quicker. If/when
00226             // cache support is added, naturally this will have to change.
00227             //
00228 
00229             FT_Load_Char( FT->face, text[i], FT_LOAD_MONOCHROME + FT_LOAD_RENDER );
00230 
00231             //
00232             // Add in the "advancement" needed to position the cursor for the next
00233             // character. Unless the text is transformed, "y" will always be zero.
00234             // Y is negative because freetype does things upside down
00235             //
00236 
00237             x += ( FT->face->glyph->advance.x );
00238             y -= ( FT->face->glyph->advance.y );
00239         }
00240     }
00241 
00242 //
00243 // Convert from unit of 1/64 of a pixel to pixels, and do it real fast with
00244 // a bitwise shift (mind you, any decent compiler SHOULD optimise /64 this way
00245 // anyway...)
00246 //
00247 
00248 // (RL, on 2005-01-23) Removed the shift bellow to avoid truncation errors
00249 // later.
00250 //yy=y>> 6;
00251 //xx=x>> 6;
00252 //
00253     *yy = y;
00254     *xx = x;
00255 }
00256 
00257 //--------------------------------------------------------------------------
00258 // FT_WriteStrW()
00259 //
00260 // Writes a string of FT text at the current cursor location.
00261 // most of the code here is identical to "FT_StrX_Y" and I will probably
00262 // collapse the two into some more efficient code eventually.
00263 //--------------------------------------------------------------------------
00264 
00265 void
00266 FT_WriteStrW( PLStream *pls, const PLUNICODE *text, short len, int x, int y )
00267 {
00268     FT_Data   *FT = (FT_Data *) pls->FT;
00269     short     i   = 0, last_char = -1;
00270     FT_Vector akerning, adjust;
00271     char      esc;
00272 
00273     plgesc( &esc );
00274 
00275 
00276 //
00277 //  Adjust for the descender - make sure the font is nice and centred
00278 //  vertically. Freetype assumes we have a base-line, but plplot thinks of
00279 //  centre-lines, so that's why we have to do this. Since this is one of our
00280 //  own adjustments, rather than a freetype one, we have to run it through
00281 //  the transform matrix manually.
00282 //
00283 //  For some odd reason, this works best if we triple the
00284 //  descender's height and then adjust the height later on...
00285 //  Don't ask me why, 'cause I don't know. But it does seem to work.
00286 //
00287 //  I really wish I knew *why* it worked better though...
00288 //
00289 //   y-=FT->face->descender >> 6;
00290 //
00291 
00292 #ifdef DODGIE_DECENDER_HACK
00293     adjust.y = ( FT->face->descender >> 6 ) * 3;
00294 #else
00295     adjust.y = ( FT->face->descender >> 6 );
00296 #endif
00297 
00298 // (RL) adjust.y is zeroed below,, making the code above (around
00299 // DODGIE_DECENDER_HACK) completely useless.  This is necessary for
00300 // getting the vertical alignment of text right, which is coped with
00301 // in function plD_render_freetype_text now.
00302 //
00303 
00304     adjust.x = 0;
00305     adjust.y = 0;
00306     FT_Vector_Transform( &adjust, &FT->matrix );
00307     x += adjust.x;
00308     y -= adjust.y;
00309 
00310 // (RL, on 2005-01-25) The computation of cumulated glyph width within
00311 // the text is done now with full precision, using 26.6 Freetype
00312 // arithmetics.  We should then shift the x and y variables by 6 bits,
00313 // as below.  Inside the character for loop, all operations regarding
00314 // x and y will be done in 26.6 mode and  these variables will be
00315 // converted to integers when passed to FT_PlotChar.  Notrice that we
00316 // are using ROUND and float division instead of ">> 6" now.  This
00317 // minimizes truncation errors.
00318 //
00319 
00320     x <<= 6;
00321     y <<= 6;
00322 
00323 // walk through the text character by character
00324 
00325     for ( i = 0; i < len; i++ )
00326     {
00327         if ( ( text[i] == esc ) && ( text[i - 1] != esc ) )
00328         {
00329             if ( text[i + 1] == esc )
00330                 continue;
00331 
00332             switch ( text[i + 1] )
00333             {
00334             //
00335             //  We run the OFFSET for the super-script and sub-script through the
00336             //  transformation matrix so we can calculate nice and easy the required
00337             //  offset no matter what's happened rotation wise. Everything else, like
00338             //  kerning and advancing from character to character is transformed
00339             //  automatically by freetype, but since the superscript/subscript is a
00340             //  feature of plplot, and not freetype, we have to make allowances.
00341             //
00342 
00343             case 'u': // super script
00344             case 'U': // super script
00345                 adjust.y = FT->face->size->metrics.height / 2;
00346                 adjust.x = 0;
00347                 FT_Vector_Transform( &adjust, &FT->matrix );
00348                 x += adjust.x;
00349                 y -= adjust.y;
00350                 i++;
00351                 break;
00352 
00353             case 'd': // subscript
00354             case 'D': // subscript
00355                 adjust.y = -FT->face->size->metrics.height / 2;
00356                 adjust.x = 0;
00357                 FT_Vector_Transform( &adjust, &FT->matrix );
00358                 x += adjust.x;
00359                 y -= adjust.y;
00360                 i++;
00361                 break;
00362             }
00363         }
00364         else if ( text[i] & PL_FCI_MARK )
00365         {
00366             // FCI in text stream; change font accordingly.
00367             FT_SetFace( pls, text[i] );
00368             FT = (FT_Data *) pls->FT;
00369             FT_Set_Transform( FT->face, &FT->matrix, &FT->pos );
00370         }
00371         else
00372         {
00373             // see if we have kerning for the particular character pair
00374             if ( ( last_char != -1 ) && ( i > 0 ) && FT_HAS_KERNING( FT->face ) )
00375             {
00376                 FT_Get_Kerning( FT->face,
00377                     text[last_char],
00378                     text[i],
00379                     ft_kerning_default, &akerning );
00380                 x += akerning.x;        // add (or subtract) the kerning
00381                 y -= akerning.y;        // Do I need this in case of rotation ?
00382             }
00383 
00384 
00385             FT_Load_Char( FT->face, text[i], ( FT->smooth_text == 0 ) ? FT_LOAD_MONOCHROME + FT_LOAD_RENDER : FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT );
00386             FT_PlotChar( pls, FT, FT->face->glyph,
00387                 ROUND( x / 64.0 ), ROUND( y / 64.0 ), 2 );          // render the text
00388 
00389             x += FT->face->glyph->advance.x;
00390             y -= FT->face->glyph->advance.y;
00391 
00392             last_char = i;
00393         }
00394     } // end for
00395 }
00396 
00397 //--------------------------------------------------------------------------
00398 // FT_PlotChar()
00399 //
00400 // Plots an individual character. I know some of this stuff, like colour
00401 // could be parsed from plstream, but it was just quicker this way.
00402 //--------------------------------------------------------------------------
00403 
00404 void
00405 FT_PlotChar( PLStream *pls, FT_Data *FT, FT_GlyphSlot slot,
00406              int x, int y, short colour )
00407 {
00408     unsigned char bittest;
00409     short         i, k, j;
00410     int           n = slot->bitmap.pitch;
00411     int           current_pixel_colour;
00412     int           R, G, B;
00413     PLFLT         alpha_a, alpha_b;
00414     int           xx;
00415     short         imin, imax, kmin, kmax;
00416 
00417     // Corners of the clipping rectangle
00418     PLINT clipxmin, clipymin, clipxmax, clipymax, tmp;
00419     PLINT clpxmi, clpxma, clpymi, clpyma;
00420 
00421     // Convert clipping box into normal coordinates
00422     clipxmin = pls->clpxmi;
00423     clipxmax = pls->clpxma;
00424     clipymin = pls->clpymi;
00425     clipymax = pls->clpyma;
00426 
00427     if ( plsc->difilt )
00428     {
00429         difilt( &clipxmin, &clipymin, 1, &clpxmi, &clpxma, &clpymi, &clpyma );
00430         difilt( &clipxmax, &clipymax, 1, &clpxmi, &clpxma, &clpymi, &clpyma );
00431     }
00432 
00433 
00434     if ( FT->scale != 0.0 )    // scale was set
00435     {
00436         clipxmin = clipxmin / FT->scale;
00437         clipxmax = clipxmax / FT->scale;
00438         if ( FT->invert_y == 1 )
00439         {
00440             clipymin = FT->ymax - ( clipymin / FT->scale );
00441             clipymax = FT->ymax - ( clipymax / FT->scale );
00442         }
00443         else
00444         {
00445             clipymin = clipymin / FT->scale;
00446             clipymax = clipymax / FT->scale;
00447         }
00448     }
00449     else
00450     {
00451         clipxmin = clipxmin / FT->scalex;
00452         clipxmax = clipxmax / FT->scalex;
00453 
00454         if ( FT->invert_y == 1 )
00455         {
00456             clipymin = FT->ymax - ( clipymin / FT->scaley );
00457             clipymax = FT->ymax - ( clipymax / FT->scaley );
00458         }
00459         else
00460         {
00461             clipymin = clipymin / FT->scaley;
00462             clipymax = clipymax / FT->scaley;
00463         }
00464     }
00465     if ( clipxmin > clipxmax )
00466     {
00467         tmp      = clipxmax;
00468         clipxmax = clipxmin;
00469         clipxmin = tmp;
00470     }
00471     if ( clipymin > clipymax )
00472     {
00473         tmp      = clipymax;
00474         clipymax = clipymin;
00475         clipymin = tmp;
00476     }
00477 
00478     // Comment this out as it fails for cases where we want to plot text
00479     // in the background font, i.e. example 24.
00480     //
00481     //if ((slot->bitmap.pixel_mode==ft_pixel_mode_mono)||(pls->icol0==0)) {
00482     if ( slot->bitmap.pixel_mode == ft_pixel_mode_mono )
00483     {
00484         x += slot->bitmap_left;
00485         y -= slot->bitmap_top;
00486 
00487         imin = MAX( 0, clipymin - y );
00488         imax = MIN( slot->bitmap.rows, clipymax - y );
00489         for ( i = imin; i < imax; i++ )
00490         {
00491             for ( k = 0; k < n; k++ )
00492             {
00493                 bittest = 128;
00494                 for ( j = 0; j < 8; j++ )
00495                 {
00496                     if ( ( bittest & (unsigned char) slot->bitmap.buffer[( i * n ) + k] ) == bittest )
00497                     {
00498                         xx = x + ( k * 8 ) + j;
00499                         if ( ( xx >= clipxmin ) && ( xx <= clipxmax ) )
00500                             FT->pixel( pls, xx, y + i );
00501                     }
00502                     bittest >>= 1;
00503                 }
00504             }
00505         }
00506     }
00507 
00508 // this is the anti-aliased stuff
00509 
00510     else
00511     {
00512         x += slot->bitmap_left;
00513         y -= slot->bitmap_top;
00514 
00515         imin = MAX( 0, clipymin - y );
00516         imax = MIN( slot->bitmap.rows, clipymax - y );
00517         kmin = MAX( 0, clipxmin - x );
00518         kmax = MIN( slot->bitmap.width, clipxmax - x );
00519         for ( i = imin; i < imax; i++ )
00520         {
00521             for ( k = kmin; k < kmax; k++ )
00522             {
00523                 FT->shade = ( slot->bitmap.buffer[( i * slot->bitmap.width ) + k] );
00524                 if ( FT->shade > 0 )
00525                 {
00526                     if ( ( FT->BLENDED_ANTIALIASING == 1 ) && ( FT->read_pixel != NULL ) )
00527                     // The New anti-aliasing technique
00528                     {
00529                         if ( FT->shade == 255 )
00530                         {
00531                             FT->pixel( pls, x + k, y + i );
00532                         }
00533                         else
00534                         {
00535                             current_pixel_colour = FT->read_pixel( pls, x + k, y + i );
00536 
00537                             G       = GetGValue( current_pixel_colour );
00538                             R       = GetRValue( current_pixel_colour );
00539                             B       = GetBValue( current_pixel_colour );
00540                             alpha_a = (float) FT->shade / 255.0;
00541 
00542                             // alpha_b=1.0-alpha_a;
00543                             // R=(plsc->cmap0[pls->icol0].r*alpha_a)+(R*alpha_b);
00544                             // G=(plsc->cmap0[pls->icol0].g*alpha_a)+(G*alpha_b);
00545                             // B=(plsc->cmap0[pls->icol0].b*alpha_a)+(B*alpha_b);
00546                             //
00547 
00548                             //  This next bit of code is, I *think*, computationally
00549                             //  more efficient than the bit above. It results in
00550                             //  an indistinguishable plot, but file sizes are different
00551                             //  suggesting subtle variations doubtless caused by rounding
00552                             //  and/or floating point conversions. Questions are - which is
00553                             //  better ? Which is more "correct" ? Does it make a difference ?
00554                             //  Is one faster than the other so that you'd ever notice ?
00555                             //
00556 
00557                             R = ( ( ( plsc->cmap0[pls->icol0].r - R ) * alpha_a ) + R );
00558                             G = ( ( ( plsc->cmap0[pls->icol0].g - G ) * alpha_a ) + G );
00559                             B = ( ( ( plsc->cmap0[pls->icol0].b - B ) * alpha_a ) + B );
00560 
00561                             FT->set_pixel( pls, x + k, y + i, RGB( R > 255 ? 255 : R, G > 255 ? 255 : G, B > 255 ? 255 : B ) );
00562                         }
00563                     }
00564                     else     // The old anti-aliasing technique
00565                     {
00566                         FT->col_idx    = FT->ncol0_width - ( ( FT->ncol0_width * FT->shade ) / 255 );
00567                         FT->last_icol0 = pls->icol0;
00568                         plcol0( pls->icol0 + ( FT->col_idx * ( FT->ncol0_org - 1 ) ) );
00569                         FT->pixel( pls, x + k, y + i );
00570                         plcol0( FT->last_icol0 );
00571                     }
00572                 }
00573             }
00574         }
00575     }
00576 }
00577 
00578 //--------------------------------------------------------------------------
00579 // plD_FreeType_init()
00580 //
00581 // Allocates memory to Freetype structure
00582 // Initialises the freetype library.
00583 // Initialises freetype structure
00584 //--------------------------------------------------------------------------
00585 
00586 void plD_FreeType_init( PLStream *pls )
00587 {
00588     FT_Data    *FT;
00589     char       *a;
00590 // font paths and file names can be long so leave generous (1024) room
00591     char       font_dir[PLPLOT_MAX_PATH];
00592     // N.B. must be in exactly same order as TrueTypeLookup
00593     const char *env_font_names[N_TrueTypeLookup] = {
00594         "PLPLOT_FREETYPE_SANS_FONT",
00595         "PLPLOT_FREETYPE_SERIF_FONT",
00596         "PLPLOT_FREETYPE_MONO_FONT",
00597         "PLPLOT_FREETYPE_SCRIPT_FONT",
00598         "PLPLOT_FREETYPE_SYMBOL_FONT",
00599         "PLPLOT_FREETYPE_SANS_ITALIC_FONT",
00600         "PLPLOT_FREETYPE_SERIF_ITALIC_FONT",
00601         "PLPLOT_FREETYPE_MONO_ITALIC_FONT",
00602         "PLPLOT_FREETYPE_SCRIPT_ITALIC_FONT",
00603         "PLPLOT_FREETYPE_SYMBOL_ITALIC_FONT",
00604         "PLPLOT_FREETYPE_SANS_OBLIQUE_FONT",
00605         "PLPLOT_FREETYPE_SERIF_OBLIQUE_FONT",
00606         "PLPLOT_FREETYPE_MONO_OBLIQUE_FONT",
00607         "PLPLOT_FREETYPE_SCRIPT_OBLIQUE_FONT",
00608         "PLPLOT_FREETYPE_SYMBOL_OBLIQUE_FONT",
00609         "PLPLOT_FREETYPE_SANS_BOLD_FONT",
00610         "PLPLOT_FREETYPE_SERIF_BOLD_FONT",
00611         "PLPLOT_FREETYPE_MONO_BOLD_FONT",
00612         "PLPLOT_FREETYPE_SCRIPT_BOLD_FONT",
00613         "PLPLOT_FREETYPE_SYMBOL_BOLD_FONT",
00614         "PLPLOT_FREETYPE_SANS_BOLD_ITALIC_FONT",
00615         "PLPLOT_FREETYPE_SERIF_BOLD_ITALIC_FONT",
00616         "PLPLOT_FREETYPE_MONO_BOLD_ITALIC_FONT",
00617         "PLPLOT_FREETYPE_SCRIPT_BOLD_ITALIC_FONT",
00618         "PLPLOT_FREETYPE_SYMBOL_BOLD_ITALIC_FONT",
00619         "PLPLOT_FREETYPE_SANS_BOLD_OBLIQUE_FONT",
00620         "PLPLOT_FREETYPE_SERIF_BOLD_OBLIQUE_FONT",
00621         "PLPLOT_FREETYPE_MONO_BOLD_OBLIQUE_FONT",
00622         "PLPLOT_FREETYPE_SCRIPT_BOLD_OBLIQUE_FONT",
00623         "PLPLOT_FREETYPE_SYMBOL_BOLD_OBLIQUE_FONT"
00624     };
00625     short      i;
00626 
00627 #if defined ( MSDOS ) || defined ( WIN32 )
00628     static char *default_font_names[] = { "arial.ttf", "times.ttf", "timesi.ttf", "arial.ttf",
00629                                           "symbol.ttf" };
00630     char        WINDIR_PATH[PLPLOT_MAX_PATH];
00631     char        *b;
00632     b = getenv( "WINDIR" );
00633     strncpy( WINDIR_PATH, b, PLPLOT_MAX_PATH - 1 );
00634     WINDIR_PATH[PLPLOT_MAX_PATH - 1] = '\0';
00635 #else
00636     const char *default_unix_font_dir = PL_FREETYPE_FONT_DIR;
00637 #endif
00638 
00639 
00640     if ( pls->FT )
00641     {
00642         plwarn( "Freetype seems already to have been initialised!" );
00643         return;
00644     }
00645 
00646     if ( ( pls->FT = calloc( 1, (size_t) sizeof ( FT_Data ) ) ) == NULL )
00647         plexit( "Could not allocate memory for Freetype" );
00648 
00649     FT = (FT_Data *) pls->FT;
00650 
00651     if ( ( FT->textbuf = calloc( NTEXT_ALLOC, 1 ) ) == NULL )
00652         plexit( "Could not allocate memory for Freetype text buffer" );
00653 
00654     if ( FT_Init_FreeType( &FT->library ) )
00655         plexit( "Could not initialise Freetype library" );
00656 
00657     // set to an impossible value for an FCI
00658     FT->fci = PL_FCI_IMPOSSIBLE;
00659 
00660 #if defined ( MSDOS ) || defined ( WIN32 )
00661 
00662 //
00663 // Work out if we have Win95+ or Win3.?... sort of.
00664 // Actually, this just tries to find the place where the fonts live by looking
00665 // for arial, which should be on all windows machines.
00666 // At present, it only looks in two places, on one drive. I might change this
00667 // soon.
00668 //
00669     if ( WINDIR_PATH == NULL )
00670     {
00671         if ( access( "c:\\windows\\fonts\\arial.ttf", F_OK ) == 0 )
00672         {
00673             strcpy( font_dir, "c:/windows/fonts/" );
00674         }
00675         else if ( access( "c:\\windows\\system\\arial.ttf", F_OK ) == 0 )
00676         {
00677             strcpy( font_dir, "c:/windows/system/" );
00678         }
00679         else
00680             plwarn( "Could not find font path; I sure hope you have defined fonts manually !" );
00681     }
00682     else
00683     {
00684         strncat( WINDIR_PATH, "\\fonts\\arial.ttf", PLPLOT_MAX_PATH - 1 - strlen( WINDIR_PATH ) );
00685         if ( access( WINDIR_PATH, F_OK ) == 0 )
00686         {
00687             b = strrchr( WINDIR_PATH, '\\' );
00688             b++;
00689             *b = 0;
00690             makeunixslash( WINDIR_PATH );
00691             strcpy( font_dir, WINDIR_PATH );
00692         }
00693         else
00694             plwarn( "Could not find font path; I sure hope you have defined fonts manually !" );
00695     }
00696 
00697     if ( pls->debug )
00698         fprintf( stderr, "%s\n", font_dir );
00699 #else
00700 
00701 //
00702 //  For Unix systems, we will set the font path up a little differently in
00703 //  that the configured PL_FREETYPE_FONT_DIR has been set as the default path,
00704 //  but the user can override this by setting the environmental variable
00705 //  "PLPLOT_FREETYPE_FONT_DIR" to something else.
00706 //  NOTE WELL - the trailing slash must be added for now !
00707 //
00708 
00709     if ( ( a = getenv( "PLPLOT_FREETYPE_FONT_DIR" ) ) != NULL )
00710         strncpy( font_dir, a, PLPLOT_MAX_PATH - 1 );
00711     else
00712         strncpy( font_dir, default_unix_font_dir, PLPLOT_MAX_PATH - 1 );
00713 
00714     font_dir[PLPLOT_MAX_PATH - 1] = '\0';
00715 #endif
00716 
00717 //
00718 // The driver looks for N_TrueTypeLookup  environmental variables
00719 // where the path and name of these fonts can be OPTIONALLY set,
00720 // overriding the configured default values.
00721 //
00722 
00723     for ( i = 0; i < N_TrueTypeLookup; i++ )
00724     {
00725         if ( ( a = getenv( env_font_names[i] ) ) != NULL )
00726         {
00727 //
00728 //  Work out if we have been given an absolute path to a font name, or just
00729 //  a font name sans-path. To do this we will look for a directory separator
00730 //  character, which means some system specific junk. DJGPP is all wise, and
00731 //  understands both Unix and DOS conventions. DOS only knows DOS, and
00732 //  I assume everything else knows Unix-speak. (Why Bill, didn't you just
00733 //  pay the extra 15c and get a REAL separator???)
00734 //
00735 
00736 #ifdef MSDOS
00737             if ( a[1] == ':' )                        // check for MS-DOS absolute path
00738 #else
00739             if ( ( a[0] == '/' ) || ( a[0] == '~' ) ) // check for unix abs path
00740 #endif
00741                 strncpy( FT->font_name[i], a, PLPLOT_MAX_PATH - 1 );
00742 
00743             else
00744             {
00745                 strncpy( FT->font_name[i], font_dir, PLPLOT_MAX_PATH - 1 );
00746                 strncat( FT->font_name[i], a, PLPLOT_MAX_PATH - 1 - strlen( FT->font_name[i] ) );
00747             }
00748         }
00749         else
00750         {
00751             strncpy( FT->font_name[i], font_dir, PLPLOT_MAX_PATH - 1 );
00752             strncat( FT->font_name[i], (char *) TrueTypeLookup[i].pfont, PLPLOT_MAX_PATH - 1 - strlen( FT->font_name[i] ) );
00753         }
00754         FT->font_name[i][PLPLOT_MAX_PATH - 1] = '\0';
00755 
00756         {
00757             FILE *infile;
00758             if ( ( infile = fopen( FT->font_name[i], "r" ) ) == NULL )
00759             {
00760                 char msgbuf[1024];
00761                 snprintf( msgbuf, 1024,
00762                     "plD_FreeType_init: Could not find the freetype compatible font:\n %s",
00763                     FT->font_name[i] );
00764                 plwarn( msgbuf );
00765             }
00766             else
00767             {
00768                 fclose( infile );
00769             }
00770         }
00771         FontLookup[i].fci   = TrueTypeLookup[i].fci;
00772         FontLookup[i].pfont = (unsigned char *) FT->font_name[i];
00773     }
00774 //
00775 // Next, we check to see if -drvopt has been used on the command line to
00776 // over-ride any settings
00777 //
00778 }
00779 
00780 
00781 //--------------------------------------------------------------------------
00782 // FT_SetFace( PLStream *pls, PLUNICODE fci )
00783 //
00784 // Sets up the font face and size
00785 //--------------------------------------------------------------------------
00786 
00787 void FT_SetFace( PLStream *pls, PLUNICODE fci )
00788 {
00789     FT_Data *FT       = (FT_Data *) pls->FT;
00790     double  font_size = pls->chrht * 72 / 25.4; // font_size in points, chrht is in mm
00791 
00792     // save a copy of character height and resolution
00793     FT->chrht = pls->chrht;
00794     FT->xdpi  = pls->xdpi;
00795     FT->ydpi  = pls->ydpi;
00796 
00797     if ( fci != FT->fci )
00798     {
00799         char *font_name = plP_FCI2FontName( fci, FontLookup, N_TrueTypeLookup );
00800         if ( font_name == NULL )
00801         {
00802             if ( FT->fci == PL_FCI_IMPOSSIBLE )
00803                 plexit( "FT_SetFace: Bad FCI and no previous valid font to fall back on" );
00804             else
00805                 plwarn( "FT_SetFace: Bad FCI.  Falling back to previous font." );
00806         }
00807         else
00808         {
00809             FT->fci = fci;
00810 
00811             if ( FT->face != NULL )
00812             {
00813                 FT_Done_Face( FT->face );
00814                 FT->face = NULL;
00815             }
00816 
00817             if ( FT->face == NULL )
00818             {
00819                 if ( FT_New_Face( FT->library, font_name, 0, &FT->face ) )
00820                     plexit( "FT_SetFace: Error loading a font in freetype" );
00821             }
00822         }
00823     }
00824     FT_Set_Char_Size( FT->face, 0,
00825         font_size * 64 / TEXT_SCALING_FACTOR, pls->xdpi,
00826         pls->ydpi );
00827 }
00828 
00829 //--------------------------------------------------------------------------
00830 // plD_render_freetype_text()
00831 //
00832 // Transforms the font
00833 // calculates real-world bitmap coordinates from plplot ones
00834 // renders text using freetype
00835 //--------------------------------------------------------------------------
00836 
00837 void plD_render_freetype_text( PLStream *pls, EscText *args )
00838 {
00839     FT_Data   *FT = (FT_Data *) pls->FT;
00840     int       x, y;
00841     int       w  = 0, h = 0;
00842     PLFLT     *t = args->xform;
00843     FT_Matrix matrix;
00844     PLFLT     angle = PI * pls->diorot / 2;
00845 //
00846 // Used later in a commented out section (See Rotate The Page), if that
00847 // section will never be used again, remove these as well.
00848 //      PLINT clxmin, clxmax, clymin, clymax;
00849 //
00850     PLFLT     Sin_A, Cos_A;
00851     FT_Vector adjust;
00852     PLUNICODE fci;
00853     FT_Fixed  height;
00854     PLFLT     height_factor;
00855 
00856     if ( ( args->string != NULL ) || ( args->unicode_array_len > 0 ) )
00857     {
00858 //
00859 //   Work out if either the font size, the font face or the
00860 //   resolution has changed.
00861 //   If either has, then we will reload the font face.
00862 //
00863         plgfci( &fci );
00864         if ( ( FT->fci != fci ) || ( FT->chrht != pls->chrht ) || ( FT->xdpi != pls->xdpi ) || ( FT->ydpi != pls->ydpi ) )
00865             FT_SetFace( pls, fci );
00866 
00867 
00868 //  this will help work out underlining and overlining
00869 
00870         Debug6( "%s %d %d %d %d\n", "plD_render_freetype_text:",
00871             FT->face->underline_position >> 6,
00872             FT->face->descender >> 6,
00873             FT->face->ascender >> 6,
00874             ( ( FT->face->underline_position * -1 ) + FT->face->ascender ) >> 6 );
00875 
00876 
00877 
00878 //
00879 //  Now we work out how long the text is (for justification etc...) and how
00880 //  high the text is. This is done on UN-TRANSFORMED text, since we will
00881 //  apply our own transformations on it later, so it's necessary for us
00882 //  to to turn all transformations off first, before calling the function
00883 //  that calculates the text size.
00884 //
00885 
00886         FT->matrix.xx = 0x10000;
00887         FT->matrix.xy = 0x00000;
00888         FT->matrix.yx = 0x00000;
00889         FT->matrix.yy = 0x10000;
00890 
00891         FT_Vector_Transform( &FT->pos, &FT->matrix );
00892         FT_Set_Transform( FT->face, &FT->matrix, &FT->pos );
00893 
00894         FT_StrX_YW( pls, args->unicode_array, args->unicode_array_len, &w, &h );
00895 
00896 //
00897 //      Set up the transformation Matrix
00898 //
00899 // Fortunately this is almost identical to plplot's own transformation matrix;
00900 // you have NO idea how much effort that saves ! Some params are in a
00901 // different order, and Freetype wants integers whereas plplot likes floats,
00902 // but such differences are quite trivial.
00903 //
00904 // For some odd reason, this needs to be set a different way for DJGPP. Why ?
00905 // I wish I knew.
00906 //
00907 
00908 // (RL, on 2005-01-21) The height_factor variable is introduced below.
00909 // It is used here and farther below when computing the vertical
00910 // adjustment.  The rationale for its introduction is as follow: up to
00911 // now, the text produced with Hershey fonts was systematically taller
00912 // than the same text produced with TT fonts, and tha by a factor of
00913 // around 1.125 (I discovered this empirically).  This corresponds
00914 // roughly to the ratio between total height and the ascender of some
00915 // TT faces.  Hence the computation below.  Remember that descender is
00916 // always a negative quantity.
00917 //
00918 
00919         height_factor = (PLFLT) ( FT->face->ascender - FT->face->descender )
00920                         / FT->face->ascender;
00921         height = (FT_Fixed) ( 0x10000 * height_factor );
00922 
00923 #ifdef DJGPP
00924         FT->matrix.xx = height * t[0];
00925         FT->matrix.xy = height * t[2];
00926         FT->matrix.yx = height * t[1];
00927         FT->matrix.yy = height * t[3];
00928 #else
00929         FT->matrix.xx = height * t[0];
00930         FT->matrix.xy = height * t[1];
00931         FT->matrix.yx = height * t[2];
00932         FT->matrix.yy = height * t[3];
00933 #endif
00934 
00935 
00936 //                            Rotate the Font
00937 //
00938 //  If the page has been rotated using -ori, this is where we rotate the
00939 //  font to point in the right direction. To make things nice and easy, we
00940 //  will use freetypes matrix math stuff to do this for us.
00941 //
00942 
00943         Cos_A = cos( angle );
00944         Sin_A = sin( angle );
00945 
00946         matrix.xx = (FT_Fixed) 0x10000 * Cos_A;
00947 
00948 #ifdef DJGPP
00949         matrix.xy = (FT_Fixed) 0x10000 * Sin_A * -1;
00950         matrix.yx = (FT_Fixed) 0x10000 * Sin_A;
00951 #else
00952         matrix.xy = (FT_Fixed) 0x10000 * Sin_A;
00953         matrix.yx = (FT_Fixed) 0x10000 * Sin_A * -1;
00954 #endif
00955 
00956         matrix.yy = (FT_Fixed) 0x10000 * Cos_A;
00957 
00958         FT_Matrix_Multiply( &matrix, &FT->matrix );
00959 
00960 
00961 //       Calculate a Vector from the matrix
00962 //
00963 // This is closely related to the "transform matrix".
00964 // The matrix is used for rendering the glyph, while the vector is used for
00965 // calculating offsets of the text box, so we need both. Why ? I dunno, but
00966 // we have to live with it, and it works...
00967 //
00968 
00969 
00970         FT_Vector_Transform( &FT->pos, &FT->matrix );
00971 
00972 
00973 //    Transform the font face
00974 //
00975 // This is where our matrix transformation is calculated for the font face.
00976 // This is only done once for each unique transformation since it is "sticky"
00977 // within the font. Font rendering is done later, using the supplied matrix,
00978 // but invisibly to us from here on. I don't believe the vector is used, but
00979 // it is asked for.
00980 //
00981 
00982         FT_Set_Transform( FT->face, &FT->matrix, &FT->pos );
00983 
00984 
00985 //                            Rotate the Page
00986 //
00987 //  If the page has been rotated using -ori, this is we recalculate the
00988 //  reference point for the text using plplot functions.
00989 //
00990 
00991 //   difilt(&args->x, &args->y, 1, &clxmin, &clxmax, &clymin, &clymax);
00992 
00993 
00994 //
00995 //   Convert into normal coordinates from virtual coordinates
00996 //
00997 
00998         if ( FT->scale != 0.0 ) // scale was set
00999         {
01000             x = args->x / FT->scale;
01001 
01002             if ( FT->invert_y == 1 )
01003                 y = FT->ymax - ( args->y / FT->scale );
01004             else
01005                 y = args->y / FT->scale;
01006         }
01007         else
01008         {
01009             x = args->x / FT->scalex;
01010 
01011             if ( FT->invert_y == 1 )
01012                 y = FT->ymax - ( args->y / FT->scaley );
01013             else
01014                 y = args->y / FT->scaley;
01015         }
01016 
01017         //          Adjust for the justification and character height
01018         //
01019         //  Eeeksss... this wasn't a nice bit of code to work out, let me tell you.
01020         //  I could not work out an entirely satisfactory solution that made
01021         //  logical sense, so came up with an "illogical" one as well.
01022         //  The logical one works fine for text in the normal "portrait"
01023         //  orientation, and does so for reasons you might expect it to work; But
01024         //  for all other orientations, the text's base line is either a little
01025         //  high, or a little low. This is because of the way the base-line pos
01026         //  is calculated from the decender height. The "dodgie" way of calculating
01027         //  the position is to use the character height here, then adjust for the
01028         //  decender height by a three-fold factor later on. That approach seems to
01029         //  work a little better for rotated pages, but why it should be so, I
01030         //  don't understand. You can compile in or out which way you want it by
01031         //  defining "DODGIE_DECENDER_HACK".
01032         //
01033         //  note: the logic of the page rotation coming up next is that we pump in
01034         //  the justification factor and then use freetype to rotate and transform
01035         //  the values, which we then use to change the plotting location.
01036         //
01037 
01038 
01039 #ifdef DODGIE_DECENDER_HACK
01040         adjust.y = h;
01041 #else
01042         adjust.y = 0;
01043 #endif
01044 
01045 // (RL, on 2005-01-24) The code below uses floating point and division
01046 // operations instead of integer shift used before. This is slower but
01047 // gives accurate placement of text in plots.
01048 //
01049 
01050 // (RL, on 2005-01-21) The hack below is intended to align single
01051 // glyphs being generated via plpoin.  The way to detect this
01052 // situation is completely hackish, I must admit, by checking whether the
01053 // length of the Unicode array is equal 2 and whether the first
01054 // character is actually a font-changing command to font number 4 (for
01055 // symbols).  This is ugly because it depends on definitions set
01056 // elsewhere, but it works.
01057 //
01058 // The computation of the vertical and horizontal adjustments are
01059 // based on the bouding box of the glyph being loaded (since there is
01060 // only one glyph in the string in this case, we are okay here).
01061 //
01062 
01063         if ( ( args->unicode_array_len == 2 )
01064              && ( args->unicode_array[0] == ( PL_FCI_MARK | 0x004 ) ) )
01065         {
01066             adjust.x = args->just * ROUND( FT->face->glyph->metrics.width / 64.0 );
01067             adjust.y = (FT_Pos) ROUND( FT->face->glyph->metrics.height / 128.0 );
01068         }
01069         else
01070         {
01071 // (RL, on 2005-01-21) The vertical adjustment is set below, making
01072 // the DODGIE conditional moot.  I use the value of h as return by FT_StrX_YW,
01073 // which should correspond to the total height of the text being
01074 // drawn.  Freetype aligns text around the baseline, while PLplot
01075 // aligns to the center of the ascender portion.  We must then adjust
01076 // by half of the ascender and this is why there is a division by
01077 // height_factor below.
01078 //
01079 
01080             adjust.y = (FT_Pos)
01081                        ROUND( FT->face->size->metrics.height / height_factor / 128.0 );
01082             adjust.x = (FT_Pos) ( args->just * ROUND( w / 64.0 ) );
01083         }
01084 
01085         FT_Vector_Transform( &adjust, &FT->matrix ); // was /&matrix); -  was I using the wrong matrix all this time ?
01086 
01087         x -= adjust.x;
01088         y += adjust.y;
01089 
01090         FT_WriteStrW( pls, args->unicode_array, args->unicode_array_len, x, y ); // write it out
01091     }
01092     else
01093     {
01094         plD_render_freetype_sym( pls, args );
01095     }
01096 }
01097 
01098 //--------------------------------------------------------------------------
01099 // plD_FreeType_Destroy()
01100 //
01101 // Restores cmap0 if it had been modifed for anti-aliasing
01102 // closes the freetype library.
01103 // Deallocates memory to the Freetype structure
01104 //--------------------------------------------------------------------------
01105 
01106 void plD_FreeType_Destroy( PLStream *pls )
01107 {
01108     FT_Data *FT = (FT_Data *) pls->FT;
01109     extern int FT_Done_Library( FT_Library library );
01110 
01111     if ( FT )
01112     {
01113         if ( ( FT->smooth_text == 1 ) && ( FT->BLENDED_ANTIALIASING == 0 ) )
01114             plscmap0n( FT->ncol0_org );
01115         if ( FT->textbuf )
01116             free( FT->textbuf );
01117         FT_Done_Library( FT->library );
01118         free( pls->FT );
01119         pls->FT = NULL;
01120     }
01121 }
01122 
01123 //--------------------------------------------------------------------------
01124 // PLFLT CalculateIncrement( int bg, int fg, int levels)
01125 //
01126 // Takes the value of the foreground, and the background, and when
01127 // given the number of desired steps, calculates how much to incriment
01128 // a value to transition from fg to bg.
01129 // This function only does it for one colour channel at a time.
01130 //--------------------------------------------------------------------------
01131 
01132 static PLFLT CalculateIncrement( int bg, int fg, int levels )
01133 {
01134     PLFLT ret = 0;
01135 
01136     if ( levels > 1 )
01137     {
01138         if ( fg > bg )
01139             ret = ( ( fg + 1 ) - bg ) / levels;
01140         else if ( fg < bg )
01141             ret = ( ( ( fg - 1 ) - bg ) / levels );
01142     }
01143     return ( ret );
01144 }
01145 
01146 //--------------------------------------------------------------------------
01147 // void pl_set_extended_cmap0(PLStream *pls, int ncol0_width, int ncol0_org)
01148 //
01149 //  ncol0_width - how many greyscale levels to accolate to each CMAP0 entry
01150 //  ncol0_org - the originl number of CMAP0 entries.
01151 //
01152 //  This function calcualtes and sets an extended CMAP0 entry for the
01153 //  driver. It is assumed that the caller has checked to make sure there is
01154 //  room for extending CMAP0 already.
01155 //
01156 //  NOTES
01157 //  We don't bother calculating an entry for CMAP[0], the background.
01158 //  It is assumed the caller has already expanded the size of CMAP[0]
01159 //--------------------------------------------------------------------------
01160 
01161 void pl_set_extended_cmap0( PLStream *pls, int ncol0_width, int ncol0_org )
01162 {
01163     int   i, j, k;
01164     int   r, g, b;
01165     PLFLT r_inc, g_inc, b_inc;
01166 
01167     for ( i = 1; i < ncol0_org; i++ )
01168     {
01169         r = pls->cmap0[i].r;
01170         g = pls->cmap0[i].g;
01171         b = pls->cmap0[i].b;
01172 
01173         r_inc = CalculateIncrement( pls->cmap0[0].r, r, ncol0_width );
01174         g_inc = CalculateIncrement( pls->cmap0[0].g, g, ncol0_width );
01175         b_inc = CalculateIncrement( pls->cmap0[0].b, b, ncol0_width );
01176 
01177         for ( j = 0, k = ncol0_org + i - 1; j < ncol0_width; j++, k += ( ncol0_org - 1 ) )
01178         {
01179             r -= r_inc;
01180             g -= g_inc;
01181             b -= b_inc;
01182             if ( ( r < 0 ) || ( g < 0 ) || ( b < 0 ) )
01183                 plscol0( k, 0, 0, 0 );
01184             else
01185                 plscol0( k, ( r > 0xff ? 0xff : r ), ( g > 0xff ? 0xff : g ), ( b > 0xff ? 0xff : b ) );
01186         }
01187     }
01188 }
01189 
01190 
01191 //--------------------------------------------------------------------------
01192 // plD_render_freetype_sym( PLStream *pls, EscText *args )
01193 //   PLStream *pls - pointer to plot stream
01194 //   EscText *args - pointer to standard "string" object.
01195 //
01196 //  This function is a simple rendering function which draws a single
01197 //  character at a time. The function is an alternative to the text
01198 //  functions which are considerably, and needlessly, more complicated
01199 //  than what we need here.
01200 //--------------------------------------------------------------------------
01201 
01202 
01203 void plD_render_freetype_sym( PLStream *pls, EscText *args )
01204 {
01205     FT_Data   *FT = (FT_Data *) pls->FT;
01206     int       x, y;
01207     FT_Vector adjust;
01208     PLUNICODE fci;
01209 
01210     if ( FT->scale != 0.0 )    // scale was set
01211     {
01212         x = args->x / FT->scale;
01213 
01214         if ( FT->invert_y == 1 )
01215             y = FT->ymax - ( args->y / FT->scale );
01216         else
01217             y = args->y / FT->scale;
01218     }
01219     else
01220     {
01221         x = args->x / FT->scalex;
01222 
01223         if ( FT->invert_y == 1 )
01224             y = FT->ymax - ( args->y / FT->scaley );
01225         else
01226             y = args->y / FT->scaley;
01227     }
01228 
01229 
01230 //
01231 //  Adjust for the descender - make sure the font is nice and centred
01232 //  vertically. Freetype assumes we have a base-line, but plplot thinks of
01233 //  centre-lines, so that's why we have to do this. Since this is one of our
01234 //  own adjustments, rather than a freetype one, we have to run it through
01235 //  the transform matrix manually.
01236 //
01237 //  For some odd reason, this works best if we triple the
01238 //  descender's height and then adjust the height later on...
01239 //  Don't ask me why, 'cause I don't know. But it does seem to work.
01240 //
01241 //  I really wish I knew *why* it worked better though...
01242 //
01243 //   y-=FT->face->descender >> 6;
01244 //
01245 
01246 #ifdef DODGIE_DECENDER_HACK
01247     adjust.y = ( FT->face->descender >> 6 ) * 3;
01248 #else
01249     adjust.y = ( FT->face->descender >> 6 );
01250 #endif
01251 
01252     adjust.x = 0;
01253     FT_Vector_Transform( &adjust, &FT->matrix );
01254     x += adjust.x;
01255     y -= adjust.y;
01256 
01257     plgfci( &fci );
01258     FT_SetFace( pls, fci );
01259 
01260     FT = (FT_Data *) pls->FT;
01261     FT_Set_Transform( FT->face, &FT->matrix, &FT->pos );
01262 
01263     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 );
01264 
01265 //
01266 // Now we have to try and componsate for the fact that the freetype glyphs are left
01267 // justified, and plplot's glyphs are centred. To do this, we will just work out the
01268 // advancment, halve it, and take it away from the x position. This wont be 100%
01269 // accurate because "spacing" is factored into the right hand side of the glyph,
01270 // but it is as good a way as I can think of.
01271 //
01272 
01273     x -= ( FT->face->glyph->advance.x >> 6 ) / 2;
01274     FT_PlotChar( pls, FT, FT->face->glyph, x, y, pls->icol0 ); // render the text
01275 }
01276 
01277 
01278 
01279 
01280 #else
01281 int
01282 plfreetype()
01283 {
01284     return 0;
01285 }
01286 
01287 #endif

Generated on Wed Oct 12 2011 20:42:22 for PLplot by  doxygen 1.7.1