/src/tesseract/src/ccstruct/fontinfo.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /////////////////////////////////////////////////////////////////////// |
2 | | // File: fontinfo.cpp |
3 | | // Description: Font information classes abstracted from intproto.h/cpp. |
4 | | // Author: rays@google.com (Ray Smith) |
5 | | // |
6 | | // (C) Copyright 2011, Google Inc. |
7 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | // you may not use this file except in compliance with the License. |
9 | | // You may obtain a copy of the License at |
10 | | // http://www.apache.org/licenses/LICENSE-2.0 |
11 | | // Unless required by applicable law or agreed to in writing, software |
12 | | // distributed under the License is distributed on an "AS IS" BASIS, |
13 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | | // See the License for the specific language governing permissions and |
15 | | // limitations under the License. |
16 | | // |
17 | | /////////////////////////////////////////////////////////////////////// |
18 | | |
19 | | #include "fontinfo.h" |
20 | | #include "bitvector.h" |
21 | | #include "unicity_table.h" |
22 | | |
23 | | namespace tesseract { |
24 | | |
25 | | // Writes to the given file. Returns false in case of error. |
26 | 0 | bool FontInfo::Serialize(FILE *fp) const { |
27 | 0 | if (!write_info(fp, *this)) { |
28 | 0 | return false; |
29 | 0 | } |
30 | 0 | if (!write_spacing_info(fp, *this)) { |
31 | 0 | return false; |
32 | 0 | } |
33 | 0 | return true; |
34 | 0 | } |
35 | | // Reads from the given file. Returns false in case of error. |
36 | | // If swap is true, assumes a big/little-endian swap is needed. |
37 | 0 | bool FontInfo::DeSerialize(TFile *fp) { |
38 | 0 | if (!read_info(fp, this)) { |
39 | 0 | return false; |
40 | 0 | } |
41 | 0 | if (!read_spacing_info(fp, this)) { |
42 | 0 | return false; |
43 | 0 | } |
44 | 0 | return true; |
45 | 0 | } |
46 | | |
47 | 0 | FontInfoTable::FontInfoTable() { |
48 | 0 | using namespace std::placeholders; // for _1, _2 |
49 | 0 | set_clear_callback(std::bind(FontInfoDeleteCallback, _1)); |
50 | 0 | } |
51 | | |
52 | 0 | FontInfoTable::~FontInfoTable() = default; |
53 | | |
54 | | // Writes to the given file. Returns false in case of error. |
55 | 0 | bool FontInfoTable::Serialize(FILE *fp) const { |
56 | 0 | return this->SerializeClasses(fp); |
57 | 0 | } |
58 | | // Reads from the given file. Returns false in case of error. |
59 | | // If swap is true, assumes a big/little-endian swap is needed. |
60 | 0 | bool FontInfoTable::DeSerialize(TFile *fp) { |
61 | 0 | truncate(0); |
62 | 0 | return this->DeSerializeClasses(fp); |
63 | 0 | } |
64 | | |
65 | | // Returns true if the given set of fonts includes one with the same |
66 | | // properties as font_id. |
67 | | bool FontInfoTable::SetContainsFontProperties(int font_id, |
68 | 0 | const std::vector<ScoredFont> &font_set) const { |
69 | 0 | uint32_t properties = at(font_id).properties; |
70 | 0 | for (auto &&f : font_set) { |
71 | 0 | if (at(f.fontinfo_id).properties == properties) { |
72 | 0 | return true; |
73 | 0 | } |
74 | 0 | } |
75 | 0 | return false; |
76 | 0 | } |
77 | | |
78 | | // Returns true if the given set of fonts includes multiple properties. |
79 | | bool FontInfoTable::SetContainsMultipleFontProperties( |
80 | 0 | const std::vector<ScoredFont> &font_set) const { |
81 | 0 | if (font_set.empty()) { |
82 | 0 | return false; |
83 | 0 | } |
84 | 0 | int first_font = font_set[0].fontinfo_id; |
85 | 0 | uint32_t properties = at(first_font).properties; |
86 | 0 | for (unsigned f = 1; f < font_set.size(); ++f) { |
87 | 0 | if (at(font_set[f].fontinfo_id).properties != properties) { |
88 | 0 | return true; |
89 | 0 | } |
90 | 0 | } |
91 | 0 | return false; |
92 | 0 | } |
93 | | |
94 | | // Moves any non-empty FontSpacingInfo entries from other to this. |
95 | 0 | void FontInfoTable::MoveSpacingInfoFrom(FontInfoTable *other) { |
96 | 0 | using namespace std::placeholders; // for _1, _2 |
97 | 0 | set_clear_callback(std::bind(FontInfoDeleteCallback, _1)); |
98 | 0 | for (unsigned i = 0; i < other->size(); ++i) { |
99 | 0 | std::vector<FontSpacingInfo *> *spacing_vec = other->at(i).spacing_vec; |
100 | 0 | if (spacing_vec != nullptr) { |
101 | 0 | int target_index = get_index(other->at(i)); |
102 | 0 | if (target_index < 0) { |
103 | | // Bit copy the FontInfo and steal all the pointers. |
104 | 0 | push_back(other->at(i)); |
105 | 0 | other->at(i).name = nullptr; |
106 | 0 | } else { |
107 | 0 | delete at(target_index).spacing_vec; |
108 | 0 | at(target_index).spacing_vec = other->at(i).spacing_vec; |
109 | 0 | } |
110 | 0 | other->at(i).spacing_vec = nullptr; |
111 | 0 | } |
112 | 0 | } |
113 | 0 | } |
114 | | |
115 | | // Moves this to the target unicity table. |
116 | 0 | void FontInfoTable::MoveTo(UnicityTable<FontInfo> *target) { |
117 | 0 | target->clear(); |
118 | 0 | using namespace std::placeholders; // for _1, _2 |
119 | 0 | target->set_clear_callback(std::bind(FontInfoDeleteCallback, _1)); |
120 | 0 | for (unsigned i = 0; i < size(); ++i) { |
121 | | // Bit copy the FontInfo and steal all the pointers. |
122 | 0 | target->push_back(at(i)); |
123 | 0 | at(i).name = nullptr; |
124 | 0 | at(i).spacing_vec = nullptr; |
125 | 0 | } |
126 | 0 | } |
127 | | |
128 | | // Callbacks for GenericVector. |
129 | 0 | void FontInfoDeleteCallback(FontInfo f) { |
130 | 0 | if (f.spacing_vec != nullptr) { |
131 | 0 | for (auto data : *f.spacing_vec) { |
132 | 0 | delete data; |
133 | 0 | } |
134 | 0 | delete f.spacing_vec; |
135 | 0 | f.spacing_vec = nullptr; |
136 | 0 | } |
137 | 0 | delete[] f.name; |
138 | 0 | f.name = nullptr; |
139 | 0 | } |
140 | | |
141 | | /*---------------------------------------------------------------------------*/ |
142 | | // Callbacks used by UnicityTable to read/write FontInfo/FontSet structures. |
143 | 1.70k | bool read_info(TFile *f, FontInfo *fi) { |
144 | 1.70k | uint32_t size; |
145 | 1.70k | if (!f->DeSerialize(&size)) { |
146 | 0 | return false; |
147 | 0 | } |
148 | 1.70k | char *font_name = new char[size + 1]; |
149 | 1.70k | fi->name = font_name; |
150 | 1.70k | if (!f->DeSerialize(font_name, size)) { |
151 | 0 | return false; |
152 | 0 | } |
153 | 1.70k | font_name[size] = '\0'; |
154 | 1.70k | return f->DeSerialize(&fi->properties); |
155 | 1.70k | } |
156 | | |
157 | 0 | bool write_info(FILE *f, const FontInfo &fi) { |
158 | 0 | int32_t size = strlen(fi.name); |
159 | 0 | return tesseract::Serialize(f, &size) && tesseract::Serialize(f, &fi.name[0], size) && |
160 | 0 | tesseract::Serialize(f, &fi.properties); |
161 | 0 | } |
162 | | |
163 | 1.70k | bool read_spacing_info(TFile *f, FontInfo *fi) { |
164 | 1.70k | int32_t vec_size, kern_size; |
165 | 1.70k | if (!f->DeSerialize(&vec_size)) { |
166 | 0 | return false; |
167 | 0 | } |
168 | 1.70k | ASSERT_HOST(vec_size >= 0); |
169 | 1.70k | if (vec_size == 0) { |
170 | 1.58k | return true; |
171 | 1.58k | } |
172 | 128 | fi->init_spacing(vec_size); |
173 | 14.5k | for (int i = 0; i < vec_size; ++i) { |
174 | 14.4k | auto *fs = new FontSpacingInfo(); |
175 | 14.4k | if (!f->DeSerialize(&fs->x_gap_before) || !f->DeSerialize(&fs->x_gap_after) || |
176 | 14.4k | !f->DeSerialize(&kern_size)) { |
177 | 0 | delete fs; |
178 | 0 | return false; |
179 | 0 | } |
180 | 14.4k | if (kern_size < 0) { // indication of a nullptr entry in fi->spacing_vec |
181 | 2.56k | delete fs; |
182 | 2.56k | continue; |
183 | 2.56k | } |
184 | 11.9k | if (kern_size > 0 && |
185 | 11.9k | (!f->DeSerialize(fs->kerned_unichar_ids) || !f->DeSerialize(fs->kerned_x_gaps))) { |
186 | 0 | delete fs; |
187 | 0 | return false; |
188 | 0 | } |
189 | 11.9k | fi->add_spacing(i, fs); |
190 | 11.9k | } |
191 | 128 | return true; |
192 | 128 | } |
193 | | |
194 | 0 | bool write_spacing_info(FILE *f, const FontInfo &fi) { |
195 | 0 | int32_t vec_size = (fi.spacing_vec == nullptr) ? 0 : fi.spacing_vec->size(); |
196 | 0 | if (!tesseract::Serialize(f, &vec_size)) { |
197 | 0 | return false; |
198 | 0 | } |
199 | 0 | int16_t x_gap_invalid = -1; |
200 | 0 | for (int i = 0; i < vec_size; ++i) { |
201 | 0 | FontSpacingInfo *fs = fi.spacing_vec->at(i); |
202 | 0 | int32_t kern_size = (fs == nullptr) ? -1 : fs->kerned_x_gaps.size(); |
203 | 0 | if (fs == nullptr) { |
204 | | // Writing two invalid x-gaps. |
205 | 0 | if (!tesseract::Serialize(f, &x_gap_invalid, 2) || !tesseract::Serialize(f, &kern_size)) { |
206 | 0 | return false; |
207 | 0 | } |
208 | 0 | } else { |
209 | 0 | if (!tesseract::Serialize(f, &fs->x_gap_before) || |
210 | 0 | !tesseract::Serialize(f, &fs->x_gap_after) || !tesseract::Serialize(f, &kern_size)) { |
211 | 0 | return false; |
212 | 0 | } |
213 | 0 | } |
214 | 0 | if (kern_size > 0 && |
215 | 0 | (!Serialize(f, fs->kerned_unichar_ids) || !Serialize(f, fs->kerned_x_gaps))) { |
216 | 0 | return false; |
217 | 0 | } |
218 | 0 | } |
219 | 0 | return true; |
220 | 0 | } |
221 | | |
222 | 0 | bool write_set(FILE *f, const FontSet &fs) { |
223 | 0 | int size = fs.size(); |
224 | 0 | return tesseract::Serialize(f, &size) && |
225 | 0 | (size > 0 ? tesseract::Serialize(f, &fs[0], size) : true); |
226 | 0 | } |
227 | | |
228 | | } // namespace tesseract. |