Logo ROOT   6.12/07
Reference Guide
Rotated.cxx
Go to the documentation of this file.
1 // @(#)root/x11:$Id$
2 // Author: O.Couet 17/11/93
3 
4 #ifndef _XVERTEXT_INCLUDED_
5 #define _XVERTEXT_INCLUDED_
6 
7 ////////////////////////////////////////////////////////////////////////////////
8 
9 /* ********************************************************************** *
10  *
11  * xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma)
12  *
13  * Alignment definition modified by O.Couet.
14  * Mods IBM/VM by O.Couet.
15  *
16  * Permission to use, copy, modify, and distribute this software and its
17  * documentation for any purpose and without fee is hereby granted, provided
18  * that the above copyright notice appear in all copies and that both the
19  * copyright notice and this permission notice appear in supporting
20  * documentation. All work developed as a consequence of the use of
21  * this program should duly acknowledge such use. No representations are
22  * made about the suitability of this software for any purpose. It is
23  * provided "as is" without express or implied warranty.
24  *
25  * ********************************************************************** */
26 
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <X11/Xatom.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 
34 #include "TMath.h"
35 
36 /* ************************************************************************ *
37  *
38  * Header file for the `xvertext 5.0' routines.
39  *
40  * Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma)
41  *
42  * ************************************************************************ */
43 
44 #define XV_VERSION 5.0
45 #define XV_COPYRIGHT \
46  "xvertext routines Copyright (c) 1993 Alan Richardson"
47 
48 /* ---------------------------------------------------------------------- */
49 
50 /* text alignment */
51 
52 #define NONE 0
53 #define TLEFT 1
54 #define TCENTRE 2
55 #define TRIGHT 3
56 #define MLEFT 4
57 #define MCENTRE 5
58 #define MRIGHT 6
59 #define BLEFT 7
60 #define BCENTRE 8
61 #define BRIGHT 9
62 
63 #ifdef VAX
64 #define X11R3
65 #endif
66 
67 
68 #endif /* _XVERTEXT_INCLUDED_ */
69 
70 /* ---------------------------------------------------------------------- */
71 
72 /* Make sure cache size is set */
73 
74 #ifndef CACHE_SIZE_LIMIT
75 #define CACHE_SIZE_LIMIT 0
76 #endif /*CACHE_SIZE_LIMIT */
77 
78 /* Make sure a cache method is specified */
79 
80 #ifndef CACHE_XIMAGES
81 #ifndef CACHE_BITMAPS
82 #define CACHE_BITMAPS
83 #endif /*CACHE_BITMAPS*/
84 #endif /*CACHE_XIMAGES*/
85 
86 /* ---------------------------------------------------------------------- */
87 
88 /* Debugging macros */
89 
90 #ifdef DEBUG
91 static int gRotatedDebug=1;
92 #else
93 static int gRotatedDebug=0;
94 #endif /*DEBUG*/
95 
96 #define DEBUG_PRINT1(a) if (gRotatedDebug) printf (a)
97 #define DEBUG_PRINT2(a, b) if (gRotatedDebug) printf (a, b)
98 #define DEBUG_PRINT3(a, b, c) if (gRotatedDebug) printf (a, b, c)
99 #define DEBUG_PRINT4(a, b, c, d) if (gRotatedDebug) printf (a, b, c, d)
100 #define DEBUG_PRINT5(a, b, c, d, e) if (gRotatedDebug) printf (a, b, c, d, e)
101 
102 /* ---------------------------------------------------------------------- */
103 
104 #ifndef M_PI
105 #define M_PI 3.14159265358979323846
106 #endif
107 
108 /* ---------------------------------------------------------------------- */
109 
110 /* A structure holding everything needed for a rotated string */
111 
112 typedef struct RotatedTextItemTemplate_t {
113  Pixmap fBitmap;
114  XImage *fXimage;
115 
116  char *fText;
117  char *font_name;
118  Font fid;
119  float fAngle;
120  int fAlign;
121  float fMagnify;
122 
123  int fColsIn;
124  int fRowsIn;
125  int fColsOut;
126  int fRowsOut;
127 
128  int fNl;
129  int fMaxWidth;
130  float *fCornersX;
131  float *fCornersY;
132 
133  long int fSize;
134  int fCached;
135 
136  struct RotatedTextItemTemplate_t *fNext;
138 
140 
141 /* ---------------------------------------------------------------------- */
142 
143 /* A structure holding current magnification and bounding box padding */
144 
145 static struct StyleTemplate_t {
146  float fMagnify;
147  int fBbxPadl;
148 } gRotStyle={
149  1.,
150  0
151  };
152 
153 /* ---------------------------------------------------------------------- */
154 static char *my_strdup(char *);
155 static char *my_strtok(char *, char *);
156 
157 float XRotVersion(char*, int);
158 void XRotSetMagnification(float);
159 void XRotSetBoundingBoxPad(int);
160 int XRotDrawString(Display*, XFontStruct*, float,Drawable, GC, int, int, char*);
161 int XRotDrawImageString(Display*, XFontStruct*, float,Drawable, GC, int, int, char*);
162 int XRotDrawAlignedString(Display*, XFontStruct*, float,Drawable, GC, int, int, char*, int);
163 int XRotDrawAlignedImageString(Display*, XFontStruct*, float,Drawable, GC, int, int, char*, int);
164 XPoint *XRotTextExtents(Display*, XFontStruct*, float,int, int, char*, int);
165 
166 static XImage *MakeXImage(Display *dpy,int w, int h);
167 static int XRotPaintAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x,int y, char *text,int align, int bg);
168 static int XRotDrawHorizontalString(Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, char *text,int align, int bg);
169 static RotatedTextItem_t *XRotRetrieveFromCache(Display *dpy, XFontStruct *font, float angle, char *text, int align);
170 static RotatedTextItem_t *XRotCreateTextItem(Display *dpy, XFontStruct *font, float angle, char *text, int align);
171 static void XRotAddToLinkedList(Display *dpy, RotatedTextItem_t *item);
172 static void XRotFreeTextItem(Display *dpy, RotatedTextItem_t *item);
173 static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage);
174 
175 
176 ////////////////////////////////////////////////////////////////////////////////
177 /// Routine to mimic `strdup()' (some machines don't have it)
178 
179 static char *my_strdup(char *str)
180 {
181  char *s;
182 
183  if(str==0) return 0;
184 
185  s=(char *)malloc((unsigned)(strlen(str)+1));
186  if(s!=0) strcpy(s, str);
187 
188  return s;
189 }
190 
191 ////////////////////////////////////////////////////////////////////////////////
192 /// Routine to replace `strtok' : this one returns a zero length string if
193 /// it encounters two consecutive delimiters
194 
195 static char *my_strtok(char *str1, char *str2)
196 {
197  char *ret;
198  int i, j, stop;
199  static int start, len;
200  static char *stext;
201 
202  if(str2==0) return 0;
203 
204  /* initialise if str1 not 0 */
205  if(str1!=0) {
206  start=0;
207  stext=str1;
208  len=strlen(str1);
209  }
210 
211  /* run out of tokens ? */
212  if(start>=len) return 0;
213 
214  /* loop through characters */
215  for(i=start; i<len; i++) {
216  /* loop through delimiters */
217  stop=0;
218  for(j=0; j<(int)strlen(str2); j++)
219  if(stext[i]==str2[j])
220  stop=1;
221 
222  if(stop) break;
223  }
224 
225  stext[i]='\0';
226 
227  ret=stext+start;
228 
229  start=i+1;
230 
231  return ret;
232 }
233 
234 
235 ////////////////////////////////////////////////////////////////////////////////
236 /// Return version/copyright information
237 
238 float XRotVersion(char *str,int n)
239 {
240  if(str!=0) strncpy(str, XV_COPYRIGHT, n);
241  return XV_VERSION;
242 }
243 
244 
245 ////////////////////////////////////////////////////////////////////////////////
246 /// Set the font magnification factor for all subsequent operations
247 
249 {
250  if(m>0.) gRotStyle.fMagnify=m;
251 }
252 
253 
254 ////////////////////////////////////////////////////////////////////////////////
255 /// Set the padding used when calculating bounding boxes
256 
258 {
259  if(p>=0) gRotStyle.fBbxPadl=p;
260 }
261 
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// Create an XImage structure and allocate memory for it
265 
266 static XImage *MakeXImage(Display *dpy,int w, int h)
267 {
268  XImage *image;
269  char *data;
270 
271  /* reserve memory for image */
272  data=(char *)calloc((unsigned)(((w-1)/8+1)*h), 1);
273  if( data==0) return 0;
274 
275  /* create the XImage */
276  image=XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap,
277  0, data, w, h, 8, 0);
278  if (image==0) {
279  free(data);
280  return 0;
281  }
282 
283  image->byte_order=image->bitmap_bit_order=MSBFirst;
284  return image;
285 }
286 
287 
288 ////////////////////////////////////////////////////////////////////////////////
289 /// A front end to XRotPaintAlignedString:
290 /// -no alignment, no background
291 
292 int XRotDrawString(Display *dpy, XFontStruct *font,float angle,Drawable drawable, GC gc, int x, int y, char *str)
293 {
294  return (XRotPaintAlignedString(dpy, font, angle, drawable, gc,
295  x, y, str, NONE, 0));
296 }
297 
298 
299 ////////////////////////////////////////////////////////////////////////////////
300 /// A front end to XRotPaintAlignedString:
301 /// -no alignment, paints background
302 
303 int XRotDrawImageString(Display *dpy,XFontStruct *font, float angle, Drawable drawable,GC gc, int x, int y, char *str)
304 {
305  return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
306  x, y, str, NONE, 1));
307 }
308 
309 
310 ////////////////////////////////////////////////////////////////////////////////
311 /// A front end to XRotPaintAlignedString:
312 /// -does alignment, no background
313 
314 int XRotDrawAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text,int align)
315 {
316  return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
317  x, y, text, align, 0));
318 }
319 
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// A front end to XRotPaintAlignedString:
323 /// -does alignment, paints background
324 
325 int XRotDrawAlignedImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text,
326  int align)
327 {
328  return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
329  x, y, text, align, 1));
330 }
331 
332 
333 ////////////////////////////////////////////////////////////////////////////////
334 /// Aligns and paints a rotated string
335 
336 static int XRotPaintAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text,
337  int align, int bg)
338 {
339  int i;
340  GC my_gc;
341  int xp, yp;
342  float hot_x, hot_y;
343  float hot_xp, hot_yp;
344  float sin_angle, cos_angle;
345  RotatedTextItem_t *item;
346  Pixmap bitmap_to_paint;
347 
348  /* return early for 0/empty strings */
349  if(text==0) return 0;
350 
351  if(strlen(text)==0) return 0;
352 
353  /* manipulate angle to 0<=angle<360 degrees */
354  while(angle<0) angle+=360;
355 
356  while(angle>=360) angle-=360;
357 
358  angle*=M_PI/180;
359 
360  /* horizontal text made easy */
361  if(angle==0. && gRotStyle.fMagnify==1.)
362  return(XRotDrawHorizontalString(dpy, font, drawable, gc, x, y,
363  text, align, bg));
364 
365  /* get a rotated bitmap */
366  item=XRotRetrieveFromCache(dpy, font, angle, text, align);
367  if(item==0) return 0;
368 
369  /* this gc has similar properties to the user's gc */
370  my_gc=XCreateGC(dpy, drawable, 0, 0);
371  XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCPlaneMask,
372  my_gc);
373 
374  /* alignment : which point (hot_x, hot_y) relative to bitmap centre
375  coincides with user's specified point? */
376 
377  /* y position */
378  if(align==TLEFT || align==TCENTRE || align==TRIGHT)
379  hot_y=(float)item->fRowsIn/2*gRotStyle.fMagnify;
380  else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
381  {
382  /* Modify by O.Couet to have Bottom alignment without font->descent */
383  hot_y=0;
384  /* hot_y=-((float)item->fRowsIn/4-(float)font->descent)*gRotStyle.fMagnify; */
385  }
386  else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
387  {
388  /* Modify by O.Couet to have Bottom alignment without font->descent */
389  /* hot_y=-(float)item->fRowsIn/2*gRotStyle.fMagnify; */
390  hot_y=-((float)item->fRowsIn/2-(float)font->descent)*gRotStyle.fMagnify;
391  }
392  else
393  hot_y=-((float)item->fRowsIn/2-(float)font->descent)*gRotStyle.fMagnify;
394 
395  /* x position */
396  if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
397  hot_x=-(float)item->fMaxWidth/2*gRotStyle.fMagnify;
398  else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
399  hot_x=0;
400  else
401  hot_x=(float)item->fMaxWidth/2*gRotStyle.fMagnify;
402 
403  /* pre-calculate sin and cos */
404  sin_angle=TMath::Sin(angle);
405  cos_angle=TMath::Cos(angle);
406 
407  /* rotate hot_x and hot_y around bitmap centre */
408  hot_xp= hot_x*cos_angle - hot_y*sin_angle;
409  hot_yp= hot_x*sin_angle + hot_y*cos_angle;
410 
411  /* text background will be drawn using XFillPolygon */
412  if(bg) {
413  GC depth_one_gc;
414  XPoint *xpoints;
415  Pixmap empty_stipple;
416 
417  /* reserve space for XPoints */
418  xpoints=(XPoint *)malloc((unsigned)(4*item->fNl*sizeof(XPoint)));
419  if(!xpoints) return 1;
420 
421  /* rotate corner positions */
422  for(i=0; i<4*item->fNl; i++) {
423  xpoints[i].x=int((float)x + ( (item->fCornersX[i]-hot_x)*cos_angle +
424  (item->fCornersY[i]+hot_y)*sin_angle));
425  xpoints[i].y=int((float)y + (-(item->fCornersX[i]-hot_x)*sin_angle +
426  (item->fCornersY[i]+hot_y)*cos_angle));
427  }
428 
429  /* we want to swap foreground and background colors here;
430  XGetGCValues() is only available in R4+ */
431 
432  empty_stipple=XCreatePixmap(dpy, drawable, 1, 1, 1);
433 
434  depth_one_gc=XCreateGC(dpy, empty_stipple, 0, 0);
435  XSetForeground(dpy, depth_one_gc, 0);
436  XFillRectangle(dpy, empty_stipple, depth_one_gc, 0, 0, 2, 2);
437 
438  XSetStipple(dpy, my_gc, empty_stipple);
439  XSetFillStyle(dpy, my_gc, FillOpaqueStippled);
440 
441  XFillPolygon(dpy, drawable, my_gc, xpoints, 4*item->fNl, Nonconvex,
442  CoordModeOrigin);
443 
444  /* free our resources */
445  free((char *)xpoints);
446  XFreeGC(dpy, depth_one_gc);
447  XFreePixmap(dpy, empty_stipple);
448  }
449 
450  /* where should top left corner of bitmap go ? */
451  xp=int((float)x-((float)item->fColsOut/2 +hot_xp));
452  yp=int((float)y-((float)item->fRowsOut/2 -hot_yp));
453 
454  /* by default we draw the rotated bitmap, solid */
455  bitmap_to_paint=item->fBitmap;
456 
457  /* handle user stippling */
458 #ifndef X11R3
459  {
460  GC depth_one_gc;
461  XGCValues values;
462  Pixmap new_bitmap, inverse;
463 
464  /* try and get some GC properties */
465  if(XGetGCValues(dpy, gc,
466  GCStipple|GCFillStyle|GCForeground|GCBackground|
467  GCTileStipXOrigin|GCTileStipYOrigin,
468  &values)) {
469 
470  /* only do this if stippling requested */
471  if((values.fill_style==FillStippled ||
472  values.fill_style==FillOpaqueStippled) && !bg) {
473 
474  /* opaque stipple: draw rotated text in background colour */
475  if(values.fill_style==FillOpaqueStippled) {
476  XSetForeground(dpy, my_gc, values.background);
477  XSetFillStyle(dpy, my_gc, FillStippled);
478  XSetStipple(dpy, my_gc, item->fBitmap);
479  XSetTSOrigin(dpy, my_gc, xp, yp);
480  XFillRectangle(dpy, drawable, my_gc, xp, yp,
481  item->fColsOut, item->fRowsOut);
482  XSetForeground(dpy, my_gc, values.foreground);
483  }
484 
485  /* this will merge the rotated text and the user's stipple */
486  new_bitmap=XCreatePixmap(dpy, drawable,
487  item->fColsOut, item->fRowsOut, 1);
488 
489  /* create a GC */
490  depth_one_gc=XCreateGC(dpy, new_bitmap, 0, 0);
491  XSetForeground(dpy, depth_one_gc, 1);
492  XSetBackground(dpy, depth_one_gc, 0);
493 
494  /* set the relative stipple origin */
495  XSetTSOrigin(dpy, depth_one_gc,
496  values.ts_x_origin-xp, values.ts_y_origin-yp);
497 
498  /* fill the whole bitmap with the user's stipple */
499  XSetStipple(dpy, depth_one_gc, values.stipple);
500  XSetFillStyle(dpy, depth_one_gc, FillOpaqueStippled);
501  XFillRectangle(dpy, new_bitmap, depth_one_gc,
502  0, 0, item->fColsOut, item->fRowsOut);
503 
504  /* set stipple origin back to normal */
505  XSetTSOrigin(dpy, depth_one_gc, 0, 0);
506 
507  /* this will contain an inverse copy of the rotated text */
508  inverse=XCreatePixmap(dpy, drawable,
509  item->fColsOut, item->fRowsOut, 1);
510 
511  /* invert text */
512  XSetFillStyle(dpy, depth_one_gc, FillSolid);
513  XSetFunction(dpy, depth_one_gc, GXcopyInverted);
514  XCopyArea(dpy, item->fBitmap, inverse, depth_one_gc,
515  0, 0, item->fColsOut, item->fRowsOut, 0, 0);
516 
517  /* now delete user's stipple everywhere EXCEPT on text */
518  XSetForeground(dpy, depth_one_gc, 0);
519  XSetBackground(dpy, depth_one_gc, 1);
520  XSetStipple(dpy, depth_one_gc, inverse);
521  XSetFillStyle(dpy, depth_one_gc, FillStippled);
522  XSetFunction(dpy, depth_one_gc, GXcopy);
523  XFillRectangle(dpy, new_bitmap, depth_one_gc,
524  0, 0, item->fColsOut, item->fRowsOut);
525 
526  /* free resources */
527  XFreePixmap(dpy, inverse);
528  XFreeGC(dpy, depth_one_gc);
529 
530  /* this is the new bitmap */
531  bitmap_to_paint=new_bitmap;
532  }
533  }
534  }
535 #endif /*X11R3*/
536 
537  /* paint text using stipple technique */
538  XSetFillStyle(dpy, my_gc, FillStippled);
539  XSetStipple(dpy, my_gc, bitmap_to_paint);
540  XSetTSOrigin(dpy, my_gc, xp, yp);
541  XFillRectangle(dpy, drawable, my_gc, xp, yp,
542  item->fColsOut, item->fRowsOut);
543 
544  /* free our resources */
545  XFreeGC(dpy, my_gc);
546 
547  /* stippled bitmap no longer needed */
548  if(bitmap_to_paint!=item->fBitmap)
549  XFreePixmap(dpy, bitmap_to_paint);
550 
551 #ifdef CACHE_XIMAGES
552  XFreePixmap(dpy, item->fBitmap);
553 #endif /*CACHE_XIMAGES*/
554 
555  /* if item isn't cached, destroy it completely */
556  if(!item->fCached)
557  XRotFreeTextItem(dpy,item);
558 
559  /* we got to the end OK! */
560  return 0;
561 }
562 
563 
564 ////////////////////////////////////////////////////////////////////////////////
565 /// Draw a horizontal string in a quick fashion
566 
567 static int XRotDrawHorizontalString(Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, char *text,
568  int align, int bg)
569 {
570  GC my_gc;
571  int nl=1, i;
572  int height;
573  int xp, yp;
574  char *str1, *str2, *str3;
575  const char *str2_a="\0", *str2_b="\n\0";
576  int dir, asc, desc;
577  XCharStruct overall;
578 
579  DEBUG_PRINT1("**\nHorizontal text.\n");
580 
581  /* this gc has similar properties to the user's gc (including stipple) */
582  my_gc=XCreateGC(dpy, drawable, 0, 0);
583  XCopyGC(dpy, gc,
584  GCForeground|GCBackground|GCFunction|GCStipple|GCFillStyle|
585  GCTileStipXOrigin|GCTileStipYOrigin|GCPlaneMask, my_gc);
586  XSetFont(dpy, my_gc, font->fid);
587 
588  /* count number of sections in string */
589  if(align!=NONE)
590  for(i=0; i<(int)strlen(text)-1; i++)
591  if(text[i]=='\n')
592  nl++;
593 
594  /* ignore newline characters if not doing alignment */
595  if(align==NONE)
596  str2=(char *)str2_a;
597  else
598  str2=(char *)str2_b;
599 
600  /* overall font height */
601  height=font->ascent+font->descent;
602 
603  /* y position */
604  if(align==TLEFT || align==TCENTRE || align==TRIGHT)
605  yp=y+font->ascent;
606  else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
607  {
608  /* Modify by O.Couet to have Middle alignment without font->descent */
609  /* yp=y-nl*height/2+font->ascent; */
610  yp=y-nl*(height-font->descent)/2+font->ascent;
611  }
612  else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
613  {
614  /* Modify by O.Couet to have Bottom alignment without font->descent */
615  /* yp=y-nl*height+font->ascent; */
616  yp=y-nl*(height-font->descent)+font->ascent;
617  }
618  else
619  yp=y;
620 
621  str1=my_strdup(text);
622  if(str1==0) return 1;
623 
624  str3=my_strtok(str1, str2);
625  if (!str3) return 0;
626 
627  /* loop through each section in the string */
628  do {
629  XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
630  &overall);
631 
632  /* where to draw section in x ? */
633  if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
634  xp=x;
635  else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
636  xp=x-overall.rbearing/2;
637  else
638  xp=x-overall.rbearing;
639 
640  /* draw string onto bitmap */
641  if(!bg)
642  XDrawString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
643  else
644  XDrawImageString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
645 
646  /* move to next line */
647  yp+=height;
648 
649  str3=my_strtok((char *)0, str2);
650  }
651  while(str3!=0);
652 
653  free(str1);
654  XFreeGC(dpy, my_gc);
655 
656  return 0;
657 }
658 
659 
660 ////////////////////////////////////////////////////////////////////////////////
661 /// Query cache for a match with this font/text/angle/alignment
662 /// request, otherwise arrange for its creation
663 
664 static RotatedTextItem_t *XRotRetrieveFromCache(Display *dpy, XFontStruct *font, float angle, char *text, int align)
665 {
666  Font fid;
667  char *font_name;
668  unsigned long name_value;
669  RotatedTextItem_t *item=0;
671 
672  /* get font name, if it exists */
673  if(XGetFontProperty(font, XA_FONT, &name_value)) {
674  DEBUG_PRINT1("got font name OK\n");
675  font_name=XGetAtomName(dpy, name_value);
676  fid=0;
677  }
678 #ifdef CACHE_FID
679  /* otherwise rely (unreliably?) on font ID */
680  else {
681  DEBUG_PRINT1("can't get fontname, caching FID\n");
682  font_name=0;
683  fid=font->fid;
684  }
685 #else
686  /* not allowed to cache font ID's */
687  else {
688  DEBUG_PRINT1("can't get fontname, can't cache\n");
689  font_name=0;
690  fid=0;
691  }
692 #endif /*CACHE_FID*/
693 
694  /* look for a match in cache */
695 
696  /* matching formula:
697  identical text;
698  identical fontname (if defined, font ID's if not);
699  angles close enough (<0.00001 here, could be smaller);
700  HORIZONTAL alignment matches, OR it's a one line string;
701  magnifications the same */
702 
703  while(i1 && !item) {
704  /* match everything EXCEPT fontname/ID */
705  if(strcmp(text, i1->fText)==0 &&
706  TMath::Abs(angle-i1->fAngle)<0.00001 &&
707  gRotStyle.fMagnify==i1->fMagnify &&
708  (i1->fNl==1 ||
709  ((align==0)?9:(align-1))%3==
710  ((i1->fAlign==0)?9:(i1->fAlign-1))%3)) {
711 
712  /* now match fontname/ID */
713  if(font_name!=0 && i1->font_name!=0) {
714  if(strcmp(font_name, i1->font_name)==0) {
715  item=i1;
716  DEBUG_PRINT1("Matched against font names\n");
717  }
718  else
719  i1=i1->fNext;
720  }
721 #ifdef CACHE_FID
722  else if(font_name==0 && i1->font_name==0) {
723  if(fid==i1->fid) {
724  item=i1;
725  DEBUG_PRINT1("Matched against FID's\n");
726  }
727  else
728  i1=i1->fNext;
729  }
730 #endif /*CACHE_FID*/
731  else
732  i1=i1->fNext;
733  }
734  else
735  i1=i1->fNext;
736  }
737 
738  if(item)
739  DEBUG_PRINT1("**\nFound target in cache.\n");
740  if(!item)
741  DEBUG_PRINT1("**\nNo match in cache.\n");
742 
743  /* no match */
744  if(!item) {
745  /* create new item */
746  item=XRotCreateTextItem(dpy, font, angle, text, align);
747  if(!item)
748  return 0;
749 
750  /* record what it shows */
751  item->fText=my_strdup(text);
752 
753  /* fontname or ID */
754  if(font_name!=0) {
755  item->font_name=my_strdup(font_name);
756  item->fid=0;
757  }
758  else {
759  item->font_name=0;
760  item->fid=fid;
761  }
762 
763  item->fAngle=angle;
764  item->fAlign=align;
765  item->fMagnify=gRotStyle.fMagnify;
766 
767  /* cache it */
768  XRotAddToLinkedList(dpy, item);
769  }
770 
771  if(font_name)
772  XFree(font_name);
773 
774  /* if XImage is cached, need to recreate the bitmap */
775 
776 #ifdef CACHE_XIMAGES
777  {
778  GC depth_one_gc;
779 
780  /* create bitmap to hold rotated text */
781  item->fBitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
782  item->fColsOut, item->fRowsOut, 1);
783 
784  /* depth one gc */
785  depth_one_gc=XCreateGC(dpy, item->fBitmap, 0, 0);
786  XSetBackground(dpy, depth_one_gc, 0);
787  XSetForeground(dpy, depth_one_gc, 1);
788 
789  /* make the text bitmap from XImage */
790  XPutImage(dpy, item->fBitmap, depth_one_gc, item->fXimage, 0, 0, 0, 0,
791  item->fColsOut, item->fRowsOut);
792 
793  XFreeGC(dpy, depth_one_gc);
794  }
795 #endif /*CACHE_XIMAGES*/
796 
797  return item;
798 }
799 
800 
801 ////////////////////////////////////////////////////////////////////////////////
802 /// Create a rotated text item
803 
804 static RotatedTextItem_t *XRotCreateTextItem(Display *dpy, XFontStruct *font, float angle, char *text, int align)
805 {
806  RotatedTextItem_t *item;
807  Pixmap canvas;
808  GC font_gc;
809  XImage *imageIn;
810  int i, j;
811  char *str1, *str2, *str3;
812  const char *str2_a="\0", *str2_b="\n\0";
813  int height;
814  int byte_w_in, byte_w_out;
815  int xp, yp;
816  float sin_angle, cos_angle;
817  int it, jt;
818  float di, dj;
819  int ic=0;
820  float xl, xr, xinc;
821  int byte_out;
822  int dir, asc, desc;
823  XCharStruct overall;
824  int old_cols_in=0, old_rows_in=0;
825 
826  /* allocate memory */
827  item=(RotatedTextItem_t *)malloc((unsigned)sizeof(RotatedTextItem_t));
828  if(!item) return 0;
829 
830  /* count number of sections in string */
831  item->fNl=1;
832  if(align!=NONE)
833  for(i=0; i<(int)strlen(text)-1; i++)
834  if(text[i]=='\n')
835  item->fNl++;
836 
837  /* ignore newline characters if not doing alignment */
838  if(align==NONE)
839  str2=(char *)str2_a;
840  else
841  str2=(char *)str2_b;
842 
843  /* find width of longest section */
844  str1=my_strdup(text);
845  if(str1==0) {
846  free(item);
847  return 0;
848  }
849 
850  str3=my_strtok(str1, str2);
851  if (!str3) {
852  free(item);
853  return 0;
854  }
855 
856  XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
857  &overall);
858 
859  item->fMaxWidth=overall.rbearing;
860 
861  /* loop through each section */
862  do {
863  str3=my_strtok((char *)0, str2);
864 
865  if(str3!=0) {
866  XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
867  &overall);
868  if(overall.rbearing>item->fMaxWidth)
869  item->fMaxWidth=overall.rbearing;
870  }
871  }
872  while(str3!=0);
873 
874  free(str1);
875 
876  /* overall font height */
877  height=font->ascent+font->descent;
878 
879  /* dimensions horizontal text will have */
880  item->fColsIn=item->fMaxWidth;
881  item->fRowsIn=item->fNl*height;
882 
883  /* bitmap for drawing on */
884  canvas=XCreatePixmap(dpy, DefaultRootWindow(dpy),
885  item->fColsIn, item->fRowsIn, 1);
886 
887  /* create a GC for the bitmap */
888  font_gc=XCreateGC(dpy, canvas, 0, 0);
889  XSetBackground(dpy, font_gc, 0);
890  XSetFont(dpy, font_gc, font->fid);
891 
892  /* make sure the bitmap is blank */
893  XSetForeground(dpy, font_gc, 0);
894  XFillRectangle(dpy, canvas, font_gc, 0, 0,
895  item->fColsIn+1, item->fRowsIn+1);
896  XSetForeground(dpy, font_gc, 1);
897 
898  /* pre-calculate sin and cos */
899  sin_angle=TMath::Sin(angle);
900  cos_angle=TMath::Cos(angle);
901 
902  /* text background will be drawn using XFillPolygon */
903  item->fCornersX = (float *)malloc((unsigned)(4*item->fNl*sizeof(float)));
904  if(!item->fCornersX) {
905  free(item);
906  return 0;
907  }
908 
909  item->fCornersY = (float *)malloc((unsigned)(4*item->fNl*sizeof(float)));
910  if(!item->fCornersY) {
911  free(item->fCornersX);
912  free(item);
913  return 0;
914  }
915 
916  /* draw text horizontally */
917 
918  /* start at top of bitmap */
919  yp=font->ascent;
920 
921  str1=my_strdup(text);
922  if (str1==0) {
923  free(item->fCornersX);
924  free(item->fCornersY);
925  free(item);
926  return 0;
927  }
928 
929  str3=my_strtok(str1, str2);
930  if (!str3) {
931  free(item->fCornersX);
932  free(item->fCornersY);
933  free(item);
934  return 0;
935  }
936 
937  /* loop through each section in the string */
938  do {
939  XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
940  &overall);
941 
942  /* where to draw section in x ? */
943  if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
944  xp=0;
945  else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
946  xp=(item->fMaxWidth-overall.rbearing)/2;
947  else
948  xp=item->fMaxWidth-overall.rbearing;
949 
950  /* draw string onto bitmap */
951  XDrawString(dpy, canvas, font_gc, xp, yp, str3, strlen(str3));
952 
953  /* keep a note of corner positions of this string */
954  item->fCornersX[ic]=((float)xp-(float)item->fColsIn/2)*gRotStyle.fMagnify;
955  item->fCornersY[ic]=((float)(yp-font->ascent)-(float)item->fRowsIn/2)
956  *gRotStyle.fMagnify;
957  item->fCornersX[ic+1]=item->fCornersX[ic];
958  item->fCornersY[ic+1]=item->fCornersY[ic]+(float)height*gRotStyle.fMagnify;
959  item->fCornersX[item->fNl*4-1-ic]=item->fCornersX[ic]+
960  (float)overall.rbearing*gRotStyle.fMagnify;
961  item->fCornersY[item->fNl*4-1-ic]=item->fCornersY[ic];
962  item->fCornersX[item->fNl*4-2-ic]=
963  item->fCornersX[item->fNl*4-1-ic];
964  item->fCornersY[item->fNl*4-2-ic]=item->fCornersY[ic+1];
965 
966  ic+=2;
967 
968  /* move to next line */
969  yp+=height;
970 
971  str3=my_strtok((char *)0, str2);
972  }
973  while(str3!=0);
974 
975  free(str1);
976 
977  /* create image to hold horizontal text */
978  imageIn=MakeXImage(dpy, item->fColsIn, item->fRowsIn);
979  if(imageIn==0) {
980  free(item->fCornersX);
981  free(item->fCornersY);
982  free(item);
983  return 0;
984  }
985 
986  /* extract horizontal text */
987  XGetSubImage(dpy, canvas, 0, 0, item->fColsIn, item->fRowsIn,
988  1, XYPixmap, imageIn, 0, 0);
989  imageIn->format=XYBitmap;
990 
991  /* magnify horizontal text */
992  if(gRotStyle.fMagnify!=1.) {
993  imageIn=XRotMagnifyImage(dpy, imageIn);
994 
995  old_cols_in=item->fColsIn;
996  old_rows_in=item->fRowsIn;
997  item->fColsIn=int((float)item->fColsIn*gRotStyle.fMagnify);
998  item->fRowsIn=int((float)item->fRowsIn*gRotStyle.fMagnify);
999  }
1000 
1001  /* how big will rotated text be ? */
1002  item->fColsOut=int(TMath::Abs((float)item->fRowsIn*sin_angle) +
1003  TMath::Abs((float)item->fColsIn*cos_angle) +0.99999 +2);
1004 
1005  item->fRowsOut=int(TMath::Abs((float)item->fRowsIn*cos_angle) +
1006  TMath::Abs((float)item->fColsIn*sin_angle) +0.99999 +2);
1007 
1008  if(item->fColsOut%2==0) item->fColsOut++;
1009 
1010  if(item->fRowsOut%2==0) item->fRowsOut++;
1011 
1012  /* create image to hold rotated text */
1013  item->fXimage=MakeXImage(dpy, item->fColsOut, item->fRowsOut);
1014  if(item->fXimage==0) {
1015  free(item->fCornersX);
1016  free(item->fCornersY);
1017  free(item);
1018  return 0;
1019  }
1020 
1021  byte_w_in=(item->fColsIn-1)/8+1;
1022  byte_w_out=(item->fColsOut-1)/8+1;
1023 
1024  /* we try to make this bit as fast as possible - which is why it looks
1025  a bit over-the-top */
1026 
1027  /* vertical distance from centre */
1028  dj=0.5-(float)item->fRowsOut/2;
1029 
1030  /* where abouts does text actually lie in rotated image? */
1031  if(angle==0 || angle==M_PI/2 ||
1032  angle==M_PI || angle==3*M_PI/2) {
1033  xl=0;
1034  xr=(float)item->fColsOut;
1035  xinc=0;
1036  }
1037  else if(angle<M_PI) {
1038  xl=(float)item->fColsOut/2+
1039  (dj-(float)item->fRowsIn/(2*cos_angle))/
1040  TMath::Tan(angle)-2;
1041  xr=(float)item->fColsOut/2+
1042  (dj+(float)item->fRowsIn/(2*cos_angle))/
1043  TMath::Tan(angle)+2;
1044  xinc=1./TMath::Tan(angle);
1045  }
1046  else {
1047  xl=(float)item->fColsOut/2+
1048  (dj+(float)item->fRowsIn/(2*cos_angle))/
1049  TMath::Tan(angle)-2;
1050  xr=(float)item->fColsOut/2+
1051  (dj-(float)item->fRowsIn/(2*cos_angle))/
1052  TMath::Tan(angle)+2;
1053 
1054  xinc=1./TMath::Tan(angle);
1055  }
1056 
1057  /* loop through all relevent bits in rotated image */
1058  if (imageIn) {
1059  for(j=0; j<item->fRowsOut; j++) {
1060 
1061  /* no point re-calculating these every pass */
1062  di=(float)((xl<0)?0:(int)xl)+0.5-(float)item->fColsOut/2;
1063  byte_out=(item->fRowsOut-j-1)*byte_w_out;
1064 
1065  /* loop through meaningful columns */
1066  for(i=((xl<0)?0:(int)xl);
1067  i<((xr>=item->fColsOut)?item->fColsOut:(int)xr); i++) {
1068 
1069  /* rotate coordinates */
1070  it=int((float)item->fColsIn/2 + ( di*cos_angle + dj*sin_angle));
1071  jt=int((float)item->fRowsIn/2 - (-di*sin_angle + dj*cos_angle));
1072 
1073  /* set pixel if required */
1074  if(it>=0 && it<item->fColsIn && jt>=0 && jt<item->fRowsIn)
1075  if((imageIn->data[jt*byte_w_in+it/8] & 128>>(it%8))>0)
1076  item->fXimage->data[byte_out+i/8]|=128>>i%8;
1077 
1078  di+=1;
1079  }
1080  dj+=1;
1081  xl+=xinc;
1082  xr+=xinc;
1083  }
1084  XDestroyImage(imageIn);
1085  }
1086 
1087  if(gRotStyle.fMagnify!=1.) {
1088  item->fColsIn=old_cols_in;
1089  item->fRowsIn=old_rows_in;
1090  }
1091 
1092 
1093 #ifdef CACHE_BITMAPS
1094 
1095  /* create a bitmap to hold rotated text */
1096  item->fBitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
1097  item->fColsOut, item->fRowsOut, 1);
1098 
1099  /* make the text bitmap from XImage */
1100  XPutImage(dpy, item->fBitmap, font_gc, item->fXimage, 0, 0, 0, 0,
1101  item->fColsOut, item->fRowsOut);
1102 
1103  XDestroyImage(item->fXimage);
1104 
1105 #endif /*CACHE_BITMAPS*/
1106 
1107  XFreeGC(dpy, font_gc);
1108  XFreePixmap(dpy, canvas);
1109 
1110  return item;
1111 }
1112 
1113 
1114 ////////////////////////////////////////////////////////////////////////////////
1115 /// Adds a text item to the end of the cache, removing as many items
1116 /// from the front as required to keep cache size below limit
1117 
1118 static void XRotAddToLinkedList(Display *dpy, RotatedTextItem_t *item)
1119 {
1120  static long int current_size=0;
1121  static RotatedTextItem_t *last=0;
1123 
1124 #ifdef CACHE_BITMAPS
1125 
1126  /* I don't know how much memory a pixmap takes in the server -
1127  probably this + a bit more we can't account for */
1128 
1129  item->fSize=((item->fColsOut-1)/8+1)*item->fRowsOut;
1130 
1131 #else
1132 
1133  /* this is pretty much the size of a RotatedTextItem_t */
1134 
1135  item->fSize=((item->fColsOut-1)/8+1)*item->fRowsOut +
1136  sizeof(XImage) + strlen(item->text) +
1137  item->fNl*8*sizeof(float) + sizeof(RotatedTextItem_t);
1138 
1139  if(item->font_name!=0)
1140  item->fSize+=strlen(item->font_name);
1141  else
1142  item->fSize+=sizeof(Font);
1143 
1144 #endif /*CACHE_BITMAPS */
1145 
1146 #ifdef DEBUG
1147  /* count number of items in cache, for debugging */
1148  {
1149  int i=0;
1150 
1151  while(i1) {
1152  i++;
1153  i1=i1->fNext;
1154  }
1155  DEBUG_PRINT2("Cache has %d items.\n", i);
1156  i1=gFirstTextItem;
1157  }
1158 #endif
1159 
1160  DEBUG_PRINT4("current cache size=%ld, new item=%ld, limit=%d\n",
1161  current_size, item->fSize, CACHE_SIZE_LIMIT*1024);
1162 
1163  /* if this item is bigger than whole cache, forget it */
1164  if(item->fSize>CACHE_SIZE_LIMIT*1024) {
1165  DEBUG_PRINT1("Too big to cache\n\n");
1166  item->fCached=0;
1167  return;
1168  }
1169 
1170  /* remove elements from cache as needed */
1171  while(i1 && current_size+item->fSize>CACHE_SIZE_LIMIT*1024) {
1172 
1173  DEBUG_PRINT2("Removed %ld bytes\n", i1->fSize);
1174 
1175  if(i1->font_name!=0)
1176  DEBUG_PRINT5(" (`%s'\n %s\n angle=%f align=%d)\n",
1177  i1->fText, i1->font_name, i1->fAngle, i1->fAlign);
1178 
1179 #ifdef CACHE_FID
1180  if(i1->font_name==0)
1181  DEBUG_PRINT5(" (`%s'\n FID=%ld\n angle=%f align=%d)\n",
1182  i1->fText, i1->fid, i1->angle, i1->align);
1183 #endif /*CACHE_FID*/
1184 
1185  current_size-=i1->fSize;
1186 
1187  i2=i1->fNext;
1188 
1189  /* free resources used by the unlucky item */
1190  XRotFreeTextItem(dpy, i1);
1191 
1192  /* remove it from linked list */
1193  gFirstTextItem=i2;
1194  i1=i2;
1195  }
1196 
1197  /* add new item to end of linked list */
1198  if(gFirstTextItem==0) {
1199  item->fNext=0;
1200  gFirstTextItem=item;
1201  last=item;
1202  }
1203  else {
1204  item->fNext=0;
1205  last->fNext=item;
1206  last=item;
1207  }
1208 
1209  /* new cache size */
1210  current_size+=item->fSize;
1211 
1212  item->fCached=1;
1213 
1214  DEBUG_PRINT1("Added item to cache.\n");
1215 }
1216 
1217 
1218 ////////////////////////////////////////////////////////////////////////////////
1219 /// Free the resources used by a text item
1220 
1221 static void XRotFreeTextItem(Display *dpy, RotatedTextItem_t *item)
1222 {
1223  free(item->fText);
1224 
1225  if(item->font_name!=0)
1226  free(item->font_name);
1227 
1228  free((char *)item->fCornersX);
1229  free((char *)item->fCornersY);
1230 
1231 #ifdef CACHE_BITMAPS
1232  XFreePixmap(dpy, item->fBitmap);
1233 #else
1234  XDestroyImage(item->fXimage);
1235 #endif /* CACHE_BITMAPS */
1236 
1237  free((char *)item);
1238 }
1239 
1240 
1241 ////////////////////////////////////////////////////////////////////////////////
1242 /// Magnify an XImage using bilinear interpolation
1243 
1244 static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage)
1245 {
1246  int i, j;
1247  float x, y;
1248  float u,t;
1249  XImage *imageOut;
1250  int cols_in, rows_in;
1251  int cols_out, rows_out;
1252  int i2, j2;
1253  float z1, z2, z3, z4;
1254  int byte_width_in, byte_width_out;
1255  float mag_inv;
1256 
1257  /* size of input image */
1258  cols_in=ximage->width;
1259  rows_in=ximage->height;
1260 
1261  /* size of final image */
1262  cols_out=int((float)cols_in*gRotStyle.fMagnify);
1263  rows_out=int((float)rows_in*gRotStyle.fMagnify);
1264 
1265  /* this will hold final image */
1266  imageOut=MakeXImage(dpy, cols_out, rows_out);
1267  if(imageOut==0)
1268  return 0;
1269 
1270  /* width in bytes of input, output images */
1271  byte_width_in=(cols_in-1)/8+1;
1272  byte_width_out=(cols_out-1)/8+1;
1273 
1274  /* for speed */
1275  mag_inv=1./gRotStyle.fMagnify;
1276 
1277  y=0.;
1278 
1279  /* loop over magnified image */
1280  for(j2=0; j2<rows_out; j2++) {
1281  x=0;
1282  j=int(y);
1283 
1284  for(i2=0; i2<cols_out; i2++) {
1285  i=int(x);
1286 
1287  /* bilinear interpolation - where are we on bitmap ? */
1288  /* right edge */
1289  if(i==cols_in-1 && j!=rows_in-1) {
1290  t=0;
1291  u=y-(float)j;
1292 
1293  z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
1294  z2=z1;
1295  z3=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
1296  z4=z3;
1297  }
1298  /* top edge */
1299  else if(i!=cols_in-1 && j==rows_in-1) {
1300  t=x-(float)i;
1301  u=0;
1302 
1303  z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
1304  z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0;
1305  z3=z2;
1306  z4=z1;
1307  }
1308  /* top right corner */
1309  else if(i==cols_in-1 && j==rows_in-1) {
1310  u=0;
1311  t=0;
1312 
1313  z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
1314  z2=z1;
1315  z3=z1;
1316  z4=z1;
1317  }
1318  /* somewhere `safe' */
1319  else {
1320  t=x-(float)i;
1321  u=y-(float)j;
1322 
1323  z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
1324  z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0;
1325  z3=(ximage->data[(j+1)*byte_width_in+(i+1)/8] &
1326  128>>((i+1)%8))>0;
1327  z4=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
1328  }
1329 
1330  /* if interpolated value is greater than 0.5, set bit */
1331  if(((1-t)*(1-u)*z1 + t*(1-u)*z2 + t*u*z3 + (1-t)*u*z4)>0.5)
1332  imageOut->data[j2*byte_width_out+i2/8]|=128>>i2%8;
1333 
1334  x+=mag_inv;
1335  }
1336  y+=mag_inv;
1337  }
1338 
1339  /* destroy original */
1340  XDestroyImage(ximage);
1341 
1342  /* return big image */
1343  return imageOut;
1344 }
1345 
1346 
1347 ////////////////////////////////////////////////////////////////////////////////
1348 /// Calculate the bounding box some text will have when painted
1349 
1350 XPoint *XRotTextExtents(Display *, XFontStruct *font, float angle, int x, int y, char *text,int align)
1351 {
1352  int i;
1353  char *str1, *str2, *str3;
1354  const char *str2_a="\0", *str2_b="\n\0";
1355  int height;
1356  float sin_angle, cos_angle;
1357  int nl, max_width;
1358  int cols_in, rows_in;
1359  float hot_x, hot_y;
1360  XPoint *xp_in, *xp_out;
1361  int dir, asc, desc;
1362  XCharStruct overall;
1363 
1364  /* manipulate angle to 0<=angle<360 degrees */
1365  while(angle<0) angle+=360;
1366 
1367  while(angle>360) angle-=360;
1368 
1369  angle*=M_PI/180;
1370 
1371  /* count number of sections in string */
1372  nl=1;
1373  if(align!=NONE)
1374  for(i=0; i<(int)strlen(text)-1; i++)
1375  if(text[i]=='\n')
1376  nl++;
1377 
1378  /* ignore newline characters if not doing alignment */
1379  if(align==NONE)
1380  str2=(char *)str2_a;
1381  else
1382  str2=(char *)str2_b;
1383 
1384  /* find width of longest section */
1385  str1=my_strdup(text);
1386  if(str1==0) return 0;
1387 
1388  str3=my_strtok(str1, str2);
1389 
1390  if(str3==0) {
1391  XTextExtents(font, str1, strlen(str1), &dir, &asc, &desc,
1392  &overall);
1393  } else {
1394  XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
1395  &overall);
1396  }
1397 
1398  max_width=overall.rbearing;
1399 
1400  /* loop through each section */
1401  do {
1402  str3=my_strtok((char *)0, str2);
1403 
1404  if(str3!=0) {
1405  XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
1406  &overall);
1407 
1408  if(overall.rbearing>max_width)
1409  max_width=overall.rbearing;
1410  }
1411  }
1412  while(str3!=0);
1413 
1414  free(str1);
1415 
1416  /* overall font height */
1417  height=font->ascent+font->descent;
1418 
1419  /* dimensions horizontal text will have */
1420  cols_in=max_width;
1421  rows_in=nl*height;
1422 
1423  /* pre-calculate sin and cos */
1424  sin_angle=TMath::Sin(angle);
1425  cos_angle=TMath::Cos(angle);
1426 
1427  /* y position */
1428  if(align==TLEFT || align==TCENTRE || align==TRIGHT)
1429  hot_y=(float)rows_in/2*gRotStyle.fMagnify;
1430  else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
1431  hot_y=0;
1432  else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
1433  hot_y=-(float)rows_in/2*gRotStyle.fMagnify;
1434  else
1435  hot_y=-((float)rows_in/2-(float)font->descent)*gRotStyle.fMagnify;
1436 
1437  /* x position */
1438  if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
1439  hot_x=-(float)max_width/2*gRotStyle.fMagnify;
1440  else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
1441  hot_x=0;
1442  else
1443  hot_x=(float)max_width/2*gRotStyle.fMagnify;
1444 
1445  /* reserve space for XPoints */
1446  xp_in=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
1447  if(!xp_in) return 0;
1448 
1449  xp_out=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
1450  if(!xp_out) {
1451  free(xp_in);
1452  return 0;
1453  }
1454 
1455  /* bounding box when horizontal, relative to bitmap centre */
1456  xp_in[0].x=(short int)(-(float)cols_in*gRotStyle.fMagnify/2-gRotStyle.fBbxPadl);
1457  xp_in[0].y=(short int)( (float)rows_in*gRotStyle.fMagnify/2+gRotStyle.fBbxPadl);
1458  xp_in[1].x=(short int)( (float)cols_in*gRotStyle.fMagnify/2+gRotStyle.fBbxPadl);
1459  xp_in[1].y=(short int)( (float)rows_in*gRotStyle.fMagnify/2+gRotStyle.fBbxPadl);
1460  xp_in[2].x=(short int)( (float)cols_in*gRotStyle.fMagnify/2+gRotStyle.fBbxPadl);
1461  xp_in[2].y=(short int)(-(float)rows_in*gRotStyle.fMagnify/2-gRotStyle.fBbxPadl);
1462  xp_in[3].x=(short int)(-(float)cols_in*gRotStyle.fMagnify/2-gRotStyle.fBbxPadl);
1463  xp_in[3].y=(short int)(-(float)rows_in*gRotStyle.fMagnify/2-gRotStyle.fBbxPadl);
1464  xp_in[4].x=xp_in[0].x;
1465  xp_in[4].y=xp_in[0].y;
1466 
1467  /* rotate and translate bounding box */
1468  for(i=0; i<5; i++) {
1469  xp_out[i].x=(short int)((float)x + ( ((float)xp_in[i].x-hot_x)*cos_angle +
1470  ((float)xp_in[i].y+hot_y)*sin_angle));
1471  xp_out[i].y=(short int)((float)y + (-((float)xp_in[i].x-hot_x)*sin_angle +
1472  ((float)xp_in[i].y+hot_y)*cos_angle));
1473  }
1474 
1475  free((char *)xp_in);
1476 
1477  return xp_out;
1478 }
#define MRIGHT
Definition: Rotated.cxx:58
#define TCENTRE
Definition: Rotated.cxx:54
static RotatedTextItem_t * gFirstTextItem
Definition: Rotated.cxx:139
XID Drawable
Definition: TGX11.h:36
static char * my_strdup(char *)
Routine to mimic `strdup()&#39; (some machines don&#39;t have it)
Definition: Rotated.cxx:179
auto * m
Definition: textangle.C:8
float XRotVersion(char *, int)
Return version/copyright information.
Definition: Rotated.cxx:238
#define BRIGHT
Definition: Rotated.cxx:61
TH1 * h
Definition: legend2.C:5
int XRotDrawAlignedString(Display *, XFontStruct *, float, Drawable, GC, int, int, char *, int)
A front end to XRotPaintAlignedString: -does alignment, no background.
Definition: Rotated.cxx:314
void XRotSetBoundingBoxPad(int)
Set the padding used when calculating bounding boxes.
Definition: Rotated.cxx:257
#define MCENTRE
Definition: Rotated.cxx:57
#define malloc
Definition: civetweb.c:818
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
static char * my_strtok(char *, char *)
Routine to replace `strtok&#39; : this one returns a zero length string if it encounters two consecutive ...
Definition: Rotated.cxx:195
static void XRotAddToLinkedList(Display *dpy, RotatedTextItem_t *item)
Adds a text item to the end of the cache, removing as many items from the front as required to keep c...
Definition: Rotated.cxx:1118
static RotatedTextItem_t * XRotCreateTextItem(Display *dpy, XFontStruct *font, float angle, char *text, int align)
Create a rotated text item.
Definition: Rotated.cxx:804
static int XRotPaintAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg)
Aligns and paints a rotated string.
Definition: Rotated.cxx:336
static struct StyleTemplate_t gRotStyle
#define DEBUG_PRINT1(a)
Definition: Rotated.cxx:96
#define TLEFT
Definition: Rotated.cxx:53
Double_t x[n]
Definition: legend1.C:17
static void XRotFreeTextItem(Display *dpy, RotatedTextItem_t *item)
Free the resources used by a text item.
Definition: Rotated.cxx:1221
#define BLEFT
Definition: Rotated.cxx:59
struct RotatedTextItemTemplate_t RotatedTextItem_t
#define XV_VERSION
Definition: Rotated.cxx:44
static int XRotDrawHorizontalString(Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg)
Draw a horizontal string in a quick fashion.
Definition: Rotated.cxx:567
int XRotDrawAlignedImageString(Display *, XFontStruct *, float, Drawable, GC, int, int, char *, int)
A front end to XRotPaintAlignedString: -does alignment, paints background.
Definition: Rotated.cxx:325
#define DEBUG_PRINT2(a, b)
Definition: Rotated.cxx:97
#define M_PI
Definition: Rotated.cxx:105
static RotatedTextItem_t * XRotRetrieveFromCache(Display *dpy, XFontStruct *font, float angle, char *text, int align)
Query cache for a match with this font/text/angle/alignment request, otherwise arrange for its creati...
Definition: Rotated.cxx:664
static XImage * XRotMagnifyImage(Display *dpy, XImage *ximage)
Magnify an XImage using bilinear interpolation.
Definition: Rotated.cxx:1244
#define TRIGHT
Definition: Rotated.cxx:55
#define calloc
Definition: civetweb.c:819
Double_t Cos(Double_t)
Definition: TMath.h:550
XPoint * XRotTextExtents(Display *, XFontStruct *, float, int, int, char *, int)
Calculate the bounding box some text will have when painted.
Definition: Rotated.cxx:1350
void XRotSetMagnification(float)
Set the font magnification factor for all subsequent operations.
Definition: Rotated.cxx:248
#define NONE
Definition: Rotated.cxx:52
TText * text
#define DEBUG_PRINT5(a, b, c, d, e)
Definition: Rotated.cxx:100
#define free
Definition: civetweb.c:821
static int gRotatedDebug
Definition: Rotated.cxx:93
Double_t y[n]
Definition: legend1.C:17
static constexpr double s
int XRotDrawImageString(Display *, XFontStruct *, float, Drawable, GC, int, int, char *)
A front end to XRotPaintAlignedString: -no alignment, paints background.
Definition: Rotated.cxx:303
#define BCENTRE
Definition: Rotated.cxx:60
#define DEBUG_PRINT4(a, b, c, d)
Definition: Rotated.cxx:99
#define CACHE_SIZE_LIMIT
Definition: Rotated.cxx:75
int XRotDrawString(Display *, XFontStruct *, float, Drawable, GC, int, int, char *)
A front end to XRotPaintAlignedString: -no alignment, no background.
Definition: Rotated.cxx:292
#define MLEFT
Definition: Rotated.cxx:56
Double_t Sin(Double_t)
Definition: TMath.h:547
#define XV_COPYRIGHT
Definition: Rotated.cxx:45
const Int_t n
Definition: legend1.C:16
Double_t Tan(Double_t)
Definition: TMath.h:553
#define XA_FONT
Definition: xatom.h:27
static XImage * MakeXImage(Display *dpy, int w, int h)
Create an XImage structure and allocate memory for it.
Definition: Rotated.cxx:266