Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/codec/SkCodec_libico.cpp

Issue 1472933002: Make SkAndroidCodec support ico (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Response to comments Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/codec/SkCodec_libico.h ('k') | src/codec/SkSwizzler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkBmpCodec.h" 8 #include "SkBmpCodec.h"
9 #include "SkCodec_libico.h" 9 #include "SkCodec_libico.h"
10 #include "SkCodec_libpng.h" 10 #include "SkCodec_libpng.h"
11 #include "SkCodecPriv.h" 11 #include "SkCodecPriv.h"
12 #include "SkColorPriv.h" 12 #include "SkColorPriv.h"
13 #include "SkData.h" 13 #include "SkData.h"
14 #include "SkStream.h" 14 #include "SkStream.h"
15 #include "SkTDArray.h" 15 #include "SkTDArray.h"
16 #include "SkTSort.h" 16 #include "SkTSort.h"
17 17
18 static bool ico_conversion_possible(const SkImageInfo& dstInfo) {
19 // We only support kN32_SkColorType.
20 // This makes sense for BMP-in-ICO. The presence of an AND
21 // mask (which changes colors and adds transparency) means that
22 // we cannot use k565 or kIndex8.
23 // FIXME: For PNG-in-ICO, we could technically support whichever
24 // color types that the png supports.
25 if (kN32_SkColorType != dstInfo.colorType()) {
26 return false;
27 }
28
29 // We only support transparent alpha types. This is necessary for
30 // BMP-in-ICOs since there will be an AND mask.
31 // FIXME: For opaque PNG-in-ICOs, we should be able to support kOpaque.
32 return kPremul_SkAlphaType == dstInfo.alphaType() ||
33 kUnpremul_SkAlphaType == dstInfo.alphaType();
34 }
35
36 static SkImageInfo fix_embedded_alpha(const SkImageInfo& dstInfo, SkAlphaType em beddedAlpha) {
37 // FIXME (msarett): ICO is considered non-opaque, even if the embedded BMP
38 // incorrectly claims it has no alpha.
39 switch (embeddedAlpha) {
40 case kPremul_SkAlphaType:
41 case kUnpremul_SkAlphaType:
42 // Use the requested alpha type if the embedded codec supports alpha .
43 embeddedAlpha = dstInfo.alphaType();
44 break;
45 case kOpaque_SkAlphaType:
46 // If the embedded codec claims it is opaque, decode as if it is opa que.
47 break;
48 default:
49 SkASSERT(false);
50 break;
51 }
52 return dstInfo.makeAlphaType(embeddedAlpha);
53 }
54
18 /* 55 /*
19 * Checks the start of the stream to see if the image is an Ico or Cur 56 * Checks the start of the stream to see if the image is an Ico or Cur
20 */ 57 */
21 bool SkIcoCodec::IsIco(SkStream* stream) { 58 bool SkIcoCodec::IsIco(SkStream* stream) {
22 const char icoSig[] = { '\x00', '\x00', '\x01', '\x00' }; 59 const char icoSig[] = { '\x00', '\x00', '\x01', '\x00' };
23 const char curSig[] = { '\x00', '\x00', '\x02', '\x00' }; 60 const char curSig[] = { '\x00', '\x00', '\x02', '\x00' };
24 char buffer[sizeof(icoSig)]; 61 char buffer[sizeof(icoSig)];
25 return stream->read(buffer, sizeof(icoSig)) == sizeof(icoSig) && 62 return stream->read(buffer, sizeof(icoSig)) == sizeof(icoSig) &&
26 (!memcmp(buffer, icoSig, sizeof(icoSig)) || 63 (!memcmp(buffer, icoSig, sizeof(icoSig)) ||
27 !memcmp(buffer, curSig, sizeof(curSig))); 64 !memcmp(buffer, curSig, sizeof(curSig)));
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 } 227 }
191 228
192 /* 229 /*
193 * Creates an instance of the decoder 230 * Creates an instance of the decoder
194 * Called only by NewFromStream 231 * Called only by NewFromStream
195 */ 232 */
196 SkIcoCodec::SkIcoCodec(const SkImageInfo& info, 233 SkIcoCodec::SkIcoCodec(const SkImageInfo& info,
197 SkTArray<SkAutoTDelete<SkCodec>, true>* codecs) 234 SkTArray<SkAutoTDelete<SkCodec>, true>* codecs)
198 : INHERITED(info, nullptr) 235 : INHERITED(info, nullptr)
199 , fEmbeddedCodecs(codecs) 236 , fEmbeddedCodecs(codecs)
237 , fCurrScanlineCodec(nullptr)
200 {} 238 {}
201 239
202 /* 240 /*
203 * Chooses the best dimensions given the desired scale 241 * Chooses the best dimensions given the desired scale
204 */ 242 */
205 SkISize SkIcoCodec::onGetScaledDimensions(float desiredScale) const { 243 SkISize SkIcoCodec::onGetScaledDimensions(float desiredScale) const {
206 // We set the dimensions to the largest candidate image by default. 244 // We set the dimensions to the largest candidate image by default.
207 // Regardless of the scale request, this is the largest image that we 245 // Regardless of the scale request, this is the largest image that we
208 // will decode. 246 // will decode.
209 int origWidth = this->getInfo().width(); 247 int origWidth = this->getInfo().width();
210 int origHeight = this->getInfo().height(); 248 int origHeight = this->getInfo().height();
211 float desiredSize = desiredScale * origWidth * origHeight; 249 float desiredSize = desiredScale * origWidth * origHeight;
212 // At least one image will have smaller error than this initial value 250 // At least one image will have smaller error than this initial value
213 float minError = ((float) (origWidth * origHeight)) - desiredSize + 1.0f; 251 float minError = ((float) (origWidth * origHeight)) - desiredSize + 1.0f;
214 int32_t minIndex = -1; 252 int32_t minIndex = -1;
215 for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) { 253 for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) {
216 int width = fEmbeddedCodecs->operator[](i)->getInfo().width(); 254 int width = fEmbeddedCodecs->operator[](i)->getInfo().width();
217 int height = fEmbeddedCodecs->operator[](i)->getInfo().height(); 255 int height = fEmbeddedCodecs->operator[](i)->getInfo().height();
218 float error = SkTAbs(((float) (width * height)) - desiredSize); 256 float error = SkTAbs(((float) (width * height)) - desiredSize);
219 if (error < minError) { 257 if (error < minError) {
220 minError = error; 258 minError = error;
221 minIndex = i; 259 minIndex = i;
222 } 260 }
223 } 261 }
224 SkASSERT(minIndex >= 0); 262 SkASSERT(minIndex >= 0);
225 263
226 return fEmbeddedCodecs->operator[](minIndex)->getInfo().dimensions(); 264 return fEmbeddedCodecs->operator[](minIndex)->getInfo().dimensions();
227 } 265 }
228 266
229 bool SkIcoCodec::onDimensionsSupported(const SkISize& dim) { 267 int SkIcoCodec::chooseCodec(const SkISize& requestedSize, int startIndex) {
268 SkASSERT(startIndex >= 0);
269
230 // FIXME: Cache the index from onGetScaledDimensions? 270 // FIXME: Cache the index from onGetScaledDimensions?
231 for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) { 271 for (int i = startIndex; i < fEmbeddedCodecs->count(); i++) {
232 if (fEmbeddedCodecs->operator[](i)->getInfo().dimensions() == dim) { 272 if (fEmbeddedCodecs->operator[](i)->getInfo().dimensions() == requestedS ize) {
233 return true; 273 return i;
234 } 274 }
235 } 275 }
236 276
237 return false; 277 return -1;
278 }
279
280 bool SkIcoCodec::onDimensionsSupported(const SkISize& dim) {
281 return this->chooseCodec(dim, 0) >= 0;
238 } 282 }
239 283
240 /* 284 /*
241 * Initiates the Ico decode 285 * Initiates the Ico decode
242 */ 286 */
243 SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo, 287 SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo,
244 void* dst, size_t dstRowBytes, 288 void* dst, size_t dstRowBytes,
245 const Options& opts, SkPMColor* colorTab le, 289 const Options& opts, SkPMColor* colorTab le,
246 int* colorCount, int* rowsDecoded) { 290 int* colorCount, int* rowsDecoded) {
247 if (opts.fSubset) { 291 if (opts.fSubset) {
248 // Subsets are not supported. 292 // Subsets are not supported.
249 return kUnimplemented; 293 return kUnimplemented;
250 } 294 }
251 295
252 if (!valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType())) { 296 if (!ico_conversion_possible(dstInfo)) {
253 return kInvalidConversion; 297 return kInvalidConversion;
254 } 298 }
255 299
256 // We return invalid scale if there is no candidate image with matching 300 int index = 0;
257 // dimensions. 301 SkCodec::Result result = kInvalidScale;
258 Result result = kInvalidScale; 302 while (true) {
259 for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) { 303 index = this->chooseCodec(dstInfo.dimensions(), index);
260 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](i); 304 if (index < 0) {
261 // If the dimensions match, try to decode 305 break;
262 if (dstInfo.dimensions() == embeddedCodec->getInfo().dimensions()) { 306 }
263 307
264 // Perform the decode 308 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index);
265 // FIXME (msarett): ICO is considered non-opaque, even if the embedd ed BMP 309 SkImageInfo decodeInfo = fix_embedded_alpha(dstInfo, embeddedCodec->getI nfo().alphaType());
266 // incorrectly claims it has no alpha. 310 SkASSERT(decodeInfo.colorType() == kN32_SkColorType);
267 SkAlphaType embeddedAlpha = embeddedCodec->getInfo().alphaType(); 311 result = embeddedCodec->getPixels(decodeInfo, dst, dstRowBytes, &opts, c olorTable,
268 switch (embeddedAlpha) { 312 colorCount);
269 case kPremul_SkAlphaType:
270 case kUnpremul_SkAlphaType:
271 // Use the requested alpha type if the embedded codec suppor ts alpha.
272 embeddedAlpha = dstInfo.alphaType();
273 break;
274 case kOpaque_SkAlphaType:
275 // If the embedded codec claims it is opaque, decode as if i t is opaque.
276 break;
277 default:
278 SkASSERT(false);
279 break;
280 }
281 SkImageInfo info = dstInfo.makeAlphaType(embeddedAlpha);
282 result = embeddedCodec->getPixels(info, dst, dstRowBytes, &opts, col orTable,
283 colorCount);
284 // The embedded codec will handle filling incomplete images, so we w ill indicate
285 // that all of the rows are initialized.
286 *rowsDecoded = info.height();
287 313
288 // On a fatal error, keep trying to find an image to decode 314 switch (result) {
289 if (kInvalidConversion == result || kInvalidInput == result || 315 case kSuccess:
290 kInvalidScale == result) { 316 case kIncompleteInput:
291 SkCodecPrintf("Warning: Attempt to decode candidate ico failed.\ n"); 317 // The embedded codec will handle filling incomplete images, so we will indicate
292 continue; 318 // that all of the rows are initialized.
293 } 319 *rowsDecoded = decodeInfo.height();
320 return result;
321 default:
322 // Continue trying to find a valid embedded codec on a failed de code.
323 break;
324 }
294 325
295 // On success or partial success, return the result 326 index++;
296 return result;
297 }
298 } 327 }
299 328
300 SkCodecPrintf("Error: No matching candidate image in ico.\n"); 329 SkCodecPrintf("Error: No matching candidate image in ico.\n");
301 return result; 330 return result;
302 } 331 }
332
333 SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
334 const SkCodec::Options& options, SkPMColor colorTable[], int* colorCount ) {
335 if (!ico_conversion_possible(dstInfo)) {
336 return kInvalidConversion;
337 }
338
339 int index = 0;
340 SkCodec::Result result = kInvalidScale;
341 while (true) {
342 index = this->chooseCodec(dstInfo.dimensions(), index);
343 if (index < 0) {
344 break;
345 }
346
347 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index);
348 SkImageInfo decodeInfo = fix_embedded_alpha(dstInfo, embeddedCodec->getI nfo().alphaType());
349 result = embeddedCodec->startScanlineDecode(decodeInfo, &options, colorT able, colorCount);
350 if (kSuccess == result) {
351 fCurrScanlineCodec = embeddedCodec;
352 return result;
353 }
354
355 index++;
356 }
357
358 SkCodecPrintf("Error: No matching candidate image in ico.\n");
359 return result;
360 }
361
362 int SkIcoCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
363 SkASSERT(fCurrScanlineCodec);
364 return fCurrScanlineCodec->getScanlines(dst, count, rowBytes);
365 }
366
367 bool SkIcoCodec::onSkipScanlines(int count) {
368 SkASSERT(fCurrScanlineCodec);
369 return fCurrScanlineCodec->skipScanlines(count);
370 }
371
372 SkCodec::SkScanlineOrder SkIcoCodec::onGetScanlineOrder() const {
373 // FIXME: This function will possibly return the wrong value if it is called
374 // before startScanlineDecode().
375 return fCurrScanlineCodec ? fCurrScanlineCodec->getScanlineOrder() :
376 INHERITED::onGetScanlineOrder();
377 }
378
379 SkSampler* SkIcoCodec::getSampler(bool createIfNecessary) {
380 return fCurrScanlineCodec ? fCurrScanlineCodec->getSampler(createIfNecessary ) : nullptr;
381 }
OLDNEW
« no previous file with comments | « src/codec/SkCodec_libico.h ('k') | src/codec/SkSwizzler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698