aboutsummaryrefslogtreecommitdiffstats
path: root/libtwin/twin_draw.c
diff options
context:
space:
mode:
Diffstat (limited to 'libtwin/twin_draw.c')
-rw-r--r--libtwin/twin_draw.c696
1 files changed, 696 insertions, 0 deletions
diff --git a/libtwin/twin_draw.c b/libtwin/twin_draw.c
new file mode 100644
index 0000000..48a9da6
--- /dev/null
+++ b/libtwin/twin_draw.c
@@ -0,0 +1,696 @@
+/*
+ * Twin - A Tiny Window System
+ * Copyright © 2004 Keith Packard <keithp@keithp.com>
+ * All rights reserved.
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Twin Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "twinint.h"
+
+/* op, src, dst */
+static twin_src_op comp2[2][4][3] = {
+ { /* OVER */
+ { /* A8 */
+ _twin_a8_over_a8,
+ _twin_a8_over_rgb16,
+ _twin_a8_over_argb32,
+ },
+ { /* RGB16 */
+ _twin_rgb16_over_a8,
+ _twin_rgb16_over_rgb16,
+ _twin_rgb16_over_argb32,
+ },
+ { /* ARGB32 */
+ _twin_argb32_over_a8,
+ _twin_argb32_over_rgb16,
+ _twin_argb32_over_argb32,
+ },
+ { /* C */
+ _twin_c_over_a8,
+ _twin_c_over_rgb16,
+ _twin_c_over_argb32,
+ }
+ },
+ { /* SOURCE */
+ { /* A8 */
+ _twin_a8_source_a8,
+ _twin_a8_source_rgb16,
+ _twin_a8_source_argb32,
+ },
+ { /* RGB16 */
+ _twin_rgb16_source_a8,
+ _twin_rgb16_source_rgb16,
+ _twin_rgb16_source_argb32,
+ },
+ { /* ARGB32 */
+ _twin_argb32_source_a8,
+ _twin_argb32_source_rgb16,
+ _twin_argb32_source_argb32,
+ },
+ { /* C */
+ _twin_c_source_a8,
+ _twin_c_source_rgb16,
+ _twin_c_source_argb32,
+ }
+ }
+};
+
+/* op, src, msk, dst */
+static twin_src_msk_op comp3[2][4][4][3] = {
+ { /* OVER */
+ { /* A8 */
+ { /* A8 */
+ _twin_a8_in_a8_over_a8,
+ _twin_a8_in_a8_over_rgb16,
+ _twin_a8_in_a8_over_argb32,
+ },
+ { /* RGB16 */
+ _twin_a8_in_rgb16_over_a8,
+ _twin_a8_in_rgb16_over_rgb16,
+ _twin_a8_in_rgb16_over_argb32,
+ },
+ { /* ARGB32 */
+ _twin_a8_in_argb32_over_a8,
+ _twin_a8_in_argb32_over_rgb16,
+ _twin_a8_in_argb32_over_argb32,
+ },
+ { /* C */
+ _twin_a8_in_c_over_a8,
+ _twin_a8_in_c_over_rgb16,
+ _twin_a8_in_c_over_argb32,
+ },
+ },
+ { /* RGB16 */
+ { /* A8 */
+ _twin_rgb16_in_a8_over_a8,
+ _twin_rgb16_in_a8_over_rgb16,
+ _twin_rgb16_in_a8_over_argb32,
+ },
+ { /* RGB16 */
+ _twin_rgb16_in_rgb16_over_a8,
+ _twin_rgb16_in_rgb16_over_rgb16,
+ _twin_rgb16_in_rgb16_over_argb32,
+ },
+ { /* ARGB32 */
+ _twin_rgb16_in_argb32_over_a8,
+ _twin_rgb16_in_argb32_over_rgb16,
+ _twin_rgb16_in_argb32_over_argb32,
+ },
+ { /* C */
+ _twin_rgb16_in_c_over_a8,
+ _twin_rgb16_in_c_over_rgb16,
+ _twin_rgb16_in_c_over_argb32,
+ },
+ },
+ { /* ARGB32 */
+ { /* A8 */
+ _twin_argb32_in_a8_over_a8,
+ _twin_argb32_in_a8_over_rgb16,
+ _twin_argb32_in_a8_over_argb32,
+ },
+ { /* RGB16 */
+ _twin_argb32_in_rgb16_over_a8,
+ _twin_argb32_in_rgb16_over_rgb16,
+ _twin_argb32_in_rgb16_over_argb32,
+ },
+ { /* ARGB32 */
+ _twin_argb32_in_argb32_over_a8,
+ _twin_argb32_in_argb32_over_rgb16,
+ _twin_argb32_in_argb32_over_argb32,
+ },
+ { /* C */
+ _twin_argb32_in_c_over_a8,
+ _twin_argb32_in_c_over_rgb16,
+ _twin_argb32_in_c_over_argb32,
+ },
+ },
+ { /* C */
+ { /* A8 */
+ _twin_c_in_a8_over_a8,
+ _twin_c_in_a8_over_rgb16,
+ _twin_c_in_a8_over_argb32,
+ },
+ { /* RGB16 */
+ _twin_c_in_rgb16_over_a8,
+ _twin_c_in_rgb16_over_rgb16,
+ _twin_c_in_rgb16_over_argb32,
+ },
+ { /* ARGB32 */
+ _twin_c_in_argb32_over_a8,
+ _twin_c_in_argb32_over_rgb16,
+ _twin_c_in_argb32_over_argb32,
+ },
+ { /* C */
+ _twin_c_in_c_over_a8,
+ _twin_c_in_c_over_rgb16,
+ _twin_c_in_c_over_argb32,
+ },
+ },
+ },
+ { /* SOURCE */
+ { /* A8 */
+ { /* A8 */
+ _twin_a8_in_a8_source_a8,
+ _twin_a8_in_a8_source_rgb16,
+ _twin_a8_in_a8_source_argb32,
+ },
+ { /* RGB16 */
+ _twin_a8_in_rgb16_source_a8,
+ _twin_a8_in_rgb16_source_rgb16,
+ _twin_a8_in_rgb16_source_argb32,
+ },
+ { /* ARGB32 */
+ _twin_a8_in_argb32_source_a8,
+ _twin_a8_in_argb32_source_rgb16,
+ _twin_a8_in_argb32_source_argb32,
+ },
+ { /* C */
+ _twin_a8_in_c_source_a8,
+ _twin_a8_in_c_source_rgb16,
+ _twin_a8_in_c_source_argb32,
+ },
+ },
+ { /* RGB16 */
+ { /* A8 */
+ _twin_rgb16_in_a8_source_a8,
+ _twin_rgb16_in_a8_source_rgb16,
+ _twin_rgb16_in_a8_source_argb32,
+ },
+ { /* RGB16 */
+ _twin_rgb16_in_rgb16_source_a8,
+ _twin_rgb16_in_rgb16_source_rgb16,
+ _twin_rgb16_in_rgb16_source_argb32,
+ },
+ { /* ARGB32 */
+ _twin_rgb16_in_argb32_source_a8,
+ _twin_rgb16_in_argb32_source_rgb16,
+ _twin_rgb16_in_argb32_source_argb32,
+ },
+ { /* C */
+ _twin_rgb16_in_c_source_a8,
+ _twin_rgb16_in_c_source_rgb16,
+ _twin_rgb16_in_c_source_argb32,
+ },
+ },
+ { /* ARGB32 */
+ { /* A8 */
+ _twin_argb32_in_a8_source_a8,
+ _twin_argb32_in_a8_source_rgb16,
+ _twin_argb32_in_a8_source_argb32,
+ },
+ { /* RGB16 */
+ _twin_argb32_in_rgb16_source_a8,
+ _twin_argb32_in_rgb16_source_rgb16,
+ _twin_argb32_in_rgb16_source_argb32,
+ },
+ { /* ARGB32 */
+ _twin_argb32_in_argb32_source_a8,
+ _twin_argb32_in_argb32_source_rgb16,
+ _twin_argb32_in_argb32_source_argb32,
+ },
+ { /* C */
+ _twin_argb32_in_c_source_a8,
+ _twin_argb32_in_c_source_rgb16,
+ _twin_argb32_in_c_source_argb32,
+ },
+ },
+ { /* C */
+ { /* A8 */
+ _twin_c_in_a8_source_a8,
+ _twin_c_in_a8_source_rgb16,
+ _twin_c_in_a8_source_argb32,
+ },
+ { /* RGB16 */
+ _twin_c_in_rgb16_source_a8,
+ _twin_c_in_rgb16_source_rgb16,
+ _twin_c_in_rgb16_source_argb32,
+ },
+ { /* ARGB32 */
+ _twin_c_in_argb32_source_a8,
+ _twin_c_in_argb32_source_rgb16,
+ _twin_c_in_argb32_source_argb32,
+ },
+ { /* C */
+ _twin_c_in_c_source_a8,
+ _twin_c_in_c_source_rgb16,
+ _twin_c_in_c_source_argb32,
+ },
+ },
+ }
+};
+
+
+#define operand_index(o) ((o)->source_kind == TWIN_SOLID ? 3 : o->u.pixmap->format)
+
+/* XXX Fixme: source clipping is busted
+ */
+static void _twin_composite_simple (twin_pixmap_t *dst,
+ twin_coord_t dst_x,
+ twin_coord_t dst_y,
+ twin_operand_t *src,
+ twin_coord_t src_x,
+ twin_coord_t src_y,
+ twin_operand_t *msk,
+ twin_coord_t msk_x,
+ twin_coord_t msk_y,
+ twin_operator_t operator,
+ twin_coord_t width,
+ twin_coord_t height)
+{
+ twin_coord_t iy;
+ twin_coord_t left, top, right, bottom;
+ twin_coord_t sdx, sdy;
+ twin_source_u s;
+
+ dst_x += dst->origin_x;
+ dst_y += dst->origin_y;
+ left = dst_x;
+ top = dst_y;
+ right = dst_x + width;
+ bottom = dst_y + height;
+
+ /* clip */
+ if (left < dst->clip.left)
+ left = dst->clip.left;
+ if (top < dst->clip.top)
+ top = dst->clip.top;
+ if (right > dst->clip.right)
+ right = dst->clip.right;
+ if (bottom > dst->clip.bottom)
+ bottom = dst->clip.bottom;
+
+ if (left >= right || top >= bottom)
+ return;
+
+ if (src->source_kind == TWIN_PIXMAP) {
+ src_x += src->u.pixmap->origin_x;
+ src_y += src->u.pixmap->origin_y;
+ } else
+ s.c = src->u.argb;
+
+ sdx = src_x - dst_x;
+ sdy = src_y - dst_y;
+
+ if (msk) {
+ twin_src_msk_op op;
+ twin_source_u m;
+ twin_coord_t mdx, mdy;
+
+ if (msk->source_kind == TWIN_PIXMAP) {
+ msk_x += msk->u.pixmap->origin_x;
+ msk_y += msk->u.pixmap->origin_y;
+ } else
+ m.c = msk->u.argb;
+
+ mdx = msk_x - dst_x;
+ mdy = msk_y - dst_y;
+
+ op = comp3[operator][operand_index(src)][operand_index(msk)][dst->format];
+ for (iy = top; iy < bottom; iy++)
+ {
+ if (src->source_kind == TWIN_PIXMAP)
+ s.p = twin_pixmap_pointer (src->u.pixmap, left+sdx, iy+sdy);
+ if (msk->source_kind == TWIN_PIXMAP)
+ m.p = twin_pixmap_pointer (msk->u.pixmap, left+mdx, iy+mdy);
+ (*op) (twin_pixmap_pointer (dst, left, iy), s, m, right - left);
+ }
+ }
+ else
+ {
+ twin_src_op op;
+
+ op = comp2[operator][operand_index(src)][dst->format];
+
+ for (iy = top; iy < bottom; iy++)
+ {
+ if (src->source_kind == TWIN_PIXMAP)
+ s.p = twin_pixmap_pointer (src->u.pixmap, left+sdx, iy+sdy);
+ (*op) (twin_pixmap_pointer (dst, left, iy), s, right - left);
+ }
+ }
+ twin_pixmap_damage (dst, left, top, right, bottom);
+}
+
+static inline int operand_xindex(twin_operand_t *o)
+{
+ int ind = operand_index(o);
+
+ return ind != TWIN_RGB16 ? ind : TWIN_ARGB32;
+}
+
+static twin_xform_t *twin_pixmap_init_xform (twin_pixmap_t *pixmap,
+ twin_coord_t left, twin_coord_t width,
+ twin_coord_t src_x, twin_coord_t src_y)
+{
+ twin_xform_t *xform;
+ twin_format_t fmt = pixmap->format;
+
+ if (fmt == TWIN_RGB16)
+ fmt = TWIN_ARGB32;
+
+ xform = calloc(1, sizeof (twin_xform_t) +
+ width * twin_bytes_per_pixel(fmt));
+ if (xform == NULL)
+ return NULL;
+
+ xform->span.v = (twin_argb32_t *)(char *)(xform + 1);
+ xform->pixmap = pixmap;
+ xform->left = left;
+ xform->width = width;
+ xform->src_x = src_x;
+ xform->src_y = src_y;
+
+ return xform;
+}
+
+static void twin_pixmap_free_xform (twin_xform_t *xform)
+{
+ if (xform)
+ free (xform);
+}
+
+#define FX(x) twin_int_to_fixed(x)
+#define XF(x) twin_fixed_to_int(x)
+
+/* we are doing clipping on source... dunno if that makes much sense
+ * but here we go ... if we decide that source clipping makes no sense
+ * then we need to still test wether we fit in the pixmap boundaries
+ * here. source clipping is useful if you try to extract one image
+ * out of a big picture though.
+ */
+#define _pix_clipped(pix, x, y) \
+ ((x) < FX((pix)->clip.left) || (x) >= FX((pix)->clip.right) || \
+ (y) < FX((pix)->clip.top) || (y) >= FX((pix)->clip.bottom))
+
+#define _get_pix_8(d, pix, x, y) \
+ do { \
+ (d) = _pix_clipped(pix, x, y) ? 0 : \
+ *((pix)->p.a8 + XF(y) * (pix)->stride + XF(x)); \
+ } while(0)
+
+#define _get_pix_16(d, pix, x, y) \
+ do { \
+ twin_rgb16_t p = _pix_clipped(pix, x, y) ? 0 : \
+ *((pix)->p.argb32 + XF(y) * ((pix)->stride >> 1) + XF(x)); \
+ *((twin_argb32_t *)(char *)(d)) = twin_rgb16_to_argb32(p); \
+ } while(0)
+
+#define _get_pix_32(d, pix, x, y) \
+ do { \
+ twin_argb32_t p = _pix_clipped(pix, x, y) ? 0 : \
+ *((pix)->p.argb32 + XF(y) * ((pix)->stride >> 2) + XF(x)); \
+ *((twin_argb32_t *)(char *)(d)) = p; \
+ } while(0)
+
+
+#define _pix_saucemix(tl, tr, bl, br, wx, wy) \
+ (( ((((br * wx) + (bl * (TWIN_FIXED_ONE - wx))) >> 16) \
+ * wy) + \
+ ((((tr * wx) + (tl * (TWIN_FIXED_ONE - wx))) >> 16) \
+ * (TWIN_FIXED_ONE - wy)) \
+ ) >> 16)
+
+
+static void twin_pixmap_read_xform_8 (twin_xform_t *xform, twin_coord_t line)
+{
+ twin_fixed_t dx, dy, sx, sy;
+ unsigned int wx, wy;
+ twin_a8_t pts[4];
+ twin_a8_t *dst = xform->span.a8;
+ twin_pixmap_t *pix = xform->pixmap;
+ twin_matrix_t *tfm = &xform->pixmap->transform;
+
+ /* for each row in the dest line */
+ dy = twin_int_to_fixed(line);
+ for (dx = 0; dx < twin_int_to_fixed(xform->width); dx += TWIN_FIXED_ONE) {
+ sx = _twin_matrix_fx(tfm, dx, dy) + FX(xform->src_x);
+ sy = _twin_matrix_fy(tfm, dx, dy) + FX(xform->src_y);
+ _get_pix_8(pts[0], pix, sx, sy);
+ _get_pix_8(pts[1], pix, sx + TWIN_FIXED_ONE, sy);
+ _get_pix_8(pts[2], pix, sx, sy + TWIN_FIXED_ONE);
+ _get_pix_8(pts[3], pix, sx, sy + TWIN_FIXED_ONE);
+ wx = sx & 0xffff;
+ wy = sy & 0xffff;
+ *(dst++) = _pix_saucemix(pts[0], pts[1], pts[2], pts[4], wx, wy);
+ }
+}
+
+static void twin_pixmap_read_xform_16 (twin_xform_t *xform, twin_coord_t line)
+{
+ twin_fixed_t dx, dy, sx, sy;
+ unsigned int wx, wy;
+ twin_a8_t pts[4][4];
+ twin_a8_t *dst = xform->span.a8;
+ twin_pixmap_t *pix = xform->pixmap;
+ twin_matrix_t *tfm = &xform->pixmap->transform;
+
+ /* for each row in the dest line */
+ dy = twin_int_to_fixed(line);
+ for (dx = 0; dx < twin_int_to_fixed(xform->width); dx += TWIN_FIXED_ONE) {
+ sx = _twin_matrix_fx(tfm, dx, dy) + FX(xform->src_x);
+ sy = _twin_matrix_fy(tfm, dx, dy) + FX(xform->src_y);
+ _get_pix_16(pts[0], pix, sx, sy);
+ _get_pix_16(pts[1], pix, sx + TWIN_FIXED_ONE, sy);
+ _get_pix_16(pts[2], pix, sx, sy + TWIN_FIXED_ONE);
+ _get_pix_16(pts[3], pix, sx + TWIN_FIXED_ONE, sy + TWIN_FIXED_ONE);
+ wx = sx & 0xffff;
+ wy = sy & 0xffff;
+ *(dst++) = _pix_saucemix(pts[0][0], pts[1][0],
+ pts[2][0], pts[3][0], wx, wy);
+ *(dst++) = _pix_saucemix(pts[0][1], pts[1][1],
+ pts[2][1], pts[3][1], wx, wy);
+ *(dst++) = _pix_saucemix(pts[0][2], pts[1][2],
+ pts[2][2], pts[3][2], wx, wy);
+ *(dst++) = _pix_saucemix(pts[0][3], pts[1][3],
+ pts[2][3], pts[3][3], wx, wy);
+ }
+}
+
+static void twin_pixmap_read_xform_32 (twin_xform_t *xform, twin_coord_t line)
+{
+ twin_fixed_t dx, dy, sx, sy;
+ unsigned int wx, wy;
+ twin_a8_t pts[4][4];
+ twin_a8_t *dst = xform->span.a8;
+ twin_pixmap_t *pix = xform->pixmap;
+ twin_matrix_t *tfm = &xform->pixmap->transform;
+
+ /* for each row in the dest line */
+ dy = twin_int_to_fixed(line);
+ for (dx = 0; dx < twin_int_to_fixed(xform->width); dx += TWIN_FIXED_ONE) {
+ sx = _twin_matrix_fx(tfm, dx, dy) + FX(xform->src_x);
+ sy = _twin_matrix_fy(tfm, dx, dy) + FX(xform->src_y);
+ _get_pix_32(pts[0], pix, sx, sy);
+ _get_pix_32(pts[1], pix, sx + TWIN_FIXED_ONE, sy);
+ _get_pix_32(pts[2], pix, sx, sy + TWIN_FIXED_ONE);
+ _get_pix_32(pts[3], pix, sx + TWIN_FIXED_ONE, sy + TWIN_FIXED_ONE);
+ wx = sx & 0xffff;
+ wy = sy & 0xffff;
+ *(dst++) = _pix_saucemix(pts[0][0], pts[1][0],
+ pts[2][0], pts[3][0], wx, wy);
+ *(dst++) = _pix_saucemix(pts[0][1], pts[1][1],
+ pts[2][1], pts[3][1], wx, wy);
+ *(dst++) = _pix_saucemix(pts[0][2], pts[1][2],
+ pts[2][2], pts[3][2], wx, wy);
+ *(dst++) = _pix_saucemix(pts[0][3], pts[1][3],
+ pts[2][3], pts[3][3], wx, wy);
+ }
+}
+
+static void twin_pixmap_read_xform (twin_xform_t *xform, twin_coord_t line)
+{
+ if (xform->pixmap->format == TWIN_A8)
+ twin_pixmap_read_xform_8(xform, line);
+ else if (xform->pixmap->format == TWIN_RGB16)
+ twin_pixmap_read_xform_16(xform, line);
+ else if (xform->pixmap->format == TWIN_ARGB32)
+ twin_pixmap_read_xform_32(xform, line);
+}
+
+static void _twin_composite_xform (twin_pixmap_t *dst,
+ twin_coord_t dst_x,
+ twin_coord_t dst_y,
+ twin_operand_t *src,
+ twin_coord_t src_x,
+ twin_coord_t src_y,
+ twin_operand_t *msk,
+ twin_coord_t msk_x,
+ twin_coord_t msk_y,
+ twin_operator_t operator,
+ twin_coord_t width,
+ twin_coord_t height)
+{
+ twin_coord_t iy;
+ twin_coord_t left, top, right, bottom;
+ twin_xform_t *sxform = NULL, *mxform = NULL;
+ twin_source_u s;
+
+ dst_x += dst->origin_x;
+ dst_y += dst->origin_y;
+ left = dst_x;
+ top = dst_y;
+ right = dst_x + width;
+ bottom = dst_y + height;
+
+ /* clip */
+ if (left < dst->clip.left)
+ left = dst->clip.left;
+ if (top < dst->clip.top)
+ top = dst->clip.top;
+ if (right > dst->clip.right)
+ right = dst->clip.right;
+ if (bottom > dst->clip.bottom)
+ bottom = dst->clip.bottom;
+
+ if (left >= right || top >= bottom)
+ return;
+
+ width = right - left;
+ height = bottom - top;
+
+ if (src->source_kind == TWIN_PIXMAP) {
+ src_x += src->u.pixmap->origin_x;
+ src_y += src->u.pixmap->origin_y;
+ sxform = twin_pixmap_init_xform(src->u.pixmap, left, width,
+ src_x, src_y);
+ if (sxform == NULL)
+ return;
+ s.p = sxform->span;
+ } else
+ s.c = src->u.argb;
+
+ if (msk) {
+ twin_src_msk_op op;
+ twin_source_u m;
+
+ if (msk->source_kind == TWIN_PIXMAP) {
+ msk_x += msk->u.pixmap->origin_x;
+ msk_y += msk->u.pixmap->origin_y;
+ mxform = twin_pixmap_init_xform(msk->u.pixmap, left, width,
+ msk_x, msk_y);
+ if (mxform == NULL)
+ return;
+ m.p = mxform->span;
+ } else
+ m.c = msk->u.argb;
+
+ op = comp3[operator][operand_xindex(src)][operand_xindex(msk)]
+ [dst->format];
+ for (iy = top; iy < bottom; iy++) {
+ if (src->source_kind == TWIN_PIXMAP)
+ twin_pixmap_read_xform (sxform, iy - top);
+ if (msk->source_kind == TWIN_PIXMAP)
+ twin_pixmap_read_xform (mxform, iy - top);
+ (*op) (twin_pixmap_pointer (dst, left, iy), s, m, right - left);
+ }
+ } else {
+ twin_src_op op;
+
+ op = comp2[operator][operand_xindex(src)][dst->format];
+
+ for (iy = top; iy < bottom; iy++) {
+ if (src->source_kind == TWIN_PIXMAP)
+ twin_pixmap_read_xform (sxform, iy - top);
+ (*op) (twin_pixmap_pointer (dst, left, iy), s, right - left);
+ }
+ }
+ twin_pixmap_damage (dst, left, top, right, bottom);
+ twin_pixmap_free_xform(sxform);
+ twin_pixmap_free_xform(mxform);
+}
+
+void twin_composite (twin_pixmap_t *dst,
+ twin_coord_t dst_x,
+ twin_coord_t dst_y,
+ twin_operand_t *src,
+ twin_coord_t src_x,
+ twin_coord_t src_y,
+ twin_operand_t *msk,
+ twin_coord_t msk_x,
+ twin_coord_t msk_y,
+ twin_operator_t operator,
+ twin_coord_t width,
+ twin_coord_t height)
+{
+ if ((src->source_kind == TWIN_PIXMAP &&
+ !twin_matrix_is_identity(&src->u.pixmap->transform)) ||
+ (msk && (msk->source_kind == TWIN_PIXMAP &&
+ !twin_matrix_is_identity(&msk->u.pixmap->transform))))
+ _twin_composite_xform(dst, dst_x, dst_y,
+ src, src_x, src_y,
+ msk, msk_x, msk_y,
+ operator, width, height);
+ else
+ _twin_composite_simple(dst, dst_x, dst_y,
+ src, src_x, src_y,
+ msk, msk_x, msk_y,
+ operator, width, height);
+}
+
+/*
+ * array primary index is OVER SOURCE
+ * array secondary index is ARGB32 RGB16 A8
+ */
+static twin_src_op fill[2][3] = {
+ { /* OVER */
+ _twin_c_over_a8,
+ _twin_c_over_rgb16,
+ _twin_c_over_argb32,
+ },
+ { /* SOURCE */
+ _twin_c_source_a8,
+ _twin_c_source_rgb16,
+ _twin_c_source_argb32,
+ }
+};
+
+void
+twin_fill (twin_pixmap_t *dst,
+ twin_argb32_t pixel,
+ twin_operator_t operator,
+ twin_coord_t left,
+ twin_coord_t top,
+ twin_coord_t right,
+ twin_coord_t bottom)
+{
+ twin_src_op op;
+ twin_source_u src;
+ twin_coord_t iy;
+
+ /* offset */
+ left += dst->origin_x;
+ top += dst->origin_y;
+ right += dst->origin_x;
+ bottom += dst->origin_y;
+
+ /* clip */
+ if (left < dst->clip.left)
+ left = dst->clip.left;
+ if (right > dst->clip.right)
+ right = dst->clip.right;
+ if (top < dst->clip.top)
+ top = dst->clip.top;
+ if (bottom > dst->clip.bottom)
+ bottom = dst->clip.bottom;
+ if (left >= right || top >= bottom)
+ return;
+ src.c = pixel;
+ op = fill[operator][dst->format];
+ for (iy = top; iy < bottom; iy++)
+ (*op) (twin_pixmap_pointer (dst, left, iy), src, right - left);
+ twin_pixmap_damage (dst, left, top, right, bottom);
+}