blob: d11b292b8f3446363ec355c5712445dd5d9dfe5b [file] [log] [blame]
caryclarka8d2ffb2014-06-24 07:55:11 -07001/*
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 */
Chris Dalton957189b2020-05-07 12:47:26 -06007#include "src/core/SkPathPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/pathops/SkOpEdgeBuilder.h"
9#include "src/pathops/SkPathOpsCommon.h"
caryclarka8d2ffb2014-06-24 07:55:11 -070010
11bool TightBounds(const SkPath& path, SkRect* result) {
caryclark61c21cd2016-10-05 13:23:00 -070012 SkRect moveBounds = { SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin };
13 bool wellBehaved = true;
Chris Dalton957189b2020-05-07 12:47:26 -060014 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
caryclark61c21cd2016-10-05 13:23:00 -070015 switch (verb) {
Chris Dalton957189b2020-05-07 12:47:26 -060016 case SkPathVerb::kMove:
Brian Osman788b9162020-02-07 10:36:46 -050017 moveBounds.fLeft = std::min(moveBounds.fLeft, pts[0].fX);
18 moveBounds.fTop = std::min(moveBounds.fTop, pts[0].fY);
19 moveBounds.fRight = std::max(moveBounds.fRight, pts[0].fX);
20 moveBounds.fBottom = std::max(moveBounds.fBottom, pts[0].fY);
caryclark61c21cd2016-10-05 13:23:00 -070021 break;
Chris Dalton957189b2020-05-07 12:47:26 -060022 case SkPathVerb::kQuad:
23 case SkPathVerb::kConic:
caryclark61c21cd2016-10-05 13:23:00 -070024 if (!wellBehaved) {
25 break;
26 }
27 wellBehaved &= between(pts[0].fX, pts[1].fX, pts[2].fX);
28 wellBehaved &= between(pts[0].fY, pts[1].fY, pts[2].fY);
29 break;
Chris Dalton957189b2020-05-07 12:47:26 -060030 case SkPathVerb::kCubic:
caryclark61c21cd2016-10-05 13:23:00 -070031 if (!wellBehaved) {
32 break;
33 }
34 wellBehaved &= between(pts[0].fX, pts[1].fX, pts[3].fX);
35 wellBehaved &= between(pts[0].fY, pts[1].fY, pts[3].fY);
36 wellBehaved &= between(pts[0].fX, pts[2].fX, pts[3].fX);
37 wellBehaved &= between(pts[0].fY, pts[2].fY, pts[3].fY);
38 break;
39 default:
40 break;
41 }
Chris Dalton957189b2020-05-07 12:47:26 -060042 }
caryclark61c21cd2016-10-05 13:23:00 -070043 if (wellBehaved) {
44 *result = path.getBounds();
45 return true;
46 }
Florin Malita14a64302017-05-24 14:53:44 -040047 SkSTArenaAlloc<4096> allocator; // FIXME: constant-ize, tune
caryclark54359292015-03-26 07:52:43 -070048 SkOpContour contour;
caryclark624637c2015-05-11 07:21:27 -070049 SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
caryclark55888e42016-07-18 10:01:36 -070050 SkOpGlobalState globalState(contourList, &allocator SkDEBUGPARAMS(false)
caryclarkdae6b972016-06-08 04:28:19 -070051 SkDEBUGPARAMS(nullptr));
caryclarka8d2ffb2014-06-24 07:55:11 -070052 // turn path into list of segments
Cary Clark5de52332018-08-30 12:58:23 -040053 SkOpEdgeBuilder builder(path, contourList, &globalState);
caryclark55888e42016-07-18 10:01:36 -070054 if (!builder.finish()) {
caryclarka8d2ffb2014-06-24 07:55:11 -070055 return false;
56 }
caryclark624637c2015-05-11 07:21:27 -070057 if (!SortContourList(&contourList, false, false)) {
caryclark61c21cd2016-10-05 13:23:00 -070058 *result = moveBounds;
caryclarka8d2ffb2014-06-24 07:55:11 -070059 return true;
60 }
caryclark624637c2015-05-11 07:21:27 -070061 SkOpContour* current = contourList;
caryclarka8d2ffb2014-06-24 07:55:11 -070062 SkPathOpsBounds bounds = current->bounds();
caryclark624637c2015-05-11 07:21:27 -070063 while ((current = current->next())) {
caryclarka8d2ffb2014-06-24 07:55:11 -070064 bounds.add(current->bounds());
65 }
66 *result = bounds;
caryclark61c21cd2016-10-05 13:23:00 -070067 if (!moveBounds.isEmpty()) {
68 result->join(moveBounds);
69 }
caryclarka8d2ffb2014-06-24 07:55:11 -070070 return true;
71}