Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SerializationTest.cpp
Go to the documentation of this file.
1/*
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
14#include "include/core/SkData.h"
16#include "include/core/SkFont.h"
26#include "include/core/SkPath.h"
33#include "include/core/SkRect.h"
58#include "tests/Test.h"
59#include "tools/Resources.h"
60#include "tools/ToolUtils.h"
62
63#include <algorithm>
64#include <array>
65#include <cstdint>
66#include <cstring>
67#include <memory>
68#include <utility>
69
70using namespace skia_private;
71
72static const uint32_t kArraySize = 64;
73static const int kBitmapSize = 256;
74
76public:
77
78template<typename T>
79static void TestAlignment(T* testObj, skiatest::Reporter* reporter) {
80 // Test memory read/write functions directly
81 unsigned char dataWritten[1024];
82 size_t bytesWrittenToMemory = testObj->writeToMemory(dataWritten);
83 REPORTER_ASSERT(reporter, SkAlign4(bytesWrittenToMemory) == bytesWrittenToMemory);
84 size_t bytesReadFromMemory = testObj->readFromMemory(dataWritten, bytesWrittenToMemory);
85 REPORTER_ASSERT(reporter, SkAlign4(bytesReadFromMemory) == bytesReadFromMemory);
86}
87};
88
89template<typename T> struct SerializationUtils {
90 // Generic case for flattenables
91 static void Write(SkWriteBuffer& writer, const T* flattenable) {
92 writer.writeFlattenable(flattenable);
93 }
94 static void Read(SkReadBuffer& reader, T** flattenable) {
95 *flattenable = (T*)reader.readFlattenable(T::GetFlattenableType());
96 }
97};
98
99template<> struct SerializationUtils<SkMatrix> {
100 static void Write(SkWriteBuffer& writer, const SkMatrix* matrix) {
101 writer.writeMatrix(*matrix);
102 }
103 static void Read(SkReadBuffer& reader, SkMatrix* matrix) {
104 reader.readMatrix(matrix);
105 }
106};
107
108template<> struct SerializationUtils<SkPath> {
109 static void Write(SkWriteBuffer& writer, const SkPath* path) {
110 writer.writePath(*path);
111 }
112 static void Read(SkReadBuffer& reader, SkPath* path) {
113 reader.readPath(path);
114 }
115};
116
117template<> struct SerializationUtils<SkRegion> {
118 static void Write(SkWriteBuffer& writer, const SkRegion* region) {
119 writer.writeRegion(*region);
120 }
121 static void Read(SkReadBuffer& reader, SkRegion* region) {
122 reader.readRegion(region);
123 }
124};
125
126template<> struct SerializationUtils<SkString> {
127 static void Write(SkWriteBuffer& writer, const SkString* string) {
128 writer.writeString(string->c_str());
129 }
130 static void Read(SkReadBuffer& reader, SkString* string) {
131 reader.readString(string);
132 }
133};
134
135template<> struct SerializationUtils<unsigned char> {
136 static void Write(SkWriteBuffer& writer, unsigned char* data, uint32_t arraySize) {
137 writer.writeByteArray(data, arraySize);
138 }
139 static bool Read(SkReadBuffer& reader, unsigned char* data, uint32_t arraySize) {
140 return reader.readByteArray(data, arraySize);
141 }
142};
143
144template<> struct SerializationUtils<SkColor> {
145 static void Write(SkWriteBuffer& writer, SkColor* data, uint32_t arraySize) {
146 writer.writeColorArray(data, arraySize);
147 }
148 static bool Read(SkReadBuffer& reader, SkColor* data, uint32_t arraySize) {
149 return reader.readColorArray(data, arraySize);
150 }
151};
152
153template<> struct SerializationUtils<SkColor4f> {
154 static void Write(SkWriteBuffer& writer, SkColor4f* data, uint32_t arraySize) {
155 writer.writeColor4fArray(data, arraySize);
156 }
157 static bool Read(SkReadBuffer& reader, SkColor4f* data, uint32_t arraySize) {
158 return reader.readColor4fArray(data, arraySize);
159 }
160};
161
162template<> struct SerializationUtils<int32_t> {
163 static void Write(SkWriteBuffer& writer, int32_t* data, uint32_t arraySize) {
164 writer.writeIntArray(data, arraySize);
165 }
166 static bool Read(SkReadBuffer& reader, int32_t* data, uint32_t arraySize) {
167 return reader.readIntArray(data, arraySize);
168 }
169};
170
171template<> struct SerializationUtils<SkPoint> {
172 static void Write(SkWriteBuffer& writer, SkPoint* data, uint32_t arraySize) {
173 writer.writePointArray(data, arraySize);
174 }
175 static bool Read(SkReadBuffer& reader, SkPoint* data, uint32_t arraySize) {
176 return reader.readPointArray(data, arraySize);
177 }
178};
179
180template<> struct SerializationUtils<SkPoint3> {
181 static void Write(SkWriteBuffer& writer, const SkPoint3* data) {
182 writer.writePoint3(*data);
183 }
184 static void Read(SkReadBuffer& reader, SkPoint3* data) {
185 reader.readPoint3(data);
186 }
187};
188
189template<> struct SerializationUtils<SkScalar> {
190 static void Write(SkWriteBuffer& writer, SkScalar* data, uint32_t arraySize) {
191 writer.writeScalarArray(data, arraySize);
192 }
193 static bool Read(SkReadBuffer& reader, SkScalar* data, uint32_t arraySize) {
194 return reader.readScalarArray(data, arraySize);
195 }
196};
197
198template<typename T, bool testInvalid> struct SerializationTestUtils {
199 static void InvalidateData(unsigned char* data) {}
200};
201
203 static void InvalidateData(unsigned char* data) {
204 data[3] |= 0x80; // Reverse sign of 1st integer
205 }
206};
207
208template<typename T, bool testInvalid>
210 SkBinaryWriteBuffer writer({});
211 SerializationUtils<T>::Write(writer, testObj);
212 size_t bytesWritten = writer.bytesWritten();
213 REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten);
214
215 unsigned char dataWritten[1024];
216 writer.writeToMemory(dataWritten);
217
219
220 // Make sure this fails when it should (test with smaller size, but still multiple of 4)
221 SkReadBuffer buffer(dataWritten, bytesWritten - 4);
222 T obj;
224 REPORTER_ASSERT(reporter, !buffer.isValid());
225
226 // Make sure this succeeds when it should
227 SkReadBuffer buffer2(dataWritten, bytesWritten);
228 size_t offsetBefore = buffer2.offset();
229 T obj2;
230 SerializationUtils<T>::Read(buffer2, &obj2);
231 size_t offsetAfter = buffer2.offset();
232 // This should have succeeded, since there are enough bytes to read this
233 REPORTER_ASSERT(reporter, buffer2.isValid() == !testInvalid);
234 // Note: This following test should always succeed, regardless of whether the buffer is valid,
235 // since if it is invalid, it will simply skip to the end, as if it had read the whole buffer.
236 REPORTER_ASSERT(reporter, offsetAfter - offsetBefore == bytesWritten);
237}
238
239template<typename T>
241 TestObjectSerializationNoAlign<T, false>(testObj, reporter);
243}
244
245template<typename T>
246static T* TestFlattenableSerialization(T* testObj, bool shouldSucceed,
248 SkBinaryWriteBuffer writer({});
249 SerializationUtils<T>::Write(writer, testObj);
250 size_t bytesWritten = writer.bytesWritten();
251 REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten);
252
253 SkASSERT(bytesWritten <= 4096);
254 unsigned char dataWritten[4096];
255 writer.writeToMemory(dataWritten);
256
257 // Make sure this fails when it should (test with smaller size, but still multiple of 4)
258 SkReadBuffer buffer(dataWritten, bytesWritten - 4);
259 T* obj = nullptr;
261 REPORTER_ASSERT(reporter, !buffer.isValid());
262 REPORTER_ASSERT(reporter, nullptr == obj);
263
264 // Make sure this succeeds when it should
265 SkReadBuffer buffer2(dataWritten, bytesWritten);
266 const unsigned char* peekBefore = static_cast<const unsigned char*>(buffer2.skip(0));
267 T* obj2 = nullptr;
268 SerializationUtils<T>::Read(buffer2, &obj2);
269 const unsigned char* peekAfter = static_cast<const unsigned char*>(buffer2.skip(0));
270 if (shouldSucceed) {
271 // This should have succeeded, since there are enough bytes to read this
272 REPORTER_ASSERT(reporter, buffer2.isValid());
273 REPORTER_ASSERT(reporter, static_cast<size_t>(peekAfter - peekBefore) == bytesWritten);
275 } else {
276 // If the deserialization was supposed to fail, make sure it did
277 REPORTER_ASSERT(reporter, !buffer.isValid());
278 REPORTER_ASSERT(reporter, nullptr == obj2);
279 }
280
281 return obj2; // Return object to perform further validity tests on it
282}
283
284template<typename T>
286 SkBinaryWriteBuffer writer({});
288 size_t bytesWritten = writer.bytesWritten();
289 // This should write the length (in 4 bytes) and the array
290 REPORTER_ASSERT(reporter, (4 + kArraySize * sizeof(T)) == bytesWritten);
291
292 unsigned char dataWritten[2048];
293 writer.writeToMemory(dataWritten);
294
295 // Make sure this fails when it should
296 SkReadBuffer buffer(dataWritten, bytesWritten);
297 T dataRead[kArraySize];
298 bool success = SerializationUtils<T>::Read(buffer, dataRead, kArraySize / 2);
299 // This should have failed, since the provided size was too small
300 REPORTER_ASSERT(reporter, !success);
301
302 // Make sure this succeeds when it should
303 SkReadBuffer buffer2(dataWritten, bytesWritten);
304 success = SerializationUtils<T>::Read(buffer2, dataRead, kArraySize);
305 // This should have succeeded, since there are enough bytes to read this
306 REPORTER_ASSERT(reporter, success);
307}
308
309static void TestBitmapSerialization(const SkBitmap& validBitmap,
310 const SkBitmap& invalidBitmap,
311 bool shouldSucceed,
313 sk_sp<SkImage> validImage(validBitmap.asImage());
314 sk_sp<SkImageFilter> validBitmapSource(SkImageFilters::Image(std::move(validImage),
316 sk_sp<SkImage> invalidImage(invalidBitmap.asImage());
317 sk_sp<SkImageFilter> invalidBitmapSource(SkImageFilters::Image(std::move(invalidImage),
319 sk_sp<SkImageFilter> xfermodeImageFilter(
321 std::move(invalidBitmapSource),
322 std::move(validBitmapSource), nullptr));
323
324 sk_sp<SkImageFilter> deserializedFilter(
325 TestFlattenableSerialization<SkImageFilter_Base>(
326 (SkImageFilter_Base*)xfermodeImageFilter.get(), shouldSucceed, reporter));
327
328 // Try to render a small bitmap using the invalid deserialized filter
329 // to make sure we don't crash while trying to render it
330 if (shouldSucceed) {
332 bitmap.allocN32Pixels(24, 24);
333 SkCanvas canvas(bitmap);
334 canvas.clear(0x00000000);
336 paint.setImageFilter(deserializedFilter);
338 canvas.drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);
339 }
340}
341
343 uint8_t table[256];
344 for (int i = 0; i < 256; ++i) {
345 table[i] = (i * 41) % 256;
346 }
347 auto filter = SkColorFilters::Table(table);
349 TestFlattenableSerialization(as_CFB(filter.get()), true, reporter));
350}
351
354 bitmap.allocN32Pixels(SkScalarCeilToInt(picture.cullRect().width()),
355 SkScalarCeilToInt(picture.cullRect().height()));
356 SkCanvas canvas(bitmap);
357 picture.playback(&canvas);
358 return bitmap;
359}
360
362 const SkBitmap& b1, const SkBitmap& b2) {
363 REPORTER_ASSERT(reporter, b1.width() == b2.width());
364 REPORTER_ASSERT(reporter, b1.height() == b2.height());
365
366 if ((b1.width() != b2.width()) ||
367 (b1.height() != b2.height())) {
368 return;
369 }
370
371 int pixelErrors = 0;
372 for (int y = 0; y < b2.height(); ++y) {
373 for (int x = 0; x < b2.width(); ++x) {
374 if (b1.getColor(x, y) != b2.getColor(x, y))
375 ++pixelErrors;
376 }
377 }
378 REPORTER_ASSERT(reporter, 0 == pixelErrors);
379}
380
382 // Write out typeface ID followed by entire typeface.
385 uint32_t typeface_id = typeface->uniqueID();
386 stream.write(&typeface_id, sizeof(typeface_id));
387 stream.write(data->data(), data->size());
388 return stream.detachAsData();
389}
390
391static sk_sp<SkTypeface> deserialize_typeface_proc(const void* data, size_t length, void* ctx) {
392 SkStream* stream;
393 if (length < sizeof(stream)) {
394 return nullptr;
395 }
396 memcpy(&stream, data, sizeof(stream));
397
399 if (!stream->read(&id, sizeof(id))) {
400 return nullptr;
401 }
402
404 return typeface;
405}
406
408 const char* text,
409 const SkSerialProcs* serial_procs,
410 const SkDeserialProcs* deserial_procs,
412 // Create a font with the typeface.
414 paint.setColor(SK_ColorGRAY);
415 SkFont font(std::move(typeface), 30);
416
417 // Paint some text.
418 SkPictureRecorder recorder;
420 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(canvasRect.width()),
421 SkIntToScalar(canvasRect.height()));
422 canvas->drawColor(SK_ColorWHITE);
423 canvas->drawString(text, 24, 32, font, paint);
424 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
425
426 // Serlialize picture and create its clone from stream.
428 picture->serialize(&stream, serial_procs);
429 std::unique_ptr<SkStream> inputStream(stream.detachAsStream());
430 sk_sp<SkPicture> loadedPicture(SkPicture::MakeFromStream(inputStream.get(), deserial_procs));
431
432 // Draw both original and clone picture and compare bitmaps -- they should be identical.
433 SkBitmap origBitmap = draw_picture(*picture);
434 SkBitmap destBitmap = draw_picture(*loadedPicture);
435 compare_bitmaps(reporter, origBitmap, destBitmap);
436}
437
439 std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
440 if (!distortable) {
441 REPORT_FAILURE(reporter, "distortable", SkString());
442 return nullptr;
443 }
444
446 { SkSetFourByteTag('w','g','h','t'), SK_ScalarSqrt2 },
447 };
449 params.setVariationDesignPosition({position, std::size(position)});
450
452
453 sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(distortable), params);
454 if (!typeface) {
455 return nullptr; // Not all SkFontMgr can makeFromStream().
456 }
457
458 int count = typeface->getVariationDesignPosition(nullptr, 0);
459 if (count == -1) {
460 return nullptr; // The number of axes is unknown.
461 }
462
463 return typeface;
464}
465
466static void TestPictureTypefaceSerialization(const SkSerialProcs* serial_procs,
467 const SkDeserialProcs* deserial_procs,
469 {
470 // Load typeface from file to test CreateFromFile with index.
471 auto typeface = ToolUtils::CreateTypefaceFromResource("fonts/test.ttc", 1);
472 if (!typeface) {
473 INFOF(reporter, "Could not run fontstream test because test.ttc not found.");
474 } else {
475 serialize_and_compare_typeface(std::move(typeface), "A!", serial_procs, deserial_procs,
476 reporter);
477 }
478 }
479
480 {
481 // Load typeface as stream to create with axis settings.
483 if (!typeface) {
484 INFOF(reporter, "Could not run fontstream test because Distortable.ttf not created.");
485 } else {
486 serialize_and_compare_typeface(std::move(typeface), "ab", serial_procs,
487 deserial_procs, reporter);
488 }
489 }
490}
491
493 int index;
494 std::unique_ptr<SkStreamAsset> typefaceStream = typeface.openStream(&index);
495 if (!typefaceStream) {
496 return SkString("No Stream");
497 }
498 size_t length = typefaceStream->getLength();
499
500 SkString s;
501 s.appendf("Index: %d\n", index);
502 s.appendf("Length: %zu\n", length);
503 return s;
504}
506 SkString m("Flags:\n");
507
508 if (metrics.fFlags == 0) {
509 m += " No flags\n";
510 } else {
512 m += " UnderlineThicknessIsValid\n";
513 }
515 m += " kUnderlinePositionIsValid\n";
516 }
518 m += " kStrikeoutThicknessIsValid\n";
519 }
521 m += " kStrikeoutPositionIsValid\n";
522 }
524 m += " kBoundsInvalid\n";
525 }
526 }
527
528 m.appendf("Top: %f\n", metrics.fTop);
529 m.appendf("Ascent: %f\n", metrics.fAscent);
530 m.appendf("Descent: %f\n", metrics.fDescent);
531 m.appendf("Bottom: %f\n", metrics.fBottom);
532 m.appendf("Leading: %f\n", metrics.fLeading);
533 m.appendf("AvgCharWidth: %f\n", metrics.fAvgCharWidth);
534 m.appendf("MaxCharWidth: %f\n", metrics.fMaxCharWidth);
535 m.appendf("XMin: %f\n", metrics.fXMin);
536 m.appendf("XMax: %f\n", metrics.fXMax);
537 m.appendf("XHeight: %f\n", metrics.fXHeight);
538 m.appendf("CapHeight: %f\n", metrics.fCapHeight);
539 m.appendf("UnderlineThickness: %f\n", metrics.fUnderlineThickness);
540 m.appendf("UnderlinePosition: %f\n", metrics.fUnderlinePosition);
541 m.appendf("StrikeoutThickness: %f\n", metrics.fStrikeoutThickness);
542 m.appendf("StrikeoutPosition: %f\n", metrics.fStrikeoutPosition);
543 return m;
544}
546 const sk_sp<SkTypeface>& typeface) {
547 SkDynamicMemoryWStream typefaceWStream;
548 typeface->serialize(&typefaceWStream);
549
550 std::unique_ptr<SkStream> typefaceStream = typefaceWStream.detachAsStream();
551 sk_sp<SkTypeface> cloneTypeface =
553 SkASSERT(cloneTypeface);
554
555 SkString name, cloneName;
556 typeface->getFamilyName(&name);
557 cloneTypeface->getFamilyName(&cloneName);
558
559 REPORTER_ASSERT(reporter, typeface->countGlyphs() == cloneTypeface->countGlyphs(),
560 "Typeface: \"%s\" CloneTypeface: \"%s\"", name.c_str(), cloneName.c_str());
561 REPORTER_ASSERT(reporter, typeface->fontStyle() == cloneTypeface->fontStyle(),
562 "Typeface: \"%s\" CloneTypeface: \"%s\"", name.c_str(), cloneName.c_str());
563
564 SkFont font(typeface, 12);
565 SkFont clone(cloneTypeface, 12);
566 SkFontMetrics fontMetrics, cloneMetrics;
567 font.getMetrics(&fontMetrics);
568 clone.getMetrics(&cloneMetrics);
569 REPORTER_ASSERT(reporter, fontMetrics == cloneMetrics,
570 "Typeface: \"%s\"\n-Metrics---\n%s-Data---\n%s\n\n"
571 "CloneTypeface: \"%s\"\n-Metrics---\n%s-Data---\n%s",
572 name.c_str(),
573 DumpFontMetrics(fontMetrics).c_str(),
574 DumpTypeface(*typeface).c_str(),
575 cloneName.c_str(),
576 DumpFontMetrics(cloneMetrics).c_str(),
577 DumpTypeface(*cloneTypeface).c_str());
578}
583
585 bitmap->allocN32Pixels(kBitmapSize, kBitmapSize);
586}
587
591
592 SkCanvas canvas(bitmap);
593 canvas.clear(0x00000000);
594 SkPaint darkPaint;
595 darkPaint.setColor(0xFF804020);
596 SkPaint lightPaint;
597 lightPaint.setColor(0xFF244484);
598 const int i = kBitmapSize / 8;
599 const SkScalar f = SkIntToScalar(i);
600 for (int y = 0; y < kBitmapSize; y += i) {
601 for (int x = 0; x < kBitmapSize; x += i) {
602 canvas.save();
604 canvas.drawRect(SkRect::MakeXYWH(0, 0, f, f), darkPaint);
605 canvas.drawRect(SkRect::MakeXYWH(f, 0, f, f), lightPaint);
606 canvas.drawRect(SkRect::MakeXYWH(0, f, f, f), lightPaint);
607 canvas.drawRect(SkRect::MakeXYWH(f, f, f, f), darkPaint);
608 canvas.restore();
609 }
610 }
611 return bitmap.asImage();
612}
613
614static void draw_something(SkCanvas* canvas) {
615 canvas->save();
616 canvas->scale(0.5f, 0.5f);
617 canvas->drawImage(make_checkerboard_image(), 0, 0);
618 canvas->restore();
619
621 paint.setAntiAlias(true);
622 paint.setColor(SK_ColorRED);
624 paint.setColor(SK_ColorBLACK);
625
627 font.setSize(kBitmapSize/3);
628 canvas->drawString("Picture", SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/4), font, paint);
629}
630
633 SkScalarRoundToInt(p.cullRect().width()), SkScalarRoundToInt(p.cullRect().height())));
634 if (!surf) {
635 return nullptr; // bounds are empty?
636 }
637 surf->getCanvas()->clear(SK_ColorWHITE);
638 p.playback(surf->getCanvas());
639 return surf->makeImageSnapshot();
640}
641
642DEF_TEST(Serialization, reporter) {
643 // Test matrix serialization
644 {
645 SkMatrix matrix = SkMatrix::I();
647 }
648
649 // Test point3 serialization
650 {
651 SkPoint3 point;
652 TestObjectSerializationNoAlign<SkPoint3, false>(&point, reporter);
653 }
654
655 // Test path serialization
656 {
657 SkPath path;
659 }
660
661 // Test region serialization
662 {
663 SkRegion region;
665 }
666
667 // Test color filter serialization
668 {
670 }
671
672 // Test string serialization
673 {
674 SkString string("string");
675 TestObjectSerializationNoAlign<SkString, false>(&string, reporter);
676 TestObjectSerializationNoAlign<SkString, true>(&string, reporter);
677 }
678
679 // Test rrect serialization
680 {
681 // SkRRect does not initialize anything.
682 // An uninitialized SkRRect can be serialized,
683 // but will branch on uninitialized data when deserialized.
684 SkRRect rrect;
685 SkRect rect = SkRect::MakeXYWH(1, 2, 20, 30);
686 SkVector corners[4] = { {1, 2}, {2, 3}, {3,4}, {4,5} };
687 rrect.setRectRadii(rect, corners);
689 }
690
691 // Test readByteArray
692 {
693 unsigned char data[kArraySize] = { 1, 2, 3 };
695 }
696
697 // Test readColorArray
698 {
701 }
702
703 // Test readColor4fArray
704 {
705 SkColor4f data[kArraySize] = {
709 { 1.f, 2.f, 4.f, 8.f }
710 };
712 }
713
714 // Test readIntArray
715 {
716 int32_t data[kArraySize] = { 1, 2, 4, 8 };
718 }
719
720 // Test readPointArray
721 {
722 SkPoint data[kArraySize] = { {6, 7}, {42, 128} };
724 }
725
726 // Test readScalarArray
727 {
730 }
731
732 // Test skipByteArray
733 {
734 // Valid case with non-empty array:
735 {
736 unsigned char data[kArraySize] = { 1, 2, 3 };
737 SkBinaryWriteBuffer writer({});
738 writer.writeByteArray(data, kArraySize);
739 SkAutoMalloc buf(writer.bytesWritten());
740 writer.writeToMemory(buf.get());
741
742 SkReadBuffer reader(buf.get(), writer.bytesWritten());
743 size_t len = ~0;
744 const void* arr = reader.skipByteArray(&len);
747 REPORTER_ASSERT(reporter, memcmp(arr, data, len) == 0);
748 }
749
750 // Writing a zero length array (can be detected as valid by non-nullptr return):
751 {
752 SkBinaryWriteBuffer writer({});
753 writer.writeByteArray(nullptr, 0);
754 SkAutoMalloc buf(writer.bytesWritten());
755 writer.writeToMemory(buf.get());
756
757 SkReadBuffer reader(buf.get(), writer.bytesWritten());
758 size_t len = ~0;
759 const void* arr = reader.skipByteArray(&len);
761 REPORTER_ASSERT(reporter, len == 0);
762 }
763
764 // If the array can't be safely read, should return nullptr:
765 {
766 SkBinaryWriteBuffer writer({});
767 writer.writeUInt(kArraySize);
768 SkAutoMalloc buf(writer.bytesWritten());
769 writer.writeToMemory(buf.get());
770
771 SkReadBuffer reader(buf.get(), writer.bytesWritten());
772 size_t len = ~0;
773 const void* arr = reader.skipByteArray(&len);
775 REPORTER_ASSERT(reporter, len == 0);
776 }
777 }
778
779 // Test invalid deserializations
780 {
782
783 SkBitmap validBitmap;
784 validBitmap.setInfo(info);
785
786 // Create a bitmap with a really large height
787 SkBitmap invalidBitmap;
788 invalidBitmap.setInfo(info.makeWH(info.width(), 1000000000));
789
790 // The deserialization should succeed, and the rendering shouldn't crash,
791 // even when the device fails to initialize, due to its size
792 TestBitmapSerialization(validBitmap, invalidBitmap, true, reporter);
793 }
794
795 // Test simple SkPicture serialization
796 {
797 skiatest::ReporterContext subtest(reporter, "simple SkPicture");
798 SkPictureRecorder recorder;
802
803 // Serialize picture. The default typeface proc should result in a non-empty
804 // typeface when deserializing.
805 SkSerialProcs sProcs;
806 sProcs.fImageProc = [](SkImage* img, void*) -> sk_sp<SkData> {
807 return SkPngEncoder::Encode(nullptr, img, SkPngEncoder::Options{});
808 };
809 sk_sp<SkData> data = pict->serialize(&sProcs);
811
812 // Deserialize picture using the default procs.
813 // TODO(kjlubick) Specify a proc for decoding image data.
814 sk_sp<SkPicture> readPict = SkPicture::MakeFromData(data.get());
815 REPORTER_ASSERT(reporter, readPict);
816 sk_sp<SkImage> img0 = render(*pict);
817 sk_sp<SkImage> img1 = render(*readPict);
818 if (img0 && img1) {
819 bool ok = ToolUtils::equal_pixels(img0.get(), img1.get());
820 REPORTER_ASSERT(reporter, ok, "before and after image did not match");
821 if (!ok) {
822 auto left = SkFILEWStream("before_serialize.png");
823 sk_sp<SkData> d = SkPngEncoder::Encode(nullptr, img0.get(), {});
824 left.write(d->data(), d->size());
825 left.fsync();
826 auto right = SkFILEWStream("after_serialize.png");
827 d = SkPngEncoder::Encode(nullptr, img1.get(), {});
828 right.write(d->data(), d->size());
829 right.fsync();
830 }
831 }
832 }
833
835
836 SkSerialProcs serial_procs;
838 SkDeserialProcs deserial_procs;
840 TestPictureTypefaceSerialization(&serial_procs, &deserial_procs, reporter);
841}
842
843///////////////////////////////////////////////////////////////////////////////////////////////////
844
847 src->serialize(&wstream, nullptr); // default is fine, no SkImages to encode
848 std::unique_ptr<SkStreamAsset> rstream(wstream.detachAsStream());
849 return SkPicture::MakeFromStream(rstream.get());
850}
851
854 const char* fKey;
856};
857
859 skiatest::Reporter* fReporter;
860 const AnnotationRec* fRec;
861 int fCount;
862 int fCurrIndex;
863
864public:
866 : SkCanvas(100, 100)
867 , fReporter(reporter)
868 , fRec(rec)
869 , fCount(count)
870 , fCurrIndex(0)
871 {}
872
874 REPORTER_ASSERT(fReporter, fCount == fCurrIndex);
875 }
876
877protected:
878 void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) override {
879 REPORTER_ASSERT(fReporter, fCurrIndex < fCount);
880 REPORTER_ASSERT(fReporter, rect == fRec[fCurrIndex].fRect);
881 REPORTER_ASSERT(fReporter, !strcmp(key, fRec[fCurrIndex].fKey));
882 REPORTER_ASSERT(fReporter, value->equals(fRec[fCurrIndex].fValue.get()));
883 fCurrIndex += 1;
884 }
885};
886
887/*
888 * Test the 3 annotation types by recording them into a picture, serializing, and then playing
889 * them back into another canvas.
890 */
891DEF_TEST(Annotations, reporter) {
892 SkPictureRecorder recorder;
893 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(100, 100));
894
895 const char* str0 = "rect-with-url";
896 const SkRect r0 = SkRect::MakeWH(10, 10);
898 SkAnnotateRectWithURL(recordingCanvas, r0, d0.get());
899
900 const char* str1 = "named-destination";
901 const SkRect r1 = SkRect::MakeXYWH(5, 5, 0, 0); // collapsed to a point
903 SkAnnotateNamedDestination(recordingCanvas, {r1.x(), r1.y()}, d1.get());
904
905 const char* str2 = "link-to-destination";
906 const SkRect r2 = SkRect::MakeXYWH(20, 20, 5, 6);
908 SkAnnotateLinkToDestination(recordingCanvas, r2, d2.get());
909
910 const AnnotationRec recs[] = {
911 { r0, SkAnnotationKeys::URL_Key(), std::move(d0) },
912 { r1, SkAnnotationKeys::Define_Named_Dest_Key(), std::move(d1) },
913 { r2, SkAnnotationKeys::Link_Named_Dest_Key(), std::move(d2) },
914 };
915
918
919 TestAnnotationCanvas canvas(reporter, recs, std::size(recs));
920 canvas.drawPicture(pict1);
921}
922
923DEF_TEST(WriteBuffer_storage, reporter) {
924 enum {
925 kSize = 32
926 };
927 int32_t storage[kSize/4];
928 char src[kSize];
929 sk_bzero(src, kSize);
930
931 SkBinaryWriteBuffer writer(storage, kSize, {});
932 REPORTER_ASSERT(reporter, writer.usingInitialStorage());
933 REPORTER_ASSERT(reporter, writer.bytesWritten() == 0);
934 writer.write(src, kSize - 4);
935 REPORTER_ASSERT(reporter, writer.usingInitialStorage());
936 REPORTER_ASSERT(reporter, writer.bytesWritten() == kSize - 4);
937 writer.writeInt(0);
938 REPORTER_ASSERT(reporter, writer.usingInitialStorage());
939 REPORTER_ASSERT(reporter, writer.bytesWritten() == kSize);
940
941 writer.reset(storage, kSize-4);
942 REPORTER_ASSERT(reporter, writer.usingInitialStorage());
943 REPORTER_ASSERT(reporter, writer.bytesWritten() == 0);
944 writer.write(src, kSize - 4);
945 REPORTER_ASSERT(reporter, writer.usingInitialStorage());
946 REPORTER_ASSERT(reporter, writer.bytesWritten() == kSize - 4);
947 writer.writeInt(0);
948 REPORTER_ASSERT(reporter, !writer.usingInitialStorage()); // this is the change
949 REPORTER_ASSERT(reporter, writer.bytesWritten() == kSize);
950}
951
952DEF_TEST(WriteBuffer_external_memory_textblob, reporter) {
954
955 SkTextBlobBuilder builder;
956 int glyph_count = 5;
957 const auto& run = builder.allocRun(font, glyph_count, 1.2f, 2.3f);
958 // allocRun() allocates only the glyph buffer.
959 std::fill(run.glyphs, run.glyphs + glyph_count, 0);
960 auto blob = builder.make();
961 SkSerialProcs procs;
962 AutoTMalloc<uint8_t> storage;
963 size_t blob_size = 0u;
964 size_t storage_size = 0u;
965
966 blob_size = SkAlign4(blob->serialize(procs)->size());
967 REPORTER_ASSERT(reporter, blob_size > 4u);
968 storage_size = blob_size - 4;
969 storage.realloc(storage_size);
970 REPORTER_ASSERT(reporter, blob->serialize(procs, storage.get(), storage_size) == 0u);
971 storage_size = blob_size;
972 storage.realloc(storage_size);
973 REPORTER_ASSERT(reporter, blob->serialize(procs, storage.get(), storage_size) != 0u);
974}
975
976DEF_TEST(WriteBuffer_external_memory_flattenable, reporter) {
977 SkScalar intervals[] = {1.f, 1.f};
978 auto path_effect = SkDashPathEffect::Make(intervals, 2, 0);
979 size_t path_size = SkAlign4(path_effect->serialize()->size());
980 REPORTER_ASSERT(reporter, path_size > 4u);
981 AutoTMalloc<uint8_t> storage;
982
983 size_t storage_size = path_size - 4;
984 storage.realloc(storage_size);
985 REPORTER_ASSERT(reporter, path_effect->serialize(storage.get(), storage_size) == 0u);
986
987 storage_size = path_size;
988 storage.realloc(storage_size);
989 REPORTER_ASSERT(reporter, path_effect->serialize(storage.get(), storage_size) != 0u);
990}
991
992DEF_TEST(ReadBuffer_empty, reporter) {
993 SkBinaryWriteBuffer writer({});
994 writer.writeInt(123);
995 writer.writeDataAsByteArray(SkData::MakeEmpty().get());
996 writer.writeInt(321);
997
998 size_t size = writer.bytesWritten();
999 SkAutoMalloc storage(size);
1000 writer.writeToMemory(storage.get());
1001
1002 SkReadBuffer reader(storage.get(), size);
1003 REPORTER_ASSERT(reporter, reader.readInt() == 123);
1004 auto data = reader.readByteArrayAsData();
1005 REPORTER_ASSERT(reporter, data->size() == 0);
1006 REPORTER_ASSERT(reporter, reader.readInt() == 321);
1007}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
SkRect fRect
reporter
int count
std::unique_ptr< SkStreamAsset > GetResourceAsStream(const char *resource, bool useFileStream)
Definition Resources.cpp:31
static void TestObjectSerializationNoAlign(T *testObj, skiatest::Reporter *reporter)
static void TestPictureTypefaceSerialization(const SkSerialProcs *serial_procs, const SkDeserialProcs *deserial_procs, skiatest::Reporter *reporter)
static sk_sp< SkPicture > copy_picture_via_serialization(SkPicture *src)
static void setup_bitmap_for_canvas(SkBitmap *bitmap)
static sk_sp< SkTypeface > makeDistortableWithNonDefaultAxes(skiatest::Reporter *reporter)
static void compare_bitmaps(skiatest::Reporter *reporter, const SkBitmap &b1, const SkBitmap &b2)
SkString DumpFontMetrics(const SkFontMetrics &metrics)
static void TestArraySerialization(T *data, skiatest::Reporter *reporter)
static sk_sp< SkImage > make_checkerboard_image()
static void serialize_and_compare_typeface(sk_sp< SkTypeface > typeface, const char *text, const SkSerialProcs *serial_procs, const SkDeserialProcs *deserial_procs, skiatest::Reporter *reporter)
static const int kBitmapSize
static void TestTypefaceSerialization(skiatest::Reporter *reporter, const sk_sp< SkTypeface > &typeface)
static void TestObjectSerialization(T *testObj, skiatest::Reporter *reporter)
static SkBitmap draw_picture(SkPicture &picture)
SkString DumpTypeface(const SkTypeface &typeface)
static const uint32_t kArraySize
static void TestBitmapSerialization(const SkBitmap &validBitmap, const SkBitmap &invalidBitmap, bool shouldSucceed, skiatest::Reporter *reporter)
static sk_sp< SkTypeface > deserialize_typeface_proc(const void *data, size_t length, void *ctx)
static sk_sp< SkImage > render(const SkPicture &p)
static void TestColorFilterSerialization(skiatest::Reporter *reporter)
static sk_sp< SkData > serialize_typeface_proc(SkTypeface *typeface, void *ctx)
static void draw_something(SkCanvas *canvas)
static T * TestFlattenableSerialization(T *testObj, bool shouldSucceed, skiatest::Reporter *reporter)
static constexpr T SkAlign4(T x)
Definition SkAlign.h:16
SK_API void SkAnnotateRectWithURL(SkCanvas *, const SkRect &, SkData *)
SK_API void SkAnnotateNamedDestination(SkCanvas *, const SkPoint &, SkData *)
SK_API void SkAnnotateLinkToDestination(SkCanvas *, const SkRect &, SkData *)
#define SkASSERT(cond)
Definition SkAssert.h:116
@ kSrcOver
r = s + (1-sa)*d
static SkColorFilterBase * as_CFB(SkColorFilter *filter)
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorGRAY
Definition SkColor.h:113
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
static bool ok(int result)
static void sk_bzero(void *buffer, size_t size)
Definition SkMalloc.h:105
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
#define SK_ScalarMax
Definition SkScalar.h:24
#define SK_Scalar1
Definition SkScalar.h:18
#define SK_ScalarHalf
Definition SkScalar.h:19
#define SkScalarRoundToInt(x)
Definition SkScalar.h:37
#define SkScalarCeilToInt(x)
Definition SkScalar.h:36
#define SkIntToScalar(x)
Definition SkScalar.h:57
#define SK_ScalarSqrt2
Definition SkScalar.h:20
uint32_t SkTypefaceID
Definition SkTypeface.h:38
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition SkTypes.h:167
#define DEF_TEST(name, reporter)
Definition Test.h:312
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
#define INFOF(REPORTER,...)
Definition Test.h:298
#define REPORT_FAILURE(reporter, cond, message)
Definition Test.h:90
SI F table(const skcms_Curve *curve, F v)
static void TestAlignment(T *testObj, skiatest::Reporter *reporter)
static const char * Define_Named_Dest_Key()
static const char * Link_Named_Dest_Key()
static const char * URL_Key()
void * get()
void writeByteArray(const void *data, size_t size) override
void writeUInt(uint32_t value) override
void writeInt(int32_t value) override
sk_sp< SkImage > asImage() const
Definition SkBitmap.cpp:645
SkColor getColor(int x, int y) const
Definition SkBitmap.h:874
int width() const
Definition SkBitmap.h:149
bool setInfo(const SkImageInfo &imageInfo, size_t rowBytes=0)
Definition SkBitmap.cpp:114
int height() const
Definition SkBitmap.h:158
void drawRect(const SkRect &rect, const SkPaint &paint)
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
void drawColor(SkColor color, SkBlendMode mode=SkBlendMode::kSrcOver)
Definition SkCanvas.h:1182
void clear(SkColor color)
Definition SkCanvas.h:1199
int save()
Definition SkCanvas.cpp:451
void scale(SkScalar sx, SkScalar sy)
void drawString(const char str[], SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint)
Definition SkCanvas.h:1803
void drawPicture(const SkPicture *picture)
Definition SkCanvas.h:1961
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition SkCanvas.h:1528
void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint &paint)
static sk_sp< SkColorFilter > Table(const uint8_t table[256])
static sk_sp< SkPathEffect > Make(const SkScalar intervals[], int count, SkScalar phase)
static sk_sp< SkData > MakeWithCString(const char cstr[])
Definition SkData.cpp:195
static sk_sp< SkData > MakeEmpty()
Definition SkData.cpp:94
std::unique_ptr< SkStreamAsset > detachAsStream()
Definition SkStream.cpp:876
SkScalar getMetrics(SkFontMetrics *metrics) const
Definition SkFont.cpp:316
static sk_sp< SkImageFilter > Image(sk_sp< SkImage > image, const SkRect &srcRect, const SkRect &dstRect, const SkSamplingOptions &sampling)
static sk_sp< SkImageFilter > Blend(SkBlendMode mode, sk_sp< SkImageFilter > background, sk_sp< SkImageFilter > foreground=nullptr, const CropRect &cropRect={})
static const SkMatrix & I()
void setColor(SkColor color)
Definition SkPaint.cpp:119
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
sk_sp< SkData > serialize(const SkSerialProcs *procs=nullptr) const
static sk_sp< SkPicture > MakeFromData(const SkData *data, const SkDeserialProcs *procs=nullptr)
static sk_sp< SkPicture > MakeFromStream(SkStream *stream, const SkDeserialProcs *procs=nullptr)
void setRectRadii(const SkRect &rect, const SkVector radii[4])
Definition SkRRect.cpp:189
bool readColor4fArray(SkColor4f *colors, size_t size)
const void * skipByteArray(size_t *size)
void readMatrix(SkMatrix *matrix)
SkFlattenable * readFlattenable(SkFlattenable::Type)
bool readByteArray(void *value, size_t size)
bool readIntArray(int32_t *values, size_t size)
bool isValid() const
const void * skip(size_t size)
sk_sp< SkData > readByteArrayAsData()
bool readPointArray(SkPoint *points, size_t size)
int32_t readInt()
void readString(SkString *string)
bool readColorArray(SkColor *colors, size_t size)
size_t offset() const
bool readScalarArray(SkScalar *values, size_t size)
void readPoint3(SkPoint3 *point)
void readRegion(SkRegion *region)
void readPath(SkPath *path)
const char * c_str() const
Definition SkString.h:133
SkTypefaceID uniqueID() const
Definition SkTypeface.h:101
void serialize(SkWStream *, SerializeBehavior=SerializeBehavior::kIncludeDataIfLocal) const
static sk_sp< SkTypeface > MakeDeserialize(SkStream *, sk_sp< SkFontMgr > lastResortMgr)
std::unique_ptr< SkStreamAsset > openStream(int *ttcIndex) const
virtual void writeScalarArray(const SkScalar *value, uint32_t count)=0
virtual void writeRegion(const SkRegion &region)=0
virtual void writePointArray(const SkPoint *point, uint32_t count)=0
virtual void writeColor4fArray(const SkColor4f *color, uint32_t count)=0
virtual void writeFlattenable(const SkFlattenable *flattenable)=0
virtual void writeMatrix(const SkMatrix &matrix)=0
virtual void writeByteArray(const void *data, size_t size)=0
virtual void writePoint3(const SkPoint3 &point)=0
virtual void writePath(const SkPath &path)=0
virtual void writeColorArray(const SkColor *color, uint32_t count)=0
virtual void writeIntArray(const int32_t *value, uint32_t count)=0
virtual void writeString(std::string_view value)=0
TestAnnotationCanvas(skiatest::Reporter *reporter, const AnnotationRec rec[], int count)
void onDrawAnnotation(const SkRect &rect, const char key[], SkData *value) override
T * get() const
Definition SkRefCnt.h:303
void realloc(size_t count)
static constexpr int kSize
const Paint & paint
const EmbeddedViewParams * params
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition main.cc:19
float SkScalar
Definition extension.cpp:12
struct MyStruct s
static const uint8_t buffer[]
uint8_t value
const char * name
Definition fuchsia.cc:50
size_t length
std::u16string text
double y
double x
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
SkFont DefaultFont()
sk_sp< SkTypeface > SampleUserTypeface()
bool equal_pixels(const SkPixmap &a, const SkPixmap &b)
sk_sp< SkTypeface > CreateTypefaceFromResource(const char *resource, int ttcIndex)
sk_sp< SkTypeface > DefaultTypeface()
sk_sp< SkFontMgr > TestFontMgr()
Definition copy.py:1
Definition run.py:1
#define T
sk_sp< SkData > fValue
static void InvalidateData(unsigned char *data)
static void InvalidateData(unsigned char *data)
static void Write(SkWriteBuffer &writer, SkColor4f *data, uint32_t arraySize)
static bool Read(SkReadBuffer &reader, SkColor4f *data, uint32_t arraySize)
static void Write(SkWriteBuffer &writer, SkColor *data, uint32_t arraySize)
static bool Read(SkReadBuffer &reader, SkColor *data, uint32_t arraySize)
static void Read(SkReadBuffer &reader, SkMatrix *matrix)
static void Write(SkWriteBuffer &writer, const SkMatrix *matrix)
static void Write(SkWriteBuffer &writer, const SkPath *path)
static void Read(SkReadBuffer &reader, SkPath *path)
static void Write(SkWriteBuffer &writer, const SkPoint3 *data)
static void Read(SkReadBuffer &reader, SkPoint3 *data)
static bool Read(SkReadBuffer &reader, SkPoint *data, uint32_t arraySize)
static void Write(SkWriteBuffer &writer, SkPoint *data, uint32_t arraySize)
static void Write(SkWriteBuffer &writer, const SkRegion *region)
static void Read(SkReadBuffer &reader, SkRegion *region)
static void Write(SkWriteBuffer &writer, SkScalar *data, uint32_t arraySize)
static bool Read(SkReadBuffer &reader, SkScalar *data, uint32_t arraySize)
static void Read(SkReadBuffer &reader, SkString *string)
static void Write(SkWriteBuffer &writer, const SkString *string)
static bool Read(SkReadBuffer &reader, int32_t *data, uint32_t arraySize)
static void Write(SkWriteBuffer &writer, int32_t *data, uint32_t arraySize)
static void Write(SkWriteBuffer &writer, unsigned char *data, uint32_t arraySize)
static bool Read(SkReadBuffer &reader, unsigned char *data, uint32_t arraySize)
static void Read(SkReadBuffer &reader, T **flattenable)
static void Write(SkWriteBuffer &writer, const T *flattenable)
SkDeserialTypefaceProc fTypefaceProc
SkFontArguments & setVariationDesignPosition(VariationPosition position)
SkScalar fTop
greatest extent above origin of any glyph bounding box, typically negative; deprecated with variable ...
SkScalar fLeading
distance to add between lines, typically positive or zero
SkScalar fAvgCharWidth
average character width, zero if unknown
SkScalar fStrikeoutPosition
distance from baseline to bottom of stroke, typically negative
SkScalar fStrikeoutThickness
strikeout thickness
SkScalar fMaxCharWidth
maximum character width, zero if unknown
SkScalar fBottom
greatest extent below origin of any glyph bounding box, typically positive; deprecated with variable ...
uint32_t fFlags
FontMetricsFlags indicating which metrics are valid.
SkScalar fAscent
distance to reserve above baseline, typically negative
SkScalar fXHeight
height of lower-case 'x', zero if unknown, typically negative
SkScalar fUnderlineThickness
underline thickness
@ kStrikeoutPositionIsValid_Flag
set if fStrikeoutPosition is valid
@ kStrikeoutThicknessIsValid_Flag
set if fStrikeoutThickness is valid
@ kUnderlinePositionIsValid_Flag
set if fUnderlinePosition is valid
@ kUnderlineThicknessIsValid_Flag
set if fUnderlineThickness is valid
@ kBoundsInvalid_Flag
set if fTop, fBottom, fXMin, fXMax invalid
SkScalar fDescent
distance to reserve below baseline, typically positive
SkScalar fCapHeight
height of an upper-case letter, zero if unknown, typically negative
SkScalar fXMin
greatest extent to left of origin of any glyph bounding box, typically negative; deprecated with vari...
SkScalar fUnderlinePosition
distance from baseline to top of stroke, typically positive
SkScalar fXMax
greatest extent to right of origin of any glyph bounding box, typically positive; deprecated with var...
constexpr int32_t height() const
Definition SkRect.h:165
constexpr int32_t width() const
Definition SkRect.h:158
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition SkRect.h:56
static SkImageInfo MakeN32Premul(int width, int height)
static SkRGBA4f FromColor(SkColor color)
constexpr float x() const
Definition SkRect.h:720
constexpr float y() const
Definition SkRect.h:727
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659
static constexpr SkRect MakeWH(float w, float h)
Definition SkRect.h:609
SkSerialImageProc fImageProc
SkSerialTypefaceProc fTypefaceProc
const uintptr_t id