PLplot
5.10.0
|
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