blob: 26c7fb06f4ab90a0fbfc3083eb12c29d6d1f62bb [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"
commit-bot@chromium.org02512882013-10-31 18:37:50 +000015#include "Test.h"
16
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) {
113 SkOrderedWriteBuffer writer(1024);
114 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);
126 REPORTER_ASSERT(reporter, !buffer.validate(true));
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.org8f457e32013-11-08 19:22:57 +0000135 REPORTER_ASSERT(reporter, buffer2.validate(true));
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) {
144 SkOrderedWriteBuffer writer(1024);
145 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];
151 writer.writeToMemory(dataWritten);
152
153 // Make sure this fails when it should (test with smaller size, but still multiple of 4)
154 SkValidatingReadBuffer buffer(dataWritten, bytesWritten - 4);
155 T* obj = NULL;
156 SerializationUtils<T>::Read(buffer, &obj);
157 REPORTER_ASSERT(reporter, !buffer.validate(true));
158 REPORTER_ASSERT(reporter, NULL == obj);
159
160 // Make sure this succeeds when it should
161 SkValidatingReadBuffer buffer2(dataWritten, bytesWritten);
162 const unsigned char* peekBefore = static_cast<const unsigned char*>(buffer2.skip(0));
163 T* obj2 = NULL;
164 SerializationUtils<T>::Read(buffer2, &obj2);
165 const unsigned char* peekAfter = static_cast<const unsigned char*>(buffer2.skip(0));
166 if (shouldSucceed) {
167 // This should have succeeded, since there are enough bytes to read this
168 REPORTER_ASSERT(reporter, buffer2.validate(true));
169 REPORTER_ASSERT(reporter, static_cast<size_t>(peekAfter - peekBefore) == bytesWritten);
170 REPORTER_ASSERT(reporter, NULL != obj2);
171 } else {
172 // If the deserialization was supposed to fail, make sure it did
173 REPORTER_ASSERT(reporter, !buffer.validate(true));
174 REPORTER_ASSERT(reporter, NULL == obj2);
175 }
176
177 return obj2; // Return object to perform further validity tests on it
178}
179
180template<typename T>
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000181static void TestArraySerialization(T* data, skiatest::Reporter* reporter) {
182 SkOrderedWriteBuffer writer(1024);
183 writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag);
184 SerializationUtils<T>::Write(writer, data, kArraySize);
185 size_t bytesWritten = writer.bytesWritten();
186 // This should write the length (in 4 bytes) and the array
187 REPORTER_ASSERT(reporter, (4 + kArraySize * sizeof(T)) == bytesWritten);
188
189 unsigned char dataWritten[1024];
190 writer.writeToMemory(dataWritten);
191
192 // Make sure this fails when it should
193 SkValidatingReadBuffer buffer(dataWritten, bytesWritten);
194 T dataRead[kArraySize];
195 bool success = SerializationUtils<T>::Read(buffer, dataRead, kArraySize / 2);
196 // This should have failed, since the provided size was too small
197 REPORTER_ASSERT(reporter, !success);
198
199 // Make sure this succeeds when it should
200 SkValidatingReadBuffer buffer2(dataWritten, bytesWritten);
201 success = SerializationUtils<T>::Read(buffer2, dataRead, kArraySize);
202 // This should have succeeded, since there are enough bytes to read this
203 REPORTER_ASSERT(reporter, success);
204}
205
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000206static void TestBitmapSerialization(const SkBitmap& validBitmap,
207 const SkBitmap& invalidBitmap,
208 bool shouldSucceed,
209 skiatest::Reporter* reporter) {
210 SkBitmapSource validBitmapSource(validBitmap);
211 SkBitmapSource invalidBitmapSource(invalidBitmap);
212 SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
213 SkXfermodeImageFilter xfermodeImageFilter(mode, &invalidBitmapSource, &validBitmapSource);
214
215 SkAutoTUnref<SkImageFilter> deserializedFilter(
216 TestFlattenableSerialization<SkImageFilter>(
217 &xfermodeImageFilter, shouldSucceed, reporter));
218
219 // Try to render a small bitmap using the invalid deserialized filter
220 // to make sure we don't crash while trying to render it
221 if (shouldSucceed) {
222 SkBitmap bitmap;
223 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 24, 24);
224 bitmap.allocPixels();
225 SkBitmapDevice device(bitmap);
226 SkCanvas canvas(&device);
227 canvas.clear(0x00000000);
228 SkPaint paint;
229 paint.setImageFilter(deserializedFilter);
230 canvas.clipRect(SkRect::MakeXYWH(0, 0, SkIntToScalar(24), SkIntToScalar(24)));
231 canvas.drawBitmap(bitmap, 0, 0, &paint);
232 }
233}
234
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000235static void Tests(skiatest::Reporter* reporter) {
236 // Test matrix serialization
237 {
238 SkMatrix matrix = SkMatrix::I();
239 TestObjectSerialization(&matrix, reporter);
240 }
241
242 // Test path serialization
243 {
244 SkPath path;
245 TestObjectSerialization(&path, reporter);
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000246 }
sugoi@google.com305f78e2013-11-04 16:18:15 +0000247
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000248 // Test region serialization
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000249 {
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000250 SkRegion region;
251 TestObjectSerialization(&region, reporter);
252 }
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000253
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000254 // Test rrect serialization
255 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000256 // SkRRect does not initialize anything.
257 // An uninitialized SkRRect can be serialized,
258 // but will branch on uninitialized data when deserialized.
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000259 SkRRect rrect;
rmistry@google.comd6bab022013-12-02 13:50:38 +0000260 SkRect rect = SkRect::MakeXYWH(1, 2, 20, 30);
261 SkVector corners[4] = { {1, 2}, {2, 3}, {3,4}, {4,5} };
262 rrect.setRectRadii(rect, corners);
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000263 TestAlignment(&rrect, reporter);
264 }
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000265
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000266 // Test readByteArray
267 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000268 unsigned char data[kArraySize] = { 1, 2, 3 };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000269 TestArraySerialization(data, reporter);
270 }
sugoi@google.comb48a59a2013-11-04 20:28:23 +0000271
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000272 // Test readColorArray
273 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000274 SkColor data[kArraySize] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorRED };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000275 TestArraySerialization(data, reporter);
276 }
277
278 // Test readIntArray
279 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000280 int32_t data[kArraySize] = { 1, 2, 4, 8 };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000281 TestArraySerialization(data, reporter);
282 }
283
284 // Test readPointArray
285 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000286 SkPoint data[kArraySize] = { {6, 7}, {42, 128} };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000287 TestArraySerialization(data, reporter);
288 }
289
290 // Test readScalarArray
291 {
rmistry@google.comd6bab022013-12-02 13:50:38 +0000292 SkScalar data[kArraySize] = { SK_Scalar1, SK_ScalarHalf, SK_ScalarMax };
commit-bot@chromium.org4faa8692013-11-05 15:46:56 +0000293 TestArraySerialization(data, reporter);
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000294 }
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000295
296 // Test invalid deserializations
297 {
298 SkBitmap validBitmap;
299 validBitmap.setConfig(SkBitmap::kARGB_8888_Config, 256, 256);
300
301 // Create a bitmap with a really large height
302 SkBitmap invalidBitmap;
303 invalidBitmap.setConfig(SkBitmap::kARGB_8888_Config, 256, 1000000000);
304
305 // The deserialization should succeed, and the rendering shouldn't crash,
306 // even when the device fails to initialize, due to its size
307 TestBitmapSerialization(validBitmap, invalidBitmap, true, reporter);
308
309 // Create a bitmap with a pixel ref too small
310 SkBitmap invalidBitmap2;
311 invalidBitmap2.setConfig(SkBitmap::kARGB_8888_Config, 256, 256);
312 invalidBitmap2.setPixelRef(SkNEW_ARGS(SkMallocPixelRef,
313 (NULL, 256, NULL)))->unref();
314
315 // The deserialization should detect the pixel ref being too small and fail
316 TestBitmapSerialization(validBitmap, invalidBitmap2, false, reporter);
317 }
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000318}
319
320#include "TestClassDef.h"
321DEFINE_TESTCLASS("Serialization", SerializationClass, Tests)