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
36namespace sfntly {
37using ::testing::TestWithParam;
38using ::testing::Values;
39
40typedef std::vector<bool> BitSet;
41
42class CMapIteratorTestCase {
43 public:
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  }
50  ~CMapIteratorTestCase() {}
51  int32_t platform_id() const { return platform_id_; }
52  int32_t encoding_id() const { return encoding_id_; }
53  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
61class CMapIteratorTests
62    : public ::testing::TestWithParam<CMapIteratorTestCase> {
63 public:
64  virtual void SetUp();
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
75void 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
89BitSet* 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
99int32_t
100CMapIteratorTests::
101CompareCMapIterAndBitSet(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
130TEST_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
141CMapIteratorTestCase kCMapIteratorTestsTestCases[] = {
142  CMapIteratorTestCase(CMapTable::WINDOWS_BMP.platform_id,
143                       CMapTable::WINDOWS_BMP.encoding_id,
144                       SAMPLE_TTF_FILE)
145};
146
147INSTANTIATE_TEST_CASE_P(CMapIteratorTests,
148                        CMapIteratorTests,
149                        ::testing::ValuesIn(kCMapIteratorTestsTestCases));
150}
151
152#else
153
154TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
155
156#endif  // GTEST_HAS_PARAM
157