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 "sfntly/port/type.h"
18 #include <assert.h>
19 #include <unicode/ucnv.h>
20 
21 #include <string>
22 #include <iostream>
23 
24 #include "gtest/gtest.h"
25 #include "sfntly/font.h"
26 #include "sfntly/font_factory.h"
27 #include "sfntly/table/core/cmap_table.h"
28 #include "sfntly/data/memory_byte_array.h"
29 #include "sfntly/table/core/font_header_table.h"
30 #include "sfntly/tag.h"
31 
32 #include "test/test_utils.h"
33 #include "test/test_font_utils.h"
34 #include "test/test_data.h"
35 
36 #if GTEST_HAS_PARAM_TEST
37 
38 namespace sfntly {
39 using ::testing::TestWithParam;
40 using ::testing::Values;
41 
42 class CMapTestCase {
43  public:
CMapTestCase(const char * font_name,int32_t first_platform_id,int32_t first_encoding_id,const char * first_charset_name,int32_t second_platform_id,int32_t second_encoding_id,const char * second_charset_name,int32_t low_char,int32_t high_char)44   CMapTestCase(const char* font_name,
45                int32_t first_platform_id,
46                int32_t first_encoding_id,
47                const char* first_charset_name,
48                int32_t second_platform_id,
49                int32_t second_encoding_id,
50                const char* second_charset_name,
51                int32_t low_char,
52                int32_t high_char)
53       : font_name_(font_name),
54         first_platform_id_(first_platform_id),
55         first_encoding_id_(first_encoding_id),
56         first_charset_name_(first_charset_name),
57         second_platform_id_(second_platform_id),
58         second_encoding_id_(second_encoding_id),
59         second_charset_name_(second_charset_name),
60         low_char_(low_char),
61         high_char_(high_char) {
62   }
63 
font_name() const64   const char* font_name() const { return font_name_; }
first_platform_id() const65   int32_t first_platform_id() const { return first_platform_id_; }
first_encoding_id() const66   int32_t first_encoding_id() const { return first_encoding_id_; }
first_charset_name() const67   const char* first_charset_name() const { return first_charset_name_; }
second_platform_id() const68   int32_t second_platform_id() const { return second_platform_id_; }
second_encoding_id() const69   int32_t second_encoding_id() const { return second_encoding_id_; }
second_charset_name() const70   const char* second_charset_name() const { return second_charset_name_; }
low_char() const71   int32_t low_char() const { return low_char_; }
high_char() const72   int32_t high_char() const { return high_char_; }
73 
74  private:
75   const char* font_name_;
76   int32_t first_platform_id_;
77   int32_t first_encoding_id_;
78   const char* first_charset_name_;
79   int32_t second_platform_id_;
80   int32_t second_encoding_id_;
81   const char* second_charset_name_;
82   int32_t low_char_;
83   int32_t high_char_;
84 };
85 
86 class CMapTests : public :: testing::TestWithParam<CMapTestCase> {
87  public:
CMapTests()88   CMapTests() : encoder1_(NULL), encoder2_(NULL), successful_setup_(false) {
89   }
SetUp()90   virtual void SetUp() {}
91   virtual void TearDown();
92 
93   void CommonSetUp(FontArray* font_array);
94 
95   void CompareCMaps();
96 
97   Ptr<CMapTable::CMap> cmap1_;
98   Ptr<CMapTable::CMap> cmap2_;
99   UConverter* encoder1_;
100   UConverter* encoder2_;
101   bool successful_setup_;
102 };
103 
operator <<(::std::ostream & os,const CMapTestCase * test_case)104 ::std::ostream& operator<<(::std::ostream& os, const CMapTestCase *test_case) {
105   return os << "("
106             << test_case->font_name() << ", "
107             << test_case->first_platform_id() << ", "
108             << test_case->first_encoding_id() << ", "
109             << test_case->first_charset_name() << ", "
110             << test_case->second_platform_id() << ", "
111             << test_case->second_encoding_id() << ", "
112             << test_case->second_charset_name() << ", "
113             << test_case->low_char() << ", "
114             << test_case->high_char() << ")";
115 }
116 
CommonSetUp(FontArray * font_array)117 void CMapTests::CommonSetUp(FontArray* font_array) {
118   ASSERT_NE(font_array, reinterpret_cast<FontArray*>(NULL));
119   ASSERT_FALSE(font_array->empty());
120   Ptr<Font> font;
121   font = font_array->at(0);
122   ASSERT_NE(font, reinterpret_cast<Font*>(NULL));
123   Ptr<CMapTable> cmap_table =
124       down_cast<CMapTable*>(font->GetTable(Tag::cmap));
125   cmap1_.Attach(cmap_table->GetCMap(GetParam().first_platform_id(),
126                                     GetParam().first_encoding_id()));
127   ASSERT_NE((cmap1_), reinterpret_cast<CMapTable::CMap*>(NULL));
128   cmap2_.Attach(cmap_table->GetCMap(GetParam().second_platform_id(),
129                                     GetParam().second_encoding_id()));
130   ASSERT_NE((cmap2_), reinterpret_cast<CMapTable::CMap*>(NULL));
131   encoder1_ = TestUtils::GetEncoder(GetParam().first_charset_name());
132   encoder2_ = TestUtils::GetEncoder(GetParam().second_charset_name());
133   successful_setup_ = true;
134 }
135 
TearDown()136 void CMapTests::TearDown() {
137   if (encoder1_)
138     ucnv_close(encoder1_);
139   if (encoder2_)
140     ucnv_close(encoder2_);
141 }
142 
CompareCMaps()143 void CMapTests::CompareCMaps() {
144   ASSERT_TRUE(successful_setup_);
145   for (int32_t uchar = GetParam().low_char();
146        uchar <= GetParam().high_char(); ++uchar) {
147     int32_t c1 = uchar;
148     if (encoder1_ != NULL)
149       c1 = TestUtils::EncodeOneChar(encoder1_, (int16_t)uchar);
150     int32_t c2 = uchar;
151     if (encoder2_ != NULL)
152       c2 = TestUtils::EncodeOneChar(encoder2_, (int16_t)uchar);
153     int32_t glyph_id1 = cmap1_->GlyphId(c1);
154     int32_t glyph_id2 = cmap2_->GlyphId(c2);
155 #ifdef SFNTLY_DEBUG_CMAP
156     if (glyph_id1 != glyph_id2)
157       fprintf(stderr, "%x: g1=%x, %x: g2=%x\n", c1, glyph_id1, c2, glyph_id2);
158 #endif
159     ASSERT_EQ(glyph_id1, glyph_id2);
160   }
161 #ifdef SFNTLY_SFNTLY_DEBUG_CMAPCMAP
162   fprintf(stderr, "\n");
163 #endif
164 }
165 
TEST_P(CMapTests,GlyphsBetweenCMapsFingerprint)166 TEST_P(CMapTests, GlyphsBetweenCMapsFingerprint) {
167   Ptr<FontFactory> font_factory;
168   font_factory.Attach(FontFactory::GetInstance());
169   font_factory->FingerprintFont(true);
170   FontArray font_array;
171   LoadFont(GetParam().font_name(), font_factory, &font_array);
172   CommonSetUp(&font_array);
173   CompareCMaps();
174 }
175 
TEST_P(CMapTests,GlyphsBetweenCMapsNoFingerprint)176 TEST_P(CMapTests, GlyphsBetweenCMapsNoFingerprint) {
177   Ptr<FontFactory> font_factory;
178   font_factory.Attach(FontFactory::GetInstance());
179   FontArray font_array;
180   LoadFont(GetParam().font_name(), font_factory, &font_array);
181   CommonSetUp(&font_array);
182   CompareCMaps();
183 }
184 
TEST_P(CMapTests,GlyphsBetweenCMapsUsingByteVector)185 TEST_P(CMapTests, GlyphsBetweenCMapsUsingByteVector) {
186   FontArray font_array;
187   LoadFontUsingByteVector(GetParam().font_name(), true, &font_array);
188   CommonSetUp(&font_array);
189   CompareCMaps();
190 }
191 
192 CMapTestCase kCMapTestsTestCases[] = {
193   CMapTestCase(SAMPLE_TTF_FILE,
194                PlatformId::kWindows,
195                WindowsEncodingId::kUnicodeUCS2,
196                NULL,
197                PlatformId::kUnicode,
198                UnicodeEncodingId::kUnicode2_0_BMP,
199                NULL,
200                (int32_t)0x20,
201                (int32_t)0x7f),
202 };
203 
204 INSTANTIATE_TEST_CASE_P(CMapTests,
205                         CMapTests,
206                         ::testing::ValuesIn(kCMapTestsTestCases));
207 }
208 
209 #else
210 
TEST(DummyTest,ValueParameterizedTestsAreNotSupportedOnThisPlatform)211 TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
212 
213 #endif  // GTEST_HAS_PARAM
214