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
38namespace sfntly {
39using ::testing::TestWithParam;
40using ::testing::Values;
41
42class CMapTestCase {
43 public:
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
64  const char* font_name() const { return font_name_; }
65  int32_t first_platform_id() const { return first_platform_id_; }
66  int32_t first_encoding_id() const { return first_encoding_id_; }
67  const char* first_charset_name() const { return first_charset_name_; }
68  int32_t second_platform_id() const { return second_platform_id_; }
69  int32_t second_encoding_id() const { return second_encoding_id_; }
70  const char* second_charset_name() const { return second_charset_name_; }
71  int32_t low_char() const { return low_char_; }
72  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
86class CMapTests : public :: testing::TestWithParam<CMapTestCase> {
87 public:
88  CMapTests() : encoder1_(NULL), encoder2_(NULL), successful_setup_(false) {
89  }
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
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
117void 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
136void CMapTests::TearDown() {
137  if (encoder1_)
138    ucnv_close(encoder1_);
139  if (encoder2_)
140    ucnv_close(encoder2_);
141}
142
143void 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
166TEST_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
176TEST_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
185TEST_P(CMapTests, GlyphsBetweenCMapsUsingByteVector) {
186  FontArray font_array;
187  LoadFontUsingByteVector(GetParam().font_name(), true, &font_array);
188  CommonSetUp(&font_array);
189  CompareCMaps();
190}
191
192CMapTestCase 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
204INSTANTIATE_TEST_CASE_P(CMapTests,
205                        CMapTests,
206                        ::testing::ValuesIn(kCMapTestsTestCases));
207}
208
209#else
210
211TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
212
213#endif  // GTEST_HAS_PARAM
214