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