
/*
 * 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 "SkDebugger.h"
#include "SkPictureRecorder.h"
#include "SkString.h"


SkDebugger::SkDebugger()
    : fPicture(nullptr)
    , fIndex(-1) {
    // Create this some other dynamic way?
    fDebugCanvas = new SkDebugCanvas(0, 0);
}

SkDebugger::~SkDebugger() {
    // Need to inherit from SkRef object in order for following to work
    SkSafeUnref(fDebugCanvas);
    SkSafeUnref(fPicture);
}

void SkDebugger::loadPicture(SkPicture* picture) {
    SkRefCnt_SafeAssign(fPicture, picture);

    delete fDebugCanvas;
    fDebugCanvas = new SkDebugCanvas(SkScalarCeilToInt(this->pictureCull().width()), 
                                     SkScalarCeilToInt(this->pictureCull().height()));
    fDebugCanvas->setPicture(picture);
    picture->playback(fDebugCanvas);
    fDebugCanvas->setPicture(nullptr);
    fIndex = fDebugCanvas->getSize() - 1;
}

SkPicture* SkDebugger::copyPicture() {
    // We can't just call clone here since we want to removed the "deleted"
    // commands. Playing back will strip those out.
    SkPictureRecorder recorder;
    SkCanvas* canvas = recorder.beginRecording(this->pictureCull().width(), 
                                               this->pictureCull().height());

    bool vizMode = fDebugCanvas->getMegaVizMode();
    fDebugCanvas->setMegaVizMode(false);
    bool overDraw = fDebugCanvas->getOverdrawViz();
    fDebugCanvas->setOverdrawViz(false);
    bool pathOps = fDebugCanvas->getAllowSimplifyClip();
    fDebugCanvas->setAllowSimplifyClip(false);

    fDebugCanvas->draw(canvas);

    fDebugCanvas->setMegaVizMode(vizMode);
    fDebugCanvas->setOverdrawViz(overDraw);
    fDebugCanvas->setAllowSimplifyClip(pathOps);

    return recorder.endRecording();
}

void SkDebugger::getOverviewText(const SkTDArray<double>* typeTimes,
                                 double totTime,
                                 SkString* overview,
                                 int numRuns) {
    const SkTDArray<SkDrawCommand*>& commands = this->getDrawCommands();

    SkTDArray<int> counts;
    counts.setCount(SkDrawCommand::kOpTypeCount);
    for (int i = 0; i < SkDrawCommand::kOpTypeCount; ++i) {
        counts[i] = 0;
    }

    for (int i = 0; i < commands.count(); i++) {
        counts[commands[i]->getType()]++;
    }

    overview->reset();
    int total = 0;
#ifdef SK_DEBUG
    double totPercent = 0, tempSum = 0;
#endif
    for (int i = 0; i < SkDrawCommand::kOpTypeCount; ++i) {
        if (0 == counts[i]) {
            // if there were no commands of this type then they should've consumed no time
            SkASSERT(nullptr == typeTimes || 0.0 == (*typeTimes)[i]);
            continue;
        }

        overview->append(SkDrawCommand::GetCommandString((SkDrawCommand::OpType) i));
        overview->append(": ");
        overview->appendS32(counts[i]);
        if (typeTimes && totTime >= 0.0) {
            overview->append(" - ");
            overview->appendf("%.2f", (*typeTimes)[i]/(float)numRuns);
            overview->append("ms");
            overview->append(" - ");
            double percent = 100.0*(*typeTimes)[i]/totTime;
            overview->appendf("%.2f", percent);
            overview->append("%");
#ifdef SK_DEBUG
            totPercent += percent;
            tempSum += (*typeTimes)[i];
#endif
        }
        overview->append("<br/>");
        total += counts[i];
    }
#ifdef SK_DEBUG
    if (typeTimes) {
        SkASSERT(SkScalarNearlyEqual(SkDoubleToScalar(totPercent),
                                     SkDoubleToScalar(100.0)));
        SkASSERT(SkScalarNearlyEqual(SkDoubleToScalar(tempSum),
                                     SkDoubleToScalar(totTime)));
    }
#endif

    if (totTime > 0.0) {
        overview->append("Total Time: ");
        overview->appendf("%.2f", totTime/(float)numRuns);
        overview->append("ms");
#ifdef SK_DEBUG
        overview->append(" ");
        overview->appendScalar(SkDoubleToScalar(totPercent));
        overview->append("% ");
#endif
        overview->append("<br/>");
    }

    SkString totalStr;
    totalStr.append("Total Draw Commands: ");
    totalStr.appendScalar(SkDoubleToScalar(total));
    totalStr.append("<br/>");
    overview->insert(0, totalStr);

    overview->append("<br/>SkPicture L: ");
    overview->appendScalar(this->pictureCull().fLeft);
    overview->append(" T: ");
    overview->appendScalar(this->pictureCull().fTop);
    overview->append(" R: ");
    overview->appendScalar(this->pictureCull().fRight);
    overview->append(" B: ");
    overview->appendScalar(this->pictureCull().fBottom);
    overview->append("<br/>");
}

void SkDebugger::getClipStackText(SkString* clipStack) {
    clipStack->set(fDebugCanvas->clipStackData());
}
