blob: 2e6915ec8a6c4535ff65cf79eadb79ef1ad37c7e [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"
9#include "SkImagePriv.h"
10#include "SkBitmap.h"
11#include "SkCanvas.h"
12#include "SkData.h"
13#include "SkDataPixelRef.h"
14
15class SkImage_Raster : public SkImage_Base {
16public:
17 static bool ValidArgs(const Info& info, SkColorSpace* cs, size_t rowBytes) {
18 const int maxDimension = SK_MaxS32 >> 2;
19 const size_t kMaxPixelByteSize = SK_MaxS32;
20
21 if (info.fWidth < 0 || info.fHeight < 0) {
22 return false;
23 }
24 if (info.fWidth > maxDimension || info.fHeight > maxDimension) {
25 return false;
26 }
27 if ((unsigned)info.fColorType > (unsigned)kLastEnum_ColorType) {
28 return false;
29 }
30 if ((unsigned)info.fAlphaType > (unsigned)kLastEnum_AlphaType) {
31 return false;
32 }
33
34 bool isOpaque;
35 if (SkImageInfoToBitmapConfig(info, &isOpaque) == SkBitmap::kNo_Config) {
36 return false;
37 }
38
39 // TODO: check colorspace
40
41 if (rowBytes < SkImageMinRowBytes(info)) {
42 return false;
43 }
44
45 int64_t size = (int64_t)info.fHeight * rowBytes;
46 if (size > kMaxPixelByteSize) {
47 return false;
48 }
49 return true;
50 }
51
52 static SkImage* NewEmpty();
53
54 SkImage_Raster(const SkImage::Info&, SkColorSpace*, SkData*, size_t rb);
55 virtual ~SkImage_Raster();
56
57 virtual void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) SK_OVERRIDE;
58
59 // exposed for SkSurface_Raster via SkNewImageFromPixelRef
60 SkImage_Raster(const SkImage::Info&, SkPixelRef*, size_t rowBytes);
61
62private:
63 SkImage_Raster() : INHERITED(0, 0) {}
64
65 SkBitmap fBitmap;
66
67 typedef SkImage_Base INHERITED;
68};
69
70///////////////////////////////////////////////////////////////////////////////
71
72SkImage* SkImage_Raster::NewEmpty() {
73 // Returns lazily created singleton
74 static SkImage* gEmpty;
75 if (NULL == gEmpty) {
76 gEmpty = SkNEW(SkImage_Raster);
77 }
78 gEmpty->ref();
79 return gEmpty;
80}
81
82SkImage_Raster::SkImage_Raster(const Info& info, SkColorSpace* cs,
83 SkData* data, size_t rowBytes)
84: INHERITED(info.fWidth, info.fHeight) {
85 bool isOpaque;
86 SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
87
88 fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes);
89 fBitmap.setPixelRef(SkNEW_ARGS(SkDataPixelRef, (data)))->unref();
90 fBitmap.setIsOpaque(isOpaque);
91 fBitmap.setImmutable();
92}
93
94SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, size_t rowBytes)
95: INHERITED(info.fWidth, info.fHeight) {
96 SkASSERT(pr->isImmutable());
97
98 bool isOpaque;
99 SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
100
101 fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes);
102 fBitmap.setPixelRef(pr);
103 fBitmap.setIsOpaque(isOpaque);
104 fBitmap.setImmutable();
105}
106
107SkImage_Raster::~SkImage_Raster() {}
108
109void SkImage_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
110 canvas->drawBitmap(fBitmap, x, y, paint);
111}
112
113///////////////////////////////////////////////////////////////////////////////
114
115SkImage* SkImage::NewRasterCopy(const SkImage::Info& info, SkColorSpace* cs,
116 const void* pixels, size_t rowBytes) {
117 if (!SkImage_Raster::ValidArgs(info, cs, rowBytes)) {
118 return NULL;
119 }
120 if (0 == info.fWidth && 0 == info.fHeight) {
121 return SkImage_Raster::NewEmpty();
122 }
123 // check this after empty-check
124 if (NULL == pixels) {
125 return NULL;
126 }
127
128 // Here we actually make a copy of the caller's pixel data
129 SkAutoDataUnref data(SkData::NewWithCopy(pixels, info.fHeight * rowBytes));
130 return SkNEW_ARGS(SkImage_Raster, (info, cs, data, rowBytes));
131}
132
133
134SkImage* SkImage::NewRasterData(const SkImage::Info& info, SkColorSpace* cs,
135 SkData* pixelData, size_t rowBytes) {
136 if (!SkImage_Raster::ValidArgs(info, cs, rowBytes)) {
137 return NULL;
138 }
139 if (0 == info.fWidth && 0 == info.fHeight) {
140 return SkImage_Raster::NewEmpty();
141 }
142 // check this after empty-check
143 if (NULL == pixelData) {
144 return NULL;
145 }
146
147 // did they give us enough data?
148 size_t size = info.fHeight * rowBytes;
149 if (pixelData->size() < size) {
150 return NULL;
151 }
152
153 SkAutoDataUnref data(pixelData);
154 return SkNEW_ARGS(SkImage_Raster, (info, cs, data, rowBytes));
155}
156
157SkImage* SkNewImageFromPixelRef(const SkImage::Info& info, SkPixelRef* pr,
158 size_t rowBytes) {
159 return SkNEW_ARGS(SkImage_Raster, (info, pr, rowBytes));
160}
161