1 | /* |
---|---|

2 | * Copyright 2006 The Android Open Source Project |

3 | * |

4 | * Use of this source code is governed by a BSD-style license that can be |

5 | * found in the LICENSE file. |

6 | */ |

7 | |

8 | #ifndef SkMatrix_DEFINED |

9 | #define SkMatrix_DEFINED |

10 | |

11 | #include "include/core/SkPoint.h" |

12 | #include "include/core/SkRect.h" |

13 | #include "include/core/SkScalar.h" |

14 | #include "include/core/SkTypes.h" |

15 | #include "include/private/base/SkMacros.h" |

16 | #include "include/private/base/SkTo.h" |

17 | |

18 | #include <cstdint> |

19 | #include <cstring> |

20 | |

21 | struct SkPoint3; |

22 | struct SkRSXform; |

23 | struct SkSize; |

24 | |

25 | // Remove when clients are updated to live without this |

26 | #define SK_SUPPORT_LEGACY_MATRIX_RECTTORECT |

27 | |

28 | /** |

29 | * When we transform points through a matrix containing perspective (the bottom row is something |

30 | * other than 0,0,1), the bruteforce math can produce confusing results (since we might divide |

31 | * by 0, or a negative w value). By default, methods that map rects and paths will apply |

32 | * perspective clipping, but this can be changed by specifying kYes to those methods. |

33 | */ |

34 | enum class SkApplyPerspectiveClip { |

35 | kNo, //!< Don't pre-clip the geometry before applying the (perspective) matrix |

36 | kYes, //!< Do pre-clip the geometry before applying the (perspective) matrix |

37 | }; |

38 | |

39 | /** \class SkMatrix |

40 | SkMatrix holds a 3x3 matrix for transforming coordinates. This allows mapping |

41 | SkPoint and vectors with translation, scaling, skewing, rotation, and |

42 | perspective. |

43 | |

44 | SkMatrix elements are in row major order. |

45 | SkMatrix constexpr default constructs to identity. |

46 | |

47 | SkMatrix includes a hidden variable that classifies the type of matrix to |

48 | improve performance. SkMatrix is not thread safe unless getType() is called first. |

49 | |

50 | example: https://fiddle.skia.org/c/@Matrix_063 |

51 | */ |

52 | SK_BEGIN_REQUIRE_DENSE |

53 | class SK_API SkMatrix { |

54 | public: |

55 | |

56 | /** Creates an identity SkMatrix: |

57 | |

58 | | 1 0 0 | |

59 | | 0 1 0 | |

60 | | 0 0 1 | |

61 | */ |

62 | constexpr SkMatrix() : SkMatrix(1,0,0, 0,1,0, 0,0,1, kIdentity_Mask | kRectStaysRect_Mask) {} |

63 | |

64 | /** Sets SkMatrix to scale by (sx, sy). Returned matrix is: |

65 | |

66 | | sx 0 0 | |

67 | | 0 sy 0 | |

68 | | 0 0 1 | |

69 | |

70 | @param sx horizontal scale factor |

71 | @param sy vertical scale factor |

72 | @return SkMatrix with scale |

73 | */ |

74 | [[nodiscard]] static SkMatrix Scale(SkScalar sx, SkScalar sy) { |

75 | SkMatrix m; |

76 | m.setScale(sx, sy); |

77 | return m; |

78 | } |

79 | |

80 | /** Sets SkMatrix to translate by (dx, dy). Returned matrix is: |

81 | |

82 | | 1 0 dx | |

83 | | 0 1 dy | |

84 | | 0 0 1 | |

85 | |

86 | @param dx horizontal translation |

87 | @param dy vertical translation |

88 | @return SkMatrix with translation |

89 | */ |

90 | [[nodiscard]] static SkMatrix Translate(SkScalar dx, SkScalar dy) { |

91 | SkMatrix m; |

92 | m.setTranslate(dx, dy); |

93 | return m; |

94 | } |

95 | [[nodiscard]] static SkMatrix Translate(SkVector t) { return Translate(dx: t.x(), dy: t.y()); } |

96 | [[nodiscard]] static SkMatrix Translate(SkIVector t) { return Translate(dx: t.x(), dy: t.y()); } |

97 | |

98 | /** Sets SkMatrix to rotate by |deg| about a pivot point at (0, 0). |

99 | |

100 | @param deg rotation angle in degrees (positive rotates clockwise) |

101 | @return SkMatrix with rotation |

102 | */ |

103 | [[nodiscard]] static SkMatrix RotateDeg(SkScalar deg) { |

104 | SkMatrix m; |

105 | m.setRotate(deg); |

106 | return m; |

107 | } |

108 | [[nodiscard]] static SkMatrix RotateDeg(SkScalar deg, SkPoint pt) { |

109 | SkMatrix m; |

110 | m.setRotate(degrees: deg, px: pt.x(), py: pt.y()); |

111 | return m; |

112 | } |

113 | [[nodiscard]] static SkMatrix RotateRad(SkScalar rad) { |

114 | return RotateDeg(SkRadiansToDegrees(rad)); |

115 | } |

116 | |

117 | /** Sets SkMatrix to skew by (kx, ky) about pivot point (0, 0). |

118 | |

119 | @param kx horizontal skew factor |

120 | @param ky vertical skew factor |

121 | @return SkMatrix with skew |

122 | */ |

123 | [[nodiscard]] static SkMatrix Skew(SkScalar kx, SkScalar ky) { |

124 | SkMatrix m; |

125 | m.setSkew(kx, ky); |

126 | return m; |

127 | } |

128 | |

129 | /** \enum SkMatrix::ScaleToFit |

130 | ScaleToFit describes how SkMatrix is constructed to map one SkRect to another. |

131 | ScaleToFit may allow SkMatrix to have unequal horizontal and vertical scaling, |

132 | or may restrict SkMatrix to square scaling. If restricted, ScaleToFit specifies |

133 | how SkMatrix maps to the side or center of the destination SkRect. |

134 | */ |

135 | enum ScaleToFit { |

136 | kFill_ScaleToFit, //!< scales in x and y to fill destination SkRect |

137 | kStart_ScaleToFit, //!< scales and aligns to left and top |

138 | kCenter_ScaleToFit, //!< scales and aligns to center |

139 | kEnd_ScaleToFit, //!< scales and aligns to right and bottom |

140 | }; |

141 | |

142 | /** Returns SkMatrix set to scale and translate src to dst. ScaleToFit selects |

143 | whether mapping completely fills dst or preserves the aspect ratio, and how to |

144 | align src within dst. Returns the identity SkMatrix if src is empty. If dst is |

145 | empty, returns SkMatrix set to: |

146 | |

147 | | 0 0 0 | |

148 | | 0 0 0 | |

149 | | 0 0 1 | |

150 | |

151 | @param src SkRect to map from |

152 | @param dst SkRect to map to |

153 | @param mode How to handle the mapping |

154 | @return SkMatrix mapping src to dst |

155 | */ |

156 | [[nodiscard]] static SkMatrix RectToRect(const SkRect& src, const SkRect& dst, |

157 | ScaleToFit mode = kFill_ScaleToFit) { |

158 | return MakeRectToRect(src, dst, stf: mode); |

159 | } |

160 | |

161 | /** Sets SkMatrix to: |

162 | |

163 | | scaleX skewX transX | |

164 | | skewY scaleY transY | |

165 | | pers0 pers1 pers2 | |

166 | |

167 | @param scaleX horizontal scale factor |

168 | @param skewX horizontal skew factor |

169 | @param transX horizontal translation |

170 | @param skewY vertical skew factor |

171 | @param scaleY vertical scale factor |

172 | @param transY vertical translation |

173 | @param pers0 input x-axis perspective factor |

174 | @param pers1 input y-axis perspective factor |

175 | @param pers2 perspective scale factor |

176 | @return SkMatrix constructed from parameters |

177 | */ |

178 | [[nodiscard]] static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, |

179 | SkScalar skewY, SkScalar scaleY, SkScalar transY, |

180 | SkScalar pers0, SkScalar pers1, SkScalar pers2) { |

181 | SkMatrix m; |

182 | m.setAll(scaleX, skewX, transX, skewY, scaleY, transY, persp0: pers0, persp1: pers1, persp2: pers2); |

183 | return m; |

184 | } |

185 | |

186 | /** \enum SkMatrix::TypeMask |

187 | Enum of bit fields for mask returned by getType(). |

188 | Used to identify the complexity of SkMatrix, to optimize performance. |

189 | */ |

190 | enum TypeMask { |

191 | kIdentity_Mask = 0, //!< identity SkMatrix; all bits clear |

192 | kTranslate_Mask = 0x01, //!< translation SkMatrix |

193 | kScale_Mask = 0x02, //!< scale SkMatrix |

194 | kAffine_Mask = 0x04, //!< skew or rotate SkMatrix |

195 | kPerspective_Mask = 0x08, //!< perspective SkMatrix |

196 | }; |

197 | |

198 | /** Returns a bit field describing the transformations the matrix may |

199 | perform. The bit field is computed conservatively, so it may include |

200 | false positives. For example, when kPerspective_Mask is set, all |

201 | other bits are set. |

202 | |

203 | @return kIdentity_Mask, or combinations of: kTranslate_Mask, kScale_Mask, |

204 | kAffine_Mask, kPerspective_Mask |

205 | */ |

206 | TypeMask getType() const { |

207 | if (fTypeMask & kUnknown_Mask) { |

208 | fTypeMask = this->computeTypeMask(); |

209 | } |

210 | // only return the public masks |

211 | return (TypeMask)(fTypeMask & 0xF); |

212 | } |

213 | |

214 | /** Returns true if SkMatrix is identity. Identity matrix is: |

215 | |

216 | | 1 0 0 | |

217 | | 0 1 0 | |

218 | | 0 0 1 | |

219 | |

220 | @return true if SkMatrix has no effect |

221 | */ |

222 | bool isIdentity() const { |

223 | return this->getType() == 0; |

224 | } |

225 | |

226 | /** Returns true if SkMatrix at most scales and translates. SkMatrix may be identity, |

227 | contain only scale elements, only translate elements, or both. SkMatrix form is: |

228 | |

229 | | scale-x 0 translate-x | |

230 | | 0 scale-y translate-y | |

231 | | 0 0 1 | |

232 | |

233 | @return true if SkMatrix is identity; or scales, translates, or both |

234 | */ |

235 | bool isScaleTranslate() const { |

236 | return !(this->getType() & ~(kScale_Mask | kTranslate_Mask)); |

237 | } |

238 | |

239 | /** Returns true if SkMatrix is identity, or translates. SkMatrix form is: |

240 | |

241 | | 1 0 translate-x | |

242 | | 0 1 translate-y | |

243 | | 0 0 1 | |

244 | |

245 | @return true if SkMatrix is identity, or translates |

246 | */ |

247 | bool isTranslate() const { return !(this->getType() & ~(kTranslate_Mask)); } |

248 | |

249 | /** Returns true SkMatrix maps SkRect to another SkRect. If true, SkMatrix is identity, |

250 | or scales, or rotates a multiple of 90 degrees, or mirrors on axes. In all |

251 | cases, SkMatrix may also have translation. SkMatrix form is either: |

252 | |

253 | | scale-x 0 translate-x | |

254 | | 0 scale-y translate-y | |

255 | | 0 0 1 | |

256 | |

257 | or |

258 | |

259 | | 0 rotate-x translate-x | |

260 | | rotate-y 0 translate-y | |

261 | | 0 0 1 | |

262 | |

263 | for non-zero values of scale-x, scale-y, rotate-x, and rotate-y. |

264 | |

265 | Also called preservesAxisAlignment(); use the one that provides better inline |

266 | documentation. |

267 | |

268 | @return true if SkMatrix maps one SkRect into another |

269 | */ |

270 | bool rectStaysRect() const { |

271 | if (fTypeMask & kUnknown_Mask) { |

272 | fTypeMask = this->computeTypeMask(); |

273 | } |

274 | return (fTypeMask & kRectStaysRect_Mask) != 0; |

275 | } |

276 | |

277 | /** Returns true SkMatrix maps SkRect to another SkRect. If true, SkMatrix is identity, |

278 | or scales, or rotates a multiple of 90 degrees, or mirrors on axes. In all |

279 | cases, SkMatrix may also have translation. SkMatrix form is either: |

280 | |

281 | | scale-x 0 translate-x | |

282 | | 0 scale-y translate-y | |

283 | | 0 0 1 | |

284 | |

285 | or |

286 | |

287 | | 0 rotate-x translate-x | |

288 | | rotate-y 0 translate-y | |

289 | | 0 0 1 | |

290 | |

291 | for non-zero values of scale-x, scale-y, rotate-x, and rotate-y. |

292 | |

293 | Also called rectStaysRect(); use the one that provides better inline |

294 | documentation. |

295 | |

296 | @return true if SkMatrix maps one SkRect into another |

297 | */ |

298 | bool preservesAxisAlignment() const { return this->rectStaysRect(); } |

299 | |

300 | /** Returns true if the matrix contains perspective elements. SkMatrix form is: |

301 | |

302 | | -- -- -- | |

303 | | -- -- -- | |

304 | | perspective-x perspective-y perspective-scale | |

305 | |

306 | where perspective-x or perspective-y is non-zero, or perspective-scale is |

307 | not one. All other elements may have any value. |

308 | |

309 | @return true if SkMatrix is in most general form |

310 | */ |

311 | bool hasPerspective() const { |

312 | return SkToBool(x: this->getPerspectiveTypeMaskOnly() & |

313 | kPerspective_Mask); |

314 | } |

315 | |

316 | /** Returns true if SkMatrix contains only translation, rotation, reflection, and |

317 | uniform scale. |

318 | Returns false if SkMatrix contains different scales, skewing, perspective, or |

319 | degenerate forms that collapse to a line or point. |

320 | |

321 | Describes that the SkMatrix makes rendering with and without the matrix are |

322 | visually alike; a transformed circle remains a circle. Mathematically, this is |

323 | referred to as similarity of a Euclidean space, or a similarity transformation. |

324 | |

325 | Preserves right angles, keeping the arms of the angle equal lengths. |

326 | |

327 | @param tol to be deprecated |

328 | @return true if SkMatrix only rotates, uniformly scales, translates |

329 | |

330 | example: https://fiddle.skia.org/c/@Matrix_isSimilarity |

331 | */ |

332 | bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const; |

333 | |

334 | /** Returns true if SkMatrix contains only translation, rotation, reflection, and |

335 | scale. Scale may differ along rotated axes. |

336 | Returns false if SkMatrix skewing, perspective, or degenerate forms that collapse |

337 | to a line or point. |

338 | |

339 | Preserves right angles, but not requiring that the arms of the angle |

340 | retain equal lengths. |

341 | |

342 | @param tol to be deprecated |

343 | @return true if SkMatrix only rotates, scales, translates |

344 | |

345 | example: https://fiddle.skia.org/c/@Matrix_preservesRightAngles |

346 | */ |

347 | bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const; |

348 | |

349 | /** SkMatrix organizes its values in row-major order. These members correspond to |

350 | each value in SkMatrix. |

351 | */ |

352 | static constexpr int kMScaleX = 0; //!< horizontal scale factor |

353 | static constexpr int kMSkewX = 1; //!< horizontal skew factor |

354 | static constexpr int kMTransX = 2; //!< horizontal translation |

355 | static constexpr int kMSkewY = 3; //!< vertical skew factor |

356 | static constexpr int kMScaleY = 4; //!< vertical scale factor |

357 | static constexpr int kMTransY = 5; //!< vertical translation |

358 | static constexpr int kMPersp0 = 6; //!< input x perspective factor |

359 | static constexpr int kMPersp1 = 7; //!< input y perspective factor |

360 | static constexpr int kMPersp2 = 8; //!< perspective bias |

361 | |

362 | /** Affine arrays are in column-major order to match the matrix used by |

363 | PDF and XPS. |

364 | */ |

365 | static constexpr int kAScaleX = 0; //!< horizontal scale factor |

366 | static constexpr int kASkewY = 1; //!< vertical skew factor |

367 | static constexpr int kASkewX = 2; //!< horizontal skew factor |

368 | static constexpr int kAScaleY = 3; //!< vertical scale factor |

369 | static constexpr int kATransX = 4; //!< horizontal translation |

370 | static constexpr int kATransY = 5; //!< vertical translation |

371 | |

372 | /** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is |

373 | defined. |

374 | |

375 | @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, |

376 | kMPersp0, kMPersp1, kMPersp2 |

377 | @return value corresponding to index |

378 | */ |

379 | SkScalar operator[](int index) const { |

380 | SkASSERT((unsigned)index < 9); |

381 | return fMat[index]; |

382 | } |

383 | |

384 | /** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is |

385 | defined. |

386 | |

387 | @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, |

388 | kMPersp0, kMPersp1, kMPersp2 |

389 | @return value corresponding to index |

390 | */ |

391 | SkScalar get(int index) const { |

392 | SkASSERT((unsigned)index < 9); |

393 | return fMat[index]; |

394 | } |

395 | |

396 | /** Returns one matrix value from a particular row/column. Asserts if index is out |

397 | of range and SK_DEBUG is defined. |

398 | |

399 | @param r matrix row to fetch |

400 | @param c matrix column to fetch |

401 | @return value at the given matrix position |

402 | */ |

403 | SkScalar rc(int r, int c) const { |

404 | SkASSERT(r >= 0 && r <= 2); |

405 | SkASSERT(c >= 0 && c <= 2); |

406 | return fMat[r*3 + c]; |

407 | } |

408 | |

409 | /** Returns scale factor multiplied by x-axis input, contributing to x-axis output. |

410 | With mapPoints(), scales SkPoint along the x-axis. |

411 | |

412 | @return horizontal scale factor |

413 | */ |

414 | SkScalar getScaleX() const { return fMat[kMScaleX]; } |

415 | |

416 | /** Returns scale factor multiplied by y-axis input, contributing to y-axis output. |

417 | With mapPoints(), scales SkPoint along the y-axis. |

418 | |

419 | @return vertical scale factor |

420 | */ |

421 | SkScalar getScaleY() const { return fMat[kMScaleY]; } |

422 | |

423 | /** Returns scale factor multiplied by x-axis input, contributing to y-axis output. |

424 | With mapPoints(), skews SkPoint along the y-axis. |

425 | Skewing both axes can rotate SkPoint. |

426 | |

427 | @return vertical skew factor |

428 | */ |

429 | SkScalar getSkewY() const { return fMat[kMSkewY]; } |

430 | |

431 | /** Returns scale factor multiplied by y-axis input, contributing to x-axis output. |

432 | With mapPoints(), skews SkPoint along the x-axis. |

433 | Skewing both axes can rotate SkPoint. |

434 | |

435 | @return horizontal scale factor |

436 | */ |

437 | SkScalar getSkewX() const { return fMat[kMSkewX]; } |

438 | |

439 | /** Returns translation contributing to x-axis output. |

440 | With mapPoints(), moves SkPoint along the x-axis. |

441 | |

442 | @return horizontal translation factor |

443 | */ |

444 | SkScalar getTranslateX() const { return fMat[kMTransX]; } |

445 | |

446 | /** Returns translation contributing to y-axis output. |

447 | With mapPoints(), moves SkPoint along the y-axis. |

448 | |

449 | @return vertical translation factor |

450 | */ |

451 | SkScalar getTranslateY() const { return fMat[kMTransY]; } |

452 | |

453 | /** Returns factor scaling input x-axis relative to input y-axis. |

454 | |

455 | @return input x-axis perspective factor |

456 | */ |

457 | SkScalar getPerspX() const { return fMat[kMPersp0]; } |

458 | |

459 | /** Returns factor scaling input y-axis relative to input x-axis. |

460 | |

461 | @return input y-axis perspective factor |

462 | */ |

463 | SkScalar getPerspY() const { return fMat[kMPersp1]; } |

464 | |

465 | /** Returns writable SkMatrix value. Asserts if index is out of range and SK_DEBUG is |

466 | defined. Clears internal cache anticipating that caller will change SkMatrix value. |

467 | |

468 | Next call to read SkMatrix state may recompute cache; subsequent writes to SkMatrix |

469 | value must be followed by dirtyMatrixTypeCache(). |

470 | |

471 | @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, |

472 | kMPersp0, kMPersp1, kMPersp2 |

473 | @return writable value corresponding to index |

474 | */ |

475 | SkScalar& operator[](int index) { |

476 | SkASSERT((unsigned)index < 9); |

477 | this->setTypeMask(kUnknown_Mask); |

478 | return fMat[index]; |

479 | } |

480 | |

481 | /** Sets SkMatrix value. Asserts if index is out of range and SK_DEBUG is |

482 | defined. Safer than operator[]; internal cache is always maintained. |

483 | |

484 | @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, |

485 | kMPersp0, kMPersp1, kMPersp2 |

486 | @param value scalar to store in SkMatrix |

487 | */ |

488 | SkMatrix& set(int index, SkScalar value) { |

489 | SkASSERT((unsigned)index < 9); |

490 | fMat[index] = value; |

491 | this->setTypeMask(kUnknown_Mask); |

492 | return *this; |

493 | } |

494 | |

495 | /** Sets horizontal scale factor. |

496 | |

497 | @param v horizontal scale factor to store |

498 | */ |

499 | SkMatrix& setScaleX(SkScalar v) { return this->set(index: kMScaleX, value: v); } |

500 | |

501 | /** Sets vertical scale factor. |

502 | |

503 | @param v vertical scale factor to store |

504 | */ |

505 | SkMatrix& setScaleY(SkScalar v) { return this->set(index: kMScaleY, value: v); } |

506 | |

507 | /** Sets vertical skew factor. |

508 | |

509 | @param v vertical skew factor to store |

510 | */ |

511 | SkMatrix& setSkewY(SkScalar v) { return this->set(index: kMSkewY, value: v); } |

512 | |

513 | /** Sets horizontal skew factor. |

514 | |

515 | @param v horizontal skew factor to store |

516 | */ |

517 | SkMatrix& setSkewX(SkScalar v) { return this->set(index: kMSkewX, value: v); } |

518 | |

519 | /** Sets horizontal translation. |

520 | |

521 | @param v horizontal translation to store |

522 | */ |

523 | SkMatrix& setTranslateX(SkScalar v) { return this->set(index: kMTransX, value: v); } |

524 | |

525 | /** Sets vertical translation. |

526 | |

527 | @param v vertical translation to store |

528 | */ |

529 | SkMatrix& setTranslateY(SkScalar v) { return this->set(index: kMTransY, value: v); } |

530 | |

531 | /** Sets input x-axis perspective factor, which causes mapXY() to vary input x-axis values |

532 | inversely proportional to input y-axis values. |

533 | |

534 | @param v perspective factor |

535 | */ |

536 | SkMatrix& setPerspX(SkScalar v) { return this->set(index: kMPersp0, value: v); } |

537 | |

538 | /** Sets input y-axis perspective factor, which causes mapXY() to vary input y-axis values |

539 | inversely proportional to input x-axis values. |

540 | |

541 | @param v perspective factor |

542 | */ |

543 | SkMatrix& setPerspY(SkScalar v) { return this->set(index: kMPersp1, value: v); } |

544 | |

545 | /** Sets all values from parameters. Sets matrix to: |

546 | |

547 | | scaleX skewX transX | |

548 | | skewY scaleY transY | |

549 | | persp0 persp1 persp2 | |

550 | |

551 | @param scaleX horizontal scale factor to store |

552 | @param skewX horizontal skew factor to store |

553 | @param transX horizontal translation to store |

554 | @param skewY vertical skew factor to store |

555 | @param scaleY vertical scale factor to store |

556 | @param transY vertical translation to store |

557 | @param persp0 input x-axis values perspective factor to store |

558 | @param persp1 input y-axis values perspective factor to store |

559 | @param persp2 perspective scale factor to store |

560 | */ |

561 | SkMatrix& setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, |

562 | SkScalar skewY, SkScalar scaleY, SkScalar transY, |

563 | SkScalar persp0, SkScalar persp1, SkScalar persp2) { |

564 | fMat[kMScaleX] = scaleX; |

565 | fMat[kMSkewX] = skewX; |

566 | fMat[kMTransX] = transX; |

567 | fMat[kMSkewY] = skewY; |

568 | fMat[kMScaleY] = scaleY; |

569 | fMat[kMTransY] = transY; |

570 | fMat[kMPersp0] = persp0; |

571 | fMat[kMPersp1] = persp1; |

572 | fMat[kMPersp2] = persp2; |

573 | this->setTypeMask(kUnknown_Mask); |

574 | return *this; |

575 | } |

576 | |

577 | /** Copies nine scalar values contained by SkMatrix into buffer, in member value |

578 | ascending order: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, |

579 | kMPersp0, kMPersp1, kMPersp2. |

580 | |

581 | @param buffer storage for nine scalar values |

582 | */ |

583 | void get9(SkScalar buffer[9]) const { |

584 | memcpy(dest: buffer, src: fMat, n: 9 * sizeof(SkScalar)); |

585 | } |

586 | |

587 | /** Sets SkMatrix to nine scalar values in buffer, in member value ascending order: |

588 | kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, kMPersp0, kMPersp1, |

589 | kMPersp2. |

590 | |

591 | Sets matrix to: |

592 | |

593 | | buffer[0] buffer[1] buffer[2] | |

594 | | buffer[3] buffer[4] buffer[5] | |

595 | | buffer[6] buffer[7] buffer[8] | |

596 | |

597 | In the future, set9 followed by get9 may not return the same values. Since SkMatrix |

598 | maps non-homogeneous coordinates, scaling all nine values produces an equivalent |

599 | transformation, possibly improving precision. |

600 | |

601 | @param buffer nine scalar values |

602 | */ |

603 | SkMatrix& set9(const SkScalar buffer[9]); |

604 | |

605 | /** Sets SkMatrix to identity; which has no effect on mapped SkPoint. Sets SkMatrix to: |

606 | |

607 | | 1 0 0 | |

608 | | 0 1 0 | |

609 | | 0 0 1 | |

610 | |

611 | Also called setIdentity(); use the one that provides better inline |

612 | documentation. |

613 | */ |

614 | SkMatrix& reset(); |

615 | |

616 | /** Sets SkMatrix to identity; which has no effect on mapped SkPoint. Sets SkMatrix to: |

617 | |

618 | | 1 0 0 | |

619 | | 0 1 0 | |

620 | | 0 0 1 | |

621 | |

622 | Also called reset(); use the one that provides better inline |

623 | documentation. |

624 | */ |

625 | SkMatrix& setIdentity() { return this->reset(); } |

626 | |

627 | /** Sets SkMatrix to translate by (dx, dy). |

628 | |

629 | @param dx horizontal translation |

630 | @param dy vertical translation |

631 | */ |

632 | SkMatrix& setTranslate(SkScalar dx, SkScalar dy); |

633 | |

634 | /** Sets SkMatrix to translate by (v.fX, v.fY). |

635 | |

636 | @param v vector containing horizontal and vertical translation |

637 | */ |

638 | SkMatrix& setTranslate(const SkVector& v) { return this->setTranslate(dx: v.fX, dy: v.fY); } |

639 | |

640 | /** Sets SkMatrix to scale by sx and sy, about a pivot point at (px, py). |

641 | The pivot point is unchanged when mapped with SkMatrix. |

642 | |

643 | @param sx horizontal scale factor |

644 | @param sy vertical scale factor |

645 | @param px pivot on x-axis |

646 | @param py pivot on y-axis |

647 | */ |

648 | SkMatrix& setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); |

649 | |

650 | /** Sets SkMatrix to scale by sx and sy about at pivot point at (0, 0). |

651 | |

652 | @param sx horizontal scale factor |

653 | @param sy vertical scale factor |

654 | */ |

655 | SkMatrix& setScale(SkScalar sx, SkScalar sy); |

656 | |

657 | /** Sets SkMatrix to rotate by degrees about a pivot point at (px, py). |

658 | The pivot point is unchanged when mapped with SkMatrix. |

659 | |

660 | Positive degrees rotates clockwise. |

661 | |

662 | @param degrees angle of axes relative to upright axes |

663 | @param px pivot on x-axis |

664 | @param py pivot on y-axis |

665 | */ |

666 | SkMatrix& setRotate(SkScalar degrees, SkScalar px, SkScalar py); |

667 | |

668 | /** Sets SkMatrix to rotate by degrees about a pivot point at (0, 0). |

669 | Positive degrees rotates clockwise. |

670 | |

671 | @param degrees angle of axes relative to upright axes |

672 | */ |

673 | SkMatrix& setRotate(SkScalar degrees); |

674 | |

675 | /** Sets SkMatrix to rotate by sinValue and cosValue, about a pivot point at (px, py). |

676 | The pivot point is unchanged when mapped with SkMatrix. |

677 | |

678 | Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1). |

679 | Vector length specifies scale. |

680 | |

681 | @param sinValue rotation vector x-axis component |

682 | @param cosValue rotation vector y-axis component |

683 | @param px pivot on x-axis |

684 | @param py pivot on y-axis |

685 | */ |

686 | SkMatrix& setSinCos(SkScalar sinValue, SkScalar cosValue, |

687 | SkScalar px, SkScalar py); |

688 | |

689 | /** Sets SkMatrix to rotate by sinValue and cosValue, about a pivot point at (0, 0). |

690 | |

691 | Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1). |

692 | Vector length specifies scale. |

693 | |

694 | @param sinValue rotation vector x-axis component |

695 | @param cosValue rotation vector y-axis component |

696 | */ |

697 | SkMatrix& setSinCos(SkScalar sinValue, SkScalar cosValue); |

698 | |

699 | /** Sets SkMatrix to rotate, scale, and translate using a compressed matrix form. |

700 | |

701 | Vector (rsxForm.fSSin, rsxForm.fSCos) describes the angle of rotation relative |

702 | to (0, 1). Vector length specifies scale. Mapped point is rotated and scaled |

703 | by vector, then translated by (rsxForm.fTx, rsxForm.fTy). |

704 | |

705 | @param rsxForm compressed SkRSXform matrix |

706 | @return reference to SkMatrix |

707 | |

708 | example: https://fiddle.skia.org/c/@Matrix_setRSXform |

709 | */ |

710 | SkMatrix& setRSXform(const SkRSXform& rsxForm); |

711 | |

712 | /** Sets SkMatrix to skew by kx and ky, about a pivot point at (px, py). |

713 | The pivot point is unchanged when mapped with SkMatrix. |

714 | |

715 | @param kx horizontal skew factor |

716 | @param ky vertical skew factor |

717 | @param px pivot on x-axis |

718 | @param py pivot on y-axis |

719 | */ |

720 | SkMatrix& setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); |

721 | |

722 | /** Sets SkMatrix to skew by kx and ky, about a pivot point at (0, 0). |

723 | |

724 | @param kx horizontal skew factor |

725 | @param ky vertical skew factor |

726 | */ |

727 | SkMatrix& setSkew(SkScalar kx, SkScalar ky); |

728 | |

729 | /** Sets SkMatrix to SkMatrix a multiplied by SkMatrix b. Either a or b may be this. |

730 | |

731 | Given: |

732 | |

733 | | A B C | | J K L | |

734 | a = | D E F |, b = | M N O | |

735 | | G H I | | P Q R | |

736 | |

737 | sets SkMatrix to: |

738 | |

739 | | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | |

740 | a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | |

741 | | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | |

742 | |

743 | @param a SkMatrix on left side of multiply expression |

744 | @param b SkMatrix on right side of multiply expression |

745 | */ |

746 | SkMatrix& setConcat(const SkMatrix& a, const SkMatrix& b); |

747 | |

748 | /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from translation (dx, dy). |

749 | This can be thought of as moving the point to be mapped before applying SkMatrix. |

750 | |

751 | Given: |

752 | |

753 | | A B C | | 1 0 dx | |

754 | Matrix = | D E F |, T(dx, dy) = | 0 1 dy | |

755 | | G H I | | 0 0 1 | |

756 | |

757 | sets SkMatrix to: |

758 | |

759 | | A B C | | 1 0 dx | | A B A*dx+B*dy+C | |

760 | Matrix * T(dx, dy) = | D E F | | 0 1 dy | = | D E D*dx+E*dy+F | |

761 | | G H I | | 0 0 1 | | G H G*dx+H*dy+I | |

762 | |

763 | @param dx x-axis translation before applying SkMatrix |

764 | @param dy y-axis translation before applying SkMatrix |

765 | */ |

766 | SkMatrix& preTranslate(SkScalar dx, SkScalar dy); |

767 | |

768 | /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from scaling by (sx, sy) |

769 | about pivot point (px, py). |

770 | This can be thought of as scaling about a pivot point before applying SkMatrix. |

771 | |

772 | Given: |

773 | |

774 | | A B C | | sx 0 dx | |

775 | Matrix = | D E F |, S(sx, sy, px, py) = | 0 sy dy | |

776 | | G H I | | 0 0 1 | |

777 | |

778 | where |

779 | |

780 | dx = px - sx * px |

781 | dy = py - sy * py |

782 | |

783 | sets SkMatrix to: |

784 | |

785 | | A B C | | sx 0 dx | | A*sx B*sy A*dx+B*dy+C | |

786 | Matrix * S(sx, sy, px, py) = | D E F | | 0 sy dy | = | D*sx E*sy D*dx+E*dy+F | |

787 | | G H I | | 0 0 1 | | G*sx H*sy G*dx+H*dy+I | |

788 | |

789 | @param sx horizontal scale factor |

790 | @param sy vertical scale factor |

791 | @param px pivot on x-axis |

792 | @param py pivot on y-axis |

793 | */ |

794 | SkMatrix& preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); |

795 | |

796 | /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from scaling by (sx, sy) |

797 | about pivot point (0, 0). |

798 | This can be thought of as scaling about the origin before applying SkMatrix. |

799 | |

800 | Given: |

801 | |

802 | | A B C | | sx 0 0 | |

803 | Matrix = | D E F |, S(sx, sy) = | 0 sy 0 | |

804 | | G H I | | 0 0 1 | |

805 | |

806 | sets SkMatrix to: |

807 | |

808 | | A B C | | sx 0 0 | | A*sx B*sy C | |

809 | Matrix * S(sx, sy) = | D E F | | 0 sy 0 | = | D*sx E*sy F | |

810 | | G H I | | 0 0 1 | | G*sx H*sy I | |

811 | |

812 | @param sx horizontal scale factor |

813 | @param sy vertical scale factor |

814 | */ |

815 | SkMatrix& preScale(SkScalar sx, SkScalar sy); |

816 | |

817 | /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from rotating by degrees |

818 | about pivot point (px, py). |

819 | This can be thought of as rotating about a pivot point before applying SkMatrix. |

820 | |

821 | Positive degrees rotates clockwise. |

822 | |

823 | Given: |

824 | |

825 | | A B C | | c -s dx | |

826 | Matrix = | D E F |, R(degrees, px, py) = | s c dy | |

827 | | G H I | | 0 0 1 | |

828 | |

829 | where |

830 | |

831 | c = cos(degrees) |

832 | s = sin(degrees) |

833 | dx = s * py + (1 - c) * px |

834 | dy = -s * px + (1 - c) * py |

835 | |

836 | sets SkMatrix to: |

837 | |

838 | | A B C | | c -s dx | | Ac+Bs -As+Bc A*dx+B*dy+C | |

839 | Matrix * R(degrees, px, py) = | D E F | | s c dy | = | Dc+Es -Ds+Ec D*dx+E*dy+F | |

840 | | G H I | | 0 0 1 | | Gc+Hs -Gs+Hc G*dx+H*dy+I | |

841 | |

842 | @param degrees angle of axes relative to upright axes |

843 | @param px pivot on x-axis |

844 | @param py pivot on y-axis |

845 | */ |

846 | SkMatrix& preRotate(SkScalar degrees, SkScalar px, SkScalar py); |

847 | |

848 | /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from rotating by degrees |

849 | about pivot point (0, 0). |

850 | This can be thought of as rotating about the origin before applying SkMatrix. |

851 | |

852 | Positive degrees rotates clockwise. |

853 | |

854 | Given: |

855 | |

856 | | A B C | | c -s 0 | |

857 | Matrix = | D E F |, R(degrees, px, py) = | s c 0 | |

858 | | G H I | | 0 0 1 | |

859 | |

860 | where |

861 | |

862 | c = cos(degrees) |

863 | s = sin(degrees) |

864 | |

865 | sets SkMatrix to: |

866 | |

867 | | A B C | | c -s 0 | | Ac+Bs -As+Bc C | |

868 | Matrix * R(degrees, px, py) = | D E F | | s c 0 | = | Dc+Es -Ds+Ec F | |

869 | | G H I | | 0 0 1 | | Gc+Hs -Gs+Hc I | |

870 | |

871 | @param degrees angle of axes relative to upright axes |

872 | */ |

873 | SkMatrix& preRotate(SkScalar degrees); |

874 | |

875 | /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from skewing by (kx, ky) |

876 | about pivot point (px, py). |

877 | This can be thought of as skewing about a pivot point before applying SkMatrix. |

878 | |

879 | Given: |

880 | |

881 | | A B C | | 1 kx dx | |

882 | Matrix = | D E F |, K(kx, ky, px, py) = | ky 1 dy | |

883 | | G H I | | 0 0 1 | |

884 | |

885 | where |

886 | |

887 | dx = -kx * py |

888 | dy = -ky * px |

889 | |

890 | sets SkMatrix to: |

891 | |

892 | | A B C | | 1 kx dx | | A+B*ky A*kx+B A*dx+B*dy+C | |

893 | Matrix * K(kx, ky, px, py) = | D E F | | ky 1 dy | = | D+E*ky D*kx+E D*dx+E*dy+F | |

894 | | G H I | | 0 0 1 | | G+H*ky G*kx+H G*dx+H*dy+I | |

895 | |

896 | @param kx horizontal skew factor |

897 | @param ky vertical skew factor |

898 | @param px pivot on x-axis |

899 | @param py pivot on y-axis |

900 | */ |

901 | SkMatrix& preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); |

902 | |

903 | /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from skewing by (kx, ky) |

904 | about pivot point (0, 0). |

905 | This can be thought of as skewing about the origin before applying SkMatrix. |

906 | |

907 | Given: |

908 | |

909 | | A B C | | 1 kx 0 | |

910 | Matrix = | D E F |, K(kx, ky) = | ky 1 0 | |

911 | | G H I | | 0 0 1 | |

912 | |

913 | sets SkMatrix to: |

914 | |

915 | | A B C | | 1 kx 0 | | A+B*ky A*kx+B C | |

916 | Matrix * K(kx, ky) = | D E F | | ky 1 0 | = | D+E*ky D*kx+E F | |

917 | | G H I | | 0 0 1 | | G+H*ky G*kx+H I | |

918 | |

919 | @param kx horizontal skew factor |

920 | @param ky vertical skew factor |

921 | */ |

922 | SkMatrix& preSkew(SkScalar kx, SkScalar ky); |

923 | |

924 | /** Sets SkMatrix to SkMatrix multiplied by SkMatrix other. |

925 | This can be thought of mapping by other before applying SkMatrix. |

926 | |

927 | Given: |

928 | |

929 | | A B C | | J K L | |

930 | Matrix = | D E F |, other = | M N O | |

931 | | G H I | | P Q R | |

932 | |

933 | sets SkMatrix to: |

934 | |

935 | | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | |

936 | Matrix * other = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | |

937 | | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | |

938 | |

939 | @param other SkMatrix on right side of multiply expression |

940 | */ |

941 | SkMatrix& preConcat(const SkMatrix& other); |

942 | |

943 | /** Sets SkMatrix to SkMatrix constructed from translation (dx, dy) multiplied by SkMatrix. |

944 | This can be thought of as moving the point to be mapped after applying SkMatrix. |

945 | |

946 | Given: |

947 | |

948 | | J K L | | 1 0 dx | |

949 | Matrix = | M N O |, T(dx, dy) = | 0 1 dy | |

950 | | P Q R | | 0 0 1 | |

951 | |

952 | sets SkMatrix to: |

953 | |

954 | | 1 0 dx | | J K L | | J+dx*P K+dx*Q L+dx*R | |

955 | T(dx, dy) * Matrix = | 0 1 dy | | M N O | = | M+dy*P N+dy*Q O+dy*R | |

956 | | 0 0 1 | | P Q R | | P Q R | |

957 | |

958 | @param dx x-axis translation after applying SkMatrix |

959 | @param dy y-axis translation after applying SkMatrix |

960 | */ |

961 | SkMatrix& postTranslate(SkScalar dx, SkScalar dy); |

962 | |

963 | /** Sets SkMatrix to SkMatrix constructed from scaling by (sx, sy) about pivot point |

964 | (px, py), multiplied by SkMatrix. |

965 | This can be thought of as scaling about a pivot point after applying SkMatrix. |

966 | |

967 | Given: |

968 | |

969 | | J K L | | sx 0 dx | |

970 | Matrix = | M N O |, S(sx, sy, px, py) = | 0 sy dy | |

971 | | P Q R | | 0 0 1 | |

972 | |

973 | where |

974 | |

975 | dx = px - sx * px |

976 | dy = py - sy * py |

977 | |

978 | sets SkMatrix to: |

979 | |

980 | | sx 0 dx | | J K L | | sx*J+dx*P sx*K+dx*Q sx*L+dx+R | |

981 | S(sx, sy, px, py) * Matrix = | 0 sy dy | | M N O | = | sy*M+dy*P sy*N+dy*Q sy*O+dy*R | |

982 | | 0 0 1 | | P Q R | | P Q R | |

983 | |

984 | @param sx horizontal scale factor |

985 | @param sy vertical scale factor |

986 | @param px pivot on x-axis |

987 | @param py pivot on y-axis |

988 | */ |

989 | SkMatrix& postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); |

990 | |

991 | /** Sets SkMatrix to SkMatrix constructed from scaling by (sx, sy) about pivot point |

992 | (0, 0), multiplied by SkMatrix. |

993 | This can be thought of as scaling about the origin after applying SkMatrix. |

994 | |

995 | Given: |

996 | |

997 | | J K L | | sx 0 0 | |

998 | Matrix = | M N O |, S(sx, sy) = | 0 sy 0 | |

999 | | P Q R | | 0 0 1 | |

1000 | |

1001 | sets SkMatrix to: |

1002 | |

1003 | | sx 0 0 | | J K L | | sx*J sx*K sx*L | |

1004 | S(sx, sy) * Matrix = | 0 sy 0 | | M N O | = | sy*M sy*N sy*O | |

1005 | | 0 0 1 | | P Q R | | P Q R | |

1006 | |

1007 | @param sx horizontal scale factor |

1008 | @param sy vertical scale factor |

1009 | */ |

1010 | SkMatrix& postScale(SkScalar sx, SkScalar sy); |

1011 | |

1012 | /** Sets SkMatrix to SkMatrix constructed from rotating by degrees about pivot point |

1013 | (px, py), multiplied by SkMatrix. |

1014 | This can be thought of as rotating about a pivot point after applying SkMatrix. |

1015 | |

1016 | Positive degrees rotates clockwise. |

1017 | |

1018 | Given: |

1019 | |

1020 | | J K L | | c -s dx | |

1021 | Matrix = | M N O |, R(degrees, px, py) = | s c dy | |

1022 | | P Q R | | 0 0 1 | |

1023 | |

1024 | where |

1025 | |

1026 | c = cos(degrees) |

1027 | s = sin(degrees) |

1028 | dx = s * py + (1 - c) * px |

1029 | dy = -s * px + (1 - c) * py |

1030 | |

1031 | sets SkMatrix to: |

1032 | |

1033 | |c -s dx| |J K L| |cJ-sM+dx*P cK-sN+dx*Q cL-sO+dx+R| |

1034 | R(degrees, px, py) * Matrix = |s c dy| |M N O| = |sJ+cM+dy*P sK+cN+dy*Q sL+cO+dy*R| |

1035 | |0 0 1| |P Q R| | P Q R| |

1036 | |

1037 | @param degrees angle of axes relative to upright axes |

1038 | @param px pivot on x-axis |

1039 | @param py pivot on y-axis |

1040 | */ |

1041 | SkMatrix& postRotate(SkScalar degrees, SkScalar px, SkScalar py); |

1042 | |

1043 | /** Sets SkMatrix to SkMatrix constructed from rotating by degrees about pivot point |

1044 | (0, 0), multiplied by SkMatrix. |

1045 | This can be thought of as rotating about the origin after applying SkMatrix. |

1046 | |

1047 | Positive degrees rotates clockwise. |

1048 | |

1049 | Given: |

1050 | |

1051 | | J K L | | c -s 0 | |

1052 | Matrix = | M N O |, R(degrees, px, py) = | s c 0 | |

1053 | | P Q R | | 0 0 1 | |

1054 | |

1055 | where |

1056 | |

1057 | c = cos(degrees) |

1058 | s = sin(degrees) |

1059 | |

1060 | sets SkMatrix to: |

1061 | |

1062 | | c -s dx | | J K L | | cJ-sM cK-sN cL-sO | |

1063 | R(degrees, px, py) * Matrix = | s c dy | | M N O | = | sJ+cM sK+cN sL+cO | |

1064 | | 0 0 1 | | P Q R | | P Q R | |

1065 | |

1066 | @param degrees angle of axes relative to upright axes |

1067 | */ |

1068 | SkMatrix& postRotate(SkScalar degrees); |

1069 | |

1070 | /** Sets SkMatrix to SkMatrix constructed from skewing by (kx, ky) about pivot point |

1071 | (px, py), multiplied by SkMatrix. |

1072 | This can be thought of as skewing about a pivot point after applying SkMatrix. |

1073 | |

1074 | Given: |

1075 | |

1076 | | J K L | | 1 kx dx | |

1077 | Matrix = | M N O |, K(kx, ky, px, py) = | ky 1 dy | |

1078 | | P Q R | | 0 0 1 | |

1079 | |

1080 | where |

1081 | |

1082 | dx = -kx * py |

1083 | dy = -ky * px |

1084 | |

1085 | sets SkMatrix to: |

1086 | |

1087 | | 1 kx dx| |J K L| |J+kx*M+dx*P K+kx*N+dx*Q L+kx*O+dx+R| |

1088 | K(kx, ky, px, py) * Matrix = |ky 1 dy| |M N O| = |ky*J+M+dy*P ky*K+N+dy*Q ky*L+O+dy*R| |

1089 | | 0 0 1| |P Q R| | P Q R| |

1090 | |

1091 | @param kx horizontal skew factor |

1092 | @param ky vertical skew factor |

1093 | @param px pivot on x-axis |

1094 | @param py pivot on y-axis |

1095 | */ |

1096 | SkMatrix& postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); |

1097 | |

1098 | /** Sets SkMatrix to SkMatrix constructed from skewing by (kx, ky) about pivot point |

1099 | (0, 0), multiplied by SkMatrix. |

1100 | This can be thought of as skewing about the origin after applying SkMatrix. |

1101 | |

1102 | Given: |

1103 | |

1104 | | J K L | | 1 kx 0 | |

1105 | Matrix = | M N O |, K(kx, ky) = | ky 1 0 | |

1106 | | P Q R | | 0 0 1 | |

1107 | |

1108 | sets SkMatrix to: |

1109 | |

1110 | | 1 kx 0 | | J K L | | J+kx*M K+kx*N L+kx*O | |

1111 | K(kx, ky) * Matrix = | ky 1 0 | | M N O | = | ky*J+M ky*K+N ky*L+O | |

1112 | | 0 0 1 | | P Q R | | P Q R | |

1113 | |

1114 | @param kx horizontal skew factor |

1115 | @param ky vertical skew factor |

1116 | */ |

1117 | SkMatrix& postSkew(SkScalar kx, SkScalar ky); |

1118 | |

1119 | /** Sets SkMatrix to SkMatrix other multiplied by SkMatrix. |

1120 | This can be thought of mapping by other after applying SkMatrix. |

1121 | |

1122 | Given: |

1123 | |

1124 | | J K L | | A B C | |

1125 | Matrix = | M N O |, other = | D E F | |

1126 | | P Q R | | G H I | |

1127 | |

1128 | sets SkMatrix to: |

1129 | |

1130 | | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | |

1131 | other * Matrix = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | |

1132 | | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | |

1133 | |

1134 | @param other SkMatrix on left side of multiply expression |

1135 | */ |

1136 | SkMatrix& postConcat(const SkMatrix& other); |

1137 | |

1138 | #ifndef SK_SUPPORT_LEGACY_MATRIX_RECTTORECT |

1139 | private: |

1140 | #endif |

1141 | /** Sets SkMatrix to scale and translate src SkRect to dst SkRect. stf selects whether |

1142 | mapping completely fills dst or preserves the aspect ratio, and how to align |

1143 | src within dst. Returns false if src is empty, and sets SkMatrix to identity. |

1144 | Returns true if dst is empty, and sets SkMatrix to: |

1145 | |

1146 | | 0 0 0 | |

1147 | | 0 0 0 | |

1148 | | 0 0 1 | |

1149 | |

1150 | @param src SkRect to map from |

1151 | @param dst SkRect to map to |

1152 | @return true if SkMatrix can represent SkRect mapping |

1153 | |

1154 | example: https://fiddle.skia.org/c/@Matrix_setRectToRect |

1155 | */ |

1156 | bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf); |

1157 | |

1158 | /** Returns SkMatrix set to scale and translate src SkRect to dst SkRect. stf selects |

1159 | whether mapping completely fills dst or preserves the aspect ratio, and how to |

1160 | align src within dst. Returns the identity SkMatrix if src is empty. If dst is |

1161 | empty, returns SkMatrix set to: |

1162 | |

1163 | | 0 0 0 | |

1164 | | 0 0 0 | |

1165 | | 0 0 1 | |

1166 | |

1167 | @param src SkRect to map from |

1168 | @param dst SkRect to map to |

1169 | @return SkMatrix mapping src to dst |

1170 | */ |

1171 | static SkMatrix MakeRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf) { |

1172 | SkMatrix m; |

1173 | m.setRectToRect(src, dst, stf); |

1174 | return m; |

1175 | } |

1176 | #ifndef SK_SUPPORT_LEGACY_MATRIX_RECTTORECT |

1177 | public: |

1178 | #endif |

1179 | |

1180 | /** Sets SkMatrix to map src to dst. count must be zero or greater, and four or less. |

1181 | |

1182 | If count is zero, sets SkMatrix to identity and returns true. |

1183 | If count is one, sets SkMatrix to translate and returns true. |

1184 | If count is two or more, sets SkMatrix to map SkPoint if possible; returns false |

1185 | if SkMatrix cannot be constructed. If count is four, SkMatrix may include |

1186 | perspective. |

1187 | |

1188 | @param src SkPoint to map from |

1189 | @param dst SkPoint to map to |

1190 | @param count number of SkPoint in src and dst |

1191 | @return true if SkMatrix was constructed successfully |

1192 | |

1193 | example: https://fiddle.skia.org/c/@Matrix_setPolyToPoly |

1194 | */ |

1195 | bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count); |

1196 | |

1197 | /** Sets inverse to reciprocal matrix, returning true if SkMatrix can be inverted. |

1198 | Geometrically, if SkMatrix maps from source to destination, inverse SkMatrix |

1199 | maps from destination to source. If SkMatrix can not be inverted, inverse is |

1200 | unchanged. |

1201 | |

1202 | @param inverse storage for inverted SkMatrix; may be nullptr |

1203 | @return true if SkMatrix can be inverted |

1204 | */ |

1205 | [[nodiscard]] bool invert(SkMatrix* inverse) const { |

1206 | // Allow the trivial case to be inlined. |

1207 | if (this->isIdentity()) { |

1208 | if (inverse) { |

1209 | inverse->reset(); |

1210 | } |

1211 | return true; |

1212 | } |

1213 | return this->invertNonIdentity(inverse); |

1214 | } |

1215 | |

1216 | /** Fills affine with identity values in column major order. |

1217 | Sets affine to: |

1218 | |

1219 | | 1 0 0 | |

1220 | | 0 1 0 | |

1221 | |

1222 | Affine 3 by 2 matrices in column major order are used by OpenGL and XPS. |

1223 | |

1224 | @param affine storage for 3 by 2 affine matrix |

1225 | |

1226 | example: https://fiddle.skia.org/c/@Matrix_SetAffineIdentity |

1227 | */ |

1228 | static void SetAffineIdentity(SkScalar affine[6]); |

1229 | |

1230 | /** Fills affine in column major order. Sets affine to: |

1231 | |

1232 | | scale-x skew-x translate-x | |

1233 | | skew-y scale-y translate-y | |

1234 | |

1235 | If SkMatrix contains perspective, returns false and leaves affine unchanged. |

1236 | |

1237 | @param affine storage for 3 by 2 affine matrix; may be nullptr |

1238 | @return true if SkMatrix does not contain perspective |

1239 | */ |

1240 | [[nodiscard]] bool asAffine(SkScalar affine[6]) const; |

1241 | |

1242 | /** Sets SkMatrix to affine values, passed in column major order. Given affine, |

1243 | column, then row, as: |

1244 | |

1245 | | scale-x skew-x translate-x | |

1246 | | skew-y scale-y translate-y | |

1247 | |

1248 | SkMatrix is set, row, then column, to: |

1249 | |

1250 | | scale-x skew-x translate-x | |

1251 | | skew-y scale-y translate-y | |

1252 | | 0 0 1 | |

1253 | |

1254 | @param affine 3 by 2 affine matrix |

1255 | */ |

1256 | SkMatrix& setAffine(const SkScalar affine[6]); |

1257 | |

1258 | /** |

1259 | * A matrix is categorized as 'perspective' if the bottom row is not [0, 0, 1]. |

1260 | * However, for most uses (e.g. mapPoints) a bottom row of [0, 0, X] behaves like a |

1261 | * non-perspective matrix, though it will be categorized as perspective. Calling |

1262 | * normalizePerspective() will change the matrix such that, if its bottom row was [0, 0, X], |

1263 | * it will be changed to [0, 0, 1] by scaling the rest of the matrix by 1/X. |

1264 | * |

1265 | * | A B C | | A/X B/X C/X | |

1266 | * | D E F | -> | D/X E/X F/X | for X != 0 |

1267 | * | 0 0 X | | 0 0 1 | |

1268 | */ |

1269 | void normalizePerspective() { |

1270 | if (fMat[8] != 1) { |

1271 | this->doNormalizePerspective(); |

1272 | } |

1273 | } |

1274 | |

1275 | /** Maps src SkPoint array of length count to dst SkPoint array of equal or greater |

1276 | length. SkPoint are mapped by multiplying each SkPoint by SkMatrix. Given: |

1277 | |

1278 | | A B C | | x | |

1279 | Matrix = | D E F |, pt = | y | |

1280 | | G H I | | 1 | |

1281 | |

1282 | where |

1283 | |

1284 | for (i = 0; i < count; ++i) { |

1285 | x = src[i].fX |

1286 | y = src[i].fY |

1287 | } |

1288 | |

1289 | each dst SkPoint is computed as: |

1290 | |

1291 | |A B C| |x| Ax+By+C Dx+Ey+F |

1292 | Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- |

1293 | |G H I| |1| Gx+Hy+I Gx+Hy+I |

1294 | |

1295 | src and dst may point to the same storage. |

1296 | |

1297 | @param dst storage for mapped SkPoint |

1298 | @param src SkPoint to transform |

1299 | @param count number of SkPoint to transform |

1300 | |

1301 | example: https://fiddle.skia.org/c/@Matrix_mapPoints |

1302 | */ |

1303 | void mapPoints(SkPoint dst[], const SkPoint src[], int count) const; |

1304 | |

1305 | /** Maps pts SkPoint array of length count in place. SkPoint are mapped by multiplying |

1306 | each SkPoint by SkMatrix. Given: |

1307 | |

1308 | | A B C | | x | |

1309 | Matrix = | D E F |, pt = | y | |

1310 | | G H I | | 1 | |

1311 | |

1312 | where |

1313 | |

1314 | for (i = 0; i < count; ++i) { |

1315 | x = pts[i].fX |

1316 | y = pts[i].fY |

1317 | } |

1318 | |

1319 | each resulting pts SkPoint is computed as: |

1320 | |

1321 | |A B C| |x| Ax+By+C Dx+Ey+F |

1322 | Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- |

1323 | |G H I| |1| Gx+Hy+I Gx+Hy+I |

1324 | |

1325 | @param pts storage for mapped SkPoint |

1326 | @param count number of SkPoint to transform |

1327 | */ |

1328 | void mapPoints(SkPoint pts[], int count) const { |

1329 | this->mapPoints(dst: pts, src: pts, count); |

1330 | } |

1331 | |

1332 | /** Maps src SkPoint3 array of length count to dst SkPoint3 array, which must of length count or |

1333 | greater. SkPoint3 array is mapped by multiplying each SkPoint3 by SkMatrix. Given: |

1334 | |

1335 | | A B C | | x | |

1336 | Matrix = | D E F |, src = | y | |

1337 | | G H I | | z | |

1338 | |

1339 | each resulting dst SkPoint is computed as: |

1340 | |

1341 | |A B C| |x| |

1342 | Matrix * src = |D E F| |y| = |Ax+By+Cz Dx+Ey+Fz Gx+Hy+Iz| |

1343 | |G H I| |z| |

1344 | |

1345 | @param dst storage for mapped SkPoint3 array |

1346 | @param src SkPoint3 array to transform |

1347 | @param count items in SkPoint3 array to transform |

1348 | |

1349 | example: https://fiddle.skia.org/c/@Matrix_mapHomogeneousPoints |

1350 | */ |

1351 | void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const; |

1352 | |

1353 | /** |

1354 | * Returns homogeneous points, starting with 2D src points (with implied w = 1). |

1355 | */ |

1356 | void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint src[], int count) const; |

1357 | |

1358 | /** Returns SkPoint pt multiplied by SkMatrix. Given: |

1359 | |

1360 | | A B C | | x | |

1361 | Matrix = | D E F |, pt = | y | |

1362 | | G H I | | 1 | |

1363 | |

1364 | result is computed as: |

1365 | |

1366 | |A B C| |x| Ax+By+C Dx+Ey+F |

1367 | Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- |

1368 | |G H I| |1| Gx+Hy+I Gx+Hy+I |

1369 | |

1370 | @param p SkPoint to map |

1371 | @return mapped SkPoint |

1372 | */ |

1373 | SkPoint mapPoint(SkPoint pt) const { |

1374 | SkPoint result; |

1375 | this->mapXY(x: pt.x(), y: pt.y(), result: &result); |

1376 | return result; |

1377 | } |

1378 | |

1379 | /** Maps SkPoint (x, y) to result. SkPoint is mapped by multiplying by SkMatrix. Given: |

1380 | |

1381 | | A B C | | x | |

1382 | Matrix = | D E F |, pt = | y | |

1383 | | G H I | | 1 | |

1384 | |

1385 | result is computed as: |

1386 | |

1387 | |A B C| |x| Ax+By+C Dx+Ey+F |

1388 | Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- |

1389 | |G H I| |1| Gx+Hy+I Gx+Hy+I |

1390 | |

1391 | @param x x-axis value of SkPoint to map |

1392 | @param y y-axis value of SkPoint to map |

1393 | @param result storage for mapped SkPoint |

1394 | |

1395 | example: https://fiddle.skia.org/c/@Matrix_mapXY |

1396 | */ |

1397 | void mapXY(SkScalar x, SkScalar y, SkPoint* result) const; |

1398 | |

1399 | /** Returns SkPoint (x, y) multiplied by SkMatrix. Given: |

1400 | |

1401 | | A B C | | x | |

1402 | Matrix = | D E F |, pt = | y | |

1403 | | G H I | | 1 | |

1404 | |

1405 | result is computed as: |

1406 | |

1407 | |A B C| |x| Ax+By+C Dx+Ey+F |

1408 | Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- |

1409 | |G H I| |1| Gx+Hy+I Gx+Hy+I |

1410 | |

1411 | @param x x-axis value of SkPoint to map |

1412 | @param y y-axis value of SkPoint to map |

1413 | @return mapped SkPoint |

1414 | */ |

1415 | SkPoint mapXY(SkScalar x, SkScalar y) const { |

1416 | SkPoint result; |

1417 | this->mapXY(x,y, result: &result); |

1418 | return result; |

1419 | } |

1420 | |

1421 | |

1422 | /** Returns (0, 0) multiplied by SkMatrix. Given: |

1423 | |

1424 | | A B C | | 0 | |

1425 | Matrix = | D E F |, pt = | 0 | |

1426 | | G H I | | 1 | |

1427 | |

1428 | result is computed as: |

1429 | |

1430 | |A B C| |0| C F |

1431 | Matrix * pt = |D E F| |0| = |C F I| = - , - |

1432 | |G H I| |1| I I |

1433 | |

1434 | @return mapped (0, 0) |

1435 | */ |

1436 | SkPoint mapOrigin() const { |

1437 | SkScalar x = this->getTranslateX(), |

1438 | y = this->getTranslateY(); |

1439 | if (this->hasPerspective()) { |

1440 | SkScalar w = fMat[kMPersp2]; |

1441 | if (w) { w = 1 / w; } |

1442 | x *= w; |

1443 | y *= w; |

1444 | } |

1445 | return {.fX: x, .fY: y}; |

1446 | } |

1447 | |

1448 | /** Maps src vector array of length count to vector SkPoint array of equal or greater |

1449 | length. Vectors are mapped by multiplying each vector by SkMatrix, treating |

1450 | SkMatrix translation as zero. Given: |

1451 | |

1452 | | A B 0 | | x | |

1453 | Matrix = | D E 0 |, src = | y | |

1454 | | G H I | | 1 | |

1455 | |

1456 | where |

1457 | |

1458 | for (i = 0; i < count; ++i) { |

1459 | x = src[i].fX |

1460 | y = src[i].fY |

1461 | } |

1462 | |

1463 | each dst vector is computed as: |

1464 | |

1465 | |A B 0| |x| Ax+By Dx+Ey |

1466 | Matrix * src = |D E 0| |y| = |Ax+By Dx+Ey Gx+Hy+I| = ------- , ------- |

1467 | |G H I| |1| Gx+Hy+I Gx+Hy+I |

1468 | |

1469 | src and dst may point to the same storage. |

1470 | |

1471 | @param dst storage for mapped vectors |

1472 | @param src vectors to transform |

1473 | @param count number of vectors to transform |

1474 | |

1475 | example: https://fiddle.skia.org/c/@Matrix_mapVectors |

1476 | */ |

1477 | void mapVectors(SkVector dst[], const SkVector src[], int count) const; |

1478 | |

1479 | /** Maps vecs vector array of length count in place, multiplying each vector by |

1480 | SkMatrix, treating SkMatrix translation as zero. Given: |

1481 | |

1482 | | A B 0 | | x | |

1483 | Matrix = | D E 0 |, vec = | y | |

1484 | | G H I | | 1 | |

1485 | |

1486 | where |

1487 | |

1488 | for (i = 0; i < count; ++i) { |

1489 | x = vecs[i].fX |

1490 | y = vecs[i].fY |

1491 | } |

1492 | |

1493 | each result vector is computed as: |

1494 | |

1495 | |A B 0| |x| Ax+By Dx+Ey |

1496 | Matrix * vec = |D E 0| |y| = |Ax+By Dx+Ey Gx+Hy+I| = ------- , ------- |

1497 | |G H I| |1| Gx+Hy+I Gx+Hy+I |

1498 | |

1499 | @param vecs vectors to transform, and storage for mapped vectors |

1500 | @param count number of vectors to transform |

1501 | */ |

1502 | void mapVectors(SkVector vecs[], int count) const { |

1503 | this->mapVectors(dst: vecs, src: vecs, count); |

1504 | } |

1505 | |

1506 | /** Maps vector (dx, dy) to result. Vector is mapped by multiplying by SkMatrix, |

1507 | treating SkMatrix translation as zero. Given: |

1508 | |

1509 | | A B 0 | | dx | |

1510 | Matrix = | D E 0 |, vec = | dy | |

1511 | | G H I | | 1 | |

1512 | |

1513 | each result vector is computed as: |

1514 | |

1515 | |A B 0| |dx| A*dx+B*dy D*dx+E*dy |

1516 | Matrix * vec = |D E 0| |dy| = |A*dx+B*dy D*dx+E*dy G*dx+H*dy+I| = ----------- , ----------- |

1517 | |G H I| | 1| G*dx+H*dy+I G*dx+*dHy+I |

1518 | |

1519 | @param dx x-axis value of vector to map |

1520 | @param dy y-axis value of vector to map |

1521 | @param result storage for mapped vector |

1522 | */ |

1523 | void mapVector(SkScalar dx, SkScalar dy, SkVector* result) const { |

1524 | SkVector vec = { .fX: dx, .fY: dy }; |

1525 | this->mapVectors(dst: result, src: &vec, count: 1); |

1526 | } |

1527 | |

1528 | /** Returns vector (dx, dy) multiplied by SkMatrix, treating SkMatrix translation as zero. |

1529 | Given: |

1530 | |

1531 | | A B 0 | | dx | |

1532 | Matrix = | D E 0 |, vec = | dy | |

1533 | | G H I | | 1 | |

1534 | |

1535 | each result vector is computed as: |

1536 | |

1537 | |A B 0| |dx| A*dx+B*dy D*dx+E*dy |

1538 | Matrix * vec = |D E 0| |dy| = |A*dx+B*dy D*dx+E*dy G*dx+H*dy+I| = ----------- , ----------- |

1539 | |G H I| | 1| G*dx+H*dy+I G*dx+*dHy+I |

1540 | |

1541 | @param dx x-axis value of vector to map |

1542 | @param dy y-axis value of vector to map |

1543 | @return mapped vector |

1544 | */ |

1545 | SkVector mapVector(SkScalar dx, SkScalar dy) const { |

1546 | SkVector vec = { .fX: dx, .fY: dy }; |

1547 | this->mapVectors(dst: &vec, src: &vec, count: 1); |

1548 | return vec; |

1549 | } |

1550 | |

1551 | /** Sets dst to bounds of src corners mapped by SkMatrix. |

1552 | Returns true if mapped corners are dst corners. |

1553 | |

1554 | Returned value is the same as calling rectStaysRect(). |

1555 | |

1556 | @param dst storage for bounds of mapped SkPoint |

1557 | @param src SkRect to map |

1558 | @param pc whether to apply perspective clipping |

1559 | @return true if dst is equivalent to mapped src |

1560 | |

1561 | example: https://fiddle.skia.org/c/@Matrix_mapRect |

1562 | */ |

1563 | bool mapRect(SkRect* dst, const SkRect& src, |

1564 | SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const; |

1565 | |

1566 | /** Sets rect to bounds of rect corners mapped by SkMatrix. |

1567 | Returns true if mapped corners are computed rect corners. |

1568 | |

1569 | Returned value is the same as calling rectStaysRect(). |

1570 | |

1571 | @param rect rectangle to map, and storage for bounds of mapped corners |

1572 | @param pc whether to apply perspective clipping |

1573 | @return true if result is equivalent to mapped rect |

1574 | */ |

1575 | bool mapRect(SkRect* rect, SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const { |

1576 | return this->mapRect(dst: rect, src: *rect, pc); |

1577 | } |

1578 | |

1579 | /** Returns bounds of src corners mapped by SkMatrix. |

1580 | |

1581 | @param src rectangle to map |

1582 | @return mapped bounds |

1583 | */ |

1584 | SkRect mapRect(const SkRect& src, |

1585 | SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const { |

1586 | SkRect dst; |

1587 | (void)this->mapRect(dst: &dst, src, pc); |

1588 | return dst; |

1589 | } |

1590 | |

1591 | /** Maps four corners of rect to dst. SkPoint are mapped by multiplying each |

1592 | rect corner by SkMatrix. rect corner is processed in this order: |

1593 | (rect.fLeft, rect.fTop), (rect.fRight, rect.fTop), (rect.fRight, rect.fBottom), |

1594 | (rect.fLeft, rect.fBottom). |

1595 | |

1596 | rect may be empty: rect.fLeft may be greater than or equal to rect.fRight; |

1597 | rect.fTop may be greater than or equal to rect.fBottom. |

1598 | |

1599 | Given: |

1600 | |

1601 | | A B C | | x | |

1602 | Matrix = | D E F |, pt = | y | |

1603 | | G H I | | 1 | |

1604 | |

1605 | where pt is initialized from each of (rect.fLeft, rect.fTop), |

1606 | (rect.fRight, rect.fTop), (rect.fRight, rect.fBottom), (rect.fLeft, rect.fBottom), |

1607 | each dst SkPoint is computed as: |

1608 | |

1609 | |A B C| |x| Ax+By+C Dx+Ey+F |

1610 | Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- |

1611 | |G H I| |1| Gx+Hy+I Gx+Hy+I |

1612 | |

1613 | @param dst storage for mapped corner SkPoint |

1614 | @param rect SkRect to map |

1615 | |

1616 | Note: this does not perform perspective clipping (as that might result in more than |

1617 | 4 points, so results are suspect if the matrix contains perspective. |

1618 | */ |

1619 | void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const { |

1620 | // This could potentially be faster if we only transformed each x and y of the rect once. |

1621 | rect.toQuad(quad: dst); |

1622 | this->mapPoints(pts: dst, count: 4); |

1623 | } |

1624 | |

1625 | /** Sets dst to bounds of src corners mapped by SkMatrix. If matrix contains |

1626 | elements other than scale or translate: asserts if SK_DEBUG is defined; |

1627 | otherwise, results are undefined. |

1628 | |

1629 | @param dst storage for bounds of mapped SkPoint |

1630 | @param src SkRect to map |

1631 | |

1632 | example: https://fiddle.skia.org/c/@Matrix_mapRectScaleTranslate |

1633 | */ |

1634 | void mapRectScaleTranslate(SkRect* dst, const SkRect& src) const; |

1635 | |

1636 | /** Returns geometric mean radius of ellipse formed by constructing circle of |

1637 | size radius, and mapping constructed circle with SkMatrix. The result squared is |

1638 | equal to the major axis length times the minor axis length. |

1639 | Result is not meaningful if SkMatrix contains perspective elements. |

1640 | |

1641 | @param radius circle size to map |

1642 | @return average mapped radius |

1643 | |

1644 | example: https://fiddle.skia.org/c/@Matrix_mapRadius |

1645 | */ |

1646 | SkScalar mapRadius(SkScalar radius) const; |

1647 | |

1648 | /** Compares a and b; returns true if a and b are numerically equal. Returns true |

1649 | even if sign of zero values are different. Returns false if either SkMatrix |

1650 | contains NaN, even if the other SkMatrix also contains NaN. |

1651 | |

1652 | @param a SkMatrix to compare |

1653 | @param b SkMatrix to compare |

1654 | @return true if SkMatrix a and SkMatrix b are numerically equal |

1655 | */ |

1656 | friend SK_API bool operator==(const SkMatrix& a, const SkMatrix& b); |

1657 | |

1658 | /** Compares a and b; returns true if a and b are not numerically equal. Returns false |

1659 | even if sign of zero values are different. Returns true if either SkMatrix |

1660 | contains NaN, even if the other SkMatrix also contains NaN. |

1661 | |

1662 | @param a SkMatrix to compare |

1663 | @param b SkMatrix to compare |

1664 | @return true if SkMatrix a and SkMatrix b are numerically not equal |

1665 | */ |

1666 | friend SK_API bool operator!=(const SkMatrix& a, const SkMatrix& b) { |

1667 | return !(a == b); |

1668 | } |

1669 | |

1670 | /** Writes text representation of SkMatrix to standard output. Floating point values |

1671 | are written with limited precision; it may not be possible to reconstruct |

1672 | original SkMatrix from output. |

1673 | |

1674 | example: https://fiddle.skia.org/c/@Matrix_dump |

1675 | */ |

1676 | void dump() const; |

1677 | |

1678 | /** Returns the minimum scaling factor of SkMatrix by decomposing the scaling and |

1679 | skewing elements. |

1680 | Returns -1 if scale factor overflows or SkMatrix contains perspective. |

1681 | |

1682 | @return minimum scale factor |

1683 | |

1684 | example: https://fiddle.skia.org/c/@Matrix_getMinScale |

1685 | */ |

1686 | SkScalar getMinScale() const; |

1687 | |

1688 | /** Returns the maximum scaling factor of SkMatrix by decomposing the scaling and |

1689 | skewing elements. |

1690 | Returns -1 if scale factor overflows or SkMatrix contains perspective. |

1691 | |

1692 | @return maximum scale factor |

1693 | |

1694 | example: https://fiddle.skia.org/c/@Matrix_getMaxScale |

1695 | */ |

1696 | SkScalar getMaxScale() const; |

1697 | |

1698 | /** Sets scaleFactors[0] to the minimum scaling factor, and scaleFactors[1] to the |

1699 | maximum scaling factor. Scaling factors are computed by decomposing |

1700 | the SkMatrix scaling and skewing elements. |

1701 | |

1702 | Returns true if scaleFactors are found; otherwise, returns false and sets |

1703 | scaleFactors to undefined values. |

1704 | |

1705 | @param scaleFactors storage for minimum and maximum scale factors |

1706 | @return true if scale factors were computed correctly |

1707 | */ |

1708 | [[nodiscard]] bool getMinMaxScales(SkScalar scaleFactors[2]) const; |

1709 | |

1710 | /** Decomposes SkMatrix into scale components and whatever remains. Returns false if |

1711 | SkMatrix could not be decomposed. |

1712 | |

1713 | Sets scale to portion of SkMatrix that scale axes. Sets remaining to SkMatrix |

1714 | with scaling factored out. remaining may be passed as nullptr |

1715 | to determine if SkMatrix can be decomposed without computing remainder. |

1716 | |

1717 | Returns true if scale components are found. scale and remaining are |

1718 | unchanged if SkMatrix contains perspective; scale factors are not finite, or |

1719 | are nearly zero. |

1720 | |

1721 | On success: Matrix = Remaining * scale. |

1722 | |

1723 | @param scale axes scaling factors; may be nullptr |

1724 | @param remaining SkMatrix without scaling; may be nullptr |

1725 | @return true if scale can be computed |

1726 | |

1727 | example: https://fiddle.skia.org/c/@Matrix_decomposeScale |

1728 | */ |

1729 | bool decomposeScale(SkSize* scale, SkMatrix* remaining = nullptr) const; |

1730 | |

1731 | /** Returns reference to const identity SkMatrix. Returned SkMatrix is set to: |

1732 | |

1733 | | 1 0 0 | |

1734 | | 0 1 0 | |

1735 | | 0 0 1 | |

1736 | |

1737 | @return const identity SkMatrix |

1738 | |

1739 | example: https://fiddle.skia.org/c/@Matrix_I |

1740 | */ |

1741 | static const SkMatrix& I(); |

1742 | |

1743 | /** Returns reference to a const SkMatrix with invalid values. Returned SkMatrix is set |

1744 | to: |

1745 | |

1746 | | SK_ScalarMax SK_ScalarMax SK_ScalarMax | |

1747 | | SK_ScalarMax SK_ScalarMax SK_ScalarMax | |

1748 | | SK_ScalarMax SK_ScalarMax SK_ScalarMax | |

1749 | |

1750 | @return const invalid SkMatrix |

1751 | |

1752 | example: https://fiddle.skia.org/c/@Matrix_InvalidMatrix |

1753 | */ |

1754 | static const SkMatrix& InvalidMatrix(); |

1755 | |

1756 | /** Returns SkMatrix a multiplied by SkMatrix b. |

1757 | |

1758 | Given: |

1759 | |

1760 | | A B C | | J K L | |

1761 | a = | D E F |, b = | M N O | |

1762 | | G H I | | P Q R | |

1763 | |

1764 | sets SkMatrix to: |

1765 | |

1766 | | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | |

1767 | a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | |

1768 | | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | |

1769 | |

1770 | @param a SkMatrix on left side of multiply expression |

1771 | @param b SkMatrix on right side of multiply expression |

1772 | @return SkMatrix computed from a times b |

1773 | */ |

1774 | static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) { |

1775 | SkMatrix result; |

1776 | result.setConcat(a, b); |

1777 | return result; |

1778 | } |

1779 | |

1780 | friend SkMatrix operator*(const SkMatrix& a, const SkMatrix& b) { |

1781 | return Concat(a, b); |

1782 | } |

1783 | |

1784 | /** Sets internal cache to unknown state. Use to force update after repeated |

1785 | modifications to SkMatrix element reference returned by operator[](int index). |

1786 | */ |

1787 | void dirtyMatrixTypeCache() { |

1788 | this->setTypeMask(kUnknown_Mask); |

1789 | } |

1790 | |

1791 | /** Initializes SkMatrix with scale and translate elements. |

1792 | |

1793 | | sx 0 tx | |

1794 | | 0 sy ty | |

1795 | | 0 0 1 | |

1796 | |

1797 | @param sx horizontal scale factor to store |

1798 | @param sy vertical scale factor to store |

1799 | @param tx horizontal translation to store |

1800 | @param ty vertical translation to store |

1801 | */ |

1802 | void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) { |

1803 | fMat[kMScaleX] = sx; |

1804 | fMat[kMSkewX] = 0; |

1805 | fMat[kMTransX] = tx; |

1806 | |

1807 | fMat[kMSkewY] = 0; |

1808 | fMat[kMScaleY] = sy; |

1809 | fMat[kMTransY] = ty; |

1810 | |

1811 | fMat[kMPersp0] = 0; |

1812 | fMat[kMPersp1] = 0; |

1813 | fMat[kMPersp2] = 1; |

1814 | |

1815 | int mask = 0; |

1816 | if (sx != 1 || sy != 1) { |

1817 | mask |= kScale_Mask; |

1818 | } |

1819 | if (tx != 0.0f || ty != 0.0f) { |

1820 | mask |= kTranslate_Mask; |

1821 | } |

1822 | if (sx != 0 && sy != 0) { |

1823 | mask |= kRectStaysRect_Mask; |

1824 | } |

1825 | this->setTypeMask(mask); |

1826 | } |

1827 | |

1828 | /** Returns true if all elements of the matrix are finite. Returns false if any |

1829 | element is infinity, or NaN. |

1830 | |

1831 | @return true if matrix has only finite elements |

1832 | */ |

1833 | bool isFinite() const { return SkScalarsAreFinite(array: fMat, count: 9); } |

1834 | |

1835 | private: |

1836 | /** Set if the matrix will map a rectangle to another rectangle. This |

1837 | can be true if the matrix is scale-only, or rotates a multiple of |

1838 | 90 degrees. |

1839 | |

1840 | This bit will be set on identity matrices |

1841 | */ |

1842 | static constexpr int kRectStaysRect_Mask = 0x10; |

1843 | |

1844 | /** Set if the perspective bit is valid even though the rest of |

1845 | the matrix is Unknown. |

1846 | */ |

1847 | static constexpr int kOnlyPerspectiveValid_Mask = 0x40; |

1848 | |

1849 | static constexpr int kUnknown_Mask = 0x80; |

1850 | |

1851 | static constexpr int kORableMasks = kTranslate_Mask | |

1852 | kScale_Mask | |

1853 | kAffine_Mask | |

1854 | kPerspective_Mask; |

1855 | |

1856 | static constexpr int kAllMasks = kTranslate_Mask | |

1857 | kScale_Mask | |

1858 | kAffine_Mask | |

1859 | kPerspective_Mask | |

1860 | kRectStaysRect_Mask; |

1861 | |

1862 | SkScalar fMat[9]; |

1863 | mutable int32_t fTypeMask; |

1864 | |

1865 | constexpr SkMatrix(SkScalar sx, SkScalar kx, SkScalar tx, |

1866 | SkScalar ky, SkScalar sy, SkScalar ty, |

1867 | SkScalar p0, SkScalar p1, SkScalar p2, int typeMask) |

1868 | : fMat{sx, kx, tx, |

1869 | ky, sy, ty, |

1870 | p0, p1, p2} |

1871 | , fTypeMask(typeMask) {} |

1872 | |

1873 | static void ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp); |

1874 | |

1875 | uint8_t computeTypeMask() const; |

1876 | uint8_t computePerspectiveTypeMask() const; |

1877 | |

1878 | void setTypeMask(int mask) { |

1879 | // allow kUnknown or a valid mask |

1880 | SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask || |

1881 | ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask) |

1882 | == (kUnknown_Mask | kOnlyPerspectiveValid_Mask)); |

1883 | fTypeMask = mask; |

1884 | } |

1885 | |

1886 | void orTypeMask(int mask) { |

1887 | SkASSERT((mask & kORableMasks) == mask); |

1888 | fTypeMask |= mask; |

1889 | } |

1890 | |

1891 | void clearTypeMask(int mask) { |

1892 | // only allow a valid mask |

1893 | SkASSERT((mask & kAllMasks) == mask); |

1894 | fTypeMask &= ~mask; |

1895 | } |

1896 | |

1897 | TypeMask getPerspectiveTypeMaskOnly() const { |

1898 | if ((fTypeMask & kUnknown_Mask) && |

1899 | !(fTypeMask & kOnlyPerspectiveValid_Mask)) { |

1900 | fTypeMask = this->computePerspectiveTypeMask(); |

1901 | } |

1902 | return (TypeMask)(fTypeMask & 0xF); |

1903 | } |

1904 | |

1905 | /** Returns true if we already know that the matrix is identity; |

1906 | false otherwise. |

1907 | */ |

1908 | bool isTriviallyIdentity() const { |

1909 | if (fTypeMask & kUnknown_Mask) { |

1910 | return false; |

1911 | } |

1912 | return ((fTypeMask & 0xF) == 0); |

1913 | } |

1914 | |

1915 | inline void updateTranslateMask() { |

1916 | if ((fMat[kMTransX] != 0) | (fMat[kMTransY] != 0)) { |

1917 | fTypeMask |= kTranslate_Mask; |

1918 | } else { |

1919 | fTypeMask &= ~kTranslate_Mask; |

1920 | } |

1921 | } |

1922 | |

1923 | typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y, |

1924 | SkPoint* result); |

1925 | |

1926 | static MapXYProc GetMapXYProc(TypeMask mask) { |

1927 | SkASSERT((mask & ~kAllMasks) == 0); |

1928 | return gMapXYProcs[mask & kAllMasks]; |

1929 | } |

1930 | |

1931 | MapXYProc getMapXYProc() const { |

1932 | return GetMapXYProc(mask: this->getType()); |

1933 | } |

1934 | |

1935 | typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[], |

1936 | const SkPoint src[], int count); |

1937 | |

1938 | static MapPtsProc GetMapPtsProc(TypeMask mask) { |

1939 | SkASSERT((mask & ~kAllMasks) == 0); |

1940 | return gMapPtsProcs[mask & kAllMasks]; |

1941 | } |

1942 | |

1943 | MapPtsProc getMapPtsProc() const { |

1944 | return GetMapPtsProc(mask: this->getType()); |

1945 | } |

1946 | |

1947 | [[nodiscard]] bool invertNonIdentity(SkMatrix* inverse) const; |

1948 | |

1949 | static bool Poly2Proc(const SkPoint[], SkMatrix*); |

1950 | static bool Poly3Proc(const SkPoint[], SkMatrix*); |

1951 | static bool Poly4Proc(const SkPoint[], SkMatrix*); |

1952 | |

1953 | static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); |

1954 | static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); |

1955 | static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); |

1956 | static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); |

1957 | static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); |

1958 | static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); |

1959 | static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); |

1960 | |

1961 | static const MapXYProc gMapXYProcs[]; |

1962 | |

1963 | static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int); |

1964 | static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); |

1965 | static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); |

1966 | static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], |

1967 | int count); |

1968 | static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); |

1969 | |

1970 | static void Affine_vpts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); |

1971 | |

1972 | static const MapPtsProc gMapPtsProcs[]; |

1973 | |

1974 | // return the number of bytes written, whether or not buffer is null |

1975 | size_t writeToMemory(void* buffer) const; |

1976 | /** |

1977 | * Reads data from the buffer parameter |

1978 | * |

1979 | * @param buffer Memory to read from |

1980 | * @param length Amount of memory available in the buffer |

1981 | * @return number of bytes read (must be a multiple of 4) or |

1982 | * 0 if there was not enough memory available |

1983 | */ |

1984 | size_t readFromMemory(const void* buffer, size_t length); |

1985 | |

1986 | // legacy method -- still needed? why not just postScale(1/divx, ...)? |

1987 | bool postIDiv(int divx, int divy); |

1988 | void doNormalizePerspective(); |

1989 | |

1990 | friend class SkPerspIter; |

1991 | friend class SkMatrixPriv; |

1992 | friend class SerializationTest; |

1993 | }; |

1994 | SK_END_REQUIRE_DENSE |

1995 | |

1996 | #endif |

1997 |