SkPathOpsTightBounds.cpp 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. /*
  2. * Copyright 2014 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 "src/pathops/SkOpEdgeBuilder.h"
  8. #include "src/pathops/SkPathOpsCommon.h"
  9. bool TightBounds(const SkPath& path, SkRect* result) {
  10. SkPath::RawIter iter(path);
  11. SkRect moveBounds = { SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin };
  12. bool wellBehaved = true;
  13. SkPath::Verb verb;
  14. do {
  15. SkPoint pts[4];
  16. verb = iter.next(pts);
  17. switch (verb) {
  18. case SkPath::kMove_Verb:
  19. moveBounds.fLeft = SkTMin(moveBounds.fLeft, pts[0].fX);
  20. moveBounds.fTop = SkTMin(moveBounds.fTop, pts[0].fY);
  21. moveBounds.fRight = SkTMax(moveBounds.fRight, pts[0].fX);
  22. moveBounds.fBottom = SkTMax(moveBounds.fBottom, pts[0].fY);
  23. break;
  24. case SkPath::kQuad_Verb:
  25. case SkPath::kConic_Verb:
  26. if (!wellBehaved) {
  27. break;
  28. }
  29. wellBehaved &= between(pts[0].fX, pts[1].fX, pts[2].fX);
  30. wellBehaved &= between(pts[0].fY, pts[1].fY, pts[2].fY);
  31. break;
  32. case SkPath::kCubic_Verb:
  33. if (!wellBehaved) {
  34. break;
  35. }
  36. wellBehaved &= between(pts[0].fX, pts[1].fX, pts[3].fX);
  37. wellBehaved &= between(pts[0].fY, pts[1].fY, pts[3].fY);
  38. wellBehaved &= between(pts[0].fX, pts[2].fX, pts[3].fX);
  39. wellBehaved &= between(pts[0].fY, pts[2].fY, pts[3].fY);
  40. break;
  41. default:
  42. break;
  43. }
  44. } while (verb != SkPath::kDone_Verb);
  45. if (wellBehaved) {
  46. *result = path.getBounds();
  47. return true;
  48. }
  49. SkSTArenaAlloc<4096> allocator; // FIXME: constant-ize, tune
  50. SkOpContour contour;
  51. SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
  52. SkOpGlobalState globalState(contourList, &allocator SkDEBUGPARAMS(false)
  53. SkDEBUGPARAMS(nullptr));
  54. // turn path into list of segments
  55. SkOpEdgeBuilder builder(path, contourList, &globalState);
  56. if (!builder.finish()) {
  57. return false;
  58. }
  59. if (!SortContourList(&contourList, false, false)) {
  60. *result = moveBounds;
  61. return true;
  62. }
  63. SkOpContour* current = contourList;
  64. SkPathOpsBounds bounds = current->bounds();
  65. while ((current = current->next())) {
  66. bounds.add(current->bounds());
  67. }
  68. *result = bounds;
  69. if (!moveBounds.isEmpty()) {
  70. result->join(moveBounds);
  71. }
  72. return true;
  73. }