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



#ifndef SkGPipePriv_DEFINED
#define SkGPipePriv_DEFINED

#include "SkTypes.h"

#define UNIMPLEMENTED

// these must be contiguous, 0...N-1
enum PaintFlats {
    kColorFilter_PaintFlat,
    kDrawLooper_PaintFlat,
    kImageFilter_PaintFlat,
    kMaskFilter_PaintFlat,
    kPathEffect_PaintFlat,
    kRasterizer_PaintFlat,
    kShader_PaintFlat,
    kXfermode_PaintFlat,

    kLast_PaintFlat = kXfermode_PaintFlat
};
#define kCount_PaintFlats   (kLast_PaintFlat + 1)

enum DrawOps {
    kSkip_DrawOp,   // skip an addition N bytes (N == data)

    // these match Canvas apis
    kClipPath_DrawOp,
    kClipRegion_DrawOp,
    kClipRect_DrawOp,
    kClipRRect_DrawOp,
    kConcat_DrawOp,
    kDrawBitmap_DrawOp,
    kDrawBitmapNine_DrawOp,
    kDrawBitmapRectToRect_DrawOp,
    kDrawDRRect_DrawOp,
    kDrawImage_DrawOp,
    kDrawImageRect_DrawOp,
    kDrawOval_DrawOp,
    kDrawPaint_DrawOp,
    kDrawPatch_DrawOp,
    kDrawPath_DrawOp,
    kDrawPicture_DrawOp,
    kDrawPoints_DrawOp,
    kDrawPosText_DrawOp,
    kDrawPosTextH_DrawOp,
    kDrawRect_DrawOp,
    kDrawRRect_DrawOp,
    kDrawSprite_DrawOp,
    kDrawText_DrawOp,
    kDrawTextBlob_DrawOp,
    kDrawTextOnPath_DrawOp,
    kDrawVertices_DrawOp,
    kRestore_DrawOp,
    kRotate_DrawOp,
    kSave_DrawOp,
    kSaveLayer_DrawOp,
    kScale_DrawOp,
    kSetMatrix_DrawOp,
    kSkew_DrawOp,
    kTranslate_DrawOp,

    kPaintOp_DrawOp,
    kSetTypeface_DrawOp,
    kSetAnnotation_DrawOp,

    kDef_Typeface_DrawOp,
    kDef_Flattenable_DrawOp,
    kDef_Bitmap_DrawOp,
    kDef_Factory_DrawOp,

    // these are signals to playback, not drawing verbs
    kReportFlags_DrawOp,
    kShareBitmapHeap_DrawOp,
    kShareImageHeap_DrawOp,
    kDone_DrawOp,
};

/**
 *  DrawOp packs into a 32bit int as follows
 *
 *  DrawOp:8 - Flags:4 - Data:20
 *
 *  Flags and Data are called out separately, so we can reuse Data between
 *  different Ops that might have different Flags. e.g. Data might be a Paint
 *  index for both drawRect (no flags) and saveLayer (does have flags).
 *
 *  All Ops that take a SkPaint use their Data field to store the index to
 *  the paint (previously defined with kPaintOp_DrawOp).
 */

#define DRAWOPS_OP_BITS     8
#define DRAWOPS_FLAG_BITS   4
#define DRAWOPS_DATA_BITS   20

#define DRAWOPS_OP_MASK     ((1 << DRAWOPS_OP_BITS) - 1)
#define DRAWOPS_FLAG_MASK   ((1 << DRAWOPS_FLAG_BITS) - 1)
#define DRAWOPS_DATA_MASK   ((1 << DRAWOPS_DATA_BITS) - 1)

static inline unsigned DrawOp_unpackOp(uint32_t op32) {
    return (op32 >> (DRAWOPS_FLAG_BITS + DRAWOPS_DATA_BITS));
}

static inline unsigned DrawOp_unpackFlags(uint32_t op32) {
    return (op32 >> DRAWOPS_DATA_BITS) & DRAWOPS_FLAG_MASK;
}

static inline unsigned DrawOp_unpackData(uint32_t op32) {
    return op32 & DRAWOPS_DATA_MASK;
}

static inline uint32_t DrawOp_packOpFlagData(DrawOps op, unsigned flags, unsigned data) {
    SkASSERT(0 == (op & ~DRAWOPS_OP_MASK));
    SkASSERT(0 == (flags & ~DRAWOPS_FLAG_MASK));
    SkASSERT(0 == (data & ~DRAWOPS_DATA_MASK));

    return (op << (DRAWOPS_FLAG_BITS + DRAWOPS_DATA_BITS)) |
           (flags << DRAWOPS_DATA_BITS) |
            data;
}

/** DrawOp specific flag bits
 */

enum {
    kSaveLayer_HasBounds_DrawOpFlag = 1 << 0,
    kSaveLayer_HasPaint_DrawOpFlag = 1 << 1,
};
enum {
    kDrawTextOnPath_HasMatrix_DrawOpFlag = 1 << 0
};
enum {
    kDrawVertices_HasTexs_DrawOpFlag     = 1 << 0,
    kDrawVertices_HasColors_DrawOpFlag   = 1 << 1,
    kDrawVertices_HasIndices_DrawOpFlag  = 1 << 2,
    kDrawVertices_HasXfermode_DrawOpFlag = 1 << 3,
};
// These are shared between drawbitmap and drawimage
enum {
    kDrawBitmap_HasPaint_DrawOpFlag   = 1 << 0,
    // Specific to drawBitmapRect, but needs to be different from HasPaint,
    // which is used for all drawBitmap calls, so include it here.
    kDrawBitmap_HasSrcRect_DrawOpFlag = 1 << 1,
    // SkCanvas::DrawBitmapRectFlags::kBleed_DrawBitmapRectFlag is
    // converted into and out of this flag to save space
    kDrawBitmap_Bleed_DrawOpFlag      = 1 << 2,
};
enum {
    kClip_HasAntiAlias_DrawOpFlag = 1 << 0,
};
///////////////////////////////////////////////////////////////////////////////

class BitmapInfo : SkNoncopyable {
public:
    BitmapInfo(SkBitmap* bitmap, uint32_t genID, int toBeDrawnCount)
        : fBitmap(bitmap)
        , fGenID(genID)
        , fBytesAllocated(0)
        , fMoreRecentlyUsed(NULL)
        , fLessRecentlyUsed(NULL)
        , fToBeDrawnCount(toBeDrawnCount)
    {}

    ~BitmapInfo() {
        SkASSERT(0 == fToBeDrawnCount);
        SkDELETE(fBitmap);
    }

    void addDraws(int drawsToAdd) {
        if (0 == fToBeDrawnCount) {
            // The readers will only ever decrement the count, so once the
            // count is zero, the writer will be the only one modifying it,
            // so it does not need to be an atomic operation.
            fToBeDrawnCount = drawsToAdd;
        } else {
            sk_atomic_add(&fToBeDrawnCount, drawsToAdd);
        }
    }

    void decDraws() {
        sk_atomic_dec(&fToBeDrawnCount);
    }

    int drawCount() const {
        return fToBeDrawnCount;
    }

    SkBitmap* fBitmap;
    // Store the generation ID of the original bitmap, since copying does
    // not copy this field, so fBitmap's generation ID will not be useful
    // for comparing.
    // FIXME: Is it reasonable to make copying a bitmap/pixelref copy the
    // generation ID?
    uint32_t fGenID;
    // Keep track of the bytes allocated for this bitmap. When replacing the
    // bitmap or removing this BitmapInfo we know how much memory has been
    // reclaimed.
    size_t fBytesAllocated;
    // TODO: Generalize the LRU caching mechanism
    BitmapInfo* fMoreRecentlyUsed;
    BitmapInfo* fLessRecentlyUsed;
private:
    int      fToBeDrawnCount;
};

static inline bool shouldFlattenBitmaps(uint32_t flags) {
    return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag
            && !(flags & SkGPipeWriter::kSharedAddressSpace_Flag));
}

class SkImageHeap : public SkRefCnt {
public:
    SkImageHeap();
    virtual ~SkImageHeap();

    // slot must be "valid" -- 0 is never valid
    const SkImage* get(int32_t slot) const;
    // returns 0 if not found, else returns slot
    int32_t find(const SkImage*) const;
    // returns non-zero value for where the image was stored
    int32_t insert(const SkImage*);

private:
    SkTDArray<const SkImage*> fArray;
};

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

enum PaintOps {
    kReset_PaintOp,     // no arg

    kFlags_PaintOp,     // arg inline
    kColor_PaintOp,     // arg 32
    kFilterLevel_PaintOp,   // arg inline
    kStyle_PaintOp,     // arg inline
    kJoin_PaintOp,      // arg inline
    kCap_PaintOp,       // arg inline
    kWidth_PaintOp,     // arg scalar
    kMiter_PaintOp,     // arg scalar

    kEncoding_PaintOp,  // arg inline - text
    kHinting_PaintOp,   // arg inline - text
    kAlign_PaintOp,     // arg inline - text
    kTextSize_PaintOp,  // arg scalar - text
    kTextScaleX_PaintOp,// arg scalar - text
    kTextSkewX_PaintOp, // arg scalar - text
    kTypeface_PaintOp,  // arg inline (index) - text

    kFlatIndex_PaintOp, // flags=paintflat, data=index
};

#define PAINTOPS_OP_BITS     8
#define PAINTOPS_FLAG_BITS   4
#define PAINTOPS_DATA_BITS   20

#define PAINTOPS_OP_MASK     ((1 << PAINTOPS_OP_BITS) - 1)
#define PAINTOPS_FLAG_MASK   ((1 << PAINTOPS_FLAG_BITS) - 1)
#define PAINTOPS_DATA_MASK   ((1 << PAINTOPS_DATA_BITS) - 1)

static inline unsigned PaintOp_unpackOp(uint32_t op32) {
    return (op32 >> (PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS));
}

static inline unsigned PaintOp_unpackFlags(uint32_t op32) {
    return (op32 >> PAINTOPS_DATA_BITS) & PAINTOPS_FLAG_MASK;
}

static inline unsigned PaintOp_unpackData(uint32_t op32) {
    return op32 & PAINTOPS_DATA_MASK;
}

static inline uint32_t PaintOp_packOp(PaintOps op) {
    SkASSERT(0 == (op & ~PAINTOPS_OP_MASK));

    return op << (PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS);
}

static inline uint32_t PaintOp_packOpData(PaintOps op, unsigned data) {
    SkASSERT(0 == (op & ~PAINTOPS_OP_MASK));
    SkASSERT(0 == (data & ~PAINTOPS_DATA_MASK));

    return (op << (PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS)) | data;
}

static inline uint32_t PaintOp_packOpFlagData(PaintOps op, unsigned flags, unsigned data) {
    SkASSERT(0 == (op & ~PAINTOPS_OP_MASK));
    SkASSERT(0 == (flags & ~PAINTOPS_FLAG_MASK));
    SkASSERT(0 == (data & ~PAINTOPS_DATA_MASK));

    return (op << (PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS)) |
    (flags << PAINTOPS_DATA_BITS) |
    data;
}

#endif