1 /* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3 Copyright (C) 2023 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20 package org.gnu.emacs;
21
22 import android.graphics.Bitmap;
23 import android.graphics.Canvas;
24 import android.graphics.Paint;
25 import android.graphics.Rect;
26 import android.graphics.RectF;
27
28 import android.util.Log;
29
30 public final class EmacsDrawRectangle
31 {
32 public static void
33 perform (EmacsDrawable drawable, EmacsGC gc,
34 int x, int y, int width, int height)
35 {
36 Paint maskPaint, paint;
37 Canvas maskCanvas;
38 Bitmap maskBitmap;
39 Rect maskRect, dstRect;
40 Canvas canvas;
41 Bitmap clipBitmap;
42
43 /* TODO implement stippling. */
44 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
45 return;
46
47 canvas = drawable.lockCanvas (gc);
48
49 if (canvas == null)
50 return;
51
52 paint = gc.gcPaint;
53 paint.setStyle (Paint.Style.STROKE);
54
55 if (gc.clip_mask == null)
56 /* Use canvas.drawRect with a RectF. That seems to reliably
57 get PostScript behavior. */
58 canvas.drawRect (new RectF (x + 0.5f, y + 0.5f,
59 x + width + 0.5f,
60 y + height + 0.5f),
61 paint);
62 else
63 {
64 /* Drawing with a clip mask involves calculating the
65 intersection of the clip mask with the dst rect, and
66 extrapolating the corresponding part of the src rect. */
67 clipBitmap = gc.clip_mask.bitmap;
68 dstRect = new Rect (x, y, x + width, y + height);
69 maskRect = new Rect (gc.clip_x_origin,
70 gc.clip_y_origin,
71 (gc.clip_x_origin
72 + clipBitmap.getWidth ()),
73 (gc.clip_y_origin
74 + clipBitmap.getHeight ()));
75
76 if (!maskRect.setIntersect (dstRect, maskRect))
77 /* There is no intersection between the clip mask and the
78 dest rect. */
79 return;
80
81 /* Finally, create a temporary bitmap that is the size of
82 maskRect. */
83
84 maskBitmap
85 = Bitmap.createBitmap (maskRect.width (), maskRect.height (),
86 Bitmap.Config.ARGB_8888);
87
88 /* Draw the mask onto the maskBitmap. */
89 maskCanvas = new Canvas (maskBitmap);
90 maskRect.offset (-gc.clip_x_origin,
91 -gc.clip_y_origin);
92 maskCanvas.drawBitmap (gc.clip_mask.bitmap,
93 maskRect, new Rect (0, 0,
94 maskRect.width (),
95 maskRect.height ()),
96 paint);
97 maskRect.offset (gc.clip_x_origin,
98 gc.clip_y_origin);
99
100 /* Set the transfer mode to SRC_IN to preserve only the parts
101 of the source that overlap with the mask. */
102 maskPaint = new Paint ();
103 maskPaint.setXfermode (EmacsGC.srcInAlu);
104 maskPaint.setStyle (Paint.Style.STROKE);
105
106 /* Draw the source. */
107 maskCanvas.drawRect (maskRect, maskPaint);
108
109 /* Finally, draw the mask bitmap to the destination. */
110 paint.setXfermode (null);
111 canvas.drawBitmap (maskBitmap, null, maskRect, paint);
112
113 /* Recycle this unused bitmap. */
114 maskBitmap.recycle ();
115 }
116
117 drawable.damageRect (new Rect (x, y, x + width + 1,
118 y + height + 1));
119 }
120 }