1 /*
2    Source File : CIDFontWriter.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 "CIDFontWriter.h"
22 #include "DictionaryContext.h"
23 #include "ObjectsContext.h"
24 #include "FreeTypeFaceWrapper.h"
25 #include "Trace.h"
26 #include "PDFStream.h"
27 #include "IByteWriter.h"
28 #include "SafeBufferMacrosDefs.h"
29 #include "CFFDescendentFontWriter.h"
30 #include "IDescendentFontWriter.h"
31 #include "UnicodeString.h"
32 
33 #include <ft2build.h>
34 #include FT_FREETYPE_H
35 
36 #include <algorithm>
37 
38 
39 using namespace PDFHummus;
40 
CIDFontWriter(void)41 CIDFontWriter::CIDFontWriter(void)
42 {
43 }
44 
~CIDFontWriter(void)45 CIDFontWriter::~CIDFontWriter(void)
46 {
47 }
48 
49 static const std::string scType = "Type";
50 static const std::string scFont = "Font";
51 static const std::string scSubtype = "Subtype";
52 static const std::string scType0 = "Type0";
53 static const std::string scBaseFont = "BaseFont";
54 static const std::string scPlus = "+";
55 static const std::string scDescendantFonts = "DescendantFonts";
56 static const std::string scToUnicode = "ToUnicode";
57 
WriteFont(FreeTypeFaceWrapper & inFontInfo,WrittenFontRepresentation * inFontOccurrence,ObjectsContext * inObjectsContext,IDescendentFontWriter * inDescendentFontWriter)58 EStatusCode CIDFontWriter::WriteFont(FreeTypeFaceWrapper& inFontInfo,
59 										WrittenFontRepresentation* inFontOccurrence,
60 										ObjectsContext* inObjectsContext,
61 										IDescendentFontWriter* inDescendentFontWriter)
62 {
63 
64 	EStatusCode status = PDFHummus::eSuccess;
65 	inObjectsContext->StartNewIndirectObject(inFontOccurrence->mWrittenObjectID);
66 
67 	mFontInfo = &inFontInfo;
68 	mFontOccurrence = inFontOccurrence;
69 	mObjectsContext = inObjectsContext;
70 
71 	do
72 	{
73 		DictionaryContext* fontContext = inObjectsContext->StartDictionary();
74 
75 		// Type
76 		fontContext->WriteKey(scType);
77 		fontContext->WriteNameValue(scFont);
78 
79 		// SubType
80 		fontContext->WriteKey(scSubtype);
81 		fontContext->WriteNameValue(scType0);
82 
83 		// BaseFont
84 		fontContext->WriteKey(scBaseFont);
85 		const char* postscriptFontName = FT_Get_Postscript_Name(inFontInfo);
86 		if(!postscriptFontName)
87 		{
88 			TRACE_LOG("CIDFontWriter::WriteFont, unexpected failure. no postscript font name for font");
89 			status = PDFHummus::eFailure;
90 			break;
91 		}
92 		std::string subsetFontName = inObjectsContext->GenerateSubsetFontPrefix() + scPlus + postscriptFontName;
93 		fontContext->WriteNameValue(subsetFontName);
94 
95 		WriteEncoding(fontContext);
96 
97 		// DescendantFonts
98 		ObjectIDType descendantFontID = mObjectsContext->GetInDirectObjectsRegistry().AllocateNewObjectID();
99 
100 		fontContext->WriteKey(scDescendantFonts);
101 		mObjectsContext->StartArray();
102 		mObjectsContext->WriteNewIndirectObjectReference(descendantFontID);
103 		mObjectsContext->EndArray(eTokenSeparatorEndLine);
104 
105 		CalculateCharacterEncodingArray(); // put the charachter in the order of encoding, for the ToUnicode map
106 
107 		// ToUnicode
108 		fontContext->WriteKey(scToUnicode);
109 		ObjectIDType toUnicodeMapObjectID = mObjectsContext->GetInDirectObjectsRegistry().AllocateNewObjectID();
110 		fontContext->WriteNewObjectReferenceValue(toUnicodeMapObjectID);
111 
112 		status = inObjectsContext->EndDictionary(fontContext);
113 		if(status != PDFHummus::eSuccess)
114 		{
115 			TRACE_LOG("CIDFontWriter::WriteFont, unexpected failure. Failed to end dictionary in font write.");
116 			break;
117 		}
118 		inObjectsContext->EndIndirectObject();
119 		WriteToUnicodeMap(toUnicodeMapObjectID);
120 
121 		// Write the descendant font
122 		status = inDescendentFontWriter->WriteFont(descendantFontID,subsetFontName,*mFontInfo,mCharactersVector,mObjectsContext);
123 
124 	} while(false);
125 
126 	return status;
127 }
128 
129 static const std::string scEncoding = "Encoding";
130 static const std::string scIdentityH = "Identity-H";
WriteEncoding(DictionaryContext * inFontContext)131 void CIDFontWriter::WriteEncoding(DictionaryContext* inFontContext)
132 {
133 	// Encoding
134 	inFontContext->WriteKey(scEncoding);
135 	inFontContext->WriteNameValue(scIdentityH);
136 }
137 
sUShortSort(const UIntAndGlyphEncodingInfo & inLeft,const UIntAndGlyphEncodingInfo & inRight)138 static bool sUShortSort(const UIntAndGlyphEncodingInfo& inLeft, const UIntAndGlyphEncodingInfo& inRight)
139 {
140 	return inLeft.second.mEncodedCharacter < inRight.second.mEncodedCharacter;
141 }
142 
CalculateCharacterEncodingArray()143 void CIDFontWriter::CalculateCharacterEncodingArray()
144 {
145 	// first we need to sort the fonts charachters by character code
146 	UIntToGlyphEncodingInfoMap::iterator it = mFontOccurrence->mGlyphIDToEncodedChar.begin();
147 
148 	for(; it != mFontOccurrence->mGlyphIDToEncodedChar.end();++it)
149 		mCharactersVector.push_back(UIntAndGlyphEncodingInfo(it->first,it->second));
150 
151 	std::sort(mCharactersVector.begin(),mCharactersVector.end(),sUShortSort);
152 }
153 
154 
155 static const char* scCmapHeader =
156 "/CIDInit /ProcSet findresource begin\n\
157 12 dict begin\n\
158 begincmap\n\
159 /CIDSystemInfo\n\
160 << /Registry (Adobe)\n\
161 /Ordering (UCS) /Supplement 0 >> def\n\
162 /CMapName /Adobe-Identity-UCS def\n\
163 /CMapType 2 def\n\
164 1 begincodespacerange\n";
165 static const char* scFourByteRangeStart = "0000";
166 static const char* scFourByteRangeEnd = "FFFF";
167 static const char* scEndCodeSpaceRange = "endcodespacerange\n";
168 static const std::string scBeginBFChar = "beginbfchar";
169 static const std::string scEndBFChar = "endbfchar";
170 static const char* scCmapFooter = "endcmap CMapName currentdict /CMap defineresource pop end end\n";
171 
WriteToUnicodeMap(ObjectIDType inToUnicodeMap)172 void CIDFontWriter::WriteToUnicodeMap(ObjectIDType inToUnicodeMap)
173 {
174 	mObjectsContext->StartNewIndirectObject(inToUnicodeMap);
175 	PDFStream* pdfStream = mObjectsContext->StartPDFStream();
176 	IByteWriter* cmapWriteContext = pdfStream->GetWriteStream();
177 	PrimitiveObjectsWriter primitiveWriter(cmapWriteContext);
178 	unsigned long i = 1;
179 	UIntAndGlyphEncodingInfoVector::iterator it = mCharactersVector.begin() + 1; // skip 0 glyph
180 	unsigned long vectorSize = (unsigned long)mCharactersVector.size() - 1; // cause 0 is not there
181 
182 	cmapWriteContext->Write((const Byte*)scCmapHeader,strlen(scCmapHeader));
183 	primitiveWriter.WriteHexString(scFourByteRangeStart);
184 	primitiveWriter.WriteHexString(scFourByteRangeEnd,eTokenSeparatorEndLine);
185 	cmapWriteContext->Write((const Byte*)scEndCodeSpaceRange,strlen(scEndCodeSpaceRange));
186 
187 	if(vectorSize < 100)
188 		primitiveWriter.WriteInteger(vectorSize);
189 	else
190 		primitiveWriter.WriteInteger(100);
191 	primitiveWriter.WriteKeyword(scBeginBFChar);
192 
193 	WriteGlyphEntry(cmapWriteContext,it->second.mEncodedCharacter,it->second.mUnicodeCharacters);
194 	++it;
195 	for(; it != mCharactersVector.end(); ++it,++i)
196 	{
197 		if(i % 100 == 0)
198 		{
199 			primitiveWriter.WriteKeyword(scEndBFChar);
200 			if(vectorSize - i < 100)
201 				primitiveWriter.WriteInteger(vectorSize - i);
202 			else
203 				primitiveWriter.WriteInteger(100);
204 			primitiveWriter.WriteKeyword(scBeginBFChar);
205 		}
206 		WriteGlyphEntry(cmapWriteContext,it->second.mEncodedCharacter,it->second.mUnicodeCharacters);
207 	}
208 	primitiveWriter.WriteKeyword(scEndBFChar);
209 	cmapWriteContext->Write((const Byte*)scCmapFooter,strlen(scCmapFooter));
210 	mObjectsContext->EndPDFStream(pdfStream);
211 	delete pdfStream;
212 }
213 
214 static const Byte scEntryEnding[2] = {'>','\n'};
215 static const Byte scAllZeros[4] = {'0','0','0','0'};
WriteGlyphEntry(IByteWriter * inWriter,unsigned short inEncodedCharacter,const ULongVector & inUnicodeValues)216 void CIDFontWriter::WriteGlyphEntry(IByteWriter* inWriter,unsigned short inEncodedCharacter,const ULongVector& inUnicodeValues)
217 {
218 	UnicodeString unicode;
219 	char formattingBuffer[17];
220 	ULongVector::const_iterator it = inUnicodeValues.begin();
221 
222 	SAFE_SPRINTF_1(formattingBuffer,17,"<%04x> <",inEncodedCharacter);
223 	inWriter->Write((const Byte*)formattingBuffer,8);
224 
225 	if(inUnicodeValues.size() == 0)
226 	{
227 		inWriter->Write(scAllZeros,4);
228 	}
229 	else
230 	{
231 		for(; it != inUnicodeValues.end(); ++it)
232 		{
233 			unicode.GetUnicodeList().push_back(*it);
234 			EStatusCodeAndUShortList utf16Result = unicode.ToUTF16UShort();
235 			unicode.GetUnicodeList().clear();
236 
237 			if(utf16Result.second.size() == 2)
238 			{
239 				SAFE_SPRINTF_2(formattingBuffer,17,"%04x%04x",
240 																utf16Result.second.front(),
241 																utf16Result.second.back());
242 				inWriter->Write((const Byte*)formattingBuffer,8);
243 			}
244 			else // 1
245 			{
246 				SAFE_SPRINTF_1(formattingBuffer,17,"%04x",utf16Result.second.front());
247 				inWriter->Write((const Byte*)formattingBuffer,4);
248 			}
249 		}
250 	}
251 	inWriter->Write(scEntryEnding,2);
252 }
253