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