1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 
5 #include "font.H"
6 
Character(class ScalableFont * sf,char c_in)7 Character::Character(class ScalableFont *sf,char c_in)
8 : dpy(sf->dpy), c(c_in)
9 {
10 XCharStruct *cs;
11 		cs = &sf->fs->per_char[((unsigned char)c)-sf->fs->min_char_or_byte2];
12 
13 		w    = cs->rbearing - cs->lbearing;
14 		h    = cs->ascent   + cs->descent;
15 		offx = cs->lbearing;
16 		offy = cs->ascent;
17 		addx = cs->width;
18 		addy = 0;
19 
20 		pix = 0;
21 		img = 0;
22 
23 		Init(sf);
24 		switch(sf->mode) {
25 		case    0:	break;
26 		case   90:	TurnLeft();				 	break;
27 		case  180:	Mirror();					break;
28 		case  270:	TurnRight();				break;
29 		case  360:	break;
30 		case  -90:	FlipY(); TurnRight();	break;
31 		case -180:	FlipX();						break;
32 		case -270:	FlipY(); TurnLeft();		break;
33 		case -360:	FlipY();						break;
34 		default:		break;
35 		}
36 }
37 
~Character()38 Character::~Character() {
39 		DropData();
40 }
41 
Init(class ScalableFont * sf)42 void Character::Init(class ScalableFont *sf) {
43 		DropPix();
44 
45 		pix = XCreatePixmap(dpy,DefaultRootWindow(dpy),w,h,1);
46 		XGCValues   values;
47 		values.foreground = 0;
48 		values.background = 0;
49 		if (sf)	 values.font = sf->fs->fid;
50 		GC gc=XCreateGC(dpy,pix,
51 								((sf)?GCFont:0)|GCForeground|GCBackground,&values);
52 		XFillRectangle(dpy,pix,gc,0,0,w,h);	/* clear background */
53 		XSetForeground(dpy,gc,1);
54 		XDrawString(dpy,pix,gc,-offx,offy,&c,1);
55 		XFreeGC(dpy,gc);
56 
57 		Pix2Img();
58 }
59 
PrintImg()60 void Character::PrintImg() {
61 	if (!img)		return;
62 	//
63 	// print the data to stdout for debugging
64 	//
65 #if (0)
66 XCharStruct *cs;
67 		cs = &sf->fs->per_char[((unsigned char)c)-sf->fs->min_char_or_byte2];
68 #endif
69 
70 	for (int y=0;y<img->height;y++) {
71 		for (int x=0;x<img->width;x++) {
72 //			if (img->data[y*img->bytes_per_line+x/8] & (1<<(7-(x%8))))
73 			if (XGetPixel(img,x,y))
74 						putchar('*');
75 			else		putchar('.');
76 		}
77 		switch(y) {
78 		case 0:	printf( " character: %c\n", c ); break;
79 		case 1:	printf( " width:   %3d, height:  %3d\n", w, h ); break;
80 		case 2:	printf( " offx:    %3d, offy:    %3d\n", offx, offy ); break;
81 		case 3:	printf( " addx:    %3d, addy:    %3d\n", addx, addy ); break;
82 #if (0)
83 		case 4:	printf( " lbearing:%3d, rbearing:%3d\n",
84 								cs->lbearing, cs->rbearing ); break;
85 		case 5:	printf( " ascent:  %3d, descent: %3d\n",
86 								cs->ascent, cs->descent ); break;
87 		case 6:	printf( " width:   %3d\n", cs->width ); break;
88 #endif
89 		default:	putchar('\n'); break;
90 		}
91 	}
92 }
93 
Pix2Img()94 void Character::Pix2Img() {
95 		DropImg();
96 
97 		img=XGetImage(dpy,pix,0,0,w,h,1,XYPixmap);
98 		// PrintImg();
99 }
100 
TurnRight()101 void Character::TurnRight() {
102 	PrepareImg();
103 
104 XImage	*new_img;
105 int		bytes_per_line = (img->bitmap_pad/8)
106 								* ((img->height+img->bitmap_pad-1)/img->bitmap_pad);
107 char		*data = (char*)malloc(bytes_per_line*img->width);
108 
109 	new_img = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),
110 		1,XYBitmap,0,data,img->height,img->width,img->bitmap_pad,bytes_per_line);
111 
112 	for (int x=0;x<new_img->width;x++) {
113 		for (int y=0;y<new_img->height;y++) {
114 			XPutPixel(new_img,x,y,XGetPixel(img,y,img->height-1-x));
115 		}
116 	}
117 
118 	DropImg();
119 	img = new_img;
120 
121 int help;
122 	help = offx;	offx = offy-h;		offy = -help;
123 	help = addx;	addx = -addy;		addy = help;
124 	help = w;		   w = h;			   h = help;
125 
126 	DropPix();
127 }
128 
TurnLeft()129 void Character::TurnLeft() {
130 	PrepareImg();
131 
132 XImage	*new_img;
133 int		bytes_per_line = (img->bitmap_pad/8)
134 								* ((img->height+img->bitmap_pad-1)/img->bitmap_pad);
135 char		*data = (char*)malloc(bytes_per_line*img->width);
136 
137 	new_img = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),
138 		1,XYBitmap,0,data,img->height,img->width,img->bitmap_pad,bytes_per_line);
139 
140 	for (int x=0;x<new_img->width;x++) {
141 		for (int y=0;y<new_img->height;y++) {
142 			XPutPixel(new_img,x,y,XGetPixel(img,img->width-1-y,x));
143 		}
144 	}
145 
146 	DropImg();
147 	img = new_img;
148 
149 int help;
150 	help = offx;	offx = -offy;		offy = help+w;
151 	help = addx;	addx = addy;		addy = -help;
152 	help = w;		   w = h;			   h = help;
153 
154 	DropPix();
155 }
156 
ImgFlipX()157 void Character::ImgFlipX() {
158 	PrepareImg();
159 	for (int y=0;y<h;y++) {
160 		for (int x=0;x<w/2;x++) {
161 			unsigned long h1=XGetPixel(img,x,y);
162 			unsigned long h2=XGetPixel(img,w-1-x,y);
163 			XPutPixel(img,x,y,h2);
164 			XPutPixel(img,w-1-x,y,h1);
165 		}
166 	}
167 	DropPix();
168 }
169 
FlipX()170 void Character::FlipX() {
171 	ImgFlipX();
172 	offx  = -offx-w;
173 	addx  = -addx;
174 }
175 
ImgFlipY()176 void Character::ImgFlipY() {
177 char buffer[1000];
178 char *b_p=buffer;
179 
180 	if ((unsigned)img->bytes_per_line>sizeof(buffer))	b_p=new char[img->bytes_per_line];
181 	PrepareImg();
182 	for (int y=0;y<h/2;y++) {
183 		char	*p1 = img->data + y * img->bytes_per_line;
184 		char	*p2 = img->data + (h-1-y) * img->bytes_per_line;
185 		memcpy(buffer,p1,img->bytes_per_line);
186 		memcpy(p1,p2,img->bytes_per_line);
187 		memcpy(p2,buffer,img->bytes_per_line);
188 	}
189 	DropPix();
190 	if (b_p!=buffer)									delete b_p;
191 }
192 
FlipY()193 void Character::FlipY() {
194 	ImgFlipY();
195 	offy = h-offy;
196 }
197 
Img2Pix()198 void Character::Img2Pix() {
199 	DropPix();
200 
201 	pix = XCreatePixmap(dpy,DefaultRootWindow(dpy),w,h,1);
202 	XGCValues   values;
203 	values.foreground = 1;
204 	values.background = 0;
205 	GC gc=XCreateGC(dpy,pix,GCForeground|GCBackground,&values);
206 	XFillRectangle(dpy,pix,gc,0,0,w,h);	/*** TEST ***/
207 	XPutImage(dpy,pix,gc,img,0,0,0,0,w,h);
208 	XFreeGC(dpy,gc);
209 }
210 
Draw(Drawable d,GC gc,int * x,int * y)211 void Character::Draw( Drawable d, GC gc, int *x, int *y ) {
212 		if (!pix)	Img2Pix();
213 #if (0)
214 		XCopyPlane(dpy,pix,d,gc,0,0,w,h, (*x)+offx, (*y)-offy,1);
215 #endif
216 #if (1)
217 		XGCValues		save_val;
218 		XGCValues		stipple_val;
219 		unsigned long	valuemask = GCFillStyle|GCStipple|GCTileStipXOrigin|GCTileStipYOrigin;
220 		XGetGCValues(dpy,gc,valuemask,&save_val);
221 		stipple_val.fill_style  = FillStippled;
222 		stipple_val.stipple     = pix;
223 		stipple_val.ts_x_origin = (*x)+offx;
224 		stipple_val.ts_y_origin = (*y)-offy;
225 		XChangeGC(dpy,gc,valuemask,&stipple_val);
226 		XFillRectangle(dpy,d,gc,(*x)+offx,(*y)-offy,w,h);
227 		if (	save_val.fill_style!=FillStippled
228 		&&		save_val.fill_style!=FillOpaqueStippled )		valuemask&= ~GCStipple;
229 		XChangeGC(dpy,gc,valuemask,&save_val);
230 #endif
231 #if (0)
232 		XSetClipMask(dpy,gc,pix);
233 		XSetClipOrigin(dpy,gc,(*x)+offx,(*y)-offy);
234 		XFillRectangle(dpy,d,gc,(*x)+offx,(*y)-offy,w,h);
235 		XSetClipMask(dpy,gc,None);
236 #endif
237 #if (0)
238 		XSetStipple(dpy,gc,pix);
239 		XSetFillStyle(dpy,gc,FillStippled);
240 		XSetTSOrigin(dpy,gc,(*x)+offx,(*y)-offy);
241 		XFillRectangle(dpy,d,gc,(*x)+offx,(*y)-offy,w,h);
242 		XSetFillStyle(dpy,gc,FillSolid);
243 #endif
244 		*x += addx;
245 		*y += addy;
246 }
247 
BBox(int * tlx,int * tly,int * brx,int * bry)248 void Character::BBox( int *tlx, int *tly, int *brx, int *bry ) {
249 	*tlx =  offx;
250 	*tly = -offy;
251 	*brx = *tlx + w;
252 	*bry = *tly + h;
253 }
254 
255 // ===========================================================================
256 
ScalableFont(Display * dpy_in,const char * fontname,int mode_in)257 ScalableFont::ScalableFont( Display *dpy_in, const char *fontname, int mode_in )
258 : dpy(dpy_in), mode(mode_in)
259 {
260 	name=strdup(fontname);
261 	fs=XLoadQueryFont(dpy,name);
262 	if (!fs) {
263 		fprintf(stderr,"ERROR: can't load font\n   '%s'\n",name);
264 		fprintf(stderr,"you should try to use the font-option on your system\n" );
265 		exit(-1);
266 	}
267 	nchr = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
268 	chr = new Character*[nchr];
269 	memset(chr,0,sizeof(Character*)*(nchr));
270 }
271 
~ScalableFont()272 ScalableFont::~ScalableFont() {
273 	for (int i=nchr-1;i>=0;i--) {
274 		if (chr[i])		delete chr[i];
275 	}
276 	delete chr;
277 	if (fs) {
278 		XFreeFont(dpy,fs);
279 	}
280 	if (name)	free(name);
281 }
282 
GetChar(char c)283 Character *ScalableFont::GetChar(char c) {
284 	int id = ((unsigned char)c)-fs->min_char_or_byte2;
285 	if (id<0 && id>=nchr)      id=0;
286 	if (!chr[id])					chr[id] = new Character(this,c);
287 	return chr[id];
288 }
289 
GetString(const char * str)290 const char *ScalableFont::GetString(const char *str) {
291 	return str;
292 }
293 
TurnRight()294 void ScalableFont::TurnRight() {
295 	mode-=90;
296 	if (mode<-360||(mode>=-90&&mode<0))	mode+=360;
297 	for (int i=0;i<nchr;i++) {
298 		if (chr[i])		chr[i]->TurnRight();
299 	}
300 }
301 
TurnLeft()302 void ScalableFont::TurnLeft() {
303 	mode+=90;
304 	if (mode>360||(mode>=0&&mode<90))	mode-=360;
305 	for (int i=0;i<nchr;i++) {
306 		if (chr[i])    chr[i]->TurnLeft();
307 	}
308 }
309 
Flip()310 void ScalableFont::Flip() {
311 	mode = (mode>=0)?mode-360:mode+360;
312 	if (mode%180==0) {
313 		for (int i=0;i<nchr;i++) {
314 			if (chr[i])    chr[i]->FlipY();
315 		}
316 	}
317 	else {
318 		for (int i=0;i<nchr;i++) {
319 			if (chr[i])    chr[i]->FlipX();
320 		}
321 	}
322 }
323 
Draw(Drawable d,GC gc,int x,int y,const char * str)324 void ScalableFont::Draw( Drawable d, GC gc, int x, int y, const char *str ) {
325 const char *str_p = GetString(str);
326 
327 	while( *str_p ) {
328 		GetChar(*str_p++)->Draw(d,gc,&x,&y);
329 	}
330 }
331 
DrawCentered(Drawable d,GC gc,int x,int y,const char * str)332 void ScalableFont::DrawCentered( Drawable d, GC gc, int x, int y, const char *str ) {
333 const char *str_p = GetString(str);
334 int	tlx, tly, brx, bry;
335 
336 	BBox(str_p,&tlx,&tly,&brx,&bry);
337 	x -= (tlx+brx)/2;
338 	y -= (tly+bry)/2;
339 	while( *str_p ) {
340 		GetChar(*str_p++)->Draw(d,gc,&x,&y);
341 	}
342 }
343 
Width(const char * str,int * ox,int * oy)344 void ScalableFont::Width( const char *str, int *ox, int *oy ) {
345 const char *str_p = GetString(str);
346 	*ox = *oy = 0;
347 	while( *str_p ) {
348 		GetChar(*str_p++)->AddWidth(ox,oy);
349 	}
350 }
351 
BBox(const char * str,int * tlx,int * tly,int * brx,int * bry)352 void ScalableFont::BBox( const char *str, int *tlx, int *tly, int *brx, int *bry ) {
353 const char *str_p = GetString(str);
354 const int MAX=32767;
355 int ox, oy;
356 int tlx2, tly2, brx2, bry2;
357 
358 	ox = oy = 0;
359 	*tlx =  MAX; *tly =  MAX;
360 	*brx = -MAX; *bry = -MAX;
361 
362 	while( *str_p ) {
363 		Character *chr_p=GetChar(*str_p++);
364 
365 		chr_p->BBox(&tlx2,&tly2,&brx2,&bry2);
366 		tlx2+=ox; tly2+=oy;
367 		brx2+=ox; bry2+=oy;
368 		if (tlx2<*tlx)		*tlx=tlx2;
369 		if (tly2<*tly)		*tly=tly2;
370 		if (brx2>*brx)		*brx=brx2;
371 		if (bry2>*bry)		*bry=bry2;
372 		chr_p->AddWidth(&ox,&oy);
373 	}
374 }
375 
376 // ===========================================================================
377 
FlipFont(Display * dpy,const char * fontname,int mode)378 FlipFont::FlipFont(Display *dpy, const char *fontname, int mode )
379 : ScalableFont(dpy,fontname,mode) {
380 }
381 
~FlipFont()382 FlipFont::~FlipFont() {
383 }
384 
GetChar(char c)385 Character *FlipFont::GetChar(char c) {
386 	int id = ((unsigned char)c)-fs->min_char_or_byte2;
387 	if (id<0 && id>=nchr)      id=0;
388 	if (!chr[id]) {
389 		if (c<0) {
390 			int flip_mode = (mode>=0)?mode-360:mode+360;
391 			chr[id] = new Character(this,c+128);
392 			if (flip_mode%180==0)	chr[id]->FlipY();
393 			else							chr[id]->FlipX();
394 		}
395 		else {
396 			chr[id] = new Character(this,c);
397 		}
398 	}
399 	return chr[id];
400 }
401 
GetString(const char * str)402 const char *FlipFont::GetString(const char *str) {
403 static char mystr[1024];
404 char *dest;
405 int	reverse;
406 
407 	if (str==mystr)		return str;
408 
409 	dest=mystr;
410 	reverse=0;
411 	while(*str&&dest<(mystr+sizeof(mystr)-1)) {
412 		if (*str=='\r')	reverse^=1;
413 		else {
414 			*dest++ = (reverse)?(*str^0x80):*str;
415 		}
416 		str++;
417 	}
418 	*dest='\0';
419 	return mystr;
420 }
421