blob: bb05432427c5756346cf281ee2969c9b093afdf6 [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];
152 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) {
183 SkOrderedWriteBuffer writer(1024);
184 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
310 // Create a bitmap with a pixel ref too small
311 SkBitmap invalidBitmap2;
reed@google.com398337b2013-12-11 21:22:39 +0000312 invalidBitmap2.setConfig(SkBitmap::kARGB_8888_Config, 256, 256);
313 invalidBitmap2.setPixelRef(SkNEW_ARGS(SkMallocPixelRef,
314 (NULL, 256, NULL)))->unref();
skia.committer@gmail.com8491d242013-12-05 07:02:16 +0000315
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000316 // The deserialization should detect the pixel ref being too small and fail
317 TestBitmapSerialization(validBitmap, invalidBitmap2, false, reporter);
318 }
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000319}