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)
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)
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() != NULL) {
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        if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
63            ++fNumAAHairlineConcavePaths;
64        }
65    }
66}
67
68void SkPictureContentInfo::onAddPaintPtr(const SkPaint* paint) {
69    if (paint && paint->getPathEffect()) {
70        ++fNumPaintWithPathEffectUses;
71    }
72}
73
74void SkPictureContentInfo::onSaveLayer() {
75    *fSaveStack.append() = kSaveLayer_Flag;
76}
77
78void SkPictureContentInfo::onSave() {
79    *fSaveStack.append() = kSave_Flag;
80}
81
82void SkPictureContentInfo::onRestore() {
83    SkASSERT(fSaveStack.count() > 0);
84
85    bool containedSaveLayer = fSaveStack.top() & kContainedSaveLayer_Flag;
86
87    if (fSaveStack.top() & kSaveLayer_Flag) {
88        ++fNumLayers;
89        if (containedSaveLayer) {
90            ++fNumInteriorLayers;
91        } else {
92            ++fNumLeafLayers;
93        }
94        containedSaveLayer = true;
95    }
96
97    fSaveStack.pop();
98
99    if (containedSaveLayer && fSaveStack.count() > 0) {
100        fSaveStack.top() |= kContainedSaveLayer_Flag;
101    }
102}
103
104void SkPictureContentInfo::rescindLastSave() {
105    SkASSERT(fSaveStack.count() > 0);
106    SkASSERT(fSaveStack.top() & kSave_Flag);
107
108    bool containedSaveLayer = fSaveStack.top() & kContainedSaveLayer_Flag;
109
110    fSaveStack.pop();
111
112    if (containedSaveLayer && fSaveStack.count() > 0) {
113        fSaveStack.top() |= kContainedSaveLayer_Flag;
114    }
115}
116
117void SkPictureContentInfo::rescindLastSaveLayer() {
118    SkASSERT(fSaveStack.count() > 0);
119    SkASSERT(fSaveStack.top() & kSaveLayer_Flag);
120
121    bool containedSaveLayer = fSaveStack.top() & kContainedSaveLayer_Flag;
122
123    fSaveStack.pop();
124
125    if (containedSaveLayer && fSaveStack.count() > 0) {
126        fSaveStack.top() |= kContainedSaveLayer_Flag;
127    }
128}
129
130void SkPictureContentInfo::set(const SkPictureContentInfo& src) {
131    fNumOperations = src.fNumOperations;
132    fNumTexts = src.fNumTexts;
133    fNumPaintWithPathEffectUses = src.fNumPaintWithPathEffectUses;
134    fNumFastPathDashEffects = src.fNumFastPathDashEffects;
135    fNumAAConcavePaths = src.fNumAAConcavePaths;
136    fNumAAHairlineConcavePaths = src.fNumAAHairlineConcavePaths;
137    fNumLayers = src.fNumLayers;
138    fNumInteriorLayers = src.fNumInteriorLayers;
139    fNumLeafLayers = src.fNumLeafLayers;
140    fSaveStack = src.fSaveStack;
141}
142
143void SkPictureContentInfo::reset() {
144    fNumOperations = 0;
145    fNumTexts = 0;
146    fNumPaintWithPathEffectUses = 0;
147    fNumFastPathDashEffects = 0;
148    fNumAAConcavePaths = 0;
149    fNumAAHairlineConcavePaths = 0;
150    fNumLayers = 0;
151    fNumInteriorLayers = 0;
152    fNumLeafLayers = 0;
153    fSaveStack.rewind();
154}
155
156void SkPictureContentInfo::swap(SkPictureContentInfo* other) {
157    SkTSwap(fNumOperations, other->fNumOperations);
158    SkTSwap(fNumTexts, other->fNumTexts);
159    SkTSwap(fNumPaintWithPathEffectUses, other->fNumPaintWithPathEffectUses);
160    SkTSwap(fNumFastPathDashEffects, other->fNumFastPathDashEffects);
161    SkTSwap(fNumAAConcavePaths, other->fNumAAConcavePaths);
162    SkTSwap(fNumAAHairlineConcavePaths, other->fNumAAHairlineConcavePaths);
163    SkTSwap(fNumLayers, other->fNumLayers);
164    SkTSwap(fNumInteriorLayers, other->fNumInteriorLayers);
165    SkTSwap(fNumLeafLayers, other->fNumLeafLayers);
166    fSaveStack.swap(other->fSaveStack);
167}
168