1 /*
2 Source File : UsedFontsRepository.cpp
3
4
5 Copyright 2011 Gal Kahana PDFWriter
6
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
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18
19
20 */
21 #include "UsedFontsRepository.h"
22 #include "FreeTypeWrapper.h"
23 #include "PDFUsedFont.h"
24 #include "Trace.h"
25 #include "ObjectsContext.h"
26 #include "DictionaryContext.h"
27 #include "PDFTextString.h"
28 #include "PDFParser.h"
29 #include "PDFObjectCast.h"
30 #include "PDFDictionary.h"
31 #include "PDFArray.h"
32 #include "PDFIndirectObjectReference.h"
33 #include "PDFLiteralString.h"
34 #include "PDFInteger.h"
35
36
37 #include <list>
38
39 #include <ft2build.h>
40 #include FT_FREETYPE_H
41
42 using namespace PDFHummus;
43
UsedFontsRepository(void)44 UsedFontsRepository::UsedFontsRepository(void)
45 {
46 mInputFontsInformation = NULL;
47 mObjectsContext = NULL;
48 }
49
~UsedFontsRepository(void)50 UsedFontsRepository::~UsedFontsRepository(void)
51 {
52 Reset();
53 }
54
SetObjectsContext(ObjectsContext * inObjectsContext)55 void UsedFontsRepository::SetObjectsContext(ObjectsContext* inObjectsContext)
56 {
57 mObjectsContext = inObjectsContext;
58 }
59
GetFontForFile(const std::string & inFontFilePath,const std::string & inOptionalMetricsFile,long inFontIndex)60 PDFUsedFont* UsedFontsRepository::GetFontForFile(const std::string& inFontFilePath,const std::string& inOptionalMetricsFile,long inFontIndex)
61 {
62 if(!mObjectsContext)
63 {
64 TRACE_LOG("UsedFontsRepository::GetFontForFile, exception, not objects context available");
65 return NULL;
66 }
67
68 StringAndLongToPDFUsedFontMap::iterator it = mUsedFonts.find(StringAndLong(inFontFilePath,inFontIndex));
69 if(it == mUsedFonts.end())
70 {
71 if(!mInputFontsInformation)
72 mInputFontsInformation = new FreeTypeWrapper();
73
74
75 FT_Face face;
76 if(inOptionalMetricsFile.size() > 0)
77 {
78 face = mInputFontsInformation->NewFace(inFontFilePath,inOptionalMetricsFile,inFontIndex);
79 mOptionaMetricsFiles.insert(StringToStringMap::value_type(inFontFilePath,inOptionalMetricsFile));
80 }
81 else
82 face = mInputFontsInformation->NewFace(inFontFilePath,inFontIndex);
83 if(!face)
84 {
85 TRACE_LOG1("UsedFontsRepository::GetFontForFile, Failed to load font from %s",inFontFilePath.c_str());
86 PDFUsedFont* aNull = NULL;
87 it = mUsedFonts.insert(StringAndLongToPDFUsedFontMap::value_type(StringAndLong(inFontFilePath,inFontIndex),aNull)).first;
88 }
89 else
90 {
91
92 PDFUsedFont* usedFont = new PDFUsedFont(face,inFontFilePath,inOptionalMetricsFile,inFontIndex,mObjectsContext);
93 if(!usedFont->IsValid())
94 {
95 TRACE_LOG1("UsedFontsRepository::GetFontForFile, Unreckognized font format for font in %s",inFontFilePath.c_str());
96 delete usedFont;
97 usedFont = NULL;
98 }
99 it = mUsedFonts.insert(StringAndLongToPDFUsedFontMap::value_type(StringAndLong(inFontFilePath,inFontIndex),usedFont)).first;
100
101 }
102 }
103 return it->second;
104 }
105
WriteUsedFontsDefinitions()106 EStatusCode UsedFontsRepository::WriteUsedFontsDefinitions()
107 {
108 StringAndLongToPDFUsedFontMap::iterator it = mUsedFonts.begin();
109 EStatusCode status = PDFHummus::eSuccess;
110
111 for(; it != mUsedFonts.end() && PDFHummus::eSuccess == status; ++it)
112 status = it->second ?
113 it->second->WriteFontDefinition():
114 eFailure;
115
116 return status;
117 }
118
GetFontForFile(const std::string & inFontFilePath,long inFontIndex)119 PDFUsedFont* UsedFontsRepository::GetFontForFile(const std::string& inFontFilePath,long inFontIndex)
120 {
121 return GetFontForFile(inFontFilePath,"",inFontIndex);
122 }
123
124 typedef std::list<ObjectIDType> ObjectIDTypeList;
WriteState(ObjectsContext * inStateWriter,ObjectIDType inObjectID)125 EStatusCode UsedFontsRepository::WriteState(ObjectsContext* inStateWriter,ObjectIDType inObjectID)
126 {
127 EStatusCode status = PDFHummus::eSuccess;
128 ObjectIDTypeList usedFontsObjects;
129
130 inStateWriter->StartNewIndirectObject(inObjectID);
131 DictionaryContext* usedFontsRepositoryObject = inStateWriter->StartDictionary();
132
133 usedFontsRepositoryObject->WriteKey("Type");
134 usedFontsRepositoryObject->WriteNameValue("UsedFontsRepository");
135
136 usedFontsRepositoryObject->WriteKey("mUsedFonts");
137 inStateWriter->StartArray();
138
139
140 StringAndLongToPDFUsedFontMap::iterator it = mUsedFonts.begin();
141
142 for(; it != mUsedFonts.end();++it)
143 {
144 PDFTextString aTextString(it->first.first);
145 inStateWriter->WriteLiteralString(aTextString.ToString());
146
147 inStateWriter->WriteInteger(it->first.second);
148
149 ObjectIDType usedFontID = inStateWriter->GetInDirectObjectsRegistry().AllocateNewObjectID();
150 inStateWriter->WriteNewIndirectObjectReference(usedFontID);
151 usedFontsObjects.push_back(usedFontID);
152 }
153
154 inStateWriter->EndArray(eTokenSeparatorEndLine);
155
156 usedFontsRepositoryObject->WriteKey("mOptionaMetricsFiles");
157 inStateWriter->StartArray();
158
159 StringToStringMap::iterator itOptionals = mOptionaMetricsFiles.begin();
160 for(; itOptionals != mOptionaMetricsFiles.end();++itOptionals)
161 {
162 PDFTextString aTextString(itOptionals->first);
163 inStateWriter->WriteLiteralString(aTextString.ToString());
164
165 aTextString = itOptionals->second;
166 inStateWriter->WriteLiteralString(aTextString.ToString());
167 }
168
169 inStateWriter->EndArray(eTokenSeparatorEndLine);
170
171 inStateWriter->EndDictionary(usedFontsRepositoryObject);
172 inStateWriter->EndIndirectObject();
173
174 if(usedFontsObjects.size() > 0)
175 {
176 it = mUsedFonts.begin();
177 ObjectIDTypeList::iterator itIDs = usedFontsObjects.begin();
178
179 for(; it != mUsedFonts.end() && PDFHummus::eSuccess == status;++it,++itIDs)
180 status = it->second->WriteState(inStateWriter,*itIDs);
181 }
182
183 return status;
184 }
185
ReadState(PDFParser * inStateReader,ObjectIDType inObjectID)186 EStatusCode UsedFontsRepository::ReadState(PDFParser* inStateReader,ObjectIDType inObjectID)
187 {
188 EStatusCode status = PDFHummus::eSuccess;
189
190 // clear current state
191 StringAndLongToPDFUsedFontMap::iterator itUsedFonts = mUsedFonts.begin();
192 for(; itUsedFonts != mUsedFonts.end();++itUsedFonts)
193 delete (itUsedFonts->second);
194 mUsedFonts.clear();
195
196
197 PDFObjectCastPtr<PDFDictionary> usedFontsRepositoryState(inStateReader->ParseNewObject(inObjectID));
198
199 mOptionaMetricsFiles.clear();
200 PDFObjectCastPtr<PDFArray> optionalMetricsState(usedFontsRepositoryState->QueryDirectObject("mOptionaMetricsFiles"));
201 SingleValueContainerIterator<PDFObjectVector> it = optionalMetricsState->GetIterator();
202 PDFObjectCastPtr<PDFLiteralString> aStringValue;
203
204 while(it.MoveNext())
205 {
206 PDFTextString aKey;
207
208 aStringValue = it.GetItem();
209 aKey = aStringValue->GetValue();
210
211 PDFTextString aValue;
212
213 it.MoveNext();
214 aStringValue = it.GetItem();
215 aValue = aStringValue->GetValue();
216
217 mOptionaMetricsFiles.insert(StringToStringMap::value_type(aKey.ToUTF8String(),aValue.ToUTF8String()));
218 }
219
220 PDFObjectCastPtr<PDFArray> usedFontsState(usedFontsRepositoryState->QueryDirectObject("mUsedFonts"));
221
222 it = usedFontsState->GetIterator();
223 PDFObjectCastPtr<PDFLiteralString> keyStringItem;
224 PDFObjectCastPtr<PDFInteger> keyIndexItem;
225 PDFObjectCastPtr<PDFIndirectObjectReference> valueItem;
226
227 if(!mInputFontsInformation)
228 mInputFontsInformation = new FreeTypeWrapper();
229
230 while(it.MoveNext() && PDFHummus::eSuccess == status)
231 {
232 keyStringItem = it.GetItem();
233 it.MoveNext();
234 keyIndexItem = it.GetItem();
235 it.MoveNext();
236 valueItem = it.GetItem();
237
238 PDFTextString aTextString(keyStringItem->GetValue());
239 std::string filePath = aTextString.ToUTF8String();
240 long fontIndex = (long)keyIndexItem->GetValue();
241
242 FT_Face face;
243 face = mInputFontsInformation->NewFace(filePath,fontIndex);
244
245 if(!face)
246 {
247 TRACE_LOG2("UsedFontsRepository::ReadState, Failed to load font from %s at index %ld",filePath.c_str(),fontIndex);
248 status = PDFHummus::eFailure;
249 break;
250 }
251
252
253 PDFUsedFont* usedFont;
254
255 StringToStringMap::iterator itOptionlMetricsFile = mOptionaMetricsFiles.find(filePath);
256 if(itOptionlMetricsFile != mOptionaMetricsFiles.end())
257 usedFont = new PDFUsedFont(face,filePath,itOptionlMetricsFile->second,fontIndex,mObjectsContext);
258 else
259 usedFont = new PDFUsedFont(face,filePath,"",fontIndex,mObjectsContext);
260 if(!usedFont->IsValid())
261 {
262 TRACE_LOG2("UsedFontsRepository::ReadState, Unreckognized font format for font in %s at index %ld",filePath.c_str(),fontIndex);
263 delete usedFont;
264 usedFont = NULL;
265 status = PDFHummus::eFailure;
266 break;
267 }
268
269 usedFont->ReadState(inStateReader,valueItem->mObjectID);
270 mUsedFonts.insert(StringAndLongToPDFUsedFontMap::value_type(StringAndLong(filePath,fontIndex),usedFont));
271
272 }
273 return status;
274
275 }
276
Reset()277 void UsedFontsRepository::Reset()
278 {
279 StringAndLongToPDFUsedFontMap::iterator it = mUsedFonts.begin();
280 for(; it != mUsedFonts.end();++it)
281 delete (it->second);
282 mUsedFonts.clear();
283 delete mInputFontsInformation;
284 mInputFontsInformation = NULL;
285 mOptionaMetricsFiles.clear();
286 }