00001
00002
00003
00004 #ifndef _XVERTEXT_INCLUDED_
00005 #define _XVERTEXT_INCLUDED_
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00038
00039
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
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
00068
00069
00070
00071
00072
00073 #ifndef CACHE_SIZE_LIMIT
00074 #define CACHE_SIZE_LIMIT 0
00075 #endif
00076
00077
00078
00079 #ifndef CACHE_XIMAGES
00080 #ifndef CACHE_BITMAPS
00081 #define CACHE_BITMAPS
00082 #endif
00083 #endif
00084
00085
00086
00087
00088
00089 #ifdef DEBUG
00090 static int gRotatedDebug=1;
00091 #else
00092 static int gRotatedDebug=0;
00093 #endif
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
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
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
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
00194
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
00204 if(str1!=0) {
00205 start=0;
00206 stext=str1;
00207 len=strlen(str1);
00208 }
00209
00210
00211 if(start>=len) return 0;
00212
00213
00214 for(i=start; i<len; i++) {
00215
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
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
00248
00249 if(m>0.) gRotStyle.fMagnify=m;
00250 }
00251
00252
00253
00254 void XRotSetBoundingBoxPad(int p)
00255 {
00256
00257
00258 if(p>=0) gRotStyle.fBbxPadl=p;
00259 }
00260
00261
00262
00263 static XImage *MakeXImage(Display *dpy,int w, int h)
00264 {
00265
00266
00267 XImage *image;
00268 char *data;
00269
00270
00271 data=(char *)calloc((unsigned)(((w-1)/8+1)*h), 1);
00272 if(data==0) return 0;
00273
00274
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
00288
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
00299
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
00310
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
00322
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
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
00345 if(text==0) return 0;
00346
00347 if(strlen(text)==0) return 0;
00348
00349
00350 while(angle<0) angle+=360;
00351
00352 while(angle>=360) angle-=360;
00353
00354 angle*=M_PI/180;
00355
00356
00357 if(angle==0. && gRotStyle.fMagnify==1.)
00358 return(XRotDrawHorizontalString(dpy, font, drawable, gc, x, y,
00359 text, align, bg));
00360
00361
00362 item=XRotRetrieveFromCache(dpy, font, angle, text, align);
00363 if(item==0) return 0;
00364
00365
00366 my_gc=XCreateGC(dpy, drawable, 0, 0);
00367 XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCPlaneMask,
00368 my_gc);
00369
00370
00371
00372
00373
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
00379 hot_y=0;
00380
00381 }
00382 else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
00383 {
00384
00385
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
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
00400 sin_angle=TMath::Sin(angle);
00401 cos_angle=TMath::Cos(angle);
00402
00403
00404 hot_xp= hot_x*cos_angle - hot_y*sin_angle;
00405 hot_yp= hot_x*sin_angle + hot_y*cos_angle;
00406
00407
00408 if(bg) {
00409 GC depth_one_gc;
00410 XPoint *xpoints;
00411 Pixmap empty_stipple;
00412
00413
00414 xpoints=(XPoint *)malloc((unsigned)(4*item->fNl*sizeof(XPoint)));
00415 if(!xpoints) return 1;
00416
00417
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
00426
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
00441 free((char *)xpoints);
00442 XFreeGC(dpy, depth_one_gc);
00443 XFreePixmap(dpy, empty_stipple);
00444 }
00445
00446
00447 xp=int((float)x-((float)item->fColsOut/2 +hot_xp));
00448 yp=int((float)y-((float)item->fRowsOut/2 -hot_yp));
00449
00450
00451 bitmap_to_paint=item->fBitmap;
00452
00453
00454 #ifndef X11R3
00455 {
00456 GC depth_one_gc;
00457 XGCValues values;
00458 Pixmap new_bitmap, inverse;
00459
00460
00461 if(XGetGCValues(dpy, gc,
00462 GCStipple|GCFillStyle|GCForeground|GCBackground|
00463 GCTileStipXOrigin|GCTileStipYOrigin,
00464 &values)) {
00465
00466
00467 if((values.fill_style==FillStippled ||
00468 values.fill_style==FillOpaqueStippled) && !bg) {
00469
00470
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
00482 new_bitmap=XCreatePixmap(dpy, drawable,
00483 item->fColsOut, item->fRowsOut, 1);
00484
00485
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
00491 XSetTSOrigin(dpy, depth_one_gc,
00492 values.ts_x_origin-xp, values.ts_y_origin-yp);
00493
00494
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
00501 XSetTSOrigin(dpy, depth_one_gc, 0, 0);
00502
00503
00504 inverse=XCreatePixmap(dpy, drawable,
00505 item->fColsOut, item->fRowsOut, 1);
00506
00507
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
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
00523 XFreePixmap(dpy, inverse);
00524 XFreeGC(dpy, depth_one_gc);
00525
00526
00527 bitmap_to_paint=new_bitmap;
00528 }
00529 }
00530 }
00531 #endif
00532
00533
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
00541 XFreeGC(dpy, my_gc);
00542
00543
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
00550
00551
00552 if(!item->fCached)
00553 XRotFreeTextItem(dpy,item);
00554
00555
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
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
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
00585 if(align!=NONE)
00586 for(i=0; i<(int)strlen(text)-1; i++)
00587 if(text[i]=='\n')
00588 nl++;
00589
00590
00591 if(align==NONE)
00592 str2=(char *)str2_a;
00593 else
00594 str2=(char *)str2_b;
00595
00596
00597 height=font->ascent+font->descent;
00598
00599
00600 if(align==TLEFT || align==TCENTRE || align==TRIGHT)
00601 yp=y+font->ascent;
00602 else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
00603 {
00604
00605
00606 yp=y-nl*(height-font->descent)/2+font->ascent;
00607 }
00608 else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
00609 {
00610
00611
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
00623 do {
00624 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
00625 &overall);
00626
00627
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
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
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
00659
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
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
00675 else {
00676 DEBUG_PRINT1("can't get fontname, caching FID\n");
00677 font_name=0;
00678 fid=font->fid;
00679 }
00680 #else
00681
00682 else {
00683 DEBUG_PRINT1("can't get fontname, can't cache\n");
00684 font_name=0;
00685 fid=0;
00686 }
00687 #endif
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698 while(i1 && !item) {
00699
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
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
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
00739 if(!item) {
00740
00741 item=XRotCreateTextItem(dpy, font, angle, text, align);
00742 if(!item)
00743 return 0;
00744
00745
00746 item->fText=my_strdup(text);
00747
00748
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
00763 XRotAddToLinkedList(dpy, item);
00764 }
00765
00766 if(font_name)
00767 XFree(font_name);
00768
00769
00770
00771 #ifdef CACHE_XIMAGES
00772 {
00773 GC depth_one_gc;
00774
00775
00776 item->fBitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
00777 item->fColsOut, item->fRowsOut, 1);
00778
00779
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
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
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
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
00822 item=(RotatedTextItem_t *)malloc((unsigned)sizeof(RotatedTextItem_t));
00823 if(!item) return 0;
00824
00825
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
00833 if(align==NONE)
00834 str2=(char *)str2_a;
00835 else
00836 str2=(char *)str2_b;
00837
00838
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
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
00868 height=font->ascent+font->descent;
00869
00870
00871 item->fColsIn=item->fMaxWidth;
00872 item->fRowsIn=item->fNl*height;
00873
00874
00875 canvas=XCreatePixmap(dpy, DefaultRootWindow(dpy),
00876 item->fColsIn, item->fRowsIn, 1);
00877
00878
00879 font_gc=XCreateGC(dpy, canvas, 0, 0);
00880 XSetBackground(dpy, font_gc, 0);
00881 XSetFont(dpy, font_gc, font->fid);
00882
00883
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
00890 sin_angle=TMath::Sin(angle);
00891 cos_angle=TMath::Cos(angle);
00892
00893
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
00909
00910
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
00922 do {
00923 XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
00924 &overall);
00925
00926
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
00935 XDrawString(dpy, canvas, font_gc, xp, yp, str3, strlen(str3));
00936
00937
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
00953 yp+=height;
00954
00955 str3=my_strtok((char *)0, str2);
00956 }
00957 while(str3!=0);
00958
00959 free(str1);
00960
00961
00962 imageIn=MakeXImage(dpy, item->fColsIn, item->fRowsIn);
00963 if(imageIn==0) {
00964 free(item);
00965 return 0;
00966 }
00967
00968
00969 XGetSubImage(dpy, canvas, 0, 0, item->fColsIn, item->fRowsIn,
00970 1, XYPixmap, imageIn, 0, 0);
00971 imageIn->format=XYBitmap;
00972
00973
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
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
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
01005
01006
01007
01008 dj=0.5-(float)item->fRowsOut/2;
01009
01010
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
01038 for(j=0; j<item->fRowsOut; j++) {
01039
01040
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
01045 for(i=((xl<0)?0:(int)xl);
01046 i<((xr>=item->fColsOut)?item->fColsOut:(int)xr); i++) {
01047
01048
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
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
01074 item->fBitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
01075 item->fColsOut, item->fRowsOut, 1);
01076
01077
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
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
01096
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
01105
01106
01107 item->fSize=((item->fColsOut-1)/8+1)*item->fRowsOut;
01108
01109 #else
01110
01111
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
01123
01124 #ifdef DEBUG
01125
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
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
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
01162
01163 current_size-=i1->fSize;
01164
01165 i2=i1->fNext;
01166
01167
01168 XRotFreeTextItem(dpy, i1);
01169
01170
01171 gFirstTextItem=i2;
01172 i1=i2;
01173 }
01174
01175
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
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
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
01214
01215 free((char *)item);
01216 }
01217
01218
01219
01220 static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage)
01221 {
01222
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
01236 cols_in=ximage->width;
01237 rows_in=ximage->height;
01238
01239
01240 cols_out=int((float)cols_in*gRotStyle.fMagnify);
01241 rows_out=int((float)rows_in*gRotStyle.fMagnify);
01242
01243
01244 imageOut=MakeXImage(dpy, cols_out, rows_out);
01245 if(imageOut==0)
01246 return 0;
01247
01248
01249 byte_width_in=(cols_in-1)/8+1;
01250 byte_width_out=(cols_out-1)/8+1;
01251
01252
01253 mag_inv=1./gRotStyle.fMagnify;
01254
01255 y=0.;
01256
01257
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
01266
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
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
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
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
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
01318 XDestroyImage(ximage);
01319
01320
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
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
01343 while(angle<0) angle+=360;
01344
01345 while(angle>360) angle-=360;
01346
01347 angle*=M_PI/180;
01348
01349
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
01357 if(align==NONE)
01358 str2=(char *)str2_a;
01359 else
01360 str2=(char *)str2_b;
01361
01362
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
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
01395 height=font->ascent+font->descent;
01396
01397
01398 cols_in=max_width;
01399 rows_in=nl*height;
01400
01401
01402 sin_angle=TMath::Sin(angle);
01403 cos_angle=TMath::Cos(angle);
01404
01405
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
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
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
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
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 }