blob: 6559f74dc5f05b00c02a4fe40dbe0ef8edcbb905 [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
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00008#include "Test.h"
9#include "TestClassDef.h"
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000010#include "SkBitmapDevice.h"
11#include "SkBitmapSource.h"
12#include "SkCanvas.h"
13#include "SkMallocPixelRef.h"
commit-bot@chromium.org02512882013-10-31 18:37:50 +000014#include "SkOrderedWriteBuffer.h"
15#include "SkValidatingReadBuffer.h"
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000016#include "SkXfermodeImageFilter.h"
commit-bot@chromium.org02512882013-10-31 18:37:50 +000017
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000018static const uint32_t kArraySize = 64;
19
20template<typename T>
21static void TestAlignment(T* testObj, skiatest::Reporter* reporter) {
22 // Test memory read/write functions directly
23 unsigned char dataWritten[1024];
24 size_t bytesWrittenToMemory = testObj->writeToMemory(dataWritten);
25 REPORTER_ASSERT(reporter, SkAlign4(bytesWrittenToMemory) == bytesWrittenToMemory);
26 size_t bytesReadFromMemory = testObj->readFromMemory(dataWritten, bytesWrittenToMemory);
27 REPORTER_ASSERT(reporter, SkAlign4(bytesReadFromMemory) == bytesReadFromMemory);
28}
29
30template<typename T> struct SerializationUtils {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000031 // Generic case for flattenables
32 static void Write(SkOrderedWriteBuffer& writer, const T* flattenable) {
33 writer.writeFlattenable(flattenable);
34 }
35 static void Read(SkValidatingReadBuffer& reader, T** flattenable) {
36 *flattenable = (T*)reader.readFlattenable(T::GetFlattenableType());
37 }
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000038};
39
40template<> struct SerializationUtils<SkMatrix> {
41 static void Write(SkOrderedWriteBuffer& writer, const SkMatrix* matrix) {
42 writer.writeMatrix(*matrix);
43 }
44 static void Read(SkValidatingReadBuffer& reader, SkMatrix* matrix) {
45 reader.readMatrix(matrix);
46 }
47};
48
49template<> struct SerializationUtils<SkPath> {
50 static void Write(SkOrderedWriteBuffer& writer, const SkPath* path) {
51 writer.writePath(*path);
52 }
53 static void Read(SkValidatingReadBuffer& reader, SkPath* path) {
54 reader.readPath(path);
55 }
56};
57
58template<> struct SerializationUtils<SkRegion> {
59 static void Write(SkOrderedWriteBuffer& writer, const SkRegion* region) {
60 writer.writeRegion(*region);
61 }
62 static void Read(SkValidatingReadBuffer& reader, SkRegion* region) {
63 reader.readRegion(region);
64 }
65};
66
67template<> struct SerializationUtils<unsigned char> {
68 static void Write(SkOrderedWriteBuffer& writer, unsigned char* data, uint32_t arraySize) {
reed@google.com12a23862013-11-04 21:35:55 +000069 writer.writeByteArray(data, arraySize);
sugoi@google.com305f78e2013-11-04 16:18:15 +000070 }
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000071 static bool Read(SkValidatingReadBuffer& reader, unsigned char* data, uint32_t arraySize) {
72 return reader.readByteArray(data, arraySize);
73 }
74};
commit-bot@chromium.org02512882013-10-31 18:37:50 +000075
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000076template<> struct SerializationUtils<SkColor> {
77 static void Write(SkOrderedWriteBuffer& writer, SkColor* data, uint32_t arraySize) {
reed@google.com12a23862013-11-04 21:35:55 +000078 writer.writeColorArray(data, arraySize);
sugoi@google.comb48a59a2013-11-04 20:28:23 +000079 }
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000080 static bool Read(SkValidatingReadBuffer& reader, SkColor* data, uint32_t arraySize) {
81 return reader.readColorArray(data, arraySize);
82 }
83};
sugoi@google.com305f78e2013-11-04 16:18:15 +000084
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000085template<> struct SerializationUtils<int32_t> {
86 static void Write(SkOrderedWriteBuffer& writer, int32_t* data, uint32_t arraySize) {
reed@google.com12a23862013-11-04 21:35:55 +000087 writer.writeIntArray(data, arraySize);
sugoi@google.comb48a59a2013-11-04 20:28:23 +000088 }
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000089 static bool Read(SkValidatingReadBuffer& reader, int32_t* data, uint32_t arraySize) {
90 return reader.readIntArray(data, arraySize);
91 }
92};
sugoi@google.com305f78e2013-11-04 16:18:15 +000093
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000094template<> struct SerializationUtils<SkPoint> {
95 static void Write(SkOrderedWriteBuffer& writer, SkPoint* data, uint32_t arraySize) {
reed@google.com12a23862013-11-04 21:35:55 +000096 writer.writePointArray(data, arraySize);
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +000097 }
98 static bool Read(SkValidatingReadBuffer& reader, SkPoint* data, uint32_t arraySize) {
99 return reader.readPointArray(data, arraySize);
100 }
101};
reed@google.com12a23862013-11-04 21:35:55 +0000102
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000103template<> struct SerializationUtils<SkScalar> {
104 static void Write(SkOrderedWriteBuffer& writer, SkScalar* data, uint32_t arraySize) {
105 writer.writeScalarArray(data, arraySize);
106 }
107 static bool Read(SkValidatingReadBuffer& reader, SkScalar* data, uint32_t arraySize) {
108 return reader.readScalarArray(data, arraySize);
109 }
110};
reed@google.com12a23862013-11-04 21:35:55 +0000111
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000112template<typename T>
113static void TestObjectSerialization(T* testObj, skiatest::Reporter* reporter) {
114 SkOrderedWriteBuffer writer(1024);
115 writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
116 SerializationUtils<T>::Write(writer, testObj);
117 size_t bytesWritten = writer.bytesWritten();
118 REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten);
reed@google.com12a23862013-11-04 21:35:55 +0000119
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000120 unsigned char dataWritten[1024];
121 writer.writeToMemory(dataWritten);
122
123 // Make sure this fails when it should (test with smaller size, but still multiple of 4)
124 SkValidatingReadBuffer buffer(dataWritten, bytesWritten - 4);
commit-bot@chromium.org8f457e32013-11-08 19:22:57 +0000125 T obj;
126 SerializationUtils<T>::Read(buffer, &obj);
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +0000127 REPORTER_ASSERT(reporter, !buffer.isValid());
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000128
129 // Make sure this succeeds when it should
130 SkValidatingReadBuffer buffer2(dataWritten, bytesWritten);
commit-bot@chromium.org8f457e32013-11-08 19:22:57 +0000131 const unsigned char* peekBefore = static_cast<const unsigned char*>(buffer2.skip(0));
132 T obj2;
133 SerializationUtils<T>::Read(buffer2, &obj2);
134 const unsigned char* peekAfter = static_cast<const unsigned char*>(buffer2.skip(0));
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000135 // This should have succeeded, since there are enough bytes to read this
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +0000136 REPORTER_ASSERT(reporter, buffer2.isValid());
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000137 REPORTER_ASSERT(reporter, static_cast<size_t>(peekAfter - peekBefore) == bytesWritten);
138
139 TestAlignment(testObj, reporter);
140}
141
142template<typename T>
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000143static T* TestFlattenableSerialization(T* testObj, bool shouldSucceed,
144 skiatest::Reporter* reporter) {
145 SkOrderedWriteBuffer writer(1024);
146 writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
147 SerializationUtils<T>::Write(writer, testObj);
148 size_t bytesWritten = writer.bytesWritten();
149 REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten);
150
151 unsigned char dataWritten[1024];
reed@google.combf790232013-12-13 19:45:58 +0000152 SkASSERT(bytesWritten <= sizeof(dataWritten));
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000153 writer.writeToMemory(dataWritten);
154
155 // Make sure this fails when it should (test with smaller size, but still multiple of 4)
156 SkValidatingReadBuffer buffer(dataWritten, bytesWritten - 4);
157 T* obj = NULL;
158 SerializationUtils<T>::Read(buffer, &obj);
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +0000159 REPORTER_ASSERT(reporter, !buffer.isValid());
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000160 REPORTER_ASSERT(reporter, NULL == obj);
161
162 // Make sure this succeeds when it should
163 SkValidatingReadBuffer buffer2(dataWritten, bytesWritten);
164 const unsigned char* peekBefore = static_cast<const unsigned char*>(buffer2.skip(0));
165 T* obj2 = NULL;
166 SerializationUtils<T>::Read(buffer2, &obj2);
167 const unsigned char* peekAfter = static_cast<const unsigned char*>(buffer2.skip(0));
168 if (shouldSucceed) {
169 // This should have succeeded, since there are enough bytes to read this
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +0000170 REPORTER_ASSERT(reporter, buffer2.isValid());
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000171 REPORTER_ASSERT(reporter, static_cast<size_t>(peekAfter - peekBefore) == bytesWritten);
172 REPORTER_ASSERT(reporter, NULL != obj2);
173 } else {
174 // If the deserialization was supposed to fail, make sure it did
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +0000175 REPORTER_ASSERT(reporter, !buffer.isValid());
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000176 REPORTER_ASSERT(reporter, NULL == obj2);
177 }
178
179 return obj2; // Return object to perform further validity tests on it
180}
181
182template<typename T>
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000183static void TestArraySerialization(T* data, skiatest::Reporter* reporter) {
184 SkOrderedWriteBuffer writer(1024);
185 writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
186 SerializationUtils<T>::Write(writer, data, kArraySize);
187 size_t bytesWritten = writer.bytesWritten();
188 // This should write the length (in 4 bytes) and the array
189 REPORTER_ASSERT(reporter, (4 + kArraySize * sizeof(T)) == bytesWritten);
190
191 unsigned char dataWritten[1024];
192 writer.writeToMemory(dataWritten);
193
194 // Make sure this fails when it should
195 SkValidatingReadBuffer buffer(dataWritten, bytesWritten);
196 T dataRead[kArraySize];
197 bool success = SerializationUtils<T>::Read(buffer, dataRead, kArraySize / 2);
198 // This should have failed, since the provided size was too small
199 REPORTER_ASSERT(reporter, !success);
200
201 // Make sure this succeeds when it should
202 SkValidatingReadBuffer buffer2(dataWritten, bytesWritten);
203 success = SerializationUtils<T>::Read(buffer2, dataRead, kArraySize);
204 // This should have succeeded, since there are enough bytes to read this
205 REPORTER_ASSERT(reporter, success);
206}
207
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000208static void TestBitmapSerialization(const SkBitmap& validBitmap,
209 const SkBitmap& invalidBitmap,
210 bool shouldSucceed,
211 skiatest::Reporter* reporter) {
212 SkBitmapSource validBitmapSource(validBitmap);
213 SkBitmapSource invalidBitmapSource(invalidBitmap);
214 SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
215 SkXfermodeImageFilter xfermodeImageFilter(mode, &invalidBitmapSource, &validBitmapSource);
216
217 SkAutoTUnref<SkImageFilter> deserializedFilter(
218 TestFlattenableSerialization<SkImageFilter>(
219 &xfermodeImageFilter, shouldSucceed, reporter));
220
221 // Try to render a small bitmap using the invalid deserialized filter
222 // to make sure we don't crash while trying to render it
223 if (shouldSucceed) {
224 SkBitmap bitmap;
225 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 24, 24);
226 bitmap.allocPixels();
227 SkBitmapDevice device(bitmap);
228 SkCanvas canvas(&device);
229 canvas.clear(0x00000000);
230 SkPaint paint;
231 paint.setImageFilter(deserializedFilter);
232 canvas.clipRect(SkRect::MakeXYWH(0, 0, SkIntToScalar(24), SkIntToScalar(24)));
233 canvas.drawBitmap(bitmap, 0, 0, &paint);
234 }
235}
236
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000237DEF_TEST(Serialization, reporter) {
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000238 // Test matrix serialization
239 {
240 SkMatrix matrix = SkMatrix::I();
241 TestObjectSerialization(&matrix, reporter);
242 }
243
244 // Test path serialization
245 {
246 SkPath path;
247 TestObjectSerialization(&path, reporter);
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000248 }
sugoi@google.com305f78e2013-11-04 16:18:15 +0000249
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000250 // Test region serialization
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000251 {
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000252 SkRegion region;
253 TestObjectSerialization(&region, reporter);
254 }
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000255
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000256 // Test rrect serialization
257 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000258 // SkRRect does not initialize anything.
259 // An uninitialized SkRRect can be serialized,
260 // but will branch on uninitialized data when deserialized.
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000261 SkRRect rrect;
rmistry@google.comd6bab022013-12-02 13:50:38 +0000262 SkRect rect = SkRect::MakeXYWH(1, 2, 20, 30);
263 SkVector corners[4] = { {1, 2}, {2, 3}, {3,4}, {4,5} };
264 rrect.setRectRadii(rect, corners);
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000265 TestAlignment(&rrect, reporter);
266 }
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000267
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000268 // Test readByteArray
269 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000270 unsigned char data[kArraySize] = { 1, 2, 3 };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000271 TestArraySerialization(data, reporter);
272 }
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000273
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000274 // Test readColorArray
275 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000276 SkColor data[kArraySize] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorRED };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000277 TestArraySerialization(data, reporter);
278 }
279
280 // Test readIntArray
281 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000282 int32_t data[kArraySize] = { 1, 2, 4, 8 };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000283 TestArraySerialization(data, reporter);
284 }
285
286 // Test readPointArray
287 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000288 SkPoint data[kArraySize] = { {6, 7}, {42, 128} };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000289 TestArraySerialization(data, reporter);
290 }
291
292 // Test readScalarArray
293 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000294 SkScalar data[kArraySize] = { SK_Scalar1, SK_ScalarHalf, SK_ScalarMax };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000295 TestArraySerialization(data, reporter);
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000296 }
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000297
298 // Test invalid deserializations
299 {
300 SkBitmap validBitmap;
301 validBitmap.setConfig(SkBitmap::kARGB_8888_Config, 256, 256);
302
303 // Create a bitmap with a really large height
304 SkBitmap invalidBitmap;
305 invalidBitmap.setConfig(SkBitmap::kARGB_8888_Config, 256, 1000000000);
306
307 // The deserialization should succeed, and the rendering shouldn't crash,
308 // even when the device fails to initialize, due to its size
309 TestBitmapSerialization(validBitmap, invalidBitmap, true, reporter);
310
311 // Create a bitmap with a pixel ref too small
reed@google.combf790232013-12-13 19:45:58 +0000312 SkImageInfo info;
313 info.fWidth = 256;
314 info.fHeight = 256;
315 info.fColorType = kPMColor_SkColorType;
316 info.fAlphaType = kPremul_SkAlphaType;
317
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000318 SkBitmap invalidBitmap2;
reed@google.combf790232013-12-13 19:45:58 +0000319 invalidBitmap2.setConfig(info);
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000320
reed@google.combf790232013-12-13 19:45:58 +0000321 // Hack to force invalid, by making the pixelref smaller than its
322 // owning bitmap.
323 info.fWidth = 32;
324 info.fHeight = 1;
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000325
reed@google.combf790232013-12-13 19:45:58 +0000326 invalidBitmap2.setPixelRef(SkMallocPixelRef::NewAllocate(
327 info, invalidBitmap2.rowBytes(), NULL))->unref();
skia.committer@gmail.com8491d242013-12-05 07:02:16 +0000328
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000329 // The deserialization should detect the pixel ref being too small and fail
330 TestBitmapSerialization(validBitmap, invalidBitmap2, false, reporter);
331 }
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000332}