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