Merge commit '493b7f189680b24565dbcd5b0233577c14930cdf' into mm
[openblackhole/openblackhole-enigma2.git] / lib / gdi / font.cpp
1 #include <lib/gdi/font.h>
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <ctype.h>
6 #include <pthread.h>
7 #include <sys/types.h>
8 #include <unistd.h>
9 #include <byteswap.h>
10
11 #ifndef BYTE_ORDER
12 #error "no BYTE_ORDER defined!"
13 #endif
14
15 // use this for init Freetype...
16 #include <ft2build.h>
17 #include FT_FREETYPE_H
18 #ifdef HAVE_FREETYPE2
19 #define FTC_Image_Cache_New(a,b)        FTC_ImageCache_New(a,b)
20 #define FTC_SBit_Cache_New(a,b)         FTC_SBitCache_New(a,b)
21 #define FTC_SBit_Cache_Lookup(a,b,c,d)  FTC_SBitCache_Lookup(a,b,c,d,NULL)
22 #endif
23
24 #include <lib/base/eerror.h>
25 #include <lib/gdi/lcd.h>
26 #include <lib/gdi/grc.h>
27 #include <lib/base/elock.h>
28 #include <lib/base/init.h>
29 #include <lib/base/init_num.h>
30
31 #define HAVE_FRIBIDI
32 // until we have it in the cdk
33
34 #ifdef HAVE_FRIBIDI
35 #include <fribidi/fribidi.h>
36 #endif
37
38 #include <map>
39
40 fontRenderClass *fontRenderClass::instance;
41
42 static pthread_mutex_t ftlock=PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
43
44 #ifndef HAVE_FREETYPE2
45 static FTC_Font cache_current_font=0;
46 #endif
47
48 struct fntColorCacheKey
49 {
50         gRGB start, end;
51         fntColorCacheKey(const gRGB &start, const gRGB &end)
52                 : start(start), end(end)
53         {
54         }
55         bool operator <(const fntColorCacheKey &c) const
56         {
57                 if (start < c.start)
58                         return 1;
59                 else if (start == c.start)
60                         return end < c.end;
61                 return 0;
62         }
63 };
64
65 std::map<fntColorCacheKey,gLookup> colorcache;
66
67 static gLookup &getColor(const gPalette &pal, const gRGB &start, const gRGB &end)
68 {
69         fntColorCacheKey key(start, end);
70         std::map<fntColorCacheKey,gLookup>::iterator i=colorcache.find(key);
71         if (i != colorcache.end())
72                 return i->second;
73         gLookup &n=colorcache.insert(std::pair<fntColorCacheKey,gLookup>(key,gLookup())).first->second;
74 //      eDebug("[FONT] creating new font color cache entry %02x%02x%02x%02x .. %02x%02x%02x%02x", start.a, start.r, start.g, start.b,
75 //              end.a, end.r, end.g, end.b);
76         n.build(16, pal, start, end);
77 //      for (int i=0; i<16; i++)
78 //              eDebugNoNewLine("%02x|%02x%02x%02x%02x ", (int)n.lookup[i], pal.data[n.lookup[i]].a, pal.data[n.lookup[i]].r, pal.data[n.lookup[i]].g, pal.data[n.lookup[i]].b);
79 //      eDebug("");
80         return n;
81 }
82
83 fontRenderClass *fontRenderClass::getInstance()
84 {
85         return instance;
86 }
87
88 FT_Error myFTC_Face_Requester(FTC_FaceID        face_id,
89                                                                                                                         FT_Library      library,
90                                                                                                                         FT_Pointer      request_data,
91                                                                                                                         FT_Face*                aface)
92 {
93         return ((fontRenderClass*)request_data)->FTC_Face_Requester(face_id, aface);
94 }
95
96
97 FT_Error fontRenderClass::FTC_Face_Requester(FTC_FaceID face_id, FT_Face* aface)
98 {
99         fontListEntry *font=(fontListEntry *)face_id;
100         if (!font)
101                 return -1;
102         
103 //      eDebug("[FONT] FTC_Face_Requester (%s)", font->face.c_str());
104
105         int error;
106         if ((error=FT_New_Face(library, font->filename.c_str(), 0, aface)))
107         {
108                 eDebug(" failed: %s", strerror(error));
109                 return error;
110         }
111         FT_Select_Charmap(*aface, ft_encoding_unicode);
112         return 0;
113 }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
114
115 int fontRenderClass::getFaceProperties(const std::string &face, FTC_FaceID &id, int &renderflags)
116 {
117         for (fontListEntry *f=font; f; f=f->next)
118         {
119                 if (f->face == face)
120                 {
121                         id = (FTC_FaceID)f;
122                         renderflags = f->renderflags;
123                         return 0;
124                 }
125         }
126         return -1;
127 }
128
129 #ifdef HAVE_FREETYPE2
130 inline FT_Error fontRenderClass::getGlyphBitmap(FTC_Image_Desc *font, FT_UInt glyph_index, FTC_SBit *sbit)
131 #else
132 inline FT_Error fontRenderClass::getGlyphBitmap(FTC_Image_Desc *font, FT_ULong glyph_index, FTC_SBit *sbit)
133 #endif
134 {
135         return FTC_SBit_Cache_Lookup(sbitsCache, font, glyph_index, sbit);
136 }
137
138 #ifdef HAVE_FREETYPE2
139 inline FT_Error fontRenderClass::getGlyphImage(FTC_Image_Desc *font, FT_UInt glyph_index, FT_Glyph *glyph, FT_Glyph *borderglyph, int bordersize)
140 #else
141 inline FT_Error fontRenderClass::getGlyphImage(FTC_Image_Desc *font, FT_ULong glyph_index, FT_Glyph *glyph, FT_Glyph *borderglyph, int bordersize)
142 #endif
143 {
144         FT_Glyph image;
145         FT_Error err = FTC_ImageCache_Lookup(imageCache, font, glyph_index, &image, NULL);
146         if (err) return err;
147
148         if (glyph)
149         {
150                 err = FT_Glyph_Copy(image, glyph);
151                 if (err) return err;
152         }
153
154         if (borderglyph && bordersize)
155         {
156                 err = FT_Glyph_Copy(image, borderglyph);
157                 if (err) return err;
158                 if (bordersize != strokerRadius)
159                 {
160                         strokerRadius = bordersize;
161                         FT_Stroker_Set(stroker, strokerRadius, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
162                 }
163                 err = FT_Glyph_Stroke(borderglyph, stroker, 1);
164         }
165         return err;
166 }
167
168 std::string fontRenderClass::AddFont(const std::string &filename, const std::string &name, int scale, int renderflags)
169 {
170         eDebugNoNewLine("[FONT] adding font %s...", filename.c_str());
171         fflush(stdout);
172         int error;
173         fontListEntry *n=new fontListEntry;
174
175         n->scale=scale;
176         FT_Face face;
177         singleLock s(ftlock);
178
179         if ((error=FT_New_Face(library, filename.c_str(), 0, &face)))
180                 eFatal(" failed: %s", strerror(error));
181
182         n->filename=filename;
183         n->face=name;
184         n->renderflags=renderflags;
185         FT_Done_Face(face);
186
187         n->next=font;
188         eDebug("OK (%s)", n->face.c_str());
189         font=n;
190
191         return n->face;
192 }
193
194 fontRenderClass::fontListEntry::~fontListEntry()
195 {
196 }
197
198 fontRenderClass::fontRenderClass(): fb(fbClass::getInstance())
199 {
200         instance=this;
201         eDebug("[FONT] initializing lib...");
202         {
203                 if (FT_Init_FreeType(&library))
204                 {
205                         eDebug("[FONT] initializing failed.");
206                         return;
207                 }
208         }
209         eDebug("[FONT] loading fonts...");
210         fflush(stdout);
211         font=0;
212         
213         int maxbytes=4*1024*1024;
214         eDebug("[FONT] Intializing font cache, using max. %dMB...", maxbytes/1024/1024);
215         fflush(stdout);
216         {
217                 if (FTC_Manager_New(library, 8, 8, maxbytes, myFTC_Face_Requester, this, &cacheManager))
218                 {
219                         eDebug("[FONT] initializing font cache failed!");
220                         return;
221                 }
222                 if (!cacheManager)
223                 {
224                         eDebug("[FONT] initializing font cache manager error.");
225                         return;
226                 }
227                 if (FTC_SBit_Cache_New(cacheManager, &sbitsCache))
228                 {
229                         eDebug("[FONT] initializing font cache sbit failed!");
230                         return;
231                 }
232                 if (FTC_Image_Cache_New(cacheManager, &imageCache))
233                 {
234                         eDebug("[FONT] initializing font cache imagecache failed!");
235                 }
236                 if (FT_Stroker_New(library, &stroker))
237                 {
238                         eDebug("[FONT] initializing font stroker failed!");
239                 }
240         }
241         strokerRadius = -1;
242         return;
243 }
244
245 float fontRenderClass::getLineHeight(const gFont& font)
246 {
247         if (!instance)
248                 return 0;
249         ePtr<Font> fnt;
250         getFont(fnt, font.family.c_str(), font.pointSize);
251         if (!fnt)
252                 return 0;
253         singleLock s(ftlock);
254         FT_Face current_face;
255 #ifdef HAVE_FREETYPE2
256         if ((FTC_Manager_LookupFace(cacheManager, fnt->scaler.face_id, &current_face) < 0) ||
257             (FTC_Manager_LookupSize(cacheManager, &fnt->scaler, &fnt->size) < 0))
258 #else
259         if (FTC_Manager_Lookup_Size(cacheManager, &fnt->font.font, &current_face, &fnt->size)<0)
260 #endif
261         {
262                 eDebug("FTC_Manager_Lookup_Size failed!");
263                 return 0;
264         }
265         int height = current_face->size->metrics.height;
266         if (!height)
267         {
268                 /* some fonts don't have height filled in. Estimate it based on the bbox dimensions. */
269                 /* Usually, 'height' is less than the complete boundingbox height, so we use only yMax, to avoid getting a much too large line spacing */
270                 height = FT_MulFix(current_face->bbox.yMax, current_face->size->metrics.y_scale);
271         }
272         return (height>>6);
273 }
274
275 fontRenderClass::~fontRenderClass()
276 {
277         singleLock s(ftlock);
278         while(font)
279         {
280                 fontListEntry *f=font;
281                 font=font->next;
282                 delete f;
283         }
284 //      auskommentiert weil freetype und enigma die kritische masse des suckens ueberschreiten. 
285 //      FTC_Manager_Done(cacheManager);
286 //      FT_Done_FreeType(library);
287 }
288
289 int fontRenderClass::getFont(ePtr<Font> &font, const std::string &face, int size, int tabwidth)
290 {
291         FTC_FaceID id;
292         int renderflags;
293         if (getFaceProperties(face, id, renderflags) < 0)
294         {
295                 font = 0;
296                 return -1;
297         }
298         font = new Font(this, id, size * ((fontListEntry*)id)->scale / 100, tabwidth, renderflags);
299         return 0;
300 }
301
302 void addFont(const char *filename, const char *alias, int scale_factor, int is_replacement, int renderflags)
303 {
304         fontRenderClass::getInstance()->AddFont(filename, alias, scale_factor, renderflags);
305         if (is_replacement)
306                 eTextPara::setReplacementFont(alias);
307 }
308
309 DEFINE_REF(Font);
310
311 Font::Font(fontRenderClass *render, FTC_FaceID faceid, int isize, int tw, int renderflags): tabwidth(tw)
312 {
313         renderer=render;
314 #ifdef HAVE_FREETYPE2
315         font.face_id = faceid;
316         font.width = isize;
317         font.height = isize;
318         font.flags = renderflags;
319         scaler.face_id = faceid;
320         scaler.width = isize;
321         scaler.height = isize;
322         scaler.pixel = 1;
323 #else
324         font.font.face_id=faceid;
325         font.font.pix_width     = isize;
326         font.font.pix_height = isize;
327         font.image_type = ftc_image_grays;
328 #endif
329         height=isize;
330         if (tabwidth==-1)
331                 tabwidth=8*isize;
332 //      font.image_type |= ftc_image_flag_autohinted;
333 }
334
335 #ifdef HAVE_FREETYPE2
336 inline FT_Error Font::getGlyphBitmap(FT_UInt glyph_index, FTC_SBit *sbit)
337 #else
338 inline FT_Error Font::getGlyphBitmap(FT_ULong glyph_index, FTC_SBit *sbit)
339 #endif
340 {
341         return renderer->getGlyphBitmap(&font, glyph_index, sbit);
342 }
343
344 #ifdef HAVE_FREETYPE2
345 inline FT_Error Font::getGlyphImage(FT_UInt glyph_index, FT_Glyph *glyph, FT_Glyph *borderglyph, int bordersize)
346 #else
347 inline FT_Error Font::getGlyphImage(FT_ULong glyph_index, FT_Glyph *glyph, FT_Glyph *borderglyph, int bordersize)
348 #endif
349 {
350         return renderer->getGlyphImage(&font, glyph_index, glyph, borderglyph, bordersize);
351 }
352
353 Font::~Font()
354 {
355 }
356
357 DEFINE_REF(eTextPara);
358 int eTextPara::appendGlyph(Font *current_font, FT_Face current_face, FT_UInt glyphIndex, int flags, int rflags, int border)
359 {
360         int xadvance, top, left, width, height;
361         pGlyph ng;
362
363         if (border)
364         {
365                 /* TODO: scale border radius with current_font scaling */
366                 if (current_font->getGlyphImage(glyphIndex, &ng.image, &ng.borderimage, 64 * border))
367                         return 1;
368                 if (ng.image && ng.image->format != FT_GLYPH_FORMAT_BITMAP)
369                 {
370                         FT_Glyph_To_Bitmap(&ng.image, FT_RENDER_MODE_NORMAL, NULL, 1);
371                         if (ng.image->format != FT_GLYPH_FORMAT_BITMAP) return 1;
372                 }
373                 if (ng.borderimage && ng.borderimage->format != FT_GLYPH_FORMAT_BITMAP)
374                 {
375                         FT_Glyph_To_Bitmap(&ng.borderimage, FT_RENDER_MODE_NORMAL, NULL, 1);
376                         if (ng.borderimage->format != FT_GLYPH_FORMAT_BITMAP) return 1;
377                 }
378                 FT_BitmapGlyph glyph = NULL;
379                 if (ng.borderimage)
380                 {
381                         xadvance = ng.borderimage->advance.x;
382                         glyph = (FT_BitmapGlyph)ng.borderimage;
383                 }
384                 else if (ng.image)
385                 {
386                         xadvance = ng.image->advance.x;
387                         glyph = (FT_BitmapGlyph)ng.image;
388
389                 }
390                 else
391                 {
392                         return 1;
393                 }
394                 xadvance >>= 16;
395                 top = glyph->top;
396                 left = glyph->left;
397                 width = glyph->bitmap.width;
398                 height = glyph->bitmap.rows;
399         }
400         else
401         {
402                 FTC_SBit glyph;
403                 if (current_font->getGlyphBitmap(glyphIndex, &glyph))
404                         return 1;
405
406                 xadvance = glyph->xadvance;
407                 top = glyph->top;
408                 left = glyph->left;
409                 width = glyph->width;
410                 height = glyph->height;
411         }
412
413         int nx=cursor.x();
414
415         nx+=xadvance;
416
417         if ((rflags & RS_WRAP) && (nx >= area.right()))
418         {
419                 int cnt = 0;
420                 glyphString::reverse_iterator i(glyphs.rbegin());
421                         /* find first possibility (from end to begin) to break */
422                 while (i != glyphs.rend())
423                 {
424                         if (i->flags&(GS_CANBREAK|GS_ISFIRST)) /* stop on either space/hyphen/shy or start of line (giving up) */
425                                 break;
426                         cnt++;
427                         ++i;
428                 }
429
430                         /* if ... */
431                 if (i != glyphs.rend()  /* ... we found anything */
432                         && (i->flags&GS_CANBREAK) /* ...and this is a space/hyphen/soft-hyphen */
433                         && (!(i->flags & GS_ISFIRST)) /* ...and this is not an start of line (line with just a single space/hyphen) */
434                         && cnt ) /* ... and there are actual non-space characters after this */
435                 {
436                                 /* if we have a soft-hyphen, and used that for breaking, turn it into a real hyphen */
437                         if (i->flags & GS_SOFTHYPHEN)
438                         {
439                                 i->flags &= ~GS_SOFTHYPHEN;
440                                 i->flags |= GS_HYPHEN;
441                         }
442                         --i; /* skip the space/hypen/softhyphen */
443                         int linelength=cursor.x()-i->x;
444                         i->flags|=GS_ISFIRST; /* make this a line start */
445                         ePoint offset=ePoint(i->x, i->y);
446                         newLine(rflags);
447                         offset-=cursor;
448
449                                 /* and move everything to the end into the next line. */
450                         do
451                         {
452                                 i->x-=offset.x();
453                                 i->y-=offset.y();
454                                 i->bbox.moveBy(-offset.x(), -offset.y());
455                         } while (i-- != glyphs.rbegin()); // rearrange them into the next line
456                         cursor+=ePoint(linelength, 0);  // put the cursor after that line
457                 } else
458                 {
459                         if (cnt)
460                         {
461                                 newLine(rflags);
462                                 flags|=GS_ISFIRST;
463                         }
464                 }
465         }
466
467         int kern=0;
468
469         if (previous && use_kerning)
470         {
471                 FT_Vector delta;
472                 FT_Get_Kerning(current_face, previous, glyphIndex, ft_kerning_default, &delta);
473                 kern=delta.x>>6;
474         }
475
476         ng.bbox.setLeft( ((flags&GS_ISFIRST)|(cursor.x()-1))+left );
477         ng.bbox.setTop( cursor.y() - top );
478         ng.bbox.setWidth( width );
479         ng.bbox.setHeight( height );
480
481         xadvance += kern;
482         ng.bbox.setWidth(xadvance);
483
484         ng.x = cursor.x()+kern;
485         ng.y = cursor.y();
486         ng.w = xadvance;
487         ng.font = current_font;
488         ng.glyph_index = glyphIndex;
489         ng.flags = flags;
490         glyphs.push_back(ng);
491
492                 /* when we have a SHY, don't xadvance. It will either be the last in the line (when used for breaking), or not displayed. */
493         if (!(flags & GS_SOFTHYPHEN))
494                 cursor += ePoint(xadvance, 0);
495         previous = glyphIndex;
496         return 0;
497 }
498
499 void eTextPara::calc_bbox()
500 {
501         if (!glyphs.size())
502         {
503                 bboxValid = 0;
504                 boundBox = eRect();
505                 return;
506         }
507         
508         bboxValid = 1;
509
510         glyphString::iterator i(glyphs.begin());
511         
512         boundBox = i->bbox; 
513         ++i;
514
515         for (; i != glyphs.end(); ++i)
516         {
517                 if (i->flags & (GS_ISSPACE|GS_SOFTHYPHEN))
518                         continue;
519                 if ( i->bbox.left() < boundBox.left() )
520                         boundBox.setLeft( i->bbox.left() );
521                 if ( i->bbox.right() > boundBox.right() )
522                         boundBox.setRight( i->bbox.right() );
523         }
524         boundBox.setTop(area.y());
525         boundBox.setBottom(area.y() + totalheight);
526 //      eDebug("boundBox left = %i, top = %i, right = %i, bottom = %i", boundBox.left(), boundBox.top(), boundBox.right(), boundBox.bottom() );
527 }
528
529 void eTextPara::newLine(int flags)
530 {
531         if (maximum.width()<cursor.x())
532                 maximum.setWidth(cursor.x());
533         cursor.setX(left);
534         int height = current_face->size->metrics.height;
535         if (!height)
536         {
537                 /* some fonts don't have height filled in. Estimate it based on the bbox dimensions. */
538                 /* Usually, 'height' is less than the complete boundingbox height, so we use only yMax, to avoid getting a much too large line spacing */
539                 height = FT_MulFix(current_face->bbox.yMax, current_face->size->metrics.y_scale);
540         }
541         height >>= 6;
542         cursor+=ePoint(0, height);
543         if (maximum.height()<cursor.y())
544                 maximum.setHeight(cursor.y());
545         previous=0;
546         totalheight += height;
547 }
548
549 eTextPara::~eTextPara()
550 {
551         clear();
552 }
553
554 void eTextPara::setFont(const gFont *font)
555 {
556         ePtr<Font> fnt, replacement;
557         fontRenderClass::getInstance()->getFont(fnt, font->family.c_str(), font->pointSize);
558         if (!fnt)
559                 eWarning("FONT '%s' MISSING!", font->family.c_str());
560         fontRenderClass::getInstance()->getFont(replacement, replacement_facename.c_str(), font->pointSize);
561         setFont(fnt, replacement);
562 }
563
564 std::string eTextPara::replacement_facename;
565 std::set<int> eTextPara::forced_replaces;
566
567 void eTextPara::setFont(Font *fnt, Font *replacement)
568 {
569         if (!fnt)
570                 return;
571         current_font=fnt;
572         replacement_font=replacement;
573         singleLock s(ftlock);
574
575                         // we ask for replacment_font first becauseof the cache
576         if (replacement_font)
577         {
578 #ifdef HAVE_FREETYPE2
579                 if ((FTC_Manager_LookupFace(fontRenderClass::instance->cacheManager,
580                                             replacement_font->scaler.face_id,
581                                             &replacement_face) < 0) ||
582                     (FTC_Manager_LookupSize(fontRenderClass::instance->cacheManager,
583                                             &replacement_font->scaler,
584                                             &replacement_font->size) < 0))
585 #else
586                 if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, 
587                                 &replacement_font->font.font, &replacement_face, 
588                                 &replacement_font->size)<0)
589 #endif
590                 {
591                         eDebug("FTC_Manager_Lookup_Size failed!");
592                         return;
593                 }
594         }
595         if (current_font)
596         {
597 #ifdef HAVE_FREETYPE2
598                 if ((FTC_Manager_LookupFace(fontRenderClass::instance->cacheManager,
599                                             current_font->scaler.face_id,
600                                             &current_face) < 0) ||
601                     (FTC_Manager_LookupSize(fontRenderClass::instance->cacheManager,
602                                             &current_font->scaler,
603                                             &current_font->size) < 0))
604 #else
605                 if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, &current_font->font.font, &current_face, &current_font->size)<0)
606 #endif
607                 {
608                         eDebug("FTC_Manager_Lookup_Size failed!");
609                         return;
610                 }
611         }
612 #ifndef HAVE_FREETYPE2
613         cache_current_font=&current_font->font.font;
614 #endif
615         previous=0;
616         use_kerning=FT_HAS_KERNING(current_face);
617 }
618
619 void
620 shape (std::vector<unsigned long> &string, const std::vector<unsigned long> &text);
621
622 int eTextPara::renderString(const char *string, int rflags, int border)
623 {
624         singleLock s(ftlock);
625         
626         if (!current_font)
627                 return -1;
628
629         if (!current_face)
630                 eFatal("eTextPara::renderString: no current_face");
631         if (!current_face->size)
632                 eFatal("eTextPara::renderString: no current_face->size");
633
634         if (cursor.y()==-1)
635         {
636                 int height = current_face->size->metrics.height;
637                 int ascender = current_face->size->metrics.ascender;
638                 if (!height || !ascender)
639                 {
640                         int ymax = FT_MulFix(current_face->bbox.yMax, current_face->size->metrics.y_scale);
641                         if (!height)
642                         {
643                                 /* some fonts don't have height filled in. Estimate it based on the bbox dimensions. */
644                                 /* For the first line we calculate the full boundingbox height, this gives the best result when centering vertically */
645                                 height = ymax - FT_MulFix(current_face->bbox.yMin, current_face->size->metrics.y_scale);
646                         }
647                         if (!ascender)
648                         {
649                                 /* some fonts don't have ascender filled in. Estimate it based on the bbox dimensions. */
650                                 ascender = ymax;
651                         }
652                 }
653                 totalheight = height >> 6;
654                 cursor=ePoint(area.x(), area.y()+(ascender>>6));
655                 left=cursor.x();
656         }
657
658 #ifdef HAVE_FREETYPE2
659         if ((FTC_Manager_LookupFace(fontRenderClass::instance->cacheManager,
660                                     current_font->scaler.face_id,
661                                     &current_face) < 0) ||
662             (FTC_Manager_LookupSize(fontRenderClass::instance->cacheManager,
663                                     &current_font->scaler,
664                                     &current_font->size) < 0))
665         {
666                 eDebug("FTC_Manager_Lookup_Size failed!");
667                 return -1;
668         }
669 #else
670         if (&current_font->font.font != cache_current_font)
671         {
672                 if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, &current_font->font.font, &current_face, &current_font->size)<0)
673                 {
674                         eDebug("FTC_Manager_Lookup_Size failed!");
675                         return -1;
676                 }
677                 cache_current_font=&current_font->font.font;
678         }
679 #endif
680
681         std::vector<unsigned long> uc_string, uc_visual;
682         if (string)
683                 uc_string.reserve(strlen(string));
684         
685         const char *p = string ? string : "";
686
687         while (*p)
688         {
689                 unsigned int unicode=(unsigned char)*p++;
690
691                 if (unicode & 0x80) // we have (hopefully) UTF8 here, and we assume that the encoding is VALID
692                 {
693                         if ((unicode & 0xE0)==0xC0) // two bytes
694                         {
695                                 unicode&=0x1F;
696                                 unicode<<=6;
697                                 if (*p)
698                                         unicode|=(*p++)&0x3F;
699                         } else if ((unicode & 0xF0)==0xE0) // three bytes
700                         {
701                                 unicode&=0x0F;
702                                 unicode<<=6;
703                                 if (*p)
704                                         unicode|=(*p++)&0x3F;
705                                 unicode<<=6;
706                                 if (*p)
707                                         unicode|=(*p++)&0x3F;
708                         } else if ((unicode & 0xF8)==0xF0) // four bytes
709                         {
710                                 unicode&=0x07;
711                                 unicode<<=6;
712                                 if (*p)
713                                         unicode|=(*p++)&0x3F;
714                                 unicode<<=6;
715                                 if (*p)
716                                         unicode|=(*p++)&0x3F;
717                                 unicode<<=6;
718                                 if (*p)
719                                         unicode|=(*p++)&0x3F;
720                         }
721                 }
722                 uc_string.push_back(unicode);
723         }
724
725         std::vector<unsigned long> uc_shape;
726
727                 // character -> glyph conversion
728         shape(uc_shape, uc_string);
729         
730                 // now do the usual logical->visual reordering
731 #ifdef HAVE_FRIBIDI     
732         FriBidiCharType dir=FRIBIDI_TYPE_ON;
733         {
734                 int size=uc_shape.size();
735                 uc_visual.resize(size);
736                 // gaaanz lahm, aber anders geht das leider nicht, sorry.
737                 FriBidiChar array[size], target[size];
738                 std::copy(uc_shape.begin(), uc_shape.end(), array);
739                 fribidi_log2vis(array, size, &dir, target, 0, 0, 0);
740                 uc_visual.assign(target, target+size);
741         }
742 #else
743         uc_visual=uc_shape;
744 #endif
745
746         glyphs.reserve(uc_visual.size());
747         
748         int nextflags = 0;
749         
750         for (std::vector<unsigned long>::const_iterator i(uc_visual.begin());
751                 i != uc_visual.end(); ++i)
752         {
753                 int isprintable=1;
754                 int flags = nextflags;
755                 nextflags = 0;
756                 unsigned long chr = *i;
757
758                 if (!(rflags&RS_DIRECT))
759                 {
760                         switch (chr)
761                         {
762                         case '\\':
763                         {
764                                 if ((i + 1) != uc_visual.end())
765                                 {
766                                         unsigned long c = *(i+1);
767                                         switch (c)
768                                         {
769                                                 case 'n':
770                                                         i++;
771                                                         goto newline;
772                                                 case 't':
773                                                         i++;
774                                                         goto tab;
775                                                 case 'r':
776                                                         i++;
777                                                         goto nprint;
778                                                 case 'c':
779                                                 {
780                                                         char color[8];
781                                                         int codeidx;
782                                                         for (codeidx = 0; codeidx < 8; codeidx++)
783                                                         {
784                                                                 if ((i + 2 + codeidx) == uc_visual.end()) break;
785                                                                 color[codeidx] = (char)((*(i + 2 + codeidx)) & 0xff);
786                                                         }
787                                                         if (codeidx == 8)
788                                                         {
789                                                                 pGlyph ng;
790                                                                 ng.newcolor = gRGB(color).argb();
791                                                                 ng.flags = GS_COLORCHANGE;
792                                                                 ng.w = 0;
793                                                                 glyphs.push_back(ng);
794                                                                 i += 1 + codeidx;
795                                                                 continue;
796                                                         }
797                                                         break;
798                                                 }
799                                                 default:
800                                                 ;
801                                         }
802                                 }
803                                 break;
804                         }
805                         case '\t':
806 tab:            isprintable=0;
807                                 cursor+=ePoint(current_font->tabwidth, 0);
808                                 cursor-=ePoint(cursor.x()%current_font->tabwidth, 0);
809                                 break;
810                         case 0x8A:
811                         case 0xE08A:
812                         case '\n':
813 newline:isprintable=0;
814                                 newLine(rflags);
815                                 nextflags|=GS_ISFIRST;
816                                 break;
817                         case '\r':
818                         case 0x86: case 0xE086:
819                         case 0x87: case 0xE087:
820 nprint: isprintable=0;
821                                 break;
822                         case 0xAD: // soft-hyphen
823                                 flags |= GS_SOFTHYPHEN;
824                                 chr = 0x2010; /* hyphen */
825                                 break;
826                         case 0x2010:
827                         case '-':
828                                 flags |= GS_HYPHEN;
829                                 break;
830                         case ' ':
831                                 flags|=GS_ISSPACE;
832                         default:
833                                 break;
834                         }
835                 }
836                 if (isprintable)
837                 {
838                         FT_UInt index = 0;
839
840                                 /* FIXME: our font doesn't seem to have a hyphen, so use hyphen-minus for it. */
841                         if (chr == 0x2010)
842                                 chr = '-';
843
844                         if (forced_replaces.find(chr) == forced_replaces.end())
845                                 index=(rflags&RS_DIRECT)? chr : FT_Get_Char_Index(current_face, chr);
846
847                         if (!index)
848                         {
849                                 if (replacement_face)
850                                         index=(rflags&RS_DIRECT)? chr : FT_Get_Char_Index(replacement_face, chr);
851
852                                 if (!index)
853                                         eDebug("unicode U+%4lx not present", chr);
854                                 else
855                                         appendGlyph(replacement_font, replacement_face, index, flags, rflags, border);
856                         } else
857                                 appendGlyph(current_font, current_face, index, flags, rflags, border);
858                 }
859         }
860         bboxValid=false;
861         calc_bbox();
862 #ifdef HAVE_FRIBIDI
863         if (dir & FRIBIDI_MASK_RTL)
864                 realign(dirRight);
865 #endif
866         return 0;
867 }
868
869 void eTextPara::blit(gDC &dc, const ePoint &offset, const gRGB &background, const gRGB &foreground, bool border)
870 {
871         if (glyphs.empty()) return;
872
873         singleLock s(ftlock);
874
875         if (!current_font)
876                 return;
877
878 #ifdef HAVE_FREETYPE2
879         if ((FTC_Manager_LookupFace(fontRenderClass::instance->cacheManager,
880                                     current_font->scaler.face_id,
881                                     &current_face) < 0) ||
882             (FTC_Manager_LookupSize(fontRenderClass::instance->cacheManager,
883                                     &current_font->scaler,
884                                     &current_font->size) < 0))
885         {
886                 eDebug("FTC_Manager_Lookup_Size failed!");
887                 return;
888         }
889 #else
890         if (&current_font->font.font != cache_current_font)
891         {
892                 if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, &current_font->font.font, &current_face, &current_font->size)<0)
893                 {
894                         eDebug("FTC_Manager_Lookup_Size failed!");
895                         return;
896                 }
897                 cache_current_font=&current_font->font.font;
898         }
899 #endif
900
901         ePtr<gPixmap> target;
902         dc.getPixmap(target);
903         gSurface *surface = target->surface;
904         gRGB currentforeground = foreground;
905
906         register int opcode = -1;
907
908         __u32 lookup32_normal[16];
909         __u32 lookup32_invert[16];
910         __u16 *lookup16_normal = (__u16*)lookup32_normal; // shares the same memory
911         __u16 *lookup16_invert = (__u16*)lookup32_invert;
912         gColor *lookup8_normal = 0;
913         gColor *lookup8_invert = (gColor*)lookup32_invert;
914         __u32 *lookup32;
915         __u16 *lookup16;
916         gColor *lookup8;
917
918         gRegion sarea(eRect(0, 0, surface->x, surface->y));
919         gRegion clip = dc.getClip() & sarea;
920         clip &= eRect(area.left() + offset.x(), area.top() + offset.y(), area.width(), area.height()+(current_face->size->metrics.ascender>>6));
921
922         int buffer_stride=surface->stride;
923
924         bool setcolor = true;
925         for (glyphString::iterator i(glyphs.begin()); i != glyphs.end(); ++i)
926         {
927                 if (setcolor)
928                 {
929                         setcolor = false;
930                         if (surface->bpp == 8)
931                         {
932                                 if (surface->clut.data)
933                                 {
934                                         lookup8_normal=getColor(surface->clut, background, currentforeground).lookup;
935
936                                         int i;
937                                         for (i=0; i<16; ++i)
938                                                 lookup8_invert[i] = lookup8_normal[i^0xF];
939
940                                         opcode=0;
941                                 } else
942                                         opcode=1;
943                         } else if (surface->bpp == 32)
944                         {
945                                 opcode=3;
946
947                                 for (int i=0; i<16; ++i)
948                                 {
949 #define BLEND(y, x, a) (y + (((x-y) * a)>>8))
950
951                                         unsigned char da = background.a, dr = background.r, dg = background.g, db = background.b;
952                                         int sa = i * 16;
953                                         if (sa < 256)
954                                         {
955                                                 da = BLEND(background.a, currentforeground.a, sa) & 0xFF;
956                                                 dr = BLEND(background.r, currentforeground.r, sa) & 0xFF;
957                                                 dg = BLEND(background.g, currentforeground.g, sa) & 0xFF;
958                                                 db = BLEND(background.b, currentforeground.b, sa) & 0xFF;
959                                         }
960 #undef BLEND
961                                         da ^= 0xFF;
962                                         lookup32_normal[i]=db | (dg << 8) | (dr << 16) | (da << 24);;
963                                 }
964                                 for (int i=0; i<16; ++i)
965                                         lookup32_invert[i]=lookup32_normal[i^0xF];
966                         } else if (surface->bpp == 16)
967                         {
968                                 opcode=2;
969                                 for (int i = 0; i != 16; ++i)
970                                 {
971 #define BLEND(y, x, a) (y + (((x-y) * a)>>8))
972                                         unsigned char da = background.a, dr = background.r, dg = background.g, db = background.b;
973                                         int sa = i * 16;
974                                         if (sa < 256)
975                                         {
976                                                 dr = BLEND(background.r, foreground.r, sa) & 0xFF;
977                                                 dg = BLEND(background.g, foreground.g, sa) & 0xFF;
978                                                 db = BLEND(background.b, foreground.b, sa) & 0xFF;
979                                         }
980 #undef BLEND
981 #if BYTE_ORDER == LITTLE_ENDIAN
982                                         lookup16_normal[i] = bswap_16(((db >> 3) << 11) | ((dg >> 2) << 5) | (dr >> 3));
983 #else
984                                         lookup16_normal[i] = ((db >> 3) << 11) | ((dg >> 2) << 5) | (dr >> 3);
985 #endif
986                                         da ^= 0xFF;
987                                 }
988                                 for (int i=0; i<16; ++i)
989                                         lookup16_invert[i]=lookup16_normal[i^0xF];                              
990                         } else
991                         {
992                                 eWarning("can't render to %dbpp", surface->bpp);
993                                 return;
994                         }
995                 }
996                 if (i->flags & GS_COLORCHANGE)
997                 {
998                         /* don't do colorchanges in borders */
999                         if (!border)
1000                         {
1001                                 currentforeground = i->newcolor;
1002                                 setcolor = true;
1003                         }
1004                         continue;
1005                 }
1006                 if (i->flags & GS_SOFTHYPHEN)
1007                         continue;
1008
1009                 if (!(i->flags & GS_INVERT))
1010                 {
1011                         lookup8 = lookup8_normal;
1012                         lookup16 = lookup16_normal;
1013                         lookup32 = lookup32_normal;
1014                 } else
1015                 {
1016                         lookup8 = lookup8_invert;
1017                         lookup16 = lookup16_invert;
1018                         lookup32 = lookup32_invert;
1019                 }
1020
1021                 int rxbase, rybase;
1022                 __u8 *dbase;
1023                 __u8 *sbase;
1024                 int sxbase;
1025                 int sybase;
1026                 int pitch;
1027                 if (i->image)
1028                 {
1029                         FT_BitmapGlyph glyph = border ? (FT_BitmapGlyph)i->borderimage : (FT_BitmapGlyph)i->image;
1030                         if (!glyph->bitmap.buffer) continue;
1031                         rxbase = i->x + glyph->left + offset.x();
1032                         rybase = i->y - glyph->top + offset.y();
1033                         sbase = glyph->bitmap.buffer;
1034                         sxbase = glyph->bitmap.width;
1035                         sybase = glyph->bitmap.rows;
1036                         pitch = glyph->bitmap.pitch;
1037                 }
1038                 else
1039                 {
1040                         static FTC_SBit glyph_bitmap;
1041                         if (fontRenderClass::instance->getGlyphBitmap(&i->font->font, i->glyph_index, &glyph_bitmap))
1042                                 continue;
1043                         rxbase=i->x+glyph_bitmap->left + offset.x();
1044                         rybase=i->y-glyph_bitmap->top  + offset.y();
1045
1046                         sbase=glyph_bitmap->buffer;
1047                         sxbase=glyph_bitmap->width;
1048                         sybase=glyph_bitmap->height;
1049                         pitch = glyph_bitmap->pitch;
1050                 }
1051                 dbase = (__u8*)(surface->data)+buffer_stride*rybase+rxbase*surface->bypp;
1052                 for (unsigned int c = 0; c < clip.rects.size(); ++c)
1053                 {
1054                         int rx = rxbase, ry = rybase;
1055                         __u8 *d = dbase;
1056                         __u8 *s = sbase;
1057                         register int sx = sxbase;
1058                         int sy = sybase;
1059                         if ((sy+ry) >= clip.rects[c].bottom())
1060                                 sy = clip.rects[c].bottom()-ry;
1061                         if ((sx+rx) >= clip.rects[c].right())
1062                                 sx = clip.rects[c].right()-rx;
1063                         if (rx < clip.rects[c].left())
1064                         {
1065                                 int diff=clip.rects[c].left()-rx;
1066                                 s+=diff;
1067                                 sx-=diff;
1068                                 rx+=diff;
1069                                 d+=diff*surface->bypp;
1070                         }
1071                         if (ry < clip.rects[c].top())
1072                         {
1073                                 int diff=clip.rects[c].top()-ry;
1074                                 s+=diff*pitch;
1075                                 sy-=diff;
1076                                 ry+=diff;
1077                                 d+=diff*buffer_stride;
1078                         }
1079                         if ((sx>0) && (sy>0))
1080                         {
1081                                 int extra_source_stride = pitch - sx;
1082                                 switch (opcode)
1083                                 { 
1084                                 case 0:                 // 4bit lookup to 8bit
1085                                         {
1086                                         register int extra_buffer_stride = buffer_stride - sx;
1087                                         register __u8 *td=d;
1088                                         for (int ay = 0; ay < sy; ay++)
1089                                         {
1090                                                 register int ax;
1091
1092                                                 for (ax=0; ax<sx; ax++)
1093                                                 {
1094                                                         register int b=(*s++)>>4;
1095                                                         if(b)
1096                                                                 *td=lookup8[b];
1097                                                         ++td;
1098                                                 }
1099                                                 s += extra_source_stride;
1100                                                 td += extra_buffer_stride;
1101                                         }
1102                                         }
1103                                         break;
1104                                 case 1: // 8bit direct
1105                                         {
1106                                         register int extra_buffer_stride = buffer_stride - sx;
1107                                         register __u8 *td=d;
1108                                         for (int ay = 0; ay < sy; ay++)
1109                                         {
1110                                                 register int ax;
1111                                                 for (ax=0; ax<sx; ax++)
1112                                                 {
1113                                                         register int b=*s++;
1114                                                         *td++^=b;
1115                                                 }
1116                                                 s += extra_source_stride;
1117                                                 td += extra_buffer_stride;
1118                                         }
1119                                         }
1120                                         break;
1121                                 case 2: // 16bit
1122                                         {
1123                                         int extra_buffer_stride = (buffer_stride >> 1) - sx;
1124                                         register __u16 *td = (__u16*)d;
1125                                         for (int ay = 0; ay != sy; ay++)
1126                                         {
1127                                                 register int ax;
1128                                                 for (ax = 0; ax != sx; ax++)
1129                                                 {
1130                                                         register int b = (*s++) >> 4;
1131                                                         if (b)
1132                                                                 *td = lookup16[b];
1133                                                         ++td;
1134                                                 }
1135                                                 s += extra_source_stride;
1136                                                 td += extra_buffer_stride;
1137                                         }
1138                                         }
1139                                         break;
1140                                 case 3: // 32bit
1141                                         {
1142                                         register int extra_buffer_stride = (buffer_stride >> 2) - sx;
1143                                         register __u32 *td=(__u32*)d;
1144                                         for (int ay = 0; ay < sy; ay++)
1145                                         {
1146                                                 register int ax;
1147                                                 for (ax=0; ax<sx; ax++)
1148                                                 {
1149                                                         register int b=(*s++)>>4;
1150                                                         if(b)
1151                                                                 *td=lookup32[b];
1152                                                         ++td;
1153                                                 }
1154                                                 s += extra_source_stride;
1155                                                 td += extra_buffer_stride;
1156                                         }
1157                                         }
1158                                         break;
1159                                 }
1160                         }
1161                 }
1162         }
1163 }
1164
1165 void eTextPara::realign(int dir)        // der code hier ist ein wenig merkwuerdig.
1166 {
1167         glyphString::iterator begin(glyphs.begin()), c(glyphs.begin()), end(glyphs.begin()), last;
1168         if (dir==dirLeft)
1169                 return;
1170         while (c != glyphs.end())
1171         {
1172                 int linelength=0;
1173                 int numspaces=0, num=0;
1174                 begin=end;
1175                 
1176                 ASSERT( end != glyphs.end());
1177                 
1178                         // zeilenende suchen
1179                 do {
1180                         last=end;
1181                         ++end;
1182                 } while ((end != glyphs.end()) && (!(end->flags&GS_ISFIRST)));
1183                         // end zeigt jetzt auf begin der naechsten zeile
1184                 
1185                 for (c=begin; c!=end; ++c)
1186                 {
1187                                 // space am zeilenende skippen
1188                         if ((c==last) && (c->flags&GS_ISSPACE))
1189                                 continue;
1190
1191                         if (c->flags&GS_ISSPACE)
1192                                 numspaces++;
1193                         linelength+=c->w;
1194                         num++;
1195                 }
1196
1197                 switch (dir)
1198                 {
1199                 case dirCenterIfFits:
1200                         // If the text is larger than the available space,
1201                         // don't re-align but align left.
1202                         if (linelength > area.width())
1203                                 return;
1204                         dir = dirCenter;
1205                         // fall-through on purpose
1206                 case dirRight:
1207                 case dirCenter:
1208                 {
1209                         int offset=area.width()-linelength;
1210                         if (dir==dirCenter)
1211                                 offset/=2;
1212                         offset+=area.left();
1213                         while (begin != end)
1214                         {
1215                                 begin->bbox.moveBy(offset-begin->x,0);
1216                                 begin->x=offset;
1217                                 offset+=begin->w;
1218                                 ++begin;
1219                         }
1220                         break;
1221                 }
1222                 case dirBlock:
1223                 {
1224                         if (end == glyphs.end())                // letzte zeile linksbuendig lassen
1225                                 continue;
1226                         int spacemode;
1227                         if (numspaces)
1228                                 spacemode=1;
1229                         else
1230                                 spacemode=0;
1231                         if ((!spacemode) && (num<2))
1232                                 break;
1233                         int off=(area.width()-linelength)*256/(spacemode?numspaces:(num-1));
1234                         int curoff=0;
1235                         while (begin != end)
1236                         {
1237                                 int doadd=0;
1238                                 if ((!spacemode) || (begin->flags&GS_ISSPACE))
1239                                         doadd=1;
1240                                 begin->x+=curoff>>8;
1241                                 begin->bbox.moveBy(curoff>>8,0);
1242                                 if (doadd)
1243                                         curoff+=off;
1244                                 ++begin;
1245                         }
1246                         break;
1247                 }
1248                 }
1249         }
1250         bboxValid=false;
1251         calc_bbox();
1252 }
1253
1254 void eTextPara::clear()
1255 {
1256         singleLock s(ftlock);
1257
1258         current_font = 0;
1259         replacement_font = 0;
1260
1261         for (unsigned int i = 0; i < glyphs.size(); i++)
1262         {
1263                 if (glyphs[i].image) FT_Done_Glyph(glyphs[i].image);
1264                 if (glyphs[i].borderimage) FT_Done_Glyph(glyphs[i].borderimage);
1265         }
1266         glyphs.clear();
1267         totalheight = 0;
1268 }
1269
1270 eAutoInitP0<fontRenderClass> init_fontRenderClass(eAutoInitNumbers::graphic-1, "Font Render Class");