1 /*
2 * Motif
3 *
4 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
5 *
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
16 * details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
22 */
23 #ifdef REV_INFO
24 #ifndef lint
25 static char rcsid[] = "$TOG: ImageCache.c /main/44 1998/10/06 17:26:25 samborn $"
26 #endif
27 #endif
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31
32
33 #include "XmI.h"
34 #include "XmosI.h" /* for mask name API and stuff */
35 #include "BitmapsI.h" /* for built-in images */
36 #include "ColorI.h" /* for _XmSearchColorCache() */
37 #include "HashI.h" /* for hash table routines. */
38 #include "ImageCachI.h" /* for DIRECT_PIXMAP_CACHED */
39 #include "ReadImageI.h" /* for read xbm stuff */
40 #include <Xm/AccColorT.h> /* for new _XmGetColoredPixmap API */
41 #include <Xm/ColorObjP.h> /* for Xme Color Obj access API */
42 #include <Xm/IconFile.h> /* XmGetIconFileName */
43 #ifdef PRINTING_SUPPORTED
44 #include <Xm/PrintSP.h> /* for pixmap resolution */
45 #endif
46 #include <Xm/XpmP.h>
47 #include <X11/Xresource.h>
48 #ifdef JPEG_SUPPORTED
49 #include "JpegI.h"
50 #endif
51 #ifdef PNG_SUPPORTED
52 #include "PngI.h"
53 #endif
54
55 /* additional value for GetImage return, FALSE, TRUE and */
56 #define NOT_CACHED 2
57
58 /* index and max size of the override_colorsarray */
59 #define NUM_SYMBOLIC_COLORS 7
60 #define SYMB_BACKGROUND 0
61 #define SYMB_FOREGROUND 1
62 #define TRANSPARENT_COLOR 2
63 #define SYMB_TOP_SHADOW_COLOR 3
64 #define SYMB_BOTTOM_SHADOW_COLOR 4
65 #define SYMB_SELECT_COLOR 5
66 #define SYMB_HIGHLIGHT_COLOR 6
67
68 /* Image set handling defines, structure, and global statics */
69
70 typedef struct _ImageData
71 {
72 int hot_x, hot_y;
73 XImage *image;
74 char *image_name;
75 unsigned char *builtin_data;
76 } ImageData;
77
78 static XmHashTable image_set = NULL;
79
80
81 /* Pixmap caching structure and global statics */
82
83 typedef struct _PixmapData
84 {
85 Screen * screen;
86 char * image_name;
87 XmAccessColorData acc_color ;
88 Pixmap pixmap;
89 int depth;
90 Dimension width ;
91 Dimension height ;
92 int reference_count;
93 unsigned short print_resolution ;
94 Widget print_shell ;
95 double scaling_ratio ;
96 Pixel * pixels;
97 int npixels;
98 } PixmapData;
99
100 static XmHashTable pixmap_set = NULL;
101 static XmHashTable pixmap_data_set = NULL;
102
103
104 /* Color caching structure and global statics */
105
106 typedef struct _CachedColorStruct {
107 Display *display;
108 Colormap colormap;
109 XrmQuark colorname;
110 unsigned short red, green, blue;
111 Pixel pixel;
112 unsigned int num_cached; /* reference count */
113 } CachedColor;
114
115 typedef struct _CachedColorListStruct {
116 int numEntries;
117 int maxEntries;
118 CachedColor *cache;
119 } CachedColorList;
120
121 static CachedColorList colorCacheList;
122
123
124 /* GC caching structure and global statics */
125
126 typedef struct _GCData
127 {
128 GC gc;
129 Screen *screen;
130 Widget print_shell;
131 int depth;
132 int image_depth;
133 Pixel foreground;
134 Pixel background;
135 } GCData;
136
137 static XmHashTable gc_set = NULL;
138
139
140 typedef struct _CleanKey {
141 Screen * screen ;
142 Widget shell ;
143 } CleanKey ;
144
145 /******** Static Function Declarations ********/
146
147 static Boolean ComparePixmaps (XmHashKey key_1, XmHashKey key_2);
148 static Boolean ComparePixmapDatas (XmHashKey key_1, XmHashKey key_2);
149 static Boolean CompareStrings (XmHashKey key_1, XmHashKey key_2);
150 static Boolean CompareGCDatas (XmHashKey key_1, XmHashKey key_2);
151 static XmHashValue HashPixmap (XmHashKey key);
152 static XmHashValue HashPixmapData (XmHashKey key);
153 static XmHashValue HashString (XmHashKey key);
154 static XmHashValue HashGCData (XmHashKey key);
155 static void InitializeImageSet( void ) ;
156 static void InitializePixmapSets( void ) ;
157 static Boolean UninstallImageMapProc (XmHashKey key, XtPointer value,
158 XtPointer image);
159 static Boolean SymbolicColorUsed(String color_name,
160 XpmColor * xpm_colors,
161 unsigned int ncolors);
162 static void CompleteUnspecColors(
163 Screen *screen,
164 XpmColorSymbol *override_colors);
165 static int GetOverrideColors(
166 Screen *screen,
167 XmAccessColorData acc_color,
168 XpmColorSymbol *override_colors);
169 static XtEnum GetXpmImage(Screen *screen, char *image_name, char *file_name,
170 XmAccessColorData acc_color, XImage **image,
171 unsigned short *pixmap_resolution,
172 Pixel **pixels, int *npixels);
173 static XtEnum GetImage(Screen *screen, char *image_name,
174 XmAccessColorData acc_color, XImage **image,
175 unsigned short * pixmap_resolution,
176 Pixel **pixels, /* allocated pixels */
177 int *npixels);
178 static GC GetGCForPutImage(Screen *screen,
179 Widget print_shell,
180 XImage * image,
181 Pixmap pixmap,
182 int depth,
183 Pixel foreground,
184 Pixel background);
185
186 static int GetCacheColor(Display *display, Colormap colormap,
187 char *colorname, XColor *color, void *data);
188 static int FreeCacheColors(Display *display, Colormap colormap,
189 Pixel *pixels, int npixels, void *data);
190
191 /******** End Static Function Declarations ********/
192
193
194
195
196 /*** IMAGE CACHE PART FIRST ***/
197
198
199
200
201 /* Compare two strings. */
202 static Boolean
CompareStrings(XmHashKey key_1,XmHashKey key_2)203 CompareStrings (XmHashKey key_1,
204 XmHashKey key_2)
205 {
206 char *data_1 = (char *) key_1;
207 char *data_2 = (char *) key_2;
208
209 return ((data_1 == data_2) || (strcmp(data_1, data_2) == 0));
210 }
211
212
213 /* Hash a string. */
214 static XmHashValue
HashString(XmHashKey key)215 HashString (XmHashKey key)
216 {
217 char *data = (char *) key;
218 unsigned int len = strlen(data);
219
220 return (((len << 8) | data[0]) << 8) | data[len];
221 }
222
223 /************************************************************************
224 *
225 * InitializeImageSet
226 * Initialize the image set.
227 *
228 ************************************************************************/
229 static void
InitializeImageSet(void)230 InitializeImageSet( void )
231 {
232 register int i;
233
234 /* Allocate the hash table. */
235 assert (image_set == NULL);
236
237 _XmProcessLock();
238 image_set =
239 _XmAllocHashTable (MAX_BUILTIN_IMAGES + 100, CompareStrings, HashString);
240
241 /* Load the built-in image data.
242 Builtins have a non NULL builtin data.
243 Their image field is setdynamically at GetImage time */
244 for (i = 0; i < MAX_BUILTIN_IMAGES ; i++)
245 {
246 ImageData *entry = XtNew(ImageData);
247
248 entry->hot_x = 0;
249 entry->hot_y = 0;
250 entry->image = NULL;
251 entry->image_name = (char*) bitmap_name_set[i];
252 entry->builtin_data = (unsigned char *) bitmaps[i];
253
254 _XmAddHashEntry(image_set, entry->image_name, entry);
255 }
256 _XmProcessUnlock();
257 }
258
259 /************************************************************************
260 *
261 * _XmInstallImage
262 *
263 * Allow a hot_spot to be specified
264 *
265 ************************************************************************/
266 Boolean
_XmInstallImage(XImage * image,char * image_name,int hot_x,int hot_y)267 _XmInstallImage(
268 XImage *image,
269 char *image_name,
270 int hot_x,
271 int hot_y)
272 {
273 ImageData *entry;
274
275
276 /* Error checking */
277
278 if (image == NULL || image_name == NULL) return (False);
279
280
281 /* Check for the initial allocation of the image set array */
282
283 if (image_set == NULL) InitializeImageSet();
284
285
286 /* Verify that the image_name is not already in the image set. */
287 _XmProcessLock();
288
289 if (_XmGetHashEntry(image_set, image_name) != NULL) {
290 _XmProcessUnlock();
291 return (False);
292 }
293
294
295 /* Initialize the image element for the new image and return True. */
296
297 entry = XtNew(ImageData);
298 entry->hot_x = hot_x;
299 entry->hot_y = hot_y;
300 entry->image = image;
301 entry->image_name = XtNewString(image_name);
302 entry->builtin_data = NULL;
303
304 _XmAddHashEntry(image_set, entry->image_name, entry);
305
306 _XmProcessUnlock();
307 return (True);
308 }
309
310 /************************************************************************
311 *
312 * XmInstallImage
313 * Add the provided image for the image set and return an
314 * id to be used for further referencing.
315 *
316 ************************************************************************/
317 Boolean
XmInstallImage(XImage * image,char * image_name)318 XmInstallImage(
319 XImage *image,
320 char *image_name )
321 {
322 Boolean ret_val;
323
324 _XmProcessLock();
325 ret_val = _XmInstallImage(image, image_name, 0, 0);
326 _XmProcessUnlock();
327
328 return ret_val;
329 }
330 /* A hash table map procedure to uninstall an image. */
331
332 /*ARGSUSED*/
333 static Boolean
UninstallImageMapProc(XmHashKey key,XtPointer value,XtPointer image)334 UninstallImageMapProc (XmHashKey key, /* unused */
335 XtPointer value,
336 XtPointer image)
337 {
338 ImageData *entry = (ImageData *) value;
339
340 if (entry->image == (XImage*) image)
341 {
342 /* Can't free built-in data. */
343 if (entry->builtin_data == NULL)
344 {
345 _XmProcessLock();
346 _XmRemoveHashEntry (image_set, entry->image_name);
347 _XmProcessUnlock();
348 XtFree(entry->image_name);
349 /* uninstall do not free the XImage itself */
350 XtFree((char*) entry);
351 }
352
353 return True;
354 }
355
356 return False;
357 }
358
359 /************************************************************************
360 *
361 * XmUninstallImage
362 * Remove an image from the image set.
363 * Return a boolean (True) if the uninstall succeeded. Return
364 * a boolean (False) if an error condition occurs.
365 *
366 ************************************************************************/
367 Boolean
XmUninstallImage(XImage * image)368 XmUninstallImage(
369 XImage *image )
370 {
371 Cardinal old_count;
372 Boolean ret_val;
373
374 /* Check for invalid conditions */
375
376 if ((image == NULL) || (image_set == NULL)) return (False);
377
378 _XmProcessLock();
379 /* Since we can't index based on the image, search the hash table */
380 /* until the desired entry is found and then remove it. */
381
382 old_count = _XmHashTableCount(image_set);
383
384 _XmMapHashTable(image_set, UninstallImageMapProc, image);
385 ret_val = (old_count > _XmHashTableCount(image_set));
386 _XmProcessUnlock();
387
388 return ret_val;
389 }
390
391
392
393 /************************************************************************
394 *
395 * SymbolicColorUsed
396 * Used to determine if a given color string is defined as a symbolic
397 * color in an Xpm image. This is used for caching policy where we
398 * don't want to cache based on irrelevant colors.
399 * Note that we don't look if the color is actually used because it
400 * is too expensive.
401 *
402 ************************************************************************/
403 static Boolean
SymbolicColorUsed(String color_name,XpmColor * xpm_colors,unsigned int ncolors)404 SymbolicColorUsed(String color_name,
405 XpmColor * xpm_colors,
406 unsigned int ncolors)
407 {
408 Cardinal i, j, data_size ;
409
410 /* first look if the color is present as a symbolic in the
411 colorTable */
412 for (i = 0; i < ncolors; i++, xpm_colors++) {
413 if (xpm_colors->symbolic &&
414 !strcmp(xpm_colors->symbolic, color_name))
415 break ;
416 }
417
418 if (i == ncolors) return False ;
419
420 return False ;
421 }
422
423
424 /************************************************************************
425 *
426 * CompleteUnspecColors
427 * Complete the unspecified_pixel values of an override_colors array
428 * based on the values coming from the ColorObj or the color cache.
429 * Does not handle highlight.
430 * The logic here comes directly from CDE.
431 *
432 * The above description does not fit with the actual logic of CDE where
433 * not only the unspecified colors are set here but the whole set of
434 * symbols! See defect CDExc17529.
435 *
436 ************************************************************************/
437 static void
CompleteUnspecColors(Screen * screen,XpmColorSymbol * override_colors)438 CompleteUnspecColors(
439 Screen *screen,
440 XpmColorSymbol *override_colors)
441 {
442 XmPixelSet pixelSets[XmCO_NUM_COLORS];
443 int colorUse ;
444 Boolean bgFound = False, fgFound = False, result = False;
445 Pixel *pixelPtr;
446 Cardinal i, j ;
447 XmAccessColorDataRec loc_acc_color;
448
449
450 /* Ask the color obj */
451 if (!(result = XmeGetColorObjData(screen,
452 &colorUse, pixelSets, XmCO_NUM_COLORS,
453 NULL, NULL, NULL, NULL, NULL)))
454 i = XmCO_NUM_COLORS;
455 else
456 i = 0;
457
458 /* Look for a pixels set containing the given fg and bg,
459 * no matter whether they are actually the fg and bg of the set...
460 */
461 for ( ; i < XmCO_NUM_COLORS; i++) {
462 bgFound = False;
463 fgFound = False;
464 pixelPtr = (Pixel *)&(pixelSets[i].fg);
465 for (j = 0; j < 5; j++, pixelPtr++) {
466 if (*pixelPtr == override_colors[SYMB_BACKGROUND].pixel)
467 bgFound = True;
468 else if (*pixelPtr == override_colors[SYMB_FOREGROUND].pixel)
469 fgFound = True;
470 }
471 if (bgFound && fgFound)
472 break;
473 }
474
475 if (i == XmCO_NUM_COLORS) {
476 /*
477 * We didn't find the bg/fg tuple in any of the Dt colorsets
478 * or if the color server is not running, we will now try
479 * the color cache.
480 */
481
482 XmColorData *old_colors;
483 XmColorData new_colors;
484
485 loc_acc_color.background = override_colors[SYMB_BACKGROUND].pixel ;
486
487 new_colors.screen = screen;
488 new_colors.color_map = DefaultColormapOfScreen(screen);
489 new_colors.background.pixel = loc_acc_color.background ;
490
491 /* Use motif color set only if already allocated.
492 */
493 if (!result && _XmSearchColorCache(
494 (XmLOOK_AT_SCREEN | XmLOOK_AT_CMAP | XmLOOK_AT_BACKGROUND),
495 &new_colors, &old_colors)) {
496 XmGetColors(screen,
497 DefaultColormapOfScreen(screen),
498 loc_acc_color.background,
499 &loc_acc_color.foreground,
500 &loc_acc_color.top_shadow_color,
501 &loc_acc_color.bottom_shadow_color,
502 &loc_acc_color.select_color);
503 } else {
504 /* Cannot generate missing colors */
505 return ;
506 }
507 }
508 else {
509 loc_acc_color.background = pixelSets[i].bg;
510 loc_acc_color.foreground = pixelSets[i].fg;
511 loc_acc_color.top_shadow_color = pixelSets[i].ts;
512 loc_acc_color.bottom_shadow_color = pixelSets[i].bs;
513 loc_acc_color.select_color = pixelSets[i].sc;
514 }
515
516 /* Now process the setting for unspecified pixel values.
517 If we're here, all the colors but highlight are available */
518
519 override_colors[SYMB_BACKGROUND].pixel = loc_acc_color.background ;
520
521 override_colors[SYMB_FOREGROUND].pixel = loc_acc_color.foreground ;
522
523 override_colors[SYMB_TOP_SHADOW_COLOR].pixel =
524 loc_acc_color.top_shadow_color ;
525
526 override_colors[SYMB_BOTTOM_SHADOW_COLOR].pixel =
527 loc_acc_color.bottom_shadow_color ;
528
529 override_colors[SYMB_SELECT_COLOR].pixel = loc_acc_color.select_color ;
530 }
531
532
533 /************************************************************************
534 *
535 * GetOverrideColors
536 * Given a set of colors in acc_color with values specified or not
537 * this function fills up an XpmColorSymbol override_colors array to
538 * be used by the Xpm reader.
539 * It then calls the ColorObject aware filling proc to find values
540 * for the still unspecified ones.
541 * It returns the number of entries to consider in override_colors,
542 * which can be 2 (background and foreground are always valid),
543 * NUM_SYMBOLIC_COLORS - 1 (if everything but the highlight could
544 * be generated), or NUM_SYMBOLIC_COLOR.
545 *
546 ************************************************************************/
547
548 static int
GetOverrideColors(Screen * screen,XmAccessColorData acc_color,XpmColorSymbol * override_colors)549 GetOverrideColors(
550 Screen *screen,
551 XmAccessColorData acc_color,
552 XpmColorSymbol *override_colors)
553 {
554 Cardinal i, n ;
555
556 /* init the value fields */
557 for (i=0; i<NUM_SYMBOLIC_COLORS; i++) override_colors[i].value = NULL ;
558
559 /* proceed each color in turn: acc_color might point to
560 XmUNSPECIFIED_PIXEL, but background/foreground should be valid */
561
562 override_colors[SYMB_BACKGROUND].name = XmNbackground ;
563 override_colors[SYMB_BACKGROUND].pixel = acc_color->background ;
564
565 override_colors[SYMB_FOREGROUND].name = XmNforeground ;
566 override_colors[SYMB_FOREGROUND].pixel = acc_color->foreground ;
567
568 /* Set "none" color to background in case the mask is not used. */
569 override_colors[TRANSPARENT_COLOR].name = NULL ;
570 override_colors[TRANSPARENT_COLOR].value = "None" ;
571 override_colors[TRANSPARENT_COLOR].pixel = acc_color->background ;
572
573 override_colors[SYMB_TOP_SHADOW_COLOR].name = XmNtopShadowColor ;
574 override_colors[SYMB_TOP_SHADOW_COLOR].pixel =
575 acc_color->top_shadow_color ;
576
577 override_colors[SYMB_BOTTOM_SHADOW_COLOR].name = XmNbottomShadowColor ;
578 override_colors[SYMB_BOTTOM_SHADOW_COLOR].pixel =
579 acc_color->bottom_shadow_color ;
580
581 override_colors[SYMB_SELECT_COLOR].name = XmNselectColor ;
582 override_colors[SYMB_SELECT_COLOR].pixel = acc_color->select_color ;
583 /* need to hack around selectColor which might be still
584 unspecified while highlight is not (and that woudl break our
585 ordering rule - see below). Use top_shadow color so that select
586 follows its set/unset semantics regarding overriding */
587 if (override_colors[SYMB_SELECT_COLOR].pixel == XmUNSPECIFIED_PIXEL)
588 override_colors[SYMB_SELECT_COLOR].pixel =
589 override_colors[SYMB_TOP_SHADOW_COLOR].pixel ;
590
591 override_colors[SYMB_HIGHLIGHT_COLOR].name = XmNhighlightColor ;
592 override_colors[SYMB_HIGHLIGHT_COLOR].pixel = acc_color->highlight_color ;
593
594
595
596 /* now call ColorObject aware routine to give it a chance to
597 fill the remaining unspecified pixel field in override_colors */
598
599 CompleteUnspecColors (screen, override_colors) ;
600
601 /* Just count the number of valid pixel.
602 This makes a strong assumption on the ordering: if we find
603 5 valid pixels, the 5 first one will be used.
604 This is ok since _XmGetColoredPixmap is only used internally
605 in such a way that this happens to be true: background/foreground
606 are always here, and highlight color is the only one
607 that might be missing after CompleteUnspecColors call.
608 The day XmGetColoredPixmap is promoted public, this simple
609 logic will have to be reviewed */
610
611 n = 0 ;
612 for (i=0; i<NUM_SYMBOLIC_COLORS; i++)
613 if (override_colors[i].pixel != XmUNSPECIFIED_PIXEL) n++;
614
615 return n ;
616 }
617
618
619
620 #ifdef _ORIG_GET_ICON_FILE
621
622 /******************************************************************
623 *
624 * GetIconFileName. get a file name using XBMLANGPATH
625 *
626 *****************************************************************/
627
628 static String
GetIconFileName(Screen * screen,char * icon_name)629 GetIconFileName(
630 Screen *screen,
631 char *icon_name)
632 {
633 char *bmPath;
634 SubstitutionRec subs[1] ;
635 Boolean user_path ;
636 Display *display = DisplayOfScreen(screen);
637 char *file_name;
638
639 subs[0].substitution = icon_name;
640
641 bmPath = _XmOSInitPath(icon_name, "XBMLANGPATH", &user_path);
642
643 if (user_path) subs[0].match = 'B';
644 else subs[0].match = MATCH_CHAR ;
645
646 file_name = XtResolvePathname(display, "bitmaps", NULL,
647 NULL, bmPath, subs, XtNumber(subs), NULL);
648 XtFree (bmPath);
649
650 return file_name ;
651
652 }
653
654 #endif
655
656 static XtEnum
GetXpmImage(Screen * screen,char * image_name,char * file_name,XmAccessColorData acc_color,XImage ** image,unsigned short * pixmap_resolution,Pixel ** pixels,int * npixels)657 GetXpmImage(
658 Screen *screen,
659 char *image_name, /* original image file name */
660 char *file_name,
661 XmAccessColorData acc_color,
662 XImage **image,
663 unsigned short *pixmap_resolution,
664 Pixel **pixels,
665 int *npixels)
666 {
667 XpmAttributes attrib;
668 int xpmStatus;
669 Boolean useIconFileCache;
670 Boolean useMask;
671 Boolean useColor;
672 XpmColorSymbol override_colors[NUM_SYMBOLIC_COLORS]; /* max */
673 int num_override_colors;
674 XImage * mask_image = NULL ;
675 int hot_x = 0 , hot_y = 0 ;
676 register Display *display = DisplayOfScreen(screen);
677
678 /* init so that we can call safely XpmFreeAttributes. */
679 attrib.valuemask = 0;
680
681 /* Init the Xpm attributes to be passed to the reader */
682 attrib.closeness = 40000;
683 attrib.bitmap_format = XYBitmap;
684 attrib.alloc_color = GetCacheColor;
685 attrib.free_colors = FreeCacheColors;
686 attrib.valuemask = XpmCloseness | XpmBitmapFormat | XpmReturnColorTable
687 | XpmAllocColor | XpmFreeColors | XpmReturnAllocPixels;
688
689 /* if any symbolic color are defined, used them */
690 if (acc_color &&
691 (num_override_colors = GetOverrideColors(screen,
692 acc_color,
693 override_colors)) != 0) {
694 attrib.colorsymbols = override_colors;
695 attrib.numsymbols = num_override_colors;
696 attrib.valuemask |= XpmColorSymbols;
697 }
698
699 /* ask the color object for information about the
700 use of mask or color */
701 (void)XmeGetIconControlInfo(screen,
702 &useMask,
703 &useColor,
704 &useIconFileCache); /* unused */
705
706 if (!useColor) {
707 attrib.depth = 1;
708 attrib.valuemask |= XpmDepth;
709 }
710
711 *image = NULL ;
712
713 xpmStatus = XmeXpmReadFileToImage(display,
714 file_name,
715 image,
716 &mask_image,
717 &attrib);
718 if (xpmStatus < 0)
719 *image = NULL ;
720 else {
721 /* store allocated colors */
722 if (pixels) *pixels = attrib.alloc_pixels;
723 if (npixels) *npixels = attrib.nalloc_pixels;
724 /* and make sure they won't be free'd */
725 attrib.alloc_pixels = NULL;
726 attrib.nalloc_pixels = 0;
727 }
728
729
730 if (!(*image))
731 *image = (XImage *) _XmReadImageAndHotSpotFromFile (display,
732 file_name,
733 &hot_x, &hot_y);
734
735 /* get the image "design" resolution */
736 /* in the future: look in the file */
737 if (pixmap_resolution) *pixmap_resolution = 0 ;
738
739
740 if (*image) {
741
742 /* if the XPM file contained a embedded mask,
743 install it using our mask name scheme if the color object
744 tell us to do so */
745 if (mask_image && useMask) {
746 char mask_name[255] ;
747
748 _XmOSGenerateMaskName(image_name, mask_name);
749 /* if an image already exist under that
750 name, nothing will be done */
751 _XmInstallImage (mask_image, mask_name, hot_x, hot_y);
752 }
753
754 /* now we have to adjust the passed acc_color */
755 if (acc_color) {
756 if ((*image)->depth == 1) {
757 /* we've loaded an xbm file, just forget about
758 the 'other' symbolic colors, for they
759 are not going to be used during pixmap
760 generation for depth 1 => pixmap putimage */
761 acc_color->top_shadow_color = XmUNSPECIFIED_PIXEL;
762 acc_color->bottom_shadow_color= XmUNSPECIFIED_PIXEL;
763 acc_color->select_color = XmUNSPECIFIED_PIXEL;
764 acc_color->highlight_color = XmUNSPECIFIED_PIXEL;
765 if (acc_color->foreground == XmUNSPECIFIED_PIXEL
766 && acc_color->background == XmUNSPECIFIED_PIXEL) {
767 acc_color->foreground = 1;
768 acc_color->background = 0;
769 }
770 } else {
771
772 /* we've loaded a xpm, check which symbolics
773 colors were actually used during the read,
774 we don't want to remember the unused one
775 for the pixmap caching */
776
777 if (!SymbolicColorUsed(XmNbackground,
778 attrib.colorTable,
779 attrib.ncolors))
780 acc_color->background = XmUNSPECIFIED_PIXEL;
781
782 if (!SymbolicColorUsed(XmNforeground,
783 attrib.colorTable,
784 attrib.ncolors))
785 acc_color->foreground = XmUNSPECIFIED_PIXEL;
786
787 if (!SymbolicColorUsed(XmNtopShadowColor,
788 attrib.colorTable,
789 attrib.ncolors))
790 acc_color->top_shadow_color = XmUNSPECIFIED_PIXEL;
791
792 if (!SymbolicColorUsed(XmNbottomShadowColor,
793 attrib.colorTable,
794 attrib.ncolors))
795 acc_color->bottom_shadow_color = XmUNSPECIFIED_PIXEL;
796
797 if (!SymbolicColorUsed(XmNselectColor,
798 attrib.colorTable,
799 attrib.ncolors))
800 acc_color->select_color = XmUNSPECIFIED_PIXEL;
801
802 if (!SymbolicColorUsed(XmNhighlightColor,
803 attrib.colorTable,
804 attrib.ncolors))
805 acc_color->highlight_color = XmUNSPECIFIED_PIXEL;
806
807 }
808 }
809
810
811 /* install the XImage with that name.
812 We do not cache the non-depth 1 ones
813 for we don't want to keep them in the image
814 cache, since they need color lookup,
815 which is done one level up in the pixmap cache */
816 if (((*image)->depth == 1)
817 && acc_color
818 && (acc_color->foreground == 1)
819 && (acc_color->background == 0)
820 ) {
821 _XmInstallImage (*image, image_name, hot_x, hot_y);
822 return TRUE ;
823 } else {
824 if (xpmStatus >= 0)
825 XmeXpmFreeAttributes(&attrib);
826 return NOT_CACHED ; /* mean the image can be destroyed
827 after it is used */
828 }
829 }
830
831 if (xpmStatus >= 0)
832 XmeXpmFreeAttributes(&attrib);
833
834 return FALSE;
835 }
836
837 /************************************************************************
838 *
839 * GetImage
840 * Main routine of the image cache part.
841 *
842 ************************************************************************/
843 static XtEnum
GetImage(Screen * screen,char * image_name,XmAccessColorData acc_color,XImage ** image,unsigned short * pixmap_resolution,Pixel ** pixels,int * npixels)844 GetImage(
845 Screen *screen,
846 char *image_name,
847 XmAccessColorData acc_color,
848 XImage **image,
849 unsigned short * pixmap_resolution,
850 Pixel **pixels, /* allocated pixels */
851 int *npixels)
852 {
853 static XImage * built_in_image = NULL;
854 register Display *display = DisplayOfScreen(screen);
855 ImageData *entry;
856 char *file_name;
857 XtEnum return_value;
858 #if defined (PNG_SUPPORTED) || defined (JPEG_SUPPORTED)
859 FILE *infile;
860 int rc;
861 #endif
862
863 /* init for when we go thru the image cache first */
864 if (pixmap_resolution) *pixmap_resolution = 0 ;
865
866 if (pixels) *pixels = NULL;
867 if (npixels) *npixels = 0;
868
869 /*** Check for the initial allocation of the image set array */
870
871 if (image_set == NULL) InitializeImageSet();
872
873 if (!image_name) return FALSE ;
874
875 /*** look in the XImage cache first */
876 _XmProcessLock();
877 entry = (ImageData*) _XmGetHashEntry(image_set, image_name);
878 _XmProcessUnlock();
879
880
881 if (entry) {
882
883 /* If the image is a builtin image then get it. */
884
885 if (entry->builtin_data) {
886 /* there is one builtin XImage shared by all builtins,
887 only the data part change every time a query is made */
888 _XmProcessLock();
889 if (!built_in_image) {
890 /* update that with new R6 init image stuff when out */
891 _XmCreateImage(built_in_image, display, NULL,
892 16, 16, MSBFirst);
893 }
894
895 built_in_image->data = (char *) entry->builtin_data;
896 _XmProcessUnlock();
897 *image = built_in_image;
898
899 } else {
900
901 /* other entry found are just fine, set the image and return */
902
903 *image = entry->image ;
904 }
905
906 return TRUE;
907 }
908
909 /*** if no entry, try to read a new file and cache it
910 only if it is a bitmap */
911
912 #ifdef _ORIG_GET_ICON_FILE
913 file_name = GetIconFileName(screen, image_name);
914 #else
915 file_name = XmGetIconFileName(screen, NULL, image_name,
916 NULL, XmUNSPECIFIED_ICON_SIZE);
917 #endif
918
919 if (!file_name) {
920 return FALSE;
921 }
922
923 #if defined (JPEG_SUPPORTED) || defined (PNG_SUPPORTED)
924 if (!(infile = fopen(file_name, "rb"))) {
925 return FALSE;
926 }
927
928 #ifdef JPEG_SUPPORTED
929 rc = _XmJpegGetImage(screen, infile, image);
930 #endif
931 #if defined (JPEG_SUPPORTED) && defined (PNG_SUPPORTED)
932 if (rc == 1) { /* not a jpeg file */
933 #endif
934 #ifdef PNG_SUPPORTED
935 Pixel background;
936
937 if (acc_color)
938 background = acc_color->background;
939 else
940 background = 0;
941
942 if (background == XmUNSPECIFIED_PIXEL)
943 background = 0; /* XXX is if OK? */
944 #endif
945 #if defined (JPEG_SUPPORTED) && defined (PNG_SUPPORTED)
946 rewind(infile);
947 #endif
948 #ifdef PNG_SUPPORTED
949 rc = _XmPngGetImage(screen, infile, background, image);
950 #endif
951 #if defined (JPEG_SUPPORTED) && defined (PNG_SUPPORTED)
952 }
953 #endif
954
955 fclose(infile);
956
957 if (rc > 1) {
958 return_value = FALSE;
959 } else if (rc == 0) {
960 return_value = NOT_CACHED;
961 } else {
962 #endif
963 return_value =
964 GetXpmImage(screen, image_name, file_name, acc_color,
965 image, pixmap_resolution, pixels, npixels);
966 #if defined (JPEG_SUPPORTED) || defined (PNG_SUPPORTED)
967 }
968 #endif
969
970 XtFree(file_name);
971
972 return return_value;
973 }
974
975 /*** Keep this one in here, this is the only entry point to
976 the Image cache. It can be used to duplicate them, etc */
977 Boolean
_XmGetImage(Screen * screen,char * image_name,XImage ** image)978 _XmGetImage(
979 Screen *screen,
980 char *image_name,
981 XImage **image )
982 {
983 return GetImage(screen, image_name, NULL, image, NULL, NULL, NULL) ;
984 }
985
986
987 /************************************************************************
988 *
989 * _XmInImageCache
990 * Used by IconFile.c
991 *
992 ************************************************************************/
993
994 Boolean
_XmInImageCache(String image_name)995 _XmInImageCache(
996 String image_name)
997 {
998 XtPointer ret_val;
999
1000 if (!image_set) return False ;
1001 _XmProcessLock();
1002 ret_val = _XmGetHashEntry(image_set, image_name);
1003 _XmProcessUnlock();
1004
1005 return (ret_val != NULL) ;
1006 }
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016 /*** PIXMAP CACHE NOW ***/
1017
1018 /** static dependencies with Image part:
1019 * GetImage(), ImageData&image_set, HashString
1020 **/
1021 /** static dependencies with Color part:
1022 * FreeCacheColors()
1023 **/
1024
1025
1026
1027
1028 static Boolean
ComparePixmaps(XmHashKey key_1,XmHashKey key_2)1029 ComparePixmaps (XmHashKey key_1,
1030 XmHashKey key_2)
1031 {
1032 PixmapData *data_1 = (PixmapData *) key_1;
1033 PixmapData *data_2 = (PixmapData *) key_2;
1034
1035 /* Check for a matching pixmap using screen and pixmap */
1036
1037 return
1038 (data_1->screen == data_2->screen &&
1039 data_1->pixmap == data_2->pixmap) ;
1040 }
1041
1042 static Boolean
ComparePixmapDatas(XmHashKey key_1,XmHashKey key_2)1043 ComparePixmapDatas (XmHashKey key_1,
1044 XmHashKey key_2)
1045 {
1046 PixmapData *data_1 = (PixmapData *) key_1;
1047 PixmapData *data_2 = (PixmapData *) key_2;
1048
1049 /* Check for a matching pixmap using depth, screen, name and
1050 colors info + print_resolution/scaling_ratio and print_shell */
1051 /* if a negative depth is given, we must look for a matching
1052 pixmap of -depth or 1 */
1053
1054 return
1055 ((data_2->pixmap == XmUNSPECIFIED_PIXMAP ||
1056 data_1->pixmap == data_2->pixmap) &&
1057 data_1->image_name != NULL &&
1058 data_2->image_name != NULL &&
1059 strcmp (data_1->image_name, data_2->image_name) == 0 &&
1060
1061 (data_1->screen == data_2->screen) &&
1062
1063 ( /* ratio == 0 means print resolution is used */
1064 (data_1->scaling_ratio == data_2->scaling_ratio &&
1065 data_1->scaling_ratio) ||
1066 (data_1->print_resolution == data_2->print_resolution &&
1067 !data_1->scaling_ratio)) &&
1068
1069 (data_1->print_shell == data_2->print_shell) &&
1070
1071 ((data_1->depth == data_2->depth) ||
1072 (data_2->depth < 0 && data_1->depth == -data_2->depth) ||
1073 (data_2->depth < 0 && data_1->depth == 1)) &&
1074
1075 ((data_1->acc_color->foreground == data_2->acc_color->foreground) ||
1076 (data_2->depth < 0 && data_1->acc_color->foreground == 1) ||
1077 (data_1->acc_color->foreground == XmUNSPECIFIED_PIXEL) ||
1078 (data_2->acc_color->foreground == XmUNSPECIFIED_PIXEL)) &&
1079 ((data_1->acc_color->background == data_2->acc_color->background) ||
1080 (data_2->depth < 0 && data_1->acc_color->background == 0) ||
1081 (data_1->acc_color->background == XmUNSPECIFIED_PIXEL)||
1082 (data_2->acc_color->background == XmUNSPECIFIED_PIXEL)) &&
1083
1084 ((data_1->acc_color->top_shadow_color ==
1085 data_2->acc_color->top_shadow_color) ||
1086 (data_1->acc_color->top_shadow_color == XmUNSPECIFIED_PIXEL)||
1087 (data_2->acc_color->top_shadow_color == XmUNSPECIFIED_PIXEL)) &&
1088 ((data_1->acc_color->bottom_shadow_color
1089 == data_2->acc_color->bottom_shadow_color)||
1090 (data_1->acc_color->bottom_shadow_color == XmUNSPECIFIED_PIXEL)||
1091 (data_2->acc_color->bottom_shadow_color == XmUNSPECIFIED_PIXEL)) &&
1092 ((data_1->acc_color->select_color ==
1093 data_2->acc_color->select_color) ||
1094 (data_1->acc_color->select_color == XmUNSPECIFIED_PIXEL)||
1095 (data_2->acc_color->select_color == XmUNSPECIFIED_PIXEL)) &&
1096 ((data_1->acc_color->highlight_color ==
1097 data_2->acc_color->highlight_color) ||
1098 (data_1->acc_color->highlight_color == XmUNSPECIFIED_PIXEL) ||
1099 (data_2->acc_color->highlight_color == XmUNSPECIFIED_PIXEL))) ;
1100 }
1101
1102 /* Hash a Pixmap entry. */
1103 static XmHashValue
HashPixmap(XmHashKey key)1104 HashPixmap (XmHashKey key)
1105 {
1106 PixmapData *data = (PixmapData *) key;
1107
1108 return ((long)data->screen + data->pixmap);
1109 }
1110
1111 /* Hash a PixmapData entry. Reuse the string hash function */
1112 static XmHashValue
HashPixmapData(XmHashKey key)1113 HashPixmapData (XmHashKey key)
1114 {
1115 PixmapData *data = (PixmapData *) key;
1116
1117 return ((long)data->screen + HashString ((XmHashKey)data->image_name));
1118 }
1119
1120 /************************************************************************
1121 *
1122 * InitializePixmapSets
1123 * Initialize the pixmap sets.
1124 *
1125 ************************************************************************/
1126 static void
InitializePixmapSets(void)1127 InitializePixmapSets( void )
1128 {
1129 /* Allocate the pixmap hash tables.
1130 One for the regular XmGetPixmap lookup, one for the
1131 XmeGetPixmapData lookup */
1132 assert (pixmap_data_set == NULL && pixmap_set == NULL);
1133
1134 _XmProcessLock();
1135 pixmap_data_set = _XmAllocHashTable (100, ComparePixmapDatas,
1136 HashPixmapData);
1137
1138 pixmap_set = _XmAllocHashTable (100, ComparePixmaps, HashPixmap);
1139 _XmProcessUnlock();
1140
1141 }
1142
1143 /************************************************************************
1144 *
1145 * _XmCachePixmap
1146 * Install a pixmap into the pixmap cache. This is used to add
1147 * cached pixmaps which have no XImage associated with them.
1148 * This one you can pass depth and size info, if you don't,
1149 * the X server will be queried: very expensive.
1150 *
1151 ************************************************************************/
1152 Boolean
_XmCachePixmap(Pixmap pixmap,Screen * screen,char * image_name,Pixel foreground,Pixel background,int depth,Dimension width,Dimension height)1153 _XmCachePixmap(
1154 Pixmap pixmap,
1155 Screen *screen,
1156 char *image_name,
1157 Pixel foreground,
1158 Pixel background,
1159 int depth,
1160 Dimension width,
1161 Dimension height)
1162 {
1163 PixmapData * pix_entry;
1164
1165 Window root;
1166 int x,y;
1167 unsigned int loc_width, loc_height, border_width, loc_depth;
1168
1169 /* Error checking */
1170 if (image_name == NULL) return (False);
1171
1172 if (!pixmap_data_set) InitializePixmapSets() ;
1173
1174 /* if no information was given, get it from the server */
1175 if (!(width && height && depth))
1176 XGetGeometry(DisplayOfScreen(screen), pixmap, &root, &x, &y,
1177 &loc_width, &loc_height, &border_width, &loc_depth);
1178 else {
1179 loc_width = width ;
1180 loc_height = height ;
1181 loc_depth = depth ;
1182 }
1183
1184 /* Allocate the cache structure and put it into the list */
1185
1186 pix_entry = XtNew (PixmapData);
1187
1188 pix_entry->screen = screen;
1189 pix_entry->acc_color = XtNew(XmAccessColorDataRec);
1190 pix_entry->acc_color->foreground = foreground;
1191 pix_entry->acc_color->background = background;
1192 pix_entry->acc_color->top_shadow_color = XmUNSPECIFIED_PIXEL;
1193 pix_entry->acc_color->bottom_shadow_color = XmUNSPECIFIED_PIXEL;
1194 pix_entry->acc_color->select_color = XmUNSPECIFIED_PIXEL;
1195 pix_entry->acc_color->highlight_color = XmUNSPECIFIED_PIXEL;
1196 pix_entry->depth = loc_depth;
1197 pix_entry->width = loc_width;
1198 pix_entry->height = loc_height;
1199 pix_entry->image_name = XtNewString(image_name);
1200 pix_entry->pixmap = pixmap;
1201 pix_entry->reference_count = 1;
1202 pix_entry->print_resolution = 100 ;
1203 pix_entry->print_shell = NULL ;
1204 pix_entry->scaling_ratio = 1 ;
1205 pix_entry->pixels = NULL;
1206 pix_entry->npixels = 0;
1207
1208 _XmProcessLock();
1209 _XmAddHashEntry(pixmap_set, (XmHashKey)pix_entry, (XtPointer)pix_entry);
1210
1211 /* Only add pixmaps not issued from XmeGetPixmapData to the "real" table */
1212 if (0 != strcmp(image_name, DIRECT_PIXMAP_CACHED))
1213 _XmAddHashEntry(pixmap_data_set, (XmHashKey)pix_entry,
1214 (XtPointer)pix_entry);
1215 _XmProcessUnlock();
1216
1217 return (True);
1218 }
1219
1220
1221
1222 /********************************************************************/
1223
1224 Boolean
_XmGetPixmapData(Screen * screen,Pixmap pixmap,char ** image_name,int * depth,Pixel * foreground,Pixel * background,int * hot_x,int * hot_y,unsigned int * width,unsigned int * height)1225 _XmGetPixmapData(
1226 Screen *screen,
1227 Pixmap pixmap,
1228 char **image_name,
1229 int *depth,
1230 Pixel *foreground,
1231 Pixel *background,
1232 int *hot_x,
1233 int *hot_y,
1234 unsigned int *width,
1235 unsigned int *height)
1236 /* no pixmap_resolution returned... */
1237 {
1238 PixmapData pix_data, *pix_entry;
1239 ImageData * entry;
1240
1241 if (!pixmap_data_set) InitializePixmapSets() ;
1242
1243 /* checks for a matching screen and pixmap. */
1244
1245 pix_data.screen = screen ;
1246 pix_data.pixmap = pixmap ;
1247
1248 _XmProcessLock();
1249 if ((pix_entry = (PixmapData*)
1250 _XmGetHashEntry(pixmap_set, (XmHashKey)&pix_data)) != NULL) {
1251
1252 *foreground = pix_entry->acc_color->foreground;
1253 *background = pix_entry->acc_color->background;
1254 *depth = pix_entry->depth;
1255 *image_name = pix_entry->image_name;
1256 *width = pix_entry->width;
1257 *height = pix_entry->height;
1258 /* try to get the hot spot data from the image cache */
1259 if (image_set) {
1260 entry = (ImageData *) _XmGetHashEntry(image_set, *image_name);
1261 if (entry) {
1262 *hot_x = entry->hot_x;
1263 *hot_y = entry->hot_y;
1264 }
1265 }
1266 _XmProcessUnlock();
1267 return True;
1268 }
1269 _XmProcessUnlock();
1270 return False ;
1271 }
1272
1273
1274
1275 /*******************************************************************/
1276 /* the real one, used by PixConv and locally too */
1277 Pixmap
_XmGetScaledPixmap(Screen * screen,Widget widget,char * image_name,XmAccessColorData acc_color,int depth,int only_if_exists,double scaling_ratio)1278 _XmGetScaledPixmap(
1279 Screen *screen,
1280 Widget widget,
1281 char *image_name,
1282 XmAccessColorData acc_color,
1283 int depth,
1284 #if NeedWidePrototypes
1285 int only_if_exists,
1286 #else
1287 Boolean only_if_exists,
1288 #endif /* NeedWidePrototypes */
1289 double scaling_ratio)
1290 {
1291 Display * display = DisplayOfScreen(screen);
1292 XImage * image;
1293 Pixmap pixmap;
1294 GC gc ;
1295 XtEnum ret ;
1296 PixmapData pix_data, *pix_entry ;
1297 unsigned short pixmap_resolution ;
1298 Pixel *pixels; /* allocated colors */
1299 int npixels;
1300 int old_image_format;
1301 char *old_image_data = NULL;
1302
1303 /* Error checking */
1304 if (image_name == NULL) return (XmUNSPECIFIED_PIXMAP);
1305
1306 if (!pixmap_data_set) InitializePixmapSets() ;
1307
1308 /* if screen not provided, widget has to be! */
1309 if (!screen) screen = XtScreen(widget);
1310
1311 /* since more than one printers can attach to one screen,
1312 we need to use the print shell in the caching */
1313 /* since resolution can be dynamic for a printer, we need
1314 to use the resolution too, when scaling is 0 */
1315 pix_data.screen = screen ;
1316 pix_data.image_name = image_name ;
1317 pix_data.depth = depth ;
1318 pix_data.acc_color = acc_color ;
1319 pix_data.print_resolution = 100 ; /* default */
1320 pix_data.scaling_ratio = scaling_ratio ;
1321
1322 pix_data.pixmap = XmUNSPECIFIED_PIXMAP;
1323
1324 /* find out the print shell ancestor */
1325 pix_data.print_shell = widget ;
1326 while(pix_data.print_shell && !XmIsPrintShell(pix_data.print_shell))
1327 pix_data.print_shell = XtParent(pix_data.print_shell);
1328 /* pix_data.print_shell might be NULL here */
1329
1330 #ifdef PRINTING_SUPPORTED
1331 /* scaling_ratio == 0 means use print_resolution and pixmap_resolution
1332 in scaling - so first find out the print_resolution, since it
1333 is used in caching */
1334 if (!scaling_ratio && pix_data.print_shell)
1335 pix_data.print_resolution =
1336 ((XmPrintShellWidget)pix_data.print_shell)->print.print_resolution ;
1337 #endif
1338
1339 /* if scaling_ratio a real number, like 1 or 1.2
1340 print_resolution still 100 and will not be used */
1341
1342 /* look if we have a match and return it */
1343 _XmProcessLock();
1344 if ((pix_entry = (PixmapData*)
1345 _XmGetHashEntry(pixmap_data_set, (XmHashKey)&pix_data)) != NULL) {
1346 pix_entry->reference_count++;
1347 _XmProcessUnlock();
1348 return pix_entry->pixmap ;
1349 }
1350 _XmProcessUnlock();
1351
1352 /* The desired pixmap is not already cached. Quit now or create it. */
1353 if (only_if_exists)
1354 return (XmUNSPECIFIED_PIXMAP);
1355
1356 /* no pixmap found, look for an XImage.
1357 generate a new one if needed.
1358 GetImage can return a bitmap or a pixmap XImage */
1359 /* GetImage modify the acc_color struct to update the
1360 colors that are not used during reading:
1361 - for xbm, everything but foreground and background.
1362 - for xpm, on a case by case basis, depending
1363 if the corresponding symbolic color was used. */
1364
1365 if (!(ret = GetImage(screen, image_name, acc_color, &image,
1366 &pixmap_resolution, &pixels, &npixels)))
1367 return (XmUNSPECIFIED_PIXMAP);
1368
1369 /* now find how much we need to scale this baby */
1370
1371 /* compute the real ratio to be used in PutImage */
1372 if (!pix_data.scaling_ratio) {
1373 /* if scaling ratio is real, like 1.2, the pixmap resolution is
1374 not used, neither is the print_resolution */
1375
1376 if (!pixmap_resolution) {
1377 /* GetImage returns the resolution for which the image
1378 was designed. if none was provided in the file, it's 0,
1379 in which case, the print shell default resolution
1380 for pixmap is used */
1381
1382 #ifdef PRINTING_SUPPORTED
1383 if (pix_data.print_shell)
1384 pixmap_resolution =
1385 ((XmPrintShellWidget)pix_data.print_shell)
1386 ->print.default_pixmap_resolution ;
1387 else
1388 #endif /* PRINTING_SUPPORTED */
1389 pixmap_resolution = 100 ;
1390 }
1391
1392 pix_data.scaling_ratio = (double)pix_data.print_resolution /
1393 (double)pixmap_resolution ;
1394 }
1395
1396
1397 /* now we treat the -depth case: if a negative depth was given
1398 then xbm file should map into bitmap and xpm into pixmap */
1399
1400 if (depth < 0) {
1401 if (image->depth == 1)
1402 depth = 1 ;
1403 else
1404 depth = -depth ;
1405 }
1406
1407 /* now check the validity of the image depth. XPutImage can
1408 only handle unequal depths for bitmaps. */
1409 if ((image->depth != depth) && (image->depth != 1))
1410 return (XmUNSPECIFIED_PIXMAP);
1411
1412 /* force the foreground/background if a Bitmap
1413 is returned. These values are going to go in the cache
1414 too, so we will have to remember this forcing for the
1415 case -depth: you ask for -depth and some
1416 foreground/background, that should match a depth 1
1417 with 1/0. Look at ComparePixmapDatas above for details */
1418
1419 if (depth == 1) {
1420 acc_color->foreground = 1;
1421 acc_color->background = 0;
1422 }
1423
1424 /* XPutImage will only deepen bitmaps -- fake it with pixmaps. */
1425 old_image_format = image->format;
1426 if (image->depth == 1) {
1427 switch(image->format)
1428 {
1429 case XYBitmap:
1430 /* XPutImage will do the right thing. */
1431 break;
1432
1433 case XYPixmap:
1434 /* We're going to muck with the shared image... */
1435 if (ret != NOT_CACHED)
1436 _XmProcessLock();
1437
1438 /* Assume black == fg in the image. */
1439 if ((BlackPixelOfScreen(screen) == 0) ||
1440 (WhitePixelOfScreen(screen) == 1))
1441 {
1442 /* Flip the bits so fg == 1 in the image. */
1443 register int nbytes = image->height * image->bytes_per_line;
1444 register int byte;
1445
1446 /* Image data may be constant, so we must copy it. */
1447 old_image_data = image->data;
1448 image->data = XtMalloc(nbytes);
1449
1450 for (byte = 0; byte < nbytes; byte++)
1451 image->data[byte] = ~old_image_data[byte];
1452 }
1453
1454 /* In this depth-1 case the image formats are equivalent. */
1455 image->format = XYBitmap;
1456 break;
1457
1458 case ZPixmap:
1459 /* Assume the application really wants BadMatch if (depth != 1). */
1460 break;
1461
1462 default:
1463 assert(FALSE);
1464 }
1465 }
1466
1467
1468 /*
1469 * Create a pixmap to hold the image, allocate a new pixmap
1470 * cache entry, put the cache entry in the tables.
1471 */
1472
1473 pix_entry = XtNew (PixmapData);
1474
1475 pix_entry->screen = screen;
1476 pix_entry->acc_color = XtNew(XmAccessColorDataRec);
1477 memcpy((void*)pix_entry->acc_color, (void*)acc_color,
1478 sizeof(XmAccessColorDataRec));
1479 pix_entry->depth = depth;
1480 pix_entry->image_name = XtNewString(image_name);
1481 pix_entry->print_shell = pix_data.print_shell;
1482 pix_entry->print_resolution = pix_data.print_resolution ;
1483 pix_entry->pixels = pixels;
1484 pix_entry->npixels = npixels;
1485
1486 /* use scaling_ratio for caching: as 0, in which case the
1487 print resolution will be used, or 1, no scaling, or a real ratio.
1488 That's because when we enter this function, we don't have
1489 pixmap_resolution to cache against, and also because
1490 print_resolution might change for the same print shell */
1491 pix_entry->scaling_ratio = scaling_ratio ;
1492
1493 /* use the pixmap scaling ratio for printing */
1494 pix_entry->width = image->width * pix_data.scaling_ratio ;
1495 pix_entry->height = image->height * pix_data.scaling_ratio ;
1496
1497 pixmap = XCreatePixmap (display, RootWindowOfScreen(screen),
1498 pix_entry->width,
1499 pix_entry->height,
1500 depth);
1501
1502 pix_entry->pixmap = pixmap;
1503 pix_entry->reference_count = 1;
1504
1505 /* put the new entry in both tables: the table used for
1506 this routine and the table used in XmeGetPixmapData */
1507 _XmProcessLock();
1508 _XmAddHashEntry(pixmap_set, (XmHashKey)pix_entry, (XtPointer)pix_entry);
1509 _XmAddHashEntry(pixmap_data_set, (XmHashKey)pix_entry,
1510 (XtPointer)pix_entry);
1511 _XmProcessUnlock();
1512
1513 /* Set up a gc for the image to pixmap copy, store the image */
1514 /* into the pixmap and return the pixmap. */
1515
1516 gc = GetGCForPutImage(screen, pix_entry->print_shell,
1517 image, pixmap, depth,
1518 acc_color->foreground,
1519 acc_color->background);
1520
1521 /* transfer and scale the image */
1522 _XmPutScaledImage (display, pixmap, gc, image,
1523 0, 0, 0, 0, image->width, image->height,
1524 pix_entry->width, pix_entry->height);
1525
1526 /* Destroy non-cached XImage now that we've cached the pixmap. */
1527 if (ret == NOT_CACHED)
1528 {
1529 XDestroyImage(image) ;
1530 if (old_image_data)
1531 XtFree(image->data);
1532 }
1533 else if (image->format != old_image_format)
1534 {
1535 /* Undo the XYPixmap to XYBitmap conversion done earlier. */
1536 image->format = old_image_format;
1537 assert(old_image_format == XYPixmap);
1538
1539 if (old_image_data)
1540 {
1541 XtFree(image->data);
1542 image->data = old_image_data;
1543 }
1544
1545 /* We're done mangling the image. */
1546 _XmProcessUnlock();
1547 }
1548
1549 return (pixmap);
1550 }
1551
1552
1553 /*******************************************************************
1554 *
1555 * _XmGetColoredPixmap
1556 * a improved version of XmGetPixmapByDepth that lets the caller
1557 * specify more color information usable during the loading
1558 * of the pixmap file to override symbolic colors.
1559 *
1560 * It also supports the negative depth convention where if a -depth
1561 * is given, xbm file give Bitmap and xpm file give Pixmap, while
1562 * with positive depth, all files give Pixmap result.
1563 *
1564 * Now a wrapper, but still used by IconG, MessageB, and Text directly.
1565 *
1566 *******************************************************************/
1567 Pixmap
_XmGetColoredPixmap(Screen * screen,char * image_name,XmAccessColorData acc_color,int depth,int only_if_exists)1568 _XmGetColoredPixmap(Screen *screen,
1569 char *image_name,
1570 XmAccessColorData acc_color,
1571 int depth,
1572 #if NeedWidePrototypes
1573 int only_if_exists)
1574 #else
1575 Boolean only_if_exists)
1576 #endif /* NeedWidePrototypes */
1577 {
1578 return _XmGetScaledPixmap (screen, NULL,
1579 image_name, acc_color, depth,
1580 only_if_exists, 1); /* no scaling */
1581 }
1582
1583 Pixmap
XmGetScaledPixmap(Widget widget,char * image_name,Pixel foreground,Pixel background,int depth,double scaling_ratio)1584 XmGetScaledPixmap(
1585 Widget widget,
1586 char *image_name,
1587 Pixel foreground,
1588 Pixel background,
1589 int depth,
1590 double scaling_ratio)
1591 {
1592 XmAccessColorDataRec acc_color_rec;
1593 Pixmap ret_val;
1594 XtAppContext app = XtWidgetToApplicationContext(widget);
1595
1596 _XmAppLock(app);
1597 _XmProcessLock();
1598 acc_color_rec.foreground = foreground ;
1599 acc_color_rec.background = background ;
1600 acc_color_rec.top_shadow_color = XmUNSPECIFIED_PIXEL ;
1601 acc_color_rec.bottom_shadow_color = XmUNSPECIFIED_PIXEL ;
1602 acc_color_rec.select_color = XmUNSPECIFIED_PIXEL ;
1603 acc_color_rec.highlight_color = XmUNSPECIFIED_PIXEL ;
1604 ret_val = _XmGetScaledPixmap(XtScreen(widget), widget, image_name,
1605 &acc_color_rec, depth, False,
1606 scaling_ratio);
1607 _XmProcessUnlock();
1608 _XmAppUnlock(app);
1609
1610 return ret_val;
1611
1612 }
1613
1614
1615 /*******************************************************************
1616 *
1617 * XmGetPixmapByDepth.
1618 * create a pixmap from the image_name. foreground and background
1619 * must be valid values. For depth 1 they should be 1 and 0
1620 * respectively.
1621 *
1622 *******************************************************************/
1623 Pixmap
XmGetPixmapByDepth(Screen * screen,char * image_name,Pixel foreground,Pixel background,int depth)1624 XmGetPixmapByDepth(
1625 Screen *screen,
1626 char *image_name,
1627 Pixel foreground,
1628 Pixel background,
1629 int depth)
1630 {
1631 XmAccessColorDataRec acc_color_rec;
1632 Pixmap ret_val;
1633 XtAppContext app = XtDisplayToApplicationContext(
1634 DisplayOfScreen(screen));
1635
1636 _XmAppLock(app);
1637 _XmProcessLock();
1638 acc_color_rec.foreground = foreground ;
1639 acc_color_rec.background = background ;
1640 acc_color_rec.top_shadow_color = XmUNSPECIFIED_PIXEL ;
1641 acc_color_rec.bottom_shadow_color = XmUNSPECIFIED_PIXEL ;
1642 acc_color_rec.select_color = XmUNSPECIFIED_PIXEL ;
1643 acc_color_rec.highlight_color = XmUNSPECIFIED_PIXEL ;
1644 ret_val = _XmGetScaledPixmap(screen, NULL, image_name,
1645 &acc_color_rec, depth, False,
1646 1);
1647 _XmProcessUnlock();
1648 _XmAppUnlock(app);
1649
1650 return ret_val;
1651 }
1652
1653
1654 /************************************************************************
1655 *
1656 * This one is deprecated, but keep it in here, it was public.
1657 *
1658 ************************************************************************/
1659
1660 Pixmap
XmGetPixmap(Screen * screen,char * image_name,Pixel foreground,Pixel background)1661 XmGetPixmap(
1662 Screen *screen,
1663 char *image_name,
1664 Pixel foreground,
1665 Pixel background )
1666 {
1667 Pixmap ret_val;
1668
1669 XtAppContext app = XtDisplayToApplicationContext(
1670 DisplayOfScreen(screen));
1671 _XmAppLock(app);
1672 ret_val = XmGetPixmapByDepth(screen, image_name, foreground, background,
1673 DefaultDepthOfScreen(screen));
1674 _XmAppUnlock(app);
1675
1676 return (ret_val);
1677 }
1678
1679
1680
1681 /************************************************************************
1682 *
1683 * XmeGetMask
1684 *
1685 ************************************************************************/
1686 Pixmap
XmeGetMask(Screen * screen,char * image_name)1687 XmeGetMask(
1688 Screen *screen,
1689 char *image_name)
1690 {
1691 char mask_name[256];
1692 Pixmap ret_val;
1693 XtAppContext app = XtDisplayToApplicationContext(
1694 DisplayOfScreen(screen));
1695
1696 _XmAppLock(app);
1697
1698 _XmProcessLock();
1699 _XmOSGenerateMaskName(image_name, mask_name);
1700 _XmProcessUnlock();
1701
1702 ret_val = XmGetPixmapByDepth(screen, mask_name, 1, 0, 1);
1703
1704 _XmAppUnlock(app);
1705 return ret_val;
1706 }
1707
1708
1709 /************************************************************************
1710 *
1711 * XmDestroyPixmap
1712 * Use the pixmap table (pixmap/screen) to find the pixmap,
1713 * then remove it from both pixmap and pixmap_data tables.
1714 *
1715 ************************************************************************/
1716 Boolean
XmDestroyPixmap(Screen * screen,Pixmap pixmap)1717 XmDestroyPixmap(
1718 Screen *screen,
1719 Pixmap pixmap )
1720 {
1721 PixmapData pix_data, *pix_entry ;
1722 XtAppContext app;
1723
1724 /* Check for invalid conditions */
1725
1726 if (screen == NULL || pixmap == 0 || pixmap_set == NULL)
1727 return (False);
1728
1729 app = XtDisplayToApplicationContext(
1730 DisplayOfScreen(screen));
1731
1732 _XmAppLock(app);
1733 _XmProcessLock();
1734
1735 pix_data.screen = screen ;
1736 pix_data.pixmap = pixmap ;
1737
1738 if ((pix_entry = (PixmapData*)
1739 _XmGetHashEntry(pixmap_set, (XmHashKey)&pix_data)) != NULL) {
1740 pix_entry->reference_count--;
1741 if (pix_entry->reference_count == 0) {
1742 _XmRemoveHashEntry (pixmap_data_set, pix_entry);
1743 _XmRemoveHashEntry (pixmap_set, pix_entry);
1744 if (0 != strcmp(pix_entry->image_name, DIRECT_PIXMAP_CACHED))
1745 XFreePixmap(DisplayOfScreen(pix_entry->screen), pix_entry->pixmap);
1746 XtFree(pix_entry->image_name);
1747 XtFree((char*)pix_entry->acc_color);
1748 if (pix_entry->pixels) {
1749 FreeCacheColors(DisplayOfScreen(pix_entry->screen),
1750 DefaultColormapOfScreen(pix_entry->screen),
1751 pix_entry->pixels, pix_entry->npixels, NULL);
1752 XmeXpmFree(pix_entry->pixels);
1753 }
1754 XtFree((char*)pix_entry);
1755 }
1756
1757 _XmProcessUnlock();
1758 _XmAppUnlock(app);
1759 return True;
1760 }
1761
1762 _XmProcessUnlock();
1763 _XmAppUnlock(app);
1764 return False;
1765 }
1766
1767
1768 /* Compare two gc entry. Only care about the colors for depth 1 */
1769 static Boolean
CompareGCDatas(XmHashKey key_1,XmHashKey key_2)1770 CompareGCDatas (XmHashKey key_1,
1771 XmHashKey key_2)
1772 {
1773 GCData *data_1 = (GCData *) key_1;
1774 GCData *data_2 = (GCData *) key_2;
1775
1776 return ((data_1->screen == data_2->screen) &&
1777 (data_1->print_shell == data_2->print_shell) &&
1778 (data_1->depth == data_2->depth) &&
1779 ((data_1->image_depth != 1) ||
1780 ((data_1->image_depth == 1) &&
1781 (data_1->foreground == data_2->foreground) &&
1782 (data_1->background == data_2->background)))) ;
1783 }
1784
1785 /* Hash a GC entry. Only care about the colors for depth 1 */
1786 static XmHashValue
HashGCData(XmHashKey key)1787 HashGCData (XmHashKey key)
1788 {
1789 GCData *data = (GCData *) key;
1790 XmHashValue hv = 0 ;
1791
1792 if (data->image_depth == 1)
1793 hv = data->foreground + data->background ;
1794
1795 return (hv + (long)data->screen + (long)data->print_shell +
1796 data->depth + data->image_depth);
1797 }
1798
1799 /***
1800 * GetGCForPutImage
1801 * Maintain a cache of GC to use for transfering the XImage to
1802 * a Pixmap depending on the screen, depth, colors.
1803 ***/
1804 static GC
GetGCForPutImage(Screen * screen,Widget print_shell,XImage * image,Pixmap pixmap,int depth,Pixel foreground,Pixel background)1805 GetGCForPutImage(Screen *screen,
1806 Widget print_shell,
1807 XImage * image,
1808 Pixmap pixmap,
1809 int depth,
1810 Pixel foreground,
1811 Pixel background)
1812 {
1813 XGCValues gcValues;
1814 GCData gc_data, *gc_entry ;
1815
1816 /* There is a problem here: we cannot simply use the xmScreen object
1817 * to store the GCs, for the pixmap conversion can be called
1818 * at a time the xmScreen is not yet available: a conversion
1819 * for the first VendorShell on this screen, or a conversion for
1820 * the xmScreen or xmDisplay.
1821 * We can either arrange for delaying the conversion for those cases,
1822 * or not use the xmScreen here. Since we need to cache per depth
1823 * in addition to per screen, and since the Xt routine cannot be used
1824 * since there is no widget available, let's forget about using the
1825 * xmScreen object, do our own specialized caching.
1826 */
1827
1828 /* There shouldn't be a lot of different GCs, one for
1829 * depth 1 to depth 1, foreground 1, back 0, one for
1830 * depth N to N, fore/back don't matter and some for depth 1 to
1831 * depth N, where colors matter, for backgroundPixmap resources
1832 * and regular use
1833 * of XmGetPixmapByDepth (with no -depth) issued from XBM file.
1834 */
1835
1836 _XmProcessLock();
1837 if (gc_set == NULL)
1838 gc_set = _XmAllocHashTable (20, CompareGCDatas, HashGCData);
1839 _XmProcessUnlock();
1840
1841 /* set up an entry for search. We only care about the colors
1842 for image_depth 1 to pixmap depth (N or 1), since otherwise, N to N,
1843 the transfer is a plain copy */
1844 gc_data.screen = screen ;
1845 gc_data.print_shell = print_shell ;
1846 gc_data.depth = depth ;
1847 gc_data.image_depth = image->depth ;
1848 gc_data.foreground = foreground ;
1849 gc_data.background = background ;
1850
1851 /* look if we have a match and return it */
1852 _XmProcessLock();
1853 if ((gc_entry = (GCData*)
1854 _XmGetHashEntry(gc_set, (XmHashKey)&gc_data)) != NULL) {
1855 _XmProcessUnlock();
1856 return gc_entry->gc ;
1857 }
1858 _XmProcessUnlock();
1859
1860 /* create a new GC, cache it and return it */
1861 gc_entry = XtNew(GCData);
1862 gc_entry->screen = screen ;
1863 gc_entry->print_shell = print_shell ;
1864 gc_entry->depth = depth ;
1865 gc_entry->image_depth = image->depth ;
1866 gc_entry->foreground = foreground ;
1867 gc_entry->background = background ;
1868 _XmProcessLock();
1869 _XmAddHashEntry(gc_set, (XmHashKey)gc_entry, (XtPointer)gc_entry);
1870 _XmProcessUnlock();
1871
1872 gcValues.foreground = foreground;
1873 gcValues.background = background;
1874 gc_entry->gc = XCreateGC (DisplayOfScreen(screen), pixmap,
1875 GCForeground | GCBackground, &gcValues);
1876
1877 return gc_entry->gc ;
1878 }
1879
1880
1881 /************
1882 When a Screen is closed, or a PrintShell, we need to clean up the
1883 respective cache .
1884 *****/
1885
1886
1887 static Boolean
CleanGCMapProc(XmHashKey key,XtPointer value,XtPointer data)1888 CleanGCMapProc (XmHashKey key, /* unused */
1889 XtPointer value,
1890 XtPointer data)
1891 {
1892 GCData *entry = (GCData *) value;
1893 CleanKey * ck = (CleanKey*) data ;
1894
1895 /* shell should be NULL for non printing screen */
1896 if (entry->print_shell == ck->shell &&
1897 entry->screen == ck->screen)
1898 {
1899 _XmProcessLock();
1900 _XmRemoveHashEntry (gc_set, entry);
1901 _XmProcessUnlock();
1902 XFreeGC(DisplayOfScreen(entry->screen), entry->gc);
1903 XtFree((char*) entry);
1904 }
1905
1906 /* never return True: remove all gc keyed on this print shell */
1907 return False;
1908 }
1909
1910 static Boolean
CleanPixmapMapProc(XmHashKey key,XtPointer value,XtPointer data)1911 CleanPixmapMapProc (XmHashKey key, /* unused */
1912 XtPointer value,
1913 XtPointer data)
1914 {
1915 PixmapData *entry = (PixmapData *) value;
1916 CleanKey * ck = (CleanKey*) data ;
1917
1918 /* shell should be NULL for non printing screen */
1919 if (entry->print_shell == ck->shell &&
1920 entry->screen == ck->screen)
1921 {
1922 /* this should take care of everything */
1923 XmDestroyPixmap(entry->screen, entry->pixmap);
1924 }
1925
1926 /* never return True: remove all pixmap keyed on this print shell */
1927 return False;
1928 }
1929
1930 #ifdef XP_DEBUG
1931 static Boolean
PrintPixmapMapProc(XmHashKey key,XtPointer value,XtPointer data)1932 PrintPixmapMapProc (XmHashKey key, /* unused */
1933 XtPointer value,
1934 XtPointer data)
1935 {
1936 PixmapData *entry = (PixmapData *) value;
1937 CleanKey * ck = (CleanKey*) data ;
1938
1939 printf("entry->screen %d\n", entry->screen);
1940 printf("entry->print_shell %d\n", entry->print_shell);
1941 printf("entry->image_name %s\n", entry->image_name);
1942 printf("entry->pixmap %d\n\n", entry->pixmap);
1943
1944 return False;
1945 }
1946
1947 static Boolean
PrintGCMapProc(XmHashKey key,XtPointer value,XtPointer data)1948 PrintGCMapProc (XmHashKey key, /* unused */
1949 XtPointer value,
1950 XtPointer data)
1951 {
1952 GCData *entry = (GCData *) value;
1953 CleanKey * ck = (CleanKey*) data ;
1954
1955 printf("entry->screen %d\n", entry->screen);
1956 printf("entry->print_shell %d\n", entry->print_shell);
1957 printf("entry->gc %d\n\n", entry->gc);
1958
1959 return False;
1960 }
1961 #endif
1962 /******
1963 This is called from PrintShell.Destroy to invalidate the
1964 GCs and Pixmap used for a given print shell and from Screen.destroy,
1965 with a NULL shell, to remove the GCs and Pixmap used for a
1966 given screen. So in the case of PrintShell, this is call twice
1967 in a row, where the second time (from Screen) takes care of
1968 the Screen (non print shell) specific pixmaps abd GCs.
1969 *******/
1970 void
_XmCleanPixmapCache(Screen * screen,Widget shell)1971 _XmCleanPixmapCache(Screen * screen, Widget shell)
1972 {
1973 CleanKey ck ;
1974
1975 ck.screen = screen;
1976 ck.shell = shell ;
1977
1978 _XmMapHashTable(gc_set, CleanGCMapProc, &ck);
1979 _XmMapHashTable(pixmap_set, CleanPixmapMapProc, &ck);
1980 }
1981
1982
1983
1984
1985 /************************************************************************
1986 *******************************************************************------
1987
1988 Design notes:
1989
1990 There is really two different caches here, an XImage cache and
1991 a Pixmap cache (+ a GC cache).
1992
1993 The XImage cache is name based (hash key is image_name). No colors are
1994 supported, and therefore, it is only useful with depth 1 XImage.
1995
1996 Program can directly install non-depth 1 XImage in this cache using
1997 the public API (XmInstallImage), but that's not advised, for the
1998 non-depth 1 XImage resulting from XPM file have color variations
1999 for the same image_name. If you ask for image_name Foo, foreground
2000 red and background blue, and a Foo has been installed in the image
2001 cache using different foreground & background, you don't want
2002 to get back this Foo, but a new instance of Foo, one that uses
2003 the red and blue colors.
2004
2005 Also, the only access to the XImage reader (GetImage) is via the pixmap
2006 API, so if a XPM with no colors sensitivity (no pertinent Motif
2007 symbolic colors) is read once, it will be found by the
2008 pixmap cache first, no need to cache it in the image cache.
2009
2010 The Pixmap cache is name/depth/colors or pixmap based, depending
2011 which API is looking up.
2012 The old XmGetPixmapByDepth() is equivalent to asking for
2013 valid foreground/background and unspecified others, which
2014 means these additional colors (shadows, select) will not be
2015 used during Xpm reading for overriding symbolic colors.
2016
2017 Motifnext adds printing support and clean cache support.
2018
2019 ***/
2020
2021
2022 #define roundint(x) MAX(1, (int)((x) + 0.5))
2023
2024 typedef struct {
2025 Position *x, *y;
2026 Dimension *width, *height;
2027 } Table;
2028
_XmPutScaledImage(Display * display,Drawable d,GC gc,XImage * src_image,int src_x,int src_y,int dest_x,int dest_y,unsigned int src_width,unsigned int src_height,unsigned int dest_width,unsigned int dest_height)2029 void _XmPutScaledImage (
2030 Display* display,
2031 Drawable d,
2032 GC gc,
2033 XImage* src_image,
2034 int src_x,
2035 int src_y,
2036 int dest_x,
2037 int dest_y,
2038 unsigned int src_width,
2039 unsigned int src_height,
2040 unsigned int dest_width,
2041 unsigned int dest_height)
2042 {
2043 XImage *dest_image;
2044 Position x, y, min_y, max_y, src_max_x;
2045 Dimension w, h, strip_height;
2046 Table table;
2047 Pixel pixel;
2048 double ratio_x, ratio_y;
2049 Bool fast8;
2050 int xp_event, xp_error;
2051
2052 if (dest_width == src_width && dest_height == src_height) {
2053 /* same for x and y, just send it out */
2054 XPutImage(display, d, gc, src_image, src_x, src_y,
2055 dest_x, dest_y, dest_width, dest_height);
2056 return;
2057 }
2058
2059 ratio_x = (double)dest_width / (double)src_width;
2060 ratio_y = (double)dest_height / (double)src_height;
2061
2062 #ifdef PRINTING_SUPPORTED
2063 /*
2064 * Check that we have uniform scaling, and that the print extension
2065 * exists. We can't call XpGetContext first, because if the print
2066 * extension doesn't exist we'll get a warning to stderr.
2067 * It would be better if the print context was passed in directly, so
2068 * that we didn't spend a round trip when scaling for the video screen,
2069 * but it's just one round trip on just the first call per display, so
2070 * it's not that bad.
2071 */
2072 h = (double)src_height * ratio_x + 0.5;
2073 if (dest_height <= h + 1 && h <= dest_height + 1 &&
2074 XpQueryExtension(display, &xp_event, &xp_error)) {
2075 /*
2076 * We could be clever and try to get the print context first from
2077 * the _XmPrintScreenToShellContext and then get the resolution from
2078 * the print shell, but we don't have a Screen* to do the lookup.
2079 */
2080 XPContext pcontext = XpGetContext(display);
2081 if (pcontext) {
2082 int media_res;
2083 media_res = atoi(XpGetOneAttribute(display, pcontext, XPDocAttr,
2084 "default-printer-resolution"));
2085 if (media_res) {
2086 int image_res = (double)media_res / ratio_x + 0.5;
2087 int prev_res;
2088 if (XpSetImageResolution(display, pcontext,
2089 image_res, &prev_res)) {
2090 XPutImage(display, d, gc, src_image, src_x, src_y,
2091 dest_x, dest_y, src_width, src_height);
2092 XpSetImageResolution(display, pcontext, prev_res, NULL);
2093 return;
2094 }
2095 }
2096 }
2097 }
2098 #endif /* PRINTING_SUPPORTED */
2099
2100 src_max_x = src_x + src_width;
2101
2102 strip_height = 65536 / roundint(ratio_x * src_image->bytes_per_line);
2103 if (strip_height == 0)
2104 strip_height = 1;
2105 if (strip_height > dest_height)
2106 strip_height = dest_height;
2107
2108 h = strip_height + roundint(ratio_y);
2109 dest_image = XCreateImage(display,
2110 DefaultVisualOfScreen(
2111 DefaultScreenOfDisplay(display)),
2112 src_image->depth, src_image->format,
2113 0, NULL,
2114 dest_width, h,
2115 src_image->bitmap_pad, 0);
2116 dest_image->data = XtMalloc(dest_image->bytes_per_line * h);
2117 fast8 = (src_image->depth == 8 && src_image->bits_per_pixel == 8 &&
2118 dest_image->bits_per_pixel == 8 && src_image->format == ZPixmap);
2119
2120 table.x = (Position *) XtMalloc(sizeof(Position) * (src_image->width + 1));
2121 table.y = (Position *) XtMalloc(sizeof(Position) * (src_image->height + 1));
2122 table.width = (Dimension *) XtMalloc(sizeof(Dimension) * src_image->width);
2123 table.height = (Dimension *) XtMalloc(sizeof(Dimension)*src_image->height);
2124
2125 table.x[0] = 0;
2126 for (x = 1; x <= src_image->width; x++) {
2127 table.x[x] = roundint(ratio_x * x);
2128 table.width[x - 1] = table.x[x] - table.x[x - 1];
2129 }
2130
2131 table.y[0] = 0;
2132 for (y = 1; y <= src_image->height; y++) {
2133 table.y[y] = roundint(ratio_y * y);
2134 table.height[y - 1] = table.y[y] - table.y[y - 1];
2135 }
2136
2137 for (min_y = table.y[src_y]; min_y < dest_height; min_y = table.y[y]) {
2138 max_y = min_y + strip_height;
2139 if (max_y > dest_height) {
2140 strip_height = dest_height - min_y;
2141 max_y = dest_height;
2142 }
2143 for (y = src_y; table.y[y] < max_y; y++) {
2144 if (table.y[y] < min_y)
2145 continue;
2146 if (fast8) {
2147 for (x = src_x; x < src_max_x; x++) {
2148 pixel = ((unsigned char *)src_image->data)
2149 [y * src_image->bytes_per_line + x];
2150 for (h = 0; h < table.height[y]; h++) {
2151 memset(dest_image->data +
2152 (table.y[y] + h - min_y) *
2153 dest_image->bytes_per_line + table.x[x],
2154 pixel, table.width[x]);
2155 }
2156 }
2157 } else {
2158 for (x = src_x; x < src_max_x; x++) {
2159 pixel = XGetPixel(src_image, x, y);
2160 for (h = 0; h < table.height[y]; h++) {
2161 for (w = 0; w < table.width[x]; w++)
2162 XPutPixel(dest_image,
2163 table.x[x] + w,
2164 table.y[y] + h - min_y,
2165 pixel);
2166 }
2167 }
2168 }
2169 }
2170 XPutImage(display, d, gc, dest_image, dest_x, 0,
2171 dest_x, dest_y + min_y, dest_width, table.y[y] - min_y);
2172 if (y >= src_image->height)
2173 break;
2174 }
2175
2176 XtFree((char *)table.x);
2177 XtFree((char *)table.y);
2178 XtFree((char *)table.width);
2179 XtFree((char *)table.height);
2180
2181 XDestroyImage(dest_image);
2182 }
2183
2184
2185
2186 /*** COLOR CACHE NOW ***/
2187
2188
2189 static Boolean
GetCacheColorByName(Display * display,Colormap colormap,char * colorname,XColor * xcolor)2190 GetCacheColorByName( Display *display, Colormap colormap,
2191 char *colorname, XColor *xcolor)
2192 {
2193 static Boolean firstTime = True;
2194 XrmQuark colorname_q;
2195 int i;
2196 CachedColor *color;
2197
2198 if (!colorname)
2199 return False;
2200
2201 if ( firstTime )
2202 {
2203 colorCacheList.numEntries = colorCacheList.maxEntries = 0;
2204 colorCacheList.cache = NULL;
2205 firstTime = False;
2206 return False;
2207 }
2208
2209 colorname_q = XrmStringToQuark(colorname);
2210
2211 for (i = 0, color = colorCacheList.cache; i < colorCacheList.numEntries;
2212 i++, color++)
2213 {
2214 if (color->colorname == colorname_q &&
2215 color->colormap == colormap &&
2216 color->display == display)
2217 {
2218 xcolor->pixel = color->pixel;
2219 color->num_cached++;
2220 return True;
2221 }
2222 }
2223 return False;
2224 }
2225
2226 static Boolean
GetCacheColorByRGB(Display * display,Colormap colormap,XColor * xcolor)2227 GetCacheColorByRGB( Display *display, Colormap colormap, XColor *xcolor)
2228 {
2229 int i;
2230 CachedColor *color;
2231
2232 for (i = 0, color = colorCacheList.cache; i < colorCacheList.numEntries;
2233 i++, color++)
2234 {
2235 if (color->colormap == colormap && color->display == display &&
2236 color->red == xcolor->red &&
2237 color->green == xcolor->green &&
2238 color->blue == xcolor->blue)
2239 {
2240 xcolor->pixel = color->pixel;
2241 color->num_cached++;
2242 return True;
2243 }
2244 }
2245 return False;
2246 }
2247
2248 static Boolean
FreeCacheColor(Display * display,Colormap colormap,Pixel pixel)2249 FreeCacheColor( Display *display, Colormap colormap, Pixel pixel)
2250 {
2251 int i;
2252 CachedColor *color;
2253
2254 for (i = 0, color = colorCacheList.cache; i < colorCacheList.numEntries;
2255 i++, color++)
2256 {
2257 if (color->colormap == colormap && color->display == display &&
2258 color->pixel == pixel)
2259 {
2260 color->num_cached--;
2261 if (color->num_cached == 0) {
2262 int j;
2263 for (j = i + 1; j < colorCacheList.numEntries; i++, j++)
2264 colorCacheList.cache[i] = colorCacheList.cache[j];
2265 colorCacheList.numEntries--;
2266 XFreeColors(display, colormap, &pixel, 1, 0);
2267 return True;
2268 }
2269 }
2270 }
2271 return False;
2272 }
2273
2274 static void
CacheColorPixel(Display * display,Colormap colormap,char * colorname,XColor * xcolor)2275 CacheColorPixel( Display *display, Colormap colormap,
2276 char *colorname, XColor *xcolor)
2277 {
2278 int numEntries = colorCacheList.numEntries;
2279
2280 if (numEntries == colorCacheList.maxEntries)
2281 {
2282 colorCacheList.maxEntries += 25;
2283 colorCacheList.cache = (CachedColor *)
2284 XtRealloc((char *)colorCacheList.cache,
2285 colorCacheList.maxEntries *
2286 sizeof(CachedColor));
2287 }
2288
2289 colorCacheList.cache[numEntries].display = display;
2290 colorCacheList.cache[numEntries].colormap = colormap;
2291 colorCacheList.cache[numEntries].colorname =
2292 colorname ? XrmStringToQuark(colorname) : NULLQUARK;
2293
2294 colorCacheList.cache[numEntries].red = xcolor->red;
2295 colorCacheList.cache[numEntries].green = xcolor->green;
2296 colorCacheList.cache[numEntries].blue = xcolor->blue;
2297 colorCacheList.cache[numEntries].pixel = xcolor->pixel;
2298 colorCacheList.cache[numEntries].num_cached = 1;
2299
2300 colorCacheList.numEntries++;
2301 }
2302
2303
2304 static int
GetCacheColor(Display * display,Colormap colormap,char * colorname,XColor * xcolor,void * closure)2305 GetCacheColor(Display *display, Colormap colormap,
2306 char *colorname, XColor *xcolor, void *closure)
2307 {
2308 int status;
2309 if (colorname) {
2310 /* look for the colorname in the cache */
2311 if (!GetCacheColorByName(display, colormap, colorname, xcolor)) {
2312 /* when not found parse and alloc color */
2313 if (!XParseColor(display, colormap, colorname, xcolor))
2314 return -1;
2315 if (!GetCacheColorByRGB(display, colormap, xcolor)) {
2316 status = XAllocColor(display, colormap, xcolor);
2317 if (status) /* if allocation succeeded, store color */
2318 CacheColorPixel(display, colormap, colorname, xcolor);
2319 } else
2320 status = 1;
2321 } else
2322 status = 1;
2323 } else {
2324 if (!GetCacheColorByRGB(display, colormap, xcolor)) {
2325 status = XAllocColor(display, colormap, xcolor);
2326 if (status) /* if allocation succeeded, store color */
2327 CacheColorPixel(display, colormap, colorname, xcolor);
2328 } else
2329 status = 1;
2330 }
2331
2332 return status != 0 ? 1 : 0;
2333 }
2334
2335 static int
FreeCacheColors(Display * display,Colormap colormap,Pixel * pixels,int n,void * closure)2336 FreeCacheColors(Display *display, Colormap colormap,
2337 Pixel *pixels, int n, void *closure)
2338 {
2339 int i, status;
2340 for (i = 0; i < n; i++, pixels++)
2341 status = FreeCacheColor(display, colormap, *pixels);
2342 return 0;
2343 }
2344