diff options
Diffstat (limited to 'java/org/gnu/emacs/EmacsCopyArea.java')
| -rw-r--r-- | java/org/gnu/emacs/EmacsCopyArea.java | 135 |
1 files changed, 112 insertions, 23 deletions
diff --git a/java/org/gnu/emacs/EmacsCopyArea.java b/java/org/gnu/emacs/EmacsCopyArea.java index f34d1ecde01..0dd5b2c1fb6 100644 --- a/java/org/gnu/emacs/EmacsCopyArea.java +++ b/java/org/gnu/emacs/EmacsCopyArea.java | |||
| @@ -32,19 +32,22 @@ public class EmacsCopyArea implements EmacsPaintReq | |||
| 32 | private int src_x, src_y, dest_x, dest_y, width, height; | 32 | private int src_x, src_y, dest_x, dest_y, width, height; |
| 33 | private EmacsDrawable destination, source; | 33 | private EmacsDrawable destination, source; |
| 34 | private EmacsGC immutableGC; | 34 | private EmacsGC immutableGC; |
| 35 | private static Xfermode xorAlu, srcInAlu; | 35 | private static Xfermode xorAlu, srcInAlu, overAlu; |
| 36 | 36 | ||
| 37 | static | 37 | static |
| 38 | { | 38 | { |
| 39 | overAlu = new PorterDuffXfermode (Mode.SRC_OVER); | ||
| 39 | xorAlu = new PorterDuffXfermode (Mode.XOR); | 40 | xorAlu = new PorterDuffXfermode (Mode.XOR); |
| 40 | srcInAlu = new PorterDuffXfermode (Mode.SRC_IN); | 41 | srcInAlu = new PorterDuffXfermode (Mode.SRC_IN); |
| 41 | }; | 42 | }; |
| 42 | 43 | ||
| 43 | public | 44 | public |
| 44 | EmacsCopyArea (EmacsDrawable destination, EmacsDrawable source, | 45 | EmacsCopyArea (EmacsDrawable source, EmacsDrawable destination, |
| 45 | int src_x, int src_y, int width, int height, | 46 | int src_x, int src_y, int width, int height, |
| 46 | int dest_x, int dest_y, EmacsGC immutableGC) | 47 | int dest_x, int dest_y, EmacsGC immutableGC) |
| 47 | { | 48 | { |
| 49 | Bitmap bitmap; | ||
| 50 | |||
| 48 | this.destination = destination; | 51 | this.destination = destination; |
| 49 | this.source = source; | 52 | this.source = source; |
| 50 | this.src_x = src_x; | 53 | this.src_x = src_x; |
| @@ -71,6 +74,16 @@ public class EmacsCopyArea implements EmacsPaintReq | |||
| 71 | return destination; | 74 | return destination; |
| 72 | } | 75 | } |
| 73 | 76 | ||
| 77 | private void | ||
| 78 | insetRectBy (Rect rect, int left, int top, int right, | ||
| 79 | int bottom) | ||
| 80 | { | ||
| 81 | rect.left += left; | ||
| 82 | rect.top += top; | ||
| 83 | rect.right -= right; | ||
| 84 | rect.bottom -= bottom; | ||
| 85 | } | ||
| 86 | |||
| 74 | @Override | 87 | @Override |
| 75 | public EmacsGC | 88 | public EmacsGC |
| 76 | getGC () | 89 | getGC () |
| @@ -86,16 +99,45 @@ public class EmacsCopyArea implements EmacsPaintReq | |||
| 86 | Bitmap bitmap; | 99 | Bitmap bitmap; |
| 87 | Paint maskPaint; | 100 | Paint maskPaint; |
| 88 | Canvas maskCanvas; | 101 | Canvas maskCanvas; |
| 89 | Bitmap maskBitmap; | 102 | Bitmap srcBitmap, maskBitmap, clipBitmap; |
| 90 | Rect rect, srcRect; | 103 | Rect rect, maskRect, srcRect, dstRect, maskDestRect; |
| 104 | boolean needFill; | ||
| 91 | 105 | ||
| 92 | /* TODO implement stippling. */ | 106 | /* TODO implement stippling. */ |
| 93 | if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED) | 107 | if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED) |
| 94 | return; | 108 | return; |
| 95 | 109 | ||
| 96 | alu = immutableGC.function; | 110 | alu = immutableGC.function; |
| 111 | |||
| 112 | /* A copy must be created or drawBitmap could end up overwriting | ||
| 113 | itself. */ | ||
| 114 | srcBitmap = source.getBitmap (); | ||
| 115 | |||
| 116 | /* If srcBitmap is out of bounds, then adjust the source rectangle | ||
| 117 | to be within bounds. Note that tiling on windows with | ||
| 118 | backgrounds is unimplemented. */ | ||
| 119 | |||
| 120 | if (src_x < 0) | ||
| 121 | { | ||
| 122 | width += src_x; | ||
| 123 | dest_x -= src_x; | ||
| 124 | src_x = 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | if (src_y < 0) | ||
| 128 | { | ||
| 129 | height += src_y; | ||
| 130 | dest_y -= src_y; | ||
| 131 | src_y = 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | if (src_x + width > srcBitmap.getWidth ()) | ||
| 135 | width = srcBitmap.getWidth () - src_x; | ||
| 136 | |||
| 137 | if (src_y + height > srcBitmap.getHeight ()) | ||
| 138 | height = srcBitmap.getHeight () - src_y; | ||
| 139 | |||
| 97 | rect = getRect (); | 140 | rect = getRect (); |
| 98 | bitmap = source.getBitmap (); | ||
| 99 | 141 | ||
| 100 | if (alu == EmacsGC.GC_COPY) | 142 | if (alu == EmacsGC.GC_COPY) |
| 101 | paint.setXfermode (null); | 143 | paint.setXfermode (null); |
| @@ -103,29 +145,76 @@ public class EmacsCopyArea implements EmacsPaintReq | |||
| 103 | paint.setXfermode (xorAlu); | 145 | paint.setXfermode (xorAlu); |
| 104 | 146 | ||
| 105 | if (immutableGC.clip_mask == null) | 147 | if (immutableGC.clip_mask == null) |
| 106 | canvas.drawBitmap (bitmap, new Rect (src_x, src_y, | 148 | { |
| 107 | src_x + width, | 149 | bitmap = Bitmap.createBitmap (srcBitmap, |
| 108 | src_y + height), | 150 | src_x, src_y, width, |
| 109 | rect, paint); | 151 | height); |
| 152 | canvas.drawBitmap (bitmap, null, rect, paint); | ||
| 153 | } | ||
| 110 | else | 154 | else |
| 111 | { | 155 | { |
| 112 | maskPaint = new Paint (); | 156 | /* Drawing with a clip mask involves calculating the |
| 113 | srcRect = new Rect (0, 0, rect.width (), | 157 | intersection of the clip mask with the dst rect, and |
| 114 | rect.height ()); | 158 | extrapolating the corresponding part of the src rect. */ |
| 115 | maskBitmap | 159 | clipBitmap = immutableGC.clip_mask.bitmap; |
| 116 | = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888, | 160 | dstRect = new Rect (dest_x, dest_y, |
| 117 | true); | 161 | dest_x + width, |
| 118 | 162 | dest_y + height); | |
| 119 | if (maskBitmap == null) | 163 | maskRect = new Rect (immutableGC.clip_x_origin, |
| 164 | immutableGC.clip_y_origin, | ||
| 165 | (immutableGC.clip_x_origin | ||
| 166 | + clipBitmap.getWidth ()), | ||
| 167 | (immutableGC.clip_y_origin | ||
| 168 | + clipBitmap.getHeight ())); | ||
| 169 | clipBitmap = immutableGC.clip_mask.bitmap; | ||
| 170 | |||
| 171 | if (!maskRect.setIntersect (dstRect, maskRect)) | ||
| 172 | /* There is no intersection between the clip mask and the | ||
| 173 | dest rect. */ | ||
| 120 | return; | 174 | return; |
| 121 | 175 | ||
| 122 | maskPaint.setXfermode (srcInAlu); | 176 | /* Now figure out which part of the source corresponds to |
| 177 | maskRect and return it relative to srcBitmap. */ | ||
| 178 | srcRect = new Rect (src_x, src_y, src_x + width, | ||
| 179 | src_y + height); | ||
| 180 | insetRectBy (srcRect, maskRect.left - dstRect.left, | ||
| 181 | maskRect.top - dstRect.top, | ||
| 182 | maskRect.right - dstRect.right, | ||
| 183 | maskRect.bottom - dstRect.bottom); | ||
| 184 | |||
| 185 | /* Finally, create a temporary bitmap that is the size of | ||
| 186 | maskRect. */ | ||
| 187 | |||
| 188 | maskBitmap | ||
| 189 | = Bitmap.createBitmap (maskRect.width (), maskRect.height (), | ||
| 190 | Bitmap.Config.ARGB_8888); | ||
| 191 | |||
| 192 | /* Draw the mask onto the maskBitmap. */ | ||
| 123 | maskCanvas = new Canvas (maskBitmap); | 193 | maskCanvas = new Canvas (maskBitmap); |
| 124 | maskCanvas.drawBitmap (bitmap, new Rect (src_x, src_y, | 194 | maskRect.offset (-immutableGC.clip_x_origin, |
| 125 | src_x + width, | 195 | -immutableGC.clip_y_origin); |
| 126 | src_y + height), | 196 | maskCanvas.drawBitmap (immutableGC.clip_mask.bitmap, |
| 127 | srcRect, maskPaint); | 197 | maskRect, new Rect (0, 0, |
| 128 | canvas.drawBitmap (maskBitmap, srcRect, rect, paint); | 198 | maskRect.width (), |
| 199 | maskRect.height ()), | ||
| 200 | paint); | ||
| 201 | maskRect.offset (immutableGC.clip_x_origin, | ||
| 202 | immutableGC.clip_y_origin); | ||
| 203 | |||
| 204 | /* Set the transfer mode to SRC_IN to preserve only the parts | ||
| 205 | of the source that overlap with the mask. */ | ||
| 206 | maskPaint = new Paint (); | ||
| 207 | maskPaint.setXfermode (srcInAlu); | ||
| 208 | |||
| 209 | /* Draw the source. */ | ||
| 210 | maskDestRect = new Rect (0, 0, srcRect.width (), | ||
| 211 | srcRect.height ()); | ||
| 212 | maskCanvas.drawBitmap (srcBitmap, srcRect, maskDestRect, | ||
| 213 | maskPaint); | ||
| 214 | |||
| 215 | /* Finally, draw the mask bitmap to the destination. */ | ||
| 216 | paint.setXfermode (overAlu); | ||
| 217 | canvas.drawBitmap (maskBitmap, null, maskRect, paint); | ||
| 129 | } | 218 | } |
| 130 | } | 219 | } |
| 131 | } | 220 | } |