| /* |
| * Copyright 2013 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/core/SkBitmap.h" |
| #include "include/core/SkCanvas.h" |
| #include "include/core/SkMatrix.h" |
| #include "include/core/SkPaint.h" |
| #include "include/core/SkRect.h" |
| #include "include/core/SkRefCnt.h" |
| #include "include/core/SkScalar.h" |
| #include "include/effects/SkLayerDrawLooper.h" |
| #include "src/core/SkArenaAlloc.h" |
| #include "src/core/SkBitmapDevice.h" |
| #include "src/core/SkDraw.h" |
| #include "tests/Test.h" |
| |
| static SkBitmap make_bm(int w, int h) { |
| SkBitmap bm; |
| bm.allocN32Pixels(w, h); |
| return bm; |
| } |
| |
| // TODO: can this be derived from SkBaseDevice? |
| class FakeDevice : public SkBitmapDevice { |
| public: |
| FakeDevice() : INHERITED(make_bm(100, 100), SkSurfaceProps(0, kUnknown_SkPixelGeometry), |
| nullptr, nullptr) { |
| } |
| |
| void drawRect(const SkRect& r, const SkPaint& paint) override { |
| fLastMatrix = this->localToDevice(); |
| this->INHERITED::drawRect(r, paint); |
| } |
| |
| SkMatrix fLastMatrix; |
| |
| private: |
| using INHERITED = SkBitmapDevice; |
| }; |
| |
| static void test_frontToBack(skiatest::Reporter* reporter) { |
| SkLayerDrawLooper::Builder looperBuilder; |
| SkLayerDrawLooper::LayerInfo layerInfo; |
| |
| // Add the front layer, with the defaults. |
| (void)looperBuilder.addLayer(layerInfo); |
| |
| // Add the back layer, with some layer info set. |
| layerInfo.fOffset.set(10.0f, 20.0f); |
| layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit; |
| SkPaint* layerPaint = looperBuilder.addLayer(layerInfo); |
| layerPaint->setBlendMode(SkBlendMode::kSrc); |
| |
| SkPaint paint; |
| auto looper(looperBuilder.detach()); |
| SkArenaAlloc alloc{48}; |
| SkDrawLooper::Context* context = looper->makeContext(&alloc); |
| SkDrawLooper::Context::Info info; |
| |
| // The back layer should come first. |
| REPORTER_ASSERT(reporter, context->next(&info, &paint)); |
| REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrc); |
| REPORTER_ASSERT(reporter, 10.0f == info.fTranslate.fX); |
| REPORTER_ASSERT(reporter, 20.0f == info.fTranslate.fY); |
| paint.reset(); |
| |
| // Then the front layer. |
| REPORTER_ASSERT(reporter, context->next(&info, &paint)); |
| REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrcOver); |
| REPORTER_ASSERT(reporter, 0.0f == info.fTranslate.fX); |
| REPORTER_ASSERT(reporter, 0.0f == info.fTranslate.fY); |
| |
| // Only two layers were added, so that should be the end. |
| REPORTER_ASSERT(reporter, !context->next(&info, &paint)); |
| } |
| |
| static void test_backToFront(skiatest::Reporter* reporter) { |
| SkLayerDrawLooper::Builder looperBuilder; |
| SkLayerDrawLooper::LayerInfo layerInfo; |
| |
| // Add the back layer, with the defaults. |
| (void)looperBuilder.addLayerOnTop(layerInfo); |
| |
| // Add the front layer, with some layer info set. |
| layerInfo.fOffset.set(10.0f, 20.0f); |
| layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit; |
| SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo); |
| layerPaint->setBlendMode(SkBlendMode::kSrc); |
| |
| SkPaint paint; |
| auto looper(looperBuilder.detach()); |
| SkArenaAlloc alloc{48}; |
| SkDrawLooper::Context* context = looper->makeContext(&alloc); |
| SkDrawLooper::Context::Info info; |
| |
| // The back layer should come first. |
| REPORTER_ASSERT(reporter, context->next(&info, &paint)); |
| REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrcOver); |
| REPORTER_ASSERT(reporter, 0.0f == info.fTranslate.fX); |
| REPORTER_ASSERT(reporter, 0.0f == info.fTranslate.fY); |
| paint.reset(); |
| |
| // Then the front layer. |
| REPORTER_ASSERT(reporter, context->next(&info, &paint)); |
| REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrc); |
| REPORTER_ASSERT(reporter, 10.0f == info.fTranslate.fX); |
| REPORTER_ASSERT(reporter, 20.0f == info.fTranslate.fY); |
| |
| // Only two layers were added, so that should be the end. |
| REPORTER_ASSERT(reporter, !context->next(&info, &paint)); |
| } |
| |
| static void test_mixed(skiatest::Reporter* reporter) { |
| SkLayerDrawLooper::Builder looperBuilder; |
| SkLayerDrawLooper::LayerInfo layerInfo; |
| |
| // Add the back layer, with the defaults. |
| (void)looperBuilder.addLayer(layerInfo); |
| |
| // Add the front layer, with some layer info set. |
| layerInfo.fOffset.set(10.0f, 20.0f); |
| layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit; |
| SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo); |
| layerPaint->setBlendMode(SkBlendMode::kSrc); |
| |
| SkPaint paint; |
| sk_sp<SkDrawLooper> looper(looperBuilder.detach()); |
| SkArenaAlloc alloc{48}; |
| SkDrawLooper::Context* context = looper->makeContext(&alloc); |
| SkDrawLooper::Context::Info info; |
| |
| // The back layer should come first. |
| REPORTER_ASSERT(reporter, context->next(&info, &paint)); |
| REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrcOver); |
| REPORTER_ASSERT(reporter, 0.0f == info.fTranslate.fX); |
| REPORTER_ASSERT(reporter, 0.0f == info.fTranslate.fY); |
| paint.reset(); |
| |
| // Then the front layer. |
| REPORTER_ASSERT(reporter, context->next(&info, &paint)); |
| REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrc); |
| REPORTER_ASSERT(reporter, 10.0f == info.fTranslate.fX); |
| REPORTER_ASSERT(reporter, 20.0f == info.fTranslate.fY); |
| |
| // Only two layers were added, so that should be the end. |
| REPORTER_ASSERT(reporter, !context->next(&info, &paint)); |
| } |
| |
| DEF_TEST(LayerDrawLooper, reporter) { |
| test_frontToBack(reporter); |
| test_backToFront(reporter); |
| test_mixed(reporter); |
| } |