Allow PasteCanvas layers with unset canvas parameters to be exported.
[synfig.git] / synfig-osx / trunk / launcher / rootless-picture.c
1 /*
2  * Support for RENDER extension with rootless
3  */
4 /*
5  * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved.
6  * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21  * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  *
26  * Except as contained in this notice, the name(s) of the above copyright
27  * holders shall not be used in advertising or otherwise to promote the sale,
28  * use or other dealings in this Software without prior written authorization.
29  */
30 /* This file is largely based on fbcompose.c and fbpict.c, which contain
31  * the following copyright:
32  *
33  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
34  */
35  /* $XFree86: xc/programs/Xserver/hw/darwin/quartz/aquaPicture.c,v 1.3 2002/09/28 00:00:03 torrey Exp $ */
36
37 #define DEFAULT_LOG_FORMATS 0
38
39 #ifdef RENDER
40
41 #include "fb.h"
42 #include "picturestr.h"
43 #include "mipict.h"
44 #include "fbpict.h"
45 #include "rootless.h"
46
47 # define mod(a,b)       ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
48
49
50 // Replacement for fbStore_x8r8g8b8 that sets the alpha channel
51 void
52 RootlessStore_x8r8g8b8 (FbCompositeOperand *op, CARD32 value)
53 {
54     FbBits  *line = op->u.drawable.line; CARD32 offset = op->u.drawable.offset;
55     ((CARD32 *)line)[offset >> 5] = (value & 0xffffff) | 0xff000000;
56 }
57
58
59 // Defined in fbcompose.c
60 extern FbCombineFunc fbCombineFuncU[];
61 extern FbCombineFunc fbCombineFuncC[];
62
63 void
64 RootlessCompositeGeneral(
65     CARD8               op,
66     PicturePtr          pSrc,
67     PicturePtr          pMask,
68     PicturePtr          pDst,
69     INT16               xSrc,
70     INT16               ySrc,
71     INT16               xMask,
72     INT16               yMask,
73     INT16               xDst,
74     INT16               yDst,
75     CARD16              width,
76     CARD16              height)
77 {
78     FbCompositeOperand  src[4],msk[4],dst[4],*pmsk;
79     FbCompositeOperand  *srcPict, *srcAlpha;
80     FbCompositeOperand  *dstPict, *dstAlpha;
81     FbCompositeOperand  *mskPict = 0, *mskAlpha = 0;
82     FbCombineFunc       f;
83     int                 w;
84
85     if (!fbBuildCompositeOperand (pSrc, src, xSrc, ySrc, TRUE, TRUE))
86         return;
87     if (!fbBuildCompositeOperand (pDst, dst, xDst, yDst, FALSE, TRUE))
88         return;
89
90     // Use Rootless operands for on screen picture formats
91     if (pDst->format == PICT_x8r8g8b8) {
92         dst[0].store = RootlessStore_x8r8g8b8;
93     }
94
95     if (pSrc->alphaMap)
96     {
97         srcPict = &src[1];
98         srcAlpha = &src[2];
99     }
100     else
101     {
102         srcPict = &src[0];
103         srcAlpha = 0;
104     }
105     if (pDst->alphaMap)
106     {
107         dstPict = &dst[1];
108         dstAlpha = &dst[2];
109     }
110     else
111     {
112         dstPict = &dst[0];
113         dstAlpha = 0;
114     }
115     f = fbCombineFuncU[op];
116     if (pMask)
117     {
118         if (!fbBuildCompositeOperand (pMask, msk, xMask, yMask, TRUE, TRUE))
119             return;
120         pmsk = msk;
121         if (pMask->componentAlpha)
122             f = fbCombineFuncC[op];
123         if (pMask->alphaMap)
124         {
125             mskPict = &msk[1];
126             mskAlpha = &msk[2];
127         }
128         else
129         {
130             mskPict = &msk[0];
131             mskAlpha = 0;
132         }
133     }
134     else
135         pmsk = 0;
136     while (height--)
137     {
138         w = width;
139         
140         while (w--)
141         {
142             (*f) (src, pmsk, dst);
143             (*src->over) (src);
144             (*dst->over) (dst);
145             if (pmsk)
146                 (*pmsk->over) (pmsk);
147         }
148         (*src->down) (src);
149         (*dst->down) (dst);
150         if (pmsk)
151             (*pmsk->down) (pmsk);
152     }
153 }
154
155 static int rootless_log_pict_formats = DEFAULT_LOG_FORMATS;
156
157 static const char *op_name (int op)
158 {
159     static const char *ops[] = {
160         "Clear", "Src", "Dst", "Over", "OverReverse", "In", "InReverse",
161         "Out", "OutReverse", "Atop", "AtopReverse", "Xor", "Add",
162         "Saturate", "Maximum",
163
164         "DisjointClear", "DisjointSrc", "DisjointDst", "DisjointOver",
165         "DisjointOverReverse", "DisjointIn", "DisjointInReverse",
166         "DisjointOut", "DisjointOutReverse", "DisjointAtop",
167         "DisjointAtopReverse", "DisjointXor", "DisjointMaximum",
168
169         "ConjointClear", "ConjointSrc", "ConjointDst", "ConjointOver",
170         "ConjointOverReverse", "ConjointIn", "ConjointInReverse",
171         "ConjointOut", "ConjointOutReverse", "ConjointAtop",
172         "ConjointAtopReverse", "ConjointXor", "ConjointMaximum",
173     };
174
175     if (op >= 0 && op < (int) (sizeof (ops) / sizeof (ops[0])))
176         return ops[op];
177     else
178         return "Unknown";
179 }
180
181 static const char *type_name (int type)
182 {
183     switch (type)
184     {
185     case PICT_TYPE_OTHER:
186         return "Other";
187     case PICT_TYPE_A:
188         return "A";
189     case PICT_TYPE_ARGB:
190         return "ARGB";
191     case PICT_TYPE_ABGR:
192         return "ABGR";
193     case PICT_TYPE_COLOR:
194         return "Color";
195     case PICT_TYPE_GRAY:
196         return "Gray";
197     default:
198         return "Unknown";
199     }
200 }
201
202 static void log_format (int op, unsigned int src,
203                         unsigned int dst, unsigned int mask)
204 {
205     struct op {
206         int op;
207         unsigned int src, dst, mask;
208     };
209
210     static struct op *ops;
211     static int n_ops, allocated_ops;
212
213     int i;
214
215     for (i = 0; i < n_ops; i++)
216     {
217         if (ops[i].op == op && ops[i].src == src
218             && ops[i].dst == dst && ops[i].mask == mask)
219         {
220             return;
221         }
222     }
223
224     if (n_ops == allocated_ops)
225     {
226         allocated_ops *= 2;
227         ops = realloc (ops, allocated_ops * sizeof (struct op));
228     }
229
230     ops[n_ops].op = op;
231     ops[n_ops].src = src;
232     ops[n_ops].dst = dst;
233     ops[n_ops].mask = mask;
234     n_ops++;
235
236     fprintf (stderr,
237              "op: %s src (%dbpp %s %04x) dst (%dbpp %s %04x) mask (%dbpp %s %04x)\n",
238              op_name (op), PICT_FORMAT_BPP (src),
239              type_name (PICT_FORMAT_TYPE (src)),
240              src & 0xffff, PICT_FORMAT_BPP (dst),
241              type_name (PICT_FORMAT_TYPE (dst)),
242              dst & 0xffff, PICT_FORMAT_BPP (mask),
243              type_name (PICT_FORMAT_TYPE (mask)),
244              mask & 0xffff);
245 }
246
247 void
248 RootlessComposite(
249     CARD8           op,
250     PicturePtr      pSrc,
251     PicturePtr      pMask,
252     PicturePtr      pDst,
253     INT16           xSrc,
254     INT16           ySrc,
255     INT16           xMask,
256     INT16           yMask,
257     INT16           xDst,
258     INT16           yDst,
259     CARD16          width,
260     CARD16          height)
261 {
262     RegionRec       region;
263     int             n;
264     BoxPtr          pbox;
265     CompositeFunc   func;
266     Bool            srcRepeat = pSrc->repeat;
267     Bool            maskRepeat = FALSE;
268     Bool            srcAlphaMap = pSrc->alphaMap != 0;
269     Bool            maskAlphaMap = FALSE;
270     Bool            dstAlphaMap = pDst->alphaMap != 0;
271     int             x_msk, y_msk, x_src, y_src, x_dst, y_dst;
272     int             w, h, w_this, h_this;
273     int             dstDepth = pDst->pDrawable->depth;
274
275     xDst += pDst->pDrawable->x;
276     yDst += pDst->pDrawable->y;
277     xSrc += pSrc->pDrawable->x;
278     ySrc += pSrc->pDrawable->y;
279     if (pMask)
280     {
281         xMask += pMask->pDrawable->x;
282         yMask += pMask->pDrawable->y;
283         maskRepeat = pMask->repeat;
284         maskAlphaMap = pMask->alphaMap != 0;
285     }
286
287     if (rootless_log_pict_formats)
288     {
289         log_format (op, pSrc->format, pDst->format,
290                     pMask != 0 ? pMask->format : 0);
291     }
292
293     if (!miComputeCompositeRegion (&region,
294                                    pSrc,
295                                    pMask,
296                                    pDst,
297                                    xSrc,
298                                    ySrc,
299                                    xMask,
300                                    yMask,
301                                    xDst,
302                                    yDst,
303                                    width,
304                                    height))
305         return;
306
307     if (pDst->pDrawable->type == DRAWABLE_WINDOW
308         && pDst->pDrawable->depth == 24
309         && pDst->pDrawable->bitsPerPixel == 32)
310     {
311         /* fbpict code sets bits above depth to zero. We don't want that! */
312
313         pDst->pDrawable->depth = 32;
314     }
315
316     func = RootlessCompositeGeneral;
317
318     if (!maskAlphaMap && !srcAlphaMap && !dstAlphaMap)
319     switch (op) {
320     case PictOpOver:
321         if (pMask)
322         {
323             if (srcRepeat && 
324                 pSrc->pDrawable->width == 1 &&
325                 pSrc->pDrawable->height == 1)
326             {
327                 srcRepeat = FALSE;
328                 if (PICT_FORMAT_COLOR(pSrc->format)) {
329                     switch (pMask->format) {
330                     case PICT_a8:
331                         switch (pDst->format) {
332                         case PICT_r5g6b5:
333                         case PICT_b5g6r5:
334                             func = fbCompositeSolidMask_nx8x0565;
335                             break;
336                         case PICT_r8g8b8:
337                         case PICT_b8g8r8:
338                             func = fbCompositeSolidMask_nx8x0888;
339                             break;
340                         case PICT_a8r8g8b8:
341                         case PICT_x8r8g8b8:
342                         case PICT_a8b8g8r8:
343                         case PICT_x8b8g8r8:
344                             func = fbCompositeSolidMask_nx8x8888;
345                             break;
346                         }
347                         break;
348                     case PICT_a8r8g8b8:
349                         if (pMask->componentAlpha) {
350                             switch (pDst->format) {
351                             case PICT_a8r8g8b8:
352                             case PICT_x8r8g8b8:
353                                 func = fbCompositeSolidMask_nx8888x8888C;
354                                 break;
355                             case PICT_r5g6b5:
356                                 func = fbCompositeSolidMask_nx8888x0565C;
357                                 break;
358                             }
359                         }
360                         break;
361                     case PICT_a8b8g8r8:
362                         if (pMask->componentAlpha) {
363                             switch (pDst->format) {
364                             case PICT_a8b8g8r8:
365                             case PICT_x8b8g8r8:
366                                 func = fbCompositeSolidMask_nx8888x8888C;
367                                 break;
368                             case PICT_b5g6r5:
369                                 func = fbCompositeSolidMask_nx8888x0565C;
370                                 break;
371                             }
372                         }
373                         break;
374                     case PICT_a1:
375                         switch (pDst->format) {
376                         case PICT_r5g6b5:
377                         case PICT_b5g6r5:
378                         case PICT_r8g8b8:
379                         case PICT_b8g8r8:
380                         case PICT_a8r8g8b8:
381                         case PICT_x8r8g8b8:
382                         case PICT_a8b8g8r8:
383                         case PICT_x8b8g8r8:
384                             func = fbCompositeSolidMask_nx1xn;
385                             break;
386                         }
387                     }
388                 }
389             }
390         }
391         else
392         {
393             switch (pSrc->format) {
394             case PICT_a8r8g8b8:
395             case PICT_x8r8g8b8:
396                 switch (pDst->format) {
397                 case PICT_a8r8g8b8:
398                 case PICT_x8r8g8b8:
399                     func = fbCompositeSrc_8888x8888;
400                     break;
401                 case PICT_r8g8b8:
402                     func = fbCompositeSrc_8888x0888;
403                     break;
404                 case PICT_r5g6b5:
405                     func = fbCompositeSrc_8888x0565;
406                     break;
407                 }
408                 break;
409             case PICT_a8b8g8r8:
410             case PICT_x8b8g8r8:
411                 switch (pDst->format) {
412                 case PICT_a8b8g8r8:
413                 case PICT_x8b8g8r8:
414                     func = fbCompositeSrc_8888x8888;
415                     break;
416                 case PICT_b8g8r8:
417                     func = fbCompositeSrc_8888x0888;
418                     break;
419                 case PICT_b5g6r5:
420                     func = fbCompositeSrc_8888x0565;
421                     break;
422                 }
423                 break;
424             case PICT_r5g6b5:
425                 switch (pDst->format) {
426                 case PICT_r5g6b5:
427                     func = fbCompositeSrc_0565x0565;
428                     break;
429                 }
430                 break;
431             case PICT_b5g6r5:
432                 switch (pDst->format) {
433                 case PICT_b5g6r5:
434                     func = fbCompositeSrc_0565x0565;
435                     break;
436                 }
437                 break;
438             }
439         }
440         break;
441     case PictOpAdd:
442         if (pMask == 0)
443         {
444             switch (pSrc->format) {
445             case PICT_a8r8g8b8:
446                 switch (pDst->format) {
447                 case PICT_a8r8g8b8:
448                     func = fbCompositeSrcAdd_8888x8888;
449                     break;
450                 }
451                 break;
452             case PICT_a8b8g8r8:
453                 switch (pDst->format) {
454                 case PICT_a8b8g8r8:
455                     func = fbCompositeSrcAdd_8888x8888;
456                     break;
457                 }
458                 break;
459             case PICT_a8:
460                 switch (pDst->format) {
461                 case PICT_a8:
462                     func = fbCompositeSrcAdd_8000x8000;
463                     break;
464                 }
465                 break;
466             case PICT_a1:
467                 switch (pDst->format) {
468                 case PICT_a1:
469                     func = fbCompositeSrcAdd_1000x1000;
470                     break;
471                 }
472                 break;
473             }
474         }
475         break;
476     }
477
478     n = REGION_NUM_RECTS (&region);
479     pbox = REGION_RECTS (&region);
480     while (n--)
481     {
482         h = pbox->y2 - pbox->y1;
483         y_src = pbox->y1 - yDst + ySrc;
484         y_msk = pbox->y1 - yDst + yMask;
485         y_dst = pbox->y1;
486         while (h)
487         {
488             h_this = h;
489             w = pbox->x2 - pbox->x1;
490             x_src = pbox->x1 - xDst + xSrc;
491             x_msk = pbox->x1 - xDst + xMask;
492             x_dst = pbox->x1;
493             if (maskRepeat)
494             {
495                 y_msk = mod (y_msk, pMask->pDrawable->height);
496                 if (h_this > pMask->pDrawable->height - y_msk)
497                     h_this = pMask->pDrawable->height - y_msk;
498             }
499             if (srcRepeat)
500             {
501                 y_src = mod (y_src, pSrc->pDrawable->height);
502                 if (h_this > pSrc->pDrawable->height - y_src)
503                     h_this = pSrc->pDrawable->height - y_src;
504             }
505             while (w)
506             {
507                 w_this = w;
508                 if (maskRepeat)
509                 {
510                     x_msk = mod (x_msk, pMask->pDrawable->width);
511                     if (w_this > pMask->pDrawable->width - x_msk)
512                         w_this = pMask->pDrawable->width - x_msk;
513                 }
514                 if (srcRepeat)
515                 {
516                     x_src = mod (x_src, pSrc->pDrawable->width);
517                     if (w_this > pSrc->pDrawable->width - x_src)
518                         w_this = pSrc->pDrawable->width - x_src;
519                 }
520                 (*func) (op, pSrc, pMask, pDst,
521                          x_src, y_src, x_msk, y_msk, x_dst, y_dst,
522                          w_this, h_this);
523                 w -= w_this;
524                 x_src += w_this;
525                 x_msk += w_this;
526                 x_dst += w_this;
527             }
528             h -= h_this;
529             y_src += h_this;
530             y_msk += h_this;
531             y_dst += h_this;
532         }
533         pbox++;
534     }
535     REGION_UNINIT (pDst->pDrawable->pScreen, &region);
536
537     pDst->pDrawable->depth = dstDepth;
538 }
539
540 #endif /* RENDER */