1 
2 /* ********************************************************************** */
3 
4 /* xvertext, Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma)
5  *
6  * Permission to use, copy, modify, and distribute this software and its
7  * documentation for any purpose and without fee is hereby granted, provided
8  * that the above copyright notice appear in all copies and that both the
9  * copyright notice and this permission notice appear in supporting
10  * documentation.  All work developed as a consequence of the use of
11  * this program should duly acknowledge such use. No representations are
12  * made about the suitability of this software for any purpose.  It is
13  * provided "as is" without express or implied warranty.
14  */
15 
16 /* ********************************************************************** */
17 
18 // Minor modifications by Chris Cannam for wm2/wmx
19 // Major modifications by Kazushi (Jam) Marukawa for wm2/wmx i18n patch
20 // Minor modifications by Sven Oliver (SvOlli) Moll for wmx multihead support
21 
22 #include <X11/Xlib.h>
23 #include <X11/Xutil.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include "Config.h"
28 #include "Rotated.h"
29 
30 #ifndef CONFIG_USE_XFT
31 
32 /* ---------------------------------------------------------------------- */
33 
34 
35 int xv_errno;
36 
37 static char *my_strdup(const char *);
38 static char *my_strtok(char *, const char *);
39 
40 
41 /* ---------------------------------------------------------------------- */
42 
43 
44 /* *** Routine to mimic `strdup()' (some machines don't have it) *** */
45 
my_strdup(const char * str)46 static char *my_strdup(const char *str)
47 {
48   char *s;
49 
50   if (str == NULL) return NULL;
51 
52   s = (char *)malloc((unsigned)(strlen(str)+1));
53   /* this error is highly unlikely ... */
54   if (s == NULL) {
55     fprintf(stderr, "Fatal error: my_strdup(): Couldn't do malloc (gulp!)\n");
56     exit(1);
57   }
58 
59   strcpy(s, str);
60   return s;
61 }
62 
63 
64 /* ---------------------------------------------------------------------- */
65 
66 
67 /* *** Routine to replace `strtok' : this one returns a zero
68        length string if it encounters two consecutive delimiters *** */
69 
my_strtok(char * str1,const char * str2)70 static char *my_strtok(char *str1, const char *str2)
71 {
72   char *ret;
73   int i, j, stop;
74   static int start, len;
75   static char *stext;
76 
77   /* this error should never occur ... */
78   if (str2 == NULL) {
79     fprintf(stderr,
80 	    "Fatal error: my_strtok(): recieved null delimiter string\n");
81     exit(1);
82   }
83 
84   /* initialise if str1 not NULL ... */
85   if (str1 != NULL) {
86     start = 0;
87     stext = str1;
88     len = strlen(str1);
89   }
90 
91   /* run out of tokens ? ... */
92   if (start >= len) return NULL;
93 
94   /* loop through characters ... */
95   for (i = start; i < len; i++) {
96 
97     /* loop through delimiters ... */
98     stop = 0;
99     for (j = 0; j < strlen(str2); j++)
100       if (stext[i] == str2[j]) stop = 1;
101 
102     if (stop) break;
103   }
104 
105   stext[i] = '\0';
106   ret = stext + start;
107   start = i+1;
108 
109   return ret;
110 }
111 
112 
113 /* ---------------------------------------------------------------------- */
114 
115 
116 /* *** Routine to return version/copyright information *** */
117 
XRotVersion(char * str,int n)118 float XRotVersion(char *str, int n)
119 {
120   if (str != NULL) strncpy(str, XV_COPYRIGHT, n);
121   return XV_VERSION;
122 }
123 
124 
125 /* ---------------------------------------------------------------------- */
126 
127 
128 /* *** Load the rotated version of a given font *** */
129 
XRotLoadFont(Display * dpy,int screen,char * fontname,float angle)130 XRotFontStruct *XRotLoadFont(Display *dpy, int screen,
131 			     char *fontname, float angle)
132 {
133   char val;
134   XImage *I1, *I2;
135   Pixmap canvas;
136   Window root;
137   GC font_gc;
138   char text[3];/*, errstr[300];*/
139   XFontStruct *fontstruct;
140   XRotFontStruct *rotfont;
141   int ichar, i, j, index, boxlen = 60, dir;
142   int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len;
143   int min_char, max_char;
144   unsigned char *vertdata, *bitdata;
145   int ascent, descent, lbearing, rbearing;
146   int on = 1, off = 0;
147 
148   /* make angle positive ... */
149   if (angle < 0) do angle += 360; while (angle < 0);
150 
151   /* get nearest vertical or horizontal direction ... */
152   dir = (int)((angle+45.)/90.)%4;
153 
154   /* useful macros ... */
155   root = RootWindow(dpy,screen);
156 
157   /* create the depth 1 canvas bitmap ... */
158   canvas = XCreatePixmap(dpy, root, boxlen, boxlen, 1);
159 
160   /* create a GC ... */
161   font_gc = XCreateGC(dpy, canvas, 0, 0);
162   XSetBackground(dpy, font_gc, off);
163 
164   /* load the font ... */
165   char **ml;
166   int mc;
167   char *ds;
168 
169   XFontSet fontset;
170   fontset = XCreateFontSet(dpy, fontname, &ml, &mc, &ds);
171   if (fontset) {
172     XFontStruct **fs_list;
173     XFontsOfFontSet(fontset, &fs_list, &ml);
174     fontstruct = fs_list[0];
175   } else {
176     fontstruct = NULL;
177   }
178 #define XTextWidth(x,y,z)     XmbTextEscapement(rotfont->xfontset,y,z)
179 #define XDrawString(t,u,v,w,x,y,z) XmbDrawString(t,u,rotfont->xfontset,v,w,x,y,z)
180 #define XDrawImageString(t,u,v,w,x,y,z) XmbDrawString(t,u,rotfont->xfontset,v,w,x,y,z)
181   if (fontstruct == NULL) {
182     xv_errno = XV_NOFONT;
183     return NULL;
184   }
185 
186   XSetFont(dpy, font_gc, fontstruct->fid);
187 
188   /* allocate space for rotated font ... */
189   rotfont = (XRotFontStruct *)malloc((unsigned)sizeof(XRotFontStruct));
190   if (rotfont == NULL) {
191     xv_errno = XV_NOMEM;
192     return NULL;
193   }
194 
195   /* determine which characters are defined in font ... */
196   min_char = fontstruct->min_char_or_byte2;
197   max_char = fontstruct->max_char_or_byte2;
198 
199   /* we only want printing characters ... */
200   if (min_char<32)  min_char = 32;
201   //  if (max_char>126) max_char = 126; // bad for non-ascii iso
202   if (max_char>255) max_char = 255;
203 
204   /* some overall font data ... */
205   rotfont->name = my_strdup(fontname);
206   rotfont->dir = dir;
207   rotfont->min_char = min_char;
208   rotfont->max_char = max_char;
209   rotfont->max_ascent = fontstruct->max_bounds.ascent;
210   rotfont->max_descent = fontstruct->max_bounds.descent;
211   rotfont->height = rotfont->max_ascent+rotfont->max_descent;
212 
213   /* remember xfontstruct for `normal' text ... */
214   rotfont->xfontset = fontset;
215   rotfont->xfontstruct = fontstruct;
216 
217   /* free pixmap and GC ... */
218   XFreePixmap(dpy, canvas);
219   XFreeGC(dpy, font_gc);
220 
221   return rotfont;
222 }
223 
224 
225 /* ---------------------------------------------------------------------- */
226 
227 
228 /* *** Free the resources associated with a rotated font *** */
229 
XRotUnloadFont(Display * dpy,int screen,XRotFontStruct * rotfont)230 void XRotUnloadFont(Display *dpy, int screen, XRotFontStruct *rotfont)
231 {
232   int ichar;
233 
234   XFreeFontSet(dpy, rotfont->xfontset);
235 
236   /* rotfont should never be referenced again ... */
237   free((char *)rotfont->name);
238   free((char *)rotfont);
239 }
240 
241 
242 /* ---------------------------------------------------------------------- */
243 
244 
245 /* *** Return the width of a string *** */
246 
XRotTextWidth(XRotFontStruct * rotfont,char * str,int len)247 int XRotTextWidth(XRotFontStruct *rotfont, char *str, int len)
248 {
249   int i, width = 0, ichar;
250 
251   if (str == NULL) return 0;
252 
253   width = XTextWidth(rotfont->xfontstruct, str, strlen(str));
254 
255   return width;
256 }
257 
258 
259 /* ---------------------------------------------------------------------- */
260 
261 
262 /* *** A front end to XRotPaintString : mimics XDrawString *** */
263 
XRotDrawString(Display * dpy,int screen,XRotFontStruct * rotfont,Drawable drawable,GC gc,int x,int y,char * str,int len)264 void XRotDrawString(Display *dpy, int screen, XRotFontStruct *rotfont,
265 		    Drawable drawable,
266 		    GC gc, int x, int y, char *str, int len)
267 {
268   static GC my_gc = 0;
269   static int lastscreen = -1;
270 
271   int i, xp, yp, dir, ichar;
272 
273   if (str == NULL || len<1) return;
274 
275   dir = rotfont->dir;
276 
277   if((lastscreen != screen) && (my_gc != 0))
278   {
279     XFreeGC(dpy,my_gc);
280     my_gc = 0;
281   }
282 
283   if(my_gc == 0) my_gc = XCreateGC(dpy, drawable, 0, 0);
284 
285   XCopyGC(dpy, gc, GCForeground|GCBackground, my_gc);
286 
287   /* a horizontal string is easy ... */
288   if (dir == 0) {
289     XSetFillStyle(dpy, my_gc, FillSolid);
290     XSetFont(dpy, my_gc, rotfont->xfontstruct->fid);
291     XDrawString(dpy, drawable, my_gc, x, y, str, len);
292 
293     return;
294   }
295 
296   /* vertical or upside down ... */
297 
298   XImage *I1, *I2;
299   unsigned char *vertdata, *bitdata;
300   int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len;
301   char val;
302 
303   /* useful macros ... */
304   Window root = RootWindow(dpy,screen);
305 
306   int ascent = rotfont->max_ascent;
307   int descent = rotfont->max_descent;
308   int width = XRotTextWidth(rotfont, str, len);
309   int height = rotfont->height;
310   if (width < 1) width = 1;
311   if (height < 1) height = 1;
312 
313   /* glyph width and height when vertical ... */
314   vert_w = width;
315   vert_h = height;
316 
317   /* width in bytes ... */
318   vert_len = (vert_w-1)/8+1;
319 
320   /* create the depth 1 canvas bitmap ... */
321   Pixmap canvas = XCreatePixmap(dpy, root, width, height, 1);
322 
323   /* create a GC ... */
324   GC font_gc = XCreateGC(dpy, canvas, 0, 0);
325   XSetBackground(dpy, font_gc, 0);
326 
327   /* clear canvas */
328   XSetForeground(dpy, font_gc, 0);
329   XFillRectangle(dpy, canvas, font_gc, 0, 0, width, height);
330 
331   /* draw the character centre top right on canvas ... */
332   XSetForeground(dpy, font_gc, 1);
333   XSetFont(dpy, font_gc, rotfont->xfontstruct->fid);
334   XDrawImageString(dpy, canvas, font_gc, 0, height-descent, str, len);
335 
336   /* reserve memory for first XImage ... */
337   vertdata = (unsigned char *) malloc((unsigned)(vert_len*vert_h));
338   if (vertdata == NULL) {
339     xv_errno = XV_NOMEM;
340     return;
341   }
342 
343   /* create the XImage ... */
344   I1 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap,
345 		    0, (char *)vertdata, vert_w, vert_h, 8, 0);
346 
347   if (I1 == NULL) {
348     xv_errno = XV_NOXIMAGE;
349     return;
350   }
351 
352   I1->byte_order = I1->bitmap_bit_order = MSBFirst;
353 
354   /* extract character from canvas ... */
355   XGetSubImage(dpy, canvas, 0, 0,
356 	       vert_w, vert_h, 1, XYPixmap, I1, 0, 0);
357   I1->format = XYBitmap;
358 
359   /* width, height of rotated character ... */
360   if (dir == 2) {
361     bit_w = vert_w;
362     bit_h = vert_h;
363   } else {
364     bit_w = vert_h;
365     bit_h = vert_w;
366   }
367 
368   /* width in bytes ... */
369   bit_len = (bit_w-1)/8 + 1;
370 
371   /* reserve memory for the rotated image ... */
372   bitdata = (unsigned char *)calloc((unsigned)(bit_h*bit_len), 1);
373   if (bitdata == NULL) {
374     xv_errno = XV_NOMEM;
375     return;
376   }
377 
378   /* create the image ... */
379   I2 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0,
380 		    (char *)bitdata, bit_w, bit_h, 8, 0);
381 
382   if (I2 == NULL) {
383     xv_errno = XV_NOXIMAGE;
384     return;
385   }
386 
387   I2->byte_order = I2->bitmap_bit_order = MSBFirst;
388 
389   /* map vertical data to rotated character ... */
390   int j;
391   for (j = 0; j < bit_h; j++) {
392     for (i = 0; i < bit_w; i++) {
393       /* map bits ... */
394       if (dir == 1)
395 	val = vertdata[i*vert_len + (vert_w-j-1)/8] &
396 	  (128>>((vert_w-j-1)%8));
397 
398       else if (dir == 2)
399 	val = vertdata[(vert_h-j-1)*vert_len + (vert_w-i-1)/8] &
400 	  (128>>((vert_w-i-1)%8));
401 
402       else
403 	val = vertdata[(vert_h-i-1)*vert_len + j/8] &
404 	  (128>>(j%8));
405 
406       if (val)
407 	bitdata[j*bit_len + i/8] = bitdata[j*bit_len + i/8] |
408 	  (128>>(i%8));
409     }
410   }
411 
412   /* create this character's bitmap ... */
413   Pixmap image = XCreatePixmap(dpy, root, bit_w, bit_h, 1);
414 
415   /* put the image into the bitmap ... */
416   XPutImage(dpy, image, font_gc, I2, 0, 0, 0, 0, bit_w, bit_h);
417 
418   /* free the image and data ... */
419   XDestroyImage(I1);
420   XDestroyImage(I2);
421   /*      free((char *)bitdata);  -- XDestroyImage does this
422 	  free((char *)vertdata);*/
423 
424   /* free pixmap and GC ... */
425   XFreePixmap(dpy, canvas);
426   XFreeGC(dpy, font_gc);
427 
428   /* suitable offset ... */
429   if (dir == 1) {
430     xp = x-rotfont->max_ascent;
431     yp = y-width; //rotfont->rbearing;
432   }
433   else if (dir == 2) {
434     xp = x-width; //rotfont->rbearing;
435     yp = y-rotfont->max_descent+1;
436   }
437   else {
438     xp = x-rotfont->max_descent+1;
439     yp = y+0; //rotfont->lbearing;
440   }
441 
442   XSetFillStyle(dpy, my_gc, FillStippled);
443   XSetStipple(dpy, my_gc, image);
444   XSetTSOrigin(dpy, my_gc, xp, yp);
445   XFillRectangle(dpy, drawable, my_gc, xp, yp,
446 		 bit_w, bit_h);
447 
448   XFreePixmap(dpy, image);
449 }
450 
451 
452 
453 /* ---------------------------------------------------------------------- */
454 
455 
456 /* *** A front end to XRotPaintAlignedString : uses XRotDrawString *** */
457 
XRotDrawAlignedString(Display * dpy,int screen,XRotFontStruct * rotfont,Drawable drawable,GC gc,int x,int y,char * text,int align)458 void XRotDrawAlignedString(Display *dpy, int screen, XRotFontStruct *rotfont,
459 			   Drawable drawable, GC gc, int x, int y,
460 			   char *text, int align)
461 {
462   int xp = 0, yp = 0, dir;
463   int i, nl = 1, max_width = 0, this_width;
464   char *str1, *str2 = "\n\0", *str3;
465 
466   if (text == NULL)
467     return;
468 
469   dir = rotfont->dir;
470 
471   /* count number of sections in string ... */
472   for (i = 0; i<strlen(text); i++)
473     if (text[i] == '\n')
474       nl++;
475 
476   /* find width of longest section ... */
477   str1 = my_strdup(text);
478   str3 = my_strtok(str1, str2);
479   max_width = XRotTextWidth(rotfont, str3, strlen(str3));
480 
481   do {
482     str3 = my_strtok((char *)NULL, str2);
483     if (str3 != NULL)
484       if (XRotTextWidth(rotfont, str3, strlen(str3))>max_width)
485 	max_width = XRotTextWidth(rotfont, str3, strlen(str3));
486   }
487   while (str3 != NULL);
488 
489   /* calculate vertical starting point according to alignment policy and
490      rotation angle ... */
491   if (dir == 0) {
492     if (align == TLEFT || align == TCENTRE || align == TRIGHT)
493       yp = y+rotfont->max_ascent;
494 
495     else if (align == BLEFT || align == BCENTRE || align == BRIGHT)
496       yp = y-(nl-1)*rotfont->height - rotfont->max_descent;
497 
498     else
499       yp = y-(nl-1)/2*rotfont->height + rotfont->max_ascent -
500 	rotfont->height/2 - ((nl%2 == 0)?rotfont->height/2:0);
501   }
502 
503   else if (dir == 1) {
504     if (align == TLEFT || align == TCENTRE || align == TRIGHT)
505       xp = x+rotfont->max_ascent;
506 
507     else if (align == BLEFT || align == BCENTRE || align == BRIGHT)
508       xp = x-(nl-1)*rotfont->height - rotfont->max_descent;
509 
510     else
511       xp = x-(nl-1)/2*rotfont->height + rotfont->max_ascent -
512 	rotfont->height/2 - ((nl%2 == 0)?rotfont->height/2:0);
513   }
514 
515   else if (dir == 2) {
516     if (align == TLEFT || align == TCENTRE || align == TRIGHT)
517       yp = y-rotfont->max_ascent;
518 
519     else if (align == BLEFT || align == BCENTRE || align == BRIGHT)
520       yp = y+(nl-1)*rotfont->height + rotfont->max_descent;
521 
522     else
523       yp = y+(nl-1)/2*rotfont->height - rotfont->max_ascent +
524 	rotfont->height/2 + ((nl%2 == 0)?rotfont->height/2:0);
525   }
526 
527   else {
528     if (align == TLEFT || align == TCENTRE || align == TRIGHT)
529       xp = x-rotfont->max_ascent;
530 
531     else if (align == BLEFT || align == BCENTRE || align == BRIGHT)
532       xp = x+(nl-1)*rotfont->height + rotfont->max_descent;
533 
534     else
535       xp = x+(nl-1)/2*rotfont->height - rotfont->max_ascent +
536 	rotfont->height/2 + ((nl%2 == 0)?rotfont->height/2:0);
537   }
538 
539   free(str1);
540   str1 = my_strdup(text);
541   str3 = my_strtok(str1, str2);
542 
543   /* loop through each section in the string ... */
544   do {
545     /* width of this section ... */
546     this_width = XRotTextWidth(rotfont, str3, strlen(str3));
547 
548     /* horizontal alignment ... */
549     if (dir == 0) {
550       if (align == TLEFT || align == MLEFT || align == BLEFT)
551 	xp = x;
552 
553       else if (align == TCENTRE || align == MCENTRE || align == BCENTRE)
554 	xp = x-this_width/2;
555 
556       else
557 	xp = x-max_width;
558     }
559 
560     else if (dir == 1) {
561       if (align == TLEFT || align == MLEFT || align == BLEFT)
562 	yp = y;
563 
564       else if (align == TCENTRE || align == MCENTRE || align == BCENTRE)
565 	yp = y+this_width/2;
566 
567       else
568 	yp = y+max_width;
569     }
570 
571     else if (dir == 2) {
572       if (align == TLEFT || align == MLEFT || align == BLEFT)
573 	xp = x;
574 
575       else if (align == TCENTRE || align == MCENTRE || align == BCENTRE)
576 	xp = x+this_width/2;
577 
578       else
579 	xp = x+max_width;
580     }
581 
582     else {
583       if (align == TLEFT || align == MLEFT || align == BLEFT)
584 	yp = y;
585 
586       else if (align == TCENTRE || align == MCENTRE || align == BCENTRE)
587 	yp = y-this_width/2;
588 
589       else
590 	yp = y-max_width;
591     }
592 
593     /* draw the section ... */
594     XRotDrawString(dpy, screen, rotfont, drawable, gc, xp, yp,
595 		   str3, strlen(str3));
596 
597     str3 = my_strtok((char *)NULL, str2);
598 
599     /* advance position ... */
600     if (dir == 0)
601       yp += rotfont->height;
602     else if (dir == 1)
603       xp += rotfont->height;
604     else if (dir == 2)
605       yp -= rotfont->height;
606     else
607       xp -= rotfont->height;
608   }
609   while (str3 != NULL);
610 
611   free(str1);
612 }
613 
614 #endif
615