Line data Source code
1 : /*
2 : * Copyright 2015 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 : #ifndef SkPictureCommon_DEFINED
8 : #define SkPictureCommon_DEFINED
9 :
10 : // Some shared code used by both SkBigPicture and SkMiniPicture.
11 : // SkTextHunter -- SkRecord visitor that returns true when the op draws text.
12 : // SkBitmapHunter -- SkRecord visitor that returns true when the op draws a bitmap or image.
13 : // SkPathCounter -- SkRecord visitor that counts paths that draw slowly on the GPU.
14 :
15 : #include "SkPathEffect.h"
16 : #include "SkRecords.h"
17 : #include "SkTLogic.h"
18 :
19 : // N.B. This name is slightly historical: hunting season is now open for SkImages too.
20 : struct SkBitmapHunter {
21 : // Some ops have a paint, some have an optional paint. Either way, get back a pointer.
22 0 : static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
23 0 : static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
24 :
25 : // Main entry for visitor:
26 : // If the op is a DrawPicture, recurse.
27 : // If the op has a bitmap or image directly, return true.
28 : // If the op has a paint and the paint has a bitmap, return true.
29 : // Otherwise, return false.
30 0 : bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willPlayBackBitmaps(); }
31 0 : bool operator()(const SkRecords::DrawDrawable&) { /*TODO*/ return false; }
32 :
33 : template <typename T>
34 0 : bool operator()(const T& op) { return CheckBitmap(op); }
35 :
36 : // If the op is tagged as having an image, return true.
37 : template <typename T>
38 0 : static SK_WHEN(T::kTags & SkRecords::kHasImage_Tag, bool) CheckBitmap(const T&) {
39 0 : return true;
40 : }
41 :
42 : // If not, look for one in its paint (if it has a paint).
43 : template <typename T>
44 0 : static SK_WHEN(!(T::kTags & SkRecords::kHasImage_Tag), bool) CheckBitmap(const T& op) {
45 0 : return CheckPaint(op);
46 : }
47 :
48 : // Most draws-type ops have paints.
49 : template <typename T>
50 0 : static SK_WHEN(T::kTags & SkRecords::kHasPaint_Tag, bool) CheckPaint(const T& op) {
51 0 : return PaintHasBitmap(AsPtr(op.paint));
52 : }
53 :
54 : template <typename T>
55 0 : static SK_WHEN(!(T::kTags & SkRecords::kHasPaint_Tag), bool) CheckPaint(const T&) {
56 0 : return false;
57 : }
58 :
59 : private:
60 0 : static bool PaintHasBitmap(const SkPaint* paint) {
61 0 : if (paint) {
62 0 : const SkShader* shader = paint->getShader();
63 0 : if (shader && shader->isAImage()) {
64 0 : return true;
65 : }
66 : }
67 0 : return false;
68 : }
69 : };
70 :
71 : // TODO: might be nicer to have operator() return an int (the number of slow paths) ?
72 : struct SkPathCounter {
73 : // Some ops have a paint, some have an optional paint. Either way, get back a pointer.
74 0 : static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
75 0 : static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
76 :
77 0 : SkPathCounter() : fNumSlowPathsAndDashEffects(0) {}
78 :
79 : // Recurse into nested pictures.
80 0 : void operator()(const SkRecords::DrawPicture& op) {
81 0 : fNumSlowPathsAndDashEffects += op.picture->numSlowPaths();
82 0 : }
83 0 : void operator()(const SkRecords::DrawDrawable&) { /* TODO */ }
84 :
85 0 : void checkPaint(const SkPaint* paint) {
86 0 : if (paint && paint->getPathEffect()) {
87 : // Initially assume it's slow.
88 0 : fNumSlowPathsAndDashEffects++;
89 : }
90 0 : }
91 :
92 0 : void operator()(const SkRecords::DrawPoints& op) {
93 0 : this->checkPaint(&op.paint);
94 0 : const SkPathEffect* effect = op.paint.getPathEffect();
95 0 : if (effect) {
96 0 : SkPathEffect::DashInfo info;
97 0 : SkPathEffect::DashType dashType = effect->asADash(&info);
98 0 : if (2 == op.count && SkPaint::kRound_Cap != op.paint.getStrokeCap() &&
99 0 : SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
100 0 : fNumSlowPathsAndDashEffects--;
101 : }
102 : }
103 0 : }
104 :
105 0 : void operator()(const SkRecords::DrawPath& op) {
106 0 : this->checkPaint(&op.paint);
107 0 : if (op.paint.isAntiAlias() && !op.path.isConvex()) {
108 0 : SkPaint::Style paintStyle = op.paint.getStyle();
109 0 : const SkRect& pathBounds = op.path.getBounds();
110 0 : if (SkPaint::kStroke_Style == paintStyle &&
111 0 : 0 == op.paint.getStrokeWidth()) {
112 : // AA hairline concave path is not slow.
113 0 : } else if (SkPaint::kFill_Style == paintStyle && pathBounds.width() < 64.f &&
114 0 : pathBounds.height() < 64.f && !op.path.isVolatile()) {
115 : // AADF eligible concave path is not slow.
116 : } else {
117 0 : fNumSlowPathsAndDashEffects++;
118 : }
119 : }
120 0 : }
121 :
122 0 : void operator()(const SkRecords::ClipPath& op) {
123 : // TODO: does the SkRegion op matter?
124 0 : if (op.opAA.aa() && !op.path.isConvex()) {
125 0 : fNumSlowPathsAndDashEffects++;
126 : }
127 0 : }
128 :
129 0 : void operator()(const SkRecords::SaveLayer& op) {
130 0 : this->checkPaint(AsPtr(op.paint));
131 0 : }
132 :
133 : template <typename T>
134 0 : SK_WHEN(T::kTags & SkRecords::kDraw_Tag, void) operator()(const T& op) {
135 0 : this->checkPaint(AsPtr(op.paint));
136 0 : }
137 :
138 : template <typename T>
139 0 : SK_WHEN(!(T::kTags & SkRecords::kDraw_Tag), void) operator()(const T& op) { /* do nothing */ }
140 :
141 : int fNumSlowPathsAndDashEffects;
142 : };
143 : #endif // SkPictureCommon_DEFINED
|