xref: /aosp_15_r20/external/skia/src/image/SkSurface_Raster.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2012 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/image/SkSurface_Raster.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCapabilities.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMallocPixelRef.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPixelRef.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMath.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkBitmapDevice.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkImageInfoPriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkImagePriv.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkSurfacePriv.h"
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
28*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
29*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker class SkImage;
32*c8dee2aaSAndroid Build Coastguard Worker class SkPaint;
33*c8dee2aaSAndroid Build Coastguard Worker class SkPixmap;
34*c8dee2aaSAndroid Build Coastguard Worker class SkSurfaceProps;
35*c8dee2aaSAndroid Build Coastguard Worker 
SkSurfaceValidateRasterInfo(const SkImageInfo & info,size_t rowBytes)36*c8dee2aaSAndroid Build Coastguard Worker bool SkSurfaceValidateRasterInfo(const SkImageInfo& info, size_t rowBytes) {
37*c8dee2aaSAndroid Build Coastguard Worker     if (!SkImageInfoIsValid(info)) {
38*c8dee2aaSAndroid Build Coastguard Worker         return false;
39*c8dee2aaSAndroid Build Coastguard Worker     }
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker     if (kIgnoreRowBytesValue == rowBytes) {
42*c8dee2aaSAndroid Build Coastguard Worker         return true;
43*c8dee2aaSAndroid Build Coastguard Worker     }
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker     if (!info.validRowBytes(rowBytes)) {
46*c8dee2aaSAndroid Build Coastguard Worker         return false;
47*c8dee2aaSAndroid Build Coastguard Worker     }
48*c8dee2aaSAndroid Build Coastguard Worker 
49*c8dee2aaSAndroid Build Coastguard Worker     uint64_t size = sk_64_mul(info.height(), rowBytes);
50*c8dee2aaSAndroid Build Coastguard Worker     static const size_t kMaxTotalSize = SK_MaxS32;
51*c8dee2aaSAndroid Build Coastguard Worker     if (size > kMaxTotalSize) {
52*c8dee2aaSAndroid Build Coastguard Worker         return false;
53*c8dee2aaSAndroid Build Coastguard Worker     }
54*c8dee2aaSAndroid Build Coastguard Worker 
55*c8dee2aaSAndroid Build Coastguard Worker     return true;
56*c8dee2aaSAndroid Build Coastguard Worker }
57*c8dee2aaSAndroid Build Coastguard Worker 
SkSurface_Raster(const SkImageInfo & info,void * pixels,size_t rb,void (* releaseProc)(void * pixels,void * context),void * context,const SkSurfaceProps * props)58*c8dee2aaSAndroid Build Coastguard Worker SkSurface_Raster::SkSurface_Raster(const SkImageInfo& info, void* pixels, size_t rb,
59*c8dee2aaSAndroid Build Coastguard Worker                                    void (*releaseProc)(void* pixels, void* context), void* context,
60*c8dee2aaSAndroid Build Coastguard Worker                                    const SkSurfaceProps* props)
61*c8dee2aaSAndroid Build Coastguard Worker     : INHERITED(info, props)
62*c8dee2aaSAndroid Build Coastguard Worker {
63*c8dee2aaSAndroid Build Coastguard Worker     fBitmap.installPixels(info, pixels, rb, releaseProc, context);
64*c8dee2aaSAndroid Build Coastguard Worker     fWeOwnThePixels = false;    // We are "Direct"
65*c8dee2aaSAndroid Build Coastguard Worker }
66*c8dee2aaSAndroid Build Coastguard Worker 
SkSurface_Raster(const SkImageInfo & info,sk_sp<SkPixelRef> pr,const SkSurfaceProps * props)67*c8dee2aaSAndroid Build Coastguard Worker SkSurface_Raster::SkSurface_Raster(const SkImageInfo& info, sk_sp<SkPixelRef> pr,
68*c8dee2aaSAndroid Build Coastguard Worker                                    const SkSurfaceProps* props)
69*c8dee2aaSAndroid Build Coastguard Worker     : INHERITED(pr->width(), pr->height(), props)
70*c8dee2aaSAndroid Build Coastguard Worker {
71*c8dee2aaSAndroid Build Coastguard Worker     fBitmap.setInfo(info, pr->rowBytes());
72*c8dee2aaSAndroid Build Coastguard Worker     fBitmap.setPixelRef(std::move(pr), 0, 0);
73*c8dee2aaSAndroid Build Coastguard Worker     fWeOwnThePixels = true;
74*c8dee2aaSAndroid Build Coastguard Worker }
75*c8dee2aaSAndroid Build Coastguard Worker 
onNewCanvas()76*c8dee2aaSAndroid Build Coastguard Worker SkCanvas* SkSurface_Raster::onNewCanvas() { return new SkCanvas(fBitmap, this->props()); }
77*c8dee2aaSAndroid Build Coastguard Worker 
onNewSurface(const SkImageInfo & info)78*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkSurface> SkSurface_Raster::onNewSurface(const SkImageInfo& info) {
79*c8dee2aaSAndroid Build Coastguard Worker     return SkSurfaces::Raster(info, &this->props());
80*c8dee2aaSAndroid Build Coastguard Worker }
81*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint)82*c8dee2aaSAndroid Build Coastguard Worker void SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
83*c8dee2aaSAndroid Build Coastguard Worker                               const SkSamplingOptions& sampling, const SkPaint* paint) {
84*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawImage(fBitmap.asImage().get(), x, y, sampling, paint);
85*c8dee2aaSAndroid Build Coastguard Worker }
86*c8dee2aaSAndroid Build Coastguard Worker 
onNewImageSnapshot(const SkIRect * subset)87*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> SkSurface_Raster::onNewImageSnapshot(const SkIRect* subset) {
88*c8dee2aaSAndroid Build Coastguard Worker     if (subset) {
89*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(SkIRect::MakeWH(fBitmap.width(), fBitmap.height()).contains(*subset));
90*c8dee2aaSAndroid Build Coastguard Worker         SkBitmap dst;
91*c8dee2aaSAndroid Build Coastguard Worker         dst.allocPixels(fBitmap.info().makeDimensions(subset->size()));
92*c8dee2aaSAndroid Build Coastguard Worker         SkAssertResult(fBitmap.readPixels(dst.pixmap(), subset->left(), subset->top()));
93*c8dee2aaSAndroid Build Coastguard Worker         dst.setImmutable(); // key, so MakeFromBitmap doesn't make a copy of the buffer
94*c8dee2aaSAndroid Build Coastguard Worker         return dst.asImage();
95*c8dee2aaSAndroid Build Coastguard Worker     }
96*c8dee2aaSAndroid Build Coastguard Worker 
97*c8dee2aaSAndroid Build Coastguard Worker     SkCopyPixelsMode cpm = kIfMutable_SkCopyPixelsMode;
98*c8dee2aaSAndroid Build Coastguard Worker     if (fWeOwnThePixels) {
99*c8dee2aaSAndroid Build Coastguard Worker         // SkImage_raster requires these pixels are immutable for its full lifetime.
100*c8dee2aaSAndroid Build Coastguard Worker         // We'll undo this via onRestoreBackingMutability() if we can avoid the COW.
101*c8dee2aaSAndroid Build Coastguard Worker         if (SkPixelRef* pr = fBitmap.pixelRef()) {
102*c8dee2aaSAndroid Build Coastguard Worker             pr->setTemporarilyImmutable();
103*c8dee2aaSAndroid Build Coastguard Worker         }
104*c8dee2aaSAndroid Build Coastguard Worker     } else {
105*c8dee2aaSAndroid Build Coastguard Worker         cpm = kAlways_SkCopyPixelsMode;
106*c8dee2aaSAndroid Build Coastguard Worker     }
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker     // Our pixels are in memory, so read access on the snapshot SkImage could be cheap.
109*c8dee2aaSAndroid Build Coastguard Worker     // Lock the shared pixel ref to ensure peekPixels() is usable.
110*c8dee2aaSAndroid Build Coastguard Worker     return SkMakeImageFromRasterBitmap(fBitmap, cpm);
111*c8dee2aaSAndroid Build Coastguard Worker }
112*c8dee2aaSAndroid Build Coastguard Worker 
onWritePixels(const SkPixmap & src,int x,int y)113*c8dee2aaSAndroid Build Coastguard Worker void SkSurface_Raster::onWritePixels(const SkPixmap& src, int x, int y) {
114*c8dee2aaSAndroid Build Coastguard Worker     fBitmap.writePixels(src, x, y);
115*c8dee2aaSAndroid Build Coastguard Worker }
116*c8dee2aaSAndroid Build Coastguard Worker 
onRestoreBackingMutability()117*c8dee2aaSAndroid Build Coastguard Worker void SkSurface_Raster::onRestoreBackingMutability() {
118*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!this->hasCachedImage());  // Shouldn't be any snapshots out there.
119*c8dee2aaSAndroid Build Coastguard Worker     if (SkPixelRef* pr = fBitmap.pixelRef()) {
120*c8dee2aaSAndroid Build Coastguard Worker         pr->restoreMutability();
121*c8dee2aaSAndroid Build Coastguard Worker     }
122*c8dee2aaSAndroid Build Coastguard Worker }
123*c8dee2aaSAndroid Build Coastguard Worker 
onCopyOnWrite(ContentChangeMode mode)124*c8dee2aaSAndroid Build Coastguard Worker bool SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {
125*c8dee2aaSAndroid Build Coastguard Worker     // are we sharing pixelrefs with the image?
126*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> cached(this->refCachedImage());
127*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(cached);
128*c8dee2aaSAndroid Build Coastguard Worker     if (SkBitmapImageGetPixelRef(cached.get()) == fBitmap.pixelRef()) {
129*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fWeOwnThePixels);
130*c8dee2aaSAndroid Build Coastguard Worker         if (kDiscard_ContentChangeMode == mode) {
131*c8dee2aaSAndroid Build Coastguard Worker             if (!fBitmap.tryAllocPixels()) {
132*c8dee2aaSAndroid Build Coastguard Worker                 return false;
133*c8dee2aaSAndroid Build Coastguard Worker             }
134*c8dee2aaSAndroid Build Coastguard Worker         } else {
135*c8dee2aaSAndroid Build Coastguard Worker             SkBitmap prev(fBitmap);
136*c8dee2aaSAndroid Build Coastguard Worker             if (!fBitmap.tryAllocPixels()) {
137*c8dee2aaSAndroid Build Coastguard Worker                 return false;
138*c8dee2aaSAndroid Build Coastguard Worker             }
139*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(prev.info() == fBitmap.info());
140*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(prev.rowBytes() == fBitmap.rowBytes());
141*c8dee2aaSAndroid Build Coastguard Worker             memcpy(fBitmap.getPixels(), prev.getPixels(), fBitmap.computeByteSize());
142*c8dee2aaSAndroid Build Coastguard Worker         }
143*c8dee2aaSAndroid Build Coastguard Worker 
144*c8dee2aaSAndroid Build Coastguard Worker         // Now fBitmap is a deep copy of itself (and therefore different from
145*c8dee2aaSAndroid Build Coastguard Worker         // what is being used by the image. Next we update the canvas to use
146*c8dee2aaSAndroid Build Coastguard Worker         // this as its backend, so we can't modify the image's pixels anymore.
147*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(this->getCachedCanvas());
148*c8dee2aaSAndroid Build Coastguard Worker         SkBitmapDevice* bmDev = static_cast<SkBitmapDevice*>(this->getCachedCanvas()->rootDevice());
149*c8dee2aaSAndroid Build Coastguard Worker         bmDev->replaceBitmapBackendForRasterSurface(fBitmap);
150*c8dee2aaSAndroid Build Coastguard Worker     }
151*c8dee2aaSAndroid Build Coastguard Worker     return true;
152*c8dee2aaSAndroid Build Coastguard Worker }
153*c8dee2aaSAndroid Build Coastguard Worker 
onCapabilities()154*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const SkCapabilities> SkSurface_Raster::onCapabilities() {
155*c8dee2aaSAndroid Build Coastguard Worker     return SkCapabilities::RasterBackend();
156*c8dee2aaSAndroid Build Coastguard Worker }
157*c8dee2aaSAndroid Build Coastguard Worker 
158*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
159*c8dee2aaSAndroid Build Coastguard Worker namespace SkSurfaces {
WrapPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,PixelsReleaseProc releaseProc,void * context,const SkSurfaceProps * props)160*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkSurface> WrapPixels(const SkImageInfo& info,
161*c8dee2aaSAndroid Build Coastguard Worker                             void* pixels,
162*c8dee2aaSAndroid Build Coastguard Worker                             size_t rowBytes,
163*c8dee2aaSAndroid Build Coastguard Worker                             PixelsReleaseProc releaseProc,
164*c8dee2aaSAndroid Build Coastguard Worker                             void* context,
165*c8dee2aaSAndroid Build Coastguard Worker                             const SkSurfaceProps* props) {
166*c8dee2aaSAndroid Build Coastguard Worker     if (nullptr == releaseProc) {
167*c8dee2aaSAndroid Build Coastguard Worker         context = nullptr;
168*c8dee2aaSAndroid Build Coastguard Worker     }
169*c8dee2aaSAndroid Build Coastguard Worker     if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
170*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
171*c8dee2aaSAndroid Build Coastguard Worker     }
172*c8dee2aaSAndroid Build Coastguard Worker     if (nullptr == pixels) {
173*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
174*c8dee2aaSAndroid Build Coastguard Worker     }
175*c8dee2aaSAndroid Build Coastguard Worker 
176*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<SkSurface_Raster>(info, pixels, rowBytes, releaseProc, context, props);
177*c8dee2aaSAndroid Build Coastguard Worker }
178*c8dee2aaSAndroid Build Coastguard Worker 
WrapPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const SkSurfaceProps * props)179*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkSurface> WrapPixels(const SkImageInfo& info,
180*c8dee2aaSAndroid Build Coastguard Worker                             void* pixels,
181*c8dee2aaSAndroid Build Coastguard Worker                             size_t rowBytes,
182*c8dee2aaSAndroid Build Coastguard Worker                             const SkSurfaceProps* props) {
183*c8dee2aaSAndroid Build Coastguard Worker     return WrapPixels(info, pixels, rowBytes, nullptr, nullptr, props);
184*c8dee2aaSAndroid Build Coastguard Worker }
185*c8dee2aaSAndroid Build Coastguard Worker 
Raster(const SkImageInfo & info,size_t rowBytes,const SkSurfaceProps * props)186*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkSurface> Raster(const SkImageInfo& info, size_t rowBytes, const SkSurfaceProps* props) {
187*c8dee2aaSAndroid Build Coastguard Worker     if (!SkSurfaceValidateRasterInfo(info)) {
188*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
189*c8dee2aaSAndroid Build Coastguard Worker     }
190*c8dee2aaSAndroid Build Coastguard Worker 
191*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, rowBytes);
192*c8dee2aaSAndroid Build Coastguard Worker     if (!pr) {
193*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
194*c8dee2aaSAndroid Build Coastguard Worker     }
195*c8dee2aaSAndroid Build Coastguard Worker     if (rowBytes) {
196*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(pr->rowBytes() == rowBytes);
197*c8dee2aaSAndroid Build Coastguard Worker     }
198*c8dee2aaSAndroid Build Coastguard Worker     return sk_make_sp<SkSurface_Raster>(info, std::move(pr), props);
199*c8dee2aaSAndroid Build Coastguard Worker }
200*c8dee2aaSAndroid Build Coastguard Worker 
201*c8dee2aaSAndroid Build Coastguard Worker }  // namespace SkSurfaces
202