• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "SkImageGenerator.h"
9 #include "SkNextID.h"
10 
SkImageGenerator(const SkImageInfo & info)11 SkImageGenerator::SkImageGenerator(const SkImageInfo& info)
12     : fInfo(info)
13     , fUniqueID(SkNextID::ImageID())
14 {}
15 
getPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,SkPMColor ctable[],int * ctableCount)16 bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
17                                  SkPMColor ctable[], int* ctableCount) {
18     if (kUnknown_SkColorType == info.colorType()) {
19         return false;
20     }
21     if (nullptr == pixels) {
22         return false;
23     }
24     if (rowBytes < info.minRowBytes()) {
25         return false;
26     }
27 
28     if (kIndex_8_SkColorType == info.colorType()) {
29         if (nullptr == ctable || nullptr == ctableCount) {
30             return false;
31         }
32     } else {
33         if (ctableCount) {
34             *ctableCount = 0;
35         }
36         ctableCount = nullptr;
37         ctable = nullptr;
38     }
39 
40     const bool success = this->onGetPixels(info, pixels, rowBytes, ctable, ctableCount);
41     if (success && ctableCount) {
42         SkASSERT(*ctableCount >= 0 && *ctableCount <= 256);
43     }
44     return success;
45 }
46 
getPixels(const SkImageInfo & info,void * pixels,size_t rowBytes)47 bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
48     SkASSERT(kIndex_8_SkColorType != info.colorType());
49     if (kIndex_8_SkColorType == info.colorType()) {
50         return false;
51     }
52     return this->getPixels(info, pixels, rowBytes, nullptr, nullptr);
53 }
54 
getYUV8Planes(SkISize sizes[3],void * planes[3],size_t rowBytes[3],SkYUVColorSpace * colorSpace)55 bool SkImageGenerator::getYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3],
56                                      SkYUVColorSpace* colorSpace) {
57 #ifdef SK_DEBUG
58     // In all cases, we need the sizes array
59     SkASSERT(sizes);
60 
61     bool isValidWithPlanes = (planes) && (rowBytes) &&
62         ((planes[0]) && (planes[1]) && (planes[2]) &&
63          (0  != rowBytes[0]) && (0  != rowBytes[1]) && (0  != rowBytes[2]));
64     bool isValidWithoutPlanes =
65         ((nullptr == planes) ||
66          ((nullptr == planes[0]) && (nullptr == planes[1]) && (nullptr == planes[2]))) &&
67         ((nullptr == rowBytes) ||
68          ((0 == rowBytes[0]) && (0 == rowBytes[1]) && (0 == rowBytes[2])));
69 
70     // Either we have all planes and rowBytes information or we have none of it
71     // Having only partial information is not supported
72     SkASSERT(isValidWithPlanes || isValidWithoutPlanes);
73 
74     // If we do have planes information, make sure all sizes are non 0
75     // and all rowBytes are valid
76     SkASSERT(!isValidWithPlanes ||
77              ((sizes[0].fWidth  >= 0) &&
78               (sizes[0].fHeight >= 0) &&
79               (sizes[1].fWidth  >= 0) &&
80               (sizes[1].fHeight >= 0) &&
81               (sizes[2].fWidth  >= 0) &&
82               (sizes[2].fHeight >= 0) &&
83               (rowBytes[0] >= (size_t)sizes[0].fWidth) &&
84               (rowBytes[1] >= (size_t)sizes[1].fWidth) &&
85               (rowBytes[2] >= (size_t)sizes[2].fWidth)));
86 #endif
87 
88     return this->onGetYUV8Planes(sizes, planes, rowBytes, colorSpace);
89 }
90 
onGetYUV8Planes(SkISize sizes[3],void * planes[3],size_t rowBytes[3])91 bool SkImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]) {
92     return false;
93 }
94 
onGetYUV8Planes(SkISize sizes[3],void * planes[3],size_t rowBytes[3],SkYUVColorSpace * colorSpace)95 bool SkImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3],
96                                        SkYUVColorSpace* colorSpace) {
97     // In order to maintain compatibility with clients that implemented the original
98     // onGetYUV8Planes interface, we assume that the color space is JPEG.
99     // TODO(rileya): remove this and the old onGetYUV8Planes once clients switch over to
100     // the new interface.
101     if (colorSpace) {
102         *colorSpace = kJPEG_SkYUVColorSpace;
103     }
104     return this->onGetYUV8Planes(sizes, planes, rowBytes);
105 }
106 
generateTexture(GrContext * ctx,const SkIRect * subset)107 GrTexture* SkImageGenerator::generateTexture(GrContext* ctx, const SkIRect* subset) {
108     if (subset && !SkIRect::MakeWH(fInfo.width(), fInfo.height()).contains(*subset)) {
109         return nullptr;
110     }
111     return this->onGenerateTexture(ctx, subset);
112 }
113 
computeScaledDimensions(SkScalar scale,SupportedSizes * sizes)114 bool SkImageGenerator::computeScaledDimensions(SkScalar scale, SupportedSizes* sizes) {
115     if (scale > 0 && scale <= 1) {
116         return this->onComputeScaledDimensions(scale, sizes);
117     }
118     return false;
119 }
120 
generateScaledPixels(const SkISize & scaledSize,const SkIPoint & subsetOrigin,const SkPixmap & subsetPixels)121 bool SkImageGenerator::generateScaledPixels(const SkISize& scaledSize,
122                                             const SkIPoint& subsetOrigin,
123                                             const SkPixmap& subsetPixels) {
124     if (scaledSize.width() <= 0 || scaledSize.height() <= 0) {
125         return false;
126     }
127     if (subsetPixels.width() <= 0 || subsetPixels.height() <= 0) {
128         return false;
129     }
130     const SkIRect subset = SkIRect::MakeXYWH(subsetOrigin.x(), subsetOrigin.y(),
131                                              subsetPixels.width(), subsetPixels.height());
132     if (!SkIRect::MakeWH(scaledSize.width(), scaledSize.height()).contains(subset)) {
133         return false;
134     }
135     return this->onGenerateScaledPixels(scaledSize, subsetOrigin, subsetPixels);
136 }
137 
138 /////////////////////////////////////////////////////////////////////////////////////////////
139 
onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM)140 SkData* SkImageGenerator::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) {
141     return nullptr;
142 }
143 
onGetPixels(const SkImageInfo & info,void * dst,size_t rb,SkPMColor * colors,int * colorCount)144 bool SkImageGenerator::onGetPixels(const SkImageInfo& info, void* dst, size_t rb,
145                                    SkPMColor* colors, int* colorCount) {
146     return false;
147 }
148 
149 ///////////////////////////////////////////////////////////////////////////////////////////////////
150 
151 #include "SkBitmap.h"
152 #include "SkColorTable.h"
153 
reset_and_return_false(SkBitmap * bitmap)154 static bool reset_and_return_false(SkBitmap* bitmap) {
155     bitmap->reset();
156     return false;
157 }
158 
tryGenerateBitmap(SkBitmap * bitmap,const SkImageInfo * infoPtr,SkBitmap::Allocator * allocator)159 bool SkImageGenerator::tryGenerateBitmap(SkBitmap* bitmap, const SkImageInfo* infoPtr,
160                                          SkBitmap::Allocator* allocator) {
161     SkImageInfo info = infoPtr ? *infoPtr : this->getInfo();
162     if (0 == info.getSafeSize(info.minRowBytes())) {
163         return false;
164     }
165     if (!bitmap->setInfo(info)) {
166         return reset_and_return_false(bitmap);
167     }
168 
169     SkPMColor ctStorage[256];
170     memset(ctStorage, 0xFF, sizeof(ctStorage)); // init with opaque-white for the moment
171     SkAutoTUnref<SkColorTable> ctable(new SkColorTable(ctStorage, 256));
172     if (!bitmap->tryAllocPixels(allocator, ctable)) {
173         // SkResourceCache's custom allcator can'thandle ctables, so it may fail on
174         // kIndex_8_SkColorTable.
175         // https://bug.skia.org/4355
176 #if 1
177         // ignroe the allocator, and see if we can succeed without it
178         if (!bitmap->tryAllocPixels(nullptr, ctable)) {
179             return reset_and_return_false(bitmap);
180         }
181 #else
182         // this is the up-scale technique, not fully debugged, but we keep it here at the moment
183         // to remind ourselves that this might be better than ignoring the allocator.
184 
185         info = SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType());
186         if (!bitmap->setInfo(info)) {
187             return reset_and_return_false(bitmap);
188         }
189         // we pass nullptr for the ctable arg, since we are now explicitly N32
190         if (!bitmap->tryAllocPixels(allocator, nullptr)) {
191             return reset_and_return_false(bitmap);
192         }
193 #endif
194     }
195 
196     bitmap->lockPixels();
197     if (!bitmap->getPixels()) {
198         return reset_and_return_false(bitmap);
199     }
200 
201     int ctCount = 0;
202     if (!this->getPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(),
203                          ctStorage, &ctCount)) {
204         return reset_and_return_false(bitmap);
205     }
206 
207     if (ctCount > 0) {
208         SkASSERT(kIndex_8_SkColorType == bitmap->colorType());
209         // we and bitmap should be owners
210         SkASSERT(!ctable->unique());
211 
212         // Now we need to overwrite the ctable we built earlier, with the correct colors.
213         // This does mean that we may have made the table too big, but that cannot be avoided
214         // until we can change SkImageGenerator's API to return us the ctable *before* we have to
215         // allocate space for all the pixels.
216         ctable->dangerous_overwriteColors(ctStorage, ctCount);
217     } else {
218         SkASSERT(kIndex_8_SkColorType != bitmap->colorType());
219         // we should be the only owner
220         SkASSERT(ctable->unique());
221     }
222     return true;
223 }
224 
225 #include "SkGraphics.h"
226 
227 static SkGraphics::ImageGeneratorFromEncodedFactory gFactory;
228 
229 SkGraphics::ImageGeneratorFromEncodedFactory
SetImageGeneratorFromEncodedFactory(ImageGeneratorFromEncodedFactory factory)230 SkGraphics::SetImageGeneratorFromEncodedFactory(ImageGeneratorFromEncodedFactory factory)
231 {
232     ImageGeneratorFromEncodedFactory prev = gFactory;
233     gFactory = factory;
234     return prev;
235 }
236 
NewFromEncoded(SkData * data)237 SkImageGenerator* SkImageGenerator::NewFromEncoded(SkData* data) {
238     if (nullptr == data) {
239         return nullptr;
240     }
241     if (gFactory) {
242         if (SkImageGenerator* generator = gFactory(data)) {
243             return generator;
244         }
245     }
246     return SkImageGenerator::NewFromEncodedImpl(data);
247 }
248