Home | History | Annotate | Download | only in docs
      1 #Topic Matrix
      2 #Alias Matrices ##
      3 #Alias Matrix_Reference ##
      4 
      5 #Class SkMatrix
      6 
      7 #Code
      8 #Populate
      9 ##
     10 
     11 Matrix holds a 3 by 3 matrix for transforming coordinates. This allows mapping
     12 Points and Vectors with translation, scaling, skewing, rotation, and
     13 perspective.
     14 
     15 Matrix elements are in row major order. Matrix does not have a constructor,
     16 so it must be explicitly initialized. setIdentity initializes Matrix
     17 so it has no effect. setTranslate, setScale, setSkew, setRotate, set9 and setAll
     18 initializes all Matrix elements with the corresponding mapping.
     19 
     20 Matrix includes a hidden variable that classifies the type of matrix to
     21 improve performance. Matrix is not thread safe unless getType is called first.
     22 
     23 # ------------------------------------------------------------------------------
     24 
     25 #Method static SkMatrix MakeScale(SkScalar sx, SkScalar sy)
     26 #In Constructors
     27 #Line # constructs from scale on x-axis and y-axis ##
     28 #Populate
     29 
     30 #Example
     31 #Image 4
     32 canvas->concat(SkMatrix::MakeScale(4, 3));
     33 canvas->drawBitmap(source, 0, 0);
     34 ##
     35 
     36 #SeeAlso setScale postScale preScale
     37 
     38 ##
     39 
     40 # ------------------------------------------------------------------------------
     41 
     42 #Method static SkMatrix MakeScale(SkScalar scale)
     43 #Populate
     44 
     45 #Example
     46 #Image 4
     47 canvas->concat(SkMatrix::MakeScale(4));
     48 canvas->drawBitmap(source, 0, 0);
     49 ##
     50 
     51 #SeeAlso setScale postScale preScale
     52 
     53 ##
     54 
     55 # ------------------------------------------------------------------------------
     56 
     57 #Method static SkMatrix MakeTrans(SkScalar dx, SkScalar dy)
     58 #In Constructors
     59 #Line # constructs from translate on x-axis and y-axis ##
     60 #Populate
     61 
     62 #Example
     63 #Image 4
     64 SkMatrix matrix = SkMatrix::MakeTrans(64, 48);
     65 for (int i = 0; i < 4; ++i) {
     66     canvas->drawBitmap(source, 0, 0);
     67     canvas->concat(matrix);
     68 }
     69 ##
     70 
     71 #SeeAlso setTranslate postTranslate preTranslate
     72 
     73 ##
     74 
     75 # ------------------------------------------------------------------------------
     76 
     77 #Method static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX,  SkScalar transX,
     78                                                       SkScalar skewY,  SkScalar scaleY, SkScalar transY,
     79                                                       SkScalar pers0, SkScalar pers1, SkScalar pers2)
     80 #In Constructors
     81 #Line # constructs all nine values ##
     82 #Populate
     83 
     84 #Example
     85     SkPaint p;
     86     SkFont font(nullptr, 64);
     87     for (SkScalar sx : { -1, 1 } ) {
     88         for (SkScalar sy : { -1, 1 } ) {
     89             SkAutoCanvasRestore autoRestore(canvas, true);
     90             SkMatrix m = SkMatrix::MakeAll(sx, 1, 128,    0, sy, 128,   0, 0, 1);
     91             canvas->concat(m);
     92             canvas->drawString("K", 0, 0, font, p);
     93         }
     94     }
     95 ##
     96 
     97 #SeeAlso setAll set9 postConcat preConcat
     98 
     99 ##
    100 
    101 
    102 # ------------------------------------------------------------------------------
    103 
    104 #Enum TypeMask
    105 #Line # bit field for Matrix complexity ##
    106 #Code
    107 #Populate
    108 ##
    109 
    110 Enumeration of bit fields for mask returned by getType.
    111 Used to identify the complexity of Matrix, to optimize performance.
    112 
    113 #Const kIdentity_Mask 0
    114 #Line # identity Matrix; all bits clear ##
    115 all bits clear if Matrix is identity
    116 ##
    117 #Const kTranslate_Mask 1
    118 #Line # translation Matrix ##
    119 set if Matrix has translation
    120 ##
    121 #Const kScale_Mask 2
    122 #Line # scale Matrix ##
    123 set if Matrix scales x-axis or y-axis
    124 ##
    125 #Const kAffine_Mask 4
    126 #Line # skew or rotate Matrix ##
    127 set if Matrix skews or rotates
    128 ##
    129 #Const kPerspective_Mask 8
    130 #Line # perspective Matrix ##
    131 set if Matrix has perspective
    132 ##
    133 
    134 #Example
    135     auto debugster = [](const char* prefix, const SkMatrix& matrix) -> void {
    136         SkString typeMask;
    137         typeMask += SkMatrix::kIdentity_Mask == matrix.getType() ? "kIdentity_Mask " : "";
    138         typeMask += SkMatrix::kTranslate_Mask & matrix.getType() ? "kTranslate_Mask " : "";
    139         typeMask += SkMatrix::kScale_Mask & matrix.getType() ? "kScale_Mask " : "";
    140         typeMask += SkMatrix::kAffine_Mask & matrix.getType() ? "kAffine_Mask " : "";
    141         typeMask += SkMatrix::kPerspective_Mask & matrix.getType() ? "kPerspective_Mask" : "";
    142         SkDebugf("after %s: %s\n", prefix, typeMask.c_str());
    143     };
    144 SkMatrix matrix;
    145 matrix.reset();
    146 debugster("reset", matrix);
    147 matrix.postTranslate(1, 0);
    148 debugster("postTranslate", matrix);
    149 matrix.postScale(2, 1);
    150 debugster("postScale", matrix);
    151 matrix.postRotate(45);
    152 debugster("postScale", matrix);
    153 SkPoint polys[][4] = {{{0, 0}, {0, 1}, {1, 1}, {1, 0}}, {{0, 0}, {0, 1}, {2, 1}, {1, 0}}};
    154 matrix.setPolyToPoly(polys[0], polys[1], 4);
    155 debugster("setPolyToPoly", matrix);
    156 #StdOut
    157 after reset: kIdentity_Mask
    158 after postTranslate: kTranslate_Mask
    159 after postScale: kTranslate_Mask kScale_Mask
    160 after postScale: kTranslate_Mask kScale_Mask kAffine_Mask
    161 after setPolyToPoly: kTranslate_Mask kScale_Mask kAffine_Mask kPerspective_Mask
    162 ##
    163 ##
    164 
    165 #SeeAlso getType
    166 
    167 ##
    168 
    169 # ------------------------------------------------------------------------------
    170 #Subtopic Property
    171 #Line # values and attributes ##
    172 ##
    173 
    174 #Method TypeMask getType() const
    175 #In Property
    176 #Line # returns transform complexity ##
    177 #Populate
    178 
    179 #Example
    180 SkMatrix matrix;
    181 matrix.setAll(1, 0, 0,   0, 1, 0,    0, 0, 1);
    182 SkDebugf("identity flags hex: %0x decimal: %d\n", matrix.getType(), matrix.getType());
    183 matrix.setAll(1, 0, 0,   0, 1, 0,    0, 0, .5f);
    184 SkDebugf("set all  flags hex: %0x decimal: %d\n", matrix.getType(), matrix.getType());
    185 #StdOut
    186 identity flags hex: 0 decimal: 0
    187 set all  flags hex: f decimal: 15
    188 ##
    189 ##
    190 
    191 #SeeAlso TypeMask
    192 
    193 ##
    194 
    195 # ------------------------------------------------------------------------------
    196 
    197 #Method bool isIdentity() const
    198 #In Property
    199 #Line # returns if matrix equals the identity Matrix  ##
    200 #Populate
    201 
    202 #Example
    203 SkMatrix matrix;
    204 matrix.setAll(1, 0, 0,   0, 1, 0,    0, 0, 1);
    205 SkDebugf("is identity: %s\n", matrix.isIdentity() ? "true" : "false");
    206 matrix.setAll(1, 0, 0,   0, 1, 0,    0, 0, 2);
    207 SkDebugf("is identity: %s\n", matrix.isIdentity() ? "true" : "false");
    208 #StdOut
    209 is identity: true
    210 is identity: false
    211 ##
    212 ##
    213 
    214 #SeeAlso reset() setIdentity getType
    215 
    216 ##
    217 
    218 # ------------------------------------------------------------------------------
    219 
    220 #Method bool isScaleTranslate() const
    221 #In Property
    222 #Line # returns if transform is limited to scale and translate ##
    223 #Populate
    224 
    225 #Example
    226 SkMatrix matrix;
    227 for (SkScalar scaleX : { 1, 2 } ) {
    228     for (SkScalar translateX : { 0, 20 } ) {
    229         matrix.setAll(scaleX, 0, translateX,   0, 1, 0,    0, 0, 1);
    230         SkDebugf("is scale-translate: %s\n", matrix.isScaleTranslate() ? "true" : "false");
    231     }
    232 }
    233 #StdOut
    234 is scale-translate: true
    235 is scale-translate: true
    236 is scale-translate: true
    237 is scale-translate: true
    238 ##
    239 ##
    240 
    241 #SeeAlso setScale isTranslate setTranslate getType
    242 
    243 ##
    244 
    245 # ------------------------------------------------------------------------------
    246 
    247 #Method bool isTranslate() const
    248 #In Property
    249 #Line # returns if transform is limited to translate ##
    250 #Populate
    251 
    252 #Example
    253 SkMatrix matrix;
    254 for (SkScalar scaleX : { 1, 2 } ) {
    255     for (SkScalar translateX : { 0, 20 } ) {
    256         matrix.setAll(scaleX, 0, translateX,   0, 1, 0,    0, 0, 1);
    257         SkDebugf("is translate: %s\n", matrix.isTranslate() ? "true" : "false");
    258     }
    259 }
    260 #StdOut
    261 is translate: true
    262 is translate: true
    263 is translate: false
    264 is translate: false
    265 ##
    266 ##
    267 
    268 #SeeAlso setTranslate getType
    269 
    270 ##
    271 
    272 # ------------------------------------------------------------------------------
    273 
    274 #Method bool rectStaysRect() const
    275 #In Property
    276 #Line # returns if mapped Rect can be represented by another Rect ##
    277 #Populate
    278 
    279 #Example
    280 SkMatrix matrix;
    281 for (SkScalar angle: { 0, 90, 180, 270 } ) {
    282     matrix.setRotate(angle);
    283     SkDebugf("rectStaysRect: %s\n", matrix.rectStaysRect() ? "true" : "false");
    284 }
    285 #StdOut
    286 rectStaysRect: true
    287 rectStaysRect: true
    288 rectStaysRect: true
    289 rectStaysRect: true
    290 ##
    291 ##
    292 
    293 #SeeAlso preservesAxisAlignment preservesRightAngles
    294 
    295 ##
    296 
    297 # ------------------------------------------------------------------------------
    298 
    299 #Method bool preservesAxisAlignment() const
    300 #In Property
    301 #Line # returns if mapping restricts to 90 degree multiples and mirroring ##
    302 #Populate
    303 
    304 #Example
    305 SkMatrix matrix;
    306 for (SkScalar angle: { 0, 90, 180, 270 } ) {
    307     matrix.setRotate(angle);
    308     SkDebugf("preservesAxisAlignment: %s\n", matrix.preservesAxisAlignment() ? "true" : "false");
    309 }
    310 #StdOut
    311 preservesAxisAlignment: true
    312 preservesAxisAlignment: true
    313 preservesAxisAlignment: true
    314 preservesAxisAlignment: true
    315 ##
    316 ##
    317 
    318 #SeeAlso rectStaysRect preservesRightAngles
    319 
    320 ##
    321 
    322 # ------------------------------------------------------------------------------
    323 
    324 #Method bool hasPerspective() const
    325 #In Property
    326 #Line # returns if transform includes perspective ##
    327 #Populate
    328 
    329 #Example
    330 #Image 4
    331 SkMatrix matrix;
    332 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
    333 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
    334 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
    335 canvas->concat(matrix);
    336 SkString string;
    337 string.printf("hasPerspective %s", matrix.hasPerspective() ? "true" : "false");
    338 canvas->drawBitmap(source, 0, 0);
    339 SkPaint paint;
    340 SkFont font(nullptr, 48);
    341 canvas->drawString(string, 0, source.bounds().height() + 48, font, paint);
    342 ##
    343 
    344 #SeeAlso setAll set9 MakeAll
    345 
    346 ##
    347 
    348 # ------------------------------------------------------------------------------
    349 
    350 #Method bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const
    351 #In Property
    352 #Line # returns if transform is limited to square scale and rotation ##
    353 #Populate
    354 
    355 #Example
    356 #Description
    357 String is drawn four times through but only two are visible. Drawing the pair
    358 with isSimilarity false reveals the pair not visible through the matrix.
    359 ##
    360     SkPaint p;
    361     p.setAntiAlias(true);
    362     SkMatrix m;
    363     int below = 175;
    364     for (SkScalar sx : { -1, 1 } ) {
    365         for (SkScalar sy : { -1, 1 } ) {
    366             m.setAll(sx, 1, 128,    1, sy, 32,   0, 0, 1);
    367             bool isSimilarity = m.isSimilarity();
    368             SkString str;
    369             str.printf("sx: %g sy: %g sim: %s", sx, sy, isSimilarity ? "true" : "false");
    370             {
    371                 SkAutoCanvasRestore autoRestore(canvas, true);
    372                 canvas->concat(m);
    373                 canvas->drawString(str, 0, 0, p);
    374             }
    375             if (!isSimilarity) {
    376                 canvas->drawString(str, 40, below, p);
    377                 below += 20;
    378             }
    379         }
    380     }
    381 ##
    382 
    383 #SeeAlso isScaleTranslate preservesRightAngles rectStaysRect isFixedStepInX
    384 
    385 ##
    386 
    387 # ------------------------------------------------------------------------------
    388 
    389 #Method bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const
    390 #In Property
    391 #Line # returns if mapped 90 angle remains 90 degrees ##
    392 #Populate
    393 
    394 #Example
    395 #Height 128
    396 #Description
    397 Equal scale is both similar and preserves right angles.
    398 Unequal scale is not similar but preserves right angles.
    399 Skews are not similar and do not preserve right angles.
    400 ##
    401 SkPaint p;
    402 p.setAntiAlias(true);
    403 SkMatrix m;
    404 int pos = 0;
    405 for (SkScalar sx : { 1, 2 } ) {
    406     for (SkScalar kx : { 0, 1 } ) {
    407         m.setAll(sx, kx, 16,    0, 1, 32,   0, 0, 1);
    408         bool isSimilarity = m.isSimilarity();
    409         bool preservesRightAngles = m.preservesRightAngles();
    410         SkString str;
    411         str.printf("sx: %g kx: %g %s %s", sx, kx, isSimilarity ? "sim" : "",
    412                     preservesRightAngles ? "right" : "");
    413         SkAutoCanvasRestore autoRestore(canvas, true);
    414         canvas->concat(m);
    415         canvas->drawString(str, 0, pos, p);
    416         pos += 20;
    417     }
    418 }
    419 ##
    420 
    421 #SeeAlso isScaleTranslate isSimilarity rectStaysRect isFixedStepInX
    422 
    423 ##
    424 
    425 # ------------------------------------------------------------------------------
    426 
    427 #Subtopic MemberIndex
    428 #In Constant
    429 #Line # member indices ##
    430 #Filter kM
    431 #Code
    432 #Populate
    433 ##
    434 
    435 Matrix organizes its values in row order. These members correspond to
    436 each value in Matrix.
    437 
    438 #Const kMScaleX 0
    439 #Line # horizontal scale factor ##
    440 ##
    441 #Const kMSkewX 1
    442 #Line # horizontal skew factor ##
    443 ##
    444 #Const kMTransX 2
    445 #Line # horizontal translation ##
    446 ##
    447 #Const kMSkewY 3
    448 #Line # vertical skew factor ##
    449 ##
    450 #Const kMScaleY 4
    451 #Line # vertical scale factor ##
    452 ##
    453 #Const kMTransY 5
    454 #Line # vertical translation ##
    455 ##
    456 #Const kMPersp0 6
    457 #Line # input x perspective factor ##
    458 ##
    459 #Const kMPersp1 7
    460 #Line # input y perspective factor ##
    461 ##
    462 #Const kMPersp2 8
    463 #Line # perspective bias ##
    464 ##
    465 
    466 #Example
    467 SkPaint black;
    468 SkFont font(nullptr, 48);
    469 SkPaint gray = black;
    470 gray.setColor(0xFF9f9f9f);
    471 SkScalar offset[] = { 1.5f, 1.5f, 20,   1.5f, 1.5f, 20,   .03f, .01f, 2 };
    472 for (int i : { SkMatrix::kMScaleX, SkMatrix::kMSkewX,  SkMatrix::kMTransX,
    473                SkMatrix::kMSkewY,  SkMatrix::kMScaleY, SkMatrix::kMTransY,
    474                SkMatrix::kMPersp0, SkMatrix::kMPersp1, SkMatrix::kMPersp2 } ) {
    475     SkMatrix m;
    476     m.setIdentity();
    477     m.set(i, offset[i]);
    478     SkAutoCanvasRestore autoRestore(canvas, true);
    479     canvas->translate(22 + (i % 3) * 88, 44 + (i / 3) * 88);
    480     canvas->drawString("&", 0, 0, font, gray);
    481     canvas->concat(m);
    482     canvas->drawString("&", 0, 0, font, black);
    483 }
    484 ##
    485 
    486 #SeeAlso get() set()
    487 
    488 ##
    489 
    490 # ------------------------------------------------------------------------------
    491 
    492 #Subtopic AffineIndex
    493 #In Constant
    494 #Line # affine member indices ##
    495 #Filter KA
    496 
    497 #Code
    498 #Populate
    499 ##
    500 
    501 Affine arrays are in column major order to match the matrix used by
    502 PDF and XPS.
    503 
    504 #Const kAScaleX 0
    505 #Line # horizontal scale factor ##
    506 ##
    507 #Const kASkewY 1
    508 #Line # vertical skew factor ##
    509 ##
    510 #Const kASkewX 2
    511 #Line # horizontal skew factor ##
    512 ##
    513 #Const kAScaleY 3
    514 #Line # vertical scale factor ##
    515 ##
    516 #Const kATransX 4
    517 #Line # horizontal translation ##
    518 ##
    519 #Const kATransY 5
    520 #Line # vertical translation ##
    521 ##
    522 
    523 #NoExample
    524 ##
    525 
    526 #SeeAlso SetAffineIdentity asAffine setAffine
    527 
    528 ##
    529 
    530 # ------------------------------------------------------------------------------
    531 
    532 #Method SkScalar operator[](int index) const
    533 
    534 #Line # returns Matrix value ##
    535 #Populate
    536 
    537 #Example
    538 SkMatrix matrix;
    539 matrix.setScale(42, 24);
    540 SkDebugf("matrix[SkMatrix::kMScaleX] %c= 42\n", matrix[SkMatrix::kMScaleX] == 42 ? '=' : '!');
    541 SkDebugf("matrix[SkMatrix::kMScaleY] %c= 24\n", matrix[SkMatrix::kMScaleY] == 24 ? '=' : '!');
    542 #StdOut
    543 matrix[SkMatrix::kMScaleX] == 42
    544 matrix[SkMatrix::kMScaleY] == 24
    545 ##
    546 ##
    547 
    548 #SeeAlso get set
    549 
    550 ##
    551 
    552 # ------------------------------------------------------------------------------
    553 
    554 #Method SkScalar get(int index) const
    555 #In Property
    556 #Line # returns one of nine Matrix values ##
    557 #Populate
    558 
    559 #Example
    560 SkMatrix matrix;
    561 matrix.setSkew(42, 24);
    562 SkDebugf("matrix.get(SkMatrix::kMSkewX) %c= 42\n",
    563          matrix.get(SkMatrix::kMSkewX) == 42 ? '=' : '!');
    564 SkDebugf("matrix.get(SkMatrix::kMSkewY) %c= 24\n",
    565          matrix.get(SkMatrix::kMSkewY) == 24 ? '=' : '!');
    566 #StdOut
    567 matrix.get(SkMatrix::kMSkewX) == 42
    568 matrix.get(SkMatrix::kMSkewY) == 24
    569 ##
    570 ##
    571 
    572 #SeeAlso operator[](int index) set
    573 
    574 ##
    575 
    576 # ------------------------------------------------------------------------------
    577 
    578 #Method SkScalar getScaleX() const
    579 #In Property
    580 #Line # returns horizontal scale factor ##
    581 #Populate
    582 
    583 #Example
    584 SkMatrix matrix;
    585 matrix.setScale(42, 24);
    586 SkDebugf("matrix.getScaleX() %c= 42\n", matrix.getScaleX() == 42 ? '=' : '!');
    587 #StdOut
    588 matrix.getScaleX() == 42
    589 ##
    590 ##
    591 
    592 #SeeAlso get getScaleY setScaleX setScale
    593 
    594 ##
    595 
    596 # ------------------------------------------------------------------------------
    597 
    598 #Method SkScalar getScaleY() const
    599 #In Property
    600 #Line # returns vertical scale factor ##
    601 #Populate
    602 
    603 #Example
    604 SkMatrix matrix;
    605 matrix.setScale(42, 24);
    606 SkDebugf("matrix.getScaleY() %c= 24\n", matrix.getScaleY() == 24 ? '=' : '!');
    607 #StdOut
    608 matrix.getScaleY() == 24
    609 ##
    610 ##
    611 
    612 #SeeAlso get getScaleX setScaleY setScale
    613 
    614 ##
    615 
    616 # ------------------------------------------------------------------------------
    617 
    618 #Method SkScalar getSkewY() const
    619 #In Property
    620 #Line # returns vertical skew factor ##
    621 #Populate
    622 
    623 #Example
    624 SkMatrix matrix;
    625 matrix.setSkew(42, 24);
    626 SkDebugf("matrix.getSkewY() %c= 24\n", matrix.getSkewY() == 24 ? '=' : '!');
    627 #StdOut
    628 matrix.getSkewY() == 24
    629 ##
    630 ##
    631 
    632 #SeeAlso get getSkewX setSkewY setSkew
    633 
    634 ##
    635 
    636 # ------------------------------------------------------------------------------
    637 
    638 #Method SkScalar getSkewX() const
    639 #In Property
    640 #Line # returns horizontal skew factor ##
    641 #Populate
    642 
    643 #Example
    644 SkMatrix matrix;
    645 matrix.setSkew(42, 24);
    646 SkDebugf("matrix.getSkewX() %c= 42\n", matrix.getSkewX() == 42 ? '=' : '!');
    647 #StdOut
    648 matrix.getSkewX() == 42
    649 ##
    650 ##
    651 
    652 #SeeAlso get getSkewY setSkewX setSkew
    653 
    654 ##
    655 
    656 # ------------------------------------------------------------------------------
    657 
    658 #Method SkScalar getTranslateX() const
    659 #In Property
    660 #Line # returns horizontal translation ##
    661 #Populate
    662 
    663 #Example
    664 SkMatrix matrix;
    665 matrix.setTranslate(42, 24);
    666 SkDebugf("matrix.getTranslateX() %c= 42\n", matrix.getTranslateX() == 42 ? '=' : '!');
    667 #StdOut
    668 matrix.getTranslateX() == 42
    669 ##
    670 ##
    671 
    672 #SeeAlso get getTranslateY setTranslateX setTranslate
    673 
    674 ##
    675 
    676 # ------------------------------------------------------------------------------
    677 
    678 #Method SkScalar getTranslateY() const
    679 #In Property
    680 #Line # returns vertical translation ##
    681 #Populate
    682 
    683 #Example
    684 SkMatrix matrix;
    685 matrix.setTranslate(42, 24);
    686 SkDebugf("matrix.getTranslateY() %c= 24\n", matrix.getTranslateY() == 24 ? '=' : '!');
    687 #StdOut
    688 matrix.getTranslateY() == 24
    689 ##
    690 ##
    691 
    692 #SeeAlso get getTranslateX setTranslateY setTranslate
    693 
    694 ##
    695 
    696 # ------------------------------------------------------------------------------
    697 
    698 #Method SkScalar getPerspX() const
    699 #In Property
    700 #Line # returns input x perspective factor ##
    701 #Populate
    702 
    703 #Example
    704     SkMatrix m;
    705     m.setIdentity();
    706     m.set(SkMatrix::kMPersp0, -0.004f);
    707     SkAutoCanvasRestore autoRestore(canvas, true);
    708     canvas->translate(22, 144);
    709     SkPaint black;
    710     SkFont font(nullptr, 24);
    711     SkPaint gray = black;
    712     gray.setColor(0xFF9f9f9f);
    713     SkString string;
    714     string.appendScalar(m.getPerspX());
    715     canvas->drawString(string, 0, -72, font, gray);
    716     canvas->concat(m);
    717     canvas->drawString(string, 0, 0, font, black);
    718 ##
    719 
    720 #SeeAlso kMPersp0 getPerspY
    721 
    722 ##
    723 
    724 # ------------------------------------------------------------------------------
    725 
    726 #Method SkScalar getPerspY() const
    727 #In Property
    728 #Line # returns input y perspective factor ##
    729 #Populate
    730 
    731 #Example
    732     SkMatrix m;
    733     m.setIdentity();
    734     m.set(SkMatrix::kMPersp1, -0.004f);
    735     SkAutoCanvasRestore autoRestore(canvas, true);
    736     canvas->translate(22, 144);
    737     SkPaint black;
    738     SkFont font(nullptr, 24);
    739     SkPaint gray;
    740     gray.setColor(0xFF9f9f9f);
    741     SkString string;
    742     string.appendScalar(m.getPerspY());
    743     canvas->drawString(string, 0, -72, font, gray);
    744     canvas->concat(m);
    745     canvas->drawString(string, 0, 0, font, black);
    746 ##
    747 
    748 #SeeAlso kMPersp1 getPerspX
    749 
    750 ##
    751 
    752 # ------------------------------------------------------------------------------
    753 
    754 #Method SkScalar& operator[](int index)
    755 
    756 #Line # returns writable reference to Matrix value ##
    757 #Populate
    758 
    759 #Example
    760 SkMatrix matrix;
    761 matrix.setIdentity();
    762 SkDebugf("with identity matrix: x = %g\n", matrix.mapXY(24, 42).fX);
    763 SkScalar& skewRef = matrix[SkMatrix::kMSkewX];
    764 skewRef = 0;
    765 SkDebugf("after skew x mod:     x = %g\n", matrix.mapXY(24, 42).fX);
    766 skewRef = 1;
    767 SkDebugf("after 2nd skew x mod: x = %g\n", matrix.mapXY(24, 42).fX);
    768 matrix.dirtyMatrixTypeCache();
    769 SkDebugf("after dirty cache:    x = %g\n", matrix.mapXY(24, 42).fX);
    770 #StdOut
    771 with identity matrix: x = 24
    772 after skew x mod:     x = 24
    773 after 2nd skew x mod: x = 24
    774 after dirty cache:    x = 66
    775 ##
    776 ##
    777 
    778 #SeeAlso get dirtyMatrixTypeCache set
    779 
    780 ##
    781 
    782 # ------------------------------------------------------------------------------
    783 #Subtopic Set
    784 #Line # sets one or more matrix values ##
    785 ##
    786 
    787 #Method void set(int index, SkScalar value)
    788 #In Set
    789 #Line # sets one value ##
    790 #Populate
    791 
    792 #Example
    793 SkMatrix matrix;
    794 matrix.setIdentity();
    795 SkDebugf("with identity matrix: x = %g\n", matrix.mapXY(24, 42).fX);
    796 matrix.set(SkMatrix::kMSkewX, 0);
    797 SkDebugf("after skew x mod:     x = %g\n", matrix.mapXY(24, 42).fX);
    798 matrix.set(SkMatrix::kMSkewX, 1);
    799 SkDebugf("after 2nd skew x mod: x = %g\n", matrix.mapXY(24, 42).fX);
    800 #StdOut
    801 with identity matrix: x = 24
    802 after skew x mod:     x = 24
    803 after 2nd skew x mod: x = 66
    804 ##
    805 ##
    806 
    807 #SeeAlso operator[] get
    808 
    809 #Method ##
    810 
    811 # ------------------------------------------------------------------------------
    812 
    813 #Method void setScaleX(SkScalar v)
    814 #In Set
    815 #Line # sets horizontal scale factor ##
    816 #Populate
    817 
    818 #Example
    819 #Height 64
    820 SkPaint paint;
    821 SkFont font(nullptr, 24);
    822 canvas->drawString("normal", 12, 24, font, paint);
    823 SkMatrix matrix;
    824 matrix.setIdentity();
    825 matrix.setScaleX(3);
    826 canvas->concat(matrix);
    827 canvas->drawString("x scale", 0, 48, font, paint);
    828 ##
    829 
    830 #SeeAlso set setScale setScaleY
    831 
    832 #Method ##
    833 
    834 # ------------------------------------------------------------------------------
    835 
    836 #Method void setScaleY(SkScalar v)
    837 #In Set
    838 #Line # sets vertical scale factor ##
    839 #Populate
    840 
    841 #Example
    842 #Height 192
    843 SkPaint paint;
    844 SkFont font(nullptr, 24);
    845 canvas->drawString("normal", 12, 24, font, paint);
    846 SkMatrix matrix;
    847 matrix.setIdentity();
    848 matrix.setScaleY(3);
    849 canvas->concat(matrix);
    850 canvas->drawString("y scale", 12, 48, font, paint);
    851 ##
    852 
    853 #SeeAlso set setScale setScaleX
    854 
    855 #Method ##
    856 
    857 # ------------------------------------------------------------------------------
    858 
    859 #Method void setSkewY(SkScalar v)
    860 #In Set
    861 #Line # sets vertical skew factor ##
    862 #Populate
    863 
    864 #Example
    865 #Height 96
    866 SkPaint paint;
    867 SkFont font(nullptr, 24);
    868 canvas->drawString("normal", 12, 24, font, paint);
    869 SkMatrix matrix;
    870 matrix.setIdentity();
    871 matrix.setSkewY(.3f);
    872 canvas->concat(matrix);
    873 canvas->drawString("y skew", 12, 48, font, paint);
    874 ##
    875 
    876 #SeeAlso set setSkew setSkewX
    877 
    878 #Method ##
    879 
    880 # ------------------------------------------------------------------------------
    881 
    882 #Method void setSkewX(SkScalar v)
    883 #In Set
    884 #Line # sets horizontal skew factor ##
    885 #Populate
    886 
    887 #Example
    888 #Height 64
    889 SkPaint paint;
    890 SkFont font(nullptr, 24);
    891 canvas->drawString("normal", 12, 24, font, paint);
    892 SkMatrix matrix;
    893 matrix.setIdentity();
    894 matrix.setSkewX(-.7f);
    895 canvas->concat(matrix);
    896 canvas->drawString("x skew", 36, 48, font, paint);
    897 ##
    898 
    899 #SeeAlso set setSkew setSkewX
    900 
    901 #Method ##
    902 
    903 # ------------------------------------------------------------------------------
    904 
    905 #Method void setTranslateX(SkScalar v)
    906 #In Set
    907 #Line # sets horizontal translation ##
    908 #Populate
    909 
    910 #Example
    911 #Height 48
    912 SkPaint paint;
    913 SkFont font(nullptr, 24);
    914 canvas->drawString("normal", 8, 24, font, paint);
    915 SkMatrix matrix;
    916 matrix.setIdentity();
    917 matrix.setTranslateX(96);
    918 canvas->concat(matrix);
    919 canvas->drawString("x translate", 8, 24, font, paint);
    920 ##
    921 
    922 #SeeAlso set setTranslate setTranslateY
    923 
    924 #Method ##
    925 
    926 # ------------------------------------------------------------------------------
    927 
    928 #Method void setTranslateY(SkScalar v)
    929 #In Set
    930 #Line # sets vertical translation ##
    931 #Populate
    932 
    933 #Example
    934 #Height 64
    935 SkPaint paint;
    936 SkFont font(nullptr, 24);
    937 canvas->drawString("normal", 8, 24, font, paint);
    938 SkMatrix matrix;
    939 matrix.setIdentity();
    940 matrix.setTranslateY(24);
    941 canvas->concat(matrix);
    942 canvas->drawString("y translate", 8, 24, font, paint);
    943 ##
    944 
    945 #SeeAlso set setTranslate setTranslateX
    946 
    947 #Method ##
    948 
    949 # ------------------------------------------------------------------------------
    950 
    951 #Method void setPerspX(SkScalar v)
    952 #In Set
    953 #Line # sets input x perspective factor ##
    954 #Populate
    955 
    956 #Example
    957 #Image 4
    958 for (SkScalar perspX : { -.003f, 0.f, .003f, .012f } ) {
    959     SkMatrix matrix;
    960     matrix.setIdentity();
    961     matrix.setPerspX(perspX);
    962     canvas->save();
    963     canvas->concat(matrix);
    964     canvas->drawBitmap(source, 0, 0);
    965     canvas->restore();
    966     canvas->translate(64, 64);
    967 }
    968 ##
    969 
    970 #SeeAlso getPerspX set setAll set9 MakeAll
    971 
    972 #Method ##
    973 
    974 # ------------------------------------------------------------------------------
    975 
    976 #Method void setPerspY(SkScalar v)
    977 #In Set
    978 #Line # sets input y perspective factor ##
    979 #Populate
    980 
    981 #Example
    982 #Image 4
    983 for (SkScalar perspX : { -.003f, 0.f, .003f, .012f } ) {
    984     SkMatrix matrix;
    985     matrix.setIdentity();
    986     matrix.setPerspY(perspX);
    987     canvas->save();
    988     canvas->concat(matrix);
    989     canvas->drawBitmap(source, 0, 0);
    990     canvas->restore();
    991     canvas->translate(64, 64);
    992 }
    993 ##
    994 
    995 #SeeAlso getPerspY set setAll set9 MakeAll
    996 
    997 #Method ##
    998 
    999 # ------------------------------------------------------------------------------
   1000 
   1001 #Method void setAll(SkScalar scaleX, SkScalar skewX,  SkScalar transX,
   1002                 SkScalar skewY,  SkScalar scaleY, SkScalar transY,
   1003                 SkScalar persp0, SkScalar persp1, SkScalar persp2)
   1004 #In Set
   1005 #Line # sets all values from parameters ##
   1006 #Populate
   1007 
   1008 #Example
   1009 #Height 128
   1010     SkPaint p;
   1011     SkFont font(nullptr, 64);
   1012     SkMatrix m;
   1013     for (SkScalar sx : { -1, 1 } ) {
   1014         for (SkScalar sy : { -1, 1 } ) {
   1015             SkAutoCanvasRestore autoRestore(canvas, true);
   1016             m.setAll(sx, 1, 128,    0, sy, 64,   0, 0, 1);
   1017             canvas->concat(m);
   1018             canvas->drawString("K", 0, 0, font, p);
   1019         }
   1020     }
   1021 ##
   1022 
   1023 #SeeAlso set9 MakeAll
   1024 
   1025 #Method ##
   1026 
   1027 # ------------------------------------------------------------------------------
   1028 
   1029 #Method void get9(SkScalar buffer[9]) const
   1030 #In Property
   1031 #Line # returns all nine Matrix values ##
   1032 #Populate
   1033 
   1034 #Example
   1035 SkMatrix matrix = SkMatrix::MakeRectToRect({0, 0, 1, 1}, {3, 4, 7, 9},
   1036                                            SkMatrix::kFill_ScaleToFit);
   1037 SkScalar b[9];
   1038 matrix.get9(b);
   1039 SkDebugf("{%g, %g, %g},\n{%g, %g, %g},\n{%g, %g, %g}\n", b[0], b[1], b[2],
   1040          b[3], b[4], b[5], b[6], b[7], b[8]);
   1041 #StdOut
   1042 {4, 0, 3},
   1043 {0, 5, 4},
   1044 {0, 0, 1}
   1045 ##
   1046 ##
   1047 
   1048 #SeeAlso set9
   1049 
   1050 #Method ##
   1051 
   1052 # ------------------------------------------------------------------------------
   1053 
   1054 #Method void set9(const SkScalar buffer[9])
   1055 #In Set
   1056 #In Constructors
   1057 #Line # sets all values from Scalar array ##
   1058 #Populate
   1059 
   1060 #Example
   1061 #Image 4
   1062 SkMatrix m;
   1063 SkScalar buffer[9] = {4, 0, 3,    0, 5, 4,     0, 0, 1};
   1064 m.set9(buffer);
   1065 canvas->concat(m);
   1066 canvas->drawBitmap(source, 0, 0);
   1067 ##
   1068 
   1069 #SeeAlso setAll get9 MakeAll
   1070 
   1071 #Method ##
   1072 
   1073 # ------------------------------------------------------------------------------
   1074 
   1075 #Method void reset()
   1076 #In Constructors
   1077 #In Set
   1078 #Line # sets Matrix to identity ##
   1079 #Populate
   1080 
   1081 #Example
   1082 SkMatrix m;
   1083 m.reset();
   1084 SkDebugf("m.isIdentity(): %s\n", m.isIdentity() ? "true" : "false");
   1085 #StdOut
   1086 m.isIdentity(): true
   1087 ##
   1088 ##
   1089 
   1090 #SeeAlso isIdentity setIdentity
   1091 
   1092 #Method ##
   1093 
   1094 # ------------------------------------------------------------------------------
   1095 
   1096 #Method void setIdentity()
   1097 #In Constructors
   1098 #In Set
   1099 #Line # sets Matrix to identity ##
   1100 #Populate
   1101 
   1102 #Example
   1103 SkMatrix m;
   1104 m.setIdentity();
   1105 SkDebugf("m.isIdentity(): %s\n", m.isIdentity() ? "true" : "false");
   1106 #StdOut
   1107 m.isIdentity(): true
   1108 ##
   1109 ##
   1110 
   1111 #SeeAlso isIdentity reset
   1112 
   1113 #Method ##
   1114 
   1115 # ------------------------------------------------------------------------------
   1116 
   1117 #Method void setTranslate(SkScalar dx, SkScalar dy)
   1118 #In Constructors
   1119 #In Set
   1120 #Line # sets to translate on x-axis and y-axis ##
   1121 #Populate
   1122 
   1123 #Example
   1124 #Height 64
   1125 SkPaint paint;
   1126 SkFont font(nullptr, 24);
   1127 canvas->drawString("normal", 8, 24, font, paint);
   1128 SkMatrix matrix;
   1129 matrix.setTranslate(96, 24);
   1130 canvas->concat(matrix);
   1131 canvas->drawString("translate", 8, 24, font, paint);
   1132 ##
   1133 
   1134 #SeeAlso setTranslateX setTranslateY
   1135 
   1136 #Method ##
   1137 
   1138 # ------------------------------------------------------------------------------
   1139 
   1140 #Method void setTranslate(const SkVector& v)
   1141 #Populate
   1142 
   1143 #Example
   1144 #Height 64
   1145 SkPaint paint;
   1146 SkFont font(nullptr, 24);
   1147 canvas->drawString("normal", 8, 24, font, paint);
   1148 SkMatrix matrix;
   1149 matrix.setTranslate({96, 24});
   1150 canvas->concat(matrix);
   1151 canvas->drawString("translate", 8, 24, font, paint);
   1152 ##
   1153 
   1154 #SeeAlso setTranslateX setTranslateY MakeTrans
   1155 
   1156 #Method ##
   1157 
   1158 # ------------------------------------------------------------------------------
   1159 
   1160 #Method void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
   1161 #In Constructors
   1162 #In Set
   1163 #Line # sets to scale about a point ##
   1164 #Populate
   1165 
   1166 #Example
   1167 #Height 128
   1168     SkPaint p;
   1169     SkFont font(nullptr, 64);
   1170     SkMatrix m;
   1171     for (SkScalar sx : { -1, 1 } ) {
   1172         for (SkScalar sy : { -1, 1 } ) {
   1173             SkAutoCanvasRestore autoRestore(canvas, true);
   1174             m.setScale(sx, sy, 128, 64);
   1175             canvas->concat(m);
   1176             canvas->drawString("%", 128, 64, font, p);
   1177         }
   1178     }
   1179 ##
   1180 
   1181 #SeeAlso setScaleX setScaleY MakeScale preScale postScale
   1182 
   1183 #Method ##
   1184 
   1185 # ------------------------------------------------------------------------------
   1186 
   1187 #Method void setScale(SkScalar sx, SkScalar sy)
   1188 #Populate
   1189 
   1190 #Example
   1191 #Height 128
   1192     SkPaint p;
   1193     SkFont font(nullptr, 64);
   1194     SkMatrix m;
   1195     for (SkScalar sx : { -1, 1 } ) {
   1196         for (SkScalar sy : { -1, 1 } ) {
   1197             SkAutoCanvasRestore autoRestore(canvas, true);
   1198             m.setScale(sx, sy);
   1199             m.postTranslate(128, 64);
   1200             canvas->concat(m);
   1201             canvas->drawString("@", 0, 0, font, p);
   1202         }
   1203     }
   1204 ##
   1205 
   1206 #SeeAlso setScaleX setScaleY MakeScale preScale postScale
   1207 
   1208 #Method ##
   1209 
   1210 # ------------------------------------------------------------------------------
   1211 
   1212 #Method void setRotate(SkScalar degrees, SkScalar px, SkScalar py)
   1213 #In Constructors
   1214 #In Set
   1215 #Line # sets to rotate about a point ##
   1216 #Populate
   1217 
   1218 #Example
   1219 #Height 128
   1220     SkPaint paint;
   1221     paint.setColor(SK_ColorGRAY);
   1222     paint.setAntiAlias(true);
   1223     SkRect rect = {20, 20, 100, 100};
   1224     canvas->drawRect(rect, paint);
   1225     paint.setColor(SK_ColorRED);
   1226     SkMatrix matrix;
   1227     matrix.setRotate(25, rect.centerX(), rect.centerY());
   1228     canvas->concat(matrix);
   1229     canvas->drawRect(rect, paint);
   1230 ##
   1231 
   1232 #SeeAlso setSinCos preRotate postRotate
   1233 
   1234 #Method ##
   1235 
   1236 # ------------------------------------------------------------------------------
   1237 
   1238 #Method void setRotate(SkScalar degrees)
   1239 #Populate
   1240 
   1241 #Example
   1242 #Height 128
   1243     SkPaint paint;
   1244     paint.setColor(SK_ColorGRAY);
   1245     paint.setAntiAlias(true);
   1246     SkRect rect = {20, 20, 100, 100};
   1247     canvas->drawRect(rect, paint);
   1248     paint.setColor(SK_ColorRED);
   1249     SkMatrix matrix;
   1250     matrix.setRotate(25);
   1251     canvas->translate(rect.centerX(), rect.centerY());
   1252     canvas->concat(matrix);
   1253     canvas->translate(-rect.centerX(), -rect.centerY());
   1254     canvas->drawRect(rect, paint);
   1255 ##
   1256 
   1257 #SeeAlso setSinCos preRotate postRotate
   1258 
   1259 #Method ##
   1260 
   1261 # ------------------------------------------------------------------------------
   1262 
   1263 #Method void setSinCos(SkScalar sinValue, SkScalar cosValue,
   1264                    SkScalar px, SkScalar py)
   1265 #In Constructors
   1266 #In Set
   1267 #Line # sets to rotate and scale about a point ##
   1268 #Populate
   1269 
   1270 #Example
   1271 #Height 128
   1272     SkPaint paint;
   1273     paint.setColor(SK_ColorGRAY);
   1274     paint.setAntiAlias(true);
   1275     SkRect rect = {20, 20, 100, 100};
   1276     canvas->drawRect(rect, paint);
   1277     paint.setColor(SK_ColorRED);
   1278     SkMatrix matrix;
   1279     matrix.setSinCos(.25f, .85f, rect.centerX(), rect.centerY());
   1280     canvas->concat(matrix);
   1281     canvas->drawRect(rect, paint);
   1282 ##
   1283 
   1284 #SeeAlso setRotate setScale setRSXform
   1285 
   1286 #Method ##
   1287 
   1288 # ------------------------------------------------------------------------------
   1289 
   1290 #Method void setSinCos(SkScalar sinValue, SkScalar cosValue)
   1291 #Populate
   1292 
   1293 #Example
   1294 #Description
   1295 Canvas needs offset after applying Matrix to pivot about Rect center.
   1296 ##
   1297 #Height 128
   1298     SkPaint paint;
   1299     paint.setColor(SK_ColorGRAY);
   1300     paint.setAntiAlias(true);
   1301     SkRect rect = {20, 20, 100, 100};
   1302     canvas->drawRect(rect, paint);
   1303     paint.setColor(SK_ColorRED);
   1304     SkMatrix matrix;
   1305     matrix.setSinCos(.25f, .85f);
   1306     matrix.postTranslate(rect.centerX(), rect.centerY());
   1307     canvas->concat(matrix);
   1308     canvas->translate(-rect.centerX(), -rect.centerY());
   1309     canvas->drawRect(rect, paint);
   1310 ##
   1311 
   1312 #SeeAlso setRotate setScale setRSXform
   1313 
   1314 #Method ##
   1315 
   1316 # ------------------------------------------------------------------------------
   1317 
   1318 #Method SkMatrix& setRSXform(const SkRSXform& rsxForm)
   1319 #In Constructors
   1320 #In Set
   1321 #Line # sets to rotate, scale, and translate ##
   1322 #Populate
   1323 
   1324 #Example
   1325 #Description
   1326 Canvas needs offset after applying Matrix to pivot about Rect center.
   1327 ##
   1328 #Height 128
   1329     SkPaint paint;
   1330     paint.setColor(SK_ColorGRAY);
   1331     paint.setAntiAlias(true);
   1332     SkRect rect = {20, 20, 100, 100};
   1333     canvas->drawRect(rect, paint);
   1334     paint.setColor(SK_ColorRED);
   1335     SkMatrix matrix;
   1336     matrix.setRSXform(SkRSXform::Make(.85f, .25f, rect.centerX(), rect.centerY()));
   1337     canvas->concat(matrix);
   1338     canvas->translate(-rect.centerX(), -rect.centerY());
   1339     canvas->drawRect(rect, paint);
   1340 ##
   1341 
   1342 #SeeAlso setSinCos setScale setTranslate
   1343 
   1344 #Method ##
   1345 
   1346 # ------------------------------------------------------------------------------
   1347 
   1348 #Method void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py)
   1349 #In Constructors
   1350 #In Set
   1351 #Line # sets to skew about a point ##
   1352 #Populate
   1353 
   1354 #Example
   1355     SkPaint p;
   1356     SkFont font(nullptr, 48);
   1357     SkMatrix m;
   1358     for (SkScalar sx : { -1, 0, 1 } ) {
   1359         for (SkScalar sy : { -1, 0, 1 } ) {
   1360             SkAutoCanvasRestore autoRestore(canvas, true);
   1361             m.setSkew(sx, sy, 96 + 64 * sx, 128 + 48 * sy);
   1362             canvas->concat(m);
   1363             canvas->drawString("K", 96 + 64 * sx, 128 + 48 * sy, font, p);
   1364         }
   1365     }
   1366 ##
   1367 
   1368 #SeeAlso setSkewX setSkewY preSkew postSkew
   1369 
   1370 #Method ##
   1371 
   1372 # ------------------------------------------------------------------------------
   1373 
   1374 #Method void setSkew(SkScalar kx, SkScalar ky)
   1375 #Populate
   1376 
   1377 #Example
   1378     SkPaint p;
   1379     SkFont font(nullptr, 48);
   1380     SkMatrix m;
   1381     for (SkScalar sx : { -1, 0, 1 } ) {
   1382         for (SkScalar sy : { -1, 0, 1 } ) {
   1383             SkAutoCanvasRestore autoRestore(canvas, true);
   1384             m.setSkew(sx, sy);
   1385             m.postTranslate(96 + 64 * sx, 128 + 48 * sy);
   1386             canvas->concat(m);
   1387             canvas->drawString("K", 0, 0, font, p);
   1388         }
   1389     }
   1390 ##
   1391 
   1392 #SeeAlso setSkewX setSkewY preSkew postSkew
   1393 
   1394 #Method ##
   1395 
   1396 # ------------------------------------------------------------------------------
   1397 
   1398 #Method void setConcat(const SkMatrix& a, const SkMatrix& b)
   1399 #In Constructors
   1400 #In Set
   1401 #Line # sets to Matrix parameter multiplied by Matrix parameter ##
   1402 #Populate
   1403 
   1404 #Example
   1405 #Image 3
   1406 #Description
   1407 setPolyToPoly creates perspective matrices, one the inverse of the other.
   1408 Multiplying the matrix by its inverse turns into an identity matrix.
   1409 ##
   1410 SkMatrix matrix, matrix2;
   1411 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1412 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1413 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1414 matrix2.setPolyToPoly(perspect, bitmapBounds, 4);
   1415 matrix.setConcat(matrix, matrix2);
   1416 canvas->concat(matrix);
   1417 canvas->drawBitmap(source, 0, 0);
   1418 ##
   1419 
   1420 #SeeAlso Concat preConcat postConcat SkCanvas::concat
   1421 
   1422 #Method ##
   1423 
   1424 # ------------------------------------------------------------------------------
   1425 
   1426 #Method void preTranslate(SkScalar dx, SkScalar dy)
   1427 #In Set
   1428 #In Operators
   1429 #Line # pre-multiplies Matrix by translation ##
   1430 #Populate
   1431 
   1432 #Example
   1433 #Height 160
   1434     SkPaint paint;
   1435     paint.setAntiAlias(true);
   1436     SkRect rect = {20, 20, 100, 100};
   1437     for (int i = 0; i < 2; ++i ) {
   1438         SkMatrix matrix;
   1439         i == 0 ? matrix.reset(): matrix.setRotate(25, rect.centerX(), 320);
   1440         {
   1441             SkAutoCanvasRestore acr(canvas, true);
   1442             canvas->concat(matrix);
   1443             paint.setColor(SK_ColorGRAY);
   1444             canvas->drawRect(rect, paint);
   1445         }
   1446         paint.setColor(SK_ColorRED);
   1447         for (int j = 0; j < 2; ++j ) {
   1448             SkAutoCanvasRestore acr(canvas, true);
   1449             matrix.preTranslate(40, 40);
   1450             canvas->concat(matrix);
   1451             canvas->drawCircle(0, 0, 3, paint);
   1452         }
   1453     }
   1454 ##
   1455 
   1456 #SeeAlso postTranslate setTranslate MakeTrans
   1457 
   1458 #Method ##
   1459 
   1460 # ------------------------------------------------------------------------------
   1461 
   1462 #Method void preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
   1463 #In Set
   1464 #In Operators
   1465 #Line # pre-multiplies Matrix by scale ##
   1466 #Populate
   1467 
   1468 #Example
   1469 #Image 3
   1470 SkMatrix matrix;
   1471 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1472 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1473 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1474 matrix.preScale(.75f, 1.5f, source.width() / 2, source.height() / 2);
   1475 canvas->concat(matrix);
   1476 canvas->drawBitmap(source, 0, 0);
   1477 ##
   1478 
   1479 #SeeAlso postScale setScale MakeScale
   1480 
   1481 #Method ##
   1482 
   1483 # ------------------------------------------------------------------------------
   1484 
   1485 #Method void preScale(SkScalar sx, SkScalar sy)
   1486 #In Set
   1487 #In Operators
   1488 #Populate
   1489 
   1490 #Example
   1491 #Image 3
   1492 SkMatrix matrix;
   1493 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1494 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1495 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1496 matrix.preScale(.75f, 1.5f);
   1497 canvas->concat(matrix);
   1498 canvas->drawBitmap(source, 0, 0);
   1499 ##
   1500 
   1501 #SeeAlso postScale setScale MakeScale
   1502 
   1503 #Method ##
   1504 
   1505 # ------------------------------------------------------------------------------
   1506 
   1507 #Method void preRotate(SkScalar degrees, SkScalar px, SkScalar py)
   1508 #In Set
   1509 #In Operators
   1510 #Line # pre-multiplies Matrix by rotation ##
   1511 #Populate
   1512 
   1513 #Example
   1514 #Image 3
   1515 SkMatrix matrix;
   1516 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1517 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1518 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1519 matrix.preRotate(45, source.width() / 2, source.height() / 2);
   1520 canvas->concat(matrix);
   1521 canvas->drawBitmap(source, 0, 0);
   1522 ##
   1523 
   1524 #SeeAlso postRotate setRotate
   1525 
   1526 #Method ##
   1527 
   1528 # ------------------------------------------------------------------------------
   1529 
   1530 #Method void preRotate(SkScalar degrees)
   1531 #Populate
   1532 
   1533 #Example
   1534 #Image 3
   1535 SkMatrix matrix;
   1536 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1537 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1538 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1539 matrix.preRotate(45);
   1540 canvas->concat(matrix);
   1541 canvas->drawBitmap(source, 0, 0);
   1542 ##
   1543 
   1544 #SeeAlso postRotate setRotate
   1545 
   1546 #Method ##
   1547 
   1548 # ------------------------------------------------------------------------------
   1549 
   1550 #Method void preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py)
   1551 #In Set
   1552 #In Operators
   1553 #Line # pre-multiplies Matrix by skew ##
   1554 #Populate
   1555 
   1556 #Example
   1557 #Image 3
   1558 SkMatrix matrix;
   1559 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1560 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1561 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1562 matrix.preSkew(.5f, 0, source.width() / 2, source.height() / 2);
   1563 canvas->concat(matrix);
   1564 canvas->drawBitmap(source, 0, 0);
   1565 ##
   1566 
   1567 #SeeAlso postSkew setSkew
   1568 
   1569 #Method ##
   1570 
   1571 # ------------------------------------------------------------------------------
   1572 
   1573 #Method void preSkew(SkScalar kx, SkScalar ky)
   1574 #Populate
   1575 
   1576 #Example
   1577 #Image 3
   1578 SkMatrix matrix;
   1579 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1580 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1581 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1582 matrix.preSkew(.5f, 0);
   1583 canvas->concat(matrix);
   1584 canvas->drawBitmap(source, 0, 0);
   1585 ##
   1586 
   1587 #SeeAlso postSkew setSkew
   1588 
   1589 #Method ##
   1590 
   1591 # ------------------------------------------------------------------------------
   1592 
   1593 #Method void preConcat(const SkMatrix& other)
   1594 #In Set
   1595 #In Operators
   1596 #Line # pre-multiplies Matrix by Matrix parameter ##
   1597 #Populate
   1598 
   1599 #Example
   1600 #Image 3
   1601 #Description
   1602 setPolyToPoly creates perspective matrices, one the inverse of the other.
   1603 Multiplying the matrix by its inverse turns into an identity matrix.
   1604 ##
   1605 SkMatrix matrix, matrix2;
   1606 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1607 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1608 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1609 matrix2.setPolyToPoly(perspect, bitmapBounds, 4);
   1610 matrix.preConcat(matrix2);
   1611 canvas->concat(matrix);
   1612 canvas->drawBitmap(source, 0, 0);
   1613 ##
   1614 
   1615 #SeeAlso postConcat setConcat Concat
   1616 
   1617 #Method ##
   1618 
   1619 # ------------------------------------------------------------------------------
   1620 
   1621 #Method void postTranslate(SkScalar dx, SkScalar dy)
   1622 #In Set
   1623 #In Operators
   1624 #Line # post-multiplies Matrix by translation ##
   1625 #Populate
   1626 
   1627 #Example
   1628 #Height 160
   1629 #Description
   1630 Compare with preTranslate example.
   1631 ##
   1632     SkPaint paint;
   1633     paint.setAntiAlias(true);
   1634     SkRect rect = {20, 20, 100, 100};
   1635     for (int i = 0; i < 2; ++i ) {
   1636         SkMatrix matrix;
   1637         i == 0 ? matrix.reset(): matrix.setRotate(25, rect.centerX(), 320);
   1638         {
   1639             SkAutoCanvasRestore acr(canvas, true);
   1640             canvas->concat(matrix);
   1641             paint.setColor(SK_ColorGRAY);
   1642             canvas->drawRect(rect, paint);
   1643         }
   1644         paint.setColor(SK_ColorRED);
   1645         for (int j = 0; j < 2; ++j ) {
   1646             SkAutoCanvasRestore acr(canvas, true);
   1647             matrix.postTranslate(40, 40);
   1648             canvas->concat(matrix);
   1649             canvas->drawCircle(0, 0, 3, paint);
   1650         }
   1651     }
   1652 ##
   1653 
   1654 #SeeAlso preTranslate setTranslate MakeTrans
   1655 
   1656 #Method ##
   1657 
   1658 # ------------------------------------------------------------------------------
   1659 
   1660 #Method void postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
   1661 #In Set
   1662 #In Operators
   1663 #Line # post-multiplies Matrix by scale ##
   1664 #Populate
   1665 
   1666 #Example
   1667 #Image 3
   1668 SkMatrix matrix;
   1669 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1670 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1671 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1672 matrix.postScale(.75f, 1.5f, source.width() / 2, source.height() / 2);
   1673 canvas->concat(matrix);
   1674 canvas->drawBitmap(source, 0, 0);
   1675 ##
   1676 
   1677 #SeeAlso preScale setScale MakeScale
   1678 
   1679 ##
   1680 
   1681 # ------------------------------------------------------------------------------
   1682 
   1683 #Method void postScale(SkScalar sx, SkScalar sy)
   1684 #Populate
   1685 
   1686 #Example
   1687 #Image 3
   1688 SkMatrix matrix;
   1689 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1690 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1691 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1692 matrix.postScale(.75f, 1.5f);
   1693 canvas->concat(matrix);
   1694 canvas->drawBitmap(source, 0, 0);
   1695 ##
   1696 
   1697 #SeeAlso preScale setScale MakeScale
   1698 
   1699 ##
   1700 
   1701 # ------------------------------------------------------------------------------
   1702 
   1703 #Method bool postIDiv(int divx, int divy)
   1704 #In Set
   1705 #In Operators
   1706 #Line # post-multiplies Matrix by inverse scale ##
   1707 Sets Matrix to Matrix constructed from scaling by (1/divx, 1/divy),
   1708 multiplied by Matrix.
   1709 
   1710 Returns false if either divx or divy is zero.
   1711 
   1712 Given:
   1713 
   1714 #Code
   1715 #Literal
   1716          | J K L |                   | sx  0  0 |
   1717 Matrix = | M N O |,  I(divx, divy) = |  0 sy  0 |
   1718          | P Q R |                   |  0  0  1 |
   1719 ##
   1720 
   1721 where
   1722 
   1723 #Code
   1724 #Literal
   1725 sx = 1 / divx
   1726 sy = 1 / divy
   1727 ##
   1728 
   1729 sets Matrix to:
   1730 
   1731 #Code
   1732 #Literal
   1733                          | sx  0  0 | | J K L |   | sx*J sx*K sx*L |
   1734 I(divx, divy) * Matrix = |  0 sy  0 | | M N O | = | sy*M sy*N sy*O |
   1735                          |  0  0  1 | | P Q R |   |    P    Q    R |
   1736 ##
   1737 
   1738 #Param divx  integer divisor for inverse scale on x-axis ##
   1739 #Param divy  integer divisor for inverse scale on y-axis ##
   1740 
   1741 #Return  true on successful scale ##
   1742 
   1743 #Example
   1744 #Image 3
   1745 SkMatrix matrix;
   1746 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1747 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1748 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1749 matrix.postIDiv(1, 2);
   1750 canvas->concat(matrix);
   1751 canvas->drawBitmap(source, 0, 0);
   1752 ##
   1753 
   1754 #SeeAlso postScale MakeScale
   1755 
   1756 ##
   1757 
   1758 # ------------------------------------------------------------------------------
   1759 
   1760 #Method void postRotate(SkScalar degrees, SkScalar px, SkScalar py)
   1761 #In Set
   1762 #In Operators
   1763 #Line # post-multiplies Matrix by rotation ##
   1764 #Populate
   1765 
   1766 #Example
   1767 #Image 3
   1768 SkMatrix matrix;
   1769 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1770 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1771 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1772 matrix.postRotate(45, source.width() / 2, source.height() / 2);
   1773 canvas->concat(matrix);
   1774 canvas->drawBitmap(source, 0, 0);
   1775 ##
   1776 
   1777 #SeeAlso preRotate setRotate
   1778 
   1779 ##
   1780 
   1781 # ------------------------------------------------------------------------------
   1782 
   1783 #Method void postRotate(SkScalar degrees)
   1784 #Populate
   1785 
   1786 #Example
   1787 #Image 3
   1788 SkMatrix matrix;
   1789 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1790 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1791 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1792 matrix.postRotate(45);
   1793 canvas->concat(matrix);
   1794 canvas->drawBitmap(source, 0, 0);
   1795 ##
   1796 
   1797 #SeeAlso preRotate setRotate
   1798 
   1799 ##
   1800 
   1801 # ------------------------------------------------------------------------------
   1802 
   1803 #Method void postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py)
   1804 #In Set
   1805 #In Operators
   1806 #Line # post-multiplies Matrix by skew ##
   1807 #Populate
   1808 
   1809 #Example
   1810 #Image 3
   1811 SkMatrix matrix;
   1812 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1813 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1814 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1815 matrix.postSkew(.5f, 0, source.width() / 2, source.height() / 2);
   1816 canvas->concat(matrix);
   1817 canvas->drawBitmap(source, 0, 0);
   1818 ##
   1819 
   1820 #SeeAlso preSkew setSkew
   1821 
   1822 ##
   1823 
   1824 # ------------------------------------------------------------------------------
   1825 
   1826 #Method void postSkew(SkScalar kx, SkScalar ky)
   1827 #Populate
   1828 
   1829 #Example
   1830 #Image 3
   1831 SkMatrix matrix;
   1832 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1833 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1834 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1835 matrix.postSkew(.5f, 0);
   1836 canvas->concat(matrix);
   1837 canvas->drawBitmap(source, 0, 0);
   1838 ##
   1839 
   1840 #SeeAlso preSkew setSkew
   1841 
   1842 ##
   1843 
   1844 # ------------------------------------------------------------------------------
   1845 
   1846 #Method void postConcat(const SkMatrix& other)
   1847 #In Set
   1848 #In Operators
   1849 #Line # post-multiplies Matrix by Matrix parameter ##
   1850 #Populate
   1851 
   1852 #Example
   1853 #Image 3
   1854 #Height 64
   1855 SkMatrix matrix;
   1856 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   1857 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   1858 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   1859 matrix.postConcat(matrix);
   1860 canvas->concat(matrix);
   1861 canvas->drawBitmap(source, 0, 0);
   1862 ##
   1863 
   1864 #SeeAlso preConcat setConcat Concat
   1865 
   1866 ##
   1867 
   1868 # ------------------------------------------------------------------------------
   1869 
   1870 #Enum ScaleToFit
   1871 #Line # options to map Rects ##
   1872 #Code
   1873     enum ScaleToFit {
   1874         kFill_ScaleToFit,
   1875         kStart_ScaleToFit,
   1876         kCenter_ScaleToFit,
   1877         kEnd_ScaleToFit,
   1878     };
   1879 ##
   1880 
   1881 ScaleToFit describes how Matrix is constructed to map one Rect to another.
   1882 ScaleToFit may allow Matrix to have unequal horizontal and vertical scaling,
   1883 or may restrict Matrix to square scaling. If restricted, ScaleToFit specifies
   1884 how Matrix maps to the side or center of the destination Rect.
   1885 
   1886 #Const kFill_ScaleToFit 0
   1887 #Line # scales about x-axis and y-axis to fill destination Rect ##
   1888     Computes Matrix that scales about x-axis and y-axis independently, so that
   1889     source Rect is mapped to completely fill destination Rect. The aspect ratio
   1890     of source Rect may change.
   1891 ##
   1892 #Const kStart_ScaleToFit 1
   1893 #Line # scales and aligns to left and top ##
   1894     Computes Matrix that maintains source Rect aspect ratio, mapping source Rect
   1895     width or height to destination Rect. Aligns mapping to left and top edges
   1896     of destination Rect.
   1897 ##
   1898 #Const kCenter_ScaleToFit 2
   1899 #Line # scales and aligns to center ##
   1900     Computes Matrix that maintains source Rect aspect ratio, mapping source Rect
   1901     width or height to destination Rect. Aligns mapping to center of destination
   1902     Rect.
   1903 ##
   1904 #Const kEnd_ScaleToFit 3
   1905 #Line # scales and aligns to right and bottom ##
   1906     Computes Matrix that maintains source Rect aspect ratio, mapping source Rect
   1907     width or height to destination Rect. Aligns mapping to right and bottom
   1908     edges of destination Rect.
   1909 ##
   1910 
   1911 #Example
   1912    const char* labels[] = { "Fill", "Start", "Center", "End" };
   1913    SkRect rects[] = {{5, 5, 59, 59}, {5, 74, 59, 108}, {10, 123, 44, 172}, {10, 187, 54, 231}};
   1914    SkRect bounds;
   1915    source.getBounds(&bounds);
   1916    SkPaint paint;
   1917    paint.setAntiAlias(true);
   1918    for (auto fit : { SkMatrix::kFill_ScaleToFit, SkMatrix::kStart_ScaleToFit,
   1919                      SkMatrix::kCenter_ScaleToFit, SkMatrix::kEnd_ScaleToFit } ) {
   1920        for (auto rect : rects ) {
   1921            canvas->drawRect(rect, paint);
   1922            SkMatrix matrix;
   1923            if (!matrix.setRectToRect(bounds, rect, fit)) {
   1924                continue;
   1925            }
   1926            SkAutoCanvasRestore acr(canvas, true);
   1927            canvas->concat(matrix);
   1928            canvas->drawBitmap(source, 0, 0);
   1929        }
   1930        canvas->drawString(labels[fit], 10, 255, paint);
   1931        canvas->translate(64, 0);
   1932    }
   1933 ##
   1934 
   1935 #SeeAlso setRectToRect MakeRectToRect setPolyToPoly
   1936 
   1937 ##
   1938 
   1939 # ------------------------------------------------------------------------------
   1940 
   1941 #Method bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf)
   1942 #In Set
   1943 #Line # sets to map one Rect to another ##
   1944 #Populate
   1945 
   1946 #Example
   1947     const SkRect srcs[] = { {0, 0, 0, 0}, {1, 2, 3, 4} };
   1948     const SkRect dsts[] = { {0, 0, 0, 0}, {5, 6, 8, 9} };
   1949     for (auto src : srcs) {
   1950         for (auto dst : dsts) {
   1951              SkMatrix matrix;
   1952              matrix.setAll(-1, -1, -1, -1, -1, -1, -1, -1, -1);
   1953              bool success = matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
   1954              SkDebugf("src: %g, %g, %g, %g  dst: %g, %g, %g, %g  success: %s\n",
   1955                       src.fLeft, src.fTop, src.fRight, src.fBottom,
   1956                       dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, success ? "true" : "false");
   1957              matrix.dump();
   1958         }
   1959     }
   1960 #StdOut
   1961 src: 0, 0, 0, 0  dst: 0, 0, 0, 0  success: false
   1962 [  1.0000   0.0000   0.0000][  0.0000   1.0000   0.0000][  0.0000   0.0000   1.0000]
   1963 src: 0, 0, 0, 0  dst: 5, 6, 8, 9  success: false
   1964 [  1.0000   0.0000   0.0000][  0.0000   1.0000   0.0000][  0.0000   0.0000   1.0000]
   1965 src: 1, 2, 3, 4  dst: 0, 0, 0, 0  success: true
   1966 [  0.0000   0.0000   0.0000][  0.0000   0.0000   0.0000][  0.0000   0.0000   1.0000]
   1967 src: 1, 2, 3, 4  dst: 5, 6, 8, 9  success: true
   1968 [  1.5000   0.0000   3.5000][  0.0000   1.5000   3.0000][  0.0000   0.0000   1.0000]
   1969 ##
   1970 ##
   1971 
   1972 #SeeAlso MakeRectToRect ScaleToFit setPolyToPoly SkRect::isEmpty
   1973 
   1974 ##
   1975 
   1976 # ------------------------------------------------------------------------------
   1977 
   1978 #Method static SkMatrix MakeRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf)
   1979 #In Constructors
   1980 #Line # constructs from source Rect to destination Rect ##
   1981 #Populate
   1982 
   1983 #Example
   1984     const SkRect srcs[] = { {0, 0, 0, 0}, {1, 2, 3, 4} };
   1985     const SkRect dsts[] = { {0, 0, 0, 0}, {5, 6, 8, 9} };
   1986     for (auto src : srcs) {
   1987         for (auto dst : dsts) {
   1988              SkMatrix matrix = SkMatrix::MakeRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
   1989              SkDebugf("src: %g, %g, %g, %g  dst: %g, %g, %g, %g\n",
   1990                       src.fLeft, src.fTop, src.fRight, src.fBottom,
   1991                       dst.fLeft, dst.fTop, dst.fRight, dst.fBottom);
   1992              matrix.dump();
   1993         }
   1994     }
   1995 #StdOut
   1996 src: 0, 0, 0, 0  dst: 0, 0, 0, 0
   1997 [  1.0000   0.0000   0.0000][  0.0000   1.0000   0.0000][  0.0000   0.0000   1.0000]
   1998 src: 0, 0, 0, 0  dst: 5, 6, 8, 9
   1999 [  1.0000   0.0000   0.0000][  0.0000   1.0000   0.0000][  0.0000   0.0000   1.0000]
   2000 src: 1, 2, 3, 4  dst: 0, 0, 0, 0
   2001 [  0.0000   0.0000   0.0000][  0.0000   0.0000   0.0000][  0.0000   0.0000   1.0000]
   2002 src: 1, 2, 3, 4  dst: 5, 6, 8, 9
   2003 [  1.5000   0.0000   3.5000][  0.0000   1.5000   3.0000][  0.0000   0.0000   1.0000]
   2004 ##
   2005 ##
   2006 
   2007 #SeeAlso setRectToRect ScaleToFit setPolyToPoly SkRect::isEmpty
   2008 
   2009 ##
   2010 
   2011 # ------------------------------------------------------------------------------
   2012 
   2013 #Method bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count)
   2014 #In Set
   2015 #Line # sets to map one to four points to an equal array of points ##
   2016 #Populate
   2017 
   2018 #Example
   2019     const SkPoint src[] = { { 0, 0}, {30,   0}, {30, -30}, { 0, -30} };
   2020     const SkPoint dst[] = { {50, 0}, {80, -10}, {90, -30}, {60, -40} };
   2021     SkPaint blackPaint;
   2022     blackPaint.setAntiAlias(true);
   2023     SkFont font(nullptr, 42);
   2024     SkPaint redPaint = blackPaint;
   2025     redPaint.setColor(SK_ColorRED);
   2026     for (int count : { 1, 2, 3, 4 } ) {
   2027         canvas->translate(35, 55);
   2028         for (int index = 0; index < count; ++index) {
   2029             canvas->drawCircle(src[index], 3, blackPaint);
   2030             canvas->drawCircle(dst[index], 3, blackPaint);
   2031             if (index > 0) {
   2032                 canvas->drawLine(src[index], src[index - 1], font, blackPaint);
   2033                 canvas->drawLine(dst[index], dst[index - 1], font, blackPaint);
   2034             }
   2035         }
   2036         SkMatrix matrix;
   2037         matrix.setPolyToPoly(src, dst, count);
   2038         canvas->drawString("A", src[0].fX, src[0].fY, font, redPaint);
   2039         SkAutoCanvasRestore acr(canvas, true);
   2040         canvas->concat(matrix);
   2041         canvas->drawString("A", src[0].fX, src[0].fY, font, redPaint);
   2042     }
   2043 ##
   2044 
   2045 #SeeAlso setRectToRect MakeRectToRect
   2046 
   2047 ##
   2048 
   2049 # ------------------------------------------------------------------------------
   2050 
   2051 #Method bool invert(SkMatrix* inverse) const
   2052 #In Operators
   2053 #Line # returns inverse, if possible ##
   2054 #Populate
   2055 
   2056 #Example
   2057 #Height 128
   2058     const SkPoint src[] = { { 10, 120}, {120, 120}, {120, 10}, {  10, 10} };
   2059     const SkPoint dst[] = { {150, 120}, {200, 100}, {240, 30}, { 130, 40} };
   2060     SkPaint paint;
   2061     paint.setAntiAlias(true);
   2062     SkMatrix matrix;
   2063     matrix.setPolyToPoly(src, dst, 4);
   2064     canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, src, paint);
   2065     canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, dst, paint);
   2066     paint.setColor(SK_ColorBLUE);
   2067     paint.setStrokeWidth(3);
   2068     paint.setStrokeCap(SkPaint::kRound_Cap);
   2069     canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, dst, paint);
   2070     if (matrix.invert(&matrix)) {
   2071         canvas->concat(matrix);
   2072         canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, dst, paint);
   2073     }
   2074 ##
   2075 
   2076 #SeeAlso Concat
   2077 
   2078 ##
   2079 
   2080 # ------------------------------------------------------------------------------
   2081 
   2082 #Method static void SetAffineIdentity(SkScalar affine[6])
   2083 #In Constructors
   2084 #Line # sets 3x2 array to identity ##
   2085 #Populate
   2086 
   2087 #Example
   2088     SkScalar affine[6];
   2089     SkMatrix::SetAffineIdentity(affine);
   2090     const char* names[] = { "ScaleX", "SkewY", "SkewX", "ScaleY", "TransX", "TransY" };
   2091     for (int i = 0; i < 6; ++i) {
   2092         SkDebugf("%s: %g ", names[i], affine[i]);
   2093     }
   2094     SkDebugf("\n");
   2095 #StdOut
   2096 ScaleX: 1 SkewY: 0 SkewX: 0 ScaleY: 1 TransX: 0 TransY: 0
   2097 ##
   2098 ##
   2099 
   2100 #SeeAlso setAffine asAffine
   2101 
   2102 ##
   2103 
   2104 # ------------------------------------------------------------------------------
   2105 
   2106 #Method bool asAffine(SkScalar affine[6]) const
   2107 #In Constructors
   2108 #Line # copies to 3x2 array ##
   2109 #Populate
   2110 
   2111 #Example
   2112 SkMatrix matrix;
   2113 matrix.setAll(2, 3, 4, 5, 6, 7, 0, 0, 1);
   2114 SkScalar affine[6];
   2115 if (matrix.asAffine(affine)) {
   2116     const char* names[] = { "ScaleX", "SkewY", "SkewX", "ScaleY", "TransX", "TransY" };
   2117     for (int i = 0; i < 6; ++i) {
   2118         SkDebugf("%s: %g ", names[i], affine[i]);
   2119     }
   2120     SkDebugf("\n");
   2121 }
   2122 #StdOut
   2123 ScaleX: 2 SkewY: 5 SkewX: 3 ScaleY: 6 TransX: 4 TransY: 7
   2124 ##
   2125 ##
   2126 
   2127 #SeeAlso setAffine SetAffineIdentity
   2128 
   2129 ##
   2130 
   2131 # ------------------------------------------------------------------------------
   2132 
   2133 #Method void setAffine(const SkScalar affine[6])
   2134 #In Constructors
   2135 #In Set
   2136 #Line # sets left two columns ##
   2137 #Populate
   2138 
   2139 #Example
   2140 SkMatrix matrix;
   2141 matrix.setAll(2, 3, 4, 5, 6, 7, 0, 0, 1);
   2142 SkScalar affine[6];
   2143 if (matrix.asAffine(affine)) {
   2144     const char* names[] = { "ScaleX", "SkewY", "SkewX", "ScaleY", "TransX", "TransY" };
   2145     for (int i = 0; i < 6; ++i) {
   2146         SkDebugf("%s: %g ", names[i], affine[i]);
   2147     }
   2148     SkDebugf("\n");
   2149     matrix.reset();
   2150     matrix.setAffine(affine);
   2151     matrix.dump();
   2152 }
   2153 #StdOut
   2154 ScaleX: 2 SkewY: 5 SkewX: 3 ScaleY: 6 TransX: 4 TransY: 7
   2155 [  2.0000   3.0000   4.0000][  5.0000   6.0000   7.0000][  0.0000   0.0000   1.0000]
   2156 ##
   2157 ##
   2158 
   2159 #SeeAlso asAffine SetAffineIdentity
   2160 
   2161 ##
   2162 
   2163 # ------------------------------------------------------------------------------
   2164 #Subtopic Transform
   2165 #Line # map points with Matrix ##
   2166 ##
   2167 
   2168 #Method void mapPoints(SkPoint dst[], const SkPoint src[], int count) const
   2169 #In Transform
   2170 #Line # maps Point array ##
   2171 #Populate
   2172 
   2173 #Example
   2174     SkMatrix matrix;
   2175     matrix.reset();
   2176     const int count = 4;
   2177     SkPoint src[count];
   2178     matrix.mapRectToQuad(src, {40, 70, 180, 220} );
   2179     SkPaint paint;
   2180     paint.setARGB(77, 23, 99, 154);
   2181     for (int i = 0; i < 5; ++i) {
   2182         SkPoint dst[count];
   2183         matrix.mapPoints(dst, src, count);
   2184         canvas->drawPoints(SkCanvas::kPolygon_PointMode, count, dst, paint);
   2185         matrix.preRotate(35, 128, 128);
   2186     }
   2187 ##
   2188 
   2189 #SeeAlso mapXY mapHomogeneousPoints mapVectors
   2190 
   2191 ##
   2192 
   2193 # ------------------------------------------------------------------------------
   2194 
   2195 #Method void mapPoints(SkPoint pts[], int count) const
   2196 #Populate
   2197 
   2198 #Example
   2199     SkMatrix matrix;
   2200     matrix.setRotate(35, 128, 128);
   2201     const int count = 4;
   2202     SkPoint pts[count];
   2203     matrix.mapRectToQuad(pts, {40, 70, 180, 220} );
   2204     SkPaint paint;
   2205     paint.setARGB(77, 23, 99, 154);
   2206     for (int i = 0; i < 5; ++i) {
   2207         canvas->drawPoints(SkCanvas::kPolygon_PointMode, count, pts, paint);
   2208         matrix.mapPoints(pts, count);
   2209     }
   2210 ##
   2211 
   2212 #SeeAlso mapXY mapHomogeneousPoints mapVectors
   2213 
   2214 ##
   2215 
   2216 # ------------------------------------------------------------------------------
   2217 
   2218 #Method void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const
   2219 #In Transform
   2220 #Line # maps Point3 array ##
   2221 #Populate
   2222 
   2223 #Example
   2224     SkPoint3 src[] = {{3, 3, 1}, {8, 2, 2}, {5, 0, 4}, {0, 1, 3},
   2225                       {3, 7, 1}, {8, 6, 2}, {5, 4, 4}, {0, 5, 3}};
   2226     int lines[] = { 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 };
   2227     constexpr int count = SK_ARRAY_COUNT(src);
   2228     auto debugster = [=](SkPoint3 src[]) -> void {
   2229     for (size_t i = 0; i < SK_ARRAY_COUNT(lines); i += 2) {
   2230         const SkPoint3& s = src[lines[i]];
   2231         const SkPoint3& e = src[lines[i + 1]];
   2232         SkPaint paint;
   2233         paint.setARGB(77, 23, 99, 154);
   2234         canvas->drawLine(s.fX / s.fZ, s.fY / s.fZ, e.fX / e.fZ, e.fY / e.fZ, paint);
   2235     }
   2236     };
   2237     canvas->save();
   2238     canvas->translate(5, 5);
   2239     canvas->scale(15, 15);
   2240     debugster(src);
   2241     canvas->restore();
   2242     canvas->translate(128, 128);
   2243     SkMatrix matrix;
   2244     matrix.setAll(15, 0, 0, 0, 15, 0, -0.08, 0.04, 1);
   2245     matrix.mapHomogeneousPoints(src, src, count);
   2246     debugster(src);
   2247 ##
   2248 
   2249 #SeeAlso mapPoints mapXY mapVectors
   2250 
   2251 ##
   2252 
   2253 # ------------------------------------------------------------------------------
   2254 
   2255 #Method void mapXY(SkScalar x, SkScalar y, SkPoint* result) const
   2256 #In Transform
   2257 #Line # maps Point ##
   2258 #Populate
   2259 
   2260 #Example
   2261     SkPaint paint;
   2262     paint.setAntiAlias(true);
   2263     SkMatrix matrix;
   2264     matrix.setRotate(60, 128, 128);
   2265     SkPoint lines[] = {{50, 50}, {150, 50}, {150, 150}};
   2266     for (size_t i = 0; i < SK_ARRAY_COUNT(lines); ++i) {
   2267         SkPoint pt;
   2268         matrix.mapXY(lines[i].fX, lines[i].fY, &pt);
   2269         canvas->drawCircle(pt.fX, pt.fY, 3, paint);
   2270     }
   2271     canvas->concat(matrix);
   2272     canvas->drawPoints(SkCanvas::kPolygon_PointMode, SK_ARRAY_COUNT(lines), lines, paint);
   2273 ##
   2274 
   2275 #SeeAlso mapPoints mapVectors
   2276 
   2277 ##
   2278 
   2279 # ------------------------------------------------------------------------------
   2280 
   2281 #Method SkPoint mapXY(SkScalar x, SkScalar y) const
   2282 #Populate
   2283 
   2284 #Example
   2285 #Image 4
   2286 SkMatrix matrix;
   2287 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {30, 206}};
   2288 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   2289 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   2290 SkPaint paint;
   2291 paint.setAntiAlias(true);
   2292 paint.setStrokeWidth(3);
   2293 for (int x : { 0, source.width() } ) {
   2294     for (int y : { 0, source.height() } ) {
   2295         canvas->drawPoint(matrix.mapXY(x, y), paint);
   2296     }
   2297 }
   2298 canvas->concat(matrix);
   2299 canvas->drawBitmap(source, 0, 0);
   2300 ##
   2301 
   2302 #SeeAlso mapPoints mapVectors
   2303 
   2304 ##
   2305 
   2306 # ------------------------------------------------------------------------------
   2307 
   2308 #Method void mapVectors(SkVector dst[], const SkVector src[], int count) const
   2309 #In Transform
   2310 #Line # maps Vector array ##
   2311 #Populate
   2312 
   2313 #Example
   2314     SkPaint paint;
   2315     paint.setAntiAlias(true);
   2316     paint.setStyle(SkPaint::kStroke_Style);
   2317     SkMatrix matrix;
   2318     matrix.reset();
   2319     const SkVector radii[] = {{8, 4}, {9, 1}, {6, 2}, {7, 3}};
   2320     for (int i = 0; i < 4; ++i) {
   2321         SkVector rScaled[4];
   2322         matrix.preScale(1.5f, 2.f);
   2323         matrix.mapVectors(rScaled, radii, SK_ARRAY_COUNT(radii));
   2324         SkRRect rrect;
   2325         rrect.setRectRadii({20, 20, 180, 70}, rScaled);
   2326         canvas->drawRRect(rrect, paint);
   2327         canvas->translate(0, 60);
   2328     }
   2329 ##
   2330 
   2331 #SeeAlso mapVector mapPoints mapXY
   2332 
   2333 ##
   2334 
   2335 # ------------------------------------------------------------------------------
   2336 
   2337 #Method void mapVectors(SkVector vecs[], int count) const
   2338 #Populate
   2339 
   2340 #Example
   2341     SkPaint paint;
   2342     paint.setAntiAlias(true);
   2343     paint.setStyle(SkPaint::kStroke_Style);
   2344     SkMatrix matrix;
   2345     matrix.setScale(2, 3);
   2346     SkVector radii[] = {{7, 7}, {3, 3}, {2, 2}, {4, 0}};
   2347     for (int i = 0; i < 4; ++i) {
   2348         SkRRect rrect;
   2349         rrect.setRectRadii({20, 20, 180, 70}, radii);
   2350         canvas->drawRRect(rrect, paint);
   2351         canvas->translate(0, 60);
   2352         matrix.mapVectors(radii, SK_ARRAY_COUNT(radii));
   2353     }
   2354 ##
   2355 
   2356 #SeeAlso mapVector mapPoints mapXY
   2357 
   2358 ##
   2359 
   2360 # ------------------------------------------------------------------------------
   2361 
   2362 #Method void mapVector(SkScalar dx, SkScalar dy, SkVector* result) const
   2363 #In Transform
   2364 #Line # maps Vector ##
   2365 #Populate
   2366 
   2367 #Example
   2368     SkPaint paint;
   2369     paint.setColor(SK_ColorGREEN);
   2370     SkFont font(nullptr, 48);
   2371     SkMatrix matrix;
   2372     matrix.setRotate(90);
   2373     SkVector offset = { 7, 7 };
   2374     for (int i = 0; i < 4; ++i) {
   2375         paint.setImageFilter(SkDropShadowImageFilter::Make(offset.fX, offset.fY, 3, 3,
   2376               SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode, nullptr));
   2377         matrix.mapVector(offset.fX, offset.fY, &offset);
   2378         canvas->translate(0, 60);
   2379         canvas->drawString("Text", 50, 0, font, paint);
   2380     }
   2381 ##
   2382 
   2383 #SeeAlso mapVectors mapPoints mapXY
   2384 
   2385 ##
   2386 
   2387 # ------------------------------------------------------------------------------
   2388 
   2389 #Method SkVector mapVector(SkScalar dx, SkScalar dy) const
   2390 #Populate
   2391 
   2392 #Example
   2393     SkPaint paint;
   2394     paint.setColor(SK_ColorGREEN);
   2395     SkFont font(nullptr, 48);
   2396     SkMatrix matrix;
   2397     matrix.setRotate(90);
   2398     SkVector offset = { 7, 7 };
   2399     for (int i = 0; i < 4; ++i) {
   2400         paint.setImageFilter(SkDropShadowImageFilter::Make(offset.fX, offset.fY, 3, 3,
   2401               SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode, nullptr));
   2402         offset = matrix.mapVector(offset.fX, offset.fY);
   2403         canvas->translate(0, 60);
   2404         canvas->drawString("Text", 50, 0, font, paint);
   2405     }
   2406 ##
   2407 
   2408 #SeeAlso mapVectors mapPoints mapXY
   2409 
   2410 ##
   2411 
   2412 # ------------------------------------------------------------------------------
   2413 
   2414 #Method bool mapRect(SkRect* dst, const SkRect& src) const
   2415 #In Transform
   2416 #Line # returns bounds of mapped Rect ##
   2417 #Populate
   2418 
   2419 #Example
   2420     SkPaint paint;
   2421     paint.setAntiAlias(true);
   2422     SkMatrix matrix;
   2423     matrix.setRotate(45, 128, 128);
   2424     SkRect rotatedBounds, bounds = {40, 50, 190, 200};
   2425     matrix.mapRect(&rotatedBounds, bounds );
   2426     paint.setColor(SK_ColorGRAY);
   2427     canvas->drawRect(rotatedBounds, paint);
   2428     canvas->concat(matrix);
   2429     paint.setColor(SK_ColorRED);
   2430     canvas->drawRect(bounds, paint);
   2431 ##
   2432 
   2433 #SeeAlso mapPoints rectStaysRect
   2434 
   2435 ##
   2436 
   2437 # ------------------------------------------------------------------------------
   2438 
   2439 #Method bool mapRect(SkRect* rect) const
   2440 #Populate
   2441 
   2442 #Example
   2443     SkPaint paint;
   2444     paint.setAntiAlias(true);
   2445     SkMatrix matrix;
   2446     matrix.setRotate(45, 128, 128);
   2447     SkRect bounds = {40, 50, 190, 200};
   2448     matrix.mapRect(&bounds);
   2449     paint.setColor(SK_ColorGRAY);
   2450     canvas->drawRect(bounds, paint);
   2451     canvas->concat(matrix);
   2452     paint.setColor(SK_ColorRED);
   2453     canvas->drawRect({40, 50, 190, 200}, paint);
   2454 ##
   2455 
   2456 #SeeAlso mapRectScaleTranslate mapPoints rectStaysRect
   2457 
   2458 ##
   2459 
   2460 # ------------------------------------------------------------------------------
   2461 
   2462 #Method SkRect mapRect(const SkRect& src) const
   2463 #Populate
   2464 
   2465 #Example
   2466   SkRect rect{110, 50, 180, 100};
   2467   SkMatrix matrix;
   2468   matrix.setRotate(50, 28, 28);
   2469   SkRect mapped = matrix.mapRect(rect);
   2470   SkPaint paint;
   2471   paint.setAntiAlias(true);
   2472   paint.setStyle(SkPaint::kStroke_Style);
   2473   canvas->drawRect(rect, paint);
   2474   canvas->drawRect(mapped, paint);
   2475   canvas->concat(matrix);
   2476   canvas->drawRect(rect, paint);
   2477 ##
   2478 
   2479 #SeeAlso mapRectToQuad mapRectScaleTranslate
   2480 #Method ##
   2481 
   2482 # ------------------------------------------------------------------------------
   2483 
   2484 #Method void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const
   2485 #In Transform
   2486 #Line # maps Rect to Point array ##
   2487 #Populate
   2488 
   2489 #Example
   2490 #Height 192
   2491     SkPaint paint;
   2492     paint.setAntiAlias(true);
   2493     SkMatrix matrix;
   2494     matrix.setRotate(60, 128, 128);
   2495     SkRect rect = {50, 50, 150, 150};
   2496     SkPoint pts[4];
   2497     matrix.mapRectToQuad(pts, rect);
   2498     for (int i = 0; i < 4; ++i) {
   2499         canvas->drawCircle(pts[i].fX, pts[i].fY, 3, paint);
   2500     }
   2501     canvas->concat(matrix);
   2502     paint.setStyle(SkPaint::kStroke_Style);
   2503     canvas->drawRect(rect, paint);
   2504 ##
   2505 
   2506 #SeeAlso mapRect mapRectScaleTranslate
   2507 
   2508 ##
   2509 
   2510 # ------------------------------------------------------------------------------
   2511 
   2512 #Method void mapRectScaleTranslate(SkRect* dst, const SkRect& src) const
   2513 #In Transform
   2514 #Line # returns bounds of mapped Rect ##
   2515 #Populate
   2516 
   2517 #Example
   2518     SkPaint paint;
   2519     SkMatrix matrix;
   2520     SkRect rect = {100, 50, 150, 180};
   2521     matrix.setScale(2, .5f, rect.centerX(), rect.centerY());
   2522     SkRect rotated;
   2523     matrix.mapRectScaleTranslate(&rotated, rect);
   2524     paint.setStyle(SkPaint::kStroke_Style);
   2525     canvas->drawRect(rect, paint);
   2526     paint.setColor(SK_ColorRED);
   2527     canvas->drawRect(rotated, paint);
   2528 ##
   2529 
   2530 #SeeAlso mapRect mapRectToQuad isScaleTranslate rectStaysRect
   2531 
   2532 ##
   2533 
   2534 # ------------------------------------------------------------------------------
   2535 
   2536 #Method SkScalar mapRadius(SkScalar radius) const
   2537 #In Transform
   2538 #Line # returns mean radius of mapped Circle ##
   2539 #Populate
   2540 
   2541 #Example
   2542 #Description
   2543 The area enclosed by a square with sides equal to mappedRadius is the same as
   2544 the area enclosed by the ellipse major and minor axes.
   2545 ##
   2546   SkPaint paint;
   2547   paint.setAntiAlias(true);
   2548   SkMatrix matrix;
   2549   const SkPoint center = {108, 93};
   2550   matrix.setScale(2, .5f, center.fX, center.fY);
   2551   matrix.postRotate(45, center.fX, center.fY);
   2552   const SkScalar circleRadius = 50;
   2553   SkScalar mappedRadius = matrix.mapRadius(circleRadius);
   2554   SkVector minorAxis, majorAxis;
   2555   matrix.mapVector(0, circleRadius, &minorAxis);
   2556   matrix.mapVector(circleRadius, 0, &majorAxis);
   2557   SkString mappedArea;
   2558   mappedArea.printf("area = %g", mappedRadius * mappedRadius);
   2559   canvas->drawString(mappedArea, 145, 250, paint);
   2560   canvas->drawString("mappedRadius", center.fX + mappedRadius + 3, center.fY, paint);
   2561   paint.setColor(SK_ColorRED);
   2562   SkString axArea;
   2563   axArea.printf("area = %g", majorAxis.length() * minorAxis.length());
   2564   paint.setStyle(SkPaint::kFill_Style);
   2565   canvas->drawString(axArea, 15, 250, paint);
   2566   paint.setStyle(SkPaint::kStroke_Style);
   2567   canvas->drawRect({10, 200, 10 + majorAxis.length(), 200 + minorAxis.length()}, paint);
   2568   paint.setColor(SK_ColorBLACK);
   2569   canvas->drawLine(center.fX, center.fY, center.fX + mappedRadius, center.fY, paint);
   2570   canvas->drawLine(center.fX, center.fY, center.fX, center.fY + mappedRadius, paint);
   2571   canvas->drawRect({140, 180, 140 + mappedRadius, 180 + mappedRadius}, paint);
   2572   canvas->concat(matrix);
   2573   canvas->drawCircle(center.fX, center.fY, circleRadius, paint);
   2574   paint.setColor(SK_ColorRED);
   2575   canvas->drawLine(center.fX, center.fY, center.fX + circleRadius, center.fY, paint);
   2576   canvas->drawLine(center.fX, center.fY, center.fX, center.fY + circleRadius, paint);
   2577 ##
   2578 
   2579 #SeeAlso mapVector
   2580 
   2581 ##
   2582 
   2583 # ------------------------------------------------------------------------------
   2584 #Method bool isFixedStepInX() const
   2585 #In Property
   2586 #Line # returns if transformation supports fixed step on x-axis ##
   2587 #Populate
   2588 
   2589 #Example
   2590     SkMatrix matrix;
   2591     for (SkScalar px : { 0.0f, 0.1f } ) {
   2592         for (SkScalar py : { 0.0f, 0.1f } ) {
   2593             for (SkScalar sy : { 1, 2 } ) {
   2594                 matrix.setAll(1, 0, 0,   0, sy, 0,   px, py, 1);
   2595                 matrix.dump();
   2596                 SkDebugf("isFixedStepInX: %s\n", matrix.isFixedStepInX() ? "true" : "false");
   2597             }
   2598         }
   2599     }
   2600 #StdOut
   2601 [  1.0000   0.0000   0.0000][  0.0000   1.0000   0.0000][  0.0000   0.0000   1.0000]
   2602 isFixedStepInX: true
   2603 [  1.0000   0.0000   0.0000][  0.0000   2.0000   0.0000][  0.0000   0.0000   1.0000]
   2604 isFixedStepInX: true
   2605 [  1.0000   0.0000   0.0000][  0.0000   1.0000   0.0000][  0.0000   0.1000   1.0000]
   2606 isFixedStepInX: true
   2607 [  1.0000   0.0000   0.0000][  0.0000   2.0000   0.0000][  0.0000   0.1000   1.0000]
   2608 isFixedStepInX: true
   2609 [  1.0000   0.0000   0.0000][  0.0000   1.0000   0.0000][  0.1000   0.0000   1.0000]
   2610 isFixedStepInX: false
   2611 [  1.0000   0.0000   0.0000][  0.0000   2.0000   0.0000][  0.1000   0.0000   1.0000]
   2612 isFixedStepInX: false
   2613 [  1.0000   0.0000   0.0000][  0.0000   1.0000   0.0000][  0.1000   0.1000   1.0000]
   2614 isFixedStepInX: false
   2615 [  1.0000   0.0000   0.0000][  0.0000   2.0000   0.0000][  0.1000   0.1000   1.0000]
   2616 isFixedStepInX: false
   2617 ##
   2618 ##
   2619 
   2620 #SeeAlso fixedStepInX getType
   2621 
   2622 ##
   2623 
   2624 # ------------------------------------------------------------------------------
   2625 
   2626 #Method SkVector fixedStepInX(SkScalar y) const
   2627 #In Property
   2628 #Line # returns step on x-axis for a position on y-axis ##
   2629 #Populate
   2630 
   2631 #Example
   2632 #Image 3
   2633     SkMatrix matrix;
   2634     const SkPoint center = { 128, 128 };
   2635     matrix.setScale(20, 25, center.fX, center.fY);
   2636     matrix.postRotate(75, center.fX, center.fY);
   2637     {
   2638        SkAutoCanvasRestore acr(canvas, true);
   2639        canvas->concat(matrix);
   2640        canvas->drawBitmap(source, 0, 0);
   2641     }
   2642     if (matrix.isFixedStepInX()) {
   2643        SkPaint paint;
   2644        paint.setAntiAlias(true);
   2645        SkVector step = matrix.fixedStepInX(128);
   2646        SkVector end = center + step;
   2647        canvas->drawLine(center, end, paint);
   2648        SkVector arrow = { step.fX + step.fY, step.fY - step.fX};
   2649        arrow = arrow * .25f;
   2650        canvas->drawLine(end, end - arrow, paint);
   2651        canvas->drawLine(end, {end.fX + arrow.fY, end.fY - arrow.fX}, paint);
   2652     }
   2653 ##
   2654 
   2655 #SeeAlso isFixedStepInX getType
   2656 
   2657 ##
   2658 
   2659 # ------------------------------------------------------------------------------
   2660 
   2661 #Method bool cheapEqualTo(const SkMatrix& m) const
   2662 #In Operators
   2663 #Line # compares Matrix pair using memcmp() ##
   2664 #Populate
   2665 
   2666 #Example
   2667     auto debugster = [](const char* prefix, const SkMatrix& a, const SkMatrix& b) -> void {
   2668         SkDebugf("%s: a %c= b a.cheapEqualTo(b): %s\n", prefix,
   2669                  a == b ? '=' : '!', a.cheapEqualTo(b) ? "true" : "false");
   2670     };
   2671     SkMatrix a, b;
   2672     a.setAll(1, 0, 0,   0, 1, 0,  0, 0, 1);
   2673     b.setIdentity();
   2674     debugster("identity", a, b);
   2675     a.setAll(1, -0.0f, 0,   0, 1, 0,  0, 0, 1);
   2676     debugster("neg zero", a, b);
   2677     a.setAll(1, SK_ScalarNaN, 0,   0, 1, 0,  0, 0, 1);
   2678     debugster(" one NaN", a, b);
   2679     b.setAll(1, SK_ScalarNaN, 0,   0, 1, 0,  0, 0, 1);
   2680     debugster("both NaN", a, b);
   2681 #StdOut
   2682 identity: a == b a.cheapEqualTo(b): true
   2683 neg zero: a == b a.cheapEqualTo(b): false
   2684  one NaN: a != b a.cheapEqualTo(b): false
   2685 both NaN: a != b a.cheapEqualTo(b): true
   2686 ##
   2687 ##
   2688 
   2689 #SeeAlso operator==(const SkMatrix& a, const SkMatrix& b)
   2690 
   2691 ##
   2692 
   2693 # ------------------------------------------------------------------------------
   2694 
   2695 #Method bool operator==(const SkMatrix& a, const SkMatrix& b)
   2696 
   2697 #Line # returns true if members are equal ##
   2698 #Populate
   2699 
   2700 #Example
   2701     auto debugster = [](const char* prefix, const SkMatrix& a, const SkMatrix& b) -> void {
   2702         SkDebugf("%s: a %c= b a.cheapEqualTo(b): %s\n", prefix,
   2703                  a == b ? '=' : '!', a.cheapEqualTo(b) ? "true" : "false");
   2704     };
   2705     SkMatrix a, b;
   2706     a.setAll(1, 0, 0,   0, 1, 0,  0, 0, 1);
   2707     b.setScale(2, 4);
   2708     b.postScale(0.5f, 0.25f);
   2709     debugster("identity", a, b);
   2710 #StdOut
   2711 identity: a == b a.cheapEqualTo(b): true
   2712 ##
   2713 ##
   2714 
   2715 #SeeAlso  cheapEqualTo operator!=(const SkMatrix& a, const SkMatrix& b)
   2716 
   2717 ##
   2718 
   2719 # ------------------------------------------------------------------------------
   2720 
   2721 #Method bool operator!=(const SkMatrix& a, const SkMatrix& b)
   2722 
   2723 #Line # returns true if members are unequal ##
   2724 #Populate
   2725 
   2726 #Example
   2727     auto debugster = [](const char* prefix, const SkMatrix& a, const SkMatrix& b) -> void {
   2728         SkDebugf("%s: a %c= b a.cheapEqualTo(b): %s\n", prefix,
   2729                  a != b ? '!' : '=', a.cheapEqualTo(b) ? "true" : "false");
   2730     };
   2731     SkMatrix a, b;
   2732     a.setAll(1, 0, 0,   0, 1, 0,  1, 0, 1);
   2733     if (a.invert(&b)) {
   2734         debugster("identity", a, b);
   2735     }
   2736 ##
   2737 
   2738 #SeeAlso cheapEqualTo operator==(const SkMatrix& a, const SkMatrix& b)
   2739 
   2740 ##
   2741 
   2742 # ------------------------------------------------------------------------------
   2743 #Subtopic Utility
   2744 #Line # rarely called management functions ##
   2745 ##
   2746 
   2747 #Method void dump() const
   2748 #In Utility
   2749 #Line # sends text representation using floats to standard output ##
   2750 #Populate
   2751 
   2752 #Example
   2753     SkMatrix matrix;
   2754     matrix.setRotate(45);
   2755     matrix.dump();
   2756     SkMatrix nearlyEqual;
   2757     nearlyEqual.setAll(0.7071f, -0.7071f, 0,   0.7071f, 0.7071f, 0,   0, 0, 1);
   2758     nearlyEqual.dump();
   2759     SkDebugf("matrix %c= nearlyEqual\n", matrix == nearlyEqual ? '=' : '!');
   2760 #StdOut
   2761 [  0.7071  -0.7071   0.0000][  0.7071   0.7071   0.0000][  0.0000   0.0000   1.0000]
   2762 [  0.7071  -0.7071   0.0000][  0.7071   0.7071   0.0000][  0.0000   0.0000   1.0000]
   2763 matrix != nearlyEqual
   2764 ##
   2765 ##
   2766 
   2767 #SeeAlso SkPath::dump
   2768 
   2769 ##
   2770 
   2771 # ------------------------------------------------------------------------------
   2772 
   2773 #Method SkScalar getMinScale() const
   2774 #In Property
   2775 #Line # returns minimum scaling, if possible ##
   2776 #Populate
   2777 
   2778 #Example
   2779     SkMatrix matrix;
   2780     matrix.setScale(42, 24);
   2781     SkDebugf("matrix.getMinScale() %g\n", matrix.getMinScale());
   2782 #StdOut
   2783 matrix.getMinScale() 24
   2784 ##
   2785 ##
   2786 
   2787 #SeeAlso getMaxScale getMinMaxScales
   2788 
   2789 ##
   2790 
   2791 # ------------------------------------------------------------------------------
   2792 
   2793 #Method SkScalar getMaxScale() const
   2794 #In Property
   2795 #Line # returns maximum scaling, if possible ##
   2796 #Populate
   2797 
   2798 #Example
   2799     SkMatrix matrix;
   2800     matrix.setScale(42, 24);
   2801     SkDebugf("matrix.getMaxScale() %g\n", matrix.getMaxScale());
   2802 #StdOut
   2803 matrix.getMaxScale() 42
   2804 ##
   2805 ##
   2806 
   2807 #SeeAlso getMinScale getMinMaxScales
   2808 
   2809 ##
   2810 
   2811 # ------------------------------------------------------------------------------
   2812 
   2813 #Method bool getMinMaxScales(SkScalar scaleFactors[2]) const
   2814 #In Property
   2815 #Line # returns minimum and maximum scaling, if possible ##
   2816 #Populate
   2817 
   2818 #Example
   2819     SkMatrix matrix;
   2820     matrix.setAll(1, 0, 0,  0, 1, 0,   0, 0, 0);
   2821     if (matrix.invert(&matrix)) {
   2822         SkScalar factor[2] = {2, 2};
   2823         bool result = matrix.getMinMaxScales(factor);
   2824         SkDebugf("matrix.getMinMaxScales() %s %g %g\n",
   2825                 result ? "true" : "false", factor[0], factor[1]);
   2826     }
   2827 #StdOut
   2828 matrix.getMinMaxScales() false 2 2
   2829 ##
   2830 ##
   2831 
   2832 #SeeAlso getMinScale getMaxScale
   2833 
   2834 ##
   2835 
   2836 # ------------------------------------------------------------------------------
   2837 
   2838 #Method bool decomposeScale(SkSize* scale, SkMatrix* remaining = nullptr) const
   2839 #In Property
   2840 #Line # separates scale if possible ##
   2841 Decomposes Matrix into scale components and whatever remains. Returns false if
   2842 Matrix could not be decomposed.
   2843 
   2844 Sets scale to portion of Matrix that scale axes. Sets remaining to Matrix
   2845 with scaling factored out. remaining may be passed as nullptr
   2846 to determine if Matrix can be decomposed without computing remainder.
   2847 
   2848 Returns true if scale components are found. scale and remaining are
   2849 unchanged if Matrix contains perspective; scale factors are not finite, or
   2850 are nearly zero.
   2851 
   2852 On success: #Formula # Matrix = scale * Remaining ##.
   2853 
   2854 #Param scale  axes scaling factors; may be nullptr ##
   2855 #Param remaining  Matrix without scaling; may be nullptr ##
   2856 
   2857 #Return  true if scale can be computed ##
   2858 
   2859 #Example
   2860     SkMatrix matrix;
   2861     matrix.setRotate(90 * SK_Scalar1);
   2862     matrix.postScale(1.f / 4, 1.f / 2);
   2863     matrix.dump();
   2864     SkSize scale = {SK_ScalarNaN, SK_ScalarNaN};
   2865     SkMatrix remaining;
   2866     remaining.reset();
   2867     bool success = matrix.decomposeScale(&scale, &remaining);
   2868     SkDebugf("success: %s  ", success ? "true" : "false");
   2869     SkDebugf("scale: %g, %g\n", scale.width(), scale.height());
   2870     remaining.dump();
   2871     SkMatrix scaleMatrix = SkMatrix::MakeScale(scale.width(), scale.height());
   2872     SkMatrix combined = SkMatrix::Concat(scaleMatrix, remaining);
   2873     combined.dump();
   2874 #StdOut
   2875 [  0.0000  -0.2500   0.0000][  0.5000   0.0000   0.0000][  0.0000   0.0000   1.0000]
   2876 success: true  scale: 0.5, 0.25
   2877 [  0.0000  -0.5000   0.0000][  2.0000   0.0000   0.0000][  0.0000   0.0000   1.0000]
   2878 [  0.0000  -0.2500   0.0000][  0.5000   0.0000   0.0000][  0.0000   0.0000   1.0000]
   2879 ##
   2880 ##
   2881 
   2882 #SeeAlso setScale MakeScale
   2883 
   2884 ##
   2885 
   2886 # ------------------------------------------------------------------------------
   2887 
   2888 #Method static const SkMatrix& I()
   2889 #In Constructors
   2890 #Line # returns a reference to a const identity Matrix ##
   2891 #Populate
   2892 
   2893 #Example
   2894     SkMatrix m1, m2, m3;
   2895     m1.reset();
   2896     m2.setIdentity();
   2897     m3 = SkMatrix::I();
   2898     SkDebugf("m1 %c= m2\n", m1 == m2 ? '=' : '!');
   2899     SkDebugf("m2 %c= m3\n", m1 == m2 ? '=' : '!');
   2900 #StdOut
   2901 m1 == m2
   2902 m2 == m3
   2903 ##
   2904 ##
   2905 
   2906 #SeeAlso reset() setIdentity
   2907 
   2908 ##
   2909 
   2910 # ------------------------------------------------------------------------------
   2911 
   2912 #Method static const SkMatrix& InvalidMatrix()
   2913 #In Constructors
   2914 #Line # returns a reference to a const invalid Matrix ##
   2915 #Populate
   2916 
   2917 #Example
   2918     SkDebugf("scaleX %g\n", SkMatrix::InvalidMatrix().getScaleX());
   2919 #StdOut
   2920 scaleX 3.40282e+38
   2921 ##
   2922 ##
   2923 
   2924 #SeeAlso getType
   2925 
   2926 ##
   2927 
   2928 # ------------------------------------------------------------------------------
   2929 
   2930 #Method static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b)
   2931 #In Operators
   2932 #Line # returns the concatenation of Matrix pair ##
   2933 #Populate
   2934 
   2935 #Example
   2936 #Height 64
   2937 #Image 4
   2938 #Description
   2939 setPolyToPoly creates perspective matrices, one the inverse of the other.
   2940 Multiplying the matrix by its inverse turns into an identity matrix.
   2941 ##
   2942 SkMatrix matrix, matrix2;
   2943 SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
   2944 SkRect::Make(source.bounds()).toQuad(bitmapBounds);
   2945 matrix.setPolyToPoly(bitmapBounds, perspect, 4);
   2946 matrix2.setPolyToPoly(perspect, bitmapBounds, 4);
   2947 SkMatrix concat = SkMatrix::Concat(matrix, matrix2);
   2948 canvas->concat(concat);
   2949 canvas->drawBitmap(source, 0, 0);
   2950 ##
   2951 
   2952 #SeeAlso preConcat postConcat
   2953 
   2954 ##
   2955 
   2956 # ------------------------------------------------------------------------------
   2957 
   2958 #Method void dirtyMatrixTypeCache()
   2959 #In Utility
   2960 #Line # sets internal cache to unknown state ##
   2961 #Populate
   2962 
   2963 #Example
   2964 SkMatrix matrix;
   2965 matrix.setIdentity();
   2966 SkDebugf("with identity matrix: x = %g\n", matrix.mapXY(24, 42).fX);
   2967 SkScalar& skewRef = matrix[SkMatrix::kMSkewX];
   2968 skewRef = 0;
   2969 SkDebugf("after skew x mod:     x = %g\n", matrix.mapXY(24, 42).fX);
   2970 skewRef = 1;
   2971 SkDebugf("after 2nd skew x mod: x = %g\n", matrix.mapXY(24, 42).fX);
   2972 matrix.dirtyMatrixTypeCache();
   2973 SkDebugf("after dirty cache:    x = %g\n", matrix.mapXY(24, 42).fX);
   2974 #StdOut
   2975 with identity matrix: x = 24
   2976 after skew x mod:     x = 24
   2977 after 2nd skew x mod: x = 24
   2978 after dirty cache:    x = 66
   2979 ##
   2980 ##
   2981 
   2982 #SeeAlso operator[](int index) getType
   2983 
   2984 ##
   2985 
   2986 # ------------------------------------------------------------------------------
   2987 
   2988 #Method void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty)
   2989 #In Constructors
   2990 #In Set
   2991 #Line # sets to scale and translate ##
   2992 #Populate
   2993 
   2994 #Example
   2995 SkMatrix matrix;
   2996 matrix.setScaleTranslate(1, 2, 3, 4);
   2997 matrix.dump();
   2998 #StdOut
   2999 [  1.0000   0.0000   3.0000][  0.0000   2.0000   4.0000][  0.0000   0.0000   1.0000]
   3000 ##
   3001 ##
   3002 
   3003 #SeeAlso setScale preTranslate postTranslate
   3004 
   3005 ##
   3006 
   3007 # ------------------------------------------------------------------------------
   3008 
   3009 #Method bool isFinite() const
   3010 #In Property
   3011 #Line # returns if all Matrix values are not infinity, NaN ##
   3012 #Populate
   3013 
   3014 #Example
   3015 SkMatrix matrix = SkMatrix::MakeTrans(SK_ScalarNaN, 0);
   3016 matrix.dump();
   3017 SkDebugf("matrix is finite: %s\n", matrix.isFinite() ? "true" : "false");
   3018 SkDebugf("matrix %c= matrix\n", matrix == matrix ? '=' : '!');
   3019 #StdOut
   3020 [  1.0000   0.0000      nan][  0.0000   1.0000   0.0000][  0.0000   0.0000   1.0000]
   3021 matrix is finite: false
   3022 matrix != matrix
   3023 ##
   3024 ##
   3025 
   3026 #SeeAlso operator==
   3027 
   3028 ##
   3029 
   3030 #Class SkMatrix ##
   3031 
   3032 #Topic Matrix ##
   3033