Roxen.git/server/font_handlers/ttf.pike:1:
// This file is part of Roxen WebServer.
- // Copyright © 1996 - 2000, Roxen IS.
+ // Copyright © 1996 - 2009, Roxen IS.
#if !constant(Image.FreeType.Face)
#if constant(has_Image_TTF)
#include <config.h>
- constant cvs_version = "$Id: ttf.pike,v 1.9 2001/08/21 14:26:51 per Exp $";
+ constant cvs_version = "$Id$";
constant name = "TTF fonts";
constant doc = "True Type font loader. Uses freetype to render text.";
constant scalable = 1;
inherit FontHandler;
- static mapping ttf_font_names_cache;
+ protected mapping ttf_font_names_cache;
- static string trimttfname( string n )
+ protected string trimttfname( string n )
{
n = lower_case(replace( n, "\t", " " ));
return ((n/" ")*"")-"'";
}
- static string translate_ttf_style( string style )
+ protected 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";
+ // Check for weight. Default is "n" for normal/regular/roman.
+ style = lower_case((style - "-") - " ");
+ string weight = "n";
+ if (has_value(style, "bold"))
+ weight = "b";
+ else if (has_value(style, "black"))
+ weight = "B";
+ else if (has_value(style, "light"))
+ weight = "l";
+
+ // Check for slant. Default is "n" for regular.
+ string slant = "n";
+ if (has_value(style, "italic") ||
+ has_value(style, "oblique"))
+ slant = "i";
+
+ // Combine to full style
+ return weight + slant;
}
- if(search(lower_case(style), "oblique"))
- return "ni"; // for now.
- return "nn";
- }
+
- static void build_font_names_cache( )
+ protected void build_font_names_cache( )
{
mapping ttf_done = ([ ]);
- ttf_font_names_cache=([]);
+ mapping new_ttf_font_names_cache=([]);
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) {
if( !file_stat( path+"/fontname" ) )
Roxen.git/server/font_handlers/ttf.pike:59: Inside #if !constant(Image.FreeType.Face)
}
// 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));
- if(!ttf_font_names_cache[f])
- ttf_font_names_cache[f] = ([]);
- ttf_font_names_cache[f][ translate_ttf_style(n->style) ]
- = combine_path(dir+"/",fname);
+ 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);
}
}
}
};
map( roxen->query("font_dirs"), traverse_font_dir );
-
+
+ ttf_font_names_cache = new_ttf_font_names_cache;
}
class TTFWrapper
{
inherit Font;
- static int size, rsize;
- static object real;
- static object encoder;
- static function(string ...:Image.image) real_write;
- static int fake_bold, fake_italic;
+ protected int size, rsize;
+ protected object real;
+ protected object encoder;
+ protected function(string ...:Image.image) real_write;
+ protected int fake_bold, fake_italic;
int height( )
{
return rsize ? rsize : (rsize = text_extents("W")[1] );
}
- static string _sprintf()
+ protected string _sprintf()
{
return sprintf( "TTF(%O,%d)", real, size );
}
- static Image.image write_encoded(string ... what)
+ protected 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() );
-
+ int oversample = roxen->query("font_oversampling");
+
// 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()),
- (int)abs(`+(0,0,@res[..sizeof(res)-2]->ysize())*y_spacing)+res[-1]->ysize() );
+ int image_width = max(0, @res->xsize());
+ int image_height =
+ (int)abs(`+(0, 0, @res[..sizeof(res) - 2]->ysize()) * y_spacing) +
+ res[-1]->ysize();
+ int y_add = 0;
+ if (oversample) {
+ // Make sure image dimensions are a multiple of 2. If height is odd
+ // we'll offset the text baseline one pixel to get the extra line at
+ // the top of the image.
+ image_width = (image_width + 1) & 0xFFFFFFFE;
+ y_add = (image_height & 1);
+ image_height = (image_height + 1) & 0xFFFFFFFE;
+ }
+ Image.Image rr = Image.Image(image_width, image_height);
float start;
if( y_spacing < 0 )
start = (float)rr->ysize()-res[0]->ysize();
-
+ start += (float) y_add;
foreach( res, object r )
{
if( j_right )
rr->paste_alpha_color( r, 255,255,255, rr->xsize()-r->xsize(), (int)start );
else if( j_center )
rr->paste_alpha_color( r, 255,255,255,(rr->xsize()-r->xsize())/2, (int)start );
else
rr->paste_alpha_color( r, 255,255,255, 0, (int)start );
start += r->ysize()*y_spacing;
}
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 );
}
-
+ rr->setcolor( 0,0,0 );
if( fake_italic )
- rr = rr->skewx( -(rr->ysize()/3), Image.Color.black );
+ rr = rr->skewx( -(rr->ysize()/3) );
+ if (oversample)
+ return rr->scale(0.5);
+ else
return rr;
-
+
}
array text_extents( string what )
{
Image.Image o = write( what );
return ({ o->xsize(), o->ysize() });
}
void create(object r, int s, string fn, int fb, int fi)
{
string encoding;
fake_bold = fb;
fake_italic = fi;
real = r;
size = s;
-
+ 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
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);
}
}
#ifdef THREADS
Thread.Mutex lock = Thread.Mutex();
#endif
- array available_fonts()
+ array available_fonts(int(0..1)|void force_reload)
{
#ifdef THREADS
object key = lock->lock();
#endif
- if( !ttf_font_names_cache ) build_font_names_cache( );
+ if( !ttf_font_names_cache || force_reload ) build_font_names_cache( );
return indices( ttf_font_names_cache );
}
array(mapping) font_information( string font )
{
if( !has_font( font, 0 ) )
return ({});
mapping res = ([
"name":font,
Roxen.git/server/font_handlers/ttf.pike:207: Inside #if !constant(Image.FreeType.Face)
if( font[0] == '/' )
f = Image.TTF( font );
else
f = Image.TTF( (font=values(ttf_font_names_cache[ font ])[0]) );
res->path = font;
res |= f->names();
return ({ res });
}
- array(string) has_font( string name, int size )
+ array(string) has_font( string name, int size, int(0..1)|void force )
{
#ifdef THREADS
object key = lock->lock();
#endif
if( !ttf_font_names_cache )
build_font_names_cache( );
if( ttf_font_names_cache[ name ] )
return indices(ttf_font_names_cache[ name ]);
-
+ if (force) {
+ build_font_names_cache();
+ if( ttf_font_names_cache[ name ] )
+ return indices(ttf_font_names_cache[ name ]);
}
-
+ }
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 ) )
return TTFWrapper( fo, size, f,0,0 );
return 0;
}
-
+ if (!ttf_font_names_cache) {
+ build_font_names_cache();
+ }
+
if(ttf_font_names_cache[ lower_case(f) ])
{
f = lower_case(f);
if( tmp = ttf_font_names_cache[ f ][ style ] )
{
fo = Image.TTF( tmp );
if( fo ) return TTFWrapper( fo(), size, tmp,0,0 );
}
if( fo = Image.TTF( roxen_path(f = values(ttf_font_names_cache[ f ])[0])))
return TTFWrapper( fo(), size, f, bold, italic );