/*
 * Copyright 2021 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm/gm.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkPaint.h"
#include "include/core/SkSize.h"
#include "include/core/SkSurface.h"
#include "include/effects/SkRuntimeEffect.h"
#include "src/gpu/ganesh/GrCaps.h"
#include "src/gpu/ganesh/GrDirectContextPriv.h"
#include "tests/Test.h"
#include "tools/Resources.h"
#include "tools/RuntimeBlendUtils.h"
#include "tools/ToolUtils.h"

static bool nearly_equal(const SkColor& x, const SkColor& y) {
    const int kTolerance = 1;
    return abs((int)SkColorGetA(x) - (int)SkColorGetA(y)) <= kTolerance &&
           abs((int)SkColorGetR(x) - (int)SkColorGetR(y)) <= kTolerance &&
           abs((int)SkColorGetG(x) - (int)SkColorGetG(y)) <= kTolerance &&
           abs((int)SkColorGetB(x) - (int)SkColorGetB(y)) <= kTolerance;
}

static void test_blend(skiatest::Reporter* r, SkSurface* surface) {
    SkBitmap bitmap;
    REPORTER_ASSERT(r, bitmap.tryAllocPixels(surface->imageInfo()));

    for (int m = 0; m < kSkBlendModeCount; ++m) {
        SkBlendMode mode = (SkBlendMode)m;
        for (int alpha : {0x80, 0xFF}) {
            for (bool useShader : {false, true}) {
                std::vector<SkColor> colors;
                for (bool useRuntimeBlend : {false, true}) {
                    // Draw a solid red pixel.
                    SkPaint paint;
                    paint.setColor(SK_ColorRED);
                    paint.setBlendMode(SkBlendMode::kSrc);
                    surface->getCanvas()->drawRect(SkRect::MakeWH(1, 1), paint);

                    // Draw a blue pixel on top of it, using the passed-in blend mode.
                    if (useShader) {
                        // Install a different color in the paint, to ensure we're using the shader
                        paint.setColor(SK_ColorGREEN);
                        paint.setShader(SkShaders::Color(SkColorSetARGB(alpha, 0x00, 0x00, 0xFF)));
                    } else {
                        paint.setColor(SkColorSetARGB(alpha, 0x00, 0x00, 0xFF));
                    }
                    if (useRuntimeBlend) {
                        paint.setBlender(GetRuntimeBlendForBlendMode(mode));
                    } else {
                        paint.setBlendMode(mode);
                    }
                    surface->getCanvas()->drawRect(SkRect::MakeWH(1, 1), paint);

                    // Read back the red/blue blended pixel.
                    REPORTER_ASSERT(r,
                                    surface->readPixels(bitmap.info(),
                                                        bitmap.getPixels(),
                                                        bitmap.rowBytes(),
                                                        /*srcX=*/0,
                                                        /*srcY=*/0));
                    colors.push_back(bitmap.getColor(/*x=*/0, /*y=*/0));
                }

                REPORTER_ASSERT(r,
                                nearly_equal(colors[0], colors[1]),
                                "Expected: %s %s %s blend matches. Actual: Built-in "
                                "A=%02X R=%02X G=%02X B=%02X, Runtime A=%02X R=%02X G=%02X B=%02X",
                                SkBlendMode_Name(mode),
                                (alpha == 0xFF) ? "solid" : "transparent",
                                useShader ? "shader" : "paint",
                                SkColorGetA(colors[0]),
                                SkColorGetR(colors[0]),
                                SkColorGetG(colors[0]),
                                SkColorGetB(colors[0]),
                                SkColorGetA(colors[1]),
                                SkColorGetR(colors[1]),
                                SkColorGetG(colors[1]),
                                SkColorGetB(colors[1]));
            }
        }
    }
}

DEF_TEST(SkRuntimeBlender_CPU, r) {
    const SkImageInfo info = SkImageInfo::MakeN32Premul(/*width=*/1, /*height=*/1);
    sk_sp<SkSurface> surface(SkSurface::MakeRaster(info));

    test_blend(r, surface.get());
}

DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRuntimeBlender_GPU, r, ctxInfo, CtsEnforcement::kApiLevel_T) {
    const SkImageInfo info = SkImageInfo::MakeN32Premul(/*width=*/1, /*height=*/1);
    sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctxInfo.directContext(),
                                                         SkBudgeted::kNo, info));
    test_blend(r, surface.get());
}
