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 <string.h>
18 
19 #include <vector>
20 #include <string>
21 #include <algorithm>
22 
23 #include "sfntly/font.h"
24 #include "sfntly/font_factory.h"
25 #include "sfntly/table/core/cmap_table.h"
26 #include "sfntly/tag.h"
27 #include "sfntly/port/type.h"
28 #include "sfntly/port/refcount.h"
29 #include "test/test_data.h"
30 #include "test/test_font_utils.h"
31 
32 #include "gtest/gtest.h"
33 
34 #if GTEST_HAS_PARAM_TEST
35 
36 namespace sfntly {
37 using ::testing::TestWithParam;
38 using ::testing::Values;
39 
40 typedef std::vector<bool> BitSet;
41 
42 class CMapIteratorTestCase {
43  public:
CMapIteratorTestCase(int32_t platform_id,int32_t encoding_id,const char * file_name)44   CMapIteratorTestCase(int32_t platform_id, int32_t encoding_id,
45                        const char* file_name)
46       : platform_id_(platform_id),
47         encoding_id_(encoding_id),
48         file_name_(file_name) {
49   }
~CMapIteratorTestCase()50   ~CMapIteratorTestCase() {}
platform_id() const51   int32_t platform_id() const { return platform_id_; }
encoding_id() const52   int32_t encoding_id() const { return encoding_id_; }
file_name() const53   const char* file_name() const { return file_name_; }
54 
55  private:
56   int32_t platform_id_;
57   int32_t encoding_id_;
58   const char* file_name_;
59 };
60 
61 class CMapIteratorTests
62     : public ::testing::TestWithParam<CMapIteratorTestCase> {
63  public:
64   virtual void SetUp();
TearDown()65   virtual void TearDown() {}
66 
67   BitSet* GenerateCMapEntries(int32_t start, int32_t count);
68   int32_t CompareCMapIterAndBitSet(CMapTable::CMap::CharacterIterator*
69                                    character_iterator,
70                                    BitSet* bit_set);
71 
72   Ptr<CMapTable::CMap> cmap_;
73 };
74 
SetUp()75 void CMapIteratorTests::SetUp() {
76   FontArray fonts;
77   Ptr<FontFactory> font_factory;
78   const char* file_name = GetParam().file_name();
79   LoadFont(file_name, font_factory, &fonts);
80   Ptr<Font> font;
81   font.Attach(fonts[0].Detach());
82   Ptr<CMapTable> cmap_table = down_cast<CMapTable*>(font->GetTable(Tag::cmap));
83   ASSERT_FALSE(cmap_table == NULL);
84   cmap_.Attach(cmap_table->GetCMap(GetParam().platform_id(),
85                                    GetParam().encoding_id()));
86   ASSERT_FALSE(cmap_ == NULL);
87 }
88 
GenerateCMapEntries(int32_t start,int32_t count)89 BitSet* CMapIteratorTests::GenerateCMapEntries(int32_t start, int32_t count) {
90   BitSet* entries = new BitSet(count);
91   for (int32_t c = start; c < start + count; ++c) {
92     int32_t g = cmap_->GlyphId(c);
93     if (g != CMapTable::NOTDEF)
94       (*entries)[c] = true;
95   }
96   return entries;
97 }
98 
99 int32_t
100 CMapIteratorTests::
CompareCMapIterAndBitSet(CMapTable::CMap::CharacterIterator * character_iterator,BitSet * bit_set)101 CompareCMapIterAndBitSet(CMapTable::CMap::CharacterIterator* character_iterator,
102                          BitSet* bit_set) {
103   int32_t iterator_not_bitset_count = 0;
104   BitSet::iterator end = bit_set->end(),
105       beginning = bit_set->begin(),
106       init_beginning = beginning,
107       current = std::find(beginning, end, true);
108   for (int32_t next_bit = current - beginning;
109        character_iterator->HasNext() && current != end;
110        next_bit = current - init_beginning) {
111     int32_t c = character_iterator->Next();
112     EXPECT_TRUE(c <= next_bit || current == end);
113     if (!(c <= next_bit || current == end))
114       return -1;
115     if (c == next_bit) {
116       beginning = current + 1;
117       current = std::find(beginning, end, true);
118     } else {
119       iterator_not_bitset_count++;
120     }
121   }
122   EXPECT_EQ(end, current);
123 #if defined (SFNTLY_DEBUG_CMAP)
124   fprintf(stderr, "%s %d: Differences between iterator and bitset: %d\n",
125           cmap_->format(), GetParam().file_name(), iterator_not_bitset_count);
126 #endif
127   return iterator_not_bitset_count;
128 }
129 
TEST_P(CMapIteratorTests,IteratorTest)130 TEST_P(CMapIteratorTests, IteratorTest) {
131   BitSet* bit_set = GenerateCMapEntries(0, 0x10ffff);
132   CMapTable::CMap::CharacterIterator* character_iterator = NULL;
133   character_iterator = cmap_->Iterator();
134   EXPECT_NE(character_iterator,
135             reinterpret_cast<CMapTable::CMap::CharacterIterator*>(NULL));
136   CompareCMapIterAndBitSet(character_iterator, bit_set);
137   delete character_iterator;
138   delete bit_set;
139 }
140 
141 CMapIteratorTestCase kCMapIteratorTestsTestCases[] = {
142   CMapIteratorTestCase(CMapTable::WINDOWS_BMP.platform_id,
143                        CMapTable::WINDOWS_BMP.encoding_id,
144                        SAMPLE_TTF_FILE)
145 };
146 
147 INSTANTIATE_TEST_CASE_P(CMapIteratorTests,
148                         CMapIteratorTests,
149                         ::testing::ValuesIn(kCMapIteratorTestsTestCases));
150 }
151 
152 #else
153 
TEST(DummyTest,ValueParameterizedTestsAreNotSupportedOnThisPlatform)154 TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
155 
156 #endif  // GTEST_HAS_PARAM
157