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

#ifndef SkPipeCanvas_DEFINED
#define SkPipeCanvas_DEFINED

#include "SkCanvasVirtualEnforcer.h"
#include "SkDeduper.h"
#include "SkImage.h"
#include "SkNoDrawCanvas.h"
#include "SkPipe.h"
#include "SkTypeface.h"
#include "SkWriteBuffer.h"

class SkPipeCanvas;
class SkPipeWriter;

template <typename T> class SkTIndexSet {
public:
    void reset() { fArray.reset(); }

    // returns the found index or 0
    int find(const T& key) const {
        const Rec* stop = fArray.end();
        for (const Rec* curr = fArray.begin(); curr < stop; ++curr) {
            if (key == curr->fKey) {
                return curr->fIndex;
            }
        }
        return 0;
    }

    // returns the new index
    int add(const T& key) {
        Rec* rec = fArray.append();
        rec->fKey = key;
        rec->fIndex = fNextIndex++;
        return rec->fIndex;
    }

private:
    struct Rec {
        T   fKey;
        int fIndex;
    };

    SkTDArray<Rec>  fArray;
    int fNextIndex = 1;
};

class SkPipeDeduper : public SkDeduper {
public:
    void resetCaches() {
        fImages.reset();
        fPictures.reset();
        fTypefaces.reset();
        fFactories.reset();
    }

    void setCanvas(SkPipeCanvas* canvas) { fPipeCanvas = canvas; }
    void setStream(SkWStream* stream) { fStream = stream; }
    void setSerialProcs(const SkSerialProcs& procs) { fProcs = procs; }

    // returns 0 if not found
    int findImage(SkImage* image) const { return fImages.find(image->uniqueID()); }
    int findPicture(SkPicture* picture) const { return fPictures.find(picture->uniqueID()); }

    int findOrDefineImage(SkImage*) override;
    int findOrDefinePicture(SkPicture*) override;
    int findOrDefineTypeface(SkTypeface*) override;
    int findOrDefineFactory(SkFlattenable*) override;

private:
    SkPipeCanvas*           fPipeCanvas = nullptr;
    SkWStream*              fStream = nullptr;
    SkSerialProcs           fProcs;

    // All our keys (at the moment) are 32bit uniqueIDs
    SkTIndexSet<uint32_t>   fImages;
    SkTIndexSet<uint32_t>   fPictures;
    SkTIndexSet<uint32_t>   fTypefaces;
    SkTIndexSet<SkFlattenable::Factory> fFactories;
};


class SkPipeCanvas : public SkCanvasVirtualEnforcer<SkNoDrawCanvas> {
public:
    SkPipeCanvas(const SkRect& cull, SkPipeDeduper*, SkWStream*);
    ~SkPipeCanvas() override;

protected:
    void willSave() override;
    SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
    void willRestore() override;

    void didConcat(const SkMatrix&) override;
    void didSetMatrix(const SkMatrix&) override;

    void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
                   const SkPaint&) override;
    void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
                     int count, SkBlendMode, const SkRect* cull, const SkPaint*) override;
    void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
    void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
                    const SkPaint&) override;
    void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
                       const SkPaint&) override;
    void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
                        SkScalar constY, const SkPaint&) override;
    void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath&, const SkMatrix*,
                          const SkPaint&) override;
    void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint&) override;
    void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
                           const SkRect* cull, const SkPaint& paint) override;
    void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4],
                     SkBlendMode, const SkPaint&) override;

    void onDrawPaint(const SkPaint&) override;
    void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
    void onDrawRect(const SkRect&, const SkPaint&) override;
    void onDrawOval(const SkRect&, const SkPaint&) override;
    void onDrawRegion(const SkRegion&, const SkPaint&) override;
    void onDrawRRect(const SkRRect&, const SkPaint&) override;
    void onDrawPath(const SkPath&, const SkPaint&) override;
    void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;

    void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override;
    void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
                         const SkPaint*, SrcRectConstraint) override;
    void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
                         const SkPaint*) override;
    void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
                            const SkPaint*) override;
    void onDrawVerticesObject(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
                              const SkPaint&) override;

    void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
    void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
    void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override;
    void onClipRegion(const SkRegion&, SkClipOp) override;

    void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
    void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
    void onDrawDrawable(SkDrawable*, const SkMatrix*) override;

    // These we turn into images
    void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override;
    void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
                          SrcRectConstraint) override;
    void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
                          const SkPaint*) override;
    void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, const SkRect& dst,
                             const SkPaint*) override;

private:
    SkPipeDeduper*  fDeduper;
    SkWStream*      fStream;

    friend class SkPipeWriter;

    typedef SkCanvasVirtualEnforcer<SkNoDrawCanvas> INHERITED;
};


#endif
