Canvas_Delegate.java revision dcc3e373c444b488f84a97654ef14667d183a423
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 17package android.graphics; 18 19import com.android.ide.common.rendering.api.LayoutLog; 20import com.android.layoutlib.bridge.Bridge; 21import com.android.layoutlib.bridge.impl.DelegateManager; 22import com.android.layoutlib.bridge.impl.GcSnapshot; 23import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 24 25import android.annotation.Nullable; 26import android.graphics.Bitmap.Config; 27 28import java.awt.Graphics2D; 29import java.awt.Rectangle; 30import java.awt.geom.AffineTransform; 31 32import 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 */ 48public 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 */ 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 */ 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 */ 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 */ 83 public DrawFilter_Delegate getDrawFilter() { 84 return mDrawFilter; 85 } 86 87 // ---- native methods ---- 88 89 @LayoutlibDelegate 90 /*package*/ static void nFreeCaches() { 91 // nothing to be done here. 92 } 93 94 @LayoutlibDelegate 95 /*package*/ static void nFreeTextLayoutCaches() { 96 // nothing to be done here yet. 97 } 98 99 @LayoutlibDelegate 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 444 public static boolean nQuickReject(long nativeCanvas, long path) { 445 // FIXME properly implement quickReject 446 return false; 447 } 448 449 @LayoutlibDelegate 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 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 private Canvas_Delegate(Bitmap_Delegate bitmap) { 474 super(bitmap); 475 } 476 477 private Canvas_Delegate() { 478 super(); 479 } 480} 481 482