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 SkRect_DEFINED |

9 | #define SkRect_DEFINED |

10 | |

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

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

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

14 | #include "include/private/base/SkFloatingPoint.h" |

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

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

17 | |

18 | #include <algorithm> |

19 | #include <cmath> |

20 | #include <cstdint> |

21 | #include <string> |

22 | |

23 | struct SkRect; |

24 | |

25 | /** \struct SkIRect |

26 | SkIRect holds four 32-bit integer coordinates describing the upper and |

27 | lower bounds of a rectangle. SkIRect may be created from outer bounds or |

28 | from position, width, and height. SkIRect describes an area; if its right |

29 | is less than or equal to its left, or if its bottom is less than or equal to |

30 | its top, it is considered empty. |

31 | */ |

32 | struct SK_API SkIRect { |

33 | int32_t fLeft = 0; //!< smaller x-axis bounds |

34 | int32_t fTop = 0; //!< smaller y-axis bounds |

35 | int32_t fRight = 0; //!< larger x-axis bounds |

36 | int32_t fBottom = 0; //!< larger y-axis bounds |

37 | |

38 | /** Returns constructed SkIRect set to (0, 0, 0, 0). |

39 | Many other rectangles are empty; if left is equal to or greater than right, |

40 | or if top is equal to or greater than bottom. Setting all members to zero |

41 | is a convenience, but does not designate a special empty rectangle. |

42 | |

43 | @return bounds (0, 0, 0, 0) |

44 | */ |

45 | [[nodiscard]] static constexpr SkIRect MakeEmpty() { |

46 | return SkIRect{.fLeft: 0, .fTop: 0, .fRight: 0, .fBottom: 0}; |

47 | } |

48 | |

49 | /** Returns constructed SkIRect set to (0, 0, w, h). Does not validate input; w or h |

50 | may be negative. |

51 | |

52 | @param w width of constructed SkIRect |

53 | @param h height of constructed SkIRect |

54 | @return bounds (0, 0, w, h) |

55 | */ |

56 | [[nodiscard]] static constexpr SkIRect MakeWH(int32_t w, int32_t h) { |

57 | return SkIRect{.fLeft: 0, .fTop: 0, .fRight: w, .fBottom: h}; |

58 | } |

59 | |

60 | /** Returns constructed SkIRect set to (0, 0, size.width(), size.height()). |

61 | Does not validate input; size.width() or size.height() may be negative. |

62 | |

63 | @param size values for SkIRect width and height |

64 | @return bounds (0, 0, size.width(), size.height()) |

65 | */ |

66 | [[nodiscard]] static constexpr SkIRect MakeSize(const SkISize& size) { |

67 | return SkIRect{.fLeft: 0, .fTop: 0, .fRight: size.fWidth, .fBottom: size.fHeight}; |

68 | } |

69 | |

70 | /** Returns constructed SkIRect set to (pt.x(), pt.y(), pt.x() + size.width(), |

71 | pt.y() + size.height()). Does not validate input; size.width() or size.height() may be |

72 | negative. |

73 | |

74 | @param pt values for SkIRect fLeft and fTop |

75 | @param size values for SkIRect width and height |

76 | @return bounds at pt with width and height of size |

77 | */ |

78 | [[nodiscard]] static constexpr SkIRect MakePtSize(SkIPoint pt, SkISize size) { |

79 | return MakeXYWH(x: pt.x(), y: pt.y(), w: size.width(), h: size.height()); |

80 | } |

81 | |

82 | /** Returns constructed SkIRect set to (l, t, r, b). Does not sort input; SkIRect may |

83 | result in fLeft greater than fRight, or fTop greater than fBottom. |

84 | |

85 | @param l integer stored in fLeft |

86 | @param t integer stored in fTop |

87 | @param r integer stored in fRight |

88 | @param b integer stored in fBottom |

89 | @return bounds (l, t, r, b) |

90 | */ |

91 | [[nodiscard]] static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) { |

92 | return SkIRect{.fLeft: l, .fTop: t, .fRight: r, .fBottom: b}; |

93 | } |

94 | |

95 | /** Returns constructed SkIRect set to: (x, y, x + w, y + h). |

96 | Does not validate input; w or h may be negative. |

97 | |

98 | @param x stored in fLeft |

99 | @param y stored in fTop |

100 | @param w added to x and stored in fRight |

101 | @param h added to y and stored in fBottom |

102 | @return bounds at (x, y) with width w and height h |

103 | */ |

104 | [[nodiscard]] static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) { |

105 | return { .fLeft: x, .fTop: y, .fRight: Sk32_sat_add(a: x, b: w), .fBottom: Sk32_sat_add(a: y, b: h) }; |

106 | } |

107 | |

108 | /** Returns left edge of SkIRect, if sorted. |

109 | Call sort() to reverse fLeft and fRight if needed. |

110 | |

111 | @return fLeft |

112 | */ |

113 | constexpr int32_t left() const { return fLeft; } |

114 | |

115 | /** Returns top edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, |

116 | and sort() to reverse fTop and fBottom if needed. |

117 | |

118 | @return fTop |

119 | */ |

120 | constexpr int32_t top() const { return fTop; } |

121 | |

122 | /** Returns right edge of SkIRect, if sorted. |

123 | Call sort() to reverse fLeft and fRight if needed. |

124 | |

125 | @return fRight |

126 | */ |

127 | constexpr int32_t right() const { return fRight; } |

128 | |

129 | /** Returns bottom edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, |

130 | and sort() to reverse fTop and fBottom if needed. |

131 | |

132 | @return fBottom |

133 | */ |

134 | constexpr int32_t bottom() const { return fBottom; } |

135 | |

136 | /** Returns left edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, |

137 | and sort() to reverse fLeft and fRight if needed. |

138 | |

139 | @return fLeft |

140 | */ |

141 | constexpr int32_t x() const { return fLeft; } |

142 | |

143 | /** Returns top edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, |

144 | and sort() to reverse fTop and fBottom if needed. |

145 | |

146 | @return fTop |

147 | */ |

148 | constexpr int32_t y() const { return fTop; } |

149 | |

150 | // Experimental |

151 | constexpr SkIPoint topLeft() const { return {.fX: fLeft, .fY: fTop}; } |

152 | |

153 | /** Returns span on the x-axis. This does not check if SkIRect is sorted, or if |

154 | result fits in 32-bit signed integer; result may be negative. |

155 | |

156 | @return fRight minus fLeft |

157 | */ |

158 | constexpr int32_t width() const { return Sk32_can_overflow_sub(a: fRight, b: fLeft); } |

159 | |

160 | /** Returns span on the y-axis. This does not check if SkIRect is sorted, or if |

161 | result fits in 32-bit signed integer; result may be negative. |

162 | |

163 | @return fBottom minus fTop |

164 | */ |

165 | constexpr int32_t height() const { return Sk32_can_overflow_sub(a: fBottom, b: fTop); } |

166 | |

167 | /** Returns spans on the x-axis and y-axis. This does not check if SkIRect is sorted, |

168 | or if result fits in 32-bit signed integer; result may be negative. |

169 | |

170 | @return SkISize (width, height) |

171 | */ |

172 | constexpr SkISize size() const { return SkISize::Make(w: this->width(), h: this->height()); } |

173 | |

174 | /** Returns span on the x-axis. This does not check if SkIRect is sorted, so the |

175 | result may be negative. This is safer than calling width() since width() might |

176 | overflow in its calculation. |

177 | |

178 | @return fRight minus fLeft cast to int64_t |

179 | */ |

180 | constexpr int64_t width64() const { return (int64_t)fRight - (int64_t)fLeft; } |

181 | |

182 | /** Returns span on the y-axis. This does not check if SkIRect is sorted, so the |

183 | result may be negative. This is safer than calling height() since height() might |

184 | overflow in its calculation. |

185 | |

186 | @return fBottom minus fTop cast to int64_t |

187 | */ |

188 | constexpr int64_t height64() const { return (int64_t)fBottom - (int64_t)fTop; } |

189 | |

190 | /** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal |

191 | to or greater than fBottom. Call sort() to reverse rectangles with negative |

192 | width64() or height64(). |

193 | |

194 | @return true if width64() or height64() are zero or negative |

195 | */ |

196 | bool isEmpty64() const { return fRight <= fLeft || fBottom <= fTop; } |

197 | |

198 | /** Returns true if width() or height() are zero or negative. |

199 | |

200 | @return true if width() or height() are zero or negative |

201 | */ |

202 | bool isEmpty() const { |

203 | int64_t w = this->width64(); |

204 | int64_t h = this->height64(); |

205 | if (w <= 0 || h <= 0) { |

206 | return true; |

207 | } |

208 | // Return true if either exceeds int32_t |

209 | return !SkTFitsIn<int32_t>(src: w | h); |

210 | } |

211 | |

212 | /** Returns true if all members in a: fLeft, fTop, fRight, and fBottom; are |

213 | identical to corresponding members in b. |

214 | |

215 | @param a SkIRect to compare |

216 | @param b SkIRect to compare |

217 | @return true if members are equal |

218 | */ |

219 | friend bool operator==(const SkIRect& a, const SkIRect& b) { |

220 | return a.fLeft == b.fLeft && a.fTop == b.fTop && |

221 | a.fRight == b.fRight && a.fBottom == b.fBottom; |

222 | } |

223 | |

224 | /** Returns true if any member in a: fLeft, fTop, fRight, and fBottom; is not |

225 | identical to the corresponding member in b. |

226 | |

227 | @param a SkIRect to compare |

228 | @param b SkIRect to compare |

229 | @return true if members are not equal |

230 | */ |

231 | friend bool operator!=(const SkIRect& a, const SkIRect& b) { |

232 | return a.fLeft != b.fLeft || a.fTop != b.fTop || |

233 | a.fRight != b.fRight || a.fBottom != b.fBottom; |

234 | } |

235 | |

236 | /** Sets SkIRect to (0, 0, 0, 0). |

237 | |

238 | Many other rectangles are empty; if left is equal to or greater than right, |

239 | or if top is equal to or greater than bottom. Setting all members to zero |

240 | is a convenience, but does not designate a special empty rectangle. |

241 | */ |

242 | void setEmpty() { memset(s: this, c: 0, n: sizeof(*this)); } |

243 | |

244 | /** Sets SkIRect to (left, top, right, bottom). |

245 | left and right are not sorted; left is not necessarily less than right. |

246 | top and bottom are not sorted; top is not necessarily less than bottom. |

247 | |

248 | @param left stored in fLeft |

249 | @param top stored in fTop |

250 | @param right stored in fRight |

251 | @param bottom stored in fBottom |

252 | */ |

253 | void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) { |

254 | fLeft = left; |

255 | fTop = top; |

256 | fRight = right; |

257 | fBottom = bottom; |

258 | } |

259 | |

260 | /** Sets SkIRect to: (x, y, x + width, y + height). |

261 | Does not validate input; width or height may be negative. |

262 | |

263 | @param x stored in fLeft |

264 | @param y stored in fTop |

265 | @param width added to x and stored in fRight |

266 | @param height added to y and stored in fBottom |

267 | */ |

268 | void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) { |

269 | fLeft = x; |

270 | fTop = y; |

271 | fRight = Sk32_sat_add(a: x, b: width); |

272 | fBottom = Sk32_sat_add(a: y, b: height); |

273 | } |

274 | |

275 | void setWH(int32_t width, int32_t height) { |

276 | fLeft = 0; |

277 | fTop = 0; |

278 | fRight = width; |

279 | fBottom = height; |

280 | } |

281 | |

282 | void setSize(SkISize size) { |

283 | fLeft = 0; |

284 | fTop = 0; |

285 | fRight = size.width(); |

286 | fBottom = size.height(); |

287 | } |

288 | |

289 | /** Returns SkIRect offset by (dx, dy). |

290 | |

291 | If dx is negative, SkIRect returned is moved to the left. |

292 | If dx is positive, SkIRect returned is moved to the right. |

293 | If dy is negative, SkIRect returned is moved upward. |

294 | If dy is positive, SkIRect returned is moved downward. |

295 | |

296 | @param dx offset added to fLeft and fRight |

297 | @param dy offset added to fTop and fBottom |

298 | @return SkIRect offset by dx and dy, with original width and height |

299 | */ |

300 | constexpr SkIRect makeOffset(int32_t dx, int32_t dy) const { |

301 | return { |

302 | .fLeft: Sk32_sat_add(a: fLeft, b: dx), .fTop: Sk32_sat_add(a: fTop, b: dy), |

303 | .fRight: Sk32_sat_add(a: fRight, b: dx), .fBottom: Sk32_sat_add(a: fBottom, b: dy), |

304 | }; |

305 | } |

306 | |

307 | /** Returns SkIRect offset by (offset.x(), offset.y()). |

308 | |

309 | If offset.x() is negative, SkIRect returned is moved to the left. |

310 | If offset.x() is positive, SkIRect returned is moved to the right. |

311 | If offset.y() is negative, SkIRect returned is moved upward. |

312 | If offset.y() is positive, SkIRect returned is moved downward. |

313 | |

314 | @param offset translation vector |

315 | @return SkIRect translated by offset, with original width and height |

316 | */ |

317 | constexpr SkIRect makeOffset(SkIVector offset) const { |

318 | return this->makeOffset(dx: offset.x(), dy: offset.y()); |

319 | } |

320 | |

321 | /** Returns SkIRect, inset by (dx, dy). |

322 | |

323 | If dx is negative, SkIRect returned is wider. |

324 | If dx is positive, SkIRect returned is narrower. |

325 | If dy is negative, SkIRect returned is taller. |

326 | If dy is positive, SkIRect returned is shorter. |

327 | |

328 | @param dx offset added to fLeft and subtracted from fRight |

329 | @param dy offset added to fTop and subtracted from fBottom |

330 | @return SkIRect inset symmetrically left and right, top and bottom |

331 | */ |

332 | SkIRect makeInset(int32_t dx, int32_t dy) const { |

333 | return { |

334 | .fLeft: Sk32_sat_add(a: fLeft, b: dx), .fTop: Sk32_sat_add(a: fTop, b: dy), |

335 | .fRight: Sk32_sat_sub(a: fRight, b: dx), .fBottom: Sk32_sat_sub(a: fBottom, b: dy), |

336 | }; |

337 | } |

338 | |

339 | /** Returns SkIRect, outset by (dx, dy). |

340 | |

341 | If dx is negative, SkIRect returned is narrower. |

342 | If dx is positive, SkIRect returned is wider. |

343 | If dy is negative, SkIRect returned is shorter. |

344 | If dy is positive, SkIRect returned is taller. |

345 | |

346 | @param dx offset subtracted to fLeft and added from fRight |

347 | @param dy offset subtracted to fTop and added from fBottom |

348 | @return SkIRect outset symmetrically left and right, top and bottom |

349 | */ |

350 | SkIRect makeOutset(int32_t dx, int32_t dy) const { |

351 | return { |

352 | .fLeft: Sk32_sat_sub(a: fLeft, b: dx), .fTop: Sk32_sat_sub(a: fTop, b: dy), |

353 | .fRight: Sk32_sat_add(a: fRight, b: dx), .fBottom: Sk32_sat_add(a: fBottom, b: dy), |

354 | }; |

355 | } |

356 | |

357 | /** Offsets SkIRect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom. |

358 | |

359 | If dx is negative, moves SkIRect returned to the left. |

360 | If dx is positive, moves SkIRect returned to the right. |

361 | If dy is negative, moves SkIRect returned upward. |

362 | If dy is positive, moves SkIRect returned downward. |

363 | |

364 | @param dx offset added to fLeft and fRight |

365 | @param dy offset added to fTop and fBottom |

366 | */ |

367 | void offset(int32_t dx, int32_t dy) { |

368 | fLeft = Sk32_sat_add(a: fLeft, b: dx); |

369 | fTop = Sk32_sat_add(a: fTop, b: dy); |

370 | fRight = Sk32_sat_add(a: fRight, b: dx); |

371 | fBottom = Sk32_sat_add(a: fBottom, b: dy); |

372 | } |

373 | |

374 | /** Offsets SkIRect by adding delta.fX to fLeft, fRight; and by adding delta.fY to |

375 | fTop, fBottom. |

376 | |

377 | If delta.fX is negative, moves SkIRect returned to the left. |

378 | If delta.fX is positive, moves SkIRect returned to the right. |

379 | If delta.fY is negative, moves SkIRect returned upward. |

380 | If delta.fY is positive, moves SkIRect returned downward. |

381 | |

382 | @param delta offset added to SkIRect |

383 | */ |

384 | void offset(const SkIPoint& delta) { |

385 | this->offset(dx: delta.fX, dy: delta.fY); |

386 | } |

387 | |

388 | /** Offsets SkIRect so that fLeft equals newX, and fTop equals newY. width and height |

389 | are unchanged. |

390 | |

391 | @param newX stored in fLeft, preserving width() |

392 | @param newY stored in fTop, preserving height() |

393 | */ |

394 | void offsetTo(int32_t newX, int32_t newY) { |

395 | fRight = Sk64_pin_to_s32(x: (int64_t)fRight + newX - fLeft); |

396 | fBottom = Sk64_pin_to_s32(x: (int64_t)fBottom + newY - fTop); |

397 | fLeft = newX; |

398 | fTop = newY; |

399 | } |

400 | |

401 | /** Insets SkIRect by (dx,dy). |

402 | |

403 | If dx is positive, makes SkIRect narrower. |

404 | If dx is negative, makes SkIRect wider. |

405 | If dy is positive, makes SkIRect shorter. |

406 | If dy is negative, makes SkIRect taller. |

407 | |

408 | @param dx offset added to fLeft and subtracted from fRight |

409 | @param dy offset added to fTop and subtracted from fBottom |

410 | */ |

411 | void inset(int32_t dx, int32_t dy) { |

412 | fLeft = Sk32_sat_add(a: fLeft, b: dx); |

413 | fTop = Sk32_sat_add(a: fTop, b: dy); |

414 | fRight = Sk32_sat_sub(a: fRight, b: dx); |

415 | fBottom = Sk32_sat_sub(a: fBottom, b: dy); |

416 | } |

417 | |

418 | /** Outsets SkIRect by (dx, dy). |

419 | |

420 | If dx is positive, makes SkIRect wider. |

421 | If dx is negative, makes SkIRect narrower. |

422 | If dy is positive, makes SkIRect taller. |

423 | If dy is negative, makes SkIRect shorter. |

424 | |

425 | @param dx subtracted to fLeft and added from fRight |

426 | @param dy subtracted to fTop and added from fBottom |

427 | */ |

428 | void outset(int32_t dx, int32_t dy) { this->inset(dx: -dx, dy: -dy); } |

429 | |

430 | /** Adjusts SkIRect by adding dL to fLeft, dT to fTop, dR to fRight, and dB to fBottom. |

431 | |

432 | If dL is positive, narrows SkIRect on the left. If negative, widens it on the left. |

433 | If dT is positive, shrinks SkIRect on the top. If negative, lengthens it on the top. |

434 | If dR is positive, narrows SkIRect on the right. If negative, widens it on the right. |

435 | If dB is positive, shrinks SkIRect on the bottom. If negative, lengthens it on the bottom. |

436 | |

437 | The resulting SkIRect is not checked for validity. Thus, if the resulting SkIRect left is |

438 | greater than right, the SkIRect will be considered empty. Call sort() after this call |

439 | if that is not the desired behavior. |

440 | |

441 | @param dL offset added to fLeft |

442 | @param dT offset added to fTop |

443 | @param dR offset added to fRight |

444 | @param dB offset added to fBottom |

445 | */ |

446 | void adjust(int32_t dL, int32_t dT, int32_t dR, int32_t dB) { |

447 | fLeft = Sk32_sat_add(a: fLeft, b: dL); |

448 | fTop = Sk32_sat_add(a: fTop, b: dT); |

449 | fRight = Sk32_sat_add(a: fRight, b: dR); |

450 | fBottom = Sk32_sat_add(a: fBottom, b: dB); |

451 | } |

452 | |

453 | /** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom. |

454 | Returns false if SkIRect is empty. |

455 | |

456 | Considers input to describe constructed SkIRect: (x, y, x + 1, y + 1) and |

457 | returns true if constructed area is completely enclosed by SkIRect area. |

458 | |

459 | @param x test SkIPoint x-coordinate |

460 | @param y test SkIPoint y-coordinate |

461 | @return true if (x, y) is inside SkIRect |

462 | */ |

463 | bool contains(int32_t x, int32_t y) const { |

464 | return x >= fLeft && x < fRight && y >= fTop && y < fBottom; |

465 | } |

466 | |

467 | /** Returns true if SkIRect contains r. |

468 | Returns false if SkIRect is empty or r is empty. |

469 | |

470 | SkIRect contains r when SkIRect area completely includes r area. |

471 | |

472 | @param r SkIRect contained |

473 | @return true if all sides of SkIRect are outside r |

474 | */ |

475 | bool contains(const SkIRect& r) const { |

476 | return !r.isEmpty() && !this->isEmpty() && // check for empties |

477 | fLeft <= r.fLeft && fTop <= r.fTop && |

478 | fRight >= r.fRight && fBottom >= r.fBottom; |

479 | } |

480 | |

481 | /** Returns true if SkIRect contains r. |

482 | Returns false if SkIRect is empty or r is empty. |

483 | |

484 | SkIRect contains r when SkIRect area completely includes r area. |

485 | |

486 | @param r SkRect contained |

487 | @return true if all sides of SkIRect are outside r |

488 | */ |

489 | inline bool contains(const SkRect& r) const; |

490 | |

491 | /** Returns true if SkIRect contains construction. |

492 | Asserts if SkIRect is empty or construction is empty, and if SK_DEBUG is defined. |

493 | |

494 | Return is undefined if SkIRect is empty or construction is empty. |

495 | |

496 | @param r SkIRect contained |

497 | @return true if all sides of SkIRect are outside r |

498 | */ |

499 | bool containsNoEmptyCheck(const SkIRect& r) const { |

500 | SkASSERT(fLeft < fRight && fTop < fBottom); |

501 | SkASSERT(r.fLeft < r.fRight && r.fTop < r.fBottom); |

502 | return fLeft <= r.fLeft && fTop <= r.fTop && fRight >= r.fRight && fBottom >= r.fBottom; |

503 | } |

504 | |

505 | /** Returns true if SkIRect intersects r, and sets SkIRect to intersection. |

506 | Returns false if SkIRect does not intersect r, and leaves SkIRect unchanged. |

507 | |

508 | Returns false if either r or SkIRect is empty, leaving SkIRect unchanged. |

509 | |

510 | @param r limit of result |

511 | @return true if r and SkIRect have area in common |

512 | */ |

513 | bool intersect(const SkIRect& r) { |

514 | return this->intersect(a: *this, b: r); |

515 | } |

516 | |

517 | /** Returns true if a intersects b, and sets SkIRect to intersection. |

518 | Returns false if a does not intersect b, and leaves SkIRect unchanged. |

519 | |

520 | Returns false if either a or b is empty, leaving SkIRect unchanged. |

521 | |

522 | @param a SkIRect to intersect |

523 | @param b SkIRect to intersect |

524 | @return true if a and b have area in common |

525 | */ |

526 | [[nodiscard]] bool intersect(const SkIRect& a, const SkIRect& b); |

527 | |

528 | /** Returns true if a intersects b. |

529 | Returns false if either a or b is empty, or do not intersect. |

530 | |

531 | @param a SkIRect to intersect |

532 | @param b SkIRect to intersect |

533 | @return true if a and b have area in common |

534 | */ |

535 | static bool Intersects(const SkIRect& a, const SkIRect& b) { |

536 | return SkIRect{}.intersect(a, b); |

537 | } |

538 | |

539 | /** Sets SkIRect to the union of itself and r. |

540 | |

541 | Has no effect if r is empty. Otherwise, if SkIRect is empty, sets SkIRect to r. |

542 | |

543 | @param r expansion SkIRect |

544 | |

545 | example: https://fiddle.skia.org/c/@IRect_join_2 |

546 | */ |

547 | void join(const SkIRect& r); |

548 | |

549 | /** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps |

550 | fTop and fBottom if fTop is greater than fBottom. Result may be empty, |

551 | and width() and height() will be zero or positive. |

552 | */ |

553 | void sort() { |

554 | using std::swap; |

555 | if (fLeft > fRight) { |

556 | swap(x&: fLeft, y&: fRight); |

557 | } |

558 | if (fTop > fBottom) { |

559 | swap(x&: fTop, y&: fBottom); |

560 | } |

561 | } |

562 | |

563 | /** Returns SkIRect with fLeft and fRight swapped if fLeft is greater than fRight; and |

564 | with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty; |

565 | and width() and height() will be zero or positive. |

566 | |

567 | @return sorted SkIRect |

568 | */ |

569 | SkIRect makeSorted() const { |

570 | return MakeLTRB(l: std::min(a: fLeft, b: fRight), t: std::min(a: fTop, b: fBottom), |

571 | r: std::max(a: fLeft, b: fRight), b: std::max(a: fTop, b: fBottom)); |

572 | } |

573 | }; |

574 | |

575 | /** \struct SkRect |

576 | SkRect holds four float coordinates describing the upper and |

577 | lower bounds of a rectangle. SkRect may be created from outer bounds or |

578 | from position, width, and height. SkRect describes an area; if its right |

579 | is less than or equal to its left, or if its bottom is less than or equal to |

580 | its top, it is considered empty. |

581 | */ |

582 | struct SK_API SkRect { |

583 | float fLeft = 0; //!< smaller x-axis bounds |

584 | float fTop = 0; //!< smaller y-axis bounds |

585 | float fRight = 0; //!< larger x-axis bounds |

586 | float fBottom = 0; //!< larger y-axis bounds |

587 | |

588 | /** Returns constructed SkRect set to (0, 0, 0, 0). |

589 | Many other rectangles are empty; if left is equal to or greater than right, |

590 | or if top is equal to or greater than bottom. Setting all members to zero |

591 | is a convenience, but does not designate a special empty rectangle. |

592 | |

593 | @return bounds (0, 0, 0, 0) |

594 | */ |

595 | [[nodiscard]] static constexpr SkRect MakeEmpty() { |

596 | return SkRect{.fLeft: 0, .fTop: 0, .fRight: 0, .fBottom: 0}; |

597 | } |

598 | |

599 | /** Returns constructed SkRect set to float values (0, 0, w, h). Does not |

600 | validate input; w or h may be negative. |

601 | |

602 | Passing integer values may generate a compiler warning since SkRect cannot |

603 | represent 32-bit integers exactly. Use SkIRect for an exact integer rectangle. |

604 | |

605 | @param w float width of constructed SkRect |

606 | @param h float height of constructed SkRect |

607 | @return bounds (0, 0, w, h) |

608 | */ |

609 | [[nodiscard]] static constexpr SkRect MakeWH(float w, float h) { |

610 | return SkRect{.fLeft: 0, .fTop: 0, .fRight: w, .fBottom: h}; |

611 | } |

612 | |

613 | /** Returns constructed SkRect set to integer values (0, 0, w, h). Does not validate |

614 | input; w or h may be negative. |

615 | |

616 | Use to avoid a compiler warning that input may lose precision when stored. |

617 | Use SkIRect for an exact integer rectangle. |

618 | |

619 | @param w integer width of constructed SkRect |

620 | @param h integer height of constructed SkRect |

621 | @return bounds (0, 0, w, h) |

622 | */ |

623 | [[nodiscard]] static SkRect MakeIWH(int w, int h) { |

624 | return {.fLeft: 0, .fTop: 0, .fRight: static_cast<float>(w), .fBottom: static_cast<float>(h)}; |

625 | } |

626 | |

627 | /** Returns constructed SkRect set to (0, 0, size.width(), size.height()). Does not |

628 | validate input; size.width() or size.height() may be negative. |

629 | |

630 | @param size float values for SkRect width and height |

631 | @return bounds (0, 0, size.width(), size.height()) |

632 | */ |

633 | [[nodiscard]] static constexpr SkRect MakeSize(const SkSize& size) { |

634 | return SkRect{.fLeft: 0, .fTop: 0, .fRight: size.fWidth, .fBottom: size.fHeight}; |

635 | } |

636 | |

637 | /** Returns constructed SkRect set to (l, t, r, b). Does not sort input; SkRect may |

638 | result in fLeft greater than fRight, or fTop greater than fBottom. |

639 | |

640 | @param l float stored in fLeft |

641 | @param t float stored in fTop |

642 | @param r float stored in fRight |

643 | @param b float stored in fBottom |

644 | @return bounds (l, t, r, b) |

645 | */ |

646 | [[nodiscard]] static constexpr SkRect MakeLTRB(float l, float t, float r, float b) { |

647 | return SkRect {.fLeft: l, .fTop: t, .fRight: r, .fBottom: b}; |

648 | } |

649 | |

650 | /** Returns constructed SkRect set to (x, y, x + w, y + h). |

651 | Does not validate input; w or h may be negative. |

652 | |

653 | @param x stored in fLeft |

654 | @param y stored in fTop |

655 | @param w added to x and stored in fRight |

656 | @param h added to y and stored in fBottom |

657 | @return bounds at (x, y) with width w and height h |

658 | */ |

659 | [[nodiscard]] static constexpr SkRect MakeXYWH(float x, float y, float w, float h) { |

660 | return SkRect {.fLeft: x, .fTop: y, .fRight: x + w, .fBottom: y + h}; |

661 | } |

662 | |

663 | /** Returns constructed SkIRect set to (0, 0, size.width(), size.height()). |

664 | Does not validate input; size.width() or size.height() may be negative. |

665 | |

666 | @param size integer values for SkRect width and height |

667 | @return bounds (0, 0, size.width(), size.height()) |

668 | */ |

669 | static SkRect Make(const SkISize& size) { |

670 | return MakeIWH(w: size.width(), h: size.height()); |

671 | } |

672 | |

673 | /** Returns constructed SkIRect set to irect, promoting integers to float. |

674 | Does not validate input; fLeft may be greater than fRight, fTop may be greater |

675 | than fBottom. |

676 | |

677 | @param irect integer unsorted bounds |

678 | @return irect members converted to float |

679 | */ |

680 | [[nodiscard]] static SkRect Make(const SkIRect& irect) { |

681 | return { |

682 | .fLeft: static_cast<float>(irect.fLeft), .fTop: static_cast<float>(irect.fTop), |

683 | .fRight: static_cast<float>(irect.fRight), .fBottom: static_cast<float>(irect.fBottom) |

684 | }; |

685 | } |

686 | |

687 | /** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal |

688 | to or greater than fBottom. Call sort() to reverse rectangles with negative |

689 | width() or height(). |

690 | |

691 | @return true if width() or height() are zero or negative |

692 | */ |

693 | bool isEmpty() const { |

694 | // We write it as the NOT of a non-empty rect, so we will return true if any values |

695 | // are NaN. |

696 | return !(fLeft < fRight && fTop < fBottom); |

697 | } |

698 | |

699 | /** Returns true if fLeft is equal to or less than fRight, or if fTop is equal |

700 | to or less than fBottom. Call sort() to reverse rectangles with negative |

701 | width() or height(). |

702 | |

703 | @return true if width() or height() are zero or positive |

704 | */ |

705 | bool isSorted() const { return fLeft <= fRight && fTop <= fBottom; } |

706 | |

707 | /** Returns true if all values in the rectangle are finite. |

708 | |

709 | @return true if no member is infinite or NaN |

710 | */ |

711 | bool isFinite() const { |

712 | float accum = 0; |

713 | accum *= fLeft; |

714 | accum *= fTop; |

715 | accum *= fRight; |

716 | accum *= fBottom; |

717 | |

718 | // accum is either NaN or it is finite (zero). |

719 | SkASSERT(0 == accum || std::isnan(accum)); |

720 | |

721 | // value==value will be true iff value is not NaN |

722 | // TODO: is it faster to say !accum or accum==accum? |

723 | return !std::isnan(lcpp_x: accum); |

724 | } |

725 | |

726 | /** Returns left edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. |

727 | Call sort() to reverse fLeft and fRight if needed. |

728 | |

729 | @return fLeft |

730 | */ |

731 | constexpr float x() const { return fLeft; } |

732 | |

733 | /** Returns top edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, |

734 | and sort() to reverse fTop and fBottom if needed. |

735 | |

736 | @return fTop |

737 | */ |

738 | constexpr float y() const { return fTop; } |

739 | |

740 | /** Returns left edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. |

741 | Call sort() to reverse fLeft and fRight if needed. |

742 | |

743 | @return fLeft |

744 | */ |

745 | constexpr float left() const { return fLeft; } |

746 | |

747 | /** Returns top edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, |

748 | and sort() to reverse fTop and fBottom if needed. |

749 | |

750 | @return fTop |

751 | */ |

752 | constexpr float top() const { return fTop; } |

753 | |

754 | /** Returns right edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. |

755 | Call sort() to reverse fLeft and fRight if needed. |

756 | |

757 | @return fRight |

758 | */ |

759 | constexpr float right() const { return fRight; } |

760 | |

761 | /** Returns bottom edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, |

762 | and sort() to reverse fTop and fBottom if needed. |

763 | |

764 | @return fBottom |

765 | */ |

766 | constexpr float bottom() const { return fBottom; } |

767 | |

768 | /** Returns span on the x-axis. This does not check if SkRect is sorted, or if |

769 | result fits in 32-bit float; result may be negative or infinity. |

770 | |

771 | @return fRight minus fLeft |

772 | */ |

773 | constexpr float width() const { return fRight - fLeft; } |

774 | |

775 | /** Returns span on the y-axis. This does not check if SkRect is sorted, or if |

776 | result fits in 32-bit float; result may be negative or infinity. |

777 | |

778 | @return fBottom minus fTop |

779 | */ |

780 | constexpr float height() const { return fBottom - fTop; } |

781 | |

782 | /** Returns average of left edge and right edge. Result does not change if SkRect |

783 | is sorted. Result may overflow to infinity if SkRect is far from the origin. |

784 | |

785 | @return midpoint on x-axis |

786 | */ |

787 | constexpr float centerX() const { |

788 | return sk_float_midpoint(a: fLeft, b: fRight); |

789 | } |

790 | |

791 | /** Returns average of top edge and bottom edge. Result does not change if SkRect |

792 | is sorted. |

793 | |

794 | @return midpoint on y-axis |

795 | */ |

796 | constexpr float centerY() const { |

797 | return sk_float_midpoint(a: fTop, b: fBottom); |

798 | } |

799 | |

800 | /** Returns the point this->centerX(), this->centerY(). |

801 | @return rectangle center |

802 | */ |

803 | constexpr SkPoint center() const { return {.fX: this->centerX(), .fY: this->centerY()}; } |

804 | |

805 | /** Returns true if all members in a: fLeft, fTop, fRight, and fBottom; are |

806 | equal to the corresponding members in b. |

807 | |

808 | a and b are not equal if either contain NaN. a and b are equal if members |

809 | contain zeroes with different signs. |

810 | |

811 | @param a SkRect to compare |

812 | @param b SkRect to compare |

813 | @return true if members are equal |

814 | */ |

815 | friend bool operator==(const SkRect& a, const SkRect& b) { |

816 | return a.fLeft == b.fLeft && |

817 | a.fTop == b.fTop && |

818 | a.fRight == b.fRight && |

819 | a.fBottom == b.fBottom; |

820 | } |

821 | |

822 | /** Returns true if any in a: fLeft, fTop, fRight, and fBottom; does not |

823 | equal the corresponding members in b. |

824 | |

825 | a and b are not equal if either contain NaN. a and b are equal if members |

826 | contain zeroes with different signs. |

827 | |

828 | @param a SkRect to compare |

829 | @param b SkRect to compare |

830 | @return true if members are not equal |

831 | */ |

832 | friend bool operator!=(const SkRect& a, const SkRect& b) { |

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

834 | } |

835 | |

836 | /** Returns four points in quad that enclose SkRect ordered as: top-left, top-right, |

837 | bottom-right, bottom-left. |

838 | |

839 | TODO: Consider adding parameter to control whether quad is clockwise or counterclockwise. |

840 | |

841 | @param quad storage for corners of SkRect |

842 | |

843 | example: https://fiddle.skia.org/c/@Rect_toQuad |

844 | */ |

845 | void toQuad(SkPoint quad[4]) const; |

846 | |

847 | /** Sets SkRect to (0, 0, 0, 0). |

848 | |

849 | Many other rectangles are empty; if left is equal to or greater than right, |

850 | or if top is equal to or greater than bottom. Setting all members to zero |

851 | is a convenience, but does not designate a special empty rectangle. |

852 | */ |

853 | void setEmpty() { *this = MakeEmpty(); } |

854 | |

855 | /** Sets SkRect to src, promoting src members from integer to float. |

856 | Very large values in src may lose precision. |

857 | |

858 | @param src integer SkRect |

859 | */ |

860 | void set(const SkIRect& src) { |

861 | fLeft = src.fLeft; |

862 | fTop = src.fTop; |

863 | fRight = src.fRight; |

864 | fBottom = src.fBottom; |

865 | } |

866 | |

867 | /** Sets SkRect to (left, top, right, bottom). |

868 | left and right are not sorted; left is not necessarily less than right. |

869 | top and bottom are not sorted; top is not necessarily less than bottom. |

870 | |

871 | @param left stored in fLeft |

872 | @param top stored in fTop |

873 | @param right stored in fRight |

874 | @param bottom stored in fBottom |

875 | */ |

876 | void setLTRB(float left, float top, float right, float bottom) { |

877 | fLeft = left; |

878 | fTop = top; |

879 | fRight = right; |

880 | fBottom = bottom; |

881 | } |

882 | |

883 | /** Sets to bounds of SkPoint array with count entries. If count is zero or smaller, |

884 | or if SkPoint array contains an infinity or NaN, sets to (0, 0, 0, 0). |

885 | |

886 | Result is either empty or sorted: fLeft is less than or equal to fRight, and |

887 | fTop is less than or equal to fBottom. |

888 | |

889 | @param pts SkPoint array |

890 | @param count entries in array |

891 | */ |

892 | void setBounds(const SkPoint pts[], int count) { |

893 | (void)this->setBoundsCheck(pts, count); |

894 | } |

895 | |

896 | /** Sets to bounds of SkPoint array with count entries. Returns false if count is |

897 | zero or smaller, or if SkPoint array contains an infinity or NaN; in these cases |

898 | sets SkRect to (0, 0, 0, 0). |

899 | |

900 | Result is either empty or sorted: fLeft is less than or equal to fRight, and |

901 | fTop is less than or equal to fBottom. |

902 | |

903 | @param pts SkPoint array |

904 | @param count entries in array |

905 | @return true if all SkPoint values are finite |

906 | |

907 | example: https://fiddle.skia.org/c/@Rect_setBoundsCheck |

908 | */ |

909 | bool setBoundsCheck(const SkPoint pts[], int count); |

910 | |

911 | /** Sets to bounds of SkPoint pts array with count entries. If any SkPoint in pts |

912 | contains infinity or NaN, all SkRect dimensions are set to NaN. |

913 | |

914 | @param pts SkPoint array |

915 | @param count entries in array |

916 | |

917 | example: https://fiddle.skia.org/c/@Rect_setBoundsNoCheck |

918 | */ |

919 | void setBoundsNoCheck(const SkPoint pts[], int count); |

920 | |

921 | /** Sets bounds to the smallest SkRect enclosing SkPoint p0 and p1. The result is |

922 | sorted and may be empty. Does not check to see if values are finite. |

923 | |

924 | @param p0 corner to include |

925 | @param p1 corner to include |

926 | */ |

927 | void set(const SkPoint& p0, const SkPoint& p1) { |

928 | fLeft = std::min(a: p0.fX, b: p1.fX); |

929 | fRight = std::max(a: p0.fX, b: p1.fX); |

930 | fTop = std::min(a: p0.fY, b: p1.fY); |

931 | fBottom = std::max(a: p0.fY, b: p1.fY); |

932 | } |

933 | |

934 | /** Sets SkRect to (x, y, x + width, y + height). |

935 | Does not validate input; width or height may be negative. |

936 | |

937 | @param x stored in fLeft |

938 | @param y stored in fTop |

939 | @param width added to x and stored in fRight |

940 | @param height added to y and stored in fBottom |

941 | */ |

942 | void setXYWH(float x, float y, float width, float height) { |

943 | fLeft = x; |

944 | fTop = y; |

945 | fRight = x + width; |

946 | fBottom = y + height; |

947 | } |

948 | |

949 | /** Sets SkRect to (0, 0, width, height). Does not validate input; |

950 | width or height may be negative. |

951 | |

952 | @param width stored in fRight |

953 | @param height stored in fBottom |

954 | */ |

955 | void setWH(float width, float height) { |

956 | fLeft = 0; |

957 | fTop = 0; |

958 | fRight = width; |

959 | fBottom = height; |

960 | } |

961 | void setIWH(int32_t width, int32_t height) { |

962 | this->setWH(width, height); |

963 | } |

964 | |

965 | /** Returns SkRect offset by (dx, dy). |

966 | |

967 | If dx is negative, SkRect returned is moved to the left. |

968 | If dx is positive, SkRect returned is moved to the right. |

969 | If dy is negative, SkRect returned is moved upward. |

970 | If dy is positive, SkRect returned is moved downward. |

971 | |

972 | @param dx added to fLeft and fRight |

973 | @param dy added to fTop and fBottom |

974 | @return SkRect offset on axes, with original width and height |

975 | */ |

976 | constexpr SkRect makeOffset(float dx, float dy) const { |

977 | return MakeLTRB(l: fLeft + dx, t: fTop + dy, r: fRight + dx, b: fBottom + dy); |

978 | } |

979 | |

980 | /** Returns SkRect offset by v. |

981 | |

982 | @param v added to rect |

983 | @return SkRect offset on axes, with original width and height |

984 | */ |

985 | constexpr SkRect makeOffset(SkVector v) const { return this->makeOffset(dx: v.x(), dy: v.y()); } |

986 | |

987 | /** Returns SkRect, inset by (dx, dy). |

988 | |

989 | If dx is negative, SkRect returned is wider. |

990 | If dx is positive, SkRect returned is narrower. |

991 | If dy is negative, SkRect returned is taller. |

992 | If dy is positive, SkRect returned is shorter. |

993 | |

994 | @param dx added to fLeft and subtracted from fRight |

995 | @param dy added to fTop and subtracted from fBottom |

996 | @return SkRect inset symmetrically left and right, top and bottom |

997 | */ |

998 | SkRect makeInset(float dx, float dy) const { |

999 | return MakeLTRB(l: fLeft + dx, t: fTop + dy, r: fRight - dx, b: fBottom - dy); |

1000 | } |

1001 | |

1002 | /** Returns SkRect, outset by (dx, dy). |

1003 | |

1004 | If dx is negative, SkRect returned is narrower. |

1005 | If dx is positive, SkRect returned is wider. |

1006 | If dy is negative, SkRect returned is shorter. |

1007 | If dy is positive, SkRect returned is taller. |

1008 | |

1009 | @param dx subtracted to fLeft and added from fRight |

1010 | @param dy subtracted to fTop and added from fBottom |

1011 | @return SkRect outset symmetrically left and right, top and bottom |

1012 | */ |

1013 | SkRect makeOutset(float dx, float dy) const { |

1014 | return MakeLTRB(l: fLeft - dx, t: fTop - dy, r: fRight + dx, b: fBottom + dy); |

1015 | } |

1016 | |

1017 | /** Offsets SkRect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom. |

1018 | |

1019 | If dx is negative, moves SkRect to the left. |

1020 | If dx is positive, moves SkRect to the right. |

1021 | If dy is negative, moves SkRect upward. |

1022 | If dy is positive, moves SkRect downward. |

1023 | |

1024 | @param dx offset added to fLeft and fRight |

1025 | @param dy offset added to fTop and fBottom |

1026 | */ |

1027 | void offset(float dx, float dy) { |

1028 | fLeft += dx; |

1029 | fTop += dy; |

1030 | fRight += dx; |

1031 | fBottom += dy; |

1032 | } |

1033 | |

1034 | /** Offsets SkRect by adding delta.fX to fLeft, fRight; and by adding delta.fY to |

1035 | fTop, fBottom. |

1036 | |

1037 | If delta.fX is negative, moves SkRect to the left. |

1038 | If delta.fX is positive, moves SkRect to the right. |

1039 | If delta.fY is negative, moves SkRect upward. |

1040 | If delta.fY is positive, moves SkRect downward. |

1041 | |

1042 | @param delta added to SkRect |

1043 | */ |

1044 | void offset(const SkPoint& delta) { |

1045 | this->offset(dx: delta.fX, dy: delta.fY); |

1046 | } |

1047 | |

1048 | /** Offsets SkRect so that fLeft equals newX, and fTop equals newY. width and height |

1049 | are unchanged. |

1050 | |

1051 | @param newX stored in fLeft, preserving width() |

1052 | @param newY stored in fTop, preserving height() |

1053 | */ |

1054 | void offsetTo(float newX, float newY) { |

1055 | fRight += newX - fLeft; |

1056 | fBottom += newY - fTop; |

1057 | fLeft = newX; |

1058 | fTop = newY; |

1059 | } |

1060 | |

1061 | /** Insets SkRect by (dx, dy). |

1062 | |

1063 | If dx is positive, makes SkRect narrower. |

1064 | If dx is negative, makes SkRect wider. |

1065 | If dy is positive, makes SkRect shorter. |

1066 | If dy is negative, makes SkRect taller. |

1067 | |

1068 | @param dx added to fLeft and subtracted from fRight |

1069 | @param dy added to fTop and subtracted from fBottom |

1070 | */ |

1071 | void inset(float dx, float dy) { |

1072 | fLeft += dx; |

1073 | fTop += dy; |

1074 | fRight -= dx; |

1075 | fBottom -= dy; |

1076 | } |

1077 | |

1078 | /** Outsets SkRect by (dx, dy). |

1079 | |

1080 | If dx is positive, makes SkRect wider. |

1081 | If dx is negative, makes SkRect narrower. |

1082 | If dy is positive, makes SkRect taller. |

1083 | If dy is negative, makes SkRect shorter. |

1084 | |

1085 | @param dx subtracted to fLeft and added from fRight |

1086 | @param dy subtracted to fTop and added from fBottom |

1087 | */ |

1088 | void outset(float dx, float dy) { this->inset(dx: -dx, dy: -dy); } |

1089 | |

1090 | /** Returns true if SkRect intersects r, and sets SkRect to intersection. |

1091 | Returns false if SkRect does not intersect r, and leaves SkRect unchanged. |

1092 | |

1093 | Returns false if either r or SkRect is empty, leaving SkRect unchanged. |

1094 | |

1095 | @param r limit of result |

1096 | @return true if r and SkRect have area in common |

1097 | |

1098 | example: https://fiddle.skia.org/c/@Rect_intersect |

1099 | */ |

1100 | bool intersect(const SkRect& r); |

1101 | |

1102 | /** Returns true if a intersects b, and sets SkRect to intersection. |

1103 | Returns false if a does not intersect b, and leaves SkRect unchanged. |

1104 | |

1105 | Returns false if either a or b is empty, leaving SkRect unchanged. |

1106 | |

1107 | @param a SkRect to intersect |

1108 | @param b SkRect to intersect |

1109 | @return true if a and b have area in common |

1110 | */ |

1111 | [[nodiscard]] bool intersect(const SkRect& a, const SkRect& b); |

1112 | |

1113 | |

1114 | private: |

1115 | static bool Intersects(float al, float at, float ar, float ab, |

1116 | float bl, float bt, float br, float bb) { |

1117 | float L = std::max(a: al, b: bl); |

1118 | float R = std::min(a: ar, b: br); |

1119 | float T = std::max(a: at, b: bt); |

1120 | float B = std::min(a: ab, b: bb); |

1121 | return L < R && T < B; |

1122 | } |

1123 | |

1124 | public: |

1125 | |

1126 | /** Returns true if SkRect intersects r. |

1127 | Returns false if either r or SkRect is empty, or do not intersect. |

1128 | |

1129 | @param r SkRect to intersect |

1130 | @return true if r and SkRect have area in common |

1131 | */ |

1132 | bool intersects(const SkRect& r) const { |

1133 | return Intersects(al: fLeft, at: fTop, ar: fRight, ab: fBottom, |

1134 | bl: r.fLeft, bt: r.fTop, br: r.fRight, bb: r.fBottom); |

1135 | } |

1136 | |

1137 | /** Returns true if a intersects b. |

1138 | Returns false if either a or b is empty, or do not intersect. |

1139 | |

1140 | @param a SkRect to intersect |

1141 | @param b SkRect to intersect |

1142 | @return true if a and b have area in common |

1143 | */ |

1144 | static bool Intersects(const SkRect& a, const SkRect& b) { |

1145 | return Intersects(al: a.fLeft, at: a.fTop, ar: a.fRight, ab: a.fBottom, |

1146 | bl: b.fLeft, bt: b.fTop, br: b.fRight, bb: b.fBottom); |

1147 | } |

1148 | |

1149 | /** Sets SkRect to the union of itself and r. |

1150 | |

1151 | Has no effect if r is empty. Otherwise, if SkRect is empty, sets |

1152 | SkRect to r. |

1153 | |

1154 | @param r expansion SkRect |

1155 | |

1156 | example: https://fiddle.skia.org/c/@Rect_join_2 |

1157 | */ |

1158 | void join(const SkRect& r); |

1159 | |

1160 | /** Sets SkRect to the union of itself and r. |

1161 | |

1162 | Asserts if r is empty and SK_DEBUG is defined. |

1163 | If SkRect is empty, sets SkRect to r. |

1164 | |

1165 | May produce incorrect results if r is empty. |

1166 | |

1167 | @param r expansion SkRect |

1168 | */ |

1169 | void joinNonEmptyArg(const SkRect& r) { |

1170 | SkASSERT(!r.isEmpty()); |

1171 | // if we are empty, just assign |

1172 | if (fLeft >= fRight || fTop >= fBottom) { |

1173 | *this = r; |

1174 | } else { |

1175 | this->joinPossiblyEmptyRect(r); |

1176 | } |

1177 | } |

1178 | |

1179 | /** Sets SkRect to the union of itself and the construction. |

1180 | |

1181 | May produce incorrect results if SkRect or r is empty. |

1182 | |

1183 | @param r expansion SkRect |

1184 | */ |

1185 | void joinPossiblyEmptyRect(const SkRect& r) { |

1186 | fLeft = std::min(a: fLeft, b: r.left()); |

1187 | fTop = std::min(a: fTop, b: r.top()); |

1188 | fRight = std::max(a: fRight, b: r.right()); |

1189 | fBottom = std::max(a: fBottom, b: r.bottom()); |

1190 | } |

1191 | |

1192 | /** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom. |

1193 | Returns false if SkRect is empty. |

1194 | |

1195 | @param x test SkPoint x-coordinate |

1196 | @param y test SkPoint y-coordinate |

1197 | @return true if (x, y) is inside SkRect |

1198 | */ |

1199 | bool contains(float x, float y) const { |

1200 | return x >= fLeft && x < fRight && y >= fTop && y < fBottom; |

1201 | } |

1202 | |

1203 | /** Returns true if SkRect contains r. |

1204 | Returns false if SkRect is empty or r is empty. |

1205 | |

1206 | SkRect contains r when SkRect area completely includes r area. |

1207 | |

1208 | @param r SkRect contained |

1209 | @return true if all sides of SkRect are outside r |

1210 | */ |

1211 | bool contains(const SkRect& r) const { |

1212 | // todo: can we eliminate the this->isEmpty check? |

1213 | return !r.isEmpty() && !this->isEmpty() && |

1214 | fLeft <= r.fLeft && fTop <= r.fTop && |

1215 | fRight >= r.fRight && fBottom >= r.fBottom; |

1216 | } |

1217 | |

1218 | /** Returns true if SkRect contains r. |

1219 | Returns false if SkRect is empty or r is empty. |

1220 | |

1221 | SkRect contains r when SkRect area completely includes r area. |

1222 | |

1223 | @param r SkIRect contained |

1224 | @return true if all sides of SkRect are outside r |

1225 | */ |

1226 | bool contains(const SkIRect& r) const { |

1227 | // todo: can we eliminate the this->isEmpty check? |

1228 | return !r.isEmpty() && !this->isEmpty() && |

1229 | fLeft <= r.fLeft && fTop <= r.fTop && |

1230 | fRight >= r.fRight && fBottom >= r.fBottom; |

1231 | } |

1232 | |

1233 | /** Sets SkIRect by adding 0.5 and discarding the fractional portion of SkRect |

1234 | members, using (sk_float_round2int(fLeft), sk_float_round2int(fTop), |

1235 | sk_float_round2int(fRight), sk_float_round2int(fBottom)). |

1236 | |

1237 | @param dst storage for SkIRect |

1238 | */ |

1239 | void round(SkIRect* dst) const { |

1240 | SkASSERT(dst); |

1241 | dst->setLTRB(sk_float_round2int(fLeft), sk_float_round2int(fTop), |

1242 | sk_float_round2int(fRight), sk_float_round2int(fBottom)); |

1243 | } |

1244 | |

1245 | /** Sets SkIRect by discarding the fractional portion of fLeft and fTop; and rounding |

1246 | up fRight and fBottom, using |

1247 | (sk_float_floor2int(fLeft), sk_float_floor2int(fTop), |

1248 | sk_float_ceil2int(fRight), sk_float_ceil2int(fBottom)). |

1249 | |

1250 | @param dst storage for SkIRect |

1251 | */ |

1252 | void roundOut(SkIRect* dst) const { |

1253 | SkASSERT(dst); |

1254 | dst->setLTRB(sk_float_floor2int(fLeft), sk_float_floor2int(fTop), |

1255 | sk_float_ceil2int(fRight), sk_float_ceil2int(fBottom)); |

1256 | } |

1257 | |

1258 | /** Sets SkRect by discarding the fractional portion of fLeft and fTop; and rounding |

1259 | up fRight and fBottom, using |

1260 | (sk_float_floor(fLeft), sk_float_floor(fTop), |

1261 | sk_float_ceil(fRight), sk_float_ceil(fBottom)). |

1262 | |

1263 | @param dst storage for SkRect |

1264 | */ |

1265 | void roundOut(SkRect* dst) const { |

1266 | dst->setLTRB(left: sk_float_floor(x: fLeft), top: sk_float_floor(x: fTop), |

1267 | right: sk_float_ceil(x: fRight), bottom: sk_float_ceil(x: fBottom)); |

1268 | } |

1269 | |

1270 | /** Sets SkRect by rounding up fLeft and fTop; and discarding the fractional portion |

1271 | of fRight and fBottom, using |

1272 | (sk_float_ceil2int(fLeft), sk_float_ceil2int(fTop), |

1273 | sk_float_floor2int(fRight), sk_float_floor2int(fBottom)). |

1274 | |

1275 | @param dst storage for SkIRect |

1276 | */ |

1277 | void roundIn(SkIRect* dst) const { |

1278 | SkASSERT(dst); |

1279 | dst->setLTRB(sk_float_ceil2int(fLeft), sk_float_ceil2int(fTop), |

1280 | sk_float_floor2int(fRight), sk_float_floor2int(fBottom)); |

1281 | } |

1282 | |

1283 | /** Returns SkIRect by adding 0.5 and discarding the fractional portion of SkRect |

1284 | members, using (sk_float_round2int(fLeft), sk_float_round2int(fTop), |

1285 | sk_float_round2int(fRight), sk_float_round2int(fBottom)). |

1286 | |

1287 | @return rounded SkIRect |

1288 | */ |

1289 | SkIRect round() const { |

1290 | SkIRect ir; |

1291 | this->round(dst: &ir); |

1292 | return ir; |

1293 | } |

1294 | |

1295 | /** Sets SkIRect by discarding the fractional portion of fLeft and fTop; and rounding |

1296 | up fRight and fBottom, using |

1297 | (sk_float_floor2int(fLeft), sk_float_floor2int(fTop), |

1298 | sk_float_ceil2int(fRight), sk_float_ceil2int(fBottom)). |

1299 | |

1300 | @return rounded SkIRect |

1301 | */ |

1302 | SkIRect roundOut() const { |

1303 | SkIRect ir; |

1304 | this->roundOut(dst: &ir); |

1305 | return ir; |

1306 | } |

1307 | /** Sets SkIRect by rounding up fLeft and fTop; and discarding the fractional portion |

1308 | of fRight and fBottom, using |

1309 | (sk_float_ceil2int(fLeft), sk_float_ceil2int(fTop), |

1310 | sk_float_floor2int(fRight), sk_float_floor2int(fBottom)). |

1311 | |

1312 | @return rounded SkIRect |

1313 | */ |

1314 | SkIRect roundIn() const { |

1315 | SkIRect ir; |

1316 | this->roundIn(dst: &ir); |

1317 | return ir; |

1318 | } |

1319 | |

1320 | /** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps |

1321 | fTop and fBottom if fTop is greater than fBottom. Result may be empty; |

1322 | and width() and height() will be zero or positive. |

1323 | */ |

1324 | void sort() { |

1325 | using std::swap; |

1326 | if (fLeft > fRight) { |

1327 | swap(x&: fLeft, y&: fRight); |

1328 | } |

1329 | |

1330 | if (fTop > fBottom) { |

1331 | swap(x&: fTop, y&: fBottom); |

1332 | } |

1333 | } |

1334 | |

1335 | /** Returns SkRect with fLeft and fRight swapped if fLeft is greater than fRight; and |

1336 | with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty; |

1337 | and width() and height() will be zero or positive. |

1338 | |

1339 | @return sorted SkRect |

1340 | */ |

1341 | SkRect makeSorted() const { |

1342 | return MakeLTRB(l: std::min(a: fLeft, b: fRight), t: std::min(a: fTop, b: fBottom), |

1343 | r: std::max(a: fLeft, b: fRight), b: std::max(a: fTop, b: fBottom)); |

1344 | } |

1345 | |

1346 | /** Returns pointer to first float in SkRect, to treat it as an array with four |

1347 | entries. |

1348 | |

1349 | @return pointer to fLeft |

1350 | */ |

1351 | const float* asScalars() const { return &fLeft; } |

1352 | |

1353 | /** Writes text representation of SkRect to standard output. Set asHex to true to |

1354 | generate exact binary representations of floating point numbers. |

1355 | |

1356 | @param asHex true if SkScalar values are written as hexadecimal |

1357 | |

1358 | example: https://fiddle.skia.org/c/@Rect_dump |

1359 | */ |

1360 | void dump(bool asHex) const; |

1361 | |

1362 | /** Writes text representation of SkRect to standard output. The representation may be |

1363 | directly compiled as C++ code. Floating point values are written |

1364 | with limited precision; it may not be possible to reconstruct original SkRect |

1365 | from output. |

1366 | */ |

1367 | void dump() const { this->dump(asHex: false); } |

1368 | |

1369 | /** Writes text representation of SkRect to standard output. The representation may be |

1370 | directly compiled as C++ code. Floating point values are written |

1371 | in hexadecimal to preserve their exact bit pattern. The output reconstructs the |

1372 | original SkRect. |

1373 | |

1374 | Use instead of dump() when submitting |

1375 | */ |

1376 | void dumpHex() const { this->dump(asHex: true); } |

1377 | }; |

1378 | |

1379 | inline bool SkIRect::contains(const SkRect& r) const { |

1380 | return !r.isEmpty() && !this->isEmpty() && // check for empties |

1381 | fLeft <= r.fLeft && fTop <= r.fTop && |

1382 | fRight >= r.fRight && fBottom >= r.fBottom; |

1383 | } |

1384 | |

1385 | #endif |

1386 |