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 |