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
8#include "GrGLPathRange.h"
9#include "GrGLPath.h"
10#include "GrGLPathRendering.h"
11#include "GrGLGpu.h"
12
13GrGLPathRange::GrGLPathRange(GrGLGpu* gpu, PathGenerator* pathGenerator, const GrStyle& style)
14    : INHERITED(gpu, pathGenerator),
15      fStyle(style),
16      fBasePathID(gpu->glPathRendering()->genPaths(this->getNumPaths())),
17      fGpuMemorySize(0) {
18    this->init();
19    this->registerWithCache(SkBudgeted::kYes);
20}
21
22GrGLPathRange::GrGLPathRange(GrGLGpu* gpu,
23                             GrGLuint basePathID,
24                             int numPaths,
25                             size_t gpuMemorySize,
26                             const GrStyle& style)
27    : INHERITED(gpu, numPaths),
28      fStyle(style),
29      fBasePathID(basePathID),
30      fGpuMemorySize(gpuMemorySize) {
31    this->init();
32    this->registerWithCache(SkBudgeted::kYes);
33}
34
35void GrGLPathRange::init() {
36    const SkStrokeRec& stroke = fStyle.strokeRec();
37    // Must force fill:
38    // * dashing: NVPR stroke dashing is different to Skia.
39    // * end caps: NVPR stroking degenerate contours with end caps is different to Skia.
40    bool forceFill = fStyle.pathEffect() ||
41            (stroke.needToApply() && stroke.getCap() != SkPaint::kButt_Cap);
42
43    if (forceFill) {
44        fShouldStroke = false;
45        fShouldFill = true;
46    } else {
47        fShouldStroke = stroke.needToApply();
48        fShouldFill = stroke.isFillStyle() ||
49                stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style;
50    }
51}
52
53void GrGLPathRange::onInitPath(int index, const SkPath& origSkPath) const {
54    GrGLGpu* gpu = static_cast<GrGLGpu*>(this->getGpu());
55    if (nullptr == gpu) {
56        return;
57    }
58    // Make sure the path at this index hasn't been initted already.
59    SkDEBUGCODE(
60        GrGLboolean isPath;
61        GR_GL_CALL_RET(gpu->glInterface(), isPath, IsPath(fBasePathID + index)));
62    SkASSERT(GR_GL_FALSE == isPath);
63
64    if (origSkPath.isEmpty()) {
65        GrGLPath::InitPathObjectEmptyPath(gpu, fBasePathID + index);
66    } else if (fShouldStroke) {
67        GrGLPath::InitPathObjectPathData(gpu, fBasePathID + index, origSkPath);
68        GrGLPath::InitPathObjectStroke(gpu, fBasePathID + index, fStyle.strokeRec());
69    } else {
70        const SkPath* skPath = &origSkPath;
71        SkTLazy<SkPath> tmpPath;
72        if (!fStyle.isSimpleFill()) {
73            SkStrokeRec::InitStyle fill;
74            // The path effect must be applied to the path. However, if a path effect is present,
75            // we must convert all the paths to fills. The path effect application may leave
76            // simple paths as strokes but converts other paths to fills.
77            // Thus we must stroke the strokes here, so that all paths in the
78            // path range are using the same style.
79            if (!fStyle.applyToPath(tmpPath.init(), &fill, *skPath, SK_Scalar1)) {
80                return;
81            }
82            // We shouldn't have allowed hairlines or arbitrary path effect styles to get here
83            // so after application we better have a filled path.
84            SkASSERT(SkStrokeRec::kFill_InitStyle == fill);
85            skPath = tmpPath.get();
86
87        }
88        GrGLPath::InitPathObjectPathData(gpu, fBasePathID + index, *skPath);
89    }
90    // TODO: Use a better approximation for the individual path sizes.
91    fGpuMemorySize += 100;
92}
93
94void GrGLPathRange::onRelease() {
95    SkASSERT(this->getGpu());
96
97    if (0 != fBasePathID) {
98        static_cast<GrGLGpu*>(this->getGpu())->glPathRendering()->deletePaths(fBasePathID,
99                                                                              this->getNumPaths());
100        fBasePathID = 0;
101    }
102
103    INHERITED::onRelease();
104}
105
106void GrGLPathRange::onAbandon() {
107    fBasePathID = 0;
108
109    INHERITED::onAbandon();
110}
111