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

#include "picture_utils.h"
#include "CopyTilesRenderer.h"
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkImageEncoder.h"
#include "SkPicture.h"
#include "SkPixelRef.h"
#include "SkRect.h"
#include "SkString.h"

namespace sk_tools {
    CopyTilesRenderer::CopyTilesRenderer(int x, int y)
    : fXTilesPerLargeTile(x)
    , fYTilesPerLargeTile(y) {
    }
    void CopyTilesRenderer::init(SkPicture* pict, const SkString* writePath,
                                 const SkString* mismatchPath, const SkString* inputFilename,
                                 bool useChecksumBasedFilenames) {
        // Do not call INHERITED::init(), which would create a (potentially large) canvas which is
        // not used by bench_pictures.
        SkASSERT(pict != NULL);
        // Only work with absolute widths (as opposed to percentages).
        SkASSERT(this->getTileWidth() != 0 && this->getTileHeight() != 0);
        fPicture.reset(pict)->ref();
        this->CopyString(&fWritePath, writePath);
        this->CopyString(&fMismatchPath, mismatchPath);
        this->CopyString(&fInputFilename, inputFilename);
        fUseChecksumBasedFilenames = useChecksumBasedFilenames;
        this->buildBBoxHierarchy();
        // In order to avoid allocating a large canvas (particularly important for GPU), create one
        // canvas that is a multiple of the tile size, and draw portions of the picture.
        fLargeTileWidth = fXTilesPerLargeTile * this->getTileWidth();
        fLargeTileHeight = fYTilesPerLargeTile * this->getTileHeight();
        fCanvas.reset(this->INHERITED::setupCanvas(fLargeTileWidth, fLargeTileHeight));
    }

    bool CopyTilesRenderer::render(SkBitmap** out) {
        int i = 0;
        bool success = true;
        SkBitmap dst;
        for (int x = 0; x < this->getViewWidth(); x += fLargeTileWidth) {
            for (int y = 0; y < this->getViewHeight(); y += fLargeTileHeight) {
                SkAutoCanvasRestore autoRestore(fCanvas, true);
                // Translate so that we draw the correct portion of the picture.
                // Perform a postTranslate so that the scaleFactor does not interfere with the
                // positioning.
                SkMatrix mat(fCanvas->getTotalMatrix());
                mat.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
                fCanvas->setMatrix(mat);
                // Draw the picture
                fCanvas->drawPicture(fPicture);
                // Now extract the picture into tiles
                const SkBitmap& baseBitmap = fCanvas->getDevice()->accessBitmap(false);
                SkIRect subset;
                for (int tileY = 0; tileY < fLargeTileHeight; tileY += this->getTileHeight()) {
                    for (int tileX = 0; tileX < fLargeTileWidth; tileX += this->getTileWidth()) {
                        subset.set(tileX, tileY, tileX + this->getTileWidth(),
                                   tileY + this->getTileHeight());
                        SkDEBUGCODE(bool extracted =)
                        baseBitmap.extractSubset(&dst, subset);
                        SkASSERT(extracted);
                        if (!fWritePath.isEmpty()) {
                            // Similar to write() in PictureRenderer.cpp, but just encodes
                            // a bitmap directly.
                            // TODO: Share more common code with write() to do this, to properly
                            // write out the JSON summary, etc.
                            SkString pathWithNumber = SkOSPath::SkPathJoin(fWritePath.c_str(),
                                                                           fInputFilename.c_str());
                            pathWithNumber.remove(pathWithNumber.size() - 4, 4);
                            pathWithNumber.appendf("%i.png", i++);
                            SkBitmap copy;
#if SK_SUPPORT_GPU
                            if (isUsingGpuDevice()) {
                                dst.pixelRef()->readPixels(&copy, &subset);
                            } else {
#endif
                                dst.copyTo(&copy);
#if SK_SUPPORT_GPU
                            }
#endif
                            success &= SkImageEncoder::EncodeFile(pathWithNumber.c_str(), copy,
                                                                  SkImageEncoder::kPNG_Type, 100);
                        }
                    }
                }
            }
        }
        return success;
    }

    SkString CopyTilesRenderer::getConfigNameInternal() {
        return SkString("copy_tiles");
    }
}
