1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2010 The Android Open Source Project
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_SUPPORT_PDF
11*c8dee2aaSAndroid Build Coastguard Worker
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkDocument.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontStyle.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontTypes.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageFilter.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSpan.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/docs/SkPDFDocument.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkImageFilters.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkPerlinNoiseShader.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkImageFilterTypes.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkImageFilter_Base.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkClusterator.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFDocumentPriv.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFFont.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFTypes.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFUnion.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/pdf/SkPDFUtils.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/GlyphRun.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/utils/SkFloatToDecimal.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "tools/Resources.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
50*c8dee2aaSAndroid Build Coastguard Worker
51*c8dee2aaSAndroid Build Coastguard Worker #include <cfloat>
52*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
53*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
54*c8dee2aaSAndroid Build Coastguard Worker #include <cstdio>
55*c8dee2aaSAndroid Build Coastguard Worker #include <cstdlib>
56*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
57*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
58*c8dee2aaSAndroid Build Coastguard Worker #include <optional>
59*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
60*c8dee2aaSAndroid Build Coastguard Worker
61*c8dee2aaSAndroid Build Coastguard Worker class SkTypeface;
62*c8dee2aaSAndroid Build Coastguard Worker
63*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
emit_to_string(T & obj)64*c8dee2aaSAndroid Build Coastguard Worker static SkString emit_to_string(T& obj) {
65*c8dee2aaSAndroid Build Coastguard Worker SkDynamicMemoryWStream buffer;
66*c8dee2aaSAndroid Build Coastguard Worker obj.emitObject(&buffer);
67*c8dee2aaSAndroid Build Coastguard Worker SkString tmp(buffer.bytesWritten());
68*c8dee2aaSAndroid Build Coastguard Worker buffer.copyTo(tmp.data());
69*c8dee2aaSAndroid Build Coastguard Worker return tmp;
70*c8dee2aaSAndroid Build Coastguard Worker }
71*c8dee2aaSAndroid Build Coastguard Worker
eq(const SkString & str,const char * strPtr,size_t len)72*c8dee2aaSAndroid Build Coastguard Worker static bool eq(const SkString& str, const char* strPtr, size_t len) {
73*c8dee2aaSAndroid Build Coastguard Worker return len == str.size() && 0 == memcmp(str.c_str(), strPtr, len);
74*c8dee2aaSAndroid Build Coastguard Worker }
75*c8dee2aaSAndroid Build Coastguard Worker
assert_eql(skiatest::Reporter * reporter,const SkString & skString,const char * str,size_t len)76*c8dee2aaSAndroid Build Coastguard Worker static void assert_eql(skiatest::Reporter* reporter,
77*c8dee2aaSAndroid Build Coastguard Worker const SkString& skString,
78*c8dee2aaSAndroid Build Coastguard Worker const char* str,
79*c8dee2aaSAndroid Build Coastguard Worker size_t len) {
80*c8dee2aaSAndroid Build Coastguard Worker if (!eq(skString, str, len)) {
81*c8dee2aaSAndroid Build Coastguard Worker REPORT_FAILURE(reporter, "", SkStringPrintf(
82*c8dee2aaSAndroid Build Coastguard Worker "'%*s' != '%s'", (int)len, str, skString.c_str()));
83*c8dee2aaSAndroid Build Coastguard Worker }
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker
assert_eq(skiatest::Reporter * reporter,const SkString & skString,const char * str)86*c8dee2aaSAndroid Build Coastguard Worker static void assert_eq(skiatest::Reporter* reporter,
87*c8dee2aaSAndroid Build Coastguard Worker const SkString& skString,
88*c8dee2aaSAndroid Build Coastguard Worker const char* str) {
89*c8dee2aaSAndroid Build Coastguard Worker assert_eql(reporter, skString, str, strlen(str));
90*c8dee2aaSAndroid Build Coastguard Worker }
91*c8dee2aaSAndroid Build Coastguard Worker
92*c8dee2aaSAndroid Build Coastguard Worker
93*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
assert_emit_eq(skiatest::Reporter * reporter,T & object,const char * string)94*c8dee2aaSAndroid Build Coastguard Worker static void assert_emit_eq(skiatest::Reporter* reporter,
95*c8dee2aaSAndroid Build Coastguard Worker T& object,
96*c8dee2aaSAndroid Build Coastguard Worker const char* string) {
97*c8dee2aaSAndroid Build Coastguard Worker SkString result = emit_to_string(object);
98*c8dee2aaSAndroid Build Coastguard Worker assert_eq(reporter, result, string);
99*c8dee2aaSAndroid Build Coastguard Worker }
100*c8dee2aaSAndroid Build Coastguard Worker
101*c8dee2aaSAndroid Build Coastguard Worker // This test used to assert without the fix submitted for
102*c8dee2aaSAndroid Build Coastguard Worker // http://code.google.com/p/skia/issues/detail?id=1083.
103*c8dee2aaSAndroid Build Coastguard Worker // SKP files might have invalid glyph ids. This test ensures they are ignored,
104*c8dee2aaSAndroid Build Coastguard Worker // and there is no assert on input data in Debug mode.
test_issue1083()105*c8dee2aaSAndroid Build Coastguard Worker static void test_issue1083() {
106*c8dee2aaSAndroid Build Coastguard Worker SkDynamicMemoryWStream outStream;
107*c8dee2aaSAndroid Build Coastguard Worker auto doc = SkPDF::MakeDocument(&outStream);
108*c8dee2aaSAndroid Build Coastguard Worker SkCanvas* canvas = doc->beginPage(100.0f, 100.0f);
109*c8dee2aaSAndroid Build Coastguard Worker
110*c8dee2aaSAndroid Build Coastguard Worker uint16_t glyphID = 65000;
111*c8dee2aaSAndroid Build Coastguard Worker SkFont font = ToolUtils::DefaultFont();
112*c8dee2aaSAndroid Build Coastguard Worker canvas->drawSimpleText(&glyphID, 2, SkTextEncoding::kGlyphID, 0, 0, font, SkPaint());
113*c8dee2aaSAndroid Build Coastguard Worker
114*c8dee2aaSAndroid Build Coastguard Worker doc->close();
115*c8dee2aaSAndroid Build Coastguard Worker }
116*c8dee2aaSAndroid Build Coastguard Worker
assert_emit_eq_number(skiatest::Reporter * reporter,float number)117*c8dee2aaSAndroid Build Coastguard Worker static void assert_emit_eq_number(skiatest::Reporter* reporter, float number) {
118*c8dee2aaSAndroid Build Coastguard Worker SkPDFUnion pdfUnion = SkPDFUnion::Scalar(number);
119*c8dee2aaSAndroid Build Coastguard Worker SkString result = emit_to_string(pdfUnion);
120*c8dee2aaSAndroid Build Coastguard Worker float value = static_cast<float>(std::atof(result.c_str()));
121*c8dee2aaSAndroid Build Coastguard Worker if (value != number) {
122*c8dee2aaSAndroid Build Coastguard Worker ERRORF(reporter, "%.9g != %s", number, result.c_str());
123*c8dee2aaSAndroid Build Coastguard Worker }
124*c8dee2aaSAndroid Build Coastguard Worker }
125*c8dee2aaSAndroid Build Coastguard Worker
126*c8dee2aaSAndroid Build Coastguard Worker
TestPDFUnion(skiatest::Reporter * reporter)127*c8dee2aaSAndroid Build Coastguard Worker static void TestPDFUnion(skiatest::Reporter* reporter) {
128*c8dee2aaSAndroid Build Coastguard Worker SkPDFUnion boolTrue = SkPDFUnion::Bool(true);
129*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, boolTrue, "true");
130*c8dee2aaSAndroid Build Coastguard Worker
131*c8dee2aaSAndroid Build Coastguard Worker SkPDFUnion boolFalse = SkPDFUnion::Bool(false);
132*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, boolFalse, "false");
133*c8dee2aaSAndroid Build Coastguard Worker
134*c8dee2aaSAndroid Build Coastguard Worker SkPDFUnion int42 = SkPDFUnion::Int(42);
135*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, int42, "42");
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq_number(reporter, SK_ScalarHalf);
138*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq_number(reporter, 110999.75f); // bigScalar
139*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq_number(reporter, 50000000.1f); // biggerScalar
140*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq_number(reporter, 1.0f / 65536); // smallScalar
141*c8dee2aaSAndroid Build Coastguard Worker
142*c8dee2aaSAndroid Build Coastguard Worker SkPDFUnion stringSimple = SkPDFUnion::TextString("test ) string ( foo");
143*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, stringSimple, "(test \\) string \\( foo)");
144*c8dee2aaSAndroid Build Coastguard Worker
145*c8dee2aaSAndroid Build Coastguard Worker SkString stringComplexInput("\ttest ) string ( foo");
146*c8dee2aaSAndroid Build Coastguard Worker SkPDFUnion stringComplex = SkPDFUnion::TextString(stringComplexInput);
147*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, stringComplex, "(\\011test \\) string \\( foo)");
148*c8dee2aaSAndroid Build Coastguard Worker
149*c8dee2aaSAndroid Build Coastguard Worker SkString binaryStringInput("\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20");
150*c8dee2aaSAndroid Build Coastguard Worker SkPDFUnion binaryString = SkPDFUnion::ByteString(binaryStringInput);
151*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, binaryString, "<0102030405060708090A0B0C0D0E0F10>");
152*c8dee2aaSAndroid Build Coastguard Worker
153*c8dee2aaSAndroid Build Coastguard Worker SkString nameInput("Test name\twith#tab");
154*c8dee2aaSAndroid Build Coastguard Worker SkPDFUnion name = SkPDFUnion::Name(nameInput);
155*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, name, "/Test#20name#09with#23tab");
156*c8dee2aaSAndroid Build Coastguard Worker
157*c8dee2aaSAndroid Build Coastguard Worker SkString nameInput2("A#/%()<>[]{}B");
158*c8dee2aaSAndroid Build Coastguard Worker SkPDFUnion name2 = SkPDFUnion::Name(nameInput2);
159*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, name2, "/A#23#2F#25#28#29#3C#3E#5B#5D#7B#7DB");
160*c8dee2aaSAndroid Build Coastguard Worker
161*c8dee2aaSAndroid Build Coastguard Worker SkPDFUnion name3 = SkPDFUnion::Name("SimpleNameWithOnlyPrintableASCII");
162*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, name3, "/SimpleNameWithOnlyPrintableASCII");
163*c8dee2aaSAndroid Build Coastguard Worker
164*c8dee2aaSAndroid Build Coastguard Worker // Test that we correctly handle characters with the high-bit set.
165*c8dee2aaSAndroid Build Coastguard Worker SkString highBitString("\xDE\xAD" "be\xEF");
166*c8dee2aaSAndroid Build Coastguard Worker SkPDFUnion highBitName = SkPDFUnion::Name(highBitString);
167*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, highBitName, "/#DE#ADbe#EF");
168*c8dee2aaSAndroid Build Coastguard Worker
169*c8dee2aaSAndroid Build Coastguard Worker // https://bugs.skia.org/9508
170*c8dee2aaSAndroid Build Coastguard Worker // https://crbug.com/494913
171*c8dee2aaSAndroid Build Coastguard Worker // Trailing '\0' characters must be removed.
172*c8dee2aaSAndroid Build Coastguard Worker const char nameInput4[] = "Test name with nil\0";
173*c8dee2aaSAndroid Build Coastguard Worker SkPDFUnion name4 = SkPDFUnion::Name(SkString(nameInput4, strlen(nameInput4) + 1));
174*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, name4, "/Test#20name#20with#20nil");
175*c8dee2aaSAndroid Build Coastguard Worker }
176*c8dee2aaSAndroid Build Coastguard Worker
TestPDFArray(skiatest::Reporter * reporter)177*c8dee2aaSAndroid Build Coastguard Worker static void TestPDFArray(skiatest::Reporter* reporter) {
178*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkPDFArray> array(new SkPDFArray);
179*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *array, "[]");
180*c8dee2aaSAndroid Build Coastguard Worker
181*c8dee2aaSAndroid Build Coastguard Worker array->appendInt(42);
182*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *array, "[42]");
183*c8dee2aaSAndroid Build Coastguard Worker
184*c8dee2aaSAndroid Build Coastguard Worker array->appendScalar(SK_ScalarHalf);
185*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *array, "[42 .5]");
186*c8dee2aaSAndroid Build Coastguard Worker
187*c8dee2aaSAndroid Build Coastguard Worker array->appendInt(0);
188*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *array, "[42 .5 0]");
189*c8dee2aaSAndroid Build Coastguard Worker
190*c8dee2aaSAndroid Build Coastguard Worker array->appendBool(true);
191*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *array, "[42 .5 0 true]");
192*c8dee2aaSAndroid Build Coastguard Worker
193*c8dee2aaSAndroid Build Coastguard Worker array->appendName("ThisName");
194*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *array, "[42 .5 0 true /ThisName]");
195*c8dee2aaSAndroid Build Coastguard Worker
196*c8dee2aaSAndroid Build Coastguard Worker array->appendName(SkString("AnotherName"));
197*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *array, "[42 .5 0 true /ThisName /AnotherName]");
198*c8dee2aaSAndroid Build Coastguard Worker
199*c8dee2aaSAndroid Build Coastguard Worker array->appendTextString("This String");
200*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *array,
201*c8dee2aaSAndroid Build Coastguard Worker "[42 .5 0 true /ThisName /AnotherName (This String)]");
202*c8dee2aaSAndroid Build Coastguard Worker
203*c8dee2aaSAndroid Build Coastguard Worker array->appendByteString(SkString("Another String"));
204*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *array,
205*c8dee2aaSAndroid Build Coastguard Worker "[42 .5 0 true /ThisName /AnotherName (This String) "
206*c8dee2aaSAndroid Build Coastguard Worker "(Another String)]");
207*c8dee2aaSAndroid Build Coastguard Worker
208*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkPDFArray> innerArray(new SkPDFArray);
209*c8dee2aaSAndroid Build Coastguard Worker innerArray->appendInt(-1);
210*c8dee2aaSAndroid Build Coastguard Worker array->appendObject(std::move(innerArray));
211*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *array,
212*c8dee2aaSAndroid Build Coastguard Worker "[42 .5 0 true /ThisName /AnotherName (This String) "
213*c8dee2aaSAndroid Build Coastguard Worker "(Another String) [-1]]");
214*c8dee2aaSAndroid Build Coastguard Worker }
215*c8dee2aaSAndroid Build Coastguard Worker
TestPDFDict(skiatest::Reporter * reporter)216*c8dee2aaSAndroid Build Coastguard Worker static void TestPDFDict(skiatest::Reporter* reporter) {
217*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkPDFDict> dict(new SkPDFDict);
218*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<<>>");
219*c8dee2aaSAndroid Build Coastguard Worker
220*c8dee2aaSAndroid Build Coastguard Worker dict->insertInt("n1", SkToSizeT(42));
221*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<</n1 42>>");
222*c8dee2aaSAndroid Build Coastguard Worker
223*c8dee2aaSAndroid Build Coastguard Worker dict = std::make_unique<SkPDFDict>();
224*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<<>>");
225*c8dee2aaSAndroid Build Coastguard Worker
226*c8dee2aaSAndroid Build Coastguard Worker dict->insertInt("n1", 42);
227*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<</n1 42>>");
228*c8dee2aaSAndroid Build Coastguard Worker
229*c8dee2aaSAndroid Build Coastguard Worker dict->insertScalar("n2", SK_ScalarHalf);
230*c8dee2aaSAndroid Build Coastguard Worker
231*c8dee2aaSAndroid Build Coastguard Worker SkString n3("n3");
232*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkPDFArray> innerArray(new SkPDFArray);
233*c8dee2aaSAndroid Build Coastguard Worker innerArray->appendInt(-100);
234*c8dee2aaSAndroid Build Coastguard Worker dict->insertObject(n3, std::move(innerArray));
235*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<</n1 42\n/n2 .5\n/n3 [-100]>>");
236*c8dee2aaSAndroid Build Coastguard Worker
237*c8dee2aaSAndroid Build Coastguard Worker dict = std::make_unique<SkPDFDict>();
238*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<<>>");
239*c8dee2aaSAndroid Build Coastguard Worker
240*c8dee2aaSAndroid Build Coastguard Worker dict->insertInt("n1", 24);
241*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<</n1 24>>");
242*c8dee2aaSAndroid Build Coastguard Worker
243*c8dee2aaSAndroid Build Coastguard Worker dict->insertInt("n2", SkToSizeT(99));
244*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<</n1 24\n/n2 99>>");
245*c8dee2aaSAndroid Build Coastguard Worker
246*c8dee2aaSAndroid Build Coastguard Worker dict->insertScalar("n3", SK_ScalarHalf);
247*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5>>");
248*c8dee2aaSAndroid Build Coastguard Worker
249*c8dee2aaSAndroid Build Coastguard Worker dict->insertName("n4", "AName");
250*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5\n/n4 /AName>>");
251*c8dee2aaSAndroid Build Coastguard Worker
252*c8dee2aaSAndroid Build Coastguard Worker dict->insertName("n5", SkString("AnotherName"));
253*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5\n/n4 /AName\n"
254*c8dee2aaSAndroid Build Coastguard Worker "/n5 /AnotherName>>");
255*c8dee2aaSAndroid Build Coastguard Worker
256*c8dee2aaSAndroid Build Coastguard Worker dict->insertTextString("n6", "A String");
257*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5\n/n4 /AName\n"
258*c8dee2aaSAndroid Build Coastguard Worker "/n5 /AnotherName\n/n6 (A String)>>");
259*c8dee2aaSAndroid Build Coastguard Worker
260*c8dee2aaSAndroid Build Coastguard Worker dict->insertByteString("n7", SkString("Another String"));
261*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5\n/n4 /AName\n"
262*c8dee2aaSAndroid Build Coastguard Worker "/n5 /AnotherName\n/n6 (A String)\n/n7 (Another String)>>");
263*c8dee2aaSAndroid Build Coastguard Worker
264*c8dee2aaSAndroid Build Coastguard Worker dict = std::make_unique<SkPDFDict>("DType");
265*c8dee2aaSAndroid Build Coastguard Worker assert_emit_eq(reporter, *dict, "<</Type /DType>>");
266*c8dee2aaSAndroid Build Coastguard Worker }
267*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(SkPDF_Primitives,reporter)268*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPDF_Primitives, reporter) {
269*c8dee2aaSAndroid Build Coastguard Worker TestPDFUnion(reporter);
270*c8dee2aaSAndroid Build Coastguard Worker TestPDFArray(reporter);
271*c8dee2aaSAndroid Build Coastguard Worker TestPDFDict(reporter);
272*c8dee2aaSAndroid Build Coastguard Worker test_issue1083();
273*c8dee2aaSAndroid Build Coastguard Worker }
274*c8dee2aaSAndroid Build Coastguard Worker
275*c8dee2aaSAndroid Build Coastguard Worker namespace {
276*c8dee2aaSAndroid Build Coastguard Worker
277*c8dee2aaSAndroid Build Coastguard Worker class TestImageFilter : public SkImageFilter_Base {
278*c8dee2aaSAndroid Build Coastguard Worker public:
TestImageFilter()279*c8dee2aaSAndroid Build Coastguard Worker TestImageFilter() : SkImageFilter_Base(nullptr, 0), fVisited(false) {}
280*c8dee2aaSAndroid Build Coastguard Worker
visited() const281*c8dee2aaSAndroid Build Coastguard Worker bool visited() const { return fVisited; }
282*c8dee2aaSAndroid Build Coastguard Worker
283*c8dee2aaSAndroid Build Coastguard Worker private:
getFactory() const284*c8dee2aaSAndroid Build Coastguard Worker Factory getFactory() const override {
285*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("Does not participate in serialization");
286*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
287*c8dee2aaSAndroid Build Coastguard Worker }
getTypeName() const288*c8dee2aaSAndroid Build Coastguard Worker const char* getTypeName() const override { return "TestImageFilter"; }
289*c8dee2aaSAndroid Build Coastguard Worker
onFilterImage(const skif::Context & ctx) const290*c8dee2aaSAndroid Build Coastguard Worker skif::FilterResult onFilterImage(const skif::Context& ctx) const override {
291*c8dee2aaSAndroid Build Coastguard Worker fVisited = true;
292*c8dee2aaSAndroid Build Coastguard Worker return ctx.source();
293*c8dee2aaSAndroid Build Coastguard Worker }
294*c8dee2aaSAndroid Build Coastguard Worker
onGetInputLayerBounds(const skif::Mapping & mapping,const skif::LayerSpace<SkIRect> & desiredOutput,std::optional<skif::LayerSpace<SkIRect>> contentBounds) const295*c8dee2aaSAndroid Build Coastguard Worker skif::LayerSpace<SkIRect> onGetInputLayerBounds(
296*c8dee2aaSAndroid Build Coastguard Worker const skif::Mapping& mapping,
297*c8dee2aaSAndroid Build Coastguard Worker const skif::LayerSpace<SkIRect>& desiredOutput,
298*c8dee2aaSAndroid Build Coastguard Worker std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override {
299*c8dee2aaSAndroid Build Coastguard Worker return desiredOutput;
300*c8dee2aaSAndroid Build Coastguard Worker }
301*c8dee2aaSAndroid Build Coastguard Worker
onGetOutputLayerBounds(const skif::Mapping & mapping,std::optional<skif::LayerSpace<SkIRect>> contentBounds) const302*c8dee2aaSAndroid Build Coastguard Worker std::optional<skif::LayerSpace<SkIRect>> onGetOutputLayerBounds(
303*c8dee2aaSAndroid Build Coastguard Worker const skif::Mapping& mapping,
304*c8dee2aaSAndroid Build Coastguard Worker std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override {
305*c8dee2aaSAndroid Build Coastguard Worker return contentBounds;
306*c8dee2aaSAndroid Build Coastguard Worker }
307*c8dee2aaSAndroid Build Coastguard Worker
308*c8dee2aaSAndroid Build Coastguard Worker mutable bool fVisited;
309*c8dee2aaSAndroid Build Coastguard Worker };
310*c8dee2aaSAndroid Build Coastguard Worker
311*c8dee2aaSAndroid Build Coastguard Worker } // namespace
312*c8dee2aaSAndroid Build Coastguard Worker
313*c8dee2aaSAndroid Build Coastguard Worker // Check that PDF rendering of image filters successfully falls back to
314*c8dee2aaSAndroid Build Coastguard Worker // CPU rasterization.
DEF_TEST(SkPDF_ImageFilter,reporter)315*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPDF_ImageFilter, reporter) {
316*c8dee2aaSAndroid Build Coastguard Worker REQUIRE_PDF_DOCUMENT(SkPDF_ImageFilter, reporter);
317*c8dee2aaSAndroid Build Coastguard Worker SkDynamicMemoryWStream stream;
318*c8dee2aaSAndroid Build Coastguard Worker auto doc = SkPDF::MakeDocument(&stream);
319*c8dee2aaSAndroid Build Coastguard Worker SkCanvas* canvas = doc->beginPage(100.0f, 100.0f);
320*c8dee2aaSAndroid Build Coastguard Worker
321*c8dee2aaSAndroid Build Coastguard Worker sk_sp<TestImageFilter> filter(new TestImageFilter());
322*c8dee2aaSAndroid Build Coastguard Worker
323*c8dee2aaSAndroid Build Coastguard Worker // Filter just created; should be unvisited.
324*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, !filter->visited());
325*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
326*c8dee2aaSAndroid Build Coastguard Worker paint.setImageFilter(filter);
327*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeWH(100, 100), paint);
328*c8dee2aaSAndroid Build Coastguard Worker doc->close();
329*c8dee2aaSAndroid Build Coastguard Worker
330*c8dee2aaSAndroid Build Coastguard Worker // Filter was used in rendering; should be visited.
331*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, filter->visited());
332*c8dee2aaSAndroid Build Coastguard Worker }
333*c8dee2aaSAndroid Build Coastguard Worker
334*c8dee2aaSAndroid Build Coastguard Worker // Check that PDF rendering of image filters successfully falls back to
335*c8dee2aaSAndroid Build Coastguard Worker // CPU rasterization.
DEF_TEST(SkPDF_FontCanEmbedTypeface,reporter)336*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPDF_FontCanEmbedTypeface, reporter) {
337*c8dee2aaSAndroid Build Coastguard Worker SkNullWStream nullWStream;
338*c8dee2aaSAndroid Build Coastguard Worker SkPDFDocument doc(&nullWStream, SkPDF::Metadata());
339*c8dee2aaSAndroid Build Coastguard Worker
340*c8dee2aaSAndroid Build Coastguard Worker const char resource[] = "fonts/Roboto2-Regular_NoEmbed.ttf";
341*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTypeface> noEmbedTypeface(ToolUtils::CreateTypefaceFromResource(resource));
342*c8dee2aaSAndroid Build Coastguard Worker if (noEmbedTypeface) {
343*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter,
344*c8dee2aaSAndroid Build Coastguard Worker !SkPDFFont::CanEmbedTypeface(*noEmbedTypeface, &doc));
345*c8dee2aaSAndroid Build Coastguard Worker }
346*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTypeface> portableTypeface(ToolUtils::DefaultTypeface());
347*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter,
348*c8dee2aaSAndroid Build Coastguard Worker SkPDFFont::CanEmbedTypeface(*portableTypeface, &doc));
349*c8dee2aaSAndroid Build Coastguard Worker }
350*c8dee2aaSAndroid Build Coastguard Worker
351*c8dee2aaSAndroid Build Coastguard Worker
352*c8dee2aaSAndroid Build Coastguard Worker // test to see that all finite scalars round trip via scanf().
check_pdf_scalar_serialization(skiatest::Reporter * reporter,float inputFloat)353*c8dee2aaSAndroid Build Coastguard Worker static void check_pdf_scalar_serialization(
354*c8dee2aaSAndroid Build Coastguard Worker skiatest::Reporter* reporter, float inputFloat) {
355*c8dee2aaSAndroid Build Coastguard Worker char floatString[kMaximumSkFloatToDecimalLength];
356*c8dee2aaSAndroid Build Coastguard Worker size_t len = SkFloatToDecimal(inputFloat, floatString);
357*c8dee2aaSAndroid Build Coastguard Worker if (len >= sizeof(floatString)) {
358*c8dee2aaSAndroid Build Coastguard Worker ERRORF(reporter, "string too long: %u", (unsigned)len);
359*c8dee2aaSAndroid Build Coastguard Worker return;
360*c8dee2aaSAndroid Build Coastguard Worker }
361*c8dee2aaSAndroid Build Coastguard Worker if (floatString[len] != '\0' || strlen(floatString) != len) {
362*c8dee2aaSAndroid Build Coastguard Worker ERRORF(reporter, "terminator misplaced.");
363*c8dee2aaSAndroid Build Coastguard Worker return; // The terminator is needed for sscanf().
364*c8dee2aaSAndroid Build Coastguard Worker }
365*c8dee2aaSAndroid Build Coastguard Worker if (reporter->verbose()) {
366*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%15.9g = \"%s\"\n", inputFloat, floatString);
367*c8dee2aaSAndroid Build Coastguard Worker }
368*c8dee2aaSAndroid Build Coastguard Worker float roundTripFloat;
369*c8dee2aaSAndroid Build Coastguard Worker if (1 != sscanf(floatString, "%f", &roundTripFloat)) {
370*c8dee2aaSAndroid Build Coastguard Worker ERRORF(reporter, "unscannable result: %s", floatString);
371*c8dee2aaSAndroid Build Coastguard Worker return;
372*c8dee2aaSAndroid Build Coastguard Worker }
373*c8dee2aaSAndroid Build Coastguard Worker if (SkIsFinite(inputFloat) && roundTripFloat != inputFloat) {
374*c8dee2aaSAndroid Build Coastguard Worker ERRORF(reporter, "roundTripFloat (%.9g) != inputFloat (%.9g)",
375*c8dee2aaSAndroid Build Coastguard Worker roundTripFloat, inputFloat);
376*c8dee2aaSAndroid Build Coastguard Worker }
377*c8dee2aaSAndroid Build Coastguard Worker }
378*c8dee2aaSAndroid Build Coastguard Worker
379*c8dee2aaSAndroid Build Coastguard Worker // Test SkPDFUtils::AppendScalar for accuracy.
DEF_TEST(SkPDF_Primitives_Scalar,reporter)380*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPDF_Primitives_Scalar, reporter) {
381*c8dee2aaSAndroid Build Coastguard Worker SkRandom random(0x5EED);
382*c8dee2aaSAndroid Build Coastguard Worker int iterationCount = 512;
383*c8dee2aaSAndroid Build Coastguard Worker while (iterationCount-- > 0) {
384*c8dee2aaSAndroid Build Coastguard Worker union { uint32_t u; float f; };
385*c8dee2aaSAndroid Build Coastguard Worker u = random.nextU();
386*c8dee2aaSAndroid Build Coastguard Worker static_assert(sizeof(float) == sizeof(uint32_t), "");
387*c8dee2aaSAndroid Build Coastguard Worker check_pdf_scalar_serialization(reporter, f);
388*c8dee2aaSAndroid Build Coastguard Worker }
389*c8dee2aaSAndroid Build Coastguard Worker float alwaysCheck[] = {
390*c8dee2aaSAndroid Build Coastguard Worker 0.0f, -0.0f, 1.0f, -1.0f, SK_ScalarPI, 0.1f, FLT_MIN, FLT_MAX,
391*c8dee2aaSAndroid Build Coastguard Worker -FLT_MIN, -FLT_MAX, FLT_MIN / 16.0f, -FLT_MIN / 16.0f,
392*c8dee2aaSAndroid Build Coastguard Worker SK_FloatNaN, SK_FloatInfinity, SK_FloatNegativeInfinity,
393*c8dee2aaSAndroid Build Coastguard Worker -FLT_MIN / 8388608.0
394*c8dee2aaSAndroid Build Coastguard Worker };
395*c8dee2aaSAndroid Build Coastguard Worker for (float inputFloat: alwaysCheck) {
396*c8dee2aaSAndroid Build Coastguard Worker check_pdf_scalar_serialization(reporter, inputFloat);
397*c8dee2aaSAndroid Build Coastguard Worker }
398*c8dee2aaSAndroid Build Coastguard Worker }
399*c8dee2aaSAndroid Build Coastguard Worker
400*c8dee2aaSAndroid Build Coastguard Worker // Test SkPDFUtils:: for accuracy.
DEF_TEST(SkPDF_Primitives_Color,reporter)401*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPDF_Primitives_Color, reporter) {
402*c8dee2aaSAndroid Build Coastguard Worker char buffer[5];
403*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 256; ++i) {
404*c8dee2aaSAndroid Build Coastguard Worker size_t len = SkPDFUtils::ColorToDecimal(i, buffer);
405*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, len == strlen(buffer));
406*c8dee2aaSAndroid Build Coastguard Worker float f;
407*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == sscanf(buffer, "%f", &f));
408*c8dee2aaSAndroid Build Coastguard Worker int roundTrip = (int)(0.5 + f * 255);
409*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, roundTrip == i);
410*c8dee2aaSAndroid Build Coastguard Worker }
411*c8dee2aaSAndroid Build Coastguard Worker }
412*c8dee2aaSAndroid Build Coastguard Worker
make_run(size_t len,const SkGlyphID * glyphs,SkPoint * pos,const SkFont & font,const uint32_t * clusters,size_t utf8TextByteLength,const char * utf8Text)413*c8dee2aaSAndroid Build Coastguard Worker static sktext::GlyphRun make_run(size_t len, const SkGlyphID* glyphs, SkPoint* pos,
414*c8dee2aaSAndroid Build Coastguard Worker const SkFont& font, const uint32_t* clusters,
415*c8dee2aaSAndroid Build Coastguard Worker size_t utf8TextByteLength, const char* utf8Text) {
416*c8dee2aaSAndroid Build Coastguard Worker return sktext::GlyphRun(font,
417*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkPoint>{pos, len},
418*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkGlyphID>{glyphs, len},
419*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const char>{utf8Text, utf8TextByteLength},
420*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const uint32_t>{clusters, len},
421*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkVector>{});
422*c8dee2aaSAndroid Build Coastguard Worker }
423*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(SkPDF_Clusterator,reporter)424*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPDF_Clusterator, reporter) {
425*c8dee2aaSAndroid Build Coastguard Worker SkFont font = ToolUtils::DefaultFont();
426*c8dee2aaSAndroid Build Coastguard Worker {
427*c8dee2aaSAndroid Build Coastguard Worker constexpr unsigned len = 11;
428*c8dee2aaSAndroid Build Coastguard Worker const uint32_t clusters[len] = { 3, 2, 2, 1, 0, 4, 4, 7, 6, 6, 5 };
429*c8dee2aaSAndroid Build Coastguard Worker const SkGlyphID glyphs[len] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
430*c8dee2aaSAndroid Build Coastguard Worker SkPoint pos[len] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
431*c8dee2aaSAndroid Build Coastguard Worker {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
432*c8dee2aaSAndroid Build Coastguard Worker const char text[] = "abcdefgh";
433*c8dee2aaSAndroid Build Coastguard Worker sktext::GlyphRun run = make_run(len, glyphs, pos, font, clusters, strlen(text), text);
434*c8dee2aaSAndroid Build Coastguard Worker SkClusterator clusterator(run);
435*c8dee2aaSAndroid Build Coastguard Worker SkClusterator::Cluster expectations[] = {
436*c8dee2aaSAndroid Build Coastguard Worker {&text[3], 1, 0, 1},
437*c8dee2aaSAndroid Build Coastguard Worker {&text[2], 1, 1, 2},
438*c8dee2aaSAndroid Build Coastguard Worker {&text[1], 1, 3, 1},
439*c8dee2aaSAndroid Build Coastguard Worker {&text[0], 1, 4, 1},
440*c8dee2aaSAndroid Build Coastguard Worker {&text[4], 1, 5, 2},
441*c8dee2aaSAndroid Build Coastguard Worker {&text[7], 1, 7, 1},
442*c8dee2aaSAndroid Build Coastguard Worker {&text[6], 1, 8, 2},
443*c8dee2aaSAndroid Build Coastguard Worker {&text[5], 1, 10, 1},
444*c8dee2aaSAndroid Build Coastguard Worker {nullptr, 0, 0, 0},
445*c8dee2aaSAndroid Build Coastguard Worker };
446*c8dee2aaSAndroid Build Coastguard Worker for (const auto& expectation : expectations) {
447*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, clusterator.next() == expectation);
448*c8dee2aaSAndroid Build Coastguard Worker }
449*c8dee2aaSAndroid Build Coastguard Worker }
450*c8dee2aaSAndroid Build Coastguard Worker {
451*c8dee2aaSAndroid Build Coastguard Worker constexpr unsigned len = 5;
452*c8dee2aaSAndroid Build Coastguard Worker const uint32_t clusters[len] = { 0, 1, 4, 5, 6 };
453*c8dee2aaSAndroid Build Coastguard Worker const SkGlyphID glyphs[len] = { 43, 167, 79, 79, 82, };
454*c8dee2aaSAndroid Build Coastguard Worker SkPoint pos[len] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
455*c8dee2aaSAndroid Build Coastguard Worker const char text[] = "Ha\xCC\x8A" "llo";
456*c8dee2aaSAndroid Build Coastguard Worker sktext::GlyphRun run = make_run(len, glyphs, pos, font, clusters, strlen(text), text);
457*c8dee2aaSAndroid Build Coastguard Worker SkClusterator clusterator(run);
458*c8dee2aaSAndroid Build Coastguard Worker SkClusterator::Cluster expectations[] = {
459*c8dee2aaSAndroid Build Coastguard Worker {&text[0], 1, 0, 1},
460*c8dee2aaSAndroid Build Coastguard Worker {&text[1], 3, 1, 1},
461*c8dee2aaSAndroid Build Coastguard Worker {&text[4], 1, 2, 1},
462*c8dee2aaSAndroid Build Coastguard Worker {&text[5], 1, 3, 1},
463*c8dee2aaSAndroid Build Coastguard Worker {&text[6], 1, 4, 1},
464*c8dee2aaSAndroid Build Coastguard Worker {nullptr, 0, 0, 0},
465*c8dee2aaSAndroid Build Coastguard Worker };
466*c8dee2aaSAndroid Build Coastguard Worker for (const auto& expectation : expectations) {
467*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, clusterator.next() == expectation);
468*c8dee2aaSAndroid Build Coastguard Worker }
469*c8dee2aaSAndroid Build Coastguard Worker }
470*c8dee2aaSAndroid Build Coastguard Worker }
471*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(fuzz875632f0,reporter)472*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(fuzz875632f0, reporter) {
473*c8dee2aaSAndroid Build Coastguard Worker SkNullWStream stream;
474*c8dee2aaSAndroid Build Coastguard Worker auto doc = SkPDF::MakeDocument(&stream);
475*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, doc);
476*c8dee2aaSAndroid Build Coastguard Worker SkCanvas* canvas = doc->beginPage(128, 160);
477*c8dee2aaSAndroid Build Coastguard Worker
478*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore autoCanvasRestore(canvas, false);
479*c8dee2aaSAndroid Build Coastguard Worker
480*c8dee2aaSAndroid Build Coastguard Worker SkPaint layerPaint({0, 0, 0, 0});
481*c8dee2aaSAndroid Build Coastguard Worker layerPaint.setImageFilter(SkImageFilters::Dilate(536870912, 0, nullptr, nullptr));
482*c8dee2aaSAndroid Build Coastguard Worker layerPaint.setBlendMode(SkBlendMode::kClear);
483*c8dee2aaSAndroid Build Coastguard Worker
484*c8dee2aaSAndroid Build Coastguard Worker canvas->saveLayer(nullptr, &layerPaint);
485*c8dee2aaSAndroid Build Coastguard Worker canvas->saveLayer(nullptr, nullptr);
486*c8dee2aaSAndroid Build Coastguard Worker
487*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
488*c8dee2aaSAndroid Build Coastguard Worker paint.setBlendMode(SkBlendMode::kDarken);
489*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(SkShaders::MakeFractalNoise(0, 0, 2, 0, nullptr));
490*c8dee2aaSAndroid Build Coastguard Worker paint.setColor4f(SkColor4f{0, 0, 0 ,0});
491*c8dee2aaSAndroid Build Coastguard Worker
492*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(SkPath(), paint);
493*c8dee2aaSAndroid Build Coastguard Worker }
494*c8dee2aaSAndroid Build Coastguard Worker #endif
495