1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "../../include/pdfwindow/PDFWindow.h"
8#include "../../include/pdfwindow/PWL_Wnd.h"
9#include "../../include/pdfwindow/PWL_FontMap.h"
10
11#define DEFAULT_FONT_NAME			"Helvetica"
12
13/* ------------------------------ CPWL_FontMap ------------------------------ */
14
15CPWL_FontMap::CPWL_FontMap(IFX_SystemHandler* pSystemHandler) :
16	m_pPDFDoc(NULL),
17	m_pSystemHandler(pSystemHandler)
18{
19	ASSERT(m_pSystemHandler != NULL);
20}
21
22CPWL_FontMap::~CPWL_FontMap()
23{
24	if (m_pPDFDoc)
25	{
26		delete m_pPDFDoc;
27		m_pPDFDoc = NULL;
28	}
29
30	Empty();
31}
32
33void CPWL_FontMap::SetSystemHandler(IFX_SystemHandler* pSystemHandler)
34{
35	m_pSystemHandler = pSystemHandler;
36}
37
38CPDF_Document* CPWL_FontMap::GetDocument()
39{
40	if (!m_pPDFDoc)
41	{
42		if (CPDF_ModuleMgr::Get())
43		{
44			m_pPDFDoc = new CPDF_Document;
45			m_pPDFDoc->CreateNewDoc();
46		}
47	}
48
49	return m_pPDFDoc;
50}
51
52CPDF_Font* CPWL_FontMap::GetPDFFont(FX_INT32 nFontIndex)
53{
54	if (nFontIndex >=0 && nFontIndex < m_aData.GetSize())
55	{
56		if (CPWL_FontMap_Data* pData = m_aData.GetAt(nFontIndex))
57		{
58			return pData->pFont;
59		}
60	}
61
62	return NULL;
63}
64
65CFX_ByteString CPWL_FontMap::GetPDFFontAlias(FX_INT32 nFontIndex)
66{
67	if (nFontIndex >=0 && nFontIndex < m_aData.GetSize())
68	{
69		if (CPWL_FontMap_Data* pData = m_aData.GetAt(nFontIndex))
70		{
71			return pData->sFontName;
72		}
73	}
74
75	return "";
76}
77
78FX_BOOL CPWL_FontMap::KnowWord(FX_INT32 nFontIndex, FX_WORD word)
79{
80	if (nFontIndex >=0 && nFontIndex < m_aData.GetSize())
81	{
82		if (m_aData.GetAt(nFontIndex))
83		{
84			return CharCodeFromUnicode(nFontIndex, word) >= 0;
85		}
86	}
87
88	return FALSE;
89}
90
91FX_INT32 CPWL_FontMap::GetWordFontIndex(FX_WORD word, FX_INT32 nCharset, FX_INT32 nFontIndex)
92{
93	if (nFontIndex > 0)
94	{
95		if (KnowWord(nFontIndex, word))
96			return nFontIndex;
97	}
98	else
99	{
100		if (const CPWL_FontMap_Data* pData = GetFontMapData(0))
101		{
102			if (nCharset == DEFAULT_CHARSET ||
103				pData->nCharset == SYMBOL_CHARSET ||
104				nCharset == pData->nCharset)
105			{
106				if (KnowWord(0, word))
107				{
108					return 0;
109				}
110			}
111		}
112	}
113
114	FX_INT32 nNewFontIndex = -1;
115
116	nNewFontIndex = this->GetFontIndex(GetNativeFontName(nCharset), nCharset, TRUE);
117	if (nNewFontIndex >= 0)
118	{
119		if (KnowWord(nNewFontIndex, word))
120			return nNewFontIndex;
121	}
122
123	nNewFontIndex = this->GetFontIndex("Arial Unicode MS", DEFAULT_CHARSET, FALSE);
124	if (nNewFontIndex >= 0)
125	{
126		if (KnowWord(nNewFontIndex, word))
127		return nNewFontIndex;
128	}
129
130	return -1;
131}
132
133FX_INT32 CPWL_FontMap::CharCodeFromUnicode(FX_INT32 nFontIndex, FX_WORD word)
134{
135	if (CPWL_FontMap_Data* pData = m_aData.GetAt(nFontIndex))
136	{
137		if (pData->pFont)
138		{
139			if (pData->pFont->IsUnicodeCompatible())
140			{
141				int nCharCode = pData->pFont->CharCodeFromUnicode(word);
142				pData->pFont->GlyphFromCharCode(nCharCode);
143				return nCharCode;
144			}
145			else
146			{
147				if (word < 0xFF)
148					return word;
149			}
150		}
151	}
152
153	return -1;
154}
155
156CFX_ByteString CPWL_FontMap::GetNativeFontName(FX_INT32 nCharset)
157{
158	//searching native font is slow, so we must save time
159	for (FX_INT32 i=0,sz=m_aNativeFont.GetSize(); i<sz; i++)
160	{
161		if (CPWL_FontMap_Native* pData = m_aNativeFont.GetAt(i))
162		{
163			if (pData->nCharset == nCharset)
164				return pData->sFontName;
165		}
166	}
167
168	CFX_ByteString sNew = GetNativeFont(nCharset);
169
170	if (!sNew.IsEmpty())
171	{
172		CPWL_FontMap_Native* pNewData = new CPWL_FontMap_Native;
173		pNewData->nCharset = nCharset;
174		pNewData->sFontName = sNew;
175
176		m_aNativeFont.Add(pNewData);
177	}
178
179	return sNew;
180}
181
182void CPWL_FontMap::Empty()
183{
184	{
185		for (FX_INT32 i=0, sz=m_aData.GetSize(); i<sz; i++)
186			delete m_aData.GetAt(i);
187
188		m_aData.RemoveAll();
189	}
190	{
191		for (FX_INT32 i=0, sz=m_aNativeFont.GetSize(); i<sz; i++)
192			delete m_aNativeFont.GetAt(i);
193
194		m_aNativeFont.RemoveAll();
195	}
196}
197
198void CPWL_FontMap::Initial(FX_LPCSTR fontname)
199{
200	CFX_ByteString sFontName = fontname;
201
202	if (sFontName.IsEmpty())
203		sFontName = DEFAULT_FONT_NAME;
204
205	GetFontIndex(sFontName, ANSI_CHARSET, FALSE);
206
207	//GetFontIndex(this->GetNativeFontName(nCharset), nCharset);
208}
209
210
211/*
212List of currently supported standard fonts:
213Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique
214Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique
215Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic
216Symbol, ZapfDingbats
217*/
218
219const char* g_sDEStandardFontName[] = {"Courier", "Courier-Bold", "Courier-BoldOblique", "Courier-Oblique",
220	"Helvetica", "Helvetica-Bold", "Helvetica-BoldOblique", "Helvetica-Oblique",
221	"Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic",
222	"Symbol", "ZapfDingbats"};
223
224FX_BOOL	CPWL_FontMap::IsStandardFont(const CFX_ByteString& sFontName)
225{
226	for (FX_INT32 i=0; i<14; i++)
227	{
228		if (sFontName == g_sDEStandardFontName[i])
229			return TRUE;
230	}
231
232	return FALSE;
233}
234
235FX_INT32 CPWL_FontMap::FindFont(const CFX_ByteString& sFontName, FX_INT32 nCharset)
236{
237	for (FX_INT32 i=0,sz=m_aData.GetSize(); i<sz; i++)
238	{
239		if (CPWL_FontMap_Data* pData = m_aData.GetAt(i))
240		{
241			if (nCharset == DEFAULT_CHARSET || nCharset == pData->nCharset)
242			{
243				if (sFontName.IsEmpty() || pData->sFontName == sFontName)
244					return i;
245			}
246		}
247	}
248
249	return -1;
250}
251
252FX_INT32 CPWL_FontMap::GetFontIndex(const CFX_ByteString& sFontName, FX_INT32 nCharset, FX_BOOL bFind)
253{
254	FX_INT32 nFontIndex = FindFont(EncodeFontAlias(sFontName, nCharset), nCharset);
255	if (nFontIndex >= 0) return nFontIndex;
256
257//	nFontIndex = FindFont("", nCharset);
258//	if (nFontIndex >= 0) return nFontIndex;
259
260	CFX_ByteString sAlias;
261	CPDF_Font* pFont = NULL;
262
263	if (bFind)
264		pFont = FindFontSameCharset(sAlias, nCharset);
265
266	if (!pFont)
267	{
268		CFX_ByteString sTemp = sFontName;
269		pFont = AddFontToDocument(GetDocument(), sTemp, nCharset);
270
271		/*
272		if (FindFont(sAlias))
273		{
274			sAlias = EncodeFontAlias(sTemp, nCharset);
275		}
276		else
277		*/
278		{
279			sAlias = EncodeFontAlias(sTemp, nCharset);
280		}
281	}
282
283	AddedFont(pFont, sAlias);
284
285	return AddFontData(pFont, sAlias, nCharset);
286}
287
288FX_INT32 CPWL_FontMap::GetPWLFontIndex(FX_WORD word, FX_INT32 nCharset)
289{
290	FX_INT32 nFind = -1;
291
292	for (FX_INT32 i=0,sz=m_aData.GetSize(); i<sz; i++)
293	{
294		if (CPWL_FontMap_Data* pData = m_aData.GetAt(i))
295		{
296			if (pData->nCharset == nCharset)
297			{
298				nFind = i;
299				break;
300			}
301		}
302	}
303
304	CPDF_Font* pNewFont = GetPDFFont(nFind);
305
306	if (!pNewFont) return -1;
307
308	/*
309	if (CPDF_Font* pFont = GetPDFFont(nFind))
310	{
311		PWLFont.AddWordToFontDict(pFontDict, word);
312	}
313	*/
314
315	CFX_ByteString sAlias = EncodeFontAlias("Arial_Chrome", nCharset);
316	AddedFont(pNewFont, sAlias);
317
318	return AddFontData(pNewFont, sAlias, nCharset);
319}
320
321CPDF_Font* CPWL_FontMap::FindFontSameCharset(CFX_ByteString& sFontAlias, FX_INT32 nCharset)
322{
323	return NULL;
324}
325
326FX_INT32 CPWL_FontMap::AddFontData(CPDF_Font* pFont, const CFX_ByteString& sFontAlias, FX_INT32 nCharset)
327{
328	CPWL_FontMap_Data* pNewData = new CPWL_FontMap_Data;
329	pNewData->pFont = pFont;
330	pNewData->sFontName = sFontAlias;
331	pNewData->nCharset = nCharset;
332
333	m_aData.Add(pNewData);
334
335	return m_aData.GetSize() -1;
336}
337
338void CPWL_FontMap::AddedFont(CPDF_Font* pFont, const CFX_ByteString& sFontAlias)
339{
340}
341
342CFX_ByteString CPWL_FontMap::GetFontName(FX_INT32 nFontIndex)
343{
344	if (nFontIndex >=0 && nFontIndex < m_aData.GetSize())
345	{
346		if (CPWL_FontMap_Data* pData = m_aData.GetAt(nFontIndex))
347		{
348			return pData->sFontName;
349		}
350	}
351
352	return "";
353}
354
355CFX_ByteString CPWL_FontMap::GetNativeFont(FX_INT32 nCharset)
356{
357	CFX_ByteString sFontName;
358
359	if (nCharset == DEFAULT_CHARSET)
360		nCharset = GetNativeCharset();
361
362	sFontName = GetDefaultFontByCharset(nCharset);
363
364	if (m_pSystemHandler)
365	{
366		if (m_pSystemHandler->FindNativeTrueTypeFont(nCharset, sFontName))
367			return sFontName;
368
369		sFontName = m_pSystemHandler->GetNativeTrueTypeFont(nCharset);
370	}
371
372	return sFontName;
373}
374
375CPDF_Font* CPWL_FontMap::AddFontToDocument(CPDF_Document* pDoc, CFX_ByteString& sFontName, FX_BYTE nCharset)
376{
377	if (IsStandardFont(sFontName))
378		return AddStandardFont(pDoc, sFontName);
379	else
380		return AddSystemFont(pDoc, sFontName, nCharset);
381}
382
383CPDF_Font* CPWL_FontMap::AddStandardFont(CPDF_Document* pDoc, CFX_ByteString& sFontName)
384{
385	if (!pDoc) return NULL;
386
387	CPDF_Font* pFont = NULL;
388
389	if (sFontName == "ZapfDingbats")
390		pFont = pDoc->AddStandardFont(sFontName, NULL);
391	else
392	{
393		CPDF_FontEncoding fe(PDFFONT_ENCODING_WINANSI);
394		pFont = pDoc->AddStandardFont(sFontName, &fe);
395	}
396
397	return pFont;
398}
399
400CPDF_Font* CPWL_FontMap::AddSystemFont(CPDF_Document* pDoc, CFX_ByteString& sFontName, FX_BYTE nCharset)
401{
402	if (!pDoc) return NULL;
403
404	if (sFontName.IsEmpty()) sFontName = GetNativeFont(nCharset);
405	if (nCharset == DEFAULT_CHARSET) nCharset = GetNativeCharset();
406
407	if (m_pSystemHandler)
408		return m_pSystemHandler->AddNativeTrueTypeFontToPDF(pDoc, sFontName, nCharset);
409
410	return NULL;
411}
412
413CFX_ByteString CPWL_FontMap::EncodeFontAlias(const CFX_ByteString& sFontName, FX_INT32 nCharset)
414{
415	CFX_ByteString sPostfix;
416	sPostfix.Format("_%02X", nCharset);
417	return EncodeFontAlias(sFontName) + sPostfix;
418}
419
420CFX_ByteString CPWL_FontMap::EncodeFontAlias(const CFX_ByteString& sFontName)
421{
422	CFX_ByteString sRet = sFontName;
423	sRet.Remove(' ');
424	return sRet;
425}
426
427FX_INT32 CPWL_FontMap::GetFontMapCount() const
428{
429	return m_aData.GetSize();
430}
431
432const CPWL_FontMap_Data* CPWL_FontMap::GetFontMapData(FX_INT32 nIndex) const
433{
434	if (nIndex >=0 && nIndex < m_aData.GetSize())
435	{
436		return m_aData.GetAt(nIndex);
437	}
438
439	return NULL;
440}
441
442FX_INT32 CPWL_FontMap::GetNativeCharset()
443{
444	FX_BYTE nCharset = ANSI_CHARSET;
445	FX_INT32 iCodePage = FXSYS_GetACP();
446	switch (iCodePage)
447	{
448	case 932://Japan
449		nCharset = SHIFTJIS_CHARSET;
450		break;
451	case 936://Chinese (PRC, Singapore)
452		nCharset = GB2312_CHARSET;
453		break;
454	case 950://Chinese (Taiwan; Hong Kong SAR, PRC)
455		nCharset = GB2312_CHARSET;
456		break;
457	case 1252://Windows 3.1 Latin 1 (US, Western Europe)
458		nCharset = ANSI_CHARSET;
459		break;
460	case 874://Thai
461		nCharset = THAI_CHARSET;
462		break;
463	case 949://Korean
464		nCharset = HANGUL_CHARSET;
465		break;
466	case 1200://Unicode (BMP of ISO 10646)
467		nCharset = ANSI_CHARSET;
468		break;
469	case 1250://Windows 3.1 Eastern European
470		nCharset = EASTEUROPE_CHARSET;
471		break;
472	case 1251://Windows 3.1 Cyrillic
473		nCharset = RUSSIAN_CHARSET;
474		break;
475	case 1253://Windows 3.1 Greek
476		nCharset = GREEK_CHARSET;
477		break;
478	case 1254://Windows 3.1 Turkish
479		nCharset = TURKISH_CHARSET;
480		break;
481	case 1255://Hebrew
482		nCharset = HEBREW_CHARSET;
483		break;
484	case 1256://Arabic
485		nCharset = ARABIC_CHARSET;
486		break;
487	case 1257://Baltic
488		nCharset = BALTIC_CHARSET;
489		break;
490	case 1258://Vietnamese
491		nCharset = VIETNAMESE_CHARSET;
492		break;
493	case 1361://Korean(Johab)
494		nCharset = JOHAB_CHARSET;
495		break;
496	}
497	return nCharset;
498}
499
500const CPWL_FontMap::CharsetFontMap CPWL_FontMap::defaultTTFMap[] = {
501	{ ANSI_CHARSET, "Helvetica" },
502	{ GB2312_CHARSET, "SimSun" },
503	{ CHINESEBIG5_CHARSET, "MingLiU" },
504	{ SHIFTJIS_CHARSET, "MS Gothic" },
505	{ HANGUL_CHARSET, "Batang" },
506	{ RUSSIAN_CHARSET, "Arial" },
507#if _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_ || _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
508	{ EASTEUROPE_CHARSET, "Arial" },
509#else
510	{ EASTEUROPE_CHARSET, "Tahoma" },
511#endif
512	{ ARABIC_CHARSET, "Arial" },
513	{ -1, NULL }
514};
515
516CFX_ByteString CPWL_FontMap::GetDefaultFontByCharset(FX_INT32 nCharset)
517{
518	int i = 0;
519	while (defaultTTFMap[i].charset != -1) {
520		if (nCharset == defaultTTFMap[i].charset)
521			return defaultTTFMap[i].fontname;
522        ++i;
523	}
524	return "";
525}
526
527FX_INT32 CPWL_FontMap::CharSetFromUnicode(FX_WORD word, FX_INT32 nOldCharset)
528{
529	if(m_pSystemHandler && (-1 != m_pSystemHandler->GetCharSet()))
530		return m_pSystemHandler->GetCharSet();
531	//to avoid CJK Font to show ASCII
532	if (word < 0x7F) return ANSI_CHARSET;
533	//follow the old charset
534	if (nOldCharset != DEFAULT_CHARSET) return nOldCharset;
535
536	//find new charset
537	if ((word >= 0x4E00 && word <= 0x9FA5) ||
538		(word >= 0xE7C7 && word <= 0xE7F3) ||
539		(word >= 0x3000 && word <= 0x303F) || //��"��" "��" "��" "��"
540		(word >= 0x2000 && word <= 0x206F))
541	{
542		return GB2312_CHARSET;
543	}
544
545	if (((word >= 0x3040) && (word <= 0x309F)) ||
546		((word >= 0x30A0) && (word <= 0x30FF)) ||
547		((word >= 0x31F0) && (word <= 0x31FF)) ||
548		((word >= 0xFF00) && (word <= 0xFFEF)) )
549	{
550		return SHIFTJIS_CHARSET;
551	}
552
553	if (((word >= 0xAC00) && (word <= 0xD7AF)) ||
554		((word >= 0x1100) && (word <= 0x11FF)) ||
555		((word >= 0x3130) && (word <= 0x318F)))
556	{
557		return HANGUL_CHARSET;
558	}
559
560	if (word >= 0x0E00 && word <= 0x0E7F)
561		return THAI_CHARSET;
562
563	if ((word >= 0x0370 && word <= 0x03FF) ||
564		(word >= 0x1F00 && word <= 0x1FFF))
565		return GREEK_CHARSET;
566
567	if ((word >= 0x0600 && word <= 0x06FF) ||
568		(word >= 0xFB50 && word <= 0xFEFC))
569		return ARABIC_CHARSET;
570
571	if (word >= 0x0590 && word <= 0x05FF)
572		return HEBREW_CHARSET;
573
574	if (word >= 0x0400 && word <= 0x04FF)
575		return RUSSIAN_CHARSET;
576
577	if (word >= 0x0100 && word <= 0x024F)
578		return EASTEUROPE_CHARSET;
579
580	if (word >= 0x1E00 && word <= 0x1EFF)
581		return VIETNAMESE_CHARSET;
582
583	return ANSI_CHARSET;
584}
585
586/* ------------------------ CPWL_DocFontMap ------------------------ */
587
588CPWL_DocFontMap::CPWL_DocFontMap(IFX_SystemHandler* pSystemHandler, CPDF_Document* pAttachedDoc)
589	: CPWL_FontMap(pSystemHandler),
590	m_pAttachedDoc(pAttachedDoc)
591{
592}
593
594CPWL_DocFontMap::~CPWL_DocFontMap()
595{
596}
597
598CPDF_Document* CPWL_DocFontMap::GetDocument()
599{
600	return m_pAttachedDoc;
601}
602