8b6da62000-09-03Martin Nilsson // This file is part of Roxen WebServer. // Copyright © 1996 - 2000, Roxen IS.
2078852000-12-11Per Hedbor #if !constant(Image.FreeType.Face)
c6fd2e2000-09-03Per Hedbor #if constant(has_Image_TTF)
8b6da62000-09-03Martin Nilsson #include <config.h>
449d242002-08-16Mattias Andersson constant cvs_version = "$Id: ttf.pike,v 1.14 2002/08/16 13:55:50 mattias Exp $";
c6fd2e2000-09-03Per Hedbor  constant name = "TTF fonts";
0bd4d92000-09-04Per Hedbor constant doc = "True Type font loader. Uses freetype to render text.";
c6fd2e2000-09-03Per Hedbor constant scalable = 1; inherit FontHandler; static mapping ttf_font_names_cache; static string trimttfname( string n ) { n = lower_case(replace( n, "\t", " " )); return ((n/" ")*"")-"'"; } static string translate_ttf_style( string style ) { switch( lower_case( (style-"-")-" " ) ) { case "normal": case "regular": return "nn"; case "italic": return "ni"; case "oblique": return "ni"; case "bold": return "bn"; case "bolditalic":case "italicbold": return "bi"; case "black": return "Bn"; case "blackitalic":case "italicblack":return "Bi"; case "light": return "ln"; case "lightitalic":case "italiclight":return "li"; } if(search(lower_case(style), "oblique")) return "ni"; // for now. return "nn"; } static void build_font_names_cache( ) { mapping ttf_done = ([ ]);
2963142001-11-14Henrik Grubbström (Grubba)  mapping new_ttf_font_names_cache=([]);
c6fd2e2000-09-03Per Hedbor  void traverse_font_dir( string dir ) { foreach(r_get_dir( dir )||({}), string fname) { string path=combine_path(dir+"/",fname); if(!ttf_done[path]++) { Stat a=file_stat(path); if(a && a[1]==-2) {
745fce2000-09-04Per Hedbor  if( !file_stat( path+"/fontname" ) ) // no, we do not want to try this dir. :-) traverse_font_dir( path );
c6fd2e2000-09-03Per Hedbor  continue; } // Here is a good place to impose the artificial restraint that // the file must match *.ttf Image.TTF ttf; if(catch(ttf = Image.TTF( combine_path(dir+"/",fname) ))) continue; if(ttf) { mapping n = ttf->names(); string f = lower_case(trimttfname(n->family));
2963142001-11-14Henrik Grubbström (Grubba)  if(!new_ttf_font_names_cache[f]) new_ttf_font_names_cache[f] = ([]); new_ttf_font_names_cache[f][ translate_ttf_style(n->style) ] = combine_path(dir+"/",fname);
c6fd2e2000-09-03Per Hedbor  } } } }; map( roxen->query("font_dirs"), traverse_font_dir );
2963142001-11-14Henrik Grubbström (Grubba)  ttf_font_names_cache = new_ttf_font_names_cache;
c6fd2e2000-09-03Per Hedbor } class TTFWrapper { inherit Font; static int size, rsize; static object real; static object encoder; static function(string ...:Image.image) real_write;
b5a1a72001-08-21Per Hedbor  static int fake_bold, fake_italic;
c6fd2e2000-09-03Per Hedbor  int height( ) { return rsize ? rsize : (rsize = text_extents("W")[1] ); } static string _sprintf() { return sprintf( "TTF(%O,%d)", real, size ); } static Image.image write_encoded(string ... what) { return real->write(@(encoder? Array.map(what, lambda(string s) { return encoder->clear()-> feed(s)->drain(); }):what)); } // FIXME: Handle x_spacing Image.Image write( string ... what ) { if( !sizeof( what ) ) return Image.Image( 1,height() ); // nbsp -> "" what = map( (array(string))what, replace, " ", "" ); // cannot write "" with Image.TTF. what = replace( what, "", " " ); array(Image.Image) res = map( what, real_write ); Image.Image rr = Image.Image( max(0,@res->xsize()),
4243242000-10-21Per Hedbor  (int)abs(`+(0,0,@res[..sizeof(res)-2]->ysize())*y_spacing)+res[-1]->ysize() );
c6fd2e2000-09-03Per Hedbor  float start; if( y_spacing < 0 ) start = (float)rr->ysize()-res[0]->ysize(); foreach( res, object r ) { if( j_right )
4243242000-10-21Per Hedbor  rr->paste_alpha_color( r, 255,255,255, rr->xsize()-r->xsize(), (int)start );
c6fd2e2000-09-03Per Hedbor  else if( j_center )
4243242000-10-21Per Hedbor  rr->paste_alpha_color( r, 255,255,255,(rr->xsize()-r->xsize())/2, (int)start );
c6fd2e2000-09-03Per Hedbor  else
4243242000-10-21Per Hedbor  rr->paste_alpha_color( r, 255,255,255, 0, (int)start );
c6fd2e2000-09-03Per Hedbor  start += r->ysize()*y_spacing; }
b5a1a72001-08-21Per Hedbor  if( fake_bold ) { object r2 = Image.Image( rr->xsize()+2, rr->ysize() ); object r3 = rr*0.3; for( int i = 0; i<2; i++ ) for( int j = 0; j<2; j++ ) r2->paste_alpha_color( r3, 255, 255, 255, i, j ); rr = r2->paste_alpha_color( rr, 255,255,255, 1,1 ); }
7e06712001-09-27Per Hedbor  rr->setcolor( 0,0,0 );
b5a1a72001-08-21Per Hedbor  if( fake_italic )
7e06712001-09-27Per Hedbor  rr = rr->skewx( -(rr->ysize()/3) );
449d242002-08-16Mattias Andersson  if( roxen->query("font_oversampling") ) return rr->scale(0.5); else return rr;
c6fd2e2000-09-03Per Hedbor  } array text_extents( string what ) {
745fce2000-09-04Per Hedbor  Image.Image o = write( what ); return ({ o->xsize(), o->ysize() });
c6fd2e2000-09-03Per Hedbor  }
b5a1a72001-08-21Per Hedbor  void create(object r, int s, string fn, int fb, int fi)
c6fd2e2000-09-03Per Hedbor  { string encoding;
b5a1a72001-08-21Per Hedbor  fake_bold = fb; fake_italic = fi;
c6fd2e2000-09-03Per Hedbor  real = r; size = s;
449d242002-08-16Mattias Andersson  if( roxen->query("font_oversampling") ) real->set_height( (int)(size*64/34.5) ); // aproximate to pixels else real->set_height( (int)(size*32/34.5) ); // aproximate to pixels
c6fd2e2000-09-03Per Hedbor  if(r_file_stat(fn+".properties")) parse_html(lopen(fn+".properties","r")->read(), ([]), (["encoding":lambda(string tag, mapping m, string enc) { encoding = enc; }])); if(encoding) encoder = Locale.Charset.encoder(encoding, ""); real_write = (encoder? write_encoded : real->write); } }
e892262000-09-04Per Hedbor #ifdef THREADS Thread.Mutex lock = Thread.Mutex(); #endif
2963142001-11-14Henrik Grubbström (Grubba) array available_fonts(int(0..1)|void force_reload)
c6fd2e2000-09-03Per Hedbor {
e892262000-09-04Per Hedbor #ifdef THREADS object key = lock->lock(); #endif
2963142001-11-14Henrik Grubbström (Grubba)  if( !ttf_font_names_cache || force_reload ) build_font_names_cache( );
c6fd2e2000-09-03Per Hedbor  return indices( ttf_font_names_cache ); }
8b6da62000-09-03Martin Nilsson array(mapping) font_information( string font )
c6fd2e2000-09-03Per Hedbor { if( !has_font( font, 0 ) )
8b6da62000-09-03Martin Nilsson  return ({});
c6fd2e2000-09-03Per Hedbor  mapping res = ([ "name":font, "format":"ttf", ]); Image.TTF f; if( font[0] == '/' ) f = Image.TTF( font ); else
8b6da62000-09-03Martin Nilsson  f = Image.TTF( (font=values(ttf_font_names_cache[ font ])[0]) );
c6fd2e2000-09-03Per Hedbor  res->path = font; res |= f->names();
8b6da62000-09-03Martin Nilsson  return ({ res });
c6fd2e2000-09-03Per Hedbor }
7ff1c02001-11-15Anders Johansson array(string) has_font( string name, int size, int(0..1)|void force )
c6fd2e2000-09-03Per Hedbor {
e892262000-09-04Per Hedbor #ifdef THREADS object key = lock->lock(); #endif
c6fd2e2000-09-03Per Hedbor  if( !ttf_font_names_cache ) build_font_names_cache( ); if( ttf_font_names_cache[ name ] ) return indices(ttf_font_names_cache[ name ]);
2963142001-11-14Henrik Grubbström (Grubba)  if (force) { build_font_names_cache(); if( ttf_font_names_cache[ name ] ) return indices(ttf_font_names_cache[ name ]); }
c6fd2e2000-09-03Per Hedbor } Font open(string f, int size, int bold, int italic ) { string tmp; int|string style = font_style( f, size, bold, italic ); object fo; if( style == -1 ) // exact file { if( fo = Image.TTF( name ) )
b5a1a72001-08-21Per Hedbor  return TTFWrapper( fo, size, f,0,0 );
c6fd2e2000-09-03Per Hedbor  return 0; }
2963142001-11-14Henrik Grubbström (Grubba)  if (!ttf_font_names_cache) { build_font_names_cache(); }
c6fd2e2000-09-03Per Hedbor  if(ttf_font_names_cache[ lower_case(f) ]) { f = lower_case(f); if( tmp = ttf_font_names_cache[ f ][ style ] ) { fo = Image.TTF( tmp );
b5a1a72001-08-21Per Hedbor  if( fo ) return TTFWrapper( fo(), size, tmp,0,0 );
c6fd2e2000-09-03Per Hedbor  } if( fo = Image.TTF( roxen_path(f = values(ttf_font_names_cache[ f ])[0])))
b5a1a72001-08-21Per Hedbor  return TTFWrapper( fo(), size, f, bold, italic );
c6fd2e2000-09-03Per Hedbor  } return 0; }
745fce2000-09-04Per Hedbor  void create() { roxen.getvar( "font_dirs" ) ->add_changed_callback( lambda(Variable.Variable v){ ttf_font_names_cache=0; } ); }
c6fd2e2000-09-03Per Hedbor #endif
2078852000-12-11Per Hedbor #endif