Coverage Report

Created: 2024-05-20 07:14

/src/skia/src/pathops/SkPathOpsTightBounds.cpp
Line
Count
Source (jump to first uncovered line)
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 "include/core/SkPath.h"
8
#include "include/core/SkPathTypes.h"
9
#include "include/core/SkPoint.h"
10
#include "include/core/SkRect.h"
11
#include "include/core/SkScalar.h"
12
#include "include/pathops/SkPathOps.h"
13
#include "src/base/SkArenaAlloc.h"
14
#include "src/core/SkPathPriv.h"
15
#include "src/pathops/SkOpContour.h"
16
#include "src/pathops/SkOpEdgeBuilder.h"
17
#include "src/pathops/SkPathOpsBounds.h"
18
#include "src/pathops/SkPathOpsCommon.h"
19
#include "src/pathops/SkPathOpsTypes.h"
20
21
#include <algorithm>
22
23
478
bool TightBounds(const SkPath& path, SkRect* result) {
24
478
    SkRect moveBounds = { SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin };
25
478
    bool wellBehaved = true;
26
7.66k
    for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
27
7.66k
        switch (verb) {
28
2.54k
            case SkPathVerb::kMove:
29
2.54k
                moveBounds.fLeft = std::min(moveBounds.fLeft, pts[0].fX);
30
2.54k
                moveBounds.fTop = std::min(moveBounds.fTop, pts[0].fY);
31
2.54k
                moveBounds.fRight = std::max(moveBounds.fRight, pts[0].fX);
32
2.54k
                moveBounds.fBottom = std::max(moveBounds.fBottom, pts[0].fY);
33
2.54k
                break;
34
1.23k
            case SkPathVerb::kQuad:
35
2.12k
            case SkPathVerb::kConic:
36
2.12k
                if (!wellBehaved) {
37
1.70k
                    break;
38
1.70k
                }
39
426
                wellBehaved &= between(pts[0].fX, pts[1].fX, pts[2].fX);
40
426
                wellBehaved &= between(pts[0].fY, pts[1].fY, pts[2].fY);
41
426
                break;
42
1.01k
            case SkPathVerb::kCubic:
43
1.01k
                if (!wellBehaved) {
44
761
                    break;
45
761
                }
46
251
                wellBehaved &= between(pts[0].fX, pts[1].fX, pts[3].fX);
47
251
                wellBehaved &= between(pts[0].fY, pts[1].fY, pts[3].fY);
48
251
                wellBehaved &= between(pts[0].fX, pts[2].fX, pts[3].fX);
49
251
                wellBehaved &= between(pts[0].fY, pts[2].fY, pts[3].fY);
50
251
                break;
51
1.98k
            default:
52
1.98k
                break;
53
7.66k
        }
54
7.66k
    }
55
478
    if (wellBehaved) {
56
138
        *result = path.getBounds();
57
138
        return true;
58
138
    }
59
340
    SkSTArenaAlloc<4096> allocator;  // FIXME: constant-ize, tune
60
340
    SkOpContour contour;
61
340
    SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
62
340
    SkOpGlobalState globalState(contourList, &allocator  SkDEBUGPARAMS(false)
63
340
            SkDEBUGPARAMS(nullptr));
64
    // turn path into list of segments
65
340
    SkOpEdgeBuilder builder(path, contourList, &globalState);
66
340
    if (!builder.finish()) {
67
1
        return false;
68
1
    }
69
339
    if (!SortContourList(&contourList, false, false)) {
70
144
        *result = moveBounds;
71
144
        return true;
72
144
    }
73
195
    SkOpContour* current = contourList;
74
195
    SkPathOpsBounds bounds = current->bounds();
75
869
    while ((current = current->next())) {
76
674
        bounds.add(current->bounds());
77
674
    }
78
195
    *result = bounds;
79
195
    if (!moveBounds.isEmpty()) {
80
33
        result->join(moveBounds);
81
33
    }
82
195
    return true;
83
339
}