1 #include <lib/gdi/font.h>
10 // use this for init Freetype...
12 #include FT_FREETYPE_H
14 #include <lib/base/eerror.h>
15 #include <lib/gdi/lcd.h>
16 #include <lib/gdi/grc.h>
17 #include <lib/base/elock.h>
18 #include <lib/base/init.h>
22 fontRenderClass *fontRenderClass::instance;
24 static FTC_Font cache_current_font=0;
26 struct fntColorCacheKey
29 fntColorCacheKey(const gRGB &start, const gRGB &end)
30 : start(start), end(end)
33 bool operator <(const fntColorCacheKey &c) const
37 else if (start == c.start)
43 std::map<fntColorCacheKey,gLookup> colorcache;
45 static gLookup &getColor(const gPalette &pal, const gRGB &start, const gRGB &end)
47 fntColorCacheKey key(start, end);
48 std::map<fntColorCacheKey,gLookup>::iterator i=colorcache.find(key);
49 if (i != colorcache.end())
51 gLookup &n=colorcache.insert(std::pair<fntColorCacheKey,gLookup>(key,gLookup())).first->second;
52 eDebug("[FONT] creating new font color cache entry %02x%02x%02x%02x .. %02x%02x%02x%02x", start.a, start.r, start.g, start.b,
53 end.a, end.r, end.g, end.b);
54 n.build(16, pal, start, end);
55 /* for (int i=0; i<16; i++)
56 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);
61 fontRenderClass *fontRenderClass::getInstance()
66 FT_Error myFTC_Face_Requester(FTC_FaceID face_id,
68 FT_Pointer request_data,
71 return ((fontRenderClass*)request_data)->FTC_Face_Requester(face_id, aface);
75 FT_Error fontRenderClass::FTC_Face_Requester(FTC_FaceID face_id, FT_Face* aface)
77 fontListEntry *font=(fontListEntry *)face_id;
81 eDebug("[FONT] FTC_Face_Requester (%s)", font->face);
84 if ((error=FT_New_Face(library, font->filename, 0, aface)))
86 eDebug(" failed: %s", strerror(error));
89 FT_Select_Charmap(*aface, ft_encoding_unicode);
93 FTC_FaceID fontRenderClass::getFaceID(const char *face)
95 for (fontListEntry *f=font; f; f=f->next)
97 if (!strcmp(f->face, face))
103 FT_Error fontRenderClass::getGlyphBitmap(FTC_ImageTypeRec *font, FT_ULong glyph_index, FTC_SBit *sbit)
105 FT_Error res=FTC_SBitCache_Lookup(sbitsCache, font, glyph_index, sbit, 0);
106 eDebug("%x", sizeof(**sbit));
110 const char* fontRenderClass::AddFont(const char *filename)
112 eDebugNoNewLine("[FONT] adding font %s...", filename);
115 fontListEntry *n=new fontListEntry;
118 eLocker lock(ftlock);
120 if ((error=FT_New_Face(library, filename, 0, &face)))
121 eFatal(" failed: %s", strerror(error));
123 strcpy(n->filename=new char[strlen(filename)+1], filename);
124 strcpy(n->face=new char[strlen(face->family_name)+strlen(face->style_name)+2], face->family_name);
125 if (face->style_name[0]!=' ')
126 strcat(n->face, " ");
127 strcat(n->face, face->style_name);
131 eDebug("OK (%s)", n->face);
137 fontRenderClass::fontListEntry::~fontListEntry()
143 fontRenderClass::fontRenderClass(): fb(fbClass::getInstance())
146 eDebug("[FONT] initializing lib...");
148 if (FT_Init_FreeType(&library))
150 eDebug("[FONT] initializing failed.");
154 eDebug("[FONT] loading fonts...");
158 int maxbytes=4*1024*1024;
159 eDebug("[FONT] Intializing font cache, using max. %dMB...", maxbytes/1024/1024);
162 if (FTC_Manager_New(library, 8, 8, maxbytes, myFTC_Face_Requester, this, &cacheManager))
164 eDebug("[FONT] initializing font cache failed!");
169 eDebug("[FONT] initializing font cache manager error.");
172 if (FTC_SBitCache_New(cacheManager, &sbitsCache))
174 eDebug("[FONT] initializing font cache sbit failed!");
177 /* if (FTC_ImageCache_New(cacheManager, &imageCache))
179 eDebug("[FONT] initializing font cache imagecache failed!");
185 fontRenderClass::~fontRenderClass()
188 // auskommentiert weil freetype und enigma die kritische masse des suckens ueberschreiten.
189 // FTC_Manager_Done(cacheManager);
190 // FT_Done_FreeType(library);
193 Font *fontRenderClass::getFont(const char *face, int size, int tabwidth)
195 FTC_FaceID id=getFaceID(face);
197 eDebug("face %s does not exist!", face);
200 return new Font(this, id, size, tabwidth);
203 Font::Font(fontRenderClass *render, FTC_FaceID faceid, int isize, int tw): tabwidth(tw)
206 font.font.face_id=faceid;
207 font.font.pix_width = isize;
208 font.font.pix_height = isize;
209 font.flags = FT_LOAD_DEFAULT;
216 FT_Error Font::getGlyphBitmap(FT_ULong glyph_index, FTC_SBit *sbit)
218 return renderer->getGlyphBitmap(&font, glyph_index, sbit);
237 int eTextPara::appendGlyph(FT_UInt glyphIndex, int flags, int rflags)
240 if (current_font->getGlyphBitmap(glyphIndex, &glyph))
245 if (! (rflags & RS_RTL))
249 eDebug("RTL: glyph->xadvance: %d", glyph->xadvance);
258 (nx >= area.right()) :
264 glyphString::iterator i(glyphs.end());
266 while (i != glyphs.begin())
268 if (i->flags&(GS_ISSPACE|GS_ISFIRST))
273 if (i != glyphs.begin() && ((i->flags&(GS_ISSPACE|GS_ISFIRST))==GS_ISSPACE) && (++i != glyphs.end())) // skip space
275 int linelength=cursor.x()-i->x;
276 // RTL: linelength is negative
277 i->flags|=GS_ISFIRST;
278 ePoint offset=ePoint(i->x, i->y);
281 while (i != glyphs.end()) // rearrange them into the next line
285 i->bbox->moveBy(-offset.x(), -offset.y());
288 cursor+=ePoint(linelength, 0); // put the cursor after that line
299 int xadvance=glyph->xadvance, kern=0;
301 if (previous && use_kerning)
304 FT_Get_Kerning(current_face, previous, glyphIndex, ft_kerning_default, &delta);
308 eRect* bbox = new eRect();
309 bbox->setLeft( (flags&GS_ISFIRST|glyphs.empty()?cursor.x():cursor.x()-1) + glyph->left );
310 bbox->setTop( cursor.y() - glyph->top );
311 bbox->setWidth( glyph->width );
312 bbox->setHeight( glyph->height );
318 if (!(rflags & RS_RTL))
319 ng.x=cursor.x()+kern;
321 ng.x=cursor.x()-xadvance;
325 ng.font=current_font;
327 ng.glyph_index=glyphIndex;
330 glyphs.push_back(ng);
332 if (!(rflags & RS_RTL))
333 cursor+=ePoint(xadvance, 0);
335 cursor-=ePoint(xadvance, 0);
340 void eTextPara::calc_bbox()
342 boundBox.setLeft( 32000 );
343 boundBox.setTop( 32000 );
344 boundBox.setRight( -32000 ); // for each glyph image, compute its bounding box, translate it,
345 boundBox.setBottom( -32000 );
346 // and grow the string bbox
348 for ( glyphString::iterator i(glyphs.begin()); i != glyphs.end(); ++i)
350 if ( i->bbox->left() < boundBox.left() )
351 boundBox.setLeft( i->bbox->left() );
352 if ( i->bbox->top() < boundBox.top() )
353 boundBox.setTop( i->bbox->top() );
354 if ( i->bbox->right() > boundBox.right() )
355 boundBox.setRight( i->bbox->right() );
356 if ( i->bbox->bottom() > boundBox.bottom() )
357 boundBox.setBottom( i->bbox->bottom() );
359 // eDebug("boundBox left = %i, top = %i, right = %i, bottom = %i", boundBox.left(), boundBox.top(), boundBox.right(), boundBox.bottom() );
363 void eTextPara::newLine(int flags)
365 if (!(flags & RS_RTL))
367 if (maximum.width()<cursor.x())
368 maximum.setWidth(cursor.x());
373 if (maximum.width()<(area.right()-cursor.x()))
374 maximum.setWidth(area.right()-cursor.x());
375 cursor.setX(area.right());
377 int linegap=current_face->size->metrics.height-(current_face->size->metrics.ascender+current_face->size->metrics.descender);
378 cursor+=ePoint(0, (current_face->size->metrics.ascender+current_face->size->metrics.descender+linegap*1/2)>>6);
379 if (maximum.height()<cursor.y())
380 maximum.setHeight(cursor.y());
384 static eLock refcntlck;
386 eTextPara::~eTextPara()
390 eFatal("verdammt man der war noch gelockt :/\n");
393 void eTextPara::destroy()
395 eLocker lock(refcntlck);
401 eTextPara *eTextPara::grab()
403 eLocker lock(refcntlck);
409 void eTextPara::setFont(const gFont &font)
412 eFatal("mod. after lock");
413 setFont(fontRenderClass::getInstance()->getFont(font.family.c_str(), font.pointSize));
416 void eTextPara::setFont(Font *fnt)
419 eFatal("mod. after lock");
422 if (current_font && !current_font->ref)
425 eLocker lock(ftlock);
427 if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, ¤t_font->font.font, ¤t_face, ¤t_font->size)<0)
429 eDebug("FTC_Manager_Lookup_Size failed!");
432 cache_current_font=¤t_font->font.font;
434 use_kerning=FT_HAS_KERNING(current_face);
437 int eTextPara::renderString(const std::string &string, int rflags)
439 eLocker lock(ftlock);
442 eFatal("mod. after lock");
449 if (!(rflags & RS_RTL))
451 cursor=ePoint(area.x(), area.y()+(current_face->size->metrics.ascender>>6));
454 cursor=ePoint(area.right(), area.y()+(current_face->size->metrics.ascender>>6));
459 glyphs.reserve(glyphs.size()+string.length());
461 if (¤t_font->font.font != cache_current_font)
463 if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, ¤t_font->font.font, ¤t_face, ¤t_font->size)<0)
465 eDebug("FTC_Manager_Lookup_Size failed!");
468 cache_current_font=¤t_font->font.font;
471 std::string::const_iterator p(string.begin());
473 while(p != string.end())
478 unsigned int unicode=*p++;
480 if (unicode & 0x80) // we have (hopefully) UTF8 here, and we assume that the encoding is VALID
482 if ((unicode & 0xE0)==0xC0) // two bytes
486 if (p != string.end())
487 unicode|=(*p++)&0x3F;
488 } else if ((unicode & 0xF0)==0xE0) // three bytes
492 if (p != string.end())
493 unicode|=(*p++)&0x3F;
495 if (p != string.end())
496 unicode|=(*p++)&0x3F;
497 } else if ((unicode & 0xF8)==0xF0) // four bytes
501 if (p != string.end())
502 unicode|=(*p++)&0x3F;
504 if (p != string.end())
505 unicode|=(*p++)&0x3F;
507 if (p != string.end())
508 unicode|=(*p++)&0x3F;
512 if (!(rflags&RS_DIRECT))
518 if (!(rflags & RS_RTL))
520 cursor+=ePoint(current_font->tabwidth, 0);
521 cursor-=ePoint(cursor.x()%current_font->tabwidth, 0);
525 cursor-=ePoint(current_font->tabwidth, 0);
526 cursor+=ePoint(cursor.x()%current_font->tabwidth, 0);
537 case 0x86: case 0xE086:
538 case 0x87: case 0xE087:
551 index=(rflags&RS_DIRECT)? unicode : FT_Get_Char_Index(current_face, unicode);
554 eDebug("unicode %d ('%c') not present", unicode, unicode);
556 appendGlyph(index, flags, rflags);
564 void eTextPara::blit(gPixmapDC &dc, const ePoint &offset, const gRGB &background, const gRGB &foreground)
566 eLocker lock(ftlock);
568 if (¤t_font->font.font != cache_current_font)
570 if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, ¤t_font->font.font, ¤t_face, ¤t_font->size)<0)
572 eDebug("FTC_Manager_Lookup_Size failed!");
575 cache_current_font=¤t_font->font.font;
578 gPixmap &target=dc.getPixmap();
586 if (target.clut.data)
588 lookup8=getColor(target.clut, background, foreground).lookup;
592 } else if (target.bpp == 32)
595 if (target.clut.data)
597 lookup8=getColor(target.clut, background, foreground).lookup;
598 for (int i=0; i<16; ++i)
599 lookup32[i]=((target.clut.data[lookup8[i]].a<<24)|
600 (target.clut.data[lookup8[i]].r<<16)|
601 (target.clut.data[lookup8[i]].g<<8)|
602 (target.clut.data[lookup8[i]].b))^0xFF000000;
605 for (int i=0; i<16; ++i)
606 lookup32[i]=(0x010101*i)|0xFF000000;
610 eWarning("can't render to %dbpp", target.bpp);
614 eRect clip(0, 0, target.x, target.y);
617 int buffer_stride=target.stride;
619 for (glyphString::iterator i(glyphs.begin()); i != glyphs.end(); ++i)
621 FTC_SBit glyph_bitmap;
622 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
623 if (fontRenderClass::instance->getGlyphBitmap(&i->font->font, i->glyph_index, &glyph_bitmap))
625 if (!glyph_bitmap->buffer)
627 int rx=i->x+glyph_bitmap->left + offset.x();
628 int ry=i->y-glyph_bitmap->top + offset.y();
629 __u8 *d=(__u8*)(target.data)+buffer_stride*ry+rx*target.bypp;
630 __u8 *s=glyph_bitmap->buffer;
631 register int sx=glyph_bitmap->width;
632 int sy=glyph_bitmap->height;
633 if ((sy+ry) >= clip.bottom())
635 if ((sx+rx) >= clip.right())
637 if (rx < clip.left())
639 int diff=clip.left()-rx;
647 int diff=clip.top()-ry;
648 s+=diff*glyph_bitmap->pitch;
651 d+=diff*buffer_stride;
654 for (int ay=0; ay<sy; ay++)
656 if (!opcode) // 4bit lookup to 8bit
660 for (ax=0; ax<sx; ax++)
662 register int b=(*s++)>>4;
668 } else if (opcode == 1) // 8bit direct
672 for (ax=0; ax<sx; ax++)
679 register __u32 *td=(__u32*)d;
681 for (ax=0; ax<sx; ax++)
683 register int b=(*s++)>>4;
690 s+=glyph_bitmap->pitch-sx;
696 void eTextPara::realign(int dir) // der code hier ist ein wenig merkwuerdig.
698 glyphString::iterator begin(glyphs.begin()), c(glyphs.begin()), end(glyphs.begin()), last;
701 while (c != glyphs.end())
704 int numspaces=0, num=0;
711 } while ((end != glyphs.end()) && (!(end->flags&GS_ISFIRST)));
712 // end zeigt jetzt auf begin der naechsten zeile
714 for (c=begin; c!=end; ++c)
716 // space am zeilenende skippen
717 if ((c==last) && (c->flags&GS_ISSPACE))
720 if (c->flags&GS_ISSPACE)
725 if (!num) // line mit nur einem space
733 int offset=area.width()-linelength;
739 begin->bbox->moveBy(offset,0);
746 if (end == glyphs.end()) // letzte zeile linksbuendig lassen
753 if ((!spacemode) && (num<2))
755 int off=(area.width()-linelength)*256/(spacemode?numspaces:(num-1));
760 if ((!spacemode) || (begin->flags&GS_ISSPACE))
763 begin->bbox->moveBy(curoff>>8,0);
775 void eTextPara::clear()
777 eLocker lock(ftlock);
779 for (glyphString::iterator i(glyphs.begin()); i!=glyphs.end(); ++i)
787 eAutoInitP0<fontRenderClass> init_fontRenderClass(1, "Font Render Class");