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