#include #include #include #include "font.H" Character::Character(class ScalableFont *sf,char c_in) : dpy(sf->dpy), c(c_in) { XCharStruct *cs; cs = &sf->fs->per_char[((unsigned char)c)-sf->fs->min_char_or_byte2]; w = cs->rbearing - cs->lbearing; h = cs->ascent + cs->descent; offx = cs->lbearing; offy = cs->ascent; addx = cs->width; addy = 0; pix = 0; img = 0; Init(sf); switch(sf->mode) { case 0: break; case 90: TurnLeft(); break; case 180: Mirror(); break; case 270: TurnRight(); break; case 360: break; case -90: FlipY(); TurnRight(); break; case -180: FlipX(); break; case -270: FlipY(); TurnLeft(); break; case -360: FlipY(); break; default: break; } } Character::~Character() { DropData(); } void Character::Init(class ScalableFont *sf) { DropPix(); pix = XCreatePixmap(dpy,DefaultRootWindow(dpy),w,h,1); XGCValues values; values.foreground = 0; values.background = 0; if (sf) values.font = sf->fs->fid; GC gc=XCreateGC(dpy,pix, ((sf)?GCFont:0)|GCForeground|GCBackground,&values); XFillRectangle(dpy,pix,gc,0,0,w,h); /* clear background */ XSetForeground(dpy,gc,1); XDrawString(dpy,pix,gc,-offx,offy,&c,1); XFreeGC(dpy,gc); Pix2Img(); } void Character::PrintImg() { if (!img) return; // // print the data to stdout for debugging // #if (0) XCharStruct *cs; cs = &sf->fs->per_char[((unsigned char)c)-sf->fs->min_char_or_byte2]; #endif for (int y=0;yheight;y++) { for (int x=0;xwidth;x++) { // if (img->data[y*img->bytes_per_line+x/8] & (1<<(7-(x%8)))) if (XGetPixel(img,x,y)) putchar('*'); else putchar('.'); } switch(y) { case 0: printf( " character: %c\n", c ); break; case 1: printf( " width: %3d, height: %3d\n", w, h ); break; case 2: printf( " offx: %3d, offy: %3d\n", offx, offy ); break; case 3: printf( " addx: %3d, addy: %3d\n", addx, addy ); break; #if (0) case 4: printf( " lbearing:%3d, rbearing:%3d\n", cs->lbearing, cs->rbearing ); break; case 5: printf( " ascent: %3d, descent: %3d\n", cs->ascent, cs->descent ); break; case 6: printf( " width: %3d\n", cs->width ); break; #endif default: putchar('\n'); break; } } } void Character::Pix2Img() { DropImg(); img=XGetImage(dpy,pix,0,0,w,h,1,XYPixmap); // PrintImg(); } void Character::TurnRight() { PrepareImg(); XImage *new_img; int bytes_per_line = (img->bitmap_pad/8) * ((img->height+img->bitmap_pad-1)/img->bitmap_pad); char *data = (char*)malloc(bytes_per_line*img->width); new_img = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)), 1,XYBitmap,0,data,img->height,img->width,img->bitmap_pad,bytes_per_line); for (int x=0;xwidth;x++) { for (int y=0;yheight;y++) { XPutPixel(new_img,x,y,XGetPixel(img,y,img->height-1-x)); } } DropImg(); img = new_img; int help; help = offx; offx = offy-h; offy = -help; help = addx; addx = -addy; addy = help; help = w; w = h; h = help; DropPix(); } void Character::TurnLeft() { PrepareImg(); XImage *new_img; int bytes_per_line = (img->bitmap_pad/8) * ((img->height+img->bitmap_pad-1)/img->bitmap_pad); char *data = (char*)malloc(bytes_per_line*img->width); new_img = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)), 1,XYBitmap,0,data,img->height,img->width,img->bitmap_pad,bytes_per_line); for (int x=0;xwidth;x++) { for (int y=0;yheight;y++) { XPutPixel(new_img,x,y,XGetPixel(img,img->width-1-y,x)); } } DropImg(); img = new_img; int help; help = offx; offx = -offy; offy = help+w; help = addx; addx = addy; addy = -help; help = w; w = h; h = help; DropPix(); } void Character::ImgFlipX() { PrepareImg(); for (int y=0;ybytes_per_line>sizeof(buffer)) b_p=new char[img->bytes_per_line]; PrepareImg(); for (int y=0;ydata + y * img->bytes_per_line; char *p2 = img->data + (h-1-y) * img->bytes_per_line; memcpy(buffer,p1,img->bytes_per_line); memcpy(p1,p2,img->bytes_per_line); memcpy(p2,buffer,img->bytes_per_line); } DropPix(); if (b_p!=buffer) delete b_p; } void Character::FlipY() { ImgFlipY(); offy = h-offy; } void Character::Img2Pix() { DropPix(); pix = XCreatePixmap(dpy,DefaultRootWindow(dpy),w,h,1); XGCValues values; values.foreground = 1; values.background = 0; GC gc=XCreateGC(dpy,pix,GCForeground|GCBackground,&values); XFillRectangle(dpy,pix,gc,0,0,w,h); /*** TEST ***/ XPutImage(dpy,pix,gc,img,0,0,0,0,w,h); XFreeGC(dpy,gc); } void Character::Draw( Drawable d, GC gc, int *x, int *y ) { if (!pix) Img2Pix(); #if (0) XCopyPlane(dpy,pix,d,gc,0,0,w,h, (*x)+offx, (*y)-offy,1); #endif #if (1) XGCValues save_val; XGCValues stipple_val; unsigned long valuemask = GCFillStyle|GCStipple|GCTileStipXOrigin|GCTileStipYOrigin; XGetGCValues(dpy,gc,valuemask,&save_val); stipple_val.fill_style = FillStippled; stipple_val.stipple = pix; stipple_val.ts_x_origin = (*x)+offx; stipple_val.ts_y_origin = (*y)-offy; XChangeGC(dpy,gc,valuemask,&stipple_val); XFillRectangle(dpy,d,gc,(*x)+offx,(*y)-offy,w,h); if ( save_val.fill_style!=FillStippled && save_val.fill_style!=FillOpaqueStippled ) valuemask&= ~GCStipple; XChangeGC(dpy,gc,valuemask,&save_val); #endif #if (0) XSetClipMask(dpy,gc,pix); XSetClipOrigin(dpy,gc,(*x)+offx,(*y)-offy); XFillRectangle(dpy,d,gc,(*x)+offx,(*y)-offy,w,h); XSetClipMask(dpy,gc,None); #endif #if (0) XSetStipple(dpy,gc,pix); XSetFillStyle(dpy,gc,FillStippled); XSetTSOrigin(dpy,gc,(*x)+offx,(*y)-offy); XFillRectangle(dpy,d,gc,(*x)+offx,(*y)-offy,w,h); XSetFillStyle(dpy,gc,FillSolid); #endif *x += addx; *y += addy; } void Character::BBox( int *tlx, int *tly, int *brx, int *bry ) { *tlx = offx; *tly = -offy; *brx = *tlx + w; *bry = *tly + h; } // =========================================================================== ScalableFont::ScalableFont( Display *dpy_in, const char *fontname, int mode_in ) : dpy(dpy_in), mode(mode_in) { name=strdup(fontname); fs=XLoadQueryFont(dpy,name); if (!fs) { fprintf(stderr,"ERROR: can't load font\n '%s'\n",name); fprintf(stderr,"you should try to use the font-option on your system\n" ); exit(-1); } nchr = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1; chr = new Character*[nchr]; memset(chr,0,sizeof(Character*)*(nchr)); } ScalableFont::~ScalableFont() { for (int i=nchr-1;i>=0;i--) { if (chr[i]) delete chr[i]; } delete chr; if (fs) { XFreeFont(dpy,fs); } if (name) free(name); } Character *ScalableFont::GetChar(char c) { int id = ((unsigned char)c)-fs->min_char_or_byte2; if (id<0 && id>=nchr) id=0; if (!chr[id]) chr[id] = new Character(this,c); return chr[id]; } const char *ScalableFont::GetString(const char *str) { return str; } void ScalableFont::TurnRight() { mode-=90; if (mode<-360||(mode>=-90&&mode<0)) mode+=360; for (int i=0;iTurnRight(); } } void ScalableFont::TurnLeft() { mode+=90; if (mode>360||(mode>=0&&mode<90)) mode-=360; for (int i=0;iTurnLeft(); } } void ScalableFont::Flip() { mode = (mode>=0)?mode-360:mode+360; if (mode%180==0) { for (int i=0;iFlipY(); } } else { for (int i=0;iFlipX(); } } } void ScalableFont::Draw( Drawable d, GC gc, int x, int y, const char *str ) { const char *str_p = GetString(str); while( *str_p ) { GetChar(*str_p++)->Draw(d,gc,&x,&y); } } void ScalableFont::DrawCentered( Drawable d, GC gc, int x, int y, const char *str ) { const char *str_p = GetString(str); int tlx, tly, brx, bry; BBox(str_p,&tlx,&tly,&brx,&bry); x -= (tlx+brx)/2; y -= (tly+bry)/2; while( *str_p ) { GetChar(*str_p++)->Draw(d,gc,&x,&y); } } void ScalableFont::Width( const char *str, int *ox, int *oy ) { const char *str_p = GetString(str); *ox = *oy = 0; while( *str_p ) { GetChar(*str_p++)->AddWidth(ox,oy); } } void ScalableFont::BBox( const char *str, int *tlx, int *tly, int *brx, int *bry ) { const char *str_p = GetString(str); const int MAX=32767; int ox, oy; int tlx2, tly2, brx2, bry2; ox = oy = 0; *tlx = MAX; *tly = MAX; *brx = -MAX; *bry = -MAX; while( *str_p ) { Character *chr_p=GetChar(*str_p++); chr_p->BBox(&tlx2,&tly2,&brx2,&bry2); tlx2+=ox; tly2+=oy; brx2+=ox; bry2+=oy; if (tlx2<*tlx) *tlx=tlx2; if (tly2<*tly) *tly=tly2; if (brx2>*brx) *brx=brx2; if (bry2>*bry) *bry=bry2; chr_p->AddWidth(&ox,&oy); } } // =========================================================================== FlipFont::FlipFont(Display *dpy, const char *fontname, int mode ) : ScalableFont(dpy,fontname,mode) { } FlipFont::~FlipFont() { } Character *FlipFont::GetChar(char c) { int id = ((unsigned char)c)-fs->min_char_or_byte2; if (id<0 && id>=nchr) id=0; if (!chr[id]) { if (c<0) { int flip_mode = (mode>=0)?mode-360:mode+360; chr[id] = new Character(this,c+128); if (flip_mode%180==0) chr[id]->FlipY(); else chr[id]->FlipX(); } else { chr[id] = new Character(this,c); } } return chr[id]; } const char *FlipFont::GetString(const char *str) { static char mystr[1024]; char *dest; int reverse; if (str==mystr) return str; dest=mystr; reverse=0; while(*str&&dest<(mystr+sizeof(mystr)-1)) { if (*str=='\r') reverse^=1; else { *dest++ = (reverse)?(*str^0x80):*str; } str++; } *dest='\0'; return mystr; }