| 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 "SkCodec_libico.h" | 9 #include "SkCodec_libico.h" |
| 10 #include "SkCodec_libpng.h" | 10 #include "SkCodec_libpng.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 */ | 34 */ |
| 35 SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { | 35 SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { |
| 36 // Ensure that we do not leak the input stream | 36 // Ensure that we do not leak the input stream |
| 37 SkAutoTDelete<SkStream> inputStream(stream); | 37 SkAutoTDelete<SkStream> inputStream(stream); |
| 38 | 38 |
| 39 // Header size constants | 39 // Header size constants |
| 40 static const uint32_t kIcoDirectoryBytes = 6; | 40 static const uint32_t kIcoDirectoryBytes = 6; |
| 41 static const uint32_t kIcoDirEntryBytes = 16; | 41 static const uint32_t kIcoDirEntryBytes = 16; |
| 42 | 42 |
| 43 // Read the directory header | 43 // Read the directory header |
| 44 SkAutoTDeleteArray<uint8_t> dirBuffer( | 44 SkAutoTDeleteArray<uint8_t> dirBuffer(new uint8_t[kIcoDirectoryBytes]); |
| 45 SkNEW_ARRAY(uint8_t, kIcoDirectoryBytes)); | |
| 46 if (inputStream.get()->read(dirBuffer.get(), kIcoDirectoryBytes) != | 45 if (inputStream.get()->read(dirBuffer.get(), kIcoDirectoryBytes) != |
| 47 kIcoDirectoryBytes) { | 46 kIcoDirectoryBytes) { |
| 48 SkCodecPrintf("Error: unable to read ico directory header.\n"); | 47 SkCodecPrintf("Error: unable to read ico directory header.\n"); |
| 49 return NULL; | 48 return NULL; |
| 50 } | 49 } |
| 51 | 50 |
| 52 // Process the directory header | 51 // Process the directory header |
| 53 const uint16_t numImages = get_short(dirBuffer.get(), 4); | 52 const uint16_t numImages = get_short(dirBuffer.get(), 4); |
| 54 if (0 == numImages) { | 53 if (0 == numImages) { |
| 55 SkCodecPrintf("Error: No images embedded in ico.\n"); | 54 SkCodecPrintf("Error: No images embedded in ico.\n"); |
| 56 return NULL; | 55 return NULL; |
| 57 } | 56 } |
| 58 | 57 |
| 59 // Ensure that we can read all of indicated directory entries | 58 // Ensure that we can read all of indicated directory entries |
| 60 SkAutoTDeleteArray<uint8_t> entryBuffer( | 59 SkAutoTDeleteArray<uint8_t> entryBuffer(new uint8_t[numImages * kIcoDirEntry
Bytes]); |
| 61 SkNEW_ARRAY(uint8_t, numImages*kIcoDirEntryBytes)); | |
| 62 if (inputStream.get()->read(entryBuffer.get(), numImages*kIcoDirEntryBytes)
!= | 60 if (inputStream.get()->read(entryBuffer.get(), numImages*kIcoDirEntryBytes)
!= |
| 63 numImages*kIcoDirEntryBytes) { | 61 numImages*kIcoDirEntryBytes) { |
| 64 SkCodecPrintf("Error: unable to read ico directory entries.\n"); | 62 SkCodecPrintf("Error: unable to read ico directory entries.\n"); |
| 65 return NULL; | 63 return NULL; |
| 66 } | 64 } |
| 67 | 65 |
| 68 // This structure is used to represent the vital information about entries | 66 // This structure is used to represent the vital information about entries |
| 69 // in the directory header. We will obtain this information for each | 67 // in the directory header. We will obtain this information for each |
| 70 // directory entry. | 68 // directory entry. |
| 71 struct Entry { | 69 struct Entry { |
| 72 uint32_t offset; | 70 uint32_t offset; |
| 73 uint32_t size; | 71 uint32_t size; |
| 74 }; | 72 }; |
| 75 SkAutoTDeleteArray<Entry> directoryEntries(SkNEW_ARRAY(Entry, numImages)); | 73 SkAutoTDeleteArray<Entry> directoryEntries(new Entry[numImages]); |
| 76 | 74 |
| 77 // Iterate over directory entries | 75 // Iterate over directory entries |
| 78 for (uint32_t i = 0; i < numImages; i++) { | 76 for (uint32_t i = 0; i < numImages; i++) { |
| 79 // The directory entry contains information such as width, height, | 77 // The directory entry contains information such as width, height, |
| 80 // bits per pixel, and number of colors in the color palette. We will | 78 // bits per pixel, and number of colors in the color palette. We will |
| 81 // ignore these fields since they are repeated in the header of the | 79 // ignore these fields since they are repeated in the header of the |
| 82 // embedded image. In the event of an inconsistency, we would always | 80 // embedded image. In the event of an inconsistency, we would always |
| 83 // defer to the value in the embedded header anyway. | 81 // defer to the value in the embedded header anyway. |
| 84 | 82 |
| 85 // Specifies the size of the embedded image, including the header | 83 // Specifies the size of the embedded image, including the header |
| (...skipping 18 matching lines...) Expand all Loading... |
| 104 return a.offset < b.offset; | 102 return a.offset < b.offset; |
| 105 } | 103 } |
| 106 }; | 104 }; |
| 107 EntryLessThan lessThan; | 105 EntryLessThan lessThan; |
| 108 SkTQSort(directoryEntries.get(), directoryEntries.get() + numImages - 1, | 106 SkTQSort(directoryEntries.get(), directoryEntries.get() + numImages - 1, |
| 109 lessThan); | 107 lessThan); |
| 110 | 108 |
| 111 // Now will construct a candidate codec for each of the embedded images | 109 // Now will construct a candidate codec for each of the embedded images |
| 112 uint32_t bytesRead = kIcoDirectoryBytes + numImages * kIcoDirEntryBytes; | 110 uint32_t bytesRead = kIcoDirectoryBytes + numImages * kIcoDirEntryBytes; |
| 113 SkAutoTDelete<SkTArray<SkAutoTDelete<SkCodec>, true>> codecs( | 111 SkAutoTDelete<SkTArray<SkAutoTDelete<SkCodec>, true>> codecs( |
| 114 SkNEW_ARGS((SkTArray<SkAutoTDelete<SkCodec>, true>), (numImages))); | 112 new (SkTArray<SkAutoTDelete<SkCodec>, true>)(numImages)); |
| 115 for (uint32_t i = 0; i < numImages; i++) { | 113 for (uint32_t i = 0; i < numImages; i++) { |
| 116 uint32_t offset = directoryEntries.get()[i].offset; | 114 uint32_t offset = directoryEntries.get()[i].offset; |
| 117 uint32_t size = directoryEntries.get()[i].size; | 115 uint32_t size = directoryEntries.get()[i].size; |
| 118 | 116 |
| 119 // Ensure that the offset is valid | 117 // Ensure that the offset is valid |
| 120 if (offset < bytesRead) { | 118 if (offset < bytesRead) { |
| 121 SkCodecPrintf("Warning: invalid ico offset.\n"); | 119 SkCodecPrintf("Warning: invalid ico offset.\n"); |
| 122 continue; | 120 continue; |
| 123 } | 121 } |
| 124 | 122 |
| 125 // If we cannot skip, assume we have reached the end of the stream and | 123 // If we cannot skip, assume we have reached the end of the stream and |
| 126 // stop trying to make codecs | 124 // stop trying to make codecs |
| 127 if (inputStream.get()->skip(offset - bytesRead) != offset - bytesRead) { | 125 if (inputStream.get()->skip(offset - bytesRead) != offset - bytesRead) { |
| 128 SkCodecPrintf("Warning: could not skip to ico offset.\n"); | 126 SkCodecPrintf("Warning: could not skip to ico offset.\n"); |
| 129 break; | 127 break; |
| 130 } | 128 } |
| 131 bytesRead = offset; | 129 bytesRead = offset; |
| 132 | 130 |
| 133 // Create a new stream for the embedded codec | 131 // Create a new stream for the embedded codec |
| 134 SkAutoTUnref<SkData> data( | 132 SkAutoTUnref<SkData> data( |
| 135 SkData::NewFromStream(inputStream.get(), size)); | 133 SkData::NewFromStream(inputStream.get(), size)); |
| 136 if (NULL == data.get()) { | 134 if (NULL == data.get()) { |
| 137 SkCodecPrintf("Warning: could not create embedded stream.\n"); | 135 SkCodecPrintf("Warning: could not create embedded stream.\n"); |
| 138 break; | 136 break; |
| 139 } | 137 } |
| 140 SkAutoTDelete<SkMemoryStream> | 138 SkAutoTDelete<SkMemoryStream> embeddedStream(new SkMemoryStream(data.get
())); |
| 141 embeddedStream(SkNEW_ARGS(SkMemoryStream, (data.get()))); | |
| 142 bytesRead += size; | 139 bytesRead += size; |
| 143 | 140 |
| 144 // Check if the embedded codec is bmp or png and create the codec | 141 // Check if the embedded codec is bmp or png and create the codec |
| 145 const bool isPng = SkPngCodec::IsPng(embeddedStream); | 142 const bool isPng = SkPngCodec::IsPng(embeddedStream); |
| 146 SkAssertResult(embeddedStream->rewind()); | 143 SkAssertResult(embeddedStream->rewind()); |
| 147 SkCodec* codec = NULL; | 144 SkCodec* codec = NULL; |
| 148 if (isPng) { | 145 if (isPng) { |
| 149 codec = SkPngCodec::NewFromStream(embeddedStream.detach()); | 146 codec = SkPngCodec::NewFromStream(embeddedStream.detach()); |
| 150 } else { | 147 } else { |
| 151 codec = SkBmpCodec::NewFromIco(embeddedStream.detach()); | 148 codec = SkBmpCodec::NewFromIco(embeddedStream.detach()); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 182 // FIXME (msarett): The BMP decoder depends on the alpha type in order | 179 // FIXME (msarett): The BMP decoder depends on the alpha type in order |
| 183 // to decode correctly, otherwise it could report kUnpremul and we would | 180 // to decode correctly, otherwise it could report kUnpremul and we would |
| 184 // not have to correct it here. Is there a better way? | 181 // not have to correct it here. Is there a better way? |
| 185 // FIXME (msarett): This is only true for BMP in ICO - could a PNG in ICO | 182 // FIXME (msarett): This is only true for BMP in ICO - could a PNG in ICO |
| 186 // be opaque? Is it okay that we missed out on the opportunity to mark | 183 // be opaque? Is it okay that we missed out on the opportunity to mark |
| 187 // such an image as opaque? | 184 // such an image as opaque? |
| 188 info = info.makeAlphaType(kUnpremul_SkAlphaType); | 185 info = info.makeAlphaType(kUnpremul_SkAlphaType); |
| 189 | 186 |
| 190 // Note that stream is owned by the embedded codec, the ico does not need | 187 // Note that stream is owned by the embedded codec, the ico does not need |
| 191 // direct access to the stream. | 188 // direct access to the stream. |
| 192 return SkNEW_ARGS(SkIcoCodec, (info, codecs.detach())); | 189 return new SkIcoCodec(info, codecs.detach()); |
| 193 } | 190 } |
| 194 | 191 |
| 195 /* | 192 /* |
| 196 * Creates an instance of the decoder | 193 * Creates an instance of the decoder |
| 197 * Called only by NewFromStream | 194 * Called only by NewFromStream |
| 198 */ | 195 */ |
| 199 SkIcoCodec::SkIcoCodec(const SkImageInfo& info, | 196 SkIcoCodec::SkIcoCodec(const SkImageInfo& info, |
| 200 SkTArray<SkAutoTDelete<SkCodec>, true>* codecs) | 197 SkTArray<SkAutoTDelete<SkCodec>, true>* codecs) |
| 201 : INHERITED(info, NULL) | 198 : INHERITED(info, NULL) |
| 202 , fEmbeddedCodecs(codecs) | 199 , fEmbeddedCodecs(codecs) |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 } | 268 } |
| 272 | 269 |
| 273 // On success or partial success, return the result | 270 // On success or partial success, return the result |
| 274 return result; | 271 return result; |
| 275 } | 272 } |
| 276 } | 273 } |
| 277 | 274 |
| 278 SkCodecPrintf("Error: No matching candidate image in ico.\n"); | 275 SkCodecPrintf("Error: No matching candidate image in ico.\n"); |
| 279 return result; | 276 return result; |
| 280 } | 277 } |
| OLD | NEW |