/*
 * 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 "SkPath.h"
#include "SkStream.h"
#include "gm.h"


// Test how short paths are stroked with various caps
class StrokeZeroGM : public skiagm::GM {
    SkPath fPaths[8];
    SkPath fClipL, fClipR, fClipS;

protected:
    void onOnceBeforeDraw() override {
        fClipL.moveTo(0, 0);
        fClipL.lineTo(3, 0);
        fClipL.lineTo(2.5f, 1);
        fClipL.lineTo(3.5f, 2.5f);
        fClipL.lineTo(2.5f, 4);
        fClipL.lineTo(3, 5);
        fClipL.lineTo(0, 5);
        fClipL.close();

        fClipR.moveTo(34, 0);
        fClipR.lineTo(34, 5);
        fClipR.lineTo(31, 5);
        fClipR.lineTo(30.5, 4);
        fClipR.lineTo(31.5, 2.5);
        fClipR.lineTo(30.5, 1);
        fClipR.lineTo(31, 0);
        fClipR.close();

        fClipS.addRect(SkRect::MakeIWH(4, 5));

        fPaths[0].moveTo(30, 0);  // single line segment
        fPaths[0].rLineTo(30, 0);

        fPaths[1].moveTo(90, 0);  // single line segment with close (does not draw caps)
        fPaths[1].rLineTo(30, 0);
        fPaths[1].close();

        fPaths[2].moveTo(150, 0);  // zero-length line
        fPaths[2].rLineTo(0, 0);

        fPaths[3].moveTo(180, 0);  // zero-length line with close (expected not to draw)
        fPaths[3].rLineTo(0, 0);
        fPaths[3].close();

        fPaths[4].moveTo(210, 0);  // close only, no line
        fPaths[4].close();

        fPaths[5].moveTo(30, 90);  // all combos below should draw two caps
        fPaths[5].rLineTo(0, 0);
        fPaths[5].moveTo(60, 90);
        fPaths[5].rLineTo(0, 0);

        fPaths[6].moveTo(90, 90);
        fPaths[6].close();
        fPaths[6].moveTo(120, 90);
        fPaths[6].close();

        fPaths[7].moveTo(150, 90);
        fPaths[7].rLineTo(0, 0);
        fPaths[7].moveTo(180, 90);
        fPaths[7].close();
    }


    SkString onShortName() override {
        return SkString("path_stroke_with_zero_length");
    }

    SkISize onISize() override {
        return SkISize::Make(1120, 840);
    }

    void onDraw(SkCanvas* canvas) override {
        SkPaint bkgrnd;
        bkgrnd.setColor(SK_ColorWHITE);
        canvas->drawRect(SkRect::MakeIWH(onISize().fWidth, onISize().fHeight), bkgrnd);

         auto drawPaths = [&](SkPaint& paint, int indexMask) {
            canvas->translate(0, 30.0f);
            int index = 0;
            for (const SkPath& path : fPaths) {
                if (indexMask & (1 << index)) {
                    canvas->drawPath(path, paint);
                }
                if (this->getMode() == skiagm::GM::kSample_Mode && paint.getStrokeWidth() < 2) {
                    drawFat(canvas, path, paint, index);
                }
                ++index;
            }
        };

        if (false) { // debugging variant that draws a single element
            SkScalar width = 0;
            bool antialias = true;

            SkPaint butt;
            butt.setAntiAlias(antialias);
            butt.setStyle(SkPaint::kStroke_Style);
            butt.setStrokeWidth(width);

            SkPaint round(butt);
            round.setStrokeCap(SkPaint::kRound_Cap);
            drawPaths(round, 1 << 7);
            return;
        }

        SkScalar widths[] = { 0, .999f, 1, 1.001f, 20 };
        bool aliases[] = { false, true };
        for (bool antialias : aliases) {
            canvas->save();
            for (SkScalar width : widths) {
                canvas->save();
                SkPaint butt;
                butt.setAntiAlias(antialias);
                butt.setStyle(SkPaint::kStroke_Style);
                butt.setStrokeWidth(width);
                drawPaths(butt, -1);

                SkPaint round(butt);
                round.setStrokeCap(SkPaint::kRound_Cap);
                drawPaths(round, -1);

                SkPaint square(butt);
                square.setStrokeCap(SkPaint::kSquare_Cap);
                drawPaths(square, -1);
                canvas->restore();
                canvas->translate(220, 0);
            }
            canvas->restore();
            canvas->translate(0, 210);
        }
    }

private:
    void drawFat(SkCanvas* canvas, const SkPath& path, const SkPaint& paint, int index) {
        const SkScalar scale = 10;
        SkRect bounds = path.getBounds();
        SkBitmap offscreen;
        offscreen.allocN32Pixels(SkScalarRoundToInt(bounds.width() + 4),
                SkScalarRoundToInt(bounds.height() + 4));
        offscreen.eraseColor(SK_ColorWHITE);
        SkScalar pathX = bounds.fLeft - 2;
        SkScalar pathY = bounds.fTop - 2;
        SkMatrix cMatrix = canvas->getTotalMatrix();
        if (!canvas->readPixels(offscreen, SkScalarRoundToInt(pathX + cMatrix.getTranslateX()),
                SkScalarRoundToInt(pathY + cMatrix.getTranslateY()))) {
            return;
        }

        canvas->save();
        SkMatrix clipM;
        clipM.reset();
        clipM.preScale(scale, scale);
        clipM.postTranslate(bounds.fLeft - 17, bounds.fTop - 24.5f + 420);
        SkPath clip;
        if (index < 2) {
            fClipL.transform(clipM, &clip);
        } else {
            fClipS.transform(clipM, &clip);
        }
        canvas->clipPath(clip, true);
        canvas->scale(scale, scale);
        canvas->drawBitmap(offscreen, (bounds.fLeft - 17) / scale,
                    (bounds.fTop - 20 + 420) / scale);
        canvas->restore();

        if (bounds.width() > 20) {
            canvas->save();
            clipM.reset();
            clipM.preScale(scale, scale);
            clipM.postTranslate(bounds.fLeft - 17 - 275, bounds.fTop - 24.5f + 420);
            SkPath clip;
            fClipR.transform(clipM, &clip);
            canvas->clipPath(clip, true);
            canvas->scale(10.f, 10.f);
            canvas->drawBitmap(offscreen, (bounds.fLeft - 17 - 275
                    + (index >= 5 ? 5 : 0)) / scale, (bounds.fTop - 20 + 420) / scale);
            canvas->restore();
        }
    }

};

///////////////////////////////////////////////////////////////////////////////

DEF_GM( return new StrokeZeroGM(); )
