aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorPo Lu2023-01-08 15:39:02 +0800
committerPo Lu2023-01-08 15:39:02 +0800
commit695e26079eb60d10ffe25bb8ae91ebc6131fb27d (patch)
treebc18692c1e4c0f5aa3e6707850f4c2023bc75e81 /java
parente816e570393a964383e8b42330f5582c4c0a54f2 (diff)
downloademacs-695e26079eb60d10ffe25bb8ae91ebc6131fb27d.tar.gz
emacs-695e26079eb60d10ffe25bb8ae91ebc6131fb27d.zip
Update Java part of Android port
* java/org/gnu/emacs/EmacsCopyArea.java (EmacsCopyArea, perform) (paintTo): * java/org/gnu/emacs/EmacsDrawLine.java (EmacsDrawLine): * java/org/gnu/emacs/EmacsDrawPoint.java (EmacsDrawPoint): * java/org/gnu/emacs/EmacsDrawRectangle.java (EmacsDrawRectangle) (paintTo): * java/org/gnu/emacs/EmacsDrawable.java (EmacsDrawable): * java/org/gnu/emacs/EmacsFillPolygon.java (EmacsFillPolygon): * java/org/gnu/emacs/EmacsFillRectangle.java (EmacsFillRectangle): * java/org/gnu/emacs/EmacsFontDriver.java (EmacsFontDriver): * java/org/gnu/emacs/EmacsGC.java (EmacsGC): * java/org/gnu/emacs/EmacsNative.java (EmacsNative): * java/org/gnu/emacs/EmacsPixmap.java (EmacsPixmap): * java/org/gnu/emacs/EmacsSdk23FontDriver.java (EmacsSdk23FontDriver): * java/org/gnu/emacs/EmacsSdk7FontDriver.java (EmacsSdk7FontDriver, textExtents1, textExtents, draw): * java/org/gnu/emacs/EmacsService.java (EmacsService, copyArea): * java/org/gnu/emacs/EmacsSurfaceView.java (EmacsSurfaceView): * java/org/gnu/emacs/EmacsView.java (EmacsView, onLayout) (onFocusChanged): * java/org/gnu/emacs/EmacsWindow.java (EmacsWindow, run) (resizeWindow, lockCanvas, getBitmap, onKeyDown, onKeyUp) (onActivityDetached): Move rendering to main thread. Make drawing operations completely static.
Diffstat (limited to 'java')
-rw-r--r--java/org/gnu/emacs/EmacsCopyArea.java131
-rw-r--r--java/org/gnu/emacs/EmacsDrawLine.java120
-rw-r--r--java/org/gnu/emacs/EmacsDrawPoint.java11
-rw-r--r--java/org/gnu/emacs/EmacsDrawRectangle.java160
-rw-r--r--java/org/gnu/emacs/EmacsDrawable.java1
-rw-r--r--java/org/gnu/emacs/EmacsFillPolygon.java128
-rw-r--r--java/org/gnu/emacs/EmacsFillRectangle.java152
-rw-r--r--java/org/gnu/emacs/EmacsFontDriver.java2
-rw-r--r--java/org/gnu/emacs/EmacsGC.java77
-rw-r--r--java/org/gnu/emacs/EmacsNative.java22
-rw-r--r--java/org/gnu/emacs/EmacsPixmap.java9
-rw-r--r--java/org/gnu/emacs/EmacsSdk23FontDriver.java71
-rw-r--r--java/org/gnu/emacs/EmacsSdk7FontDriver.java139
-rw-r--r--java/org/gnu/emacs/EmacsService.java122
-rw-r--r--java/org/gnu/emacs/EmacsSurfaceView.java22
-rw-r--r--java/org/gnu/emacs/EmacsView.java133
-rw-r--r--java/org/gnu/emacs/EmacsWindow.java141
17 files changed, 685 insertions, 756 deletions
diff --git a/java/org/gnu/emacs/EmacsCopyArea.java b/java/org/gnu/emacs/EmacsCopyArea.java
index 0dd5b2c1fb6..00e817bb97d 100644
--- a/java/org/gnu/emacs/EmacsCopyArea.java
+++ b/java/org/gnu/emacs/EmacsCopyArea.java
@@ -27,54 +27,16 @@ import android.graphics.PorterDuffXfermode;
27import android.graphics.Rect; 27import android.graphics.Rect;
28import android.graphics.Xfermode; 28import android.graphics.Xfermode;
29 29
30public class EmacsCopyArea implements EmacsPaintReq 30public class EmacsCopyArea
31{ 31{
32 private int src_x, src_y, dest_x, dest_y, width, height; 32 private static Xfermode overAlu;
33 private EmacsDrawable destination, source;
34 private EmacsGC immutableGC;
35 private static Xfermode xorAlu, srcInAlu, overAlu;
36 33
37 static 34 static
38 { 35 {
39 overAlu = new PorterDuffXfermode (Mode.SRC_OVER); 36 overAlu = new PorterDuffXfermode (Mode.SRC_OVER);
40 xorAlu = new PorterDuffXfermode (Mode.XOR);
41 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
42 }; 37 };
43 38
44 public 39 private static void
45 EmacsCopyArea (EmacsDrawable source, EmacsDrawable destination,
46 int src_x, int src_y, int width, int height,
47 int dest_x, int dest_y, EmacsGC immutableGC)
48 {
49 Bitmap bitmap;
50
51 this.destination = destination;
52 this.source = source;
53 this.src_x = src_x;
54 this.src_y = src_y;
55 this.width = width;
56 this.height = height;
57 this.dest_x = dest_x;
58 this.dest_y = dest_y;
59 this.immutableGC = immutableGC;
60 }
61
62 @Override
63 public Rect
64 getRect ()
65 {
66 return new Rect (dest_x, dest_y, dest_x + width,
67 dest_y + height);
68 }
69
70 @Override
71 public EmacsDrawable
72 getDrawable ()
73 {
74 return destination;
75 }
76
77 private void
78 insetRectBy (Rect rect, int left, int top, int right, 40 insetRectBy (Rect rect, int left, int top, int right,
79 int bottom) 41 int bottom)
80 { 42 {
@@ -84,30 +46,38 @@ public class EmacsCopyArea implements EmacsPaintReq
84 rect.bottom -= bottom; 46 rect.bottom -= bottom;
85 } 47 }
86 48
87 @Override 49 public static void
88 public EmacsGC 50 perform (EmacsDrawable source, EmacsGC gc,
89 getGC () 51 EmacsDrawable destination,
90 { 52 int src_x, int src_y, int width, int height,
91 return immutableGC; 53 int dest_x, int dest_y)
92 }
93
94 @Override
95 public void
96 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
97 { 54 {
98 int alu; 55 int i;
99 Bitmap bitmap; 56 Bitmap bitmap;
100 Paint maskPaint; 57 Paint maskPaint, paint;
101 Canvas maskCanvas; 58 Canvas maskCanvas, canvas;
102 Bitmap srcBitmap, maskBitmap, clipBitmap; 59 Bitmap srcBitmap, maskBitmap, clipBitmap;
103 Rect rect, maskRect, srcRect, dstRect, maskDestRect; 60 Rect rect, maskRect, srcRect, dstRect, maskDestRect;
104 boolean needFill; 61 boolean needFill;
105 62
106 /* TODO implement stippling. */ 63 /* TODO implement stippling. */
107 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED) 64 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
108 return; 65 return;
109 66
110 alu = immutableGC.function; 67 paint = gc.gcPaint;
68
69 canvas = destination.lockCanvas ();
70
71 if (canvas == null)
72 return;
73
74 canvas.save ();
75
76 if (gc.real_clip_rects != null)
77 {
78 for (i = 0; i < gc.real_clip_rects.length; ++i)
79 canvas.clipRect (gc.real_clip_rects[i]);
80 }
111 81
112 /* A copy must be created or drawBitmap could end up overwriting 82 /* A copy must be created or drawBitmap could end up overwriting
113 itself. */ 83 itself. */
@@ -137,14 +107,10 @@ public class EmacsCopyArea implements EmacsPaintReq
137 if (src_y + height > srcBitmap.getHeight ()) 107 if (src_y + height > srcBitmap.getHeight ())
138 height = srcBitmap.getHeight () - src_y; 108 height = srcBitmap.getHeight () - src_y;
139 109
140 rect = getRect (); 110 rect = new Rect (dest_x, dest_y, dest_x + width,
141 111 dest_y + height);
142 if (alu == EmacsGC.GC_COPY)
143 paint.setXfermode (null);
144 else
145 paint.setXfermode (xorAlu);
146 112
147 if (immutableGC.clip_mask == null) 113 if (gc.clip_mask == null)
148 { 114 {
149 bitmap = Bitmap.createBitmap (srcBitmap, 115 bitmap = Bitmap.createBitmap (srcBitmap,
150 src_x, src_y, width, 116 src_x, src_y, width,
@@ -156,17 +122,17 @@ public class EmacsCopyArea implements EmacsPaintReq
156 /* Drawing with a clip mask involves calculating the 122 /* Drawing with a clip mask involves calculating the
157 intersection of the clip mask with the dst rect, and 123 intersection of the clip mask with the dst rect, and
158 extrapolating the corresponding part of the src rect. */ 124 extrapolating the corresponding part of the src rect. */
159 clipBitmap = immutableGC.clip_mask.bitmap; 125 clipBitmap = gc.clip_mask.bitmap;
160 dstRect = new Rect (dest_x, dest_y, 126 dstRect = new Rect (dest_x, dest_y,
161 dest_x + width, 127 dest_x + width,
162 dest_y + height); 128 dest_y + height);
163 maskRect = new Rect (immutableGC.clip_x_origin, 129 maskRect = new Rect (gc.clip_x_origin,
164 immutableGC.clip_y_origin, 130 gc.clip_y_origin,
165 (immutableGC.clip_x_origin 131 (gc.clip_x_origin
166 + clipBitmap.getWidth ()), 132 + clipBitmap.getWidth ()),
167 (immutableGC.clip_y_origin 133 (gc.clip_y_origin
168 + clipBitmap.getHeight ())); 134 + clipBitmap.getHeight ()));
169 clipBitmap = immutableGC.clip_mask.bitmap; 135 clipBitmap = gc.clip_mask.bitmap;
170 136
171 if (!maskRect.setIntersect (dstRect, maskRect)) 137 if (!maskRect.setIntersect (dstRect, maskRect))
172 /* There is no intersection between the clip mask and the 138 /* There is no intersection between the clip mask and the
@@ -191,20 +157,21 @@ public class EmacsCopyArea implements EmacsPaintReq
191 157
192 /* Draw the mask onto the maskBitmap. */ 158 /* Draw the mask onto the maskBitmap. */
193 maskCanvas = new Canvas (maskBitmap); 159 maskCanvas = new Canvas (maskBitmap);
194 maskRect.offset (-immutableGC.clip_x_origin, 160 maskPaint = new Paint ();
195 -immutableGC.clip_y_origin); 161 maskRect.offset (-gc.clip_x_origin,
196 maskCanvas.drawBitmap (immutableGC.clip_mask.bitmap, 162 -gc.clip_y_origin);
197 maskRect, new Rect (0, 0, 163 maskCanvas.drawBitmap (gc.clip_mask.bitmap,
198 maskRect.width (), 164 maskRect,
199 maskRect.height ()), 165 new Rect (0, 0,
200 paint); 166 maskRect.width (),
201 maskRect.offset (immutableGC.clip_x_origin, 167 maskRect.height ()),
202 immutableGC.clip_y_origin); 168 maskPaint);
169 maskRect.offset (gc.clip_x_origin,
170 gc.clip_y_origin);
203 171
204 /* Set the transfer mode to SRC_IN to preserve only the parts 172 /* Set the transfer mode to SRC_IN to preserve only the parts
205 of the source that overlap with the mask. */ 173 of the source that overlap with the mask. */
206 maskPaint = new Paint (); 174 maskPaint.setXfermode (EmacsGC.srcInAlu);
207 maskPaint.setXfermode (srcInAlu);
208 175
209 /* Draw the source. */ 176 /* Draw the source. */
210 maskDestRect = new Rect (0, 0, srcRect.width (), 177 maskDestRect = new Rect (0, 0, srcRect.width (),
@@ -215,6 +182,10 @@ public class EmacsCopyArea implements EmacsPaintReq
215 /* Finally, draw the mask bitmap to the destination. */ 182 /* Finally, draw the mask bitmap to the destination. */
216 paint.setXfermode (overAlu); 183 paint.setXfermode (overAlu);
217 canvas.drawBitmap (maskBitmap, null, maskRect, paint); 184 canvas.drawBitmap (maskBitmap, null, maskRect, paint);
185 gc.resetXfermode ();
218 } 186 }
187
188 canvas.restore ();
189 destination.damageRect (rect);
219 } 190 }
220} 191}
diff --git a/java/org/gnu/emacs/EmacsDrawLine.java b/java/org/gnu/emacs/EmacsDrawLine.java
index 6389031bbfa..8941d4c217f 100644
--- a/java/org/gnu/emacs/EmacsDrawLine.java
+++ b/java/org/gnu/emacs/EmacsDrawLine.java
@@ -29,109 +29,49 @@ import android.graphics.PorterDuffXfermode;
29import android.graphics.Rect; 29import android.graphics.Rect;
30import android.graphics.Xfermode; 30import android.graphics.Xfermode;
31 31
32public class EmacsDrawLine implements EmacsPaintReq 32public class EmacsDrawLine
33{ 33{
34 private int x, y, x2, y2; 34 public static void
35 private EmacsDrawable drawable; 35 perform (EmacsDrawable drawable, EmacsGC gc,
36 private EmacsGC immutableGC; 36 int x, int y, int x2, int y2)
37 private static Xfermode xorAlu, srcInAlu;
38
39 static
40 { 37 {
41 xorAlu = new PorterDuffXfermode (Mode.XOR); 38 Rect rect;
42 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN); 39 Canvas canvas;
43 }; 40 Paint paint;
41 int i;
44 42
45 public 43 /* TODO implement stippling. */
46 EmacsDrawLine (EmacsDrawable drawable, int x, int y, 44 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
47 int x2, int y2, EmacsGC immutableGC) 45 return;
48 {
49 this.drawable = drawable;
50 this.x = x;
51 this.y = y;
52 this.x2 = x2;
53 this.y2 = y2;
54 this.immutableGC = immutableGC;
55 }
56 46
57 @Override 47 paint = gc.gcPaint;
58 public Rect 48 rect = new Rect (Math.min (x, x2 + 1),
59 getRect ()
60 {
61 return new Rect (Math.min (x, x2 + 1),
62 Math.min (y, y2 + 1), 49 Math.min (y, y2 + 1),
63 Math.max (x2 + 1, x), 50 Math.max (x2 + 1, x),
64 Math.max (y2 + 1, y)); 51 Math.max (y2 + 1, y));
65 } 52 canvas = drawable.lockCanvas ();
66
67 @Override
68 public EmacsDrawable
69 getDrawable ()
70 {
71 return drawable;
72 }
73
74 @Override
75 public EmacsGC
76 getGC ()
77 {
78 return immutableGC;
79 }
80
81 @Override
82 public void
83 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
84 {
85 int alu;
86 Paint maskPaint;
87 Canvas maskCanvas;
88 Bitmap maskBitmap;
89 Rect rect, srcRect;
90 int width, height;
91 53
92 /* TODO implement stippling. */ 54 if (canvas == null)
93 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
94 return; 55 return;
95 56
96 alu = immutableGC.function; 57 canvas.save ();
97 rect = getRect ();
98 width = rect.width ();
99 height = rect.height ();
100
101 paint.setStyle (Paint.Style.STROKE);
102
103 if (alu == EmacsGC.GC_COPY)
104 paint.setXfermode (null);
105 else
106 paint.setXfermode (xorAlu);
107 58
108 if (immutableGC.clip_mask == null) 59 if (gc.real_clip_rects != null)
109 {
110 paint.setColor (immutableGC.foreground | 0xff000000);
111 canvas.drawLine ((float) x, (float) y,
112 (float) x2, (float) y2,
113 paint);
114 }
115 else
116 { 60 {
117 maskPaint = new Paint (); 61 for (i = 0; i < gc.real_clip_rects.length; ++i)
118 maskBitmap 62 canvas.clipRect (gc.real_clip_rects[i]);
119 = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888,
120 true);
121
122 if (maskBitmap == null)
123 return;
124
125 maskPaint.setXfermode (srcInAlu);
126 maskPaint.setColor (immutableGC.foreground | 0xff000000);
127 maskCanvas = new Canvas (maskBitmap);
128 srcRect = new Rect (0, 0, maskBitmap.getWidth (),
129 maskBitmap.getHeight ());
130 maskCanvas.drawLine (0.0f, 0.0f, (float) Math.abs (x - x2),
131 (float) Math.abs (y - y2), maskPaint);
132 canvas.drawBitmap (maskBitmap, srcRect, rect, paint);
133 } 63 }
134 64
135 paint.setXfermode (null); 65 paint.setStyle (Paint.Style.STROKE);
66
67 if (gc.clip_mask == null)
68 canvas.drawLine ((float) x, (float) y,
69 (float) x2, (float) y2,
70 paint);
71
72 /* DrawLine with clip mask not implemented; it is not used by
73 Emacs. */
74 canvas.restore ();
75 drawable.damageRect (rect);
136 } 76 }
137} 77}
diff --git a/java/org/gnu/emacs/EmacsDrawPoint.java b/java/org/gnu/emacs/EmacsDrawPoint.java
index 772757ff424..3bc7be17961 100644
--- a/java/org/gnu/emacs/EmacsDrawPoint.java
+++ b/java/org/gnu/emacs/EmacsDrawPoint.java
@@ -19,12 +19,13 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 19
20package org.gnu.emacs; 20package org.gnu.emacs;
21 21
22public class EmacsDrawPoint extends EmacsDrawRectangle 22public class EmacsDrawPoint
23{ 23{
24 public 24 public static void
25 EmacsDrawPoint (EmacsDrawable drawable, int x, int y, 25 perform (EmacsDrawable drawable,
26 EmacsGC immutableGC) 26 EmacsGC immutableGC, int x, int y)
27 { 27 {
28 super (drawable, x, y, 1, 1, immutableGC); 28 EmacsDrawRectangle.perform (drawable, immutableGC,
29 x, y, 1, 1);
29 } 30 }
30} 31}
diff --git a/java/org/gnu/emacs/EmacsDrawRectangle.java b/java/org/gnu/emacs/EmacsDrawRectangle.java
index e3f28227146..b42e9556e8c 100644
--- a/java/org/gnu/emacs/EmacsDrawRectangle.java
+++ b/java/org/gnu/emacs/EmacsDrawRectangle.java
@@ -22,110 +22,104 @@ package org.gnu.emacs;
22import android.graphics.Bitmap; 22import android.graphics.Bitmap;
23import android.graphics.Canvas; 23import android.graphics.Canvas;
24import android.graphics.Paint; 24import android.graphics.Paint;
25import android.graphics.PorterDuff.Mode;
26import android.graphics.PorterDuffXfermode;
27import android.graphics.Rect; 25import android.graphics.Rect;
28import android.graphics.Xfermode;
29 26
30public class EmacsDrawRectangle implements EmacsPaintReq 27import android.util.Log;
31{
32 private int x, y, width, height;
33 private EmacsDrawable drawable;
34 private EmacsGC immutableGC;
35 private static Xfermode xorAlu, srcInAlu;
36
37 static
38 {
39 xorAlu = new PorterDuffXfermode (Mode.XOR);
40 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
41 };
42
43 public
44 EmacsDrawRectangle (EmacsDrawable drawable, int x, int y,
45 int width, int height,
46 EmacsGC immutableGC)
47 {
48 this.drawable = drawable;
49 this.x = x;
50 this.y = y;
51 this.width = width;
52 this.height = height;
53 this.immutableGC = immutableGC;
54 }
55 28
56 @Override 29public class EmacsDrawRectangle
57 public Rect 30{
58 getRect () 31 public static void
59 { 32 perform (EmacsDrawable drawable, EmacsGC gc,
60 /* Canvas.drawRect actually behaves exactly like PolyRectangle wrt 33 int x, int y, int width, int height)
61 to where the lines are placed, so extend the width and height
62 by 1 in the damage rectangle. */
63 return new Rect (x, y, x + width + 1, y + height + 1);
64 }
65
66 @Override
67 public EmacsDrawable
68 getDrawable ()
69 {
70 return drawable;
71 }
72
73 @Override
74 public EmacsGC
75 getGC ()
76 {
77 return immutableGC;
78 }
79
80 @Override
81 public void
82 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
83 { 34 {
84 int alu; 35 int i;
85 Paint maskPaint; 36 Paint maskPaint, paint;
86 Canvas maskCanvas; 37 Canvas maskCanvas;
87 Bitmap maskBitmap; 38 Bitmap maskBitmap;
88 Rect rect, srcRect; 39 Rect rect;
40 Rect maskRect, dstRect;
41 Canvas canvas;
42 Bitmap clipBitmap;
89 43
90 /* TODO implement stippling. */ 44 /* TODO implement stippling. */
91 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED) 45 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
92 return; 46 return;
93 47
94 alu = immutableGC.function; 48 canvas = drawable.lockCanvas ();
95 rect = new Rect (x, y, x + width, y + height);
96 49
97 paint.setStyle (Paint.Style.STROKE); 50 if (canvas == null)
98 paint.setStrokeWidth (1); 51 return;
99 52
100 if (alu == EmacsGC.GC_COPY) 53 canvas.save ();
101 paint.setXfermode (null);
102 else
103 paint.setXfermode (xorAlu);
104 54
105 if (immutableGC.clip_mask == null) 55 if (gc.real_clip_rects != null)
106 { 56 {
107 paint.setColor (immutableGC.foreground | 0xff000000); 57 for (i = 0; i < gc.real_clip_rects.length; ++i)
108 canvas.drawRect (rect, paint); 58 canvas.clipRect (gc.real_clip_rects[i]);
109 } 59 }
60
61 paint = gc.gcPaint;
62 rect = new Rect (x, y, x + width, y + height);
63
64 paint.setStyle (Paint.Style.STROKE);
65
66 if (gc.clip_mask == null)
67 canvas.drawRect (rect, paint);
110 else 68 else
111 { 69 {
112 maskPaint = new Paint (); 70 /* Drawing with a clip mask involves calculating the
113 maskBitmap 71 intersection of the clip mask with the dst rect, and
114 = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888, 72 extrapolating the corresponding part of the src rect. */
115 true); 73 clipBitmap = gc.clip_mask.bitmap;
116 74 dstRect = new Rect (x, y, x + width, y + height);
117 if (maskBitmap == null) 75 maskRect = new Rect (gc.clip_x_origin,
76 gc.clip_y_origin,
77 (gc.clip_x_origin
78 + clipBitmap.getWidth ()),
79 (gc.clip_y_origin
80 + clipBitmap.getHeight ()));
81 clipBitmap = gc.clip_mask.bitmap;
82
83 if (!maskRect.setIntersect (dstRect, maskRect))
84 /* There is no intersection between the clip mask and the
85 dest rect. */
118 return; 86 return;
119 87
120 maskPaint.setXfermode (srcInAlu); 88 /* Finally, create a temporary bitmap that is the size of
121 maskPaint.setColor (immutableGC.foreground | 0xff000000); 89 maskRect. */
90
91 maskBitmap
92 = Bitmap.createBitmap (maskRect.width (), maskRect.height (),
93 Bitmap.Config.ARGB_8888);
94
95 /* Draw the mask onto the maskBitmap. */
122 maskCanvas = new Canvas (maskBitmap); 96 maskCanvas = new Canvas (maskBitmap);
123 srcRect = new Rect (0, 0, maskBitmap.getWidth (), 97 maskRect.offset (-gc.clip_x_origin,
124 maskBitmap.getHeight ()); 98 -gc.clip_y_origin);
125 maskCanvas.drawRect (srcRect, maskPaint); 99 maskCanvas.drawBitmap (gc.clip_mask.bitmap,
126 canvas.drawBitmap (maskBitmap, srcRect, rect, paint); 100 maskRect, new Rect (0, 0,
101 maskRect.width (),
102 maskRect.height ()),
103 paint);
104 maskRect.offset (gc.clip_x_origin,
105 gc.clip_y_origin);
106
107 /* Set the transfer mode to SRC_IN to preserve only the parts
108 of the source that overlap with the mask. */
109 maskPaint = new Paint ();
110 maskPaint.setXfermode (EmacsGC.srcInAlu);
111 maskPaint.setStyle (Paint.Style.STROKE);
112
113 /* Draw the source. */
114 maskCanvas.drawRect (maskRect, maskPaint);
115
116 /* Finally, draw the mask bitmap to the destination. */
117 paint.setXfermode (null);
118 canvas.drawBitmap (maskBitmap, null, maskRect, paint);
127 } 119 }
128 120
129 paint.setXfermode (null); 121 canvas.restore ();
122 drawable.damageRect (new Rect (x, y, x + width + 1,
123 y + height + 1));
130 } 124 }
131} 125}
diff --git a/java/org/gnu/emacs/EmacsDrawable.java b/java/org/gnu/emacs/EmacsDrawable.java
index 19062137213..6a6199ff214 100644
--- a/java/org/gnu/emacs/EmacsDrawable.java
+++ b/java/org/gnu/emacs/EmacsDrawable.java
@@ -26,7 +26,6 @@ import android.graphics.Canvas;
26public interface EmacsDrawable 26public interface EmacsDrawable
27{ 27{
28 public Canvas lockCanvas (); 28 public Canvas lockCanvas ();
29 public void unlockCanvas ();
30 public void damageRect (Rect damageRect); 29 public void damageRect (Rect damageRect);
31 public Bitmap getBitmap (); 30 public Bitmap getBitmap ();
32 public boolean isDestroyed (); 31 public boolean isDestroyed ();
diff --git a/java/org/gnu/emacs/EmacsFillPolygon.java b/java/org/gnu/emacs/EmacsFillPolygon.java
index 3198c7f07c4..42b73886dff 100644
--- a/java/org/gnu/emacs/EmacsFillPolygon.java
+++ b/java/org/gnu/emacs/EmacsFillPolygon.java
@@ -26,34 +26,35 @@ import android.graphics.Canvas;
26import android.graphics.Paint; 26import android.graphics.Paint;
27import android.graphics.Path; 27import android.graphics.Path;
28import android.graphics.Point; 28import android.graphics.Point;
29import android.graphics.PorterDuff.Mode;
30import android.graphics.PorterDuffXfermode;
31import android.graphics.Rect; 29import android.graphics.Rect;
32import android.graphics.RectF; 30import android.graphics.RectF;
33import android.graphics.Xfermode;
34 31
35public class EmacsFillPolygon implements EmacsPaintReq 32public class EmacsFillPolygon
36{ 33{
37 private EmacsDrawable drawable; 34 public static void
38 private EmacsGC immutableGC; 35 perform (EmacsDrawable drawable, EmacsGC gc, Point points[])
39 private Path path; 36 {
37 Canvas canvas;
38 Path path;
39 Paint paint;
40 Rect rect;
41 RectF rectF;
42 int i;
40 43
41 private static Xfermode xorAlu, srcInAlu; 44 canvas = drawable.lockCanvas ();
42 45
43 static 46 if (canvas == null)
44 { 47 return;
45 xorAlu = new PorterDuffXfermode (Mode.XOR);
46 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
47 };
48 48
49 public 49 paint = gc.gcPaint;
50 EmacsFillPolygon (EmacsDrawable drawable, Point points[], 50
51 EmacsGC immutableGC) 51 canvas.save ();
52 {
53 int i;
54 52
55 this.drawable = drawable; 53 if (gc.real_clip_rects != null)
56 this.immutableGC = immutableGC; 54 {
55 for (i = 0; i < gc.real_clip_rects.length; ++i)
56 canvas.clipRect (gc.real_clip_rects[i]);
57 }
57 58
58 /* Build the path from the given array of points. */ 59 /* Build the path from the given array of points. */
59 path = new Path (); 60 path = new Path ();
@@ -67,84 +68,25 @@ public class EmacsFillPolygon implements EmacsPaintReq
67 68
68 path.close (); 69 path.close ();
69 } 70 }
70 }
71
72 @Override
73 public Rect
74 getRect ()
75 {
76 RectF rect;
77 71
78 rect = new RectF (0, 0, 0, 0); 72 /* Compute the damage rectangle. */
79 path.computeBounds (rect, true); 73 rectF = new RectF (0, 0, 0, 0);
74 path.computeBounds (rectF, true);
80 75
81 return new Rect ((int) Math.floor (rect.left), 76 rect = new Rect ((int) Math.floor (rectF.left),
82 (int) Math.floor (rect.top), 77 (int) Math.floor (rectF.top),
83 (int) Math.ceil (rect.right), 78 (int) Math.ceil (rectF.right),
84 (int) Math.ceil (rect.bottom)); 79 (int) Math.ceil (rectF.bottom));
85 }
86 80
87 @Override 81 paint.setStyle (Paint.Style.FILL);
88 public EmacsDrawable
89 getDrawable ()
90 {
91 return drawable;
92 }
93
94 @Override
95 public EmacsGC
96 getGC ()
97 {
98 return immutableGC;
99 }
100
101 @Override
102 public void
103 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
104 {
105 int alu;
106 Paint maskPaint;
107 Canvas maskCanvas;
108 Bitmap maskBitmap;
109 Rect rect;
110
111 /* TODO implement stippling. */
112 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
113 return;
114
115 alu = immutableGC.function;
116 rect = getRect ();
117 82
118 if (alu == EmacsGC.GC_COPY) 83 if (gc.clip_mask == null)
119 paint.setXfermode (null); 84 canvas.drawPath (path, paint);
120 else
121 paint.setXfermode (xorAlu);
122 85
123 paint.setStyle (Paint.Style.FILL); 86 canvas.restore ();
87 drawable.damageRect (rect);
124 88
125 if (immutableGC.clip_mask == null) 89 /* FillPolygon with clip mask not implemented; it is not used by
126 { 90 Emacs. */
127 paint.setColor (immutableGC.foreground | 0xff000000);
128 canvas.drawPath (path, paint);
129 }
130 else
131 {
132 maskPaint = new Paint ();
133 maskBitmap = immutableGC.clip_mask.bitmap;
134 maskBitmap = maskBitmap.copy (Bitmap.Config.ARGB_8888,
135 true);
136
137 if (maskBitmap == null)
138 return;
139
140 maskPaint.setXfermode (srcInAlu);
141 maskPaint.setColor (immutableGC.foreground | 0xff000000);
142 maskCanvas = new Canvas (maskBitmap);
143 path.offset (-rect.left, -rect.top, null);
144 maskCanvas.drawPath (path, maskPaint);
145 canvas.drawBitmap (maskBitmap, new Rect (0, 0, rect.width (),
146 rect.height ()),
147 rect, paint);
148 }
149 } 91 }
150} 92}
diff --git a/java/org/gnu/emacs/EmacsFillRectangle.java b/java/org/gnu/emacs/EmacsFillRectangle.java
index 7246c13de7f..b733b417d6b 100644
--- a/java/org/gnu/emacs/EmacsFillRectangle.java
+++ b/java/org/gnu/emacs/EmacsFillRectangle.java
@@ -22,108 +22,102 @@ package org.gnu.emacs;
22import android.graphics.Bitmap; 22import android.graphics.Bitmap;
23import android.graphics.Canvas; 23import android.graphics.Canvas;
24import android.graphics.Paint; 24import android.graphics.Paint;
25import android.graphics.PorterDuff.Mode;
26import android.graphics.PorterDuffXfermode;
27import android.graphics.Rect; 25import android.graphics.Rect;
28import android.graphics.Xfermode;
29 26
30import android.util.Log; 27import android.util.Log;
31 28
32public class EmacsFillRectangle implements EmacsPaintReq 29public class EmacsFillRectangle
33{ 30{
34 private int x, y, width, height; 31 public static void
35 private EmacsDrawable drawable; 32 perform (EmacsDrawable drawable, EmacsGC gc,
36 private EmacsGC immutableGC; 33 int x, int y, int width, int height)
37 private static Xfermode xorAlu, srcInAlu;
38
39 static
40 {
41 xorAlu = new PorterDuffXfermode (Mode.XOR);
42 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
43 };
44
45 public
46 EmacsFillRectangle (EmacsDrawable drawable, int x, int y,
47 int width, int height,
48 EmacsGC immutableGC)
49 {
50 this.drawable = drawable;
51 this.x = x;
52 this.y = y;
53 this.width = width;
54 this.height = height;
55 this.immutableGC = immutableGC;
56 }
57
58 @Override
59 public Rect
60 getRect ()
61 {
62 return new Rect (x, y, x + width, y + height);
63 }
64
65 @Override
66 public EmacsDrawable
67 getDrawable ()
68 { 34 {
69 return drawable; 35 int i;
70 } 36 Paint maskPaint, paint;
71
72 @Override
73 public EmacsGC
74 getGC ()
75 {
76 return immutableGC;
77 }
78
79 @Override
80 public void
81 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
82 {
83 int alu;
84 Paint maskPaint;
85 Canvas maskCanvas; 37 Canvas maskCanvas;
86 Bitmap maskBitmap; 38 Bitmap maskBitmap;
87 Rect rect, srcRect; 39 Rect rect;
40 Rect maskRect, dstRect;
41 Canvas canvas;
42 Bitmap clipBitmap;
88 43
89 /* TODO implement stippling. */ 44 /* TODO implement stippling. */
90 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED) 45 if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
91 return; 46 return;
92 47
93 alu = immutableGC.function; 48 canvas = drawable.lockCanvas ();
94 rect = getRect ();
95 49
96 paint.setStyle (Paint.Style.FILL); 50 if (canvas == null)
51 return;
97 52
98 if (alu == EmacsGC.GC_COPY) 53 canvas.save ();
99 paint.setXfermode (null);
100 else
101 paint.setXfermode (xorAlu);
102 54
103 if (immutableGC.clip_mask == null) 55 if (gc.real_clip_rects != null)
104 { 56 {
105 paint.setColor (immutableGC.foreground | 0xff000000); 57 for (i = 0; i < gc.real_clip_rects.length; ++i)
106 canvas.drawRect (rect, paint); 58 canvas.clipRect (gc.real_clip_rects[i]);
107 } 59 }
60
61 paint = gc.gcPaint;
62 rect = new Rect (x, y, x + width, y + height);
63
64 paint.setStyle (Paint.Style.FILL);
65
66 if (gc.clip_mask == null)
67 canvas.drawRect (rect, paint);
108 else 68 else
109 { 69 {
110 maskPaint = new Paint (); 70 /* Drawing with a clip mask involves calculating the
111 maskBitmap 71 intersection of the clip mask with the dst rect, and
112 = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888, 72 extrapolating the corresponding part of the src rect. */
113 true); 73 clipBitmap = gc.clip_mask.bitmap;
114 74 dstRect = new Rect (x, y, x + width, y + height);
115 if (maskBitmap == null) 75 maskRect = new Rect (gc.clip_x_origin,
76 gc.clip_y_origin,
77 (gc.clip_x_origin
78 + clipBitmap.getWidth ()),
79 (gc.clip_y_origin
80 + clipBitmap.getHeight ()));
81 clipBitmap = gc.clip_mask.bitmap;
82
83 if (!maskRect.setIntersect (dstRect, maskRect))
84 /* There is no intersection between the clip mask and the
85 dest rect. */
116 return; 86 return;
117 87
118 maskPaint.setXfermode (srcInAlu); 88 /* Finally, create a temporary bitmap that is the size of
119 maskPaint.setColor (immutableGC.foreground | 0xff000000); 89 maskRect. */
90
91 maskBitmap
92 = Bitmap.createBitmap (maskRect.width (), maskRect.height (),
93 Bitmap.Config.ARGB_8888);
94
95 /* Draw the mask onto the maskBitmap. */
120 maskCanvas = new Canvas (maskBitmap); 96 maskCanvas = new Canvas (maskBitmap);
121 srcRect = new Rect (0, 0, maskBitmap.getWidth (), 97 maskRect.offset (-gc.clip_x_origin,
122 maskBitmap.getHeight ()); 98 -gc.clip_y_origin);
123 maskCanvas.drawRect (srcRect, maskPaint); 99 maskCanvas.drawBitmap (gc.clip_mask.bitmap,
124 canvas.drawBitmap (maskBitmap, srcRect, rect, paint); 100 maskRect, new Rect (0, 0,
101 maskRect.width (),
102 maskRect.height ()),
103 paint);
104 maskRect.offset (gc.clip_x_origin,
105 gc.clip_y_origin);
106
107 /* Set the transfer mode to SRC_IN to preserve only the parts
108 of the source that overlap with the mask. */
109 maskPaint = new Paint ();
110 maskPaint.setXfermode (EmacsGC.srcInAlu);
111
112 /* Draw the source. */
113 maskCanvas.drawRect (maskRect, maskPaint);
114
115 /* Finally, draw the mask bitmap to the destination. */
116 paint.setXfermode (null);
117 canvas.drawBitmap (maskBitmap, null, maskRect, paint);
125 } 118 }
126 119
127 paint.setXfermode (null); 120 canvas.restore ();
121 drawable.damageRect (rect);
128 } 122 }
129} 123}
diff --git a/java/org/gnu/emacs/EmacsFontDriver.java b/java/org/gnu/emacs/EmacsFontDriver.java
index 9f40aa04c44..1d1e6f7b33f 100644
--- a/java/org/gnu/emacs/EmacsFontDriver.java
+++ b/java/org/gnu/emacs/EmacsFontDriver.java
@@ -164,7 +164,7 @@ public abstract class EmacsFontDriver
164 public static EmacsFontDriver 164 public static EmacsFontDriver
165 createFontDriver () 165 createFontDriver ()
166 { 166 {
167 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) 167 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
168 return new EmacsSdk23FontDriver (); 168 return new EmacsSdk23FontDriver ();
169 169
170 return new EmacsSdk7FontDriver (); 170 return new EmacsSdk7FontDriver ();
diff --git a/java/org/gnu/emacs/EmacsGC.java b/java/org/gnu/emacs/EmacsGC.java
index 0becb04519d..caa5c91edd4 100644
--- a/java/org/gnu/emacs/EmacsGC.java
+++ b/java/org/gnu/emacs/EmacsGC.java
@@ -20,6 +20,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
20package org.gnu.emacs; 20package org.gnu.emacs;
21 21
22import android.graphics.Rect; 22import android.graphics.Rect;
23import android.graphics.Paint;
24
25import android.graphics.PorterDuff.Mode;
26import android.graphics.PorterDuffXfermode;
27import android.graphics.Xfermode;
23 28
24/* X like graphics context structures. Keep the enums in synch with 29/* X like graphics context structures. Keep the enums in synch with
25 androidgui.h! */ 30 androidgui.h! */
@@ -32,14 +37,21 @@ public class EmacsGC extends EmacsHandleObject
32 public static final int GC_FILL_SOLID = 0; 37 public static final int GC_FILL_SOLID = 0;
33 public static final int GC_FILL_OPAQUE_STIPPLED = 1; 38 public static final int GC_FILL_OPAQUE_STIPPLED = 1;
34 39
40 public static final Xfermode xorAlu, srcInAlu;
41
35 public int function, fill_style; 42 public int function, fill_style;
36 public int foreground, background; 43 public int foreground, background;
37 public int clip_x_origin, clip_y_origin; 44 public int clip_x_origin, clip_y_origin;
38 public int ts_origin_x, ts_origin_y; 45 public int ts_origin_x, ts_origin_y;
39 public Rect clip_rects[]; 46 public Rect clip_rects[], real_clip_rects[];
40 public EmacsPixmap clip_mask, stipple; 47 public EmacsPixmap clip_mask, stipple;
41 private boolean dirty; 48 public Paint gcPaint;
42 private EmacsGC immutableGC; 49
50 static
51 {
52 xorAlu = new PorterDuffXfermode (Mode.XOR);
53 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
54 }
43 55
44 /* The following fields are only set on immutable GCs. */ 56 /* The following fields are only set on immutable GCs. */
45 57
@@ -55,62 +67,41 @@ public class EmacsGC extends EmacsHandleObject
55 fill_style = GC_FILL_SOLID; 67 fill_style = GC_FILL_SOLID;
56 function = GC_COPY; 68 function = GC_COPY;
57 foreground = 0; 69 foreground = 0;
58 background = 0xffffffff; 70 background = 0xffffff;
71 gcPaint = new Paint ();
59 } 72 }
60 73
61 public 74 /* Mark this GC as dirty. Apply parameters to the paint and
62 EmacsGC (EmacsGC source) 75 recompute real_clip_rects. */
63 {
64 super ((short) 0);
65 76
77 public void
78 markDirty ()
79 {
66 int i; 80 int i;
67 81
68 function = source.function;
69 fill_style = source.fill_style;
70 foreground = source.foreground;
71 background = source.background;
72 clip_x_origin = source.clip_x_origin;
73 clip_y_origin = source.clip_y_origin;
74 clip_rects = source.clip_rects;
75 clip_mask = source.clip_mask;
76 stipple = source.stipple;
77 ts_origin_x = source.ts_origin_x;
78 ts_origin_y = source.ts_origin_y;
79
80 /* Offset all the clip rects by ts_origin_x and ts_origin_y. */
81
82 if ((ts_origin_x != 0 || ts_origin_y != 0) 82 if ((ts_origin_x != 0 || ts_origin_y != 0)
83 && clip_rects != null) 83 && clip_rects != null)
84 { 84 {
85 clip_rects = new Rect[clip_rects.length]; 85 real_clip_rects = new Rect[clip_rects.length];
86 86
87 for (i = 0; i < clip_rects.length; ++i) 87 for (i = 0; i < clip_rects.length; ++i)
88 { 88 {
89 clip_rects[i] = new Rect (source.clip_rects[i]); 89 real_clip_rects[i] = new Rect (clip_rects[i]);
90 clip_rects[i].offset (ts_origin_x, 90 real_clip_rects[i].offset (ts_origin_x, ts_origin_y);
91 ts_origin_y);
92 } 91 }
93 } 92 }
94 } 93 else
94 real_clip_rects = clip_rects;
95 95
96 /* Mark this GC as dirty. This means immutableGC will return a new 96 gcPaint.setColor (foreground | 0xff000000);
97 copy of this GC the next time it is called. */ 97 gcPaint.setXfermode (function == GC_XOR
98 ? xorAlu : srcInAlu);
99 }
98 100
99 public void 101 public void
100 markDirty () 102 resetXfermode ()
101 { 103 {
102 dirty = true; 104 gcPaint.setXfermode (function == GC_XOR
105 ? xorAlu : srcInAlu);
103 } 106 }
104
105 public EmacsGC
106 immutableGC ()
107 {
108 if (immutableGC == null || dirty)
109 {
110 immutableGC = new EmacsGC (this);
111 dirty = false;
112 }
113
114 return immutableGC;
115 };
116}; 107};
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java
index c80339031a8..ae48ce30408 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -79,6 +79,28 @@ public class EmacsNative
79 /* Send an ANDROID_WINDOW_ACTION event. */ 79 /* Send an ANDROID_WINDOW_ACTION event. */
80 public static native void sendWindowAction (short window, int action); 80 public static native void sendWindowAction (short window, int action);
81 81
82 /* Send an ANDROID_ENTER_NOTIFY event. */
83 public static native void sendEnterNotify (short window, int x, int y,
84 long time);
85
86 /* Send an ANDROID_LEAVE_NOTIFY event. */
87 public static native void sendLeaveNotify (short window, int x, int y,
88 long time);
89
90 /* Send an ANDROID_MOTION_NOTIFY event. */
91 public static native void sendMotionNotify (short window, int x, int y,
92 long time);
93
94 /* Send an ANDROID_BUTTON_PRESS event. */
95 public static native void sendButtonPress (short window, int x, int y,
96 long time, int state,
97 int button);
98
99 /* Send an ANDROID_BUTTON_RELEASE event. */
100 public static native void sendButtonRelease (short window, int x, int y,
101 long time, int state,
102 int button);
103
82 static 104 static
83 { 105 {
84 System.loadLibrary ("emacs"); 106 System.loadLibrary ("emacs");
diff --git a/java/org/gnu/emacs/EmacsPixmap.java b/java/org/gnu/emacs/EmacsPixmap.java
index 897902c5b57..15452f007c4 100644
--- a/java/org/gnu/emacs/EmacsPixmap.java
+++ b/java/org/gnu/emacs/EmacsPixmap.java
@@ -93,6 +93,8 @@ public class EmacsPixmap extends EmacsHandleObject
93 break; 93 break;
94 } 94 }
95 95
96 bitmap.eraseColor (0xff000000);
97
96 this.width = width; 98 this.width = width;
97 this.height = height; 99 this.height = height;
98 this.depth = depth; 100 this.depth = depth;
@@ -110,13 +112,6 @@ public class EmacsPixmap extends EmacsHandleObject
110 112
111 @Override 113 @Override
112 public void 114 public void
113 unlockCanvas ()
114 {
115
116 }
117
118 @Override
119 public void
120 damageRect (Rect damageRect) 115 damageRect (Rect damageRect)
121 { 116 {
122 117
diff --git a/java/org/gnu/emacs/EmacsSdk23FontDriver.java b/java/org/gnu/emacs/EmacsSdk23FontDriver.java
index 34e2b1803a2..11e128d5769 100644
--- a/java/org/gnu/emacs/EmacsSdk23FontDriver.java
+++ b/java/org/gnu/emacs/EmacsSdk23FontDriver.java
@@ -20,9 +20,80 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
20package org.gnu.emacs; 20package org.gnu.emacs;
21 21
22import android.graphics.Paint; 22import android.graphics.Paint;
23import android.graphics.Rect;
23 24
24public class EmacsSdk23FontDriver extends EmacsSdk7FontDriver 25public class EmacsSdk23FontDriver extends EmacsSdk7FontDriver
25{ 26{
27 private void
28 textExtents1 (Sdk7FontObject font, int code, FontMetrics metrics,
29 Paint paint, Rect bounds)
30 {
31 char[] text;
32
33 text = new char[2];
34 text[0] = (char) code;
35 text[1] = 'c';
36
37 paint.getTextBounds (text, 0, 1, bounds);
38
39 metrics.lbearing = (short) bounds.left;
40 metrics.rbearing = (short) bounds.right;
41 metrics.ascent = (short) -bounds.top;
42 metrics.descent = (short) bounds.bottom;
43 metrics.width
44 = (short) paint.getRunAdvance (text, 0, 1, 0, 1, false, 1);
45 }
46
47 @Override
48 public void
49 textExtents (FontObject font, int code[], FontMetrics fontMetrics)
50 {
51 int i;
52 Paint paintCache;
53 Rect boundsCache;
54 Sdk7FontObject fontObject;
55 char[] text;
56 float width;
57
58 fontObject = (Sdk7FontObject) font;
59 paintCache = fontObject.typeface.typefacePaint;
60 paintCache.setTextSize (fontObject.pixelSize);
61 boundsCache = new Rect ();
62
63 if (code.length == 0)
64 {
65 fontMetrics.lbearing = 0;
66 fontMetrics.rbearing = 0;
67 fontMetrics.ascent = 0;
68 fontMetrics.descent = 0;
69 fontMetrics.width = 0;
70 }
71 else if (code.length == 1)
72 textExtents1 ((Sdk7FontObject) font, code[0], fontMetrics,
73 paintCache, boundsCache);
74 else
75 {
76 text = new char[code.length + 1];
77
78 for (i = 0; i < code.length; ++i)
79 text[i] = (char) code[i];
80
81 text[code.length] = 'c';
82
83 paintCache.getTextBounds (text, 0, code.length,
84 boundsCache);
85 width = paintCache.getRunAdvance (text, 0, code.length, 0,
86 code.length,
87 false, code.length);
88
89 fontMetrics.lbearing = (short) boundsCache.left;
90 fontMetrics.rbearing = (short) boundsCache.right;
91 fontMetrics.ascent = (short) -boundsCache.top;
92 fontMetrics.descent = (short) boundsCache.bottom;
93 fontMetrics.width = (short) width;
94 }
95 }
96
26 @Override 97 @Override
27 public int 98 public int
28 hasChar (FontSpec font, char charCode) 99 hasChar (FontSpec font, char charCode)
diff --git a/java/org/gnu/emacs/EmacsSdk7FontDriver.java b/java/org/gnu/emacs/EmacsSdk7FontDriver.java
index 437f38e62db..8a9426050ae 100644
--- a/java/org/gnu/emacs/EmacsSdk7FontDriver.java
+++ b/java/org/gnu/emacs/EmacsSdk7FontDriver.java
@@ -243,93 +243,6 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
243 } 243 }
244 }; 244 };
245 245
246 private class Sdk7DrawString implements EmacsPaintReq
247 {
248 private boolean drawBackground;
249 private Sdk7FontObject fontObject;
250 private char[] chars;
251 private EmacsGC immutableGC;
252 private EmacsDrawable drawable;
253 private Rect rect;
254 private int originX, originY;
255
256 public
257 Sdk7DrawString (Sdk7FontObject fontObject, char[] chars,
258 EmacsGC immutableGC, EmacsDrawable drawable,
259 boolean drawBackground, Rect rect,
260 int originX, int originY)
261 {
262 this.fontObject = fontObject;
263 this.chars = chars;
264 this.immutableGC = immutableGC;
265 this.drawable = drawable;
266 this.drawBackground = drawBackground;
267 this.rect = rect;
268 this.originX = originX;
269 this.originY = originY;
270 }
271
272 @Override
273 public EmacsDrawable
274 getDrawable ()
275 {
276 return drawable;
277 }
278
279 @Override
280 public EmacsGC
281 getGC ()
282 {
283 return immutableGC;
284 }
285
286 @Override
287 public void
288 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
289 {
290 int scratch;
291
292 paint.setStyle (Paint.Style.FILL);
293
294 if (drawBackground)
295 {
296 paint.setColor (immutableGC.background | 0xff000000);
297 canvas.drawRect (rect, paint);
298 }
299
300 paint.setTextSize (fontObject.pixelSize);
301 paint.setColor (immutableGC.foreground | 0xff000000);
302 paint.setTypeface (fontObject.typeface.typeface);
303 paint.setAntiAlias (true);
304
305 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
306 /* Disable hinting as that leads to displayed text not
307 matching the computed metrics. */
308 paint.setHinting (Paint.HINTING_OFF);
309
310 canvas.drawText (chars, 0, chars.length, originX, originY, paint);
311 paint.setAntiAlias (false);
312 }
313
314 @Override
315 public Rect
316 getRect ()
317 {
318 Rect rect;
319
320 rect = new Rect ();
321
322 fontObject.typeface.typefacePaint.setTextSize (fontObject.pixelSize);
323 fontObject.typeface.typefacePaint.getTextBounds (chars, 0, chars.length,
324 rect);
325
326 /* Add the background rect to the damage as well. */
327 rect.union (this.rect);
328
329 return rect;
330 }
331 };
332
333 private String[] fontFamilyList; 246 private String[] fontFamilyList;
334 private Sdk7Typeface[] typefaceList; 247 private Sdk7Typeface[] typefaceList;
335 private Sdk7Typeface fallbackTypeface; 248 private Sdk7Typeface fallbackTypeface;
@@ -498,14 +411,11 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
498 Paint paint, Rect bounds) 411 Paint paint, Rect bounds)
499 { 412 {
500 char[] text; 413 char[] text;
501 float[] width;
502 414
503 text = new char[1]; 415 text = new char[1];
504 text[0] = (char) code; 416 text[0] = (char) code;
505 417
506 paint.getTextBounds (text, 0, 1, bounds); 418 paint.getTextBounds (text, 0, 1, bounds);
507 width = new float[1];
508 paint.getTextWidths (text, 0, 1, width);
509 419
510 /* bounds is the bounding box of the glyph corresponding to CODE. 420 /* bounds is the bounding box of the glyph corresponding to CODE.
511 Translate these into XCharStruct values. 421 Translate these into XCharStruct values.
@@ -526,7 +436,7 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
526 metrics.rbearing = (short) bounds.right; 436 metrics.rbearing = (short) bounds.right;
527 metrics.ascent = (short) -bounds.top; 437 metrics.ascent = (short) -bounds.top;
528 metrics.descent = (short) bounds.bottom; 438 metrics.descent = (short) bounds.bottom;
529 metrics.width = (short) Math.round (width[0]); 439 metrics.width = (short) paint.measureText ("" + text[0]);
530 } 440 }
531 441
532 @Override 442 @Override
@@ -563,7 +473,8 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
563 for (i = 0; i < code.length; ++i) 473 for (i = 0; i < code.length; ++i)
564 text[i] = (char) code[i]; 474 text[i] = (char) code[i];
565 475
566 paintCache.getTextBounds (text, 0, 1, boundsCache); 476 paintCache.getTextBounds (text, 0, code.length,
477 boundsCache);
567 width = paintCache.measureText (text, 0, code.length); 478 width = paintCache.measureText (text, 0, code.length);
568 479
569 fontMetrics.lbearing = (short) boundsCache.left; 480 fontMetrics.lbearing = (short) boundsCache.left;
@@ -587,11 +498,12 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
587 int[] chars, int x, int y, int backgroundWidth, 498 int[] chars, int x, int y, int backgroundWidth,
588 boolean withBackground) 499 boolean withBackground)
589 { 500 {
590 Rect backgroundRect; 501 Rect backgroundRect, bounds;
591 Sdk7FontObject sdk7FontObject; 502 Sdk7FontObject sdk7FontObject;
592 Sdk7DrawString op;
593 char[] charsArray; 503 char[] charsArray;
594 int i; 504 int i;
505 Canvas canvas;
506 Paint paint;
595 507
596 sdk7FontObject = (Sdk7FontObject) fontObject; 508 sdk7FontObject = (Sdk7FontObject) fontObject;
597 charsArray = new char[chars.length]; 509 charsArray = new char[chars.length];
@@ -605,12 +517,41 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
605 backgroundRect.right = x + backgroundWidth; 517 backgroundRect.right = x + backgroundWidth;
606 backgroundRect.bottom = y + sdk7FontObject.descent; 518 backgroundRect.bottom = y + sdk7FontObject.descent;
607 519
608 op = new Sdk7DrawString (sdk7FontObject, charsArray, 520 canvas = drawable.lockCanvas ();
609 gc.immutableGC (), drawable, 521
610 withBackground, 522 if (canvas == null)
611 backgroundRect, x, y); 523 return 0;
524
525 canvas.save ();
526 paint = gc.gcPaint;
527
528 if (gc.real_clip_rects != null)
529 {
530 for (i = 0; i < gc.real_clip_rects.length; ++i)
531 canvas.clipRect (gc.real_clip_rects[i]);
532 }
533
534 paint.setStyle (Paint.Style.FILL);
535
536 if (withBackground)
537 {
538 paint.setColor (gc.background | 0xff000000);
539 canvas.drawRect (backgroundRect, paint);
540 paint.setColor (gc.foreground | 0xff000000);
541 }
612 542
613 EmacsService.SERVICE.appendPaintOperation (op); 543 paint.setTextSize (sdk7FontObject.pixelSize);
544 paint.setTypeface (sdk7FontObject.typeface.typeface);
545 paint.setAntiAlias (true);
546 canvas.drawText (charsArray, 0, chars.length, x, y, paint);
547
548 canvas.restore ();
549 bounds = new Rect ();
550 paint.getTextBounds (charsArray, 0, chars.length, bounds);
551 bounds.offset (x, y);
552 bounds.union (backgroundRect);
553 drawable.damageRect (bounds);
554 paint.setAntiAlias (false);
614 return 1; 555 return 1;
615 } 556 }
616}; 557};
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java
index 41a45b0bd85..4444b7f1c56 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -19,7 +19,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 19
20package org.gnu.emacs; 20package org.gnu.emacs;
21 21
22import java.lang.Runnable;
23import java.io.IOException; 22import java.io.IOException;
24import java.util.List; 23import java.util.List;
25import java.util.ArrayList; 24import java.util.ArrayList;
@@ -59,7 +58,6 @@ public class EmacsService extends Service
59 58
60 private EmacsThread thread; 59 private EmacsThread thread;
61 private Handler handler; 60 private Handler handler;
62 private EmacsPaintQueue paintQueue;
63 61
64 /* Display metrics used by font backends. */ 62 /* Display metrics used by font backends. */
65 public DisplayMetrics metrics; 63 public DisplayMetrics metrics;
@@ -191,126 +189,42 @@ public class EmacsService extends Service
191 return view.thing; 189 return view.thing;
192 } 190 }
193 191
194 /* X drawing operations. These are quite primitive operations. The
195 drawing queue is kept on the Emacs thread, but is periodically
196 flushed to the application thread, upon buffers swaps and once it
197 gets too big. */
198
199
200
201 private void
202 ensurePaintQueue ()
203 {
204 if (paintQueue == null)
205 paintQueue = new EmacsPaintQueue ();
206 }
207
208 public void
209 flushPaintQueue ()
210 {
211 final EmacsPaintQueue queue;
212
213 if (paintQueue == null)
214 return;
215
216 if (paintQueue.numRequests < 1)
217 /* No requests to flush. */
218 return;
219
220 queue = paintQueue;
221
222 handler.post (new Runnable () {
223 @Override
224 public void
225 run ()
226 {
227 queue.run ();
228 }
229 });
230
231 /* Clear the paint queue. */
232 paintQueue = null;
233 }
234
235 private void
236 checkFlush ()
237 {
238 if (paintQueue != null
239 && paintQueue.numRequests > MAX_PENDING_REQUESTS)
240 flushPaintQueue ();
241 }
242
243 public void 192 public void
244 fillRectangle (EmacsDrawable drawable, EmacsGC gc, 193 fillRectangle (EmacsDrawable drawable, EmacsGC gc,
245 int x, int y, int width, int height) 194 int x, int y, int width, int height)
246 { 195 {
247 EmacsPaintReq req; 196 EmacsFillRectangle.perform (drawable, gc, x, y,
248 197 width, height);
249 ensurePaintQueue ();
250
251 req = new EmacsFillRectangle (drawable, x, y,
252 width, height,
253 gc.immutableGC ());
254 paintQueue.appendPaintOperation (req);
255 checkFlush ();
256 } 198 }
257 199
258 public void 200 public void
259 fillPolygon (EmacsDrawable drawable, EmacsGC gc, 201 fillPolygon (EmacsDrawable drawable, EmacsGC gc,
260 Point points[]) 202 Point points[])
261 { 203 {
262 EmacsPaintReq req; 204 EmacsFillPolygon.perform (drawable, gc, points);
263
264 ensurePaintQueue ();
265
266 req = new EmacsFillPolygon (drawable, points,
267 gc.immutableGC ());
268 paintQueue.appendPaintOperation (req);
269 checkFlush ();
270 } 205 }
271 206
272 public void 207 public void
273 drawRectangle (EmacsDrawable drawable, EmacsGC gc, 208 drawRectangle (EmacsDrawable drawable, EmacsGC gc,
274 int x, int y, int width, int height) 209 int x, int y, int width, int height)
275 { 210 {
276 EmacsPaintReq req; 211 EmacsDrawRectangle.perform (drawable, gc, x, y,
277 212 width, height);
278 ensurePaintQueue ();
279
280 req = new EmacsDrawRectangle (drawable, x, y,
281 width, height,
282 gc.immutableGC ());
283 paintQueue.appendPaintOperation (req);
284 checkFlush ();
285 } 213 }
286 214
287 public void 215 public void
288 drawLine (EmacsDrawable drawable, EmacsGC gc, 216 drawLine (EmacsDrawable drawable, EmacsGC gc,
289 int x, int y, int x2, int y2) 217 int x, int y, int x2, int y2)
290 { 218 {
291 EmacsPaintReq req; 219 EmacsDrawLine.perform (drawable, gc, x, y,
292 220 x2, y2);
293 ensurePaintQueue ();
294
295 req = new EmacsDrawLine (drawable, x, y,
296 x2, y2,
297 gc.immutableGC ());
298 paintQueue.appendPaintOperation (req);
299 checkFlush ();
300 } 221 }
301 222
302 public void 223 public void
303 drawPoint (EmacsDrawable drawable, EmacsGC gc, 224 drawPoint (EmacsDrawable drawable, EmacsGC gc,
304 int x, int y) 225 int x, int y)
305 { 226 {
306 EmacsPaintReq req; 227 EmacsDrawPoint.perform (drawable, gc, x, y);
307
308 ensurePaintQueue ();
309
310 req = new EmacsDrawPoint (drawable, x, y,
311 gc.immutableGC ());
312 paintQueue.appendPaintOperation (req);
313 checkFlush ();
314 } 228 }
315 229
316 public void 230 public void
@@ -319,15 +233,9 @@ public class EmacsService extends Service
319 int srcX, int srcY, int width, int height, int destX, 233 int srcX, int srcY, int width, int height, int destX,
320 int destY) 234 int destY)
321 { 235 {
322 EmacsPaintReq req; 236 EmacsCopyArea.perform (srcDrawable, gc, dstDrawable,
323 237 srcX, srcY, width, height, destX,
324 ensurePaintQueue (); 238 destY);
325
326 req = new EmacsCopyArea (srcDrawable, dstDrawable,
327 srcX, srcY, width, height, destX,
328 destY, gc.immutableGC ());
329 paintQueue.appendPaintOperation (req);
330 checkFlush ();
331 } 239 }
332 240
333 public void 241 public void
@@ -342,12 +250,4 @@ public class EmacsService extends Service
342 { 250 {
343 window.clearArea (x, y, width, height); 251 window.clearArea (x, y, width, height);
344 } 252 }
345
346 public void
347 appendPaintOperation (EmacsPaintReq op)
348 {
349 ensurePaintQueue ();
350 paintQueue.appendPaintOperation (op);
351 checkFlush ();
352 }
353}; 253};
diff --git a/java/org/gnu/emacs/EmacsSurfaceView.java b/java/org/gnu/emacs/EmacsSurfaceView.java
index b8b828e4820..5efb8882263 100644
--- a/java/org/gnu/emacs/EmacsSurfaceView.java
+++ b/java/org/gnu/emacs/EmacsSurfaceView.java
@@ -29,6 +29,7 @@ import android.graphics.Rect;
29 29
30public class EmacsSurfaceView extends SurfaceView 30public class EmacsSurfaceView extends SurfaceView
31{ 31{
32 public Object surfaceChangeLock;
32 private boolean created; 33 private boolean created;
33 34
34 public 35 public
@@ -36,33 +37,36 @@ public class EmacsSurfaceView extends SurfaceView
36 { 37 {
37 super (view.getContext ()); 38 super (view.getContext ());
38 39
40 surfaceChangeLock = new Object ();
41
39 getHolder ().addCallback (new SurfaceHolder.Callback () { 42 getHolder ().addCallback (new SurfaceHolder.Callback () {
40 @Override 43 @Override
41 public void 44 public void
42 surfaceChanged (SurfaceHolder holder, int format, 45 surfaceChanged (SurfaceHolder holder, int format,
43 int width, int height) 46 int width, int height)
44 { 47 {
45 /* Force a buffer swap now to get the contents of the Emacs 48 view.swapBuffers ();
46 view on screen. */
47 view.swapBuffers (true);
48 } 49 }
49 50
50 @Override 51 @Override
51 public void 52 public void
52 surfaceCreated (SurfaceHolder holder) 53 surfaceCreated (SurfaceHolder holder)
53 { 54 {
54 created = true; 55 synchronized (surfaceChangeLock)
55 56 {
56 /* Force a buffer swap now to get the contents of the Emacs 57 created = true;
57 view on screen. */ 58 view.swapBuffers ();
58 view.swapBuffers (true); 59 }
59 } 60 }
60 61
61 @Override 62 @Override
62 public void 63 public void
63 surfaceDestroyed (SurfaceHolder holder) 64 surfaceDestroyed (SurfaceHolder holder)
64 { 65 {
65 created = false; 66 synchronized (surfaceChangeLock)
67 {
68 created = false;
69 }
66 } 70 }
67 }); 71 });
68 } 72 }
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java
index 7b48eaf0aa6..169a1e42ee3 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -23,6 +23,7 @@ import android.content.res.ColorStateList;
23 23
24import android.view.View; 24import android.view.View;
25import android.view.KeyEvent; 25import android.view.KeyEvent;
26import android.view.MotionEvent;
26import android.view.ViewGroup; 27import android.view.ViewGroup;
27 28
28import android.graphics.Bitmap; 29import android.graphics.Bitmap;
@@ -64,6 +65,14 @@ public class EmacsView extends ViewGroup
64 /* The associated surface view. */ 65 /* The associated surface view. */
65 private EmacsSurfaceView surfaceView; 66 private EmacsSurfaceView surfaceView;
66 67
68 /* Whether or not a configure event must be sent for the next layout
69 event regardless of what changed. */
70 public boolean mustReportLayout;
71
72 /* If non-null, whether or not bitmaps must be recreated upon the
73 next call to getBitmap. */
74 private Rect bitmapDirty;
75
67 public 76 public
68 EmacsView (EmacsWindow window) 77 EmacsView (EmacsWindow window)
69 { 78 {
@@ -81,6 +90,43 @@ public class EmacsView extends ViewGroup
81 addView (this.surfaceView); 90 addView (this.surfaceView);
82 } 91 }
83 92
93 private void
94 handleDirtyBitmap ()
95 {
96 /* Recreate the front and back buffer bitmaps. */
97 bitmap
98 = Bitmap.createBitmap (bitmapDirty.width (),
99 bitmapDirty.height (),
100 Bitmap.Config.ARGB_8888);
101 bitmap.eraseColor (0xffffffff);
102
103 /* And canvases. */
104 canvas = new Canvas (bitmap);
105
106 /* If Emacs is drawing to the bitmap right now from the
107 main thread, the image contents are lost until the next
108 ConfigureNotify and complete garbage. Sorry! */
109 bitmapDirty = null;
110 }
111
112 public synchronized Bitmap
113 getBitmap ()
114 {
115 if (bitmapDirty != null)
116 handleDirtyBitmap ();
117
118 return bitmap;
119 }
120
121 public synchronized Canvas
122 getCanvas ()
123 {
124 if (bitmapDirty != null)
125 handleDirtyBitmap ();
126
127 return canvas;
128 }
129
84 @Override 130 @Override
85 protected void 131 protected void
86 onMeasure (int widthMeasureSpec, int heightMeasureSpec) 132 onMeasure (int widthMeasureSpec, int heightMeasureSpec)
@@ -114,7 +160,7 @@ public class EmacsView extends ViewGroup
114 } 160 }
115 161
116 @Override 162 @Override
117 protected void 163 protected synchronized void
118 onLayout (boolean changed, int left, int top, int right, 164 onLayout (boolean changed, int left, int top, int right,
119 int bottom) 165 int bottom)
120 { 166 {
@@ -122,19 +168,15 @@ public class EmacsView extends ViewGroup
122 View child; 168 View child;
123 Rect windowRect; 169 Rect windowRect;
124 170
125 if (changed) 171 if (changed || mustReportLayout)
126 { 172 {
173 mustReportLayout = false;
127 window.viewLayout (left, top, right, bottom); 174 window.viewLayout (left, top, right, bottom);
128
129 /* Recreate the front and back buffer bitmaps. */
130 bitmap
131 = Bitmap.createBitmap (right - left, bottom - top,
132 Bitmap.Config.ARGB_8888);
133
134 /* And canvases. */
135 canvas = new Canvas (bitmap);
136 } 175 }
137 176
177 if (changed)
178 bitmapDirty = new Rect (left, top, right, bottom);
179
138 count = getChildCount (); 180 count = getChildCount ();
139 181
140 for (i = 0; i < count; ++i) 182 for (i = 0; i < count; ++i)
@@ -159,47 +201,60 @@ public class EmacsView extends ViewGroup
159 } 201 }
160 } 202 }
161 203
162 public void 204 public synchronized void
163 damageRect (Rect damageRect) 205 damageRect (Rect damageRect)
164 { 206 {
165 damageRegion.union (damageRect); 207 damageRegion.union (damageRect);
166 } 208 }
167 209
168 public void 210 /* This method is called from both the UI thread and the Emacs
211 thread. */
212
213 public synchronized void
169 swapBuffers (boolean force) 214 swapBuffers (boolean force)
170 { 215 {
171 Bitmap back;
172 Canvas canvas; 216 Canvas canvas;
173 Rect damageRect; 217 Rect damageRect;
218 Bitmap bitmap;
174 219
175 if (damageRegion.isEmpty ()) 220 if (damageRegion.isEmpty ())
176 return; 221 return;
177 222
178 if (!surfaceView.isCreated ()) 223 bitmap = getBitmap ();
179 return;
180 224
181 if (bitmap == null) 225 /* Emacs must take the following lock to ensure the access to the
182 return; 226 canvas occurs with the surface created. Otherwise, Android
227 will throttle calls to lockCanvas. */
228
229 synchronized (surfaceView.surfaceChangeLock)
230 {
231 damageRect = damageRegion.getBounds ();
183 232
184 /* Lock the canvas with the specified damage. */ 233 if (!surfaceView.isCreated ())
185 damageRect = damageRegion.getBounds (); 234 return;
186 canvas = surfaceView.lockCanvas (damageRect);
187 235
188 /* Return if locking the canvas failed. */ 236 if (bitmap == null)
189 if (canvas == null) 237 return;
190 return; 238
239 /* Lock the canvas with the specified damage. */
240 canvas = surfaceView.lockCanvas (damageRect);
191 241
192 /* Copy from the back buffer to the canvas. If damageRect was 242 /* Return if locking the canvas failed. */
193 made empty, then draw the entire back buffer. */ 243 if (canvas == null)
244 return;
194 245
195 if (damageRect.isEmpty ()) 246 /* Copy from the back buffer to the canvas. If damageRect was
196 canvas.drawBitmap (bitmap, 0f, 0f, paint); 247 made empty, then draw the entire back buffer. */
197 else
198 canvas.drawBitmap (bitmap, damageRect, damageRect, paint);
199 248
200 /* Unlock the canvas and clear the damage. */ 249 if (damageRect.isEmpty ())
201 surfaceView.unlockCanvasAndPost (canvas); 250 canvas.drawBitmap (bitmap, 0f, 0f, paint);
202 damageRegion.setEmpty (); 251 else
252 canvas.drawBitmap (bitmap, damageRect, damageRect, paint);
253
254 /* Unlock the canvas and clear the damage. */
255 surfaceView.unlockCanvasAndPost (canvas);
256 damageRegion.setEmpty ();
257 }
203 } 258 }
204 259
205 public void 260 public void
@@ -241,4 +296,18 @@ public class EmacsView extends ViewGroup
241 super.onFocusChanged (gainFocus, direction, 296 super.onFocusChanged (gainFocus, direction,
242 previouslyFocusedRect); 297 previouslyFocusedRect);
243 } 298 }
299
300 @Override
301 public boolean
302 onGenericMotionEvent (MotionEvent motion)
303 {
304 return window.onSomeKindOfMotionEvent (motion);
305 }
306
307 @Override
308 public boolean
309 onTouchEvent (MotionEvent motion)
310 {
311 return window.onSomeKindOfMotionEvent (motion);
312 }
244}; 313};
diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java
index 26e788a20a8..a9a24b61869 100644
--- a/java/org/gnu/emacs/EmacsWindow.java
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -31,8 +31,13 @@ import android.graphics.Point;
31import android.view.View; 31import android.view.View;
32import android.view.ViewGroup; 32import android.view.ViewGroup;
33import android.view.KeyEvent; 33import android.view.KeyEvent;
34import android.view.MotionEvent;
35import android.view.InputDevice;
34 36
35import android.content.Intent; 37import android.content.Intent;
38import android.util.Log;
39
40import android.os.Build;
36 41
37/* This defines a window, which is a handle. Windows represent a 42/* This defines a window, which is a handle. Windows represent a
38 rectangular subset of the screen with their own contents. 43 rectangular subset of the screen with their own contents.
@@ -68,6 +73,10 @@ public class EmacsWindow extends EmacsHandleObject
68 window background. */ 73 window background. */
69 private EmacsGC scratchGC; 74 private EmacsGC scratchGC;
70 75
76 /* The button state and keyboard modifier mask at the time of the
77 last button press or release event. */
78 private int lastButtonState, lastModifiers;
79
71 public 80 public
72 EmacsWindow (short handle, final EmacsWindow parent, int x, int y, 81 EmacsWindow (short handle, final EmacsWindow parent, int x, int y,
73 int width, int height) 82 int width, int height)
@@ -212,6 +221,7 @@ public class EmacsWindow extends EmacsHandleObject
212 public void 221 public void
213 run () 222 run ()
214 { 223 {
224 view.mustReportLayout = true;
215 view.requestLayout (); 225 view.requestLayout ();
216 } 226 }
217 }); 227 });
@@ -224,6 +234,8 @@ public class EmacsWindow extends EmacsHandleObject
224 { 234 {
225 rect.right = rect.left + width; 235 rect.right = rect.left + width;
226 rect.bottom = rect.top + height; 236 rect.bottom = rect.top + height;
237
238 requestViewLayout ();
227 } 239 }
228 } 240 }
229 241
@@ -279,17 +291,7 @@ public class EmacsWindow extends EmacsHandleObject
279 public Canvas 291 public Canvas
280 lockCanvas () 292 lockCanvas ()
281 { 293 {
282 if (view.canvas != null) 294 return view.getCanvas ();
283 return view.canvas;
284
285 return null;
286 }
287
288 @Override
289 public void
290 unlockCanvas ()
291 {
292
293 } 295 }
294 296
295 @Override 297 @Override
@@ -302,17 +304,7 @@ public class EmacsWindow extends EmacsHandleObject
302 public void 304 public void
303 swapBuffers () 305 swapBuffers ()
304 { 306 {
305 /* Before calling swapBuffers, make sure to flush the paint 307 view.swapBuffers ();
306 queue. */
307 EmacsService.SERVICE.flushPaintQueue ();
308 view.post (new Runnable () {
309 @Override
310 public void
311 run ()
312 {
313 view.swapBuffers ();
314 }
315 });
316 } 308 }
317 309
318 public void 310 public void
@@ -337,7 +329,7 @@ public class EmacsWindow extends EmacsHandleObject
337 public Bitmap 329 public Bitmap
338 getBitmap () 330 getBitmap ()
339 { 331 {
340 return view.bitmap; 332 return view.getBitmap ();
341 } 333 }
342 334
343 public void 335 public void
@@ -357,6 +349,7 @@ public class EmacsWindow extends EmacsHandleObject
357 recognized as an ASCII key press 349 recognized as an ASCII key press
358 event. */ 350 event. */
359 event.getUnicodeChar (state)); 351 event.getUnicodeChar (state));
352 lastModifiers = event.getModifiers ();
360 } 353 }
361 354
362 public void 355 public void
@@ -372,6 +365,7 @@ public class EmacsWindow extends EmacsHandleObject
372 event.getModifiers (), 365 event.getModifiers (),
373 keyCode, 366 keyCode,
374 event.getUnicodeChar (state)); 367 event.getUnicodeChar (state));
368 lastModifiers = event.getModifiers ();
375 } 369 }
376 370
377 public void 371 public void
@@ -386,4 +380,105 @@ public class EmacsWindow extends EmacsHandleObject
386 /* Destroy the associated frame when the activity is detached. */ 380 /* Destroy the associated frame when the activity is detached. */
387 EmacsNative.sendWindowAction (this.handle, 0); 381 EmacsNative.sendWindowAction (this.handle, 0);
388 } 382 }
383
384 /* Look through the button state to determine what button EVENT was
385 generated from. DOWN is true if EVENT is a button press event,
386 false otherwise. Value is the X number of the button. */
387
388 private int
389 whatButtonWasIt (MotionEvent event, boolean down)
390 {
391 int eventState, notIn;
392
393 if (Build.VERSION.SDK_INT
394 < Build.VERSION_CODES.ICE_CREAM_SANDWICH)
395 /* Earlier versions of Android only support one mouse
396 button. */
397 return 1;
398
399 eventState = event.getButtonState ();
400 notIn = (down ? eventState & ~lastButtonState
401 : lastButtonState & ~eventState);
402
403 if ((notIn & MotionEvent.BUTTON_PRIMARY) != 0)
404 return 1;
405
406 if ((notIn & MotionEvent.BUTTON_SECONDARY) != 0)
407 return 3;
408
409 if ((notIn & MotionEvent.BUTTON_TERTIARY) != 0)
410 return 2;
411
412 /* Not a real value. */
413 return 4;
414 }
415
416 public boolean
417 onSomeKindOfMotionEvent (MotionEvent event)
418 {
419 if (!event.isFromSource (InputDevice.SOURCE_CLASS_POINTER))
420 return false;
421
422 switch (event.getAction ())
423 {
424 case MotionEvent.ACTION_HOVER_ENTER:
425 EmacsNative.sendEnterNotify (this.handle, (int) event.getX (),
426 (int) event.getY (),
427 event.getEventTime ());
428 return true;
429
430 case MotionEvent.ACTION_MOVE:
431 case MotionEvent.ACTION_HOVER_MOVE:
432 EmacsNative.sendMotionNotify (this.handle, (int) event.getX (),
433 (int) event.getY (),
434 event.getEventTime ());
435 return true;
436
437 case MotionEvent.ACTION_HOVER_EXIT:
438 EmacsNative.sendLeaveNotify (this.handle, (int) event.getX (),
439 (int) event.getY (),
440 event.getEventTime ());
441 return true;
442
443 case MotionEvent.ACTION_BUTTON_PRESS:
444 /* Find the button which was pressed. */
445 EmacsNative.sendButtonPress (this.handle, (int) event.getX (),
446 (int) event.getY (),
447 event.getEventTime (),
448 lastModifiers,
449 whatButtonWasIt (event, true));
450
451 if (Build.VERSION.SDK_INT
452 < Build.VERSION_CODES.ICE_CREAM_SANDWICH)
453 return true;
454
455 lastButtonState = event.getButtonState ();
456 return true;
457
458 case MotionEvent.ACTION_BUTTON_RELEASE:
459 /* Find the button which was released. */
460 EmacsNative.sendButtonRelease (this.handle, (int) event.getX (),
461 (int) event.getY (),
462 event.getEventTime (),
463 lastModifiers,
464 whatButtonWasIt (event, false));
465
466 if (Build.VERSION.SDK_INT
467 < Build.VERSION_CODES.ICE_CREAM_SANDWICH)
468 return true;
469
470 lastButtonState = event.getButtonState ();
471 return true;
472
473 case MotionEvent.ACTION_DOWN:
474 case MotionEvent.ACTION_UP:
475 /* Emacs must return true even though touch events are not yet
476 handled, because the value of this function is used by the
477 system to decide whether or not Emacs gets ACTION_MOVE
478 events. */
479 return true;
480 }
481
482 return false;
483 }
389}; 484};