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.
Serialize(FILE * fp) const26 bool FontInfo::Serialize(FILE *fp) const {
27   if (!write_info(fp, *this)) {
28     return false;
29   }
30   if (!write_spacing_info(fp, *this)) {
31     return false;
32   }
33   return true;
34 }
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.
DeSerialize(TFile * fp)37 bool FontInfo::DeSerialize(TFile *fp) {
38   if (!read_info(fp, this)) {
39     return false;
40   }
41   if (!read_spacing_info(fp, this)) {
42     return false;
43   }
44   return true;
45 }
46 
FontInfoTable()47 FontInfoTable::FontInfoTable() {
48   using namespace std::placeholders; // for _1, _2
49   set_clear_callback(std::bind(FontInfoDeleteCallback, _1));
50 }
51 
52 FontInfoTable::~FontInfoTable() = default;
53 
54 // Writes to the given file. Returns false in case of error.
Serialize(FILE * fp) const55 bool FontInfoTable::Serialize(FILE *fp) const {
56   return this->SerializeClasses(fp);
57 }
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.
DeSerialize(TFile * fp)60 bool FontInfoTable::DeSerialize(TFile *fp) {
61   truncate(0);
62   return this->DeSerializeClasses(fp);
63 }
64 
65 // Returns true if the given set of fonts includes one with the same
66 // properties as font_id.
SetContainsFontProperties(int font_id,const std::vector<ScoredFont> & font_set) const67 bool FontInfoTable::SetContainsFontProperties(int font_id,
68                                               const std::vector<ScoredFont> &font_set) const {
69   uint32_t properties = at(font_id).properties;
70   for (auto f : font_set) {
71     if (at(f.fontinfo_id).properties == properties) {
72       return true;
73     }
74   }
75   return false;
76 }
77 
78 // Returns true if the given set of fonts includes multiple properties.
SetContainsMultipleFontProperties(const std::vector<ScoredFont> & font_set) const79 bool FontInfoTable::SetContainsMultipleFontProperties(
80     const std::vector<ScoredFont> &font_set) const {
81   if (font_set.empty()) {
82     return false;
83   }
84   int first_font = font_set[0].fontinfo_id;
85   uint32_t properties = at(first_font).properties;
86   for (unsigned f = 1; f < font_set.size(); ++f) {
87     if (at(font_set[f].fontinfo_id).properties != properties) {
88       return true;
89     }
90   }
91   return false;
92 }
93 
94 // Moves any non-empty FontSpacingInfo entries from other to this.
MoveSpacingInfoFrom(FontInfoTable * other)95 void FontInfoTable::MoveSpacingInfoFrom(FontInfoTable *other) {
96   using namespace std::placeholders; // for _1, _2
97   set_clear_callback(std::bind(FontInfoDeleteCallback, _1));
98   for (unsigned i = 0; i < other->size(); ++i) {
99     std::vector<FontSpacingInfo *> *spacing_vec = other->at(i).spacing_vec;
100     if (spacing_vec != nullptr) {
101       int target_index = get_index(other->at(i));
102       if (target_index < 0) {
103         // Bit copy the FontInfo and steal all the pointers.
104         push_back(other->at(i));
105         other->at(i).name = nullptr;
106       } else {
107         delete at(target_index).spacing_vec;
108         at(target_index).spacing_vec = other->at(i).spacing_vec;
109       }
110       other->at(i).spacing_vec = nullptr;
111     }
112   }
113 }
114 
115 // Moves this to the target unicity table.
MoveTo(UnicityTable<FontInfo> * target)116 void FontInfoTable::MoveTo(UnicityTable<FontInfo> *target) {
117   target->clear();
118   using namespace std::placeholders; // for _1, _2
119   target->set_clear_callback(std::bind(FontInfoDeleteCallback, _1));
120   for (unsigned i = 0; i < size(); ++i) {
121     // Bit copy the FontInfo and steal all the pointers.
122     target->push_back(at(i));
123     at(i).name = nullptr;
124     at(i).spacing_vec = nullptr;
125   }
126 }
127 
128 // Callbacks for GenericVector.
FontInfoDeleteCallback(FontInfo f)129 void FontInfoDeleteCallback(FontInfo f) {
130   if (f.spacing_vec != nullptr) {
131     for (auto data : *f.spacing_vec) {
132       delete data;
133     }
134     delete f.spacing_vec;
135     f.spacing_vec = nullptr;
136   }
137   delete[] f.name;
138   f.name = nullptr;
139 }
140 
141 /*---------------------------------------------------------------------------*/
142 // Callbacks used by UnicityTable to read/write FontInfo/FontSet structures.
read_info(TFile * f,FontInfo * fi)143 bool read_info(TFile *f, FontInfo *fi) {
144   uint32_t size;
145   if (!f->DeSerialize(&size)) {
146     return false;
147   }
148   char *font_name = new char[size + 1];
149   fi->name = font_name;
150   if (!f->DeSerialize(font_name, size)) {
151     return false;
152   }
153   font_name[size] = '\0';
154   return f->DeSerialize(&fi->properties);
155 }
156 
write_info(FILE * f,const FontInfo & fi)157 bool write_info(FILE *f, const FontInfo &fi) {
158   int32_t size = strlen(fi.name);
159   return tesseract::Serialize(f, &size) && tesseract::Serialize(f, &fi.name[0], size) &&
160          tesseract::Serialize(f, &fi.properties);
161 }
162 
read_spacing_info(TFile * f,FontInfo * fi)163 bool read_spacing_info(TFile *f, FontInfo *fi) {
164   int32_t vec_size, kern_size;
165   if (!f->DeSerialize(&vec_size)) {
166     return false;
167   }
168   ASSERT_HOST(vec_size >= 0);
169   if (vec_size == 0) {
170     return true;
171   }
172   fi->init_spacing(vec_size);
173   for (int i = 0; i < vec_size; ++i) {
174     auto *fs = new FontSpacingInfo();
175     if (!f->DeSerialize(&fs->x_gap_before) || !f->DeSerialize(&fs->x_gap_after) ||
176         !f->DeSerialize(&kern_size)) {
177       delete fs;
178       return false;
179     }
180     if (kern_size < 0) { // indication of a nullptr entry in fi->spacing_vec
181       delete fs;
182       continue;
183     }
184     if (kern_size > 0 &&
185         (!f->DeSerialize(fs->kerned_unichar_ids) || !f->DeSerialize(fs->kerned_x_gaps))) {
186       delete fs;
187       return false;
188     }
189     fi->add_spacing(i, fs);
190   }
191   return true;
192 }
193 
write_spacing_info(FILE * f,const FontInfo & fi)194 bool write_spacing_info(FILE *f, const FontInfo &fi) {
195   int32_t vec_size = (fi.spacing_vec == nullptr) ? 0 : fi.spacing_vec->size();
196   if (!tesseract::Serialize(f, &vec_size)) {
197     return false;
198   }
199   int16_t x_gap_invalid = -1;
200   for (int i = 0; i < vec_size; ++i) {
201     FontSpacingInfo *fs = fi.spacing_vec->at(i);
202     int32_t kern_size = (fs == nullptr) ? -1 : fs->kerned_x_gaps.size();
203     if (fs == nullptr) {
204       // Writing two invalid x-gaps.
205       if (!tesseract::Serialize(f, &x_gap_invalid, 2) || !tesseract::Serialize(f, &kern_size)) {
206         return false;
207       }
208     } else {
209       if (!tesseract::Serialize(f, &fs->x_gap_before) ||
210           !tesseract::Serialize(f, &fs->x_gap_after) || !tesseract::Serialize(f, &kern_size)) {
211         return false;
212       }
213     }
214     if (kern_size > 0 &&
215         (!Serialize(f, fs->kerned_unichar_ids) || !Serialize(f, fs->kerned_x_gaps))) {
216       return false;
217     }
218   }
219   return true;
220 }
221 
write_set(FILE * f,const FontSet & fs)222 bool write_set(FILE *f, const FontSet &fs) {
223   int size = fs.size();
224   return tesseract::Serialize(f, &size) && tesseract::Serialize(f, &fs[0], size);
225 }
226 
227 } // namespace tesseract.
228