1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics; 18 19 import com.android.ide.common.rendering.api.LayoutLog; 20 import com.android.layoutlib.bridge.Bridge; 21 import com.android.layoutlib.bridge.impl.DelegateManager; 22 import com.android.layoutlib.bridge.impl.GcSnapshot; 23 import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 24 25 import android.annotation.Nullable; 26 import android.graphics.Bitmap.Config; 27 28 import java.awt.Graphics2D; 29 import java.awt.Rectangle; 30 import java.awt.geom.AffineTransform; 31 32 import libcore.util.NativeAllocationRegistry_Delegate; 33 34 35 /** 36 * Delegate implementing the native methods of android.graphics.Canvas 37 * 38 * Through the layoutlib_create tool, the original native methods of Canvas have been replaced 39 * by calls to methods of the same name in this delegate class. 40 * 41 * This class behaves like the original native implementation, but in Java, keeping previously 42 * native data into its own objects and mapping them to int that are sent back and forth between 43 * it and the original Canvas class. 44 * 45 * @see DelegateManager 46 * 47 */ 48 public final class Canvas_Delegate extends BaseCanvas_Delegate { 49 50 // ---- delegate manager ---- 51 private static long sFinalizer = -1; 52 53 private DrawFilter_Delegate mDrawFilter = null; 54 55 // ---- Public Helper methods ---- 56 57 /** 58 * Returns the native delegate associated to a given {@link Canvas} object. 59 */ getDelegate(Canvas canvas)60 public static Canvas_Delegate getDelegate(Canvas canvas) { 61 return (Canvas_Delegate) sManager.getDelegate(canvas.getNativeCanvasWrapper()); 62 } 63 64 /** 65 * Returns the native delegate associated to a given an int referencing a {@link Canvas} object. 66 */ getDelegate(long native_canvas)67 public static Canvas_Delegate getDelegate(long native_canvas) { 68 return (Canvas_Delegate) sManager.getDelegate(native_canvas); 69 } 70 71 /** 72 * Returns the current {@link Graphics2D} used to draw. 73 */ getSnapshot()74 public GcSnapshot getSnapshot() { 75 return mSnapshot; 76 } 77 78 /** 79 * Returns the {@link DrawFilter} delegate or null if none have been set. 80 * 81 * @return the delegate or null. 82 */ getDrawFilter()83 public DrawFilter_Delegate getDrawFilter() { 84 return mDrawFilter; 85 } 86 87 // ---- native methods ---- 88 89 @LayoutlibDelegate nFreeCaches()90 /*package*/ static void nFreeCaches() { 91 // nothing to be done here. 92 } 93 94 @LayoutlibDelegate nFreeTextLayoutCaches()95 /*package*/ static void nFreeTextLayoutCaches() { 96 // nothing to be done here yet. 97 } 98 99 @LayoutlibDelegate nInitRaster(@ullable Bitmap bitmap)100 /*package*/ static long nInitRaster(@Nullable Bitmap bitmap) { 101 long nativeBitmapOrZero = 0; 102 if (bitmap != null) { 103 nativeBitmapOrZero = bitmap.getNativeInstance(); 104 } 105 if (nativeBitmapOrZero > 0) { 106 // get the Bitmap from the int 107 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero); 108 109 // create a new Canvas_Delegate with the given bitmap and return its new native int. 110 Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate); 111 112 return sManager.addNewDelegate(newDelegate); 113 } 114 115 // create a new Canvas_Delegate and return its new native int. 116 Canvas_Delegate newDelegate = new Canvas_Delegate(); 117 118 return sManager.addNewDelegate(newDelegate); 119 } 120 121 @LayoutlibDelegate nSetBitmap(long canvas, Bitmap bitmap)122 public static void nSetBitmap(long canvas, Bitmap bitmap) { 123 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); 124 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); 125 if (canvasDelegate == null || bitmapDelegate==null) { 126 return; 127 } 128 canvasDelegate.mBitmap = bitmapDelegate; 129 canvasDelegate.mSnapshot = GcSnapshot.createDefaultSnapshot(bitmapDelegate); 130 } 131 132 @LayoutlibDelegate nIsOpaque(long nativeCanvas)133 public static boolean nIsOpaque(long nativeCanvas) { 134 // get the delegate from the native int. 135 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 136 if (canvasDelegate == null) { 137 return false; 138 } 139 140 return canvasDelegate.mBitmap.getConfig() == Config.RGB_565; 141 } 142 143 @LayoutlibDelegate nSetHighContrastText(long nativeCanvas, boolean highContrastText)144 public static void nSetHighContrastText(long nativeCanvas, boolean highContrastText){} 145 146 @LayoutlibDelegate nGetWidth(long nativeCanvas)147 public static int nGetWidth(long nativeCanvas) { 148 // get the delegate from the native int. 149 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 150 if (canvasDelegate == null) { 151 return 0; 152 } 153 154 return canvasDelegate.mBitmap.getImage().getWidth(); 155 } 156 157 @LayoutlibDelegate nGetHeight(long nativeCanvas)158 public static int nGetHeight(long nativeCanvas) { 159 // get the delegate from the native int. 160 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 161 if (canvasDelegate == null) { 162 return 0; 163 } 164 165 return canvasDelegate.mBitmap.getImage().getHeight(); 166 } 167 168 @LayoutlibDelegate nSave(long nativeCanvas, int saveFlags)169 public static int nSave(long nativeCanvas, int saveFlags) { 170 // get the delegate from the native int. 171 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 172 if (canvasDelegate == null) { 173 return 0; 174 } 175 176 return canvasDelegate.save(saveFlags); 177 } 178 179 @LayoutlibDelegate nSaveLayer(long nativeCanvas, float l, float t, float r, float b, long paint, int layerFlags)180 public static int nSaveLayer(long nativeCanvas, float l, 181 float t, float r, float b, 182 long paint, int layerFlags) { 183 // get the delegate from the native int. 184 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 185 if (canvasDelegate == null) { 186 return 0; 187 } 188 189 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint); 190 if (paintDelegate == null) { 191 return 0; 192 } 193 194 return canvasDelegate.saveLayer(new RectF(l, t, r, b), 195 paintDelegate, layerFlags); 196 } 197 198 @LayoutlibDelegate nSaveLayerAlpha(long nativeCanvas, float l, float t, float r, float b, int alpha, int layerFlags)199 public static int nSaveLayerAlpha(long nativeCanvas, float l, 200 float t, float r, float b, 201 int alpha, int layerFlags) { 202 // get the delegate from the native int. 203 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 204 if (canvasDelegate == null) { 205 return 0; 206 } 207 208 return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags); 209 } 210 211 @LayoutlibDelegate nRestore(long nativeCanvas)212 public static boolean nRestore(long nativeCanvas) { 213 // FIXME: implement throwOnUnderflow. 214 // get the delegate from the native int. 215 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 216 if (canvasDelegate == null) { 217 return false; 218 } 219 220 canvasDelegate.restore(); 221 return true; 222 } 223 224 @LayoutlibDelegate nRestoreToCount(long nativeCanvas, int saveCount)225 public static void nRestoreToCount(long nativeCanvas, int saveCount) { 226 // FIXME: implement throwOnUnderflow. 227 // get the delegate from the native int. 228 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 229 if (canvasDelegate == null) { 230 return; 231 } 232 233 canvasDelegate.restoreTo(saveCount); 234 } 235 236 @LayoutlibDelegate nGetSaveCount(long nativeCanvas)237 public static int nGetSaveCount(long nativeCanvas) { 238 // get the delegate from the native int. 239 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 240 if (canvasDelegate == null) { 241 return 0; 242 } 243 244 return canvasDelegate.getSnapshot().size(); 245 } 246 247 @LayoutlibDelegate nTranslate(long nativeCanvas, float dx, float dy)248 public static void nTranslate(long nativeCanvas, float dx, float dy) { 249 // get the delegate from the native int. 250 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 251 if (canvasDelegate == null) { 252 return; 253 } 254 255 canvasDelegate.getSnapshot().translate(dx, dy); 256 } 257 258 @LayoutlibDelegate nScale(long nativeCanvas, float sx, float sy)259 public static void nScale(long nativeCanvas, float sx, float sy) { 260 // get the delegate from the native int. 261 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 262 if (canvasDelegate == null) { 263 return; 264 } 265 266 canvasDelegate.getSnapshot().scale(sx, sy); 267 } 268 269 @LayoutlibDelegate nRotate(long nativeCanvas, float degrees)270 public static void nRotate(long nativeCanvas, float degrees) { 271 // get the delegate from the native int. 272 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 273 if (canvasDelegate == null) { 274 return; 275 } 276 277 canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees)); 278 } 279 280 @LayoutlibDelegate nSkew(long nativeCanvas, float kx, float ky)281 public static void nSkew(long nativeCanvas, float kx, float ky) { 282 // get the delegate from the native int. 283 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 284 if (canvasDelegate == null) { 285 return; 286 } 287 288 // get the current top graphics2D object. 289 GcSnapshot g = canvasDelegate.getSnapshot(); 290 291 // get its current matrix 292 AffineTransform currentTx = g.getTransform(); 293 // get the AffineTransform for the given skew. 294 float[] mtx = Matrix_Delegate.getSkew(kx, ky); 295 AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx); 296 297 // combine them so that the given matrix is applied after. 298 currentTx.preConcatenate(matrixTx); 299 300 // give it to the graphics2D as a new matrix replacing all previous transform 301 g.setTransform(currentTx); 302 } 303 304 @LayoutlibDelegate nConcat(long nCanvas, long nMatrix)305 public static void nConcat(long nCanvas, long nMatrix) { 306 // get the delegate from the native int. 307 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas); 308 if (canvasDelegate == null) { 309 return; 310 } 311 312 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix); 313 if (matrixDelegate == null) { 314 return; 315 } 316 317 // get the current top graphics2D object. 318 GcSnapshot snapshot = canvasDelegate.getSnapshot(); 319 320 // get its current matrix 321 AffineTransform currentTx = snapshot.getTransform(); 322 // get the AffineTransform of the given matrix 323 AffineTransform matrixTx = matrixDelegate.getAffineTransform(); 324 325 // combine them so that the given matrix is applied after. 326 currentTx.concatenate(matrixTx); 327 328 // give it to the graphics2D as a new matrix replacing all previous transform 329 snapshot.setTransform(currentTx); 330 } 331 332 @LayoutlibDelegate nSetMatrix(long nCanvas, long nMatrix)333 public static void nSetMatrix(long nCanvas, long nMatrix) { 334 // get the delegate from the native int. 335 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas); 336 if (canvasDelegate == null) { 337 return; 338 } 339 340 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix); 341 if (matrixDelegate == null) { 342 return; 343 } 344 345 // get the current top graphics2D object. 346 GcSnapshot snapshot = canvasDelegate.getSnapshot(); 347 348 // get the AffineTransform of the given matrix 349 AffineTransform matrixTx = matrixDelegate.getAffineTransform(); 350 351 // give it to the graphics2D as a new matrix replacing all previous transform 352 snapshot.setTransform(matrixTx); 353 354 if (matrixDelegate.hasPerspective()) { 355 assert false; 356 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE, 357 "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " + 358 "supports affine transformations.", null, null /*data*/); 359 } 360 } 361 362 @LayoutlibDelegate nClipRect(long nCanvas, float left, float top, float right, float bottom, int regionOp)363 public static boolean nClipRect(long nCanvas, 364 float left, float top, 365 float right, float bottom, 366 int regionOp) { 367 // get the delegate from the native int. 368 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas); 369 if (canvasDelegate == null) { 370 return false; 371 } 372 373 return canvasDelegate.clipRect(left, top, right, bottom, regionOp); 374 } 375 376 @LayoutlibDelegate nClipPath(long nativeCanvas, long nativePath, int regionOp)377 public static boolean nClipPath(long nativeCanvas, 378 long nativePath, 379 int regionOp) { 380 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 381 if (canvasDelegate == null) { 382 return true; 383 } 384 385 Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath); 386 if (pathDelegate == null) { 387 return true; 388 } 389 390 return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp); 391 } 392 393 @LayoutlibDelegate nSetDrawFilter(long nativeCanvas, long nativeFilter)394 public static void nSetDrawFilter(long nativeCanvas, long nativeFilter) { 395 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 396 if (canvasDelegate == null) { 397 return; 398 } 399 400 canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter); 401 402 if (canvasDelegate.mDrawFilter != null && !canvasDelegate.mDrawFilter.isSupported()) { 403 Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER, 404 canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/); 405 } 406 } 407 408 @LayoutlibDelegate nGetClipBounds(long nativeCanvas, Rect bounds)409 public static boolean nGetClipBounds(long nativeCanvas, 410 Rect bounds) { 411 // get the delegate from the native int. 412 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 413 if (canvasDelegate == null) { 414 return false; 415 } 416 417 Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds(); 418 if (rect != null && !rect.isEmpty()) { 419 bounds.left = rect.x; 420 bounds.top = rect.y; 421 bounds.right = rect.x + rect.width; 422 bounds.bottom = rect.y + rect.height; 423 return true; 424 } 425 426 return false; 427 } 428 429 @LayoutlibDelegate nGetMatrix(long canvas, long matrix)430 public static void nGetMatrix(long canvas, long matrix) { 431 // get the delegate from the native int. 432 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); 433 if (canvasDelegate == null) { 434 return; 435 } 436 437 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix); 438 if (matrixDelegate == null) { 439 return; 440 } 441 442 AffineTransform transform = canvasDelegate.getSnapshot().getTransform(); 443 matrixDelegate.set(Matrix_Delegate.makeValues(transform)); 444 } 445 446 @LayoutlibDelegate nQuickReject(long nativeCanvas, long path)447 public static boolean nQuickReject(long nativeCanvas, long path) { 448 // FIXME properly implement quickReject 449 return false; 450 } 451 452 @LayoutlibDelegate nQuickReject(long nativeCanvas, float left, float top, float right, float bottom)453 public static boolean nQuickReject(long nativeCanvas, 454 float left, float top, 455 float right, float bottom) { 456 // FIXME properly implement quickReject 457 return false; 458 } 459 460 @LayoutlibDelegate nGetNativeFinalizer()461 /*package*/ static long nGetNativeFinalizer() { 462 synchronized (Canvas_Delegate.class) { 463 if (sFinalizer == -1) { 464 sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(nativePtr -> { 465 Canvas_Delegate delegate = Canvas_Delegate.getDelegate(nativePtr); 466 if (delegate != null) { 467 delegate.dispose(); 468 } 469 sManager.removeJavaReferenceFor(nativePtr); 470 }); 471 } 472 } 473 return sFinalizer; 474 } 475 Canvas_Delegate(Bitmap_Delegate bitmap)476 private Canvas_Delegate(Bitmap_Delegate bitmap) { 477 super(bitmap); 478 } 479 Canvas_Delegate()480 private Canvas_Delegate() { 481 super(); 482 } 483 } 484 485