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 nGetWidth(long nativeCanvas)144 public static int nGetWidth(long nativeCanvas) { 145 // get the delegate from the native int. 146 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 147 if (canvasDelegate == null) { 148 return 0; 149 } 150 151 return canvasDelegate.mBitmap.getImage().getWidth(); 152 } 153 154 @LayoutlibDelegate nGetHeight(long nativeCanvas)155 public static int nGetHeight(long nativeCanvas) { 156 // get the delegate from the native int. 157 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 158 if (canvasDelegate == null) { 159 return 0; 160 } 161 162 return canvasDelegate.mBitmap.getImage().getHeight(); 163 } 164 165 @LayoutlibDelegate nSave(long nativeCanvas, int saveFlags)166 public static int nSave(long nativeCanvas, int saveFlags) { 167 // get the delegate from the native int. 168 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 169 if (canvasDelegate == null) { 170 return 0; 171 } 172 173 return canvasDelegate.save(saveFlags); 174 } 175 176 @LayoutlibDelegate nSaveLayer(long nativeCanvas, float l, float t, float r, float b, long paint, int layerFlags)177 public static int nSaveLayer(long nativeCanvas, float l, 178 float t, float r, float b, 179 long paint, int layerFlags) { 180 // get the delegate from the native int. 181 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 182 if (canvasDelegate == null) { 183 return 0; 184 } 185 186 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint); 187 if (paintDelegate == null) { 188 return 0; 189 } 190 191 return canvasDelegate.saveLayer(new RectF(l, t, r, b), 192 paintDelegate, layerFlags); 193 } 194 195 @LayoutlibDelegate nSaveLayerAlpha(long nativeCanvas, float l, float t, float r, float b, int alpha, int layerFlags)196 public static int nSaveLayerAlpha(long nativeCanvas, float l, 197 float t, float r, float b, 198 int alpha, int layerFlags) { 199 // get the delegate from the native int. 200 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 201 if (canvasDelegate == null) { 202 return 0; 203 } 204 205 return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags); 206 } 207 208 @LayoutlibDelegate nRestore(long nativeCanvas)209 public static boolean nRestore(long nativeCanvas) { 210 // FIXME: implement throwOnUnderflow. 211 // get the delegate from the native int. 212 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 213 if (canvasDelegate == null) { 214 return false; 215 } 216 217 canvasDelegate.restore(); 218 return true; 219 } 220 221 @LayoutlibDelegate nRestoreToCount(long nativeCanvas, int saveCount)222 public static void nRestoreToCount(long nativeCanvas, int saveCount) { 223 // FIXME: implement throwOnUnderflow. 224 // get the delegate from the native int. 225 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 226 if (canvasDelegate == null) { 227 return; 228 } 229 230 canvasDelegate.restoreTo(saveCount); 231 } 232 233 @LayoutlibDelegate nGetSaveCount(long nativeCanvas)234 public static int nGetSaveCount(long nativeCanvas) { 235 // get the delegate from the native int. 236 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 237 if (canvasDelegate == null) { 238 return 0; 239 } 240 241 return canvasDelegate.getSnapshot().size(); 242 } 243 244 @LayoutlibDelegate nTranslate(long nativeCanvas, float dx, float dy)245 public static void nTranslate(long nativeCanvas, float dx, float dy) { 246 // get the delegate from the native int. 247 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 248 if (canvasDelegate == null) { 249 return; 250 } 251 252 canvasDelegate.getSnapshot().translate(dx, dy); 253 } 254 255 @LayoutlibDelegate nScale(long nativeCanvas, float sx, float sy)256 public static void nScale(long nativeCanvas, float sx, float sy) { 257 // get the delegate from the native int. 258 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 259 if (canvasDelegate == null) { 260 return; 261 } 262 263 canvasDelegate.getSnapshot().scale(sx, sy); 264 } 265 266 @LayoutlibDelegate nRotate(long nativeCanvas, float degrees)267 public static void nRotate(long nativeCanvas, float degrees) { 268 // get the delegate from the native int. 269 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 270 if (canvasDelegate == null) { 271 return; 272 } 273 274 canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees)); 275 } 276 277 @LayoutlibDelegate nSkew(long nativeCanvas, float kx, float ky)278 public static void nSkew(long nativeCanvas, float kx, float ky) { 279 // get the delegate from the native int. 280 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 281 if (canvasDelegate == null) { 282 return; 283 } 284 285 // get the current top graphics2D object. 286 GcSnapshot g = canvasDelegate.getSnapshot(); 287 288 // get its current matrix 289 AffineTransform currentTx = g.getTransform(); 290 // get the AffineTransform for the given skew. 291 float[] mtx = Matrix_Delegate.getSkew(kx, ky); 292 AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx); 293 294 // combine them so that the given matrix is applied after. 295 currentTx.preConcatenate(matrixTx); 296 297 // give it to the graphics2D as a new matrix replacing all previous transform 298 g.setTransform(currentTx); 299 } 300 301 @LayoutlibDelegate nConcat(long nCanvas, long nMatrix)302 public static void nConcat(long nCanvas, long nMatrix) { 303 // get the delegate from the native int. 304 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas); 305 if (canvasDelegate == null) { 306 return; 307 } 308 309 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix); 310 if (matrixDelegate == null) { 311 return; 312 } 313 314 // get the current top graphics2D object. 315 GcSnapshot snapshot = canvasDelegate.getSnapshot(); 316 317 // get its current matrix 318 AffineTransform currentTx = snapshot.getTransform(); 319 // get the AffineTransform of the given matrix 320 AffineTransform matrixTx = matrixDelegate.getAffineTransform(); 321 322 // combine them so that the given matrix is applied after. 323 currentTx.concatenate(matrixTx); 324 325 // give it to the graphics2D as a new matrix replacing all previous transform 326 snapshot.setTransform(currentTx); 327 } 328 329 @LayoutlibDelegate nSetMatrix(long nCanvas, long nMatrix)330 public static void nSetMatrix(long nCanvas, long nMatrix) { 331 // get the delegate from the native int. 332 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas); 333 if (canvasDelegate == null) { 334 return; 335 } 336 337 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix); 338 if (matrixDelegate == null) { 339 return; 340 } 341 342 // get the current top graphics2D object. 343 GcSnapshot snapshot = canvasDelegate.getSnapshot(); 344 345 // get the AffineTransform of the given matrix 346 AffineTransform matrixTx = matrixDelegate.getAffineTransform(); 347 348 // give it to the graphics2D as a new matrix replacing all previous transform 349 snapshot.setTransform(matrixTx); 350 351 if (matrixDelegate.hasPerspective()) { 352 assert false; 353 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE, 354 "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " + 355 "supports affine transformations.", null, null /*data*/); 356 } 357 } 358 359 @LayoutlibDelegate nClipRect(long nCanvas, float left, float top, float right, float bottom, int regionOp)360 public static boolean nClipRect(long nCanvas, 361 float left, float top, 362 float right, float bottom, 363 int regionOp) { 364 // get the delegate from the native int. 365 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas); 366 if (canvasDelegate == null) { 367 return false; 368 } 369 370 return canvasDelegate.clipRect(left, top, right, bottom, regionOp); 371 } 372 373 @LayoutlibDelegate nClipPath(long nativeCanvas, long nativePath, int regionOp)374 public static boolean nClipPath(long nativeCanvas, 375 long nativePath, 376 int regionOp) { 377 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 378 if (canvasDelegate == null) { 379 return true; 380 } 381 382 Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath); 383 if (pathDelegate == null) { 384 return true; 385 } 386 387 return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp); 388 } 389 390 @LayoutlibDelegate nSetDrawFilter(long nativeCanvas, long nativeFilter)391 public static void nSetDrawFilter(long nativeCanvas, long nativeFilter) { 392 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 393 if (canvasDelegate == null) { 394 return; 395 } 396 397 canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter); 398 399 if (canvasDelegate.mDrawFilter != null && !canvasDelegate.mDrawFilter.isSupported()) { 400 Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER, 401 canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/); 402 } 403 } 404 405 @LayoutlibDelegate nGetClipBounds(long nativeCanvas, Rect bounds)406 public static boolean nGetClipBounds(long nativeCanvas, 407 Rect bounds) { 408 // get the delegate from the native int. 409 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); 410 if (canvasDelegate == null) { 411 return false; 412 } 413 414 Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds(); 415 if (rect != null && !rect.isEmpty()) { 416 bounds.left = rect.x; 417 bounds.top = rect.y; 418 bounds.right = rect.x + rect.width; 419 bounds.bottom = rect.y + rect.height; 420 return true; 421 } 422 423 return false; 424 } 425 426 @LayoutlibDelegate nGetMatrix(long canvas, long matrix)427 public static void nGetMatrix(long canvas, long matrix) { 428 // get the delegate from the native int. 429 Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); 430 if (canvasDelegate == null) { 431 return; 432 } 433 434 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix); 435 if (matrixDelegate == null) { 436 return; 437 } 438 439 AffineTransform transform = canvasDelegate.getSnapshot().getTransform(); 440 matrixDelegate.set(Matrix_Delegate.makeValues(transform)); 441 } 442 443 @LayoutlibDelegate nQuickReject(long nativeCanvas, long path)444 public static boolean nQuickReject(long nativeCanvas, long path) { 445 // FIXME properly implement quickReject 446 return false; 447 } 448 449 @LayoutlibDelegate nQuickReject(long nativeCanvas, float left, float top, float right, float bottom)450 public static boolean nQuickReject(long nativeCanvas, 451 float left, float top, 452 float right, float bottom) { 453 // FIXME properly implement quickReject 454 return false; 455 } 456 457 @LayoutlibDelegate nGetNativeFinalizer()458 /*package*/ static long nGetNativeFinalizer() { 459 synchronized (Canvas_Delegate.class) { 460 if (sFinalizer == -1) { 461 sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(nativePtr -> { 462 Canvas_Delegate delegate = Canvas_Delegate.getDelegate(nativePtr); 463 if (delegate != null) { 464 delegate.dispose(); 465 } 466 sManager.removeJavaReferenceFor(nativePtr); 467 }); 468 } 469 } 470 return sFinalizer; 471 } 472 473 @LayoutlibDelegate nSetCompatibilityVersion(int apiLevel)474 /*package*/ static void nSetCompatibilityVersion(int apiLevel) { 475 // Unsupported by layoutlib, do nothing 476 } 477 Canvas_Delegate(Bitmap_Delegate bitmap)478 private Canvas_Delegate(Bitmap_Delegate bitmap) { 479 super(bitmap); 480 } 481 Canvas_Delegate()482 private Canvas_Delegate() { 483 super(); 484 } 485 } 486 487