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