
/*
 * 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 SkPictureFlat_DEFINED
#define SkPictureFlat_DEFINED

#include "SkChunkAlloc.h"
#include "SkBitmap.h"
#include "SkPicture.h"
#include "SkMatrix.h"
#include "SkPaint.h"
#include "SkPath.h"
#include "SkRegion.h"

enum DrawType {
    UNUSED,
    CLIP_PATH,
    CLIP_REGION,
    CLIP_RECT,
    CONCAT,
    DRAW_BITMAP,
    DRAW_BITMAP_MATRIX,
    DRAW_BITMAP_NINE,
    DRAW_BITMAP_RECT,
    DRAW_CLEAR,
    DRAW_DATA,
    DRAW_PAINT,
    DRAW_PATH,
    DRAW_PICTURE,
    DRAW_POINTS,
    DRAW_POS_TEXT,
    DRAW_POS_TEXT_H,
    DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
    DRAW_RECT,
    DRAW_SPRITE,
    DRAW_TEXT,
    DRAW_TEXT_ON_PATH,
    DRAW_TEXT_TOP_BOTTOM,   // fast variant of DRAW_TEXT
    DRAW_VERTICES,
    RESTORE,
    ROTATE,
    SAVE,
    SAVE_LAYER,
    SCALE,
    SET_MATRIX,
    SKEW,
    TRANSLATE
};

enum DrawVertexFlags {
    DRAW_VERTICES_HAS_TEXS    = 0x01,
    DRAW_VERTICES_HAS_COLORS  = 0x02,
    DRAW_VERTICES_HAS_INDICES = 0x04
};

///////////////////////////////////////////////////////////////////////////////
// clipparams are packed in 5 bits
//  doAA:1 | regionOp:4

static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) {
    unsigned doAABit = doAA ? 1 : 0;
    return (doAABit << 4) | op;
}

static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) {
    return (SkRegion::Op)(packed & 0xF);
}

static inline bool ClipParams_unpackDoAA(uint32_t packed) {
    return SkToBool((packed >> 4) & 1);
}

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

class SkRefCntPlayback {
public:
    SkRefCntPlayback();
    virtual ~SkRefCntPlayback();
    
    int count() const { return fCount; }
    
    void reset(const SkRefCntSet*);

    void setCount(int count);
    SkRefCnt* set(int index, SkRefCnt*);

    virtual void setupBuffer(SkFlattenableReadBuffer& buffer) const {
        buffer.setRefCntArray(fArray, fCount);
    }
    
protected:
    int fCount;
    SkRefCnt** fArray;
};

class SkTypefacePlayback : public SkRefCntPlayback {
public:
    virtual void setupBuffer(SkFlattenableReadBuffer& buffer) const {
        buffer.setTypefaceArray((SkTypeface**)fArray, fCount);
    }
};

class SkFactoryPlayback {
public:
    SkFactoryPlayback(int count) : fCount(count) {
        fArray = SkNEW_ARRAY(SkFlattenable::Factory, count);
    }

    ~SkFactoryPlayback() {
        SkDELETE_ARRAY(fArray);
    }
    
    SkFlattenable::Factory* base() const { return fArray; }

    void setupBuffer(SkFlattenableReadBuffer& buffer) const {
        buffer.setFactoryPlayback(fArray, fCount);
    }
    
private:
    int fCount;
    SkFlattenable::Factory* fArray;
};

class SkFlatData {
public:
    static int Compare(const SkFlatData* a, const SkFlatData* b) {
        return memcmp(&a->fAllocSize, &b->fAllocSize, a->fAllocSize);
    }
    
    int index() const { return fIndex; }
    
#ifdef SK_DEBUG_SIZE
    size_t size() const { return sizeof(fIndex) + fAllocSize; }
#endif

protected:
    static SkFlatData* Alloc(SkChunkAlloc* heap, int32_t size, int index);
    
    int fIndex;
    int32_t fAllocSize;
};

class SkFlatBitmap : public SkFlatData {
public:
    static SkFlatBitmap* Flatten(SkChunkAlloc*, const SkBitmap&, int index,
                                 SkRefCntSet*);

    void unflatten(SkBitmap* bitmap, SkRefCntPlayback* rcp) const {
        SkFlattenableReadBuffer buffer(fBitmapData);
        if (rcp) {
            rcp->setupBuffer(buffer);
        }
        bitmap->unflatten(buffer);
    }

#ifdef SK_DEBUG_VALIDATE
    void validate() const {
        // to be written
    }
#endif

private:
    char fBitmapData[1];
    typedef SkFlatData INHERITED;
};

class SkFlatMatrix : public SkFlatData {
public:
    static SkFlatMatrix* Flatten(SkChunkAlloc* heap, const SkMatrix& matrix, int index);

    void unflatten(SkMatrix* result) const {
        result->unflatten(fMatrixData);
    }

#ifdef SK_DEBUG_DUMP
    void dump() const;
#endif

#ifdef SK_DEBUG_VALIDATE
    void validate() const {
        // to be written
    }
#endif

private:
    char fMatrixData[1];
    typedef SkFlatData INHERITED;
};

class SkFlatPaint : public SkFlatData {
public:
    static SkFlatPaint* Flatten(SkChunkAlloc* heap, const SkPaint& paint,
                                int index, SkRefCntSet*,
                                SkRefCntSet* faceRecorder);
    
    void unflatten(SkPaint* result, SkRefCntPlayback* rcp,
                   SkTypefacePlayback* facePlayback) const {
        Read(fPaintData, result, rcp, facePlayback);
    }
    
    static void Read(const void* storage, SkPaint* paint, SkRefCntPlayback*,
                     SkTypefacePlayback* facePlayback);

#ifdef SK_DEBUG_DUMP
    void dump() const;
#endif
    
private:
    char fPaintData[1];
    typedef SkFlatData INHERITED;
};

class SkFlatRegion : public SkFlatData {
public:
    static SkFlatRegion* Flatten(SkChunkAlloc* heap, const SkRegion& region, int index);
    
    void unflatten(SkRegion* result) const {
        result->unflatten(fRegionData);
    }

#ifdef SK_DEBUG_VALIDATE
    void validate() const {
        // to be written
    }
#endif

private:
    char fRegionData[1];
    typedef SkFlatData INHERITED;
};

#endif
