| /* | |
| * 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 "src/capture/SkCaptureManager.h" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkPicture.h" | |
| #include "include/core/SkRefCnt.h" | |
| #include "include/core/SkSurface.h" | |
| #include "src/capture/SkCapture.h" | |
| #include "src/capture/SkCaptureCanvas.h" | |
| #include "src/image/SkSurface_Base.h" | |
| #include <algorithm> | |
| #include <memory> | |
| SkCaptureManager::SkCaptureManager() {} | |
| SkCanvas* SkCaptureManager::makeCaptureCanvas(SkCanvas* canvas) { | |
| auto newCanvas = std::make_unique<SkCaptureCanvas>(canvas, this); | |
| auto rawCanvasPtr = newCanvas.get(); | |
| fTrackedCanvases.emplace_back(std::move(newCanvas)); | |
| return rawCanvasPtr; | |
| } | |
| void SkCaptureManager::deregisterCaptureCanvas(SkCanvas* canvas) { | |
| if (!canvas) { | |
| return; | |
| } | |
| for (int i = 0; i < fTrackedCanvases.size(); ++i) { | |
| if (fTrackedCanvases[i].get() != canvas) { continue; } | |
| // Make sure we gather any draws that haven't been inserted into a recording | |
| // before removing the canvas. | |
| if (fIsCurrentlyCapturing) { | |
| auto picture = this->snapAndIncrement(fTrackedCanvases[i].get()); | |
| if (picture && fActiveCapture) { | |
| fActiveCapture->addAsset(std::move(picture)); | |
| } | |
| } | |
| fTrackedCanvases.removeShuffle(i); | |
| return; | |
| } | |
| } | |
| sk_sp<SkPicture> SkCaptureManager::snapAndIncrement(SkCaptureCanvas* canvas) { | |
| auto picture = canvas->snapPicture(); | |
| if (picture) { | |
| if (auto storage = asSB(canvas->getBaseCanvasSurface())->getPixelStorage()) { | |
| storage->incrementContentId(); | |
| } | |
| } | |
| return picture; | |
| } | |
| void SkCaptureManager::captureUninsertedDrawTasks() { | |
| for (auto& canvas : fTrackedCanvases) { | |
| if (canvas) { | |
| auto picture = this->snapAndIncrement(canvas.get()); | |
| if (picture && fActiveCapture) { | |
| fActiveCapture->addAsset(std::move(picture)); | |
| } | |
| } | |
| } | |
| } | |
| // TODO: make thread safe by using exchange() and a mutex. | |
| void SkCaptureManager::toggleCapture(bool capturing) { | |
| if (capturing != fIsCurrentlyCapturing) { | |
| if (capturing) { | |
| fActiveCapture = SkCapture::MakeEmpty(); | |
| } else { | |
| // on capture stop, save the capture and reset | |
| this->captureUninsertedDrawTasks(); | |
| fLastCapture = std::move(fActiveCapture); | |
| } | |
| } | |
| fIsCurrentlyCapturing = capturing; | |
| } | |
| sk_sp<SkPicture> SkCaptureManager::snapPicture(SkSurface* surface) { | |
| for (auto& canvas : fTrackedCanvases) { | |
| if (canvas) { | |
| if (canvas->getBaseCanvasSurface() == surface) { | |
| return this->snapAndIncrement(canvas.get()); | |
| } | |
| } | |
| } | |
| return nullptr; | |
| } | |
| sk_sp<SkCapture> SkCaptureManager::getLastCapture() const { | |
| return fLastCapture; | |
| } | |
| skia_private::TArray<sk_sp<SkPicture>> SkCaptureManager::snapDrawTasksForStorageIDs( | |
| SkSpan<const uint32_t> storageIds) { | |
| skia_private::TArray<sk_sp<SkPicture>> snapped; | |
| if (!fIsCurrentlyCapturing || storageIds.empty()) { | |
| return snapped; | |
| } | |
| for (auto& canvas : fTrackedCanvases) { | |
| if (!canvas) { | |
| continue; | |
| } | |
| SkSurface* surface = canvas->getBaseCanvasSurface(); | |
| if (!surface) { | |
| continue; | |
| } | |
| auto storage = asSB(surface)->getPixelStorage(); | |
| if (!storage) { | |
| continue; | |
| } | |
| uint32_t id = storage->getPixelStorageId(); | |
| if (std::find(storageIds.begin(), storageIds.end(), id) != storageIds.end()) { | |
| if (auto picture = this->snapAndIncrement(canvas.get())) { | |
| snapped.push_back(std::move(picture)); | |
| } | |
| } | |
| } | |
| return snapped; | |
| } | |
| void SkCaptureManager::onInsertRecording(const skia_private::TArray<sk_sp<SkPicture>>& capturedPictures) { | |
| if (!fIsCurrentlyCapturing || !fActiveCapture) return; | |
| skia_private::TArray<SkCapture::DrawTask> drawTasks; | |
| for (const auto& pic : capturedPictures) { | |
| fActiveCapture->addAsset(pic); | |
| uint32_t assetIdx = fActiveCapture->getMetadata().numAssets - 1; | |
| drawTasks.push_back({assetIdx}); | |
| } | |
| SkCapture::RecordingCapture rec = { | |
| std::move(drawTasks) | |
| }; | |
| fActiveCapture->addRecordingCapture(std::move(rec)); | |
| } |