68 #if !defined ( WIN32 ) || defined ( __GNUC__ )
73 int access(
char *filename,
int flag )
76 infile = fopen( filename,
"r" );
89 #define makeunixslash( b ) do { char *I; for ( I = b; *I != 0; *I++ ) if ( *I == '\\' ) *I = '/';} while ( 0 )
94 #ifdef PL_HAVE_FREETYPE
98 #define FT_Data _FT_Data_
112 #define TEXT_SCALING_FACTOR .7
117 #define NTEXT_ALLOC 1024
123 #define Debug6( a, b, c, d, e, f ) do { if ( pls->debug ) { fprintf( stderr, a, b, c, d, e, f ); } } while ( 0 )
130 void plD_FreeType_init(
PLStream *pls );
132 void plD_FreeType_Destroy(
PLStream *pls );
133 void pl_set_extended_cmap0(
PLStream *pls,
int ncol0_width,
int ncol0_org );
134 void pl_RemakeFreeType_text_from_buffer(
PLStream *pls );
139 static void FT_PlotChar(
PLStream *pls, FT_Data *FT, FT_GlyphSlot slot,
int x,
int y );
141 static PLFLT CalculateIncrement(
int bg,
int fg,
int levels );
151 static void FT_StrX_YW(
PLStream *pls,
const PLUNICODE *
text,
short len,
int *xx,
int *yy,
int *overyy,
int *underyy );
164 FT_StrX_YW(
PLStream *pls,
const PLUNICODE *
text,
short len,
int *xx,
int *yy,
int *overyy,
int *underyy )
166 FT_Data *FT = (FT_Data *) pls->
FT;
168 FT_Vector akerning, adjust;
169 int x = 0,
y = 0, startingy;
181 y -= (int) FT->face->size->metrics.height;
190 for ( i = 0; i < len; i++ )
197 switch ( text[i + 1] )
201 adjust.y = FT->face->size->metrics.height / 2;
203 FT_Vector_Transform( &adjust, &FT->matrix );
207 *overyy =
y - startingy < *overyy ?
y - startingy : *overyy;
213 adjust.y = -FT->face->size->metrics.height / 2;
215 FT_Vector_Transform( &adjust, &FT->matrix );
219 *underyy = startingy -
y < *underyy ? startingy -
y : *underyy;
227 FT_SetFace( pls, text[i] );
228 *yy = FT->face->size->metrics.height > -*yy ? -FT->face->size->metrics.height : *yy;
233 if ( ( i > 0 ) && FT_HAS_KERNING( FT->face ) )
235 FT_Get_Kerning( FT->face,
240 x += (int) ( akerning.x >> 6 );
253 FT_Load_Char( FT->face, text[i], FT_LOAD_MONOCHROME + FT_LOAD_RENDER );
261 x += (int) ( FT->face->glyph->advance.x );
262 y -= (int) ( FT->face->glyph->advance.y );
291 FT_Data *FT = (FT_Data *) pls->
FT;
292 short i = 0, last_char = -1;
293 FT_Vector akerning, adjust;
315 #ifdef DODGIE_DECENDER_HACK
316 adjust.y = ( FT->face->descender >> 6 ) * 3;
318 adjust.y = ( FT->face->descender >> 6 );
329 FT_Vector_Transform( &adjust, &FT->matrix );
348 for ( i = 0; i < len; i++ )
355 switch ( text[i + 1] )
368 adjust.y = FT->face->size->metrics.height / 2;
370 FT_Vector_Transform( &adjust, &FT->matrix );
378 adjust.y = -FT->face->size->metrics.height / 2;
380 FT_Vector_Transform( &adjust, &FT->matrix );
387 else if ( text[i] & PL_FCI_MARK )
390 FT_SetFace( pls, text[i] );
391 FT = (FT_Data *) pls->
FT;
392 FT_Set_Transform( FT->face, &FT->matrix, &FT->pos );
397 if ( ( last_char != -1 ) && ( i > 0 ) && FT_HAS_KERNING( FT->face ) )
399 FT_Get_Kerning( FT->face,
402 ft_kerning_default, &akerning );
403 x += (int) akerning.x;
404 y -= (
int) akerning.y;
408 FT_Load_Char( FT->face, text[i], ( FT->smooth_text == 0 ) ? FT_LOAD_MONOCHROME + FT_LOAD_RENDER : FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT );
409 FT_PlotChar( pls, FT, FT->face->glyph,
412 x += (int) FT->face->glyph->advance.x;
413 y -= (
int) FT->face->glyph->advance.y;
428 FT_PlotChar(
PLStream *pls, FT_Data *FT, FT_GlyphSlot slot,
431 unsigned char bittest;
433 int n = slot->bitmap.pitch;
434 int current_pixel_colour;
439 short imin, imax, kmin, kmax;
442 PLINT clipxmin, clipymin, clipxmax, clipymax, tmp;
443 PLINT clpxmi, clpxma, clpymi, clpyma;
453 difilt( &clipxmin, &clipymin, 1, &clpxmi, &clpxma, &clpymi, &clpyma );
454 difilt( &clipxmax, &clipymax, 1, &clpxmi, &clpxma, &clpymi, &clpyma );
458 if ( FT->scale != 0.0 )
460 clipxmin = (
PLINT) ( clipxmin / FT->scale );
461 clipxmax = (
PLINT) ( clipxmax / FT->scale );
462 if ( FT->invert_y == 1 )
464 clipymin = (
PLINT) ( FT->ymax - ( clipymin / FT->scale ) );
465 clipymax = (
PLINT) ( FT->ymax - ( clipymax / FT->scale ) );
469 clipymin = (
PLINT) ( clipymin / FT->scale );
470 clipymax = (
PLINT) ( clipymax / FT->scale );
475 clipxmin = (
PLINT) ( clipxmin / FT->scalex );
476 clipxmax = (
PLINT) ( clipxmax / FT->scalex );
478 if ( FT->invert_y == 1 )
480 clipymin = (
PLINT) ( FT->ymax - ( clipymin / FT->scaley ) );
481 clipymax = (
PLINT) ( FT->ymax - ( clipymax / FT->scaley ) );
485 clipymin = (
PLINT) ( clipymin / FT->scaley );
486 clipymax = (
PLINT) ( clipymax / FT->scaley );
489 if ( clipxmin > clipxmax )
495 if ( clipymin > clipymax )
506 if ( slot->bitmap.pixel_mode == ft_pixel_mode_mono )
508 x += slot->bitmap_left;
509 y -= slot->bitmap_top;
511 imin = (short)
MAX( 0, clipymin - y );
512 imax = (short)
MIN( slot->bitmap.rows, clipymax - y );
513 for ( i = imin; i < imax; i++ )
515 for ( k = 0; k < n; k++ )
518 for ( j = 0; j < 8; j++ )
520 if ( ( bittest & (
unsigned char) slot->bitmap.buffer[( i * n ) + k] ) == bittest )
522 xx = x + ( k * 8 ) + j;
523 if ( ( xx >= clipxmin ) && ( xx <= clipxmax ) )
524 FT->pixel( pls, xx, y + i );
536 x += slot->bitmap_left;
537 y -= slot->bitmap_top;
539 imin = (short)
MAX( 0, clipymin - y );
540 imax = (short)
MIN( slot->bitmap.rows, clipymax - y );
541 kmin = (short)
MAX( 0, clipxmin - x );
542 kmax = (short)
MIN( slot->bitmap.width, clipxmax - x );
543 for ( i = imin; i < imax; i++ )
545 for ( k = kmin; k < kmax; k++ )
547 FT->shade = ( slot->bitmap.buffer[( i * slot->bitmap.width ) + k] );
550 if ( ( FT->BLENDED_ANTIALIASING == 1 ) && ( FT->read_pixel != NULL ) )
553 if ( FT->shade == 255 )
555 FT->pixel( pls, x + k, y + i );
559 current_pixel_colour = FT->read_pixel( pls, x + k, y + i );
561 G = GetGValue( current_pixel_colour );
562 R = GetRValue( current_pixel_colour );
563 B = GetBValue( current_pixel_colour );
564 alpha_a = (float) FT->shade / 255.0;
581 R = (
int) ( ( ( plsc->curcolor.r - R ) * alpha_a ) + R );
582 G = (int) ( ( ( plsc->curcolor.g - G ) * alpha_a ) + G );
583 B = (int) ( ( ( plsc->curcolor.b - B ) * alpha_a ) + B );
585 FT->set_pixel( pls, x + k, y + i, RGB( R > 255 ? 255 : R, G > 255 ? 255 : G, B > 255 ? 255 : B ) );
590 FT->col_idx = FT->ncol0_width - ( ( FT->ncol0_width * FT->shade ) / 255 );
591 FT->last_icol0 = pls->
icol0;
592 plcol0( pls->
icol0 + ( FT->col_idx * ( FT->ncol0_org - 1 ) ) );
593 FT->pixel( pls, x + k, y + i );
610 void plD_FreeType_init(
PLStream *pls )
618 "PLPLOT_FREETYPE_SANS_FONT",
619 "PLPLOT_FREETYPE_SERIF_FONT",
620 "PLPLOT_FREETYPE_MONO_FONT",
621 "PLPLOT_FREETYPE_SCRIPT_FONT",
622 "PLPLOT_FREETYPE_SYMBOL_FONT",
623 "PLPLOT_FREETYPE_SANS_ITALIC_FONT",
624 "PLPLOT_FREETYPE_SERIF_ITALIC_FONT",
625 "PLPLOT_FREETYPE_MONO_ITALIC_FONT",
626 "PLPLOT_FREETYPE_SCRIPT_ITALIC_FONT",
627 "PLPLOT_FREETYPE_SYMBOL_ITALIC_FONT",
628 "PLPLOT_FREETYPE_SANS_OBLIQUE_FONT",
629 "PLPLOT_FREETYPE_SERIF_OBLIQUE_FONT",
630 "PLPLOT_FREETYPE_MONO_OBLIQUE_FONT",
631 "PLPLOT_FREETYPE_SCRIPT_OBLIQUE_FONT",
632 "PLPLOT_FREETYPE_SYMBOL_OBLIQUE_FONT",
633 "PLPLOT_FREETYPE_SANS_BOLD_FONT",
634 "PLPLOT_FREETYPE_SERIF_BOLD_FONT",
635 "PLPLOT_FREETYPE_MONO_BOLD_FONT",
636 "PLPLOT_FREETYPE_SCRIPT_BOLD_FONT",
637 "PLPLOT_FREETYPE_SYMBOL_BOLD_FONT",
638 "PLPLOT_FREETYPE_SANS_BOLD_ITALIC_FONT",
639 "PLPLOT_FREETYPE_SERIF_BOLD_ITALIC_FONT",
640 "PLPLOT_FREETYPE_MONO_BOLD_ITALIC_FONT",
641 "PLPLOT_FREETYPE_SCRIPT_BOLD_ITALIC_FONT",
642 "PLPLOT_FREETYPE_SYMBOL_BOLD_ITALIC_FONT",
643 "PLPLOT_FREETYPE_SANS_BOLD_OBLIQUE_FONT",
644 "PLPLOT_FREETYPE_SERIF_BOLD_OBLIQUE_FONT",
645 "PLPLOT_FREETYPE_MONO_BOLD_OBLIQUE_FONT",
646 "PLPLOT_FREETYPE_SCRIPT_BOLD_OBLIQUE_FONT",
647 "PLPLOT_FREETYPE_SYMBOL_BOLD_OBLIQUE_FONT"
651 #if defined ( MSDOS ) || defined ( WIN32 )
652 static char *default_font_names[] = {
"arial.ttf",
"times.ttf",
"timesi.ttf",
"arial.ttf",
656 b = getenv(
"WINDIR" );
666 plwarn(
"Freetype seems already to have been initialised!" );
670 if ( ( pls->
FT = calloc( 1, (
size_t)
sizeof ( FT_Data ) ) ) == NULL )
671 plexit(
"Could not allocate memory for Freetype" );
673 FT = (FT_Data *) pls->
FT;
675 if ( ( FT->textbuf = calloc( NTEXT_ALLOC, 1 ) ) == NULL )
676 plexit(
"Could not allocate memory for Freetype text buffer" );
678 if ( FT_Init_FreeType( &FT->library ) )
679 plexit(
"Could not initialise Freetype library" );
684 #if defined ( MSDOS ) || defined ( WIN32 )
689 if ( ( a = getenv(
"PLPLOT_FREETYPE_FONT_DIR" ) ) != NULL )
693 else if ( WINDIR_PATH == NULL )
696 if ( access(
"c:\\windows\\fonts\\arial.ttf", F_OK ) == 0 )
698 strcpy( font_dir,
"c:/windows/fonts/" );
700 else if ( access(
"c:\\windows\\system\\arial.ttf", F_OK ) == 0 )
702 strcpy( font_dir,
"c:/windows/system/" );
705 plwarn(
"Could not find font path; I sure hope you have defined fonts manually !" );
710 strncat( WINDIR_PATH,
"\\fonts\\arial.ttf",
PLPLOT_MAX_PATH - 1 - strlen( WINDIR_PATH ) );
711 if ( access( WINDIR_PATH, F_OK ) == 0 )
713 b = strrchr( WINDIR_PATH,
'\\' );
717 strcpy( font_dir, WINDIR_PATH );
720 plwarn(
"Could not find font path; I sure hope you have defined fonts manually !" );
725 fprintf( stderr,
"%s\n", font_dir );
736 if ( ( a = getenv(
"PLPLOT_FREETYPE_FONT_DIR" ) ) != NULL )
752 if ( ( a = getenv( env_font_names[i] ) ) != NULL )
766 if ( ( a[0] ==
'/' ) || ( a[0] ==
'~' ) )
773 strncat( FT->font_name[i], a,
PLPLOT_MAX_PATH - 1 - strlen( FT->font_name[i] ) );
785 if ( ( infile = fopen( FT->font_name[i],
"r" ) ) == NULL )
789 "plD_FreeType_init: Could not find the freetype compatible font:\n %s",
799 if ( FT->font_name[i][0] ==
'\0' )
800 FontLookup[i].pfont = NULL;
802 FontLookup[i].pfont = (
unsigned char *) FT->font_name[i];
819 FT_Data *FT = (FT_Data *) pls->
FT;
820 double font_size = pls->
chrht * 72 / 25.4;
823 FT->chrht = pls->
chrht;
824 FT->xdpi = pls->
xdpi;
825 FT->ydpi = pls->
ydpi;
827 if ( fci != FT->fci )
829 const char *font_name =
plP_FCI2FontName( fci, FontLookup, N_TrueTypeLookup );
830 if ( font_name == NULL )
833 plexit(
"FT_SetFace: Bad FCI and no previous valid font to fall back on" );
835 plwarn(
"FT_SetFace: Bad FCI. Falling back to previous font." );
841 if ( FT->face != NULL )
843 FT_Done_Face( FT->face );
847 if ( FT->face == NULL )
849 if ( FT_New_Face( FT->library, font_name, 0, &FT->face ) )
850 plexit(
"FT_SetFace: Error loading a font in freetype" );
855 if ( FT->face->charmap == NULL )
856 FT_Select_Charmap( FT->face, FT->face->charmaps[0]->encoding );
859 FT_Set_Char_Size( FT->face, 0,
860 (FT_F26Dot6) ( font_size * 64 / TEXT_SCALING_FACTOR ), (FT_UInt) pls->
xdpi,
861 (FT_UInt) pls->
ydpi );
874 FT_Data *FT = (FT_Data *) pls->
FT;
876 int w = 0, h = 0, overh = 0, underh = 0;
882 int prevlineheights = 0;
902 if ( ( FT->fci != fci ) || ( FT->chrht != pls->
chrht ) || ( FT->xdpi != pls->
xdpi ) || ( FT->ydpi != pls->
ydpi ) )
903 FT_SetFace( pls, fci );
908 Debug6(
"%s %d %d %d %d\n",
"plD_render_freetype_text:",
909 FT->face->underline_position >> 6,
910 FT->face->descender >> 6,
911 FT->face->ascender >> 6,
912 ( ( FT->face->underline_position * -1 ) + FT->face->ascender ) >> 6 );
933 FT->matrix.xx = 0x10000;
934 FT->matrix.xy = 0x00000;
935 FT->matrix.yx = 0x00000;
936 FT->matrix.yy = 0x10000;
938 FT_Vector_Transform( &FT->pos, &FT->matrix );
939 FT_Set_Transform( FT->face, &FT->matrix, &FT->pos );
941 FT_StrX_YW( pls,
line, (
short) linelen, &w, &h, &overh, &underh );
966 height_factor = (
PLFLT) ( FT->face->ascender - FT->face->descender )
967 / FT->face->ascender;
968 height = (FT_Fixed) ( 0x10000 * height_factor );
971 FT->matrix.xx = (FT_Fixed) ( (
PLFLT) height * t[0] );
972 FT->matrix.xy = (FT_Fixed) ( (
PLFLT) height * t[2] );
973 FT->matrix.yx = (FT_Fixed) ( (
PLFLT) height * t[1] );
974 FT->matrix.yy = (FT_Fixed) ( (
PLFLT) height * t[3] );
976 FT->matrix.xx = (FT_Fixed) ( (
PLFLT) height * t[0] );
977 FT->matrix.xy = (FT_Fixed) ( (
PLFLT) height * t[1] );
978 FT->matrix.yx = (FT_Fixed) ( (
PLFLT) height * t[2] );
979 FT->matrix.yy = (FT_Fixed) ( (
PLFLT) height * t[3] );
990 Cos_A = cos( angle );
991 Sin_A = sin( angle );
993 matrix.xx = (FT_Fixed) ( (
PLFLT) 0x10000 * Cos_A );
996 matrix.xy = (FT_Fixed) ( (
PLFLT) 0x10000 * Sin_A * -1.0 );
997 matrix.yx = (FT_Fixed) ( (
PLFLT) 0x10000 * Sin_A );
999 matrix.xy = (FT_Fixed) ( (
PLFLT) 0x10000 * Sin_A );
1000 matrix.yx = (FT_Fixed) ( (
PLFLT) 0x10000 * Sin_A * -1.0 );
1003 matrix.yy = (FT_Fixed) ( (
PLFLT) 0x10000 * Cos_A );
1005 FT_Matrix_Multiply( &matrix, &FT->matrix );
1017 FT_Vector_Transform( &FT->pos, &FT->matrix );
1029 FT_Set_Transform( FT->face, &FT->matrix, &FT->pos );
1045 if ( FT->scale != 0.0 )
1047 x = (int) ( args->
x / FT->scale );
1049 if ( FT->invert_y == 1 )
1050 y = (int) ( FT->ymax - ( args->
y / FT->scale ) );
1052 y = (int) ( args->
y / FT->scale );
1056 x = (int) ( args->
x / FT->scalex );
1058 if ( FT->invert_y == 1 )
1059 y = (int) ( FT->ymax - ( args->
y / FT->scaley ) );
1061 y = (int) ( args->
y / FT->scaley );
1086 #ifdef DODGIE_DECENDER_HACK
1113 adjust.x = (FT_Pos) ( args->
just *
ROUND( (
PLFLT) FT->face->glyph->metrics.width / 64.0 ) );
1114 adjust.y = (FT_Pos)
ROUND( (
PLFLT) FT->face->glyph->metrics.height / 128.0 );
1128 ROUND( (
PLFLT) FT->face->size->metrics.height / height_factor / 128.0 - ( prevlineheights + overh ) / 64.0 );
1129 adjust.x = (FT_Pos) ( args->
just *
ROUND( w / 64.0 ) );
1132 FT_Vector_Transform( &adjust, &FT->matrix );
1134 x -= (int) adjust.x;
1135 y += (
int) adjust.y;
1137 FT_WriteStrW( pls,
line, (
short) linelen, x, y );
1142 line += linelen + 1;
1143 prevlineheights += h + overh + underh;
1148 plD_render_freetype_sym( pls, args );
1160 void plD_FreeType_Destroy(
PLStream *pls )
1162 FT_Data *FT = (FT_Data *) pls->
FT;
1167 if ( ( FT->smooth_text == 1 ) && ( FT->BLENDED_ANTIALIASING == 0 ) )
1170 free( FT->textbuf );
1171 FT_Done_Library( FT->library );
1186 static PLFLT CalculateIncrement(
int bg,
int fg,
int levels )
1193 ret = ( ( fg + 1 ) - bg ) / levels;
1195 ret = ( ( ( fg - 1 ) - bg ) / levels );
1215 void pl_set_extended_cmap0(
PLStream *pls,
int ncol0_width,
int ncol0_org )
1219 PLFLT r_inc, g_inc, b_inc;
1221 for ( i = 1; i < ncol0_org; i++ )
1227 r_inc = CalculateIncrement( pls->
cmap0[0].
r, r, ncol0_width );
1228 g_inc = CalculateIncrement( pls->
cmap0[0].
g, g, ncol0_width );
1229 b_inc = CalculateIncrement( pls->
cmap0[0].
b, b, ncol0_width );
1231 for ( j = 0, k = ncol0_org + i - 1; j < ncol0_width; j++, k += ( ncol0_org - 1 ) )
1236 if ( ( r < 0 ) || ( g < 0 ) || ( b < 0 ) )
1239 plscol0( k, ( r > 0xff ? 0xff : r ), ( g > 0xff ? 0xff : g ), ( b > 0xff ? 0xff : b ) );
1259 FT_Data *FT = (FT_Data *) pls->
FT;
1264 if ( FT->scale != 0.0 )
1266 x = (int) ( args->
x / FT->scale );
1268 if ( FT->invert_y == 1 )
1269 y = (int) ( FT->ymax - ( args->
y / FT->scale ) );
1271 y = (int) ( args->
y / FT->scale );
1275 x = (int) ( args->
x / FT->scalex );
1277 if ( FT->invert_y == 1 )
1278 y = (int) ( FT->ymax - ( args->
y / FT->scaley ) );
1280 y = (int) ( args->
y / FT->scaley );
1300 #ifdef DODGIE_DECENDER_HACK
1301 adjust.y = ( FT->face->descender >> 6 ) * 3;
1303 adjust.y = ( FT->face->descender >> 6 );
1307 FT_Vector_Transform( &adjust, &FT->matrix );
1308 x += (int) adjust.x;
1309 y -= (
int) adjust.y;
1312 FT_SetFace( pls, fci );
1314 FT = (FT_Data *) pls->
FT;
1315 FT_Set_Transform( FT->face, &FT->matrix, &FT->pos );
1317 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 );
1327 x -= (int) ( ( FT->face->glyph->advance.x >> 6 ) / 2 );
1328 FT_PlotChar( pls, FT, FT->face->glyph, x, y );