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/fpdfdoc/fpdf_doc.h"
8#include "doc_utils.h"
9
10static const int FPDFDOC_UTILS_MAXRECURSION = 32;
11
12CFX_WideString GetFullName(CPDF_Dictionary* pFieldDict)
13{
14    CFX_WideString full_name;
15    CPDF_Dictionary* pLevel = pFieldDict;
16    while (pLevel) {
17        CFX_WideString short_name = pLevel->GetUnicodeText("T");
18        if (short_name != L"") {
19            if (full_name == L"") {
20                full_name = short_name;
21            } else {
22                full_name = short_name + L"." + full_name;
23            }
24        }
25        pLevel = pLevel->GetDict("Parent");
26    }
27    return full_name;
28}
29FX_BOOL CPDF_DefaultAppearance::HasFont()
30{
31    if (m_csDA.IsEmpty()) {
32        return FALSE;
33    }
34    CPDF_SimpleParser syntax(m_csDA);
35    return syntax.FindTagParam("Tf", 2);
36}
37CFX_ByteString CPDF_DefaultAppearance::GetFontString()
38{
39    CFX_ByteString csFont;
40    if (m_csDA.IsEmpty()) {
41        return csFont;
42    }
43    CPDF_SimpleParser syntax(m_csDA);
44    if (syntax.FindTagParam("Tf", 2)) {
45        csFont += (CFX_ByteString)syntax.GetWord();
46        csFont += " ";
47        csFont += (CFX_ByteString)syntax.GetWord();
48        csFont += " ";
49        csFont += (CFX_ByteString)syntax.GetWord();
50    }
51    return csFont;
52}
53void CPDF_DefaultAppearance::GetFont(CFX_ByteString& csFontNameTag, FX_FLOAT& fFontSize)
54{
55    csFontNameTag = "";
56    fFontSize = 0;
57    if (m_csDA.IsEmpty()) {
58        return;
59    }
60    CPDF_SimpleParser syntax(m_csDA);
61    if (syntax.FindTagParam("Tf", 2)) {
62        csFontNameTag = (CFX_ByteString)syntax.GetWord();
63        csFontNameTag.Delete(0, 1);
64        fFontSize = FX_atof((CFX_ByteString)syntax.GetWord());
65    }
66    csFontNameTag = PDF_NameDecode(csFontNameTag);
67}
68FX_BOOL CPDF_DefaultAppearance::HasColor(FX_BOOL bStrokingOperation)
69{
70    if (m_csDA.IsEmpty()) {
71        return FALSE;
72    }
73    CPDF_SimpleParser syntax(m_csDA);
74    if (syntax.FindTagParam(bStrokingOperation ? "G" : "g", 1)) {
75        return TRUE;
76    }
77    syntax.SetPos(0);
78    if (syntax.FindTagParam(bStrokingOperation ? "RG" : "rg", 3)) {
79        return TRUE;
80    }
81    syntax.SetPos(0);
82    return syntax.FindTagParam(bStrokingOperation ? "K" : "k", 4);
83}
84CFX_ByteString CPDF_DefaultAppearance::GetColorString(FX_BOOL bStrokingOperation)
85{
86    CFX_ByteString csColor;
87    if (m_csDA.IsEmpty()) {
88        return csColor;
89    }
90    CPDF_SimpleParser syntax(m_csDA);
91    if (syntax.FindTagParam(bStrokingOperation ? "G" : "g", 1)) {
92        csColor += (CFX_ByteString)syntax.GetWord();
93        csColor += " ";
94        csColor += (CFX_ByteString)syntax.GetWord();
95        return csColor;
96    }
97    syntax.SetPos(0);
98    if (syntax.FindTagParam(bStrokingOperation ? "RG" : "rg", 3)) {
99        csColor += (CFX_ByteString)syntax.GetWord();
100        csColor += " ";
101        csColor += (CFX_ByteString)syntax.GetWord();
102        csColor += " ";
103        csColor += (CFX_ByteString)syntax.GetWord();
104        csColor += " ";
105        csColor += (CFX_ByteString)syntax.GetWord();
106        return csColor;
107    }
108    syntax.SetPos(0);
109    if (syntax.FindTagParam(bStrokingOperation ? "K" : "k", 4)) {
110        csColor += (CFX_ByteString)syntax.GetWord();
111        csColor += " ";
112        csColor += (CFX_ByteString)syntax.GetWord();
113        csColor += " ";
114        csColor += (CFX_ByteString)syntax.GetWord();
115        csColor += " ";
116        csColor += (CFX_ByteString)syntax.GetWord();
117        csColor += " ";
118        csColor += (CFX_ByteString)syntax.GetWord();
119    }
120    return csColor;
121}
122void CPDF_DefaultAppearance::GetColor(int& iColorType, FX_FLOAT fc[4], FX_BOOL bStrokingOperation)
123{
124    iColorType = COLORTYPE_TRANSPARENT;
125    for (int c = 0; c < 4; c ++) {
126        fc[c] = 0;
127    }
128    if (m_csDA.IsEmpty()) {
129        return;
130    }
131    CPDF_SimpleParser syntax(m_csDA);
132    if (syntax.FindTagParam(bStrokingOperation ? "G" : "g", 1)) {
133        iColorType = COLORTYPE_GRAY;
134        fc[0] = FX_atof((CFX_ByteString)syntax.GetWord());
135        return;
136    }
137    syntax.SetPos(0);
138    if (syntax.FindTagParam(bStrokingOperation ? "RG" : "rg", 3)) {
139        iColorType = COLORTYPE_RGB;
140        fc[0] = FX_atof((CFX_ByteString)syntax.GetWord());
141        fc[1] = FX_atof((CFX_ByteString)syntax.GetWord());
142        fc[2] = FX_atof((CFX_ByteString)syntax.GetWord());
143        return;
144    }
145    syntax.SetPos(0);
146    if (syntax.FindTagParam(bStrokingOperation ? "K" : "k", 4)) {
147        iColorType = COLORTYPE_CMYK;
148        fc[0] = FX_atof((CFX_ByteString)syntax.GetWord());
149        fc[1] = FX_atof((CFX_ByteString)syntax.GetWord());
150        fc[2] = FX_atof((CFX_ByteString)syntax.GetWord());
151        fc[3] = FX_atof((CFX_ByteString)syntax.GetWord());
152    }
153}
154void CPDF_DefaultAppearance::GetColor(FX_ARGB& color, int& iColorType, FX_BOOL bStrokingOperation)
155{
156    color = 0;
157    iColorType = COLORTYPE_TRANSPARENT;
158    if (m_csDA.IsEmpty()) {
159        return;
160    }
161    CPDF_SimpleParser syntax(m_csDA);
162    if (syntax.FindTagParam(bStrokingOperation ? "G" : "g", 1)) {
163        iColorType = COLORTYPE_GRAY;
164        FX_FLOAT g = FX_atof((CFX_ByteString)syntax.GetWord()) * 255 + 0.5f;
165        color = ArgbEncode(255, (int)g, (int)g, (int)g);
166        return;
167    }
168    syntax.SetPos(0);
169    if (syntax.FindTagParam(bStrokingOperation ? "RG" : "rg", 3)) {
170        iColorType = COLORTYPE_RGB;
171        FX_FLOAT r = FX_atof((CFX_ByteString)syntax.GetWord()) * 255 + 0.5f;
172        FX_FLOAT g = FX_atof((CFX_ByteString)syntax.GetWord()) * 255 + 0.5f;
173        FX_FLOAT b = FX_atof((CFX_ByteString)syntax.GetWord()) * 255 + 0.5f;
174        color = ArgbEncode(255, (int)r, (int)g, (int)b);
175        return;
176    }
177    syntax.SetPos(0);
178    if (syntax.FindTagParam(bStrokingOperation ? "K" : "k", 4)) {
179        iColorType = COLORTYPE_CMYK;
180        FX_FLOAT c = FX_atof((CFX_ByteString)syntax.GetWord());
181        FX_FLOAT m = FX_atof((CFX_ByteString)syntax.GetWord());
182        FX_FLOAT y = FX_atof((CFX_ByteString)syntax.GetWord());
183        FX_FLOAT k = FX_atof((CFX_ByteString)syntax.GetWord());
184        FX_FLOAT r = 1.0f - FX_MIN(1.0f, c + k);
185        FX_FLOAT g = 1.0f - FX_MIN(1.0f, m + k);
186        FX_FLOAT b = 1.0f - FX_MIN(1.0f, y + k);
187        color = ArgbEncode(255, (int)(r * 255 + 0.5f), (int)(g * 255 + 0.5f), (int)(b * 255 + 0.5f));
188    }
189}
190FX_BOOL CPDF_DefaultAppearance::HasTextMatrix()
191{
192    if (m_csDA.IsEmpty()) {
193        return FALSE;
194    }
195    CPDF_SimpleParser syntax(m_csDA);
196    return syntax.FindTagParam("Tm", 6);
197}
198CFX_ByteString CPDF_DefaultAppearance::GetTextMatrixString()
199{
200    CFX_ByteString csTM;
201    if (m_csDA.IsEmpty()) {
202        return csTM;
203    }
204    CPDF_SimpleParser syntax(m_csDA);
205    if (syntax.FindTagParam("Tm", 6)) {
206        for (int i = 0; i < 6; i ++) {
207            csTM += (CFX_ByteString)syntax.GetWord();
208            csTM += " ";
209        }
210        csTM += (CFX_ByteString)syntax.GetWord();
211    }
212    return csTM;
213}
214CFX_AffineMatrix CPDF_DefaultAppearance::GetTextMatrix()
215{
216    CFX_AffineMatrix tm;
217    if (m_csDA.IsEmpty()) {
218        return tm;
219    }
220    CPDF_SimpleParser syntax(m_csDA);
221    if (syntax.FindTagParam("Tm", 6)) {
222        FX_FLOAT f[6];
223        for (int i = 0; i < 6; i ++) {
224            f[i] = FX_atof((CFX_ByteString)syntax.GetWord());
225        }
226        tm.Set(f[0], f[1], f[2], f[3], f[4], f[5]);
227    }
228    return tm;
229}
230void InitInterFormDict(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument)
231{
232    if (pDocument == NULL) {
233        return;
234    }
235    if (pFormDict == NULL) {
236        pFormDict = CPDF_Dictionary::Create();
237        if (pFormDict == NULL) {
238            return;
239        }
240        FX_DWORD dwObjNum = pDocument->AddIndirectObject(pFormDict);
241        CPDF_Dictionary* pRoot = pDocument->GetRoot();
242        pRoot->SetAtReference("AcroForm", pDocument, dwObjNum);
243    }
244    CFX_ByteString csDA;
245    if (!pFormDict->KeyExist("DR")) {
246        CPDF_Font* pFont = NULL;
247        CFX_ByteString csBaseName, csDefault;
248        FX_BYTE charSet = CPDF_InterForm::GetNativeCharSet();
249        pFont = CPDF_InterForm::AddStandardFont(pDocument, "Helvetica");
250        if (pFont != NULL) {
251            AddInterFormFont(pFormDict, pDocument, pFont, csBaseName);
252            csDefault = csBaseName;
253        }
254        if (charSet != 0) {
255            CFX_ByteString csFontName = CPDF_InterForm::GetNativeFont(charSet, NULL);
256            if (pFont == NULL || csFontName != "Helvetica") {
257                pFont = CPDF_InterForm::AddNativeFont(pDocument);
258                if (pFont != NULL) {
259                    csBaseName = "";
260                    AddInterFormFont(pFormDict, pDocument, pFont, csBaseName);
261                    csDefault = csBaseName;
262                }
263            }
264        }
265        if (pFont != NULL) {
266            csDA = "/" + PDF_NameEncode(csDefault) + " 0 Tf";
267        }
268    }
269    if (!csDA.IsEmpty()) {
270        csDA += " ";
271    }
272    csDA += "0 g";
273    if (!pFormDict->KeyExist("DA")) {
274        pFormDict->SetAtString("DA", csDA);
275    }
276}
277FX_DWORD CountInterFormFonts(CPDF_Dictionary* pFormDict)
278{
279    if (pFormDict == NULL) {
280        return 0;
281    }
282    CPDF_Dictionary* pDR = pFormDict->GetDict("DR");
283    if (pDR == NULL) {
284        return 0;
285    }
286    CPDF_Dictionary* pFonts = pDR->GetDict("Font");
287    if (pFonts == NULL) {
288        return 0;
289    }
290    FX_DWORD dwCount = 0;
291    FX_POSITION pos = pFonts->GetStartPos();
292    while (pos) {
293        CPDF_Object* pObj = NULL;
294        CFX_ByteString csKey;
295        pObj = pFonts->GetNextElement(pos, csKey);
296        if (pObj == NULL) {
297            continue;
298        }
299        CPDF_Object* pDirect = pObj->GetDirect();
300        if (pDirect != NULL && pDirect->GetType() == PDFOBJ_DICTIONARY) {
301            if (((CPDF_Dictionary*)pDirect)->GetString("Type") == "Font") {
302                dwCount ++;
303            }
304        }
305    }
306    return dwCount;
307}
308CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, FX_DWORD index, CFX_ByteString& csNameTag)
309{
310    if (pFormDict == NULL) {
311        return NULL;
312    }
313    CPDF_Dictionary* pDR = pFormDict->GetDict("DR");
314    if (pDR == NULL) {
315        return NULL;
316    }
317    CPDF_Dictionary* pFonts = pDR->GetDict("Font");
318    if (pFonts == NULL) {
319        return NULL;
320    }
321    FX_DWORD dwCount = 0;
322    FX_POSITION pos = pFonts->GetStartPos();
323    while (pos) {
324        CPDF_Object* pObj = NULL;
325        CFX_ByteString csKey;
326        pObj = pFonts->GetNextElement(pos, csKey);
327        if (pObj == NULL) {
328            continue;
329        }
330        CPDF_Object* pDirect = pObj->GetDirect();
331        if (pDirect == NULL || pDirect->GetType() != PDFOBJ_DICTIONARY) {
332            continue;
333        }
334        CPDF_Dictionary* pElement = (CPDF_Dictionary*)pDirect;
335        if (pElement->GetString("Type") != "Font") {
336            continue;
337        }
338        if (dwCount == index) {
339            csNameTag = csKey;
340            return pDocument->LoadFont(pElement);
341        }
342        dwCount ++;
343    }
344    return NULL;
345}
346CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, CFX_ByteString csNameTag)
347{
348    CFX_ByteString csAlias = PDF_NameDecode(csNameTag);
349    if (pFormDict == NULL || csAlias.IsEmpty()) {
350        return NULL;
351    }
352    CPDF_Dictionary* pDR = pFormDict->GetDict("DR");
353    if (pDR == NULL) {
354        return NULL;
355    }
356    CPDF_Dictionary* pFonts = pDR->GetDict("Font");
357    if (pFonts == NULL) {
358        return NULL;
359    }
360    CPDF_Dictionary* pElement = pFonts->GetDict(csAlias);
361    if (pElement == NULL) {
362        return NULL;
363    }
364    if (pElement->GetString("Type") == "Font") {
365        return pDocument->LoadFont(pElement);
366    }
367    return NULL;
368}
369CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, CFX_ByteString csFontName, CFX_ByteString& csNameTag)
370{
371    if (pFormDict == NULL || csFontName.IsEmpty()) {
372        return NULL;
373    }
374    CPDF_Dictionary* pDR = pFormDict->GetDict("DR");
375    if (pDR == NULL) {
376        return NULL;
377    }
378    CPDF_Dictionary* pFonts = pDR->GetDict("Font");
379    if (pFonts == NULL) {
380        return NULL;
381    }
382    FX_POSITION pos = pFonts->GetStartPos();
383    while (pos) {
384        CPDF_Object* pObj = NULL;
385        CFX_ByteString csKey;
386        pObj = pFonts->GetNextElement(pos, csKey);
387        if (pObj == NULL) {
388            continue;
389        }
390        CPDF_Object* pDirect = pObj->GetDirect();
391        if (pDirect == NULL || pDirect->GetType() != PDFOBJ_DICTIONARY) {
392            continue;
393        }
394        CPDF_Dictionary* pElement = (CPDF_Dictionary*)pDirect;
395        if (pElement->GetString("Type") != "Font") {
396            continue;
397        }
398        CPDF_Font* pFind = pDocument->LoadFont(pElement);
399        if (pFind == NULL) {
400            continue;
401        }
402        CFX_ByteString csBaseFont;
403        csBaseFont = pFind->GetBaseFont();
404        csBaseFont.Remove(' ');
405        if (csBaseFont == csFontName) {
406            csNameTag = csKey;
407            return pFind;
408        }
409    }
410    return NULL;
411}
412CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, FX_BYTE charSet, CFX_ByteString& csNameTag)
413{
414    if (pFormDict == NULL) {
415        return NULL;
416    }
417    CPDF_Dictionary* pDR = pFormDict->GetDict("DR");
418    if (pDR == NULL) {
419        return NULL;
420    }
421    CPDF_Dictionary* pFonts = pDR->GetDict("Font");
422    if (pFonts == NULL) {
423        return NULL;
424    }
425    FX_POSITION pos = pFonts->GetStartPos();
426    while (pos) {
427        CPDF_Object* pObj = NULL;
428        CFX_ByteString csKey;
429        pObj = pFonts->GetNextElement(pos, csKey);
430        if (pObj == NULL) {
431            continue;
432        }
433        CPDF_Object* pDirect = pObj->GetDirect();
434        if (pDirect == NULL || pDirect->GetType() != PDFOBJ_DICTIONARY) {
435            continue;
436        }
437        CPDF_Dictionary* pElement = (CPDF_Dictionary*)pDirect;
438        if (pElement->GetString("Type") != "Font") {
439            continue;
440        }
441        CPDF_Font* pFind = pDocument->LoadFont(pElement);
442        if (pFind == NULL) {
443            continue;
444        }
445        CFX_SubstFont* pSubst = (CFX_SubstFont*)pFind->GetSubstFont();
446        if (pSubst == NULL) {
447            continue;
448        }
449        if (pSubst->m_Charset == (int)charSet) {
450            csNameTag = csKey;
451            return pFind;
452        }
453    }
454    return NULL;
455}
456CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, CFX_ByteString& csNameTag)
457{
458    csNameTag = "";
459    FX_BYTE charSet = CPDF_InterForm::GetNativeCharSet();
460    CFX_SubstFont* pSubst;
461    CPDF_Font* pFont = GetDefaultInterFormFont(pFormDict, pDocument);
462    if (pFont != NULL) {
463        pSubst = (CFX_SubstFont*)pFont->GetSubstFont();
464        if (pSubst != NULL && pSubst->m_Charset == (int)charSet) {
465            FindInterFormFont(pFormDict, pFont, csNameTag);
466            return pFont;
467        }
468    }
469    return GetNativeInterFormFont(pFormDict, pDocument, charSet, csNameTag);
470}
471FX_BOOL FindInterFormFont(CPDF_Dictionary* pFormDict, const CPDF_Font* pFont, CFX_ByteString& csNameTag)
472{
473    if (pFormDict == NULL || pFont == NULL) {
474        return FALSE;
475    }
476    CPDF_Dictionary* pDR = pFormDict->GetDict("DR");
477    if (pDR == NULL) {
478        return FALSE;
479    }
480    CPDF_Dictionary* pFonts = pDR->GetDict("Font");
481    if (pFonts == NULL) {
482        return FALSE;
483    }
484    FX_POSITION pos = pFonts->GetStartPos();
485    while (pos) {
486        CPDF_Object* pObj = NULL;
487        CFX_ByteString csKey;
488        pObj = pFonts->GetNextElement(pos, csKey);
489        if (pObj == NULL) {
490            continue;
491        }
492        CPDF_Object* pDirect = pObj->GetDirect();
493        if (pDirect == NULL || pDirect->GetType() != PDFOBJ_DICTIONARY) {
494            continue;
495        }
496        CPDF_Dictionary* pElement = (CPDF_Dictionary*)pDirect;
497        if (pElement->GetString("Type") != "Font") {
498            continue;
499        }
500        if (pFont->GetFontDict() == pElement) {
501            csNameTag = csKey;
502            return TRUE;
503        }
504    }
505    return FALSE;
506}
507FX_BOOL FindInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, CFX_ByteString csFontName, CPDF_Font*& pFont, CFX_ByteString& csNameTag)
508{
509    if (pFormDict == NULL) {
510        return FALSE;
511    }
512    CPDF_Dictionary* pDR = pFormDict->GetDict("DR");
513    if (pDR == NULL) {
514        return FALSE;
515    }
516    CPDF_Dictionary* pFonts = pDR->GetDict("Font");
517    if (pFonts == NULL) {
518        return FALSE;
519    }
520    if (csFontName.GetLength() > 0) {
521        csFontName.Remove(' ');
522    }
523    FX_POSITION pos = pFonts->GetStartPos();
524    while (pos) {
525        CPDF_Object* pObj = NULL;
526        CFX_ByteString csKey, csTmp;
527        pObj = pFonts->GetNextElement(pos, csKey);
528        if (pObj == NULL) {
529            continue;
530        }
531        CPDF_Object* pDirect = pObj->GetDirect();
532        if (pDirect == NULL || pDirect->GetType() != PDFOBJ_DICTIONARY) {
533            continue;
534        }
535        CPDF_Dictionary* pElement = (CPDF_Dictionary*)pDirect;
536        if (pElement->GetString("Type") != "Font") {
537            continue;
538        }
539        pFont = pDocument->LoadFont(pElement);
540        if (pFont == NULL) {
541            continue;
542        }
543        CFX_ByteString csBaseFont;
544        csBaseFont = pFont->GetBaseFont();
545        csBaseFont.Remove(' ');
546        if (csBaseFont == csFontName) {
547            csNameTag = csKey;
548            return TRUE;
549        }
550    }
551    return FALSE;
552}
553void AddInterFormFont(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument, const CPDF_Font* pFont, CFX_ByteString& csNameTag)
554{
555    if (pFont == NULL) {
556        return;
557    }
558    if (pFormDict == NULL) {
559        InitInterFormDict(pFormDict, pDocument);
560    }
561    CFX_ByteString csTag;
562    if (FindInterFormFont(pFormDict, pFont, csTag)) {
563        csNameTag = csTag;
564        return;
565    }
566    if (pFormDict == NULL) {
567        InitInterFormDict(pFormDict, pDocument);
568    }
569    CPDF_Dictionary* pDR = pFormDict->GetDict("DR");
570    if (pDR == NULL) {
571        pDR = CPDF_Dictionary::Create();
572        if (pDR == NULL) {
573            return;
574        }
575        pFormDict->SetAt("DR", pDR);
576    }
577    CPDF_Dictionary* pFonts = pDR->GetDict("Font");
578    if (pFonts == NULL) {
579        pFonts = CPDF_Dictionary::Create();
580        pDR->SetAt("Font", pFonts);
581    }
582    if (csNameTag.IsEmpty()) {
583        csNameTag = pFont->GetBaseFont();
584    }
585    csNameTag.Remove(' ');
586    csNameTag = CPDF_InterForm::GenerateNewResourceName(pDR, "Font", 4, csNameTag);
587    pFonts->SetAtReference(csNameTag, pDocument, pFont->GetFontDict());
588}
589CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument, FX_BYTE charSet, CFX_ByteString& csNameTag)
590{
591    if (pFormDict == NULL) {
592        InitInterFormDict(pFormDict, pDocument);
593    }
594    CFX_ByteString csTemp;
595    CPDF_Font* pFont = GetNativeInterFormFont(pFormDict, pDocument, charSet, csTemp);
596    if (pFont != NULL) {
597        csNameTag = csTemp;
598        return pFont;
599    }
600    CFX_ByteString csFontName = CPDF_InterForm::GetNativeFont(charSet);
601    if (!csFontName.IsEmpty()) {
602        if (FindInterFormFont(pFormDict, pDocument, csFontName, pFont, csNameTag)) {
603            return pFont;
604        }
605    }
606    pFont = CPDF_InterForm::AddNativeFont(charSet, pDocument);
607    if (pFont != NULL) {
608        AddInterFormFont(pFormDict, pDocument, pFont, csNameTag);
609    }
610    return pFont;
611}
612CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument, CFX_ByteString& csNameTag)
613{
614    FX_BYTE charSet = CPDF_InterForm::GetNativeCharSet();
615    return AddNativeInterFormFont(pFormDict, pDocument, charSet, csNameTag);
616}
617void RemoveInterFormFont(CPDF_Dictionary* pFormDict, const CPDF_Font* pFont)
618{
619    if (pFormDict == NULL || pFont == NULL) {
620        return;
621    }
622    CFX_ByteString csTag;
623    if (!FindInterFormFont(pFormDict, pFont, csTag)) {
624        return;
625    }
626    CPDF_Dictionary* pDR = pFormDict->GetDict("DR");
627    CPDF_Dictionary* pFonts = pDR->GetDict("Font");
628    pFonts->RemoveAt(csTag);
629}
630void RemoveInterFormFont(CPDF_Dictionary* pFormDict, CFX_ByteString csNameTag)
631{
632    if (pFormDict == NULL || csNameTag.IsEmpty()) {
633        return;
634    }
635    CPDF_Dictionary* pDR = pFormDict->GetDict("DR");
636    if (pDR == NULL) {
637        return;
638    }
639    CPDF_Dictionary* pFonts = pDR->GetDict("Font");
640    if (pFonts == NULL) {
641        return;
642    }
643    pFonts->RemoveAt(csNameTag);
644}
645CPDF_Font* GetDefaultInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument)
646{
647    if (pFormDict == NULL) {
648        return NULL;
649    }
650    CPDF_DefaultAppearance cDA = pFormDict->GetString("DA");
651    CFX_ByteString csFontNameTag;
652    FX_FLOAT fFontSize;
653    cDA.GetFont(csFontNameTag, fFontSize);
654    return GetInterFormFont(pFormDict, pDocument, csFontNameTag);
655}
656CPDF_IconFit::ScaleMethod CPDF_IconFit::GetScaleMethod()
657{
658    if (m_pDict == NULL) {
659        return Always;
660    }
661    CFX_ByteString csSW = m_pDict->GetString("SW", "A");
662    if (csSW == "B") {
663        return Bigger;
664    } else if (csSW == "S") {
665        return Smaller;
666    } else if (csSW == "N") {
667        return Never;
668    }
669    return Always;
670}
671FX_BOOL CPDF_IconFit::IsProportionalScale()
672{
673    if (m_pDict == NULL) {
674        return TRUE;
675    }
676    return m_pDict->GetString("S", "P") != "A";
677}
678void CPDF_IconFit::GetIconPosition(FX_FLOAT& fLeft, FX_FLOAT& fBottom)
679{
680    fLeft = fBottom = 0.5;
681    if (m_pDict == NULL) {
682        return;
683    }
684    CPDF_Array* pA = m_pDict->GetArray("A");
685    if (pA != NULL) {
686        FX_DWORD dwCount = pA->GetCount();
687        if (dwCount > 0) {
688            fLeft = pA->GetNumber(0);
689        }
690        if (dwCount > 1) {
691            fBottom = pA->GetNumber(1);
692        }
693    }
694}
695FX_BOOL CPDF_IconFit::GetFittingBounds()
696{
697    if (m_pDict == NULL) {
698        return FALSE;
699    }
700    return m_pDict->GetBoolean("FB");
701}
702void SaveCheckedFieldStatus(CPDF_FormField* pField, CFX_ByteArray& statusArray)
703{
704    int iCount = pField->CountControls();
705    for (int i = 0; i < iCount; i ++) {
706        CPDF_FormControl* pControl = pField->GetControl(i);
707        if (pControl == NULL) {
708            continue;
709        }
710        statusArray.Add(pControl->IsChecked() ? 1 : 0);
711    }
712}
713CPDF_Object* FPDF_GetFieldAttr(CPDF_Dictionary* pFieldDict, const FX_CHAR* name, int nLevel)
714{
715    if (nLevel > FPDFDOC_UTILS_MAXRECURSION) {
716        return NULL;
717    }
718    if (pFieldDict == NULL) {
719        return NULL;
720    }
721    CPDF_Object* pAttr = pFieldDict->GetElementValue(name);
722    if (pAttr) {
723        return pAttr;
724    }
725    CPDF_Dictionary* pParent = pFieldDict->GetDict("Parent");
726    if (pParent == NULL) {
727        return NULL;
728    }
729    return FPDF_GetFieldAttr(pParent, name, nLevel + 1);
730}
731