SkRasterClip.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. /*
  2. * Copyright 2010 Google Inc.
  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. #include "include/core/SkPath.h"
  8. #include "src/core/SkRasterClip.h"
  9. #include "src/core/SkRegionPriv.h"
  10. enum MutateResult {
  11. kDoNothing_MutateResult,
  12. kReplaceClippedAgainstGlobalBounds_MutateResult,
  13. kContinue_MutateResult,
  14. };
  15. static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) {
  16. if (inverseFilled) {
  17. switch (*op) {
  18. case SkRegion::kIntersect_Op:
  19. case SkRegion::kDifference_Op:
  20. // These ops can only shrink the current clip. So leaving
  21. // the clip unchanged conservatively respects the contract.
  22. return kDoNothing_MutateResult;
  23. case SkRegion::kUnion_Op:
  24. case SkRegion::kReplace_Op:
  25. case SkRegion::kReverseDifference_Op:
  26. case SkRegion::kXOR_Op: {
  27. // These ops can grow the current clip up to the extents of
  28. // the input clip, which is inverse filled, so we just set
  29. // the current clip to the device bounds.
  30. *op = SkRegion::kReplace_Op;
  31. return kReplaceClippedAgainstGlobalBounds_MutateResult;
  32. }
  33. }
  34. } else {
  35. // Not inverse filled
  36. switch (*op) {
  37. case SkRegion::kIntersect_Op:
  38. case SkRegion::kUnion_Op:
  39. case SkRegion::kReplace_Op:
  40. return kContinue_MutateResult;
  41. case SkRegion::kDifference_Op:
  42. // Difference can only shrink the current clip.
  43. // Leaving clip unchanged conservatively fullfills the contract.
  44. return kDoNothing_MutateResult;
  45. case SkRegion::kReverseDifference_Op:
  46. // To reverse, we swap in the bounds with a replace op.
  47. // As with difference, leave it unchanged.
  48. *op = SkRegion::kReplace_Op;
  49. return kContinue_MutateResult;
  50. case SkRegion::kXOR_Op:
  51. // Be conservative, based on (A XOR B) always included in (A union B),
  52. // which is always included in (bounds(A) union bounds(B))
  53. *op = SkRegion::kUnion_Op;
  54. return kContinue_MutateResult;
  55. }
  56. }
  57. SkASSERT(false); // unknown op
  58. return kDoNothing_MutateResult;
  59. }
  60. void SkConservativeClip::opRect(const SkRect& localRect, const SkMatrix& ctm,
  61. const SkIRect& devBounds, SkRegion::Op op, bool doAA) {
  62. SkIRect ir;
  63. switch (mutate_conservative_op(&op, false)) {
  64. case kDoNothing_MutateResult:
  65. return;
  66. case kReplaceClippedAgainstGlobalBounds_MutateResult:
  67. ir = devBounds;
  68. break;
  69. case kContinue_MutateResult: {
  70. SkRect devRect;
  71. ctm.mapRect(&devRect, localRect);
  72. ir = doAA ? devRect.roundOut() : devRect.round();
  73. } break;
  74. }
  75. this->opIRect(ir, op);
  76. }
  77. void SkConservativeClip::opRRect(const SkRRect& rrect, const SkMatrix& ctm,
  78. const SkIRect& devBounds, SkRegion::Op op, bool doAA) {
  79. this->opRect(rrect.getBounds(), ctm, devBounds, op, doAA);
  80. }
  81. void SkConservativeClip::opPath(const SkPath& path, const SkMatrix& ctm, const SkIRect& devBounds,
  82. SkRegion::Op op, bool doAA) {
  83. SkIRect ir;
  84. switch (mutate_conservative_op(&op, path.isInverseFillType())) {
  85. case kDoNothing_MutateResult:
  86. return;
  87. case kReplaceClippedAgainstGlobalBounds_MutateResult:
  88. ir = devBounds;
  89. break;
  90. case kContinue_MutateResult: {
  91. SkRect bounds = path.getBounds();
  92. ctm.mapRect(&bounds);
  93. ir = bounds.roundOut();
  94. break;
  95. }
  96. }
  97. return this->opIRect(ir, op);
  98. }
  99. void SkConservativeClip::opRegion(const SkRegion& rgn, SkRegion::Op op) {
  100. this->opIRect(rgn.getBounds(), op);
  101. }
  102. void SkConservativeClip::opIRect(const SkIRect& devRect, SkRegion::Op op) {
  103. if (SkRegion::kIntersect_Op == op) {
  104. if (!fBounds.intersect(devRect)) {
  105. fBounds.setEmpty();
  106. }
  107. return;
  108. }
  109. // This may still create a complex region (which we would then take the bounds
  110. // Perhaps we should inline the op-logic directly to never create the rgn...
  111. SkRegion result;
  112. result.op(SkRegion(fBounds), SkRegion(devRect), op);
  113. fBounds = result.getBounds();
  114. this->applyClipRestriction(op, &fBounds);
  115. }
  116. ///////////////////////////////////////////////////////////////////////////////////////////////////
  117. SkRasterClip::SkRasterClip(const SkRasterClip& src) {
  118. AUTO_RASTERCLIP_VALIDATE(src);
  119. fIsBW = src.fIsBW;
  120. if (fIsBW) {
  121. fBW = src.fBW;
  122. } else {
  123. fAA = src.fAA;
  124. }
  125. fIsEmpty = src.isEmpty();
  126. fIsRect = src.isRect();
  127. fClipRestrictionRect = src.fClipRestrictionRect;
  128. SkDEBUGCODE(this->validate();)
  129. }
  130. SkRasterClip::SkRasterClip(const SkRegion& rgn) : fBW(rgn) {
  131. fIsBW = true;
  132. fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
  133. fIsRect = !fIsEmpty;
  134. SkDEBUGCODE(this->validate();)
  135. }
  136. SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
  137. fIsBW = true;
  138. fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
  139. fIsRect = !fIsEmpty;
  140. SkDEBUGCODE(this->validate();)
  141. }
  142. SkRasterClip::SkRasterClip() {
  143. fIsBW = true;
  144. fIsEmpty = true;
  145. fIsRect = false;
  146. SkDEBUGCODE(this->validate();)
  147. }
  148. SkRasterClip::~SkRasterClip() {
  149. SkDEBUGCODE(this->validate();)
  150. }
  151. bool SkRasterClip::operator==(const SkRasterClip& other) const {
  152. if (fIsBW != other.fIsBW) {
  153. return false;
  154. }
  155. bool isEqual = fIsBW ? fBW == other.fBW : fAA == other.fAA;
  156. #ifdef SK_DEBUG
  157. if (isEqual) {
  158. SkASSERT(fIsEmpty == other.fIsEmpty);
  159. SkASSERT(fIsRect == other.fIsRect);
  160. }
  161. #endif
  162. return isEqual;
  163. }
  164. bool SkRasterClip::isComplex() const {
  165. return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
  166. }
  167. const SkIRect& SkRasterClip::getBounds() const {
  168. return fIsBW ? fBW.getBounds() : fAA.getBounds();
  169. }
  170. bool SkRasterClip::setEmpty() {
  171. AUTO_RASTERCLIP_VALIDATE(*this);
  172. fIsBW = true;
  173. fBW.setEmpty();
  174. fAA.setEmpty();
  175. fIsEmpty = true;
  176. fIsRect = false;
  177. return false;
  178. }
  179. bool SkRasterClip::setRect(const SkIRect& rect) {
  180. AUTO_RASTERCLIP_VALIDATE(*this);
  181. fIsBW = true;
  182. fAA.setEmpty();
  183. fIsRect = fBW.setRect(rect);
  184. fIsEmpty = !fIsRect;
  185. return fIsRect;
  186. }
  187. /////////////////////////////////////////////////////////////////////////////////////
  188. bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) {
  189. SkRegion::Op op;
  190. if (isInverse) {
  191. op = SkRegion::kDifference_Op;
  192. } else {
  193. op = SkRegion::kIntersect_Op;
  194. }
  195. fBW.setRect(clipR);
  196. fBW.op(r.roundOut(), op);
  197. return this->updateCacheAndReturnNonEmpty();
  198. }
  199. /////////////////////////////////////////////////////////////////////////////////////
  200. bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
  201. AUTO_RASTERCLIP_VALIDATE(*this);
  202. if (this->isBW() && !doAA) {
  203. (void)fBW.setPath(path, clip);
  204. } else {
  205. // TODO: since we are going to over-write fAA completely (aren't we?)
  206. // we should just clear our BW data (if any) and set fIsAA=true
  207. if (this->isBW()) {
  208. this->convertToAA();
  209. }
  210. (void)fAA.setPath(path, &clip, doAA);
  211. }
  212. return this->updateCacheAndReturnNonEmpty();
  213. }
  214. bool SkRasterClip::op(const SkRRect& rrect, const SkMatrix& matrix, const SkIRect& devBounds,
  215. SkRegion::Op op, bool doAA) {
  216. SkIRect bounds(devBounds);
  217. this->applyClipRestriction(op, &bounds);
  218. SkPath path;
  219. path.addRRect(rrect);
  220. return this->op(path, matrix, bounds, op, doAA);
  221. }
  222. bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& devBounds,
  223. SkRegion::Op op, bool doAA) {
  224. AUTO_RASTERCLIP_VALIDATE(*this);
  225. SkIRect bounds(devBounds);
  226. this->applyClipRestriction(op, &bounds);
  227. // base is used to limit the size (and therefore memory allocation) of the
  228. // region that results from scan converting devPath.
  229. SkRegion base;
  230. SkPath devPath;
  231. if (matrix.isIdentity()) {
  232. devPath = path;
  233. } else {
  234. path.transform(matrix, &devPath);
  235. devPath.setIsVolatile(true);
  236. }
  237. if (SkRegion::kIntersect_Op == op) {
  238. // since we are intersect, we can do better (tighter) with currRgn's
  239. // bounds, than just using the device. However, if currRgn is complex,
  240. // our region blitter may hork, so we do that case in two steps.
  241. if (this->isRect()) {
  242. // FIXME: we should also be able to do this when this->isBW(),
  243. // but relaxing the test above triggers GM asserts in
  244. // SkRgnBuilder::blitH(). We need to investigate what's going on.
  245. return this->setPath(devPath, this->bwRgn(), doAA);
  246. } else {
  247. base.setRect(this->getBounds());
  248. SkRasterClip clip;
  249. clip.setPath(devPath, base, doAA);
  250. return this->op(clip, op);
  251. }
  252. } else {
  253. base.setRect(bounds);
  254. if (SkRegion::kReplace_Op == op) {
  255. return this->setPath(devPath, base, doAA);
  256. } else {
  257. SkRasterClip clip;
  258. clip.setPath(devPath, base, doAA);
  259. return this->op(clip, op);
  260. }
  261. }
  262. }
  263. bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
  264. SkRegion tmp;
  265. tmp.setRect(clip);
  266. return this->setPath(path, tmp, doAA);
  267. }
  268. bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
  269. AUTO_RASTERCLIP_VALIDATE(*this);
  270. fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
  271. return this->updateCacheAndReturnNonEmpty();
  272. }
  273. bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
  274. AUTO_RASTERCLIP_VALIDATE(*this);
  275. if (fIsBW) {
  276. (void)fBW.op(rgn, op);
  277. } else {
  278. SkAAClip tmp;
  279. tmp.setRegion(rgn);
  280. (void)fAA.op(tmp, op);
  281. }
  282. return this->updateCacheAndReturnNonEmpty();
  283. }
  284. bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
  285. AUTO_RASTERCLIP_VALIDATE(*this);
  286. clip.validate();
  287. if (this->isBW() && clip.isBW()) {
  288. (void)fBW.op(clip.fBW, op);
  289. } else {
  290. SkAAClip tmp;
  291. const SkAAClip* other;
  292. if (this->isBW()) {
  293. this->convertToAA();
  294. }
  295. if (clip.isBW()) {
  296. tmp.setRegion(clip.bwRgn());
  297. other = &tmp;
  298. } else {
  299. other = &clip.aaRgn();
  300. }
  301. (void)fAA.op(*other, op);
  302. }
  303. return this->updateCacheAndReturnNonEmpty();
  304. }
  305. /**
  306. * Our antialiasing currently has a granularity of 1/4 of a pixel along each
  307. * axis. Thus we can treat an axis coordinate as an integer if it differs
  308. * from its nearest int by < half of that value (1.8 in this case).
  309. */
  310. static bool nearly_integral(SkScalar x) {
  311. static const SkScalar domain = SK_Scalar1 / 4;
  312. static const SkScalar halfDomain = domain / 2;
  313. x += halfDomain;
  314. return x - SkScalarFloorToScalar(x) < domain;
  315. }
  316. bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkIRect& devBounds,
  317. SkRegion::Op op, bool doAA) {
  318. AUTO_RASTERCLIP_VALIDATE(*this);
  319. SkRect devRect;
  320. const bool isScaleTrans = matrix.isScaleTranslate();
  321. if (!isScaleTrans) {
  322. SkPath path;
  323. path.addRect(localRect);
  324. path.setIsVolatile(true);
  325. return this->op(path, matrix, devBounds, op, doAA);
  326. }
  327. matrix.mapRect(&devRect, localRect);
  328. if (fIsBW && doAA) {
  329. // check that the rect really needs aa, or is it close enought to
  330. // integer boundaries that we can just treat it as a BW rect?
  331. if (nearly_integral(devRect.fLeft) && nearly_integral(devRect.fTop) &&
  332. nearly_integral(devRect.fRight) && nearly_integral(devRect.fBottom)) {
  333. doAA = false;
  334. }
  335. }
  336. if (fIsBW && !doAA) {
  337. SkIRect ir;
  338. devRect.round(&ir);
  339. this->applyClipRestriction(op, &ir);
  340. (void)fBW.op(ir, op);
  341. } else {
  342. if (fIsBW) {
  343. this->convertToAA();
  344. }
  345. this->applyClipRestriction(op, &devRect);
  346. (void)fAA.op(devRect, op, doAA);
  347. }
  348. return this->updateCacheAndReturnNonEmpty();
  349. }
  350. void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
  351. if (nullptr == dst) {
  352. return;
  353. }
  354. AUTO_RASTERCLIP_VALIDATE(*this);
  355. if (this->isEmpty()) {
  356. dst->setEmpty();
  357. return;
  358. }
  359. if (0 == (dx | dy)) {
  360. *dst = *this;
  361. return;
  362. }
  363. dst->fIsBW = fIsBW;
  364. if (fIsBW) {
  365. fBW.translate(dx, dy, &dst->fBW);
  366. dst->fAA.setEmpty();
  367. } else {
  368. fAA.translate(dx, dy, &dst->fAA);
  369. dst->fBW.setEmpty();
  370. }
  371. dst->updateCacheAndReturnNonEmpty();
  372. }
  373. bool SkRasterClip::quickContains(const SkIRect& ir) const {
  374. return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
  375. }
  376. ///////////////////////////////////////////////////////////////////////////////
  377. const SkRegion& SkRasterClip::forceGetBW() {
  378. AUTO_RASTERCLIP_VALIDATE(*this);
  379. if (!fIsBW) {
  380. fBW.setRect(fAA.getBounds());
  381. }
  382. return fBW;
  383. }
  384. void SkRasterClip::convertToAA() {
  385. AUTO_RASTERCLIP_VALIDATE(*this);
  386. SkASSERT(fIsBW);
  387. fAA.setRegion(fBW);
  388. fIsBW = false;
  389. // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize"
  390. // ourselves back to BW.
  391. (void)this->updateCacheAndReturnNonEmpty(false);
  392. }
  393. #ifdef SK_DEBUG
  394. void SkRasterClip::validate() const {
  395. // can't ever assert that fBW is empty, since we may have called forceGetBW
  396. if (fIsBW) {
  397. SkASSERT(fAA.isEmpty());
  398. }
  399. SkRegionPriv::Validate(fBW);
  400. fAA.validate();
  401. SkASSERT(this->computeIsEmpty() == fIsEmpty);
  402. SkASSERT(this->computeIsRect() == fIsRect);
  403. }
  404. #endif
  405. ///////////////////////////////////////////////////////////////////////////////
  406. SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
  407. SkDEBUGCODE(fClipRgn = nullptr;)
  408. SkDEBUGCODE(fBlitter = nullptr;)
  409. }
  410. SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
  411. SkBlitter* blitter) {
  412. this->init(clip, blitter);
  413. }
  414. SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
  415. SkBlitter* blitter) {
  416. SkASSERT(blitter);
  417. SkASSERT(aaclip);
  418. fBWRgn.setRect(aaclip->getBounds());
  419. fAABlitter.init(blitter, aaclip);
  420. // now our return values
  421. fClipRgn = &fBWRgn;
  422. fBlitter = &fAABlitter;
  423. }
  424. void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
  425. SkASSERT(blitter);
  426. if (clip.isBW()) {
  427. fClipRgn = &clip.bwRgn();
  428. fBlitter = blitter;
  429. } else {
  430. const SkAAClip& aaclip = clip.aaRgn();
  431. fBWRgn.setRect(aaclip.getBounds());
  432. fAABlitter.init(blitter, &aaclip);
  433. // now our return values
  434. fClipRgn = &fBWRgn;
  435. fBlitter = &fAABlitter;
  436. }
  437. }