Index: src/record/SkRecordOpts.cpp |
diff --git a/src/record/SkRecordOpts.cpp b/src/record/SkRecordOpts.cpp |
index aaa611cf392cf6126b5548f9c5f4e1bcb6a46e59..5b648f4215e5bcfae6e2878981b0e8b28b7ed948 100644 |
--- a/src/record/SkRecordOpts.cpp |
+++ b/src/record/SkRecordOpts.cpp |
@@ -16,6 +16,7 @@ using namespace SkRecords; |
void SkRecordOptimize(SkRecord* record) { |
// TODO(mtklein): fuse independent optimizations to reduce number of passes? |
SkRecordNoopSaveRestores(record); |
+ SkRecordNoopSaveLayerDrawRestores(record); |
SkRecordAnnotateCullingPairs(record); |
SkRecordReduceDrawPosTextStrength(record); // Helpful to run this before BoundDrawPosTextH. |
SkRecordBoundDrawPosTextH(record); |
@@ -69,6 +70,73 @@ void SkRecordNoopSaveRestores(SkRecord* record) { |
while (apply(&pass, record)); // Run until it stops changing things. |
} |
+// For some SaveLayer-[drawing command]-Restore patterns, merge the SaveLayer's alpha into the |
+// draw, and no-op the SaveLayer and Restore. |
+struct SaveLayerDrawRestoreNooper { |
+ typedef Pattern3<Is<SaveLayer>, IsDraw, Is<Restore> > Pattern; |
+ |
+ bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned end) { |
+ SaveLayer* saveLayer = pattern->first<SaveLayer>(); |
+ if (saveLayer->bounds != NULL) { |
+ // SaveLayer with bounds is too tricky for us. |
+ return false; |
+ } |
+ |
+ SkPaint* layerPaint = saveLayer->paint; |
+ if (NULL == layerPaint) { |
+ // There wasn't really any point to this SaveLayer at all. |
+ return KillSaveLayerAndRestore(record, begin); |
+ } |
+ |
+ SkPaint* drawPaint = pattern->second<SkPaint>(); |
+ if (drawPaint == NULL) { |
+ // We can just give the draw the SaveLayer's paint. |
+ // TODO(mtklein): figure out how to do this clearly |
+ return false; |
+ } |
+ |
+ const uint32_t layerColor = layerPaint->getColor(); |
+ const uint32_t drawColor = drawPaint->getColor(); |
+ if (!IsOnlyAlpha(layerColor) || !IsOpaque(drawColor) || HasAnyEffect(*layerPaint)) { |
+ // Too fancy for us. Actually, as long as layerColor is just an alpha |
+ // we can blend it into drawColor's alpha; drawColor doesn't strictly have to be opaque. |
+ return false; |
+ } |
+ |
+ drawPaint->setColor(SkColorSetA(drawColor, SkColorGetA(layerColor))); |
+ return KillSaveLayerAndRestore(record, begin); |
+ } |
+ |
+ static bool KillSaveLayerAndRestore(SkRecord* record, unsigned saveLayerIndex) { |
+ record->replace<NoOp>(saveLayerIndex); // SaveLayer |
+ record->replace<NoOp>(saveLayerIndex+2); // Restore |
+ return true; |
+ } |
+ |
+ static bool HasAnyEffect(const SkPaint& paint) { |
+ return paint.getPathEffect() || |
+ paint.getShader() || |
+ paint.getXfermode() || |
+ paint.getMaskFilter() || |
+ paint.getColorFilter() || |
+ paint.getRasterizer() || |
+ paint.getLooper() || |
+ paint.getImageFilter(); |
+ } |
+ |
+ static bool IsOpaque(SkColor color) { |
+ return SkColorGetA(color) == SK_AlphaOPAQUE; |
+ } |
+ static bool IsOnlyAlpha(SkColor color) { |
+ return SK_ColorTRANSPARENT == SkColorSetA(color, SK_AlphaTRANSPARENT); |
+ } |
+}; |
+void SkRecordNoopSaveLayerDrawRestores(SkRecord* record) { |
+ SaveLayerDrawRestoreNooper pass; |
+ apply(&pass, record); |
+} |
+ |
+ |
// Replaces DrawPosText with DrawPosTextH when all Y coordinates are equal. |
struct StrengthReducer { |
typedef Pattern1<Is<DrawPosText> > Pattern; |