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 "Test.h" 9 #include "RecordTestUtils.h" 10 11 #include "SkColorFilter.h" 12 #include "SkRecord.h" 13 #include "SkRecordOpts.h" 14 #include "SkRecorder.h" 15 #include "SkRecords.h" 16 #include "SkXfermode.h" 17 #include "SkPictureRecorder.h" 18 #include "SkPictureImageFilter.h" 19 20 static const int W = 1920, H = 1080; 21 22 DEF_TEST(RecordOpts_NoopDraw, r) { 23 SkRecord record; 24 SkRecorder recorder(&record, W, H); 25 26 recorder.drawRect(SkRect::MakeWH(200, 200), SkPaint()); 27 recorder.drawRect(SkRect::MakeWH(300, 300), SkPaint()); 28 recorder.drawRect(SkRect::MakeWH(100, 100), SkPaint()); 29 30 record.replace<SkRecords::NoOp>(1); // NoOps should be allowed. 31 32 SkRecordNoopSaveRestores(&record); 33 34 REPORTER_ASSERT(r, 2 == count_instances_of_type<SkRecords::DrawRect>(record)); 35 } 36 37 DEF_TEST(RecordOpts_SingleNoopSaveRestore, r) { 38 SkRecord record; 39 SkRecorder recorder(&record, W, H); 40 41 recorder.save(); 42 recorder.clipRect(SkRect::MakeWH(200, 200)); 43 recorder.restore(); 44 45 SkRecordNoopSaveRestores(&record); 46 for (unsigned i = 0; i < 3; i++) { 47 assert_type<SkRecords::NoOp>(r, record, i); 48 } 49 } 50 51 DEF_TEST(RecordOpts_NoopSaveRestores, r) { 52 SkRecord record; 53 SkRecorder recorder(&record, W, H); 54 55 // The second pass will clean up this pair after the first pass noops all the innards. 56 recorder.save(); 57 // A simple pointless pair of save/restore. 58 recorder.save(); 59 recorder.restore(); 60 61 // As long as we don't draw in there, everything is a noop. 62 recorder.save(); 63 recorder.clipRect(SkRect::MakeWH(200, 200)); 64 recorder.clipRect(SkRect::MakeWH(100, 100)); 65 recorder.restore(); 66 recorder.restore(); 67 68 SkRecordNoopSaveRestores(&record); 69 for (unsigned index = 0; index < record.count(); index++) { 70 assert_type<SkRecords::NoOp>(r, record, index); 71 } 72 } 73 74 DEF_TEST(RecordOpts_SaveSaveLayerRestoreRestore, r) { 75 SkRecord record; 76 SkRecorder recorder(&record, W, H); 77 78 // A previous bug NoOp'd away the first 3 commands. 79 recorder.save(); 80 recorder.saveLayer(NULL, NULL); 81 recorder.restore(); 82 recorder.restore(); 83 84 SkRecordNoopSaveRestores(&record); 85 switch (record.count()) { 86 case 4: 87 assert_type<SkRecords::Save> (r, record, 0); 88 assert_type<SkRecords::SaveLayer>(r, record, 1); 89 assert_type<SkRecords::Restore> (r, record, 2); 90 assert_type<SkRecords::Restore> (r, record, 3); 91 break; 92 case 2: 93 assert_type<SkRecords::SaveLayer>(r, record, 0); 94 assert_type<SkRecords::Restore> (r, record, 1); 95 break; 96 case 0: 97 break; 98 default: 99 REPORTER_ASSERT(r, false); 100 } 101 } 102 103 static void assert_savelayer_restore(skiatest::Reporter* r, 104 SkRecord* record, 105 unsigned i, 106 bool shouldBeNoOped) { 107 SkRecordNoopSaveLayerDrawRestores(record); 108 if (shouldBeNoOped) { 109 assert_type<SkRecords::NoOp>(r, *record, i); 110 assert_type<SkRecords::NoOp>(r, *record, i+2); 111 } else { 112 assert_type<SkRecords::SaveLayer>(r, *record, i); 113 assert_type<SkRecords::Restore>(r, *record, i+2); 114 } 115 } 116 117 DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) { 118 SkRecord record; 119 SkRecorder recorder(&record, W, H); 120 121 SkRect bounds = SkRect::MakeWH(100, 200); 122 SkRect draw = SkRect::MakeWH(50, 60); 123 124 SkPaint alphaOnlyLayerPaint, translucentLayerPaint, xfermodeLayerPaint; 125 alphaOnlyLayerPaint.setColor(0x03000000); // Only alpha. 126 translucentLayerPaint.setColor(0x03040506); // Not only alpha. 127 xfermodeLayerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode); // Any effect will do. 128 129 SkPaint opaqueDrawPaint, translucentDrawPaint; 130 opaqueDrawPaint.setColor(0xFF020202); // Opaque. 131 translucentDrawPaint.setColor(0x0F020202); // Not opaque. 132 133 // SaveLayer/Restore removed: No paint = no point. 134 recorder.saveLayer(NULL, NULL); 135 recorder.drawRect(draw, opaqueDrawPaint); 136 recorder.restore(); 137 assert_savelayer_restore(r, &record, 0, true); 138 139 // Bounds don't matter. 140 recorder.saveLayer(&bounds, NULL); 141 recorder.drawRect(draw, opaqueDrawPaint); 142 recorder.restore(); 143 assert_savelayer_restore(r, &record, 3, true); 144 145 // TODO(mtklein): test case with null draw paint 146 147 // No change: layer paint isn't alpha-only. 148 recorder.saveLayer(NULL, &translucentLayerPaint); 149 recorder.drawRect(draw, opaqueDrawPaint); 150 recorder.restore(); 151 assert_savelayer_restore(r, &record, 6, false); 152 153 // No change: layer paint has an effect. 154 recorder.saveLayer(NULL, &xfermodeLayerPaint); 155 recorder.drawRect(draw, opaqueDrawPaint); 156 recorder.restore(); 157 assert_savelayer_restore(r, &record, 9, false); 158 159 // SaveLayer/Restore removed: we can fold in the alpha! 160 recorder.saveLayer(NULL, &alphaOnlyLayerPaint); 161 recorder.drawRect(draw, translucentDrawPaint); 162 recorder.restore(); 163 assert_savelayer_restore(r, &record, 12, true); 164 165 // SaveLayer/Restore removed: we can fold in the alpha! 166 recorder.saveLayer(NULL, &alphaOnlyLayerPaint); 167 recorder.drawRect(draw, opaqueDrawPaint); 168 recorder.restore(); 169 assert_savelayer_restore(r, &record, 15, true); 170 171 const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, record, 16); 172 REPORTER_ASSERT(r, drawRect != NULL); 173 REPORTER_ASSERT(r, drawRect->paint.getColor() == 0x03020202); 174 } 175 176 static void assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter* r, 177 SkRecord* record, 178 unsigned i, 179 bool shouldBeNoOped) { 180 SkRecordMergeSvgOpacityAndFilterLayers(record); 181 if (shouldBeNoOped) { 182 assert_type<SkRecords::NoOp>(r, *record, i); 183 assert_type<SkRecords::NoOp>(r, *record, i + 6); 184 } else { 185 assert_type<SkRecords::SaveLayer>(r, *record, i); 186 assert_type<SkRecords::Restore>(r, *record, i + 6); 187 } 188 } 189 190 DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers, r) { 191 SkRecord record; 192 SkRecorder recorder(&record, W, H); 193 194 SkRect bounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(200)); 195 SkRect clip = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(60)); 196 197 SkPaint alphaOnlyLayerPaint; 198 alphaOnlyLayerPaint.setColor(0x03000000); // Only alpha. 199 SkPaint translucentLayerPaint; 200 translucentLayerPaint.setColor(0x03040506); // Not only alpha. 201 SkPaint xfermodePaint; 202 xfermodePaint.setXfermodeMode(SkXfermode::kDstIn_Mode); 203 SkPaint colorFilterPaint; 204 colorFilterPaint.setColorFilter( 205 SkColorFilter::CreateModeFilter(SK_ColorLTGRAY, SkXfermode::kSrcIn_Mode))->unref(); 206 207 SkPaint opaqueFilterLayerPaint; 208 opaqueFilterLayerPaint.setColor(0xFF020202); // Opaque. 209 SkPaint translucentFilterLayerPaint; 210 translucentFilterLayerPaint.setColor(0x0F020202); // Not opaque. 211 SkAutoTUnref<SkPicture> shape; 212 { 213 SkPictureRecorder recorder; 214 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(100), SkIntToScalar(100)); 215 SkPaint shapePaint; 216 shapePaint.setColor(SK_ColorWHITE); 217 canvas->drawRect(SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50)), shapePaint); 218 shape.reset(recorder.endRecordingAsPicture()); 219 } 220 translucentFilterLayerPaint.setImageFilter(SkPictureImageFilter::Create(shape))->unref(); 221 222 int index = 0; 223 224 { 225 // Any combination of these should cause the pattern to be optimized. 226 SkRect* firstBounds[] = { NULL, &bounds }; 227 SkPaint* firstPaints[] = { NULL, &alphaOnlyLayerPaint }; 228 SkRect* secondBounds[] = { NULL, &bounds }; 229 SkPaint* secondPaints[] = { &opaqueFilterLayerPaint, &translucentFilterLayerPaint }; 230 231 for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) { 232 for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) { 233 for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) { 234 for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) { 235 recorder.saveLayer(firstBounds[i], firstPaints[j]); 236 recorder.save(); 237 recorder.clipRect(clip); 238 recorder.saveLayer(secondBounds[k], secondPaints[m]); 239 recorder.restore(); 240 recorder.restore(); 241 recorder.restore(); 242 assert_merge_svg_opacity_and_filter_layers(r, &record, index, true); 243 index += 7; 244 } 245 } 246 } 247 } 248 } 249 250 // These should cause the pattern to stay unoptimized: 251 struct { 252 SkPaint* firstPaint; 253 SkPaint* secondPaint; 254 } noChangeTests[] = { 255 // No change: NULL filter layer paint not implemented. 256 { &alphaOnlyLayerPaint, NULL }, 257 // No change: layer paint is not alpha-only. 258 { &translucentLayerPaint, &opaqueFilterLayerPaint }, 259 // No change: layer paint has an xfereffect. 260 { &xfermodePaint, &opaqueFilterLayerPaint }, 261 // No change: filter layer paint has an xfereffect. 262 { &alphaOnlyLayerPaint, &xfermodePaint }, 263 // No change: layer paint has a color filter. 264 { &colorFilterPaint, &opaqueFilterLayerPaint }, 265 // No change: filter layer paint has a color filter (until the optimization accounts for 266 // constant color draws that can filter the color). 267 { &alphaOnlyLayerPaint, &colorFilterPaint } 268 }; 269 270 for (size_t i = 0; i < SK_ARRAY_COUNT(noChangeTests); ++i) { 271 recorder.saveLayer(NULL, noChangeTests[i].firstPaint); 272 recorder.save(); 273 recorder.clipRect(clip); 274 recorder.saveLayer(NULL, noChangeTests[i].secondPaint); 275 recorder.restore(); 276 recorder.restore(); 277 recorder.restore(); 278 assert_merge_svg_opacity_and_filter_layers(r, &record, index, false); 279 index += 7; 280 } 281 282 // Test the folded alpha value. 283 recorder.saveLayer(NULL, &alphaOnlyLayerPaint); 284 recorder.save(); 285 recorder.clipRect(clip); 286 recorder.saveLayer(NULL, &opaqueFilterLayerPaint); 287 recorder.restore(); 288 recorder.restore(); 289 recorder.restore(); 290 assert_merge_svg_opacity_and_filter_layers(r, &record, index, true); 291 292 const SkRecords::SaveLayer* saveLayer = assert_type<SkRecords::SaveLayer>(r, record, index + 3); 293 REPORTER_ASSERT(r, saveLayer != NULL); 294 REPORTER_ASSERT(r, saveLayer->paint->getColor() == 0x03020202); 295 296 index += 7; 297 298 // Test that currently we do not fold alphas for patterns without the clip. This is just not 299 // implemented. 300 recorder.saveLayer(NULL, &alphaOnlyLayerPaint); 301 recorder.saveLayer(NULL, &opaqueFilterLayerPaint); 302 recorder.restore(); 303 recorder.restore(); 304 SkRecordMergeSvgOpacityAndFilterLayers(&record); 305 assert_type<SkRecords::SaveLayer>(r, record, index); 306 assert_type<SkRecords::SaveLayer>(r, record, index + 1); 307 assert_type<SkRecords::Restore>(r, record, index + 2); 308 assert_type<SkRecords::Restore>(r, record, index + 3); 309 index += 4; 310 } 311