OLD | NEW |
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 "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
11 #include "SkData.h" | 11 #include "SkData.h" |
12 #include "SkIcoCodec.h" | 12 #include "SkIcoCodec.h" |
13 #include "SkPngCodec.h" | 13 #include "SkPngCodec.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 | |
55 /* | 18 /* |
56 * Checks the start of the stream to see if the image is an Ico or Cur | 19 * Checks the start of the stream to see if the image is an Ico or Cur |
57 */ | 20 */ |
58 bool SkIcoCodec::IsIco(const void* buffer, size_t bytesRead) { | 21 bool SkIcoCodec::IsIco(const void* buffer, size_t bytesRead) { |
59 const char icoSig[] = { '\x00', '\x00', '\x01', '\x00' }; | 22 const char icoSig[] = { '\x00', '\x00', '\x01', '\x00' }; |
60 const char curSig[] = { '\x00', '\x00', '\x02', '\x00' }; | 23 const char curSig[] = { '\x00', '\x00', '\x02', '\x00' }; |
61 return bytesRead >= sizeof(icoSig) && | 24 return bytesRead >= sizeof(icoSig) && |
62 (!memcmp(buffer, icoSig, sizeof(icoSig)) || | 25 (!memcmp(buffer, icoSig, sizeof(icoSig)) || |
63 !memcmp(buffer, curSig, sizeof(curSig))); | 26 !memcmp(buffer, curSig, sizeof(curSig))); |
64 } | 27 } |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 for (int32_t i = 0; i < codecs->count(); i++) { | 163 for (int32_t i = 0; i < codecs->count(); i++) { |
201 SkImageInfo info = codecs->operator[](i)->getInfo(); | 164 SkImageInfo info = codecs->operator[](i)->getInfo(); |
202 uint32_t size = info.width() * info.height(); | 165 uint32_t size = info.width() * info.height(); |
203 if (size > maxSize) { | 166 if (size > maxSize) { |
204 maxSize = size; | 167 maxSize = size; |
205 maxIndex = i; | 168 maxIndex = i; |
206 } | 169 } |
207 } | 170 } |
208 SkImageInfo info = codecs->operator[](maxIndex)->getInfo(); | 171 SkImageInfo info = codecs->operator[](maxIndex)->getInfo(); |
209 | 172 |
210 // ICOs contain an alpha mask after the image which means we cannot | |
211 // guarantee that an image is opaque, even if the sub-codec thinks it | |
212 // is. | |
213 // FIXME (msarett): The BMP decoder depends on the alpha type in order | |
214 // to decode correctly, otherwise it could report kUnpremul and we would | |
215 // not have to correct it here. Is there a better way? | |
216 // FIXME (msarett): This is only true for BMP in ICO - could a PNG in ICO | |
217 // be opaque? Is it okay that we missed out on the opportunity to mark | |
218 // such an image as opaque? | |
219 info = info.makeAlphaType(kUnpremul_SkAlphaType); | |
220 | |
221 // Note that stream is owned by the embedded codec, the ico does not need | 173 // Note that stream is owned by the embedded codec, the ico does not need |
222 // direct access to the stream. | 174 // direct access to the stream. |
223 return new SkIcoCodec(info, codecs.detach()); | 175 return new SkIcoCodec(info, codecs.detach()); |
224 } | 176 } |
225 | 177 |
226 /* | 178 /* |
227 * Creates an instance of the decoder | 179 * Creates an instance of the decoder |
228 * Called only by NewFromStream | 180 * Called only by NewFromStream |
229 */ | 181 */ |
230 SkIcoCodec::SkIcoCodec(const SkImageInfo& info, | 182 SkIcoCodec::SkIcoCodec(const SkImageInfo& info, |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 */ | 235 */ |
284 SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo, | 236 SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo, |
285 void* dst, size_t dstRowBytes, | 237 void* dst, size_t dstRowBytes, |
286 const Options& opts, SkPMColor* colorTab
le, | 238 const Options& opts, SkPMColor* colorTab
le, |
287 int* colorCount, int* rowsDecoded) { | 239 int* colorCount, int* rowsDecoded) { |
288 if (opts.fSubset) { | 240 if (opts.fSubset) { |
289 // Subsets are not supported. | 241 // Subsets are not supported. |
290 return kUnimplemented; | 242 return kUnimplemented; |
291 } | 243 } |
292 | 244 |
293 if (!ico_conversion_possible(dstInfo)) { | |
294 return kInvalidConversion; | |
295 } | |
296 | |
297 int index = 0; | 245 int index = 0; |
298 SkCodec::Result result = kInvalidScale; | 246 SkCodec::Result result = kInvalidScale; |
299 while (true) { | 247 while (true) { |
300 index = this->chooseCodec(dstInfo.dimensions(), index); | 248 index = this->chooseCodec(dstInfo.dimensions(), index); |
301 if (index < 0) { | 249 if (index < 0) { |
302 break; | 250 break; |
303 } | 251 } |
304 | 252 |
305 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); | 253 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); |
306 SkImageInfo decodeInfo = fix_embedded_alpha(dstInfo, embeddedCodec->getI
nfo().alphaType()); | 254 result = embeddedCodec->getPixels(dstInfo, dst, dstRowBytes, &opts, colo
rTable, |
307 SkASSERT(decodeInfo.colorType() == kN32_SkColorType); | |
308 result = embeddedCodec->getPixels(decodeInfo, dst, dstRowBytes, &opts, c
olorTable, | |
309 colorCount); | 255 colorCount); |
310 | 256 |
311 switch (result) { | 257 switch (result) { |
312 case kSuccess: | 258 case kSuccess: |
313 case kIncompleteInput: | 259 case kIncompleteInput: |
314 // The embedded codec will handle filling incomplete images, so
we will indicate | 260 // The embedded codec will handle filling incomplete images, so
we will indicate |
315 // that all of the rows are initialized. | 261 // that all of the rows are initialized. |
316 *rowsDecoded = decodeInfo.height(); | 262 *rowsDecoded = dstInfo.height(); |
317 return result; | 263 return result; |
318 default: | 264 default: |
319 // Continue trying to find a valid embedded codec on a failed de
code. | 265 // Continue trying to find a valid embedded codec on a failed de
code. |
320 break; | 266 break; |
321 } | 267 } |
322 | 268 |
323 index++; | 269 index++; |
324 } | 270 } |
325 | 271 |
326 SkCodecPrintf("Error: No matching candidate image in ico.\n"); | 272 SkCodecPrintf("Error: No matching candidate image in ico.\n"); |
327 return result; | 273 return result; |
328 } | 274 } |
329 | 275 |
330 SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, | 276 SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, |
331 const SkCodec::Options& options, SkPMColor colorTable[], int* colorCount
) { | 277 const SkCodec::Options& options, SkPMColor colorTable[], int* colorCount
) { |
332 if (!ico_conversion_possible(dstInfo)) { | |
333 return kInvalidConversion; | |
334 } | |
335 | |
336 int index = 0; | 278 int index = 0; |
337 SkCodec::Result result = kInvalidScale; | 279 SkCodec::Result result = kInvalidScale; |
338 while (true) { | 280 while (true) { |
339 index = this->chooseCodec(dstInfo.dimensions(), index); | 281 index = this->chooseCodec(dstInfo.dimensions(), index); |
340 if (index < 0) { | 282 if (index < 0) { |
341 break; | 283 break; |
342 } | 284 } |
343 | 285 |
344 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); | 286 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); |
345 SkImageInfo decodeInfo = fix_embedded_alpha(dstInfo, embeddedCodec->getI
nfo().alphaType()); | 287 result = embeddedCodec->startScanlineDecode(dstInfo, &options, colorTabl
e, colorCount); |
346 result = embeddedCodec->startScanlineDecode(decodeInfo, &options, colorT
able, colorCount); | |
347 if (kSuccess == result) { | 288 if (kSuccess == result) { |
348 fCurrScanlineCodec = embeddedCodec; | 289 fCurrScanlineCodec = embeddedCodec; |
349 return result; | 290 return result; |
350 } | 291 } |
351 | 292 |
352 index++; | 293 index++; |
353 } | 294 } |
354 | 295 |
355 SkCodecPrintf("Error: No matching candidate image in ico.\n"); | 296 SkCodecPrintf("Error: No matching candidate image in ico.\n"); |
356 return result; | 297 return result; |
(...skipping 12 matching lines...) Expand all Loading... |
369 SkCodec::SkScanlineOrder SkIcoCodec::onGetScanlineOrder() const { | 310 SkCodec::SkScanlineOrder SkIcoCodec::onGetScanlineOrder() const { |
370 // FIXME: This function will possibly return the wrong value if it is called | 311 // FIXME: This function will possibly return the wrong value if it is called |
371 // before startScanlineDecode(). | 312 // before startScanlineDecode(). |
372 return fCurrScanlineCodec ? fCurrScanlineCodec->getScanlineOrder() : | 313 return fCurrScanlineCodec ? fCurrScanlineCodec->getScanlineOrder() : |
373 INHERITED::onGetScanlineOrder(); | 314 INHERITED::onGetScanlineOrder(); |
374 } | 315 } |
375 | 316 |
376 SkSampler* SkIcoCodec::getSampler(bool createIfNecessary) { | 317 SkSampler* SkIcoCodec::getSampler(bool createIfNecessary) { |
377 return fCurrScanlineCodec ? fCurrScanlineCodec->getSampler(createIfNecessary
) : nullptr; | 318 return fCurrScanlineCodec ? fCurrScanlineCodec->getSampler(createIfNecessary
) : nullptr; |
378 } | 319 } |
OLD | NEW |