import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
public final class EmacsFillRectangle
{
+ /* Color filter that inverts colors from the source. */
+ private static final ColorFilter invertFilter;
+
+ static
+ {
+ invertFilter = new ColorMatrixColorFilter (new float[] {
+ -1f, 0f, 0f, 0f, 255f,
+ 0f, -1f, 0f, 0f, 255f,
+ 0f, 0f, -1f, 0f, 255f,
+ 0f, 0f, 0f, 1f, 0f,
+ });
+ };
+
public static void
perform (EmacsDrawable drawable, EmacsGC gc,
int x, int y, int width, int height)
{
- Paint maskPaint, paint;
- Canvas maskCanvas;
- Bitmap maskBitmap;
+ Paint paint;
Rect rect;
- Rect maskRect, dstRect;
Canvas canvas;
- Bitmap clipBitmap;
+ Bitmap invertBitmap;
canvas = drawable.lockCanvas (gc);
- if (canvas == null)
+ /* Clip masks are not respected or implemented when specified with
+ this request. */
+ if (canvas == null || gc.clip_mask != null)
return;
rect = new Rect (x, y, x + width, y + height);
- paint = gc.gcPaint;
- paint.setStyle (Paint.Style.FILL);
-
- if (gc.clip_mask == null)
+ if (gc.function != EmacsGC.GC_INVERT)
{
+ paint = gc.gcPaint;
+ paint.setStyle (Paint.Style.FILL);
+
if (gc.fill_style != EmacsGC.GC_FILL_OPAQUE_STIPPLED)
canvas.drawRect (rect, paint);
else
}
else
{
- /* Drawing with a clip mask involves calculating the
- intersection of the clip mask with the dst rect, and
- extrapolating the corresponding part of the src rect. */
-
- clipBitmap = gc.clip_mask.bitmap;
- dstRect = new Rect (x, y, x + width, y + height);
- maskRect = new Rect (gc.clip_x_origin,
- gc.clip_y_origin,
- (gc.clip_x_origin
- + clipBitmap.getWidth ()),
- (gc.clip_y_origin
- + clipBitmap.getHeight ()));
-
- if (!maskRect.setIntersect (dstRect, maskRect))
- /* There is no intersection between the clip mask and the
- dest rect. */
- return;
-
- /* Finally, create a temporary bitmap that is the size of
- maskRect. */
-
- maskBitmap
- = Bitmap.createBitmap (maskRect.width (), maskRect.height (),
- Bitmap.Config.ARGB_8888);
-
- /* Draw the mask onto the maskBitmap. */
- maskCanvas = new Canvas (maskBitmap);
- maskRect.offset (-gc.clip_x_origin,
- -gc.clip_y_origin);
- maskCanvas.drawBitmap (gc.clip_mask.bitmap,
- maskRect, new Rect (0, 0,
- maskRect.width (),
- maskRect.height ()),
- paint);
- maskRect.offset (gc.clip_x_origin,
- gc.clip_y_origin);
-
- /* Set the transfer mode to SRC_IN to preserve only the parts
- of the source that overlap with the mask. */
- maskPaint = new Paint ();
- maskPaint.setXfermode (EmacsGC.srcInAlu);
-
- /* Draw the source. */
- maskCanvas.drawRect (maskRect, maskPaint);
-
- /* Finally, draw the mask bitmap to the destination. */
- paint.setXfermode (null);
- canvas.drawBitmap (maskBitmap, null, maskRect, paint);
-
- /* Recycle this unused bitmap. */
- maskBitmap.recycle ();
+ paint = new Paint ();
+
+ /* Simply invert the destination, which is only implemented for
+ this request. As Android doesn't permit copying a bitmap to
+ itself, a copy of the source must be procured beforehand. */
+ invertBitmap = Bitmap.createBitmap (drawable.getBitmap (),
+ x, y, width, height);
+ paint.setColorFilter (invertFilter);
+ canvas.drawBitmap (invertBitmap, null, rect, paint);
+ paint.setColorFilter (null);
+ invertBitmap.recycle ();
}
drawable.damageRect (rect);
}
-/* Xor a rectangle SRC_X, SRC_Y, WIDTH and HEIGHT from SRC, described
- by SRC_INFO, to DST_X and DST_Y in DST, as described by DST_INFO.
-
- Ignore the alpha channel when computing the exclusive-or of the
- destination pixel.
-
- If MASK is set, mask the source data using MASK_INFO, translating
- it by GC->clip_x_origin and GC->clip_y_origin. MASK must be a
- pixmap of depth 1.
-
- N.B. that currently only copies between bitmaps of depth 24 are
- implemented. */
-
-static void
-android_blit_xor (int src_x, int src_y, int width, int height,
- int dst_x, int dst_y, struct android_gc *gc,
- unsigned char *src, AndroidBitmapInfo *src_info,
- unsigned char *dst, AndroidBitmapInfo *dst_info,
- unsigned char *mask, AndroidBitmapInfo *mask_info)
-{
-#if 0
- uintptr_t start, end;
- int mask_offset;
- size_t pixel, offset, offset1;
- unsigned char *src_current, *dst_current;
- unsigned char *mask_current;
- int overflow, temp, i;
- bool backwards;
- unsigned int *long_src, *long_dst;
-#endif /* 0 */
-
- /* Note that this alu hasn't been tested -- it probably does not
- work! */
- emacs_abort ();
-
-#if 0
- /* Assert that the specified coordinates are within bounds. */
- eassert (src_x >= 0 && src_y >= 0
- && dst_x >= 0 && dst_y >= 0);
- eassert (src_x + width <= src_info->width);
- eassert (src_y + height <= src_info->height);
- eassert (dst_x + width <= dst_info->width);
- eassert (dst_y + height <= dst_info->height);
-
- /* Now check that each bitmap has the correct format. */
- eassert (src_info->format == dst_info->format
- && src_info->format == ANDROID_BITMAP_FORMAT_RGBA_8888);
- pixel = sizeof (unsigned int);
-
- /* Android doesn't have A1 bitmaps, so A8 is used to represent
- packed bitmaps of depth 1. */
- eassert (!mask || mask_info->format == ANDROID_BITMAP_FORMAT_A_8);
-
- /* Calculate the address of the first pixel of the first row to be
- copied in both src and dst. Compare them to determine the
- direction in which the copy is to take place. */
-
- overflow = ckd_mul (&start, src_y, src_info->stride);
- overflow |= ckd_mul (&end, src_x, pixel);
- overflow |= ckd_add (&start, (uintptr_t) src, start);
-
- if (overflow)
- return;
-
- src_current = (unsigned char *) start;
-
- overflow = ckd_mul (&start, dst_y, src_info->stride);
- overflow |= ckd_mul (&end, dst_x, pixel);
- overflow |= ckd_add (&start, (uintptr_t) dst, start);
-
- if (overflow)
- return;
-
- dst_current = (unsigned char *) start;
- backwards = false;
-
- /* Now see if copying should proceed from the bottom up. */
-
- if (src == dst && dst_current >= src_current)
- {
- backwards = true;
-
- /* Walk src and dst from bottom to top, in order to avoid
- overlap. Calculate the coordinate of the last pixel of the
- last row in both src and dst. */
-
- overflow = ckd_mul (&start, src_y + height - 1,
- src_info->stride);
- if (mask) /* If a mask is set, put the pointers before the end
- of the row. */
- overflow |= ckd_mul (&end, src_x + width - 1, pixel);
- else
- overflow |= ckd_mul (&end, src_x, pixel);
- overflow |= ckd_add (&start, start, end);
- overflow |= ckd_add (&start, (uintptr_t) src, start);
-
- if (overflow)
- return;
-
- src_current = (unsigned char *) start;
-
- overflow = ckd_mul (&start, dst_y + height - 1,
- dst_info->stride);
- if (mask) /* If a mask is set, put the pointers before the end
- of the row. */
- overflow |= ckd_mul (&end, dst_x + width - 1, pixel);
- else
- overflow |= ckd_mul (&end, dst_x, pixel);
- overflow |= ckd_add (&start, start, end);
- overflow |= ckd_add (&start, (uintptr_t) dst, start);
-
- if (overflow)
- return;
-
- dst_current = (unsigned char *) start;
- }
-
- if (!mask)
- {
- /* Change the direction of the copy depending on how SRC and DST
- overlap. */
-
- for (i = 0; i < height; ++i)
- {
- if (backwards)
- {
- for (i = width - 1; i <= 0; --i)
- (((unsigned int *) dst_current)[i])
- /* Keep the alpha channel intact. */
- ^= (((unsigned int *) src_current)[i]) & 0xffffff;
-
- /* Proceed to the last row. */
- src_current -= src_info->stride;
- dst_current -= dst_info->stride;
- }
- else
- {
- for (i = 0; i < width; ++i)
- (((unsigned int *) dst_current)[i])
- /* Keep the alpha channel intact. */
- ^= (((unsigned int *) src_current)[i]) & 0xffffff;
-
- /* Proceed to the next row. */
- src_current += src_info->stride;
- dst_current += dst_info->stride;
- }
- }
- }
- else
- {
- /* Adjust the source and destination Y. The start is MAX
- (dst_y, gc->clip_y_origin); the difference between that value
- and dst_y is the offset to apply to src_y. */
-
- temp = dst_y;
- dst_y = MAX (dst_y, gc->clip_y_origin);
- src_y += dst_y - temp;
- height -= dst_y - temp;
-
- /* Verify that the bounds are correct. */
- eassert (dst_y + height
- <= gc->clip_y_origin + mask_info->height);
- eassert (dst_y >= gc->clip_y_origin);
-
- /* There is a mask. For each scan line... */
-
- if (backwards)
- {
- /* Calculate the number of pixels at the end of the
- mask. */
-
- mask_offset = dst_x + width;
- mask_offset -= mask_info->width + gc->clip_x_origin;
-
- if (mask_info < 0)
- mask_info = 0;
-
- /* Calculate the last column of the mask that will be
- consulted. */
-
- temp = dst_x - gc->clip_x_origin;
- temp += MIN (mask_info->width - temp,
- width - mask_offset);
-
- if (temp < 0)
- return;
-
- /* Now calculate the last row of the mask that will be
- consulted. */
- i = dst_y - gc->clip_y_origin + height;
-
- /* Turn both into offsets. */
-
- if (ckd_mul (&offset, temp, pixel)
- || ckd_mul (&offset1, i, mask_info->stride)
- || ckd_add (&offset, offset, offset1)
- || ckd_add (&start, (uintptr_t) mask, offset))
- return;
-
- mask = mask_current = (unsigned char *) start;
-
- for (i = 0; i < height; ++i)
- {
- /* Skip backwards past the end of the mask. */
-
- long_src = (unsigned int *) (src_current - mask_offset * pixel);
- long_dst = (unsigned int *) (dst_current - mask_offset * pixel);
- mask = mask_current;
-
- /* For each pixel covered by the mask... */
- temp = MIN (mask_info->width - temp, width - mask_offset);
- while (temp--)
- /* XOR the source to the destination, masked by the
- mask. */
- *long_dst-- ^= ((*(long_src--) & (0u - (*(mask--) & 1)))
- & 0xffffff);
-
- /* Return to the last row. */
- src_current -= src_info->stride;
- dst_current -= dst_info->stride;
- mask_current -= mask_info->stride;
- }
- }
- else
- {
- /* Calculate the first column of the mask that will be
- consulted. */
-
- mask_offset = dst_x - gc->clip_x_origin;
-
- /* Adjust the mask by that much. */
-
- if (mask_offset > 0)
- mask += mask_offset;
- else
- {
- /* Offset src and dst by the mask offset. */
- src_current += -mask_offset * pixel;
- dst_current += -mask_offset * pixel;
- width -= mask_offset;
- }
-
- /* Now move mask to the position of the first row. */
-
- mask += gc->clip_y_origin * mask_info->stride;
-
- for (i = 0; i < height; ++i)
- {
- long_src = (unsigned int *) src_current;
- long_dst = (unsigned int *) dst_current;
- mask_current = mask;
-
- if (mask_offset > 0)
- {
- /* Copy bytes according to the mask. */
- temp = MIN (mask_info->width - mask_offset, width);
- while (temp--)
- *long_dst++ ^= ((*(long_src++)
- & (0u - (*(mask_current++) & 1)))
- & 0xffffff);
- }
- else
- {
- /* Copy bytes according to the mask. */
- temp = MIN (mask_info->width, width);
- while (temp--)
- *long_dst++ = ((*(long_src++)
- & (0u - (*(mask_current++) & 1)))
- & 0xffffff);
- }
-
- src_current += src_info->stride;
- dst_current += dst_info->stride;
- mask += mask_info->stride;
- }
- }
- }
-#endif /* 0 */
-}
-
void
android_copy_area (android_drawable src, android_drawable dest,
struct android_gc *gc, int src_x, int src_y,
do_blit = android_blit_copy;
break;
- case ANDROID_GC_XOR:
- do_blit = android_blit_xor;
- break;
-
+ /* case ANDROID_GC_INVERT: */
+ /* do_blit = android_blit_invert; */
+ /* A GC with its operation set to ANDROID_GC_INVERT is never given
+ to CopyArea. */
default:
emacs_abort ();
}