OLD | NEW |
| (Empty) |
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 "core/fpdfdoc/include/cpdf_formfield.h" | |
8 | |
9 #include "core/fpdfapi/fpdf_parser/include/cfdf_document.h" | |
10 #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" | |
11 #include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" | |
12 #include "core/fpdfapi/fpdf_parser/include/cpdf_number.h" | |
13 #include "core/fpdfapi/fpdf_parser/include/cpdf_simple_parser.h" | |
14 #include "core/fpdfapi/fpdf_parser/include/cpdf_string.h" | |
15 #include "core/fpdfapi/fpdf_parser/include/fpdf_parser_decode.h" | |
16 #include "core/fpdfdoc/cpvt_generateap.h" | |
17 #include "core/fpdfdoc/doc_utils.h" | |
18 #include "core/fpdfdoc/include/cpdf_formcontrol.h" | |
19 #include "core/fpdfdoc/include/cpdf_interform.h" | |
20 | |
21 namespace { | |
22 | |
23 const int kFormListMultiSelect = 0x100; | |
24 | |
25 const int kFormComboEdit = 0x100; | |
26 | |
27 const int kFormFieldReadOnly = 0x01; | |
28 const int kFormFieldRequired = 0x02; | |
29 const int kFormFieldNoExport = 0x04; | |
30 | |
31 const int kFormRadioNoToggleOff = 0x100; | |
32 const int kFormRadioUnison = 0x200; | |
33 | |
34 const int kFormTextMultiLine = 0x100; | |
35 const int kFormTextPassword = 0x200; | |
36 const int kFormTextNoScroll = 0x400; | |
37 const int kFormTextComb = 0x800; | |
38 | |
39 bool PDF_FormField_IsUnison(CPDF_FormField* pField) { | |
40 if (pField->GetType() == CPDF_FormField::CheckBox) | |
41 return true; | |
42 | |
43 return (pField->GetFieldFlags() & 0x2000000) != 0; | |
44 } | |
45 | |
46 } // namespace | |
47 | |
48 CPDF_FormField::CPDF_FormField(CPDF_InterForm* pForm, CPDF_Dictionary* pDict) | |
49 : m_Type(Unknown), | |
50 m_pForm(pForm), | |
51 m_pDict(pDict), | |
52 m_FontSize(0), | |
53 m_pFont(nullptr) { | |
54 SyncFieldFlags(); | |
55 } | |
56 | |
57 CPDF_FormField::~CPDF_FormField() {} | |
58 | |
59 void CPDF_FormField::SyncFieldFlags() { | |
60 CFX_ByteString type_name = FPDF_GetFieldAttr(m_pDict, "FT") | |
61 ? FPDF_GetFieldAttr(m_pDict, "FT")->GetString() | |
62 : CFX_ByteString(); | |
63 uint32_t flags = FPDF_GetFieldAttr(m_pDict, "Ff") | |
64 ? FPDF_GetFieldAttr(m_pDict, "Ff")->GetInteger() | |
65 : 0; | |
66 m_Flags = 0; | |
67 if (flags & 1) { | |
68 m_Flags |= kFormFieldReadOnly; | |
69 } | |
70 if (flags & 2) { | |
71 m_Flags |= kFormFieldRequired; | |
72 } | |
73 if (flags & 4) { | |
74 m_Flags |= kFormFieldNoExport; | |
75 } | |
76 if (type_name == "Btn") { | |
77 if (flags & 0x8000) { | |
78 m_Type = RadioButton; | |
79 if (flags & 0x4000) { | |
80 m_Flags |= kFormRadioNoToggleOff; | |
81 } | |
82 if (flags & 0x2000000) { | |
83 m_Flags |= kFormRadioUnison; | |
84 } | |
85 } else if (flags & 0x10000) { | |
86 m_Type = PushButton; | |
87 } else { | |
88 m_Type = CheckBox; | |
89 } | |
90 } else if (type_name == "Tx") { | |
91 if (flags & 0x100000) { | |
92 m_Type = File; | |
93 } else if (flags & 0x2000000) { | |
94 m_Type = RichText; | |
95 } else { | |
96 m_Type = Text; | |
97 if (flags & 0x1000) { | |
98 m_Flags |= kFormTextMultiLine; | |
99 } | |
100 if (flags & 0x2000) { | |
101 m_Flags |= kFormTextPassword; | |
102 } | |
103 if (flags & 0x800000) { | |
104 m_Flags |= kFormTextNoScroll; | |
105 } | |
106 if (flags & 0x100000) { | |
107 m_Flags |= kFormTextComb; | |
108 } | |
109 } | |
110 LoadDA(); | |
111 } else if (type_name == "Ch") { | |
112 if (flags & 0x20000) { | |
113 m_Type = ComboBox; | |
114 if (flags & 0x40000) { | |
115 m_Flags |= kFormComboEdit; | |
116 } | |
117 } else { | |
118 m_Type = ListBox; | |
119 if (flags & 0x200000) { | |
120 m_Flags |= kFormListMultiSelect; | |
121 } | |
122 } | |
123 LoadDA(); | |
124 } else if (type_name == "Sig") { | |
125 m_Type = Sign; | |
126 } | |
127 } | |
128 CFX_WideString CPDF_FormField::GetFullName() const { | |
129 return ::GetFullName(m_pDict); | |
130 } | |
131 | |
132 FX_BOOL CPDF_FormField::ResetField(FX_BOOL bNotify) { | |
133 switch (m_Type) { | |
134 case CPDF_FormField::CheckBox: | |
135 case CPDF_FormField::RadioButton: { | |
136 int iCount = CountControls(); | |
137 if (iCount) { | |
138 // TODO(weili): Check whether anything special needs to be done for | |
139 // unison field. Otherwise, merge these branches. | |
140 if (PDF_FormField_IsUnison(this)) { | |
141 for (int i = 0; i < iCount; i++) { | |
142 CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE); | |
143 } | |
144 } else { | |
145 for (int i = 0; i < iCount; i++) { | |
146 CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE); | |
147 } | |
148 } | |
149 } | |
150 if (bNotify && m_pForm->m_pFormNotify) { | |
151 m_pForm->m_pFormNotify->AfterCheckedStatusChange(this); | |
152 } | |
153 } break; | |
154 case CPDF_FormField::ComboBox: | |
155 case CPDF_FormField::ListBox: { | |
156 CFX_WideString csValue; | |
157 ClearSelection(); | |
158 int iIndex = GetDefaultSelectedItem(); | |
159 if (iIndex >= 0) | |
160 csValue = GetOptionLabel(iIndex); | |
161 | |
162 if (bNotify && !NotifyListOrComboBoxBeforeChange(csValue)) | |
163 return FALSE; | |
164 | |
165 SetItemSelection(iIndex, TRUE); | |
166 if (bNotify) | |
167 NotifyListOrComboBoxAfterChange(); | |
168 } break; | |
169 case CPDF_FormField::Text: | |
170 case CPDF_FormField::RichText: | |
171 case CPDF_FormField::File: | |
172 default: { | |
173 CPDF_Object* pDV = FPDF_GetFieldAttr(m_pDict, "DV"); | |
174 CFX_WideString csDValue; | |
175 if (pDV) | |
176 csDValue = pDV->GetUnicodeText(); | |
177 | |
178 CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V"); | |
179 CFX_WideString csValue; | |
180 if (pV) | |
181 csValue = pV->GetUnicodeText(); | |
182 | |
183 CPDF_Object* pRV = FPDF_GetFieldAttr(m_pDict, "RV"); | |
184 if (!pRV && (csDValue == csValue)) | |
185 return FALSE; | |
186 | |
187 if (bNotify && !NotifyBeforeValueChange(csDValue)) | |
188 return FALSE; | |
189 | |
190 if (pDV) { | |
191 CPDF_Object* pClone = pDV->Clone(); | |
192 if (!pClone) | |
193 return FALSE; | |
194 | |
195 m_pDict->SetAt("V", pClone); | |
196 if (pRV) { | |
197 CPDF_Object* pCloneR = pDV->Clone(); | |
198 m_pDict->SetAt("RV", pCloneR); | |
199 } | |
200 } else { | |
201 m_pDict->RemoveAt("V"); | |
202 m_pDict->RemoveAt("RV"); | |
203 } | |
204 if (bNotify) | |
205 NotifyAfterValueChange(); | |
206 } break; | |
207 } | |
208 return TRUE; | |
209 } | |
210 | |
211 int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl) const { | |
212 if (!pControl) | |
213 return -1; | |
214 | |
215 for (int i = 0; i < m_ControlList.GetSize(); i++) { | |
216 if (m_ControlList.GetAt(i) == pControl) | |
217 return i; | |
218 } | |
219 return -1; | |
220 } | |
221 | |
222 int CPDF_FormField::GetFieldType() const { | |
223 switch (m_Type) { | |
224 case PushButton: | |
225 return FIELDTYPE_PUSHBUTTON; | |
226 case CheckBox: | |
227 return FIELDTYPE_CHECKBOX; | |
228 case RadioButton: | |
229 return FIELDTYPE_RADIOBUTTON; | |
230 case ComboBox: | |
231 return FIELDTYPE_COMBOBOX; | |
232 case ListBox: | |
233 return FIELDTYPE_LISTBOX; | |
234 case Text: | |
235 case RichText: | |
236 case File: | |
237 return FIELDTYPE_TEXTFIELD; | |
238 case Sign: | |
239 return FIELDTYPE_SIGNATURE; | |
240 default: | |
241 break; | |
242 } | |
243 return FIELDTYPE_UNKNOWN; | |
244 } | |
245 | |
246 CPDF_AAction CPDF_FormField::GetAdditionalAction() const { | |
247 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "AA"); | |
248 return CPDF_AAction(pObj ? pObj->GetDict() : nullptr); | |
249 } | |
250 | |
251 CFX_WideString CPDF_FormField::GetAlternateName() const { | |
252 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TU"); | |
253 if (!pObj) { | |
254 return L""; | |
255 } | |
256 return pObj->GetUnicodeText(); | |
257 } | |
258 CFX_WideString CPDF_FormField::GetMappingName() const { | |
259 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TM"); | |
260 if (!pObj) { | |
261 return L""; | |
262 } | |
263 return pObj->GetUnicodeText(); | |
264 } | |
265 uint32_t CPDF_FormField::GetFieldFlags() const { | |
266 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "Ff"); | |
267 if (!pObj) { | |
268 return 0; | |
269 } | |
270 return pObj->GetInteger(); | |
271 } | |
272 CFX_ByteString CPDF_FormField::GetDefaultStyle() const { | |
273 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DS"); | |
274 if (!pObj) { | |
275 return ""; | |
276 } | |
277 return pObj->GetString(); | |
278 } | |
279 CFX_WideString CPDF_FormField::GetRichTextString() const { | |
280 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "RV"); | |
281 if (!pObj) { | |
282 return L""; | |
283 } | |
284 return pObj->GetUnicodeText(); | |
285 } | |
286 CFX_WideString CPDF_FormField::GetValue(FX_BOOL bDefault) const { | |
287 if (GetType() == CheckBox || GetType() == RadioButton) | |
288 return GetCheckValue(bDefault); | |
289 | |
290 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, bDefault ? "DV" : "V"); | |
291 if (!pValue) { | |
292 if (!bDefault) { | |
293 if (m_Type == RichText) { | |
294 pValue = FPDF_GetFieldAttr(m_pDict, "V"); | |
295 } | |
296 if (!pValue && m_Type != Text) { | |
297 pValue = FPDF_GetFieldAttr(m_pDict, "DV"); | |
298 } | |
299 } | |
300 if (!pValue) | |
301 return CFX_WideString(); | |
302 } | |
303 switch (pValue->GetType()) { | |
304 case CPDF_Object::STRING: | |
305 case CPDF_Object::STREAM: | |
306 return pValue->GetUnicodeText(); | |
307 case CPDF_Object::ARRAY: | |
308 pValue = pValue->AsArray()->GetDirectObjectAt(0); | |
309 if (pValue) | |
310 return pValue->GetUnicodeText(); | |
311 break; | |
312 default: | |
313 break; | |
314 } | |
315 return CFX_WideString(); | |
316 } | |
317 | |
318 CFX_WideString CPDF_FormField::GetValue() const { | |
319 return GetValue(FALSE); | |
320 } | |
321 | |
322 CFX_WideString CPDF_FormField::GetDefaultValue() const { | |
323 return GetValue(TRUE); | |
324 } | |
325 | |
326 FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, | |
327 FX_BOOL bDefault, | |
328 FX_BOOL bNotify) { | |
329 switch (m_Type) { | |
330 case CheckBox: | |
331 case RadioButton: { | |
332 SetCheckValue(value, bDefault, bNotify); | |
333 return TRUE; | |
334 } | |
335 case File: | |
336 case RichText: | |
337 case Text: | |
338 case ComboBox: { | |
339 CFX_WideString csValue = value; | |
340 if (bNotify && !NotifyBeforeValueChange(csValue)) | |
341 return FALSE; | |
342 | |
343 int iIndex = FindOptionValue(csValue); | |
344 if (iIndex < 0) { | |
345 CFX_ByteString bsEncodeText = PDF_EncodeText(csValue); | |
346 m_pDict->SetAtString(bDefault ? "DV" : "V", bsEncodeText); | |
347 if (m_Type == RichText && !bDefault) | |
348 m_pDict->SetAtString("RV", bsEncodeText); | |
349 m_pDict->RemoveAt("I"); | |
350 } else { | |
351 m_pDict->SetAtString(bDefault ? "DV" : "V", PDF_EncodeText(csValue)); | |
352 if (!bDefault) { | |
353 ClearSelection(); | |
354 SetItemSelection(iIndex, TRUE); | |
355 } | |
356 } | |
357 if (bNotify) | |
358 NotifyAfterValueChange(); | |
359 } break; | |
360 case ListBox: { | |
361 int iIndex = FindOptionValue(value); | |
362 if (iIndex < 0) | |
363 return FALSE; | |
364 | |
365 if (bDefault && iIndex == GetDefaultSelectedItem()) | |
366 return FALSE; | |
367 | |
368 if (bNotify && !NotifyBeforeSelectionChange(value)) | |
369 return FALSE; | |
370 | |
371 if (!bDefault) { | |
372 ClearSelection(); | |
373 SetItemSelection(iIndex, TRUE); | |
374 } | |
375 if (bNotify) | |
376 NotifyAfterSelectionChange(); | |
377 break; | |
378 } | |
379 default: | |
380 break; | |
381 } | |
382 return TRUE; | |
383 } | |
384 | |
385 FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bNotify) { | |
386 return SetValue(value, FALSE, bNotify); | |
387 } | |
388 | |
389 int CPDF_FormField::GetMaxLen() const { | |
390 if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "MaxLen")) | |
391 return pObj->GetInteger(); | |
392 | |
393 for (int i = 0; i < m_ControlList.GetSize(); i++) { | |
394 CPDF_FormControl* pControl = m_ControlList.GetAt(i); | |
395 if (!pControl) | |
396 continue; | |
397 | |
398 CPDF_Dictionary* pWidgetDict = pControl->m_pWidgetDict; | |
399 if (pWidgetDict->KeyExist("MaxLen")) | |
400 return pWidgetDict->GetIntegerBy("MaxLen"); | |
401 } | |
402 return 0; | |
403 } | |
404 | |
405 int CPDF_FormField::CountSelectedItems() const { | |
406 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); | |
407 if (!pValue) { | |
408 pValue = FPDF_GetFieldAttr(m_pDict, "I"); | |
409 if (!pValue) | |
410 return 0; | |
411 } | |
412 | |
413 if (pValue->IsString() || pValue->IsNumber()) | |
414 return pValue->GetString().IsEmpty() ? 0 : 1; | |
415 if (CPDF_Array* pArray = pValue->AsArray()) | |
416 return pArray->GetCount(); | |
417 return 0; | |
418 } | |
419 | |
420 int CPDF_FormField::GetSelectedIndex(int index) const { | |
421 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); | |
422 if (!pValue) { | |
423 pValue = FPDF_GetFieldAttr(m_pDict, "I"); | |
424 if (!pValue) | |
425 return -1; | |
426 } | |
427 if (pValue->IsNumber()) | |
428 return pValue->GetInteger(); | |
429 | |
430 CFX_WideString sel_value; | |
431 if (pValue->IsString()) { | |
432 if (index != 0) | |
433 return -1; | |
434 sel_value = pValue->GetUnicodeText(); | |
435 } else { | |
436 CPDF_Array* pArray = pValue->AsArray(); | |
437 if (!pArray || index < 0) | |
438 return -1; | |
439 | |
440 CPDF_Object* elementValue = pArray->GetDirectObjectAt(index); | |
441 sel_value = | |
442 elementValue ? elementValue->GetUnicodeText() : CFX_WideString(); | |
443 } | |
444 if (index < CountSelectedOptions()) { | |
445 int iOptIndex = GetSelectedOptionIndex(index); | |
446 CFX_WideString csOpt = GetOptionValue(iOptIndex); | |
447 if (csOpt == sel_value) { | |
448 return iOptIndex; | |
449 } | |
450 } | |
451 for (int i = 0; i < CountOptions(); i++) { | |
452 if (sel_value == GetOptionValue(i)) | |
453 return i; | |
454 } | |
455 return -1; | |
456 } | |
457 | |
458 FX_BOOL CPDF_FormField::ClearSelection(FX_BOOL bNotify) { | |
459 if (bNotify && m_pForm->m_pFormNotify) { | |
460 CFX_WideString csValue; | |
461 int iIndex = GetSelectedIndex(0); | |
462 if (iIndex >= 0) | |
463 csValue = GetOptionLabel(iIndex); | |
464 | |
465 if (!NotifyListOrComboBoxBeforeChange(csValue)) | |
466 return FALSE; | |
467 } | |
468 m_pDict->RemoveAt("V"); | |
469 m_pDict->RemoveAt("I"); | |
470 if (bNotify) | |
471 NotifyListOrComboBoxAfterChange(); | |
472 return TRUE; | |
473 } | |
474 | |
475 FX_BOOL CPDF_FormField::IsItemSelected(int index) const { | |
476 ASSERT(GetType() == ComboBox || GetType() == ListBox); | |
477 if (index < 0 || index >= CountOptions()) { | |
478 return FALSE; | |
479 } | |
480 if (IsOptionSelected(index)) { | |
481 return TRUE; | |
482 } | |
483 CFX_WideString opt_value = GetOptionValue(index); | |
484 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); | |
485 if (!pValue) { | |
486 pValue = FPDF_GetFieldAttr(m_pDict, "I"); | |
487 if (!pValue) { | |
488 return FALSE; | |
489 } | |
490 } | |
491 | |
492 if (pValue->IsString()) | |
493 return pValue->GetUnicodeText() == opt_value; | |
494 | |
495 if (pValue->IsNumber()) { | |
496 if (pValue->GetString().IsEmpty()) | |
497 return FALSE; | |
498 return (pValue->GetInteger() == index); | |
499 } | |
500 | |
501 CPDF_Array* pArray = pValue->AsArray(); | |
502 if (!pArray) | |
503 return FALSE; | |
504 | |
505 int iPos = -1; | |
506 for (int j = 0; j < CountSelectedOptions(); j++) { | |
507 if (GetSelectedOptionIndex(j) == index) { | |
508 iPos = j; | |
509 break; | |
510 } | |
511 } | |
512 for (int i = 0; i < static_cast<int>(pArray->GetCount()); i++) | |
513 if (pArray->GetDirectObjectAt(i)->GetUnicodeText() == opt_value && | |
514 i == iPos) { | |
515 return TRUE; | |
516 } | |
517 return FALSE; | |
518 } | |
519 | |
520 FX_BOOL CPDF_FormField::SetItemSelection(int index, | |
521 FX_BOOL bSelected, | |
522 FX_BOOL bNotify) { | |
523 ASSERT(GetType() == ComboBox || GetType() == ListBox); | |
524 if (index < 0 || index >= CountOptions()) | |
525 return FALSE; | |
526 | |
527 CFX_WideString opt_value = GetOptionValue(index); | |
528 if (bNotify && !NotifyListOrComboBoxBeforeChange(opt_value)) | |
529 return FALSE; | |
530 | |
531 if (bSelected) { | |
532 if (GetType() == ListBox) { | |
533 SelectOption(index, TRUE); | |
534 if (!(m_Flags & kFormListMultiSelect)) { | |
535 m_pDict->SetAtString("V", PDF_EncodeText(opt_value)); | |
536 } else { | |
537 CPDF_Array* pArray = new CPDF_Array; | |
538 for (int i = 0; i < CountOptions(); i++) { | |
539 if (i == index || IsItemSelected(i)) { | |
540 opt_value = GetOptionValue(i); | |
541 pArray->AddString(PDF_EncodeText(opt_value)); | |
542 } | |
543 } | |
544 m_pDict->SetAt("V", pArray); | |
545 } | |
546 } else { | |
547 m_pDict->SetAtString("V", PDF_EncodeText(opt_value)); | |
548 CPDF_Array* pI = new CPDF_Array; | |
549 pI->AddInteger(index); | |
550 m_pDict->SetAt("I", pI); | |
551 } | |
552 } else { | |
553 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); | |
554 if (pValue) { | |
555 if (GetType() == ListBox) { | |
556 SelectOption(index, FALSE); | |
557 if (pValue->IsString()) { | |
558 if (pValue->GetUnicodeText() == opt_value) | |
559 m_pDict->RemoveAt("V"); | |
560 } else if (pValue->IsArray()) { | |
561 CPDF_Array* pArray = new CPDF_Array; | |
562 for (int i = 0; i < CountOptions(); i++) { | |
563 if (i != index && IsItemSelected(i)) { | |
564 opt_value = GetOptionValue(i); | |
565 pArray->AddString(PDF_EncodeText(opt_value)); | |
566 } | |
567 } | |
568 if (pArray->GetCount() < 1) | |
569 pArray->Release(); | |
570 else | |
571 m_pDict->SetAt("V", pArray); | |
572 } | |
573 } else { | |
574 m_pDict->RemoveAt("V"); | |
575 m_pDict->RemoveAt("I"); | |
576 } | |
577 } | |
578 } | |
579 if (bNotify) | |
580 NotifyListOrComboBoxAfterChange(); | |
581 return TRUE; | |
582 } | |
583 | |
584 FX_BOOL CPDF_FormField::IsItemDefaultSelected(int index) const { | |
585 ASSERT(GetType() == ComboBox || GetType() == ListBox); | |
586 if (index < 0 || index >= CountOptions()) | |
587 return FALSE; | |
588 int iDVIndex = GetDefaultSelectedItem(); | |
589 return iDVIndex >= 0 && iDVIndex == index; | |
590 } | |
591 | |
592 int CPDF_FormField::GetDefaultSelectedItem() const { | |
593 ASSERT(GetType() == ComboBox || GetType() == ListBox); | |
594 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "DV"); | |
595 if (!pValue) | |
596 return -1; | |
597 CFX_WideString csDV = pValue->GetUnicodeText(); | |
598 if (csDV.IsEmpty()) | |
599 return -1; | |
600 for (int i = 0; i < CountOptions(); i++) { | |
601 if (csDV == GetOptionValue(i)) | |
602 return i; | |
603 } | |
604 return -1; | |
605 } | |
606 | |
607 int CPDF_FormField::CountOptions() const { | |
608 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt")); | |
609 return pArray ? pArray->GetCount() : 0; | |
610 } | |
611 | |
612 CFX_WideString CPDF_FormField::GetOptionText(int index, int sub_index) const { | |
613 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt")); | |
614 if (!pArray) | |
615 return CFX_WideString(); | |
616 | |
617 CPDF_Object* pOption = pArray->GetDirectObjectAt(index); | |
618 if (!pOption) | |
619 return CFX_WideString(); | |
620 if (CPDF_Array* pOptionArray = pOption->AsArray()) | |
621 pOption = pOptionArray->GetDirectObjectAt(sub_index); | |
622 | |
623 CPDF_String* pString = ToString(pOption); | |
624 return pString ? pString->GetUnicodeText() : CFX_WideString(); | |
625 } | |
626 CFX_WideString CPDF_FormField::GetOptionLabel(int index) const { | |
627 return GetOptionText(index, 1); | |
628 } | |
629 CFX_WideString CPDF_FormField::GetOptionValue(int index) const { | |
630 return GetOptionText(index, 0); | |
631 } | |
632 | |
633 int CPDF_FormField::FindOption(CFX_WideString csOptLabel) const { | |
634 for (int i = 0; i < CountOptions(); i++) { | |
635 if (GetOptionValue(i) == csOptLabel) | |
636 return i; | |
637 } | |
638 return -1; | |
639 } | |
640 | |
641 int CPDF_FormField::FindOptionValue(const CFX_WideString& csOptValue) const { | |
642 for (int i = 0; i < CountOptions(); i++) { | |
643 if (GetOptionValue(i) == csOptValue) | |
644 return i; | |
645 } | |
646 return -1; | |
647 } | |
648 | |
649 #ifdef PDF_ENABLE_XFA | |
650 int CPDF_FormField::InsertOption(CFX_WideString csOptLabel, | |
651 int index, | |
652 FX_BOOL bNotify) { | |
653 if (csOptLabel.IsEmpty()) | |
654 return -1; | |
655 | |
656 if (bNotify && !NotifyListOrComboBoxBeforeChange(csOptLabel)) | |
657 return -1; | |
658 | |
659 CFX_ByteString csStr = | |
660 PDF_EncodeText(csOptLabel.c_str(), csOptLabel.GetLength()); | |
661 CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt"); | |
662 CPDF_Array* pOpt = ToArray(pValue); | |
663 if (!pOpt) { | |
664 pOpt = new CPDF_Array; | |
665 m_pDict->SetAt("Opt", pOpt); | |
666 } | |
667 | |
668 int iCount = (int)pOpt->GetCount(); | |
669 if (index < 0 || index >= iCount) { | |
670 pOpt->AddString(csStr); | |
671 index = iCount; | |
672 } else { | |
673 CPDF_String* pString = new CPDF_String(csStr, FALSE); | |
674 pOpt->InsertAt(index, pString); | |
675 } | |
676 | |
677 if (bNotify) | |
678 NotifyListOrComboBoxAfterChange(); | |
679 return index; | |
680 } | |
681 | |
682 FX_BOOL CPDF_FormField::ClearOptions(FX_BOOL bNotify) { | |
683 if (bNotify && m_pForm->m_pFormNotify) { | |
684 CFX_WideString csValue; | |
685 int iIndex = GetSelectedIndex(0); | |
686 if (iIndex >= 0) | |
687 csValue = GetOptionLabel(iIndex); | |
688 if (!NotifyListOrComboBoxBeforeChange(csValue)) | |
689 return FALSE; | |
690 } | |
691 | |
692 m_pDict->RemoveAt("Opt"); | |
693 m_pDict->RemoveAt("V"); | |
694 m_pDict->RemoveAt("DV"); | |
695 m_pDict->RemoveAt("I"); | |
696 m_pDict->RemoveAt("TI"); | |
697 | |
698 if (bNotify) | |
699 NotifyListOrComboBoxAfterChange(); | |
700 | |
701 return TRUE; | |
702 } | |
703 #endif // PDF_ENABLE_XFA | |
704 | |
705 FX_BOOL CPDF_FormField::CheckControl(int iControlIndex, | |
706 bool bChecked, | |
707 bool bNotify) { | |
708 ASSERT(GetType() == CheckBox || GetType() == RadioButton); | |
709 CPDF_FormControl* pControl = GetControl(iControlIndex); | |
710 if (!pControl) { | |
711 return FALSE; | |
712 } | |
713 if (!bChecked && pControl->IsChecked() == bChecked) { | |
714 return FALSE; | |
715 } | |
716 CFX_WideString csWExport = pControl->GetExportValue(); | |
717 CFX_ByteString csBExport = PDF_EncodeText(csWExport); | |
718 int iCount = CountControls(); | |
719 bool bUnison = PDF_FormField_IsUnison(this); | |
720 for (int i = 0; i < iCount; i++) { | |
721 CPDF_FormControl* pCtrl = GetControl(i); | |
722 if (bUnison) { | |
723 CFX_WideString csEValue = pCtrl->GetExportValue(); | |
724 if (csEValue == csWExport) { | |
725 if (pCtrl->GetOnStateName() == pControl->GetOnStateName()) { | |
726 pCtrl->CheckControl(bChecked); | |
727 } else if (bChecked) { | |
728 pCtrl->CheckControl(FALSE); | |
729 } | |
730 } else if (bChecked) { | |
731 pCtrl->CheckControl(FALSE); | |
732 } | |
733 } else { | |
734 if (i == iControlIndex) { | |
735 pCtrl->CheckControl(bChecked); | |
736 } else if (bChecked) { | |
737 pCtrl->CheckControl(FALSE); | |
738 } | |
739 } | |
740 } | |
741 CPDF_Object* pOpt = FPDF_GetFieldAttr(m_pDict, "Opt"); | |
742 if (!ToArray(pOpt)) { | |
743 if (bChecked) { | |
744 m_pDict->SetAtName("V", csBExport); | |
745 } else { | |
746 CFX_ByteString csV; | |
747 CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V"); | |
748 if (pV) { | |
749 csV = pV->GetString(); | |
750 } | |
751 if (csV == csBExport) { | |
752 m_pDict->SetAtName("V", "Off"); | |
753 } | |
754 } | |
755 } else if (bChecked) { | |
756 CFX_ByteString csIndex; | |
757 csIndex.Format("%d", iControlIndex); | |
758 m_pDict->SetAtName("V", csIndex); | |
759 } | |
760 if (bNotify && m_pForm->m_pFormNotify) | |
761 m_pForm->m_pFormNotify->AfterCheckedStatusChange(this); | |
762 return TRUE; | |
763 } | |
764 | |
765 CFX_WideString CPDF_FormField::GetCheckValue(FX_BOOL bDefault) const { | |
766 ASSERT(GetType() == CheckBox || GetType() == RadioButton); | |
767 CFX_WideString csExport = L"Off"; | |
768 int iCount = CountControls(); | |
769 for (int i = 0; i < iCount; i++) { | |
770 CPDF_FormControl* pControl = GetControl(i); | |
771 FX_BOOL bChecked = | |
772 bDefault ? pControl->IsDefaultChecked() : pControl->IsChecked(); | |
773 if (bChecked) { | |
774 csExport = pControl->GetExportValue(); | |
775 break; | |
776 } | |
777 } | |
778 return csExport; | |
779 } | |
780 | |
781 FX_BOOL CPDF_FormField::SetCheckValue(const CFX_WideString& value, | |
782 FX_BOOL bDefault, | |
783 FX_BOOL bNotify) { | |
784 ASSERT(GetType() == CheckBox || GetType() == RadioButton); | |
785 int iCount = CountControls(); | |
786 for (int i = 0; i < iCount; i++) { | |
787 CPDF_FormControl* pControl = GetControl(i); | |
788 CFX_WideString csExport = pControl->GetExportValue(); | |
789 bool val = csExport == value; | |
790 if (!bDefault) | |
791 CheckControl(GetControlIndex(pControl), val); | |
792 if (val) | |
793 break; | |
794 } | |
795 if (bNotify && m_pForm->m_pFormNotify) | |
796 m_pForm->m_pFormNotify->AfterCheckedStatusChange(this); | |
797 return TRUE; | |
798 } | |
799 | |
800 int CPDF_FormField::GetTopVisibleIndex() const { | |
801 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TI"); | |
802 return pObj ? pObj->GetInteger() : 0; | |
803 } | |
804 | |
805 int CPDF_FormField::CountSelectedOptions() const { | |
806 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I")); | |
807 return pArray ? pArray->GetCount() : 0; | |
808 } | |
809 | |
810 int CPDF_FormField::GetSelectedOptionIndex(int index) const { | |
811 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I")); | |
812 if (!pArray) | |
813 return -1; | |
814 | |
815 int iCount = pArray->GetCount(); | |
816 if (iCount < 0 || index >= iCount) | |
817 return -1; | |
818 return pArray->GetIntegerAt(index); | |
819 } | |
820 | |
821 FX_BOOL CPDF_FormField::IsOptionSelected(int iOptIndex) const { | |
822 CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I")); | |
823 if (!pArray) | |
824 return FALSE; | |
825 | |
826 for (CPDF_Object* pObj : *pArray) { | |
827 if (pObj->GetInteger() == iOptIndex) | |
828 return TRUE; | |
829 } | |
830 return FALSE; | |
831 } | |
832 | |
833 FX_BOOL CPDF_FormField::SelectOption(int iOptIndex, | |
834 FX_BOOL bSelected, | |
835 FX_BOOL bNotify) { | |
836 CPDF_Array* pArray = m_pDict->GetArrayBy("I"); | |
837 if (!pArray) { | |
838 if (!bSelected) | |
839 return TRUE; | |
840 | |
841 pArray = new CPDF_Array; | |
842 m_pDict->SetAt("I", pArray); | |
843 } | |
844 | |
845 FX_BOOL bReturn = FALSE; | |
846 for (size_t i = 0; i < pArray->GetCount(); i++) { | |
847 int iFind = pArray->GetIntegerAt(i); | |
848 if (iFind == iOptIndex) { | |
849 if (bSelected) | |
850 return TRUE; | |
851 | |
852 if (bNotify && m_pForm->m_pFormNotify) { | |
853 CFX_WideString csValue = GetOptionLabel(iOptIndex); | |
854 if (!NotifyListOrComboBoxBeforeChange(csValue)) | |
855 return FALSE; | |
856 } | |
857 pArray->RemoveAt(i); | |
858 bReturn = TRUE; | |
859 break; | |
860 } | |
861 | |
862 if (iFind > iOptIndex) { | |
863 if (!bSelected) | |
864 continue; | |
865 | |
866 if (bNotify && m_pForm->m_pFormNotify) { | |
867 CFX_WideString csValue = GetOptionLabel(iOptIndex); | |
868 if (!NotifyListOrComboBoxBeforeChange(csValue)) | |
869 return FALSE; | |
870 } | |
871 pArray->InsertAt(i, new CPDF_Number(iOptIndex)); | |
872 bReturn = TRUE; | |
873 break; | |
874 } | |
875 } | |
876 if (!bReturn) { | |
877 if (bSelected) | |
878 pArray->AddInteger(iOptIndex); | |
879 | |
880 if (pArray->GetCount() == 0) | |
881 m_pDict->RemoveAt("I"); | |
882 } | |
883 if (bNotify) | |
884 NotifyListOrComboBoxAfterChange(); | |
885 | |
886 return TRUE; | |
887 } | |
888 | |
889 FX_BOOL CPDF_FormField::ClearSelectedOptions(FX_BOOL bNotify) { | |
890 if (bNotify && m_pForm->m_pFormNotify) { | |
891 CFX_WideString csValue; | |
892 int iIndex = GetSelectedIndex(0); | |
893 if (iIndex >= 0) | |
894 csValue = GetOptionLabel(iIndex); | |
895 | |
896 if (!NotifyListOrComboBoxBeforeChange(csValue)) | |
897 return FALSE; | |
898 } | |
899 m_pDict->RemoveAt("I"); | |
900 if (bNotify) | |
901 NotifyListOrComboBoxAfterChange(); | |
902 | |
903 return TRUE; | |
904 } | |
905 | |
906 void CPDF_FormField::LoadDA() { | |
907 CPDF_Dictionary* pFormDict = m_pForm->m_pFormDict; | |
908 if (!pFormDict) | |
909 return; | |
910 | |
911 CFX_ByteString DA; | |
912 if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DA")) | |
913 DA = pObj->GetString(); | |
914 | |
915 if (DA.IsEmpty()) | |
916 DA = pFormDict->GetStringBy("DA"); | |
917 | |
918 if (DA.IsEmpty()) | |
919 return; | |
920 | |
921 CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); | |
922 if (!pDR) | |
923 return; | |
924 | |
925 CPDF_Dictionary* pFont = pDR->GetDictBy("Font"); | |
926 if (!pFont) | |
927 return; | |
928 | |
929 CPDF_SimpleParser syntax(DA.AsStringC()); | |
930 syntax.FindTagParamFromStart("Tf", 2); | |
931 CFX_ByteString font_name(syntax.GetWord()); | |
932 CPDF_Dictionary* pFontDict = pFont->GetDictBy(font_name); | |
933 if (!pFontDict) | |
934 return; | |
935 | |
936 m_pFont = m_pForm->m_pDocument->LoadFont(pFontDict); | |
937 m_FontSize = FX_atof(syntax.GetWord()); | |
938 } | |
939 | |
940 bool CPDF_FormField::NotifyBeforeSelectionChange(const CFX_WideString& value) { | |
941 if (!m_pForm->m_pFormNotify) | |
942 return true; | |
943 return m_pForm->m_pFormNotify->BeforeSelectionChange(this, value) >= 0; | |
944 } | |
945 | |
946 void CPDF_FormField::NotifyAfterSelectionChange() { | |
947 if (!m_pForm->m_pFormNotify) | |
948 return; | |
949 m_pForm->m_pFormNotify->AfterSelectionChange(this); | |
950 } | |
951 | |
952 bool CPDF_FormField::NotifyBeforeValueChange(const CFX_WideString& value) { | |
953 if (!m_pForm->m_pFormNotify) | |
954 return true; | |
955 return m_pForm->m_pFormNotify->BeforeValueChange(this, value) >= 0; | |
956 } | |
957 | |
958 void CPDF_FormField::NotifyAfterValueChange() { | |
959 if (!m_pForm->m_pFormNotify) | |
960 return; | |
961 m_pForm->m_pFormNotify->AfterValueChange(this); | |
962 } | |
963 | |
964 bool CPDF_FormField::NotifyListOrComboBoxBeforeChange( | |
965 const CFX_WideString& value) { | |
966 switch (GetType()) { | |
967 case ListBox: | |
968 return NotifyBeforeSelectionChange(value); | |
969 case ComboBox: | |
970 return NotifyBeforeValueChange(value); | |
971 default: | |
972 return true; | |
973 } | |
974 } | |
975 | |
976 void CPDF_FormField::NotifyListOrComboBoxAfterChange() { | |
977 switch (GetType()) { | |
978 case ListBox: | |
979 NotifyAfterSelectionChange(); | |
980 break; | |
981 case ComboBox: | |
982 NotifyAfterValueChange(); | |
983 break; | |
984 default: | |
985 break; | |
986 } | |
987 } | |
OLD | NEW |