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

#include "gm.h"
#include "SkCanvas.h"
#include "SkRSXform.h"
#include "SkSurface.h"

// Create a square atlas of:
//   opaque white  |     opaque red
//  ------------------------------------
//   opaque green  |  transparent black
//
static SkImage* make_atlas(SkCanvas* caller, int atlasSize) {
    const int kBlockSize = atlasSize/2;

    SkImageInfo info = SkImageInfo::MakeN32Premul(atlasSize, atlasSize);
    SkAutoTUnref<SkSurface> surface(caller->newSurface(info));
    if (nullptr == surface) {
        surface.reset(SkSurface::NewRaster(info));
    }
    SkCanvas* canvas = surface->getCanvas();

    SkPaint paint;
    paint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode));

    paint.setColor(SK_ColorWHITE);
    SkRect r = SkRect::MakeXYWH(0, 0, 
                                SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
    canvas->drawRect(r, paint);

    paint.setColor(SK_ColorRED);
    r = SkRect::MakeXYWH(SkIntToScalar(kBlockSize), 0, 
                         SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
    canvas->drawRect(r, paint);

    paint.setColor(SK_ColorGREEN);
    r = SkRect::MakeXYWH(0, SkIntToScalar(kBlockSize), 
                         SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
    canvas->drawRect(r, paint);

    paint.setColor(SK_ColorTRANSPARENT);
    r = SkRect::MakeXYWH(SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize), 
                         SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
    canvas->drawRect(r, paint);

    return surface->newImageSnapshot();
}

// This GM tests the drawAtlas API with colors, different xfer modes
// and transparency in the atlas image
class DrawAtlasColorsGM : public skiagm::GM {
public:
    DrawAtlasColorsGM() {
        this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
    }
    
protected:
    SkString onShortName() override {
        return SkString("draw-atlas-colors");
    }
    
    SkISize onISize() override {
        return SkISize::Make(kNumXferModes * (kAtlasSize + kPad) + kPad,
                             2 * kNumColors * (kAtlasSize + kPad) + kTextPad + kPad);
    }
    
    void onDraw(SkCanvas* canvas) override {
        const SkRect target = SkRect::MakeWH(SkIntToScalar(kAtlasSize), SkIntToScalar(kAtlasSize));

        if (nullptr == fAtlas) {
            fAtlas.reset(make_atlas(canvas, kAtlasSize));
        }

        const struct {
            SkXfermode::Mode fMode;
            const char*      fLabel;
        } gModes[] = {
            { SkXfermode::kClear_Mode,      "Clear"     },
            { SkXfermode::kSrc_Mode,        "Src"       },
            { SkXfermode::kDst_Mode,        "Dst"       },
            { SkXfermode::kSrcOver_Mode,    "SrcOver"   },
            { SkXfermode::kDstOver_Mode,    "DstOver"   },
            { SkXfermode::kSrcIn_Mode,      "SrcIn"     },
            { SkXfermode::kDstIn_Mode,      "DstIn"     },
            { SkXfermode::kSrcOut_Mode,     "SrcOut"    },
            { SkXfermode::kDstOut_Mode,     "DstOut"    },
            { SkXfermode::kSrcATop_Mode,    "SrcATop"   },
            { SkXfermode::kDstATop_Mode,    "DstATop"   },
            { SkXfermode::kXor_Mode,        "Xor"       },
            { SkXfermode::kPlus_Mode,       "Plus"      },
            { SkXfermode::kModulate_Mode,   "Mod"       },
            { SkXfermode::kScreen_Mode,     "Screen"    },
            { SkXfermode::kOverlay_Mode,    "Overlay"   },
            { SkXfermode::kDarken_Mode,     "Darken"    },
            { SkXfermode::kLighten_Mode,    "Lighten"   },
            { SkXfermode::kColorDodge_Mode, "Dodge"     },
            { SkXfermode::kColorBurn_Mode,  "Burn"      },
            { SkXfermode::kHardLight_Mode,  "Hard"      },
            { SkXfermode::kSoftLight_Mode,  "Soft"      },
            { SkXfermode::kDifference_Mode, "Diff"      },
            { SkXfermode::kExclusion_Mode,  "Exclusion" },
            { SkXfermode::kMultiply_Mode,   "Multiply"  },
            { SkXfermode::kHue_Mode,        "Hue"       },
            { SkXfermode::kSaturation_Mode, "Sat"       },
            { SkXfermode::kColor_Mode,      "Color"     },
            { SkXfermode::kLuminosity_Mode, "Luminosity"},
        };

        SkColor gColors[] = {
            SK_ColorWHITE,
            SK_ColorRED,
            0x88888888,         // transparent grey
            0x88000088          // transparent blue
        };

        const int numModes = SK_ARRAY_COUNT(gModes);
        SkASSERT(numModes == kNumXferModes);
        const int numColors = SK_ARRAY_COUNT(gColors);
        SkASSERT(numColors == kNumColors);
        SkRSXform xforms[numColors];
        SkRect rects[numColors];
        SkColor quadColors[numColors];

        SkPaint paint;
        paint.setAntiAlias(true);

        for (int i = 0; i < numColors; ++i) {
            xforms[i].set(1.0f, 0.0f, SkIntToScalar(kPad), i*(target.width()+kPad));
            rects[i] = target;
            quadColors[i] = gColors[i];
        }

        SkPaint textP;
        textP.setTextSize(SkIntToScalar(kTextPad));
        textP.setAntiAlias(true);
        sk_tool_utils::set_portable_typeface(&textP, nullptr);

        for (int i = 0; i < numModes; ++i) {
            canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
                             i*(target.width()+kPad)+kPad, SkIntToScalar(kTextPad),
                             textP);
        }

        for (int i = 0; i < numModes; ++i) {
            canvas->save();            
            canvas->translate(SkIntToScalar(i*(target.height()+kPad)),
                              SkIntToScalar(kTextPad+kPad));
            // w/o a paint
            canvas->drawAtlas(fAtlas, xforms, rects, quadColors, numColors, 
                              gModes[i].fMode, nullptr, nullptr);
            canvas->translate(0.0f, numColors*(target.height()+kPad));
            // w a paint
            canvas->drawAtlas(fAtlas, xforms, rects, quadColors, numColors, 
                              gModes[i].fMode, nullptr, &paint);
            canvas->restore();        
        }
    }
    
private:
    static const int kNumXferModes = 29;
    static const int kNumColors = 4;
    static const int kAtlasSize = 30;
    static const int kPad = 2;
    static const int kTextPad = 8;


    SkAutoTUnref<SkImage> fAtlas;

    typedef GM INHERITED;
};
DEF_GM( return new DrawAtlasColorsGM; )