aboutsummaryrefslogtreecommitdiff
path: root/lib/gdi
diff options
context:
space:
mode:
authorFelix Domke <tmbinc@elitedvb.net>2003-10-17 15:35:43 +0000
committerFelix Domke <tmbinc@elitedvb.net>2003-10-17 15:35:43 +0000
commitfc2f5b2cd655f1391f2abda1b39e37cdec98a951 (patch)
tree312efcea86a319de407a7c314fb981fb1c71019a /lib/gdi
downloadenigma2-fc2f5b2cd655f1391f2abda1b39e37cdec98a951.tar.gz
enigma2-fc2f5b2cd655f1391f2abda1b39e37cdec98a951.zip
Initial revision
Diffstat (limited to 'lib/gdi')
-rw-r--r--lib/gdi/.cvsignore7
-rw-r--r--lib/gdi/Makefile.am8
-rw-r--r--lib/gdi/epng.cpp187
-rw-r--r--lib/gdi/epng.h9
-rw-r--r--lib/gdi/epoint.h172
-rw-r--r--lib/gdi/erect.cpp204
-rw-r--r--lib/gdi/erect.h229
-rw-r--r--lib/gdi/esize.h187
-rw-r--r--lib/gdi/fb.cpp186
-rw-r--r--lib/gdi/fb.h43
-rw-r--r--lib/gdi/font.cpp855
-rw-r--r--lib/gdi/font.cpp-new787
-rw-r--r--lib/gdi/font.h163
-rw-r--r--lib/gdi/font_arabic.cpp266
-rw-r--r--lib/gdi/gfbdc.cpp166
-rw-r--r--lib/gdi/gfbdc.h35
-rw-r--r--lib/gdi/glcddc.cpp56
-rw-r--r--lib/gdi/glcddc.h26
-rw-r--r--lib/gdi/gpixmap.cpp295
-rw-r--r--lib/gdi/gpixmap.h142
-rw-r--r--lib/gdi/grc.cpp348
-rw-r--r--lib/gdi/grc.h245
-rw-r--r--lib/gdi/lcd.cpp210
-rw-r--r--lib/gdi/lcd.h53
24 files changed, 4879 insertions, 0 deletions
diff --git a/lib/gdi/.cvsignore b/lib/gdi/.cvsignore
new file mode 100644
index 00000000..316b06f5
--- /dev/null
+++ b/lib/gdi/.cvsignore
@@ -0,0 +1,7 @@
+*.moc.*
+Makefile
+Makefile.in
+.deps
+.libs
+*.lo
+*.la
diff --git a/lib/gdi/Makefile.am b/lib/gdi/Makefile.am
new file mode 100644
index 00000000..eff43b08
--- /dev/null
+++ b/lib/gdi/Makefile.am
@@ -0,0 +1,8 @@
+INCLUDES = \
+ -I$(top_srcdir)/include
+
+noinst_LIBRARIES = libenigma_gdi.a
+
+libenigma_gdi_a_SOURCES = \
+ epng.cpp erect.cpp fb.cpp font.cpp font_arabic.cpp gfbdc.cpp \
+ glcddc.cpp gpixmap.cpp grc.cpp lcd.cpp
diff --git a/lib/gdi/epng.cpp b/lib/gdi/epng.cpp
new file mode 100644
index 00000000..d476ec3a
--- /dev/null
+++ b/lib/gdi/epng.cpp
@@ -0,0 +1,187 @@
+#include <png.h>
+#include <stdio.h>
+#include <lib/gdi/epng.h>
+#include <unistd.h>
+
+gImage *loadPNG(const char *filename)
+{
+ __u8 header[8];
+ FILE *fp=fopen(filename, "rb");
+
+ gImage *res=0;
+
+ if (!fp)
+ {
+// eDebug("couldn't open %s", filename );
+ return 0;
+ }
+ if (!fread(header, 8, 1, fp))
+ {
+ eDebug("couldn't read");
+ fclose(fp);
+ return 0;
+ }
+ if (png_sig_cmp(header, 0, 8))
+ {
+ fclose(fp);
+ return 0;
+ }
+ png_structp png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ if (!png_ptr)
+ {
+ eDebug("no pngptr");
+ fclose(fp);
+ return 0;
+ }
+ png_infop info_ptr=png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ eDebug("no info ptr");
+ png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
+ fclose(fp);
+ return 0;
+ }
+ png_infop end_info = png_create_info_struct(png_ptr);
+ if (!end_info)
+ {
+ eDebug("no end");
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ fclose(fp);
+ return 0;
+ }
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ eDebug("das war wohl nix");
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ fclose(fp);
+ if (res)
+ delete res;
+ return 0;
+ }
+ png_init_io(png_ptr, fp);
+ png_set_sig_bytes(png_ptr, 8);
+ png_set_invert_alpha(png_ptr);
+ png_read_info(png_ptr, info_ptr);
+
+ png_uint_32 width, height;
+ int bit_depth;
+ int color_type;
+
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
+
+// eDebug("%s: %dx%dx%d png, %d", filename, (int)width, (int)height, (int)bit_depth, color_type);
+
+ if (color_type != 6)
+ {
+ res=new gImage(eSize(width, height), bit_depth);
+
+ png_bytep *rowptr=new png_bytep[height];
+
+ for (unsigned int i=0; i<height; i++)
+ rowptr[i]=((png_byte*)(res->data))+i*res->stride;
+ png_read_rows(png_ptr, rowptr, 0, height);
+
+ delete rowptr;
+
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE))
+ {
+ png_color *palette;
+ int num_palette;
+ png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
+ if (num_palette)
+ res->clut.data=new gRGB[num_palette];
+ else
+ res->clut.data=0;
+ res->clut.colors=num_palette;
+
+ for (int i=0; i<num_palette; i++)
+ {
+ res->clut.data[i].a=0;
+ res->clut.data[i].r=palette[i].red;
+ res->clut.data[i].g=palette[i].green;
+ res->clut.data[i].b=palette[i].blue;
+ }
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ {
+ png_byte *trans;
+ png_get_tRNS(png_ptr, info_ptr, &trans, &num_palette, 0);
+ for (int i=0; i<num_palette; i++)
+ res->clut.data[i].a=255-trans[i];
+ }
+ } else
+ {
+ res->clut.data=0;
+ res->clut.colors=0;
+ }
+ png_read_end(png_ptr, end_info);
+ } else
+ res=0;
+
+ png_destroy_read_struct(&png_ptr, &info_ptr,&end_info);
+ fclose(fp);
+ return res;
+}
+
+int savePNG(const char *filename, gPixmap *pixmap)
+{
+ FILE *fp=fopen(filename, "wb");
+ if (!fp)
+ return -1;
+ png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ if (!png_ptr)
+ {
+ eDebug("write png, couldnt allocate write struct");
+ fclose(fp);
+ unlink(filename);
+ return -2;
+ }
+ png_infop info_ptr=png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ eDebug("info");
+ png_destroy_write_struct(&png_ptr, 0);
+ fclose(fp);
+ unlink(filename);
+ return -3;
+ }
+ if (setjmp(png_ptr->jmpbuf))
+ {
+ eDebug("error :/");
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ unlink(filename);
+ return -4;
+ }
+ png_init_io(png_ptr, fp);
+ png_set_filter(png_ptr, 0, PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_PAETH);
+ png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
+
+ png_set_IHDR(png_ptr, info_ptr, pixmap->x, pixmap->y, pixmap->bpp,
+ pixmap->clut.data ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ if (pixmap->clut.data)
+ {
+ png_color palette[pixmap->clut.colors];
+ png_byte trans[pixmap->clut.colors];
+ for (int i=0; i<pixmap->clut.colors; ++i)
+ {
+ palette[i].red=pixmap->clut.data[i].r;
+ palette[i].green=pixmap->clut.data[i].g;
+ palette[i].blue=pixmap->clut.data[i].b;
+ trans[i]=255-pixmap->clut.data[i].a;
+ }
+ png_set_PLTE(png_ptr, info_ptr, palette, pixmap->clut.colors);
+ png_set_tRNS(png_ptr, info_ptr, trans, pixmap->clut.colors, 0);
+ }
+ png_write_info(png_ptr, info_ptr);
+ png_set_packing(png_ptr);
+ png_byte *row_pointers[pixmap->y];
+ for (int i=0; i<pixmap->y; ++i)
+ row_pointers[i]=((png_byte*)pixmap->data)+i*pixmap->stride;
+ png_write_image(png_ptr, row_pointers);
+ png_write_end(png_ptr, info_ptr);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ eDebug("wrote png ! fine !");
+ return 0;
+}
diff --git a/lib/gdi/epng.h b/lib/gdi/epng.h
new file mode 100644
index 00000000..650c2513
--- /dev/null
+++ b/lib/gdi/epng.h
@@ -0,0 +1,9 @@
+#ifndef __png_h
+#define __png_h
+
+#include "grc.h"
+
+gImage *loadPNG(const char *filename);
+int savePNG(const char *filename, gPixmap *pixmap);
+
+#endif
diff --git a/lib/gdi/epoint.h b/lib/gdi/epoint.h
new file mode 100644
index 00000000..fc5f9836
--- /dev/null
+++ b/lib/gdi/epoint.h
@@ -0,0 +1,172 @@
+#ifndef EPOINT_H
+#define EPOINT_H
+
+#include <iostream>
+
+#ifndef ABS
+#define ABS(x) ( x>0 ? x : -x )
+#endif
+
+class ePoint
+{
+public:
+ ePoint();
+ ePoint( int xpos, int ypos );
+
+ bool isNull() const;
+
+ int x() const;
+ int y() const;
+ void setX( int x );
+ void setY( int y );
+
+ int manhattanLength() const;
+
+ int &rx();
+ int &ry();
+
+ ePoint &operator+=( const ePoint &p );
+ ePoint &operator-=( const ePoint &p );
+ ePoint &operator*=( int c );
+ ePoint &operator*=( double c );
+ ePoint &operator/=( int c );
+ ePoint &operator/=( double c );
+
+ friend inline bool operator==( const ePoint &, const ePoint & );
+ friend inline bool operator!=( const ePoint &, const ePoint & );
+ friend inline ePoint operator+( const ePoint &, const ePoint & );
+ friend inline ePoint operator-( const ePoint &, const ePoint & );
+ friend inline ePoint operator*( const ePoint &, int );
+ friend inline ePoint operator*( int, const ePoint & );
+ friend inline ePoint operator*( const ePoint &, double );
+ friend inline ePoint operator*( double, const ePoint & );
+ friend inline ePoint operator-( const ePoint & );
+ friend inline ePoint operator/( const ePoint &, int );
+ friend inline ePoint operator/( const ePoint &, double );
+private:
+ int xp;
+ int yp;
+};
+
+
+inline int ePoint::manhattanLength() const
+{
+ return ABS(x())+ABS(y());
+}
+
+
+/*****************************************************************************
+ ePoint stream functions
+ *****************************************************************************/
+namespace std
+{
+ inline ostream &operator<<( ostream & s, const ePoint & p )
+ {
+ s << p.x() << p.y();
+ return s;
+ }
+
+ inline istream &operator>>( istream & s, ePoint & p )
+ {
+ s >> p.rx() >> p.ry();
+ return s;
+ }
+}
+
+
+/*****************************************************************************
+ ePoint inline functions
+ *****************************************************************************/
+
+inline ePoint::ePoint()
+{ xp=0; yp=0; }
+
+inline ePoint::ePoint( int xpos, int ypos )
+{ xp=(int)xpos; yp=(int)ypos; }
+
+inline bool ePoint::isNull() const
+{ return xp == 0 && yp == 0; }
+
+inline int ePoint::x() const
+{ return xp; }
+
+inline int ePoint::y() const
+{ return yp; }
+
+inline void ePoint::setX( int x )
+{ xp = (int)x; }
+
+inline void ePoint::setY( int y )
+{ yp = (int)y; }
+
+inline int &ePoint::rx()
+{ return xp; }
+
+inline int &ePoint::ry()
+{ return yp; }
+
+inline ePoint &ePoint::operator+=( const ePoint &p )
+{ xp+=p.xp; yp+=p.yp; return *this; }
+
+inline ePoint &ePoint::operator-=( const ePoint &p )
+{ xp-=p.xp; yp-=p.yp; return *this; }
+
+inline ePoint &ePoint::operator*=( int c )
+{ xp*=(int)c; yp*=(int)c; return *this; }
+
+inline ePoint &ePoint::operator*=( double c )
+{ xp=(int)(xp*c); yp=(int)(yp*c); return *this; }
+
+inline bool operator==( const ePoint &p1, const ePoint &p2 )
+{ return p1.xp == p2.xp && p1.yp == p2.yp; }
+
+inline bool operator!=( const ePoint &p1, const ePoint &p2 )
+{ return p1.xp != p2.xp || p1.yp != p2.yp; }
+
+inline ePoint operator+( const ePoint &p1, const ePoint &p2 )
+{ return ePoint(p1.xp+p2.xp, p1.yp+p2.yp); }
+
+inline ePoint operator-( const ePoint &p1, const ePoint &p2 )
+{ return ePoint(p1.xp-p2.xp, p1.yp-p2.yp); }
+
+inline ePoint operator*( const ePoint &p, int c )
+{ return ePoint(p.xp*c, p.yp*c); }
+
+inline ePoint operator*( int c, const ePoint &p )
+{ return ePoint(p.xp*c, p.yp*c); }
+
+inline ePoint operator*( const ePoint &p, double c )
+{ return ePoint((int)(p.xp*c), (int)(p.yp*c)); }
+
+inline ePoint operator*( double c, const ePoint &p )
+{ return ePoint((int)(p.xp*c), (int)(p.yp*c)); }
+
+inline ePoint operator-( const ePoint &p )
+{ return ePoint(-p.xp, -p.yp); }
+
+inline ePoint &ePoint::operator/=( int c )
+{
+ xp/=(int)c;
+ yp/=(int)c;
+ return *this;
+}
+
+inline ePoint &ePoint::operator/=( double c )
+{
+ xp=(int)(xp/c);
+ yp=(int)(yp/c);
+ return *this;
+}
+
+inline ePoint operator/( const ePoint &p, int c )
+{
+ return ePoint(p.xp/c, p.yp/c);
+}
+
+inline ePoint operator/( const ePoint &p, double c )
+{
+ return ePoint((int)(p.xp/c), (int)(p.yp/c));
+}
+
+
+#endif // EPOINT_H
diff --git a/lib/gdi/erect.cpp b/lib/gdi/erect.cpp
new file mode 100644
index 00000000..b72e5d04
--- /dev/null
+++ b/lib/gdi/erect.cpp
@@ -0,0 +1,204 @@
+#include <lib/gdi/erect.h>
+#include <iostream>
+
+/*****************************************************************************
+ eRect member functions
+ *****************************************************************************/
+
+eRect::eRect( const ePoint &topLeft, const ePoint &bottomRight )
+{
+ x1 = topLeft.x();
+ y1 = topLeft.y();
+ x2 = bottomRight.x();
+ y2 = bottomRight.y();
+}
+
+eRect eRect::normalize() const
+{
+ eRect r;
+ if ( x2 < x1 ) { // swap bad x values
+ r.x1 = x2;
+ r.x2 = x1;
+ } else {
+ r.x1 = x1;
+ r.x2 = x2;
+ }
+ if ( y2 < y1 ) { // swap bad y values
+ r.y1 = y2;
+ r.y2 = y1;
+ } else {
+ r.y1 = y1;
+ r.y2 = y2;
+ }
+ return r;
+}
+
+void eRect::rect( int *x, int *y, int *w, int *h ) const
+{
+ *x = x1;
+ *y = y1;
+ *w = x2-x1;
+ *h = y2-y1;
+}
+
+void eRect::coords( int *xp1, int *yp1, int *xp2, int *yp2 ) const
+{
+ *xp1 = x1;
+ *yp1 = y1;
+ *xp2 = x2;
+ *yp2 = y2;
+}
+
+void eRect::moveTopLeft( const ePoint &p )
+{
+ x2 += (p.x() - x1);
+ y2 += (p.y() - y1);
+ x1 = p.x();
+ y1 = p.y();
+}
+
+void eRect::moveBottomRight( const ePoint &p )
+{
+ x1 += (p.x() - x2);
+ y1 += (p.y() - y2);
+ x2 = p.x();
+ y2 = p.y();
+}
+
+void eRect::moveTopRight( const ePoint &p )
+{
+ x1 += (p.x() - x2);
+ y2 += (p.y() - y1);
+ x2 = p.x();
+ y1 = p.y();
+}
+
+void eRect::moveBottomLeft( const ePoint &p )
+{
+ x2 += (p.x() - x1);
+ y1 += (p.y() - y2);
+ x1 = p.x();
+ y2 = p.y();
+}
+
+void eRect::moveCenter( const ePoint &p )
+{
+ int w = x2 - x1;
+ int h = y2 - y1;
+ x1 = (p.x() - w/2);
+ y1 = (p.y() - h/2);
+ x2 = x1 + w;
+ y2 = y1 + h;
+}
+
+void eRect::setRect( int x, int y, int w, int h )
+{
+ x1 = x;
+ y1 = y;
+ x2 = (x+w);
+ y2 = (y+h);
+}
+
+void eRect::setCoords( int xp1, int yp1, int xp2, int yp2 )
+{
+ x1 = xp1;
+ y1 = yp1;
+ x2 = xp2;
+ y2 = yp2;
+}
+
+void eRect::setWidth( int w )
+{
+ x2 = x1 + w;
+}
+
+void eRect::setHeight( int h )
+{
+ y2 = y1 + h;
+}
+
+void eRect::setSize( const eSize &s )
+{
+ x2 = s.width() +x1;
+ y2 = s.height()+y1;
+}
+
+bool eRect::contains( const ePoint &p) const
+{
+ return p.x() >= x1 && p.x() < x2 &&
+ p.y() >= y1 && p.y() < y2;
+}
+
+bool eRect::contains( const eRect &r) const
+{
+ return r.x1 >= x1 &&
+ r.x2 <= x2 &&
+ r.y1 >= y1 &&
+ r.y2 <= y2;
+}
+
+eRect& eRect::operator|=(const eRect &r)
+{
+ *this = *this | r;
+ return *this;
+}
+
+eRect& eRect::operator&=(const eRect &r)
+{
+ *this = *this & r;
+ return *this;
+}
+
+eRect eRect::operator|(const eRect &r) const
+{
+ if ( isValid() ) {
+ if ( r.isValid() ) {
+ eRect tmp;
+ tmp.setLeft( MIN( x1, r.x1 ) );
+ tmp.setRight( MAX( x2, r.x2 ) );
+ tmp.setTop( MIN( y1, r.y1 ) );
+ tmp.setBottom( MAX( y2, r.y2 ) );
+ return tmp;
+ } else {
+ return *this;
+ }
+ } else {
+ return r;
+ }
+}
+
+eRect eRect::unite( const eRect &r ) const
+{
+ return *this | r;
+}
+
+eRect eRect::operator&( const eRect &r ) const
+{
+ eRect tmp;
+ tmp.x1 = MAX( x1, r.x1 );
+ tmp.x2 = MIN( x2, r.x2 );
+ tmp.y1 = MAX( y1, r.y1 );
+ tmp.y2 = MIN( y2, r.y2 );
+ return tmp;
+}
+
+eRect eRect::intersect( const eRect &r ) const
+{
+ return *this & r;
+}
+
+bool eRect::intersects( const eRect &r ) const
+{
+ return ( MAX( x1, r.x1 ) < MIN( x2, r.x2 ) &&
+ MAX( y1, r.y1 ) < MIN( y2, r.y2 ) );
+}
+
+bool operator==( const eRect &r1, const eRect &r2 )
+{
+ return r1.x1==r2.x1 && r1.x2==r2.x2 && r1.y1==r2.y1 && r1.y2==r2.y2;
+}
+
+bool operator!=( const eRect &r1, const eRect &r2 )
+{
+ return r1.x1!=r2.x1 || r1.x2!=r2.x2 || r1.y1!=r2.y1 || r1.y2!=r2.y2;
+}
diff --git a/lib/gdi/erect.h b/lib/gdi/erect.h
new file mode 100644
index 00000000..c41d8314
--- /dev/null
+++ b/lib/gdi/erect.h
@@ -0,0 +1,229 @@
+#ifndef ERECT_H
+#define ERECT_H
+
+#include <lib/gdi/esize.h>
+#include <lib/gdi/epoint.h>
+
+
+// x2 = x1 + width (AND NOT, NEVER, NEVER EVER +1 or -1 !!!!)
+
+class eRect // rectangle class
+{
+public:
+ eRect() { x1 = y1 = x2 = y2 = 0; }
+ eRect( const ePoint &topleft, const ePoint &bottomright );
+
+ // we use this contructor very often... do it inline...
+ eRect( const ePoint &topleft, const eSize &size )
+ {
+ x1 = topleft.x();
+ y1 = topleft.y();
+ x2 = (x1+size.width());
+ y2 = (y1+size.height());
+ }
+
+ eRect( int left, int top, int width, int height );
+
+ bool isNull() const;
+ bool isEmpty() const;
+ bool isValid() const;
+ eRect normalize() const;
+
+ int left() const;
+ int top() const;
+ int right() const;
+ int bottom() const;
+ int &rLeft();
+ int &rTop();
+ int &rRight();
+ int &rBottom();
+
+ int x() const;
+ int y() const;
+ void setLeft( int pos );
+ void setTop( int pos );
+ void setRight( int pos );
+ void setBottom( int pos );
+ void setX( int x );
+ void setY( int y );
+
+ ePoint topLeft() const;
+ ePoint bottomRight() const;
+ ePoint topRight() const;
+ ePoint bottomLeft() const;
+ ePoint center() const;
+
+ void rect( int *x, int *y, int *w, int *h ) const;
+ void coords( int *x1, int *y1, int *x2, int *y2 ) const;
+
+ void moveTopLeft( const ePoint &p );
+ void moveBottomRight( const ePoint &p );
+ void moveTopRight( const ePoint &p );
+ void moveBottomLeft( const ePoint &p );
+ void moveCenter( const ePoint &p );
+
+ void moveBy( int dx, int dy )
+ {
+ x1 += dx;
+ y1 += dy;
+ x2 += dx;
+ y2 += dy;
+ }
+
+ void setRect( int x, int y, int w, int h );
+ void setCoords( int x1, int y1, int x2, int y2 );
+
+ eSize size() const;
+ int width() const;
+ int height() const;
+ void setWidth( int w );
+ void setHeight( int h );
+ void setSize( const eSize &s );
+
+ eRect operator|(const eRect &r) const;
+ eRect operator&(const eRect &r) const;
+ eRect& operator|=(const eRect &r);
+ eRect& operator&=(const eRect &r);
+
+ bool contains( const ePoint &p) const;
+ bool contains( int x, int y) const;
+ bool contains( const eRect &r) const;
+ eRect unite( const eRect &r ) const;
+ eRect intersect( const eRect &r ) const;
+ bool intersects( const eRect &r ) const;
+
+ friend bool operator==( const eRect &, const eRect & );
+ friend bool operator!=( const eRect &, const eRect & );
+
+private:
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+};
+
+bool operator==( const eRect &, const eRect & );
+bool operator!=( const eRect &, const eRect & );
+
+
+/*****************************************************************************
+ eRect stream functions
+ *****************************************************************************/
+namespace std
+{
+ inline ostream &operator<<( ostream & s, const eRect & r )
+ {
+ s << r.left() << r.top()
+ << r.right() << r.bottom();
+
+ return s;
+ }
+
+ inline istream &operator>>( istream & s, eRect & r )
+ {
+ int x1, y1, x2, y2;
+ s >> x1 >> y1 >> x2 >> y2;
+ r.setCoords( x1, y1, x2, y2 );
+ return s;
+ }
+}
+
+/*****************************************************************************
+ eRect inline member functions
+ *****************************************************************************/
+
+inline eRect::eRect( int left, int top, int width, int height )
+{
+ x1 = left;
+ y1 = top;
+ x2 = left+width;
+ y2 = top+height;
+}
+
+inline bool eRect::isNull() const
+{ return x2 == x1 && y2 == y1; }
+
+inline bool eRect::isEmpty() const
+{ return x1 >= x2 || y1 >= y2; }
+
+inline bool eRect::isValid() const
+{ return x1 <= x2 && y1 <= y2; }
+
+inline int eRect::left() const
+{ return x1; }
+
+inline int eRect::top() const
+{ return y1; }
+
+inline int eRect::right() const
+{ return x2; }
+
+inline int eRect::bottom() const
+{ return y2; }
+
+inline int &eRect::rLeft()
+{ return x1; }
+
+inline int & eRect::rTop()
+{ return y1; }
+
+inline int & eRect::rRight()
+{ return x2; }
+
+inline int & eRect::rBottom()
+{ return y2; }
+
+inline int eRect::x() const
+{ return x1; }
+
+inline int eRect::y() const
+{ return y1; }
+
+inline void eRect::setLeft( int pos )
+{ x1 = pos; }
+
+inline void eRect::setTop( int pos )
+{ y1 = pos; }
+
+inline void eRect::setRight( int pos )
+{ x2 = pos; }
+
+inline void eRect::setBottom( int pos )
+{ y2 = pos; }
+
+inline void eRect::setX( int x )
+{ x1 = x; }
+
+inline void eRect::setY( int y )
+{ y1 = y; }
+
+inline ePoint eRect::topLeft() const
+{ return ePoint(x1, y1); }
+
+inline ePoint eRect::bottomRight() const
+{ return ePoint(x2, y2); }
+
+inline ePoint eRect::topRight() const
+{ return ePoint(x2, y1); }
+
+inline ePoint eRect::bottomLeft() const
+{ return ePoint(x1, y2); }
+
+inline ePoint eRect::center() const
+{ return ePoint((x1+x2)/2, (y1+y2)/2); }
+
+inline int eRect::width() const
+{ return x2 - x1; }
+
+inline int eRect::height() const
+{ return y2 - y1; }
+
+inline eSize eRect::size() const
+{ return eSize(x2-x1, y2-y1); }
+
+inline bool eRect::contains( int x, int y) const
+{
+ return x >= x1 && x < x2 && y >= y1 && y < y2;
+}
+
+#endif // eRect_H
diff --git a/lib/gdi/esize.h b/lib/gdi/esize.h
new file mode 100644
index 00000000..d4bd4afb
--- /dev/null
+++ b/lib/gdi/esize.h
@@ -0,0 +1,187 @@
+#ifndef ESIZE_H
+#define ESIZE_H
+
+#include <iostream>
+
+#define MIN(a,b) (a < b ? a : b)
+#define MAX(a,b) (a > b ? a : b)
+
+class eSize
+{
+public:
+ eSize();
+ eSize( int w, int h );
+
+ bool isNull() const;
+ bool isEmpty() const;
+ bool isValid() const;
+
+ int width() const;
+ int height() const;
+ void setWidth( int w );
+ void setHeight( int h );
+ void transpose();
+
+ eSize expandedTo( const eSize & ) const;
+ eSize boundedTo( const eSize & ) const;
+
+ int &rwidth();
+ int &rheight();
+
+ eSize &operator+=( const eSize & );
+ eSize &operator-=( const eSize & );
+ eSize &operator*=( int c );
+ eSize &operator*=( double c );
+ eSize &operator/=( int c );
+ eSize &operator/=( double c );
+
+ friend inline bool operator==( const eSize &, const eSize & );
+ friend inline bool operator!=( const eSize &, const eSize & );
+ friend inline eSize operator+( const eSize &, const eSize & );
+ friend inline eSize operator-( const eSize &, const eSize & );
+ friend inline eSize operator*( const eSize &, int );
+ friend inline eSize operator*( int, const eSize & );
+ friend inline eSize operator*( const eSize &, double );
+ friend inline eSize operator*( double, const eSize & );
+ friend inline eSize operator/( const eSize &, int );
+ friend inline eSize operator/( const eSize &, double );
+
+private:
+ int wd;
+ int ht;
+};
+
+
+/*****************************************************************************
+ eSize stream functions
+ *****************************************************************************/
+
+namespace std
+{
+ inline ostream &operator<<( ostream &s, const eSize &sz )
+ {
+ s << sz.width() << sz.height();
+ return s;
+ }
+
+ inline istream &operator>>( istream &s, eSize &sz )
+ {
+ s >> sz.rwidth() >> sz.rheight();
+ return s;
+ }
+}
+
+
+/*****************************************************************************
+ eSize inline functions
+ *****************************************************************************/
+
+inline eSize::eSize()
+{ wd = ht = -1; }
+
+inline eSize::eSize( int w, int h )
+{ wd=w; ht=h; }
+
+inline bool eSize::isNull() const
+{ return wd==0 && ht==0; }
+
+inline bool eSize::isEmpty() const
+{ return wd<1 || ht<1; }
+
+inline bool eSize::isValid() const
+{ return wd>=0 && ht>=0; }
+
+inline int eSize::width() const
+{ return wd; }
+
+inline int eSize::height() const
+{ return ht; }
+
+inline void eSize::setWidth( int w )
+{ wd=w; }
+
+inline void eSize::setHeight( int h )
+{ ht=h; }
+
+inline int &eSize::rwidth()
+{ return wd; }
+
+inline int &eSize::rheight()
+{ return ht; }
+
+inline eSize &eSize::operator+=( const eSize &s )
+{ wd+=s.wd; ht+=s.ht; return *this; }
+
+inline eSize &eSize::operator-=( const eSize &s )
+{ wd-=s.wd; ht-=s.ht; return *this; }
+
+inline eSize &eSize::operator*=( int c )
+{ wd*=c; ht*=c; return *this; }
+
+inline eSize &eSize::operator*=( double c )
+{ wd=(int)(wd*c); ht=(int)(ht*c); return *this; }
+
+inline bool operator==( const eSize &s1, const eSize &s2 )
+{ return s1.wd == s2.wd && s1.ht == s2.ht; }
+
+inline bool operator!=( const eSize &s1, const eSize &s2 )
+{ return s1.wd != s2.wd || s1.ht != s2.ht; }
+
+inline eSize operator+( const eSize & s1, const eSize & s2 )
+{ return eSize(s1.wd+s2.wd, s1.ht+s2.ht); }
+
+inline eSize operator-( const eSize &s1, const eSize &s2 )
+{ return eSize(s1.wd-s2.wd, s1.ht-s2.ht); }
+
+inline eSize operator*( const eSize &s, int c )
+{ return eSize(s.wd*c, s.ht*c); }
+
+inline eSize operator*( int c, const eSize &s )
+{ return eSize(s.wd*c, s.ht*c); }
+
+inline eSize operator*( const eSize &s, double c )
+{ return eSize((int)(s.wd*c), (int)(s.ht*c)); }
+
+inline eSize operator*( double c, const eSize &s )
+{ return eSize((int)(s.wd*c), (int)(s.ht*c)); }
+
+inline eSize &eSize::operator/=( int c )
+{
+ wd/=c; ht/=c;
+ return *this;
+}
+
+inline eSize &eSize::operator/=( double c )
+{
+ wd=(int)(wd/c); ht=(int)(ht/c);
+ return *this;
+}
+
+inline eSize operator/( const eSize &s, int c )
+{
+ return eSize(s.wd/c, s.ht/c);
+}
+
+inline eSize operator/( const eSize &s, double c )
+{
+ return eSize((int)(s.wd/c), (int)(s.ht/c));
+}
+
+inline eSize eSize::expandedTo( const eSize & otherSize ) const
+{
+ return eSize( MAX(wd,otherSize.wd), MAX(ht,otherSize.ht) );
+}
+
+inline eSize eSize::boundedTo( const eSize & otherSize ) const
+{
+ return eSize( MIN(wd,otherSize.wd), MIN(ht,otherSize.ht) );
+}
+
+inline void eSize::transpose()
+{
+ int tmp = wd;
+ wd = ht;
+ ht = tmp;
+}
+
+#endif // ESIZE_H
diff --git a/lib/gdi/fb.cpp b/lib/gdi/fb.cpp
new file mode 100644
index 00000000..96ca4313
--- /dev/null
+++ b/lib/gdi/fb.cpp
@@ -0,0 +1,186 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <memory.h>
+#include <linux/kd.h>
+
+#include <lib/base/econfig.h>
+#include <lib/gdi/fb.h>
+
+fbClass *fbClass::instance;
+
+fbClass *fbClass::getInstance()
+{
+ return instance;
+}
+
+fbClass::fbClass(const char *fb)
+{
+ instance=this;
+ locked=0;
+ available=0;
+ cmap.start=0;
+ cmap.len=256;
+ cmap.red=red;
+ cmap.green=green;
+ cmap.blue=blue;
+ cmap.transp=trans;
+
+ int state=0;
+ eConfig::getInstance()->getKey("/ezap/osd/showConsoleOnFB", state);
+
+ fd=open(fb, O_RDWR);
+ if (fd<0)
+ {
+ perror(fb);
+ goto nolfb;
+ }
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &screeninfo)<0)
+ {
+ perror("FBIOGET_VSCREENINFO");
+ goto nolfb;
+ }
+
+ memcpy(&oldscreen, &screeninfo, sizeof(screeninfo));
+
+ fb_fix_screeninfo fix;
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)<0)
+ {
+ perror("FBIOGET_FSCREENINFO");
+ goto nolfb;
+ }
+
+ available=fix.smem_len;
+ eDebug("%dk video mem", available/1024);
+ lfb=(unsigned char*)mmap(0, available, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
+ if (!lfb)
+ {
+ perror("mmap");
+ goto nolfb;
+ }
+
+ showConsole(state);
+ return;
+nolfb:
+ lfb=0;
+ printf("framebuffer not available.\n");
+ return;
+}
+
+int fbClass::showConsole(int state)
+{
+ int fd=open("/dev/vc/0", O_RDWR);
+ if(fd>=0)
+ {
+ if(ioctl(fd, KDSETMODE, state?KD_TEXT:KD_GRAPHICS)<0)
+ {
+ eDebug("setting /dev/vc/0 status failed.");
+ }
+ close(fd);
+ }
+ return 0;
+}
+
+int fbClass::SetMode(unsigned int nxRes, unsigned int nyRes, unsigned int nbpp)
+{
+ screeninfo.xres_virtual=screeninfo.xres=nxRes;
+ screeninfo.yres_virtual=screeninfo.yres=nyRes;
+ screeninfo.xoffset=screeninfo.yoffset=0;
+ screeninfo.bits_per_pixel=nbpp;
+ if (ioctl(fd, FBIOPUT_VSCREENINFO, &screeninfo)<0)
+ {
+ perror("FBIOPUT_VSCREENINFO");
+ printf("fb failed\n");
+ return -1;
+ }
+ if ((screeninfo.xres!=nxRes) && (screeninfo.yres!=nyRes) && (screeninfo.bits_per_pixel!=nbpp))
+ {
+ eDebug("SetMode failed: wanted: %dx%dx%d, got %dx%dx%d",
+ nxRes, nyRes, nbpp,
+ screeninfo.xres, screeninfo.yres, screeninfo.bits_per_pixel);
+ }
+ xRes=screeninfo.xres;
+ yRes=screeninfo.yres;
+ bpp=screeninfo.bits_per_pixel;
+ fb_fix_screeninfo fix;
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)<0)
+ {
+ perror("FBIOGET_FSCREENINFO");
+ printf("fb failed\n");
+ }
+ stride=fix.line_length;
+ memset(lfb, 0, stride*yRes);
+ return 0;
+}
+
+fbClass::~fbClass()
+{
+ if (available)
+ ioctl(fd, FBIOPUT_VSCREENINFO, &oldscreen);
+ if (lfb)
+ munmap(lfb, available);
+}
+
+int fbClass::PutCMAP()
+{
+ return ioctl(fd, FBIOPUTCMAP, &cmap);
+}
+
+void fbClass::Box(int x, int y, int width, int height, int color, int backcolor)
+{
+ if (width<=2)
+ return;
+ int offset=y*stride+x/2;
+ int first=0xF0|((color&0xF0)>>4);
+ int last= 0xF0|((backcolor&0xF0)>>4);
+ color=(color&0xF)*0x11;
+ int halfwidth=width/2;
+ for (int ay=y; ay<(y+height); ay++)
+ {
+ lfb[offset]=first;
+ memset(lfb+offset+1, color, halfwidth-2);
+ lfb[offset+halfwidth-1]=last;
+ offset+=stride;
+ }
+}
+
+void fbClass::NBox(int x, int y, int width, int height, int color)
+{
+ int offset=y*stride+x/2;
+ int halfwidth=width/2;
+ for (int ay=y; ay<(y+height); ay++)
+ {
+ memset(lfb+offset, color, halfwidth);
+ offset+=stride;
+ }
+}
+
+void fbClass::VLine(int x, int y, int sy, int color)
+{
+ int offset=y*stride+x/2;
+ while (sy--)
+ {
+ lfb[offset]=color;
+ offset+=stride;
+ }
+}
+
+int fbClass::lock()
+{
+ if (locked)
+ return -1;
+ locked=1;
+ return fd;
+}
+
+void fbClass::unlock()
+{
+ if (!locked)
+ return;
+ locked=0;
+ SetMode(xRes, yRes, bpp);
+ PutCMAP();
+}
diff --git a/lib/gdi/fb.h b/lib/gdi/fb.h
new file mode 100644
index 00000000..d0ad6fed
--- /dev/null
+++ b/lib/gdi/fb.h
@@ -0,0 +1,43 @@
+#ifndef __FB_H
+#define __FB_H
+
+#include <linux/fb.h>
+#include <lib/base/eerror.h>
+
+class fbClass
+{
+ int fd;
+ unsigned int xRes, yRes, stride, bpp;
+ int available;
+ struct fb_var_screeninfo screeninfo, oldscreen;
+ fb_cmap cmap;
+ __u16 red[256], green[256], blue[256], trans[256];
+ static fbClass *instance;
+
+ int locked;
+public:
+ unsigned char *lfb;
+ int showConsole(int state);
+ int SetMode(unsigned int xRes, unsigned int yRes, unsigned int bpp);
+ int Available() { return available; }
+ unsigned int Stride() { return stride; }
+ fb_cmap *CMAP() { return &cmap; }
+
+ fbClass(const char *fb="/dev/fb/0");
+ ~fbClass();
+
+ static fbClass *getInstance();
+
+ // low level gfx stuff
+ int PutCMAP();
+
+ // gfx stuff (colors are 8bit!)
+ void Box(int x, int y, int width, int height, int color, int backcolor=0);
+ void NBox(int x, int y, int width, int height, int color);
+ void VLine(int x, int y, int sy, int color);
+
+ int lock();
+ void unlock();
+};
+
+#endif
diff --git a/lib/gdi/font.cpp b/lib/gdi/font.cpp
new file mode 100644
index 00000000..e7a0074f
--- /dev/null
+++ b/lib/gdi/font.cpp
@@ -0,0 +1,855 @@
+#include <lib/gdi/font.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+// use this for init Freetype...
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include <lib/base/eerror.h>
+#include <lib/gdi/lcd.h>
+#include <lib/gdi/grc.h>
+#include <lib/base/elock.h>
+#include <lib/base/init.h>
+#include <lib/base/init_num.h>
+
+//#define HAVE_FRIBIDI
+// until we have it in the cdk
+
+#ifdef HAVE_FRIBIDI
+#include <fribidi/fribidi.h>
+#endif
+
+#include <map>
+
+fontRenderClass *fontRenderClass::instance;
+
+static pthread_mutex_t ftlock=PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
+static pthread_mutex_t refcntlck=PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
+
+static FTC_Font cache_current_font=0;
+
+struct fntColorCacheKey
+{
+ gRGB start, end;
+ fntColorCacheKey(const gRGB &start, const gRGB &end)
+ : start(start), end(end)
+ {
+ }
+ bool operator <(const fntColorCacheKey &c) const
+ {
+ if (start < c.start)
+ return 1;
+ else if (start == c.start)
+ return end < c.end;
+ return 0;
+ }
+};
+
+std::map<fntColorCacheKey,gLookup> colorcache;
+
+static gLookup &getColor(const gPalette &pal, const gRGB &start, const gRGB &end)
+{
+ fntColorCacheKey key(start, end);
+ std::map<fntColorCacheKey,gLookup>::iterator i=colorcache.find(key);
+ if (i != colorcache.end())
+ return i->second;
+ gLookup &n=colorcache.insert(std::pair<fntColorCacheKey,gLookup>(key,gLookup())).first->second;
+ eDebug("[FONT] creating new font color cache entry %02x%02x%02x%02x .. %02x%02x%02x%02x", start.a, start.r, start.g, start.b,
+ end.a, end.r, end.g, end.b);
+ n.build(16, pal, start, end);
+/* for (int i=0; i<16; i++)
+ 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);
+ eDebug("");*/
+ return n;
+}
+
+fontRenderClass *fontRenderClass::getInstance()
+{
+ return instance;
+}
+
+FT_Error myFTC_Face_Requester(FTC_FaceID face_id,
+ FT_Library library,
+ FT_Pointer request_data,
+ FT_Face* aface)
+{
+ return ((fontRenderClass*)request_data)->FTC_Face_Requester(face_id, aface);
+}
+
+
+FT_Error fontRenderClass::FTC_Face_Requester(FTC_FaceID face_id, FT_Face* aface)
+{
+ fontListEntry *font=(fontListEntry *)face_id;
+ if (!font)
+ return -1;
+
+// eDebug("[FONT] FTC_Face_Requester (%s)", font->face.c_str());
+
+ int error;
+ if ((error=FT_New_Face(library, font->filename.c_str(), 0, aface)))
+ {
+ eDebug(" failed: %s", strerror(error));
+ return error;
+ }
+ FT_Select_Charmap(*aface, ft_encoding_unicode);
+ return 0;
+}
+
+FTC_FaceID fontRenderClass::getFaceID(const eString &face)
+{
+ for (fontListEntry *f=font; f; f=f->next)
+ {
+ if (f->face == face)
+ return (FTC_FaceID)f;
+ }
+ return 0;
+}
+
+FT_Error fontRenderClass::getGlyphBitmap(FTC_Image_Desc *font, FT_ULong glyph_index, FTC_SBit *sbit)
+{
+ FT_Error res=FTC_SBit_Cache_Lookup(sbitsCache, font, glyph_index, sbit);
+ return res;
+}
+
+eString fontRenderClass::AddFont(const eString &filename, const eString &name, int scale)
+{
+ eDebugNoNewLine("[FONT] adding font %s...", filename.c_str());
+ fflush(stdout);
+ int error;
+ fontListEntry *n=new fontListEntry;
+
+ n->scale=scale;
+ FT_Face face;
+ singleLock s(ftlock);
+
+ if ((error=FT_New_Face(library, filename.c_str(), 0, &face)))
+ eFatal(" failed: %s", strerror(error));
+
+ n->filename=filename;
+ n->face=name;
+ FT_Done_Face(face);
+
+ n->next=font;
+ eDebug("OK (%s)", n->face.c_str());
+ font=n;
+
+ return n->face;
+}
+
+fontRenderClass::fontListEntry::~fontListEntry()
+{
+}
+
+fontRenderClass::fontRenderClass(): fb(fbClass::getInstance())
+{
+ instance=this;
+ eDebug("[FONT] initializing lib...");
+ {
+ if (FT_Init_FreeType(&library))
+ {
+ eDebug("[FONT] initializing failed.");
+ return;
+ }
+ }
+ eDebug("[FONT] loading fonts...");
+ fflush(stdout);
+ font=0;
+
+ int maxbytes=4*1024*1024;
+ eDebug("[FONT] Intializing font cache, using max. %dMB...", maxbytes/1024/1024);
+ fflush(stdout);
+ {
+ if (FTC_Manager_New(library, 8, 8, maxbytes, myFTC_Face_Requester, this, &cacheManager))
+ {
+ eDebug("[FONT] initializing font cache failed!");
+ return;
+ }
+ if (!cacheManager)
+ {
+ eDebug("[FONT] initializing font cache manager error.");
+ return;
+ }
+ if (FTC_SBit_Cache_New(cacheManager, &sbitsCache))
+ {
+ eDebug("[FONT] initializing font cache sbit failed!");
+ return;
+ }
+ if (FTC_Image_Cache_New(cacheManager, &imageCache))
+ {
+ eDebug("[FONT] initializing font cache imagecache failed!");
+ }
+ }
+ return;
+}
+
+float fontRenderClass::getLineHeight(const gFont& font)
+{
+ if (!instance)
+ return 0;
+ Font *fnt = getFont( font.family.c_str(), font.pointSize);
+ if (!fnt)
+ return 0;
+ singleLock s(ftlock);
+ FT_Face current_face;
+ if (FTC_Manager_Lookup_Size(cacheManager, &fnt->font.font, &current_face, &fnt->size)<0)
+ {
+ eDebug("FTC_Manager_Lookup_Size failed!");
+ return 0;
+ }
+ int linegap=current_face->size->metrics.height-(current_face->size->metrics.ascender+current_face->size->metrics.descender);
+ float height=(current_face->size->metrics.ascender+current_face->size->metrics.descender+linegap/2.0)/64;
+ delete fnt;
+ return height;
+}
+
+
+fontRenderClass::~fontRenderClass()
+{
+ singleLock s(ftlock);
+// auskommentiert weil freetype und enigma die kritische masse des suckens ueberschreiten.
+// FTC_Manager_Done(cacheManager);
+// FT_Done_FreeType(library);
+}
+
+Font *fontRenderClass::getFont(const eString &face, int size, int tabwidth)
+{
+ FTC_FaceID id=getFaceID(face);
+ if (!id)
+ return 0;
+ return new Font(this, id, size * ((fontListEntry*)id)->scale / 100, tabwidth);
+}
+
+Font::Font(fontRenderClass *render, FTC_FaceID faceid, int isize, int tw): tabwidth(tw)
+{
+ renderer=render;
+ font.font.face_id=faceid;
+ font.font.pix_width = isize;
+ font.font.pix_height = isize;
+ font.image_type = ftc_image_grays;
+ height=isize;
+ if (tabwidth==-1)
+ tabwidth=8*isize;
+ ref=0;
+// font.image_type |= ftc_image_flag_autohinted;
+}
+
+FT_Error Font::getGlyphBitmap(FT_ULong glyph_index, FTC_SBit *sbit)
+{
+ return renderer->getGlyphBitmap(&font, glyph_index, sbit);
+}
+
+Font::~Font()
+{
+}
+
+void Font::lock()
+{
+ ref++;
+}
+
+void Font::unlock()
+{
+ ref--;
+ if (!ref)
+ delete this;
+}
+
+int eTextPara::appendGlyph(Font *current_font, FT_Face current_face, FT_UInt glyphIndex, int flags, int rflags)
+{
+ FTC_SBit glyph;
+ if (current_font->getGlyphBitmap(glyphIndex, &glyph))
+ return 1;
+
+ int nx=cursor.x();
+
+ nx+=glyph->xadvance;
+
+ if (
+ (rflags&RS_WRAP) &&
+ (nx >= area.right())
+ )
+ {
+ int cnt = 0;
+ glyphString::iterator i(glyphs.end());
+ --i;
+ while (i != glyphs.begin())
+ {
+ if (i->flags&(GS_ISSPACE|GS_ISFIRST))
+ break;
+ cnt++;
+ --i;
+ }
+ if (i != glyphs.begin() && ((i->flags&(GS_ISSPACE|GS_ISFIRST))==GS_ISSPACE) && (++i != glyphs.end())) // skip space
+ {
+ int linelength=cursor.x()-i->x;
+ i->flags|=GS_ISFIRST;
+ ePoint offset=ePoint(i->x, i->y);
+ newLine(rflags);
+ offset-=cursor;
+ while (i != glyphs.end()) // rearrange them into the next line
+ {
+ i->x-=offset.x();
+ i->y-=offset.y();
+ i->bbox.moveBy(-offset.x(), -offset.y());
+ ++i;
+ }
+ cursor+=ePoint(linelength, 0); // put the cursor after that line
+ } else
+ {
+ if (cnt)
+ {
+ newLine(rflags);
+ flags|=GS_ISFIRST;
+ }
+ }
+ }
+
+ int xadvance=glyph->xadvance, kern=0;
+
+ if (previous && use_kerning)
+ {
+ FT_Vector delta;
+ FT_Get_Kerning(current_face, previous, glyphIndex, ft_kerning_default, &delta);
+ kern=delta.x>>6;
+ }
+
+ pGlyph ng;
+
+ ng.bbox.setLeft( (flags&GS_ISFIRST|glyphs.empty()?cursor.x():cursor.x()-1) + glyph->left );
+ ng.bbox.setTop( cursor.y() - glyph->top );
+ ng.bbox.setWidth( glyph->width );
+ ng.bbox.setHeight( glyph->height );
+
+ xadvance+=kern;
+
+ ng.x=cursor.x()+kern;
+
+ ng.y=cursor.y();
+ ng.w=xadvance;
+ ng.font=current_font;
+ ng.font->lock();
+ ng.glyph_index=glyphIndex;
+ ng.flags=flags;
+ glyphs.push_back(ng);
+
+ cursor+=ePoint(xadvance, 0);
+ previous=glyphIndex;
+ return 0;
+}
+
+void eTextPara::calc_bbox()
+{
+ boundBox.setLeft( 32000 );
+ boundBox.setTop( 32000 );
+ boundBox.setRight( -32000 ); // for each glyph image, compute its bounding box, translate it,
+ boundBox.setBottom( -32000 );
+ // and grow the string bbox
+
+ for ( glyphString::iterator i(glyphs.begin()); i != glyphs.end(); ++i)
+ {
+ if ( i->bbox.left() < boundBox.left() )
+ boundBox.setLeft( i->bbox.left() );
+ if ( i->bbox.top() < boundBox.top() )
+ boundBox.setTop( i->bbox.top() );
+ if ( i->bbox.right() > boundBox.right() )
+ boundBox.setRight( i->bbox.right() );
+ if ( i->bbox.bottom() > boundBox.bottom() )
+ boundBox.setBottom( i->bbox.bottom() );
+ }
+// eDebug("boundBox left = %i, top = %i, right = %i, bottom = %i", boundBox.left(), boundBox.top(), boundBox.right(), boundBox.bottom() );
+ bboxValid=1;
+}
+
+void eTextPara::newLine(int flags)
+{
+ if (maximum.width()<cursor.x())
+ maximum.setWidth(cursor.x());
+ cursor.setX(left);
+ previous=0;
+ int linegap=current_face->size->metrics.height-(current_face->size->metrics.ascender+current_face->size->metrics.descender);
+ cursor+=ePoint(0, (current_face->size->metrics.ascender+current_face->size->metrics.descender+linegap*1/2)>>6);
+ if (maximum.height()<cursor.y())
+ maximum.setHeight(cursor.y());
+ previous=0;
+}
+
+eTextPara::~eTextPara()
+{
+ clear();
+ if (refcnt>=0)
+ eFatal("verdammt man der war noch gelockt :/\n");
+}
+
+void eTextPara::destroy()
+{
+ singleLock s(refcntlck);
+
+ if (!refcnt--)
+ delete this;
+}
+
+eTextPara *eTextPara::grab()
+{
+ singleLock s(refcntlck);
+
+ refcnt++;
+ return this;
+}
+
+void eTextPara::setFont(const gFont &font)
+{
+ if (refcnt)
+ eFatal("mod. after lock");
+ Font *fnt=fontRenderClass::getInstance()->getFont(font.family.c_str(), font.pointSize);
+ if (!fnt)
+ eWarning("FONT '%s' MISSING!", font.family.c_str());
+ setFont(fnt,
+ fontRenderClass::getInstance()->getFont(replacement_facename.c_str(), font.pointSize));
+}
+
+eString eTextPara::replacement_facename;
+
+void eTextPara::setFont(Font *fnt, Font *replacement)
+{
+ if (refcnt)
+ eFatal("mod. after lock");
+ if (!fnt)
+ return;
+ if (current_font && !current_font->ref)
+ delete current_font;
+ current_font=fnt;
+ replacement_font=replacement;
+ singleLock s(ftlock);
+
+ // we ask for replacment_font first becauseof the cache
+ if (replacement_font)
+ {
+ if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager,
+ &replacement_font->font.font, &replacement_face,
+ &replacement_font->size)<0)
+ {
+ eDebug("FTC_Manager_Lookup_Size failed!");
+ return;
+ }
+ }
+ if (current_font)
+ {
+ if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, &current_font->font.font, &current_face, &current_font->size)<0)
+ {
+ eDebug("FTC_Manager_Lookup_Size failed!");
+ return;
+ }
+ }
+ cache_current_font=&current_font->font.font;
+ previous=0;
+ use_kerning=FT_HAS_KERNING(current_face);
+}
+
+void
+shape (std::vector<unsigned long> &string, const std::vector<unsigned long> &text);
+
+int eTextPara::renderString(const eString &string, int rflags)
+{
+ singleLock s(ftlock);
+
+ if (refcnt)
+ eFatal("mod. after lock");
+
+ if (!current_font)
+ return -1;
+
+ if (cursor.y()==-1)
+ {
+ cursor=ePoint(area.x(), area.y()+(current_face->size->metrics.ascender>>6));
+ left=cursor.x();
+ }
+
+ if (&current_font->font.font != cache_current_font)
+ {
+ if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, &current_font->font.font, &current_face, &current_font->size)<0)
+ {
+ eDebug("FTC_Manager_Lookup_Size failed!");
+ return -1;
+ }
+ cache_current_font=&current_font->font.font;
+ }
+
+ std::vector<unsigned long> uc_string, uc_visual;
+ uc_string.reserve(string.length());
+
+ std::string::const_iterator p(string.begin());
+
+ while(p != string.end())
+ {
+ unsigned int unicode=*p++;
+
+ if (unicode & 0x80) // we have (hopefully) UTF8 here, and we assume that the encoding is VALID
+ {
+ if ((unicode & 0xE0)==0xC0) // two bytes
+ {
+ unicode&=0x1F;
+ unicode<<=6;
+ if (p != string.end())
+ unicode|=(*p++)&0x3F;
+ } else if ((unicode & 0xF0)==0xE0) // three bytes
+ {
+ unicode&=0x0F;
+ unicode<<=6;
+ if (p != string.end())
+ unicode|=(*p++)&0x3F;
+ unicode<<=6;
+ if (p != string.end())
+ unicode|=(*p++)&0x3F;
+ } else if ((unicode & 0xF8)==0xF0) // four bytes
+ {
+ unicode&=0x07;
+ unicode<<=6;
+ if (p != string.end())
+ unicode|=(*p++)&0x3F;
+ unicode<<=6;
+ if (p != string.end())
+ unicode|=(*p++)&0x3F;
+ unicode<<=6;
+ if (p != string.end())
+ unicode|=(*p++)&0x3F;
+ }
+ }
+ uc_string.push_back(unicode);
+ }
+
+ std::vector<unsigned long> uc_shape;
+
+ // character -> glyph conversion
+ shape(uc_shape, uc_string);
+
+ // now do the usual logical->visual reordering
+#ifdef HAVE_FRIBIDI
+ FriBidiCharType dir=FRIBIDI_TYPE_ON;
+ {
+ int size=uc_shape.size();
+ uc_visual.resize(size);
+ // gaaanz lahm, aber anders geht das leider nicht, sorry.
+ FriBidiChar array[size], target[size];
+ std::copy(uc_shape.begin(), uc_shape.end(), array);
+ fribidi_log2vis(array, size, &dir, target, 0, 0, 0);
+ uc_visual.assign(target, target+size);
+ }
+#else
+ uc_visual=uc_shape;
+#endif
+
+ glyphs.reserve(uc_visual.size());
+
+ for (std::vector<unsigned long>::const_iterator i(uc_visual.begin());
+ i != uc_visual.end(); ++i)
+ {
+ int isprintable=1;
+ int flags=0;
+ if (!(rflags&RS_DIRECT))
+ {
+ switch (*i)
+ {
+ case '\\':
+ {
+ unsigned long c = *(i+1);
+ switch (c)
+ {
+ case 'n':
+ i++;
+ goto newline;
+ case 't':
+ i++;
+ goto tab;
+ case 'r':
+ i++;
+ goto nprint;
+ default:
+ ;
+ }
+ break;
+ }
+ case '\t':
+tab: isprintable=0;
+ cursor+=ePoint(current_font->tabwidth, 0);
+ cursor-=ePoint(cursor.x()%current_font->tabwidth, 0);
+ break;
+ case 0x8A:
+ case 0xE08A:
+ case '\n':
+newline:isprintable=0;
+ newLine(rflags);
+ flags|=GS_ISFIRST;
+ break;
+ case '\r':
+ case 0x86: case 0xE086:
+ case 0x87: case 0xE087:
+nprint: isprintable=0;
+ break;
+ case ' ':
+ flags|=GS_ISSPACE;
+ default:
+ break;
+ }
+ }
+ if (isprintable)
+ {
+ FT_UInt index;
+
+ index=(rflags&RS_DIRECT)? *i : FT_Get_Char_Index(current_face, *i);
+
+ if (!index)
+ {
+ if (replacement_face)
+ index=(rflags&RS_DIRECT)? *i : FT_Get_Char_Index(replacement_face, *i);
+
+ if (!index)
+ eDebug("unicode %d ('%c') not present", *i, *i);
+ else
+ appendGlyph(replacement_font, replacement_face, index, flags, rflags);
+ } else
+ appendGlyph(current_font, current_face, index, flags, rflags);
+ }
+ }
+ bboxValid=false;
+ calc_bbox();
+#ifdef HAVE_FRIBIDI
+ if (dir & FRIBIDI_MASK_RTL)
+ realign(dirRight);
+#endif
+ return 0;
+}
+
+void eTextPara::blit(gPixmapDC &dc, const ePoint &offset, const gRGB &background, const gRGB &foreground)
+{
+ singleLock s(ftlock);
+
+ if (!current_font)
+ return;
+
+ if (&current_font->font.font != cache_current_font)
+ {
+ if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, &current_font->font.font, &current_face, &current_font->size)<0)
+ {
+ eDebug("FTC_Manager_Lookup_Size failed!");
+ return;
+ }
+ cache_current_font=&current_font->font.font;
+ }
+
+ ePtr<gPixmap> target;
+ dc.getPixmap(target);
+
+ register int opcode;
+ gColor *lookup8=0;
+ __u32 lookup32[16];
+
+ if (target->bpp == 8)
+ {
+ if (target->clut.data)
+ {
+ lookup8=getColor(target->clut, background, foreground).lookup;
+ opcode=0;
+ } else
+ opcode=1;
+ } else if (target->bpp == 32)
+ {
+ opcode=3;
+ if (target->clut.data)
+ {
+ lookup8=getColor(target->clut, background, foreground).lookup;
+ for (int i=0; i<16; ++i)
+ lookup32[i]=((target->clut.data[lookup8[i]].a<<24)|
+ (target->clut.data[lookup8[i]].r<<16)|
+ (target->clut.data[lookup8[i]].g<<8)|
+ (target->clut.data[lookup8[i]].b))^0xFF000000;
+ } else
+ {
+ for (int i=0; i<16; ++i)
+ lookup32[i]=(0x010101*i)|0xFF000000;
+ }
+ } else
+ {
+ eWarning("can't render to %dbpp", target->bpp);
+ return;
+ }
+
+ eRect clip(0, 0, target->x, target->y);
+ clip&=dc.getClip();
+
+ int buffer_stride=target->stride;
+
+ for (glyphString::iterator i(glyphs.begin()); i != glyphs.end(); ++i)
+ {
+ static FTC_SBit glyph_bitmap;
+ if (fontRenderClass::instance->getGlyphBitmap(&i->font->font, i->glyph_index, &glyph_bitmap))
+ continue;
+ int rx=i->x+glyph_bitmap->left + offset.x();
+ int ry=i->y-glyph_bitmap->top + offset.y();
+ __u8 *d=(__u8*)(target->data)+buffer_stride*ry+rx*target->bypp;
+ __u8 *s=glyph_bitmap->buffer;
+ register int sx=glyph_bitmap->width;
+ int sy=glyph_bitmap->height;
+ if ((sy+ry) >= clip.bottom())
+ sy=clip.bottom()-ry;
+ if ((sx+rx) >= clip.right())
+ sx=clip.right()-rx;
+ if (rx < clip.left())
+ {
+ int diff=clip.left()-rx;
+ s+=diff;
+ sx-=diff;
+ rx+=diff;
+ d+=diff*target->bypp;
+ }
+ if (ry < clip.top())
+ {
+ int diff=clip.top()-ry;
+ s+=diff*glyph_bitmap->pitch;
+ sy-=diff;
+ ry+=diff;
+ d+=diff*buffer_stride;
+ }
+ if (sx>0)
+ for (int ay=0; ay<sy; ay++)
+ {
+ if (!opcode) // 4bit lookup to 8bit
+ {
+ register __u8 *td=d;
+ register int ax;
+ for (ax=0; ax<sx; ax++)
+ {
+ register int b=(*s++)>>4;
+ if(b)
+ *td++=lookup8[b];
+ else
+ td++;
+ }
+ } else if (opcode == 1) // 8bit direct
+ {
+ register __u8 *td=d;
+ register int ax;
+ for (ax=0; ax<sx; ax++)
+ {
+ register int b=*s++;
+ *td++^=b;
+ }
+ } else
+ {
+ register __u32 *td=(__u32*)d;
+ register int ax;
+ for (ax=0; ax<sx; ax++)
+ {
+ register int b=(*s++)>>4;
+ if(b)
+ *td++=lookup32[b];
+ else
+ td++;
+ }
+ }
+ s+=glyph_bitmap->pitch-sx;
+ d+=buffer_stride;
+ }
+ }
+}
+
+void eTextPara::realign(int dir) // der code hier ist ein wenig merkwuerdig.
+{
+ glyphString::iterator begin(glyphs.begin()), c(glyphs.begin()), end(glyphs.begin()), last;
+ if (dir==dirLeft)
+ return;
+ while (c != glyphs.end())
+ {
+ int linelength=0;
+ int numspaces=0, num=0;
+ begin=end;
+
+ ASSERT( end != glyphs.end());
+
+ // zeilenende suchen
+ do {
+ last=end;
+ ++end;
+ } while ((end != glyphs.end()) && (!(end->flags&GS_ISFIRST)));
+ // end zeigt jetzt auf begin der naechsten zeile
+
+ for (c=begin; c!=end; ++c)
+ {
+ // space am zeilenende skippen
+ if ((c==last) && (c->flags&GS_ISSPACE))
+ continue;
+
+ if (c->flags&GS_ISSPACE)
+ numspaces++;
+ linelength+=c->w;
+ num++;
+ }
+ if (!num) // line mit nur einem space
+ continue;
+
+ switch (dir)
+ {
+ case dirRight:
+ case dirCenter:
+ {
+ int offset=area.width()-linelength;
+ if (dir==dirCenter)
+ offset/=2;
+ offset+=area.left();
+ while (begin != end)
+ {
+ begin->bbox.moveBy(offset-begin->x,0);
+ begin->x=offset;
+ offset+=begin->w;
+ ++begin;
+ }
+ break;
+ }
+ case dirBlock:
+ {
+ if (end == glyphs.end()) // letzte zeile linksbuendig lassen
+ continue;
+ int spacemode;
+ if (numspaces)
+ spacemode=1;
+ else
+ spacemode=0;
+ if ((!spacemode) && (num<2))
+ break;
+ int off=(area.width()-linelength)*256/(spacemode?numspaces:(num-1));
+ int curoff=0;
+ while (begin != end)
+ {
+ int doadd=0;
+ if ((!spacemode) || (begin->flags&GS_ISSPACE))
+ doadd=1;
+ begin->x+=curoff>>8;
+ begin->bbox.moveBy(curoff>>8,0);
+ if (doadd)
+ curoff+=off;
+ ++begin;
+ }
+ break;
+ }
+ }
+ }
+ bboxValid=false;
+ calc_bbox();
+}
+
+void eTextPara::clear()
+{
+ singleLock s(ftlock);
+
+ for (glyphString::iterator i(glyphs.begin()); i!=glyphs.end(); ++i)
+ i->font->unlock();
+
+ glyphs.clear();
+}
+
+eAutoInitP0<fontRenderClass> init_fontRenderClass(eAutoInitNumbers::graphic-1, "Font Render Class");
diff --git a/lib/gdi/font.cpp-new b/lib/gdi/font.cpp-new
new file mode 100644
index 00000000..e9aa5430
--- /dev/null
+++ b/lib/gdi/font.cpp-new
@@ -0,0 +1,787 @@
+#include <lib/gdi/font.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+// use this for init Freetype...
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include <lib/base/eerror.h>
+#include <lib/gdi/lcd.h>
+#include <lib/gdi/grc.h>
+#include <lib/base/elock.h>
+#include <lib/base/init.h>
+
+#include <map>
+
+fontRenderClass *fontRenderClass::instance;
+static eLock ftlock;
+static FTC_Font cache_current_font=0;
+
+struct fntColorCacheKey
+{
+ gRGB start, end;
+ fntColorCacheKey(const gRGB &start, const gRGB &end)
+ : start(start), end(end)
+ {
+ }
+ bool operator <(const fntColorCacheKey &c) const
+ {
+ if (start < c.start)
+ return 1;
+ else if (start == c.start)
+ return end < c.end;
+ return 0;
+ }
+};
+
+std::map<fntColorCacheKey,gLookup> colorcache;
+
+static gLookup &getColor(const gPalette &pal, const gRGB &start, const gRGB &end)
+{
+ fntColorCacheKey key(start, end);
+ std::map<fntColorCacheKey,gLookup>::iterator i=colorcache.find(key);
+ if (i != colorcache.end())
+ return i->second;
+ gLookup &n=colorcache.insert(std::pair<fntColorCacheKey,gLookup>(key,gLookup())).first->second;
+ eDebug("[FONT] creating new font color cache entry %02x%02x%02x%02x .. %02x%02x%02x%02x", start.a, start.r, start.g, start.b,
+ end.a, end.r, end.g, end.b);
+ n.build(16, pal, start, end);
+/* for (int i=0; i<16; i++)
+ 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);
+ eDebug("");*/
+ return n;
+}
+
+fontRenderClass *fontRenderClass::getInstance()
+{
+ return instance;
+}
+
+FT_Error myFTC_Face_Requester(FTC_FaceID face_id,
+ FT_Library library,
+ FT_Pointer request_data,
+ FT_Face* aface)
+{
+ return ((fontRenderClass*)request_data)->FTC_Face_Requester(face_id, aface);
+}
+
+
+FT_Error fontRenderClass::FTC_Face_Requester(FTC_FaceID face_id, FT_Face* aface)
+{
+ fontListEntry *font=(fontListEntry *)face_id;
+ if (!font)
+ return -1;
+
+ eDebug("[FONT] FTC_Face_Requester (%s)", font->face);
+
+ int error;
+ if ((error=FT_New_Face(library, font->filename, 0, aface)))
+ {
+ eDebug(" failed: %s", strerror(error));
+ return error;
+ }
+ FT_Select_Charmap(*aface, ft_encoding_unicode);
+ return 0;
+}
+
+FTC_FaceID fontRenderClass::getFaceID(const char *face)
+{
+ for (fontListEntry *f=font; f; f=f->next)
+ {
+ if (!strcmp(f->face, face))
+ return (FTC_FaceID)f;
+ }
+ return 0;
+}
+
+FT_Error fontRenderClass::getGlyphBitmap(FTC_ImageTypeRec *font, FT_ULong glyph_index, FTC_SBit *sbit)
+{
+ FT_Error res=FTC_SBitCache_Lookup(sbitsCache, font, glyph_index, sbit, 0);
+ eDebug("%x", sizeof(**sbit));
+ return res;
+}
+
+const char* fontRenderClass::AddFont(const char *filename)
+{
+ eDebugNoNewLine("[FONT] adding font %s...", filename);
+ fflush(stdout);
+ int error;
+ fontListEntry *n=new fontListEntry;
+
+ FT_Face face;
+ eLocker lock(ftlock);
+
+ if ((error=FT_New_Face(library, filename, 0, &face)))
+ eFatal(" failed: %s", strerror(error));
+
+ strcpy(n->filename=new char[strlen(filename)+1], filename);
+ strcpy(n->face=new char[strlen(face->family_name)+strlen(face->style_name)+2], face->family_name);
+ if (face->style_name[0]!=' ')
+ strcat(n->face, " ");
+ strcat(n->face, face->style_name);
+ FT_Done_Face(face);
+
+ n->next=font;
+ eDebug("OK (%s)", n->face);
+ font=n;
+
+ return n->face;
+}
+
+fontRenderClass::fontListEntry::~fontListEntry()
+{
+ delete[] filename;
+ delete[] face;
+}
+
+fontRenderClass::fontRenderClass(): fb(fbClass::getInstance())
+{
+ instance=this;
+ eDebug("[FONT] initializing lib...");
+ {
+ if (FT_Init_FreeType(&library))
+ {
+ eDebug("[FONT] initializing failed.");
+ return;
+ }
+ }
+ eDebug("[FONT] loading fonts...");
+ fflush(stdout);
+ font=0;
+
+ int maxbytes=4*1024*1024;
+ eDebug("[FONT] Intializing font cache, using max. %dMB...", maxbytes/1024/1024);
+ fflush(stdout);
+ {
+ if (FTC_Manager_New(library, 8, 8, maxbytes, myFTC_Face_Requester, this, &cacheManager))
+ {
+ eDebug("[FONT] initializing font cache failed!");
+ return;
+ }
+ if (!cacheManager)
+ {
+ eDebug("[FONT] initializing font cache manager error.");
+ return;
+ }
+ if (FTC_SBitCache_New(cacheManager, &sbitsCache))
+ {
+ eDebug("[FONT] initializing font cache sbit failed!");
+ return;
+ }
+/* if (FTC_ImageCache_New(cacheManager, &imageCache))
+ {
+ eDebug("[FONT] initializing font cache imagecache failed!");
+ } */
+ }
+ return;
+}
+
+fontRenderClass::~fontRenderClass()
+{
+ ftlock.lock();
+// auskommentiert weil freetype und enigma die kritische masse des suckens ueberschreiten.
+// FTC_Manager_Done(cacheManager);
+// FT_Done_FreeType(library);
+}
+
+Font *fontRenderClass::getFont(const char *face, int size, int tabwidth)
+{
+ FTC_FaceID id=getFaceID(face);
+ if (!id)
+ eDebug("face %s does not exist!", face);
+ if (!id)
+ return 0;
+ return new Font(this, id, size, tabwidth);
+}
+
+Font::Font(fontRenderClass *render, FTC_FaceID faceid, int isize, int tw): tabwidth(tw)
+{
+ renderer=render;
+ font.font.face_id=faceid;
+ font.font.pix_width = isize;
+ font.font.pix_height = isize;
+ font.flags = FT_LOAD_DEFAULT;
+ height=isize;
+ if (tabwidth==-1)
+ tabwidth=8*isize;
+ ref=0;
+}
+
+FT_Error Font::getGlyphBitmap(FT_ULong glyph_index, FTC_SBit *sbit)
+{
+ return renderer->getGlyphBitmap(&font, glyph_index, sbit);
+}
+
+Font::~Font()
+{
+}
+
+void Font::lock()
+{
+ ref++;
+}
+
+void Font::unlock()
+{
+ ref--;
+ if (!ref)
+ delete this;
+}
+
+int eTextPara::appendGlyph(FT_UInt glyphIndex, int flags, int rflags)
+{
+ FTC_SBit glyph;
+ if (current_font->getGlyphBitmap(glyphIndex, &glyph))
+ return 1;
+
+ int nx=cursor.x();
+
+ if (! (rflags & RS_RTL))
+ nx+=glyph->xadvance;
+ else
+ {
+ eDebug("RTL: glyph->xadvance: %d", glyph->xadvance);
+ nx-=glyph->xadvance;
+ }
+
+ if (
+ (rflags&RS_WRAP) &&
+ (
+ (!(rflags & RS_RTL))
+ ?
+ (nx >= area.right()) :
+ (nx < area.left())
+ )
+ )
+ {
+ int cnt = 0;
+ glyphString::iterator i(glyphs.end());
+ --i;
+ while (i != glyphs.begin())
+ {
+ if (i->flags&(GS_ISSPACE|GS_ISFIRST))
+ break;
+ cnt++;
+ --i;
+ }
+ if (i != glyphs.begin() && ((i->flags&(GS_ISSPACE|GS_ISFIRST))==GS_ISSPACE) && (++i != glyphs.end())) // skip space
+ {
+ int linelength=cursor.x()-i->x;
+ // RTL: linelength is negative
+ i->flags|=GS_ISFIRST;
+ ePoint offset=ePoint(i->x, i->y);
+ newLine(rflags);
+ offset-=cursor;
+ while (i != glyphs.end()) // rearrange them into the next line
+ {
+ i->x-=offset.x();
+ i->y-=offset.y();
+ i->bbox->moveBy(-offset.x(), -offset.y());
+ ++i;
+ }
+ cursor+=ePoint(linelength, 0); // put the cursor after that line
+ } else
+ {
+ if (cnt)
+ {
+ newLine(rflags);
+ flags|=GS_ISFIRST;
+ }
+ }
+ }
+
+ int xadvance=glyph->xadvance, kern=0;
+
+ if (previous && use_kerning)
+ {
+ FT_Vector delta;
+ FT_Get_Kerning(current_face, previous, glyphIndex, ft_kerning_default, &delta);
+ kern=delta.x>>6;
+ }
+
+ eRect* bbox = new eRect();
+ bbox->setLeft( (flags&GS_ISFIRST|glyphs.empty()?cursor.x():cursor.x()-1) + glyph->left );
+ bbox->setTop( cursor.y() - glyph->top );
+ bbox->setWidth( glyph->width );
+ bbox->setHeight( glyph->height );
+
+ pGlyph ng;
+
+ xadvance+=kern;
+
+ if (!(rflags & RS_RTL))
+ ng.x=cursor.x()+kern;
+ else
+ ng.x=cursor.x()-xadvance;
+
+ ng.y=cursor.y();
+ ng.w=xadvance;
+ ng.font=current_font;
+ ng.font->lock();
+ ng.glyph_index=glyphIndex;
+ ng.flags=flags;
+ ng.bbox=bbox;
+ glyphs.push_back(ng);
+
+ if (!(rflags & RS_RTL))
+ cursor+=ePoint(xadvance, 0);
+ else
+ cursor-=ePoint(xadvance, 0);
+ previous=glyphIndex;
+ return 0;
+}
+
+void eTextPara::calc_bbox()
+{
+ boundBox.setLeft( 32000 );
+ boundBox.setTop( 32000 );
+ boundBox.setRight( -32000 ); // for each glyph image, compute its bounding box, translate it,
+ boundBox.setBottom( -32000 );
+ // and grow the string bbox
+
+ for ( glyphString::iterator i(glyphs.begin()); i != glyphs.end(); ++i)
+ {
+ if ( i->bbox->left() < boundBox.left() )
+ boundBox.setLeft( i->bbox->left() );
+ if ( i->bbox->top() < boundBox.top() )
+ boundBox.setTop( i->bbox->top() );
+ if ( i->bbox->right() > boundBox.right() )
+ boundBox.setRight( i->bbox->right() );
+ if ( i->bbox->bottom() > boundBox.bottom() )
+ boundBox.setBottom( i->bbox->bottom() );
+ }
+// eDebug("boundBox left = %i, top = %i, right = %i, bottom = %i", boundBox.left(), boundBox.top(), boundBox.right(), boundBox.bottom() );
+ bboxValid=1;
+}
+
+void eTextPara::newLine(int flags)
+{
+ if (!(flags & RS_RTL))
+ {
+ if (maximum.width()<cursor.x())
+ maximum.setWidth(cursor.x());
+ cursor.setX(left);
+ previous=0;
+ } else
+ {
+ if (maximum.width()<(area.right()-cursor.x()))
+ maximum.setWidth(area.right()-cursor.x());
+ cursor.setX(area.right());
+ }
+ int linegap=current_face->size->metrics.height-(current_face->size->metrics.ascender+current_face->size->metrics.descender);
+ cursor+=ePoint(0, (current_face->size->metrics.ascender+current_face->size->metrics.descender+linegap*1/2)>>6);
+ if (maximum.height()<cursor.y())
+ maximum.setHeight(cursor.y());
+ previous=0;
+}
+
+static eLock refcntlck;
+
+eTextPara::~eTextPara()
+{
+ clear();
+ if (refcnt>=0)
+ eFatal("verdammt man der war noch gelockt :/\n");
+}
+
+void eTextPara::destroy()
+{
+ eLocker lock(refcntlck);
+
+ if (!refcnt--)
+ delete this;
+}
+
+eTextPara *eTextPara::grab()
+{
+ eLocker lock(refcntlck);
+
+ refcnt++;
+ return this;
+}
+
+void eTextPara::setFont(const gFont &font)
+{
+ if (refcnt)
+ eFatal("mod. after lock");
+ setFont(fontRenderClass::getInstance()->getFont(font.family.c_str(), font.pointSize));
+}
+
+void eTextPara::setFont(Font *fnt)
+{
+ if (refcnt)
+ eFatal("mod. after lock");
+ if (!fnt)
+ return;
+ if (current_font && !current_font->ref)
+ delete current_font;
+ current_font=fnt;
+ eLocker lock(ftlock);
+
+ if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, &current_font->font.font, &current_face, &current_font->size)<0)
+ {
+ eDebug("FTC_Manager_Lookup_Size failed!");
+ return;
+ }
+ cache_current_font=&current_font->font.font;
+ previous=0;
+ use_kerning=FT_HAS_KERNING(current_face);
+}
+
+int eTextPara::renderString(const eString &string, int rflags)
+{
+ eLocker lock(ftlock);
+
+ if (refcnt)
+ eFatal("mod. after lock");
+
+ if (!current_font)
+ return -1;
+
+ if (cursor.y()==-1)
+ {
+ if (!(rflags & RS_RTL))
+ {
+ cursor=ePoint(area.x(), area.y()+(current_face->size->metrics.ascender>>6));
+ } else
+ {
+ cursor=ePoint(area.right(), area.y()+(current_face->size->metrics.ascender>>6));
+ }
+ left=cursor.x();
+ }
+
+ glyphs.reserve(glyphs.size()+string.length());
+
+ if (&current_font->font.font != cache_current_font)
+ {
+ if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, &current_font->font.font, &current_face, &current_font->size)<0)
+ {
+ eDebug("FTC_Manager_Lookup_Size failed!");
+ return -1;
+ }
+ cache_current_font=&current_font->font.font;
+ }
+
+ std::string::const_iterator p(string.begin());
+
+ while(p != string.end())
+ {
+ int isprintable=1;
+ int flags=0;
+
+ unsigned int unicode=*p++;
+
+ if (unicode & 0x80) // we have (hopefully) UTF8 here, and we assume that the encoding is VALID
+ {
+ if ((unicode & 0xE0)==0xC0) // two bytes
+ {
+ unicode&=0x1F;
+ unicode<<=6;
+ if (p != string.end())
+ unicode|=(*p++)&0x3F;
+ } else if ((unicode & 0xF0)==0xE0) // three bytes
+ {
+ unicode&=0x0F;
+ unicode<<=6;
+ if (p != string.end())
+ unicode|=(*p++)&0x3F;
+ unicode<<=6;
+ if (p != string.end())
+ unicode|=(*p++)&0x3F;
+ } else if ((unicode & 0xF8)==0xF0) // four bytes
+ {
+ unicode&=0x07;
+ unicode<<=6;
+ if (p != string.end())
+ unicode|=(*p++)&0x3F;
+ unicode<<=6;
+ if (p != string.end())
+ unicode|=(*p++)&0x3F;
+ unicode<<=6;
+ if (p != string.end())
+ unicode|=(*p++)&0x3F;
+ }
+ }
+
+ if (!(rflags&RS_DIRECT))
+ {
+ switch (unicode)
+ {
+ case '\t':
+ isprintable=0;
+ if (!(rflags & RS_RTL))
+ {
+ cursor+=ePoint(current_font->tabwidth, 0);
+ cursor-=ePoint(cursor.x()%current_font->tabwidth, 0);
+ } else
+ {
+ // does this work?
+ cursor-=ePoint(current_font->tabwidth, 0);
+ cursor+=ePoint(cursor.x()%current_font->tabwidth, 0);
+ }
+ break;
+ case 0x8A:
+ case 0xE08A:
+ case '\n':
+ isprintable=0;
+ newLine(rflags);
+ flags|=GS_ISFIRST;
+ break;
+ case '\r':
+ case 0x86: case 0xE086:
+ case 0x87: case 0xE087:
+ isprintable=0;
+ break;
+ case ' ':
+ flags|=GS_ISSPACE;
+ default:
+ break;
+ }
+ }
+ if (isprintable)
+ {
+ FT_UInt index;
+
+ index=(rflags&RS_DIRECT)? unicode : FT_Get_Char_Index(current_face, unicode);
+
+ if (!index)
+ eDebug("unicode %d ('%c') not present", unicode, unicode);
+ else
+ appendGlyph(index, flags, rflags);
+ }
+ }
+ bboxValid=false;
+ calc_bbox();
+ return 0;
+}
+
+void eTextPara::blit(gPixmapDC &dc, const ePoint &offset, const gRGB &background, const gRGB &foreground)
+{
+ eLocker lock(ftlock);
+
+ if (&current_font->font.font != cache_current_font)
+ {
+ if (FTC_Manager_Lookup_Size(fontRenderClass::instance->cacheManager, &current_font->font.font, &current_face, &current_font->size)<0)
+ {
+ eDebug("FTC_Manager_Lookup_Size failed!");
+ return;
+ }
+ cache_current_font=&current_font->font.font;
+ }
+
+ gPixmap &target=dc.getPixmap();
+
+ register int opcode;
+ gColor *lookup8=0;
+ __u32 lookup32[16];
+
+ if (target.bpp == 8)
+ {
+ if (target.clut.data)
+ {
+ lookup8=getColor(target.clut, background, foreground).lookup;
+ opcode=0;
+ } else
+ opcode=1;
+ } else if (target.bpp == 32)
+ {
+ opcode=3;
+ if (target.clut.data)
+ {
+ lookup8=getColor(target.clut, background, foreground).lookup;
+ for (int i=0; i<16; ++i)
+ lookup32[i]=((target.clut.data[lookup8[i]].a<<24)|
+ (target.clut.data[lookup8[i]].r<<16)|
+ (target.clut.data[lookup8[i]].g<<8)|
+ (target.clut.data[lookup8[i]].b))^0xFF000000;
+ } else
+ {
+ for (int i=0; i<16; ++i)
+ lookup32[i]=(0x010101*i)|0xFF000000;
+ }
+ } else
+ {
+ eWarning("can't render to %dbpp", target.bpp);
+ return;
+ }
+
+ eRect clip(0, 0, target.x, target.y);
+ clip&=dc.getClip();
+
+ int buffer_stride=target.stride;
+
+ for (glyphString::iterator i(glyphs.begin()); i != glyphs.end(); ++i)
+ {
+ FTC_SBit glyph_bitmap;
+ memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
+ if (fontRenderClass::instance->getGlyphBitmap(&i->font->font, i->glyph_index, &glyph_bitmap))
+ continue;
+ if (!glyph_bitmap->buffer)
+ eFatal("you suck.");
+ int rx=i->x+glyph_bitmap->left + offset.x();
+ int ry=i->y-glyph_bitmap->top + offset.y();
+ __u8 *d=(__u8*)(target.data)+buffer_stride*ry+rx*target.bypp;
+ __u8 *s=glyph_bitmap->buffer;
+ register int sx=glyph_bitmap->width;
+ int sy=glyph_bitmap->height;
+ if ((sy+ry) >= clip.bottom())
+ sy=clip.bottom()-ry;
+ if ((sx+rx) >= clip.right())
+ sx=clip.right()-rx;
+ if (rx < clip.left())
+ {
+ int diff=clip.left()-rx;
+ s+=diff;
+ sx-=diff;
+ rx+=diff;
+ d+=diff*target.bypp;
+ }
+ if (ry < clip.top())
+ {
+ int diff=clip.top()-ry;
+ s+=diff*glyph_bitmap->pitch;
+ sy-=diff;
+ ry+=diff;
+ d+=diff*buffer_stride;
+ }
+ if (sx>0)
+ for (int ay=0; ay<sy; ay++)
+ {
+ if (!opcode) // 4bit lookup to 8bit
+ {
+ register __u8 *td=d;
+ register int ax;
+ for (ax=0; ax<sx; ax++)
+ {
+ register int b=(*s++)>>4;
+ if(b)
+ *td++=lookup8[b];
+ else
+ td++;
+ }
+ } else if (opcode == 1) // 8bit direct
+ {
+ register __u8 *td=d;
+ register int ax;
+ for (ax=0; ax<sx; ax++)
+ {
+ register int b=*s++;
+ *td++^=b;
+ }
+ } else
+ {
+ register __u32 *td=(__u32*)d;
+ register int ax;
+ for (ax=0; ax<sx; ax++)
+ {
+ register int b=(*s++)>>4;
+ if(b)
+ *td++=lookup32[b];
+ else
+ td++;
+ }
+ }
+ s+=glyph_bitmap->pitch-sx;
+ d+=buffer_stride;
+ }
+ }
+}
+
+void eTextPara::realign(int dir) // der code hier ist ein wenig merkwuerdig.
+{
+ glyphString::iterator begin(glyphs.begin()), c(glyphs.begin()), end(glyphs.begin()), last;
+ if (dir==dirLeft)
+ return;
+ while (c != glyphs.end())
+ {
+ int linelength=0;
+ int numspaces=0, num=0;
+ begin=end;
+
+ // zeilenende suchen
+ do {
+ last=end;
+ ++end;
+ } while ((end != glyphs.end()) && (!(end->flags&GS_ISFIRST)));
+ // end zeigt jetzt auf begin der naechsten zeile
+
+ for (c=begin; c!=end; ++c)
+ {
+ // space am zeilenende skippen
+ if ((c==last) && (c->flags&GS_ISSPACE))
+ continue;
+
+ if (c->flags&GS_ISSPACE)
+ numspaces++;
+ linelength+=c->w;;
+ num++;
+ }
+ if (!num) // line mit nur einem space
+ continue;
+
+ switch (dir)
+ {
+ case dirRight:
+ case dirCenter:
+ {
+ int offset=area.width()-linelength;
+ if (dir==dirCenter)
+ offset/=2;
+ while (begin != end)
+ {
+ begin->x+=offset;
+ begin->bbox->moveBy(offset,0);
+ ++begin;
+ }
+ break;
+ }
+ case dirBlock:
+ {
+ if (end == glyphs.end()) // letzte zeile linksbuendig lassen
+ continue;
+ int spacemode;
+ if (numspaces)
+ spacemode=1;
+ else
+ spacemode=0;
+ if ((!spacemode) && (num<2))
+ break;
+ int off=(area.width()-linelength)*256/(spacemode?numspaces:(num-1));
+ int curoff=0;
+ while (begin != end)
+ {
+ int doadd=0;
+ if ((!spacemode) || (begin->flags&GS_ISSPACE))
+ doadd=1;
+ begin->x+=curoff>>8;
+ begin->bbox->moveBy(curoff>>8,0);
+ if (doadd)
+ curoff+=off;
+ ++begin;
+ }
+ break;
+ }
+ }
+ }
+ bboxValid=false;
+}
+
+void eTextPara::clear()
+{
+ eLocker lock(ftlock);
+
+ for (glyphString::iterator i(glyphs.begin()); i!=glyphs.end(); ++i)
+ {
+ i->font->unlock();
+ delete i->bbox;
+ }
+ glyphs.clear();
+}
+
+eAutoInitP0<fontRenderClass> init_fontRenderClass(1, "Font Render Class");
diff --git a/lib/gdi/font.h b/lib/gdi/font.h
new file mode 100644
index 00000000..ac55c884
--- /dev/null
+++ b/lib/gdi/font.h
@@ -0,0 +1,163 @@
+#ifndef __FONT_H
+#define __FONT_H
+
+#include <freetype/freetype.h>
+#include <freetype/ftcache.h>
+#include <freetype/cache/ftcglyph.h>
+#include <freetype/cache/ftcimage.h>
+#include <freetype/cache/ftcmanag.h>
+#include <freetype/cache/ftcsbits.h>
+#include <freetype/cache/ftlru.h>
+#include <vector>
+
+#include <lib/gdi/fb.h>
+#include <lib/gdi/esize.h>
+#include <lib/gdi/epoint.h>
+#include <lib/gdi/erect.h>
+#include <lib/base/estring.h>
+
+class FontRenderClass;
+class Font;
+class gPixmapDC;
+class gFont;
+class gRGB;
+
+class fontRenderClass
+{
+ friend class Font;
+ friend class eTextPara;
+ fbClass *fb;
+ struct fontListEntry
+ {
+ eString filename, face;
+ int scale; // 100 is 1:1
+ fontListEntry *next;
+ ~fontListEntry();
+ } *font;
+
+ FT_Library library;
+ FTC_Manager cacheManager; /* the cache manager */
+ FTC_Image_Cache imageCache; /* the glyph image cache */
+ FTC_SBit_Cache sbitsCache; /* the glyph small bitmaps cache */
+
+ FTC_FaceID getFaceID(const eString &face);
+ FT_Error getGlyphBitmap(FTC_Image_Desc *font, FT_ULong glyph_index, FTC_SBit *sbit);
+ static fontRenderClass *instance;
+public:
+ float getLineHeight(const gFont& font);
+ eString AddFont(const eString &filename, const eString &name, int scale);
+ static fontRenderClass *getInstance();
+ FT_Error FTC_Face_Requester(FTC_FaceID face_id,
+ FT_Face* aface);
+ Font *getFont(const eString &face, int size, int tabwidth=-1);
+ fontRenderClass();
+ ~fontRenderClass();
+};
+
+#define RS_WRAP 1
+#define RS_DOT 2
+#define RS_DIRECT 4
+#define RS_FADE 8
+
+#define GS_ISSPACE 1
+#define GS_ISFIRST 2
+#define GS_USED 4
+
+struct pGlyph
+{
+ int x, y, w;
+ Font *font;
+ FT_ULong glyph_index;
+ int flags;
+ eRect bbox;
+};
+
+typedef std::vector<pGlyph> glyphString;
+
+class Font;
+class eLCD;
+
+class eTextPara
+{
+ Font *current_font, *replacement_font;
+ FT_Face current_face, replacement_face;
+ int use_kerning;
+ int previous;
+ static eString replacement_facename;
+
+ eRect area;
+ ePoint cursor;
+ eSize maximum;
+ int left;
+ glyphString glyphs;
+ int refcnt;
+
+ int appendGlyph(Font *current_font, FT_Face current_face, FT_UInt glyphIndex, int flags, int rflags);
+ void newLine(int flags);
+ void setFont(Font *font, Font *replacement_font);
+ eRect boundBox;
+ void calc_bbox();
+ int bboxValid;
+public:
+ eTextPara(eRect area, ePoint start=ePoint(-1, -1))
+ : current_font(0), replacement_font(0), current_face(0), replacement_face(0),
+ area(area), cursor(start), maximum(0, 0), left(start.x()), refcnt(0), bboxValid(0)
+ {
+ }
+ ~eTextPara();
+
+ static void setReplacementFont(eString font) { replacement_facename=font; }
+
+ void destroy();
+ eTextPara *grab();
+
+ void setFont(const gFont &font);
+ int renderString(const eString &string, int flags=0);
+
+ void clear();
+
+ void blit(gPixmapDC &dc, const ePoint &offset, const gRGB &background, const gRGB &foreground);
+
+ enum
+ {
+ dirLeft, dirRight, dirCenter, dirBlock
+ };
+
+ void realign(int dir);
+
+ const eRect & getBoundBox()
+ {
+ if (!bboxValid)
+ calc_bbox();
+
+ return boundBox;
+ }
+
+ const eRect& getGlyphBBox(int num) const
+ {
+ return glyphs[num].bbox;
+ }
+};
+
+class Font
+{
+public:
+ FTC_Image_Desc font;
+ fontRenderClass *renderer;
+ int ref;
+ FT_Error getGlyphBitmap(FT_ULong glyph_index, FTC_SBit *sbit);
+ FT_Face face;
+ FT_Size size;
+
+ int tabwidth;
+ int height;
+ Font(fontRenderClass *render, FTC_FaceID faceid, int isize, int tabwidth);
+ ~Font();
+
+ void lock();
+ void unlock(); // deletes if ref==0
+};
+
+extern fontRenderClass *font;
+
+#endif
diff --git a/lib/gdi/font_arabic.cpp b/lib/gdi/font_arabic.cpp
new file mode 100644
index 00000000..573f9fa2
--- /dev/null
+++ b/lib/gdi/font_arabic.cpp
@@ -0,0 +1,266 @@
+/*
+ * This was taken from pango.
+ * Modified for enigma by Felix Domke <tmbinc@gmx.net>.
+ * I removed support for vowels and ligatures. Sorry.
+ *
+ * Original header:
+ *
+ * This is part of Pango - Arabic shaping module
+ *
+ * (C) 2000 Karl Koehler <koehler@or.uni-bonn.de>
+ * (C) 2001 Roozbeh Pournader <roozbeh@sharif.edu>
+ *
+ */
+
+#include <vector>
+#include <lib/base/eerror.h>
+
+typedef struct
+{
+ unsigned long basechar;
+ int count;
+ unsigned long charshape[4];
+} shapestruct;
+
+typedef struct
+{
+ unsigned long basechar;
+ char numshapes;
+} charstruct;
+
+static void
+charstruct_init (charstruct * s)
+{
+ s->basechar = 0;
+ s->numshapes = 1;
+}
+
+#define connects_to_left(a) ((a).numshapes > 2)
+
+/* The Unicode order is always 'isolated, final, initial, medial'. */
+
+/* *INDENT-OFF* */
+static shapestruct chartable[] = {
+ {0x0621, 1, {0xFE80}}, /* HAMZA */
+ {0x0622, 2, {0xFE81, 0xFE82}}, /* ALEF WITH MADDA ABOVE */
+ {0x0623, 2, {0xFE83, 0xFE84}}, /* ALEF WITH HAMZA ABOVE */
+ {0x0624, 2, {0xFE85, 0xFE86}}, /* WAW WITH HAMZA ABOVE */
+ {0x0625, 2, {0xFE87, 0xFE88}}, /* ALEF WITH HAMZA BELOW */
+ {0x0626, 4, {0xFE89, 0xFE8A, 0xFE8B, 0xFE8C}}, /* YEH WITH HAMZA ABOVE */
+ {0x0627, 2, {0xFE8D, 0xFE8E}}, /* ALEF */
+ {0x0628, 4, {0xFE8F, 0xFE90, 0xFE91, 0xFE92}}, /* BEH */
+ {0x0629, 2, {0xFE93, 0xFE94}}, /* TEH MARBUTA */
+ {0x062A, 4, {0xFE95, 0xFE96, 0xFE97, 0xFE98}}, /* TEH */
+ {0x062B, 4, {0xFE99, 0xFE9A, 0xFE9B, 0xFE9C}}, /* THEH */
+ {0x062C, 4, {0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0}}, /* JEEM */
+ {0x062D, 4, {0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4}}, /* HAH */
+ {0x062E, 4, {0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8}}, /* KHAH */
+ {0x062F, 2, {0xFEA9, 0xFEAA}}, /* DAL */
+ {0x0630, 2, {0xFEAB, 0xFEAC}}, /* THAL */
+ {0x0631, 2, {0xFEAD, 0xFEAE}}, /* REH */
+ {0x0632, 2, {0xFEAF, 0xFEB0}}, /* ZAIN */
+ {0x0633, 4, {0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4}}, /* SEEN */
+ {0x0634, 4, {0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8}}, /* SHEEN */
+ {0x0635, 4, {0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC}}, /* SAD */
+ {0x0636, 4, {0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0}}, /* DAD */
+ {0x0637, 4, {0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4}}, /* TAH */
+ {0x0638, 4, {0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8}}, /* ZAH */
+ {0x0639, 4, {0xFEC9, 0xFECA, 0xFECB, 0xFECC}}, /* AIN */
+ {0x063A, 4, {0xFECD, 0xFECE, 0xFECF, 0xFED0}}, /* GHAIN */
+ {0x0640, 4, {0x0640, 0x0640, 0x0640, 0x0640}}, /* TATWEEL */
+ {0x0641, 4, {0xFED1, 0xFED2, 0xFED3, 0xFED4}}, /* FEH */
+ {0x0642, 4, {0xFED5, 0xFED6, 0xFED7, 0xFED8}}, /* QAF */
+ {0x0643, 4, {0xFED9, 0xFEDA, 0xFEDB, 0xFEDC}}, /* KAF */
+ {0x0644, 4, {0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0}}, /* LAM */
+ {0x0645, 4, {0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4}}, /* MEEM */
+ {0x0646, 4, {0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8}}, /* NOON */
+ {0x0647, 4, {0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC}}, /* HEH */
+ {0x0648, 2, {0xFEED, 0xFEEE}}, /* WAW */
+ {0x0649, 4, {0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9}}, /* ALEF MAKSURA */
+ {0x064A, 4, {0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4}}, /* YEH */
+ {0x0671, 2, {0xFB50, 0xFB51}}, /* ALEF WASLA */
+ {0x0679, 4, {0xFB66, 0xFB67, 0xFB68, 0xFB69}}, /* TTEH */
+ {0x067A, 4, {0xFB5E, 0xFB5F, 0xFB60, 0xFB61}}, /* TTEHEH */
+ {0x067B, 4, {0xFB52, 0xFB53, 0xFB54, 0xFB55}}, /* BEEH */
+ {0x067E, 4, {0xFB56, 0xFB57, 0xFB58, 0xFB59}}, /* PEH */
+ {0x067F, 4, {0xFB62, 0xFB63, 0xFB64, 0xFB65}}, /* TEHEH */
+ {0x0680, 4, {0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D}}, /* BEHEH */
+ {0x0683, 4, {0xFB76, 0xFB77, 0xFB78, 0xFB79}}, /* NYEH */
+ {0x0684, 4, {0xFB72, 0xFB73, 0xFB74, 0xFB75}}, /* DYEH */
+ {0x0686, 4, {0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D}}, /* TCHEH */
+ {0x0687, 4, {0xFB7E, 0xFB7F, 0xFB80, 0xFB81}}, /* TCHEHEH */
+ {0x0688, 2, {0xFB88, 0xFB89}}, /* DDAL */
+ {0x068C, 2, {0xFB84, 0xFB85}}, /* DAHAL */
+ {0x068D, 2, {0xFB82, 0xFB83}}, /* DDAHAL */
+ {0x068E, 2, {0xFB86, 0xFB87}}, /* DUL */
+ {0x0691, 2, {0xFB8C, 0xFB8D}}, /* RREH */
+ {0x0698, 2, {0xFB8A, 0xFB8B}}, /* JEH */
+ {0x06A4, 4, {0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D}}, /* VEH */
+ {0x06A6, 4, {0xFB6E, 0xFB6F, 0xFB70, 0xFB71}}, /* PEHEH */
+ {0x06A9, 4, {0xFB8E, 0xFB8F, 0xFB90, 0xFB91}}, /* KEHEH */
+ {0x06AD, 4, {0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6}}, /* NG */
+ {0x06AF, 4, {0xFB92, 0xFB93, 0xFB94, 0xFB95}}, /* GAF */
+ {0x06B1, 4, {0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D}}, /* NGOEH */
+ {0x06B3, 4, {0xFB96, 0xFB97, 0xFB98, 0xFB99}}, /* GUEH */
+ {0x06BB, 4, {0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3}}, /* RNOON */
+ {0x06BE, 4, {0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD}}, /* HEH DOACHASHMEE */
+ {0x06C0, 2, {0xFBA4, 0xFBA5}}, /* HEH WITH YEH ABOVE */
+ {0x06C1, 4, {0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9}}, /* HEH GOAL */
+ {0x06C5, 2, {0xFBE0, 0xFBE1}}, /* KIRGHIZ OE */
+ {0x06C6, 2, {0xFBD9, 0xFBDA}}, /* OE */
+ {0x06C7, 2, {0xFBD7, 0xFBD8}}, /* U */
+ {0x06C8, 2, {0xFBDB, 0xFBDC}}, /* YU */
+ {0x06C9, 2, {0xFBE2, 0xFBE3}}, /* KIRGHIZ YU */
+ {0x06CB, 2, {0xFBDE, 0xFBDF}}, /* VE */
+ {0x06CC, 4, {0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF}}, /* FARSI YEH */
+ {0x06D0, 4, {0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7}}, /* E */
+ {0x06D2, 2, {0xFBAE, 0xFBAF}}, /* YEH BARREE */
+ {0x06D3, 2, {0xFBB0, 0xFBB1}}, /* YEH BARREE WITH HAMZA ABOVE */
+};
+
+#define ALEF 0x0627
+#define ALEFHAMZA 0x0623
+#define ALEFHAMZABELOW 0x0625
+#define ALEFMADDA 0x0622
+#define LAM 0x0644
+#define HAMZA 0x0621
+#define TATWEEL 0x0640
+#define ZWJ 0x200D
+
+#define HAMZAABOVE 0x0654
+#define HAMZABELOW 0x0655
+
+#define WAWHAMZA 0x0624
+#define YEHHAMZA 0x0626
+#define WAW 0x0648
+#define ALEFMAKSURA 0x0649
+#define YEH 0x064A
+#define FARSIYEH 0x06CC
+
+#define SHADDA 0x0651
+#define KASRA 0x0650
+#define FATHA 0x064E
+#define DAMMA 0x064F
+#define MADDA 0x0653
+
+#define LAM_ALEF 0xFEFB
+#define LAM_ALEFHAMZA 0xFEF7
+#define LAM_ALEFHAMZABELOW 0xFEF9
+#define LAM_ALEFMADDA 0xFEF5
+
+static short
+shapecount (unsigned long s)
+{
+ int l, r, m;
+ if ((s >= 0x0621) && (s <= 0x06D3))
+ {
+ l = 0;
+ r = sizeof (chartable) / sizeof (shapestruct);
+ while (l <= r)
+ {
+ m = (l + r) / 2;
+ if (s == chartable[m].basechar)
+ {
+ return chartable[m].count;
+ }
+ else if (s < chartable[m].basechar)
+ {
+ r = m - 1;
+ }
+ else
+ {
+ l = m + 1;
+ }
+ }
+ }
+ else if (s == ZWJ)
+ {
+ return 4;
+ }
+ return 1;
+}
+
+static unsigned long
+charshape (unsigned long s, int which)
+/* which 0=isolated 1=final 2=initial 3=medial */
+{
+ int l, r, m;
+ if ((s >= 0x0621) && (s <= 0x06D3))
+ {
+ l = 0;
+ r = sizeof (chartable) / sizeof (shapestruct);
+ while (l <= r)
+ {
+ m = (l + r) / 2;
+ if (s == chartable[m].basechar)
+ {
+ return chartable[m].charshape[which];
+ }
+ else if (s < chartable[m].basechar)
+ {
+ r = m - 1;
+ }
+ else
+ {
+ l = m + 1;
+ }
+ }
+ }
+ else if ((s >= 0xFEF5) && (s <= 0xFEFB))
+ { /* Lam+Alef */
+ return s + which;
+ }
+
+ return s;
+}
+
+void
+shape (std::vector<unsigned long> &string, const std::vector<unsigned long> &text)
+{
+ string.reserve(text.size());
+
+ charstruct oldchar, curchar;
+ int which;
+ unsigned long nextletter;
+
+ charstruct_init (&oldchar);
+ charstruct_init (&curchar);
+
+ for (std::vector<unsigned long>::const_iterator i(text.begin());
+ i != text.end(); ++i)
+ {
+ nextletter = *i;
+ int nc = shapecount (nextletter);
+
+ if (nc == 1)
+ which = 0; /* final or isolated */
+ else
+ which = 2; /* medial or initial */
+ if (connects_to_left (oldchar))
+ which++;
+ which = which % (curchar.numshapes);
+ curchar.basechar = charshape (curchar.basechar, which);
+ /* get rid of oldchar */
+ if (oldchar.basechar)
+ string.push_back(oldchar.basechar);
+ oldchar = curchar; /* new values in oldchar */
+
+ /* init new curchar */
+ charstruct_init (&curchar);
+ curchar.basechar = nextletter;
+ curchar.numshapes = nc;
+ }
+
+ /* Handle last char */
+ if (connects_to_left (oldchar))
+ which = 1;
+ else
+ which = 0;
+ which = which % (curchar.numshapes);
+ curchar.basechar = charshape (curchar.basechar, which);
+
+ if (oldchar.basechar != 0)
+ string.push_back(oldchar.basechar);
+ if (curchar.basechar != 0)
+ string.push_back(curchar.basechar);
+}
diff --git a/lib/gdi/gfbdc.cpp b/lib/gdi/gfbdc.cpp
new file mode 100644
index 00000000..83f681d7
--- /dev/null
+++ b/lib/gdi/gfbdc.cpp
@@ -0,0 +1,166 @@
+#include <lib/gdi/gfbdc.h>
+
+#include <lib/base/init.h>
+#include <lib/base/init_num.h>
+#include <lib/base/econfig.h>
+
+gFBDC *gFBDC::instance;
+
+gFBDC::gFBDC()
+{
+ instance=this;
+ fb=new fbClass;
+
+ if (!fb->Available())
+ eFatal("no framebuffer available");
+
+ fb->SetMode(720, 576, 8);
+ for (int y=0; y<576; y++) // make whole screen transparent
+ memset(fb->lfb+y*fb->Stride(), 0x00, fb->Stride());
+
+ pixmap=new gPixmap();
+ pixmap->x=720;
+ pixmap->y=576;
+ pixmap->bpp=8;
+ pixmap->bypp=1;
+ pixmap->stride=fb->Stride();
+ pixmap->data=fb->lfb;
+
+ pixmap->clut.colors=256;
+ pixmap->clut.data=new gRGB[pixmap->clut.colors];
+ memset(pixmap->clut.data, 0, sizeof(*pixmap->clut.data)*pixmap->clut.colors);
+ reloadSettings();
+}
+
+gFBDC::~gFBDC()
+{
+ delete pixmap;
+ delete fb;
+ instance=0;
+}
+
+void gFBDC::calcRamp()
+{
+#if 0
+ float fgamma=gamma ? gamma : 1;
+ fgamma/=10.0;
+ fgamma=1/log(fgamma);
+ for (int i=0; i<256; i++)
+ {
+ float raw=i/255.0; // IIH, float.
+ float corr=pow(raw, fgamma) * 256.0;
+
+ int d=corr * (float)(256-brightness) / 256 + brightness;
+ if (d < 0)
+ d=0;
+ if (d > 255)
+ d=255;
+ ramp[i]=d;
+
+ rampalpha[i]=i*alpha/256;
+ }
+#endif
+ for (int i=0; i<256; i++)
+ {
+ int d;
+ d=i;
+ d=(d-128)*(gamma+64)/(128+64)+128;
+ d+=brightness-128; // brightness correction
+ if (d<0)
+ d=0;
+ if (d>255)
+ d=255;
+ ramp[i]=d;
+
+/* if ( eDVB::getInstance()->getmID == 1 )
+ rampalpha[i]=i*alpha/65535;
+ else*/
+ rampalpha[i]=i*alpha/256;
+ }
+
+ rampalpha[255]=255; // transparent BLEIBT bitte so.
+}
+
+void gFBDC::setPalette()
+{
+ if (!pixmap->clut.data)
+ return;
+
+ for (int i=0; i<256; ++i)
+ {
+ fb->CMAP()->red[i]=ramp[pixmap->clut.data[i].r]<<8;
+ fb->CMAP()->green[i]=ramp[pixmap->clut.data[i].g]<<8;
+ fb->CMAP()->blue[i]=ramp[pixmap->clut.data[i].b]<<8;
+ fb->CMAP()->transp[i]=rampalpha[pixmap->clut.data[i].a]<<8;
+ if (!fb->CMAP()->red[i])
+ fb->CMAP()->red[i]=0x100;
+ }
+ fb->PutCMAP();
+}
+
+void gFBDC::exec(gOpcode *o)
+{
+ switch (o->opcode)
+ {
+ case gOpcode::setPalette:
+ {
+ gPixmapDC::exec(o);
+ setPalette();
+ break;
+ }
+ default:
+ gPixmapDC::exec(o);
+ break;
+ }
+}
+
+gFBDC *gFBDC::getInstance()
+{
+ return instance;
+}
+
+void gFBDC::setAlpha(int a)
+{
+ alpha=a;
+
+ calcRamp();
+ setPalette();
+}
+
+void gFBDC::setBrightness(int b)
+{
+ brightness=b;
+
+ calcRamp();
+ setPalette();
+}
+
+void gFBDC::setGamma(int g)
+{
+ gamma=g;
+
+ calcRamp();
+ setPalette();
+}
+
+void gFBDC::saveSettings()
+{
+ eConfig::getInstance()->setKey("/ezap/osd/alpha", alpha);
+ eConfig::getInstance()->setKey("/ezap/osd/gamma", gamma);
+ eConfig::getInstance()->setKey("/ezap/osd/brightness", brightness);
+}
+
+void gFBDC::reloadSettings()
+{
+ if (eConfig::getInstance()->getKey("/ezap/osd/alpha", alpha))
+ alpha=255;
+ if (eConfig::getInstance()->getKey("/ezap/osd/gamma", gamma))
+ gamma=128;
+ if (eConfig::getInstance()->getKey("/ezap/osd/brightness", brightness))
+ brightness=128;
+
+ calcRamp();
+ setPalette();
+}
+
+eAutoInitP0<gFBDC> init_gFBDC(eAutoInitNumbers::graphic+1, "GFBDC");
diff --git a/lib/gdi/gfbdc.h b/lib/gdi/gfbdc.h
new file mode 100644
index 00000000..f975fb5f
--- /dev/null
+++ b/lib/gdi/gfbdc.h
@@ -0,0 +1,35 @@
+#ifndef __gfbdc_h
+#define __gfbdc_h
+
+#include "fb.h"
+#include "gpixmap.h"
+#include "grc.h"
+
+class gFBDC: public gPixmapDC
+{
+ fbClass *fb;
+ static gFBDC *instance;
+ void exec(gOpcode *opcode);
+ unsigned char ramp[256], rampalpha[256]; // RGB ramp 0..255
+ int brightness, gamma, alpha;
+ void calcRamp();
+ void setPalette();
+public:
+ void reloadSettings();
+ void setAlpha(int alpha);
+ void setBrightness(int brightness);
+ void setGamma(int gamma);
+
+ int getAlpha() { return alpha; }
+ int getBrightness() { return brightness; }
+ int getGamma() { return gamma; }
+
+ void saveSettings();
+
+ gFBDC();
+ ~gFBDC();
+ static gFBDC *getInstance();
+};
+
+
+#endif
diff --git a/lib/gdi/glcddc.cpp b/lib/gdi/glcddc.cpp
new file mode 100644
index 00000000..3895df9a
--- /dev/null
+++ b/lib/gdi/glcddc.cpp
@@ -0,0 +1,56 @@
+#ifndef DISABLE_LCD
+
+#include <lib/gdi/glcddc.h>
+#include <lib/gdi/lcd.h>
+
+gLCDDC *gLCDDC::instance;
+
+gLCDDC::gLCDDC(eLCD *lcd): lcd(lcd)
+{
+ instance=this;
+
+ update=1;
+
+ pixmap=new gPixmap();
+ pixmap->x=lcd->size().width();
+ pixmap->y=lcd->size().height();
+ pixmap->bpp=8;
+ pixmap->bypp=1;
+ pixmap->stride=lcd->stride();
+ pixmap->data=lcd->buffer();
+
+ pixmap->clut.colors=256;
+ pixmap->clut.data=0;
+}
+
+gLCDDC::~gLCDDC()
+{
+ delete pixmap;
+ instance=0;
+}
+
+void gLCDDC::exec(gOpcode *o)
+{
+ switch (o->opcode)
+ {
+ case gOpcode::flush:
+ case gOpcode::end:
+ if (update)
+ lcd->update();
+ default:
+ gPixmapDC::exec(o);
+ break;
+ }
+}
+
+gLCDDC *gLCDDC::getInstance()
+{
+ return instance;
+}
+
+void gLCDDC::setUpdate(int u)
+{
+ update=u;
+}
+
+#endif //DISABLE_LCD
diff --git a/lib/gdi/glcddc.h b/lib/gdi/glcddc.h
new file mode 100644
index 00000000..9342e5e2
--- /dev/null
+++ b/lib/gdi/glcddc.h
@@ -0,0 +1,26 @@
+#ifndef DISABLE_LCD
+
+#ifndef __glcddc_h
+#define __glcddc_h
+
+#include "grc.h"
+
+class eLCD;
+
+class gLCDDC: public gPixmapDC
+{
+ eLCD *lcd;
+ static gLCDDC *instance;
+ int update;
+ void exec(gOpcode *opcode);
+public:
+ gLCDDC(eLCD *lcd);
+ ~gLCDDC();
+ void setUpdate(int update);
+ static gLCDDC *getInstance();
+};
+
+
+#endif
+
+#endif //DISABLE_LCD
diff --git a/lib/gdi/gpixmap.cpp b/lib/gdi/gpixmap.cpp
new file mode 100644
index 00000000..c089051d
--- /dev/null
+++ b/lib/gdi/gpixmap.cpp
@@ -0,0 +1,295 @@
+#include <lib/gdi/gpixmap.h>
+
+gLookup::gLookup()
+{
+ size=0;
+ lookup=0;
+}
+
+gLookup::gLookup(int size, const gPalette &pal, const gRGB &start, const gRGB &end)
+{
+ size=0;
+ lookup=0;
+ build(size, pal, start, end);
+}
+
+void gLookup::build(int _size, const gPalette &pal, const gRGB &start, const gRGB &end)
+{
+ if (lookup)
+ {
+ delete lookup;
+ lookup=0;
+ size=0;
+ }
+ size=_size;
+ if (!size)
+ return;
+ lookup=new gColor[size];
+
+ for (int i=0; i<size; i++)
+ {
+ gRGB col;
+ if (i)
+ {
+ int rdiff=-start.r+end.r;
+ int gdiff=-start.g+end.g;
+ int bdiff=-start.b+end.b;
+ int adiff=-start.a+end.a;
+ rdiff*=i; rdiff/=(size-1);
+ gdiff*=i; gdiff/=(size-1);
+ bdiff*=i; bdiff/=(size-1);
+ adiff*=i; adiff/=(size-1);
+ col.r=start.r+rdiff;
+ col.g=start.g+gdiff;
+ col.b=start.b+bdiff;
+ col.a=start.a+adiff;
+ } else
+ col=start;
+ lookup[i]=pal.findColor(col);
+ }
+}
+
+DEFINE_REF(gPixmap);
+
+void gPixmap::fill(const eRect &area, const gColor &color)
+{
+ if ((area.height()<=0) || (area.width()<=0))
+ return;
+ if (bpp == 8)
+ for (int y=area.top(); y<area.bottom(); y++)
+ memset(((__u8*)data)+y*stride+area.left(), color.color, area.width());
+ else if (bpp == 32)
+ for (int y=area.top(); y<area.bottom(); y++)
+ {
+ __u32 *dst=(__u32*)(((__u8*)data)+y*stride+area.left()*bypp);
+ int x=area.width();
+ __u32 col;
+
+ if (clut.data && color < clut.colors)
+ col=(clut.data[color].a<<24)|(clut.data[color].r<<16)|(clut.data[color].g<<8)|(clut.data[color].b);
+ else
+ col=0x10101*color;
+ col^=0xFF000000;
+ while (x--)
+ *dst++=col;
+ }
+ else
+ eWarning("couldn't fill %d bpp", bpp);
+}
+
+void gPixmap::blit(const gPixmap &src, ePoint pos, const eRect &clip, int flag)
+{
+
+ eRect area=eRect(pos, src.getSize());
+ if (!clip.isNull())
+ area&=clip;
+ area&=eRect(ePoint(0, 0), getSize());
+ if ((area.width()<0) || (area.height()<0))
+ return;
+
+ eRect srcarea=area;
+ srcarea.moveBy(-pos.x(), -pos.y());
+
+ if ((bpp == 8) && (src.bpp==8))
+ {
+ __u8 *srcptr=(__u8*)src.data;
+ __u8 *dstptr=(__u8*)data;
+
+ srcptr+=srcarea.left()*bypp+srcarea.top()*src.stride;
+ dstptr+=area.left()*bypp+area.top()*stride;
+ for (int y=0; y<area.height(); y++)
+ {
+ if (flag & blitAlphaTest)
+ {
+ // no real alphatest yet
+ int width=area.width();
+ unsigned char *src=(unsigned char*)srcptr;
+ unsigned char *dst=(unsigned char*)dstptr;
+ // use duff's device here!
+ while (width--)
+ {
+ if (!*src)
+ {
+ src++;
+ dst++;
+ } else
+ *dst++=*src++;
+ }
+ } else
+ memcpy(dstptr, srcptr, area.width()*bypp);
+ srcptr+=src.stride;
+ dstptr+=stride;
+ }
+ } else if ((bpp == 32) && (src.bpp==8))
+ {
+ __u8 *srcptr=(__u8*)src.data;
+ __u8 *dstptr=(__u8*)data; // !!
+ __u32 pal[256];
+
+ for (int i=0; i<256; ++i)
+ {
+ if (src.clut.data && (i<src.clut.colors))
+ pal[i]=(src.clut.data[i].a<<24)|(src.clut.data[i].r<<16)|(src.clut.data[i].g<<8)|(src.clut.data[i].b);
+ else
+ pal[i]=0x010101*i;
+ pal[i]^=0xFF000000;
+ }
+
+ srcptr+=srcarea.left()*bypp+srcarea.top()*src.stride;
+ dstptr+=area.left()*bypp+area.top()*stride;
+ for (int y=0; y<area.height(); y++)
+ {
+ if (flag & blitAlphaTest)
+ {
+ // no real alphatest yet
+ int width=area.width();
+ unsigned char *src=(unsigned char*)srcptr;
+ __u32 *dst=(__u32*)dstptr;
+ // use duff's device here!
+ while (width--)
+ {
+ if (!*src)
+ {
+ src++;
+ dst++;
+ } else
+ *dst++=pal[*src++];
+ }
+ } else
+ {
+ int width=area.width();
+ unsigned char *src=(unsigned char*)srcptr;
+ __u32 *dst=(__u32*)dstptr;
+ while (width--)
+ *dst++=pal[*src++];
+ }
+ srcptr+=src.stride;
+ dstptr+=stride;
+ }
+ } else
+ eFatal("cannot blit %dbpp from %dbpp", bpp, src.bpp);
+}
+
+void gPixmap::mergePalette(const gPixmap &target)
+{
+ if ((!clut.colors) || (!target.clut.colors))
+ return;
+ gColor *lookup=new gColor[clut.colors];
+
+ for (int i=0; i<clut.colors; i++)
+ lookup[i].color=target.clut.findColor(clut.data[i]);
+
+ delete clut.data;
+ clut.colors=target.clut.colors;
+ clut.data=new gRGB[clut.colors];
+ memcpy(clut.data, target.clut.data, sizeof(gRGB)*clut.colors);
+
+ __u8 *dstptr=(__u8*)data;
+
+ for (int ay=0; ay<y; ay++)
+ {
+ for (int ax=0; ax<x; ax++)
+ dstptr[ax]=lookup[dstptr[ax]];
+ dstptr+=stride;
+ }
+
+ delete lookup;
+}
+
+void gPixmap::line(ePoint start, ePoint dst, gColor color)
+{
+int Ax=start.x(), // dieser code rult ganz ganz doll weil er ganz ganz fast ist und auch sehr gut dokumentiert is
+Ay=start.y(), Bx=dst.x(), // t. es handelt sich immerhin um den weltbekannten bresenham algorithmus der nicht nur
+By=dst.y(); int dX, dY, fbXincr, // sehr schnell ist sondern auch sehr gut dokumentiert und getestet wurde. nicht
+fbYincr, fbXYincr, dPr, dPru, P; __u8 // nur auf dem LCD der dbox, sondern auch ueberall anders. und auch auf der
+*AfbAddr = &((__u8*)data)[Ay*stride+Ax*bypp]; __u8 // dbox mit LCD soll das teil nun tun, und ich denke das tut es. ausse
+*BfbAddr = &((__u8*)data)[By*stride+Bx*bypp]; fbXincr= // rdem hat dieser algo den vorteil dass man fehler sehr leicht fi
+bypp; if ( (dX=Bx-Ax) >= 0) goto AFTERNEGX; dX=-dX; // ndet und beheben kann. das liegt nicht zuletzt an den komment
+fbXincr=-1; AFTERNEGX: fbYincr=stride; if ( (dY=By // aren. und ausserdem, je kuerzer der code, desto weniger k
+-Ay) >= 0) goto AFTERNEGY; fbYincr=-stride; dY=-dY;AFTERNEGY: // ann daran falsch sein. erwaehnte ich schon, da
+fbXYincr = fbXincr+fbYincr; if (dY > dX) goto YisIndependent; dPr = dY+ // s dieser tolle code wahnsinnig schnell
+dY; P = -dX; dPru = P+P; dY = dX>>1; XLOOP: *AfbAddr=color; *BfbAddr=color; if ((P+=dPr) > 0) // ist? bye, tmbinc
+goto RightAndUp; AfbAddr+=fbXincr; BfbAddr-=fbXincr; if ((dY=dY-1) > 0) goto XLOOP; *AfbAddr=color; if ((dX & 1)
+== 0) return; *BfbAddr=color; return; RightAndUp: AfbAddr+=fbXYincr; BfbAddr-=fbXYincr; P+=dPru; if ((dY=dY-1) >
+0) goto XLOOP; *AfbAddr=color; if ((dX & 1) == 0) return; *BfbAddr=color; return; YisIndependent: dPr = dX+dX; P
+= -dY; dPru = P+P; dX = dY>>1; YLOOP: *AfbAddr=color; *BfbAddr=color; if ((P+=dPr) > 0) goto RightAndUp2; AfbAddr
++=fbYincr; BfbAddr-=fbYincr; if ((dX=dX-1) > 0) goto YLOOP; *AfbAddr=color; if ((dY & 1) == 0) return; *BfbAddr=
+color;return; RightAndUp2: AfbAddr+=fbXYincr; BfbAddr-=fbXYincr; P+=dPru; if ((dX=dX-1) > 0) goto YLOOP; *AfbAddr
+=color; if((dY & 1) == 0) return; *BfbAddr=color; return; // nun ist der tolle code leider zu ende. tut mir leid.
+}
+
+gColor gPalette::findColor(const gRGB &rgb) const
+{
+ int difference=1<<30, best_choice=0;
+ for (int t=0; t<colors; t++)
+ {
+ int ttd;
+ int td=(signed)(rgb.r-data[t].r); td*=td; td*=(255-data[t].a);
+ ttd=td;
+ if (ttd>=difference)
+ continue;
+ td=(signed)(rgb.g-data[t].g); td*=td; td*=(255-data[t].a);
+ ttd+=td;
+ if (ttd>=difference)
+ continue;
+ td=(signed)(rgb.b-data[t].b); td*=td; td*=(255-data[t].a);
+ ttd+=td;
+ if (ttd>=difference)
+ continue;
+ td=(signed)(rgb.a-data[t].a); td*=td; td*=255;
+ ttd+=td;
+ if (ttd>=difference)
+ continue;
+ difference=ttd;
+ best_choice=t;
+ }
+ return best_choice;
+}
+
+gPixmap::gPixmap()
+{
+}
+
+gPixmap::~gPixmap()
+{
+}
+
+gImage::gImage(eSize size, int _bpp)
+{
+ x=size.width();
+ y=size.height();
+ bpp=_bpp;
+ switch (bpp)
+ {
+ case 8:
+ bypp=1;
+ break;
+ case 15:
+ case 16:
+ bypp=2;
+ break;
+ case 24: // never use 24bit mode
+ case 32:
+ bypp=4;
+ break;
+ default:
+ bypp=(bpp+7)/8;
+ }
+ stride=x*bypp;
+ if (bpp==8)
+ {
+ clut.colors=256;
+ clut.data=new gRGB[clut.colors];
+ } else
+ {
+ clut.colors=0;
+ clut.data=0;
+ }
+ data=new char[x*y*bypp];
+}
+
+gImage::~gImage()
+{
+ delete[] clut.data;
+ delete[] (char*)data;
+}
diff --git a/lib/gdi/gpixmap.h b/lib/gdi/gpixmap.h
new file mode 100644
index 00000000..f68a5748
--- /dev/null
+++ b/lib/gdi/gpixmap.h
@@ -0,0 +1,142 @@
+#ifndef __gpixmap_h
+#define __gpixmap_h
+
+#include <pthread.h>
+#include <lib/base/estring.h>
+#include <lib/gdi/erect.h>
+#include <lib/gdi/fb.h>
+#include <lib/base/elock.h>
+
+#include <lib/base/object.h>
+
+struct gColor
+{
+ int color;
+ gColor(int color): color(color)
+ {
+ }
+ gColor(): color(0)
+ {
+ }
+ operator int() const { return color; }
+ bool operator==(const gColor &o) const { return o.color==color; }
+};
+
+struct gRGB
+{
+ int b, g, r, a;
+ gRGB(int r, int g, int b, int a=0): b(b), g(g), r(r), a(a)
+ {
+ }
+ gRGB(unsigned long val): b(val&0xFF), g((val>>8)&0xFF), r((val>>16)&0xFF), a((val>>24)&0xFF) // ARGB
+ {
+ }
+ gRGB()
+ {
+ }
+ bool operator < (const gRGB &c) const
+ {
+ if (b < c.b)
+ return 1;
+ if (b == c.b)
+ {
+ if (g < c.g)
+ return 1;
+ if (g == c.g)
+ {
+ if (r < c.r)
+ return 1;
+ if (r == c.r)
+ return a < c.a;
+ }
+ }
+ return 0;
+ }
+ bool operator==(const gRGB &c) const
+ {
+ return (b == c.b) && (g == c.g) && (r == c.r) && (a == c.a);
+ }
+};
+
+struct gPalette
+{
+ int start, colors;
+ gRGB *data;
+ gColor findColor(const gRGB &rgb) const;
+};
+
+struct gLookup
+{
+ int size;
+ gColor *lookup;
+ gLookup(int size, const gPalette &pal, const gRGB &start, const gRGB &end);
+ gLookup();
+ void build(int size, const gPalette &pal, const gRGB &start, const gRGB &end);
+};
+
+/**
+ * \brief A softreference to a font.
+ *
+ * The font is specified by a name and a size.
+ * \c gFont is part of the \ref gdi.
+ */
+struct gFont
+{
+ eString family;
+ int pointSize;
+
+ /**
+ * \brief Constructs a font with the given name and size.
+ * \param family The name of the font, for example "NimbusSansL-Regular Sans L Regular".
+ * \param pointSize the size of the font in PIXELS.
+ */
+ gFont(const eString &family, int pointSize):
+ family(family), pointSize(pointSize)
+ {
+ }
+
+ enum
+ {
+ tRegular, tFixed
+ };
+
+ gFont(int type, int pointSize);
+
+ gFont()
+ :pointSize(0)
+ {
+ }
+};
+
+struct gPixmap: public iObject
+{
+DECLARE_REF;
+public:
+ int x, y, bpp, bypp, stride;
+ void *data;
+
+ gPalette clut;
+
+ eSize getSize() const { return eSize(x, y); }
+
+ void fill(const eRect &area, const gColor &color);
+
+ enum
+ {
+ blitAlphaTest=1
+ };
+ void blit(const gPixmap &src, ePoint pos, const eRect &clip=eRect(), int flags=0);
+
+ void mergePalette(const gPixmap &target);
+ void line(ePoint start, ePoint end, gColor color);
+ gPixmap();
+ virtual ~gPixmap();
+};
+
+struct gImage: gPixmap
+{
+ gImage(eSize size, int bpp);
+ ~gImage();
+};
+
+#endif
diff --git a/lib/gdi/grc.cpp b/lib/gdi/grc.cpp
new file mode 100644
index 00000000..3bd00782
--- /dev/null
+++ b/lib/gdi/grc.cpp
@@ -0,0 +1,348 @@
+// for debugging use:
+// #define SYNC_PAINT
+#include <unistd.h>
+#ifndef SYNC_PAINT
+#include <pthread.h>
+#endif
+
+#include <lib/gdi/grc.h>
+#include <lib/gdi/font.h>
+#include <lib/base/init.h>
+#include <lib/base/init_num.h>
+
+#define MAXSIZE 1024
+
+#ifndef SYNC_PAINT
+void *gRC::thread_wrapper(void *ptr)
+{
+ nice(3);
+ return ((gRC*)ptr)->thread();
+}
+#endif
+
+gRC *gRC::instance=0;
+
+gRC::gRC(): queuelock(MAXSIZE), queue(2048)
+{
+ ASSERT(!instance);
+ instance=this;
+ queuelock.lock(MAXSIZE);
+#ifndef SYNC_PAINT
+ eDebug(pthread_create(&the_thread, 0, thread_wrapper, this)?"RC thread couldn't be created":"RC thread createted successfully");
+#endif
+}
+
+gRC::~gRC()
+{
+ gOpcode o;
+ o.dc=0;
+ o.opcode=gOpcode::shutdown;
+ submit(o);
+ instance=0;
+}
+
+void *gRC::thread()
+{
+#ifndef SYNC_PAINT
+ while (1)
+#else
+ while (queue.size())
+#endif
+ {
+ queuelock.lock(1);
+ gOpcode& o(queue.current());
+ if (o.opcode==gOpcode::shutdown)
+ break;
+ o.dc->exec(&o);
+ queue.dequeue();
+ }
+#ifndef SYNC_PAINT
+ pthread_exit(0);
+#endif
+ return 0;
+}
+
+gRC &gRC::getInstance()
+{
+ return *instance;
+}
+
+static int gPainter_instances;
+
+gPainter::gPainter(gDC &dc, eRect rect): dc(dc), rc(gRC::getInstance()), foregroundColor(0), backgroundColor(0)
+{
+ if (rect.isNull())
+ rect=eRect(ePoint(0, 0), dc.getSize());
+// ASSERT(!gPainter_instances);
+ gPainter_instances++;
+ begin(rect);
+}
+
+gPainter::~gPainter()
+{
+ end();
+ gPainter_instances--;
+}
+
+void gPainter::begin(const eRect &rect)
+{
+ gOpcode o;
+ dc.lock();
+ o.dc=&dc;
+ o.opcode=gOpcode::begin;
+ o.parm.begin=new gOpcode::para::pbegin(rect);
+// cliparea=std::stack<eRect, std::list<eRect> >();
+ cliparea=std::stack<eRect>();
+ cliparea.push(rect);
+ setLogicalZero(cliparea.top().topLeft());
+ rc.submit(o);
+}
+
+void gPainter::setBackgroundColor(const gColor &color)
+{
+ backgroundColor=color;
+}
+
+void gPainter::setForegroundColor(const gColor &color)
+{
+ foregroundColor=color;
+}
+
+void gPainter::setFont(const gFont &mfont)
+{
+ font=mfont;
+}
+
+void gPainter::renderText(const eRect &pos, const std::string &string, int flags)
+{
+ eRect area=pos;
+ area.moveBy(logicalZero.x(), logicalZero.y());
+
+ gOpcode o;
+ o.dc=&dc;
+ o.opcode=gOpcode::renderText;
+ o.parm.renderText=new gOpcode::para::prenderText(font, area, string, dc.getRGB(foregroundColor), dc.getRGB(backgroundColor));
+ o.flags=flags;
+ rc.submit(o);
+}
+
+void gPainter::renderPara(eTextPara &para, ePoint offset)
+{
+ gOpcode o;
+ o.dc=&dc;
+ o.opcode=gOpcode::renderPara;
+ o.parm.renderPara=new gOpcode::para::prenderPara(logicalZero+offset, para.grab(), dc.getRGB(foregroundColor), dc.getRGB(backgroundColor));
+ rc.submit(o);
+}
+
+void gPainter::fill(const eRect &area)
+{
+ gOpcode o;
+ o.dc=&dc;
+ o.opcode=gOpcode::fill;
+ eRect a=area;
+ a.moveBy(logicalZero.x(), logicalZero.y());
+ a&=cliparea.top();
+
+ o.parm.fill=new gOpcode::para::pfill(a, foregroundColor);
+ rc.submit(o);
+}
+
+void gPainter::clear()
+{
+ gOpcode o;
+ o.dc=&dc;
+ o.opcode=gOpcode::fill;
+ o.parm.fill=new gOpcode::para::pfill(cliparea.top(), backgroundColor);
+ rc.submit(o);
+}
+
+void gPainter::setPalette(gRGB *colors, int start, int len)
+{
+ gOpcode o;
+ o.dc=&dc;
+ o.opcode=gOpcode::setPalette;
+ gPalette *p=new gPalette;
+
+ p->data=new gRGB[len];
+ memcpy(p->data, colors, len*sizeof(gRGB));
+ p->start=start;
+ p->colors=len;
+ o.parm.setPalette=new gOpcode::para::psetPalette(p);
+ rc.submit(o);
+}
+
+void gPainter::mergePalette(gPixmap *target)
+{
+ gOpcode o;
+ o.dc=&dc;
+ o.opcode=gOpcode::mergePalette;
+ o.parm.mergePalette=new gOpcode::para::pmergePalette(target);
+ rc.submit(o);
+}
+
+void gPainter::line(ePoint start, ePoint end)
+{
+ gOpcode o;
+ o.dc=&dc;
+ o.opcode=gOpcode::line;
+ o.parm.line=new gOpcode::para::pline(start+logicalZero, end+logicalZero, foregroundColor);
+ rc.submit(o);
+}
+
+void gPainter::setLogicalZero(ePoint rel)
+{
+ logicalZero=rel;
+}
+
+void gPainter::moveLogicalZero(ePoint rel)
+{
+ logicalZero+=rel;
+}
+
+void gPainter::resetLogicalZero()
+{
+ logicalZero.setX(0);
+ logicalZero.setY(0);
+}
+
+void gPainter::clip(eRect clip)
+{
+ gOpcode o;
+ o.dc=&dc;
+ o.opcode=gOpcode::clip;
+ clip.moveBy(logicalZero.x(), logicalZero.y());
+ cliparea.push(cliparea.top()&clip);
+ o.parm.clip=new gOpcode::para::pclip(cliparea.top());
+
+ rc.submit(o);
+}
+
+void gPainter::clippop()
+{
+ ASSERT (cliparea.size()>1);
+ gOpcode o;
+ o.dc=&dc;
+ o.opcode=gOpcode::clip;
+ cliparea.pop();
+ o.parm.clip=new gOpcode::para::pclip(cliparea.top());
+ rc.submit(o);
+}
+
+void gPainter::flush()
+{
+ gOpcode o;
+ o.dc=&dc;
+ o.opcode=gOpcode::flush;
+ rc.submit(o);
+}
+
+void gPainter::end()
+{
+ gOpcode o;
+ o.dc=&dc;
+ o.opcode=gOpcode::end;
+ rc.submit(o);
+}
+
+gDC::~gDC()
+{
+}
+
+gPixmapDC::gPixmapDC(): pixmap(0)
+{
+}
+
+gPixmapDC::gPixmapDC(gPixmap *pixmap): pixmap(pixmap)
+{
+}
+
+gPixmapDC::~gPixmapDC()
+{
+ dclock.lock();
+}
+
+void gPixmapDC::exec(gOpcode *o)
+{
+ switch(o->opcode)
+ {
+ case gOpcode::begin:
+ clip=o->parm.begin->area;
+ delete o->parm.begin;
+ break;
+ case gOpcode::renderText:
+ {
+ eTextPara *para=new eTextPara(o->parm.renderText->area);
+ para->setFont(o->parm.renderText->font);
+ para->renderString(o->parm.renderText->text, o->flags);
+ para->blit(*this, ePoint(0, 0), o->parm.renderText->backgroundColor, o->parm.renderText->foregroundColor);
+ para->destroy();
+ delete o->parm.renderText;
+ break;
+ }
+ case gOpcode::renderPara:
+ {
+ o->parm.renderPara->textpara->blit(*this, o->parm.renderPara->offset, o->parm.renderPara->backgroundColor, o->parm.renderPara->foregroundColor);
+ o->parm.renderPara->textpara->destroy();
+ delete o->parm.renderPara;
+ break;
+ }
+ case gOpcode::fill:
+ pixmap->fill(o->parm.fill->area, o->parm.fill->color);
+ delete o->parm.fill;
+ break;
+ case gOpcode::blit:
+ {
+ if (o->parm.blit->clip.isNull())
+ o->parm.blit->clip=clip;
+ else
+ o->parm.blit->clip&=clip;
+ pixmap->blit(*o->parm.blit->pixmap, o->parm.blit->position, o->parm.blit->clip, o->flags);
+ delete o->parm.blit;
+ break;
+ }
+ case gOpcode::setPalette:
+ if (o->parm.setPalette->palette->start>pixmap->clut.colors)
+ o->parm.setPalette->palette->start=pixmap->clut.colors;
+ if (o->parm.setPalette->palette->colors>(pixmap->clut.colors-o->parm.setPalette->palette->start))
+ o->parm.setPalette->palette->colors=pixmap->clut.colors-o->parm.setPalette->palette->start;
+ if (o->parm.setPalette->palette->colors)
+ memcpy(pixmap->clut.data+o->parm.setPalette->palette->start, o->parm.setPalette->palette->data, o->parm.setPalette->palette->colors*sizeof(gRGB));
+ delete[] o->parm.setPalette->palette->data;
+ delete o->parm.setPalette->palette;
+ delete o->parm.setPalette;
+ break;
+ case gOpcode::mergePalette:
+ pixmap->mergePalette(*o->parm.blit->pixmap);
+ delete o->parm.blit;
+ break;
+ case gOpcode::line:
+ pixmap->line(o->parm.line->start, o->parm.line->end, o->parm.line->color);
+ delete o->parm.line;
+ break;
+ case gOpcode::clip:
+ clip=o->parm.clip->clip;
+ delete o->parm.clip;
+ break;
+ case gOpcode::end:
+ unlock();
+ case gOpcode::flush:
+ break;
+ default:
+ eFatal("illegal opcode %d. expect memory leak!", o->opcode);
+ }
+}
+
+gRGB gPixmapDC::getRGB(gColor col)
+{
+ if ((!pixmap) || (!pixmap->clut.data))
+ return gRGB(col, col, col);
+ if (col<0)
+ {
+ eFatal("bla transp");
+ return gRGB(0, 0, 0, 0xFF);
+ }
+ return pixmap->clut.data[col];
+}
+
+eAutoInitP0<gRC> init_grc(eAutoInitNumbers::graphic, "gRC");
diff --git a/lib/gdi/grc.h b/lib/gdi/grc.h
new file mode 100644
index 00000000..53cd4a8c
--- /dev/null
+++ b/lib/gdi/grc.h
@@ -0,0 +1,245 @@
+#ifndef __grc_h
+#define __grc_h
+
+/*
+ gPainter ist die high-level version. die highlevel daten werden zu low level opcodes ueber
+ die gRC-queue geschickt und landen beim gDC der hardwarespezifisch ist, meist aber auf einen
+ gPixmap aufsetzt (und damit unbeschleunigt ist).
+*/
+
+#include <pthread.h>
+#include <stack>
+#include <list>
+
+#include <lib/base/estring.h>
+#include <lib/base/ringbuffer.h>
+#include <lib/gdi/erect.h>
+#include <lib/base/elock.h>
+#include <lib/gdi/gpixmap.h>
+
+
+class eTextPara;
+
+class gDC;
+struct gOpcode
+{
+ enum Opcode
+ {
+ begin,
+
+ renderText,
+ renderPara,
+
+ fill,
+ blit,
+
+ setPalette,
+ mergePalette,
+
+ line,
+
+ clip,
+
+ flush,
+ end,
+
+ shutdown
+ } opcode;
+
+ union para
+ {
+ struct pbegin
+ {
+ eRect area;
+ pbegin(const eRect &area): area(area) { }
+ } *begin;
+
+ struct pfill
+ {
+ eRect area;
+ gColor color;
+ pfill(const eRect &area, gColor color): area(area), color(color) { }
+ } *fill;
+
+ struct prenderText
+ {
+ gFont font;
+ eRect area;
+ eString text;
+ gRGB foregroundColor, backgroundColor;
+ prenderText(const gFont &font, const eRect &area, const eString &text, const gRGB &foregroundColor, const gRGB &backgroundColor):
+ font(font), area(area), text(text), foregroundColor(foregroundColor), backgroundColor(backgroundColor) { }
+ } *renderText;
+
+ struct prenderPara
+ {
+ ePoint offset;
+ eTextPara *textpara;
+ gRGB foregroundColor, backgroundColor;
+ prenderPara(const ePoint &offset, eTextPara *textpara, const gRGB &foregroundColor, const gRGB &backgroundColor)
+ : offset(offset), textpara(textpara), foregroundColor(foregroundColor), backgroundColor(backgroundColor) { }
+ } *renderPara;
+
+ struct psetPalette
+ {
+ gPalette *palette;
+ psetPalette(gPalette *palette): palette(palette) { }
+ } *setPalette;
+
+ struct pblit
+ {
+ ePtr<gPixmap> pixmap;
+ ePoint position;
+ eRect clip;
+ pblit(gPixmap *pixmap, const ePoint &position, const eRect &clip)
+ : pixmap(pixmap), position(position), clip(clip) { }
+ } *blit;
+
+ struct pmergePalette
+ {
+ ePtr<gPixmap> target;
+ pmergePalette(gPixmap *target): target(target) { }
+ } *mergePalette;
+
+ struct pline
+ {
+ ePoint start, end;
+ gColor color;
+ pline(const ePoint &start, const ePoint &end, gColor color): start(start), end(end), color(color) { }
+ } *line;
+
+ struct pclip
+ {
+ eRect clip;
+ pclip(const eRect &clip): clip(clip) { }
+ } *clip;
+ } parm;
+
+ int flags;
+
+ gDC *dc;
+};
+
+class gRC
+{
+ static gRC *instance;
+
+ static void *thread_wrapper(void *ptr);
+ pthread_t the_thread;
+ void *thread();
+
+ eLock queuelock;
+
+ queueRingBuffer<gOpcode> queue;
+public:
+ gRC();
+ virtual ~gRC();
+
+ void submit(const gOpcode &o)
+ {
+ static int collected=0;
+ queue.enqueue(o);
+ collected++;
+ if (o.opcode==gOpcode::end)
+ {
+ queuelock.unlock(collected);
+#ifdef SYNC_PAINT
+ thread();
+#endif
+ collected=0;
+ }
+ }
+
+ static gRC &getInstance();
+};
+
+class gPainter
+{
+ gDC &dc;
+ gRC &rc;
+ friend class gRC;
+
+ gOpcode *beginptr;
+ /* paint states */
+// std::stack<eRect, std::list<eRect> > cliparea;
+ std::stack<eRect> cliparea;
+ gFont font;
+ gColor foregroundColor, backgroundColor;
+ ePoint logicalZero;
+ void begin(const eRect &rect);
+ void end();
+public:
+ gPainter(gDC &dc, eRect rect=eRect());
+ virtual ~gPainter();
+
+ void setBackgroundColor(const gColor &color);
+ void setForegroundColor(const gColor &color);
+
+ void setFont(const gFont &font);
+ void renderText(const eRect &position, const std::string &string, int flags=0);
+ void renderPara(eTextPara &para, ePoint offset=ePoint(0, 0));
+
+ void fill(const eRect &area);
+
+ void clear();
+
+ void gPainter::blit(gPixmap *pixmap, ePoint pos, eRect clip=eRect(), int flags=0)
+ {
+ gOpcode o;
+ o.dc=&dc;
+ o.opcode=gOpcode::blit;
+ pos+=logicalZero;
+ clip.moveBy(logicalZero.x(), logicalZero.y());
+ o.parm.blit=new gOpcode::para::pblit(pixmap, pos, clip);
+ o.flags=flags;
+ rc.submit(o);
+ }
+
+ void setPalette(gRGB *colors, int start=0, int len=256);
+ void mergePalette(gPixmap *target);
+
+ void line(ePoint start, ePoint end);
+
+ void setLogicalZero(ePoint abs);
+ void moveLogicalZero(ePoint rel);
+ void resetLogicalZero();
+
+ void clip(eRect clip);
+ void clippop();
+
+ void flush();
+};
+
+class gDC
+{
+protected:
+ eLock dclock;
+public:
+ virtual void exec(gOpcode *opcode)=0;
+ virtual RESULT getPixmap(ePtr<gPixmap> &)=0;
+ virtual eSize getSize()=0;
+ virtual const eRect &getClip()=0;
+ virtual gRGB getRGB(gColor col)=0;
+ virtual ~gDC();
+ void lock() { dclock.lock(1); }
+ void unlock() { dclock.unlock(1); }
+};
+
+class gPixmapDC: public gDC
+{
+protected:
+ ePtr<gPixmap> pixmap;
+ eRect clip;
+
+ void exec(gOpcode *opcode);
+ gPixmapDC();
+public:
+ gPixmapDC(gPixmap *pixmap);
+ virtual ~gPixmapDC();
+ RESULT getPixmap(ePtr<gPixmap> &ptr) { ptr = pixmap; return 0; }
+ gRGB getRGB(gColor col);
+ const eRect &getClip() { return clip; }
+ virtual eSize getSize() { return eSize(pixmap->x, pixmap->y); }
+};
+
+#endif
diff --git a/lib/gdi/lcd.cpp b/lib/gdi/lcd.cpp
new file mode 100644
index 00000000..844ad08f
--- /dev/null
+++ b/lib/gdi/lcd.cpp
@@ -0,0 +1,210 @@
+#ifndef DISABLE_LCD
+
+#include <lib/gdi/lcd.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <dbox/fp.h>
+#include <dbox/lcd-ks0713.h>
+
+#include <lib/gdi/esize.h>
+#include <lib/base/init.h>
+#include <lib/base/init_num.h>
+#include <lib/gdi/glcddc.h>
+#include <lib/base/econfig.h>
+
+eDBoxLCD *eDBoxLCD::instance;
+
+eLCD::eLCD(eSize size): res(size)
+{
+ locked=0;
+ _buffer=new unsigned char[res.height()*res.width()];
+ _stride=res.width();
+}
+
+eLCD::~eLCD()
+{
+ delete [] _buffer;
+}
+
+int eLCD::lock()
+{
+ if (locked)
+ return -1;
+
+ locked=1;
+ return lcdfd;
+}
+
+void eLCD::unlock()
+{
+ read( lcdfd, NULL, 0);
+ if ( errno == 9 )
+ {
+ eDebug("reopen lcd");
+ lcdfd=open("/dev/dbox/lcd0", O_RDWR); // reopen device
+ }
+ else
+ eDebug("do not reopen lcd.. errno = %d", errno);
+
+ locked=0;
+}
+
+/* void eLCD::line(ePoint start, ePoint dst, int color)
+{
+int Ax=start.x(), // dieser code rult ganz ganz doll weil er ganz ganz fast ist und auch sehr gut dokumentiert is
+Ay=start.y(), Bx=dst.x(), // t. es handelt sich immerhin um den weltbekannten bresenham algorithmus der nicht nur
+By=dst.y(); int dX, dY, fbXincr, // sehr schnell ist sondern auch sehr gut dokumentiert und getestet wurde. nicht
+fbYincr, fbXYincr, dPr, dPru, P; __u8 // nur auf dem LCD der dbox, sondern auch ueberall anders. und auch auf der
+*AfbAddr = &buffer()[Ay*stride()+Ax]; __u8 // dbox mit LCD soll das teil nun tun, und ich denke das tut es. ausse
+*BfbAddr = &buffer()[By*stride()+Bx]; fbXincr= // rdem hat dieser algo den vorteil dass man fehler sehr leicht fi
+1; if ( (dX=Bx-Ax) >= 0) goto AFTERNEGX; dX=-dX; // ndet und beheben kann. das liegt nicht zuletzt an den komment
+fbXincr=-1; AFTERNEGX: fbYincr=stride(); if ( (dY=By // aren. und ausserdem, je kuerzer der code, desto weniger k
+-Ay) >= 0) goto AFTERNEGY; fbYincr=-stride(); dY=-dY;AFTERNEGY: // ann daran falsch sein. erwaehnte ich schon, da
+fbXYincr = fbXincr+fbYincr; if (dY > dX) goto YisIndependent; dPr = dY+ // s dieser tolle code wahnsinnig schnell
+dY; P = -dX; dPru = P+P; dY = dX>>1; XLOOP: *AfbAddr=color; *BfbAddr=color; if ((P+=dPr) > 0) // ist? bye, tmbinc
+goto RightAndUp; AfbAddr+=fbXincr; BfbAddr-=fbXincr; if ((dY=dY-1) > 0) goto XLOOP; *AfbAddr=color; if ((dX & 1)
+== 0) return; *BfbAddr=color; return; RightAndUp: AfbAddr+=fbXYincr; BfbAddr-=fbXYincr; P+=dPru; if ((dY=dY-1) >
+0) goto XLOOP; *AfbAddr=color; if ((dX & 1) == 0) return; *BfbAddr=color; return; YisIndependent: dPr = dX+dX; P
+= -dY; dPru = P+P; dX = dY>>1; YLOOP: *AfbAddr=color; *BfbAddr=color; if ((P+=dPr) > 0) goto RightAndUp2; AfbAddr
++=fbYincr; BfbAddr-=fbYincr; if ((dX=dX-1) > 0) goto YLOOP; *AfbAddr=color; if ((dY & 1) == 0) return; *BfbAddr=
+color;return; RightAndUp2: AfbAddr+=fbXYincr; BfbAddr-=fbXYincr; P+=dPru; if ((dX=dX-1) > 0) goto YLOOP; *AfbAddr
+=color; if((dY & 1) == 0) return; *BfbAddr=color; return; // nun ist der tolle code leider zu ende. tut mir leid.
+} */
+
+eDBoxLCD::eDBoxLCD(): eLCD(eSize(128, 64))
+{
+#ifndef NO_LCD
+ lcdfd=open("/dev/dbox/lcd0", O_RDWR);
+#else
+ lcdfd=-1;
+#endif
+ instance=this;
+
+ if (lcdfd<0)
+ eDebug("couldn't open LCD - load lcd.o!");
+ else
+ {
+ int i=LCD_MODE_BIN;
+ ioctl(lcdfd, LCD_IOCTL_ASC_MODE, &i);
+ int lcdbrightness=0, lcdcontrast=0;
+
+ if( eConfig::getInstance()->getKey("/ezap/lcd/brightness", lcdbrightness) )
+ {
+ lcdbrightness=130;
+ eConfig::getInstance()->setKey("/ezap/lcd/brightness", lcdbrightness);
+ }
+ if( eConfig::getInstance()->getKey("/ezap/lcd/contrast", lcdcontrast) )
+ {
+ lcdcontrast=32;
+ eConfig::getInstance()->setKey("/ezap/lcd/contrast", lcdcontrast);
+ }
+ setLCDParameter(lcdbrightness, lcdcontrast);
+ int tmp;
+ if( eConfig::getInstance()->getKey("/ezap/lcd/inverted", tmp ) )
+ {
+ inverted=0;
+ eConfig::getInstance()->setKey("/ezap/lcd/inverted", (int) 0 );
+ }
+ else
+ inverted=(unsigned char)tmp;
+ }
+}
+
+void eDBoxLCD::setInverted(unsigned char inv)
+{
+ inverted=inv;
+ update();
+}
+
+int eDBoxLCD::setLCDParameter(int brightness, int contrast)
+{
+ int fp;
+ if((fp=open("/dev/dbox/fp0", O_RDWR))<=0)
+ {
+ eDebug("[LCD] can't open /dev/dbox/fp0");
+ return(-1);
+ }
+
+ if(ioctl(lcdfd, LCD_IOCTL_SRV, &contrast))
+ {
+ eDebug("[LCD] can't set lcd contrast");
+ }
+
+ if(ioctl(fp, FP_IOCTL_LCD_DIMM, &brightness))
+ {
+ eDebug("[LCD] can't set lcd brightness");
+ }
+ eDebug("[LCD] set brightness %d, contrast %d", brightness, contrast);
+ return(0);
+}
+
+int eDBoxLCD::switchLCD(int state)
+{
+ int lcdbrightness, lcdcontrast, lcdstandby=0;
+
+ eConfig::getInstance()->getKey("/ezap/lcd/contrast", lcdcontrast);
+
+ if(state==0)
+ {
+ eConfig::getInstance()->getKey("/ezap/lcd/standby", lcdstandby);
+ setLCDParameter(lcdstandby, lcdcontrast);
+ }
+ else
+ {
+ eConfig::getInstance()->getKey("/ezap/lcd/brightness", lcdbrightness);
+ setLCDParameter(lcdbrightness, lcdcontrast);
+
+ }
+ return(0);
+}
+
+eDBoxLCD::~eDBoxLCD()
+{
+ if (lcdfd>0)
+ close(lcdfd);
+}
+
+eDBoxLCD *eDBoxLCD::getInstance()
+{
+ return instance;
+}
+
+void eDBoxLCD::update()
+{
+ if (!locked)
+ {
+ unsigned char raw[120*8];
+ int x, y, yy;
+ for (y=0; y<8; y++)
+ {
+ for (x=0; x<120; x++)
+ {
+ int pix=0;
+ for (yy=0; yy<8; yy++)
+ {
+ pix|=(_buffer[(y*8+yy)*128+x]>=108)<<yy;
+ }
+ raw[y*120+x]=(pix^inverted);
+ }
+ }
+ if (lcdfd>0)
+ write(lcdfd, raw, 120*8);
+ }
+}
+
+class eDBoxLCDHardware
+{
+ eDBoxLCD lcd;
+ gLCDDC lcddc;
+public:
+ eDBoxLCDHardware(): lcddc(&lcd)
+ {
+ }
+};
+
+eAutoInitP0<eDBoxLCDHardware> init_eDBoxLCDHardware(eAutoInitNumbers::lowlevel, "d-Box LCD Hardware");
+
+#endif //DISABLE_LCD
diff --git a/lib/gdi/lcd.h b/lib/gdi/lcd.h
new file mode 100644
index 00000000..567d0649
--- /dev/null
+++ b/lib/gdi/lcd.h
@@ -0,0 +1,53 @@
+#ifndef DISABLE_LCD
+
+#ifndef __lcd_h
+#define __lcd_h
+
+#include <asm/types.h>
+#include <lib/gdi/esize.h>
+#include <lib/gdi/erect.h>
+
+#define LCD_CONTRAST_MIN 0
+#define LCD_CONTRAST_MAX 63
+#define LCD_BRIGHTNESS_MIN 0
+#define LCD_BRIGHTNESS_MAX 255
+
+class eLCD
+{
+protected:
+ eSize res;
+ unsigned char *_buffer;
+ int lcdfd;
+ int _stride;
+ int locked;
+public:
+ int lock();
+ void unlock();
+
+ eLCD(eSize size);
+ virtual ~eLCD();
+
+ __u8 *buffer() { return (__u8*)_buffer; }
+ int stride() { return _stride; }
+ eSize size() { return res; }
+
+ virtual void update()=0;
+};
+
+class eDBoxLCD: public eLCD
+{
+ static eDBoxLCD *instance;
+ unsigned char inverted;
+public:
+ static eDBoxLCD *getInstance();
+ int switchLCD(int state);
+ int setLCDParameter(int brightness, int contrast);
+ void setInverted( unsigned char );
+ eDBoxLCD();
+ ~eDBoxLCD();
+ void update();
+};
+
+#endif
+
+#endif //DISABLE_LCD