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

#include "GrPictureUtils.h"
#include "SkDevice.h"
#include "SkDraw.h"
#include "SkPaintPriv.h"
#include "SkPicturePlayback.h"

SkPicture::AccelData::Key GPUAccelData::ComputeAccelDataKey() {
    static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();

    return gGPUID;
}

// The GrGather device performs GPU-backend-specific preprocessing on
// a picture. The results are stored in a GPUAccelData.
//
// Currently the only interesting work is done in drawDevice (i.e., when a
// saveLayer is collapsed back into its parent) and, maybe, in onCreateDevice.
// All the current work could be done much more efficiently by just traversing the
// raw op codes in the SkPicture (although we would still need to replay all the
// clip calls).
class GrGatherDevice : public SkBaseDevice {
public:
    SK_DECLARE_INST_COUNT(GrGatherDevice)

    GrGatherDevice(int width, int height, const SkPicture* picture, GPUAccelData* accelData,
                   int saveLayerDepth) {
        fPicture = picture;
        fSaveLayerDepth = saveLayerDepth;
        fInfo.fValid = true;
        fInfo.fSize.set(width, height);
        fInfo.fPaint = NULL;
        fInfo.fSaveLayerOpID = fPicture->EXPERIMENTAL_curOpID();
        fInfo.fRestoreOpID = 0;
        fInfo.fHasNestedLayers = false;
        fInfo.fIsNested = (2 == fSaveLayerDepth);

        fEmptyBitmap.setInfo(SkImageInfo::MakeUnknown(fInfo.fSize.fWidth, fInfo.fSize.fHeight));
        fAccelData = accelData;
        fAlreadyDrawn = false;
    }

    virtual ~GrGatherDevice() { }

    virtual SkImageInfo imageInfo() const SK_OVERRIDE {
        return fEmptyBitmap.info();
    }

#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
    virtual void writePixels(const SkBitmap& bitmap, int x, int y,
                             SkCanvas::Config8888 config8888) SK_OVERRIDE {
        NotSupported();
    }
#endif
    virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }

protected:
    virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
        return false;
    }
    virtual void clear(SkColor color) SK_OVERRIDE {
        NothingToDo();
    }
    virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
    }
    virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
                            const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
    }
    virtual void drawRect(const SkDraw& draw, const SkRect& rect,
                          const SkPaint& paint) SK_OVERRIDE {
    }
    virtual void drawOval(const SkDraw& draw, const SkRect& rect,
                          const SkPaint& paint) SK_OVERRIDE {
    }
    virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
                           const SkPaint& paint) SK_OVERRIDE {
    }
    virtual void drawPath(const SkDraw& draw, const SkPath& path,
                          const SkPaint& paint, const SkMatrix* prePathMatrix,
                          bool pathIsMutable) SK_OVERRIDE {
    }
    virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
                            const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
    }
    virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
                            int x, int y, const SkPaint& paint) SK_OVERRIDE {
    }
    virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
                                const SkRect* srcOrNull, const SkRect& dst,
                                const SkPaint& paint,
                                SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
    }
    virtual void drawText(const SkDraw& draw, const void* text, size_t len,
                          SkScalar x, SkScalar y,
                          const SkPaint& paint) SK_OVERRIDE {
    }
    virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
                             const SkScalar pos[], SkScalar constY,
                             int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE {
    }
    virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len,
                                const SkPath& path, const SkMatrix* matrix,
                                const SkPaint& paint) SK_OVERRIDE {
    }
    virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount,
                              const SkPoint verts[], const SkPoint texs[],
                              const SkColor colors[], SkXfermode* xmode,
                              const uint16_t indices[], int indexCount,
                              const SkPaint& paint) SK_OVERRIDE {
    }
    virtual void drawDevice(const SkDraw& draw, SkBaseDevice* deviceIn, int x, int y,
                            const SkPaint& paint) SK_OVERRIDE {
        // deviceIn is the one that is being "restored" back to its parent
        GrGatherDevice* device = static_cast<GrGatherDevice*>(deviceIn);

        if (device->fAlreadyDrawn) {
            return;
        }

        device->fInfo.fRestoreOpID = fPicture->EXPERIMENTAL_curOpID();
        device->fInfo.fCTM = *draw.fMatrix;
        device->fInfo.fCTM.postTranslate(SkIntToScalar(-device->getOrigin().fX),
                                         SkIntToScalar(-device->getOrigin().fY));

        device->fInfo.fOffset = device->getOrigin();

        if (NeedsDeepCopy(paint)) {
            // This NULL acts as a signal that the paint was uncopyable (for now)
            device->fInfo.fPaint = NULL;
            device->fInfo.fValid = false;
        } else {
            device->fInfo.fPaint = SkNEW_ARGS(SkPaint, (paint));
        }

        fAccelData->addSaveLayerInfo(device->fInfo);
        device->fAlreadyDrawn = true;
    }
    // TODO: allow this call to return failure, or move to SkBitmapDevice only.
    virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
        return fEmptyBitmap;
    }
#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
    virtual bool onReadPixels(const SkBitmap& bitmap,
                              int x, int y,
                              SkCanvas::Config8888 config8888) SK_OVERRIDE {
        NotSupported();
        return false;
    }
#endif
    virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
    virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
    virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
    virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
    virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&,
                             SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
        return false;
    }

private:
    // The picture being processed
    const SkPicture *fPicture;

    SkBitmap fEmptyBitmap; // legacy -- need to remove

    // All information gathered during the gather process is stored here
    GPUAccelData* fAccelData;

    // true if this device has already been drawn back to its parent(s) at least
    // once.
    bool   fAlreadyDrawn;

    // The information regarding the saveLayer call this device represents.
    GPUAccelData::SaveLayerInfo fInfo;

    // The depth of this device in the saveLayer stack
    int fSaveLayerDepth;

    virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
        NotSupported();
    }

    virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE {
        // we expect to only get called via savelayer, in which case it is fine.
        SkASSERT(kSaveLayer_Usage == usage);

        fInfo.fHasNestedLayers = true;
        return SkNEW_ARGS(GrGatherDevice, (info.width(), info.height(), fPicture,
                                           fAccelData, fSaveLayerDepth+1));
    }

    virtual void flush() SK_OVERRIDE {}

    static void NotSupported() {
        SkDEBUGFAIL("this method should never be called");
    }

    static void NothingToDo() {}

    typedef SkBaseDevice INHERITED;
};

// The GrGatherCanvas allows saveLayers but simplifies clipping. It is really
// only intended to be used as:
//
//      GrGatherDevice dev(w, h, picture, accelData);
//      GrGatherCanvas canvas(..., picture);
//      canvas.gather();
//
// which is all just to fill in 'accelData'
class SK_API GrGatherCanvas : public SkCanvas {
public:
    GrGatherCanvas(GrGatherDevice* device, const SkPicture* pict)
        : INHERITED(device)
        , fPicture(pict) {
    }

    void gather() {
        if (NULL == fPicture || 0 == fPicture->width() || 0 == fPicture->height()) {
            return;
        }

        this->clipRect(SkRect::MakeWH(SkIntToScalar(fPicture->width()),
                                      SkIntToScalar(fPicture->height())),
                       SkRegion::kIntersect_Op, false);
        this->drawPicture(fPicture);
    }

protected:
    // disable aa for speed
    virtual void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
        this->INHERITED::onClipRect(rect, op, kHard_ClipEdgeStyle);
    }

    // for speed, just respect the bounds, and disable AA. May give us a few
    // false positives and negatives.
    virtual void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
        this->updateClipConservativelyUsingBounds(path.getBounds(), op,
                                                  path.isInverseFillType());
    }
    virtual void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
        this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
    }

    virtual void onDrawPicture(const SkPicture* picture) SK_OVERRIDE {
        // BBH-based rendering doesn't re-issue many of the operations the gather
        // process cares about (e.g., saves and restores) so it must be disabled.
        if (NULL != picture->fPlayback) {
            picture->fPlayback->setUseBBH(false);
        }
        picture->draw(this);
        if (NULL != picture->fPlayback) {
            picture->fPlayback->setUseBBH(true);
        }
    }

private:
    const SkPicture* fPicture;

    typedef SkCanvas INHERITED;
};

// GatherGPUInfo is only intended to be called within the context of SkGpuDevice's
// EXPERIMENTAL_optimize method.
void GatherGPUInfo(const SkPicture* pict, GPUAccelData* accelData) {
    if (0 == pict->width() || 0 == pict->height()) {
        return ;
    }

    GrGatherDevice device(pict->width(), pict->height(), pict, accelData, 0);
    GrGatherCanvas canvas(&device, pict);

    canvas.gather();
}
