aboutsummaryrefslogtreecommitdiffstats
path: root/src/android.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/android.c')
-rw-r--r--src/android.c923
1 files changed, 867 insertions, 56 deletions
diff --git a/src/android.c b/src/android.c
index 8a41a7cdec5..33d766a90d9 100644
--- a/src/android.c
+++ b/src/android.c
@@ -28,6 +28,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
28#include <errno.h> 28#include <errno.h>
29#include <math.h> 29#include <math.h>
30#include <string.h> 30#include <string.h>
31#include <stdckdint.h>
31 32
32#include <sys/stat.h> 33#include <sys/stat.h>
33#include <sys/mman.h> 34#include <sys/mman.h>
@@ -68,6 +69,10 @@ bool android_init_gui;
68 69
69#include <sys/syscall.h> 70#include <sys/syscall.h>
70 71
72#ifdef __aarch64__
73#include <arm_neon.h>
74#endif /* __aarch64__ */
75
71#define ANDROID_THROW(env, class, msg) \ 76#define ANDROID_THROW(env, class, msg) \
72 ((*(env))->ThrowNew ((env), (*(env))->FindClass ((env), class), msg)) 77 ((*(env))->ThrowNew ((env), (*(env))->FindClass ((env), class), msg))
73 78
@@ -95,7 +100,6 @@ struct android_emacs_service
95 jmethodID draw_rectangle; 100 jmethodID draw_rectangle;
96 jmethodID draw_line; 101 jmethodID draw_line;
97 jmethodID draw_point; 102 jmethodID draw_point;
98 jmethodID copy_area;
99 jmethodID clear_window; 103 jmethodID clear_window;
100 jmethodID clear_area; 104 jmethodID clear_area;
101 jmethodID ring_bell; 105 jmethodID ring_bell;
@@ -2178,10 +2182,6 @@ android_init_emacs_service (void)
2178 FIND_METHOD (draw_point, "drawPoint", 2182 FIND_METHOD (draw_point, "drawPoint",
2179 "(Lorg/gnu/emacs/EmacsDrawable;" 2183 "(Lorg/gnu/emacs/EmacsDrawable;"
2180 "Lorg/gnu/emacs/EmacsGC;II)V"); 2184 "Lorg/gnu/emacs/EmacsGC;II)V");
2181 FIND_METHOD (copy_area, "copyArea",
2182 "(Lorg/gnu/emacs/EmacsDrawable;"
2183 "Lorg/gnu/emacs/EmacsDrawable;"
2184 "Lorg/gnu/emacs/EmacsGC;IIIIII)V");
2185 FIND_METHOD (clear_window, "clearWindow", 2185 FIND_METHOD (clear_window, "clearWindow",
2186 "(Lorg/gnu/emacs/EmacsWindow;)V"); 2186 "(Lorg/gnu/emacs/EmacsWindow;)V");
2187 FIND_METHOD (clear_area, "clearArea", 2187 FIND_METHOD (clear_area, "clearArea",
@@ -3356,6 +3356,16 @@ android_create_gc (enum android_gc_value_mask mask,
3356 /* This means to not apply any clipping. */ 3356 /* This means to not apply any clipping. */
3357 gc->num_clip_rects = -1; 3357 gc->num_clip_rects = -1;
3358 3358
3359 /* Apply the other default values. */
3360 gc->function = ANDROID_GC_COPY;
3361 gc->fill_style = ANDROID_FILL_SOLID;
3362 gc->clip_x_origin = 0;
3363 gc->clip_y_origin = 0;
3364 gc->clip_mask = ANDROID_NONE;
3365 gc->stipple = ANDROID_NONE;
3366 gc->ts_x_origin = 0;
3367 gc->ts_y_origin = 0;
3368
3359 if (!gc->gcontext) 3369 if (!gc->gcontext)
3360 { 3370 {
3361 xfree (gc); 3371 xfree (gc);
@@ -3430,10 +3440,13 @@ android_change_gc (struct android_gc *gc,
3430 } 3440 }
3431 3441
3432 if (mask & ANDROID_GC_FUNCTION) 3442 if (mask & ANDROID_GC_FUNCTION)
3433 (*android_java_env)->SetIntField (android_java_env, 3443 {
3434 gcontext, 3444 (*android_java_env)->SetIntField (android_java_env,
3435 emacs_gc_function, 3445 gcontext,
3436 values->function); 3446 emacs_gc_function,
3447 values->function);
3448 gc->function = values->function;
3449 }
3437 3450
3438 if (mask & ANDROID_GC_CLIP_X_ORIGIN) 3451 if (mask & ANDROID_GC_CLIP_X_ORIGIN)
3439 { 3452 {
@@ -3441,6 +3454,7 @@ android_change_gc (struct android_gc *gc,
3441 gcontext, 3454 gcontext,
3442 emacs_gc_clip_x_origin, 3455 emacs_gc_clip_x_origin,
3443 values->clip_x_origin); 3456 values->clip_x_origin);
3457 gc->clip_x_origin = values->clip_x_origin;
3444 clip_changed = true; 3458 clip_changed = true;
3445 } 3459 }
3446 3460
@@ -3450,6 +3464,7 @@ android_change_gc (struct android_gc *gc,
3450 gcontext, 3464 gcontext,
3451 emacs_gc_clip_y_origin, 3465 emacs_gc_clip_y_origin,
3452 values->clip_y_origin); 3466 values->clip_y_origin);
3467 gc->clip_y_origin = values->clip_y_origin;
3453 clip_changed = true; 3468 clip_changed = true;
3454 } 3469 }
3455 3470
@@ -3461,6 +3476,7 @@ android_change_gc (struct android_gc *gc,
3461 gcontext, 3476 gcontext,
3462 emacs_gc_clip_mask, 3477 emacs_gc_clip_mask,
3463 what); 3478 what);
3479 gc->clip_mask = values->clip_mask;
3464 3480
3465 /* Changing GCClipMask also clears the clip rectangles. */ 3481 /* Changing GCClipMask also clears the clip rectangles. */
3466 (*android_java_env)->SetObjectField (android_java_env, 3482 (*android_java_env)->SetObjectField (android_java_env,
@@ -3482,25 +3498,35 @@ android_change_gc (struct android_gc *gc,
3482 gcontext, 3498 gcontext,
3483 emacs_gc_stipple, 3499 emacs_gc_stipple,
3484 what); 3500 what);
3501 gc->stipple = values->stipple;
3485 } 3502 }
3486 3503
3487 if (mask & ANDROID_GC_FILL_STYLE) 3504 if (mask & ANDROID_GC_FILL_STYLE)
3488 (*android_java_env)->SetIntField (android_java_env, 3505 {
3489 gcontext, 3506 (*android_java_env)->SetIntField (android_java_env,
3490 emacs_gc_fill_style, 3507 gcontext,
3491 values->fill_style); 3508 emacs_gc_fill_style,
3509 values->fill_style);
3510 gc->fill_style = values->fill_style;
3511 }
3492 3512
3493 if (mask & ANDROID_GC_TILE_STIP_X_ORIGIN) 3513 if (mask & ANDROID_GC_TILE_STIP_X_ORIGIN)
3494 (*android_java_env)->SetIntField (android_java_env, 3514 {
3495 gcontext, 3515 (*android_java_env)->SetIntField (android_java_env,
3496 emacs_gc_ts_origin_x, 3516 gcontext,
3497 values->ts_x_origin); 3517 emacs_gc_ts_origin_x,
3518 values->ts_x_origin);
3519 gc->ts_x_origin = values->ts_x_origin;
3520 }
3498 3521
3499 if (mask & ANDROID_GC_TILE_STIP_Y_ORIGIN) 3522 if (mask & ANDROID_GC_TILE_STIP_Y_ORIGIN)
3500 (*android_java_env)->SetIntField (android_java_env, 3523 {
3501 gcontext, 3524 (*android_java_env)->SetIntField (android_java_env,
3502 emacs_gc_ts_origin_y, 3525 gcontext,
3503 values->ts_y_origin); 3526 emacs_gc_ts_origin_y,
3527 values->ts_y_origin);
3528 gc->ts_y_origin = values->ts_y_origin;
3529 }
3504 3530
3505 if (mask) 3531 if (mask)
3506 { 3532 {
@@ -3732,22 +3758,13 @@ android_get_gc_values (struct android_gc *gc,
3732 values->background = gc->background; 3758 values->background = gc->background;
3733 3759
3734 if (mask & ANDROID_GC_FUNCTION) 3760 if (mask & ANDROID_GC_FUNCTION)
3735 values->function 3761 values->function = gc->function;
3736 = (*android_java_env)->GetIntField (android_java_env,
3737 gcontext,
3738 emacs_gc_function);
3739 3762
3740 if (mask & ANDROID_GC_CLIP_X_ORIGIN) 3763 if (mask & ANDROID_GC_CLIP_X_ORIGIN)
3741 values->clip_x_origin 3764 values->clip_x_origin = gc->clip_x_origin;
3742 = (*android_java_env)->GetIntField (android_java_env,
3743 gcontext,
3744 emacs_gc_clip_x_origin);
3745 3765
3746 if (mask & ANDROID_GC_CLIP_Y_ORIGIN) 3766 if (mask & ANDROID_GC_CLIP_Y_ORIGIN)
3747 values->clip_y_origin 3767 values->clip_y_origin = gc->clip_y_origin;
3748 = (*android_java_env)->GetIntField (android_java_env,
3749 gcontext,
3750 emacs_gc_clip_y_origin);
3751 3768
3752 if (mask & ANDROID_GC_FILL_STYLE) 3769 if (mask & ANDROID_GC_FILL_STYLE)
3753 values->fill_style 3770 values->fill_style
@@ -3913,34 +3930,827 @@ android_set_fill_style (struct android_gc *gc,
3913 android_change_gc (gc, ANDROID_GC_FILL_STYLE, &gcv); 3930 android_change_gc (gc, ANDROID_GC_FILL_STYLE, &gcv);
3914} 3931}
3915 3932
3933
3934
3935/* Pixmap bit blit implementation. This exists as `Canvas.drawBitmap'
3936 seems to have trouble with copying bitmap data from one bitmap back
3937 to itself on Android 8.0. */
3938
3939/* Function called to actually perform the copy. */
3940
3941typedef void (*android_blit_func) (int, int, int, int, int, int,
3942 struct android_gc *,
3943 unsigned char *, AndroidBitmapInfo *,
3944 unsigned char *, AndroidBitmapInfo *,
3945 unsigned char *, AndroidBitmapInfo *);
3946
3947
3948
3949#ifdef __aarch64__
3950
3951/* Copy N pixels from SRC to DST, using MASK as a depth 1 clip
3952 mask. */
3953
3954static void
3955android_neon_mask_line (unsigned int *src, unsigned int *dst,
3956 unsigned char *mask, int n)
3957{
3958 uint32x4_t src_low, src_high, dst_low, dst_high;
3959 int16x8_t vmask;
3960 int32x4_t ext_mask_low, ext_mask_high, low, high;
3961 int rem;
3962
3963 /* Calculate the remainder. */
3964 rem = n & 7;
3965
3966 /* Process eight pixels at a time. */
3967
3968 if (n -= rem)
3969 {
3970 again:
3971 /* Load the low and high four pixels from the source. */
3972 src_low = vld1q_u32 (src);
3973 src_high = vld1q_u32 (src + 4);
3974
3975 /* Do the same with the destination. */
3976 dst_low = vld1q_u32 (dst);
3977 dst_high = vld1q_u32 (dst + 4);
3978
3979 /* Load and sign extend the mask. */
3980 vmask = vmovl_s8 (vld1_u8 (mask));
3981 ext_mask_low = vmovl_s16 (vget_low_s16 (vmask));
3982 ext_mask_high = vmovl_s16 (vget_high_s16 (vmask));
3983
3984 /* Reinterpret the mask. */
3985 low = vreinterpretq_u32_s32 (ext_mask_low);
3986 high = vreinterpretq_u32_s32 (ext_mask_high);
3987
3988 /* Apply the mask. */
3989 dst_low = vbicq_u32 (dst_low, low);
3990 src_low = vandq_u32 (src_low, low);
3991 dst_high = vbicq_u32 (dst_high, high);
3992 src_high = vandq_u32 (src_high, high);
3993
3994 /* Write the result after combining both masked vectors. */
3995 vst1q_u32 (dst, vorrq_u32 (dst_low, src_low));
3996 vst1q_u32 (dst + 4, vorrq_u32 (dst_high, src_high));
3997
3998 /* Adjust src, dst and mask. */
3999 dst += 8;
4000 src += 8;
4001 mask += 8;
4002
4003 /* See if this loop should continue. */
4004 n -= 8;
4005 if (n > 0)
4006 goto again;
4007 }
4008
4009 /* Process the remaining pixels. */
4010
4011 while (--rem)
4012 {
4013 /* Sign extend the mask. */
4014 n = *(signed char *) mask++;
4015
4016 /* Combine src and dst. */
4017 *dst = ((*src & n) | (*dst & ~n));
4018 src++, dst++;
4019 }
4020}
4021
4022#endif /* __aarch64__ */
4023
4024
4025
4026/* Copy a rectangle SRC_X, SRC_Y, WIDTH and HEIGHT from SRC, described
4027 by SRC_INFO, to DST_X and DST_Y in DST, as described by DST_INFO.
4028
4029 If MASK is set, mask the source data using MASK_INFO, translating
4030 it by GC->clip_x_origin and GC->clip_y_origin. MASK must be a
4031 pixmap of depth 1.
4032
4033 N.B. that currently only copies between bitmaps of depth 24 are
4034 implemented. */
4035
4036void
4037android_blit_copy (int src_x, int src_y, int width, int height,
4038 int dst_x, int dst_y, struct android_gc *gc,
4039 unsigned char *src, AndroidBitmapInfo *src_info,
4040 unsigned char *dst, AndroidBitmapInfo *dst_info,
4041 unsigned char *mask, AndroidBitmapInfo *mask_info)
4042{
4043 uintptr_t start, end;
4044 int mask_offset;
4045 size_t pixel, offset, offset1;
4046 unsigned char *src_current, *dst_current;
4047 unsigned char *mask_current;
4048 int overflow, temp, i, xdir;
4049 bool backwards;
4050 unsigned int *long_src, *long_dst;
4051
4052 /* Assert that the specified coordinates are within bounds. */
4053 eassert (src_x >= 0 && src_y >= 0
4054 && dst_x >= 0 && dst_y >= 0);
4055 eassert (src_x + width <= src_info->width);
4056 eassert (src_y + height <= src_info->height);
4057 eassert (dst_x + width <= dst_info->width);
4058 eassert (dst_y + height <= dst_info->height);
4059
4060 /* Now check that each bitmap has the correct format. */
4061 eassert (src_info->format == dst_info->format
4062 && src_info->format == ANDROID_BITMAP_FORMAT_RGBA_8888);
4063 pixel = sizeof (unsigned int);
4064
4065 /* Android doesn't have A1 bitmaps, so A8 is used to represent
4066 packed bitmaps of depth 1. */
4067 eassert (!mask || mask_info->format == ANDROID_BITMAP_FORMAT_A_8);
4068
4069 /* Calculate the address of the first pixel of the first row to be
4070 copied in both src and dst. Compare them to determine the
4071 direction in which the copy is to take place. */
4072
4073 overflow = ckd_mul (&start, src_y, src_info->stride);
4074 overflow |= ckd_mul (&end, src_x, pixel);
4075 overflow |= ckd_add (&start, end, start);
4076 overflow |= ckd_add (&start, (uintptr_t) src, start);
4077
4078 if (overflow)
4079 return;
4080
4081 src_current = (unsigned char *) start;
4082
4083 overflow = ckd_mul (&start, dst_y, dst_info->stride);
4084 overflow |= ckd_mul (&end, dst_x, pixel);
4085 overflow |= ckd_add (&start, end, start);
4086 overflow |= ckd_add (&start, (uintptr_t) dst, start);
4087
4088 if (overflow)
4089 return;
4090
4091 dst_current = (unsigned char *) start;
4092 backwards = false;
4093
4094 /* Now see if copying should proceed from the bottom up. */
4095
4096 if (src == dst && dst_current >= src_current)
4097 {
4098 backwards = true;
4099
4100 /* Walk src and dst from bottom to top, in order to avoid
4101 overlap. Calculate the coordinate of the last pixel of the
4102 last row in both src and dst. */
4103
4104 overflow = ckd_mul (&start, src_y + height - 1,
4105 src_info->stride);
4106 if (mask) /* If a mask is set, put the pointers before the end
4107 of the row. */
4108 overflow |= ckd_mul (&end, src_x + width - 1, pixel);
4109 else
4110 overflow |= ckd_mul (&end, src_x, pixel);
4111 overflow |= ckd_add (&start, start, end);
4112 overflow |= ckd_add (&start, (uintptr_t) src, start);
4113
4114 if (overflow)
4115 return;
4116
4117 src_current = (unsigned char *) start;
4118
4119 overflow = ckd_mul (&start, dst_y + height - 1,
4120 dst_info->stride);
4121 if (mask) /* If a mask is set, put the pointers before the end
4122 of the row. */
4123 overflow |= ckd_mul (&end, dst_x + width - 1, pixel);
4124 else
4125 overflow |= ckd_mul (&end, dst_x, pixel);
4126 overflow |= ckd_add (&start, start, end);
4127 overflow |= ckd_add (&start, (uintptr_t) dst, start);
4128
4129 if (overflow)
4130 return;
4131
4132 dst_current = (unsigned char *) start;
4133 }
4134
4135 if (!mask)
4136 {
4137 /* Change the direction of the copy depending on how SRC and DST
4138 overlap. */
4139
4140 for (i = 0; i < height; ++i)
4141 {
4142 memmove (dst_current, src_current,
4143 width * pixel);
4144
4145 if (backwards)
4146 {
4147 /* Proceed to the last row. */
4148 src_current -= src_info->stride;
4149 dst_current -= dst_info->stride;
4150 }
4151 else
4152 {
4153 /* Proceed to the next row. */
4154 src_current += src_info->stride;
4155 dst_current += dst_info->stride;
4156 }
4157 }
4158 }
4159 else
4160 {
4161 /* Adjust the source and destination Y. The start is MAX
4162 (dst_y, gc->clip_y_origin); the difference between that value
4163 and dst_y is the offset to apply to src_y. */
4164
4165 temp = dst_y;
4166 dst_y = MAX (dst_y, gc->clip_y_origin);
4167 src_y += dst_y - temp;
4168 height -= dst_y - temp;
4169
4170 /* Verify that the bounds are correct. */
4171 eassert (dst_y + height
4172 <= gc->clip_y_origin + mask_info->height);
4173 eassert (dst_y >= gc->clip_y_origin);
4174
4175 /* There is a mask. For each scan line... */
4176
4177 if (backwards)
4178 {
4179 /* Calculate the number of pixels at the end of the
4180 mask. */
4181
4182 mask_offset = dst_x + width;
4183 mask_offset -= mask_info->width + gc->clip_x_origin;
4184
4185 if (mask_offset < 0)
4186 mask_offset = 0;
4187
4188 /* Calculate the last column of the mask that will be
4189 consulted. */
4190
4191 temp = dst_x - gc->clip_x_origin;
4192 temp += MIN (mask_info->width - temp,
4193 width - mask_offset);
4194
4195 if (temp < 0)
4196 return;
4197
4198 /* Now calculate the last row of the mask that will be
4199 consulted. */
4200 i = dst_y - gc->clip_y_origin + height;
4201
4202 /* Turn both into offsets. */
4203
4204 if (INT_MULTIPLY_WRAPV (temp, pixel, &offset)
4205 || INT_MULTIPLY_WRAPV (i, mask_info->stride, &offset1)
4206 || INT_ADD_WRAPV (offset, offset1, &offset)
4207 || INT_ADD_WRAPV ((uintptr_t) mask, offset, &start))
4208 return;
4209
4210 mask = mask_current = (unsigned char *) start;
4211
4212 while (--height)
4213 {
4214 /* Skip backwards past the end of the mask. */
4215
4216 long_src = (unsigned int *) (src_current - mask_offset * pixel);
4217 long_dst = (unsigned int *) (dst_current - mask_offset * pixel);
4218 mask = mask_current;
4219
4220 /* For each pixel covered by the mask... */
4221 temp = MIN (mask_info->width - temp, width - mask_offset);
4222 while (temp--)
4223 {
4224 /* Copy the destination it to the source, masked by
4225 the mask. */
4226
4227 /* Sign extend the mask. */
4228 i = *(signed char *) mask--;
4229
4230 /* Apply the mask. */
4231 *long_dst = ((*long_src & i) | (*long_dst & ~i));
4232
4233 long_dst--;
4234 long_src--;
4235 }
4236
4237 /* Return to the last row. */
4238 src_current -= src_info->stride;
4239 dst_current -= dst_info->stride;
4240 mask_current -= mask_info->stride;
4241 }
4242 }
4243 else
4244 {
4245 /* Calculate the first column of the mask that will be
4246 consulted. */
4247
4248 mask_offset = dst_x - gc->clip_x_origin;
4249
4250 /* Adjust the mask by that much. */
4251
4252 if (mask_offset > 0)
4253 mask += mask_offset;
4254 else
4255 {
4256 /* Offset src and dst by the mask offset. */
4257 src_current += -mask_offset * pixel;
4258 dst_current += -mask_offset * pixel;
4259 width += mask_offset;
4260 }
4261
4262 /* Make sure it's not out of bounds. */
4263
4264 eassert (dst_y - gc->clip_y_origin >= 0);
4265 if ((dst_y - gc->clip_y_origin) + height > mask_info->height)
4266 return;
4267
4268 /* Now move mask to the position of the first row. */
4269
4270 mask += ((dst_y - gc->clip_y_origin)
4271 * mask_info->stride);
4272
4273 /* Determine how many bytes need to be copied. */
4274
4275 if (mask_offset > 0)
4276 temp = MIN (mask_info->width - mask_offset, width);
4277 else
4278 temp = MIN (mask_info->width, width);
4279
4280 /* Copy bytes according to the mask. */
4281
4282 while (--height)
4283 {
4284 long_src = (unsigned int *) src_current;
4285 long_dst = (unsigned int *) dst_current;
4286 mask_current = mask;
4287
4288#ifndef __aarch64__
4289 while (temp--)
4290 {
4291 /* Sign extend the mask. */
4292 height = *(signed char *) mask_current++;
4293
4294 /* Apply the mask. */
4295 *long_dst = ((*long_src & height)
4296 | (*long_dst & ~height));
4297 }
4298#else /* __aarch64__ */
4299 android_neon_mask_line (long_src, long_dst, mask, temp);
4300#endif /* __aarch64__ */
4301
4302 src_current += src_info->stride;
4303 dst_current += dst_info->stride;
4304 mask += mask_info->stride;
4305 }
4306 }
4307 }
4308}
4309
4310
4311/* Xor a rectangle SRC_X, SRC_Y, WIDTH and HEIGHT from SRC, described
4312 by SRC_INFO, to DST_X and DST_Y in DST, as described by DST_INFO.
4313
4314 Ignore the alpha channel when computing the exclusive-or of the
4315 destination pixel.
4316
4317 If MASK is set, mask the source data using MASK_INFO, translating
4318 it by GC->clip_x_origin and GC->clip_y_origin. MASK must be a
4319 pixmap of depth 1.
4320
4321 N.B. that currently only copies between bitmaps of depth 24 are
4322 implemented. */
4323
4324void
4325android_blit_xor (int src_x, int src_y, int width, int height,
4326 int dst_x, int dst_y, struct android_gc *gc,
4327 unsigned char *src, AndroidBitmapInfo *src_info,
4328 unsigned char *dst, AndroidBitmapInfo *dst_info,
4329 unsigned char *mask, AndroidBitmapInfo *mask_info)
4330{
4331 uintptr_t start, end;
4332 int mask_offset;
4333 size_t pixel, offset, offset1;
4334 unsigned char *src_current, *dst_current;
4335 unsigned char *mask_current;
4336 int overflow, temp, i, xdir;
4337 bool backwards;
4338 unsigned int *long_src, *long_dst;
4339
4340 /* Note that this alu hasn't been tested -- it probably does not
4341 work! */
4342 emacs_abort ();
4343
4344#if 0
4345 /* Assert that the specified coordinates are within bounds. */
4346 eassert (src_x >= 0 && src_y >= 0
4347 && dst_x >= 0 && dst_y >= 0);
4348 eassert (src_x + width <= src_info->width);
4349 eassert (src_y + height <= src_info->height);
4350 eassert (dst_x + width <= dst_info->width);
4351 eassert (dst_y + height <= dst_info->height);
4352
4353 /* Now check that each bitmap has the correct format. */
4354 eassert (src_info->format == dst_info->format
4355 && src_info->format == ANDROID_BITMAP_FORMAT_RGBA_8888);
4356 pixel = sizeof (unsigned int);
4357
4358 /* Android doesn't have A1 bitmaps, so A8 is used to represent
4359 packed bitmaps of depth 1. */
4360 eassert (!mask || mask_info->format == ANDROID_BITMAP_FORMAT_A_8);
4361
4362 /* Calculate the address of the first pixel of the first row to be
4363 copied in both src and dst. Compare them to determine the
4364 direction in which the copy is to take place. */
4365
4366 overflow = ckd_mul (&start, src_y, src_info->stride);
4367 overflow |= ckd_mul (&end, src_x, pixel);
4368 overflow |= ckd_add (&start, (uintptr_t) src, start);
4369
4370 if (overflow)
4371 return;
4372
4373 src_current = (unsigned char *) start;
4374
4375 overflow = ckd_mul (&start, dst_y, src_info->stride);
4376 overflow |= ckd_mul (&end, dst_x, pixel);
4377 overflow |= ckd_add (&start, (uintptr_t) dst, start);
4378
4379 if (overflow)
4380 return;
4381
4382 dst_current = (unsigned char *) start;
4383 backwards = false;
4384
4385 /* Now see if copying should proceed from the bottom up. */
4386
4387 if (src == dst && dst_current >= src_current)
4388 {
4389 backwards = true;
4390
4391 /* Walk src and dst from bottom to top, in order to avoid
4392 overlap. Calculate the coordinate of the last pixel of the
4393 last row in both src and dst. */
4394
4395 overflow = ckd_mul (&start, src_y + height - 1,
4396 src_info->stride);
4397 if (mask) /* If a mask is set, put the pointers before the end
4398 of the row. */
4399 overflow |= ckd_mul (&end, src_x + width - 1, pixel);
4400 else
4401 overflow |= ckd_mul (&end, src_x, pixel);
4402 overflow |= ckd_add (&start, start, end);
4403 overflow |= ckd_add (&start, (uintptr_t) src, start);
4404
4405 if (overflow)
4406 return;
4407
4408 src_current = (unsigned char *) start;
4409
4410 overflow = ckd_mul (&start, dst_y + height - 1,
4411 dst_info->stride);
4412 if (mask) /* If a mask is set, put the pointers before the end
4413 of the row. */
4414 overflow |= ckd_mul (&end, dst_x + width - 1, pixel);
4415 else
4416 overflow |= ckd_mul (&end, dst_x, pixel);
4417 overflow |= ckd_add (&start, start, end);
4418 overflow |= ckd_add (&start, (uintptr_t) dst, start);
4419
4420 if (overflow)
4421 return;
4422
4423 dst_current = (unsigned char *) start;
4424 }
4425
4426 if (!mask)
4427 {
4428 /* Change the direction of the copy depending on how SRC and DST
4429 overlap. */
4430
4431 for (i = 0; i < height; ++i)
4432 {
4433 if (backwards)
4434 {
4435 for (i = width - 1; i <= 0; --i)
4436 (((unsigned int *) dst_current)[i])
4437 /* Keep the alpha channel intact. */
4438 ^= (((unsigned int *) src_current)[i]) & 0xffffff;
4439
4440 /* Proceed to the last row. */
4441 src_current -= src_info->stride;
4442 dst_current -= dst_info->stride;
4443 }
4444 else
4445 {
4446 for (i = 0; i < width; ++i)
4447 (((unsigned int *) dst_current)[i])
4448 /* Keep the alpha channel intact. */
4449 ^= (((unsigned int *) src_current)[i]) & 0xffffff;
4450
4451 /* Proceed to the next row. */
4452 src_current += src_info->stride;
4453 dst_current += dst_info->stride;
4454 }
4455 }
4456 }
4457 else
4458 {
4459 /* Adjust the source and destination Y. The start is MAX
4460 (dst_y, gc->clip_y_origin); the difference between that value
4461 and dst_y is the offset to apply to src_y. */
4462
4463 temp = dst_y;
4464 dst_y = MAX (dst_y, gc->clip_y_origin);
4465 src_y += dst_y - temp;
4466 height -= dst_y - temp;
4467
4468 /* Verify that the bounds are correct. */
4469 eassert (dst_y + height
4470 <= gc->clip_y_origin + mask_info->height);
4471 eassert (dst_y >= gc->clip_y_origin);
4472
4473 /* There is a mask. For each scan line... */
4474
4475 if (backwards)
4476 {
4477 /* Calculate the number of pixels at the end of the
4478 mask. */
4479
4480 mask_offset = dst_x + width;
4481 mask_offset -= mask_info->width + gc->clip_x_origin;
4482
4483 if (mask_info < 0)
4484 mask_info = 0;
4485
4486 /* Calculate the last column of the mask that will be
4487 consulted. */
4488
4489 temp = dst_x - gc->clip_x_origin;
4490 temp += MIN (mask_info->width - temp,
4491 width - mask_offset);
4492
4493 if (temp < 0)
4494 return;
4495
4496 /* Now calculate the last row of the mask that will be
4497 consulted. */
4498 i = dst_y - gc->clip_y_origin + height;
4499
4500 /* Turn both into offsets. */
4501
4502 if (INT_MULTIPLY_WRAPV (temp, pixel, &offset)
4503 || INT_MULTIPLY_WRAPV (i, mask_info->stride, &offset1)
4504 || INT_ADD_WRAPV (offset, offset1, &offset)
4505 || INT_ADD_WRAPV ((uintptr_t) mask, offset, &start))
4506 return;
4507
4508 mask = mask_current = (unsigned char *) start;
4509
4510 for (i = 0; i < height; ++i)
4511 {
4512 /* Skip backwards past the end of the mask. */
4513
4514 long_src = (unsigned int *) (src_current - mask_offset * pixel);
4515 long_dst = (unsigned int *) (dst_current - mask_offset * pixel);
4516 mask = mask_current;
4517
4518 /* For each pixel covered by the mask... */
4519 temp = MIN (mask_info->width - temp, width - mask_offset);
4520 while (temp--)
4521 /* XOR the source to the destination, masked by the
4522 mask. */
4523 *long_dst-- ^= ((*(long_src--) & (0u - (*(mask--) & 1)))
4524 & 0xffffff);
4525
4526 /* Return to the last row. */
4527 src_current -= src_info->stride;
4528 dst_current -= dst_info->stride;
4529 mask_current -= mask_info->stride;
4530 }
4531 }
4532 else
4533 {
4534 /* Calculate the first column of the mask that will be
4535 consulted. */
4536
4537 mask_offset = dst_x - gc->clip_x_origin;
4538
4539 /* Adjust the mask by that much. */
4540
4541 if (mask_offset > 0)
4542 mask += mask_offset;
4543 else
4544 {
4545 /* Offset src and dst by the mask offset. */
4546 src_current += -mask_offset * pixel;
4547 dst_current += -mask_offset * pixel;
4548 width -= mask_offset;
4549 }
4550
4551 /* Now move mask to the position of the first row. */
4552
4553 mask += gc->clip_y_origin * mask_info->stride;
4554
4555 for (i = 0; i < height; ++i)
4556 {
4557 long_src = (unsigned int *) src_current;
4558 long_dst = (unsigned int *) dst_current;
4559 mask_current = mask;
4560
4561 if (mask_offset > 0)
4562 {
4563 /* Copy bytes according to the mask. */
4564 temp = MIN (mask_info->width - mask_offset, width);
4565 while (temp--)
4566 *long_dst++ ^= ((*(long_src++)
4567 & (0u - (*(mask_current++) & 1)))
4568 & 0xffffff);
4569 }
4570 else
4571 {
4572 /* Copy bytes according to the mask. */
4573 temp = MIN (mask_info->width, width);
4574 while (temp--)
4575 *long_dst++ = ((*(long_src++)
4576 & (0u - (*(mask_current++) & 1)))
4577 & 0xffffff);
4578 }
4579
4580 src_current += src_info->stride;
4581 dst_current += dst_info->stride;
4582 mask += mask_info->stride;
4583 }
4584 }
4585 }
4586#endif /* 0 */
4587}
4588
3916void 4589void
3917android_copy_area (android_drawable src, android_drawable dest, 4590android_copy_area (android_drawable src, android_drawable dest,
3918 struct android_gc *gc, int src_x, int src_y, 4591 struct android_gc *gc, int src_x, int src_y,
3919 unsigned int width, unsigned int height, 4592 unsigned int width, unsigned int height,
3920 int dest_x, int dest_y) 4593 int dest_x, int dest_y)
3921{ 4594{
3922 jobject src_object, dest_object, gcontext; 4595 jobject src_object, dest_object, mask;
4596 android_blit_func do_blit;
4597 AndroidBitmapInfo src_info, dest_info, mask_info;
4598 void *src_data, *dest_data, *mask_data;
4599 int n_clip_rects, i;
4600 bool flag;
4601 struct android_rectangle bounds, rect, temp, *clip_rectangles;
3923 4602
3924 src_object = android_resolve_handle2 (src, ANDROID_HANDLE_WINDOW, 4603 /* Perform the copy. Loop over each clip rectangle, unless none are
3925 ANDROID_HANDLE_PIXMAP); 4604 set. Also, obtain bitmaps for src and dst, and possibly the mask
3926 dest_object = android_resolve_handle2 (dest, ANDROID_HANDLE_WINDOW, 4605 as well if it is present. */
3927 ANDROID_HANDLE_PIXMAP);
3928 gcontext = android_resolve_handle (gc->gcontext,
3929 ANDROID_HANDLE_GCONTEXT);
3930 4606
3931 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env, 4607 src_data = android_lock_bitmap (src, &src_info, &src_object);
3932 emacs_service, 4608 if (!src_data)
3933 service_class.class, 4609 return;
3934 service_class.copy_area, 4610
3935 src_object, 4611 mask_data = mask = NULL;
3936 dest_object, 4612
3937 gcontext, 4613 if (src != dest)
3938 (jint) src_x, (jint) src_y, 4614 {
3939 (jint) width, (jint) height, 4615 dest_data = android_lock_bitmap (dest, &dest_info, &dest_object);
3940 (jint) dest_x, (jint) dest_y); 4616 if (!dest_data)
3941 android_exception_check (); 4617 goto fail;
4618 }
4619 else
4620 {
4621 dest_data = src_data;
4622 dest_info = src_info;
4623 }
4624
4625 /* Obtain the bitmap for the mask if necessary. */
4626
4627 if (gc->clip_mask)
4628 {
4629 mask_data = android_lock_bitmap (gc->clip_mask,
4630 &mask_info, &mask);
4631 if (!mask_data)
4632 goto fail1;
4633 }
4634
4635 /* Calculate the number of clip rectangles. */
4636 n_clip_rects = gc->num_clip_rects;
4637
4638 /* If n_clip_rects is -1, then no clipping is in effect. Set rect
4639 to the bounds of the destination. */
4640
4641 flag = n_clip_rects == -1;
4642 if (flag)
4643 {
4644 n_clip_rects = 1;
4645 clip_rectangles = &rect;
4646 }
4647 else if (!n_clip_rects)
4648 goto fail2;
4649 else
4650 clip_rectangles = gc->clip_rects;
4651
4652 /* Set rect to the bounds of the destination. */
4653
4654 rect.x = 0;
4655 rect.y = 0;
4656 rect.width = dest_info.width;
4657 rect.height = dest_info.height;
4658
4659 if (mask_data)
4660 {
4661 /* Clip width and height to that of the mask. */
4662
4663 if (src_x + width > mask_info.width)
4664 width = mask_info.width - src_x;
4665
4666 if (src_y + height > mask_info.height)
4667 height = mask_info.height - src_y;
4668 }
4669
4670 /* Clip width and height to that of the source. */
4671
4672 if (src_x + width > src_info.width)
4673 width = src_info.width - src_x;
4674
4675 if (src_y + height > src_info.height)
4676 height = src_info.height - src_y;
4677
4678 /* Return if the copy is outside the source. */
4679
4680 if (width <= 0 || height <= 0)
4681 goto fail2;
4682
4683 /* Look up the right function for the alu. */
4684
4685 switch (gc->function)
4686 {
4687 case ANDROID_GC_COPY:
4688 do_blit = android_blit_copy;
4689 break;
4690
4691 case ANDROID_GC_XOR:
4692 do_blit = android_blit_xor;
4693 break;
4694 }
4695
4696 /* Load the bounds of the destination rectangle. */
4697 bounds.x = dest_x;
4698 bounds.y = dest_y;
4699 bounds.width = width;
4700 bounds.height = height;
4701
4702 /* For each clip rectangle... */
4703 for (i = 0; i < n_clip_rects; ++i)
4704 {
4705 /* Calculate its intersection with the destination
4706 rectangle. */
4707
4708 if (!gui_intersect_rectangles (&clip_rectangles[i], &bounds,
4709 &temp))
4710 continue;
4711
4712 /* And that of the destination itself. */
4713
4714 if (!flag && !gui_intersect_rectangles (&temp, &rect, &temp))
4715 continue;
4716
4717 /* Now perform the copy. */
4718 (*do_blit) (src_x + temp.x - dest_x, /* temp.x relative to src_x */
4719 src_y + temp.y - dest_y, /* temp.y relative to src_y */
4720 temp.width, /* Width of area to copy. */
4721 temp.height, /* Height of area to copy. */
4722 temp.x, temp.y, /* Coordinates to copy to. */
4723 gc, /* GC. */
4724 src_data, &src_info, /* Source drawable. */
4725 dest_data, &dest_info, /* Destination drawable. */
4726 mask_data, &mask_info); /* Mask drawable. */
4727 }
4728
4729 /* Now damage the destination drawable accordingly, should it be a
4730 window. */
4731
4732 if (android_handles[dest].type == ANDROID_HANDLE_WINDOW)
4733 android_damage_window (dest, &bounds);
4734
4735 fail2:
4736 if (mask)
4737 {
4738 AndroidBitmap_unlockPixels (android_java_env, mask);
4739 ANDROID_DELETE_LOCAL_REF (mask);
4740 }
4741 fail1:
4742 if (src != dest)
4743 {
4744 AndroidBitmap_unlockPixels (android_java_env, dest_object);
4745 ANDROID_DELETE_LOCAL_REF (dest_object);
4746 }
4747 fail:
4748 AndroidBitmap_unlockPixels (android_java_env, src_object);
4749 ANDROID_DELETE_LOCAL_REF (src_object);
3942} 4750}
3943 4751
4752
4753
3944void 4754void
3945android_free_pixmap (android_pixmap pixmap) 4755android_free_pixmap (android_pixmap pixmap)
3946{ 4756{
@@ -4815,26 +5625,27 @@ android_wc_lookup_string (android_key_pressed_event *event,
4815 5625
4816/* Low level drawing primitives. */ 5626/* Low level drawing primitives. */
4817 5627
4818/* Lock the bitmap corresponding to the window WINDOW. Return the 5628/* Lock the bitmap corresponding to the drawable DRAWABLE. Return the
4819 bitmap data upon success, and store the bitmap object in 5629 bitmap data upon success, and store the bitmap object in
4820 BITMAP_RETURN. Value is NULL upon failure. 5630 BITMAP_RETURN. Value is NULL upon failure.
4821 5631
4822 The caller must take care to unlock the bitmap data afterwards. */ 5632 The caller must take care to unlock the bitmap data afterwards. */
4823 5633
4824unsigned char * 5634unsigned char *
4825android_lock_bitmap (android_window window, 5635android_lock_bitmap (android_window drawable,
4826 AndroidBitmapInfo *bitmap_info, 5636 AndroidBitmapInfo *bitmap_info,
4827 jobject *bitmap_return) 5637 jobject *bitmap_return)
4828{ 5638{
4829 jobject drawable, bitmap; 5639 jobject object, bitmap;
4830 void *data; 5640 void *data;
4831 5641
4832 drawable = android_resolve_handle (window, ANDROID_HANDLE_WINDOW); 5642 object = android_resolve_handle2 (drawable, ANDROID_HANDLE_WINDOW,
5643 ANDROID_HANDLE_PIXMAP);
4833 5644
4834 /* Look up the drawable and get the bitmap corresponding to it. 5645 /* Look up the drawable and get the bitmap corresponding to it.
4835 Then, lock the bitmap's bits. */ 5646 Then, lock the bitmap's bits. */
4836 bitmap = (*android_java_env)->CallObjectMethod (android_java_env, 5647 bitmap = (*android_java_env)->CallObjectMethod (android_java_env,
4837 drawable, 5648 object,
4838 drawable_class.get_bitmap); 5649 drawable_class.get_bitmap);
4839 if (!bitmap) 5650 if (!bitmap)
4840 /* NULL is returned when the bitmap does not currently exist due 5651 /* NULL is returned when the bitmap does not currently exist due