~ubuntu-branches/ubuntu/gutsy/plotutils/gutsy

« back to all changes in this revision

Viewing changes to libplot/x_afftext.c

  • Committer: Bazaar Package Importer
  • Author(s): Floris Bruynooghe
  • Date: 2007-05-10 19:48:54 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070510194854-mrr3lgwzpxd8hovo
Tags: 2.5-2
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the GNU plotutils package.  Copyright (C) 1995,
 
2
   1996, 1997, 1998, 1999, 2000, 2005, Free Software Foundation, Inc.
 
3
 
 
4
   The GNU plotutils package is free software.  You may redistribute it
 
5
   and/or modify it under the terms of the GNU General Public License as
 
6
   published by the Free Software foundation; either version 2, or (at your
 
7
   option) any later version.
 
8
 
 
9
   The GNU plotutils package is distributed in the hope that it will be
 
10
   useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
   General Public License for more details.
 
13
 
 
14
   You should have received a copy of the GNU General Public License along
 
15
   with the GNU plotutils package; see the file COPYING.  If not, write to
 
16
   the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
 
17
   Boston, MA 02110-1301, USA. */
 
18
 
 
19
/* This is the XAffText module, which was originally independent of
 
20
   libplot.  The header file that accompanies it is x_afftext.h.
 
21
 
 
22
   To use the module independently of libplot, simply do not specify
 
23
   "-DLIBPLOT" at compile time.
 
24
 
 
25
   The module supplies two external functions, which are generalizations of
 
26
   the core X11 function XDrawString: XAffDrawRotString and
 
27
   XAffDrawAffString.  They draw, respectively, a rotated text string and
 
28
   (more generally) a matrix-transformed text string.  In both cases a
 
29
   specified core X font is used.  The rotation angle and transformation
 
30
   matrix are specified by the user.  The matrix is passed as a 4-element
 
31
   array, with the element ordering convention and sign convention being
 
32
   those of the Matrix Extension to the XLFD (X Logical Font Description).
 
33
 
 
34
   `XAffText' is an abbreviation of `X11 affinely transformed text'.  The
 
35
   module was inspired by Alan Richardson's xvertext module for displaying
 
36
   rotated text strings in X11, using the core X fonts.  It works in a
 
37
   similar way.  (It retrieves a bitmap from the X server into an XImage,
 
38
   transforms the XImage, monochrome pixel by pixel, and sends it back to a
 
39
   bitmap on the server, for use as a stipple.)  But it supports arbitrary
 
40
   transformation matrices, and pays extra attention to pixel-level
 
41
   accuracy.  It uses integer arithmetic when possible. */
 
42
 
 
43
#include "x_afftext.h"
 
44
#ifdef DEBUG
 
45
#ifdef __cplusplus
 
46
#include <cstdio>
 
47
#else  /* not __cplusplus */
 
48
#include <stdio.h>
 
49
#endif /* not __cplusplus */
 
50
#endif /* DEBUG */
 
51
 
 
52
#ifdef LIBPLOT
 
53
#include "sys-defines.h"        /* plotutils-specific */
 
54
#include "extern.h"             /* libplot-specific */
 
55
#else  /* not LIBPLOT */
 
56
#include <stdlib.h>
 
57
#include <string.h>
 
58
#include <limits.h>
 
59
#include <math.h>
 
60
#ifndef M_PI
 
61
#define M_PI        3.14159265358979323846264
 
62
#endif
 
63
#define IMAX(a,b) ((a) > (b) ? (a) : (b))
 
64
#define IMIN(a,b) ((a) < (b) ? (a) : (b))
 
65
#define IROUND(x) ((int) ((x) > 0 ? (x) + 0.5 : (x) - 0.5))
 
66
#define _pl_xmalloc malloc
 
67
#define _pl_xcalloc calloc
 
68
#endif /* not LIBPLOT */
 
69
 
 
70
#define XAFF_XPROD(v,a) ((v).x * (a)[0] + (v).y * (a)[2])
 
71
#define XAFF_YPROD(v,a) ((v).x * (a)[1] + (v).y * (a)[3])
 
72
 
 
73
typedef struct XAffVectorStruct
 
74
{
 
75
  int x, y;
 
76
} XAffVector;
 
77
 
 
78
typedef struct XAffRealVectorStruct
 
79
{
 
80
  double x, y;
 
81
} XAffRealVector;
 
82
 
 
83
typedef struct XAffSizeStruct
 
84
{
 
85
  unsigned int x, y;
 
86
} XAffSize;
 
87
 
 
88
typedef struct XAffAffinedTextStruct
 
89
{
 
90
  Pixmap bitmap;                /* depth-1 Pixmap, i.e., bitmap */
 
91
  XAffSize size;                /* bitmap size */
 
92
  XAffVector origin;            /* location of text origin within bitmap */
 
93
} XAffAffinedText;
 
94
 
 
95
/* forward decls of internal ctors/dtors */
 
96
 
 
97
static XImage * XAffCreateXImage (Display *dpy, XAffSize size);
 
98
static void XAffFreeXImage (XImage *im);
 
99
 
 
100
static XAffAffinedText *XAffCreateAffinedText (Display *dpy, XFontStruct *font, double a[4], const char *text);
 
101
static void XAffFreeAffinedText (Display *dpy, XAffAffinedText *afftext);
 
102
 
 
103
/* other internal functions */
 
104
 
 
105
static int can_use_XDrawString (XFontStruct *font, double a[4], const char *text);
 
106
#ifdef DEBUG
 
107
static void print_image (const XImage *im_in, XAffSize size);
 
108
#endif /* DEBUG */
 
109
 
 
110
/**************************************************************************/
 
111
/*  Create/destroy a depth-1 XImage object                                */
 
112
/**************************************************************************/
 
113
 
 
114
static XImage *
 
115
XAffCreateXImage (Display *dpy, XAffSize size)
 
116
{
 
117
  XImage *im;
 
118
  char *data;
 
119
  
 
120
  if (size.x == 0 || size.y == 0)
 
121
    return NULL;
 
122
 
 
123
  data = (char *)_pl_xcalloc(size.y * ((size.x + 7) / 8), 1);
 
124
  if (data == NULL)
 
125
    return NULL;
 
126
  
 
127
  im = XCreateImage (dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 
 
128
                     (unsigned int)1, /* depth = 1 */
 
129
                     XYBitmap, 
 
130
                     0,         /* origin = 0 */
 
131
                     data, 
 
132
                     size.x, size.y, 
 
133
                     8,         /* pad: quantum of each scanline */
 
134
                     0);        /* scanlines contigous in memory */
 
135
  if (im == NULL)
 
136
    return NULL;
 
137
  
 
138
  im->bitmap_bit_order = MSBFirst;
 
139
  im->byte_order = MSBFirst;
 
140
 
 
141
  return im;
 
142
}
 
143
 
 
144
static void 
 
145
XAffFreeXImage (XImage *im)
 
146
{
 
147
  free (im->data);
 
148
  XFree (im);
 
149
}
 
150
 
 
151
/**************************************************************************/
 
152
/*  Create/destroy an affinely transformed text string                    */
 
153
/**************************************************************************/
 
154
 
 
155
static XAffAffinedText *
 
156
XAffCreateAffinedText (Display *dpy, XFontStruct *font, double a[4], const char *text)
 
157
{
 
158
  XAffAffinedText *afftext = NULL;
 
159
  GC gc;
 
160
  XCharStruct bounds;
 
161
  int direction, font_ascent, font_descent;
 
162
  XAffSize size_in, size_out;
 
163
  XAffRealVector corner_in[4];
 
164
  XAffVector origin_in, origin_out;
 
165
  XAffVector mincorner, maxcorner;
 
166
  Pixmap bitmap_in, bitmap_out;
 
167
  XImage *im_in, *im_out;
 
168
  int scanline_len_in, scanline_len_out;
 
169
  double aa[4], a_inverse[4], det;
 
170
  int i, j;
 
171
 
 
172
  /* allocate memory for new instance */
 
173
  afftext = (XAffAffinedText *)_pl_xmalloc(sizeof(XAffAffinedText));
 
174
  if (!afftext)
 
175
    return NULL;
 
176
        
 
177
  /* as passed, a[] is in the format used in the matrix LFD enhancement,
 
178
     which assumes a right-handed coordinate system; so convert it to X11's
 
179
     left-hand coordinate system (y grows downward) */
 
180
  aa[0] = a[0];
 
181
  aa[1] = -a[1];
 
182
  aa[2] = -a[2];
 
183
  aa[3] = a[3];
 
184
 
 
185
  /* invert transformation matrix */
 
186
  det = aa[0] * aa[3] - aa[1] * aa[2];
 
187
  if (det == 0.0)
 
188
    return NULL;                /* don't support singular matrices */
 
189
  a_inverse[0] =   aa[3] / det;
 
190
  a_inverse[1] = - aa[1] / det;
 
191
  a_inverse[2] = - aa[2] / det;
 
192
  a_inverse[3] =   aa[0] / det;
 
193
 
 
194
  /* to include all pixels in text, how large should bitmap be? */
 
195
  XTextExtents (font, text, strlen (text), 
 
196
                &direction, &font_ascent, &font_descent, &bounds);
 
197
 
 
198
  /* bitmap size, number-of-pixels by number-of-pixels */
 
199
  size_in.x = - bounds.lbearing + bounds.rbearing;
 
200
  size_in.y = bounds.ascent + bounds.descent;
 
201
 
 
202
  /* within this bitmap, where is `origin' of text string? */
 
203
  origin_in.x = - bounds.lbearing;
 
204
  origin_in.y = bounds.ascent;
 
205
  
 
206
  /* paranoia */
 
207
  if (size_in.x == 0 || size_in.y == 0)
 
208
    return NULL;
 
209
 
 
210
  /* work around a possible bug: some X displays can't create pixmaps that
 
211
     are only one pixel wide or high */
 
212
  if (size_in.x == 1)
 
213
    size_in.x = 2;
 
214
  if (size_in.y == 1)
 
215
    size_in.y = 2;
 
216
 
 
217
#ifdef DEBUG
 
218
  fprintf (stderr, "string \"%s\": lbearing=%hd, rbearing=%hd, ascent=%hd, descent=%hd\n", text, bounds.lbearing, bounds.rbearing, bounds.ascent, bounds.descent);
 
219
  fprintf (stderr, "\tsize=(%u,%u), origin=(%d,%d)\n", size_in.x, size_in.y, origin_in.x, origin_in.y);
 
220
#endif
 
221
 
 
222
  /* create bitmap for text, and lightweight gc */
 
223
  bitmap_in = XCreatePixmap (dpy, DefaultRootWindow (dpy), 
 
224
                             size_in.x, size_in.y, (unsigned int)1);
 
225
  gc = XCreateGC (dpy, bitmap_in, (unsigned long)0, (XGCValues *)NULL);
 
226
  XSetBackground (dpy, gc, (unsigned long)0);
 
227
  XSetFont (dpy, gc, font->fid);
 
228
 
 
229
  /* clear the bitmap */
 
230
  XSetForeground (dpy, gc, (unsigned long)0);
 
231
  XFillRectangle (dpy, bitmap_in, gc, 0, 0, size_in.x, size_in.y);
 
232
  XSetForeground (dpy, gc, (unsigned long)1);
 
233
    
 
234
  /* draw text onto bitmap */
 
235
  XDrawString (dpy, bitmap_in, gc, origin_in.x, origin_in.y, 
 
236
               text, strlen (text));
 
237
 
 
238
  /* create local image */
 
239
  im_in = XAffCreateXImage (dpy, size_in);
 
240
  if (im_in == NULL)
 
241
    return NULL;
 
242
 
 
243
  /* copy bitmap to it */
 
244
  XGetSubImage (dpy, bitmap_in, 0, 0, size_in.x, size_in.y,
 
245
                (unsigned long)1, XYPixmap, im_in, 0, 0);
 
246
  im_in->format = XYBitmap;
 
247
 
 
248
#ifdef DEBUG
 
249
  print_image (im_in, size_in);
 
250
#endif /* DEBUG */
 
251
 
 
252
  /* free now-unneeded bitmap */
 
253
  XFreePixmap (dpy, bitmap_in);
 
254
 
 
255
  /* vertices of image, in real coordinates, if each pixel is taken to be a
 
256
     unit square */
 
257
  corner_in[0].x = -0.5;
 
258
  corner_in[0].y = -0.5;
 
259
  corner_in[1].x = (int)size_in.x - 0.5;
 
260
  corner_in[1].y = -0.5;
 
261
  corner_in[2].x = (int)size_in.x - 0.5;
 
262
  corner_in[2].y = (int)size_in.y - 0.5;
 
263
  corner_in[3].x = -0.5;
 
264
  corner_in[3].y = (int)size_in.y - 0.5;
 
265
 
 
266
  /* compute vertices (in integer coordinates) of a rectangular array of
 
267
     pixels that will snugly hold the affinely transformed image */
 
268
 
 
269
  mincorner.x = mincorner.y = INT_MAX;
 
270
  maxcorner.x = maxcorner.y = INT_MIN;
 
271
  for (i = 0; i < 4; i++)
 
272
    {
 
273
      XAffRealVector v_shifted_in;
 
274
      XAffVector corner_out[4];
 
275
      
 
276
      v_shifted_in.x = corner_in[i].x - origin_in.x;
 
277
      v_shifted_in.y = corner_in[i].y - origin_in.y;
 
278
 
 
279
      corner_out[i].x = IROUND(XAFF_XPROD(v_shifted_in, aa)) + origin_in.x;
 
280
      corner_out[i].y = IROUND(XAFF_YPROD(v_shifted_in, aa)) + origin_in.y;
 
281
 
 
282
      mincorner.x = IMIN(mincorner.x, corner_out[i].x);
 
283
      mincorner.y = IMIN(mincorner.y, corner_out[i].y);
 
284
 
 
285
      maxcorner.x = IMAX(maxcorner.x, corner_out[i].x);
 
286
      maxcorner.y = IMAX(maxcorner.y, corner_out[i].y);
 
287
    }
 
288
  size_out.x = maxcorner.x - mincorner.x + 1;
 
289
  size_out.y = maxcorner.y - mincorner.y + 1;
 
290
  
 
291
  origin_out.x = origin_in.x - mincorner.x;
 
292
  origin_out.y = origin_in.y - mincorner.y;
 
293
 
 
294
  /* work around a possible bug: some X displays can't create pixmaps that
 
295
     are only one pixel wide or high */
 
296
  if (size_out.x == 1)
 
297
    size_out.x = 2;
 
298
  if (size_out.y == 1)
 
299
    size_out.y = 2;
 
300
 
 
301
#ifdef DEBUG
 
302
  fprintf (stderr, "size_in = (%u,%u)\n", size_in.x, size_in.y);
 
303
  fprintf (stderr, "size_out = (%u,%u)\n", size_out.x, size_out.y);
 
304
  fprintf (stderr, "origin_in = (%d,%d)\n", origin_in.x, origin_in.y);
 
305
  fprintf (stderr, "origin_out = (%d,%d)\n", origin_out.x, origin_out.y);
 
306
#endif
 
307
 
 
308
  /* create 2nd image, to hold affinely transformed text */
 
309
  im_out = XAffCreateXImage (dpy, size_out);
 
310
  if (im_out == NULL)
 
311
    return NULL;
 
312
    
 
313
  /* copy from 1st image to this new one */
 
314
 
 
315
  scanline_len_in = (size_in.x + 7) / 8;
 
316
  scanline_len_out = (size_out.x + 7) / 8;
 
317
 
 
318
  for (j = 0; j < (int)size_out.y; j++)
 
319
    {
 
320
      int scanline_hit;
 
321
      XAffVector v_in, v_out, v_shifted_out;
 
322
 
 
323
      scanline_hit = 0;
 
324
 
 
325
      v_out.y = j;
 
326
      v_shifted_out.y = v_out.y + mincorner.y - origin_in.y;
 
327
 
 
328
      for (i = 0; i < (int)size_out.x; i++)
 
329
        {
 
330
          v_out.x = i;
 
331
          v_shifted_out.x = v_out.x + mincorner.x - origin_in.x;
 
332
 
 
333
          v_in.x = IROUND(XAFF_XPROD(v_shifted_out, a_inverse)) + origin_in.x;
 
334
          v_in.y = IROUND(XAFF_YPROD(v_shifted_out, a_inverse)) + origin_in.y;
 
335
 
 
336
          if ((!(v_in.x >= 0)) || (!(v_in.x < (int)size_in.x)) ||
 
337
              (!(v_in.y >= 0)) || (!(v_in.y < (int)size_in.y)))
 
338
            {
 
339
              if (scanline_hit)
 
340
                /* will be no more hits; so move to next scanline */
 
341
                break;
 
342
              else             /* move to next position on this scanline */
 
343
                continue;
 
344
            }
 
345
          else
 
346
            scanline_hit = 1;
 
347
          
 
348
          if (im_in->data[v_in.y * scanline_len_in + v_in.x / 8] 
 
349
              & (128 >> (v_in.x % 8)))
 
350
            {
 
351
              im_out->data[v_out.y * scanline_len_out + v_out.x / 8] 
 
352
                |= (128 >> (v_out.x % 8));
 
353
            }
 
354
        }
 
355
    }
 
356
 
 
357
  /* free now-unneeded 1st image */
 
358
  XAffFreeXImage (im_in);
 
359
 
 
360
  /* create bitmap to hold transformed text */
 
361
  bitmap_out = XCreatePixmap (dpy, DefaultRootWindow (dpy),
 
362
                              size_out.x, size_out.y, (unsigned int)1);
 
363
  
 
364
  /* copy transformed text from 2nd image */
 
365
  XPutImage (dpy, bitmap_out, gc, im_out, 
 
366
             0, 0, 0, 0, size_out.x, size_out.y);
 
367
 
 
368
#ifdef DEBUG
 
369
  print_image (im_out, size_out);
 
370
#endif
 
371
 
 
372
  /* free 2nd image and GC */
 
373
  XAffFreeXImage (im_out);
 
374
  XFreeGC (dpy, gc);
 
375
 
 
376
  /* fill in data members of instance */
 
377
  afftext->bitmap = bitmap_out;
 
378
  afftext->size = size_out;
 
379
  afftext->origin = origin_out;
 
380
 
 
381
  return afftext;
 
382
}
 
383
 
 
384
static void 
 
385
XAffFreeAffinedText (Display *dpy, XAffAffinedText *afftext)
 
386
{
 
387
  XFreePixmap (dpy, afftext->bitmap);
 
388
  free (afftext);
 
389
}
 
390
 
 
391
/**************************************************************************/
 
392
/*  Draw an affinely transformed text string                              */
 
393
/**************************************************************************/
 
394
 
 
395
int 
 
396
XAffDrawAffString (Display *dpy, Drawable drawable, GC gc, XFontStruct *font, int x, int y, double a[4], const char *text)
 
397
{
 
398
  XAffAffinedText *afftext;
 
399
  GC our_gc;
 
400
    
 
401
  if (text == NULL || strlen (text) == 0)
 
402
    return 0;
 
403
    
 
404
  if (can_use_XDrawString (font, a, text))
 
405
    /* a[] must be equal to, or near the identity matrix */
 
406
    return XDrawString (dpy, drawable, gc, x, y, text, strlen (text));
 
407
 
 
408
  /* construct annotated bitmap, containing affinely transformed text */
 
409
  afftext = XAffCreateAffinedText (dpy, font, a, text);
 
410
  if (afftext == NULL)
 
411
    return 0;
 
412
    
 
413
  /* copy gc from user's gc */
 
414
  our_gc = XCreateGC (dpy, drawable, (unsigned long)0, (XGCValues *)NULL);
 
415
  XCopyGC (dpy, gc, GCForeground|GCFunction|GCPlaneMask, our_gc);
 
416
 
 
417
  /* use stipple drawing technique (screen-door patterning) */
 
418
  XSetFillStyle (dpy, our_gc, FillStippled);
 
419
  XSetStipple (dpy, our_gc, afftext->bitmap);
 
420
  XSetTSOrigin (dpy, our_gc, 
 
421
                x - afftext->origin.x, y - afftext->origin.y);
 
422
  XFillRectangle (dpy, drawable, our_gc, 
 
423
                  x - afftext->origin.x, y - afftext->origin.y, 
 
424
                  afftext->size.x, afftext->size.y);
 
425
    
 
426
  /* free resources */
 
427
  XFreeGC (dpy, our_gc);
 
428
  XAffFreeAffinedText (dpy, afftext);
 
429
 
 
430
  return 0;
 
431
}
 
432
 
 
433
/**************************************************************************/
 
434
/*  Special case: draw a rotated text string                              */
 
435
/**************************************************************************/
 
436
 
 
437
int 
 
438
XAffDrawRotString (Display *dpy, Drawable drawable, GC gc, XFontStruct *font, int x, int y, double angle, const char *text)
 
439
{
 
440
  double a[4];
 
441
  
 
442
  /* convert rotation angle to radians */
 
443
  angle *= (M_PI / 180.0);
 
444
 
 
445
  /* construct transformation matrix (using the XLFD-matrix-extension sign
 
446
     convention for the off-diagonal elements) */
 
447
  a[0] = + cos (angle);
 
448
  a[1] = + sin (angle);
 
449
  a[2] = - sin (angle);
 
450
  a[3] = + cos (angle);
 
451
 
 
452
  return XAffDrawAffString (dpy, drawable, gc, font, x, y, a, text);
 
453
}
 
454
 
 
455
/**************************************************************************/
 
456
/* Can simply use core XDrawString function rather than transforming the  */
 
457
/* resulting bitmap?  (Yes, if the matrix a[] is near the identity.)      */
 
458
/**************************************************************************/
 
459
 
 
460
static int
 
461
can_use_XDrawString (XFontStruct *font, double a[4], const char *text)
 
462
{
 
463
  int direction, font_ascent, font_descent;
 
464
  XCharStruct bounds;
 
465
  XAffVector corner_in[4], corner_out[4];
 
466
  XAffSize size_in;
 
467
  XAffVector origin_in;
 
468
  int i, can_do_it = 1;
 
469
  double aa[4];
 
470
 
 
471
  /* as passed, a[] is in the format used in the matrix LFD enhancement,
 
472
     which assumes a right-handed coordinate system; so convert it to X11's
 
473
     left-hand coordinate system (y grows downward) */
 
474
  aa[0] = a[0];
 
475
  aa[1] = -a[1];
 
476
  aa[2] = -a[2];
 
477
  aa[3] = a[3];
 
478
 
 
479
  /* to include all pixels in text, how large should bitmap be? */
 
480
  XTextExtents (font, text, strlen (text), 
 
481
                &direction, &font_ascent, &font_descent, &bounds);
 
482
 
 
483
  /* bitmap size, number-of-pixels by number-of-pixels */
 
484
  size_in.x = - bounds.lbearing + bounds.rbearing;
 
485
  size_in.y = bounds.ascent + bounds.descent;
 
486
 
 
487
  /* within this bitmap, where is `origin' of text string? */
 
488
  origin_in.x = - bounds.lbearing;
 
489
  origin_in.y = bounds.ascent;
 
490
  
 
491
  /* corners in integer coordinates, relative to origin */
 
492
  corner_in[0].x = 0;
 
493
  corner_in[0].y = 0;
 
494
  corner_in[1].x = size_in.x - 1;
 
495
  corner_in[1].y = 0;
 
496
  corner_in[2].x = size_in.x - 1;
 
497
  corner_in[2].y = size_in.y - 1;
 
498
  corner_in[3].x = 0;
 
499
  corner_in[3].y = size_in.y - 1;
 
500
 
 
501
  /* compute how corners are transformed by a[] */
 
502
  for (i = 0; i < 4; i++)
 
503
    {
 
504
      XAffVector v_shifted_in;
 
505
      
 
506
      v_shifted_in.x = corner_in[i].x - origin_in.x;
 
507
      v_shifted_in.y = corner_in[i].y - origin_in.y;
 
508
 
 
509
      corner_out[i].x = IROUND(XAFF_XPROD(v_shifted_in, aa)) + origin_in.x;
 
510
      corner_out[i].y = IROUND(XAFF_YPROD(v_shifted_in, aa)) + origin_in.y;
 
511
 
 
512
      if (corner_out[i].x != corner_in[i].x
 
513
          || corner_out[i].y != corner_in[i].y)
 
514
        /* at least one corner moves, no good, alas */
 
515
        {
 
516
          can_do_it = 0;
 
517
          break;
 
518
        }
 
519
    }
 
520
 
 
521
  return can_do_it;
 
522
}
 
523
 
 
524
/**************************************************************************/
 
525
/*  Print an image to stderr (used for debugging, if -DDEBUG is specified)*/
 
526
/**************************************************************************/
 
527
 
 
528
#ifdef DEBUG
 
529
static void 
 
530
print_image (const XImage *im, XAffSize size)
 
531
{
 
532
  int scanline_len;
 
533
  int i, j;
 
534
  
 
535
  scanline_len = (size.x + 7) / 8;
 
536
 
 
537
  for (j = 0; j < (int)size.y; j++)
 
538
    {
 
539
      for (i = 0; i < (int)size.x; i++)
 
540
        {
 
541
          if (im->data[j * scanline_len + i / 8] & (128 >> (i % 8)))
 
542
            fprintf (stderr, "*");
 
543
          else
 
544
            fprintf (stderr, " ");
 
545
        }
 
546
      fprintf (stderr, "\n");
 
547
    }
 
548
}
 
549
#endif /* DEBUG */
 
550