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 "SkPaint.h"
9#include "SkPathEffect.h"
10#include "SkPictureContentInfo.h"
11
12bool SkPictureContentInfo::suitableForGpuRasterization(GrContext* context, const char **reason,
13                                                       int sampleCount) const {
14    // TODO: the heuristic used here needs to be refined
15    static const int kNumPaintWithPathEffectUsesTol = 1;
16    static const int kNumAAConcavePaths = 5;
17
18    SkASSERT(fNumAAHairlineConcavePaths <= fNumAAConcavePaths);
19
20    int numNonDashedPathEffects = fNumPaintWithPathEffectUses -
21                                  fNumFastPathDashEffects;
22
23    bool suitableForDash = (0 == fNumPaintWithPathEffectUses) ||
24                           (numNonDashedPathEffects < kNumPaintWithPathEffectUsesTol
25                            && 0 == sampleCount);
26
27    bool ret = suitableForDash &&
28                    (fNumAAConcavePaths - fNumAAHairlineConcavePaths - fNumAADFEligibleConcavePaths)
29                    < kNumAAConcavePaths;
30    if (!ret && reason) {
31        if (!suitableForDash) {
32            if (0 != sampleCount) {
33                *reason = "Can't use multisample on dash effect.";
34            } else {
35                *reason = "Too many non dashed path effects.";
36            }
37        } else if ((fNumAAConcavePaths - fNumAAHairlineConcavePaths - fNumAADFEligibleConcavePaths)
38                    >= kNumAAConcavePaths) {
39            *reason = "Too many anti-aliased concave paths.";
40        } else {
41            *reason = "Unknown reason for GPU unsuitability.";
42        }
43    }
44    return ret;
45}
46
47void SkPictureContentInfo::onDrawPoints(size_t count, const SkPaint& paint) {
48    if (paint.getPathEffect() != nullptr) {
49        SkPathEffect::DashInfo info;
50        SkPathEffect::DashType dashType = paint.getPathEffect()->asADash(&info);
51        if (2 == count && SkPaint::kRound_Cap != paint.getStrokeCap() &&
52            SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
53            ++fNumFastPathDashEffects;
54        }
55    }
56}
57
58void SkPictureContentInfo::onDrawPath(const SkPath& path, const SkPaint& paint) {
59    if (paint.isAntiAlias() && !path.isConvex()) {
60        ++fNumAAConcavePaths;
61
62        SkPaint::Style paintStyle = paint.getStyle();
63        const SkRect& pathBounds = path.getBounds();
64        if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
65            ++fNumAAHairlineConcavePaths;
66        } else if (SkPaint::kFill_Style == paintStyle && pathBounds.width() < 64.f &&
67                   pathBounds.height() < 64.f && !path.isVolatile()) {
68            ++fNumAADFEligibleConcavePaths;
69        }
70    }
71}
72
73void SkPictureContentInfo::onAddPaintPtr(const SkPaint* paint) {
74    if (paint && paint->getPathEffect()) {
75        ++fNumPaintWithPathEffectUses;
76    }
77}
78
79void SkPictureContentInfo::onSaveLayer() {
80    *fSaveStack.append() = kSaveLayer_Flag;
81}
82
83void SkPictureContentInfo::onSave() {
84    *fSaveStack.append() = kSave_Flag;
85}
86
87void SkPictureContentInfo::onRestore() {
88    SkASSERT(fSaveStack.count() > 0);
89
90    bool containedSaveLayer = fSaveStack.top() & kContainedSaveLayer_Flag;
91
92    if (fSaveStack.top() & kSaveLayer_Flag) {
93        ++fNumLayers;
94        if (containedSaveLayer) {
95            ++fNumInteriorLayers;
96        } else {
97            ++fNumLeafLayers;
98        }
99        containedSaveLayer = true;
100    }
101
102    fSaveStack.pop();
103
104    if (containedSaveLayer && fSaveStack.count() > 0) {
105        fSaveStack.top() |= kContainedSaveLayer_Flag;
106    }
107}
108
109void SkPictureContentInfo::rescindLastSave() {
110    SkASSERT(fSaveStack.count() > 0);
111    SkASSERT(fSaveStack.top() & kSave_Flag);
112
113    bool containedSaveLayer = fSaveStack.top() & kContainedSaveLayer_Flag;
114
115    fSaveStack.pop();
116
117    if (containedSaveLayer && fSaveStack.count() > 0) {
118        fSaveStack.top() |= kContainedSaveLayer_Flag;
119    }
120}
121
122void SkPictureContentInfo::rescindLastSaveLayer() {
123    SkASSERT(fSaveStack.count() > 0);
124    SkASSERT(fSaveStack.top() & kSaveLayer_Flag);
125
126    bool containedSaveLayer = fSaveStack.top() & kContainedSaveLayer_Flag;
127
128    fSaveStack.pop();
129
130    if (containedSaveLayer && fSaveStack.count() > 0) {
131        fSaveStack.top() |= kContainedSaveLayer_Flag;
132    }
133}
134
135void SkPictureContentInfo::set(const SkPictureContentInfo& src) {
136    fNumOperations = src.fNumOperations;
137    fNumTexts = src.fNumTexts;
138    fNumPaintWithPathEffectUses = src.fNumPaintWithPathEffectUses;
139    fNumFastPathDashEffects = src.fNumFastPathDashEffects;
140    fNumAAConcavePaths = src.fNumAAConcavePaths;
141    fNumAAHairlineConcavePaths = src.fNumAAHairlineConcavePaths;
142    fNumAADFEligibleConcavePaths = src.fNumAADFEligibleConcavePaths;
143    fNumLayers = src.fNumLayers;
144    fNumInteriorLayers = src.fNumInteriorLayers;
145    fNumLeafLayers = src.fNumLeafLayers;
146    fSaveStack = src.fSaveStack;
147}
148
149void SkPictureContentInfo::reset() {
150    fNumOperations = 0;
151    fNumTexts = 0;
152    fNumPaintWithPathEffectUses = 0;
153    fNumFastPathDashEffects = 0;
154    fNumAAConcavePaths = 0;
155    fNumAAHairlineConcavePaths = 0;
156    fNumAADFEligibleConcavePaths = 0;
157    fNumLayers = 0;
158    fNumInteriorLayers = 0;
159    fNumLeafLayers = 0;
160    fSaveStack.rewind();
161}
162
163void SkPictureContentInfo::swap(SkPictureContentInfo* other) {
164    SkTSwap(fNumOperations, other->fNumOperations);
165    SkTSwap(fNumTexts, other->fNumTexts);
166    SkTSwap(fNumPaintWithPathEffectUses, other->fNumPaintWithPathEffectUses);
167    SkTSwap(fNumFastPathDashEffects, other->fNumFastPathDashEffects);
168    SkTSwap(fNumAAConcavePaths, other->fNumAAConcavePaths);
169    SkTSwap(fNumAAHairlineConcavePaths, other->fNumAAHairlineConcavePaths);
170    SkTSwap(fNumAADFEligibleConcavePaths, other->fNumAADFEligibleConcavePaths);
171    SkTSwap(fNumLayers, other->fNumLayers);
172    SkTSwap(fNumInteriorLayers, other->fNumInteriorLayers);
173    SkTSwap(fNumLeafLayers, other->fNumLeafLayers);
174    fSaveStack.swap(other->fSaveStack);
175}
176