1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h"
8cb93a386Sopenharmony_ci#include "src/pathops/SkOpEdgeBuilder.h"
9cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCommon.h"
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_cibool TightBounds(const SkPath& path, SkRect* result) {
12cb93a386Sopenharmony_ci    SkRect moveBounds = { SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin };
13cb93a386Sopenharmony_ci    bool wellBehaved = true;
14cb93a386Sopenharmony_ci    for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
15cb93a386Sopenharmony_ci        switch (verb) {
16cb93a386Sopenharmony_ci            case SkPathVerb::kMove:
17cb93a386Sopenharmony_ci                moveBounds.fLeft = std::min(moveBounds.fLeft, pts[0].fX);
18cb93a386Sopenharmony_ci                moveBounds.fTop = std::min(moveBounds.fTop, pts[0].fY);
19cb93a386Sopenharmony_ci                moveBounds.fRight = std::max(moveBounds.fRight, pts[0].fX);
20cb93a386Sopenharmony_ci                moveBounds.fBottom = std::max(moveBounds.fBottom, pts[0].fY);
21cb93a386Sopenharmony_ci                break;
22cb93a386Sopenharmony_ci            case SkPathVerb::kQuad:
23cb93a386Sopenharmony_ci            case SkPathVerb::kConic:
24cb93a386Sopenharmony_ci                if (!wellBehaved) {
25cb93a386Sopenharmony_ci                    break;
26cb93a386Sopenharmony_ci                }
27cb93a386Sopenharmony_ci                wellBehaved &= between(pts[0].fX, pts[1].fX, pts[2].fX);
28cb93a386Sopenharmony_ci                wellBehaved &= between(pts[0].fY, pts[1].fY, pts[2].fY);
29cb93a386Sopenharmony_ci                break;
30cb93a386Sopenharmony_ci            case SkPathVerb::kCubic:
31cb93a386Sopenharmony_ci                if (!wellBehaved) {
32cb93a386Sopenharmony_ci                    break;
33cb93a386Sopenharmony_ci                }
34cb93a386Sopenharmony_ci                wellBehaved &= between(pts[0].fX, pts[1].fX, pts[3].fX);
35cb93a386Sopenharmony_ci                wellBehaved &= between(pts[0].fY, pts[1].fY, pts[3].fY);
36cb93a386Sopenharmony_ci                wellBehaved &= between(pts[0].fX, pts[2].fX, pts[3].fX);
37cb93a386Sopenharmony_ci                wellBehaved &= between(pts[0].fY, pts[2].fY, pts[3].fY);
38cb93a386Sopenharmony_ci                break;
39cb93a386Sopenharmony_ci            default:
40cb93a386Sopenharmony_ci                break;
41cb93a386Sopenharmony_ci        }
42cb93a386Sopenharmony_ci    }
43cb93a386Sopenharmony_ci    if (wellBehaved) {
44cb93a386Sopenharmony_ci        *result = path.getBounds();
45cb93a386Sopenharmony_ci        return true;
46cb93a386Sopenharmony_ci    }
47cb93a386Sopenharmony_ci    SkSTArenaAlloc<4096> allocator;  // FIXME: constant-ize, tune
48cb93a386Sopenharmony_ci    SkOpContour contour;
49cb93a386Sopenharmony_ci    SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
50cb93a386Sopenharmony_ci    SkOpGlobalState globalState(contourList, &allocator  SkDEBUGPARAMS(false)
51cb93a386Sopenharmony_ci            SkDEBUGPARAMS(nullptr));
52cb93a386Sopenharmony_ci    // turn path into list of segments
53cb93a386Sopenharmony_ci    SkOpEdgeBuilder builder(path, contourList, &globalState);
54cb93a386Sopenharmony_ci    if (!builder.finish()) {
55cb93a386Sopenharmony_ci        return false;
56cb93a386Sopenharmony_ci    }
57cb93a386Sopenharmony_ci    if (!SortContourList(&contourList, false, false)) {
58cb93a386Sopenharmony_ci        *result = moveBounds;
59cb93a386Sopenharmony_ci        return true;
60cb93a386Sopenharmony_ci    }
61cb93a386Sopenharmony_ci    SkOpContour* current = contourList;
62cb93a386Sopenharmony_ci    SkPathOpsBounds bounds = current->bounds();
63cb93a386Sopenharmony_ci    while ((current = current->next())) {
64cb93a386Sopenharmony_ci        bounds.add(current->bounds());
65cb93a386Sopenharmony_ci    }
66cb93a386Sopenharmony_ci    *result = bounds;
67cb93a386Sopenharmony_ci    if (!moveBounds.isEmpty()) {
68cb93a386Sopenharmony_ci        result->join(moveBounds);
69cb93a386Sopenharmony_ci    }
70cb93a386Sopenharmony_ci    return true;
71cb93a386Sopenharmony_ci}
72