diff options
Diffstat (limited to 'src/android.c')
| -rw-r--r-- | src/android.c | 923 |
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 | |||
| 3941 | typedef 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 | |||
| 3954 | static void | ||
| 3955 | android_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 | |||
| 4036 | void | ||
| 4037 | android_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 | |||
| 4324 | void | ||
| 4325 | android_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 | |||
| 3916 | void | 4589 | void |
| 3917 | android_copy_area (android_drawable src, android_drawable dest, | 4590 | android_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 = ▭ | ||
| 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 | |||
| 3944 | void | 4754 | void |
| 3945 | android_free_pixmap (android_pixmap pixmap) | 4755 | android_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 | ||
| 4824 | unsigned char * | 5634 | unsigned char * |
| 4825 | android_lock_bitmap (android_window window, | 5635 | android_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 |