blob: 53f0b7353296be131d386d313e8d36973046492a [file]
/*
* Copyright 2025 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "tools/viewer/CaptureSlide.h"
#include "imgui.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkClipOp.h"
#include "include/core/SkData.h"
#include "include/core/SkPicture.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkStream.h"
#include "include/private/SkDebug.h"
#include "src/capture/SkCapture.h"
#include "src/core/SkBigPicture.h"
#include "src/core/SkRecord.h"
#include "src/utils/SkJSONWriter.h"
#include "tools/ProcsUtils.h"
#include "tools/UrlDataManager.h"
#include "tools/debugger/DebugCanvas.h"
#include "tools/debugger/DrawCommand.h"
#include <string>
const char* RecordTypeNames[] = {
#define CASE(T) #T,
SK_RECORD_TYPES(CASE)
#undef CASE
};
CaptureSlide::CaptureSlide(const SkString& name, const SkString& path) {
auto data = SkData::MakeFromFileName(path.c_str());
fCapture = SkCapture::MakeFromData(data);
if (fCapture) {
fMetadata = fCapture->getMetadata();
} else {
SkDebugf("Couldn't load capture %s", path.c_str());
}
}
CaptureSlide::~CaptureSlide() {}
void drawCommandHistory(const DebugCanvas* debugCanvas) {
static int currentCommandIdx = 0;
ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_Appearing);
if (!ImGui::Begin("Command History")) {
ImGui::End();
return;
}
ImGui::Text("Total Commands: %d", debugCanvas->getSize());
ImGui::Separator();
const char* previewValue = "Select a command...";
if (currentCommandIdx >= 0 && currentCommandIdx < debugCanvas->getSize()) {
DrawCommand* cmd = debugCanvas->getDrawCommandAt(currentCommandIdx);
previewValue = DrawCommand::GetCommandString(cmd->getOpType());
}
if (ImGui::BeginCombo("Select Command", previewValue)) {
for (int i = 0; i < debugCanvas->getSize(); ++i) {
const bool isSelected = (currentCommandIdx == i);
DrawCommand* cmd = debugCanvas->getDrawCommandAt(i);
const char* commandName = DrawCommand::GetCommandString(cmd->getOpType());
if (ImGui::Selectable(commandName, isSelected)) {
currentCommandIdx = i;
}
if (isSelected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
if (currentCommandIdx >= 0 && currentCommandIdx < debugCanvas->getSize()) {
ImGui::Separator();
ImGui::Text("JSON for Command #%d:", currentCommandIdx);
DrawCommand* cmd = debugCanvas->getDrawCommandAt(currentCommandIdx);
SkDynamicMemoryWStream stream;
SkJSONWriter writer(&stream, ToolUtils::default_serial_procs(), SkJSONWriter::Mode::kPretty);
UrlDataManager urlDataManager(SkString("data"));
writer.beginObject();
cmd->toJSON(writer, urlDataManager);
writer.endObject();
writer.flush();
stream.write8(0);
sk_sp<SkData> data = stream.detachAsData();
char* dataString = const_cast<char*>(static_cast<const char*>(data->data()));
ImGui::InputTextMultiline("###json_output",
dataString,
data->size(),
ImVec2(-1, -1),
ImGuiInputTextFlags_ReadOnly);
}
ImGui::End();
}
void drawMetadata(int currentPictureIndex) {
ImGui::Begin("Capture Info");
ImGui::Text("Current Index: %d", currentPictureIndex);
ImGui::End();
}
void CaptureSlide::draw(SkCanvas* canvas) {
if (!fCapture) {
return;
}
auto focusPicture = fCapture->getPicture(fCurrentPictureIndex);
auto bounds = focusPicture->cullRect().roundOut();
DebugCanvas debugCanvas(bounds.width(), bounds.height());
focusPicture->playback(&debugCanvas);
canvas->clipIRect(bounds, SkClipOp::kIntersect);
canvas->drawPicture(fCapture->getPicture(fCurrentPictureIndex));
drawMetadata(fCurrentPictureIndex);
drawCommandHistory(&debugCanvas);
}
bool CaptureSlide::animate(double) {
if (fInvalidate) {
fInvalidate = false;
return true;
}
return fInvalidate;
}
void CaptureSlide::load(SkScalar, SkScalar) {}
void CaptureSlide::unload() { fCapture.reset(nullptr); }
SkISize CaptureSlide::getDimensions() const { return {0, 0}; }
bool CaptureSlide::onChar(SkUnichar c) {
switch (c) {
case 'N':
fCurrentPictureIndex = (fCurrentPictureIndex + 1) % fMetadata.numPictures;
fInvalidate = true;
return true;
case 'P':
fCurrentPictureIndex =
(fCurrentPictureIndex + fMetadata.numPictures - 1) % fMetadata.numPictures;
fInvalidate = true;
return true;
case 'F':
ImGui::GetIO().FontGlobalScale = ImGui::GetIO().FontGlobalScale + 0.1f;
return true;
case 'S':
ImGui::GetIO().FontGlobalScale = ImGui::GetIO().FontGlobalScale - 0.1f;
return true;
}
return Slide::onChar(c);
}