/* * Copyright 2010 The Android Open Source Project * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/core/SkTypes.h" #ifdef SK_SUPPORT_PDF #include "include/core/SkStream.h" #include "include/private/base/SkTDArray.h" #include "include/private/base/SkTemplates.h" #include "include/private/base/SkTo.h" #include "src/pdf/SkPDFGlyphUse.h" #include "src/pdf/SkPDFMakeToUnicodeCmap.h" #include "tests/Test.h" #include #include #include using namespace skia_private; static constexpr SkGlyphID kMaximumGlyphIndex = UINT16_MAX; static bool stream_equals(const SkDynamicMemoryWStream& stream, const char* buffer) { const size_t streamSize = stream.bytesWritten(); AutoTMalloc data(streamSize); stream.copyTo(data.get()); if ((false)) { SkDebugf("Output\n%.*s\n", SkToInt(streamSize), data.data()); } if (streamSize != strlen(buffer)) { return false; } return memcmp(data.get(), buffer, streamSize) == 0; } DEF_TEST(SkPDF_ToUnicode, reporter) { SkTDArray glyphToUnicode; THashMap glyphToUnicodeEx; SkTDArray glyphsInSubset; SkPDFGlyphUse subset(1, kMaximumGlyphIndex); glyphToUnicode.push_back(0); // 0 glyphToUnicode.push_back(0); // 1 glyphToUnicode.push_back(0); // 2 glyphsInSubset.push_back(3); glyphToUnicode.push_back(0x20); // 3 glyphsInSubset.push_back(4); glyphToUnicode.push_back(0x25); // 4 glyphsInSubset.push_back(5); glyphToUnicode.push_back(0x27); // 5 glyphsInSubset.push_back(6); glyphToUnicode.push_back(0x28); // 6 glyphsInSubset.push_back(7); glyphToUnicode.push_back(0x29); // 7 glyphsInSubset.push_back(8); glyphToUnicode.push_back(0x2F); // 8 glyphsInSubset.push_back(9); glyphToUnicode.push_back(0x33); // 9 glyphToUnicode.push_back(0); // 10 glyphsInSubset.push_back(11); glyphToUnicode.push_back(0x35); // 11 glyphsInSubset.push_back(12); glyphToUnicode.push_back(0x36); // 12 glyphsInSubset.push_back(13); glyphToUnicode.push_back(0x37); // 13 for (uint16_t i = 14; i < 0xFE; ++i) { glyphToUnicode.push_back(0); // Zero from index 0x9 to 0xFD } glyphsInSubset.push_back(0xFE); glyphToUnicode.push_back(0x1010); glyphsInSubset.push_back(0xFF); glyphToUnicode.push_back(0x1011); glyphsInSubset.push_back(0x100); glyphToUnicode.push_back(0x1012); glyphsInSubset.push_back(0x101); glyphToUnicode.push_back(0x1013); glyphToUnicodeEx.set(0x9, SkString("ffi")); glyphToUnicodeEx.set(0xFC, SkString("st")); SkGlyphID lastGlyphID = SkToU16(glyphToUnicode.size() - 1); SkDynamicMemoryWStream buffer; for (uint16_t v : glyphsInSubset) { subset.set(v); } SkPDFAppendCmapSections(glyphToUnicode.data(), glyphToUnicodeEx, &subset, &buffer, true, 0, std::min(0xFFFF, lastGlyphID)); char expectedResult[] = "4 beginbfchar\n\ <0003> <0020>\n\ <0004> <0025>\n\ <0008> <002F>\n\ <0009> <0033>\n\ endbfchar\n\ 2 beginbfchar\n\ <0009> <006600660069>\n\ <00FC> <00730074>\n\ endbfchar\n\ 4 beginbfrange\n\ <0005> <0007> <0027>\n\ <000B> <000D> <0035>\n\ <00FE> <00FF> <1010>\n\ <0100> <0101> <1012>\n\ endbfrange\n"; REPORTER_ASSERT(reporter, stream_equals(buffer, expectedResult)); // Remove characters and ranges. buffer.reset(); SkPDFAppendCmapSections(glyphToUnicode.data(), glyphToUnicodeEx, &subset, &buffer, true, 8, std::min(0x00FF, lastGlyphID)); char expectedResultChop1[] = "2 beginbfchar\n\ <0008> <002F>\n\ <0009> <0033>\n\ endbfchar\n\ 2 beginbfchar\n\ <0009> <006600660069>\n\ <00FC> <00730074>\n\ endbfchar\n\ 2 beginbfrange\n\ <000B> <000D> <0035>\n\ <00FE> <00FF> <1010>\n\ endbfrange\n"; REPORTER_ASSERT(reporter, stream_equals(buffer, expectedResultChop1)); // Remove characters from range to downdrade it to one char. buffer.reset(); SkPDFAppendCmapSections(glyphToUnicode.data(), glyphToUnicodeEx, &subset, &buffer, true, 0x00D, std::min(0x00FE, lastGlyphID)); char expectedResultChop2[] = "2 beginbfchar\n\ <000D> <0037>\n\ <00FE> <1010>\n\ endbfchar\n\ 1 beginbfchar\n\ <00FC> <00730074>\n\ endbfchar\n"; REPORTER_ASSERT(reporter, stream_equals(buffer, expectedResultChop2)); buffer.reset(); SkPDFAppendCmapSections(glyphToUnicode.data(), glyphToUnicodeEx, &subset, &buffer, false, 0xFC, std::min(0x110, lastGlyphID)); char expectedResultSingleBytes[] = "1 beginbfchar\n\ <01> <00730074>\n\ endbfchar\n\ 1 beginbfrange\n\ <03> <06> <1010>\n\ endbfrange\n"; REPORTER_ASSERT(reporter, stream_equals(buffer, expectedResultSingleBytes)); glyphToUnicode.reset(); glyphToUnicodeEx.reset(); glyphsInSubset.reset(); SkPDFGlyphUse subset2(1, kMaximumGlyphIndex); // Test mapping: // I n s t a l // Glyph id 2c 51 56 57 44 4f // Unicode 49 6e 73 74 61 6c for (SkUnichar i = 0; i < 100; ++i) { glyphToUnicode.push_back(i + 29); } lastGlyphID = SkToU16(glyphToUnicode.size() - 1); glyphsInSubset.push_back(0x2C); glyphsInSubset.push_back(0x44); glyphsInSubset.push_back(0x4F); glyphsInSubset.push_back(0x51); glyphsInSubset.push_back(0x56); glyphsInSubset.push_back(0x57); SkDynamicMemoryWStream buffer2; for (uint16_t v : glyphsInSubset) { subset2.set(v); } SkPDFAppendCmapSections(glyphToUnicode.data(), glyphToUnicodeEx, &subset2, &buffer2, true, 0, std::min(0xFFFF, lastGlyphID)); char expectedResult2[] = "4 beginbfchar\n\ <002C> <0049>\n\ <0044> <0061>\n\ <004F> <006C>\n\ <0051> <006E>\n\ endbfchar\n\ 1 beginbfrange\n\ <0056> <0057> <0073>\n\ endbfrange\n"; REPORTER_ASSERT(reporter, stream_equals(buffer2, expectedResult2)); } #endif