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 }