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