| /* | |
| * Copyright 2023 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "src/image/SkSurface_Base.h" | |
| #include "include/core/SkBitmap.h" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkCapabilities.h" | |
| #include "include/core/SkColorSpace.h" // IWYU pragma: keep | |
| #include "include/core/SkImage.h" | |
| #include "include/core/SkImageInfo.h" | |
| #include "include/core/SkPixmap.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkRefCnt.h" | |
| #include "include/core/SkScalar.h" | |
| #include "include/core/SkSize.h" | |
| #include "include/core/SkSurface.h" | |
| #include "src/capture/SkCaptureCanvas.h" | |
| #include "src/capture/SkCaptureManager.h" | |
| #include "src/image/SkRescaleAndReadPixels.h" | |
| #include <atomic> | |
| #include <cstdint> | |
| class GrRecordingContext; | |
| class SkPaint; | |
| class SkSurfaceProps; | |
| namespace skgpu { namespace graphite { class Recorder; } } | |
| SkSurface_Base::SkSurface_Base(int width, int height, const SkSurfaceProps* props, | |
| sk_sp<SkPixelStorage> storage) | |
| : SkSurface(width, height, props), fPixelStorage(std::move(storage)) {} | |
| SkSurface_Base::SkSurface_Base(const SkImageInfo& info, const SkSurfaceProps* props, | |
| sk_sp<SkPixelStorage> storage) | |
| : SkSurface(info, props), fPixelStorage(std::move(storage)) {} | |
| SkSurface_Base::~SkSurface_Base() { | |
| // in case the canvas outsurvives us, we null the callback | |
| if (fCachedCanvas) { | |
| fCachedCanvas->setSurfaceBase(nullptr); | |
| fCachedCanvas->onSurfaceDelete(); | |
| } | |
| } | |
| GrRecordingContext* SkSurface_Base::onGetRecordingContext() const { return nullptr; } | |
| skgpu::graphite::Recorder* SkSurface_Base::onGetRecorder() const { return nullptr; } | |
| SkRecorder* SkSurface_Base::onGetBaseRecorder() const { return nullptr; } | |
| void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, | |
| const SkSamplingOptions& sampling, const SkPaint* paint) { | |
| auto image = this->makeTemporaryImage(); | |
| if (image) { | |
| canvas->drawImage(image.get(), x, y, sampling, paint); | |
| } | |
| } | |
| void SkSurface_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info, | |
| SkIRect origSrcRect, | |
| SkSurface::RescaleGamma rescaleGamma, | |
| RescaleMode rescaleMode, | |
| SkSurface::ReadPixelsCallback callback, | |
| SkSurface::ReadPixelsContext context) { | |
| SkBitmap src; | |
| SkPixmap peek; | |
| SkIRect srcRect; | |
| if (this->peekPixels(&peek)) { | |
| src.installPixels(peek); | |
| srcRect = origSrcRect; | |
| } else { | |
| src.setInfo(this->imageInfo().makeDimensions(origSrcRect.size())); | |
| src.allocPixels(); | |
| if (!this->readPixels(src, origSrcRect.x(), origSrcRect.y())) { | |
| callback(context, nullptr); | |
| return; | |
| } | |
| srcRect = SkIRect::MakeSize(src.dimensions()); | |
| } | |
| return SkRescaleAndReadPixels(src, info, srcRect, rescaleGamma, rescaleMode, callback, | |
| context); | |
| } | |
| void SkSurface_Base::onAsyncRescaleAndReadPixelsYUV420( | |
| SkYUVColorSpace yuvColorSpace, bool readAlpha, sk_sp<SkColorSpace> dstColorSpace, | |
| SkIRect srcRect, SkISize dstSize, RescaleGamma rescaleGamma, RescaleMode, | |
| ReadPixelsCallback callback, ReadPixelsContext context) { | |
| // TODO: Call non-YUV asyncRescaleAndReadPixels and then make our callback convert to YUV and | |
| // call client's callback. | |
| callback(context, nullptr); | |
| } | |
| bool SkSurface_Base::outstandingImageSnapshot() const { | |
| return fCachedImage && !fCachedImage->unique(); | |
| } | |
| bool SkSurface_Base::aboutToDraw(ContentChangeMode mode) { | |
| this->dirtyGenerationID(); | |
| SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this); | |
| if (fCachedImage) { | |
| // the surface may need to fork its backend, if its sharing it with | |
| // the cached image. Note: we only call if there is an outstanding owner | |
| // on the image (besides us). | |
| bool unique = fCachedImage->unique(); | |
| if (!unique) { | |
| if (!this->onCopyOnWrite(mode)) { | |
| return false; | |
| } | |
| } | |
| // regardless of copy-on-write, we must drop our cached image now, so | |
| // that the next request will get our new contents. | |
| fCachedImage.reset(); | |
| if (unique) { | |
| // Our content isn't held by any image now, so we can consider that content mutable. | |
| // Raster surfaces need to be told it's safe to consider its pixels mutable again. | |
| // We make this call after the ->unref() so the subclass can assert there are no images. | |
| this->onRestoreBackingMutability(); | |
| } | |
| } else if (kDiscard_ContentChangeMode == mode) { | |
| this->onDiscard(); | |
| } | |
| return true; | |
| } | |
| uint32_t SkSurface_Base::newGenerationID() { | |
| SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this); | |
| static std::atomic<uint32_t> nextID{1}; | |
| return nextID.fetch_add(1, std::memory_order_relaxed); | |
| } | |
| sk_sp<const SkCapabilities> SkSurface_Base::onCapabilities() { | |
| return SkCapabilities::RasterBackend(); | |
| } | |
| void SkSurface_Base::createCaptureBreakpoint() { | |
| if (this->baseRecorder()) { | |
| this->baseRecorder()->createCaptureBreakpoint(this); | |
| } | |
| } |