Logo ROOT   6.16/01
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
91static int gRotatedDebug=1;
92#else
93static 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
112typedef 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
145static struct StyleTemplate_t {
146 float fMagnify;
147 int fBbxPadl;
148} gRotStyle={
149 1.,
150 0
151 };
152
153/* ---------------------------------------------------------------------- */
154static char *my_strdup(char *);
155static char *my_strtok(char *, char *);
156
157float XRotVersion(char*, int);
158void XRotSetMagnification(float);
159void XRotSetBoundingBoxPad(int);
160int XRotDrawString(Display*, XFontStruct*, float,Drawable, GC, int, int, char*);
161int XRotDrawImageString(Display*, XFontStruct*, float,Drawable, GC, int, int, char*);
162int XRotDrawAlignedString(Display*, XFontStruct*, float,Drawable, GC, int, int, char*, int);
163int XRotDrawAlignedImageString(Display*, XFontStruct*, float,Drawable, GC, int, int, char*, int);
164XPoint *XRotTextExtents(Display*, XFontStruct*, float,int, int, char*, int);
165
166static XImage *MakeXImage(Display *dpy,int w, int h);
167static int XRotPaintAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x,int y, char *text,int align, int bg);
168static int XRotDrawHorizontalString(Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, char *text,int align, int bg);
169static RotatedTextItem_t *XRotRetrieveFromCache(Display *dpy, XFontStruct *font, float angle, char *text, int align);
170static RotatedTextItem_t *XRotCreateTextItem(Display *dpy, XFontStruct *font, float angle, char *text, int align);
171static void XRotAddToLinkedList(Display *dpy, RotatedTextItem_t *item);
172static void XRotFreeTextItem(Display *dpy, RotatedTextItem_t *item);
173static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage);
174
175
176////////////////////////////////////////////////////////////////////////////////
177/// Routine to mimic `strdup()' (some machines don't have it)
178
179static 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
195static 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
238float 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
266static 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
292int 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
303int 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
314int 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
325int 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
336static 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
567static 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
664static 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
804static 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
1118static 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
1221static 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
1244static 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
1350XPoint *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 h(i)
Definition: RSha256.hxx:106
int XRotDrawImageString(Display *, XFontStruct *, float, Drawable, GC, int, int, char *)
A front end to XRotPaintAlignedString: -no alignment, paints background.
Definition: Rotated.cxx:303
#define MLEFT
Definition: Rotated.cxx:56
int XRotDrawString(Display *, XFontStruct *, float, Drawable, GC, int, int, char *)
A front end to XRotPaintAlignedString: -no alignment, no background.
Definition: Rotated.cxx:292
static struct StyleTemplate_t gRotStyle
#define BCENTRE
Definition: Rotated.cxx:60
#define TCENTRE
Definition: Rotated.cxx:54
float XRotVersion(char *, int)
Return version/copyright information.
Definition: Rotated.cxx:238
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 NONE
Definition: Rotated.cxx:52
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
void XRotSetBoundingBoxPad(int)
Set the padding used when calculating bounding boxes.
Definition: Rotated.cxx:257
static RotatedTextItem_t * XRotCreateTextItem(Display *dpy, XFontStruct *font, float angle, char *text, int align)
Create a rotated text item.
Definition: Rotated.cxx:804
#define MRIGHT
Definition: Rotated.cxx:58
static char * my_strdup(char *)
Routine to mimic ‘strdup()’ (some machines don't have it)
Definition: Rotated.cxx:179
#define MCENTRE
Definition: Rotated.cxx:57
#define BLEFT
Definition: Rotated.cxx:59
struct RotatedTextItemTemplate_t RotatedTextItem_t
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 void XRotFreeTextItem(Display *dpy, RotatedTextItem_t *item)
Free the resources used by a text item.
Definition: Rotated.cxx:1221
#define TLEFT
Definition: Rotated.cxx:53
#define DEBUG_PRINT5(a, b, c, d, e)
Definition: Rotated.cxx:100
static XImage * XRotMagnifyImage(Display *dpy, XImage *ximage)
Magnify an XImage using bilinear interpolation.
Definition: Rotated.cxx:1244
#define CACHE_SIZE_LIMIT
Definition: Rotated.cxx:75
#define XV_COPYRIGHT
Definition: Rotated.cxx:45
#define DEBUG_PRINT2(a, b)
Definition: Rotated.cxx:97
int XRotDrawAlignedString(Display *, XFontStruct *, float, Drawable, GC, int, int, char *, int)
A front end to XRotPaintAlignedString: -does alignment, no background.
Definition: Rotated.cxx:314
#define XV_VERSION
Definition: Rotated.cxx:44
#define DEBUG_PRINT4(a, b, c, d)
Definition: Rotated.cxx:99
static RotatedTextItem_t * gFirstTextItem
Definition: Rotated.cxx:139
#define TRIGHT
Definition: Rotated.cxx:55
static int gRotatedDebug
Definition: Rotated.cxx:93
XPoint * XRotTextExtents(Display *, XFontStruct *, float, int, int, char *, int)
Calculate the bounding box some text will have when painted.
Definition: Rotated.cxx:1350
static char * my_strtok(char *, char *)
Routine to replace ‘strtok’ : this one returns a zero length string if it encounters two consecutive ...
Definition: Rotated.cxx:195
#define BRIGHT
Definition: Rotated.cxx:61
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
void XRotSetMagnification(float)
Set the font magnification factor for all subsequent operations.
Definition: Rotated.cxx:248
#define M_PI
Definition: Rotated.cxx:105
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
#define DEBUG_PRINT1(a)
Definition: Rotated.cxx:96
static XImage * MakeXImage(Display *dpy, int w, int h)
Create an XImage structure and allocate memory for it.
Definition: Rotated.cxx:266
XID Drawable
Definition: TGX11.h:36
#define free
Definition: civetweb.c:1539
#define calloc
Definition: civetweb.c:1537
#define malloc
Definition: civetweb.c:1536
TText * text
Double_t y[n]
Definition: legend1.C:17
Double_t x[n]
Definition: legend1.C:17
const Int_t n
Definition: legend1.C:16
static constexpr double s
Double_t Cos(Double_t)
Definition: TMath.h:629
Double_t Sin(Double_t)
Definition: TMath.h:625
Double_t Tan(Double_t)
Definition: TMath.h:633
Short_t Abs(Short_t d)
Definition: TMathBase.h:120
auto * m
Definition: textangle.C:8
#define XA_FONT
Definition: xatom.h:27