mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-26 07:11:34 -08:00
Implement android_copy_area in C
* java/org/gnu/emacs/EmacsCopyArea.java: Remove file. * java/org/gnu/emacs/EmacsService.java (EmacsService, copyArea): Delete function. * src/android.c (struct android_emacs_service) (android_init_emacs_service): Remove `copy_area'. (android_create_gc, android_change_gc, android_get_gc_values): Record new GC values. (android_neon_mask_line): New function. (android_blit_copy, android_blit_xor): New functions. (android_copy_area): Implement in C. (android_lock_bitmap): Accept drawables instead of windows. * src/android.h: Adjust prototype for `android_lock_bitmap'. * src/androidgui.h (struct android_gc): Record last known GC values.
This commit is contained in:
parent
327d2d0131
commit
00671b1843
5 changed files with 883 additions and 275 deletions
|
|
@ -1,206 +0,0 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff.Mode;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Xfermode;
|
||||
|
||||
public final class EmacsCopyArea
|
||||
{
|
||||
private static Xfermode overAlu;
|
||||
|
||||
static
|
||||
{
|
||||
overAlu = new PorterDuffXfermode (Mode.SRC_OVER);
|
||||
};
|
||||
|
||||
private static void
|
||||
insetRectBy (Rect rect, int left, int top, int right,
|
||||
int bottom)
|
||||
{
|
||||
rect.left += left;
|
||||
rect.top += top;
|
||||
rect.right -= right;
|
||||
rect.bottom -= bottom;
|
||||
}
|
||||
|
||||
public static void
|
||||
perform (EmacsDrawable source, EmacsGC gc,
|
||||
EmacsDrawable destination,
|
||||
int src_x, int src_y, int width, int height,
|
||||
int dest_x, int dest_y)
|
||||
{
|
||||
int i;
|
||||
Bitmap bitmap;
|
||||
Paint maskPaint, paint;
|
||||
Canvas maskCanvas, canvas;
|
||||
Bitmap srcBitmap, maskBitmap, clipBitmap;
|
||||
Rect rect, maskRect, srcRect, dstRect, maskDestRect;
|
||||
boolean needFill;
|
||||
|
||||
/* TODO implement stippling. */
|
||||
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
|
||||
return;
|
||||
|
||||
paint = gc.gcPaint;
|
||||
|
||||
canvas = destination.lockCanvas (gc);
|
||||
|
||||
if (canvas == null)
|
||||
return;
|
||||
|
||||
/* A copy must be created or drawBitmap could end up overwriting
|
||||
itself. */
|
||||
srcBitmap = source.getBitmap ();
|
||||
|
||||
/* If srcBitmap is out of bounds, then adjust the source rectangle
|
||||
to be within bounds. Note that tiling on windows with
|
||||
backgrounds is unimplemented. */
|
||||
|
||||
if (src_x < 0)
|
||||
{
|
||||
width += src_x;
|
||||
dest_x -= src_x;
|
||||
src_x = 0;
|
||||
}
|
||||
|
||||
if (src_y < 0)
|
||||
{
|
||||
height += src_y;
|
||||
dest_y -= src_y;
|
||||
src_y = 0;
|
||||
}
|
||||
|
||||
if (src_x + width > srcBitmap.getWidth ())
|
||||
width = srcBitmap.getWidth () - src_x;
|
||||
|
||||
if (src_y + height > srcBitmap.getHeight ())
|
||||
height = srcBitmap.getHeight () - src_y;
|
||||
|
||||
/* If width and height are empty or negative, then skip the entire
|
||||
CopyArea operation lest createBitmap throw an exception. */
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
rect = new Rect (dest_x, dest_y, dest_x + width,
|
||||
dest_y + height);
|
||||
|
||||
if (gc.clip_mask == null)
|
||||
{
|
||||
if (source == destination)
|
||||
{
|
||||
/* Create a copy of the bitmap, since Android can't handle
|
||||
overlapping copies. */
|
||||
bitmap = Bitmap.createBitmap (srcBitmap,
|
||||
src_x, src_y, width,
|
||||
height);
|
||||
canvas.drawBitmap (bitmap, null, rect, paint);
|
||||
bitmap.recycle ();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* But here the bitmaps are known to not overlap, so avoid
|
||||
that extra consing overhead. */
|
||||
|
||||
srcRect = new Rect (src_x, src_y, src_x + width,
|
||||
src_y + height);
|
||||
canvas.drawBitmap (srcBitmap, srcRect, rect, paint);
|
||||
}
|
||||
}
|
||||
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 (dest_x, dest_y,
|
||||
dest_x + width,
|
||||
dest_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 ()));
|
||||
clipBitmap = gc.clip_mask.bitmap;
|
||||
|
||||
if (!maskRect.setIntersect (dstRect, maskRect))
|
||||
/* There is no intersection between the clip mask and the
|
||||
dest rect. */
|
||||
return;
|
||||
|
||||
/* Now figure out which part of the source corresponds to
|
||||
maskRect and return it relative to srcBitmap. */
|
||||
srcRect = new Rect (src_x, src_y, src_x + width,
|
||||
src_y + height);
|
||||
insetRectBy (srcRect, maskRect.left - dstRect.left,
|
||||
maskRect.top - dstRect.top,
|
||||
maskRect.right - dstRect.right,
|
||||
maskRect.bottom - dstRect.bottom);
|
||||
|
||||
/* 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);
|
||||
maskPaint = new Paint ();
|
||||
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 ()),
|
||||
maskPaint);
|
||||
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.setXfermode (EmacsGC.srcInAlu);
|
||||
|
||||
/* Draw the source. */
|
||||
maskDestRect = new Rect (0, 0, srcRect.width (),
|
||||
srcRect.height ());
|
||||
maskCanvas.drawBitmap (srcBitmap, srcRect, maskDestRect,
|
||||
maskPaint);
|
||||
|
||||
/* Finally, draw the mask bitmap to the destination. */
|
||||
paint.setXfermode (overAlu);
|
||||
canvas.drawBitmap (maskBitmap, null, maskRect, paint);
|
||||
gc.resetXfermode ();
|
||||
|
||||
/* Recycle this unused bitmap. */
|
||||
maskBitmap.recycle ();
|
||||
}
|
||||
|
||||
destination.damageRect (rect);
|
||||
}
|
||||
}
|
||||
|
|
@ -374,18 +374,6 @@ public final class EmacsService extends Service
|
|||
EmacsDrawPoint.perform (drawable, gc, x, y);
|
||||
}
|
||||
|
||||
public void
|
||||
copyArea (EmacsDrawable srcDrawable, EmacsDrawable dstDrawable,
|
||||
EmacsGC gc,
|
||||
int srcX, int srcY, int width, int height, int destX,
|
||||
int destY)
|
||||
{
|
||||
checkEmacsThread ();
|
||||
EmacsCopyArea.perform (srcDrawable, gc, dstDrawable,
|
||||
srcX, srcY, width, height, destX,
|
||||
destY);
|
||||
}
|
||||
|
||||
public void
|
||||
clearWindow (EmacsWindow window)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue