blob: ab37659f2f5ab41a54c353044327f08e09434c62 [file] [log] [blame]
reed@google.com58b21ec2012-07-30 18:20:12 +00001/*
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 "SkImage_Base.h"
reed@google.com58b21ec2012-07-30 18:20:12 +00009#include "SkBitmap.h"
10#include "SkCanvas.h"
11#include "SkData.h"
reed871872f2015-06-22 12:48:26 -070012#include "SkImageGeneratorPriv.h"
kkinnunen73953e72015-02-23 22:12:12 -080013#include "SkImagePriv.h"
14#include "SkPixelRef.h"
reed4af267b2014-11-21 08:46:37 -080015#include "SkSurface.h"
reed@google.com58b21ec2012-07-30 18:20:12 +000016
17class SkImage_Raster : public SkImage_Base {
18public:
reedde499882015-06-18 13:41:40 -070019 static bool ValidArgs(const Info& info, size_t rowBytes, size_t* minSize) {
reed@google.com58b21ec2012-07-30 18:20:12 +000020 const int maxDimension = SK_MaxS32 >> 2;
reed@google.com58b21ec2012-07-30 18:20:12 +000021
reedb2497c22014-12-31 12:31:43 -080022 if (info.width() <= 0 || info.height() <= 0) {
reed@google.com58b21ec2012-07-30 18:20:12 +000023 return false;
24 }
reede5ea5002014-09-03 11:54:58 -070025 if (info.width() > maxDimension || info.height() > maxDimension) {
reed@google.com58b21ec2012-07-30 18:20:12 +000026 return false;
27 }
reede5ea5002014-09-03 11:54:58 -070028 if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) {
reed@google.com58b21ec2012-07-30 18:20:12 +000029 return false;
30 }
reede5ea5002014-09-03 11:54:58 -070031 if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) {
reed@google.com58b21ec2012-07-30 18:20:12 +000032 return false;
33 }
34
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +000035 if (kUnknown_SkColorType == info.colorType()) {
reed@google.com58b21ec2012-07-30 18:20:12 +000036 return false;
37 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000038
reed@google.com58b21ec2012-07-30 18:20:12 +000039 // TODO: check colorspace
rmistry@google.comfbfcd562012-08-23 18:09:54 +000040
reed@google.com58b21ec2012-07-30 18:20:12 +000041 if (rowBytes < SkImageMinRowBytes(info)) {
42 return false;
43 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000044
reedde499882015-06-18 13:41:40 -070045 size_t size = info.getSafeSize(rowBytes);
46 if (0 == size) {
reed@google.com58b21ec2012-07-30 18:20:12 +000047 return false;
48 }
reedde499882015-06-18 13:41:40 -070049
50 if (minSize) {
51 *minSize = size;
52 }
reed@google.com58b21ec2012-07-30 18:20:12 +000053 return true;
54 }
55
reed4af267b2014-11-21 08:46:37 -080056 SkImage_Raster(const SkImageInfo&, SkData*, size_t rb, const SkSurfaceProps*);
reed@google.com58b21ec2012-07-30 18:20:12 +000057 virtual ~SkImage_Raster();
58
mtklein36352bf2015-03-25 18:17:31 -070059 SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) const override;
60 bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY) const override;
61 const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const override;
reed871872f2015-06-22 12:48:26 -070062 SkData* onRefEncoded() const override;
mtklein36352bf2015-03-25 18:17:31 -070063 bool getROPixels(SkBitmap*) const override;
reed@google.com58b21ec2012-07-30 18:20:12 +000064
65 // exposed for SkSurface_Raster via SkNewImageFromPixelRef
kkinnunen73953e72015-02-23 22:12:12 -080066 SkImage_Raster(const SkImageInfo&, SkPixelRef*, const SkIPoint& pixelRefOrigin, size_t rowBytes,
67 const SkSurfaceProps*);
reed@google.com58b21ec2012-07-30 18:20:12 +000068
reed@google.com97af1a62012-08-28 12:19:02 +000069 SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
70
tfarina7831a4b2015-04-27 07:53:07 -070071 SkShader* onNewShader(SkShader::TileMode,
72 SkShader::TileMode,
73 const SkMatrix* localMatrix) const override;
piotaixrcef04f82014-07-14 07:48:04 -070074
mtklein36352bf2015-03-25 18:17:31 -070075 bool isOpaque() const override;
piotaixrd2a35222014-08-19 14:29:02 -070076
reed4af267b2014-11-21 08:46:37 -080077 SkImage_Raster(const SkBitmap& bm, const SkSurfaceProps* props)
78 : INHERITED(bm.width(), bm.height(), props)
halcanaryea4673f2014-08-18 08:27:09 -070079 , fBitmap(bm) {}
80
reed@google.com58b21ec2012-07-30 18:20:12 +000081private:
reed4af267b2014-11-21 08:46:37 -080082 SkImage_Raster() : INHERITED(0, 0, NULL) {}
reed@google.com58b21ec2012-07-30 18:20:12 +000083
84 SkBitmap fBitmap;
85
86 typedef SkImage_Base INHERITED;
87};
88
89///////////////////////////////////////////////////////////////////////////////
90
reed@google.com4f7c6152014-02-06 14:11:56 +000091static void release_data(void* addr, void* context) {
92 SkData* data = static_cast<SkData*>(context);
93 data->unref();
94}
95
reed4af267b2014-11-21 08:46:37 -080096SkImage_Raster::SkImage_Raster(const Info& info, SkData* data, size_t rowBytes,
97 const SkSurfaceProps* props)
98 : INHERITED(info.width(), info.height(), props)
reed@google.com4f7c6152014-02-06 14:11:56 +000099{
100 data->ref();
101 void* addr = const_cast<void*>(data->data());
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +0000102 SkColorTable* ctable = NULL;
reed@google.com4f7c6152014-02-06 14:11:56 +0000103
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +0000104 fBitmap.installPixels(info, addr, rowBytes, ctable, release_data, data);
reed@google.com58b21ec2012-07-30 18:20:12 +0000105 fBitmap.setImmutable();
reed@google.com4f7c6152014-02-06 14:11:56 +0000106 fBitmap.lockPixels();
reed@google.com58b21ec2012-07-30 18:20:12 +0000107}
108
kkinnunen73953e72015-02-23 22:12:12 -0800109SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, const SkIPoint& pixelRefOrigin,
110 size_t rowBytes, const SkSurfaceProps* props)
reed4af267b2014-11-21 08:46:37 -0800111 : INHERITED(info.width(), info.height(), props)
commit-bot@chromium.orgf1901782014-01-08 22:24:55 +0000112{
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000113 fBitmap.setInfo(info, rowBytes);
kkinnunen73953e72015-02-23 22:12:12 -0800114 fBitmap.setPixelRef(pr, pixelRefOrigin);
reed@google.com4f7c6152014-02-06 14:11:56 +0000115 fBitmap.lockPixels();
reed@google.com58b21ec2012-07-30 18:20:12 +0000116}
117
118SkImage_Raster::~SkImage_Raster() {}
119
reed8572fc02014-08-11 13:03:55 -0700120SkShader* SkImage_Raster::onNewShader(SkShader::TileMode tileX, SkShader::TileMode tileY,
121 const SkMatrix* localMatrix) const {
piotaixr76d5b472014-07-22 15:02:05 -0700122 return SkShader::CreateBitmapShader(fBitmap, tileX, tileY, localMatrix);
piotaixrcef04f82014-07-14 07:48:04 -0700123}
124
reed4af267b2014-11-21 08:46:37 -0800125SkSurface* SkImage_Raster::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) const {
126 return SkSurface::NewRaster(info, &props);
127}
128
reed96472de2014-12-10 09:53:42 -0800129bool SkImage_Raster::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
130 int srcX, int srcY) const {
reedb4f629c2014-12-25 13:55:08 -0800131 SkBitmap shallowCopy(fBitmap);
132 return shallowCopy.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
reed@google.com4f7c6152014-02-06 14:11:56 +0000133}
134
reed8572fc02014-08-11 13:03:55 -0700135const void* SkImage_Raster::onPeekPixels(SkImageInfo* infoPtr, size_t* rowBytesPtr) const {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000136 const SkImageInfo info = fBitmap.info();
137 if ((kUnknown_SkColorType == info.colorType()) || !fBitmap.getPixels()) {
reed@google.com2776e012014-02-06 14:30:44 +0000138 return NULL;
reed@google.com4f7c6152014-02-06 14:11:56 +0000139 }
140 *infoPtr = info;
141 *rowBytesPtr = fBitmap.rowBytes();
142 return fBitmap.getPixels();
143}
144
reed871872f2015-06-22 12:48:26 -0700145SkData* SkImage_Raster::onRefEncoded() const {
146 SkPixelRef* pr = fBitmap.pixelRef();
147 const SkImageInfo prInfo = pr->info();
148 const SkImageInfo bmInfo = fBitmap.info();
149
150 // we only try if we (the image) cover the entire area of the pixelRef
151 if (prInfo.width() == bmInfo.width() && prInfo.height() == bmInfo.height()) {
152 return pr->refEncodedData();
153 }
154 return NULL;
155}
156
reed@google.com4b0757b2013-05-20 16:33:41 +0000157bool SkImage_Raster::getROPixels(SkBitmap* dst) const {
158 *dst = fBitmap;
159 return true;
160}
161
reed@google.com58b21ec2012-07-30 18:20:12 +0000162///////////////////////////////////////////////////////////////////////////////
163
reed@google.com2bd8b812013-11-01 13:46:54 +0000164SkImage* SkImage::NewRasterCopy(const SkImageInfo& info, const void* pixels, size_t rowBytes) {
reedde499882015-06-18 13:41:40 -0700165 size_t size;
166 if (!SkImage_Raster::ValidArgs(info, rowBytes, &size) || !pixels) {
reed@google.com58b21ec2012-07-30 18:20:12 +0000167 return NULL;
168 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000169
reed@google.com58b21ec2012-07-30 18:20:12 +0000170 // Here we actually make a copy of the caller's pixel data
reedde499882015-06-18 13:41:40 -0700171 SkAutoDataUnref data(SkData::NewWithCopy(pixels, size));
reed4af267b2014-11-21 08:46:37 -0800172 return SkNEW_ARGS(SkImage_Raster, (info, data, rowBytes, NULL));
reed@google.com58b21ec2012-07-30 18:20:12 +0000173}
174
175
reed@google.com999da9c2014-02-06 13:43:07 +0000176SkImage* SkImage::NewRasterData(const SkImageInfo& info, SkData* data, size_t rowBytes) {
reedde499882015-06-18 13:41:40 -0700177 size_t size;
178 if (!SkImage_Raster::ValidArgs(info, rowBytes, &size) || !data) {
reed@google.com58b21ec2012-07-30 18:20:12 +0000179 return NULL;
180 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000181
reed@google.com58b21ec2012-07-30 18:20:12 +0000182 // did they give us enough data?
reed@google.com999da9c2014-02-06 13:43:07 +0000183 if (data->size() < size) {
reed@google.com58b21ec2012-07-30 18:20:12 +0000184 return NULL;
185 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000186
reed4af267b2014-11-21 08:46:37 -0800187 return SkNEW_ARGS(SkImage_Raster, (info, data, rowBytes, NULL));
reed@google.com58b21ec2012-07-30 18:20:12 +0000188}
189
reedde499882015-06-18 13:41:40 -0700190SkImage* SkImage::NewFromRaster(const SkImageInfo& info, const void* pixels, size_t rowBytes,
191 RasterReleaseProc proc, ReleaseContext ctx) {
192 size_t size;
193 if (!SkImage_Raster::ValidArgs(info, rowBytes, &size) || !pixels) {
194 return NULL;
195 }
196
197 SkAutoDataUnref data(SkData::NewWithProc(pixels, size, proc, ctx));
198 return SkNEW_ARGS(SkImage_Raster, (info, data, rowBytes, NULL));
199}
200
reed871872f2015-06-22 12:48:26 -0700201SkImage* SkImage::NewFromGenerator(SkImageGenerator* generator, const SkIRect* subset) {
halcanaryea4673f2014-08-18 08:27:09 -0700202 SkBitmap bitmap;
reed871872f2015-06-22 12:48:26 -0700203 if (!SkInstallDiscardablePixelRef(generator, subset, &bitmap, NULL)) {
halcanaryea4673f2014-08-18 08:27:09 -0700204 return NULL;
205 }
reed7983bf92015-01-23 04:24:16 -0800206 if (0 == bitmap.width() || 0 == bitmap.height()) {
207 return NULL;
208 }
209
reed4af267b2014-11-21 08:46:37 -0800210 return SkNEW_ARGS(SkImage_Raster, (bitmap, NULL));
halcanaryea4673f2014-08-18 08:27:09 -0700211}
212
kkinnunen73953e72015-02-23 22:12:12 -0800213SkImage* SkNewImageFromPixelRef(const SkImageInfo& info, SkPixelRef* pr,
214 const SkIPoint& pixelRefOrigin, size_t rowBytes,
reed4af267b2014-11-21 08:46:37 -0800215 const SkSurfaceProps* props) {
reedde499882015-06-18 13:41:40 -0700216 if (!SkImage_Raster::ValidArgs(info, rowBytes, NULL)) {
reed7983bf92015-01-23 04:24:16 -0800217 return NULL;
218 }
kkinnunen73953e72015-02-23 22:12:12 -0800219 return SkNEW_ARGS(SkImage_Raster, (info, pr, pixelRefOrigin, rowBytes, props));
220}
221
222SkImage* SkNewImageFromBitmap(const SkBitmap& bm, bool canSharePixelRef,
223 const SkSurfaceProps* props) {
reedde499882015-06-18 13:41:40 -0700224 if (!SkImage_Raster::ValidArgs(bm.info(), bm.rowBytes(), NULL)) {
kkinnunen73953e72015-02-23 22:12:12 -0800225 return NULL;
226 }
227
228 SkImage* image = NULL;
229 if (canSharePixelRef || bm.isImmutable()) {
230 image = SkNEW_ARGS(SkImage_Raster, (bm, props));
231 } else {
232 bm.lockPixels();
233 if (bm.getPixels()) {
234 image = SkImage::NewRasterCopy(bm.info(), bm.getPixels(), bm.rowBytes());
235 }
236 bm.unlockPixels();
237
238 // we don't expose props to NewRasterCopy (need a private vers) so post-init it here
239 if (image && props) {
240 as_IB(image)->initWithProps(*props);
241 }
242 }
243 return image;
reed@google.com58b21ec2012-07-30 18:20:12 +0000244}
245
piotaixr65151752014-10-16 11:58:39 -0700246const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
247 return ((const SkImage_Raster*)image)->getPixelRef();
reed@google.com97af1a62012-08-28 12:19:02 +0000248}
piotaixrd2a35222014-08-19 14:29:02 -0700249
250bool SkImage_Raster::isOpaque() const {
251 return fBitmap.isOpaque();
252}
reed96a857e2015-01-25 10:33:58 -0800253