PDFPrimitivesTest.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /*
  2. * Copyright 2010 The Android Open Source Project
  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. #include "tests/Test.h"
  8. #ifdef SK_SUPPORT_PDF
  9. #include "include/core/SkBitmap.h"
  10. #include "include/core/SkCanvas.h"
  11. #include "include/core/SkData.h"
  12. #include "include/core/SkImageEncoder.h"
  13. #include "include/core/SkMatrix.h"
  14. #include "include/core/SkScalar.h"
  15. #include "include/core/SkStream.h"
  16. #include "include/core/SkTypes.h"
  17. #include "include/private/SkTo.h"
  18. #include "src/core/SkGlyphRun.h"
  19. #include "src/core/SkImageFilterPriv.h"
  20. #include "src/core/SkMakeUnique.h"
  21. #include "src/core/SkReadBuffer.h"
  22. #include "src/core/SkSpecialImage.h"
  23. #include "src/pdf/SkClusterator.h"
  24. #include "src/pdf/SkDeflate.h"
  25. #include "src/pdf/SkPDFDevice.h"
  26. #include "src/pdf/SkPDFDocumentPriv.h"
  27. #include "src/pdf/SkPDFFont.h"
  28. #include "src/pdf/SkPDFTypes.h"
  29. #include "src/pdf/SkPDFUnion.h"
  30. #include "src/pdf/SkPDFUtils.h"
  31. #include "tools/Resources.h"
  32. #include "tools/ToolUtils.h"
  33. #include <cstdlib>
  34. #include <cmath>
  35. #define DUMMY_TEXT "DCT compessed stream."
  36. template <typename T>
  37. static SkString emit_to_string(T& obj) {
  38. SkDynamicMemoryWStream buffer;
  39. obj.emitObject(&buffer);
  40. SkString tmp(buffer.bytesWritten());
  41. buffer.copyTo(tmp.writable_str());
  42. return tmp;
  43. }
  44. static bool eq(const SkString& str, const char* strPtr, size_t len) {
  45. return len == str.size() && 0 == memcmp(str.c_str(), strPtr, len);
  46. }
  47. static void assert_eql(skiatest::Reporter* reporter,
  48. const SkString& skString,
  49. const char* str,
  50. size_t len) {
  51. if (!eq(skString, str, len)) {
  52. REPORT_FAILURE(reporter, "", SkStringPrintf(
  53. "'%*s' != '%s'", len, str, skString.c_str()));
  54. }
  55. }
  56. static void assert_eq(skiatest::Reporter* reporter,
  57. const SkString& skString,
  58. const char* str) {
  59. assert_eql(reporter, skString, str, strlen(str));
  60. }
  61. template <typename T>
  62. static void assert_emit_eq(skiatest::Reporter* reporter,
  63. T& object,
  64. const char* string) {
  65. SkString result = emit_to_string(object);
  66. assert_eq(reporter, result, string);
  67. }
  68. // This test used to assert without the fix submitted for
  69. // http://code.google.com/p/skia/issues/detail?id=1083.
  70. // SKP files might have invalid glyph ids. This test ensures they are ignored,
  71. // and there is no assert on input data in Debug mode.
  72. static void test_issue1083() {
  73. SkDynamicMemoryWStream outStream;
  74. auto doc = SkPDF::MakeDocument(&outStream);
  75. SkCanvas* canvas = doc->beginPage(100.0f, 100.0f);
  76. uint16_t glyphID = 65000;
  77. canvas->drawSimpleText(&glyphID, 2, SkTextEncoding::kGlyphID, 0, 0, SkFont(), SkPaint());
  78. doc->close();
  79. }
  80. static void assert_emit_eq_number(skiatest::Reporter* reporter, float number) {
  81. SkPDFUnion pdfUnion = SkPDFUnion::Scalar(number);
  82. SkString result = emit_to_string(pdfUnion);
  83. float value = static_cast<float>(std::atof(result.c_str()));
  84. if (value != number) {
  85. ERRORF(reporter, "%.9g != %s", number, result.c_str());
  86. }
  87. }
  88. static void TestPDFUnion(skiatest::Reporter* reporter) {
  89. SkPDFUnion boolTrue = SkPDFUnion::Bool(true);
  90. assert_emit_eq(reporter, boolTrue, "true");
  91. SkPDFUnion boolFalse = SkPDFUnion::Bool(false);
  92. assert_emit_eq(reporter, boolFalse, "false");
  93. SkPDFUnion int42 = SkPDFUnion::Int(42);
  94. assert_emit_eq(reporter, int42, "42");
  95. assert_emit_eq_number(reporter, SK_ScalarHalf);
  96. assert_emit_eq_number(reporter, 110999.75f); // bigScalar
  97. assert_emit_eq_number(reporter, 50000000.1f); // biggerScalar
  98. assert_emit_eq_number(reporter, 1.0f / 65536); // smallScalar
  99. SkPDFUnion stringSimple = SkPDFUnion::String("test ) string ( foo");
  100. assert_emit_eq(reporter, stringSimple, "(test \\) string \\( foo)");
  101. SkString stringComplexInput("\ttest ) string ( foo");
  102. SkPDFUnion stringComplex = SkPDFUnion::String(stringComplexInput);
  103. assert_emit_eq(reporter, stringComplex, "(\\011test \\) string \\( foo)");
  104. SkString binaryStringInput("\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20");
  105. SkPDFUnion binaryString = SkPDFUnion::String(binaryStringInput);
  106. assert_emit_eq(reporter, binaryString, "<0102030405060708090A0B0C0D0E0F10>");
  107. SkString nameInput("Test name\twith#tab");
  108. SkPDFUnion name = SkPDFUnion::Name(nameInput);
  109. assert_emit_eq(reporter, name, "/Test#20name#09with#23tab");
  110. SkString nameInput2("A#/%()<>[]{}B");
  111. SkPDFUnion name2 = SkPDFUnion::Name(nameInput2);
  112. assert_emit_eq(reporter, name2, "/A#23#2F#25#28#29#3C#3E#5B#5D#7B#7DB");
  113. SkPDFUnion name3 = SkPDFUnion::Name("SimpleNameWithOnlyPrintableASCII");
  114. assert_emit_eq(reporter, name3, "/SimpleNameWithOnlyPrintableASCII");
  115. // Test that we correctly handle characters with the high-bit set.
  116. SkString highBitString("\xDE\xAD" "be\xEF");
  117. SkPDFUnion highBitName = SkPDFUnion::Name(highBitString);
  118. assert_emit_eq(reporter, highBitName, "/#DE#ADbe#EF");
  119. }
  120. static void TestPDFArray(skiatest::Reporter* reporter) {
  121. std::unique_ptr<SkPDFArray> array(new SkPDFArray);
  122. assert_emit_eq(reporter, *array, "[]");
  123. array->appendInt(42);
  124. assert_emit_eq(reporter, *array, "[42]");
  125. array->appendScalar(SK_ScalarHalf);
  126. assert_emit_eq(reporter, *array, "[42 .5]");
  127. array->appendInt(0);
  128. assert_emit_eq(reporter, *array, "[42 .5 0]");
  129. array->appendBool(true);
  130. assert_emit_eq(reporter, *array, "[42 .5 0 true]");
  131. array->appendName("ThisName");
  132. assert_emit_eq(reporter, *array, "[42 .5 0 true /ThisName]");
  133. array->appendName(SkString("AnotherName"));
  134. assert_emit_eq(reporter, *array, "[42 .5 0 true /ThisName /AnotherName]");
  135. array->appendString("This String");
  136. assert_emit_eq(reporter, *array,
  137. "[42 .5 0 true /ThisName /AnotherName (This String)]");
  138. array->appendString(SkString("Another String"));
  139. assert_emit_eq(reporter, *array,
  140. "[42 .5 0 true /ThisName /AnotherName (This String) "
  141. "(Another String)]");
  142. std::unique_ptr<SkPDFArray> innerArray(new SkPDFArray);
  143. innerArray->appendInt(-1);
  144. array->appendObject(std::move(innerArray));
  145. assert_emit_eq(reporter, *array,
  146. "[42 .5 0 true /ThisName /AnotherName (This String) "
  147. "(Another String) [-1]]");
  148. }
  149. static void TestPDFDict(skiatest::Reporter* reporter) {
  150. std::unique_ptr<SkPDFDict> dict(new SkPDFDict);
  151. assert_emit_eq(reporter, *dict, "<<>>");
  152. dict->insertInt("n1", SkToSizeT(42));
  153. assert_emit_eq(reporter, *dict, "<</n1 42>>");
  154. dict.reset(new SkPDFDict);
  155. assert_emit_eq(reporter, *dict, "<<>>");
  156. dict->insertInt("n1", 42);
  157. assert_emit_eq(reporter, *dict, "<</n1 42>>");
  158. dict->insertScalar("n2", SK_ScalarHalf);
  159. SkString n3("n3");
  160. std::unique_ptr<SkPDFArray> innerArray(new SkPDFArray);
  161. innerArray->appendInt(-100);
  162. dict->insertObject(n3, std::move(innerArray));
  163. assert_emit_eq(reporter, *dict, "<</n1 42\n/n2 .5\n/n3 [-100]>>");
  164. dict.reset(new SkPDFDict);
  165. assert_emit_eq(reporter, *dict, "<<>>");
  166. dict->insertInt("n1", 24);
  167. assert_emit_eq(reporter, *dict, "<</n1 24>>");
  168. dict->insertInt("n2", SkToSizeT(99));
  169. assert_emit_eq(reporter, *dict, "<</n1 24\n/n2 99>>");
  170. dict->insertScalar("n3", SK_ScalarHalf);
  171. assert_emit_eq(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5>>");
  172. dict->insertName("n4", "AName");
  173. assert_emit_eq(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5\n/n4 /AName>>");
  174. dict->insertName("n5", SkString("AnotherName"));
  175. assert_emit_eq(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5\n/n4 /AName\n"
  176. "/n5 /AnotherName>>");
  177. dict->insertString("n6", "A String");
  178. assert_emit_eq(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5\n/n4 /AName\n"
  179. "/n5 /AnotherName\n/n6 (A String)>>");
  180. dict->insertString("n7", SkString("Another String"));
  181. assert_emit_eq(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5\n/n4 /AName\n"
  182. "/n5 /AnotherName\n/n6 (A String)\n/n7 (Another String)>>");
  183. dict.reset(new SkPDFDict("DType"));
  184. assert_emit_eq(reporter, *dict, "<</Type /DType>>");
  185. }
  186. DEF_TEST(SkPDF_Primitives, reporter) {
  187. TestPDFUnion(reporter);
  188. TestPDFArray(reporter);
  189. TestPDFDict(reporter);
  190. test_issue1083();
  191. }
  192. namespace {
  193. class DummyImageFilter : public SkImageFilter {
  194. public:
  195. static sk_sp<DummyImageFilter> Make(bool visited = false) {
  196. return sk_sp<DummyImageFilter>(new DummyImageFilter(visited));
  197. }
  198. bool visited() const { return fVisited; }
  199. protected:
  200. sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
  201. SkIPoint* offset) const override {
  202. fVisited = true;
  203. offset->fX = offset->fY = 0;
  204. return sk_ref_sp<SkSpecialImage>(source);
  205. }
  206. private:
  207. SK_FLATTENABLE_HOOKS(DummyImageFilter)
  208. DummyImageFilter(bool visited) : INHERITED(nullptr, 0, nullptr), fVisited(visited) {}
  209. mutable bool fVisited;
  210. typedef SkImageFilter INHERITED;
  211. };
  212. sk_sp<SkFlattenable> DummyImageFilter::CreateProc(SkReadBuffer& buffer) {
  213. SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
  214. bool visited = buffer.readBool();
  215. return DummyImageFilter::Make(visited);
  216. }
  217. };
  218. // Check that PDF rendering of image filters successfully falls back to
  219. // CPU rasterization.
  220. DEF_TEST(SkPDF_ImageFilter, reporter) {
  221. REQUIRE_PDF_DOCUMENT(SkPDF_ImageFilter, reporter);
  222. SkDynamicMemoryWStream stream;
  223. auto doc = SkPDF::MakeDocument(&stream);
  224. SkCanvas* canvas = doc->beginPage(100.0f, 100.0f);
  225. sk_sp<DummyImageFilter> filter(DummyImageFilter::Make());
  226. // Filter just created; should be unvisited.
  227. REPORTER_ASSERT(reporter, !filter->visited());
  228. SkPaint paint;
  229. paint.setImageFilter(filter);
  230. canvas->drawRect(SkRect::MakeWH(100, 100), paint);
  231. doc->close();
  232. // Filter was used in rendering; should be visited.
  233. REPORTER_ASSERT(reporter, filter->visited());
  234. }
  235. // Check that PDF rendering of image filters successfully falls back to
  236. // CPU rasterization.
  237. DEF_TEST(SkPDF_FontCanEmbedTypeface, reporter) {
  238. SkNullWStream nullWStream;
  239. SkPDFDocument doc(&nullWStream, SkPDF::Metadata());
  240. const char resource[] = "fonts/Roboto2-Regular_NoEmbed.ttf";
  241. sk_sp<SkTypeface> noEmbedTypeface(MakeResourceAsTypeface(resource));
  242. if (noEmbedTypeface) {
  243. REPORTER_ASSERT(reporter,
  244. !SkPDFFont::CanEmbedTypeface(noEmbedTypeface.get(), &doc));
  245. }
  246. sk_sp<SkTypeface> portableTypeface(ToolUtils::create_portable_typeface(nullptr, SkFontStyle()));
  247. REPORTER_ASSERT(reporter,
  248. SkPDFFont::CanEmbedTypeface(portableTypeface.get(), &doc));
  249. }
  250. // test to see that all finite scalars round trip via scanf().
  251. static void check_pdf_scalar_serialization(
  252. skiatest::Reporter* reporter, float inputFloat) {
  253. char floatString[kMaximumSkFloatToDecimalLength];
  254. size_t len = SkFloatToDecimal(inputFloat, floatString);
  255. if (len >= sizeof(floatString)) {
  256. ERRORF(reporter, "string too long: %u", (unsigned)len);
  257. return;
  258. }
  259. if (floatString[len] != '\0' || strlen(floatString) != len) {
  260. ERRORF(reporter, "terminator misplaced.");
  261. return; // The terminator is needed for sscanf().
  262. }
  263. if (reporter->verbose()) {
  264. SkDebugf("%15.9g = \"%s\"\n", inputFloat, floatString);
  265. }
  266. float roundTripFloat;
  267. if (1 != sscanf(floatString, "%f", &roundTripFloat)) {
  268. ERRORF(reporter, "unscannable result: %s", floatString);
  269. return;
  270. }
  271. if (std::isfinite(inputFloat) && roundTripFloat != inputFloat) {
  272. ERRORF(reporter, "roundTripFloat (%.9g) != inputFloat (%.9g)",
  273. roundTripFloat, inputFloat);
  274. }
  275. }
  276. // Test SkPDFUtils::AppendScalar for accuracy.
  277. DEF_TEST(SkPDF_Primitives_Scalar, reporter) {
  278. SkRandom random(0x5EED);
  279. int iterationCount = 512;
  280. while (iterationCount-- > 0) {
  281. union { uint32_t u; float f; };
  282. u = random.nextU();
  283. static_assert(sizeof(float) == sizeof(uint32_t), "");
  284. check_pdf_scalar_serialization(reporter, f);
  285. }
  286. float alwaysCheck[] = {
  287. 0.0f, -0.0f, 1.0f, -1.0f, SK_ScalarPI, 0.1f, FLT_MIN, FLT_MAX,
  288. -FLT_MIN, -FLT_MAX, FLT_MIN / 16.0f, -FLT_MIN / 16.0f,
  289. SK_FloatNaN, SK_FloatInfinity, SK_FloatNegativeInfinity,
  290. -FLT_MIN / 8388608.0
  291. };
  292. for (float inputFloat: alwaysCheck) {
  293. check_pdf_scalar_serialization(reporter, inputFloat);
  294. }
  295. }
  296. // Test SkPDFUtils:: for accuracy.
  297. DEF_TEST(SkPDF_Primitives_Color, reporter) {
  298. char buffer[5];
  299. for (int i = 0; i < 256; ++i) {
  300. size_t len = SkPDFUtils::ColorToDecimal(i, buffer);
  301. REPORTER_ASSERT(reporter, len == strlen(buffer));
  302. float f;
  303. REPORTER_ASSERT(reporter, 1 == sscanf(buffer, "%f", &f));
  304. int roundTrip = (int)(0.5 + f * 255);
  305. REPORTER_ASSERT(reporter, roundTrip == i);
  306. }
  307. }
  308. static SkGlyphRun make_run(size_t len, const SkGlyphID* glyphs, SkPoint* pos,
  309. const SkFont& font, const uint32_t* clusters,
  310. size_t utf8TextByteLength, const char* utf8Text) {
  311. return SkGlyphRun(font,
  312. SkSpan<const SkPoint>{pos, len},
  313. SkSpan<const SkGlyphID>{glyphs, len},
  314. SkSpan<const char>{utf8Text, utf8TextByteLength},
  315. SkSpan<const uint32_t>{clusters, len});
  316. }
  317. DEF_TEST(SkPDF_Clusterator, reporter) {
  318. SkFont font;
  319. {
  320. constexpr unsigned len = 11;
  321. const uint32_t clusters[len] = { 3, 2, 2, 1, 0, 4, 4, 7, 6, 6, 5 };
  322. const SkGlyphID glyphs[len] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
  323. SkPoint pos[len] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
  324. {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
  325. const char text[] = "abcdefgh";
  326. SkGlyphRun run = make_run(len, glyphs, pos, font, clusters, strlen(text), text);
  327. SkClusterator clusterator(run);
  328. SkClusterator::Cluster expectations[] = {
  329. {&text[3], 1, 0, 1},
  330. {&text[2], 1, 1, 2},
  331. {&text[1], 1, 3, 1},
  332. {&text[0], 1, 4, 1},
  333. {&text[4], 1, 5, 2},
  334. {&text[7], 1, 7, 1},
  335. {&text[6], 1, 8, 2},
  336. {&text[5], 1, 10, 1},
  337. {nullptr, 0, 0, 0},
  338. };
  339. for (const auto& expectation : expectations) {
  340. REPORTER_ASSERT(reporter, clusterator.next() == expectation);
  341. }
  342. }
  343. {
  344. constexpr unsigned len = 5;
  345. const uint32_t clusters[len] = { 0, 1, 4, 5, 6 };
  346. const SkGlyphID glyphs[len] = { 43, 167, 79, 79, 82, };
  347. SkPoint pos[len] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
  348. const char text[] = "Ha\xCC\x8A" "llo";
  349. SkGlyphRun run = make_run(len, glyphs, pos, font, clusters, strlen(text), text);
  350. SkClusterator clusterator(run);
  351. SkClusterator::Cluster expectations[] = {
  352. {&text[0], 1, 0, 1},
  353. {&text[1], 3, 1, 1},
  354. {&text[4], 1, 2, 1},
  355. {&text[5], 1, 3, 1},
  356. {&text[6], 1, 4, 1},
  357. {nullptr, 0, 0, 0},
  358. };
  359. for (const auto& expectation : expectations) {
  360. REPORTER_ASSERT(reporter, clusterator.next() == expectation);
  361. }
  362. }
  363. }
  364. #endif