Fix Debian #368733: implement fontconfig support
[synfig.git] / synfig-core / trunk / src / modules / lyr_freetype / lyr_freetype.cpp
1 /*! ========================================================================
2 ** Synfig
3 ** Template File
4 ** $Id: lyr_freetype.cpp,v 1.5 2005/01/24 05:00:18 darco Exp $
5 **
6 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
7 **      Copyright (c) 2006 Paul Wise
8 **
9 **      This package is free software; you can redistribute it and/or
10 **      modify it under the terms of the GNU General Public License as
11 **      published by the Free Software Foundation; either version 2 of
12 **      the License, or (at your option) any later version.
13 **
14 **      This package is distributed in the hope that it will be useful,
15 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
16 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 **      General Public License for more details.
18 **
19 ** === N O T E S ===========================================================
20 **
21 ** ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #define SYNFIG_LAYER
26
27 #ifdef USING_PCH
28 #       include "pch.h"
29 #else
30 #ifdef HAVE_CONFIG_H
31 #       include <config.h>
32 #endif
33 #ifdef WITH_FONTCONFIG
34 #include <fontconfig/fontconfig.h>
35 #endif
36
37 #include "lyr_freetype.h"
38
39
40 #endif
41
42 using namespace std;
43 using namespace etl;
44 using namespace synfig;
45
46 /* === M A C R O S ========================================================= */
47
48 #define MAX_GLYPHS              2000
49
50 #define PANGO_STYLE_NORMAL (0)
51 #define PANGO_STYLE_OBLIQUE (1)
52 #define PANGO_STYLE_ITALIC (2)
53
54
55 #define WEIGHT_NORMAL (400)
56 #define WEIGHT_BOLD (700)
57
58 /* === G L O B A L S ======================================================= */
59
60 SYNFIG_LAYER_INIT(lyr_freetype);
61 SYNFIG_LAYER_SET_NAME(lyr_freetype,"text");
62 SYNFIG_LAYER_SET_LOCAL_NAME(lyr_freetype,_("Simple Text"));
63 SYNFIG_LAYER_SET_CATEGORY(lyr_freetype,_("Typography"));
64 SYNFIG_LAYER_SET_VERSION(lyr_freetype,"0.2");
65 SYNFIG_LAYER_SET_CVS_ID(lyr_freetype,"$Id: lyr_freetype.cpp,v 1.5 2005/01/24 05:00:18 darco Exp $");
66
67 /* === P R O C E D U R E S ================================================= */
68
69 /*Glyph::~Glyph()
70 {
71         if(glyph)FT_Done_Glyph(glyph);  
72 }
73 */
74 void
75 TextLine::clear_and_free()
76 {
77         std::vector<Glyph>::iterator iter;
78         for(iter=glyph_table.begin();iter!=glyph_table.end();++iter)
79         {
80                 if(iter->glyph)FT_Done_Glyph(iter->glyph);
81                 iter->glyph=0;
82         }
83         glyph_table.clear();
84 }
85
86 /* === M E T H O D S ======================================================= */
87
88 lyr_freetype::lyr_freetype()
89 {
90         face=0;
91         
92         size=Vector(0.25,0.25);
93         text=_("Text Layer");
94         color=Color::black();
95         pos=Vector(0,0);
96         orient=Vector(0.5,0.5);
97         compress=1.0;
98         vcompress=1.0;
99         weight=WEIGHT_NORMAL;
100         style=PANGO_STYLE_NORMAL;
101         family="Sans Serif";
102         use_kerning=true;
103         grid_fit=false;
104         old_version=false;
105         set_blend_method(Color::BLEND_COMPOSITE);
106         needs_sync_=true;
107         
108         new_font(family,style,weight);
109         
110         invert=false;
111 }
112
113 lyr_freetype::~lyr_freetype()
114 {
115         if(face)
116                 FT_Done_Face(face);
117 }
118
119 void
120 lyr_freetype::new_font(const synfig::String &family, int style, int weight)
121 {               
122         if(
123                 !new_font_(family,style,weight) &&
124                 !new_font_(family,style,WEIGHT_NORMAL) &&
125                 !new_font_(family,PANGO_STYLE_NORMAL,weight) &&
126                 !new_font_(family,PANGO_STYLE_NORMAL,WEIGHT_NORMAL) &&
127                 !new_font_("sans serif",style,weight) &&
128                 !new_font_("sans serif",style,WEIGHT_NORMAL) &&
129                 !new_font_("sans serif",PANGO_STYLE_NORMAL,weight)
130         )
131                 new_font_("sans serif",PANGO_STYLE_NORMAL,WEIGHT_NORMAL);
132 }
133
134 bool
135 lyr_freetype::new_font_(const synfig::String &font_fam_, int style, int weight)
136 {
137         synfig::String font_fam(font_fam_);
138
139         if(new_face(font_fam_))
140                 return true;
141         
142         //start evil hack
143         for(unsigned int i=0;i<font_fam.size();i++)font_fam[i]=tolower(font_fam[i]);
144         //end evil hack
145
146         if(font_fam=="arial black")
147 #ifndef __APPLE__
148         if(new_face("ariblk"))
149                         return true;
150                 else
151 #endif
152                 font_fam="sans serif";
153         
154         if(font_fam=="sans serif" || font_fam=="arial")
155         {
156                 String arial("arial");
157                 if(weight>WEIGHT_NORMAL)
158                         arial+='b';
159                 if(style==PANGO_STYLE_ITALIC||style==PANGO_STYLE_OBLIQUE)
160                         arial+='i';
161                 else
162                         if(weight>WEIGHT_NORMAL) arial+='d';
163
164                 if(new_face(arial))
165                         return true;
166 #ifdef __APPLE__
167                 if(new_face("Helvetica RO"))
168                         return true;
169 #endif
170         }
171
172         if(font_fam=="comic" || font_fam=="comic sans")
173         {
174                 String filename("comic");
175                 if(weight>WEIGHT_NORMAL)
176                         filename+='b';
177                 if(style==PANGO_STYLE_ITALIC||style==PANGO_STYLE_OBLIQUE)
178                         filename+='i';
179                 else if(weight>WEIGHT_NORMAL) filename+='d';
180
181                 if(new_face(filename))
182                         return true;
183         }
184
185         if(font_fam=="courier" || font_fam=="courier new")
186         {
187                 String filename("cour");
188                 if(weight>WEIGHT_NORMAL)
189                         filename+='b';
190                 if(style==PANGO_STYLE_ITALIC||style==PANGO_STYLE_OBLIQUE)
191                         filename+='i';
192                 else if(weight>WEIGHT_NORMAL) filename+='d';
193
194                 if(new_face(filename))
195                         return true;
196         }
197
198         if(font_fam=="serif" || font_fam=="times" || font_fam=="times new roman")
199         {
200                 String filename("times");
201                 if(weight>WEIGHT_NORMAL)
202                         filename+='b';
203                 if(style==PANGO_STYLE_ITALIC||style==PANGO_STYLE_OBLIQUE)
204                         filename+='i';
205                 else if(weight>WEIGHT_NORMAL) filename+='d';
206
207                 if(new_face(filename))
208                         return true;
209         }
210         
211         if(font_fam=="trebuchet")
212         {
213                 String filename("trebuc");
214                 if(weight>WEIGHT_NORMAL)
215                         filename+='b';
216                 if(style==PANGO_STYLE_ITALIC||style==PANGO_STYLE_OBLIQUE)
217                 {
218                         filename+='i';
219                         if(weight<=WEIGHT_NORMAL) filename+='t';
220                 }
221                 else if(weight>WEIGHT_NORMAL) filename+='d';
222
223                 if(new_face(filename))
224                         return true;
225         }
226                 
227         
228         if(font_fam=="sans serif" || font_fam=="luxi sans")
229         {
230                 {
231                         String luxi("luxis");
232                         if(weight>WEIGHT_NORMAL)
233                                 luxi+='b';
234                         else
235                                 luxi+='r';
236                         if(style==PANGO_STYLE_ITALIC||style==PANGO_STYLE_OBLIQUE)
237                                 luxi+='i';
238                         
239                         
240                         if(new_face(luxi))
241                                 return true;
242                 }
243                 if(new_face("arial"))
244                         return true;
245                 if(new_face("Arial"))
246                         return true;
247         }
248         if(font_fam=="serif" || font_fam=="times" || font_fam=="times new roman" || font_fam=="luxi serif")
249         {
250                 {
251                         String luxi("luxir");
252                         if(weight>WEIGHT_NORMAL)
253                                 luxi+='b';
254                         else
255                                 luxi+='r';
256                         if(style==PANGO_STYLE_ITALIC||style==PANGO_STYLE_OBLIQUE)
257                                 luxi+='i';
258                         
259                         if(new_face(luxi))
260                                 return true;
261                 }
262                 if(new_face("Times New Roman"))
263                         return true;
264                 if(new_face("Times"))
265                         return true;
266         }
267         if(font_fam=="luxi")
268         {
269                 {
270                         String luxi("luxim");
271                         if(weight>WEIGHT_NORMAL)
272                                 luxi+='b';
273                         else
274                                 luxi+='r';
275                         if(style==PANGO_STYLE_ITALIC||style==PANGO_STYLE_OBLIQUE)
276                                 luxi+='i';
277                         
278                         if(new_face(luxi))
279                                 return true;
280                 }
281
282                 if(new_face("Times New Roman"))
283                         return true;
284                 if(new_face("Times"))
285                         return true;
286         }
287         
288         return new_face(font_fam_) || new_face(font_fam);
289         
290         return false;
291 }
292
293 #ifdef USE_MAC_FT_FUNCS
294 void fss2path(char *path, FSSpec *fss)
295 {
296   int l;             //fss->name contains name of last item in path
297   for(l=0; l<(fss->name[0]); l++) path[l] = fss->name[l + 1]; 
298   path[l] = 0;
299
300   if(fss->parID != fsRtParID) //path is more than just a volume name
301   { 
302     int i, len;
303     CInfoPBRec pb;
304     
305     pb.dirInfo.ioNamePtr = fss->name;
306     pb.dirInfo.ioVRefNum = fss->vRefNum;
307     pb.dirInfo.ioDrParID = fss->parID;
308     do
309     {
310       pb.dirInfo.ioFDirIndex = -1;  //get parent directory name
311       pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;   
312       if(PBGetCatInfoSync(&pb) != noErr) break;
313
314       len = fss->name[0] + 1;
315       for(i=l; i>=0;  i--) path[i + len] = path[i];
316       for(i=1; i<len; i++) path[i - 1] = fss->name[i]; //add to start of path
317       path[i - 1] = ':';
318       l += len;
319 } while(pb.dirInfo.ioDrDirID != fsRtDirID); //while more directory levels
320   }
321 }
322 #endif
323
324 bool
325 lyr_freetype::new_face(const String &newfont)
326 {
327         int error;
328         FT_Long face_index=0;
329
330         // If we are already loaded, don't bother reloading.
331         if(face && font==newfont)
332                 return true;
333
334         if(face)
335         {
336                 FT_Done_Face(face);
337                 face=0;
338         }
339
340         error=FT_New_Face(ft_library,newfont.c_str(),face_index,&face);
341         if(error)error=FT_New_Face(ft_library,(newfont+".ttf").c_str(),face_index,&face);
342
343         if(get_canvas())
344         {
345                 if(error)error=FT_New_Face(ft_library,(get_canvas()->get_file_path()+ETL_DIRECTORY_SEPERATOR+newfont).c_str(),face_index,&face);
346                 if(error)error=FT_New_Face(ft_library,(get_canvas()->get_file_path()+ETL_DIRECTORY_SEPERATOR+newfont+".ttf").c_str(),face_index,&face);
347         }
348
349 #ifdef USE_MAC_FT_FUNCS
350         if(error)
351         {
352                 FSSpec fs_spec;
353                 error=FT_GetFile_From_Mac_Name(newfont.c_str(),&fs_spec,&face_index);
354                 if(!error)
355                 {
356                         char filename[512];
357                         fss2path(filename,&fs_spec);
358                         //FSSpecToNativePathName(fs_spec,filename,sizeof(filename)-1, 0);
359                         
360                         error=FT_New_Face(ft_library, filename, face_index,&face);
361                         //error=FT_New_Face_From_FSSpec(ft_library, &fs_spec, face_index,&face);
362                         synfig::info(__FILE__":%d: \"%s\" (%s) -- ft_error=%d",__LINE__,newfont.c_str(),filename,error);
363                 }
364                 else
365                 {
366                         synfig::info(__FILE__":%d: \"%s\" -- ft_error=%d",__LINE__,newfont.c_str(),error);
367                         // Unable to generate fs_spec
368                 }
369                   
370         }
371 #endif
372
373 #ifdef WITH_FONTCONFIG
374         if(error)
375         {
376                 FcFontSet *fs;
377                 FcResult result;
378                 if( !FcInit() )
379                 {
380                         synfig::warning("lyr_freetype: fontconfig: %s",_("unable to initialise")));
381                         error = 1;
382                 } else {
383                         FcPattern* pat = FcNameParse((FcChar8 *) newfont.c_str());
384                         FcConfigSubstitute(0, pat, FcMatchPattern);
385                         FcDefaultSubstitute(pat);
386                         FcPattern *match;
387                         fs = FcFontSetCreate();
388                         match = FcFontMatch(0, pat, &result);
389                         if (match)
390                                 FcFontSetAdd(fs, match);
391                         if (pat)
392                                 FcPatternDestroy(pat);
393                         if(fs){
394                                 FcChar8* file;
395                                 if( FcPatternGetString (fs->fonts[0], FC_FILE, 0, &file) == FcResultMatch )
396                                         error=FT_New_Face(ft_library,(const char*)file,face_index,&face);
397                                 FcFontSetDestroy(fs);
398                         } else
399                                 synfig::warning("lyr_freetype: fontconfig: %s",_("empty font set")));
400                 }
401         }
402 #endif
403
404 #ifdef WIN32
405         if(error)error=FT_New_Face(ft_library,("C:\\WINDOWS\\FONTS\\"+newfont).c_str(),face_index,&face);
406         if(error)error=FT_New_Face(ft_library,("C:\\WINDOWS\\FONTS\\"+newfont+".ttf").c_str(),face_index,&face);
407 #else
408
409 #ifdef __APPLE__
410         if(error)error=FT_New_Face(ft_library,("~/Library/Fonts/"+newfont).c_str(),face_index,&face);
411         if(error)error=FT_New_Face(ft_library,("~/Library/Fonts/"+newfont+".ttf").c_str(),face_index,&face);
412         if(error)error=FT_New_Face(ft_library,("~/Library/Fonts/"+newfont+".dfont").c_str(),face_index,&face);
413
414         if(error)error=FT_New_Face(ft_library,("/Library/Fonts/"+newfont).c_str(),face_index,&face);
415         if(error)error=FT_New_Face(ft_library,("/Library/Fonts/"+newfont+".ttf").c_str(),face_index,&face);
416         if(error)error=FT_New_Face(ft_library,("/Library/Fonts/"+newfont+".dfont").c_str(),face_index,&face);
417 #endif
418
419         if(error)error=FT_New_Face(ft_library,("/usr/X11R6/lib/X11/fonts/type1/"+newfont).c_str(),face_index,&face);
420         if(error)error=FT_New_Face(ft_library,("/usr/X11R6/lib/X11/fonts/type1/"+newfont+".ttf").c_str(),face_index,&face);
421
422         if(error)error=FT_New_Face(ft_library,("/usr/share/fonts/truetype/"+newfont).c_str(),face_index,&face);
423         if(error)error=FT_New_Face(ft_library,("/usr/share/fonts/truetype/"+newfont+".ttf").c_str(),face_index,&face);
424
425         if(error)error=FT_New_Face(ft_library,("/usr/X11R6/lib/X11/fonts/TTF/"+newfont).c_str(),face_index,&face);
426         if(error)error=FT_New_Face(ft_library,("/usr/X11R6/lib/X11/fonts/TTF/"+newfont+".ttf").c_str(),face_index,&face);
427
428         if(error)error=FT_New_Face(ft_library,("/usr/X11R6/lib/X11/fonts/truetype/"+newfont).c_str(),face_index,&face);
429         if(error)error=FT_New_Face(ft_library,("/usr/X11R6/lib/X11/fonts/truetype/"+newfont+".ttf").c_str(),face_index,&face);
430
431 #endif
432         if(error)
433         {
434                 //synfig::error(strprintf("lyr_freetype:%s (err=%d)",_("Unable to open face."),error));
435                 return false;
436         }
437
438         font=newfont;
439
440         needs_sync_=true;
441         return true;
442 }
443
444 bool
445 lyr_freetype::set_param(const String & param, const ValueBase &value)
446 {
447         Mutex::Lock lock(mutex);
448 /*
449         if(param=="font" && value.same_as(font))
450         {
451                 new_font(etl::basename(value.get(font)),style,weight);
452                 family=etl::basename(value.get(font));
453                 return true;
454         }
455 */
456         IMPORT_PLUS(family,new_font(family,style,weight));
457         IMPORT_PLUS(weight,new_font(family,style,weight));
458         IMPORT_PLUS(style,new_font(family,style,weight));
459         IMPORT_PLUS(size, if(old_version){size/=2.0;} needs_sync_=true );
460         IMPORT_PLUS(text,needs_sync_=true);
461         IMPORT_PLUS(pos,needs_sync_=true);
462         IMPORT(color);
463         IMPORT(invert);
464         IMPORT_PLUS(orient,needs_sync_=true);
465         IMPORT_PLUS(compress,needs_sync_=true);
466         IMPORT_PLUS(vcompress,needs_sync_=true);
467         IMPORT_PLUS(use_kerning,needs_sync_=true);
468         IMPORT_PLUS(grid_fit,needs_sync_=true);
469         
470         return Layer_Composite::set_param(param,value);
471 }
472
473 ValueBase
474 lyr_freetype::get_param(const String& param)const
475 {
476         EXPORT(font);
477         EXPORT(family);
478         EXPORT(style);
479         EXPORT(weight);
480         EXPORT(size);
481         EXPORT(text);
482         EXPORT(color);
483         EXPORT(pos);
484         EXPORT(orient);
485         EXPORT(compress);
486         EXPORT(vcompress);
487         EXPORT(use_kerning);
488         EXPORT(grid_fit);
489         EXPORT(invert);
490         
491         EXPORT_NAME();
492         EXPORT_VERSION();
493
494         return Layer_Composite::get_param(param);
495 }
496
497 Layer::Vocab
498 lyr_freetype::get_param_vocab(void)const
499 {
500         Layer::Vocab ret(Layer_Composite::get_param_vocab());
501
502         ret.push_back(ParamDesc("text")
503                 .set_local_name(_("Text"))
504                 .set_description(_("Text to Render"))
505                 .set_hint("paragraph")
506         );
507
508         ret.push_back(ParamDesc("color")
509                 .set_local_name(_("Color"))
510                 .set_description(_("Color of the text"))
511         );
512
513         ret.push_back(ParamDesc("family")
514                 .set_local_name(_("Font Family"))
515                 .set_hint("font_family")
516         );
517
518         ret.push_back(ParamDesc("style")
519                 .set_local_name(_("Style"))
520                 .set_hint("enum")
521                 .add_enum_value(PANGO_STYLE_NORMAL, "normal" ,_("Normal"))
522                 .add_enum_value(PANGO_STYLE_OBLIQUE, "oblique" ,_("Oblique"))
523                 .add_enum_value(PANGO_STYLE_ITALIC, "italic" ,_("Italic"))
524         );
525
526         ret.push_back(ParamDesc("weight")
527                 .set_local_name(_("Weight"))
528                 .set_hint("enum")
529                 .add_enum_value(200, "ultralight" ,_("Ultralight"))
530                 .add_enum_value(300, "light" ,_("light"))
531                 .add_enum_value(400, "normal" ,_("Normal"))
532                 .add_enum_value(700, "bold" ,_("Bold"))
533                 .add_enum_value(800, "ultrabold" ,_("Ultrabold"))
534                 .add_enum_value(900, "heavy" ,_("Heavy"))
535         );
536         ret.push_back(ParamDesc("compress")
537                 .set_local_name(_("Hozontal Spacing"))
538                 .set_description(_("Describes how close glyphs are horizontally"))
539         );
540
541         ret.push_back(ParamDesc("vcompress")
542                 .set_local_name(_("Vertical Spacing"))
543                 .set_description(_("Describes how close lines of text are vertically"))
544         );
545
546         ret.push_back(ParamDesc("size")
547                 .set_local_name(_("Size"))
548                 .set_description(_("Size of the text"))
549                 .set_hint("size")
550                 .set_origin("pos")
551                 .set_scalar(1)
552         );
553
554         ret.push_back(ParamDesc("orient")
555                 .set_local_name(_("Orientation"))
556                 .set_description(_("Text Orientation"))
557                 .set_invisible_duck()
558         );
559
560         ret.push_back(ParamDesc("pos")
561                 .set_local_name(_("Position"))
562                 .set_description(_("Text Position"))
563         );
564
565         ret.push_back(ParamDesc("font")
566                 .set_local_name(_("Font"))
567                 .set_description(_("Filename of the font to use"))
568                 .set_hint("filename")
569                 .not_critical()
570                 .hidden()
571         );
572
573         ret.push_back(ParamDesc("use_kerning")
574                 .set_local_name(_("Kerning"))
575                 .set_description(_("Enables/Disables font kerning (If the font supports it)"))
576         );
577
578         ret.push_back(ParamDesc("grid_fit")
579                 .set_local_name(_("Sharpen Edges"))
580                 .set_description(_("Turn this off if you are going to be animating the text"))
581         );
582         ret.push_back(ParamDesc("invert")
583                 .set_local_name(_("Invert"))
584         );
585         return ret;
586 }
587
588 void
589 lyr_freetype::sync()
590 {
591         needs_sync_=false;
592         
593         
594         
595         
596 }
597
598 Color
599 lyr_freetype::get_color(Context context, const synfig::Point &pos)const
600 {
601         if(needs_sync_)
602                 const_cast<lyr_freetype*>(this)->sync();
603         
604         if(!face)
605                 return context.get_color(pos);
606         return context.get_color(pos);
607 }
608
609 bool
610 lyr_freetype::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
611 {
612         static synfig::RecMutex freetype_mutex;
613
614         if(needs_sync_)
615                 const_cast<lyr_freetype*>(this)->sync();
616
617         
618         
619         
620         int error;
621         Vector size(lyr_freetype::size*2);
622         
623         if(!context.accelerated_render(surface,quality,renddesc,cb))
624                 return false;
625         
626         if(is_disabled() || text.empty())
627                 return true;
628         
629         // If there is no font loaded, just bail
630         if(!face)
631         {
632                 if(cb)cb->warning(string("lyr_freetype:")+_("No face loaded, no text will be rendered."));
633                 return true;
634         }
635
636         String text(lyr_freetype::text);
637         if(text=="@_FILENAME_@" && get_canvas() && !get_canvas()->get_file_name().empty())
638         {
639                 text=basename(get_canvas()->get_file_name());
640         }
641         
642         // Width and Height of a pixel
643         Vector::value_type pw=renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
644         Vector::value_type ph=renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
645
646     // Calculate character width and height
647         int w=abs(round_to_int(size[0]*pw));
648         int h=abs(round_to_int(size[1]*ph));
649
650     //int bx=(int)((pos[0]-renddesc.get_tl()[0])*pw*64+0.5);
651     //int by=(int)((pos[1]-renddesc.get_tl()[1])*ph*64+0.5);
652     int bx=0;
653     int by=0;
654         
655     // If the font is the size of a pixel, don't bother rendering any text
656         if(w<=1 || h<=1)
657         {
658                 if(cb)cb->warning(string("lyr_freetype:")+_("Text too small, no text will be rendered."));
659                 return true;
660         }
661
662         synfig::RecMutex::Lock lock(freetype_mutex);
663
664 #define CHAR_RESOLUTION         (64)
665         error = FT_Set_Char_Size(
666                 face,                                           // handle to face object           
667                 (int)CHAR_RESOLUTION,   // char_width in 1/64th of points 
668                 (int)CHAR_RESOLUTION,   // char_height in 1/64th of points 
669                 round_to_int(abs(size[0]*pw*CHAR_RESOLUTION)),                                          // horizontal device resolution    
670                 round_to_int(abs(size[1]*ph*CHAR_RESOLUTION)) );                                                // vertical device resolution      
671
672         // Here is where we can compensate for the
673         // error in freetype's rendering engine.
674         const float xerror(abs(size[0]*pw)/(float)face->size->metrics.x_ppem/1.13f/0.996);
675         const float yerror(abs(size[1]*ph)/(float)face->size->metrics.y_ppem/1.13f/0.996);
676         //synfig::info("xerror=%f, yerror=%f",xerror,yerror);
677         const float compress(lyr_freetype::compress*xerror);
678         const float vcompress(lyr_freetype::vcompress*yerror);
679
680         if(error)
681         {
682                 if(cb)cb->error(string("lyr_freetype:")+_("Unable to set face size.")+strprintf(" (err=%d)",error));
683                 return false;
684         }
685
686         FT_GlyphSlot  slot = face->glyph;  // a small shortcut
687         FT_UInt       glyph_index(0);
688         FT_UInt       previous(0);
689         int u,v;
690
691         std::list<TextLine> lines;
692
693         /*
694  --     ** -- CREATE GLYPHS -------------------------------------------------------
695         */
696
697         lines.push_front(TextLine());
698         string::const_iterator iter;
699         for (iter=text.begin(); iter!=text.end(); ++iter)
700         {
701                 int multiplier(1);
702                 if(*iter=='\n')
703                 {
704                         lines.push_front(TextLine());
705                         bx=0;
706                         by=0;
707                         previous=0;
708                         continue;
709                 }
710                 if(*iter=='\t')
711                 {
712                         multiplier=8;
713                         glyph_index = FT_Get_Char_Index( face, ' ' );
714                 }
715                 else
716                         glyph_index = FT_Get_Char_Index( face, *iter );
717
718         // retrieve kerning distance and move pen position
719                 if ( FT_HAS_KERNING(face) && use_kerning && previous && glyph_index )
720                 {
721                         FT_Vector  delta;
722
723                         if(grid_fit)
724                                 FT_Get_Kerning( face, previous, glyph_index, ft_kerning_default, &delta );
725                         else    
726                                 FT_Get_Kerning( face, previous, glyph_index, ft_kerning_unfitted, &delta );
727
728                         if(compress<1.0f)
729                         {
730                                 bx += round_to_int(delta.x*compress);
731                                 by += round_to_int(delta.y*compress);
732                         }
733                         else
734                         {
735                                 bx += delta.x;
736                                 by += delta.y;
737                         }
738         }
739                 
740                 Glyph curr_glyph;
741                 
742         // store current pen position
743         curr_glyph.pos.x = bx;
744         curr_glyph.pos.y = by;
745
746         // load glyph image into the slot. DO NOT RENDER IT !!
747         if(grid_fit)
748                         error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT);
749                 else
750                         error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING );
751         if (error) continue;  // ignore errors, jump to next glyph
752
753         // extract glyph image and store it in our table
754         error = FT_Get_Glyph( face->glyph, &curr_glyph.glyph );
755         if (error) continue;  // ignore errors, jump to next glyph
756
757         // record current glyph index
758         previous = glyph_index;
759                 
760                 // Update the line width
761                 lines.front().width=bx+slot->advance.x;
762                 
763                 // increment pen position
764                 if(multiplier>1)
765                         bx += round_to_int(slot->advance.x*multiplier*compress)-bx%round_to_int(slot->advance.x*multiplier*compress);
766                 else
767                         bx += round_to_int(slot->advance.x*compress*multiplier);
768
769                 //bx += round_to_int(slot->advance.x*compress*multiplier);
770                 //by += round_to_int(slot->advance.y*compress);
771                 by += slot->advance.y*multiplier;
772
773                 lines.front().glyph_table.push_back(curr_glyph);
774                 
775         }
776       
777
778         //float string_height;
779         //string_height=(((lines.size()-1)*face->size->metrics.height+lines.back().actual_height()));
780
781         //int string_height=face->size->metrics.ascender;
782 //#define METRICS_SCALE_ONE             (65536.0f)
783 #define METRICS_SCALE_ONE               ((float)(1<<16))
784         
785         float line_height;
786         line_height=vcompress*((float)face->height*(((float)face->size->metrics.y_scale/METRICS_SCALE_ONE)));
787
788         int     string_height;
789         string_height=round_to_int(((lines.size()-1)*line_height+lines.back().actual_height()));
790         //synfig::info("string_height=%d",string_height);
791         //synfig::info("line_height=%f",line_height);
792         
793         /*
794  --     ** -- RENDER THE GLYPHS ---------------------------------------------------
795         */
796
797         Surface src_;
798         Surface *src_surface;
799         
800         src_surface=surface;
801
802         if(invert)
803         {
804                 src_=*surface;
805                 Surface::alpha_pen pen(surface->begin(),get_amount(),get_blend_method());
806                 
807                 surface->fill(color,pen,src_.get_w(),src_.get_h());
808                 
809                 src_surface=&src_;
810         }
811         
812         {
813         std::list<TextLine>::iterator iter;
814         int curr_line;
815         for(curr_line=0,iter=lines.begin();iter!=lines.end();++iter,curr_line++)
816         {
817                 bx=round_to_int((pos[0]-renddesc.get_tl()[0])*pw*CHAR_RESOLUTION-orient[0]*iter->width);
818                 by=round_to_int((pos[1]-renddesc.get_tl()[1])*ph*CHAR_RESOLUTION+(1.0-orient[1])*string_height-line_height*curr_line);
819                 //by=round_to_int(vcompress*((pos[1]-renddesc.get_tl()[1])*ph*64+(1.0-orient[1])*string_height-face->size->metrics.height*curr_line));
820                 //synfig::info("curr_line=%d, bx=%d, by=%d",curr_line,bx,by);
821                 
822                 std::vector<Glyph>::iterator iter2;
823                 for(iter2=iter->glyph_table.begin();iter2!=iter->glyph_table.end();++iter2)
824                 {
825                         FT_Glyph  image(iter2->glyph);
826                         FT_Vector pen;
827                         FT_BitmapGlyph  bit;
828                                 
829                         pen.x = bx + iter2->pos.x;
830                         pen.y = by + iter2->pos.y;
831                         
832                         //synfig::info("GLYPH: pen.x=%d, pen,y=%d",curr_line,(pen.x+32)>>6,(pen.y+32)>>6);
833                 
834                         error = FT_Glyph_To_Bitmap( &image, ft_render_mode_normal,0/*&pen*/, 1 );
835                         if(error) { FT_Done_Glyph( image ); continue; }
836                 
837                         bit = (FT_BitmapGlyph)image;
838
839                         for(v=0;v<bit->bitmap.rows;v++)
840                                 for(u=0;u<bit->bitmap.width;u++)
841                                 {
842                                         int x=u+((pen.x+32)>>6)+ bit->left;
843                                         int y=v+((pen.y+32)>>6)- bit->top;
844                                         if(     y>=0 &&
845                                                 x>=0 &&
846                                                 y<surface->get_h() &&
847                                                 x<surface->get_w())
848                                         {
849                                                 float myamount=(float)bit->bitmap.buffer[v*bit->bitmap.pitch+u]/255.0f;
850                                                 if(invert)
851                                                         myamount=1.0f-myamount;
852                                                 (*surface)[y][x]=Color::blend(color,(*src_surface)[y][x],myamount*get_amount(),get_blend_method());
853                                         }
854                                 }
855                 
856                         FT_Done_Glyph( image );
857                 }
858                 //iter->clear_and_free();
859         }
860         }
861    
862
863         return true;
864 }
865
866 synfig::Rect
867 lyr_freetype::get_bounding_rect()const
868 {
869         if(needs_sync_)
870                 const_cast<lyr_freetype*>(this)->sync();
871 //      if(!is_disabled())
872                 return synfig::Rect::full_plane();
873 }