1 /* 2 * Copyright 2013 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 "SkArenaAlloc.h" 9 #include "SkBitmap.h" 10 #include "SkBitmapDevice.h" 11 #include "SkCanvas.h" 12 #include "SkDraw.h" 13 #include "SkLayerDrawLooper.h" 14 #include "SkMatrix.h" 15 #include "SkPaint.h" 16 #include "SkRect.h" 17 #include "SkRefCnt.h" 18 #include "SkScalar.h" 19 #include "Test.h" 20 21 static SkBitmap make_bm(int w, int h) { 22 SkBitmap bm; 23 bm.allocN32Pixels(w, h); 24 return bm; 25 } 26 27 // TODO: can this be derived from SkBaseDevice? 28 class FakeDevice : public SkBitmapDevice { 29 public: 30 FakeDevice() : INHERITED(make_bm(100, 100), SkSurfaceProps(0, kUnknown_SkPixelGeometry), 31 nullptr, nullptr) { 32 } 33 34 void drawRect(const SkRect& r, const SkPaint& paint) override { 35 fLastMatrix = this->ctm(); 36 this->INHERITED::drawRect(r, paint); 37 } 38 39 SkMatrix fLastMatrix; 40 41 private: 42 typedef SkBitmapDevice INHERITED; 43 }; 44 45 static void test_frontToBack(skiatest::Reporter* reporter) { 46 SkLayerDrawLooper::Builder looperBuilder; 47 SkLayerDrawLooper::LayerInfo layerInfo; 48 49 // Add the front layer, with the defaults. 50 (void)looperBuilder.addLayer(layerInfo); 51 52 // Add the back layer, with some layer info set. 53 layerInfo.fOffset.set(10.0f, 20.0f); 54 layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit; 55 SkPaint* layerPaint = looperBuilder.addLayer(layerInfo); 56 layerPaint->setBlendMode(SkBlendMode::kSrc); 57 58 FakeDevice device; 59 SkCanvas canvas(sk_ref_sp(&device)); 60 SkPaint paint; 61 auto looper(looperBuilder.detach()); 62 SkArenaAlloc alloc{48}; 63 SkDrawLooper::Context* context = looper->makeContext(&canvas, &alloc); 64 65 // The back layer should come first. 66 REPORTER_ASSERT(reporter, context->next(&canvas, &paint)); 67 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrc); 68 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint); 69 REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX()); 70 REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY()); 71 paint.reset(); 72 73 // Then the front layer. 74 REPORTER_ASSERT(reporter, context->next(&canvas, &paint)); 75 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrcOver); 76 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint); 77 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX()); 78 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY()); 79 80 // Only two layers were added, so that should be the end. 81 REPORTER_ASSERT(reporter, !context->next(&canvas, &paint)); 82 } 83 84 static void test_backToFront(skiatest::Reporter* reporter) { 85 SkLayerDrawLooper::Builder looperBuilder; 86 SkLayerDrawLooper::LayerInfo layerInfo; 87 88 // Add the back layer, with the defaults. 89 (void)looperBuilder.addLayerOnTop(layerInfo); 90 91 // Add the front layer, with some layer info set. 92 layerInfo.fOffset.set(10.0f, 20.0f); 93 layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit; 94 SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo); 95 layerPaint->setBlendMode(SkBlendMode::kSrc); 96 97 FakeDevice device; 98 SkCanvas canvas(sk_ref_sp(&device)); 99 SkPaint paint; 100 auto looper(looperBuilder.detach()); 101 SkArenaAlloc alloc{48}; 102 SkDrawLooper::Context* context = looper->makeContext(&canvas, &alloc); 103 104 // The back layer should come first. 105 REPORTER_ASSERT(reporter, context->next(&canvas, &paint)); 106 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrcOver); 107 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint); 108 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX()); 109 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY()); 110 paint.reset(); 111 112 // Then the front layer. 113 REPORTER_ASSERT(reporter, context->next(&canvas, &paint)); 114 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrc); 115 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint); 116 REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX()); 117 REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY()); 118 119 // Only two layers were added, so that should be the end. 120 REPORTER_ASSERT(reporter, !context->next(&canvas, &paint)); 121 } 122 123 static void test_mixed(skiatest::Reporter* reporter) { 124 SkLayerDrawLooper::Builder looperBuilder; 125 SkLayerDrawLooper::LayerInfo layerInfo; 126 127 // Add the back layer, with the defaults. 128 (void)looperBuilder.addLayer(layerInfo); 129 130 // Add the front layer, with some layer info set. 131 layerInfo.fOffset.set(10.0f, 20.0f); 132 layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit; 133 SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo); 134 layerPaint->setBlendMode(SkBlendMode::kSrc); 135 136 FakeDevice device; 137 SkCanvas canvas(sk_ref_sp(&device)); 138 SkPaint paint; 139 sk_sp<SkDrawLooper> looper(looperBuilder.detach()); 140 SkArenaAlloc alloc{48}; 141 SkDrawLooper::Context* context = looper->makeContext(&canvas, &alloc); 142 143 // The back layer should come first. 144 REPORTER_ASSERT(reporter, context->next(&canvas, &paint)); 145 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrcOver); 146 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint); 147 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX()); 148 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY()); 149 paint.reset(); 150 151 // Then the front layer. 152 REPORTER_ASSERT(reporter, context->next(&canvas, &paint)); 153 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrc); 154 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint); 155 REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX()); 156 REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY()); 157 158 // Only two layers were added, so that should be the end. 159 REPORTER_ASSERT(reporter, !context->next(&canvas, &paint)); 160 } 161 162 DEF_TEST(LayerDrawLooper, reporter) { 163 test_frontToBack(reporter); 164 test_backToFront(reporter); 165 test_mixed(reporter); 166 } 167