1 /*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkSurface_Base.h"
9 #include "SkImagePriv.h"
10 #include "SkCanvas.h"
11 #include "SkDevice.h"
12 #include "SkMallocPixelRef.h"
13
14 static const size_t kIgnoreRowBytesValue = (size_t)~0;
15
16 class SkSurface_Raster : public SkSurface_Base {
17 public:
18 static bool Valid(const SkImageInfo&, size_t rb = kIgnoreRowBytesValue);
19
20 SkSurface_Raster(const SkImageInfo&, void*, size_t rb,
21 void (*releaseProc)(void* pixels, void* context), void* context,
22 const SkSurfaceProps*);
23 SkSurface_Raster(sk_sp<SkPixelRef>, const SkSurfaceProps*);
24
25 SkCanvas* onNewCanvas() override;
26 sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override;
27 sk_sp<SkImage> onNewImageSnapshot() override;
28 void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override;
29 void onCopyOnWrite(ContentChangeMode) override;
30 void onRestoreBackingMutability() override;
31
32 private:
33 SkBitmap fBitmap;
34 size_t fRowBytes;
35 bool fWeOwnThePixels;
36
37 typedef SkSurface_Base INHERITED;
38 };
39
40 ///////////////////////////////////////////////////////////////////////////////
41
Valid(const SkImageInfo & info,size_t rowBytes)42 bool SkSurface_Raster::Valid(const SkImageInfo& info, size_t rowBytes) {
43 if (info.isEmpty()) {
44 return false;
45 }
46
47 static const size_t kMaxTotalSize = SK_MaxS32;
48
49 int shift = 0;
50 switch (info.colorType()) {
51 case kAlpha_8_SkColorType:
52 if (info.colorSpace()) {
53 return false;
54 }
55 shift = 0;
56 break;
57 case kRGB_565_SkColorType:
58 if (info.colorSpace()) {
59 return false;
60 }
61 shift = 1;
62 break;
63 case kN32_SkColorType:
64 if (info.colorSpace() && !info.colorSpace()->gammaCloseToSRGB()) {
65 return false;
66 }
67 shift = 2;
68 break;
69 case kRGBA_F16_SkColorType:
70 if (info.colorSpace() && !info.colorSpace()->gammaIsLinear()) {
71 return false;
72 }
73 shift = 3;
74 break;
75 default:
76 return false;
77 }
78
79 if (kIgnoreRowBytesValue == rowBytes) {
80 return true;
81 }
82
83 uint64_t minRB = (uint64_t)info.width() << shift;
84 if (minRB > rowBytes) {
85 return false;
86 }
87
88 size_t alignedRowBytes = rowBytes >> shift << shift;
89 if (alignedRowBytes != rowBytes) {
90 return false;
91 }
92
93 uint64_t size = sk_64_mul(info.height(), rowBytes);
94 if (size > kMaxTotalSize) {
95 return false;
96 }
97
98 return true;
99 }
100
SkSurface_Raster(const SkImageInfo & info,void * pixels,size_t rb,void (* releaseProc)(void * pixels,void * context),void * context,const SkSurfaceProps * props)101 SkSurface_Raster::SkSurface_Raster(const SkImageInfo& info, void* pixels, size_t rb,
102 void (*releaseProc)(void* pixels, void* context), void* context,
103 const SkSurfaceProps* props)
104 : INHERITED(info, props)
105 {
106 fBitmap.installPixels(info, pixels, rb, nullptr, releaseProc, context);
107 fRowBytes = 0; // don't need to track the rowbytes
108 fWeOwnThePixels = false; // We are "Direct"
109 }
110
SkSurface_Raster(sk_sp<SkPixelRef> pr,const SkSurfaceProps * props)111 SkSurface_Raster::SkSurface_Raster(sk_sp<SkPixelRef> pr, const SkSurfaceProps* props)
112 : INHERITED(pr->info().width(), pr->info().height(), props)
113 {
114 const SkImageInfo& info = pr->info();
115
116 fBitmap.setInfo(info, pr->rowBytes());
117 fRowBytes = pr->rowBytes(); // we track this, so that subsequent re-allocs will match
118 fBitmap.setPixelRef(std::move(pr), 0, 0);
119 fWeOwnThePixels = true;
120 }
121
onNewCanvas()122 SkCanvas* SkSurface_Raster::onNewCanvas() { return new SkCanvas(fBitmap, this->props()); }
123
onNewSurface(const SkImageInfo & info)124 sk_sp<SkSurface> SkSurface_Raster::onNewSurface(const SkImageInfo& info) {
125 return SkSurface::MakeRaster(info, &this->props());
126 }
127
onDraw(SkCanvas * canvas,SkScalar x,SkScalar y,const SkPaint * paint)128 void SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
129 const SkPaint* paint) {
130 canvas->drawBitmap(fBitmap, x, y, paint);
131 }
132
onNewImageSnapshot()133 sk_sp<SkImage> SkSurface_Raster::onNewImageSnapshot() {
134 SkCopyPixelsMode cpm = kIfMutable_SkCopyPixelsMode;
135 if (fWeOwnThePixels) {
136 // SkImage_raster requires these pixels are immutable for its full lifetime.
137 // We'll undo this via onRestoreBackingMutability() if we can avoid the COW.
138 if (SkPixelRef* pr = fBitmap.pixelRef()) {
139 pr->setTemporarilyImmutable();
140 }
141 } else {
142 cpm = kAlways_SkCopyPixelsMode;
143 }
144
145 // Our pixels are in memory, so read access on the snapshot SkImage could be cheap.
146 // Lock the shared pixel ref to ensure peekPixels() is usable.
147 return SkMakeImageFromRasterBitmap(fBitmap, cpm);
148 }
149
onRestoreBackingMutability()150 void SkSurface_Raster::onRestoreBackingMutability() {
151 SkASSERT(!this->hasCachedImage()); // Shouldn't be any snapshots out there.
152 if (SkPixelRef* pr = fBitmap.pixelRef()) {
153 pr->restoreMutability();
154 }
155 }
156
onCopyOnWrite(ContentChangeMode mode)157 void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {
158 // are we sharing pixelrefs with the image?
159 sk_sp<SkImage> cached(this->refCachedImage());
160 SkASSERT(cached);
161 if (SkBitmapImageGetPixelRef(cached.get()) == fBitmap.pixelRef()) {
162 SkASSERT(fWeOwnThePixels);
163 if (kDiscard_ContentChangeMode == mode) {
164 fBitmap.allocPixels();
165 } else {
166 SkBitmap prev(fBitmap);
167 fBitmap.allocPixels();
168 prev.lockPixels();
169 SkASSERT(prev.info() == fBitmap.info());
170 SkASSERT(prev.rowBytes() == fBitmap.rowBytes());
171 memcpy(fBitmap.getPixels(), prev.getPixels(), fBitmap.getSafeSize());
172 }
173 SkASSERT(fBitmap.rowBytes() == fRowBytes); // be sure we always use the same value
174
175 // Now fBitmap is a deep copy of itself (and therefore different from
176 // what is being used by the image. Next we update the canvas to use
177 // this as its backend, so we can't modify the image's pixels anymore.
178 SkASSERT(this->getCachedCanvas());
179 this->getCachedCanvas()->getDevice()->replaceBitmapBackendForRasterSurface(fBitmap);
180 }
181 }
182
183 ///////////////////////////////////////////////////////////////////////////////
184
MakeRasterDirectReleaseProc(const SkImageInfo & info,void * pixels,size_t rb,void (* releaseProc)(void * pixels,void * context),void * context,const SkSurfaceProps * props)185 sk_sp<SkSurface> SkSurface::MakeRasterDirectReleaseProc(const SkImageInfo& info, void* pixels,
186 size_t rb, void (*releaseProc)(void* pixels, void* context), void* context,
187 const SkSurfaceProps* props) {
188 if (nullptr == releaseProc) {
189 context = nullptr;
190 }
191 if (!SkSurface_Raster::Valid(info, rb)) {
192 return nullptr;
193 }
194 if (nullptr == pixels) {
195 return nullptr;
196 }
197
198 return sk_make_sp<SkSurface_Raster>(info, pixels, rb, releaseProc, context, props);
199 }
200
MakeRasterDirect(const SkImageInfo & info,void * pixels,size_t rowBytes,const SkSurfaceProps * props)201 sk_sp<SkSurface> SkSurface::MakeRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes,
202 const SkSurfaceProps* props) {
203 return MakeRasterDirectReleaseProc(info, pixels, rowBytes, nullptr, nullptr, props);
204 }
205
MakeRaster(const SkImageInfo & info,size_t rowBytes,const SkSurfaceProps * props)206 sk_sp<SkSurface> SkSurface::MakeRaster(const SkImageInfo& info, size_t rowBytes,
207 const SkSurfaceProps* props) {
208 if (!SkSurface_Raster::Valid(info)) {
209 return nullptr;
210 }
211
212 sk_sp<SkPixelRef> pr(SkMallocPixelRef::NewZeroed(info, rowBytes, nullptr));
213 if (!pr) {
214 return nullptr;
215 }
216 if (rowBytes) {
217 SkASSERT(pr->rowBytes() == rowBytes);
218 }
219 return sk_make_sp<SkSurface_Raster>(std::move(pr), props);
220 }
221