Rotated.cxx

Go to the documentation of this file.
00001 // @(#)root/x11:$Id: Rotated.cxx 35053 2010-08-27 16:19:23Z couet $
00002 // Author: O.Couet   17/11/93
00003 
00004 #ifndef _XVERTEXT_INCLUDED_
00005 #define _XVERTEXT_INCLUDED_
00006 
00007 //______________________________________________________________________________
00008 /* ********************************************************************** *
00009  *
00010  * xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma)
00011  *
00012  * Alignment definition modified by O.Couet.
00013  * Mods IBM/VM by O.Couet.
00014  *
00015  * Permission to use, copy, modify, and distribute this software and its
00016  * documentation for any purpose and without fee is hereby granted, provided
00017  * that the above copyright notice appear in all copies and that both the
00018  * copyright notice and this permission notice appear in supporting
00019  * documentation.  All work developed as a consequence of the use of
00020  * this program should duly acknowledge such use. No representations are
00021  * made about the suitability of this software for any purpose.  It is
00022  * provided "as is" without express or implied warranty.
00023  *
00024  * ********************************************************************** */
00025 
00026 #include <X11/Xlib.h>
00027 #include <X11/Xutil.h>
00028 #include <X11/Xatom.h>
00029 #include <stdio.h>
00030 #include <string.h>
00031 #include <stdlib.h>
00032 
00033 #include "TMath.h"
00034 
00035 /* ************************************************************************ *
00036  *
00037  * Header file for the `xvertext 5.0' routines.
00038  *
00039  * Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma)
00040  *
00041  * ************************************************************************ */
00042 
00043 #define XV_VERSION      5.0
00044 #define XV_COPYRIGHT \
00045       "xvertext routines Copyright (c) 1993 Alan Richardson"
00046 
00047 /* ---------------------------------------------------------------------- */
00048 
00049 /* text alignment */
00050 
00051 #define NONE             0
00052 #define TLEFT            1
00053 #define TCENTRE          2
00054 #define TRIGHT           3
00055 #define MLEFT            4
00056 #define MCENTRE          5
00057 #define MRIGHT           6
00058 #define BLEFT            7
00059 #define BCENTRE          8
00060 #define BRIGHT           9
00061 
00062 #ifdef VAX
00063 #define X11R3
00064 #endif
00065 
00066 
00067 #endif /* _XVERTEXT_INCLUDED_ */
00068 
00069 /* ---------------------------------------------------------------------- */
00070 
00071 /* Make sure cache size is set */
00072 
00073 #ifndef CACHE_SIZE_LIMIT
00074 #define CACHE_SIZE_LIMIT 0
00075 #endif /*CACHE_SIZE_LIMIT */
00076 
00077 /* Make sure a cache method is specified */
00078 
00079 #ifndef CACHE_XIMAGES
00080 #ifndef CACHE_BITMAPS
00081 #define CACHE_BITMAPS
00082 #endif /*CACHE_BITMAPS*/
00083 #endif /*CACHE_XIMAGES*/
00084 
00085 /* ---------------------------------------------------------------------- */
00086 
00087 /* Debugging macros */
00088 
00089 #ifdef DEBUG
00090 static int gRotatedDebug=1;
00091 #else
00092 static int gRotatedDebug=0;
00093 #endif /*DEBUG*/
00094 
00095 #define DEBUG_PRINT1(a) if (gRotatedDebug) printf (a)
00096 #define DEBUG_PRINT2(a, b) if (gRotatedDebug) printf (a, b)
00097 #define DEBUG_PRINT3(a, b, c) if (gRotatedDebug) printf (a, b, c)
00098 #define DEBUG_PRINT4(a, b, c, d) if (gRotatedDebug) printf (a, b, c, d)
00099 #define DEBUG_PRINT5(a, b, c, d, e) if (gRotatedDebug) printf (a, b, c, d, e)
00100 
00101 /* ---------------------------------------------------------------------- */
00102 
00103 #ifndef M_PI
00104 #define M_PI 3.14159265358979323846
00105 #endif
00106 
00107 /* ---------------------------------------------------------------------- */
00108 
00109 /* A structure holding everything needed for a rotated string */
00110 
00111 typedef struct RotatedTextItemTemplate_t {
00112    Pixmap fBitmap;
00113    XImage *fXimage;
00114 
00115    char *fText;
00116    char *font_name;
00117    Font fid;
00118    float fAngle;
00119    int fAlign;
00120    float fMagnify;
00121 
00122    int fColsIn;
00123    int fRowsIn;
00124    int fColsOut;
00125    int fRowsOut;
00126 
00127    int fNl;
00128    int fMaxWidth;
00129    float *fCornersX;
00130    float *fCornersY;
00131 
00132    long int fSize;
00133    int fCached;
00134 
00135    struct RotatedTextItemTemplate_t *fNext;
00136 } RotatedTextItem_t;
00137 
00138 static RotatedTextItem_t *gFirstTextItem=0;
00139 
00140 /* ---------------------------------------------------------------------- */
00141 
00142 /* A structure holding current magnification and bounding box padding */
00143 
00144 static struct StyleTemplate_t {
00145    float fMagnify;
00146    int fBbxPadl;
00147 } gRotStyle={
00148    1.,
00149    0
00150    };
00151 
00152 /* ---------------------------------------------------------------------- */
00153 static char              *my_strdup(char *);
00154 static char              *my_strtok(char *, char *);
00155 
00156 float                     XRotVersion(char*, int);
00157 void                      XRotSetMagnification(float);
00158 void                      XRotSetBoundingBoxPad(int);
00159 int                       XRotDrawString(Display*, XFontStruct*, float,Drawable, GC, int, int, char*);
00160 int                       XRotDrawImageString(Display*, XFontStruct*, float,Drawable, GC, int, int, char*);
00161 int                       XRotDrawAlignedString(Display*, XFontStruct*, float,Drawable, GC, int, int, char*, int);
00162 int                       XRotDrawAlignedImageString(Display*, XFontStruct*, float,Drawable, GC, int, int, char*, int);
00163 XPoint                   *XRotTextExtents(Display*, XFontStruct*, float,int, int, char*, int);
00164 
00165 static XImage            *MakeXImage(Display *dpy,int  w, int h);
00166 static int                XRotPaintAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x,int y, char *text,int align, int bg);
00167 static int                XRotDrawHorizontalString(Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, char *text,int align, int bg);
00168 static RotatedTextItem_t *XRotRetrieveFromCache(Display *dpy, XFontStruct *font, float angle, char *text, int align);
00169 static RotatedTextItem_t *XRotCreateTextItem(Display *dpy, XFontStruct *font, float angle, char *text, int align);
00170 static void               XRotAddToLinkedList(Display *dpy, RotatedTextItem_t *item);
00171 static void               XRotFreeTextItem(Display *dpy, RotatedTextItem_t *item);
00172 static XImage            *XRotMagnifyImage(Display *dpy, XImage *ximage);
00173 
00174 
00175 //______________________________________________________________________________
00176 static char *my_strdup(char *str)
00177 {
00178    // Routine to mimic `strdup()' (some machines don't have it)
00179 
00180    char *s;
00181 
00182    if(str==0) return 0;
00183 
00184    s=(char *)malloc((unsigned)(strlen(str)+1));
00185    if(s!=0) strcpy(s, str);
00186 
00187    return s;
00188 }
00189 
00190 //______________________________________________________________________________
00191 static char *my_strtok(char *str1, char *str2)
00192 {
00193    // Routine to replace `strtok' : this one returns a zero length string if
00194    // it encounters two consecutive delimiters
00195 
00196    char *ret;
00197    int i, j, stop;
00198    static int start, len;
00199    static char *stext;
00200 
00201    if(str2==0) return 0;
00202 
00203    /* initialise if str1 not 0 */
00204    if(str1!=0) {
00205       start=0;
00206       stext=str1;
00207       len=strlen(str1);
00208    }
00209 
00210    /* run out of tokens ? */
00211    if(start>=len) return 0;
00212 
00213    /* loop through characters */
00214    for(i=start; i<len; i++) {
00215       /* loop through delimiters */
00216       stop=0;
00217       for(j=0; j<(int)strlen(str2); j++)
00218       if(stext[i]==str2[j])
00219       stop=1;
00220 
00221       if(stop) break;
00222    }
00223 
00224    stext[i]='\0';
00225 
00226    ret=stext+start;
00227 
00228    start=i+1;
00229 
00230    return ret;
00231 }
00232 
00233 
00234 //______________________________________________________________________________
00235 float XRotVersion(char *str,int n)
00236 {
00237    // Return version/copyright information
00238 
00239    if(str!=0) strncpy(str, XV_COPYRIGHT, n);
00240    return XV_VERSION;
00241 }
00242 
00243 
00244 //______________________________________________________________________________
00245 void XRotSetMagnification(float m)
00246 {
00247    // Set the font magnification factor for all subsequent operations
00248 
00249    if(m>0.) gRotStyle.fMagnify=m;
00250 }
00251 
00252 
00253 //______________________________________________________________________________
00254 void XRotSetBoundingBoxPad(int p)
00255 {
00256    // Set the padding used when calculating bounding boxes
00257 
00258    if(p>=0) gRotStyle.fBbxPadl=p;
00259 }
00260 
00261 
00262 //______________________________________________________________________________
00263 static XImage *MakeXImage(Display *dpy,int  w, int h)
00264 {
00265    // Create an XImage structure and allocate memory for it
00266 
00267    XImage *image;
00268    char *data;
00269 
00270    /* reserve memory for image */
00271    data=(char *)calloc((unsigned)(((w-1)/8+1)*h), 1);
00272    if(data==0) return 0;
00273 
00274    /* create the XImage */
00275    image=XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap,
00276                    0, data, w, h, 8, 0);
00277    if(image==0) return 0;
00278 
00279    image->byte_order=image->bitmap_bit_order=MSBFirst;
00280    return image;
00281 }
00282 
00283 
00284 //______________________________________________________________________________
00285 int XRotDrawString(Display *dpy, XFontStruct *font,float angle,Drawable drawable, GC gc, int x, int y, char *str)
00286 {
00287    // A front end to XRotPaintAlignedString:
00288    //     -no alignment, no background
00289 
00290    return (XRotPaintAlignedString(dpy, font, angle, drawable, gc,
00291                                   x, y, str, NONE, 0));
00292 }
00293 
00294 
00295 //______________________________________________________________________________
00296 int XRotDrawImageString(Display *dpy,XFontStruct *font, float angle, Drawable drawable,GC  gc, int x, int y, char *str)
00297 {
00298    // A front end to XRotPaintAlignedString:
00299    //     -no alignment, paints background
00300 
00301    return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
00302                                  x, y, str, NONE, 1));
00303 }
00304 
00305 
00306 //______________________________________________________________________________
00307 int XRotDrawAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text,int align)
00308 {
00309    // A front end to XRotPaintAlignedString:
00310    //     -does alignment, no background
00311 
00312    return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
00313                                  x, y, text, align, 0));
00314 }
00315 
00316 
00317 //______________________________________________________________________________
00318 int XRotDrawAlignedImageString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text,
00319                                int align)
00320 {
00321    // A front end to XRotPaintAlignedString:
00322    //     -does alignment, paints background
00323 
00324    return(XRotPaintAlignedString(dpy, font, angle, drawable, gc,
00325                                  x, y, text, align, 1));
00326 }
00327 
00328 
00329 //______________________________________________________________________________
00330 static int XRotPaintAlignedString(Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text,
00331                                   int align, int bg)
00332 {
00333    // Aligns and paints a rotated string
00334 
00335    int i;
00336    GC my_gc;
00337    int xp, yp;
00338    float hot_x, hot_y;
00339    float hot_xp, hot_yp;
00340    float sin_angle, cos_angle;
00341    RotatedTextItem_t *item;
00342    Pixmap bitmap_to_paint;
00343 
00344    /* return early for 0/empty strings */
00345    if(text==0) return 0;
00346 
00347    if(strlen(text)==0) return 0;
00348 
00349    /* manipulate angle to 0<=angle<360 degrees */
00350    while(angle<0) angle+=360;
00351 
00352    while(angle>=360) angle-=360;
00353 
00354    angle*=M_PI/180;
00355 
00356    /* horizontal text made easy */
00357    if(angle==0. && gRotStyle.fMagnify==1.)
00358       return(XRotDrawHorizontalString(dpy, font, drawable, gc, x, y,
00359                                       text, align, bg));
00360 
00361    /* get a rotated bitmap */
00362    item=XRotRetrieveFromCache(dpy, font, angle, text, align);
00363    if(item==0) return 0;
00364 
00365    /* this gc has similar properties to the user's gc */
00366    my_gc=XCreateGC(dpy, drawable, 0, 0);
00367    XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCPlaneMask,
00368            my_gc);
00369 
00370    /* alignment : which point (hot_x, hot_y) relative to bitmap centre
00371       coincides with user's specified point? */
00372 
00373    /* y position */
00374    if(align==TLEFT || align==TCENTRE || align==TRIGHT)
00375       hot_y=(float)item->fRowsIn/2*gRotStyle.fMagnify;
00376    else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
00377    {
00378       /*  Modify by O.Couet to have Bottom alignment without font->descent */
00379       hot_y=0;
00380       /*    hot_y=-((float)item->fRowsIn/4-(float)font->descent)*gRotStyle.fMagnify; */
00381    }
00382    else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
00383    {
00384       /*  Modify by O.Couet to have Bottom alignment without font->descent */
00385       /*  hot_y=-(float)item->fRowsIn/2*gRotStyle.fMagnify; */
00386       hot_y=-((float)item->fRowsIn/2-(float)font->descent)*gRotStyle.fMagnify;
00387    }
00388    else
00389       hot_y=-((float)item->fRowsIn/2-(float)font->descent)*gRotStyle.fMagnify;
00390 
00391    /* x position */
00392    if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
00393       hot_x=-(float)item->fMaxWidth/2*gRotStyle.fMagnify;
00394    else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
00395       hot_x=0;
00396    else
00397       hot_x=(float)item->fMaxWidth/2*gRotStyle.fMagnify;
00398 
00399    /* pre-calculate sin and cos */
00400    sin_angle=TMath::Sin(angle);
00401    cos_angle=TMath::Cos(angle);
00402 
00403    /* rotate hot_x and hot_y around bitmap centre */
00404    hot_xp= hot_x*cos_angle - hot_y*sin_angle;
00405    hot_yp= hot_x*sin_angle + hot_y*cos_angle;
00406 
00407    /* text background will be drawn using XFillPolygon */
00408    if(bg) {
00409       GC depth_one_gc;
00410       XPoint *xpoints;
00411       Pixmap empty_stipple;
00412 
00413       /* reserve space for XPoints */
00414       xpoints=(XPoint *)malloc((unsigned)(4*item->fNl*sizeof(XPoint)));
00415       if(!xpoints) return 1;
00416 
00417       /* rotate corner positions */
00418       for(i=0; i<4*item->fNl; i++) {
00419          xpoints[i].x=int((float)x + ( (item->fCornersX[i]-hot_x)*cos_angle +
00420                                    (item->fCornersY[i]+hot_y)*sin_angle));
00421          xpoints[i].y=int((float)y + (-(item->fCornersX[i]-hot_x)*sin_angle +
00422                                    (item->fCornersY[i]+hot_y)*cos_angle));
00423       }
00424 
00425       /* we want to swap foreground and background colors here;
00426          XGetGCValues() is only available in R4+ */
00427 
00428       empty_stipple=XCreatePixmap(dpy, drawable, 1, 1, 1);
00429 
00430       depth_one_gc=XCreateGC(dpy, empty_stipple, 0, 0);
00431       XSetForeground(dpy, depth_one_gc, 0);
00432       XFillRectangle(dpy, empty_stipple, depth_one_gc, 0, 0, 2, 2);
00433 
00434       XSetStipple(dpy, my_gc, empty_stipple);
00435       XSetFillStyle(dpy, my_gc, FillOpaqueStippled);
00436 
00437       XFillPolygon(dpy, drawable, my_gc, xpoints, 4*item->fNl, Nonconvex,
00438                    CoordModeOrigin);
00439 
00440       /* free our resources */
00441       free((char *)xpoints);
00442       XFreeGC(dpy, depth_one_gc);
00443       XFreePixmap(dpy, empty_stipple);
00444    }
00445 
00446    /* where should top left corner of bitmap go ? */
00447    xp=int((float)x-((float)item->fColsOut/2 +hot_xp));
00448    yp=int((float)y-((float)item->fRowsOut/2 -hot_yp));
00449 
00450    /* by default we draw the rotated bitmap, solid */
00451    bitmap_to_paint=item->fBitmap;
00452 
00453     /* handle user stippling */
00454 #ifndef X11R3
00455    {
00456       GC depth_one_gc;
00457       XGCValues values;
00458       Pixmap new_bitmap, inverse;
00459 
00460       /* try and get some GC properties */
00461       if(XGetGCValues(dpy, gc,
00462                       GCStipple|GCFillStyle|GCForeground|GCBackground|
00463                       GCTileStipXOrigin|GCTileStipYOrigin,
00464                       &values)) {
00465 
00466          /* only do this if stippling requested */
00467          if((values.fill_style==FillStippled ||
00468              values.fill_style==FillOpaqueStippled) && !bg) {
00469 
00470             /* opaque stipple: draw rotated text in background colour */
00471             if(values.fill_style==FillOpaqueStippled) {
00472                XSetForeground(dpy, my_gc, values.background);
00473                XSetFillStyle(dpy, my_gc, FillStippled);
00474                XSetStipple(dpy, my_gc, item->fBitmap);
00475                XSetTSOrigin(dpy, my_gc, xp, yp);
00476                XFillRectangle(dpy, drawable, my_gc, xp, yp,
00477                               item->fColsOut, item->fRowsOut);
00478                XSetForeground(dpy, my_gc, values.foreground);
00479             }
00480 
00481             /* this will merge the rotated text and the user's stipple */
00482             new_bitmap=XCreatePixmap(dpy, drawable,
00483                                      item->fColsOut, item->fRowsOut, 1);
00484 
00485             /* create a GC */
00486             depth_one_gc=XCreateGC(dpy, new_bitmap, 0, 0);
00487             XSetForeground(dpy, depth_one_gc, 1);
00488             XSetBackground(dpy, depth_one_gc, 0);
00489 
00490             /* set the relative stipple origin */
00491             XSetTSOrigin(dpy, depth_one_gc,
00492                          values.ts_x_origin-xp, values.ts_y_origin-yp);
00493 
00494             /* fill the whole bitmap with the user's stipple */
00495             XSetStipple(dpy, depth_one_gc, values.stipple);
00496             XSetFillStyle(dpy, depth_one_gc, FillOpaqueStippled);
00497             XFillRectangle(dpy, new_bitmap, depth_one_gc,
00498                            0, 0, item->fColsOut, item->fRowsOut);
00499 
00500             /* set stipple origin back to normal */
00501             XSetTSOrigin(dpy, depth_one_gc, 0, 0);
00502 
00503             /* this will contain an inverse copy of the rotated text */
00504             inverse=XCreatePixmap(dpy, drawable,
00505                                   item->fColsOut, item->fRowsOut, 1);
00506 
00507             /* invert text */
00508             XSetFillStyle(dpy, depth_one_gc, FillSolid);
00509             XSetFunction(dpy, depth_one_gc, GXcopyInverted);
00510             XCopyArea(dpy, item->fBitmap, inverse, depth_one_gc,
00511                       0, 0, item->fColsOut, item->fRowsOut, 0, 0);
00512 
00513             /* now delete user's stipple everywhere EXCEPT on text */
00514             XSetForeground(dpy, depth_one_gc, 0);
00515             XSetBackground(dpy, depth_one_gc, 1);
00516             XSetStipple(dpy, depth_one_gc, inverse);
00517             XSetFillStyle(dpy, depth_one_gc, FillStippled);
00518             XSetFunction(dpy, depth_one_gc, GXcopy);
00519             XFillRectangle(dpy, new_bitmap, depth_one_gc,
00520                            0, 0, item->fColsOut, item->fRowsOut);
00521 
00522             /* free resources */
00523             XFreePixmap(dpy, inverse);
00524             XFreeGC(dpy, depth_one_gc);
00525 
00526             /* this is the new bitmap */
00527             bitmap_to_paint=new_bitmap;
00528          }
00529       }
00530    }
00531 #endif /*X11R3*/
00532 
00533    /* paint text using stipple technique */
00534    XSetFillStyle(dpy, my_gc, FillStippled);
00535    XSetStipple(dpy, my_gc, bitmap_to_paint);
00536    XSetTSOrigin(dpy, my_gc, xp, yp);
00537    XFillRectangle(dpy, drawable, my_gc, xp, yp,
00538                   item->fColsOut, item->fRowsOut);
00539 
00540    /* free our resources */
00541    XFreeGC(dpy, my_gc);
00542 
00543    /* stippled bitmap no longer needed */
00544    if(bitmap_to_paint!=item->fBitmap)
00545       XFreePixmap(dpy, bitmap_to_paint);
00546 
00547 #ifdef CACHE_XIMAGES
00548    XFreePixmap(dpy, item->fBitmap);
00549 #endif /*CACHE_XIMAGES*/
00550 
00551    /* if item isn't cached, destroy it completely */
00552    if(!item->fCached)
00553       XRotFreeTextItem(dpy,item);
00554 
00555    /* we got to the end OK! */
00556    return 0;
00557 }
00558 
00559 
00560 //______________________________________________________________________________
00561 static int XRotDrawHorizontalString(Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, char *text,
00562                                     int align, int bg)
00563 {
00564    //  Draw a horizontal string in a quick fashion
00565 
00566    GC my_gc;
00567    int nl=1, i;
00568    int height;
00569    int xp, yp;
00570    char *str1, *str2, *str3;
00571    const char *str2_a="\0", *str2_b="\n\0";
00572    int dir, asc, desc;
00573    XCharStruct overall;
00574 
00575    DEBUG_PRINT1("**\nHorizontal text.\n");
00576 
00577    /* this gc has similar properties to the user's gc (including stipple) */
00578    my_gc=XCreateGC(dpy, drawable, 0, 0);
00579    XCopyGC(dpy, gc,
00580            GCForeground|GCBackground|GCFunction|GCStipple|GCFillStyle|
00581            GCTileStipXOrigin|GCTileStipYOrigin|GCPlaneMask, my_gc);
00582    XSetFont(dpy, my_gc, font->fid);
00583 
00584    /* count number of sections in string */
00585    if(align!=NONE)
00586       for(i=0; i<(int)strlen(text)-1; i++)
00587          if(text[i]=='\n')
00588             nl++;
00589 
00590    /* ignore newline characters if not doing alignment */
00591    if(align==NONE)
00592       str2=(char *)str2_a;
00593    else
00594       str2=(char *)str2_b;
00595 
00596    /* overall font height */
00597    height=font->ascent+font->descent;
00598 
00599    /* y position */
00600    if(align==TLEFT || align==TCENTRE || align==TRIGHT)
00601       yp=y+font->ascent;
00602    else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
00603    {
00604       /*  Modify by O.Couet to have Middle alignment without font->descent */
00605       /*  yp=y-nl*height/2+font->ascent; */
00606       yp=y-nl*(height-font->descent)/2+font->ascent;
00607    }
00608    else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
00609    {
00610       /*  Modify by O.Couet to have Bottom alignment without font->descent */
00611       /*  yp=y-nl*height+font->ascent; */
00612       yp=y-nl*(height-font->descent)+font->ascent;
00613    }
00614    else
00615       yp=y;
00616 
00617    str1=my_strdup(text);
00618    if(str1==0) return 1;
00619 
00620    str3=my_strtok(str1, str2);
00621 
00622    /* loop through each section in the string */
00623    do {
00624       XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
00625                    &overall);
00626 
00627       /* where to draw section in x ? */
00628       if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
00629          xp=x;
00630       else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
00631          xp=x-overall.rbearing/2;
00632       else
00633          xp=x-overall.rbearing;
00634 
00635       /* draw string onto bitmap */
00636       if(!bg)
00637          XDrawString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
00638       else
00639          XDrawImageString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
00640 
00641       /* move to next line */
00642       yp+=height;
00643 
00644       str3=my_strtok((char *)0, str2);
00645    }
00646    while(str3!=0);
00647 
00648    free(str1);
00649    XFreeGC(dpy, my_gc);
00650 
00651    return 0;
00652 }
00653 
00654 
00655 //______________________________________________________________________________
00656 static RotatedTextItem_t *XRotRetrieveFromCache(Display *dpy, XFontStruct *font, float angle, char *text, int align)
00657 {
00658    // Query cache for a match with this font/text/angle/alignment
00659    //    request, otherwise arrange for its creation
00660 
00661    Font fid;
00662    char *font_name;
00663    unsigned long name_value;
00664    RotatedTextItem_t *item=0;
00665    RotatedTextItem_t *i1=gFirstTextItem;
00666 
00667    /* get font name, if it exists */
00668    if(XGetFontProperty(font, XA_FONT, &name_value)) {
00669       DEBUG_PRINT1("got font name OK\n");
00670       font_name=XGetAtomName(dpy, name_value);
00671       fid=0;
00672    }
00673 #ifdef CACHE_FID
00674    /* otherwise rely (unreliably?) on font ID */
00675    else {
00676       DEBUG_PRINT1("can't get fontname, caching FID\n");
00677       font_name=0;
00678       fid=font->fid;
00679    }
00680 #else
00681    /* not allowed to cache font ID's */
00682    else {
00683       DEBUG_PRINT1("can't get fontname, can't cache\n");
00684       font_name=0;
00685       fid=0;
00686    }
00687 #endif /*CACHE_FID*/
00688 
00689    /* look for a match in cache */
00690 
00691    /* matching formula:
00692       identical text;
00693       identical fontname (if defined, font ID's if not);
00694       angles close enough (<0.00001 here, could be smaller);
00695       HORIZONTAL alignment matches, OR it's a one line string;
00696       magnifications the same */
00697 
00698    while(i1 && !item) {
00699       /* match everything EXCEPT fontname/ID */
00700       if(strcmp(text, i1->fText)==0 &&
00701          TMath::Abs(angle-i1->fAngle)<0.00001 &&
00702          gRotStyle.fMagnify==i1->fMagnify &&
00703          (i1->fNl==1 ||
00704          ((align==0)?9:(align-1))%3==
00705          ((i1->fAlign==0)?9:(i1->fAlign-1))%3)) {
00706 
00707          /* now match fontname/ID */
00708          if(font_name!=0 && i1->font_name!=0) {
00709             if(strcmp(font_name, i1->font_name)==0) {
00710                item=i1;
00711                DEBUG_PRINT1("Matched against font names\n");
00712             }
00713             else
00714                i1=i1->fNext;
00715          }
00716 #ifdef CACHE_FID
00717          else if(font_name==0 && i1->font_name==0) {
00718             if(fid==i1->fid) {
00719                item=i1;
00720                DEBUG_PRINT1("Matched against FID's\n");
00721             }
00722             else
00723                i1=i1->fNext;
00724          }
00725 #endif /*CACHE_FID*/
00726          else
00727             i1=i1->fNext;
00728       }
00729       else
00730          i1=i1->fNext;
00731    }
00732 
00733    if(item)
00734       DEBUG_PRINT1("**\nFound target in cache.\n");
00735    if(!item)
00736       DEBUG_PRINT1("**\nNo match in cache.\n");
00737 
00738    /* no match */
00739    if(!item) {
00740       /* create new item */
00741       item=XRotCreateTextItem(dpy, font, angle, text, align);
00742       if(!item)
00743          return 0;
00744 
00745       /* record what it shows */
00746       item->fText=my_strdup(text);
00747 
00748       /* fontname or ID */
00749       if(font_name!=0) {
00750          item->font_name=my_strdup(font_name);
00751          item->fid=0;
00752       }
00753       else {
00754          item->font_name=0;
00755          item->fid=fid;
00756       }
00757 
00758       item->fAngle=angle;
00759       item->fAlign=align;
00760       item->fMagnify=gRotStyle.fMagnify;
00761 
00762       /* cache it */
00763       XRotAddToLinkedList(dpy, item);
00764    }
00765 
00766    if(font_name)
00767       XFree(font_name);
00768 
00769    /* if XImage is cached, need to recreate the bitmap */
00770 
00771 #ifdef CACHE_XIMAGES
00772    {
00773       GC depth_one_gc;
00774 
00775       /* create bitmap to hold rotated text */
00776       item->fBitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
00777                                   item->fColsOut, item->fRowsOut, 1);
00778 
00779       /* depth one gc */
00780       depth_one_gc=XCreateGC(dpy, item->fBitmap, 0, 0);
00781       XSetBackground(dpy, depth_one_gc, 0);
00782       XSetForeground(dpy, depth_one_gc, 1);
00783 
00784       /* make the text bitmap from XImage */
00785       XPutImage(dpy, item->fBitmap, depth_one_gc, item->fXimage, 0, 0, 0, 0,
00786                 item->fColsOut, item->fRowsOut);
00787 
00788       XFreeGC(dpy, depth_one_gc);
00789    }
00790 #endif /*CACHE_XIMAGES*/
00791 
00792    return item;
00793 }
00794 
00795 
00796 //______________________________________________________________________________
00797 static RotatedTextItem_t *XRotCreateTextItem(Display *dpy, XFontStruct *font, float angle, char *text, int align)
00798 {
00799    //  Create a rotated text item
00800 
00801    RotatedTextItem_t *item;
00802    Pixmap canvas;
00803    GC font_gc;
00804    XImage *imageIn;
00805    register int i, j;
00806    char *str1, *str2, *str3;
00807    const char *str2_a="\0", *str2_b="\n\0";
00808    int height;
00809    int byte_w_in, byte_w_out;
00810    int xp, yp;
00811    float sin_angle, cos_angle;
00812    int it, jt;
00813    float di, dj;
00814    int ic=0;
00815    float xl, xr, xinc;
00816    int byte_out;
00817    int dir, asc, desc;
00818    XCharStruct overall;
00819    int old_cols_in=0, old_rows_in=0;
00820 
00821    /* allocate memory */
00822    item=(RotatedTextItem_t *)malloc((unsigned)sizeof(RotatedTextItem_t));
00823    if(!item) return 0;
00824 
00825    /* count number of sections in string */
00826    item->fNl=1;
00827    if(align!=NONE)
00828       for(i=0; i<(int)strlen(text)-1; i++)
00829          if(text[i]=='\n')
00830             item->fNl++;
00831 
00832    /* ignore newline characters if not doing alignment */
00833    if(align==NONE)
00834       str2=(char *)str2_a;
00835    else
00836       str2=(char *)str2_b;
00837 
00838    /* find width of longest section */
00839    str1=my_strdup(text);
00840    if(str1==0) {
00841       free(item);
00842       return 0;
00843    }
00844 
00845    str3=my_strtok(str1, str2);
00846 
00847    XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
00848                 &overall);
00849 
00850    item->fMaxWidth=overall.rbearing;
00851 
00852    /* loop through each section */
00853    do {
00854       str3=my_strtok((char *)0, str2);
00855 
00856       if(str3!=0) {
00857          XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
00858                       &overall);
00859          if(overall.rbearing>item->fMaxWidth)
00860             item->fMaxWidth=overall.rbearing;
00861       }
00862    }
00863    while(str3!=0);
00864 
00865    free(str1);
00866 
00867    /* overall font height */
00868    height=font->ascent+font->descent;
00869 
00870    /* dimensions horizontal text will have */
00871    item->fColsIn=item->fMaxWidth;
00872    item->fRowsIn=item->fNl*height;
00873 
00874    /* bitmap for drawing on */
00875    canvas=XCreatePixmap(dpy, DefaultRootWindow(dpy),
00876                          item->fColsIn, item->fRowsIn, 1);
00877 
00878    /* create a GC for the bitmap */
00879    font_gc=XCreateGC(dpy, canvas, 0, 0);
00880    XSetBackground(dpy, font_gc, 0);
00881    XSetFont(dpy, font_gc, font->fid);
00882 
00883    /* make sure the bitmap is blank */
00884    XSetForeground(dpy, font_gc, 0);
00885    XFillRectangle(dpy, canvas, font_gc, 0, 0,
00886                   item->fColsIn+1, item->fRowsIn+1);
00887    XSetForeground(dpy, font_gc, 1);
00888 
00889    /* pre-calculate sin and cos */
00890    sin_angle=TMath::Sin(angle);
00891    cos_angle=TMath::Cos(angle);
00892 
00893    /* text background will be drawn using XFillPolygon */
00894    item->fCornersX=
00895        (float *)malloc((unsigned)(4*item->fNl*sizeof(float)));
00896    if(!item->fCornersX) {
00897       free(item);
00898       return 0;
00899    }
00900 
00901    item->fCornersY=
00902        (float *)malloc((unsigned)(4*item->fNl*sizeof(float)));
00903    if(!item->fCornersY) {
00904       free(item);
00905       return 0;
00906    }
00907 
00908    /* draw text horizontally */
00909 
00910    /* start at top of bitmap */
00911    yp=font->ascent;
00912 
00913    str1=my_strdup(text);
00914    if(str1==0) {
00915       free(item);
00916       return 0;
00917    }
00918 
00919    str3=my_strtok(str1, str2);
00920 
00921    /* loop through each section in the string */
00922    do {
00923       XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
00924                    &overall);
00925 
00926       /* where to draw section in x ? */
00927       if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
00928          xp=0;
00929       else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
00930          xp=(item->fMaxWidth-overall.rbearing)/2;
00931       else
00932          xp=item->fMaxWidth-overall.rbearing;
00933 
00934       /* draw string onto bitmap */
00935       XDrawString(dpy, canvas, font_gc, xp, yp, str3, strlen(str3));
00936 
00937       /* keep a note of corner positions of this string */
00938       item->fCornersX[ic]=((float)xp-(float)item->fColsIn/2)*gRotStyle.fMagnify;
00939       item->fCornersY[ic]=((float)(yp-font->ascent)-(float)item->fRowsIn/2)
00940           *gRotStyle.fMagnify;
00941       item->fCornersX[ic+1]=item->fCornersX[ic];
00942       item->fCornersY[ic+1]=item->fCornersY[ic]+(float)height*gRotStyle.fMagnify;
00943       item->fCornersX[item->fNl*4-1-ic]=item->fCornersX[ic]+
00944           (float)overall.rbearing*gRotStyle.fMagnify;
00945       item->fCornersY[item->fNl*4-1-ic]=item->fCornersY[ic];
00946       item->fCornersX[item->fNl*4-2-ic]=
00947           item->fCornersX[item->fNl*4-1-ic];
00948       item->fCornersY[item->fNl*4-2-ic]=item->fCornersY[ic+1];
00949 
00950       ic+=2;
00951 
00952       /* move to next line */
00953       yp+=height;
00954 
00955       str3=my_strtok((char *)0, str2);
00956    }
00957    while(str3!=0);
00958 
00959    free(str1);
00960 
00961    /* create image to hold horizontal text */
00962    imageIn=MakeXImage(dpy, item->fColsIn, item->fRowsIn);
00963    if(imageIn==0) {
00964       free(item);
00965       return 0;
00966    }
00967 
00968    /* extract horizontal text */
00969    XGetSubImage(dpy, canvas, 0, 0, item->fColsIn, item->fRowsIn,
00970                 1, XYPixmap, imageIn, 0, 0);
00971    imageIn->format=XYBitmap;
00972 
00973    /* magnify horizontal text */
00974    if(gRotStyle.fMagnify!=1.) {
00975       imageIn=XRotMagnifyImage(dpy, imageIn);
00976 
00977       old_cols_in=item->fColsIn;
00978       old_rows_in=item->fRowsIn;
00979       item->fColsIn=int((float)item->fColsIn*gRotStyle.fMagnify);
00980       item->fRowsIn=int((float)item->fRowsIn*gRotStyle.fMagnify);
00981    }
00982 
00983    /* how big will rotated text be ? */
00984    item->fColsOut=int(TMath::Abs((float)item->fRowsIn*sin_angle) +
00985        TMath::Abs((float)item->fColsIn*cos_angle) +0.99999 +2);
00986 
00987    item->fRowsOut=int(TMath::Abs((float)item->fRowsIn*cos_angle) +
00988        TMath::Abs((float)item->fColsIn*sin_angle) +0.99999 +2);
00989 
00990    if(item->fColsOut%2==0) item->fColsOut++;
00991 
00992    if(item->fRowsOut%2==0) item->fRowsOut++;
00993 
00994    /* create image to hold rotated text */
00995    item->fXimage=MakeXImage(dpy, item->fColsOut, item->fRowsOut);
00996    if(item->fXimage==0) {
00997       free(item);
00998       return 0;
00999    }
01000 
01001    byte_w_in=(item->fColsIn-1)/8+1;
01002    byte_w_out=(item->fColsOut-1)/8+1;
01003 
01004    /* we try to make this bit as fast as possible - which is why it looks
01005       a bit over-the-top */
01006 
01007    /* vertical distance from centre */
01008    dj=0.5-(float)item->fRowsOut/2;
01009 
01010    /* where abouts does text actually lie in rotated image? */
01011    if(angle==0 || angle==M_PI/2 ||
01012       angle==M_PI || angle==3*M_PI/2) {
01013       xl=0;
01014       xr=(float)item->fColsOut;
01015       xinc=0;
01016    }
01017    else if(angle<M_PI) {
01018       xl=(float)item->fColsOut/2+
01019          (dj-(float)item->fRowsIn/(2*cos_angle))/
01020          TMath::Tan(angle)-2;
01021       xr=(float)item->fColsOut/2+
01022          (dj+(float)item->fRowsIn/(2*cos_angle))/
01023          TMath::Tan(angle)+2;
01024       xinc=1./TMath::Tan(angle);
01025    }
01026    else {
01027       xl=(float)item->fColsOut/2+
01028          (dj+(float)item->fRowsIn/(2*cos_angle))/
01029          TMath::Tan(angle)-2;
01030       xr=(float)item->fColsOut/2+
01031          (dj-(float)item->fRowsIn/(2*cos_angle))/
01032          TMath::Tan(angle)+2;
01033 
01034       xinc=1./TMath::Tan(angle);
01035    }
01036 
01037    /* loop through all relevent bits in rotated image */
01038    for(j=0; j<item->fRowsOut; j++) {
01039 
01040       /* no point re-calculating these every pass */
01041       di=(float)((xl<0)?0:(int)xl)+0.5-(float)item->fColsOut/2;
01042       byte_out=(item->fRowsOut-j-1)*byte_w_out;
01043 
01044       /* loop through meaningful columns */
01045       for(i=((xl<0)?0:(int)xl);
01046          i<((xr>=item->fColsOut)?item->fColsOut:(int)xr); i++) {
01047 
01048          /* rotate coordinates */
01049          it=int((float)item->fColsIn/2 + ( di*cos_angle + dj*sin_angle));
01050          jt=int((float)item->fRowsIn/2 - (-di*sin_angle + dj*cos_angle));
01051 
01052          /* set pixel if required */
01053          if(it>=0 && it<item->fColsIn && jt>=0 && jt<item->fRowsIn)
01054             if((imageIn->data[jt*byte_w_in+it/8] & 128>>(it%8))>0)
01055                item->fXimage->data[byte_out+i/8]|=128>>i%8;
01056 
01057          di+=1;
01058       }
01059       dj+=1;
01060       xl+=xinc;
01061       xr+=xinc;
01062    }
01063    XDestroyImage(imageIn);
01064 
01065    if(gRotStyle.fMagnify!=1.) {
01066       item->fColsIn=old_cols_in;
01067       item->fRowsIn=old_rows_in;
01068    }
01069 
01070 
01071 #ifdef CACHE_BITMAPS
01072 
01073    /* create a bitmap to hold rotated text */
01074    item->fBitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
01075                                item->fColsOut, item->fRowsOut, 1);
01076 
01077    /* make the text bitmap from XImage */
01078    XPutImage(dpy, item->fBitmap, font_gc, item->fXimage, 0, 0, 0, 0,
01079              item->fColsOut, item->fRowsOut);
01080 
01081    XDestroyImage(item->fXimage);
01082 
01083 #endif /*CACHE_BITMAPS*/
01084 
01085    XFreeGC(dpy, font_gc);
01086    XFreePixmap(dpy, canvas);
01087 
01088    return item;
01089 }
01090 
01091 
01092 //______________________________________________________________________________
01093 static void XRotAddToLinkedList(Display *dpy, RotatedTextItem_t *item)
01094 {
01095    // Adds a text item to the end of the cache, removing as many items
01096    //     from the front as required to keep cache size below limit
01097 
01098    static long int current_size=0;
01099    static RotatedTextItem_t *last=0;
01100    RotatedTextItem_t *i1=gFirstTextItem, *i2;
01101 
01102 #ifdef CACHE_BITMAPS
01103 
01104    /* I don't know how much memory a pixmap takes in the server -
01105           probably this + a bit more we can't account for */
01106 
01107    item->fSize=((item->fColsOut-1)/8+1)*item->fRowsOut;
01108 
01109 #else
01110 
01111    /* this is pretty much the size of a RotatedTextItem_t */
01112 
01113    item->fSize=((item->fColsOut-1)/8+1)*item->fRowsOut +
01114       sizeof(XImage) + strlen(item->text) +
01115          item->fNl*8*sizeof(float) + sizeof(RotatedTextItem_t);
01116 
01117    if(item->font_name!=0)
01118       item->fSize+=strlen(item->font_name);
01119    else
01120       item->fSize+=sizeof(Font);
01121 
01122 #endif /*CACHE_BITMAPS */
01123 
01124 #ifdef DEBUG
01125    /* count number of items in cache, for debugging */
01126    {
01127       int i=0;
01128 
01129       while(i1) {
01130          i++;
01131          i1=i1->fNext;
01132       }
01133       DEBUG_PRINT2("Cache has %d items.\n", i);
01134       i1=gFirstTextItem;
01135    }
01136 #endif
01137 
01138    DEBUG_PRINT4("current cache size=%ld, new item=%ld, limit=%d\n",
01139                  current_size, item->fSize, CACHE_SIZE_LIMIT*1024);
01140 
01141    /* if this item is bigger than whole cache, forget it */
01142    if(item->fSize>CACHE_SIZE_LIMIT*1024) {
01143       DEBUG_PRINT1("Too big to cache\n\n");
01144       item->fCached=0;
01145       return;
01146    }
01147 
01148    /* remove elements from cache as needed */
01149    while(i1 && current_size+item->fSize>CACHE_SIZE_LIMIT*1024) {
01150 
01151       DEBUG_PRINT2("Removed %ld bytes\n", i1->fSize);
01152 
01153       if(i1->font_name!=0)
01154          DEBUG_PRINT5("  (`%s'\n   %s\n   angle=%f align=%d)\n",
01155                       i1->fText, i1->font_name, i1->fAngle, i1->fAlign);
01156 
01157 #ifdef CACHE_FID
01158       if(i1->font_name==0)
01159          DEBUG_PRINT5("  (`%s'\n  FID=%ld\n   angle=%f align=%d)\n",
01160                       i1->fText, i1->fid, i1->angle, i1->align);
01161 #endif /*CACHE_FID*/
01162 
01163       current_size-=i1->fSize;
01164 
01165       i2=i1->fNext;
01166 
01167       /* free resources used by the unlucky item */
01168       XRotFreeTextItem(dpy, i1);
01169 
01170       /* remove it from linked list */
01171       gFirstTextItem=i2;
01172       i1=i2;
01173    }
01174 
01175    /* add new item to end of linked list */
01176    if(gFirstTextItem==0) {
01177       item->fNext=0;
01178       gFirstTextItem=item;
01179       last=item;
01180    }
01181    else {
01182       item->fNext=0;
01183       last->fNext=item;
01184       last=item;
01185    }
01186 
01187    /* new cache size */
01188    current_size+=item->fSize;
01189 
01190    item->fCached=1;
01191 
01192    DEBUG_PRINT1("Added item to cache.\n");
01193 }
01194 
01195 
01196 //______________________________________________________________________________
01197 static void XRotFreeTextItem(Display *dpy, RotatedTextItem_t *item)
01198 {
01199    //  Free the resources used by a text item
01200 
01201    free(item->fText);
01202 
01203    if(item->font_name!=0)
01204       free(item->font_name);
01205 
01206    free((char *)item->fCornersX);
01207    free((char *)item->fCornersY);
01208 
01209 #ifdef CACHE_BITMAPS
01210    XFreePixmap(dpy, item->fBitmap);
01211 #else
01212    XDestroyImage(item->fXimage);
01213 #endif /* CACHE_BITMAPS */
01214 
01215    free((char *)item);
01216 }
01217 
01218 
01219 //______________________________________________________________________________
01220 static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage)
01221 {
01222    // Magnify an XImage using bilinear interpolation
01223 
01224    int i, j;
01225    float x, y;
01226    float u,t;
01227    XImage *imageOut;
01228    int cols_in, rows_in;
01229    int cols_out, rows_out;
01230    register int i2, j2;
01231    float z1, z2, z3, z4;
01232    int byte_width_in, byte_width_out;
01233    float mag_inv;
01234 
01235    /* size of input image */
01236    cols_in=ximage->width;
01237    rows_in=ximage->height;
01238 
01239    /* size of final image */
01240    cols_out=int((float)cols_in*gRotStyle.fMagnify);
01241    rows_out=int((float)rows_in*gRotStyle.fMagnify);
01242 
01243    /* this will hold final image */
01244    imageOut=MakeXImage(dpy, cols_out, rows_out);
01245    if(imageOut==0)
01246       return 0;
01247 
01248    /* width in bytes of input, output images */
01249    byte_width_in=(cols_in-1)/8+1;
01250    byte_width_out=(cols_out-1)/8+1;
01251 
01252    /* for speed */
01253    mag_inv=1./gRotStyle.fMagnify;
01254 
01255    y=0.;
01256 
01257    /* loop over magnified image */
01258    for(j2=0; j2<rows_out; j2++) {
01259       x=0;
01260       j=int(y);
01261 
01262       for(i2=0; i2<cols_out; i2++) {
01263          i=int(x);
01264 
01265          /* bilinear interpolation - where are we on bitmap ? */
01266          /* right edge */
01267          if(i==cols_in-1 && j!=rows_in-1) {
01268             t=0;
01269             u=y-(float)j;
01270 
01271             z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
01272             z2=z1;
01273             z3=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
01274             z4=z3;
01275          }
01276          /* top edge */
01277          else if(i!=cols_in-1 && j==rows_in-1) {
01278             t=x-(float)i;
01279             u=0;
01280 
01281             z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
01282             z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0;
01283             z3=z2;
01284             z4=z1;
01285          }
01286          /* top right corner */
01287          else if(i==cols_in-1 && j==rows_in-1) {
01288             u=0;
01289             t=0;
01290 
01291             z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
01292             z2=z1;
01293             z3=z1;
01294             z4=z1;
01295          }
01296          /* somewhere `safe' */
01297          else {
01298             t=x-(float)i;
01299             u=y-(float)j;
01300 
01301             z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
01302             z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0;
01303             z3=(ximage->data[(j+1)*byte_width_in+(i+1)/8] &
01304                 128>>((i+1)%8))>0;
01305             z4=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
01306          }
01307 
01308          /* if interpolated value is greater than 0.5, set bit */
01309          if(((1-t)*(1-u)*z1 + t*(1-u)*z2 + t*u*z3 + (1-t)*u*z4)>0.5)
01310             imageOut->data[j2*byte_width_out+i2/8]|=128>>i2%8;
01311 
01312          x+=mag_inv;
01313       }
01314       y+=mag_inv;
01315    }
01316 
01317    /* destroy original */
01318    XDestroyImage(ximage);
01319 
01320    /* return big image */
01321    return imageOut;
01322 }
01323 
01324 
01325 //______________________________________________________________________________
01326 XPoint *XRotTextExtents(Display *, XFontStruct *font, float angle, int x, int y, char *text,int align)
01327 {
01328    // Calculate the bounding box some text will have when painted
01329 
01330    register int i;
01331    char *str1, *str2, *str3;
01332    const char *str2_a="\0", *str2_b="\n\0";
01333    int height;
01334    float sin_angle, cos_angle;
01335    int nl, max_width;
01336    int cols_in, rows_in;
01337    float hot_x, hot_y;
01338    XPoint *xp_in, *xp_out;
01339    int dir, asc, desc;
01340    XCharStruct overall;
01341 
01342    /* manipulate angle to 0<=angle<360 degrees */
01343    while(angle<0) angle+=360;
01344 
01345    while(angle>360) angle-=360;
01346 
01347    angle*=M_PI/180;
01348 
01349    /* count number of sections in string */
01350    nl=1;
01351    if(align!=NONE)
01352       for(i=0; i<(int)strlen(text)-1; i++)
01353          if(text[i]=='\n')
01354             nl++;
01355 
01356    /* ignore newline characters if not doing alignment */
01357    if(align==NONE)
01358       str2=(char *)str2_a;
01359    else
01360       str2=(char *)str2_b;
01361 
01362    /* find width of longest section */
01363    str1=my_strdup(text);
01364    if(str1==0) return 0;
01365 
01366    str3=my_strtok(str1, str2);
01367 
01368    if(str3==0) {
01369       XTextExtents(font, str1, strlen(str1), &dir, &asc, &desc,
01370                    &overall);
01371    } else {
01372       XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
01373                    &overall);
01374    }
01375 
01376    max_width=overall.rbearing;
01377 
01378    /* loop through each section */
01379    do {
01380       str3=my_strtok((char *)0, str2);
01381 
01382       if(str3!=0) {
01383          XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
01384                       &overall);
01385 
01386          if(overall.rbearing>max_width)
01387             max_width=overall.rbearing;
01388       }
01389    }
01390    while(str3!=0);
01391 
01392    free(str1);
01393 
01394    /* overall font height */
01395    height=font->ascent+font->descent;
01396 
01397    /* dimensions horizontal text will have */
01398    cols_in=max_width;
01399    rows_in=nl*height;
01400 
01401    /* pre-calculate sin and cos */
01402    sin_angle=TMath::Sin(angle);
01403    cos_angle=TMath::Cos(angle);
01404 
01405    /* y position */
01406    if(align==TLEFT || align==TCENTRE || align==TRIGHT)
01407       hot_y=(float)rows_in/2*gRotStyle.fMagnify;
01408    else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
01409       hot_y=0;
01410    else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
01411       hot_y=-(float)rows_in/2*gRotStyle.fMagnify;
01412    else
01413       hot_y=-((float)rows_in/2-(float)font->descent)*gRotStyle.fMagnify;
01414 
01415    /* x position */
01416    if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
01417       hot_x=-(float)max_width/2*gRotStyle.fMagnify;
01418    else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
01419       hot_x=0;
01420    else
01421       hot_x=(float)max_width/2*gRotStyle.fMagnify;
01422 
01423    /* reserve space for XPoints */
01424    xp_in=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
01425    if(!xp_in) return 0;
01426 
01427    xp_out=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
01428    if(!xp_out) {
01429       free(xp_in);
01430       return 0;
01431    }
01432 
01433    /* bounding box when horizontal, relative to bitmap centre */
01434    xp_in[0].x=(short int)(-(float)cols_in*gRotStyle.fMagnify/2-gRotStyle.fBbxPadl);
01435    xp_in[0].y=(short int)( (float)rows_in*gRotStyle.fMagnify/2+gRotStyle.fBbxPadl);
01436    xp_in[1].x=(short int)( (float)cols_in*gRotStyle.fMagnify/2+gRotStyle.fBbxPadl);
01437    xp_in[1].y=(short int)( (float)rows_in*gRotStyle.fMagnify/2+gRotStyle.fBbxPadl);
01438    xp_in[2].x=(short int)( (float)cols_in*gRotStyle.fMagnify/2+gRotStyle.fBbxPadl);
01439    xp_in[2].y=(short int)(-(float)rows_in*gRotStyle.fMagnify/2-gRotStyle.fBbxPadl);
01440    xp_in[3].x=(short int)(-(float)cols_in*gRotStyle.fMagnify/2-gRotStyle.fBbxPadl);
01441    xp_in[3].y=(short int)(-(float)rows_in*gRotStyle.fMagnify/2-gRotStyle.fBbxPadl);
01442    xp_in[4].x=xp_in[0].x;
01443    xp_in[4].y=xp_in[0].y;
01444 
01445    /* rotate and translate bounding box */
01446    for(i=0; i<5; i++) {
01447       xp_out[i].x=(short int)((float)x + ( ((float)xp_in[i].x-hot_x)*cos_angle +
01448                                            ((float)xp_in[i].y+hot_y)*sin_angle));
01449       xp_out[i].y=(short int)((float)y + (-((float)xp_in[i].x-hot_x)*sin_angle +
01450                                           ((float)xp_in[i].y+hot_y)*cos_angle));
01451    }
01452 
01453    free((char *)xp_in);
01454 
01455    return xp_out;
01456 }

Generated on Tue Jul 5 14:14:46 2011 for ROOT_528-00b_version by  doxygen 1.5.1