OLD | NEW |
1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
6 | 6 |
7 #include "core/fpdfapi/fpdf_font/include/cpdf_font.h" | 7 #include "core/fpdfapi/fpdf_font/include/cpdf_font.h" |
8 #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" | 8 #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" |
9 #include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" | 9 #include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" |
10 #include "core/fpdfapi/fpdf_parser/include/cpdf_simple_parser.h" | 10 #include "core/fpdfapi/fpdf_parser/include/cpdf_simple_parser.h" |
11 #include "core/fpdfapi/fpdf_parser/include/cpdf_stream.h" | 11 #include "core/fpdfapi/fpdf_parser/include/cpdf_stream.h" |
| 12 #include "core/fpdfdoc/cpvt_provider.h" |
12 #include "core/fpdfdoc/doc_utils.h" | 13 #include "core/fpdfdoc/doc_utils.h" |
13 #include "core/fpdfdoc/pdf_vt.h" | 14 #include "core/fpdfdoc/pdf_vt.h" |
14 #include "core/include/fpdfdoc/fpdf_ap.h" | |
15 #include "core/include/fpdfdoc/fpdf_doc.h" | 15 #include "core/include/fpdfdoc/fpdf_doc.h" |
16 #include "core/include/fpdfdoc/fpdf_vt.h" | 16 #include "core/include/fpdfdoc/fpdf_vt.h" |
17 | 17 |
18 #define PBS_SOLID 0 | |
19 #define PBS_DASH 1 | |
20 #define PBS_BEVELED 2 | |
21 #define PBS_INSET 3 | |
22 #define PBS_UNDERLINED 4 | |
23 | |
24 FX_BOOL FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { | |
25 if (!pAnnotDict || pAnnotDict->GetConstStringBy("Subtype") != "Widget") { | |
26 return FALSE; | |
27 } | |
28 CFX_ByteString field_type = FPDF_GetFieldAttr(pAnnotDict, "FT")->GetString(); | |
29 uint32_t flags = FPDF_GetFieldAttr(pAnnotDict, "Ff") | |
30 ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger() | |
31 : 0; | |
32 if (field_type == "Tx") { | |
33 return CPVT_GenerateAP::GenerateTextFieldAP(pDoc, pAnnotDict); | |
34 } | |
35 if (field_type == "Ch") { | |
36 return (flags & (1 << 17)) | |
37 ? CPVT_GenerateAP::GenerateComboBoxAP(pDoc, pAnnotDict) | |
38 : CPVT_GenerateAP::GenerateListBoxAP(pDoc, pAnnotDict); | |
39 } | |
40 if (field_type == "Btn") { | |
41 if (!(flags & (1 << 16))) { | |
42 if (!pAnnotDict->KeyExist("AS")) { | |
43 if (CPDF_Dictionary* pParentDict = pAnnotDict->GetDictBy("Parent")) { | |
44 if (pParentDict->KeyExist("AS")) { | |
45 pAnnotDict->SetAtString("AS", pParentDict->GetStringBy("AS")); | |
46 } | |
47 } | |
48 } | |
49 } | |
50 } | |
51 return FALSE; | |
52 } | |
53 | |
54 class CPVT_FontMap : public IPVT_FontMap { | |
55 public: | |
56 CPVT_FontMap(CPDF_Document* pDoc, | |
57 CPDF_Dictionary* pResDict, | |
58 CPDF_Font* pDefFont, | |
59 const CFX_ByteString& sDefFontAlias); | |
60 ~CPVT_FontMap() override; | |
61 | |
62 // IPVT_FontMap | |
63 CPDF_Font* GetPDFFont(int32_t nFontIndex) override; | |
64 CFX_ByteString GetPDFFontAlias(int32_t nFontIndex) override; | |
65 | |
66 static void GetAnnotSysPDFFont(CPDF_Document* pDoc, | |
67 CPDF_Dictionary* pResDict, | |
68 CPDF_Font*& pSysFont, | |
69 CFX_ByteString& sSysFontAlias); | |
70 | |
71 private: | |
72 CPDF_Document* m_pDocument; | |
73 CPDF_Dictionary* m_pResDict; | |
74 CPDF_Font* m_pDefFont; | |
75 CFX_ByteString m_sDefFontAlias; | |
76 CPDF_Font* m_pSysFont; | |
77 CFX_ByteString m_sSysFontAlias; | |
78 }; | |
79 | |
80 CPVT_FontMap::CPVT_FontMap(CPDF_Document* pDoc, | |
81 CPDF_Dictionary* pResDict, | |
82 CPDF_Font* pDefFont, | |
83 const CFX_ByteString& sDefFontAlias) | |
84 : m_pDocument(pDoc), | |
85 m_pResDict(pResDict), | |
86 m_pDefFont(pDefFont), | |
87 m_sDefFontAlias(sDefFontAlias), | |
88 m_pSysFont(NULL), | |
89 m_sSysFontAlias() {} | |
90 CPVT_FontMap::~CPVT_FontMap() {} | |
91 void CPVT_FontMap::GetAnnotSysPDFFont(CPDF_Document* pDoc, | |
92 CPDF_Dictionary* pResDict, | |
93 CPDF_Font*& pSysFont, | |
94 CFX_ByteString& sSysFontAlias) { | |
95 if (pDoc && pResDict) { | |
96 CFX_ByteString sFontAlias; | |
97 CPDF_Dictionary* pFormDict = pDoc->GetRoot()->GetDictBy("AcroForm"); | |
98 if (CPDF_Font* pPDFFont = | |
99 AddNativeInterFormFont(pFormDict, pDoc, sSysFontAlias)) { | |
100 if (CPDF_Dictionary* pFontList = pResDict->GetDictBy("Font")) { | |
101 if (!pFontList->KeyExist(sSysFontAlias)) { | |
102 pFontList->SetAtReference(sSysFontAlias, pDoc, | |
103 pPDFFont->GetFontDict()); | |
104 } | |
105 } | |
106 pSysFont = pPDFFont; | |
107 } | |
108 } | |
109 } | |
110 CPDF_Font* CPVT_FontMap::GetPDFFont(int32_t nFontIndex) { | |
111 switch (nFontIndex) { | |
112 case 0: | |
113 return m_pDefFont; | |
114 case 1: | |
115 if (!m_pSysFont) { | |
116 GetAnnotSysPDFFont(m_pDocument, m_pResDict, m_pSysFont, | |
117 m_sSysFontAlias); | |
118 } | |
119 return m_pSysFont; | |
120 } | |
121 return NULL; | |
122 } | |
123 CFX_ByteString CPVT_FontMap::GetPDFFontAlias(int32_t nFontIndex) { | |
124 switch (nFontIndex) { | |
125 case 0: | |
126 return m_sDefFontAlias; | |
127 case 1: | |
128 if (!m_pSysFont) { | |
129 GetAnnotSysPDFFont(m_pDocument, m_pResDict, m_pSysFont, | |
130 m_sSysFontAlias); | |
131 } | |
132 return m_sSysFontAlias; | |
133 } | |
134 return ""; | |
135 } | |
136 CPVT_Provider::CPVT_Provider(IPVT_FontMap* pFontMap) : m_pFontMap(pFontMap) { | 18 CPVT_Provider::CPVT_Provider(IPVT_FontMap* pFontMap) : m_pFontMap(pFontMap) { |
137 ASSERT(m_pFontMap); | 19 ASSERT(m_pFontMap); |
138 } | 20 } |
139 CPVT_Provider::~CPVT_Provider() {} | 21 CPVT_Provider::~CPVT_Provider() {} |
140 int32_t CPVT_Provider::GetCharWidth(int32_t nFontIndex, | 22 int32_t CPVT_Provider::GetCharWidth(int32_t nFontIndex, |
141 uint16_t word, | 23 uint16_t word, |
142 int32_t nWordStyle) { | 24 int32_t nWordStyle) { |
143 if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) { | 25 if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) { |
144 uint32_t charcode = pPDFFont->CharCodeFromUnicode(word); | 26 uint32_t charcode = pPDFFont->CharCodeFromUnicode(word); |
145 if (charcode != CPDF_Font::kInvalidCharCode) { | 27 if (charcode != CPDF_Font::kInvalidCharCode) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 if ((word >= 0x61 && word <= 0x7A) || (word >= 0x41 && word <= 0x5A) || | 61 if ((word >= 0x61 && word <= 0x7A) || (word >= 0x41 && word <= 0x5A) || |
180 word == 0x2D || word == 0x27) { | 62 word == 0x2D || word == 0x27) { |
181 return TRUE; | 63 return TRUE; |
182 } | 64 } |
183 return FALSE; | 65 return FALSE; |
184 } | 66 } |
185 int32_t CPVT_Provider::GetDefaultFontIndex() { | 67 int32_t CPVT_Provider::GetDefaultFontIndex() { |
186 return 0; | 68 return 0; |
187 } | 69 } |
188 | 70 |
189 static CFX_ByteString GetPDFWordString(IPVT_FontMap* pFontMap, | |
190 int32_t nFontIndex, | |
191 uint16_t Word, | |
192 uint16_t SubWord) { | |
193 CFX_ByteString sWord; | |
194 if (SubWord > 0) { | |
195 sWord.Format("%c", SubWord); | |
196 return sWord; | |
197 } | |
198 | |
199 if (!pFontMap) | |
200 return sWord; | |
201 | |
202 if (CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex)) { | |
203 if (pPDFFont->GetBaseFont().Compare("Symbol") == 0 || | |
204 pPDFFont->GetBaseFont().Compare("ZapfDingbats") == 0) { | |
205 sWord.Format("%c", Word); | |
206 } else { | |
207 uint32_t dwCharCode = pPDFFont->CharCodeFromUnicode(Word); | |
208 if (dwCharCode != CPDF_Font::kInvalidCharCode) { | |
209 pPDFFont->AppendChar(sWord, dwCharCode); | |
210 } | |
211 } | |
212 } | |
213 return sWord; | |
214 } | |
215 | |
216 static CFX_ByteString GetWordRenderString(const CFX_ByteString& strWords) { | |
217 if (strWords.GetLength() > 0) { | |
218 return PDF_EncodeString(strWords) + " Tj\n"; | |
219 } | |
220 return ""; | |
221 } | |
222 static CFX_ByteString GetFontSetString(IPVT_FontMap* pFontMap, | |
223 int32_t nFontIndex, | |
224 FX_FLOAT fFontSize) { | |
225 CFX_ByteTextBuf sRet; | |
226 if (pFontMap) { | |
227 CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex); | |
228 if (sFontAlias.GetLength() > 0 && fFontSize > 0) { | |
229 sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n"; | |
230 } | |
231 } | |
232 return sRet.GetByteString(); | |
233 } | |
234 static CPVT_Color ParseColor(const CFX_ByteString& str) { | |
235 CPDF_SimpleParser syntax(str); | |
236 if (syntax.FindTagParamFromStart("g", 1)) { | |
237 return CPVT_Color(CPVT_Color::kGray, FX_atof(syntax.GetWord())); | |
238 } | |
239 if (syntax.FindTagParamFromStart("rg", 3)) { | |
240 FX_FLOAT f1 = FX_atof(syntax.GetWord()); | |
241 FX_FLOAT f2 = FX_atof(syntax.GetWord()); | |
242 FX_FLOAT f3 = FX_atof(syntax.GetWord()); | |
243 return CPVT_Color(CPVT_Color::kRGB, f1, f2, f3); | |
244 } | |
245 if (syntax.FindTagParamFromStart("k", 4)) { | |
246 FX_FLOAT f1 = FX_atof(syntax.GetWord()); | |
247 FX_FLOAT f2 = FX_atof(syntax.GetWord()); | |
248 FX_FLOAT f3 = FX_atof(syntax.GetWord()); | |
249 FX_FLOAT f4 = FX_atof(syntax.GetWord()); | |
250 return CPVT_Color(CPVT_Color::kCMYK, f1, f2, f3, f4); | |
251 } | |
252 return CPVT_Color(CPVT_Color::kTransparent); | |
253 } | |
254 static CPVT_Color ParseColor(const CPDF_Array& array) { | |
255 CPVT_Color rt; | |
256 switch (array.GetCount()) { | |
257 case 1: | |
258 rt = CPVT_Color(CPVT_Color::kGray, array.GetFloatAt(0)); | |
259 break; | |
260 case 3: | |
261 rt = CPVT_Color(CPVT_Color::kRGB, array.GetFloatAt(0), | |
262 array.GetFloatAt(1), array.GetFloatAt(2)); | |
263 break; | |
264 case 4: | |
265 rt = CPVT_Color(CPVT_Color::kCMYK, array.GetFloatAt(0), | |
266 array.GetFloatAt(1), array.GetFloatAt(2), | |
267 array.GetFloatAt(3)); | |
268 break; | |
269 } | |
270 return rt; | |
271 } | |
272 static FX_BOOL GenerateWidgetAP(CPDF_Document* pDoc, | |
273 CPDF_Dictionary* pAnnotDict, | |
274 const int32_t& nWidgetType) { | |
275 CPDF_Dictionary* pFormDict = NULL; | |
276 if (CPDF_Dictionary* pRootDict = pDoc->GetRoot()) { | |
277 pFormDict = pRootDict->GetDictBy("AcroForm"); | |
278 } | |
279 if (!pFormDict) { | |
280 return FALSE; | |
281 } | |
282 CFX_ByteString DA; | |
283 if (CPDF_Object* pDAObj = FPDF_GetFieldAttr(pAnnotDict, "DA")) { | |
284 DA = pDAObj->GetString(); | |
285 } | |
286 if (DA.IsEmpty()) { | |
287 DA = pFormDict->GetStringBy("DA"); | |
288 } | |
289 if (DA.IsEmpty()) { | |
290 return FALSE; | |
291 } | |
292 CPDF_SimpleParser syntax(DA); | |
293 syntax.FindTagParamFromStart("Tf", 2); | |
294 CFX_ByteString sFontName = syntax.GetWord(); | |
295 sFontName = PDF_NameDecode(sFontName); | |
296 if (sFontName.IsEmpty()) { | |
297 return FALSE; | |
298 } | |
299 FX_FLOAT fFontSize = FX_atof(syntax.GetWord()); | |
300 CPVT_Color crText = ParseColor(DA); | |
301 FX_BOOL bUseFormRes = FALSE; | |
302 CPDF_Dictionary* pFontDict = NULL; | |
303 CPDF_Dictionary* pDRDict = pAnnotDict->GetDictBy("DR"); | |
304 if (!pDRDict) { | |
305 pDRDict = pFormDict->GetDictBy("DR"); | |
306 bUseFormRes = TRUE; | |
307 } | |
308 CPDF_Dictionary* pDRFontDict = pDRDict ? pDRDict->GetDictBy("Font") : nullptr; | |
309 if (pDRFontDict) { | |
310 pFontDict = pDRFontDict->GetDictBy(sFontName.Mid(1)); | |
311 if (!pFontDict && !bUseFormRes) { | |
312 pDRDict = pFormDict->GetDictBy("DR"); | |
313 pDRFontDict = pDRDict->GetDictBy("Font"); | |
314 if (pDRFontDict) { | |
315 pFontDict = pDRFontDict->GetDictBy(sFontName.Mid(1)); | |
316 } | |
317 } | |
318 } | |
319 if (!pDRFontDict) { | |
320 return FALSE; | |
321 } | |
322 if (!pFontDict) { | |
323 pFontDict = new CPDF_Dictionary; | |
324 pFontDict->SetAtName("Type", "Font"); | |
325 pFontDict->SetAtName("Subtype", "Type1"); | |
326 pFontDict->SetAtName("BaseFont", "Helvetica"); | |
327 pFontDict->SetAtName("Encoding", "WinAnsiEncoding"); | |
328 pDoc->AddIndirectObject(pFontDict); | |
329 pDRFontDict->SetAtReference(sFontName.Mid(1), pDoc, pFontDict); | |
330 } | |
331 CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict); | |
332 if (!pDefFont) { | |
333 return FALSE; | |
334 } | |
335 CFX_FloatRect rcAnnot = pAnnotDict->GetRectBy("Rect"); | |
336 int32_t nRotate = 0; | |
337 if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictBy("MK")) { | |
338 nRotate = pMKDict->GetIntegerBy("R"); | |
339 } | |
340 CFX_FloatRect rcBBox; | |
341 CFX_Matrix matrix; | |
342 switch (nRotate % 360) { | |
343 case 0: | |
344 rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left, | |
345 rcAnnot.top - rcAnnot.bottom); | |
346 break; | |
347 case 90: | |
348 matrix = CFX_Matrix(0, 1, -1, 0, rcAnnot.right - rcAnnot.left, 0); | |
349 rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom, | |
350 rcAnnot.right - rcAnnot.left); | |
351 break; | |
352 case 180: | |
353 matrix = CFX_Matrix(-1, 0, 0, -1, rcAnnot.right - rcAnnot.left, | |
354 rcAnnot.top - rcAnnot.bottom); | |
355 rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left, | |
356 rcAnnot.top - rcAnnot.bottom); | |
357 break; | |
358 case 270: | |
359 matrix = CFX_Matrix(0, -1, 1, 0, 0, rcAnnot.top - rcAnnot.bottom); | |
360 rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom, | |
361 rcAnnot.right - rcAnnot.left); | |
362 break; | |
363 } | |
364 int32_t nBorderStyle = PBS_SOLID; | |
365 FX_FLOAT fBorderWidth = 1; | |
366 CPVT_Dash dsBorder(3, 0, 0); | |
367 CPVT_Color crLeftTop, crRightBottom; | |
368 if (CPDF_Dictionary* pBSDict = pAnnotDict->GetDictBy("BS")) { | |
369 if (pBSDict->KeyExist("W")) { | |
370 fBorderWidth = pBSDict->GetNumberBy("W"); | |
371 } | |
372 if (CPDF_Array* pArray = pBSDict->GetArrayBy("D")) { | |
373 dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1), | |
374 pArray->GetIntegerAt(2)); | |
375 } | |
376 switch (pBSDict->GetStringBy("S").GetAt(0)) { | |
377 case 'S': | |
378 nBorderStyle = PBS_SOLID; | |
379 break; | |
380 case 'D': | |
381 nBorderStyle = PBS_DASH; | |
382 break; | |
383 case 'B': | |
384 nBorderStyle = PBS_BEVELED; | |
385 fBorderWidth *= 2; | |
386 crLeftTop = CPVT_Color(CPVT_Color::kGray, 1); | |
387 crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.5); | |
388 break; | |
389 case 'I': | |
390 nBorderStyle = PBS_INSET; | |
391 fBorderWidth *= 2; | |
392 crLeftTop = CPVT_Color(CPVT_Color::kGray, 0.5); | |
393 crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.75); | |
394 break; | |
395 case 'U': | |
396 nBorderStyle = PBS_UNDERLINED; | |
397 break; | |
398 } | |
399 } | |
400 CPVT_Color crBorder, crBG; | |
401 if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictBy("MK")) { | |
402 if (CPDF_Array* pArray = pMKDict->GetArrayBy("BC")) { | |
403 crBorder = ParseColor(*pArray); | |
404 } | |
405 if (CPDF_Array* pArray = pMKDict->GetArrayBy("BG")) { | |
406 crBG = ParseColor(*pArray); | |
407 } | |
408 } | |
409 CFX_ByteTextBuf sAppStream; | |
410 CFX_ByteString sBG = CPVT_GenerateAP::GenerateColorAP(crBG, TRUE); | |
411 if (sBG.GetLength() > 0) { | |
412 sAppStream << "q\n" << sBG << rcBBox.left << " " << rcBBox.bottom << " " | |
413 << rcBBox.Width() << " " << rcBBox.Height() << " re f\n" | |
414 << "Q\n"; | |
415 } | |
416 CFX_ByteString sBorderStream = CPVT_GenerateAP::GenerateBorderAP( | |
417 rcBBox, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, | |
418 dsBorder); | |
419 if (sBorderStream.GetLength() > 0) { | |
420 sAppStream << "q\n" << sBorderStream << "Q\n"; | |
421 } | |
422 CFX_FloatRect rcBody = | |
423 CFX_FloatRect(rcBBox.left + fBorderWidth, rcBBox.bottom + fBorderWidth, | |
424 rcBBox.right - fBorderWidth, rcBBox.top - fBorderWidth); | |
425 rcBody.Normalize(); | |
426 CPDF_Dictionary* pAPDict = pAnnotDict->GetDictBy("AP"); | |
427 if (!pAPDict) { | |
428 pAPDict = new CPDF_Dictionary; | |
429 pAnnotDict->SetAt("AP", pAPDict); | |
430 } | |
431 CPDF_Stream* pNormalStream = pAPDict->GetStreamBy("N"); | |
432 if (!pNormalStream) { | |
433 pNormalStream = new CPDF_Stream(nullptr, 0, nullptr); | |
434 int32_t objnum = pDoc->AddIndirectObject(pNormalStream); | |
435 pAnnotDict->GetDictBy("AP")->SetAtReference("N", pDoc, objnum); | |
436 } | |
437 CPDF_Dictionary* pStreamDict = pNormalStream->GetDict(); | |
438 if (pStreamDict) { | |
439 pStreamDict->SetAtMatrix("Matrix", matrix); | |
440 pStreamDict->SetAtRect("BBox", rcBBox); | |
441 CPDF_Dictionary* pStreamResList = pStreamDict->GetDictBy("Resources"); | |
442 if (pStreamResList) { | |
443 CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictBy("Font"); | |
444 if (!pStreamResFontList) { | |
445 pStreamResFontList = new CPDF_Dictionary; | |
446 pStreamResList->SetAt("Font", pStreamResFontList); | |
447 } | |
448 if (!pStreamResFontList->KeyExist(sFontName)) { | |
449 pStreamResFontList->SetAtReference(sFontName, pDoc, pFontDict); | |
450 } | |
451 } else { | |
452 pStreamDict->SetAt("Resources", pFormDict->GetDictBy("DR")->Clone()); | |
453 pStreamResList = pStreamDict->GetDictBy("Resources"); | |
454 } | |
455 } | |
456 switch (nWidgetType) { | |
457 case 0: { | |
458 CFX_WideString swValue = | |
459 FPDF_GetFieldAttr(pAnnotDict, "V") | |
460 ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText() | |
461 : CFX_WideString(); | |
462 int32_t nAlign = FPDF_GetFieldAttr(pAnnotDict, "Q") | |
463 ? FPDF_GetFieldAttr(pAnnotDict, "Q")->GetInteger() | |
464 : 0; | |
465 uint32_t dwFlags = FPDF_GetFieldAttr(pAnnotDict, "Ff") | |
466 ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger() | |
467 : 0; | |
468 uint32_t dwMaxLen = | |
469 FPDF_GetFieldAttr(pAnnotDict, "MaxLen") | |
470 ? FPDF_GetFieldAttr(pAnnotDict, "MaxLen")->GetInteger() | |
471 : 0; | |
472 CPVT_FontMap map(pDoc, | |
473 pStreamDict ? pStreamDict->GetDictBy("Resources") : NULL, | |
474 pDefFont, sFontName.Right(sFontName.GetLength() - 1)); | |
475 CPVT_Provider prd(&map); | |
476 CPDF_VariableText vt; | |
477 vt.SetProvider(&prd); | |
478 vt.SetPlateRect(rcBody); | |
479 vt.SetAlignment(nAlign); | |
480 if (IsFloatZero(fFontSize)) { | |
481 vt.SetAutoFontSize(TRUE); | |
482 } else { | |
483 vt.SetFontSize(fFontSize); | |
484 } | |
485 FX_BOOL bMultiLine = (dwFlags >> 12) & 1; | |
486 if (bMultiLine) { | |
487 vt.SetMultiLine(TRUE); | |
488 vt.SetAutoReturn(TRUE); | |
489 } | |
490 uint16_t subWord = 0; | |
491 if ((dwFlags >> 13) & 1) { | |
492 subWord = '*'; | |
493 vt.SetPasswordChar(subWord); | |
494 } | |
495 FX_BOOL bCharArray = (dwFlags >> 24) & 1; | |
496 if (bCharArray) { | |
497 vt.SetCharArray(dwMaxLen); | |
498 } else { | |
499 vt.SetLimitChar(dwMaxLen); | |
500 } | |
501 vt.Initialize(); | |
502 vt.SetText(swValue.c_str()); | |
503 vt.RearrangeAll(); | |
504 CFX_FloatRect rcContent = vt.GetContentRect(); | |
505 CFX_FloatPoint ptOffset(0.0f, 0.0f); | |
506 if (!bMultiLine) { | |
507 ptOffset = | |
508 CFX_FloatPoint(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f); | |
509 } | |
510 CFX_ByteString sBody = CPVT_GenerateAP::GenerateEditAP( | |
511 &map, vt.GetIterator(), ptOffset, !bCharArray, subWord); | |
512 if (sBody.GetLength() > 0) { | |
513 sAppStream << "/Tx BMC\n" | |
514 << "q\n"; | |
515 if (rcContent.Width() > rcBody.Width() || | |
516 rcContent.Height() > rcBody.Height()) { | |
517 sAppStream << rcBody.left << " " << rcBody.bottom << " " | |
518 << rcBody.Width() << " " << rcBody.Height() | |
519 << " re\nW\nn\n"; | |
520 } | |
521 sAppStream << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE) | |
522 << sBody << "ET\n" | |
523 << "Q\nEMC\n"; | |
524 } | |
525 } break; | |
526 case 1: { | |
527 CFX_WideString swValue = | |
528 FPDF_GetFieldAttr(pAnnotDict, "V") | |
529 ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText() | |
530 : CFX_WideString(); | |
531 CPVT_FontMap map(pDoc, | |
532 pStreamDict ? pStreamDict->GetDictBy("Resources") : NULL, | |
533 pDefFont, sFontName.Right(sFontName.GetLength() - 1)); | |
534 CPVT_Provider prd(&map); | |
535 CPDF_VariableText vt; | |
536 vt.SetProvider(&prd); | |
537 CFX_FloatRect rcButton = rcBody; | |
538 rcButton.left = rcButton.right - 13; | |
539 rcButton.Normalize(); | |
540 CFX_FloatRect rcEdit = rcBody; | |
541 rcEdit.right = rcButton.left; | |
542 rcEdit.Normalize(); | |
543 vt.SetPlateRect(rcEdit); | |
544 if (IsFloatZero(fFontSize)) { | |
545 vt.SetAutoFontSize(TRUE); | |
546 } else { | |
547 vt.SetFontSize(fFontSize); | |
548 } | |
549 vt.Initialize(); | |
550 vt.SetText(swValue.c_str()); | |
551 vt.RearrangeAll(); | |
552 CFX_FloatRect rcContent = vt.GetContentRect(); | |
553 CFX_FloatPoint ptOffset = | |
554 CFX_FloatPoint(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f); | |
555 CFX_ByteString sEdit = CPVT_GenerateAP::GenerateEditAP( | |
556 &map, vt.GetIterator(), ptOffset, TRUE, 0); | |
557 if (sEdit.GetLength() > 0) { | |
558 sAppStream << "/Tx BMC\n" | |
559 << "q\n"; | |
560 sAppStream << rcEdit.left << " " << rcEdit.bottom << " " | |
561 << rcEdit.Width() << " " << rcEdit.Height() << " re\nW\nn\n"; | |
562 sAppStream << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE) | |
563 << sEdit << "ET\n" | |
564 << "Q\nEMC\n"; | |
565 } | |
566 CFX_ByteString sButton = CPVT_GenerateAP::GenerateColorAP( | |
567 CPVT_Color(CPVT_Color::kRGB, 220.0f / 255.0f, 220.0f / 255.0f, | |
568 220.0f / 255.0f), | |
569 TRUE); | |
570 if (sButton.GetLength() > 0 && !rcButton.IsEmpty()) { | |
571 sAppStream << "q\n" << sButton; | |
572 sAppStream << rcButton.left << " " << rcButton.bottom << " " | |
573 << rcButton.Width() << " " << rcButton.Height() << " re f\n"; | |
574 sAppStream << "Q\n"; | |
575 CFX_ByteString sButtonBorder = CPVT_GenerateAP::GenerateBorderAP( | |
576 rcButton, 2, CPVT_Color(CPVT_Color::kGray, 0), | |
577 CPVT_Color(CPVT_Color::kGray, 1), | |
578 CPVT_Color(CPVT_Color::kGray, 0.5), PBS_BEVELED, | |
579 CPVT_Dash(3, 0, 0)); | |
580 if (sButtonBorder.GetLength() > 0) { | |
581 sAppStream << "q\n" << sButtonBorder << "Q\n"; | |
582 } | |
583 CFX_FloatPoint ptCenter = | |
584 CFX_FloatPoint((rcButton.left + rcButton.right) / 2, | |
585 (rcButton.top + rcButton.bottom) / 2); | |
586 if (IsFloatBigger(rcButton.Width(), 6) && | |
587 IsFloatBigger(rcButton.Height(), 6)) { | |
588 sAppStream << "q\n" | |
589 << " 0 g\n"; | |
590 sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n"; | |
591 sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n"; | |
592 sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n"; | |
593 sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n"; | |
594 sAppStream << sButton << "Q\n"; | |
595 } | |
596 } | |
597 } break; | |
598 case 2: { | |
599 CPVT_FontMap map(pDoc, | |
600 pStreamDict ? pStreamDict->GetDictBy("Resources") : NULL, | |
601 pDefFont, sFontName.Right(sFontName.GetLength() - 1)); | |
602 CPVT_Provider prd(&map); | |
603 CPDF_Array* pOpts = FPDF_GetFieldAttr(pAnnotDict, "Opt") | |
604 ? FPDF_GetFieldAttr(pAnnotDict, "Opt")->GetArray() | |
605 : NULL; | |
606 CPDF_Array* pSels = FPDF_GetFieldAttr(pAnnotDict, "I") | |
607 ? FPDF_GetFieldAttr(pAnnotDict, "I")->GetArray() | |
608 : NULL; | |
609 int32_t nTop = FPDF_GetFieldAttr(pAnnotDict, "TI") | |
610 ? FPDF_GetFieldAttr(pAnnotDict, "TI")->GetInteger() | |
611 : 0; | |
612 CFX_ByteTextBuf sBody; | |
613 if (pOpts) { | |
614 FX_FLOAT fy = rcBody.top; | |
615 for (int32_t i = nTop, sz = pOpts->GetCount(); i < sz; i++) { | |
616 if (IsFloatSmaller(fy, rcBody.bottom)) { | |
617 break; | |
618 } | |
619 if (CPDF_Object* pOpt = pOpts->GetDirectObjectAt(i)) { | |
620 CFX_WideString swItem; | |
621 if (pOpt->IsString()) | |
622 swItem = pOpt->GetUnicodeText(); | |
623 else if (CPDF_Array* pArray = pOpt->AsArray()) | |
624 swItem = pArray->GetDirectObjectAt(1)->GetUnicodeText(); | |
625 | |
626 FX_BOOL bSelected = FALSE; | |
627 if (pSels) { | |
628 for (uint32_t s = 0, ssz = pSels->GetCount(); s < ssz; s++) { | |
629 if (i == pSels->GetIntegerAt(s)) { | |
630 bSelected = TRUE; | |
631 break; | |
632 } | |
633 } | |
634 } | |
635 CPDF_VariableText vt; | |
636 vt.SetProvider(&prd); | |
637 vt.SetPlateRect( | |
638 CFX_FloatRect(rcBody.left, 0.0f, rcBody.right, 0.0f)); | |
639 if (IsFloatZero(fFontSize)) { | |
640 vt.SetFontSize(12.0f); | |
641 } else { | |
642 vt.SetFontSize(fFontSize); | |
643 } | |
644 vt.Initialize(); | |
645 vt.SetText(swItem.c_str()); | |
646 vt.RearrangeAll(); | |
647 FX_FLOAT fItemHeight = vt.GetContentRect().Height(); | |
648 if (bSelected) { | |
649 CFX_FloatRect rcItem = CFX_FloatRect( | |
650 rcBody.left, fy - fItemHeight, rcBody.right, fy); | |
651 sBody << "q\n" << CPVT_GenerateAP::GenerateColorAP( | |
652 CPVT_Color(CPVT_Color::kRGB, 0, | |
653 51.0f / 255.0f, 113.0f / 255.0f), | |
654 TRUE) | |
655 << rcItem.left << " " << rcItem.bottom << " " | |
656 << rcItem.Width() << " " << rcItem.Height() << " re f\n" | |
657 << "Q\n"; | |
658 sBody << "BT\n" << CPVT_GenerateAP::GenerateColorAP( | |
659 CPVT_Color(CPVT_Color::kGray, 1), TRUE) | |
660 << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(), | |
661 CFX_FloatPoint(0.0f, fy), | |
662 TRUE, 0) | |
663 << "ET\n"; | |
664 } else { | |
665 sBody << "BT\n" << CPVT_GenerateAP::GenerateColorAP(crText, TRUE) | |
666 << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(), | |
667 CFX_FloatPoint(0.0f, fy), | |
668 TRUE, 0) | |
669 << "ET\n"; | |
670 } | |
671 fy -= fItemHeight; | |
672 } | |
673 } | |
674 } | |
675 if (sBody.GetSize() > 0) { | |
676 sAppStream << "/Tx BMC\n" | |
677 << "q\n"; | |
678 sAppStream << rcBody.left << " " << rcBody.bottom << " " | |
679 << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n"; | |
680 sAppStream << sBody.GetByteString() << "Q\nEMC\n"; | |
681 } | |
682 } break; | |
683 } | |
684 if (pNormalStream) { | |
685 pNormalStream->SetData((uint8_t*)sAppStream.GetBuffer(), | |
686 sAppStream.GetSize(), FALSE, FALSE); | |
687 pStreamDict = pNormalStream->GetDict(); | |
688 if (pStreamDict) { | |
689 pStreamDict->SetAtMatrix("Matrix", matrix); | |
690 pStreamDict->SetAtRect("BBox", rcBBox); | |
691 CPDF_Dictionary* pStreamResList = pStreamDict->GetDictBy("Resources"); | |
692 if (pStreamResList) { | |
693 CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictBy("Font"); | |
694 if (!pStreamResFontList) { | |
695 pStreamResFontList = new CPDF_Dictionary; | |
696 pStreamResList->SetAt("Font", pStreamResFontList); | |
697 } | |
698 if (!pStreamResFontList->KeyExist(sFontName)) { | |
699 pStreamResFontList->SetAtReference(sFontName, pDoc, pFontDict); | |
700 } | |
701 } else { | |
702 pStreamDict->SetAt("Resources", pFormDict->GetDictBy("DR")->Clone()); | |
703 pStreamResList = pStreamDict->GetDictBy("Resources"); | |
704 } | |
705 } | |
706 } | |
707 return TRUE; | |
708 } | |
709 FX_BOOL CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc, | |
710 CPDF_Dictionary* pAnnotDict) { | |
711 return GenerateWidgetAP(pDoc, pAnnotDict, 0); | |
712 } | |
713 FX_BOOL CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc, | |
714 CPDF_Dictionary* pAnnotDict) { | |
715 return GenerateWidgetAP(pDoc, pAnnotDict, 1); | |
716 } | |
717 FX_BOOL CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc, | |
718 CPDF_Dictionary* pAnnotDict) { | |
719 return GenerateWidgetAP(pDoc, pAnnotDict, 2); | |
720 } | |
721 CFX_ByteString CPVT_GenerateAP::GenerateEditAP( | |
722 IPVT_FontMap* pFontMap, | |
723 IPDF_VariableText_Iterator* pIterator, | |
724 const CFX_FloatPoint& ptOffset, | |
725 FX_BOOL bContinuous, | |
726 uint16_t SubWord, | |
727 const CPVT_WordRange* pVisible) { | |
728 CFX_ByteTextBuf sEditStream, sLineStream, sWords; | |
729 CFX_FloatPoint ptOld(0.0f, 0.0f), ptNew(0.0f, 0.0f); | |
730 int32_t nCurFontIndex = -1; | |
731 if (pIterator) { | |
732 if (pVisible) { | |
733 pIterator->SetAt(pVisible->BeginPos); | |
734 } else { | |
735 pIterator->SetAt(0); | |
736 } | |
737 CPVT_WordPlace oldplace; | |
738 while (pIterator->NextWord()) { | |
739 CPVT_WordPlace place = pIterator->GetAt(); | |
740 if (pVisible && place.WordCmp(pVisible->EndPos) > 0) { | |
741 break; | |
742 } | |
743 if (bContinuous) { | |
744 if (place.LineCmp(oldplace) != 0) { | |
745 if (sWords.GetSize() > 0) { | |
746 sLineStream << GetWordRenderString(sWords.GetByteString()); | |
747 sEditStream << sLineStream; | |
748 sLineStream.Clear(); | |
749 sWords.Clear(); | |
750 } | |
751 CPVT_Word word; | |
752 if (pIterator->GetWord(word)) { | |
753 ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x, | |
754 word.ptWord.y + ptOffset.y); | |
755 } else { | |
756 CPVT_Line line; | |
757 pIterator->GetLine(line); | |
758 ptNew = CFX_FloatPoint(line.ptLine.x + ptOffset.x, | |
759 line.ptLine.y + ptOffset.y); | |
760 } | |
761 if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) { | |
762 sLineStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y | |
763 << " Td\n"; | |
764 ptOld = ptNew; | |
765 } | |
766 } | |
767 CPVT_Word word; | |
768 if (pIterator->GetWord(word)) { | |
769 if (word.nFontIndex != nCurFontIndex) { | |
770 if (sWords.GetSize() > 0) { | |
771 sLineStream << GetWordRenderString(sWords.GetByteString()); | |
772 sWords.Clear(); | |
773 } | |
774 sLineStream << GetFontSetString(pFontMap, word.nFontIndex, | |
775 word.fFontSize); | |
776 nCurFontIndex = word.nFontIndex; | |
777 } | |
778 sWords << GetPDFWordString(pFontMap, nCurFontIndex, word.Word, | |
779 SubWord); | |
780 } | |
781 oldplace = place; | |
782 } else { | |
783 CPVT_Word word; | |
784 if (pIterator->GetWord(word)) { | |
785 ptNew = CFX_FloatPoint(word.ptWord.x + ptOffset.x, | |
786 word.ptWord.y + ptOffset.y); | |
787 if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) { | |
788 sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y | |
789 << " Td\n"; | |
790 ptOld = ptNew; | |
791 } | |
792 if (word.nFontIndex != nCurFontIndex) { | |
793 sEditStream << GetFontSetString(pFontMap, word.nFontIndex, | |
794 word.fFontSize); | |
795 nCurFontIndex = word.nFontIndex; | |
796 } | |
797 sEditStream << GetWordRenderString( | |
798 GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord)); | |
799 } | |
800 } | |
801 } | |
802 if (sWords.GetSize() > 0) { | |
803 sLineStream << GetWordRenderString(sWords.GetByteString()); | |
804 sEditStream << sLineStream; | |
805 sWords.Clear(); | |
806 } | |
807 } | |
808 return sEditStream.GetByteString(); | |
809 } | |
810 CFX_ByteString CPVT_GenerateAP::GenerateBorderAP( | |
811 const CFX_FloatRect& rect, | |
812 FX_FLOAT fWidth, | |
813 const CPVT_Color& color, | |
814 const CPVT_Color& crLeftTop, | |
815 const CPVT_Color& crRightBottom, | |
816 int32_t nStyle, | |
817 const CPVT_Dash& dash) { | |
818 CFX_ByteTextBuf sAppStream; | |
819 CFX_ByteString sColor; | |
820 FX_FLOAT fLeft = rect.left; | |
821 FX_FLOAT fRight = rect.right; | |
822 FX_FLOAT fTop = rect.top; | |
823 FX_FLOAT fBottom = rect.bottom; | |
824 if (fWidth > 0.0f) { | |
825 FX_FLOAT fHalfWidth = fWidth / 2.0f; | |
826 switch (nStyle) { | |
827 default: | |
828 case PBS_SOLID: | |
829 sColor = GenerateColorAP(color, TRUE); | |
830 if (sColor.GetLength() > 0) { | |
831 sAppStream << sColor; | |
832 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " | |
833 << fTop - fBottom << " re\n"; | |
834 sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " " | |
835 << fRight - fLeft - fWidth * 2 << " " | |
836 << fTop - fBottom - fWidth * 2 << " re\n"; | |
837 sAppStream << "f*\n"; | |
838 } | |
839 break; | |
840 case PBS_DASH: | |
841 sColor = GenerateColorAP(color, FALSE); | |
842 if (sColor.GetLength() > 0) { | |
843 sAppStream << sColor; | |
844 sAppStream << fWidth << " w" | |
845 << " [" << dash.nDash << " " << dash.nGap << "] " | |
846 << dash.nPhase << " d\n"; | |
847 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 | |
848 << " m\n"; | |
849 sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2 | |
850 << " l\n"; | |
851 sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2 | |
852 << " l\n"; | |
853 sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2 | |
854 << " l\n"; | |
855 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 | |
856 << " l S\n"; | |
857 } | |
858 break; | |
859 case PBS_BEVELED: | |
860 case PBS_INSET: | |
861 sColor = GenerateColorAP(crLeftTop, TRUE); | |
862 if (sColor.GetLength() > 0) { | |
863 sAppStream << sColor; | |
864 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth | |
865 << " m\n"; | |
866 sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth | |
867 << " l\n"; | |
868 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth | |
869 << " l\n"; | |
870 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 | |
871 << " l\n"; | |
872 sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 | |
873 << " l\n"; | |
874 sAppStream << fLeft + fHalfWidth * 2 << " " | |
875 << fBottom + fHalfWidth * 2 << " l f\n"; | |
876 } | |
877 sColor = GenerateColorAP(crRightBottom, TRUE); | |
878 if (sColor.GetLength() > 0) { | |
879 sAppStream << sColor; | |
880 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth | |
881 << " m\n"; | |
882 sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth | |
883 << " l\n"; | |
884 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth | |
885 << " l\n"; | |
886 sAppStream << fLeft + fHalfWidth * 2 << " " | |
887 << fBottom + fHalfWidth * 2 << " l\n"; | |
888 sAppStream << fRight - fHalfWidth * 2 << " " | |
889 << fBottom + fHalfWidth * 2 << " l\n"; | |
890 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 | |
891 << " l f\n"; | |
892 } | |
893 sColor = GenerateColorAP(color, TRUE); | |
894 if (sColor.GetLength() > 0) { | |
895 sAppStream << sColor; | |
896 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " | |
897 << fTop - fBottom << " re\n"; | |
898 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " " | |
899 << fRight - fLeft - fHalfWidth * 2 << " " | |
900 << fTop - fBottom - fHalfWidth * 2 << " re f*\n"; | |
901 } | |
902 break; | |
903 case PBS_UNDERLINED: | |
904 sColor = GenerateColorAP(color, FALSE); | |
905 if (sColor.GetLength() > 0) { | |
906 sAppStream << sColor; | |
907 sAppStream << fWidth << " w\n"; | |
908 sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n"; | |
909 sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n"; | |
910 } | |
911 break; | |
912 } | |
913 } | |
914 return sAppStream.GetByteString(); | |
915 } | |
916 CFX_ByteString CPVT_GenerateAP::GenerateColorAP(const CPVT_Color& color, | |
917 const FX_BOOL& bFillOrStroke) { | |
918 CFX_ByteTextBuf sColorStream; | |
919 switch (color.nColorType) { | |
920 case CPVT_Color::kRGB: | |
921 sColorStream << color.fColor1 << " " << color.fColor2 << " " | |
922 << color.fColor3 << " " << (bFillOrStroke ? "rg" : "RG") | |
923 << "\n"; | |
924 break; | |
925 case CPVT_Color::kGray: | |
926 sColorStream << color.fColor1 << " " << (bFillOrStroke ? "g" : "G") | |
927 << "\n"; | |
928 break; | |
929 case CPVT_Color::kCMYK: | |
930 sColorStream << color.fColor1 << " " << color.fColor2 << " " | |
931 << color.fColor3 << " " << color.fColor4 << " " | |
932 << (bFillOrStroke ? "k" : "K") << "\n"; | |
933 break; | |
934 case CPVT_Color::kTransparent: | |
935 break; | |
936 } | |
937 return sColorStream.GetByteString(); | |
938 } | |
OLD | NEW |