/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file */ #include "include/core/SkCanvas.h" #include "src/core/SkSpecialImage.h" #include "src/core/SkSpecialSurface.h" #include "src/core/SkSurfacePriv.h" /////////////////////////////////////////////////////////////////////////////// class SkSpecialSurface_Base : public SkSpecialSurface { public: SkSpecialSurface_Base(const SkIRect& subset, const SkSurfaceProps* props) : INHERITED(subset, props) , fCanvas(nullptr) { } virtual ~SkSpecialSurface_Base() { } // reset is called after an SkSpecialImage has been snapped void reset() { fCanvas.reset(); } // This can return nullptr if reset has already been called or something when wrong in the ctor SkCanvas* onGetCanvas() { return fCanvas.get(); } virtual sk_sp onMakeImageSnapshot() = 0; protected: std::unique_ptr fCanvas; // initialized by derived classes in ctors private: typedef SkSpecialSurface INHERITED; }; /////////////////////////////////////////////////////////////////////////////// static SkSpecialSurface_Base* as_SB(SkSpecialSurface* surface) { return static_cast(surface); } SkSpecialSurface::SkSpecialSurface(const SkIRect& subset, const SkSurfaceProps* props) : fProps(SkSurfacePropsCopyOrDefault(props).flags(), kUnknown_SkPixelGeometry) , fSubset(subset) { SkASSERT(fSubset.width() > 0); SkASSERT(fSubset.height() > 0); } SkCanvas* SkSpecialSurface::getCanvas() { return as_SB(this)->onGetCanvas(); } sk_sp SkSpecialSurface::makeImageSnapshot() { sk_sp image(as_SB(this)->onMakeImageSnapshot()); as_SB(this)->reset(); return image; // the caller gets the creation ref } /////////////////////////////////////////////////////////////////////////////// #include "include/core/SkMallocPixelRef.h" class SkSpecialSurface_Raster : public SkSpecialSurface_Base { public: SkSpecialSurface_Raster(const SkImageInfo& info, sk_sp pr, const SkIRect& subset, const SkSurfaceProps* props) : INHERITED(subset, props) { SkASSERT(info.width() == pr->width() && info.height() == pr->height()); fBitmap.setInfo(info, info.minRowBytes()); fBitmap.setPixelRef(std::move(pr), 0, 0); fCanvas.reset(new SkCanvas(fBitmap, this->props())); fCanvas->clipRect(SkRect::Make(subset)); #ifdef SK_IS_BOT fCanvas->clear(SK_ColorRED); // catch any imageFilter sloppiness #endif } ~SkSpecialSurface_Raster() override { } sk_sp onMakeImageSnapshot() override { return SkSpecialImage::MakeFromRaster(this->subset(), fBitmap, &this->props()); } private: SkBitmap fBitmap; typedef SkSpecialSurface_Base INHERITED; }; sk_sp SkSpecialSurface::MakeFromBitmap(const SkIRect& subset, SkBitmap& bm, const SkSurfaceProps* props) { if (subset.isEmpty() || !SkSurfaceValidateRasterInfo(bm.info(), bm.rowBytes())) { return nullptr; } return sk_make_sp(bm.info(), sk_ref_sp(bm.pixelRef()), subset, props); } sk_sp SkSpecialSurface::MakeRaster(const SkImageInfo& info, const SkSurfaceProps* props) { if (!SkSurfaceValidateRasterInfo(info)) { return nullptr; } sk_sp pr = SkMallocPixelRef::MakeAllocate(info, 0); if (!pr) { return nullptr; } const SkIRect subset = SkIRect::MakeWH(info.width(), info.height()); return sk_make_sp(info, std::move(pr), subset, props); } #if SK_SUPPORT_GPU /////////////////////////////////////////////////////////////////////////////// #include "include/gpu/GrBackendSurface.h" #include "include/private/GrRecordingContext.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/SkGpuDevice.h" class SkSpecialSurface_Gpu : public SkSpecialSurface_Base { public: SkSpecialSurface_Gpu(GrRecordingContext* context, sk_sp renderTargetContext, int width, int height, const SkIRect& subset) : INHERITED(subset, &renderTargetContext->surfaceProps()) , fRenderTargetContext(std::move(renderTargetContext)) { // CONTEXT TODO: remove this use of 'backdoor' to create an SkGpuDevice sk_sp device(SkGpuDevice::Make(context->priv().backdoor(), fRenderTargetContext, width, height, SkGpuDevice::kUninit_InitContents)); if (!device) { return; } fCanvas.reset(new SkCanvas(device)); fCanvas->clipRect(SkRect::Make(subset)); #ifdef SK_IS_BOT fCanvas->clear(SK_ColorRED); // catch any imageFilter sloppiness #endif } ~SkSpecialSurface_Gpu() override { } sk_sp onMakeImageSnapshot() override { if (!fRenderTargetContext->asTextureProxy()) { return nullptr; } sk_sp tmp(SkSpecialImage::MakeDeferredFromGpu( fCanvas->getGrContext(), this->subset(), kNeedNewImageUniqueID_SpecialImage, fRenderTargetContext->asTextureProxyRef(), fRenderTargetContext->colorSpaceInfo().refColorSpace(), &this->props())); fRenderTargetContext = nullptr; return tmp; } private: sk_sp fRenderTargetContext; typedef SkSpecialSurface_Base INHERITED; }; sk_sp SkSpecialSurface::MakeRenderTarget(GrRecordingContext* context, int width, int height, GrColorType colorType, sk_sp colorSpace, const SkSurfaceProps* props) { if (!context) { return nullptr; } sk_sp renderTargetContext( context->priv().makeDeferredRenderTargetContext( SkBackingFit::kApprox, width, height, colorType, std::move(colorSpace), 1, GrMipMapped::kNo, kBottomLeft_GrSurfaceOrigin, props)); if (!renderTargetContext) { return nullptr; } const SkIRect subset = SkIRect::MakeWH(width, height); return sk_make_sp(context, std::move(renderTargetContext), width, height, subset); } #endif