xref: /aosp_15_r20/external/skia/tests/PDFGlyphsToUnicodeTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 
8 #include "include/core/SkTypes.h"
9 
10 #ifdef SK_SUPPORT_PDF
11 
12 #include "include/core/SkStream.h"
13 #include "include/private/base/SkTDArray.h"
14 #include "include/private/base/SkTemplates.h"
15 #include "include/private/base/SkTo.h"
16 #include "src/pdf/SkPDFGlyphUse.h"
17 #include "src/pdf/SkPDFMakeToUnicodeCmap.h"
18 #include "tests/Test.h"
19 
20 #include <algorithm>
21 #include <cstdint>
22 #include <cstring>
23 
24 using namespace skia_private;
25 
26 static constexpr SkGlyphID kMaximumGlyphIndex = UINT16_MAX;
27 
stream_equals(const SkDynamicMemoryWStream & stream,const char * buffer)28 static bool stream_equals(const SkDynamicMemoryWStream& stream, const char* buffer) {
29     const size_t streamSize = stream.bytesWritten();
30     AutoTMalloc<char> data(streamSize);
31     stream.copyTo(data.get());
32 
33     if ((false)) {
34         SkDebugf("Output\n%.*s\n", SkToInt(streamSize), data.data());
35     }
36 
37     if (streamSize != strlen(buffer)) {
38         return false;
39     }
40     return memcmp(data.get(), buffer, streamSize) == 0;
41 }
42 
DEF_TEST(SkPDF_ToUnicode,reporter)43 DEF_TEST(SkPDF_ToUnicode, reporter) {
44     SkTDArray<SkUnichar> glyphToUnicode;
45     THashMap<SkGlyphID, SkString> glyphToUnicodeEx;
46     SkTDArray<uint16_t> glyphsInSubset;
47     SkPDFGlyphUse subset(1, kMaximumGlyphIndex);
48 
49     glyphToUnicode.push_back(0);  // 0
50     glyphToUnicode.push_back(0);  // 1
51     glyphToUnicode.push_back(0);  // 2
52     glyphsInSubset.push_back(3);
53     glyphToUnicode.push_back(0x20);  // 3
54     glyphsInSubset.push_back(4);
55     glyphToUnicode.push_back(0x25);  // 4
56     glyphsInSubset.push_back(5);
57     glyphToUnicode.push_back(0x27);  // 5
58     glyphsInSubset.push_back(6);
59     glyphToUnicode.push_back(0x28);  // 6
60     glyphsInSubset.push_back(7);
61     glyphToUnicode.push_back(0x29);  // 7
62     glyphsInSubset.push_back(8);
63     glyphToUnicode.push_back(0x2F);  // 8
64     glyphsInSubset.push_back(9);
65     glyphToUnicode.push_back(0x33);  // 9
66     glyphToUnicode.push_back(0);  // 10
67     glyphsInSubset.push_back(11);
68     glyphToUnicode.push_back(0x35);  // 11
69     glyphsInSubset.push_back(12);
70     glyphToUnicode.push_back(0x36);  // 12
71     glyphsInSubset.push_back(13);
72     glyphToUnicode.push_back(0x37);  // 13
73     for (uint16_t i = 14; i < 0xFE; ++i) {
74         glyphToUnicode.push_back(0);  // Zero from index 0x9 to 0xFD
75     }
76     glyphsInSubset.push_back(0xFE);
77     glyphToUnicode.push_back(0x1010);
78     glyphsInSubset.push_back(0xFF);
79     glyphToUnicode.push_back(0x1011);
80     glyphsInSubset.push_back(0x100);
81     glyphToUnicode.push_back(0x1012);
82     glyphsInSubset.push_back(0x101);
83     glyphToUnicode.push_back(0x1013);
84 
85     glyphToUnicodeEx.set(0x9, SkString("ffi"));
86     glyphToUnicodeEx.set(0xFC, SkString("st"));
87 
88     SkGlyphID lastGlyphID = SkToU16(glyphToUnicode.size() - 1);
89 
90     SkDynamicMemoryWStream buffer;
91     for (uint16_t v : glyphsInSubset) {
92         subset.set(v);
93     }
94     SkPDFAppendCmapSections(glyphToUnicode.data(), glyphToUnicodeEx, &subset, &buffer, true, 0,
95                             std::min<SkGlyphID>(0xFFFF,  lastGlyphID));
96 
97     char expectedResult[] =
98 "4 beginbfchar\n\
99 <0003> <0020>\n\
100 <0004> <0025>\n\
101 <0008> <002F>\n\
102 <0009> <0033>\n\
103 endbfchar\n\
104 2 beginbfchar\n\
105 <0009> <006600660069>\n\
106 <00FC> <00730074>\n\
107 endbfchar\n\
108 4 beginbfrange\n\
109 <0005> <0007> <0027>\n\
110 <000B> <000D> <0035>\n\
111 <00FE> <00FF> <1010>\n\
112 <0100> <0101> <1012>\n\
113 endbfrange\n";
114 
115     REPORTER_ASSERT(reporter, stream_equals(buffer, expectedResult));
116 
117     // Remove characters and ranges.
118     buffer.reset();
119 
120     SkPDFAppendCmapSections(glyphToUnicode.data(), glyphToUnicodeEx, &subset, &buffer, true, 8,
121                             std::min<SkGlyphID>(0x00FF, lastGlyphID));
122 
123     char expectedResultChop1[] =
124 "2 beginbfchar\n\
125 <0008> <002F>\n\
126 <0009> <0033>\n\
127 endbfchar\n\
128 2 beginbfchar\n\
129 <0009> <006600660069>\n\
130 <00FC> <00730074>\n\
131 endbfchar\n\
132 2 beginbfrange\n\
133 <000B> <000D> <0035>\n\
134 <00FE> <00FF> <1010>\n\
135 endbfrange\n";
136 
137     REPORTER_ASSERT(reporter, stream_equals(buffer, expectedResultChop1));
138 
139     // Remove characters from range to downdrade it to one char.
140     buffer.reset();
141 
142     SkPDFAppendCmapSections(glyphToUnicode.data(), glyphToUnicodeEx, &subset, &buffer, true, 0x00D,
143                             std::min<SkGlyphID>(0x00FE, lastGlyphID));
144 
145     char expectedResultChop2[] =
146 "2 beginbfchar\n\
147 <000D> <0037>\n\
148 <00FE> <1010>\n\
149 endbfchar\n\
150 1 beginbfchar\n\
151 <00FC> <00730074>\n\
152 endbfchar\n";
153 
154     REPORTER_ASSERT(reporter, stream_equals(buffer, expectedResultChop2));
155 
156     buffer.reset();
157 
158     SkPDFAppendCmapSections(glyphToUnicode.data(), glyphToUnicodeEx, &subset, &buffer, false, 0xFC,
159                             std::min<SkGlyphID>(0x110, lastGlyphID));
160 
161     char expectedResultSingleBytes[] =
162 "1 beginbfchar\n\
163 <01> <00730074>\n\
164 endbfchar\n\
165 1 beginbfrange\n\
166 <03> <06> <1010>\n\
167 endbfrange\n";
168 
169     REPORTER_ASSERT(reporter, stream_equals(buffer, expectedResultSingleBytes));
170 
171     glyphToUnicode.reset();
172     glyphToUnicodeEx.reset();
173     glyphsInSubset.reset();
174     SkPDFGlyphUse subset2(1, kMaximumGlyphIndex);
175 
176     // Test mapping:
177     //           I  n  s  t  a  l
178     // Glyph id 2c 51 56 57 44 4f
179     // Unicode  49 6e 73 74 61 6c
180     for (SkUnichar i = 0; i < 100; ++i) {
181       glyphToUnicode.push_back(i + 29);
182     }
183     lastGlyphID = SkToU16(glyphToUnicode.size() - 1);
184 
185     glyphsInSubset.push_back(0x2C);
186     glyphsInSubset.push_back(0x44);
187     glyphsInSubset.push_back(0x4F);
188     glyphsInSubset.push_back(0x51);
189     glyphsInSubset.push_back(0x56);
190     glyphsInSubset.push_back(0x57);
191 
192     SkDynamicMemoryWStream buffer2;
193     for (uint16_t v : glyphsInSubset) {
194         subset2.set(v);
195     }
196     SkPDFAppendCmapSections(glyphToUnicode.data(), glyphToUnicodeEx, &subset2, &buffer2, true, 0,
197                             std::min<SkGlyphID>(0xFFFF, lastGlyphID));
198 
199     char expectedResult2[] =
200 "4 beginbfchar\n\
201 <002C> <0049>\n\
202 <0044> <0061>\n\
203 <004F> <006C>\n\
204 <0051> <006E>\n\
205 endbfchar\n\
206 1 beginbfrange\n\
207 <0056> <0057> <0073>\n\
208 endbfrange\n";
209 
210     REPORTER_ASSERT(reporter, stream_equals(buffer2, expectedResult2));
211 }
212 
213 #endif
214