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