PageRenderTime 27ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/branches/hbabcock/src/plfreetype.c

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