blob: 4d96b9ffff4b53df8ef68eb6c0de7ccaa98881e7 [file] [log] [blame]
reed@google.comf6627b72012-07-27 18:02:50 +00001#include "SkImage.h"
reed@google.com889b09e2012-07-27 21:10:42 +00002#include "SkImagePriv.h"
reed@google.comf6627b72012-07-27 18:02:50 +00003#include "SkBitmap.h"
4
5///////////////////////////////////////////////////////////////////////////////
6
7class SkImage_Base : public SkImage {
8public:
9 SkImage_Base(int width, int height) : INHERITED(width, height) {}
10
11 virtual const SkBitmap* asABitmap() { return NULL; }
12
13private:
14 typedef SkImage INHERITED;
15};
16
17static SkImage_Base* asIB(SkImage* image) {
18 return static_cast<SkImage_Base*>(image);
19}
20
21///////////////////////////////////////////////////////////////////////////////
22
reed@google.comf6627b72012-07-27 18:02:50 +000023
24class SkImage_Raster : public SkImage_Base {
25public:
26 static bool ValidArgs(const Info& info, SkColorSpace* cs, size_t rowBytes) {
27 const int maxDimension = SK_MaxS32 >> 2;
28 const size_t kMaxPixelByteSize = SK_MaxS32;
29
30 if (info.fWidth < 0 || info.fHeight < 0) {
31 return false;
32 }
33 if (info.fWidth > maxDimension || info.fHeight > maxDimension) {
34 return false;
35 }
36 if ((unsigned)info.fColorType > (unsigned)kLastEnum_ColorType) {
37 return false;
38 }
39 if ((unsigned)info.fAlphaType > (unsigned)kLastEnum_AlphaType) {
40 return false;
41 }
42
43 bool isOpaque;
reed@google.com889b09e2012-07-27 21:10:42 +000044 if (SkImageInfoToBitmapConfig(info, &isOpaque) == SkBitmap::kNo_Config) {
reed@google.comf6627b72012-07-27 18:02:50 +000045 return false;
46 }
47
48 // TODO: check colorspace
49
reed@google.com889b09e2012-07-27 21:10:42 +000050 if (rowBytes < SkImageMinRowBytes(info)) {
reed@google.comf6627b72012-07-27 18:02:50 +000051 return false;
52 }
53
54 int64_t size = (int64_t)info.fHeight * rowBytes;
55 if (size > kMaxPixelByteSize) {
56 return false;
57 }
58 return true;
59 }
60
61 static SkImage* NewEmpty();
62
63 SkImage_Raster(const SkImage::Info&, SkColorSpace*, SkData*, size_t rb);
64 virtual ~SkImage_Raster();
65
66 virtual const SkBitmap* asABitmap() SK_OVERRIDE;
67
reed@google.com889b09e2012-07-27 21:10:42 +000068 // exposed for SkSurface_Raster via SkNewImageFromPixelRef
69 SkImage_Raster(const SkImage::Info&, SkPixelRef*, size_t rowBytes);
70
reed@google.comf6627b72012-07-27 18:02:50 +000071private:
72 SkImage_Raster() : INHERITED(0, 0) {}
73
74 SkBitmap fBitmap;
75
76 typedef SkImage_Base INHERITED;
77};
78
reed@google.com889b09e2012-07-27 21:10:42 +000079SkImage* SkNewImageFromPixelRef(const SkImage::Info& info, SkPixelRef* pr,
80 size_t rowBytes) {
81 return SkNEW_ARGS(SkImage_Raster, (info, pr, rowBytes));
82}
83
reed@google.comf6627b72012-07-27 18:02:50 +000084///////////////////////////////////////////////////////////////////////////////
85
86#include "SkData.h"
87#include "SkDataPixelRef.h"
88
89SkImage* SkImage_Raster::NewEmpty() {
90 // Returns lazily created singleton
91 static SkImage* gEmpty;
92 if (NULL == gEmpty) {
93 gEmpty = SkNEW(SkImage_Raster);
94 }
95 gEmpty->ref();
96 return gEmpty;
97}
98
99SkImage_Raster::SkImage_Raster(const Info& info, SkColorSpace* cs,
100 SkData* data, size_t rowBytes)
reed@google.com889b09e2012-07-27 21:10:42 +0000101: INHERITED(info.fWidth, info.fHeight) {
reed@google.comf6627b72012-07-27 18:02:50 +0000102 bool isOpaque;
reed@google.com889b09e2012-07-27 21:10:42 +0000103 SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
104
reed@google.comf6627b72012-07-27 18:02:50 +0000105 fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes);
106 fBitmap.setPixelRef(SkNEW_ARGS(SkDataPixelRef, (data)))->unref();
107 fBitmap.setIsOpaque(isOpaque);
reed@google.com889b09e2012-07-27 21:10:42 +0000108 fBitmap.setImmutable();
109}
110
111SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, size_t rowBytes)
112 : INHERITED(info.fWidth, info.fHeight) {
113 SkASSERT(pr->isImmutable());
114
115 bool isOpaque;
116 SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
117
118 fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes);
119 fBitmap.setPixelRef(pr);
120 fBitmap.setIsOpaque(isOpaque);
121 fBitmap.setImmutable();
reed@google.comf6627b72012-07-27 18:02:50 +0000122}
123
124SkImage_Raster::~SkImage_Raster() {}
125
126const SkBitmap* SkImage_Raster::asABitmap() {
127 return &fBitmap;
128}
129
130///////////////////////////////////////////////////////////////////////////////
131
132SkImage* SkImage::NewRasterCopy(const SkImage::Info& info, SkColorSpace* cs,
133 const void* pixels, size_t rowBytes) {
134 if (!SkImage_Raster::ValidArgs(info, cs, rowBytes)) {
135 return NULL;
136 }
137 if (0 == info.fWidth && 0 == info.fHeight) {
138 return SkImage_Raster::NewEmpty();
139 }
140 // check this after empty-check
141 if (NULL == pixels) {
142 return NULL;
143 }
144
145 // Here we actually make a copy of the caller's pixel data
146 SkAutoDataUnref data(SkData::NewWithCopy(pixels, info.fHeight * rowBytes));
147 return SkNEW_ARGS(SkImage_Raster, (info, cs, data, rowBytes));
148}
149
150
151SkImage* SkImage::NewRasterData(const SkImage::Info& info, SkColorSpace* cs,
152 SkData* pixelData, size_t rowBytes) {
153 if (!SkImage_Raster::ValidArgs(info, cs, rowBytes)) {
154 return NULL;
155 }
156 if (0 == info.fWidth && 0 == info.fHeight) {
157 return SkImage_Raster::NewEmpty();
158 }
159 // check this after empty-check
160 if (NULL == pixelData) {
161 return NULL;
162 }
163
164 // did they give us enough data?
165 size_t size = info.fHeight * rowBytes;
166 if (pixelData->size() < size) {
167 return NULL;
168 }
169
170 SkAutoDataUnref data(pixelData);
171 return SkNEW_ARGS(SkImage_Raster, (info, cs, data, rowBytes));
172}
173
174///////////////////////////////////////////////////////////////////////////////
175
176#include "SkCanvas.h"
177
178uint32_t SkImage::NextUniqueID() {
179 static int32_t gUniqueID;
180
181 // never return 0;
182 uint32_t id;
183 do {
184 id = sk_atomic_inc(&gUniqueID) + 1;
185 } while (0 == id);
186 return id;
187}
188
189void SkImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
190 const SkPaint* paint) {
191 const SkBitmap* bitmap = asIB(this)->asABitmap();
192 if (bitmap) {
193 canvas->drawBitmap(*bitmap, x, y, paint);
194 }
195}
196