/*
 * 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 "PageCachingDocument.h"
#include "SkCanvas.h"
#include "SkDocument.h"
#include "SkPictureRecorder.h"
#include "SkRect.h"
#include "SkTDArray.h"

namespace {

typedef void (*DoneProc)(SkWStream*, bool);
typedef SkData* (*Encoder)(size_t*, const SkBitmap&);

// This class allows us to compare the relative memory consumption of
// the PDF and SkPicture backends.
class PageCachingDocument : public SkDocument {
public:
    PageCachingDocument(SkWStream*, DoneProc, Encoder, SkScalar rasterDpi);
    virtual ~PageCachingDocument();
    virtual SkCanvas* onBeginPage(SkScalar width,
                                  SkScalar height,
                                  const SkRect& content) SK_OVERRIDE;
    virtual void onEndPage() SK_OVERRIDE;
    virtual bool onClose(SkWStream*) SK_OVERRIDE;
    virtual void onAbort() SK_OVERRIDE;

private:
    struct Page {
        SkScalar fWidth;
        SkScalar fHeight;
        SkAutoTUnref<SkPicture> fPic;
    };
    SkPictureRecorder fRecorder;
    SkTDArray<Page> fPages;
    Encoder fEncoder;
    SkScalar fRasterDpi;
};

PageCachingDocument::PageCachingDocument(SkWStream* stream,
                                         DoneProc done,
                                         Encoder encoder,
                                         SkScalar rasterDpi)
    : SkDocument(stream, done), fEncoder(encoder), fRasterDpi(rasterDpi) {
}

PageCachingDocument::~PageCachingDocument() {
    for (Page* p = fPages.begin(); p != fPages.end(); ++p) {
        p->~Page();
    }
}

SkCanvas* PageCachingDocument::onBeginPage(SkScalar width,
                                           SkScalar height,
                                           const SkRect& content) {
    Page* page = fPages.push();
    sk_bzero(page, sizeof(*page));
    page->fWidth = width;
    page->fHeight = height;
    SkASSERT(!page->fPic.get());
    SkCanvas* canvas = fRecorder.beginRecording(content);
    return canvas;
}

void PageCachingDocument::onEndPage() {
    SkASSERT(fPages.count() > 0);
    SkASSERT(!fPages[fPages.count() - 1].fPic);
    fPages[fPages.count() - 1].fPic.reset(fRecorder.endRecording());
}

bool PageCachingDocument::onClose(SkWStream* stream) {
    SkAutoTUnref<SkDocument> doc(
        SkDocument::CreatePDF(stream, NULL, fEncoder, fRasterDpi));
    for (Page* page = fPages.begin(); page != fPages.end(); ++page) {
        SkRect cullRect = page->fPic->cullRect();
        SkCanvas* canvas =
            doc->beginPage(page->fWidth, page->fHeight, &cullRect);
        canvas->drawPicture(page->fPic);
        doc->endPage();
    }
    return doc->close();
}

void PageCachingDocument::onAbort() {
}
}  // namespace

SkDocument* CreatePageCachingDocument(SkWStream* stream,
                                      DoneProc done,
                                      Encoder encoder,
                                      SkScalar rasterDpi) {
    return SkNEW_ARGS(PageCachingDocument, (stream, done, encoder, rasterDpi));
}
