1 /*
2  * Copyright 2011 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <vector>
18 #include <algorithm>
19 
20 #include "gtest/gtest.h"
21 #include "sfntly/port/type.h"
22 #include "sfntly/data/writable_font_data.h"
23 #include "sfntly/data/memory_byte_array.h"
24 
25 namespace sfntly {
26 
27 const int32_t BYTE_ARRAY_SIZES[] =
28   {1, 7, 127, 128, 129, 255, 256, 257, 666, 1023, 0x10000};
29 
30 // array data for searching
31 const int32_t LOWER_BYTE_ARRAY_FOR_SEARCHING[] = {2, 4, 7, 13, 127};
32 const int32_t UPPER_BYTE_ARRAY_FOR_SEARCHING[] = {2, 5, 12, 16, 256};
33 const int32_t kLowerByteArrayForSearchingLength = 5;
34 const int32_t kUpperByteArrayForSearchingLength = 5;
35 
36 // search test result pairs - number to search for; index found at
37 const int32_t SEARCH_TEST_PAIRS[][2] = {
38   {0, -1}, {1, -1}, {2, 0}, {3, -1}, {4, 1}, {5, 1}, {6, -1}, {12, 2},
39   {13, 3}, {17, -1}, {126, -1}, {127, 4}, {256, 4}, {257, -1}, {0x1000, -1}
40 };
41 const int32_t kSearchTestPairsLength = 15;
42 
43 // offset and start index data for searching data
44 // array data size, lower_start_index, lower_offset, upper_start_index,
45 // upper_offset
46 const int32_t SEARCH_TEST_OFFSETS[][5] = {
47   // lower[], upper[]
48   { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
49     * DataSize::kUSHORT,
50     0,
51     DataSize::kUSHORT,
52     kLowerByteArrayForSearchingLength * DataSize::kUSHORT,
53     DataSize::kUSHORT },
54 
55   // {lower, upper} []
56   { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
57     * DataSize::kUSHORT,
58     0,
59     2 * DataSize::kUSHORT,
60     DataSize::kUSHORT,
61     2 * DataSize::kUSHORT },
62 
63   // upper[], lower[]
64   { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
65     * DataSize::kUSHORT,
66     kLowerByteArrayForSearchingLength * DataSize::kUSHORT,
67     DataSize::kUSHORT,
68     0,
69     DataSize::kUSHORT },
70 
71   // {upper, lower} []
72   { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
73     * DataSize::kUSHORT,
74     DataSize::kUSHORT,
75     2 * DataSize::kUSHORT,
76     0,
77     2 * DataSize::kUSHORT }
78 };
79 const int32_t kSearchTestOffsetLength = 4;
80 
81 ReadableFontData*
FillTestFontDataWithShortsForSearching(WritableFontData * wfd,const int32_t * lower_data,int32_t lower_start_index,int32_t lower_offset,const int32_t * upper_data,int32_t upper_start_index,int32_t upper_offset)82 FillTestFontDataWithShortsForSearching(WritableFontData* wfd,
83                                        const int32_t* lower_data,
84                                        int32_t lower_start_index,
85                                        int32_t lower_offset,
86                                        const int32_t* upper_data,
87                                        int32_t upper_start_index,
88                                        int32_t upper_offset) {
89   // lower data
90   int offset = lower_start_index;
91   for (int32_t i = 0; i < kLowerByteArrayForSearchingLength; ++i) {
92     wfd->WriteUShort(offset, lower_data[i]);
93     offset += lower_offset;
94   }
95 
96   // upper data
97   offset = upper_start_index;
98   for (int32_t i = 0; i < kUpperByteArrayForSearchingLength; ++i) {
99     wfd->WriteUShort(offset, upper_data[i]);
100     offset += upper_offset;
101   }
102 
103   return wfd;
104 }
105 
TestReadableFontDataSearching()106 bool TestReadableFontDataSearching() {
107   for (int32_t i = 0; i < kSearchTestOffsetLength; ++i) {
108     const int32_t* array_setup_offset = SEARCH_TEST_OFFSETS[i];
109     WritableFontDataPtr wfd;
110     wfd.Attach(WritableFontData::CreateWritableFontData(array_setup_offset[0]));
111     FillTestFontDataWithShortsForSearching(wfd,
112                                            LOWER_BYTE_ARRAY_FOR_SEARCHING,
113                                            array_setup_offset[1],
114                                            array_setup_offset[2],
115                                            UPPER_BYTE_ARRAY_FOR_SEARCHING,
116                                            array_setup_offset[3],
117                                            array_setup_offset[4]);
118     for (int32_t j = 0; j < kSearchTestPairsLength; ++j) {
119       const int32_t* test_case = SEARCH_TEST_PAIRS[j];
120       int32_t found = wfd->SearchUShort(array_setup_offset[1],
121                                         array_setup_offset[2],
122                                         array_setup_offset[3],
123                                         array_setup_offset[4],
124                                         kLowerByteArrayForSearchingLength,
125                                         test_case[0]);
126 #if defined (SFNTLY_DEBUG_FONTDATA)
127       fprintf(stderr, "Searching for %d; Got %d; Expected %d; "
128               "[test %d][offset %d]\n",
129               test_case[0], found, test_case[1], j, i);
130 #endif
131       EXPECT_EQ(test_case[1], found);
132     }
133   }
134   return true;
135 }
136 
FillTestByteArray(ByteArray * ba,int32_t size)137 void FillTestByteArray(ByteArray* ba, int32_t size) {
138   for (int32_t i = 0; i < size; ++i) {
139     ba->Put(i, (byte_t)(i % 256));
140   }
141 }
142 
ReadFontDataWithSingleByte(ReadableFontData * rfd,ByteVector * buffer)143 void ReadFontDataWithSingleByte(ReadableFontData* rfd, ByteVector* buffer) {
144   buffer->resize(rfd->Length());
145   for (int32_t index = 0; index < rfd->Length(); ++index) {
146     (*buffer)[index] = (byte_t)(rfd->ReadByte(index));
147   }
148 }
149 
ReadFontDataWithBuffer(ReadableFontData * rfd,int32_t buffer_size,ByteVector * b)150 void ReadFontDataWithBuffer(ReadableFontData* rfd,
151                             int32_t buffer_size,
152                             ByteVector* b) {
153   ByteVector buffer(buffer_size);
154   b->resize(rfd->Length());
155 
156   int32_t index = 0;
157   while (index < rfd->Length()) {
158     int32_t bytes_read = rfd->ReadBytes(index, &(buffer[0]), 0, buffer.size());
159     EXPECT_GE(bytes_read, 0);
160     std::copy(buffer.begin(), buffer.begin() + bytes_read, b->begin() + index);
161     index += bytes_read;
162   }
163 }
164 
ReadFontDataWithSlidingWindow(ReadableFontData * rfd,int32_t window_size,ByteVector * b)165 void ReadFontDataWithSlidingWindow(ReadableFontData* rfd, int32_t window_size,
166                                    ByteVector* b) {
167   b->resize(rfd->Length());
168   int32_t index = 0;
169   while (index < rfd->Length()) {
170     int32_t actual_window_size =
171         std::min<int32_t>(window_size, b->size() - index);
172     int32_t bytes_read =
173         rfd->ReadBytes(index, &((*b)[0]), index, actual_window_size);
174     EXPECT_GE(bytes_read, 0);
175     index += bytes_read;
176   }
177 }
178 
WriteFontDataWithSingleByte(ReadableFontData * rfd,WritableFontData * wfd)179 void WriteFontDataWithSingleByte(ReadableFontData* rfd, WritableFontData* wfd) {
180   for (int32_t index = 0; index < rfd->Length(); ++index) {
181     byte_t b = (byte_t)(rfd->ReadByte(index));
182     wfd->WriteByte(index, b);
183   }
184 }
185 
WriteFontDataWithBuffer(ReadableFontData * rfd,WritableFontData * wfd,int32_t buffer_size)186 void WriteFontDataWithBuffer(ReadableFontData* rfd,
187                              WritableFontData* wfd,
188                              int32_t buffer_size) {
189   ByteVector buffer(buffer_size);
190   int32_t index = 0;
191   while (index < rfd->Length()) {
192     int32_t bytesRead = rfd->ReadBytes(index, &(buffer[0]), 0, buffer.size());
193     wfd->WriteBytes(index, &(buffer[0]), 0, buffer.size());
194     index += bytesRead;
195   }
196 }
197 
WriteFontDataWithSlidingWindow(ReadableFontData * rfd,WritableFontData * wfd,int32_t window_size)198 void WriteFontDataWithSlidingWindow(ReadableFontData* rfd,
199                                     WritableFontData* wfd,
200                                     int32_t window_size) {
201   ByteVector b(rfd->Length());
202   int32_t index = 0;
203   while (index < rfd->Length()) {
204     int32_t sliding_size = std::min<int32_t>(window_size, b.size() - index);
205     int32_t bytes_read = rfd->ReadBytes(index, &(b[0]), index, sliding_size);
206     wfd->WriteBytes(index, &(b[0]), index, sliding_size);
207     index += bytes_read;
208   }
209 }
210 
ReadComparison(int32_t offset,int32_t length,ReadableFontData * rfd1,ReadableFontData * rfd2)211 bool ReadComparison(int32_t offset,
212                     int32_t length,
213                     ReadableFontData* rfd1,
214                     ReadableFontData* rfd2) {
215   EXPECT_TRUE(length == rfd2->Length());
216   ByteVector b1, b2;
217   b1.resize(length);
218   b2.resize(length);
219 
220   // single byte reads
221   ReadFontDataWithSingleByte(rfd1, &b1);
222   ReadFontDataWithSingleByte(rfd2, &b2);
223   EXPECT_EQ(memcmp(&(b1[offset]), &(b2[0]), length), 0);
224 
225   // buffer reads
226   int32_t increments = std::max<int32_t>(length / 11, 1);
227   for (int32_t buffer_size = 1; buffer_size <= length;
228        buffer_size += increments) {
229     b1.clear();
230     b2.clear();
231     b1.resize(length);
232     b2.resize(length);
233     ReadFontDataWithBuffer(rfd1, buffer_size, &b1);
234     ReadFontDataWithBuffer(rfd2, buffer_size, &b2);
235     int result = memcmp(&(b1[offset]), &(b2[0]), length);
236     EXPECT_EQ(result, 0);
237   }
238 
239   // sliding window reads
240   for (int32_t window_size = 1; window_size <= length;
241        window_size += increments) {
242     b1.clear();
243     b2.clear();
244     b1.resize(length);
245     b2.resize(length);
246     ReadFontDataWithSlidingWindow(rfd1, window_size, &b1);
247     ReadFontDataWithSlidingWindow(rfd2, window_size, &b2);
248     int result = memcmp(&(b1[offset]), &(b2[0]), length);
249     EXPECT_EQ(result, 0);
250   }
251   return true;
252 }
253 
SlicingReadTest(ReadableFontData * rfd)254 void SlicingReadTest(ReadableFontData* rfd) {
255   fprintf(stderr, "read - trim = ");
256   for (int32_t trim = 0; trim < (rfd->Length() / 2) + 1;
257        trim += (rfd->Length() / 21) + 1) {
258     fprintf(stderr, "%d ", trim);
259     int32_t length = rfd->Length() - 2 * trim;
260     ReadableFontDataPtr slice;
261     slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length)));
262     EXPECT_TRUE(ReadComparison(trim, length, rfd, slice));
263   }
264   fprintf(stderr, "\n");
265 }
266 
SlicingWriteTest(ReadableFontData * rfd,WritableFontData * wfd)267 void SlicingWriteTest(ReadableFontData* rfd, WritableFontData* wfd) {
268   fprintf(stderr, "write - trim = ");
269   for (int32_t trim = 0; trim < (rfd->Length() / 2) + 1;
270        trim += (rfd->Length() / 21) + 1) {
271     fprintf(stderr, "%d ", trim);
272     int32_t length = rfd->Length() - 2 * trim;
273     WritableFontDataPtr w_slice;
274     ReadableFontDataPtr r_slice;
275 
276     // single byte writes
277     w_slice.Attach(down_cast<WritableFontData*>(wfd->Slice(trim, length)));
278     r_slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length)));
279     WriteFontDataWithSingleByte(r_slice, w_slice);
280     EXPECT_TRUE(ReadComparison(trim, length, rfd, w_slice));
281 
282     // buffer writes
283     int32_t increments = std::max<int32_t>(length / 11, 1);
284     for (int32_t buffer_size = 1; buffer_size < length;
285          buffer_size += increments) {
286       w_slice.Attach(down_cast<WritableFontData*>(wfd->Slice(trim, length)));
287       r_slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length)));
288       WriteFontDataWithBuffer(r_slice, w_slice, buffer_size);
289       EXPECT_TRUE(ReadComparison(trim, length, rfd, w_slice));
290     }
291 
292     // sliding window writes
293     for (int window_size = 1; window_size < length; window_size += increments) {
294       w_slice.Attach(down_cast<WritableFontData*>(wfd->Slice(trim, length)));
295       r_slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length)));
296       WriteFontDataWithSlidingWindow(r_slice, w_slice, window_size);
297       EXPECT_TRUE(ReadComparison(trim, length, rfd, w_slice));
298     }
299   }
300   fprintf(stderr, "\n");
301 }
302 
TestReadableFontData()303 bool TestReadableFontData() {
304   for (size_t i = 0; i < sizeof(BYTE_ARRAY_SIZES) / sizeof(int32_t); ++i) {
305     int32_t size = BYTE_ARRAY_SIZES[i];
306     ByteArrayPtr ba = new MemoryByteArray(size);
307     FillTestByteArray(ba, size);
308     ReadableFontDataPtr rfd = new ReadableFontData(ba);
309     SlicingReadTest(rfd);
310   }
311   return true;
312 }
313 
TestWritableFontData()314 bool TestWritableFontData() {
315   for (size_t i = 0; i < sizeof(BYTE_ARRAY_SIZES) / sizeof(int32_t); ++i) {
316     int32_t size = BYTE_ARRAY_SIZES[i];
317     ByteArrayPtr ba = new MemoryByteArray(size);
318     FillTestByteArray(ba, size);
319     WritableFontDataPtr wfd = new WritableFontData(ba);
320     SlicingReadTest(wfd);
321     ByteArrayPtr temp = new MemoryByteArray(size);
322     WritableFontDataPtr wfd_copy = new WritableFontData(temp);
323     SlicingWriteTest(wfd, wfd_copy);
324   }
325   return true;
326 }
327 
328 }  // namespace sfntly
329 
TEST(FontData,ReadableFontDataSearching)330 TEST(FontData, ReadableFontDataSearching) {
331   ASSERT_TRUE(sfntly::TestReadableFontDataSearching());
332 }
333 
TEST(FontData,All)334 TEST(FontData, All) {
335   ASSERT_TRUE(sfntly::TestReadableFontData());
336   ASSERT_TRUE(sfntly::TestWritableFontData());
337 }
338