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