home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume21 / xfig / patch02k / xfig.10
Encoding:
Text File  |  1993-10-21  |  28.4 KB  |  1,001 lines

  1. !  else
  2. !   for(i=0; i<len; i++) {
  3. !    ichar=str[i]-32;
  4. !   
  5. !    /* make sure it's a printing character ... */
  6. !    if((ichar>=0)&&(ichar<95)) 
  7. !     width+=rotfont->per_char[ichar].width;
  8. !   }
  9.   
  10. !  return width;
  11.   }
  12.   
  13. - /* *** Return the height of a string *** */
  14.   
  15. ! int XRotTextHeight(rotfont, str, len)
  16. !  XRotFontStruct *rotfont;
  17. !  char *str;
  18. !  int len;
  19.   {
  20. !  int i, height=0, ichar;
  21. !  int maxasc=0;
  22. !  int maxdsc=0;
  23. !  int dum;
  24. !  XCharStruct ch;
  25.   
  26. !  if(str==NULL) return 0;
  27.   
  28. !  if(rotfont->dir==0) {
  29. !     XTextExtents(rotfont->xfontstruct, str, len, &dum,&dum,&dum,&ch);
  30. !     height = ch.ascent + ch.descent;
  31. !  }
  32. !  else
  33. !   for(i=0; i<len; i++)
  34. !   {
  35. !    ichar=str[i]-32;
  36. !   
  37. !    /* make sure it's a printing character ... */
  38. !    /* then find the highest and most descending */
  39. !    if((ichar>=0)&&(ichar<95)) {
  40. !     maxasc=max2(maxasc,rotfont->per_char[ichar].ascent);
  41. !     maxdsc=max2(maxdsc,rotfont->per_char[ichar].descent);
  42. !    }
  43. !    /* and add the two together */
  44. !    height = maxasc+maxdsc;
  45. !   }
  46.   
  47. !  return height;
  48. ! }
  49.   
  50.   
  51. ! /* ---------------------------------------------------------------------- */
  52.   
  53.   
  54. ! /* *** A front end to XRotPaintString : mimics XDrawString *** */
  55.   
  56. ! void XRotDrawString(dpy,  drawable, rotfont,gc, x, y, str, len)
  57. !  Display *dpy;
  58. !  Drawable drawable;
  59. !  XRotFontStruct *rotfont;
  60. !  GC gc;
  61. !  int x, y;
  62. !  char *str;
  63. !  int len;
  64. ! {
  65. !  XRotPaintString(dpy, drawable, rotfont, gc, x, y, str, len, 0);
  66.   }
  67.   
  68.   
  69.   /* ---------------------------------------------------------------------- */
  70. -  
  71.   
  72. - /* *** A front end to XRotPaintString : mimics XDrawImageString *** */
  73.   
  74. ! void XRotDrawImageString(dpy,  drawable, rotfont, gc, x, y, str, len)
  75. !  Display *dpy;
  76. !  Drawable drawable;
  77. !  XRotFontStruct *rotfont;
  78. !  GC gc;
  79. !  int x, y;
  80. !  char *str;
  81. !  int len;
  82.   {
  83. !  XRotPaintString(dpy, drawable, rotfont, gc, x, y, str, len, 1);
  84.   }
  85.   
  86.   
  87.   /* ---------------------------------------------------------------------- */
  88. -               
  89. -               
  90. - /* *** Paint a simple string with a rotated font *** */
  91.   
  92. - /* *** The user should use one of the two front ends above *** */
  93.   
  94. ! void XRotPaintString(dpy,  drawable, rotfont, gc, x, y, str, len, paintbg)
  95. !  Display *dpy;
  96. !  Drawable drawable;
  97. !  XRotFontStruct *rotfont;
  98. !  GC gc;
  99. !  int x, y;
  100. !  char *str;
  101. !  int len;
  102. !  int paintbg;
  103. ! {            
  104. !  static GC my_gc=NULL;
  105. !  XGCValues values;
  106. !  int i, xp, yp, dir, ichar, width;
  107. ! #ifdef X11R3
  108. !  static Pixmap empty_stipple=(Pixmap)NULL;
  109. ! #endif
  110.   
  111. !  dir=rotfont->dir;
  112.   
  113. !  if(!my_gc) my_gc=XCreateGC(dpy, drawable, NULL, 0);
  114.   
  115. !  XCopyGC(dpy, gc, GCFunction|GCForeground|GCBackground, my_gc);
  116.   
  117. !  /* a horizontal string is easy ... */
  118. !  if(dir==0)
  119. !   { XSetFillStyle(dpy, my_gc, FillSolid);
  120. !     XSetFont(dpy, my_gc, rotfont->xfontstruct->fid);
  121. !     if(!paintbg) XDrawString(dpy, drawable, my_gc, x, y, str, len);
  122. !     else         XDrawImageString(dpy, drawable, my_gc, x, y, str, len);
  123.   
  124. !     return;
  125. !   }
  126.   
  127. !  /* vertical or upside down ... */
  128.   
  129. !  /* to draw an `image string' we need to fill the background ... */
  130. !  if(paintbg)
  131. !   {
  132. ! #ifdef X11R3
  133. !    /* Release 3 doesn't have XGetGCValues(), so this is a
  134. !       slightly slower fudge ... */
  135. !    {
  136. !     GC stipple_gc;
  137. !     int bestw, besth;
  138.   
  139. !     if(!empty_stipple)    
  140. !      { XQueryBestStipple(dpy, drawable, 1, 1, &bestw, &besth);
  141. !        empty_stipple=XCreatePixmap(dpy, drawable, bestw, besth, 1);
  142.   
  143. !        stipple_gc=XCreateGC(dpy, empty_stipple, NULL, 0);
  144. !        XSetForeground(dpy, stipple_gc, 0);
  145.   
  146. !        XFillRectangle(dpy, empty_stipple, stipple_gc, 0, 0, bestw+1, besth+1);
  147. !        XFreeGC(dpy, stipple_gc);
  148. !      }
  149.   
  150. !      XSetStipple(dpy, my_gc, empty_stipple);
  151. !      XSetFillStyle(dpy, my_gc, FillOpaqueStippled);
  152. !    }    
  153. ! #else
  154. !    /* get the foreground and background colors
  155. !         ( note that this is not a round trip -> little speed penalty ) */
  156. !    XGetGCValues(dpy, my_gc, GCForeground|GCBackground, &values);
  157.   
  158. !    XSetForeground(dpy, my_gc, values.background);
  159. !    XSetFillStyle(dpy, my_gc, FillSolid);
  160. ! #endif
  161.   
  162. !    width=XRotTextWidth(rotfont, str, strlen(str));
  163.   
  164. !    if(dir==1)
  165. !      XFillRectangle(dpy, drawable, my_gc, x-rotfont->max_ascent+1, y-width,
  166. !                     rotfont->height-1, width);
  167. !    else if(dir==2)
  168. !      XFillRectangle(dpy, drawable, my_gc, x-width, y-rotfont->max_descent+1,
  169. !                     width, rotfont->height-1);
  170. !    else
  171. !      XFillRectangle(dpy, drawable, my_gc, x-rotfont->max_descent+1,
  172. !                     y, rotfont->height-1, width);
  173.   
  174. ! #ifndef X11R3
  175. !    XSetForeground(dpy, my_gc, values.foreground);
  176. ! #endif
  177. !   }
  178.   
  179. !  XSetFillStyle(dpy, my_gc, FillStippled);
  180.   
  181. !  /* loop through each character in string ... */
  182. !  for(i=0; i<len; i++)
  183. !  {
  184. !   ichar=str[i]-32;
  185.   
  186. !   /* make sure it's a printing character ... */
  187. !   if((ichar>=0)&&(ichar<95))
  188. !   {
  189. !    /* suitable offset ... */
  190. !    if(dir==1)
  191. !      { xp=x-rotfont->per_char[ichar].ascent;
  192. !        yp=y-rotfont->per_char[ichar].rbearing; }
  193. !    else if(dir==2)
  194. !      { xp=x-rotfont->per_char[ichar].rbearing;
  195. !        yp=y-rotfont->per_char[ichar].descent+1; }
  196. !    else
  197. !      { xp=x-rotfont->per_char[ichar].descent+1;  
  198. !        yp=y+rotfont->per_char[ichar].lbearing; }
  199. !                    
  200. !    /* draw the glyph ... */
  201. !    XSetStipple(dpy, my_gc, rotfont->per_char[ichar].glyph.bm);
  202.   
  203. !    XSetTSOrigin(dpy, my_gc, xp, yp);
  204. !    
  205. !    XFillRectangle(dpy, drawable, my_gc, xp, yp,
  206. !                   rotfont->per_char[ichar].glyph.bit_w,
  207. !                   rotfont->per_char[ichar].glyph.bit_h);
  208. !     
  209. !    /* advance position ... */
  210. !    if(dir==1)      y-=rotfont->per_char[ichar].width;
  211. !    else if(dir==2) x-=rotfont->per_char[ichar].width;
  212. !    else            y+=rotfont->per_char[ichar].width;
  213. !   }
  214. !  }
  215.   }
  216. !   
  217. !     
  218.   /* ---------------------------------------------------------------------- */
  219.   
  220.   
  221. ! /* *** A front end to XRotPaintAlignedString : uses XRotDrawString *** */
  222.   
  223. ! void XRotDrawAlignedString(dpy, drawable, rotfont, gc, x, y,
  224. !                                   text, align)
  225. !  Display *dpy;                    
  226. !  Drawable drawable;
  227. !  XRotFontStruct *rotfont;
  228. !  GC gc;
  229. !  int x, y;
  230. !  char *text;
  231. !  int align;
  232.   {
  233. !  XRotPaintAlignedString(dpy, drawable, rotfont, gc, x, y, text, align, 0);
  234.   }
  235.   
  236.   
  237. --- 383,1310 ----
  238.   /* ---------------------------------------------------------------------- */
  239.   
  240.   
  241. ! /**************************************************************************/
  242. ! /*  Aligns and paints a rotated string                                    */
  243. ! /**************************************************************************/
  244.   
  245. ! static int XRotPaintAlignedString(dpy, font, angle, drawable, gc, x, y, text,
  246. !                   align, bg)
  247. !     Display *dpy;
  248. !     XFontStruct *font;
  249. !     float angle;
  250. !     Drawable drawable;
  251. !     GC gc;
  252. !     int x, y;
  253. !     char *text;
  254. !     int align;
  255. !     int bg;
  256.   {
  257. !     int i;
  258. !     GC my_gc;
  259. !     int xp, yp;
  260. !     float hot_x, hot_y;
  261. !     float hot_xp, hot_yp;
  262. !     float sin_angle, cos_angle;
  263. !     RotatedTextItem *item;
  264. !     Pixmap bitmap_to_paint;
  265. !     
  266. !     /* return early for NULL/empty strings */
  267. !     if(text==NULL || *text=='\0')
  268. !         return 0;
  269. !     
  270. !     /* manipulate angle to 0<=angle<2*PI radians */
  271. !     while(angle<0.0)
  272. !         angle+=M_2PI;
  273. !     
  274. !     while(angle>=M_2PI)
  275. !         angle-=M_2PI;
  276. !     
  277. !     /* horizontal text made easy */
  278. !     if(angle==0. && style.magnify==1.) 
  279. !     return(XRotDrawHorizontalString(dpy, font, drawable, gc, x, y,
  280. !                     text, align, bg));
  281. !     
  282. !     /* get a rotated bitmap */
  283. !     item=XRotRetrieveFromCache(dpy, font, angle, text, align);
  284. !     if(item==NULL)
  285. !     return NULL;
  286. !     
  287. !     /* this gc has similar properties to the user's gc */
  288. !     my_gc=XCreateGC(dpy, drawable, (unsigned long) 0, 0);
  289. !     XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCPlaneMask,
  290. !         my_gc);
  291.   
  292. !     /* alignment : which point (hot_x, hot_y) relative to bitmap centre
  293. !        coincides with user's specified point? */
  294. !     
  295. !     /* y position */
  296. !     if(align==TLEFT || align==TCENTRE || align==TRIGHT)
  297. !         hot_y=(float)item->rows_in/2*style.magnify;
  298. !     else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
  299. !     hot_y=0;
  300. !     else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
  301. !     hot_y= -(float)item->rows_in/2*style.magnify;
  302. !     else
  303. !     hot_y= -((float)item->rows_in/2-(float)font->descent)*style.magnify;
  304. !     
  305. !     /* x position */
  306. !     if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
  307. !     hot_x= -(float)item->max_width/2*style.magnify;
  308. !     else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
  309. !     hot_x=0;
  310. !     else
  311. !         hot_x=(float)item->max_width/2*style.magnify;
  312. !     
  313. !     /* pre-calculate sin and cos */
  314. !     sin_angle=sin(angle);
  315. !     cos_angle=cos(angle);
  316. !     
  317. !     /* rotate hot_x and hot_y around bitmap centre */
  318. !     hot_xp= hot_x*cos_angle - hot_y*sin_angle;
  319. !     hot_yp= hot_x*sin_angle + hot_y*cos_angle;
  320. !     
  321. !     /* text background will be drawn using XFillPolygon */
  322. !     if(bg) {
  323. !     GC depth_one_gc;
  324. !     XPoint *xpoints;
  325. !     Pixmap empty_stipple;
  326. !     
  327. !     /* reserve space for XPoints */
  328. !     xpoints=(XPoint *)malloc((unsigned)(4*item->nl*sizeof(XPoint)));
  329. !     if(!xpoints)
  330. !         return 1;
  331. !     
  332. !     /* rotate corner positions */
  333. !     for(i=0; i<4*item->nl; i++) {
  334. !         xpoints[i].x=(float)x + ( (item->corners_x[i]-hot_x)*cos_angle + 
  335. !                       (item->corners_y[i]+hot_y)*sin_angle);
  336. !         xpoints[i].y=(float)y + (-(item->corners_x[i]-hot_x)*sin_angle + 
  337. !                       (item->corners_y[i]+hot_y)*cos_angle);
  338. !     }
  339. !     
  340. !     /* we want to swap foreground and background colors here;
  341. !        XGetGCValues() is only available in R4+ */
  342. !     
  343. !     empty_stipple=XCreatePixmap(dpy, drawable, 1, 1, 1);
  344. !     
  345. !     depth_one_gc=XCreateGC(dpy, empty_stipple, (unsigned long) 0, 0);
  346. !     XSetForeground(dpy, depth_one_gc, 0);
  347. !     XFillRectangle(dpy, empty_stipple, depth_one_gc, 0, 0, 2, 2);
  348.   
  349. !     XSetStipple(dpy, my_gc, empty_stipple);
  350. !     XSetFillStyle(dpy, my_gc, FillOpaqueStippled);
  351. !     
  352. !     XFillPolygon(dpy, drawable, my_gc, xpoints, 4*item->nl, Nonconvex,
  353. !              CoordModeOrigin);
  354. !     
  355. !     /* free our resources */
  356. !     free((char *)xpoints);
  357. !     XFreeGC(dpy, depth_one_gc);
  358. !     XFreePixmap(dpy, empty_stipple);
  359. !     }
  360. !     
  361. !     /* where should top left corner of bitmap go ? */
  362. !     xp=(float)x-((float)item->cols_out/2 +hot_xp);
  363. !     yp=(float)y-((float)item->rows_out/2 -hot_yp);
  364. !     
  365. !     /* by default we draw the rotated bitmap, solid */
  366. !     bitmap_to_paint=item->bitmap;
  367.   
  368. !     /* handle user stippling */
  369. ! #ifndef X11R3
  370. !     {
  371. !     GC depth_one_gc;
  372. !     XGCValues values;
  373. !     Pixmap new_bitmap, inverse;
  374. !     
  375. !     /* try and get some GC properties */
  376. !     if(XGetGCValues(dpy, gc, 
  377. !             GCStipple|GCFillStyle|GCForeground|GCBackground|
  378. !             GCTileStipXOrigin|GCTileStipYOrigin,
  379. !             &values)) {
  380. !         /* only do this if stippling requested */
  381. !         if((values.fill_style==FillStippled ||
  382. !         values.fill_style==FillOpaqueStippled) && !bg) {
  383. !         /* opaque stipple: draw rotated text in background colour */
  384. !         if(values.fill_style==FillOpaqueStippled) {
  385. !             XSetForeground(dpy, my_gc, values.background);
  386. !             XSetFillStyle(dpy, my_gc, FillStippled);
  387. !             XSetStipple(dpy, my_gc, item->bitmap);
  388. !             XSetTSOrigin(dpy, my_gc, xp, yp);
  389. !             XFillRectangle(dpy, drawable, my_gc, xp, yp,
  390. !                    item->cols_out, item->rows_out);
  391. !             XSetForeground(dpy, my_gc, values.foreground);
  392. !         }
  393. !         /* this will merge the rotated text and the user's stipple */
  394. !         new_bitmap=XCreatePixmap(dpy, drawable,
  395. !                      item->cols_out, item->rows_out, 1);
  396. !         /* create a GC */
  397. !         depth_one_gc=XCreateGC(dpy, new_bitmap, (unsigned long) 0, 0);
  398. !         XSetForeground(dpy, depth_one_gc, 1);
  399. !         XSetBackground(dpy, depth_one_gc, 0);
  400. !         /* set the relative stipple origin */
  401. !         XSetTSOrigin(dpy, depth_one_gc, 
  402. !                  values.ts_x_origin-xp, values.ts_y_origin-yp);
  403. !         /* fill the whole bitmap with the user's stipple */
  404. !         XSetStipple(dpy, depth_one_gc, values.stipple);
  405. !         XSetFillStyle(dpy, depth_one_gc, FillOpaqueStippled);
  406. !         XFillRectangle(dpy, new_bitmap, depth_one_gc,
  407. !                    0, 0, item->cols_out, item->rows_out);
  408. !         /* set stipple origin back to normal */
  409. !         XSetTSOrigin(dpy, depth_one_gc, 0, 0);
  410. !         /* this will contain an inverse copy of the rotated text */
  411. !         inverse=XCreatePixmap(dpy, drawable,
  412. !                       item->cols_out, item->rows_out, 1);
  413. !         /* invert text */
  414. !         XSetFillStyle(dpy, depth_one_gc, FillSolid);
  415. !         XSetFunction(dpy, depth_one_gc, GXcopyInverted);
  416. !         XCopyArea(dpy, item->bitmap, inverse, depth_one_gc,
  417. !               0, 0, item->cols_out, item->rows_out, 0, 0);
  418. !         /* now delete user's stipple everywhere EXCEPT on text */
  419. !                 XSetForeground(dpy, depth_one_gc, 0);
  420. !                 XSetBackground(dpy, depth_one_gc, 1);
  421. !         XSetStipple(dpy, depth_one_gc, inverse);
  422. !         XSetFillStyle(dpy, depth_one_gc, FillStippled);
  423. !         XSetFunction(dpy, depth_one_gc, GXcopy);
  424. !         XFillRectangle(dpy, new_bitmap, depth_one_gc,
  425. !                                0, 0, item->cols_out, item->rows_out);
  426. !         /* free resources */
  427. !         XFreePixmap(dpy, inverse);
  428. !         XFreeGC(dpy, depth_one_gc);
  429. !         /* this is the new bitmap */
  430. !         bitmap_to_paint=new_bitmap;
  431. !         }
  432. !     }
  433. !     }
  434. ! #endif /*X11R3*/
  435. !     /* paint text using stipple technique */
  436. !     XSetFillStyle(dpy, my_gc, FillStippled);
  437. !     XSetStipple(dpy, my_gc, bitmap_to_paint);
  438. !     XSetTSOrigin(dpy, my_gc, xp, yp);
  439. !     XFillRectangle(dpy, drawable, my_gc, xp, yp, 
  440. !            item->cols_out, item->rows_out);
  441. !     
  442. !     /* free our resources */
  443. !     XFreeGC(dpy, my_gc);
  444. !     /* stippled bitmap no longer needed */
  445. !     if(bitmap_to_paint!=item->bitmap)
  446. !     XFreePixmap(dpy, bitmap_to_paint);
  447. ! #ifdef CACHE_XIMAGES
  448. !     XFreePixmap(dpy, item->bitmap);
  449. ! #endif /*CACHE_XIMAGES*/
  450. !     /* if item isn't cached, destroy it completely */
  451. !     if(!item->cached) 
  452. !     XRotFreeTextItem(dpy,item);
  453. !     /* we got to the end OK! */
  454. !     return 0;
  455.   }
  456.   
  457.   
  458.   /* ---------------------------------------------------------------------- */
  459.   
  460.   
  461. ! /**************************************************************************/
  462. ! /*  Draw a horizontal string in a quick fashion                           */
  463. ! /**************************************************************************/
  464. ! static int XRotDrawHorizontalString(dpy, font, drawable, gc, x, y, text, 
  465. !                      align, bg)
  466. !     Display *dpy;
  467. !     XFontStruct *font;
  468. !     Drawable drawable;
  469. !     GC gc;
  470. !     int x, y;
  471. !     char *text;
  472. !     int align;
  473. !     int bg;
  474.   {
  475. !     GC my_gc;
  476. !     int nl=1, i;
  477. !     int height;
  478. !     int xp, yp;
  479. !     char *str1, *str2, *str3;
  480. !     char *str2_a="\0", *str2_b="\n\0";
  481. !     int dir, asc, desc;
  482. !     XCharStruct overall;
  483.   
  484. !     DEBUG_PRINT1("**Horizontal text.\n");
  485. !     if (text == NULL || *text=='\0') {
  486. !     DEBUG_PRINT1("Empty string, ignoring\n");
  487.       return 0;
  488. +     }
  489.   
  490. !     /* this gc has similar properties to the user's gc (including stipple) */
  491. !     my_gc=XCreateGC(dpy, drawable, (unsigned long) 0, 0);
  492. !     XCopyGC(dpy, gc,
  493. !         GCForeground|GCBackground|GCFunction|GCStipple|GCFillStyle|
  494. !         GCTileStipXOrigin|GCTileStipYOrigin|GCPlaneMask, my_gc);
  495. !     XSetFont(dpy, my_gc, font->fid);
  496. !     
  497. !     /* count number of sections in string */
  498. !     if(align!=NONE)
  499. !     for(i=0; i<strlen(text)-1; i++)
  500. !         if(text[i]=='\n')
  501. !         nl++;
  502. !     
  503. !     /* ignore newline characters if not doing alignment */
  504. !     if(align==NONE)
  505. !     str2=str2_a;
  506. !     else
  507. !     str2=str2_b;
  508. !     
  509. !     /* overall font height */
  510. !     height=font->ascent+font->descent;
  511. !     
  512. !     /* y position */
  513. !     if(align==TLEFT || align==TCENTRE || align==TRIGHT)
  514. !     yp=y+font->ascent;
  515. !     else if(align==MLEFT || align==MCENTRE || align==MRIGHT)
  516. !     yp=y-nl*height/2+font->ascent;
  517. !     else if(align==BLEFT || align==BCENTRE || align==BRIGHT)
  518. !     yp=y-nl*height+font->ascent;
  519. !     else
  520. !     yp=y;
  521. !     
  522. !     str1=my_strdup(text);
  523. !     if(str1==NULL)
  524. !     return 1;
  525. !     
  526. !     str3=my_strtok(str1, str2);
  527. !     
  528. !     /* loop through each section in the string */
  529. !     do {
  530. !         XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
  531. !                      &overall);
  532.   
  533. !     /* where to draw section in x ? */
  534. !     if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
  535. !         xp=x;
  536. !     else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
  537. !         xp=x-overall.rbearing/2;
  538. !     else
  539. !         xp=x-overall.rbearing;
  540. !     
  541. !     /* draw string onto bitmap */
  542. !     if(!bg)
  543. !         XDrawString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
  544. !     else
  545. !         XDrawImageString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
  546. !     
  547. !     /* move to next line */
  548. !     yp+=height;
  549. !     
  550. !     str3=my_strtok((char *)NULL, str2);
  551. !     }
  552. !     while(str3!=NULL);
  553. !     
  554. !     free(str1);
  555. !     XFreeGC(dpy, my_gc);
  556.   
  557. !     return 0;
  558.   }
  559.   
  560.   
  561. ! /* ---------------------------------------------------------------------- */
  562. ! /**************************************************************************/
  563. ! /*   Query cache for a match with this font/text/angle/alignment          */
  564. ! /*       request, otherwise arrange for its creation                      */
  565. ! /**************************************************************************/
  566. ! static RotatedTextItem *XRotRetrieveFromCache(dpy, font, angle, text, align)
  567. !     Display *dpy;
  568. !     XFontStruct *font;
  569. !     float angle;
  570. !     char *text;
  571. !     int align;
  572.   {
  573. !     Font fid;
  574. !     char *font_name=NULL;
  575. !     unsigned long name_value;
  576. !     RotatedTextItem *item=NULL;
  577. !     RotatedTextItem *i1=first_text_item;
  578. !     
  579. !     /* get font name, if it exists */
  580. !     if(XGetFontProperty(font, XA_FONT, &name_value)) {
  581. !     DEBUG_PRINT1("got font name OK\n");
  582. !     font_name=XGetAtomName(dpy, name_value);
  583. !     fid=0;
  584. !     }
  585. ! #ifdef CACHE_FID
  586. !     /* otherwise rely (unreliably?) on font ID */
  587. !     else {
  588. !     DEBUG_PRINT1("can't get fontname, caching FID\n");
  589. !     font_name=NULL;
  590. !     fid=font->fid;
  591. !     }
  592. ! #else
  593. !     /* not allowed to cache font ID's */
  594. !     else {
  595. !     DEBUG_PRINT1("can't get fontname, can't cache\n");
  596. !     font_name=NULL;
  597. !     fid=0;
  598. !     }
  599. ! #endif /*CACHE_FID*/
  600. !     
  601. !     /* look for a match in cache */
  602.   
  603. !     /* matching formula:
  604. !        identical text;
  605. !        identical fontname (if defined, font ID's if not);
  606. !        angles close enough (<0.00001 here, could be smaller);
  607. !        HORIZONTAL alignment matches, OR it's a one line string;
  608. !        magnifications the same */
  609.   
  610. !     while(i1 && !item) {
  611. !     /* match everything EXCEPT fontname/ID */
  612. !     if(strcmp(text, i1->text)==0 &&
  613. !        fabs(angle-i1->angle)<0.00001 &&
  614. !        style.magnify==i1->magnify &&
  615. !        (i1->nl==1 ||
  616. !         ((align==0)?9:(align-1))%3==
  617. !           ((i1->align==0)?9:(i1->align-1))%3)) {
  618.   
  619. !         /* now match fontname/ID */
  620. !         if(font_name!=NULL && i1->font_name!=NULL) {
  621. !         if(strcmp(font_name, i1->font_name)==0) {
  622. !             item=i1;
  623. !             DEBUG_PRINT1("Matched against font names\n");
  624. !         }
  625. !         else
  626. !             i1=i1->next;
  627. !         }
  628. ! #ifdef CACHE_FID
  629. !         else if(font_name==NULL && i1->font_name==NULL) {
  630. !         if(fid==i1->fid) {
  631. !             item=i1;
  632. !             DEBUG_PRINT1("Matched against FID's\n");
  633. !                 }
  634. !         else
  635. !                     i1=i1->next;
  636. !         }
  637. ! #endif /*CACHE_FID*/
  638. !         else
  639. !         i1=i1->next;
  640. !     }
  641. !     else
  642. !         i1=i1->next;
  643. !     }
  644. !     
  645. !     if(item)
  646. !     DEBUG_PRINT1("**Found target in cache.\n");
  647. !     if(!item)
  648. !     DEBUG_PRINT1("**No match in cache.\n");
  649.   
  650. +     /* no match */
  651. +     if(!item) {
  652. +     /* create new item */
  653. +     item=XRotCreateTextItem(dpy, font, angle, text, align);
  654. +     if(!item)
  655. +         return NULL;
  656.   
  657. !     /* record what it shows */
  658. !     item->text=my_strdup(text);
  659.   
  660. +     /* fontname or ID */
  661. +     if(font_name!=NULL) {
  662. +         item->font_name=my_strdup(font_name);
  663. +         item->fid=0;
  664. +     }
  665. +     else {
  666. +         item->font_name=NULL;
  667. +         item->fid=fid;
  668. +     }
  669.   
  670. !     item->angle=angle;
  671. !     item->align=align;
  672. !     item->magnify=style.magnify;
  673.   
  674. !     /* cache it */
  675. !     XRotAddToLinkedList(dpy, item);
  676. !     }
  677. !     if(font_name)
  678. !     XFree(font_name);
  679. !     /* if XImage is cached, need to recreate the bitmap */
  680. ! #ifdef CACHE_XIMAGES
  681. !     {
  682. !     GC depth_one_gc;
  683. !     /* create bitmap to hold rotated text */
  684. !     item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
  685. !                    item->cols_out, item->rows_out, 1);
  686. !     
  687. !     /* depth one gc */
  688. !     depth_one_gc=XCreateGC(dpy, item->bitmap, (unsigned long) 0, 0);
  689. !     XSetBackground(dpy, depth_one_gc, 0);
  690. !     XSetForeground(dpy, depth_one_gc, 1);
  691. !     /* make the text bitmap from XImage */
  692. !     XPutImage(dpy, item->bitmap, depth_one_gc, item->ximage, 0, 0, 0, 0,
  693. !           item->cols_out, item->rows_out);
  694. !     XFreeGC(dpy, depth_one_gc);
  695. !     }
  696. ! #endif /*CACHE_XIMAGES*/
  697. !     
  698. !     return item;
  699.   }
  700.   
  701.   
  702.   /* ---------------------------------------------------------------------- */
  703.   
  704.   
  705. ! /**************************************************************************/
  706. ! /*  Create a rotated text item                                            */
  707. ! /**************************************************************************/
  708. ! static RotatedTextItem *XRotCreateTextItem(dpy, font, angle, text, align)
  709. !     Display *dpy;
  710. !     XFontStruct *font;
  711. !     float angle;
  712. !     char *text;
  713. !     int align;
  714.   {
  715. !     RotatedTextItem *item=NULL;
  716. !     Pixmap canvas;
  717. !     GC font_gc;
  718. !     XImage *I_in;
  719. !     register int i, j;
  720. !     char *str1, *str2, *str3;
  721. !     char *str2_a="\0", *str2_b="\n\0";
  722. !     int height;
  723. !     int byte_w_in, byte_w_out;
  724. !     int xp, yp;
  725. !     float sin_angle, cos_angle;
  726. !     int it, jt;
  727. !     float di, dj;
  728. !     int ic=0;
  729. !     float xl, xr, xinc;
  730. !     int byte_out;
  731. !     int dir, asc, desc;
  732. !     XCharStruct overall;
  733. !     int old_cols_in=0, old_rows_in=0;
  734. !     
  735. !     /* allocate memory */
  736. !     item=(RotatedTextItem *)malloc((unsigned)sizeof(RotatedTextItem));
  737. !     if(!item)
  738. !     return NULL;
  739. !     
  740. !     /* count number of sections in string */
  741. !     item->nl=1;
  742. !     if(align!=NONE)
  743. !     for(i=0; i<strlen(text)-1; i++)
  744. !         if(text[i]=='\n')
  745. !         item->nl++;
  746. !     
  747. !     /* ignore newline characters if not doing alignment */
  748. !     if(align==NONE)
  749. !     str2=str2_a;
  750. !     else
  751. !     str2=str2_b;
  752. !     
  753. !     /* find width of longest section */
  754. !     str1=my_strdup(text);
  755. !     if(str1==NULL)
  756. !     return NULL;
  757. !     
  758. !     str3=my_strtok(str1, str2);
  759. !     XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
  760. !          &overall);
  761. !     
  762. !     item->max_width=overall.rbearing;
  763. !     
  764. !     /* loop through each section */
  765. !     do {
  766. !     str3=my_strtok((char *)NULL, str2);
  767. !     if(str3!=NULL) {
  768. !         XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
  769. !              &overall);
  770. !         if(overall.rbearing>item->max_width)
  771. !         item->max_width=overall.rbearing;
  772. !     }
  773. !     }
  774. !     while(str3!=NULL);
  775. !     
  776. !     free(str1);
  777. !     
  778. !     /* overall font height */
  779. !     height=font->ascent+font->descent;
  780. !     
  781. !     /* dimensions horizontal text will have */
  782. !     item->cols_in=item->max_width;
  783. !     item->rows_in=item->nl*height;
  784. !     
  785. !     /* bitmap for drawing on */
  786. !     canvas=XCreatePixmap(dpy, DefaultRootWindow(dpy),
  787. !              item->cols_in, item->rows_in, 1);
  788. !     
  789. !     /* create a GC for the bitmap */
  790. !     font_gc=XCreateGC(dpy, canvas, (unsigned long) 0, 0);
  791. !     XSetBackground(dpy, font_gc, 0);
  792. !     XSetFont(dpy, font_gc, font->fid);
  793. !     
  794. !     /* make sure the bitmap is blank */
  795. !     XSetForeground(dpy, font_gc, 0);
  796. !     XFillRectangle(dpy, canvas, font_gc, 0, 0, 
  797. !            item->cols_in+1, item->rows_in+1);
  798. !     XSetForeground(dpy, font_gc, 1);
  799. !     
  800. !     /* pre-calculate sin and cos */
  801. !     sin_angle=sin(angle);
  802. !     cos_angle=cos(angle);
  803. !     
  804. !     /* text background will be drawn using XFillPolygon */
  805. !     item->corners_x=
  806. !     (float *)malloc((unsigned)(4*item->nl*sizeof(float)));
  807. !     if(!item->corners_x)
  808. !     return NULL;
  809. !     
  810. !     item->corners_y=
  811. !     (float *)malloc((unsigned)(4*item->nl*sizeof(float)));
  812. !     if(!item->corners_y)
  813. !     return NULL;
  814. !     
  815. !     /* draw text horizontally */
  816. !     
  817. !     /* start at top of bitmap */
  818. !     yp=font->ascent;
  819. !     
  820. !     str1=my_strdup(text);
  821. !     if(str1==NULL)
  822. !     return NULL;
  823. !     
  824. !     str3=my_strtok(str1, str2);
  825. !     
  826. !     /* loop through each section in the string */
  827. !     do {
  828. !     XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
  829. !         &overall);
  830. !     /* where to draw section in x ? */
  831. !     if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE)
  832. !         xp=0;
  833. !     else if(align==TCENTRE || align==MCENTRE || align==BCENTRE)
  834. !         xp=(item->max_width-overall.rbearing)/2;
  835. !     else
  836. !             xp=item->max_width-overall.rbearing;
  837. !     /* draw string onto bitmap */
  838. !     XDrawString(dpy, canvas, font_gc, xp, yp, str3, strlen(str3));
  839. !     
  840. !     /* keep a note of corner positions of this string */
  841. !     item->corners_x[ic]=((float)xp-(float)item->cols_in/2)*style.magnify;
  842. !     item->corners_y[ic]=((float)(yp-font->ascent)-(float)item->rows_in/2)
  843. !         *style.magnify;
  844. !     item->corners_x[ic+1]=item->corners_x[ic];
  845. !     item->corners_y[ic+1]=item->corners_y[ic]+(float)height*style.magnify;
  846. !     item->corners_x[item->nl*4-1-ic]=item->corners_x[ic]+
  847. !         (float)overall.rbearing*style.magnify;
  848. !     item->corners_y[item->nl*4-1-ic]=item->corners_y[ic];
  849. !     item->corners_x[item->nl*4-2-ic]=
  850. !         item->corners_x[item->nl*4-1-ic];
  851. !     item->corners_y[item->nl*4-2-ic]=item->corners_y[ic+1];
  852. !     
  853. !     ic+=2;
  854. !     
  855. !     /* move to next line */
  856. !     yp+=height;
  857. !     
  858. !     str3=my_strtok((char *)NULL, str2);
  859. !     }
  860. !     while(str3!=NULL);
  861. !     
  862. !     free(str1);
  863. !     
  864. !     /* create image to hold horizontal text */
  865. !     I_in=MakeXImage(dpy, item->cols_in, item->rows_in);
  866. !     if(I_in==NULL)
  867. !     return NULL;
  868. !     
  869. !     /* extract horizontal text */
  870. !     XGetSubImage(dpy, canvas, 0, 0, item->cols_in, item->rows_in,
  871. !          1, XYPixmap, I_in, 0, 0);
  872. !     I_in->format=XYBitmap;
  873. !     
  874. !     /* magnify horizontal text */
  875. !     if(style.magnify!=1.) {
  876. !     I_in=XRotMagnifyImage(dpy, I_in);
  877. !     old_cols_in=item->cols_in;
  878. !     old_rows_in=item->rows_in;
  879. !     item->cols_in=(float)item->cols_in*style.magnify;
  880. !     item->rows_in=(float)item->rows_in*style.magnify;
  881. !     }
  882. !     /* how big will rotated text be ? */
  883. !     item->cols_out=fabs((float)item->rows_in*sin_angle) +
  884. !     fabs((float)item->cols_in*cos_angle) +0.99999 +2;
  885. !     item->rows_out=fabs((float)item->rows_in*cos_angle) +
  886. !     fabs((float)item->cols_in*sin_angle) +0.99999 +2;
  887. !     if(item->cols_out%2==0)
  888. !     item->cols_out++;
  889. !     
  890. !     if(item->rows_out%2==0)
  891. !     item->rows_out++;
  892. !     
  893. !     /* create image to hold rotated text */
  894. !     item->ximage=MakeXImage(dpy, item->cols_out, item->rows_out);
  895. !     if(item->ximage==NULL)
  896. !     return NULL;
  897. !     
  898. !     byte_w_in=(item->cols_in-1)/8+1;
  899. !     byte_w_out=(item->cols_out-1)/8+1;
  900. !     
  901. !     /* we try to make this bit as fast as possible - which is why it looks
  902. !        a bit over-the-top */
  903. !     
  904. !     /* vertical distance from centre */
  905. !     dj=0.5-(float)item->rows_out/2;
  906. !     /* where abouts does text actually lie in rotated image? */
  907. !     /* check angle within 0.5 degrees (0.008 radians) */
  908. !     if(fabs((double)angle)<0.008 || fabs((double)angle-M_PI/2)<0.008 || 
  909. !        fabs((double)angle-M_PI)<0.008 || fabs((double)angle-3*M_PI/2)<0.008) {
  910. !     xl=0;
  911. !     xr=(float)item->cols_out;
  912. !     xinc=0;
  913. !     }
  914. !     else if(angle<M_PI) {
  915. !     xl=(float)item->cols_out/2+
  916. !         (dj-(float)item->rows_in/(2*cos_angle))/
  917. !         tan(angle)-2;
  918. !     xr=(float)item->cols_out/2+
  919. !         (dj+(float)item->rows_in/(2*cos_angle))/
  920. !         tan(angle)+2;
  921. !     xinc=1./tan(angle);
  922. !     }
  923. !     else {
  924. !     xl=(float)item->cols_out/2+
  925. !         (dj+(float)item->rows_in/(2*cos_angle))/
  926. !         tan(angle)-2;
  927. !     xr=(float)item->cols_out/2+
  928. !         (dj-(float)item->rows_in/(2*cos_angle))/
  929. !         tan(angle)+2;
  930. !     
  931. !     xinc=1./tan(angle);
  932. !     }
  933. !     /* loop through all relevent bits in rotated image */
  934. !     for(j=0; j<item->rows_out; j++) {
  935. !     
  936. !     /* no point re-calculating these every pass */
  937. !     di=(float)((xl<0)?0:(int)xl)+0.5-(float)item->cols_out/2;
  938. !     byte_out=(item->rows_out-j-1)*byte_w_out;
  939. !     
  940. !     /* loop through meaningful columns */
  941. !     for(i=((xl<0)?0:(int)xl); 
  942. !         i<((xr>=item->cols_out)?item->cols_out:(int)xr); i++) {
  943. !         
  944. !         /* rotate coordinates */
  945. !         it=(float)item->cols_in/2 + ( di*cos_angle + dj*sin_angle);
  946. !         jt=(float)item->rows_in/2 - (-di*sin_angle + dj*cos_angle);
  947. !         
  948. !             /* set pixel if required */
  949. !             if(it>=0 && it<item->cols_in && jt>=0 && jt<item->rows_in)
  950. !                 if((I_in->data[jt*byte_w_in+it/8] & 128>>(it%8))>0)
  951. !                     item->ximage->data[byte_out+i/8]|=128>>i%8;
  952. !         
  953. !         di+=1;
  954. !     }
  955. !     dj+=1;
  956. !     xl+=xinc;
  957. !     xr+=xinc;
  958. !     }
  959. !     XDestroyImage(I_in);
  960. !     
  961.