1 /*
2 * Copyright 2014 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.h"
9 #include "SkImageGenerator.h"
10 #include "SkNextID.h"
11
SkImageGenerator(const SkImageInfo & info,uint32_t uniqueID)12 SkImageGenerator::SkImageGenerator(const SkImageInfo& info, uint32_t uniqueID)
13 : fInfo(info)
14 , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID)
15 {}
16
getPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,SkPMColor ctable[],int * ctableCount)17 bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
18 SkPMColor ctable[], int* ctableCount) {
19 if (kUnknown_SkColorType == info.colorType()) {
20 return false;
21 }
22 if (nullptr == pixels) {
23 return false;
24 }
25 if (rowBytes < info.minRowBytes()) {
26 return false;
27 }
28
29 if (kIndex_8_SkColorType == info.colorType()) {
30 if (nullptr == ctable || nullptr == ctableCount) {
31 return false;
32 }
33 } else {
34 if (ctableCount) {
35 *ctableCount = 0;
36 }
37 ctableCount = nullptr;
38 ctable = nullptr;
39 }
40
41 const bool success = this->onGetPixels(info, pixels, rowBytes, ctable, ctableCount);
42 if (success && ctableCount) {
43 SkASSERT(*ctableCount >= 0 && *ctableCount <= 256);
44 }
45 return success;
46 }
47
getPixels(const SkImageInfo & info,void * pixels,size_t rowBytes)48 bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
49 SkASSERT(kIndex_8_SkColorType != info.colorType());
50 if (kIndex_8_SkColorType == info.colorType()) {
51 return false;
52 }
53 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr);
54 }
55
queryYUV8(SkYUVSizeInfo * sizeInfo,SkYUVColorSpace * colorSpace) const56 bool SkImageGenerator::queryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const {
57 SkASSERT(sizeInfo);
58
59 return this->onQueryYUV8(sizeInfo, colorSpace);
60 }
61
getYUV8Planes(const SkYUVSizeInfo & sizeInfo,void * planes[3])62 bool SkImageGenerator::getYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
63 SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth >= 0);
64 SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight >= 0);
65 SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU].fWidth >= 0);
66 SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU].fHeight >= 0);
67 SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kV].fWidth >= 0);
68 SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kV].fHeight >= 0);
69 SkASSERT(sizeInfo.fWidthBytes[SkYUVSizeInfo::kY] >=
70 (size_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth);
71 SkASSERT(sizeInfo.fWidthBytes[SkYUVSizeInfo::kU] >=
72 (size_t) sizeInfo.fSizes[SkYUVSizeInfo::kU].fWidth);
73 SkASSERT(sizeInfo.fWidthBytes[SkYUVSizeInfo::kV] >=
74 (size_t) sizeInfo.fSizes[SkYUVSizeInfo::kV].fWidth);
75 SkASSERT(planes && planes[0] && planes[1] && planes[2]);
76
77 return this->onGetYUV8Planes(sizeInfo, planes);
78 }
79
80 #if SK_SUPPORT_GPU
81 #include "GrTextureProxy.h"
82
generateTexture(GrContext * ctx,const SkImageInfo & info,const SkIPoint & origin)83 sk_sp<GrTextureProxy> SkImageGenerator::generateTexture(GrContext* ctx, const SkImageInfo& info,
84 const SkIPoint& origin) {
85 SkIRect srcRect = SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height());
86 if (!SkIRect::MakeWH(fInfo.width(), fInfo.height()).contains(srcRect)) {
87 return nullptr;
88 }
89 return this->onGenerateTexture(ctx, info, origin);
90 }
91
onGenerateTexture(GrContext *,const SkImageInfo &,const SkIPoint &)92 sk_sp<GrTextureProxy> SkImageGenerator::onGenerateTexture(GrContext*, const SkImageInfo&,
93 const SkIPoint&) {
94 return nullptr;
95 }
96 #endif
97
98 /////////////////////////////////////////////////////////////////////////////////////////////
99
onRefEncodedData(GrContext * ctx)100 SkData* SkImageGenerator::onRefEncodedData(GrContext* ctx) {
101 return nullptr;
102 }
103
onGetPixels(const SkImageInfo & info,void * dst,size_t rb,SkPMColor * colors,int * colorCount)104 bool SkImageGenerator::onGetPixels(const SkImageInfo& info, void* dst, size_t rb,
105 SkPMColor* colors, int* colorCount) {
106 return false;
107 }
108
109 ///////////////////////////////////////////////////////////////////////////////////////////////////
110
111 #include "SkBitmap.h"
112 #include "SkColorTable.h"
113
reset_and_return_false(SkBitmap * bitmap)114 static bool reset_and_return_false(SkBitmap* bitmap) {
115 bitmap->reset();
116 return false;
117 }
118
tryGenerateBitmap(SkBitmap * bitmap,const SkImageInfo & info,SkBitmap::Allocator * allocator)119 bool SkImageGenerator::tryGenerateBitmap(SkBitmap* bitmap, const SkImageInfo& info,
120 SkBitmap::Allocator* allocator) {
121 if (0 == info.getSafeSize(info.minRowBytes())) {
122 return false;
123 }
124 if (!bitmap->setInfo(info)) {
125 return reset_and_return_false(bitmap);
126 }
127
128 SkPMColor ctStorage[256];
129 memset(ctStorage, 0xFF, sizeof(ctStorage)); // init with opaque-white for the moment
130 sk_sp<SkColorTable> ctable(new SkColorTable(ctStorage, 256));
131 if (!bitmap->tryAllocPixels(allocator, ctable.get())) {
132 // SkResourceCache's custom allcator can'thandle ctables, so it may fail on
133 // kIndex_8_SkColorTable.
134 // https://bug.skia.org/4355
135 #if 1
136 // ignore the allocator, and see if we can succeed without it
137 if (!bitmap->tryAllocPixels(nullptr, ctable.get())) {
138 return reset_and_return_false(bitmap);
139 }
140 #else
141 // this is the up-scale technique, not fully debugged, but we keep it here at the moment
142 // to remind ourselves that this might be better than ignoring the allocator.
143
144 info = SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType());
145 if (!bitmap->setInfo(info)) {
146 return reset_and_return_false(bitmap);
147 }
148 // we pass nullptr for the ctable arg, since we are now explicitly N32
149 if (!bitmap->tryAllocPixels(allocator, nullptr)) {
150 return reset_and_return_false(bitmap);
151 }
152 #endif
153 }
154
155 bitmap->lockPixels();
156 if (!bitmap->getPixels()) {
157 return reset_and_return_false(bitmap);
158 }
159
160 int ctCount = 0;
161 if (!this->getPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(),
162 ctStorage, &ctCount)) {
163 return reset_and_return_false(bitmap);
164 }
165
166 if (ctCount > 0) {
167 SkASSERT(kIndex_8_SkColorType == bitmap->colorType());
168 // we and bitmap should be owners
169 SkASSERT(!ctable->unique());
170
171 // Now we need to overwrite the ctable we built earlier, with the correct colors.
172 // This does mean that we may have made the table too big, but that cannot be avoided
173 // until we can change SkImageGenerator's API to return us the ctable *before* we have to
174 // allocate space for all the pixels.
175 ctable->dangerous_overwriteColors(ctStorage, ctCount);
176 } else {
177 SkASSERT(kIndex_8_SkColorType != bitmap->colorType());
178 // we should be the only owner
179 SkASSERT(ctable->unique());
180 }
181 return true;
182 }
183
184 #include "SkGraphics.h"
185
186 static SkGraphics::ImageGeneratorFromEncodedDataFactory gFactory;
187
188 SkGraphics::ImageGeneratorFromEncodedDataFactory
SetImageGeneratorFromEncodedDataFactory(ImageGeneratorFromEncodedDataFactory factory)189 SkGraphics::SetImageGeneratorFromEncodedDataFactory(ImageGeneratorFromEncodedDataFactory factory)
190 {
191 ImageGeneratorFromEncodedDataFactory prev = gFactory;
192 gFactory = factory;
193 return prev;
194 }
195
MakeFromEncoded(sk_sp<SkData> data)196 std::unique_ptr<SkImageGenerator> SkImageGenerator::MakeFromEncoded(sk_sp<SkData> data) {
197 if (!data) {
198 return nullptr;
199 }
200 if (gFactory) {
201 if (std::unique_ptr<SkImageGenerator> generator = gFactory(data)) {
202 return generator;
203 }
204 }
205 return SkImageGenerator::MakeFromEncodedImpl(std::move(data));
206 }
207