blob: 76612b631845b0f93db9a345bf7def0640f6f125 [file] [log] [blame]
commit-bot@chromium.org02512882013-10-31 18:37:50 +00001/*
2 * Copyright 2013 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
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +00008#include "SkBitmapDevice.h"
9#include "SkBitmapSource.h"
10#include "SkCanvas.h"
11#include "SkMallocPixelRef.h"
commit-bot@chromium.org02512882013-10-31 18:37:50 +000012#include "SkOrderedWriteBuffer.h"
13#include "SkValidatingReadBuffer.h"
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000014#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000015#include "Test.h"
commit-bot@chromium.org02512882013-10-31 18:37:50 +000016
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000017static const uint32_t kArraySize = 64;
18
19template<typename T>
20static void TestAlignment(T* testObj, skiatest::Reporter* reporter) {
21 // Test memory read/write functions directly
22 unsigned char dataWritten[1024];
23 size_t bytesWrittenToMemory = testObj->writeToMemory(dataWritten);
24 REPORTER_ASSERT(reporter, SkAlign4(bytesWrittenToMemory) == bytesWrittenToMemory);
25 size_t bytesReadFromMemory = testObj->readFromMemory(dataWritten, bytesWrittenToMemory);
26 REPORTER_ASSERT(reporter, SkAlign4(bytesReadFromMemory) == bytesReadFromMemory);
27}
28
29template<typename T> struct SerializationUtils {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000030 // Generic case for flattenables
31 static void Write(SkOrderedWriteBuffer& writer, const T* flattenable) {
32 writer.writeFlattenable(flattenable);
33 }
34 static void Read(SkValidatingReadBuffer& reader, T** flattenable) {
35 *flattenable = (T*)reader.readFlattenable(T::GetFlattenableType());
36 }
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000037};
38
39template<> struct SerializationUtils<SkMatrix> {
40 static void Write(SkOrderedWriteBuffer& writer, const SkMatrix* matrix) {
41 writer.writeMatrix(*matrix);
42 }
43 static void Read(SkValidatingReadBuffer& reader, SkMatrix* matrix) {
44 reader.readMatrix(matrix);
45 }
46};
47
48template<> struct SerializationUtils<SkPath> {
49 static void Write(SkOrderedWriteBuffer& writer, const SkPath* path) {
50 writer.writePath(*path);
51 }
52 static void Read(SkValidatingReadBuffer& reader, SkPath* path) {
53 reader.readPath(path);
54 }
55};
56
57template<> struct SerializationUtils<SkRegion> {
58 static void Write(SkOrderedWriteBuffer& writer, const SkRegion* region) {
59 writer.writeRegion(*region);
60 }
61 static void Read(SkValidatingReadBuffer& reader, SkRegion* region) {
62 reader.readRegion(region);
63 }
64};
65
66template<> struct SerializationUtils<unsigned char> {
67 static void Write(SkOrderedWriteBuffer& writer, unsigned char* data, uint32_t arraySize) {
reed@google.com12a23862013-11-04 21:35:55 +000068 writer.writeByteArray(data, arraySize);
sugoi@google.com305f78e2013-11-04 16:18:15 +000069 }
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000070 static bool Read(SkValidatingReadBuffer& reader, unsigned char* data, uint32_t arraySize) {
71 return reader.readByteArray(data, arraySize);
72 }
73};
commit-bot@chromium.org02512882013-10-31 18:37:50 +000074
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000075template<> struct SerializationUtils<SkColor> {
76 static void Write(SkOrderedWriteBuffer& writer, SkColor* data, uint32_t arraySize) {
reed@google.com12a23862013-11-04 21:35:55 +000077 writer.writeColorArray(data, arraySize);
sugoi@google.comb48a59a2013-11-04 20:28:23 +000078 }
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000079 static bool Read(SkValidatingReadBuffer& reader, SkColor* data, uint32_t arraySize) {
80 return reader.readColorArray(data, arraySize);
81 }
82};
sugoi@google.com305f78e2013-11-04 16:18:15 +000083
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000084template<> struct SerializationUtils<int32_t> {
85 static void Write(SkOrderedWriteBuffer& writer, int32_t* data, uint32_t arraySize) {
reed@google.com12a23862013-11-04 21:35:55 +000086 writer.writeIntArray(data, arraySize);
sugoi@google.comb48a59a2013-11-04 20:28:23 +000087 }
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000088 static bool Read(SkValidatingReadBuffer& reader, int32_t* data, uint32_t arraySize) {
89 return reader.readIntArray(data, arraySize);
90 }
91};
sugoi@google.com305f78e2013-11-04 16:18:15 +000092
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000093template<> struct SerializationUtils<SkPoint> {
94 static void Write(SkOrderedWriteBuffer& writer, SkPoint* data, uint32_t arraySize) {
reed@google.com12a23862013-11-04 21:35:55 +000095 writer.writePointArray(data, arraySize);
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000096 }
97 static bool Read(SkValidatingReadBuffer& reader, SkPoint* data, uint32_t arraySize) {
98 return reader.readPointArray(data, arraySize);
99 }
100};
reed@google.com12a23862013-11-04 21:35:55 +0000101
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000102template<> struct SerializationUtils<SkScalar> {
103 static void Write(SkOrderedWriteBuffer& writer, SkScalar* data, uint32_t arraySize) {
104 writer.writeScalarArray(data, arraySize);
105 }
106 static bool Read(SkValidatingReadBuffer& reader, SkScalar* data, uint32_t arraySize) {
107 return reader.readScalarArray(data, arraySize);
108 }
109};
reed@google.com12a23862013-11-04 21:35:55 +0000110
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000111template<typename T>
112static void TestObjectSerialization(T* testObj, skiatest::Reporter* reporter) {
commit-bot@chromium.org19382422014-01-14 20:51:26 +0000113 SkOrderedWriteBuffer writer;
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000114 writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
115 SerializationUtils<T>::Write(writer, testObj);
116 size_t bytesWritten = writer.bytesWritten();
117 REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten);
reed@google.com12a23862013-11-04 21:35:55 +0000118
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000119 unsigned char dataWritten[1024];
120 writer.writeToMemory(dataWritten);
121
122 // Make sure this fails when it should (test with smaller size, but still multiple of 4)
123 SkValidatingReadBuffer buffer(dataWritten, bytesWritten - 4);
commit-bot@chromium.org8f457e32013-11-08 19:22:57 +0000124 T obj;
125 SerializationUtils<T>::Read(buffer, &obj);
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +0000126 REPORTER_ASSERT(reporter, !buffer.isValid());
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000127
128 // Make sure this succeeds when it should
129 SkValidatingReadBuffer buffer2(dataWritten, bytesWritten);
commit-bot@chromium.org8f457e32013-11-08 19:22:57 +0000130 const unsigned char* peekBefore = static_cast<const unsigned char*>(buffer2.skip(0));
131 T obj2;
132 SerializationUtils<T>::Read(buffer2, &obj2);
133 const unsigned char* peekAfter = static_cast<const unsigned char*>(buffer2.skip(0));
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000134 // This should have succeeded, since there are enough bytes to read this
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +0000135 REPORTER_ASSERT(reporter, buffer2.isValid());
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000136 REPORTER_ASSERT(reporter, static_cast<size_t>(peekAfter - peekBefore) == bytesWritten);
137
138 TestAlignment(testObj, reporter);
139}
140
141template<typename T>
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000142static T* TestFlattenableSerialization(T* testObj, bool shouldSucceed,
143 skiatest::Reporter* reporter) {
commit-bot@chromium.org19382422014-01-14 20:51:26 +0000144 SkOrderedWriteBuffer writer;
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000145 writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
146 SerializationUtils<T>::Write(writer, testObj);
147 size_t bytesWritten = writer.bytesWritten();
148 REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten);
149
150 unsigned char dataWritten[1024];
reed@google.combf790232013-12-13 19:45:58 +0000151 SkASSERT(bytesWritten <= sizeof(dataWritten));
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000152 writer.writeToMemory(dataWritten);
153
154 // Make sure this fails when it should (test with smaller size, but still multiple of 4)
155 SkValidatingReadBuffer buffer(dataWritten, bytesWritten - 4);
156 T* obj = NULL;
157 SerializationUtils<T>::Read(buffer, &obj);
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +0000158 REPORTER_ASSERT(reporter, !buffer.isValid());
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000159 REPORTER_ASSERT(reporter, NULL == obj);
160
161 // Make sure this succeeds when it should
162 SkValidatingReadBuffer buffer2(dataWritten, bytesWritten);
163 const unsigned char* peekBefore = static_cast<const unsigned char*>(buffer2.skip(0));
164 T* obj2 = NULL;
165 SerializationUtils<T>::Read(buffer2, &obj2);
166 const unsigned char* peekAfter = static_cast<const unsigned char*>(buffer2.skip(0));
167 if (shouldSucceed) {
168 // This should have succeeded, since there are enough bytes to read this
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +0000169 REPORTER_ASSERT(reporter, buffer2.isValid());
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000170 REPORTER_ASSERT(reporter, static_cast<size_t>(peekAfter - peekBefore) == bytesWritten);
171 REPORTER_ASSERT(reporter, NULL != obj2);
172 } else {
173 // If the deserialization was supposed to fail, make sure it did
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +0000174 REPORTER_ASSERT(reporter, !buffer.isValid());
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000175 REPORTER_ASSERT(reporter, NULL == obj2);
176 }
177
178 return obj2; // Return object to perform further validity tests on it
179}
180
181template<typename T>
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000182static void TestArraySerialization(T* data, skiatest::Reporter* reporter) {
commit-bot@chromium.org19382422014-01-14 20:51:26 +0000183 SkOrderedWriteBuffer writer;
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000184 writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
185 SerializationUtils<T>::Write(writer, data, kArraySize);
186 size_t bytesWritten = writer.bytesWritten();
187 // This should write the length (in 4 bytes) and the array
188 REPORTER_ASSERT(reporter, (4 + kArraySize * sizeof(T)) == bytesWritten);
189
190 unsigned char dataWritten[1024];
191 writer.writeToMemory(dataWritten);
192
193 // Make sure this fails when it should
194 SkValidatingReadBuffer buffer(dataWritten, bytesWritten);
195 T dataRead[kArraySize];
196 bool success = SerializationUtils<T>::Read(buffer, dataRead, kArraySize / 2);
197 // This should have failed, since the provided size was too small
198 REPORTER_ASSERT(reporter, !success);
199
200 // Make sure this succeeds when it should
201 SkValidatingReadBuffer buffer2(dataWritten, bytesWritten);
202 success = SerializationUtils<T>::Read(buffer2, dataRead, kArraySize);
203 // This should have succeeded, since there are enough bytes to read this
204 REPORTER_ASSERT(reporter, success);
205}
206
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000207static void TestBitmapSerialization(const SkBitmap& validBitmap,
208 const SkBitmap& invalidBitmap,
209 bool shouldSucceed,
210 skiatest::Reporter* reporter) {
211 SkBitmapSource validBitmapSource(validBitmap);
212 SkBitmapSource invalidBitmapSource(invalidBitmap);
213 SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
214 SkXfermodeImageFilter xfermodeImageFilter(mode, &invalidBitmapSource, &validBitmapSource);
215
216 SkAutoTUnref<SkImageFilter> deserializedFilter(
217 TestFlattenableSerialization<SkImageFilter>(
218 &xfermodeImageFilter, shouldSucceed, reporter));
219
220 // Try to render a small bitmap using the invalid deserialized filter
221 // to make sure we don't crash while trying to render it
222 if (shouldSucceed) {
223 SkBitmap bitmap;
224 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 24, 24);
225 bitmap.allocPixels();
226 SkBitmapDevice device(bitmap);
227 SkCanvas canvas(&device);
228 canvas.clear(0x00000000);
229 SkPaint paint;
230 paint.setImageFilter(deserializedFilter);
231 canvas.clipRect(SkRect::MakeXYWH(0, 0, SkIntToScalar(24), SkIntToScalar(24)));
232 canvas.drawBitmap(bitmap, 0, 0, &paint);
233 }
234}
235
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000236DEF_TEST(Serialization, reporter) {
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000237 // Test matrix serialization
238 {
239 SkMatrix matrix = SkMatrix::I();
240 TestObjectSerialization(&matrix, reporter);
241 }
242
243 // Test path serialization
244 {
245 SkPath path;
246 TestObjectSerialization(&path, reporter);
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000247 }
sugoi@google.com305f78e2013-11-04 16:18:15 +0000248
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000249 // Test region serialization
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000250 {
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000251 SkRegion region;
252 TestObjectSerialization(&region, reporter);
253 }
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000254
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000255 // Test rrect serialization
256 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000257 // SkRRect does not initialize anything.
258 // An uninitialized SkRRect can be serialized,
259 // but will branch on uninitialized data when deserialized.
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000260 SkRRect rrect;
rmistry@google.comd6bab022013-12-02 13:50:38 +0000261 SkRect rect = SkRect::MakeXYWH(1, 2, 20, 30);
262 SkVector corners[4] = { {1, 2}, {2, 3}, {3,4}, {4,5} };
263 rrect.setRectRadii(rect, corners);
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000264 TestAlignment(&rrect, reporter);
265 }
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000266
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000267 // Test readByteArray
268 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000269 unsigned char data[kArraySize] = { 1, 2, 3 };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000270 TestArraySerialization(data, reporter);
271 }
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000272
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000273 // Test readColorArray
274 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000275 SkColor data[kArraySize] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorRED };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000276 TestArraySerialization(data, reporter);
277 }
278
279 // Test readIntArray
280 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000281 int32_t data[kArraySize] = { 1, 2, 4, 8 };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000282 TestArraySerialization(data, reporter);
283 }
284
285 // Test readPointArray
286 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000287 SkPoint data[kArraySize] = { {6, 7}, {42, 128} };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000288 TestArraySerialization(data, reporter);
289 }
290
291 // Test readScalarArray
292 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000293 SkScalar data[kArraySize] = { SK_Scalar1, SK_ScalarHalf, SK_ScalarMax };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000294 TestArraySerialization(data, reporter);
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000295 }
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000296
297 // Test invalid deserializations
298 {
299 SkBitmap validBitmap;
300 validBitmap.setConfig(SkBitmap::kARGB_8888_Config, 256, 256);
301
302 // Create a bitmap with a really large height
303 SkBitmap invalidBitmap;
304 invalidBitmap.setConfig(SkBitmap::kARGB_8888_Config, 256, 1000000000);
305
306 // The deserialization should succeed, and the rendering shouldn't crash,
307 // even when the device fails to initialize, due to its size
308 TestBitmapSerialization(validBitmap, invalidBitmap, true, reporter);
309
reed@google.comdcea5302014-01-03 13:43:01 +0000310 // we assert if the pixelref doesn't agree with the config, so skip this
311 // test (at least for now)
312#if 0
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000313 // Create a bitmap with a pixel ref too small
reed@google.combf790232013-12-13 19:45:58 +0000314 SkImageInfo info;
315 info.fWidth = 256;
316 info.fHeight = 256;
317 info.fColorType = kPMColor_SkColorType;
318 info.fAlphaType = kPremul_SkAlphaType;
319
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000320 SkBitmap invalidBitmap2;
reed@google.combf790232013-12-13 19:45:58 +0000321 invalidBitmap2.setConfig(info);
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000322
reed@google.combf790232013-12-13 19:45:58 +0000323 // Hack to force invalid, by making the pixelref smaller than its
324 // owning bitmap.
325 info.fWidth = 32;
326 info.fHeight = 1;
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000327
reed@google.combf790232013-12-13 19:45:58 +0000328 invalidBitmap2.setPixelRef(SkMallocPixelRef::NewAllocate(
329 info, invalidBitmap2.rowBytes(), NULL))->unref();
skia.committer@gmail.com8491d242013-12-05 07:02:16 +0000330
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000331 // The deserialization should detect the pixel ref being too small and fail
332 TestBitmapSerialization(validBitmap, invalidBitmap2, false, reporter);
reed@google.comdcea5302014-01-03 13:43:01 +0000333#endif
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000334 }
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000335}