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