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 20 import com.android.ide.common.rendering.api.LayoutLog; 21 import com.android.layoutlib.bridge.Bridge; 22 import com.android.layoutlib.bridge.impl.DelegateManager; 23 import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 24 25 import android.graphics.Matrix.ScaleToFit; 26 27 import java.awt.geom.AffineTransform; 28 import java.awt.geom.NoninvertibleTransformException; 29 30 import libcore.util.NativeAllocationRegistry_Delegate; 31 32 /** 33 * Delegate implementing the native methods of android.graphics.Matrix 34 * 35 * Through the layoutlib_create tool, the original native methods of Matrix have been replaced 36 * by calls to methods of the same name in this delegate class. 37 * 38 * This class behaves like the original native implementation, but in Java, keeping previously 39 * native data into its own objects and mapping them to int that are sent back and forth between 40 * it and the original Matrix class. 41 * 42 * @see DelegateManager 43 * 44 */ 45 public final class Matrix_Delegate { 46 47 private final static int MATRIX_SIZE = 9; 48 49 // ---- delegate manager ---- 50 private static final DelegateManager<Matrix_Delegate> sManager = 51 new DelegateManager<Matrix_Delegate>(Matrix_Delegate.class); 52 private static long sFinalizer = -1; 53 54 // ---- delegate data ---- 55 private float mValues[] = new float[MATRIX_SIZE]; 56 57 // ---- Public Helper methods ---- 58 getDelegate(long native_instance)59 public static Matrix_Delegate getDelegate(long native_instance) { 60 return sManager.getDelegate(native_instance); 61 } 62 63 /** 64 * Returns an {@link AffineTransform} matching the given Matrix. 65 */ getAffineTransform(Matrix m)66 public static AffineTransform getAffineTransform(Matrix m) { 67 Matrix_Delegate delegate = sManager.getDelegate(m.native_instance); 68 if (delegate == null) { 69 return null; 70 } 71 72 return delegate.getAffineTransform(); 73 } 74 hasPerspective(Matrix m)75 public static boolean hasPerspective(Matrix m) { 76 Matrix_Delegate delegate = sManager.getDelegate(m.native_instance); 77 if (delegate == null) { 78 return false; 79 } 80 81 return delegate.hasPerspective(); 82 } 83 84 /** 85 * Sets the content of the matrix with the content of another matrix. 86 */ set(Matrix_Delegate matrix)87 public void set(Matrix_Delegate matrix) { 88 System.arraycopy(matrix.mValues, 0, mValues, 0, MATRIX_SIZE); 89 } 90 91 /** 92 * Sets the content of the matrix with the content of another matrix represented as an array 93 * of values. 94 */ set(float[] values)95 public void set(float[] values) { 96 System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE); 97 } 98 99 /** 100 * Resets the matrix to be the identity matrix. 101 */ reset()102 public void reset() { 103 reset(mValues); 104 } 105 106 /** 107 * Returns whether or not the matrix is identity. 108 */ isIdentity()109 public boolean isIdentity() { 110 for (int i = 0, k = 0; i < 3; i++) { 111 for (int j = 0; j < 3; j++, k++) { 112 if (mValues[k] != ((i==j) ? 1 : 0)) { 113 return false; 114 } 115 } 116 } 117 118 return true; 119 } 120 setValues(AffineTransform matrix, float[] values)121 private static float[] setValues(AffineTransform matrix, float[] values) { 122 values[0] = (float) matrix.getScaleX(); 123 values[1] = (float) matrix.getShearX(); 124 values[2] = (float) matrix.getTranslateX(); 125 values[3] = (float) matrix.getShearY(); 126 values[4] = (float) matrix.getScaleY(); 127 values[5] = (float) matrix.getTranslateY(); 128 values[6] = 0.f; 129 values[7] = 0.f; 130 values[8] = 1.f; 131 132 return values; 133 } 134 makeValues(AffineTransform matrix)135 public static float[] makeValues(AffineTransform matrix) { 136 return setValues(matrix, new float[MATRIX_SIZE]); 137 } 138 make(AffineTransform matrix)139 public static Matrix_Delegate make(AffineTransform matrix) { 140 return new Matrix_Delegate(makeValues(matrix)); 141 } 142 mapRect(RectF dst, RectF src)143 public boolean mapRect(RectF dst, RectF src) { 144 // array with 4 corners 145 float[] corners = new float[] { 146 src.left, src.top, 147 src.right, src.top, 148 src.right, src.bottom, 149 src.left, src.bottom, 150 }; 151 152 // apply the transform to them. 153 mapPoints(corners); 154 155 // now put the result in the rect. We take the min/max of Xs and min/max of Ys 156 dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6])); 157 dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6])); 158 159 dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7])); 160 dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7])); 161 162 163 return (computeTypeMask() & kRectStaysRect_Mask) != 0; 164 } 165 166 167 /** 168 * Returns an {@link AffineTransform} matching the matrix. 169 */ getAffineTransform()170 public AffineTransform getAffineTransform() { 171 return getAffineTransform(mValues); 172 } 173 hasPerspective()174 public boolean hasPerspective() { 175 return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1); 176 } 177 178 179 180 // ---- native methods ---- 181 182 @LayoutlibDelegate nCreate(long native_src_or_zero)183 /*package*/ static long nCreate(long native_src_or_zero) { 184 // create the delegate 185 Matrix_Delegate newDelegate = new Matrix_Delegate(); 186 187 // copy from values if needed. 188 if (native_src_or_zero > 0) { 189 Matrix_Delegate oldDelegate = sManager.getDelegate(native_src_or_zero); 190 if (oldDelegate != null) { 191 System.arraycopy( 192 oldDelegate.mValues, 0, 193 newDelegate.mValues, 0, 194 MATRIX_SIZE); 195 } 196 } 197 198 return sManager.addNewDelegate(newDelegate); 199 } 200 201 @LayoutlibDelegate nIsIdentity(long native_object)202 /*package*/ static boolean nIsIdentity(long native_object) { 203 Matrix_Delegate d = sManager.getDelegate(native_object); 204 if (d == null) { 205 return false; 206 } 207 208 return d.isIdentity(); 209 } 210 211 @LayoutlibDelegate nIsAffine(long native_object)212 /*package*/ static boolean nIsAffine(long native_object) { 213 Matrix_Delegate d = sManager.getDelegate(native_object); 214 if (d == null) { 215 return true; 216 } 217 218 return (d.computeTypeMask() & kPerspective_Mask) == 0; 219 } 220 221 @LayoutlibDelegate nRectStaysRect(long native_object)222 /*package*/ static boolean nRectStaysRect(long native_object) { 223 Matrix_Delegate d = sManager.getDelegate(native_object); 224 if (d == null) { 225 return true; 226 } 227 228 return (d.computeTypeMask() & kRectStaysRect_Mask) != 0; 229 } 230 231 @LayoutlibDelegate nReset(long native_object)232 /*package*/ static void nReset(long native_object) { 233 Matrix_Delegate d = sManager.getDelegate(native_object); 234 if (d == null) { 235 return; 236 } 237 238 reset(d.mValues); 239 } 240 241 @LayoutlibDelegate nSet(long native_object, long other)242 /*package*/ static void nSet(long native_object, long other) { 243 Matrix_Delegate d = sManager.getDelegate(native_object); 244 if (d == null) { 245 return; 246 } 247 248 Matrix_Delegate src = sManager.getDelegate(other); 249 if (src == null) { 250 return; 251 } 252 253 System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE); 254 } 255 256 @LayoutlibDelegate nSetTranslate(long native_object, float dx, float dy)257 /*package*/ static void nSetTranslate(long native_object, float dx, float dy) { 258 Matrix_Delegate d = sManager.getDelegate(native_object); 259 if (d == null) { 260 return; 261 } 262 263 setTranslate(d.mValues, dx, dy); 264 } 265 266 @LayoutlibDelegate nSetScale(long native_object, float sx, float sy, float px, float py)267 /*package*/ static void nSetScale(long native_object, float sx, float sy, 268 float px, float py) { 269 Matrix_Delegate d = sManager.getDelegate(native_object); 270 if (d == null) { 271 return; 272 } 273 274 d.mValues = getScale(sx, sy, px, py); 275 } 276 277 @LayoutlibDelegate nSetScale(long native_object, float sx, float sy)278 /*package*/ static void nSetScale(long native_object, float sx, float sy) { 279 Matrix_Delegate d = sManager.getDelegate(native_object); 280 if (d == null) { 281 return; 282 } 283 284 d.mValues[0] = sx; 285 d.mValues[1] = 0; 286 d.mValues[2] = 0; 287 d.mValues[3] = 0; 288 d.mValues[4] = sy; 289 d.mValues[5] = 0; 290 d.mValues[6] = 0; 291 d.mValues[7] = 0; 292 d.mValues[8] = 1; 293 } 294 295 @LayoutlibDelegate nSetRotate(long native_object, float degrees, float px, float py)296 /*package*/ static void nSetRotate(long native_object, float degrees, float px, float py) { 297 Matrix_Delegate d = sManager.getDelegate(native_object); 298 if (d == null) { 299 return; 300 } 301 302 d.mValues = getRotate(degrees, px, py); 303 } 304 305 @LayoutlibDelegate nSetRotate(long native_object, float degrees)306 /*package*/ static void nSetRotate(long native_object, float degrees) { 307 Matrix_Delegate d = sManager.getDelegate(native_object); 308 if (d == null) { 309 return; 310 } 311 312 setRotate(d.mValues, degrees); 313 } 314 315 @LayoutlibDelegate nSetSinCos(long native_object, float sinValue, float cosValue, float px, float py)316 /*package*/ static void nSetSinCos(long native_object, float sinValue, float cosValue, 317 float px, float py) { 318 Matrix_Delegate d = sManager.getDelegate(native_object); 319 if (d == null) { 320 return; 321 } 322 323 // TODO: do it in one pass 324 325 // translate so that the pivot is in 0,0 326 setTranslate(d.mValues, -px, -py); 327 328 // scale 329 d.postTransform(getRotate(sinValue, cosValue)); 330 // translate back the pivot 331 d.postTransform(getTranslate(px, py)); 332 } 333 334 @LayoutlibDelegate nSetSinCos(long native_object, float sinValue, float cosValue)335 /*package*/ static void nSetSinCos(long native_object, float sinValue, float cosValue) { 336 Matrix_Delegate d = sManager.getDelegate(native_object); 337 if (d == null) { 338 return; 339 } 340 341 setRotate(d.mValues, sinValue, cosValue); 342 } 343 344 @LayoutlibDelegate nSetSkew(long native_object, float kx, float ky, float px, float py)345 /*package*/ static void nSetSkew(long native_object, float kx, float ky, 346 float px, float py) { 347 Matrix_Delegate d = sManager.getDelegate(native_object); 348 if (d == null) { 349 return; 350 } 351 352 d.mValues = getSkew(kx, ky, px, py); 353 } 354 355 @LayoutlibDelegate nSetSkew(long native_object, float kx, float ky)356 /*package*/ static void nSetSkew(long native_object, float kx, float ky) { 357 Matrix_Delegate d = sManager.getDelegate(native_object); 358 if (d == null) { 359 return; 360 } 361 362 d.mValues[0] = 1; 363 d.mValues[1] = kx; 364 d.mValues[2] = -0; 365 d.mValues[3] = ky; 366 d.mValues[4] = 1; 367 d.mValues[5] = 0; 368 d.mValues[6] = 0; 369 d.mValues[7] = 0; 370 d.mValues[8] = 1; 371 } 372 373 @LayoutlibDelegate nSetConcat(long native_object, long a, long b)374 /*package*/ static void nSetConcat(long native_object, long a, long b) { 375 if (a == native_object) { 376 nPreConcat(native_object, b); 377 return; 378 } else if (b == native_object) { 379 nPostConcat(native_object, a); 380 return; 381 } 382 383 Matrix_Delegate d = sManager.getDelegate(native_object); 384 Matrix_Delegate a_mtx = sManager.getDelegate(a); 385 Matrix_Delegate b_mtx = sManager.getDelegate(b); 386 if (d != null && a_mtx != null && b_mtx != null) { 387 multiply(d.mValues, a_mtx.mValues, b_mtx.mValues); 388 } 389 } 390 391 @LayoutlibDelegate nPreTranslate(long native_object, float dx, float dy)392 /*package*/ static void nPreTranslate(long native_object, float dx, float dy) { 393 Matrix_Delegate d = sManager.getDelegate(native_object); 394 if (d != null) { 395 d.preTransform(getTranslate(dx, dy)); 396 } 397 } 398 399 @LayoutlibDelegate nPreScale(long native_object, float sx, float sy, float px, float py)400 /*package*/ static void nPreScale(long native_object, float sx, float sy, 401 float px, float py) { 402 Matrix_Delegate d = sManager.getDelegate(native_object); 403 if (d != null) { 404 d.preTransform(getScale(sx, sy, px, py)); 405 } 406 } 407 408 @LayoutlibDelegate nPreScale(long native_object, float sx, float sy)409 /*package*/ static void nPreScale(long native_object, float sx, float sy) { 410 Matrix_Delegate d = sManager.getDelegate(native_object); 411 if (d != null) { 412 d.preTransform(getScale(sx, sy)); 413 } 414 } 415 416 @LayoutlibDelegate nPreRotate(long native_object, float degrees, float px, float py)417 /*package*/ static void nPreRotate(long native_object, float degrees, 418 float px, float py) { 419 Matrix_Delegate d = sManager.getDelegate(native_object); 420 if (d != null) { 421 d.preTransform(getRotate(degrees, px, py)); 422 } 423 } 424 425 @LayoutlibDelegate nPreRotate(long native_object, float degrees)426 /*package*/ static void nPreRotate(long native_object, float degrees) { 427 Matrix_Delegate d = sManager.getDelegate(native_object); 428 if (d != null) { 429 430 double rad = Math.toRadians(degrees); 431 float sin = (float) Math.sin(rad); 432 float cos = (float) Math.cos(rad); 433 434 d.preTransform(getRotate(sin, cos)); 435 } 436 } 437 438 @LayoutlibDelegate nPreSkew(long native_object, float kx, float ky, float px, float py)439 /*package*/ static void nPreSkew(long native_object, float kx, float ky, 440 float px, float py) { 441 Matrix_Delegate d = sManager.getDelegate(native_object); 442 if (d != null) { 443 d.preTransform(getSkew(kx, ky, px, py)); 444 } 445 } 446 447 @LayoutlibDelegate nPreSkew(long native_object, float kx, float ky)448 /*package*/ static void nPreSkew(long native_object, float kx, float ky) { 449 Matrix_Delegate d = sManager.getDelegate(native_object); 450 if (d != null) { 451 d.preTransform(getSkew(kx, ky)); 452 } 453 } 454 455 @LayoutlibDelegate nPreConcat(long native_object, long other_matrix)456 /*package*/ static void nPreConcat(long native_object, long other_matrix) { 457 Matrix_Delegate d = sManager.getDelegate(native_object); 458 Matrix_Delegate other = sManager.getDelegate(other_matrix); 459 if (d != null && other != null) { 460 d.preTransform(other.mValues); 461 } 462 } 463 464 @LayoutlibDelegate nPostTranslate(long native_object, float dx, float dy)465 /*package*/ static void nPostTranslate(long native_object, float dx, float dy) { 466 Matrix_Delegate d = sManager.getDelegate(native_object); 467 if (d != null) { 468 d.postTransform(getTranslate(dx, dy)); 469 } 470 } 471 472 @LayoutlibDelegate nPostScale(long native_object, float sx, float sy, float px, float py)473 /*package*/ static void nPostScale(long native_object, float sx, float sy, 474 float px, float py) { 475 Matrix_Delegate d = sManager.getDelegate(native_object); 476 if (d != null) { 477 d.postTransform(getScale(sx, sy, px, py)); 478 } 479 } 480 481 @LayoutlibDelegate nPostScale(long native_object, float sx, float sy)482 /*package*/ static void nPostScale(long native_object, float sx, float sy) { 483 Matrix_Delegate d = sManager.getDelegate(native_object); 484 if (d != null) { 485 d.postTransform(getScale(sx, sy)); 486 } 487 } 488 489 @LayoutlibDelegate nPostRotate(long native_object, float degrees, float px, float py)490 /*package*/ static void nPostRotate(long native_object, float degrees, 491 float px, float py) { 492 Matrix_Delegate d = sManager.getDelegate(native_object); 493 if (d != null) { 494 d.postTransform(getRotate(degrees, px, py)); 495 } 496 } 497 498 @LayoutlibDelegate nPostRotate(long native_object, float degrees)499 /*package*/ static void nPostRotate(long native_object, float degrees) { 500 Matrix_Delegate d = sManager.getDelegate(native_object); 501 if (d != null) { 502 d.postTransform(getRotate(degrees)); 503 } 504 } 505 506 @LayoutlibDelegate nPostSkew(long native_object, float kx, float ky, float px, float py)507 /*package*/ static void nPostSkew(long native_object, float kx, float ky, 508 float px, float py) { 509 Matrix_Delegate d = sManager.getDelegate(native_object); 510 if (d != null) { 511 d.postTransform(getSkew(kx, ky, px, py)); 512 } 513 } 514 515 @LayoutlibDelegate nPostSkew(long native_object, float kx, float ky)516 /*package*/ static void nPostSkew(long native_object, float kx, float ky) { 517 Matrix_Delegate d = sManager.getDelegate(native_object); 518 if (d != null) { 519 d.postTransform(getSkew(kx, ky)); 520 } 521 } 522 523 @LayoutlibDelegate nPostConcat(long native_object, long other_matrix)524 /*package*/ static void nPostConcat(long native_object, long other_matrix) { 525 Matrix_Delegate d = sManager.getDelegate(native_object); 526 Matrix_Delegate other = sManager.getDelegate(other_matrix); 527 if (d != null && other != null) { 528 d.postTransform(other.mValues); 529 } 530 } 531 532 @LayoutlibDelegate nSetRectToRect(long native_object, RectF src, RectF dst, int stf)533 /*package*/ static boolean nSetRectToRect(long native_object, RectF src, 534 RectF dst, int stf) { 535 Matrix_Delegate d = sManager.getDelegate(native_object); 536 if (d == null) { 537 return false; 538 } 539 540 if (src.isEmpty()) { 541 reset(d.mValues); 542 return false; 543 } 544 545 if (dst.isEmpty()) { 546 d.mValues[0] = d.mValues[1] = d.mValues[2] = d.mValues[3] = d.mValues[4] = d.mValues[5] 547 = d.mValues[6] = d.mValues[7] = 0; 548 d.mValues[8] = 1; 549 } else { 550 float tx, sx = dst.width() / src.width(); 551 float ty, sy = dst.height() / src.height(); 552 boolean xLarger = false; 553 554 if (stf != ScaleToFit.FILL.nativeInt) { 555 if (sx > sy) { 556 xLarger = true; 557 sx = sy; 558 } else { 559 sy = sx; 560 } 561 } 562 563 tx = dst.left - src.left * sx; 564 ty = dst.top - src.top * sy; 565 if (stf == ScaleToFit.CENTER.nativeInt || stf == ScaleToFit.END.nativeInt) { 566 float diff; 567 568 if (xLarger) { 569 diff = dst.width() - src.width() * sy; 570 } else { 571 diff = dst.height() - src.height() * sy; 572 } 573 574 if (stf == ScaleToFit.CENTER.nativeInt) { 575 diff = diff / 2; 576 } 577 578 if (xLarger) { 579 tx += diff; 580 } else { 581 ty += diff; 582 } 583 } 584 585 d.mValues[0] = sx; 586 d.mValues[4] = sy; 587 d.mValues[2] = tx; 588 d.mValues[5] = ty; 589 d.mValues[1] = d.mValues[3] = d.mValues[6] = d.mValues[7] = 0; 590 591 } 592 // shared cleanup 593 d.mValues[8] = 1; 594 return true; 595 } 596 597 @LayoutlibDelegate nSetPolyToPoly(long native_object, float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount)598 /*package*/ static boolean nSetPolyToPoly(long native_object, float[] src, int srcIndex, 599 float[] dst, int dstIndex, int pointCount) { 600 // FIXME 601 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 602 "Matrix.setPolyToPoly is not supported.", 603 null, null, null /*data*/); 604 return false; 605 } 606 607 @LayoutlibDelegate nInvert(long native_object, long inverse)608 /*package*/ static boolean nInvert(long native_object, long inverse) { 609 Matrix_Delegate d = sManager.getDelegate(native_object); 610 if (d == null) { 611 return false; 612 } 613 614 Matrix_Delegate inv_mtx = sManager.getDelegate(inverse); 615 if (inv_mtx == null) { 616 return false; 617 } 618 619 float det = d.mValues[0] * (d.mValues[4] * d.mValues[8] - d.mValues[5] * d.mValues[7]) 620 + d.mValues[1] * (d.mValues[5] * d.mValues[6] - d.mValues[3] * d.mValues[8]) 621 + d.mValues[2] * (d.mValues[3] * d.mValues[7] - d.mValues[4] * d.mValues[6]); 622 623 if (det == 0.0) { 624 return false; 625 } 626 627 inv_mtx.mValues[0] = (d.mValues[4] * d.mValues[8] - d.mValues[5] * d.mValues[7]) / det; 628 inv_mtx.mValues[1] = (d.mValues[2] * d.mValues[7] - d.mValues[1] * d.mValues[8]) / det; 629 inv_mtx.mValues[2] = (d.mValues[1] * d.mValues[5] - d.mValues[2] * d.mValues[4]) / det; 630 inv_mtx.mValues[3] = (d.mValues[5] * d.mValues[6] - d.mValues[3] * d.mValues[8]) / det; 631 inv_mtx.mValues[4] = (d.mValues[0] * d.mValues[8] - d.mValues[2] * d.mValues[6]) / det; 632 inv_mtx.mValues[5] = (d.mValues[2] * d.mValues[3] - d.mValues[0] * d.mValues[5]) / det; 633 inv_mtx.mValues[6] = (d.mValues[3] * d.mValues[7] - d.mValues[4] * d.mValues[6]) / det; 634 inv_mtx.mValues[7] = (d.mValues[1] * d.mValues[6] - d.mValues[0] * d.mValues[7]) / det; 635 inv_mtx.mValues[8] = (d.mValues[0] * d.mValues[4] - d.mValues[1] * d.mValues[3]) / det; 636 637 return true; 638 } 639 640 @LayoutlibDelegate nMapPoints(long native_object, float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount, boolean isPts)641 /*package*/ static void nMapPoints(long native_object, float[] dst, int dstIndex, 642 float[] src, int srcIndex, int ptCount, boolean isPts) { 643 Matrix_Delegate d = sManager.getDelegate(native_object); 644 if (d == null) { 645 return; 646 } 647 648 if (isPts) { 649 d.mapPoints(dst, dstIndex, src, srcIndex, ptCount); 650 } else { 651 d.mapVectors(dst, dstIndex, src, srcIndex, ptCount); 652 } 653 } 654 655 @LayoutlibDelegate nMapRect(long native_object, RectF dst, RectF src)656 /*package*/ static boolean nMapRect(long native_object, RectF dst, RectF src) { 657 Matrix_Delegate d = sManager.getDelegate(native_object); 658 if (d == null) { 659 return false; 660 } 661 662 return d.mapRect(dst, src); 663 } 664 665 @LayoutlibDelegate nMapRadius(long native_object, float radius)666 /*package*/ static float nMapRadius(long native_object, float radius) { 667 Matrix_Delegate d = sManager.getDelegate(native_object); 668 if (d == null) { 669 return 0.f; 670 } 671 672 float[] src = new float[] { radius, 0.f, 0.f, radius }; 673 d.mapVectors(src, 0, src, 0, 2); 674 675 float l1 = (float) Math.hypot(src[0], src[1]); 676 float l2 = (float) Math.hypot(src[2], src[3]); 677 return (float) Math.sqrt(l1 * l2); 678 } 679 680 @LayoutlibDelegate nGetValues(long native_object, float[] values)681 /*package*/ static void nGetValues(long native_object, float[] values) { 682 Matrix_Delegate d = sManager.getDelegate(native_object); 683 if (d == null) { 684 return; 685 } 686 687 System.arraycopy(d.mValues, 0, values, 0, MATRIX_SIZE); 688 } 689 690 @LayoutlibDelegate nSetValues(long native_object, float[] values)691 /*package*/ static void nSetValues(long native_object, float[] values) { 692 Matrix_Delegate d = sManager.getDelegate(native_object); 693 if (d == null) { 694 return; 695 } 696 697 System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE); 698 } 699 700 @LayoutlibDelegate nEquals(long native_a, long native_b)701 /*package*/ static boolean nEquals(long native_a, long native_b) { 702 Matrix_Delegate a = sManager.getDelegate(native_a); 703 if (a == null) { 704 return false; 705 } 706 707 Matrix_Delegate b = sManager.getDelegate(native_b); 708 if (b == null) { 709 return false; 710 } 711 712 for (int i = 0 ; i < MATRIX_SIZE ; i++) { 713 if (a.mValues[i] != b.mValues[i]) { 714 return false; 715 } 716 } 717 718 return true; 719 } 720 721 @LayoutlibDelegate nGetNativeFinalizer()722 /*package*/ static long nGetNativeFinalizer() { 723 synchronized (Matrix_Delegate.class) { 724 if (sFinalizer == -1) { 725 sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(sManager::removeJavaReferenceFor); 726 } 727 } 728 return sFinalizer; 729 } 730 731 // ---- Private helper methods ---- 732 getAffineTransform(float[] matrix)733 /*package*/ static AffineTransform getAffineTransform(float[] matrix) { 734 // the AffineTransform constructor takes the value in a different order 735 // for a matrix [ 0 1 2 ] 736 // [ 3 4 5 ] 737 // the order is 0, 3, 1, 4, 2, 5... 738 return new AffineTransform( 739 matrix[0], matrix[3], matrix[1], 740 matrix[4], matrix[2], matrix[5]); 741 } 742 743 /** 744 * Reset a matrix to the identity 745 */ reset(float[] mtx)746 private static void reset(float[] mtx) { 747 for (int i = 0, k = 0; i < 3; i++) { 748 for (int j = 0; j < 3; j++, k++) { 749 mtx[k] = ((i==j) ? 1 : 0); 750 } 751 } 752 } 753 754 @SuppressWarnings("unused") 755 private final static int kIdentity_Mask = 0; 756 private final static int kTranslate_Mask = 0x01; //!< set if the matrix has translation 757 private final static int kScale_Mask = 0x02; //!< set if the matrix has X or Y scale 758 private final static int kAffine_Mask = 0x04; //!< set if the matrix skews or rotates 759 private final static int kPerspective_Mask = 0x08; //!< set if the matrix is in perspective 760 private final static int kRectStaysRect_Mask = 0x10; 761 @SuppressWarnings("unused") 762 private final static int kUnknown_Mask = 0x80; 763 764 @SuppressWarnings("unused") 765 private final static int kAllMasks = kTranslate_Mask | 766 kScale_Mask | 767 kAffine_Mask | 768 kPerspective_Mask | 769 kRectStaysRect_Mask; 770 771 // these guys align with the masks, so we can compute a mask from a variable 0/1 772 @SuppressWarnings("unused") 773 private final static int kTranslate_Shift = 0; 774 @SuppressWarnings("unused") 775 private final static int kScale_Shift = 1; 776 @SuppressWarnings("unused") 777 private final static int kAffine_Shift = 2; 778 @SuppressWarnings("unused") 779 private final static int kPerspective_Shift = 3; 780 private final static int kRectStaysRect_Shift = 4; 781 computeTypeMask()782 private int computeTypeMask() { 783 int mask = 0; 784 785 if (mValues[6] != 0. || mValues[7] != 0. || mValues[8] != 1.) { 786 mask |= kPerspective_Mask; 787 } 788 789 if (mValues[2] != 0. || mValues[5] != 0.) { 790 mask |= kTranslate_Mask; 791 } 792 793 float m00 = mValues[0]; 794 float m01 = mValues[1]; 795 float m10 = mValues[3]; 796 float m11 = mValues[4]; 797 798 if (m01 != 0. || m10 != 0.) { 799 mask |= kAffine_Mask; 800 } 801 802 if (m00 != 1. || m11 != 1.) { 803 mask |= kScale_Mask; 804 } 805 806 if ((mask & kPerspective_Mask) == 0) { 807 // map non-zero to 1 808 int im00 = m00 != 0 ? 1 : 0; 809 int im01 = m01 != 0 ? 1 : 0; 810 int im10 = m10 != 0 ? 1 : 0; 811 int im11 = m11 != 0 ? 1 : 0; 812 813 // record if the (p)rimary and (s)econdary diagonals are all 0 or 814 // all non-zero (answer is 0 or 1) 815 int dp0 = (im00 | im11) ^ 1; // true if both are 0 816 int dp1 = im00 & im11; // true if both are 1 817 int ds0 = (im01 | im10) ^ 1; // true if both are 0 818 int ds1 = im01 & im10; // true if both are 1 819 820 // return 1 if primary is 1 and secondary is 0 or 821 // primary is 0 and secondary is 1 822 mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift; 823 } 824 825 return mask; 826 } 827 Matrix_Delegate()828 private Matrix_Delegate() { 829 reset(); 830 } 831 Matrix_Delegate(float[] values)832 private Matrix_Delegate(float[] values) { 833 System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE); 834 } 835 836 /** 837 * Adds the given transformation to the current Matrix 838 * <p/>This in effect does this = this*matrix 839 * @param matrix 840 */ postTransform(float[] matrix)841 private void postTransform(float[] matrix) { 842 float[] tmp = new float[9]; 843 multiply(tmp, mValues, matrix); 844 mValues = tmp; 845 } 846 847 /** 848 * Adds the given transformation to the current Matrix 849 * <p/>This in effect does this = matrix*this 850 * @param matrix 851 */ preTransform(float[] matrix)852 private void preTransform(float[] matrix) { 853 float[] tmp = new float[9]; 854 multiply(tmp, matrix, mValues); 855 mValues = tmp; 856 } 857 858 /** 859 * Apply this matrix to the array of 2D points specified by src, and write 860 * the transformed points into the array of points specified by dst. The 861 * two arrays represent their "points" as pairs of floats [x, y]. 862 * 863 * @param dst The array of dst points (x,y pairs) 864 * @param dstIndex The index of the first [x,y] pair of dst floats 865 * @param src The array of src points (x,y pairs) 866 * @param srcIndex The index of the first [x,y] pair of src floats 867 * @param pointCount The number of points (x,y pairs) to transform 868 */ 869 mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, int pointCount)870 private void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, 871 int pointCount) { 872 final int count = pointCount * 2; 873 874 float[] tmpDest = dst; 875 boolean inPlace = dst == src; 876 if (inPlace) { 877 tmpDest = new float[dstIndex + count]; 878 } 879 880 for (int i = 0 ; i < count ; i += 2) { 881 // just in case we are doing in place, we better put this in temp vars 882 float x = mValues[0] * src[i + srcIndex] + 883 mValues[1] * src[i + srcIndex + 1] + 884 mValues[2]; 885 float y = mValues[3] * src[i + srcIndex] + 886 mValues[4] * src[i + srcIndex + 1] + 887 mValues[5]; 888 889 tmpDest[i + dstIndex] = x; 890 tmpDest[i + dstIndex + 1] = y; 891 } 892 893 if (inPlace) { 894 System.arraycopy(tmpDest, dstIndex, dst, dstIndex, count); 895 } 896 } 897 898 /** 899 * Apply this matrix to the array of 2D points, and write the transformed 900 * points back into the array 901 * 902 * @param pts The array [x0, y0, x1, y1, ...] of points to transform. 903 */ 904 mapPoints(float[] pts)905 private void mapPoints(float[] pts) { 906 mapPoints(pts, 0, pts, 0, pts.length >> 1); 907 } 908 mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount)909 private void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount) { 910 if (hasPerspective()) { 911 // transform the (0,0) point 912 float[] origin = new float[] { 0.f, 0.f}; 913 mapPoints(origin); 914 915 // translate the vector data as points 916 mapPoints(dst, dstIndex, src, srcIndex, ptCount); 917 918 // then substract the transformed origin. 919 final int count = ptCount * 2; 920 for (int i = 0 ; i < count ; i += 2) { 921 dst[dstIndex + i] = dst[dstIndex + i] - origin[0]; 922 dst[dstIndex + i + 1] = dst[dstIndex + i + 1] - origin[1]; 923 } 924 } else { 925 // make a copy of the matrix 926 Matrix_Delegate copy = new Matrix_Delegate(mValues); 927 928 // remove the translation 929 setTranslate(copy.mValues, 0, 0); 930 931 // map the content as points. 932 copy.mapPoints(dst, dstIndex, src, srcIndex, ptCount); 933 } 934 } 935 936 /** 937 * multiply two matrices and store them in a 3rd. 938 * <p/>This in effect does dest = a*b 939 * dest cannot be the same as a or b. 940 */ multiply(float dest[], float[] a, float[] b)941 /*package*/ static void multiply(float dest[], float[] a, float[] b) { 942 // first row 943 dest[0] = b[0] * a[0] + b[1] * a[3] + b[2] * a[6]; 944 dest[1] = b[0] * a[1] + b[1] * a[4] + b[2] * a[7]; 945 dest[2] = b[0] * a[2] + b[1] * a[5] + b[2] * a[8]; 946 947 // 2nd row 948 dest[3] = b[3] * a[0] + b[4] * a[3] + b[5] * a[6]; 949 dest[4] = b[3] * a[1] + b[4] * a[4] + b[5] * a[7]; 950 dest[5] = b[3] * a[2] + b[4] * a[5] + b[5] * a[8]; 951 952 // 3rd row 953 dest[6] = b[6] * a[0] + b[7] * a[3] + b[8] * a[6]; 954 dest[7] = b[6] * a[1] + b[7] * a[4] + b[8] * a[7]; 955 dest[8] = b[6] * a[2] + b[7] * a[5] + b[8] * a[8]; 956 } 957 958 /** 959 * Returns a matrix that represents a given translate 960 * @param dx 961 * @param dy 962 * @return 963 */ getTranslate(float dx, float dy)964 /*package*/ static float[] getTranslate(float dx, float dy) { 965 return setTranslate(new float[9], dx, dy); 966 } 967 setTranslate(float[] dest, float dx, float dy)968 /*package*/ static float[] setTranslate(float[] dest, float dx, float dy) { 969 dest[0] = 1; 970 dest[1] = 0; 971 dest[2] = dx; 972 dest[3] = 0; 973 dest[4] = 1; 974 dest[5] = dy; 975 dest[6] = 0; 976 dest[7] = 0; 977 dest[8] = 1; 978 return dest; 979 } 980 getScale(float sx, float sy)981 /*package*/ static float[] getScale(float sx, float sy) { 982 return new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 }; 983 } 984 985 /** 986 * Returns a matrix that represents the given scale info. 987 * @param sx 988 * @param sy 989 * @param px 990 * @param py 991 */ getScale(float sx, float sy, float px, float py)992 /*package*/ static float[] getScale(float sx, float sy, float px, float py) { 993 float[] tmp = new float[9]; 994 float[] tmp2 = new float[9]; 995 996 // TODO: do it in one pass 997 998 // translate tmp so that the pivot is in 0,0 999 setTranslate(tmp, -px, -py); 1000 1001 // scale into tmp2 1002 multiply(tmp2, tmp, getScale(sx, sy)); 1003 1004 // translate back the pivot back into tmp 1005 multiply(tmp, tmp2, getTranslate(px, py)); 1006 1007 return tmp; 1008 } 1009 1010 getRotate(float degrees)1011 /*package*/ static float[] getRotate(float degrees) { 1012 double rad = Math.toRadians(degrees); 1013 float sin = (float)Math.sin(rad); 1014 float cos = (float)Math.cos(rad); 1015 1016 return getRotate(sin, cos); 1017 } 1018 getRotate(float sin, float cos)1019 /*package*/ static float[] getRotate(float sin, float cos) { 1020 return setRotate(new float[9], sin, cos); 1021 } 1022 setRotate(float[] dest, float degrees)1023 /*package*/ static float[] setRotate(float[] dest, float degrees) { 1024 double rad = Math.toRadians(degrees); 1025 float sin = (float)Math.sin(rad); 1026 float cos = (float)Math.cos(rad); 1027 1028 return setRotate(dest, sin, cos); 1029 } 1030 setRotate(float[] dest, float sin, float cos)1031 /*package*/ static float[] setRotate(float[] dest, float sin, float cos) { 1032 dest[0] = cos; 1033 dest[1] = -sin; 1034 dest[2] = 0; 1035 dest[3] = sin; 1036 dest[4] = cos; 1037 dest[5] = 0; 1038 dest[6] = 0; 1039 dest[7] = 0; 1040 dest[8] = 1; 1041 return dest; 1042 } 1043 getRotate(float degrees, float px, float py)1044 /*package*/ static float[] getRotate(float degrees, float px, float py) { 1045 float[] tmp = new float[9]; 1046 float[] tmp2 = new float[9]; 1047 1048 // TODO: do it in one pass 1049 1050 // translate so that the pivot is in 0,0 1051 setTranslate(tmp, -px, -py); 1052 1053 // rotate into tmp2 1054 double rad = Math.toRadians(degrees); 1055 float cos = (float)Math.cos(rad); 1056 float sin = (float)Math.sin(rad); 1057 multiply(tmp2, tmp, getRotate(sin, cos)); 1058 1059 // translate back the pivot back into tmp 1060 multiply(tmp, tmp2, getTranslate(px, py)); 1061 1062 return tmp; 1063 } 1064 getSkew(float kx, float ky)1065 /*package*/ static float[] getSkew(float kx, float ky) { 1066 return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }; 1067 } 1068 getSkew(float kx, float ky, float px, float py)1069 /*package*/ static float[] getSkew(float kx, float ky, float px, float py) { 1070 float[] tmp = new float[9]; 1071 float[] tmp2 = new float[9]; 1072 1073 // TODO: do it in one pass 1074 1075 // translate so that the pivot is in 0,0 1076 setTranslate(tmp, -px, -py); 1077 1078 // skew into tmp2 1079 multiply(tmp2, tmp, new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }); 1080 // translate back the pivot back into tmp 1081 multiply(tmp, tmp2, getTranslate(px, py)); 1082 1083 return tmp; 1084 } 1085 } 1086