PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/branches/v5_9_6_debian/src/plfreetype.c

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