PageRenderTime 30ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/src/plfreetype.c

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