static void TestObjectSerializationNoAlign(T* testObj, skiatest::Reporter* reporter) { SkBinaryWriteBuffer writer; SerializationUtils<T>::Write(writer, testObj); size_t bytesWritten = writer.bytesWritten(); REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten); unsigned char dataWritten[1024]; writer.writeToMemory(dataWritten); SerializationTestUtils<T, testInvalid>::InvalidateData(dataWritten); // Make sure this fails when it should (test with smaller size, but still multiple of 4) SkReadBuffer buffer(dataWritten, bytesWritten - 4); T obj; SerializationUtils<T>::Read(buffer, &obj); REPORTER_ASSERT(reporter, !buffer.isValid()); // Make sure this succeeds when it should SkReadBuffer buffer2(dataWritten, bytesWritten); size_t offsetBefore = buffer2.offset(); T obj2; SerializationUtils<T>::Read(buffer2, &obj2); size_t offsetAfter = buffer2.offset(); // This should have succeeded, since there are enough bytes to read this REPORTER_ASSERT(reporter, buffer2.isValid() == !testInvalid); // Note: This following test should always succeed, regardless of whether the buffer is valid, // since if it is invalid, it will simply skip to the end, as if it had read the whole buffer. REPORTER_ASSERT(reporter, offsetAfter - offsetBefore == bytesWritten); }
sk_sp<SkData> SkFlattenable::serialize(const SkSerialProcs* procs) const { SkBinaryWriteBuffer writer; if (procs) { writer.setSerialProcs(*procs); } writer.writeFlattenable(this); size_t size = writer.bytesWritten(); auto data = SkData::MakeUninitialized(size); writer.writeToMemory(data->writable_data()); return data; }
static sk_sp<SkColorFilter> reincarnate_colorfilter(SkFlattenable* obj) { SkBinaryWriteBuffer wb; wb.writeFlattenable(obj); size_t size = wb.bytesWritten(); SkAutoSMalloc<1024> storage(size); // make a copy into storage wb.writeToMemory(storage.get()); SkReadBuffer rb(storage.get(), size); return rb.readColorFilter(); }
DEF_TEST(FlattenDrawable, r) { // Create and serialize the test drawable sk_sp<SkDrawable> drawable(new IntDrawable(1, 2, 3, 4)); SkPaint paint; paint.setColor(SK_ColorBLUE); sk_sp<RootDrawable> root(new RootDrawable(5, 6, 7, 8, paint, 9, 10, 11, 12, drawable.get())); SkBinaryWriteBuffer writeBuffer; writeBuffer.writeFlattenable(root.get()); // Copy the contents of the write buffer into a read buffer sk_sp<SkData> data = SkData::MakeUninitialized(writeBuffer.bytesWritten()); writeBuffer.writeToMemory(data->writable_data()); SkReadBuffer readBuffer(data->data(), data->size()); register_test_drawables(readBuffer); // Deserialize and verify the drawable sk_sp<SkDrawable> out((SkDrawable*)readBuffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); REPORTER_ASSERT(r, out); REPORTER_ASSERT(r, !strcmp("RootDrawable", out->getTypeName())); RootDrawable* rootOut = (RootDrawable*) out.get(); REPORTER_ASSERT(r, 5 == rootOut->compoundDrawable()->intDrawable()->a()); REPORTER_ASSERT(r, 6 == rootOut->compoundDrawable()->intDrawable()->b()); REPORTER_ASSERT(r, 7 == rootOut->compoundDrawable()->intDrawable()->c()); REPORTER_ASSERT(r, 8 == rootOut->compoundDrawable()->intDrawable()->d()); REPORTER_ASSERT(r, SK_ColorBLUE == rootOut->compoundDrawable()->paintDrawable()->paint().getColor()); REPORTER_ASSERT(r, 9 == rootOut->intDrawable()->a()); REPORTER_ASSERT(r, 10 == rootOut->intDrawable()->b()); REPORTER_ASSERT(r, 11 == rootOut->intDrawable()->c()); REPORTER_ASSERT(r, 12 == rootOut->intDrawable()->d()); // Note that we can still recognize the generic drawable as an IntDrawable SkDrawable* generic = rootOut->drawable(); REPORTER_ASSERT(r, !strcmp("IntDrawable", generic->getTypeName())); IntDrawable* integer = (IntDrawable*) generic; REPORTER_ASSERT(r, 1 == integer->a()); REPORTER_ASSERT(r, 2 == integer->b()); REPORTER_ASSERT(r, 3 == integer->c()); REPORTER_ASSERT(r, 4 == integer->d()); }
DEF_TEST(FlattenRecordedDrawable, r) { // Record a set of canvas draw commands SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(1000.0f, 1000.0f); SkPaint paint; paint.setColor(SK_ColorGREEN); canvas->drawPoint(42.0f, 17.0f, paint); paint.setColor(SK_ColorRED); canvas->drawPaint(paint); SkPaint textPaint; textPaint.setColor(SK_ColorBLUE); canvas->drawString("TEXT", 467.0f, 100.0f, textPaint); // Draw some drawables as well sk_sp<SkDrawable> drawable(new IntDrawable(1, 2, 3, 4)); sk_sp<RootDrawable> root(new RootDrawable(5, 6, 7, 8, paint, 9, 10, 11, 12, drawable.get())); canvas->drawDrawable(root.get(), 747.0f, 242.0f); sk_sp<PaintDrawable> paintDrawable(new PaintDrawable(paint)); canvas->drawDrawable(paintDrawable.get(), 500.0, 500.0f); sk_sp<CompoundDrawable> comDrawable(new CompoundDrawable(13, 14, 15, 16, textPaint)); canvas->drawDrawable(comDrawable.get(), 10.0f, 10.0f); // Serialize the recorded drawable sk_sp<SkDrawable> recordedDrawable = recorder.finishRecordingAsDrawable(); SkBinaryWriteBuffer writeBuffer; writeBuffer.writeFlattenable(recordedDrawable.get()); // Copy the contents of the write buffer into a read buffer sk_sp<SkData> data = SkData::MakeUninitialized(writeBuffer.bytesWritten()); writeBuffer.writeToMemory(data->writable_data()); SkReadBuffer readBuffer(data->data(), data->size()); register_test_drawables(readBuffer); // Deserialize and verify the drawable sk_sp<SkDrawable> out((SkDrawable*)readBuffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); REPORTER_ASSERT(r, out); REPORTER_ASSERT(r, !strcmp("SkRecordedDrawable", out->getTypeName())); }
static void TestArraySerialization(T* data, skiatest::Reporter* reporter) { SkBinaryWriteBuffer writer; SerializationUtils<T>::Write(writer, data, kArraySize); size_t bytesWritten = writer.bytesWritten(); // This should write the length (in 4 bytes) and the array REPORTER_ASSERT(reporter, (4 + kArraySize * sizeof(T)) == bytesWritten); unsigned char dataWritten[2048]; writer.writeToMemory(dataWritten); // Make sure this fails when it should SkReadBuffer buffer(dataWritten, bytesWritten); T dataRead[kArraySize]; bool success = SerializationUtils<T>::Read(buffer, dataRead, kArraySize / 2); // This should have failed, since the provided size was too small REPORTER_ASSERT(reporter, !success); // Make sure this succeeds when it should SkReadBuffer buffer2(dataWritten, bytesWritten); success = SerializationUtils<T>::Read(buffer2, dataRead, kArraySize); // This should have succeeded, since there are enough bytes to read this REPORTER_ASSERT(reporter, success); }
static T* TestFlattenableSerialization(T* testObj, bool shouldSucceed, skiatest::Reporter* reporter) { SkBinaryWriteBuffer writer; SerializationUtils<T>::Write(writer, testObj); size_t bytesWritten = writer.bytesWritten(); REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten); SkASSERT(bytesWritten <= 4096); unsigned char dataWritten[4096]; writer.writeToMemory(dataWritten); // Make sure this fails when it should (test with smaller size, but still multiple of 4) SkReadBuffer buffer(dataWritten, bytesWritten - 4); T* obj = nullptr; SerializationUtils<T>::Read(buffer, &obj); REPORTER_ASSERT(reporter, !buffer.isValid()); REPORTER_ASSERT(reporter, nullptr == obj); // Make sure this succeeds when it should SkReadBuffer buffer2(dataWritten, bytesWritten); const unsigned char* peekBefore = static_cast<const unsigned char*>(buffer2.skip(0)); T* obj2 = nullptr; SerializationUtils<T>::Read(buffer2, &obj2); const unsigned char* peekAfter = static_cast<const unsigned char*>(buffer2.skip(0)); if (shouldSucceed) { // This should have succeeded, since there are enough bytes to read this REPORTER_ASSERT(reporter, buffer2.isValid()); REPORTER_ASSERT(reporter, static_cast<size_t>(peekAfter - peekBefore) == bytesWritten); REPORTER_ASSERT(reporter, obj2); } else { // If the deserialization was supposed to fail, make sure it did REPORTER_ASSERT(reporter, !buffer.isValid()); REPORTER_ASSERT(reporter, nullptr == obj2); } return obj2; // Return object to perform further validity tests on it }
DEF_TEST(UnflattenWithCustomFactory, r) { // Create and flatten the test flattenable SkBinaryWriteBuffer writeBuffer; sk_sp<SkFlattenable> flattenable1(new IntFlattenable(1, 2, 3, 4)); writeBuffer.writeFlattenable(flattenable1.get()); sk_sp<SkFlattenable> flattenable2(new IntFlattenable(2, 3, 4, 5)); writeBuffer.writeFlattenable(flattenable2.get()); sk_sp<SkFlattenable> flattenable3(new IntFlattenable(3, 4, 5, 6)); writeBuffer.writeFlattenable(flattenable3.get()); // Copy the contents of the write buffer into a read buffer sk_sp<SkData> data = SkData::MakeUninitialized(writeBuffer.bytesWritten()); writeBuffer.writeToMemory(data->writable_data()); SkReadBuffer readBuffer(data->data(), data->size()); // Register a custom factory with the read buffer readBuffer.setCustomFactory(SkString("IntFlattenable"), &custom_create_proc); // Unflatten and verify the flattenables sk_sp<IntFlattenable> out1((IntFlattenable*) readBuffer.readFlattenable( SkFlattenable::kSkUnused_Type)); REPORTER_ASSERT(r, out1); REPORTER_ASSERT(r, 2 == out1->a()); REPORTER_ASSERT(r, 3 == out1->b()); REPORTER_ASSERT(r, 4 == out1->c()); REPORTER_ASSERT(r, 5 == out1->d()); sk_sp<IntFlattenable> out2((IntFlattenable*) readBuffer.readFlattenable( SkFlattenable::kSkUnused_Type)); REPORTER_ASSERT(r, out2); REPORTER_ASSERT(r, 3 == out2->a()); REPORTER_ASSERT(r, 4 == out2->b()); REPORTER_ASSERT(r, 5 == out2->c()); REPORTER_ASSERT(r, 6 == out2->d()); sk_sp<IntFlattenable> out3((IntFlattenable*) readBuffer.readFlattenable( SkFlattenable::kSkUnused_Type)); REPORTER_ASSERT(r, out3); REPORTER_ASSERT(r, 4 == out3->a()); REPORTER_ASSERT(r, 5 == out3->b()); REPORTER_ASSERT(r, 6 == out3->c()); REPORTER_ASSERT(r, 7 == out3->d()); }
DEF_TEST(Serialization, reporter) { // Test matrix serialization { SkMatrix matrix = SkMatrix::I(); TestObjectSerialization(&matrix, reporter); } // Test path serialization { SkPath path; TestObjectSerialization(&path, reporter); } // Test region serialization { SkRegion region; TestObjectSerialization(®ion, reporter); } // Test color filter serialization { TestColorFilterSerialization(reporter); } // Test string serialization { SkString string("string"); TestObjectSerializationNoAlign<SkString, false>(&string, reporter); TestObjectSerializationNoAlign<SkString, true>(&string, reporter); } // Test rrect serialization { // SkRRect does not initialize anything. // An uninitialized SkRRect can be serialized, // but will branch on uninitialized data when deserialized. SkRRect rrect; SkRect rect = SkRect::MakeXYWH(1, 2, 20, 30); SkVector corners[4] = { {1, 2}, {2, 3}, {3,4}, {4,5} }; rrect.setRectRadii(rect, corners); SerializationTest::TestAlignment(&rrect, reporter); } // Test readByteArray { unsigned char data[kArraySize] = { 1, 2, 3 }; TestArraySerialization(data, reporter); } // Test readColorArray { SkColor data[kArraySize] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorRED }; TestArraySerialization(data, reporter); } // Test readColor4fArray { SkColor4f data[kArraySize] = { SkColor4f::FromColor(SK_ColorBLACK), SkColor4f::FromColor(SK_ColorWHITE), SkColor4f::FromColor(SK_ColorRED), { 1.f, 2.f, 4.f, 8.f } }; TestArraySerialization(data, reporter); } // Test readIntArray { int32_t data[kArraySize] = { 1, 2, 4, 8 }; TestArraySerialization(data, reporter); } // Test readPointArray { SkPoint data[kArraySize] = { {6, 7}, {42, 128} }; TestArraySerialization(data, reporter); } // Test readScalarArray { SkScalar data[kArraySize] = { SK_Scalar1, SK_ScalarHalf, SK_ScalarMax }; TestArraySerialization(data, reporter); } // Test invalid deserializations { SkImageInfo info = SkImageInfo::MakeN32Premul(kBitmapSize, kBitmapSize); SkBitmap validBitmap; validBitmap.setInfo(info); // Create a bitmap with a really large height SkBitmap invalidBitmap; invalidBitmap.setInfo(info.makeWH(info.width(), 1000000000)); // The deserialization should succeed, and the rendering shouldn't crash, // even when the device fails to initialize, due to its size TestBitmapSerialization(validBitmap, invalidBitmap, true, reporter); } // Test simple SkPicture serialization { SkPictureRecorder recorder; draw_something(recorder.beginRecording(SkIntToScalar(kBitmapSize), SkIntToScalar(kBitmapSize), nullptr, 0)); sk_sp<SkPicture> pict(recorder.finishRecordingAsPicture()); // Serialize picture SkBinaryWriteBuffer writer; pict->flatten(writer); size_t size = writer.bytesWritten(); SkAutoTMalloc<unsigned char> data(size); writer.writeToMemory(static_cast<void*>(data.get())); // Deserialize picture SkReadBuffer reader(static_cast<void*>(data.get()), size); sk_sp<SkPicture> readPict(SkPicture::MakeFromBuffer(reader)); REPORTER_ASSERT(reporter, reader.isValid()); REPORTER_ASSERT(reporter, readPict.get()); } TestPictureTypefaceSerialization(reporter); }
DEF_TEST(Serialization, reporter) { // Test matrix serialization { SkMatrix matrix = SkMatrix::I(); TestObjectSerialization(&matrix, reporter); } // Test path serialization { SkPath path; TestObjectSerialization(&path, reporter); } // Test region serialization { SkRegion region; TestObjectSerialization(®ion, reporter); } // Test xfermode serialization { TestXfermodeSerialization(reporter); } // Test color filter serialization { TestColorFilterSerialization(reporter); } // Test string serialization { SkString string("string"); TestObjectSerializationNoAlign<SkString, false>(&string, reporter); TestObjectSerializationNoAlign<SkString, true>(&string, reporter); } // Test rrect serialization { // SkRRect does not initialize anything. // An uninitialized SkRRect can be serialized, // but will branch on uninitialized data when deserialized. SkRRect rrect; SkRect rect = SkRect::MakeXYWH(1, 2, 20, 30); SkVector corners[4] = { {1, 2}, {2, 3}, {3,4}, {4,5} }; rrect.setRectRadii(rect, corners); TestAlignment(&rrect, reporter); } // Test readByteArray { unsigned char data[kArraySize] = { 1, 2, 3 }; TestArraySerialization(data, reporter); } // Test readColorArray { SkColor data[kArraySize] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorRED }; TestArraySerialization(data, reporter); } // Test readIntArray { int32_t data[kArraySize] = { 1, 2, 4, 8 }; TestArraySerialization(data, reporter); } // Test readPointArray { SkPoint data[kArraySize] = { {6, 7}, {42, 128} }; TestArraySerialization(data, reporter); } // Test readScalarArray { SkScalar data[kArraySize] = { SK_Scalar1, SK_ScalarHalf, SK_ScalarMax }; TestArraySerialization(data, reporter); } // Test invalid deserializations { SkImageInfo info = SkImageInfo::MakeN32Premul(kBitmapSize, kBitmapSize); SkBitmap validBitmap; validBitmap.setInfo(info); // Create a bitmap with a really large height SkBitmap invalidBitmap; invalidBitmap.setInfo(info.makeWH(info.width(), 1000000000)); // The deserialization should succeed, and the rendering shouldn't crash, // even when the device fails to initialize, due to its size TestBitmapSerialization(validBitmap, invalidBitmap, true, reporter); } // Test simple SkPicture serialization { SkPictureRecorder recorder; draw_something(recorder.beginRecording(SkIntToScalar(kBitmapSize), SkIntToScalar(kBitmapSize), nullptr, 0)); sk_sp<SkPicture> pict(recorder.finishRecordingAsPicture()); // Serialize picture SkBinaryWriteBuffer writer; pict->flatten(writer); size_t size = writer.bytesWritten(); SkAutoTMalloc<unsigned char> data(size); writer.writeToMemory(static_cast<void*>(data.get())); // Deserialize picture SkValidatingReadBuffer reader(static_cast<void*>(data.get()), size); sk_sp<SkPicture> readPict(SkPicture::MakeFromBuffer(reader)); REPORTER_ASSERT(reporter, readPict.get()); } TestPictureTypefaceSerialization(reporter); // Test SkLightingShader/NormalMapSource serialization { const int kTexSize = 2; SkLights::Builder builder; builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f), SkVector3::Make(1.0f, 0.0f, 0.0f))); builder.add(SkLights::Light(SkColor3f::Make(0.2f, 0.2f, 0.2f))); sk_sp<SkLights> fLights = builder.finish(); SkBitmap diffuse = sk_tool_utils::create_checkerboard_bitmap( kTexSize, kTexSize, sk_tool_utils::color_to_565(0x0), sk_tool_utils::color_to_565(0xFF804020), 8); SkRect bitmapBounds = SkRect::MakeIWH(diffuse.width(), diffuse.height()); SkMatrix matrix; SkRect r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize)); matrix.setRectToRect(bitmapBounds, r, SkMatrix::kFill_ScaleToFit); SkMatrix ctm; ctm.setRotate(45); SkBitmap normals; normals.allocN32Pixels(kTexSize, kTexSize); sk_tool_utils::create_frustum_normal_map(&normals, SkIRect::MakeWH(kTexSize, kTexSize)); sk_sp<SkShader> normalMap = SkShader::MakeBitmapShader(normals, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, &matrix); sk_sp<SkNormalSource> normalSource = SkNormalSource::MakeFromNormalMap(std::move(normalMap), ctm); sk_sp<SkShader> diffuseShader = SkShader::MakeBitmapShader(diffuse, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, &matrix); sk_sp<SkShader> lightingShader = SkLightingShader::Make(diffuseShader, normalSource, fLights); SkAutoTUnref<SkShader>(TestFlattenableSerialization(lightingShader.get(), true, reporter)); lightingShader = SkLightingShader::Make(std::move(diffuseShader), nullptr, fLights); SkAutoTUnref<SkShader>(TestFlattenableSerialization(lightingShader.get(), true, reporter)); lightingShader = SkLightingShader::Make(nullptr, std::move(normalSource), fLights); SkAutoTUnref<SkShader>(TestFlattenableSerialization(lightingShader.get(), true, reporter)); lightingShader = SkLightingShader::Make(nullptr, nullptr, fLights); SkAutoTUnref<SkShader>(TestFlattenableSerialization(lightingShader.get(), true, reporter)); } // Test NormalBevelSource serialization { sk_sp<SkNormalSource> bevelSource = SkNormalSource::MakeBevel( SkNormalSource::BevelType::kLinear, 2.0f, 5.0f); SkAutoTUnref<SkNormalSource>(TestFlattenableSerialization(bevelSource.get(), true, reporter)); // TODO test equality? } }