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