Copy fast path lookup code into pixman-utils.c
[profile/ivi/pixman.git] / pixman / pixman-utils.c
1 /*
2  * Copyright © 2000 SuSE, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of SuSE not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  SuSE makes no representations about the
11  * suitability of this software for any purpose.  It is provided "as is"
12  * without express or implied warranty.
13  *
14  * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
16  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
18  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
19  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  * Author:  Keith Packard, SuSE, Inc.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdlib.h>
29
30 #include "pixman-private.h"
31 #include "pixman-mmx.h"
32 #include "pixman-sse2.h"
33
34 #if defined(USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
35 __attribute__((__force_align_arg_pointer__))
36 #endif
37 PIXMAN_EXPORT pixman_bool_t
38 pixman_blt (uint32_t *src_bits,
39             uint32_t *dst_bits,
40             int src_stride,
41             int dst_stride,
42             int src_bpp,
43             int dst_bpp,
44             int src_x, int src_y,
45             int dst_x, int dst_y,
46             int width, int height)
47 {
48 #ifdef USE_SSE2
49     if (pixman_have_sse2())
50     {
51         return pixmanBltsse2 (src_bits, dst_bits, src_stride, dst_stride, src_bpp, dst_bpp,
52                               src_x, src_y, dst_x, dst_y, width, height);
53     }
54     else
55 #endif
56 #ifdef USE_MMX
57     if (pixman_have_mmx())
58     {
59         return pixman_blt_mmx (src_bits, dst_bits, src_stride, dst_stride, src_bpp, dst_bpp,
60                                src_x, src_y, dst_x, dst_y, width, height);
61     }
62     else
63 #endif
64         return FALSE;
65 }
66
67 static void
68 pixman_fill8 (uint32_t  *bits,
69               int       stride,
70               int       x,
71               int       y,
72               int       width,
73               int       height,
74               uint32_t  xor)
75 {
76     int byte_stride = stride * (int) sizeof (uint32_t);
77     uint8_t *dst = (uint8_t *) bits;
78     uint8_t v = xor & 0xff;
79     int i;
80
81     dst = dst + y * byte_stride + x;
82
83     while (height--)
84     {
85         for (i = 0; i < width; ++i)
86             dst[i] = v;
87
88         dst += byte_stride;
89     }
90 }
91
92 static void
93 pixman_fill16 (uint32_t *bits,
94                int       stride,
95                int       x,
96                int       y,
97                int       width,
98                int       height,
99                uint32_t  xor)
100 {
101     int short_stride = (stride * (int) sizeof (uint32_t)) / (int) sizeof (uint16_t);
102     uint16_t *dst = (uint16_t *)bits;
103     uint16_t v = xor & 0xffff;
104     int i;
105
106     dst = dst + y * short_stride + x;
107
108     while (height--)
109     {
110         for (i = 0; i < width; ++i)
111             dst[i] = v;
112
113         dst += short_stride;
114     }
115 }
116
117 static void
118 pixman_fill32 (uint32_t *bits,
119                int       stride,
120                int       x,
121                int       y,
122                int       width,
123                int       height,
124                uint32_t  xor)
125 {
126     int i;
127
128     bits = bits + y * stride + x;
129
130     while (height--)
131     {
132         for (i = 0; i < width; ++i)
133             bits[i] = xor;
134
135         bits += stride;
136     }
137 }
138
139 #if defined(USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
140 __attribute__((__force_align_arg_pointer__))
141 #endif
142 PIXMAN_EXPORT pixman_bool_t
143 pixman_fill (uint32_t *bits,
144              int stride,
145              int bpp,
146              int x,
147              int y,
148              int width,
149              int height,
150              uint32_t xor)
151 {
152 #if 0
153     printf ("filling: %d %d %d %d (stride: %d, bpp: %d)   pixel: %x\n",
154             x, y, width, height, stride, bpp, xor);
155 #endif
156
157 #ifdef USE_SSE2
158     if (pixman_have_sse2() && pixmanFillsse2 (bits, stride, bpp, x, y, width, height, xor))
159         return TRUE;
160 #endif
161
162 #ifdef USE_MMX
163     if (pixman_have_mmx() && pixman_fill_mmx (bits, stride, bpp, x, y, width, height, xor))
164         return TRUE;
165 #endif
166     
167     switch (bpp)
168     {
169     case 8:
170         pixman_fill8 (bits, stride, x, y, width, height, xor);
171         break;
172         
173     case 16:
174         pixman_fill16 (bits, stride, x, y, width, height, xor);
175         break;
176         
177     case 32:
178         pixman_fill32 (bits, stride, x, y, width, height, xor);
179         break;
180         
181     default:
182         return FALSE;
183         break;
184     }
185
186     return TRUE;
187 }
188
189
190 /*
191  * Compute the smallest value no less than y which is on a
192  * grid row
193  */
194
195 PIXMAN_EXPORT pixman_fixed_t
196 pixman_sample_ceil_y (pixman_fixed_t y, int n)
197 {
198     pixman_fixed_t   f = pixman_fixed_frac(y);
199     pixman_fixed_t   i = pixman_fixed_floor(y);
200
201     f = ((f + Y_FRAC_FIRST(n)) / STEP_Y_SMALL(n)) * STEP_Y_SMALL(n) + Y_FRAC_FIRST(n);
202     if (f > Y_FRAC_LAST(n))
203     {
204         if (pixman_fixed_to_int(i) == 0x7fff)
205         {
206             f = 0xffff; /* saturate */
207         } else {
208             f = Y_FRAC_FIRST(n);
209             i += pixman_fixed_1;
210         }
211     }
212     return (i | f);
213 }
214
215 #define _div(a,b)    ((a) >= 0 ? (a) / (b) : -((-(a) + (b) - 1) / (b)))
216
217 /*
218  * Compute the largest value no greater than y which is on a
219  * grid row
220  */
221 PIXMAN_EXPORT pixman_fixed_t
222 pixman_sample_floor_y (pixman_fixed_t y, int n)
223 {
224     pixman_fixed_t   f = pixman_fixed_frac(y);
225     pixman_fixed_t   i = pixman_fixed_floor (y);
226
227     f = _div(f - Y_FRAC_FIRST(n), STEP_Y_SMALL(n)) * STEP_Y_SMALL(n) + Y_FRAC_FIRST(n);
228     if (f < Y_FRAC_FIRST(n))
229     {
230         if (pixman_fixed_to_int(i) == 0x8000)
231         {
232             f = 0; /* saturate */
233         } else {
234             f = Y_FRAC_LAST(n);
235             i -= pixman_fixed_1;
236         }
237     }
238     return (i | f);
239 }
240
241 /*
242  * Step an edge by any amount (including negative values)
243  */
244 PIXMAN_EXPORT void
245 pixman_edge_step (pixman_edge_t *e, int n)
246 {
247     pixman_fixed_48_16_t        ne;
248
249     e->x += n * e->stepx;
250
251     ne = e->e + n * (pixman_fixed_48_16_t) e->dx;
252
253     if (n >= 0)
254     {
255         if (ne > 0)
256         {
257             int nx = (ne + e->dy - 1) / e->dy;
258             e->e = ne - nx * (pixman_fixed_48_16_t) e->dy;
259             e->x += nx * e->signdx;
260         }
261     }
262     else
263     {
264         if (ne <= -e->dy)
265         {
266             int nx = (-ne) / e->dy;
267             e->e = ne + nx * (pixman_fixed_48_16_t) e->dy;
268             e->x -= nx * e->signdx;
269         }
270     }
271 }
272
273 /*
274  * A private routine to initialize the multi-step
275  * elements of an edge structure
276  */
277 static void
278 _pixman_edge_multi_init (pixman_edge_t *e, int n, pixman_fixed_t *stepx_p, pixman_fixed_t *dx_p)
279 {
280     pixman_fixed_t      stepx;
281     pixman_fixed_48_16_t        ne;
282
283     ne = n * (pixman_fixed_48_16_t) e->dx;
284     stepx = n * e->stepx;
285     if (ne > 0)
286     {
287         int nx = ne / e->dy;
288         ne -= nx * e->dy;
289         stepx += nx * e->signdx;
290     }
291     *dx_p = ne;
292     *stepx_p = stepx;
293 }
294
295 /*
296  * Initialize one edge structure given the line endpoints and a
297  * starting y value
298  */
299 PIXMAN_EXPORT void
300 pixman_edge_init (pixman_edge_t *e,
301                   int           n,
302                   pixman_fixed_t                y_start,
303                   pixman_fixed_t                x_top,
304                   pixman_fixed_t                y_top,
305                   pixman_fixed_t                x_bot,
306                   pixman_fixed_t                y_bot)
307 {
308     pixman_fixed_t      dx, dy;
309
310     e->x = x_top;
311     e->e = 0;
312     dx = x_bot - x_top;
313     dy = y_bot - y_top;
314     e->dy = dy;
315     e->dx = 0;
316     if (dy)
317     {
318         if (dx >= 0)
319         {
320             e->signdx = 1;
321             e->stepx = dx / dy;
322             e->dx = dx % dy;
323             e->e = -dy;
324         }
325         else
326         {
327             e->signdx = -1;
328             e->stepx = -(-dx / dy);
329             e->dx = -dx % dy;
330             e->e = 0;
331         }
332
333         _pixman_edge_multi_init (e, STEP_Y_SMALL(n), &e->stepx_small, &e->dx_small);
334         _pixman_edge_multi_init (e, STEP_Y_BIG(n), &e->stepx_big, &e->dx_big);
335     }
336     pixman_edge_step (e, y_start - y_top);
337 }
338
339 /*
340  * Initialize one edge structure given a line, starting y value
341  * and a pixel offset for the line
342  */
343 PIXMAN_EXPORT void
344 pixman_line_fixed_edge_init (pixman_edge_t *e,
345                              int            n,
346                              pixman_fixed_t         y,
347                              const pixman_line_fixed_t *line,
348                              int            x_off,
349                              int            y_off)
350 {
351     pixman_fixed_t      x_off_fixed = pixman_int_to_fixed(x_off);
352     pixman_fixed_t      y_off_fixed = pixman_int_to_fixed(y_off);
353     const pixman_point_fixed_t *top, *bot;
354
355     if (line->p1.y <= line->p2.y)
356     {
357         top = &line->p1;
358         bot = &line->p2;
359     }
360     else
361     {
362         top = &line->p2;
363         bot = &line->p1;
364     }
365     pixman_edge_init (e, n, y,
366                     top->x + x_off_fixed,
367                     top->y + y_off_fixed,
368                     bot->x + x_off_fixed,
369                     bot->y + y_off_fixed);
370 }
371
372 pixman_bool_t
373 pixman_multiply_overflows_int (unsigned int a,
374                                unsigned int b)
375 {
376     return a >= INT32_MAX / b;
377 }
378
379 pixman_bool_t
380 pixman_addition_overflows_int (unsigned int a,
381                                unsigned int b)
382 {
383     return a > INT32_MAX - b;
384 }
385
386 void *
387 pixman_malloc_ab(unsigned int a,
388                  unsigned int b)
389 {
390     if (a >= INT32_MAX / b)
391         return NULL;
392
393     return malloc (a * b);
394 }
395
396 void *
397 pixman_malloc_abc (unsigned int a,
398                    unsigned int b,
399                    unsigned int c)
400 {
401     if (a >= INT32_MAX / b)
402         return NULL;
403     else if (a * b >= INT32_MAX / c)
404         return NULL;
405     else
406         return malloc (a * b * c);
407 }
408
409
410 /**
411  * pixman_version:
412  *
413  * Returns the version of the pixman library encoded in a single
414  * integer as per %PIXMAN_VERSION_ENCODE. The encoding ensures that
415  * later versions compare greater than earlier versions.
416  *
417  * A run-time comparison to check that pixman's version is greater than
418  * or equal to version X.Y.Z could be performed as follows:
419  *
420  * <informalexample><programlisting>
421  * if (pixman_version() >= PIXMAN_VERSION_ENCODE(X,Y,Z)) {...}
422  * </programlisting></informalexample>
423  *
424  * See also pixman_version_string() as well as the compile-time
425  * equivalents %PIXMAN_VERSION and %PIXMAN_VERSION_STRING.
426  *
427  * Return value: the encoded version.
428  **/
429 PIXMAN_EXPORT int
430 pixman_version (void)
431 {
432     return PIXMAN_VERSION;
433 }
434
435 /**
436  * pixman_version_string:
437  *
438  * Returns the version of the pixman library as a human-readable string
439  * of the form "X.Y.Z".
440  *
441  * See also pixman_version() as well as the compile-time equivalents
442  * %PIXMAN_VERSION_STRING and %PIXMAN_VERSION.
443  *
444  * Return value: a string containing the version.
445  **/
446 PIXMAN_EXPORT const char*
447 pixman_version_string (void)
448 {
449     return PIXMAN_VERSION_STRING;
450 }
451
452 /**
453  * pixman_format_supported_destination:
454  * @format: A pixman_format_code_t format
455  * 
456  * Return value: whether the provided format code is a supported
457  * format for a pixman surface used as a destination in
458  * rendering.
459  *
460  * Currently, all pixman_format_code_t values are supported
461  * except for the YUV formats.
462  **/
463 PIXMAN_EXPORT pixman_bool_t
464 pixman_format_supported_destination (pixman_format_code_t format)
465 {
466     switch (format) {
467     /* 32 bpp formats */
468     case PIXMAN_a2b10g10r10:
469     case PIXMAN_x2b10g10r10:
470     case PIXMAN_a8r8g8b8:
471     case PIXMAN_x8r8g8b8:
472     case PIXMAN_a8b8g8r8:
473     case PIXMAN_x8b8g8r8:
474     case PIXMAN_b8g8r8a8:
475     case PIXMAN_b8g8r8x8:
476     case PIXMAN_r8g8b8:
477     case PIXMAN_b8g8r8:
478     case PIXMAN_r5g6b5:
479     case PIXMAN_b5g6r5:
480     /* 16 bpp formats */
481     case PIXMAN_a1r5g5b5:
482     case PIXMAN_x1r5g5b5:
483     case PIXMAN_a1b5g5r5:
484     case PIXMAN_x1b5g5r5:
485     case PIXMAN_a4r4g4b4:
486     case PIXMAN_x4r4g4b4:
487     case PIXMAN_a4b4g4r4:
488     case PIXMAN_x4b4g4r4:
489     /* 8bpp formats */
490     case PIXMAN_a8:
491     case PIXMAN_r3g3b2:
492     case PIXMAN_b2g3r3:
493     case PIXMAN_a2r2g2b2:
494     case PIXMAN_a2b2g2r2:
495     case PIXMAN_c8:
496     case PIXMAN_g8:
497     case PIXMAN_x4a4:
498     /* Collides with PIXMAN_c8
499     case PIXMAN_x4c4:
500     */
501     /* Collides with PIXMAN_g8
502     case PIXMAN_x4g4:
503     */
504     /* 4bpp formats */
505     case PIXMAN_a4:
506     case PIXMAN_r1g2b1:
507     case PIXMAN_b1g2r1:
508     case PIXMAN_a1r1g1b1:
509     case PIXMAN_a1b1g1r1:
510     case PIXMAN_c4:
511     case PIXMAN_g4:
512     /* 1bpp formats */
513     case PIXMAN_a1:
514     case PIXMAN_g1:
515         return TRUE;
516         
517     /* YUV formats */
518     case PIXMAN_yuy2:
519     case PIXMAN_yv12:
520     default:
521         return FALSE;
522     }
523 }
524
525 /**
526  * pixman_format_supported_source:
527  * @format: A pixman_format_code_t format
528  * 
529  * Return value: whether the provided format code is a supported
530  * format for a pixman surface used as a source in
531  * rendering.
532  *
533  * Currently, all pixman_format_code_t values are supported.
534  **/
535 PIXMAN_EXPORT pixman_bool_t
536 pixman_format_supported_source (pixman_format_code_t format)
537 {
538     switch (format) {
539     /* 32 bpp formats */
540     case PIXMAN_a2b10g10r10:
541     case PIXMAN_x2b10g10r10:
542     case PIXMAN_a8r8g8b8:
543     case PIXMAN_x8r8g8b8:
544     case PIXMAN_a8b8g8r8:
545     case PIXMAN_x8b8g8r8:
546     case PIXMAN_b8g8r8a8:
547     case PIXMAN_b8g8r8x8:
548     case PIXMAN_r8g8b8:
549     case PIXMAN_b8g8r8:
550     case PIXMAN_r5g6b5:
551     case PIXMAN_b5g6r5:
552     /* 16 bpp formats */
553     case PIXMAN_a1r5g5b5:
554     case PIXMAN_x1r5g5b5:
555     case PIXMAN_a1b5g5r5:
556     case PIXMAN_x1b5g5r5:
557     case PIXMAN_a4r4g4b4:
558     case PIXMAN_x4r4g4b4:
559     case PIXMAN_a4b4g4r4:
560     case PIXMAN_x4b4g4r4:
561     /* 8bpp formats */
562     case PIXMAN_a8:
563     case PIXMAN_r3g3b2:
564     case PIXMAN_b2g3r3:
565     case PIXMAN_a2r2g2b2:
566     case PIXMAN_a2b2g2r2:
567     case PIXMAN_c8:
568     case PIXMAN_g8:
569     case PIXMAN_x4a4:
570     /* Collides with PIXMAN_c8
571     case PIXMAN_x4c4:
572     */
573     /* Collides with PIXMAN_g8
574     case PIXMAN_x4g4:
575     */
576     /* 4bpp formats */
577     case PIXMAN_a4:
578     case PIXMAN_r1g2b1:
579     case PIXMAN_b1g2r1:
580     case PIXMAN_a1r1g1b1:
581     case PIXMAN_a1b1g1r1:
582     case PIXMAN_c4:
583     case PIXMAN_g4:
584     /* 1bpp formats */
585     case PIXMAN_a1:
586     case PIXMAN_g1:
587     /* YUV formats */
588     case PIXMAN_yuy2:
589     case PIXMAN_yv12:
590         return TRUE;
591
592     default:
593         return FALSE;
594     }
595 }
596
597 void
598 _pixman_walk_composite_region (pixman_implementation_t *imp,
599                               pixman_op_t op,
600                               pixman_image_t * pSrc,
601                               pixman_image_t * pMask,
602                               pixman_image_t * pDst,
603                               int16_t xSrc,
604                               int16_t ySrc,
605                               int16_t xMask,
606                               int16_t yMask,
607                               int16_t xDst,
608                               int16_t yDst,
609                               uint16_t width,
610                               uint16_t height,
611                               pixman_bool_t srcRepeat,
612                               pixman_bool_t maskRepeat,
613                               pixman_composite_func_t compositeRect)
614 {
615     int             n;
616     const pixman_box32_t *pbox;
617     int             w, h, w_this, h_this;
618     int             x_msk, y_msk, x_src, y_src, x_dst, y_dst;
619     pixman_region32_t reg;
620     pixman_region32_t *region;
621
622     pixman_region32_init (&reg);
623     if (!pixman_compute_composite_region32 (&reg, pSrc, pMask, pDst,
624                                             xSrc, ySrc, xMask, yMask, xDst, yDst, width, height))
625     {
626         return;
627     }
628
629     region = &reg;
630
631     pbox = pixman_region32_rectangles (region, &n);
632     while (n--)
633     {
634         h = pbox->y2 - pbox->y1;
635         y_src = pbox->y1 - yDst + ySrc;
636         y_msk = pbox->y1 - yDst + yMask;
637         y_dst = pbox->y1;
638         while (h)
639         {
640             h_this = h;
641             w = pbox->x2 - pbox->x1;
642             x_src = pbox->x1 - xDst + xSrc;
643             x_msk = pbox->x1 - xDst + xMask;
644             x_dst = pbox->x1;
645             if (maskRepeat)
646             {
647                 y_msk = MOD (y_msk, pMask->bits.height);
648                 if (h_this > pMask->bits.height - y_msk)
649                     h_this = pMask->bits.height - y_msk;
650             }
651             if (srcRepeat)
652             {
653                 y_src = MOD (y_src, pSrc->bits.height);
654                 if (h_this > pSrc->bits.height - y_src)
655                     h_this = pSrc->bits.height - y_src;
656             }
657             while (w)
658             {
659                 w_this = w;
660                 if (maskRepeat)
661                 {
662                     x_msk = MOD (x_msk, pMask->bits.width);
663                     if (w_this > pMask->bits.width - x_msk)
664                         w_this = pMask->bits.width - x_msk;
665                 }
666                 if (srcRepeat)
667                 {
668                     x_src = MOD (x_src, pSrc->bits.width);
669                     if (w_this > pSrc->bits.width - x_src)
670                         w_this = pSrc->bits.width - x_src;
671                 }
672                 (*compositeRect) (imp,
673                                   op, pSrc, pMask, pDst,
674                                   x_src, y_src, x_msk, y_msk, x_dst, y_dst,
675                                   w_this, h_this);
676                 w -= w_this;
677                 x_src += w_this;
678                 x_msk += w_this;
679                 x_dst += w_this;
680             }
681             h -= h_this;
682             y_src += h_this;
683             y_msk += h_this;
684             y_dst += h_this;
685         }
686         pbox++;
687     }
688     pixman_region32_fini (&reg);
689 }
690
691 static pixman_bool_t
692 mask_is_solid (pixman_image_t *mask)
693 {
694     if (mask->type == SOLID)
695         return TRUE;
696
697     if (mask->type == BITS &&
698         mask->common.repeat == PIXMAN_REPEAT_NORMAL &&
699         mask->bits.width == 1 &&
700         mask->bits.height == 1)
701     {
702         return TRUE;
703     }
704
705     return FALSE;
706 }
707
708 static const FastPathInfo *
709 get_fast_path (const FastPathInfo *fast_paths,
710                pixman_op_t         op,
711                pixman_image_t     *pSrc,
712                pixman_image_t     *pMask,
713                pixman_image_t     *pDst,
714                pixman_bool_t       is_pixbuf)
715 {
716     const FastPathInfo *info;
717
718     for (info = fast_paths; info->op != PIXMAN_OP_NONE; info++)
719     {
720         pixman_bool_t valid_src         = FALSE;
721         pixman_bool_t valid_mask        = FALSE;
722
723         if (info->op != op)
724             continue;
725
726         if ((info->src_format == PIXMAN_solid && pixman_image_can_get_solid (pSrc))             ||
727             (pSrc->type == BITS && info->src_format == pSrc->bits.format))
728         {
729             valid_src = TRUE;
730         }
731
732         if (!valid_src)
733             continue;
734
735         if ((info->mask_format == PIXMAN_null && !pMask)                        ||
736             (pMask && pMask->type == BITS && info->mask_format == pMask->bits.format))
737         {
738             valid_mask = TRUE;
739
740             if (info->flags & NEED_SOLID_MASK)
741             {
742                 if (!pMask || !mask_is_solid (pMask))
743                     valid_mask = FALSE;
744             }
745
746             if (info->flags & NEED_COMPONENT_ALPHA)
747             {
748                 if (!pMask || !pMask->common.component_alpha)
749                     valid_mask = FALSE;
750             }
751         }
752
753         if (!valid_mask)
754             continue;
755         
756         if (info->dest_format != pDst->bits.format)
757             continue;
758
759         if ((info->flags & NEED_PIXBUF) && !is_pixbuf)
760             continue;
761
762         return info;
763     }
764
765     return NULL;
766 }
767
768 pixman_composite_func_t
769 _pixman_look_up_fast_path (const FastPathInfo *paths,
770                            pixman_op_t op,
771                            pixman_image_t *src,
772                            pixman_image_t *mask,
773                            pixman_image_t *dest,
774                            int32_t src_x,
775                            int32_t src_y,
776                            int32_t mask_x,
777                            int32_t mask_y)
778 {
779     pixman_composite_func_t func = NULL;
780     pixman_bool_t src_repeat = src->common.repeat == PIXMAN_REPEAT_NORMAL;
781     pixman_bool_t mask_repeat = mask->common.repeat == PIXMAN_REPEAT_NORMAL;
782     
783     if ((src->type == BITS || pixman_image_can_get_solid (src)) &&
784         (!mask || mask->type == BITS)
785         && !src->common.transform && !mask->common.transform
786         && !mask->common.alpha_map && !src->common.alpha_map && !dest->common.alpha_map
787         && (src->common.filter != PIXMAN_FILTER_CONVOLUTION)
788         && (src->common.repeat != PIXMAN_REPEAT_PAD)
789         && (src->common.repeat != PIXMAN_REPEAT_REFLECT)
790         && (!mask || (mask->common.filter != PIXMAN_FILTER_CONVOLUTION &&
791                       mask->common.repeat != PIXMAN_REPEAT_PAD &&
792                       mask->common.repeat != PIXMAN_REPEAT_REFLECT))
793         && !src->common.read_func && !src->common.write_func
794         && !(mask && mask->common.read_func)
795         && !(mask && mask->common.write_func)
796         && !dest->common.read_func
797         && !dest->common.write_func)
798     {
799         const FastPathInfo *info;       
800         pixman_bool_t pixbuf;
801
802         pixbuf =
803             src && src->type == BITS            &&
804             mask && mask->type == BITS          &&
805             src->bits.bits == mask->bits.bits   &&
806             src_x == mask_x                     &&
807             src_y == mask_y                     &&
808             !mask->common.component_alpha       &&
809             !mask_repeat;
810         
811         info = get_fast_path (paths, op, src, mask, dest, pixbuf);
812
813         if (info)
814         {
815             func = info->func;
816                 
817             if (info->src_format == PIXMAN_solid)
818                 src_repeat = FALSE;
819
820             if (info->mask_format == PIXMAN_solid || info->flags & NEED_SOLID_MASK)
821                 mask_repeat = FALSE;
822
823             if ((src_repeat                     &&
824                  src->bits.width == 1           &&
825                  src->bits.height == 1) ||
826                 (mask_repeat                    &&
827                  mask->bits.width == 1          &&
828                  mask->bits.height == 1))
829             {
830                 /* If src or mask are repeating 1x1 images and src_repeat or
831                  * mask_repeat are still TRUE, it means the fast path we
832                  * selected does not actually handle repeating images.
833                  *
834                  * So rather than call the "fast path" with a zillion
835                  * 1x1 requests, we just fall back to the general code (which
836                  * does do something sensible with 1x1 repeating images).
837                  */
838                 func = NULL;
839             }
840         }
841     }
842
843     return func;
844 }