Clean up CPDF_AnnotList.
[pdfium.git] / fpdfsdk / src / fsdk_baseform.cpp
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 "../../third_party/base/nonstd_unique_ptr.h"
8 #include "../include/fsdk_define.h"
9 #include "../include/fsdk_mgr.h"
10 #include "../include/fsdk_baseannot.h"
11 #include "../include/fsdk_baseform.h"
12 #include "../include/formfiller/FFL_FormFiller.h"
13 #include "../include/fsdk_actionhandler.h"
14
15 #include "../include/javascript/IJavaScript.h"
16
17 //------------------------------------------------------------------------------------
18 //*                                     CPDFSDK_Widget
19 //------------------------------------------------------------------------------------
20
21 #define IsFloatZero(f) ((f) < 0.01 && (f) > -0.01)
22 #define IsFloatBigger(fa, fb) ((fa) > (fb) && !IsFloatZero((fa) - (fb)))
23 #define IsFloatSmaller(fa, fb) ((fa) < (fb) && !IsFloatZero((fa) - (fb)))
24 #define IsFloatEqual(fa, fb) IsFloatZero((fa) - (fb))
25
26 CPDFSDK_Widget::CPDFSDK_Widget(CPDF_Annot* pAnnot,
27                                CPDFSDK_PageView* pPageView,
28                                CPDFSDK_InterForm* pInterForm)
29     : CPDFSDK_Annot(pAnnot, pPageView),
30       m_pInterForm(pInterForm),
31       m_nAppAge(0),
32       m_nValueAge(0) {
33   ASSERT(m_pInterForm != NULL);
34 }
35
36 CPDFSDK_Widget::~CPDFSDK_Widget() {}
37
38 FX_BOOL CPDFSDK_Widget::IsWidgetAppearanceValid(
39     CPDF_Annot::AppearanceMode mode) {
40   CPDF_Dictionary* pAP = m_pAnnot->GetAnnotDict()->GetDict("AP");
41   if (!pAP)
42     return FALSE;
43
44   // Choose the right sub-ap
45   const FX_CHAR* ap_entry = "N";
46   if (mode == CPDF_Annot::Down)
47     ap_entry = "D";
48   else if (mode == CPDF_Annot::Rollover)
49     ap_entry = "R";
50   if (!pAP->KeyExist(ap_entry))
51     ap_entry = "N";
52
53   // Get the AP stream or subdirectory
54   CPDF_Object* psub = pAP->GetElementValue(ap_entry);
55   if (!psub)
56     return FALSE;
57
58   int nFieldType = GetFieldType();
59   switch (nFieldType) {
60     case FIELDTYPE_PUSHBUTTON:
61     case FIELDTYPE_COMBOBOX:
62     case FIELDTYPE_LISTBOX:
63     case FIELDTYPE_TEXTFIELD:
64     case FIELDTYPE_SIGNATURE:
65       return psub->IsStream();
66     case FIELDTYPE_CHECKBOX:
67     case FIELDTYPE_RADIOBUTTON:
68       if (CPDF_Dictionary* pSubDict = psub->AsDictionary()) {
69         return pSubDict->GetStream(GetAppState()) != NULL;
70       }
71       return FALSE;
72   }
73   return TRUE;
74 }
75
76 int CPDFSDK_Widget::GetFieldType() const {
77   CPDF_FormField* pField = GetFormField();
78   ASSERT(pField != NULL);
79
80   return pField->GetFieldType();
81 }
82
83 int CPDFSDK_Widget::GetFieldFlags() const {
84   CPDF_InterForm* pPDFInterForm = m_pInterForm->GetInterForm();
85   ASSERT(pPDFInterForm != NULL);
86
87   CPDF_FormControl* pFormControl =
88       pPDFInterForm->GetControlByDict(m_pAnnot->GetAnnotDict());
89   CPDF_FormField* pFormField = pFormControl->GetField();
90   return pFormField->GetFieldFlags();
91 }
92
93 CFX_ByteString CPDFSDK_Widget::GetSubType() const {
94   int nType = GetFieldType();
95
96   if (nType == FIELDTYPE_SIGNATURE)
97     return BFFT_SIGNATURE;
98   return CPDFSDK_Annot::GetSubType();
99 }
100
101 CPDF_FormField* CPDFSDK_Widget::GetFormField() const {
102   return GetFormControl()->GetField();
103 }
104
105 CPDF_FormControl* CPDFSDK_Widget::GetFormControl() const {
106   CPDF_InterForm* pPDFInterForm = m_pInterForm->GetInterForm();
107   return pPDFInterForm->GetControlByDict(GetAnnotDict());
108 }
109
110 CPDF_FormControl* CPDFSDK_Widget::GetFormControl(
111     CPDF_InterForm* pInterForm,
112     const CPDF_Dictionary* pAnnotDict) {
113   ASSERT(pAnnotDict != NULL);
114   return pInterForm->GetControlByDict(pAnnotDict);
115 }
116
117 int CPDFSDK_Widget::GetRotate() const {
118   CPDF_FormControl* pCtrl = GetFormControl();
119   return pCtrl->GetRotation() % 360;
120 }
121
122 FX_BOOL CPDFSDK_Widget::GetFillColor(FX_COLORREF& color) const {
123   CPDF_FormControl* pFormCtrl = GetFormControl();
124   ASSERT(pFormCtrl != NULL);
125
126   int iColorType = 0;
127   color = FX_ARGBTOCOLORREF(pFormCtrl->GetBackgroundColor(iColorType));
128
129   return iColorType != COLORTYPE_TRANSPARENT;
130 }
131
132 FX_BOOL CPDFSDK_Widget::GetBorderColor(FX_COLORREF& color) const {
133   CPDF_FormControl* pFormCtrl = GetFormControl();
134   ASSERT(pFormCtrl != NULL);
135
136   int iColorType = 0;
137   color = FX_ARGBTOCOLORREF(pFormCtrl->GetBorderColor(iColorType));
138
139   return iColorType != COLORTYPE_TRANSPARENT;
140 }
141
142 FX_BOOL CPDFSDK_Widget::GetTextColor(FX_COLORREF& color) const {
143   CPDF_FormControl* pFormCtrl = GetFormControl();
144   ASSERT(pFormCtrl != NULL);
145
146   CPDF_DefaultAppearance da = pFormCtrl->GetDefaultAppearance();
147   if (da.HasColor()) {
148     FX_ARGB argb;
149     int iColorType = COLORTYPE_TRANSPARENT;
150     da.GetColor(argb, iColorType);
151     color = FX_ARGBTOCOLORREF(argb);
152
153     return iColorType != COLORTYPE_TRANSPARENT;
154   }
155
156   return FALSE;
157 }
158
159 FX_FLOAT CPDFSDK_Widget::GetFontSize() const {
160   CPDF_FormControl* pFormCtrl = GetFormControl();
161   ASSERT(pFormCtrl != NULL);
162
163   CPDF_DefaultAppearance pDa = pFormCtrl->GetDefaultAppearance();
164   CFX_ByteString csFont = "";
165   FX_FLOAT fFontSize = 0.0f;
166   pDa.GetFont(csFont, fFontSize);
167
168   return fFontSize;
169 }
170
171 int CPDFSDK_Widget::GetSelectedIndex(int nIndex) const {
172   CPDF_FormField* pFormField = GetFormField();
173   return pFormField->GetSelectedIndex(nIndex);
174 }
175
176 CFX_WideString CPDFSDK_Widget::GetValue() const {
177   CPDF_FormField* pFormField = GetFormField();
178   return pFormField->GetValue();
179 }
180
181 CFX_WideString CPDFSDK_Widget::GetDefaultValue() const {
182   CPDF_FormField* pFormField = GetFormField();
183   ASSERT(pFormField != NULL);
184
185   return pFormField->GetDefaultValue();
186 }
187
188 CFX_WideString CPDFSDK_Widget::GetOptionLabel(int nIndex) const {
189   CPDF_FormField* pFormField = GetFormField();
190   ASSERT(pFormField != NULL);
191
192   return pFormField->GetOptionLabel(nIndex);
193 }
194
195 int CPDFSDK_Widget::CountOptions() const {
196   CPDF_FormField* pFormField = GetFormField();
197   ASSERT(pFormField != NULL);
198
199   return pFormField->CountOptions();
200 }
201
202 FX_BOOL CPDFSDK_Widget::IsOptionSelected(int nIndex) const {
203   CPDF_FormField* pFormField = GetFormField();
204   return pFormField->IsItemSelected(nIndex);
205 }
206
207 int CPDFSDK_Widget::GetTopVisibleIndex() const {
208   CPDF_FormField* pFormField = GetFormField();
209   ASSERT(pFormField != NULL);
210
211   return pFormField->GetTopVisibleIndex();
212 }
213
214 FX_BOOL CPDFSDK_Widget::IsChecked() const {
215   CPDF_FormControl* pFormCtrl = GetFormControl();
216   ASSERT(pFormCtrl != NULL);
217
218   return pFormCtrl->IsChecked();
219 }
220
221 int CPDFSDK_Widget::GetAlignment() const {
222   CPDF_FormControl* pFormCtrl = GetFormControl();
223   ASSERT(pFormCtrl != NULL);
224
225   return pFormCtrl->GetControlAlignment();
226 }
227
228 int CPDFSDK_Widget::GetMaxLen() const {
229   CPDF_FormField* pFormField = GetFormField();
230   ASSERT(pFormField != NULL);
231
232   return pFormField->GetMaxLen();
233 }
234
235 void CPDFSDK_Widget::SetCheck(FX_BOOL bChecked, FX_BOOL bNotify) {
236   CPDF_FormControl* pFormCtrl = GetFormControl();
237   ASSERT(pFormCtrl != NULL);
238
239   CPDF_FormField* pFormField = pFormCtrl->GetField();
240   ASSERT(pFormField != NULL);
241
242   pFormField->CheckControl(pFormField->GetControlIndex(pFormCtrl), bChecked,
243                            bNotify);
244 }
245
246 void CPDFSDK_Widget::SetValue(const CFX_WideString& sValue, FX_BOOL bNotify) {
247   CPDF_FormField* pFormField = GetFormField();
248   ASSERT(pFormField != NULL);
249
250   pFormField->SetValue(sValue, bNotify);
251 }
252
253 void CPDFSDK_Widget::SetDefaultValue(const CFX_WideString& sValue) {}
254 void CPDFSDK_Widget::SetOptionSelection(int index,
255                                         FX_BOOL bSelected,
256                                         FX_BOOL bNotify) {
257   CPDF_FormField* pFormField = GetFormField();
258   ASSERT(pFormField != NULL);
259
260   pFormField->SetItemSelection(index, bSelected, bNotify);
261 }
262
263 void CPDFSDK_Widget::ClearSelection(FX_BOOL bNotify) {
264   CPDF_FormField* pFormField = GetFormField();
265   ASSERT(pFormField != NULL);
266
267   pFormField->ClearSelection(bNotify);
268 }
269
270 void CPDFSDK_Widget::SetTopVisibleIndex(int index) {}
271
272 void CPDFSDK_Widget::SetAppModified() {
273   m_bAppModified = TRUE;
274 }
275
276 void CPDFSDK_Widget::ClearAppModified() {
277   m_bAppModified = FALSE;
278 }
279
280 FX_BOOL CPDFSDK_Widget::IsAppModified() const {
281   return m_bAppModified;
282 }
283
284 void CPDFSDK_Widget::ResetAppearance(const FX_WCHAR* sValue,
285                                      FX_BOOL bValueChanged) {
286   SetAppModified();
287
288   m_nAppAge++;
289   if (m_nAppAge > 999999)
290     m_nAppAge = 0;
291   if (bValueChanged)
292     m_nValueAge++;
293
294   int nFieldType = GetFieldType();
295
296   switch (nFieldType) {
297     case FIELDTYPE_PUSHBUTTON:
298       ResetAppearance_PushButton();
299       break;
300     case FIELDTYPE_CHECKBOX:
301       ResetAppearance_CheckBox();
302       break;
303     case FIELDTYPE_RADIOBUTTON:
304       ResetAppearance_RadioButton();
305       break;
306     case FIELDTYPE_COMBOBOX:
307       ResetAppearance_ComboBox(sValue);
308       break;
309     case FIELDTYPE_LISTBOX:
310       ResetAppearance_ListBox();
311       break;
312     case FIELDTYPE_TEXTFIELD:
313       ResetAppearance_TextField(sValue);
314       break;
315   }
316
317   ASSERT(m_pAnnot != NULL);
318   m_pAnnot->ClearCachedAP();
319 }
320
321 CFX_WideString CPDFSDK_Widget::OnFormat(FX_BOOL& bFormated) {
322   CPDF_FormField* pFormField = GetFormField();
323   ASSERT(pFormField != NULL);
324   return m_pInterForm->OnFormat(pFormField, bFormated);
325 }
326
327 void CPDFSDK_Widget::ResetFieldAppearance(FX_BOOL bValueChanged) {
328   CPDF_FormField* pFormField = GetFormField();
329   ASSERT(pFormField != NULL);
330
331   ASSERT(m_pInterForm != NULL);
332
333   m_pInterForm->ResetFieldAppearance(pFormField, NULL, bValueChanged);
334 }
335
336 void CPDFSDK_Widget::DrawAppearance(CFX_RenderDevice* pDevice,
337                                     const CPDF_Matrix* pUser2Device,
338                                     CPDF_Annot::AppearanceMode mode,
339                                     const CPDF_RenderOptions* pOptions) {
340   int nFieldType = GetFieldType();
341
342   if ((nFieldType == FIELDTYPE_CHECKBOX ||
343        nFieldType == FIELDTYPE_RADIOBUTTON) &&
344       mode == CPDF_Annot::Normal &&
345       !IsWidgetAppearanceValid(CPDF_Annot::Normal)) {
346     CFX_PathData pathData;
347
348     CPDF_Rect rcAnnot = GetRect();
349
350     pathData.AppendRect(rcAnnot.left, rcAnnot.bottom, rcAnnot.right,
351                         rcAnnot.top);
352
353     CFX_GraphStateData gsd;
354     gsd.m_LineWidth = 0.0f;
355
356     pDevice->DrawPath(&pathData, pUser2Device, &gsd, 0, 0xFFAAAAAA,
357                       FXFILL_ALTERNATE);
358   } else {
359     CPDFSDK_Annot::DrawAppearance(pDevice, pUser2Device, mode, pOptions);
360   }
361 }
362
363 void CPDFSDK_Widget::UpdateField() {
364   CPDF_FormField* pFormField = GetFormField();
365   ASSERT(pFormField != NULL);
366
367   ASSERT(m_pInterForm != NULL);
368   m_pInterForm->UpdateField(pFormField);
369 }
370
371 void CPDFSDK_Widget::DrawShadow(CFX_RenderDevice* pDevice,
372                                 CPDFSDK_PageView* pPageView) {
373   ASSERT(m_pInterForm != NULL);
374
375   int nFieldType = GetFieldType();
376   if (m_pInterForm->IsNeedHighLight(nFieldType)) {
377     CPDF_Rect rc = GetRect();
378     FX_COLORREF color = m_pInterForm->GetHighlightColor(nFieldType);
379     uint8_t alpha = m_pInterForm->GetHighlightAlpha();
380
381     CFX_FloatRect rcDevice;
382     ASSERT(m_pInterForm->GetDocument());
383     CPDFDoc_Environment* pEnv = m_pInterForm->GetDocument()->GetEnv();
384     if (!pEnv)
385       return;
386     CFX_AffineMatrix page2device;
387     pPageView->GetCurrentMatrix(page2device);
388     page2device.Transform(((FX_FLOAT)rc.left), ((FX_FLOAT)rc.bottom),
389                           rcDevice.left, rcDevice.bottom);
390     page2device.Transform(((FX_FLOAT)rc.right), ((FX_FLOAT)rc.top),
391                           rcDevice.right, rcDevice.top);
392
393     rcDevice.Normalize();
394
395     FX_ARGB argb = ArgbEncode((int)alpha, color);
396     FX_RECT rcDev((int)rcDevice.left, (int)rcDevice.top, (int)rcDevice.right,
397                   (int)rcDevice.bottom);
398     pDevice->FillRect(&rcDev, argb);
399   }
400 }
401
402 void CPDFSDK_Widget::ResetAppearance_PushButton() {
403   CPDF_FormControl* pControl = GetFormControl();
404   ASSERT(pControl != NULL);
405
406   CPDF_Rect rcWindow = GetRotatedRect();
407
408   int32_t nLayout = 0;
409
410   switch (pControl->GetTextPosition()) {
411     case TEXTPOS_ICON:
412       nLayout = PPBL_ICON;
413       break;
414     case TEXTPOS_BELOW:
415       nLayout = PPBL_ICONTOPLABELBOTTOM;
416       break;
417     case TEXTPOS_ABOVE:
418       nLayout = PPBL_LABELTOPICONBOTTOM;
419       break;
420     case TEXTPOS_RIGHT:
421       nLayout = PPBL_ICONLEFTLABELRIGHT;
422       break;
423     case TEXTPOS_LEFT:
424       nLayout = PPBL_LABELLEFTICONRIGHT;
425       break;
426     case TEXTPOS_OVERLAID:
427       nLayout = PPBL_LABELOVERICON;
428       break;
429     default:
430       nLayout = PPBL_LABEL;
431       break;
432   }
433
434   CPWL_Color crBackground, crBorder;
435
436   int iColorType;
437   FX_FLOAT fc[4];
438
439   pControl->GetOriginalBackgroundColor(iColorType, fc);
440   if (iColorType > 0)
441     crBackground = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
442
443   pControl->GetOriginalBorderColor(iColorType, fc);
444   if (iColorType > 0)
445     crBorder = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
446
447   FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
448   int32_t nBorderStyle = 0;
449   CPWL_Dash dsBorder(3, 0, 0);
450   CPWL_Color crLeftTop, crRightBottom;
451
452   switch (GetBorderStyle()) {
453     case BBS_DASH:
454       nBorderStyle = PBS_DASH;
455       dsBorder = CPWL_Dash(3, 3, 0);
456       break;
457     case BBS_BEVELED:
458       nBorderStyle = PBS_BEVELED;
459       fBorderWidth *= 2;
460       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
461       crRightBottom = CPWL_Utils::DevideColor(crBackground, 2);
462       break;
463     case BBS_INSET:
464       nBorderStyle = PBS_INSET;
465       fBorderWidth *= 2;
466       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5);
467       crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75);
468       break;
469     case BBS_UNDERLINE:
470       nBorderStyle = PBS_UNDERLINED;
471       break;
472     default:
473       nBorderStyle = PBS_SOLID;
474       break;
475   }
476
477   CPDF_Rect rcClient = CPWL_Utils::DeflateRect(rcWindow, fBorderWidth);
478
479   CPWL_Color crText(COLORTYPE_GRAY, 0);
480
481   FX_FLOAT fFontSize = 12.0f;
482   CFX_ByteString csNameTag;
483
484   CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
485   if (da.HasColor()) {
486     da.GetColor(iColorType, fc);
487     crText = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
488   }
489
490   if (da.HasFont())
491     da.GetFont(csNameTag, fFontSize);
492
493   CFX_WideString csWCaption;
494   CFX_WideString csNormalCaption, csRolloverCaption, csDownCaption;
495
496   if (pControl->HasMKEntry("CA")) {
497     csNormalCaption = pControl->GetNormalCaption();
498   }
499   if (pControl->HasMKEntry("RC")) {
500     csRolloverCaption = pControl->GetRolloverCaption();
501   }
502   if (pControl->HasMKEntry("AC")) {
503     csDownCaption = pControl->GetDownCaption();
504   }
505
506   CPDF_Stream* pNormalIcon = NULL;
507   CPDF_Stream* pRolloverIcon = NULL;
508   CPDF_Stream* pDownIcon = NULL;
509
510   if (pControl->HasMKEntry("I")) {
511     pNormalIcon = pControl->GetNormalIcon();
512   }
513   if (pControl->HasMKEntry("RI")) {
514     pRolloverIcon = pControl->GetRolloverIcon();
515   }
516   if (pControl->HasMKEntry("IX")) {
517     pDownIcon = pControl->GetDownIcon();
518   }
519
520   if (pNormalIcon) {
521     if (CPDF_Dictionary* pImageDict = pNormalIcon->GetDict()) {
522       if (pImageDict->GetString("Name").IsEmpty())
523         pImageDict->SetAtString("Name", "ImgA");
524     }
525   }
526
527   if (pRolloverIcon) {
528     if (CPDF_Dictionary* pImageDict = pRolloverIcon->GetDict()) {
529       if (pImageDict->GetString("Name").IsEmpty())
530         pImageDict->SetAtString("Name", "ImgB");
531     }
532   }
533
534   if (pDownIcon) {
535     if (CPDF_Dictionary* pImageDict = pDownIcon->GetDict()) {
536       if (pImageDict->GetString("Name").IsEmpty())
537         pImageDict->SetAtString("Name", "ImgC");
538     }
539   }
540
541   CPDF_IconFit iconFit = pControl->GetIconFit();
542
543   CPDFSDK_Document* pDoc = m_pInterForm->GetDocument();
544   ASSERT(pDoc != NULL);
545   CPDFDoc_Environment* pEnv = pDoc->GetEnv();
546
547   CBA_FontMap FontMap(this, pEnv->GetSysHandler());
548   FontMap.Initial();
549
550   FontMap.SetAPType("N");
551
552   CFX_ByteString csAP =
553       CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) +
554       CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
555                                      crLeftTop, crRightBottom, nBorderStyle,
556                                      dsBorder) +
557       CPWL_Utils::GetPushButtonAppStream(
558           iconFit.GetFittingBounds() ? rcWindow : rcClient, &FontMap,
559           pNormalIcon, iconFit, csNormalCaption, crText, fFontSize, nLayout);
560
561   WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP);
562   if (pNormalIcon)
563     AddImageToAppearance("N", pNormalIcon);
564
565   CPDF_FormControl::HighlightingMode eHLM = pControl->GetHighlightingMode();
566   if (eHLM == CPDF_FormControl::Push || eHLM == CPDF_FormControl::Toggle) {
567     if (csRolloverCaption.IsEmpty() && !pRolloverIcon) {
568       csRolloverCaption = csNormalCaption;
569       pRolloverIcon = pNormalIcon;
570     }
571
572     FontMap.SetAPType("R");
573
574     csAP = CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) +
575            CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
576                                           crLeftTop, crRightBottom,
577                                           nBorderStyle, dsBorder) +
578            CPWL_Utils::GetPushButtonAppStream(
579                iconFit.GetFittingBounds() ? rcWindow : rcClient, &FontMap,
580                pRolloverIcon, iconFit, csRolloverCaption, crText, fFontSize,
581                nLayout);
582
583     WriteAppearance("R", GetRotatedRect(), GetMatrix(), csAP);
584     if (pRolloverIcon)
585       AddImageToAppearance("R", pRolloverIcon);
586
587     if (csDownCaption.IsEmpty() && !pDownIcon) {
588       csDownCaption = csNormalCaption;
589       pDownIcon = pNormalIcon;
590     }
591
592     switch (nBorderStyle) {
593       case PBS_BEVELED: {
594         CPWL_Color crTemp = crLeftTop;
595         crLeftTop = crRightBottom;
596         crRightBottom = crTemp;
597       } break;
598       case PBS_INSET:
599         crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0);
600         crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1);
601         break;
602     }
603
604     FontMap.SetAPType("D");
605
606     csAP = CPWL_Utils::GetRectFillAppStream(
607                rcWindow, CPWL_Utils::SubstractColor(crBackground, 0.25f)) +
608            CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
609                                           crLeftTop, crRightBottom,
610                                           nBorderStyle, dsBorder) +
611            CPWL_Utils::GetPushButtonAppStream(
612                iconFit.GetFittingBounds() ? rcWindow : rcClient, &FontMap,
613                pDownIcon, iconFit, csDownCaption, crText, fFontSize, nLayout);
614
615     WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP);
616     if (pDownIcon)
617       AddImageToAppearance("D", pDownIcon);
618   } else {
619     RemoveAppearance("D");
620     RemoveAppearance("R");
621   }
622 }
623
624 void CPDFSDK_Widget::ResetAppearance_CheckBox() {
625   CPDF_FormControl* pControl = GetFormControl();
626   ASSERT(pControl != NULL);
627
628   CPWL_Color crBackground, crBorder, crText;
629
630   int iColorType;
631   FX_FLOAT fc[4];
632
633   pControl->GetOriginalBackgroundColor(iColorType, fc);
634   if (iColorType > 0)
635     crBackground = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
636
637   pControl->GetOriginalBorderColor(iColorType, fc);
638   if (iColorType > 0)
639     crBorder = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
640
641   FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
642   int32_t nBorderStyle = 0;
643   CPWL_Dash dsBorder(3, 0, 0);
644   CPWL_Color crLeftTop, crRightBottom;
645
646   switch (GetBorderStyle()) {
647     case BBS_DASH:
648       nBorderStyle = PBS_DASH;
649       dsBorder = CPWL_Dash(3, 3, 0);
650       break;
651     case BBS_BEVELED:
652       nBorderStyle = PBS_BEVELED;
653       fBorderWidth *= 2;
654       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
655       crRightBottom = CPWL_Utils::DevideColor(crBackground, 2);
656       break;
657     case BBS_INSET:
658       nBorderStyle = PBS_INSET;
659       fBorderWidth *= 2;
660       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5);
661       crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75);
662       break;
663     case BBS_UNDERLINE:
664       nBorderStyle = PBS_UNDERLINED;
665       break;
666     default:
667       nBorderStyle = PBS_SOLID;
668       break;
669   }
670
671   CPDF_Rect rcWindow = GetRotatedRect();
672   CPDF_Rect rcClient = CPWL_Utils::DeflateRect(rcWindow, fBorderWidth);
673
674   CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
675   if (da.HasColor()) {
676     da.GetColor(iColorType, fc);
677     crText = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
678   }
679
680   int32_t nStyle = 0;
681
682   CFX_WideString csWCaption = pControl->GetNormalCaption();
683   if (csWCaption.GetLength() > 0) {
684     switch (csWCaption[0]) {
685       case L'l':
686         nStyle = PCS_CIRCLE;
687         break;
688       case L'8':
689         nStyle = PCS_CROSS;
690         break;
691       case L'u':
692         nStyle = PCS_DIAMOND;
693         break;
694       case L'n':
695         nStyle = PCS_SQUARE;
696         break;
697       case L'H':
698         nStyle = PCS_STAR;
699         break;
700       default:  // L'4'
701         nStyle = PCS_CHECK;
702         break;
703     }
704   } else {
705     nStyle = PCS_CHECK;
706   }
707
708   CFX_ByteString csAP_N_ON =
709       CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) +
710       CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
711                                      crLeftTop, crRightBottom, nBorderStyle,
712                                      dsBorder);
713
714   CFX_ByteString csAP_N_OFF = csAP_N_ON;
715
716   switch (nBorderStyle) {
717     case PBS_BEVELED: {
718       CPWL_Color crTemp = crLeftTop;
719       crLeftTop = crRightBottom;
720       crRightBottom = crTemp;
721     } break;
722     case PBS_INSET:
723       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0);
724       crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1);
725       break;
726   }
727
728   CFX_ByteString csAP_D_ON =
729       CPWL_Utils::GetRectFillAppStream(
730           rcWindow, CPWL_Utils::SubstractColor(crBackground, 0.25f)) +
731       CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
732                                      crLeftTop, crRightBottom, nBorderStyle,
733                                      dsBorder);
734
735   CFX_ByteString csAP_D_OFF = csAP_D_ON;
736
737   csAP_N_ON += CPWL_Utils::GetCheckBoxAppStream(rcClient, nStyle, crText);
738   csAP_D_ON += CPWL_Utils::GetCheckBoxAppStream(rcClient, nStyle, crText);
739
740   WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP_N_ON,
741                   pControl->GetCheckedAPState());
742   WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP_N_OFF, "Off");
743
744   WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP_D_ON,
745                   pControl->GetCheckedAPState());
746   WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP_D_OFF, "Off");
747
748   CFX_ByteString csAS = GetAppState();
749   if (csAS.IsEmpty())
750     SetAppState("Off");
751 }
752
753 void CPDFSDK_Widget::ResetAppearance_RadioButton() {
754   CPDF_FormControl* pControl = GetFormControl();
755   ASSERT(pControl != NULL);
756
757   CPWL_Color crBackground, crBorder, crText;
758
759   int iColorType;
760   FX_FLOAT fc[4];
761
762   pControl->GetOriginalBackgroundColor(iColorType, fc);
763   if (iColorType > 0)
764     crBackground = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
765
766   pControl->GetOriginalBorderColor(iColorType, fc);
767   if (iColorType > 0)
768     crBorder = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
769
770   FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
771   int32_t nBorderStyle = 0;
772   CPWL_Dash dsBorder(3, 0, 0);
773   CPWL_Color crLeftTop, crRightBottom;
774
775   switch (GetBorderStyle()) {
776     case BBS_DASH:
777       nBorderStyle = PBS_DASH;
778       dsBorder = CPWL_Dash(3, 3, 0);
779       break;
780     case BBS_BEVELED:
781       nBorderStyle = PBS_BEVELED;
782       fBorderWidth *= 2;
783       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
784       crRightBottom = CPWL_Utils::DevideColor(crBackground, 2);
785       break;
786     case BBS_INSET:
787       nBorderStyle = PBS_INSET;
788       fBorderWidth *= 2;
789       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5);
790       crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75);
791       break;
792     case BBS_UNDERLINE:
793       nBorderStyle = PBS_UNDERLINED;
794       break;
795     default:
796       nBorderStyle = PBS_SOLID;
797       break;
798   }
799
800   CPDF_Rect rcWindow = GetRotatedRect();
801   CPDF_Rect rcClient = CPWL_Utils::DeflateRect(rcWindow, fBorderWidth);
802
803   CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
804   if (da.HasColor()) {
805     da.GetColor(iColorType, fc);
806     crText = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
807   }
808
809   int32_t nStyle = 0;
810
811   CFX_WideString csWCaption = pControl->GetNormalCaption();
812   if (csWCaption.GetLength() > 0) {
813     switch (csWCaption[0]) {
814       default:  // L'l':
815         nStyle = PCS_CIRCLE;
816         break;
817       case L'8':
818         nStyle = PCS_CROSS;
819         break;
820       case L'u':
821         nStyle = PCS_DIAMOND;
822         break;
823       case L'n':
824         nStyle = PCS_SQUARE;
825         break;
826       case L'H':
827         nStyle = PCS_STAR;
828         break;
829       case L'4':
830         nStyle = PCS_CHECK;
831         break;
832     }
833   } else {
834     nStyle = PCS_CIRCLE;
835   }
836
837   CFX_ByteString csAP_N_ON;
838
839   CPDF_Rect rcCenter =
840       CPWL_Utils::DeflateRect(CPWL_Utils::GetCenterSquare(rcWindow), 1.0f);
841
842   if (nStyle == PCS_CIRCLE) {
843     if (nBorderStyle == PBS_BEVELED) {
844       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
845       crRightBottom = CPWL_Utils::SubstractColor(crBackground, 0.25f);
846     } else if (nBorderStyle == PBS_INSET) {
847       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5f);
848       crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75f);
849     }
850
851     csAP_N_ON = CPWL_Utils::GetCircleFillAppStream(rcCenter, crBackground) +
852                 CPWL_Utils::GetCircleBorderAppStream(
853                     rcCenter, fBorderWidth, crBorder, crLeftTop, crRightBottom,
854                     nBorderStyle, dsBorder);
855   } else {
856     csAP_N_ON = CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) +
857                 CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
858                                                crLeftTop, crRightBottom,
859                                                nBorderStyle, dsBorder);
860   }
861
862   CFX_ByteString csAP_N_OFF = csAP_N_ON;
863
864   switch (nBorderStyle) {
865     case PBS_BEVELED: {
866       CPWL_Color crTemp = crLeftTop;
867       crLeftTop = crRightBottom;
868       crRightBottom = crTemp;
869     } break;
870     case PBS_INSET:
871       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0);
872       crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1);
873       break;
874   }
875
876   CFX_ByteString csAP_D_ON;
877
878   if (nStyle == PCS_CIRCLE) {
879     CPWL_Color crBK = CPWL_Utils::SubstractColor(crBackground, 0.25f);
880     if (nBorderStyle == PBS_BEVELED) {
881       crLeftTop = CPWL_Utils::SubstractColor(crBackground, 0.25f);
882       crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1);
883       crBK = crBackground;
884     } else if (nBorderStyle == PBS_INSET) {
885       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0);
886       crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1);
887     }
888
889     csAP_D_ON = CPWL_Utils::GetCircleFillAppStream(rcCenter, crBK) +
890                 CPWL_Utils::GetCircleBorderAppStream(
891                     rcCenter, fBorderWidth, crBorder, crLeftTop, crRightBottom,
892                     nBorderStyle, dsBorder);
893   } else {
894     csAP_D_ON = CPWL_Utils::GetRectFillAppStream(
895                     rcWindow, CPWL_Utils::SubstractColor(crBackground, 0.25f)) +
896                 CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
897                                                crLeftTop, crRightBottom,
898                                                nBorderStyle, dsBorder);
899   }
900
901   CFX_ByteString csAP_D_OFF = csAP_D_ON;
902
903   csAP_N_ON += CPWL_Utils::GetRadioButtonAppStream(rcClient, nStyle, crText);
904   csAP_D_ON += CPWL_Utils::GetRadioButtonAppStream(rcClient, nStyle, crText);
905
906   WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP_N_ON,
907                   pControl->GetCheckedAPState());
908   WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP_N_OFF, "Off");
909
910   WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP_D_ON,
911                   pControl->GetCheckedAPState());
912   WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP_D_OFF, "Off");
913
914   CFX_ByteString csAS = GetAppState();
915   if (csAS.IsEmpty())
916     SetAppState("Off");
917 }
918
919 void CPDFSDK_Widget::ResetAppearance_ComboBox(const FX_WCHAR* sValue) {
920   CPDF_FormControl* pControl = GetFormControl();
921   ASSERT(pControl != NULL);
922   CPDF_FormField* pField = pControl->GetField();
923   ASSERT(pField != NULL);
924
925   CFX_ByteTextBuf sBody, sLines;
926
927   CPDF_Rect rcClient = GetClientRect();
928   CPDF_Rect rcButton = rcClient;
929   rcButton.left = rcButton.right - 13;
930   rcButton.Normalize();
931
932   if (IFX_Edit* pEdit = IFX_Edit::NewEdit()) {
933     pEdit->EnableRefresh(FALSE);
934
935     CPDFSDK_Document* pDoc = m_pInterForm->GetDocument();
936     ASSERT(pDoc != NULL);
937     CPDFDoc_Environment* pEnv = pDoc->GetEnv();
938     CBA_FontMap FontMap(this, pEnv->GetSysHandler());
939     FontMap.Initial();
940     pEdit->SetFontMap(&FontMap);
941
942     CPDF_Rect rcEdit = rcClient;
943     rcEdit.right = rcButton.left;
944     rcEdit.Normalize();
945
946     pEdit->SetPlateRect(rcEdit);
947     pEdit->SetAlignmentV(1);
948
949     FX_FLOAT fFontSize = GetFontSize();
950     if (IsFloatZero(fFontSize))
951       pEdit->SetAutoFontSize(TRUE);
952     else
953       pEdit->SetFontSize(fFontSize);
954
955     pEdit->Initialize();
956
957     if (sValue)
958       pEdit->SetText(sValue);
959     else {
960       int32_t nCurSel = pField->GetSelectedIndex(0);
961
962       if (nCurSel < 0)
963         pEdit->SetText(pField->GetValue().c_str());
964       else
965         pEdit->SetText(pField->GetOptionLabel(nCurSel).c_str());
966     }
967
968     CPDF_Rect rcContent = pEdit->GetContentRect();
969
970     CFX_ByteString sEdit =
971         CPWL_Utils::GetEditAppStream(pEdit, CPDF_Point(0.0f, 0.0f));
972     if (sEdit.GetLength() > 0) {
973       sBody << "/Tx BMC\n"
974             << "q\n";
975       if (rcContent.Width() > rcEdit.Width() ||
976           rcContent.Height() > rcEdit.Height()) {
977         sBody << rcEdit.left << " " << rcEdit.bottom << " " << rcEdit.Width()
978               << " " << rcEdit.Height() << " re\nW\nn\n";
979       }
980
981       CPWL_Color crText = GetTextPWLColor();
982       sBody << "BT\n" << CPWL_Utils::GetColorAppStream(crText) << sEdit
983             << "ET\n"
984             << "Q\nEMC\n";
985     }
986
987     IFX_Edit::DelEdit(pEdit);
988   }
989
990   sBody << CPWL_Utils::GetDropButtonAppStream(rcButton);
991
992   CFX_ByteString sAP = GetBackgroundAppStream() + GetBorderAppStream() +
993                        sLines.GetByteString() + sBody.GetByteString();
994
995   WriteAppearance("N", GetRotatedRect(), GetMatrix(), sAP);
996 }
997
998 void CPDFSDK_Widget::ResetAppearance_ListBox() {
999   CPDF_FormControl* pControl = GetFormControl();
1000   ASSERT(pControl != NULL);
1001   CPDF_FormField* pField = pControl->GetField();
1002   ASSERT(pField != NULL);
1003
1004   CPDF_Rect rcClient = GetClientRect();
1005
1006   CFX_ByteTextBuf sBody, sLines;
1007
1008   if (IFX_Edit* pEdit = IFX_Edit::NewEdit()) {
1009     pEdit->EnableRefresh(FALSE);
1010
1011     CPDFSDK_Document* pDoc = m_pInterForm->GetDocument();
1012     ASSERT(pDoc != NULL);
1013     CPDFDoc_Environment* pEnv = pDoc->GetEnv();
1014
1015     CBA_FontMap FontMap(this, pEnv->GetSysHandler());
1016     FontMap.Initial();
1017     pEdit->SetFontMap(&FontMap);
1018
1019     pEdit->SetPlateRect(CPDF_Rect(rcClient.left, 0.0f, rcClient.right, 0.0f));
1020
1021     FX_FLOAT fFontSize = GetFontSize();
1022
1023     if (IsFloatZero(fFontSize))
1024       pEdit->SetFontSize(12.0f);
1025     else
1026       pEdit->SetFontSize(fFontSize);
1027
1028     pEdit->Initialize();
1029
1030     CFX_ByteTextBuf sList;
1031     FX_FLOAT fy = rcClient.top;
1032
1033     int32_t nTop = pField->GetTopVisibleIndex();
1034     int32_t nCount = pField->CountOptions();
1035     int32_t nSelCount = pField->CountSelectedItems();
1036
1037     for (int32_t i = nTop; i < nCount; i++) {
1038       FX_BOOL bSelected = FALSE;
1039       for (int32_t j = 0; j < nSelCount; j++) {
1040         if (pField->GetSelectedIndex(j) == i) {
1041           bSelected = TRUE;
1042           break;
1043         }
1044       }
1045
1046       pEdit->SetText(pField->GetOptionLabel(i).c_str());
1047
1048       CPDF_Rect rcContent = pEdit->GetContentRect();
1049       FX_FLOAT fItemHeight = rcContent.Height();
1050
1051       if (bSelected) {
1052         CPDF_Rect rcItem =
1053             CPDF_Rect(rcClient.left, fy - fItemHeight, rcClient.right, fy);
1054         sList << "q\n" << CPWL_Utils::GetColorAppStream(
1055                               CPWL_Color(COLORTYPE_RGB, 0, 51.0f / 255.0f,
1056                                          113.0f / 255.0f),
1057                               TRUE)
1058               << rcItem.left << " " << rcItem.bottom << " " << rcItem.Width()
1059               << " " << rcItem.Height() << " re f\n"
1060               << "Q\n";
1061
1062         sList << "BT\n" << CPWL_Utils::GetColorAppStream(
1063                                CPWL_Color(COLORTYPE_GRAY, 1), TRUE)
1064               << CPWL_Utils::GetEditAppStream(pEdit, CPDF_Point(0.0f, fy))
1065               << "ET\n";
1066       } else {
1067         CPWL_Color crText = GetTextPWLColor();
1068         sList << "BT\n" << CPWL_Utils::GetColorAppStream(crText, TRUE)
1069               << CPWL_Utils::GetEditAppStream(pEdit, CPDF_Point(0.0f, fy))
1070               << "ET\n";
1071       }
1072
1073       fy -= fItemHeight;
1074     }
1075
1076     if (sList.GetSize() > 0) {
1077       sBody << "/Tx BMC\n"
1078             << "q\n" << rcClient.left << " " << rcClient.bottom << " "
1079             << rcClient.Width() << " " << rcClient.Height() << " re\nW\nn\n";
1080       sBody << sList << "Q\nEMC\n";
1081     }
1082
1083     IFX_Edit::DelEdit(pEdit);
1084   }
1085
1086   CFX_ByteString sAP = GetBackgroundAppStream() + GetBorderAppStream() +
1087                        sLines.GetByteString() + sBody.GetByteString();
1088
1089   WriteAppearance("N", GetRotatedRect(), GetMatrix(), sAP);
1090 }
1091
1092 void CPDFSDK_Widget::ResetAppearance_TextField(const FX_WCHAR* sValue) {
1093   CPDF_FormControl* pControl = GetFormControl();
1094   ASSERT(pControl != NULL);
1095   CPDF_FormField* pField = pControl->GetField();
1096   ASSERT(pField != NULL);
1097
1098   CFX_ByteTextBuf sBody, sLines;
1099
1100   if (IFX_Edit* pEdit = IFX_Edit::NewEdit()) {
1101     pEdit->EnableRefresh(FALSE);
1102
1103     CPDFSDK_Document* pDoc = m_pInterForm->GetDocument();
1104     ASSERT(pDoc != NULL);
1105     CPDFDoc_Environment* pEnv = pDoc->GetEnv();
1106
1107     CBA_FontMap FontMap(this, pEnv->GetSysHandler());
1108     FontMap.Initial();
1109     pEdit->SetFontMap(&FontMap);
1110
1111     CPDF_Rect rcClient = GetClientRect();
1112     pEdit->SetPlateRect(rcClient);
1113     pEdit->SetAlignmentH(pControl->GetControlAlignment());
1114
1115     FX_DWORD dwFieldFlags = pField->GetFieldFlags();
1116     FX_BOOL bMultiLine = (dwFieldFlags >> 12) & 1;
1117
1118     if (bMultiLine) {
1119       pEdit->SetMultiLine(TRUE);
1120       pEdit->SetAutoReturn(TRUE);
1121     } else {
1122       pEdit->SetAlignmentV(1);
1123     }
1124
1125     FX_WORD subWord = 0;
1126     if ((dwFieldFlags >> 13) & 1) {
1127       subWord = '*';
1128       pEdit->SetPasswordChar(subWord);
1129     }
1130
1131     int nMaxLen = pField->GetMaxLen();
1132     FX_BOOL bCharArray = (dwFieldFlags >> 24) & 1;
1133     FX_FLOAT fFontSize = GetFontSize();
1134
1135     if (nMaxLen > 0) {
1136       if (bCharArray) {
1137         pEdit->SetCharArray(nMaxLen);
1138
1139         if (IsFloatZero(fFontSize)) {
1140           fFontSize = CPWL_Edit::GetCharArrayAutoFontSize(FontMap.GetPDFFont(0),
1141                                                           rcClient, nMaxLen);
1142         }
1143       } else {
1144         if (sValue)
1145           nMaxLen = wcslen((const wchar_t*)sValue);
1146         pEdit->SetLimitChar(nMaxLen);
1147       }
1148     }
1149
1150     if (IsFloatZero(fFontSize))
1151       pEdit->SetAutoFontSize(TRUE);
1152     else
1153       pEdit->SetFontSize(fFontSize);
1154
1155     pEdit->Initialize();
1156
1157     if (sValue)
1158       pEdit->SetText(sValue);
1159     else
1160       pEdit->SetText(pField->GetValue().c_str());
1161
1162     CPDF_Rect rcContent = pEdit->GetContentRect();
1163
1164     CFX_ByteString sEdit = CPWL_Utils::GetEditAppStream(
1165         pEdit, CPDF_Point(0.0f, 0.0f), NULL, !bCharArray, subWord);
1166
1167     if (sEdit.GetLength() > 0) {
1168       sBody << "/Tx BMC\n"
1169             << "q\n";
1170       if (rcContent.Width() > rcClient.Width() ||
1171           rcContent.Height() > rcClient.Height()) {
1172         sBody << rcClient.left << " " << rcClient.bottom << " "
1173               << rcClient.Width() << " " << rcClient.Height() << " re\nW\nn\n";
1174       }
1175       CPWL_Color crText = GetTextPWLColor();
1176       sBody << "BT\n" << CPWL_Utils::GetColorAppStream(crText) << sEdit
1177             << "ET\n"
1178             << "Q\nEMC\n";
1179     }
1180
1181     if (bCharArray) {
1182       switch (GetBorderStyle()) {
1183         case BBS_SOLID: {
1184           CFX_ByteString sColor =
1185               CPWL_Utils::GetColorAppStream(GetBorderPWLColor(), FALSE);
1186           if (sColor.GetLength() > 0) {
1187             sLines << "q\n" << GetBorderWidth() << " w\n"
1188                    << CPWL_Utils::GetColorAppStream(GetBorderPWLColor(), FALSE)
1189                    << " 2 J 0 j\n";
1190
1191             for (int32_t i = 1; i < nMaxLen; i++) {
1192               sLines << rcClient.left +
1193                             ((rcClient.right - rcClient.left) / nMaxLen) * i
1194                      << " " << rcClient.bottom << " m\n"
1195                      << rcClient.left +
1196                             ((rcClient.right - rcClient.left) / nMaxLen) * i
1197                      << " " << rcClient.top << " l S\n";
1198             }
1199
1200             sLines << "Q\n";
1201           }
1202         } break;
1203         case BBS_DASH: {
1204           CFX_ByteString sColor =
1205               CPWL_Utils::GetColorAppStream(GetBorderPWLColor(), FALSE);
1206           if (sColor.GetLength() > 0) {
1207             CPWL_Dash dsBorder = CPWL_Dash(3, 3, 0);
1208
1209             sLines << "q\n" << GetBorderWidth() << " w\n"
1210                    << CPWL_Utils::GetColorAppStream(GetBorderPWLColor(), FALSE)
1211                    << "[" << dsBorder.nDash << " " << dsBorder.nGap << "] "
1212                    << dsBorder.nPhase << " d\n";
1213
1214             for (int32_t i = 1; i < nMaxLen; i++) {
1215               sLines << rcClient.left +
1216                             ((rcClient.right - rcClient.left) / nMaxLen) * i
1217                      << " " << rcClient.bottom << " m\n"
1218                      << rcClient.left +
1219                             ((rcClient.right - rcClient.left) / nMaxLen) * i
1220                      << " " << rcClient.top << " l S\n";
1221             }
1222
1223             sLines << "Q\n";
1224           }
1225         } break;
1226       }
1227     }
1228
1229     IFX_Edit::DelEdit(pEdit);
1230   }
1231
1232   CFX_ByteString sAP = GetBackgroundAppStream() + GetBorderAppStream() +
1233                        sLines.GetByteString() + sBody.GetByteString();
1234   WriteAppearance("N", GetRotatedRect(), GetMatrix(), sAP);
1235 }
1236
1237 CPDF_Rect CPDFSDK_Widget::GetClientRect() const {
1238   CPDF_Rect rcWindow = GetRotatedRect();
1239   FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
1240   switch (GetBorderStyle()) {
1241     case BBS_BEVELED:
1242     case BBS_INSET:
1243       fBorderWidth *= 2.0f;
1244       break;
1245   }
1246
1247   return CPWL_Utils::DeflateRect(rcWindow, fBorderWidth);
1248 }
1249
1250 CPDF_Rect CPDFSDK_Widget::GetRotatedRect() const {
1251   CPDF_Rect rectAnnot = GetRect();
1252   FX_FLOAT fWidth = rectAnnot.right - rectAnnot.left;
1253   FX_FLOAT fHeight = rectAnnot.top - rectAnnot.bottom;
1254
1255   CPDF_FormControl* pControl = GetFormControl();
1256   CPDF_Rect rcPDFWindow;
1257   switch (abs(pControl->GetRotation() % 360)) {
1258     case 0:
1259     case 180:
1260     default:
1261       rcPDFWindow = CPDF_Rect(0, 0, fWidth, fHeight);
1262       break;
1263     case 90:
1264     case 270:
1265       rcPDFWindow = CPDF_Rect(0, 0, fHeight, fWidth);
1266       break;
1267   }
1268
1269   return rcPDFWindow;
1270 }
1271
1272 CFX_ByteString CPDFSDK_Widget::GetBackgroundAppStream() const {
1273   CPWL_Color crBackground = GetFillPWLColor();
1274   if (crBackground.nColorType != COLORTYPE_TRANSPARENT) {
1275     return CPWL_Utils::GetRectFillAppStream(GetRotatedRect(), crBackground);
1276   }
1277   return "";
1278 }
1279
1280 CFX_ByteString CPDFSDK_Widget::GetBorderAppStream() const {
1281   CPDF_Rect rcWindow = GetRotatedRect();
1282   CPWL_Color crBorder = GetBorderPWLColor();
1283   CPWL_Color crBackground = GetFillPWLColor();
1284   CPWL_Color crLeftTop, crRightBottom;
1285
1286   FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth();
1287   int32_t nBorderStyle = 0;
1288   CPWL_Dash dsBorder(3, 0, 0);
1289
1290   switch (GetBorderStyle()) {
1291     case BBS_DASH:
1292       nBorderStyle = PBS_DASH;
1293       dsBorder = CPWL_Dash(3, 3, 0);
1294       break;
1295     case BBS_BEVELED:
1296       nBorderStyle = PBS_BEVELED;
1297       fBorderWidth *= 2;
1298       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1);
1299       crRightBottom = CPWL_Utils::DevideColor(crBackground, 2);
1300       break;
1301     case BBS_INSET:
1302       nBorderStyle = PBS_INSET;
1303       fBorderWidth *= 2;
1304       crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5);
1305       crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75);
1306       break;
1307     case BBS_UNDERLINE:
1308       nBorderStyle = PBS_UNDERLINED;
1309       break;
1310     default:
1311       nBorderStyle = PBS_SOLID;
1312       break;
1313   }
1314
1315   return CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder,
1316                                         crLeftTop, crRightBottom, nBorderStyle,
1317                                         dsBorder);
1318 }
1319
1320 CPDF_Matrix CPDFSDK_Widget::GetMatrix() const {
1321   CPDF_Matrix mt;
1322   CPDF_FormControl* pControl = GetFormControl();
1323   ASSERT(pControl != NULL);
1324
1325   CPDF_Rect rcAnnot = GetRect();
1326   FX_FLOAT fWidth = rcAnnot.right - rcAnnot.left;
1327   FX_FLOAT fHeight = rcAnnot.top - rcAnnot.bottom;
1328
1329   switch (abs(pControl->GetRotation() % 360)) {
1330     case 0:
1331     default:
1332       mt = CPDF_Matrix(1, 0, 0, 1, 0, 0);
1333       break;
1334     case 90:
1335       mt = CPDF_Matrix(0, 1, -1, 0, fWidth, 0);
1336       break;
1337     case 180:
1338       mt = CPDF_Matrix(-1, 0, 0, -1, fWidth, fHeight);
1339       break;
1340     case 270:
1341       mt = CPDF_Matrix(0, -1, 1, 0, 0, fHeight);
1342       break;
1343   }
1344
1345   return mt;
1346 }
1347
1348 CPWL_Color CPDFSDK_Widget::GetTextPWLColor() const {
1349   CPWL_Color crText = CPWL_Color(COLORTYPE_GRAY, 0);
1350
1351   CPDF_FormControl* pFormCtrl = GetFormControl();
1352   ASSERT(pFormCtrl != NULL);
1353
1354   CPDF_DefaultAppearance da = pFormCtrl->GetDefaultAppearance();
1355   if (da.HasColor()) {
1356     int32_t iColorType;
1357     FX_FLOAT fc[4];
1358     da.GetColor(iColorType, fc);
1359     crText = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1360   }
1361
1362   return crText;
1363 }
1364
1365 CPWL_Color CPDFSDK_Widget::GetBorderPWLColor() const {
1366   CPWL_Color crBorder;
1367
1368   CPDF_FormControl* pFormCtrl = GetFormControl();
1369   ASSERT(pFormCtrl != NULL);
1370
1371   int32_t iColorType;
1372   FX_FLOAT fc[4];
1373   pFormCtrl->GetOriginalBorderColor(iColorType, fc);
1374   if (iColorType > 0)
1375     crBorder = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1376
1377   return crBorder;
1378 }
1379
1380 CPWL_Color CPDFSDK_Widget::GetFillPWLColor() const {
1381   CPWL_Color crFill;
1382
1383   CPDF_FormControl* pFormCtrl = GetFormControl();
1384   ASSERT(pFormCtrl != NULL);
1385
1386   int32_t iColorType;
1387   FX_FLOAT fc[4];
1388   pFormCtrl->GetOriginalBackgroundColor(iColorType, fc);
1389   if (iColorType > 0)
1390     crFill = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1391
1392   return crFill;
1393 }
1394
1395 void CPDFSDK_Widget::AddImageToAppearance(const CFX_ByteString& sAPType,
1396                                           CPDF_Stream* pImage) {
1397   ASSERT(pImage != NULL);
1398
1399   CPDF_Document* pDoc = m_pPageView->GetPDFDocument();
1400   ASSERT(pDoc != NULL);
1401
1402   CPDF_Dictionary* pAPDict = m_pAnnot->GetAnnotDict()->GetDict("AP");
1403   ASSERT(pAPDict != NULL);
1404
1405   CPDF_Stream* pStream = pAPDict->GetStream(sAPType);
1406   ASSERT(pStream != NULL);
1407
1408   CPDF_Dictionary* pStreamDict = pStream->GetDict();
1409   ASSERT(pStreamDict != NULL);
1410
1411   CFX_ByteString sImageAlias = "IMG";
1412
1413   if (CPDF_Dictionary* pImageDict = pImage->GetDict()) {
1414     sImageAlias = pImageDict->GetString("Name");
1415     if (sImageAlias.IsEmpty())
1416       sImageAlias = "IMG";
1417   }
1418
1419   CPDF_Dictionary* pStreamResList = pStreamDict->GetDict("Resources");
1420   if (!pStreamResList) {
1421     pStreamResList = new CPDF_Dictionary();
1422     pStreamDict->SetAt("Resources", pStreamResList);
1423   }
1424
1425   if (pStreamResList) {
1426     CPDF_Dictionary* pXObject = new CPDF_Dictionary;
1427     pXObject->SetAtReference(sImageAlias, pDoc, pImage);
1428     pStreamResList->SetAt("XObject", pXObject);
1429   }
1430 }
1431
1432 void CPDFSDK_Widget::RemoveAppearance(const CFX_ByteString& sAPType) {
1433   if (CPDF_Dictionary* pAPDict = m_pAnnot->GetAnnotDict()->GetDict("AP")) {
1434     pAPDict->RemoveAt(sAPType);
1435   }
1436 }
1437
1438 FX_BOOL CPDFSDK_Widget::OnAAction(CPDF_AAction::AActionType type,
1439                                   PDFSDK_FieldAction& data,
1440                                   CPDFSDK_PageView* pPageView) {
1441   CPDF_Action action = GetAAction(type);
1442
1443   if (action && action.GetType() != CPDF_Action::Unknown) {
1444     CPDFSDK_Document* pDocument = pPageView->GetSDKDocument();
1445     CPDFDoc_Environment* pEnv = pDocument->GetEnv();
1446     CPDFSDK_ActionHandler* pActionHandler = pEnv->GetActionHander();
1447     return pActionHandler->DoAction_Field(action, type, pDocument,
1448                                           GetFormField(), data);
1449   }
1450   return FALSE;
1451 }
1452
1453 CPDF_Action CPDFSDK_Widget::GetAAction(CPDF_AAction::AActionType eAAT) {
1454   switch (eAAT) {
1455     case CPDF_AAction::CursorEnter:
1456     case CPDF_AAction::CursorExit:
1457     case CPDF_AAction::ButtonDown:
1458     case CPDF_AAction::ButtonUp:
1459     case CPDF_AAction::GetFocus:
1460     case CPDF_AAction::LoseFocus:
1461     case CPDF_AAction::PageOpen:
1462     case CPDF_AAction::PageClose:
1463     case CPDF_AAction::PageVisible:
1464     case CPDF_AAction::PageInvisible:
1465       return CPDFSDK_Annot::GetAAction(eAAT);
1466
1467     case CPDF_AAction::KeyStroke:
1468     case CPDF_AAction::Format:
1469     case CPDF_AAction::Validate:
1470     case CPDF_AAction::Calculate: {
1471       CPDF_FormField* pField = GetFormField();
1472       if (CPDF_AAction aa = pField->GetAdditionalAction())
1473         return aa.GetAction(eAAT);
1474
1475       return CPDFSDK_Annot::GetAAction(eAAT);
1476     }
1477     default:
1478       break;
1479   }
1480
1481   return CPDF_Action();
1482 }
1483
1484 CFX_WideString CPDFSDK_Widget::GetAlternateName() const {
1485   CPDF_FormField* pFormField = GetFormField();
1486   ASSERT(pFormField != NULL);
1487
1488   return pFormField->GetAlternateName();
1489 }
1490
1491 int32_t CPDFSDK_Widget::GetAppearanceAge() const {
1492   return m_nAppAge;
1493 }
1494
1495 int32_t CPDFSDK_Widget::GetValueAge() const {
1496   return m_nValueAge;
1497 }
1498
1499 FX_BOOL CPDFSDK_Widget::HitTest(FX_FLOAT pageX, FX_FLOAT pageY) {
1500   CPDF_Annot* pAnnot = GetPDFAnnot();
1501   CFX_FloatRect annotRect;
1502   pAnnot->GetRect(annotRect);
1503   if (annotRect.Contains(pageX, pageY)) {
1504     if (!IsVisible())
1505       return FALSE;
1506
1507     int nFieldFlags = GetFieldFlags();
1508     if ((nFieldFlags & FIELDFLAG_READONLY) == FIELDFLAG_READONLY)
1509       return FALSE;
1510
1511     return TRUE;
1512   }
1513   return FALSE;
1514 }
1515
1516 CPDFSDK_InterForm::CPDFSDK_InterForm(CPDFSDK_Document* pDocument)
1517     : m_pDocument(pDocument),
1518       m_pInterForm(NULL),
1519       m_bCalculate(TRUE),
1520       m_bBusy(FALSE) {
1521   ASSERT(m_pDocument != NULL);
1522   m_pInterForm = new CPDF_InterForm(m_pDocument->GetDocument(), FALSE);
1523   ASSERT(m_pInterForm != NULL);
1524   m_pInterForm->SetFormNotify(this);
1525
1526   for (int i = 0; i < 6; i++)
1527     m_bNeedHightlight[i] = FALSE;
1528   m_iHighlightAlpha = 0;
1529 }
1530
1531 CPDFSDK_InterForm::~CPDFSDK_InterForm() {
1532   delete m_pInterForm;
1533   m_pInterForm = nullptr;
1534   m_Map.clear();
1535 }
1536
1537 FX_BOOL CPDFSDK_InterForm::HighlightWidgets() {
1538   return FALSE;
1539 }
1540
1541 CPDFSDK_Widget* CPDFSDK_InterForm::GetSibling(CPDFSDK_Widget* pWidget,
1542                                               FX_BOOL bNext) const {
1543   nonstd::unique_ptr<CBA_AnnotIterator> pIterator(
1544       new CBA_AnnotIterator(pWidget->GetPageView(), "Widget", ""));
1545
1546   if (bNext) {
1547     return (CPDFSDK_Widget*)pIterator->GetNextAnnot(pWidget);
1548   }
1549   return (CPDFSDK_Widget*)pIterator->GetPrevAnnot(pWidget);
1550 }
1551
1552 CPDFSDK_Widget* CPDFSDK_InterForm::GetWidget(CPDF_FormControl* pControl) const {
1553   if (!pControl || !m_pInterForm)
1554     return nullptr;
1555
1556   CPDFSDK_Widget* pWidget = nullptr;
1557   const auto it = m_Map.find(pControl);
1558   if (it != m_Map.end())
1559     pWidget = it->second;
1560
1561   if (pWidget)
1562     return pWidget;
1563
1564   CPDF_Dictionary* pControlDict = pControl->GetWidget();
1565   CPDF_Document* pDocument = m_pDocument->GetDocument();
1566   CPDFSDK_PageView* pPage = nullptr;
1567
1568   if (CPDF_Dictionary* pPageDict = pControlDict->GetDict("P")) {
1569     int nPageIndex = pDocument->GetPageIndex(pPageDict->GetObjNum());
1570     if (nPageIndex >= 0) {
1571       pPage = m_pDocument->GetPageView(nPageIndex);
1572     }
1573   }
1574
1575   if (!pPage) {
1576     int nPageIndex = GetPageIndexByAnnotDict(pDocument, pControlDict);
1577     if (nPageIndex >= 0) {
1578       pPage = m_pDocument->GetPageView(nPageIndex);
1579     }
1580   }
1581
1582   if (!pPage)
1583     return nullptr;
1584   return (CPDFSDK_Widget*)pPage->GetAnnotByDict(pControlDict);
1585 }
1586
1587 void CPDFSDK_InterForm::GetWidgets(const CFX_WideString& sFieldName,
1588                                    CFX_PtrArray& widgets) {
1589   ASSERT(m_pInterForm != NULL);
1590
1591   for (int i = 0, sz = m_pInterForm->CountFields(sFieldName); i < sz; i++) {
1592     CPDF_FormField* pFormField = m_pInterForm->GetField(i, sFieldName);
1593     ASSERT(pFormField != NULL);
1594
1595     GetWidgets(pFormField, widgets);
1596   }
1597 }
1598
1599 void CPDFSDK_InterForm::GetWidgets(CPDF_FormField* pField,
1600                                    CFX_PtrArray& widgets) {
1601   ASSERT(pField != NULL);
1602
1603   for (int i = 0, isz = pField->CountControls(); i < isz; i++) {
1604     CPDF_FormControl* pFormCtrl = pField->GetControl(i);
1605     ASSERT(pFormCtrl != NULL);
1606
1607     CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl);
1608
1609     if (pWidget)
1610       widgets.Add(pWidget);
1611   }
1612 }
1613
1614 int CPDFSDK_InterForm::GetPageIndexByAnnotDict(
1615     CPDF_Document* pDocument,
1616     CPDF_Dictionary* pAnnotDict) const {
1617   ASSERT(pDocument != NULL);
1618   ASSERT(pAnnotDict != NULL);
1619
1620   for (int i = 0, sz = pDocument->GetPageCount(); i < sz; i++) {
1621     if (CPDF_Dictionary* pPageDict = pDocument->GetPage(i)) {
1622       if (CPDF_Array* pAnnots = pPageDict->GetArray("Annots")) {
1623         for (int j = 0, jsz = pAnnots->GetCount(); j < jsz; j++) {
1624           CPDF_Object* pDict = pAnnots->GetElementValue(j);
1625           if (pAnnotDict == pDict) {
1626             return i;
1627           }
1628         }
1629       }
1630     }
1631   }
1632
1633   return -1;
1634 }
1635
1636 void CPDFSDK_InterForm::AddMap(CPDF_FormControl* pControl,
1637                                CPDFSDK_Widget* pWidget) {
1638   m_Map[pControl] = pWidget;
1639 }
1640
1641 void CPDFSDK_InterForm::RemoveMap(CPDF_FormControl* pControl) {
1642   m_Map.erase(pControl);
1643 }
1644
1645 void CPDFSDK_InterForm::EnableCalculate(FX_BOOL bEnabled) {
1646   m_bCalculate = bEnabled;
1647 }
1648
1649 FX_BOOL CPDFSDK_InterForm::IsCalculateEnabled() const {
1650   return m_bCalculate;
1651 }
1652
1653 #ifdef _WIN32
1654 CPDF_Stream* CPDFSDK_InterForm::LoadImageFromFile(const CFX_WideString& sFile) {
1655   ASSERT(m_pDocument != NULL);
1656   CPDF_Document* pDocument = m_pDocument->GetDocument();
1657   ASSERT(pDocument != NULL);
1658
1659   CPDF_Stream* pRetStream = NULL;
1660
1661   if (CFX_DIBitmap* pBmp = CFX_WindowsDIB::LoadFromFile(sFile.c_str())) {
1662     int nWidth = pBmp->GetWidth();
1663     int nHeight = pBmp->GetHeight();
1664
1665     CPDF_Image Image(pDocument);
1666     Image.SetImage(pBmp, FALSE);
1667     CPDF_Stream* pImageStream = Image.GetStream();
1668     if (pImageStream) {
1669       if (pImageStream->GetObjNum() == 0)
1670         pDocument->AddIndirectObject(pImageStream);
1671
1672       CPDF_Dictionary* pStreamDict = new CPDF_Dictionary();
1673       pStreamDict->SetAtName("Subtype", "Form");
1674       pStreamDict->SetAtName("Name", "IMG");
1675       CPDF_Array* pMatrix = new CPDF_Array();
1676       pStreamDict->SetAt("Matrix", pMatrix);
1677       pMatrix->AddInteger(1);
1678       pMatrix->AddInteger(0);
1679       pMatrix->AddInteger(0);
1680       pMatrix->AddInteger(1);
1681       pMatrix->AddInteger(-nWidth / 2);
1682       pMatrix->AddInteger(-nHeight / 2);
1683       CPDF_Dictionary* pResource = new CPDF_Dictionary();
1684       pStreamDict->SetAt("Resources", pResource);
1685       CPDF_Dictionary* pXObject = new CPDF_Dictionary();
1686       pResource->SetAt("XObject", pXObject);
1687       pXObject->SetAtReference("Img", pDocument, pImageStream);
1688       CPDF_Array* pProcSet = new CPDF_Array();
1689       pResource->SetAt("ProcSet", pProcSet);
1690       pProcSet->AddName("PDF");
1691       pProcSet->AddName("ImageC");
1692       pStreamDict->SetAtName("Type", "XObject");
1693       CPDF_Array* pBBox = new CPDF_Array();
1694       pStreamDict->SetAt("BBox", pBBox);
1695       pBBox->AddInteger(0);
1696       pBBox->AddInteger(0);
1697       pBBox->AddInteger(nWidth);
1698       pBBox->AddInteger(nHeight);
1699       pStreamDict->SetAtInteger("FormType", 1);
1700
1701       pRetStream = new CPDF_Stream(NULL, 0, NULL);
1702       CFX_ByteString csStream;
1703       csStream.Format("q\n%d 0 0 %d 0 0 cm\n/Img Do\nQ", nWidth, nHeight);
1704       pRetStream->InitStream((uint8_t*)csStream.c_str(), csStream.GetLength(),
1705                              pStreamDict);
1706       pDocument->AddIndirectObject(pRetStream);
1707     }
1708
1709     delete pBmp;
1710   }
1711
1712   return pRetStream;
1713 }
1714 #endif
1715
1716 void CPDFSDK_InterForm::OnCalculate(CPDF_FormField* pFormField) {
1717   ASSERT(m_pDocument != NULL);
1718   CPDFDoc_Environment* pEnv = m_pDocument->GetEnv();
1719   ASSERT(pEnv);
1720   if (!pEnv->IsJSInitiated())
1721     return;
1722
1723   if (m_bBusy)
1724     return;
1725
1726   m_bBusy = TRUE;
1727
1728   if (IsCalculateEnabled()) {
1729     IJS_Runtime* pRuntime = m_pDocument->GetJsRuntime();
1730     ASSERT(pRuntime != NULL);
1731
1732     pRuntime->SetReaderDocument(m_pDocument);
1733
1734     int nSize = m_pInterForm->CountFieldsInCalculationOrder();
1735     for (int i = 0; i < nSize; i++) {
1736       if (CPDF_FormField* pField =
1737               m_pInterForm->GetFieldInCalculationOrder(i)) {
1738         int nType = pField->GetFieldType();
1739         if (nType == FIELDTYPE_COMBOBOX || nType == FIELDTYPE_TEXTFIELD) {
1740           CPDF_AAction aAction = pField->GetAdditionalAction();
1741           if (aAction && aAction.ActionExist(CPDF_AAction::Calculate)) {
1742             CPDF_Action action = aAction.GetAction(CPDF_AAction::Calculate);
1743             if (action) {
1744               CFX_WideString csJS = action.GetJavaScript();
1745               if (!csJS.IsEmpty()) {
1746                 IJS_Context* pContext = pRuntime->NewContext();
1747                 ASSERT(pContext != NULL);
1748
1749                 CFX_WideString sOldValue = pField->GetValue();
1750                 CFX_WideString sValue = sOldValue;
1751                 FX_BOOL bRC = TRUE;
1752                 pContext->OnField_Calculate(pFormField, pField, sValue, bRC);
1753
1754                 CFX_WideString sInfo;
1755                 FX_BOOL bRet = pContext->RunScript(csJS, &sInfo);
1756                 pRuntime->ReleaseContext(pContext);
1757
1758                 if (bRet) {
1759                   if (bRC) {
1760                     if (sValue.Compare(sOldValue) != 0)
1761                       pField->SetValue(sValue, TRUE);
1762                   }
1763                 }
1764               }
1765             }
1766           }
1767         }
1768       }
1769     }
1770   }
1771
1772   m_bBusy = FALSE;
1773 }
1774
1775 CFX_WideString CPDFSDK_InterForm::OnFormat(CPDF_FormField* pFormField,
1776                                            FX_BOOL& bFormated) {
1777   ASSERT(m_pDocument != NULL);
1778   ASSERT(pFormField != NULL);
1779
1780   CFX_WideString sValue = pFormField->GetValue();
1781   CPDFDoc_Environment* pEnv = m_pDocument->GetEnv();
1782   ASSERT(pEnv);
1783   if (!pEnv->IsJSInitiated()) {
1784     bFormated = FALSE;
1785     return sValue;
1786   }
1787
1788   IJS_Runtime* pRuntime = m_pDocument->GetJsRuntime();
1789   ASSERT(pRuntime != NULL);
1790
1791   pRuntime->SetReaderDocument(m_pDocument);
1792
1793   if (pFormField->GetFieldType() == FIELDTYPE_COMBOBOX) {
1794     if (pFormField->CountSelectedItems() > 0) {
1795       int index = pFormField->GetSelectedIndex(0);
1796       if (index >= 0)
1797         sValue = pFormField->GetOptionLabel(index);
1798     }
1799   }
1800
1801   bFormated = FALSE;
1802
1803   CPDF_AAction aAction = pFormField->GetAdditionalAction();
1804   if (aAction != NULL && aAction.ActionExist(CPDF_AAction::Format)) {
1805     CPDF_Action action = aAction.GetAction(CPDF_AAction::Format);
1806     if (action) {
1807       CFX_WideString script = action.GetJavaScript();
1808       if (!script.IsEmpty()) {
1809         CFX_WideString Value = sValue;
1810
1811         IJS_Context* pContext = pRuntime->NewContext();
1812         ASSERT(pContext != NULL);
1813
1814         pContext->OnField_Format(pFormField, Value, TRUE);
1815
1816         CFX_WideString sInfo;
1817         FX_BOOL bRet = pContext->RunScript(script, &sInfo);
1818         pRuntime->ReleaseContext(pContext);
1819
1820         if (bRet) {
1821           sValue = Value;
1822           bFormated = TRUE;
1823         }
1824       }
1825     }
1826   }
1827
1828   return sValue;
1829 }
1830
1831 void CPDFSDK_InterForm::ResetFieldAppearance(CPDF_FormField* pFormField,
1832                                              const FX_WCHAR* sValue,
1833                                              FX_BOOL bValueChanged) {
1834   ASSERT(pFormField != NULL);
1835
1836   for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
1837     CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
1838     ASSERT(pFormCtrl != NULL);
1839
1840     ASSERT(m_pInterForm != NULL);
1841     if (CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl))
1842       pWidget->ResetAppearance(sValue, bValueChanged);
1843   }
1844 }
1845
1846 void CPDFSDK_InterForm::UpdateField(CPDF_FormField* pFormField) {
1847   ASSERT(pFormField != NULL);
1848
1849   for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
1850     CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
1851     ASSERT(pFormCtrl != NULL);
1852
1853     if (CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl)) {
1854       CPDFDoc_Environment* pEnv = m_pDocument->GetEnv();
1855       CFFL_IFormFiller* pIFormFiller = pEnv->GetIFormFiller();
1856
1857       CPDF_Page* pPage = pWidget->GetPDFPage();
1858       CPDFSDK_PageView* pPageView = m_pDocument->GetPageView(pPage, FALSE);
1859
1860       FX_RECT rcBBox = pIFormFiller->GetViewBBox(pPageView, pWidget);
1861
1862       pEnv->FFI_Invalidate(pPage, rcBBox.left, rcBBox.top, rcBBox.right,
1863                            rcBBox.bottom);
1864     }
1865   }
1866 }
1867
1868 void CPDFSDK_InterForm::OnKeyStrokeCommit(CPDF_FormField* pFormField,
1869                                           CFX_WideString& csValue,
1870                                           FX_BOOL& bRC) {
1871   ASSERT(pFormField != NULL);
1872
1873   CPDF_AAction aAction = pFormField->GetAdditionalAction();
1874   if (aAction != NULL && aAction.ActionExist(CPDF_AAction::KeyStroke)) {
1875     CPDF_Action action = aAction.GetAction(CPDF_AAction::KeyStroke);
1876     if (action) {
1877       ASSERT(m_pDocument != NULL);
1878       CPDFDoc_Environment* pEnv = m_pDocument->GetEnv();
1879       ASSERT(pEnv != NULL);
1880
1881       CPDFSDK_ActionHandler* pActionHandler = pEnv->GetActionHander();
1882       ASSERT(pActionHandler != NULL);
1883
1884       PDFSDK_FieldAction fa;
1885       fa.bModifier = pEnv->FFI_IsCTRLKeyDown(0);
1886       fa.bShift = pEnv->FFI_IsSHIFTKeyDown(0);
1887       fa.sValue = csValue;
1888
1889       pActionHandler->DoAction_FieldJavaScript(action, CPDF_AAction::KeyStroke,
1890                                                m_pDocument, pFormField, fa);
1891       bRC = fa.bRC;
1892     }
1893   }
1894 }
1895
1896 void CPDFSDK_InterForm::OnValidate(CPDF_FormField* pFormField,
1897                                    CFX_WideString& csValue,
1898                                    FX_BOOL& bRC) {
1899   ASSERT(pFormField != NULL);
1900
1901   CPDF_AAction aAction = pFormField->GetAdditionalAction();
1902   if (aAction != NULL && aAction.ActionExist(CPDF_AAction::Validate)) {
1903     CPDF_Action action = aAction.GetAction(CPDF_AAction::Validate);
1904     if (action) {
1905       ASSERT(m_pDocument != NULL);
1906       CPDFDoc_Environment* pEnv = m_pDocument->GetEnv();
1907       ASSERT(pEnv != NULL);
1908
1909       CPDFSDK_ActionHandler* pActionHandler = pEnv->GetActionHander();
1910       ASSERT(pActionHandler != NULL);
1911
1912       PDFSDK_FieldAction fa;
1913       fa.bModifier = pEnv->FFI_IsCTRLKeyDown(0);
1914       fa.bShift = pEnv->FFI_IsSHIFTKeyDown(0);
1915       fa.sValue = csValue;
1916
1917       pActionHandler->DoAction_FieldJavaScript(action, CPDF_AAction::Validate,
1918                                                m_pDocument, pFormField, fa);
1919       bRC = fa.bRC;
1920     }
1921   }
1922 }
1923
1924 /* ----------------------------- action ----------------------------- */
1925
1926 FX_BOOL CPDFSDK_InterForm::DoAction_Hide(const CPDF_Action& action) {
1927   ASSERT(action);
1928
1929   CPDF_ActionFields af = action.GetWidgets();
1930   CFX_PtrArray fieldObjects;
1931   af.GetAllFields(fieldObjects);
1932   CFX_PtrArray widgetArray;
1933   CFX_PtrArray fields;
1934   GetFieldFromObjects(fieldObjects, fields);
1935
1936   FX_BOOL bHide = action.GetHideStatus();
1937
1938   FX_BOOL bChanged = FALSE;
1939
1940   for (int i = 0, sz = fields.GetSize(); i < sz; i++) {
1941     CPDF_FormField* pField = (CPDF_FormField*)fields[i];
1942     ASSERT(pField != NULL);
1943
1944     for (int j = 0, jsz = pField->CountControls(); j < jsz; j++) {
1945       CPDF_FormControl* pControl = pField->GetControl(j);
1946       ASSERT(pControl != NULL);
1947
1948       if (CPDFSDK_Widget* pWidget = GetWidget(pControl)) {
1949         int nFlags = pWidget->GetFlags();
1950         if (bHide) {
1951           nFlags &= (~ANNOTFLAG_INVISIBLE);
1952           nFlags &= (~ANNOTFLAG_NOVIEW);
1953           nFlags |= (ANNOTFLAG_HIDDEN);
1954         } else {
1955           nFlags &= (~ANNOTFLAG_INVISIBLE);
1956           nFlags &= (~ANNOTFLAG_HIDDEN);
1957           nFlags &= (~ANNOTFLAG_NOVIEW);
1958         }
1959         pWidget->SetFlags(nFlags);
1960
1961         CPDFSDK_PageView* pPageView = pWidget->GetPageView();
1962         ASSERT(pPageView != NULL);
1963
1964         pPageView->UpdateView(pWidget);
1965
1966         bChanged = TRUE;
1967       }
1968     }
1969   }
1970
1971   return bChanged;
1972 }
1973
1974 FX_BOOL CPDFSDK_InterForm::DoAction_SubmitForm(const CPDF_Action& action) {
1975   ASSERT(m_pInterForm != NULL);
1976   CFX_WideString sDestination = action.GetFilePath();
1977   if (sDestination.IsEmpty())
1978     return FALSE;
1979
1980   CPDF_Dictionary* pActionDict = action.GetDict();
1981   if (pActionDict->KeyExist("Fields")) {
1982     CPDF_ActionFields af = action.GetWidgets();
1983     FX_DWORD dwFlags = action.GetFlags();
1984     CFX_PtrArray fieldObjects;
1985     af.GetAllFields(fieldObjects);
1986
1987     CFX_PtrArray fields;
1988     GetFieldFromObjects(fieldObjects, fields);
1989     if (fields.GetSize() != 0) {
1990       FX_BOOL bIncludeOrExclude = !(dwFlags & 0x01);
1991       if (m_pInterForm->CheckRequiredFields(&fields, bIncludeOrExclude))
1992         return FALSE;
1993
1994       return SubmitFields(sDestination, fields, bIncludeOrExclude, FALSE);
1995     }
1996   }
1997   if (m_pInterForm->CheckRequiredFields())
1998     return FALSE;
1999
2000   return SubmitForm(sDestination, FALSE);
2001 }
2002
2003 FX_BOOL CPDFSDK_InterForm::SubmitFields(const CFX_WideString& csDestination,
2004                                         const CFX_PtrArray& fields,
2005                                         FX_BOOL bIncludeOrExclude,
2006                                         FX_BOOL bUrlEncoded) {
2007   CPDFDoc_Environment* pEnv = m_pDocument->GetEnv();
2008   ASSERT(pEnv != NULL);
2009
2010   CFX_ByteTextBuf textBuf;
2011   ExportFieldsToFDFTextBuf(fields, bIncludeOrExclude, textBuf);
2012
2013   uint8_t* pBuffer = textBuf.GetBuffer();
2014   FX_STRSIZE nBufSize = textBuf.GetLength();
2015
2016   if (bUrlEncoded) {
2017     if (!FDFToURLEncodedData(pBuffer, nBufSize))
2018       return FALSE;
2019   }
2020
2021   pEnv->JS_docSubmitForm(pBuffer, nBufSize, csDestination.c_str());
2022
2023   return TRUE;
2024 }
2025
2026 FX_BOOL CPDFSDK_InterForm::FDFToURLEncodedData(CFX_WideString csFDFFile,
2027                                                CFX_WideString csTxtFile) {
2028   return TRUE;
2029 }
2030
2031 FX_BOOL CPDFSDK_InterForm::FDFToURLEncodedData(uint8_t*& pBuf,
2032                                                FX_STRSIZE& nBufSize) {
2033   CFDF_Document* pFDF = CFDF_Document::ParseMemory(pBuf, nBufSize);
2034   if (pFDF) {
2035     CPDF_Dictionary* pMainDict = pFDF->GetRoot()->GetDict("FDF");
2036     if (pMainDict == NULL)
2037       return FALSE;
2038
2039     // Get fields
2040     CPDF_Array* pFields = pMainDict->GetArray("Fields");
2041     if (pFields == NULL)
2042       return FALSE;
2043
2044     CFX_ByteTextBuf fdfEncodedData;
2045
2046     for (FX_DWORD i = 0; i < pFields->GetCount(); i++) {
2047       CPDF_Dictionary* pField = pFields->GetDict(i);
2048       if (pField == NULL)
2049         continue;
2050       CFX_WideString name;
2051       name = pField->GetUnicodeText("T");
2052       CFX_ByteString name_b = CFX_ByteString::FromUnicode(name);
2053       CFX_ByteString csBValue = pField->GetString("V");
2054       CFX_WideString csWValue = PDF_DecodeText(csBValue);
2055       CFX_ByteString csValue_b = CFX_ByteString::FromUnicode(csWValue);
2056
2057       fdfEncodedData = fdfEncodedData << name_b.GetBuffer(name_b.GetLength());
2058       name_b.ReleaseBuffer();
2059       fdfEncodedData = fdfEncodedData << "=";
2060       fdfEncodedData = fdfEncodedData
2061                        << csValue_b.GetBuffer(csValue_b.GetLength());
2062       csValue_b.ReleaseBuffer();
2063       if (i != pFields->GetCount() - 1)
2064         fdfEncodedData = fdfEncodedData << "&";
2065     }
2066
2067     nBufSize = fdfEncodedData.GetLength();
2068     pBuf = FX_Alloc(uint8_t, nBufSize);
2069     FXSYS_memcpy(pBuf, fdfEncodedData.GetBuffer(), nBufSize);
2070   }
2071   return TRUE;
2072 }
2073
2074 FX_BOOL CPDFSDK_InterForm::ExportFieldsToFDFTextBuf(const CFX_PtrArray& fields,
2075                                                     FX_BOOL bIncludeOrExclude,
2076                                                     CFX_ByteTextBuf& textBuf) {
2077   ASSERT(m_pDocument != NULL);
2078   ASSERT(m_pInterForm != NULL);
2079
2080   CFDF_Document* pFDF = m_pInterForm->ExportToFDF(
2081       m_pDocument->GetPath(), (CFX_PtrArray&)fields, bIncludeOrExclude);
2082   if (!pFDF)
2083     return FALSE;
2084   FX_BOOL bRet = pFDF->WriteBuf(textBuf);
2085   delete pFDF;
2086
2087   return bRet;
2088 }
2089
2090 CFX_WideString CPDFSDK_InterForm::GetTemporaryFileName(
2091     const CFX_WideString& sFileExt) {
2092   CFX_WideString sFileName;
2093   return L"";
2094 }
2095
2096 FX_BOOL CPDFSDK_InterForm::SubmitForm(const CFX_WideString& sDestination,
2097                                       FX_BOOL bUrlEncoded) {
2098   if (sDestination.IsEmpty())
2099     return FALSE;
2100
2101   CPDFDoc_Environment* pEnv = m_pDocument->GetEnv();
2102   ASSERT(pEnv != NULL);
2103
2104   if (NULL == m_pDocument)
2105     return FALSE;
2106   CFX_WideString wsPDFFilePath = m_pDocument->GetPath();
2107
2108   if (NULL == m_pInterForm)
2109     return FALSE;
2110   CFDF_Document* pFDFDoc = m_pInterForm->ExportToFDF(wsPDFFilePath);
2111   if (NULL == pFDFDoc)
2112     return FALSE;
2113
2114   CFX_ByteTextBuf FdfBuffer;
2115   FX_BOOL bRet = pFDFDoc->WriteBuf(FdfBuffer);
2116   delete pFDFDoc;
2117   if (!bRet)
2118     return FALSE;
2119
2120   uint8_t* pBuffer = FdfBuffer.GetBuffer();
2121   FX_STRSIZE nBufSize = FdfBuffer.GetLength();
2122
2123   if (bUrlEncoded) {
2124     if (!FDFToURLEncodedData(pBuffer, nBufSize))
2125       return FALSE;
2126   }
2127
2128   pEnv->JS_docSubmitForm(pBuffer, nBufSize, sDestination.c_str());
2129
2130   if (bUrlEncoded) {
2131     FX_Free(pBuffer);
2132     pBuffer = NULL;
2133   }
2134
2135   return TRUE;
2136 }
2137
2138 FX_BOOL CPDFSDK_InterForm::ExportFormToFDFTextBuf(CFX_ByteTextBuf& textBuf) {
2139   ASSERT(m_pInterForm != NULL);
2140   ASSERT(m_pDocument != NULL);
2141
2142   CFDF_Document* pFDF = m_pInterForm->ExportToFDF(m_pDocument->GetPath());
2143   if (!pFDF)
2144     return FALSE;
2145
2146   FX_BOOL bRet = pFDF->WriteBuf(textBuf);
2147   delete pFDF;
2148
2149   return bRet;
2150 }
2151
2152 FX_BOOL CPDFSDK_InterForm::DoAction_ResetForm(const CPDF_Action& action) {
2153   ASSERT(action);
2154
2155   CPDF_Dictionary* pActionDict = action.GetDict();
2156   if (pActionDict->KeyExist("Fields")) {
2157     CPDF_ActionFields af = action.GetWidgets();
2158     FX_DWORD dwFlags = action.GetFlags();
2159
2160     CFX_PtrArray fieldObjects;
2161     af.GetAllFields(fieldObjects);
2162     CFX_PtrArray fields;
2163     GetFieldFromObjects(fieldObjects, fields);
2164     return m_pInterForm->ResetForm(fields, !(dwFlags & 0x01), TRUE);
2165   }
2166
2167   return m_pInterForm->ResetForm(TRUE);
2168 }
2169
2170 FX_BOOL CPDFSDK_InterForm::DoAction_ImportData(const CPDF_Action& action) {
2171   return FALSE;
2172 }
2173
2174 void CPDFSDK_InterForm::GetFieldFromObjects(const CFX_PtrArray& objects,
2175                                             CFX_PtrArray& fields) {
2176   ASSERT(m_pInterForm != NULL);
2177
2178   int iCount = objects.GetSize();
2179   for (int i = 0; i < iCount; i++) {
2180     CPDF_Object* pObject = static_cast<CPDF_Object*>(objects[i]);
2181     if (!pObject)
2182       continue;
2183
2184     if (pObject->IsString()) {
2185       CFX_WideString csName = pObject->GetUnicodeText();
2186       CPDF_FormField* pField = m_pInterForm->GetField(0, csName);
2187       if (pField)
2188         fields.Add(pField);
2189     } else if (pObject->IsDictionary()) {
2190       if (m_pInterForm->IsValidFormField(pObject))
2191         fields.Add(pObject);
2192     }
2193   }
2194 }
2195
2196 /* ----------------------------- CPDF_FormNotify -----------------------------
2197  */
2198
2199 int CPDFSDK_InterForm::BeforeValueChange(const CPDF_FormField* pField,
2200                                          CFX_WideString& csValue) {
2201   CPDF_FormField* pFormField = (CPDF_FormField*)pField;
2202   int nType = pFormField->GetFieldType();
2203   if (nType == FIELDTYPE_COMBOBOX || nType == FIELDTYPE_TEXTFIELD) {
2204     FX_BOOL bRC = TRUE;
2205     OnKeyStrokeCommit(pFormField, csValue, bRC);
2206     if (bRC) {
2207       OnValidate(pFormField, csValue, bRC);
2208       return bRC ? 1 : -1;
2209     }
2210     return -1;
2211   }
2212   return 0;
2213 }
2214
2215 int CPDFSDK_InterForm::AfterValueChange(const CPDF_FormField* pField) {
2216   CPDF_FormField* pFormField = (CPDF_FormField*)pField;
2217   int nType = pFormField->GetFieldType();
2218   if (nType == FIELDTYPE_COMBOBOX || nType == FIELDTYPE_TEXTFIELD) {
2219     OnCalculate(pFormField);
2220     FX_BOOL bFormated = FALSE;
2221     CFX_WideString sValue = OnFormat(pFormField, bFormated);
2222     if (bFormated)
2223       ResetFieldAppearance(pFormField, sValue.c_str(), TRUE);
2224     else
2225       ResetFieldAppearance(pFormField, NULL, TRUE);
2226     UpdateField(pFormField);
2227   }
2228   return 0;
2229 }
2230
2231 int CPDFSDK_InterForm::BeforeSelectionChange(const CPDF_FormField* pField,
2232                                              CFX_WideString& csValue) {
2233   CPDF_FormField* pFormField = (CPDF_FormField*)pField;
2234   if (pFormField->GetFieldType() != FIELDTYPE_LISTBOX)
2235     return 0;
2236
2237   FX_BOOL bRC = TRUE;
2238   OnKeyStrokeCommit(pFormField, csValue, bRC);
2239   if (!bRC)
2240     return -1;
2241
2242   OnValidate(pFormField, csValue, bRC);
2243   if (!bRC)
2244     return -1;
2245
2246   return 1;
2247 }
2248
2249 int CPDFSDK_InterForm::AfterSelectionChange(const CPDF_FormField* pField) {
2250   CPDF_FormField* pFormField = (CPDF_FormField*)pField;
2251   if (pFormField->GetFieldType() == FIELDTYPE_LISTBOX) {
2252     OnCalculate(pFormField);
2253     ResetFieldAppearance(pFormField, NULL, TRUE);
2254     UpdateField(pFormField);
2255   }
2256   return 0;
2257 }
2258
2259 int CPDFSDK_InterForm::AfterCheckedStatusChange(
2260     const CPDF_FormField* pField,
2261     const CFX_ByteArray& statusArray) {
2262   CPDF_FormField* pFormField = (CPDF_FormField*)pField;
2263   int nType = pFormField->GetFieldType();
2264   if (nType == FIELDTYPE_CHECKBOX || nType == FIELDTYPE_RADIOBUTTON) {
2265     OnCalculate(pFormField);
2266     UpdateField(pFormField);
2267   }
2268   return 0;
2269 }
2270
2271 int CPDFSDK_InterForm::BeforeFormReset(const CPDF_InterForm* pForm) {
2272   return 0;
2273 }
2274
2275 int CPDFSDK_InterForm::AfterFormReset(const CPDF_InterForm* pForm) {
2276   OnCalculate(nullptr);
2277   return 0;
2278 }
2279
2280 int CPDFSDK_InterForm::BeforeFormImportData(const CPDF_InterForm* pForm) {
2281   return 0;
2282 }
2283
2284 int CPDFSDK_InterForm::AfterFormImportData(const CPDF_InterForm* pForm) {
2285   OnCalculate(nullptr);
2286   return 0;
2287 }
2288
2289 FX_BOOL CPDFSDK_InterForm::IsNeedHighLight(int nFieldType) {
2290   if (nFieldType < 1 || nFieldType > 6)
2291     return FALSE;
2292   return m_bNeedHightlight[nFieldType - 1];
2293 }
2294
2295 void CPDFSDK_InterForm::RemoveAllHighLight() {
2296   memset((void*)m_bNeedHightlight, 0, 6 * sizeof(FX_BOOL));
2297 }
2298 void CPDFSDK_InterForm::SetHighlightColor(FX_COLORREF clr, int nFieldType) {
2299   if (nFieldType < 0 || nFieldType > 6)
2300     return;
2301   switch (nFieldType) {
2302     case 0: {
2303       for (int i = 0; i < 6; i++) {
2304         m_aHighlightColor[i] = clr;
2305         m_bNeedHightlight[i] = TRUE;
2306       }
2307       break;
2308     }
2309     default: {
2310       m_aHighlightColor[nFieldType - 1] = clr;
2311       m_bNeedHightlight[nFieldType - 1] = TRUE;
2312       break;
2313     }
2314   }
2315 }
2316
2317 FX_COLORREF CPDFSDK_InterForm::GetHighlightColor(int nFieldType) {
2318   if (nFieldType < 0 || nFieldType > 6)
2319     return FXSYS_RGB(255, 255, 255);
2320   if (nFieldType == 0)
2321     return m_aHighlightColor[0];
2322   return m_aHighlightColor[nFieldType - 1];
2323 }
2324
2325 /* ------------------------- CBA_AnnotIterator ------------------------- */
2326
2327 CBA_AnnotIterator::CBA_AnnotIterator(CPDFSDK_PageView* pPageView,
2328                                      const CFX_ByteString& sType,
2329                                      const CFX_ByteString& sSubType)
2330     : m_pPageView(pPageView),
2331       m_sType(sType),
2332       m_sSubType(sSubType),
2333       m_nTabs(BAI_STRUCTURE) {
2334   ASSERT(m_pPageView != NULL);
2335
2336   CPDF_Page* pPDFPage = m_pPageView->GetPDFPage();
2337   ASSERT(pPDFPage != NULL);
2338   ASSERT(pPDFPage->m_pFormDict != NULL);
2339
2340   CFX_ByteString sTabs = pPDFPage->m_pFormDict->GetString("Tabs");
2341
2342   if (sTabs == "R") {
2343     m_nTabs = BAI_ROW;
2344   } else if (sTabs == "C") {
2345     m_nTabs = BAI_COLUMN;
2346   } else {
2347     m_nTabs = BAI_STRUCTURE;
2348   }
2349
2350   GenerateResults();
2351 }
2352
2353 CBA_AnnotIterator::~CBA_AnnotIterator() {
2354   m_Annots.RemoveAll();
2355 }
2356
2357 CPDFSDK_Annot* CBA_AnnotIterator::GetFirstAnnot() {
2358   if (m_Annots.GetSize() > 0)
2359     return m_Annots[0];
2360
2361   return NULL;
2362 }
2363
2364 CPDFSDK_Annot* CBA_AnnotIterator::GetLastAnnot() {
2365   if (m_Annots.GetSize() > 0)
2366     return m_Annots[m_Annots.GetSize() - 1];
2367
2368   return NULL;
2369 }
2370
2371 CPDFSDK_Annot* CBA_AnnotIterator::GetNextAnnot(CPDFSDK_Annot* pAnnot) {
2372   for (int i = 0, sz = m_Annots.GetSize(); i < sz; ++i) {
2373     if (m_Annots[i] == pAnnot)
2374       return (i + 1 < sz) ? m_Annots[i + 1] : m_Annots[0];
2375   }
2376   return NULL;
2377 }
2378
2379 CPDFSDK_Annot* CBA_AnnotIterator::GetPrevAnnot(CPDFSDK_Annot* pAnnot) {
2380   for (int i = 0, sz = m_Annots.GetSize(); i < sz; ++i) {
2381     if (m_Annots[i] == pAnnot)
2382       return (i - 1 >= 0) ? m_Annots[i - 1] : m_Annots[sz - 1];
2383   }
2384   return NULL;
2385 }
2386
2387 int CBA_AnnotIterator::CompareByLeft(CPDFSDK_Annot* p1, CPDFSDK_Annot* p2) {
2388   ASSERT(p1);
2389   ASSERT(p2);
2390
2391   CPDF_Rect rcAnnot1 = GetAnnotRect(p1);
2392   CPDF_Rect rcAnnot2 = GetAnnotRect(p2);
2393
2394   if (rcAnnot1.left < rcAnnot2.left)
2395     return -1;
2396   if (rcAnnot1.left > rcAnnot2.left)
2397     return 1;
2398   return 0;
2399 }
2400
2401 int CBA_AnnotIterator::CompareByTop(CPDFSDK_Annot* p1, CPDFSDK_Annot* p2) {
2402   ASSERT(p1 != NULL);
2403   ASSERT(p2 != NULL);
2404
2405   CPDF_Rect rcAnnot1 = GetAnnotRect(p1);
2406   CPDF_Rect rcAnnot2 = GetAnnotRect(p2);
2407
2408   if (rcAnnot1.top < rcAnnot2.top)
2409     return -1;
2410   if (rcAnnot1.top > rcAnnot2.top)
2411     return 1;
2412   return 0;
2413 }
2414
2415 void CBA_AnnotIterator::GenerateResults() {
2416   switch (m_nTabs) {
2417     case BAI_STRUCTURE: {
2418       for (size_t i = 0; i < m_pPageView->CountAnnots(); ++i) {
2419         CPDFSDK_Annot* pAnnot = m_pPageView->GetAnnot(i);
2420         if (pAnnot->GetType() == m_sType && pAnnot->GetSubType() == m_sSubType)
2421           m_Annots.Add(pAnnot);
2422       }
2423       break;
2424     }
2425     case BAI_ROW: {
2426       CPDFSDK_SortAnnots sa;
2427       for (size_t i = 0; i < m_pPageView->CountAnnots(); ++i) {
2428         CPDFSDK_Annot* pAnnot = m_pPageView->GetAnnot(i);
2429         if (pAnnot->GetType() == m_sType && pAnnot->GetSubType() == m_sSubType)
2430           sa.Add(pAnnot);
2431       }
2432
2433       if (sa.GetSize() > 0)
2434         sa.Sort(CBA_AnnotIterator::CompareByLeft);
2435
2436       while (sa.GetSize() > 0) {
2437         int nLeftTopIndex = -1;
2438         FX_FLOAT fTop = 0.0f;
2439
2440         for (int i = sa.GetSize() - 1; i >= 0; i--) {
2441           CPDFSDK_Annot* pAnnot = sa.GetAt(i);
2442           ASSERT(pAnnot);
2443
2444           CPDF_Rect rcAnnot = GetAnnotRect(pAnnot);
2445
2446           if (rcAnnot.top > fTop) {
2447             nLeftTopIndex = i;
2448             fTop = rcAnnot.top;
2449           }
2450         }
2451
2452         if (nLeftTopIndex >= 0) {
2453           CPDFSDK_Annot* pLeftTopAnnot = sa.GetAt(nLeftTopIndex);
2454           ASSERT(pLeftTopAnnot);
2455
2456           CPDF_Rect rcLeftTop = GetAnnotRect(pLeftTopAnnot);
2457
2458           m_Annots.Add(pLeftTopAnnot);
2459           sa.RemoveAt(nLeftTopIndex);
2460
2461           CFX_ArrayTemplate<int> aSelect;
2462
2463           for (int i = 0, sz = sa.GetSize(); i < sz; ++i) {
2464             CPDFSDK_Annot* pAnnot = sa.GetAt(i);
2465             ASSERT(pAnnot);
2466
2467             CPDF_Rect rcAnnot = GetAnnotRect(pAnnot);
2468             FX_FLOAT fCenterY = (rcAnnot.top + rcAnnot.bottom) / 2.0f;
2469             if (fCenterY > rcLeftTop.bottom && fCenterY < rcLeftTop.top)
2470               aSelect.Add(i);
2471           }
2472
2473           for (int i = 0, sz = aSelect.GetSize(); i < sz; ++i)
2474             m_Annots.Add(sa[aSelect[i]]);
2475
2476           for (int i = aSelect.GetSize() - 1; i >= 0; --i)
2477               sa.RemoveAt(aSelect[i]);
2478
2479           aSelect.RemoveAll();
2480         }
2481       }
2482       sa.RemoveAll();
2483       break;
2484     }
2485     case BAI_COLUMN: {
2486       CPDFSDK_SortAnnots sa;
2487       for (size_t i = 0; i < m_pPageView->CountAnnots(); ++i) {
2488         CPDFSDK_Annot* pAnnot = m_pPageView->GetAnnot(i);
2489         if (pAnnot->GetType() == m_sType && pAnnot->GetSubType() == m_sSubType)
2490           sa.Add(pAnnot);
2491       }
2492
2493       if (sa.GetSize() > 0)
2494         sa.Sort(CBA_AnnotIterator::CompareByTop, FALSE);
2495
2496       while (sa.GetSize() > 0) {
2497         int nLeftTopIndex = -1;
2498         FX_FLOAT fLeft = -1.0f;
2499
2500         for (int i = sa.GetSize() - 1; i >= 0; --i) {
2501           CPDFSDK_Annot* pAnnot = sa.GetAt(i);
2502           ASSERT(pAnnot);
2503
2504           CPDF_Rect rcAnnot = GetAnnotRect(pAnnot);
2505
2506           if (fLeft < 0) {
2507             nLeftTopIndex = 0;
2508             fLeft = rcAnnot.left;
2509           } else if (rcAnnot.left < fLeft) {
2510             nLeftTopIndex = i;
2511             fLeft = rcAnnot.left;
2512           }
2513         }
2514
2515         if (nLeftTopIndex >= 0) {
2516           CPDFSDK_Annot* pLeftTopAnnot = sa.GetAt(nLeftTopIndex);
2517           ASSERT(pLeftTopAnnot);
2518
2519           CPDF_Rect rcLeftTop = GetAnnotRect(pLeftTopAnnot);
2520
2521           m_Annots.Add(pLeftTopAnnot);
2522           sa.RemoveAt(nLeftTopIndex);
2523
2524           CFX_ArrayTemplate<int> aSelect;
2525           for (int i = 0, sz = sa.GetSize(); i < sz; ++i) {
2526             CPDFSDK_Annot* pAnnot = sa.GetAt(i);
2527             ASSERT(pAnnot);
2528
2529             CPDF_Rect rcAnnot = GetAnnotRect(pAnnot);
2530             FX_FLOAT fCenterX = (rcAnnot.left + rcAnnot.right) / 2.0f;
2531             if (fCenterX > rcLeftTop.left && fCenterX < rcLeftTop.right)
2532               aSelect.Add(i);
2533           }
2534
2535           for (int i = 0, sz = aSelect.GetSize(); i < sz; ++i)
2536             m_Annots.Add(sa[aSelect[i]]);
2537
2538           for (int i = aSelect.GetSize() - 1; i >= 0; --i)
2539             sa.RemoveAt(aSelect[i]);
2540
2541           aSelect.RemoveAll();
2542         }
2543       }
2544       sa.RemoveAll();
2545       break;
2546     }
2547   }
2548 }
2549
2550 CPDF_Rect CBA_AnnotIterator::GetAnnotRect(CPDFSDK_Annot* pAnnot) {
2551   CPDF_Rect rcAnnot;
2552   pAnnot->GetPDFAnnot()->GetRect(rcAnnot);
2553   return rcAnnot;
2554 }