1 /**
2  * @file render.c
3  * @author Joe Wingbermuehle
4  * @date 2005-2006
5  *
6  * @brief Functions to render icons using the XRender extension.
7  *
8  */
9 
10 #include "jwm.h"
11 #include "render.h"
12 #include "icon.h"
13 #include "image.h"
14 #include "main.h"
15 #include "color.h"
16 #include "misc.h"
17 
18 /** Draw a scaled icon. */
PutScaledRenderIcon(const IconNode * icon,const ScaledIconNode * node,Drawable d,int x,int y,int width,int height)19 void PutScaledRenderIcon(const IconNode *icon,
20                          const ScaledIconNode *node,
21                          Drawable d, int x, int y, int width, int height)
22 {
23 
24 #ifdef USE_XRENDER
25 
26    Picture source;
27 
28    Assert(icon);
29    Assert(haveRender);
30 
31    source = node->image;
32    if(source != None) {
33 
34       XRenderPictureAttributes pa;
35       XTransform xf;
36       int xscale, yscale;
37       int nwidth, nheight;
38       Picture dest;
39       Picture alpha = node->mask;
40       XRenderPictFormat *fp = JXRenderFindVisualFormat(display, rootVisual);
41       Assert(fp);
42 
43       pa.subwindow_mode = IncludeInferiors;
44       dest = JXRenderCreatePicture(display, d, fp, CPSubwindowMode, &pa);
45 
46       width = width == 0 ? node->width : width;
47       height = height == 0 ? node->height : height;
48       if(icon->preserveAspect) {
49          const int ratio = (icon->width << 16) / icon->height;
50          nwidth = Min(width, (height * ratio) >> 16);
51          nheight = Min(height, (nwidth << 16) / ratio);
52          nwidth = (nheight * ratio) >> 16;
53          nwidth = Max(1, nwidth);
54          nheight = Max(1, nheight);
55          x += (width - nwidth) / 2;
56          y += (height - nheight) / 2;
57       } else {
58          nwidth = width;
59          nheight = height;
60       }
61       xscale = (node->width << 16) / nwidth;
62       yscale = (node->height << 16) / nheight;
63 
64       memset(&xf, 0, sizeof(xf));
65       xf.matrix[0][0] = xscale;
66       xf.matrix[1][1] = yscale;
67       xf.matrix[2][2] = 65536;
68       XRenderSetPictureTransform(display, source, &xf);
69       XRenderSetPictureFilter(display, source, FilterBest, NULL, 0);
70       XRenderSetPictureTransform(display, alpha, &xf);
71       XRenderSetPictureFilter(display, alpha, FilterBest, NULL, 0);
72 
73       JXRenderComposite(display, PictOpOver, source, alpha, dest,
74                         0, 0, 0, 0, x, y, width, height);
75 
76       JXRenderFreePicture(display, dest);
77 
78    }
79 
80 #endif
81 
82 }
83 
84 /** Create a scaled icon. */
CreateScaledRenderIcon(ImageNode * image,long fg)85 ScaledIconNode *CreateScaledRenderIcon(ImageNode *image, long fg)
86 {
87 
88    ScaledIconNode *result = NULL;
89 
90 #ifdef USE_XRENDER
91 
92    XRenderPictFormat *fp;
93    XColor color;
94    GC maskGC;
95    XImage *destImage;
96    XImage *destMask;
97    Pixmap pmap, mask;
98    const unsigned width = image->width;
99    const unsigned height = image->height;
100    unsigned perLine;
101    int x, y;
102    int maskLine;
103 
104    Assert(haveRender);
105 
106    result = Allocate(sizeof(ScaledIconNode));
107    result->fg = fg;
108    result->width = width;
109    result->height = height;
110 
111    mask = JXCreatePixmap(display, rootWindow, width, height, 8);
112    maskGC = JXCreateGC(display, mask, 0, NULL);
113    pmap = JXCreatePixmap(display, rootWindow, width, height, rootDepth);
114 
115    destImage = JXCreateImage(display, rootVisual, rootDepth,
116                              ZPixmap, 0, NULL, width, height, 8, 0);
117    destImage->data = Allocate(sizeof(unsigned long) * width * height);
118 
119    destMask = JXCreateImage(display, rootVisual, 8, ZPixmap,
120                             0, NULL, width, height, 8, 0);
121    destMask->data = Allocate(width * height);
122 
123    if(image->bitmap) {
124       perLine = (image->width >> 3) + ((image->width & 7) ? 1 : 0);
125    } else {
126       perLine = image->width;
127    }
128    maskLine = 0;
129    for(y = 0; y < height; y++) {
130       const int yindex = y * perLine;
131       for(x = 0; x < width; x++) {
132          if(image->bitmap) {
133 
134             const int offset = yindex + (x >> 3);
135             const int mask = 1 << (x & 7);
136             unsigned long alpha = 0;
137             if(image->data[offset] & mask) {
138                alpha = 255;
139                XPutPixel(destImage, x, y, fg);
140             }
141             destMask->data[maskLine + x] = alpha;
142 
143          } else {
144 
145             const int index = 4 * (yindex + x);
146             const unsigned long alpha = image->data[index];
147             color.red = image->data[index + 1];
148             color.red |= color.red << 8;
149             color.green = image->data[index + 2];
150             color.green |= color.green << 8;
151             color.blue = image->data[index + 3];
152             color.blue |= color.blue << 8;
153 
154             color.red = (color.red * alpha) >> 8;
155             color.green = (color.green * alpha) >> 8;
156             color.blue = (color.blue * alpha) >> 8;
157 
158             GetColor(&color);
159             XPutPixel(destImage, x, y, color.pixel);
160             destMask->data[maskLine + x] = alpha;
161          }
162       }
163       maskLine += destMask->bytes_per_line;
164    }
165 
166    /* Render the image data to the image pixmap. */
167    JXPutImage(display, pmap, rootGC, destImage, 0, 0, 0, 0, width, height);
168    Release(destImage->data);
169    destImage->data = NULL;
170    JXDestroyImage(destImage);
171 
172    /* Render the alpha data to the mask pixmap. */
173    JXPutImage(display, mask, maskGC, destMask, 0, 0, 0, 0, width, height);
174    Release(destMask->data);
175    destMask->data = NULL;
176    JXDestroyImage(destMask);
177    JXFreeGC(display, maskGC);
178 
179    /* Create the alpha picture. */
180    fp = JXRenderFindStandardFormat(display, PictStandardA8);
181    Assert(fp);
182    result->mask = JXRenderCreatePicture(display, mask, fp, 0, NULL);
183    JXFreePixmap(display, mask);
184 
185    /* Create the render picture. */
186    fp = JXRenderFindVisualFormat(display, rootVisual);
187    Assert(fp);
188    result->image = JXRenderCreatePicture(display, pmap, fp, 0, NULL);
189    JXFreePixmap(display, pmap);
190 
191 #endif
192 
193    return result;
194 
195 }
196