Merge to XFA: Cleanup: Make CPDF_Annot::m_pAnnotDict private.
[pdfium.git] / fpdfsdk / src / fsdk_baseannot.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 "../include/fsdk_define.h"
8 #include "../include/fpdfxfa/fpdfxfa_doc.h"
9 #include "../include/fsdk_mgr.h"
10 #include "../include/fsdk_baseannot.h"
11
12
13 //---------------------------------------------------------------------------
14 //                                                              CPDFSDK_DateTime        
15 //---------------------------------------------------------------------------
16 int _gAfxGetTimeZoneInSeconds(FX_CHAR tzhour, FX_BYTE tzminute)
17 {
18         return (int)tzhour * 3600 + (int)tzminute * (tzhour >= 0 ? 60 : -60);
19 }
20
21 FX_BOOL _gAfxIsLeapYear(FX_SHORT year)
22 {
23         return ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)));
24 }
25
26 FX_WORD _gAfxGetYearDays(FX_SHORT year)
27 {
28         return (_gAfxIsLeapYear(year) == TRUE ? 366 : 365);
29 }
30
31 FX_BYTE _gAfxGetMonthDays(FX_SHORT year, FX_BYTE month)
32 {
33         FX_BYTE mDays;
34         switch (month)
35         {
36         case 1:
37         case 3:
38         case 5:
39         case 7:
40         case 8:
41         case 10:
42         case 12:
43                 mDays = 31;
44                 break;
45
46         case 4:
47         case 6:
48         case 9:
49         case 11:
50                 mDays = 30;
51                 break;
52
53         case 2:
54                 if (_gAfxIsLeapYear(year) == TRUE)
55                         mDays = 29;
56                 else
57                         mDays = 28;
58                 break;
59
60         default:
61                 mDays = 0;
62                 break;
63         }
64
65         return mDays;
66 }
67
68 CPDFSDK_DateTime::CPDFSDK_DateTime()
69 {
70         ResetDateTime();
71 }
72
73 CPDFSDK_DateTime::CPDFSDK_DateTime(const CFX_ByteString& dtStr)
74 {
75         ResetDateTime();
76
77         FromPDFDateTimeString(dtStr);
78 }
79
80 CPDFSDK_DateTime::CPDFSDK_DateTime(const CPDFSDK_DateTime& datetime)
81 {
82         operator = (datetime);
83 }
84
85 CPDFSDK_DateTime::CPDFSDK_DateTime(const FX_SYSTEMTIME& st)
86 {
87         operator = (st) ;
88 }
89
90
91 void CPDFSDK_DateTime::ResetDateTime()
92 {
93         tzset();
94
95         time_t  curTime;
96         time(&curTime);
97         struct tm* newtime;
98         //newtime = gmtime(&curTime);
99         newtime = localtime(&curTime);
100
101         dt.year = newtime->tm_year + 1900;
102         dt.month = newtime->tm_mon + 1;
103         dt.day = newtime->tm_mday;
104         dt.hour = newtime->tm_hour;
105         dt.minute = newtime->tm_min;
106         dt.second = newtime->tm_sec;
107 //      dt.tzHour = _timezone / 3600 * -1;
108 //      dt.tzMinute = (abs(_timezone) % 3600) / 60;
109 }
110
111 CPDFSDK_DateTime& CPDFSDK_DateTime::operator = (const CPDFSDK_DateTime& datetime)
112 {
113         FXSYS_memcpy(&dt, &datetime.dt, sizeof(FX_DATETIME));
114         return *this;
115 }
116
117 CPDFSDK_DateTime& CPDFSDK_DateTime::operator = (const FX_SYSTEMTIME& st)
118 {
119         tzset();
120
121         dt.year = (FX_SHORT)st.wYear;
122         dt.month = (FX_BYTE)st.wMonth;
123         dt.day = (FX_BYTE)st.wDay;
124         dt.hour = (FX_BYTE)st.wHour;
125         dt.minute = (FX_BYTE)st.wMinute;
126         dt.second = (FX_BYTE)st.wSecond;
127 //      dt.tzHour = _timezone / 3600 * -1;
128 //      dt.tzMinute = (abs(_timezone) % 3600) / 60;
129         return *this;
130 }
131
132 FX_BOOL CPDFSDK_DateTime::operator == (CPDFSDK_DateTime& datetime)
133 {
134         return (FXSYS_memcmp(&dt, &datetime.dt, sizeof(FX_DATETIME)) == 0);
135 }
136
137 FX_BOOL CPDFSDK_DateTime::operator != (CPDFSDK_DateTime& datetime)
138 {
139         return (FXSYS_memcmp(&dt, &datetime.dt, sizeof(FX_DATETIME)) != 0);
140 }
141
142 FX_BOOL CPDFSDK_DateTime::operator > (CPDFSDK_DateTime& datetime)
143 {
144         CPDFSDK_DateTime dt1 = ToGMT();
145         CPDFSDK_DateTime dt2 = datetime.ToGMT();
146         int d1 = (((int)dt1.dt.year) << 16) | (((int)dt1.dt.month) << 8) | (int)dt1.dt.day;
147         int d2 = (((int)dt1.dt.hour) << 16) | (((int)dt1.dt.minute) << 8) | (int)dt1.dt.second;
148         int d3 = (((int)dt2.dt.year) << 16) | (((int)dt2.dt.month) << 8) | (int)dt2.dt.day;
149         int d4 = (((int)dt2.dt.hour) << 16) | (((int)dt2.dt.minute) << 8) | (int)dt2.dt.second;
150
151         if (d1 > d3) return TRUE;
152         if (d2 > d4) return TRUE;
153         return FALSE;
154 }
155
156 FX_BOOL CPDFSDK_DateTime::operator >= (CPDFSDK_DateTime& datetime)
157 {
158         CPDFSDK_DateTime dt1 = ToGMT();
159         CPDFSDK_DateTime dt2 = datetime.ToGMT();
160         int d1 = (((int)dt1.dt.year) << 16) | (((int)dt1.dt.month) << 8) | (int)dt1.dt.day;
161         int d2 = (((int)dt1.dt.hour) << 16) | (((int)dt1.dt.minute) << 8) | (int)dt1.dt.second;
162         int d3 = (((int)dt2.dt.year) << 16) | (((int)dt2.dt.month) << 8) | (int)dt2.dt.day;
163         int d4 = (((int)dt2.dt.hour) << 16) | (((int)dt2.dt.minute) << 8) | (int)dt2.dt.second;
164
165         if (d1 >= d3) return TRUE;
166         if (d2 >= d4) return TRUE;
167         return FALSE;
168 }
169
170 FX_BOOL CPDFSDK_DateTime::operator < (CPDFSDK_DateTime& datetime)
171 {
172         CPDFSDK_DateTime dt1 = ToGMT();
173         CPDFSDK_DateTime dt2 = datetime.ToGMT();
174         int d1 = (((int)dt1.dt.year) << 16) | (((int)dt1.dt.month) << 8) | (int)dt1.dt.day;
175         int d2 = (((int)dt1.dt.hour) << 16) | (((int)dt1.dt.minute) << 8) | (int)dt1.dt.second;
176         int d3 = (((int)dt2.dt.year) << 16) | (((int)dt2.dt.month) << 8) | (int)dt2.dt.day;
177         int d4 = (((int)dt2.dt.hour) << 16) | (((int)dt2.dt.minute) << 8) | (int)dt2.dt.second;
178
179         if (d1 < d3) return TRUE;
180         if (d2 < d4) return TRUE;
181         return FALSE;
182 }
183
184 FX_BOOL CPDFSDK_DateTime::operator <= (CPDFSDK_DateTime& datetime)
185 {
186         CPDFSDK_DateTime dt1 = ToGMT();
187         CPDFSDK_DateTime dt2 = datetime.ToGMT();
188         int d1 = (((int)dt1.dt.year) << 16) | (((int)dt1.dt.month) << 8) | (int)dt1.dt.day;
189         int d2 = (((int)dt1.dt.hour) << 16) | (((int)dt1.dt.minute) << 8) | (int)dt1.dt.second;
190         int d3 = (((int)dt2.dt.year) << 16) | (((int)dt2.dt.month) << 8) | (int)dt2.dt.day;
191         int d4 = (((int)dt2.dt.hour) << 16) | (((int)dt2.dt.minute) << 8) | (int)dt2.dt.second;
192
193         if (d1 <= d3) return TRUE;
194         if (d2 <= d4) return TRUE;
195         return FALSE;
196 }
197
198 CPDFSDK_DateTime::operator time_t()
199 {
200         struct tm newtime;
201
202         newtime.tm_year = dt.year - 1900;
203         newtime.tm_mon = dt.month - 1;
204         newtime.tm_mday = dt.day;
205         newtime.tm_hour = dt.hour;
206         newtime.tm_min = dt.minute;
207         newtime.tm_sec = dt.second;
208
209         return mktime(&newtime);
210 }
211
212 CPDFSDK_DateTime& CPDFSDK_DateTime::FromPDFDateTimeString(const CFX_ByteString& dtStr)
213 {
214         int strLength = dtStr.GetLength();
215         if (strLength > 0)
216         {
217                 int i = 0;
218                 int j, k;
219                 FX_CHAR ch;
220                 while (i < strLength)
221                 {
222                         ch = dtStr[i];
223                         if (ch >= '0' && ch <= '9') break;
224                         i ++;
225                 }
226                 if (i >= strLength) return *this;
227
228                 j = 0;
229                 k = 0;
230                 while (i < strLength && j < 4)
231                 {
232                         ch = dtStr[i];
233                         k = k * 10 + ch - '0';
234                         j ++;
235                         if (ch < '0' || ch > '9') break;
236                         i ++;
237                 }
238                 dt.year = (FX_SHORT)k;
239                 if (i >= strLength || j < 4) return *this;
240
241                 j = 0;
242                 k = 0;
243                 while (i < strLength && j < 2)
244                 {
245                         ch = dtStr[i];
246                         k = k * 10 + ch - '0';
247                         j ++;
248                         if (ch < '0' || ch > '9') break;
249                         i ++;
250                 }
251                 dt.month = (FX_BYTE)k;
252                 if (i >= strLength || j < 2) return *this;
253
254                 j = 0;
255                 k = 0;
256                 while (i < strLength && j < 2)
257                 {
258                         ch = dtStr[i];
259                         k = k * 10 + ch - '0';
260                         j ++;
261                         if (ch < '0' || ch > '9') break;
262                         i ++;
263                 }
264                 dt.day = (FX_BYTE)k;
265                 if (i >= strLength || j < 2) return *this;
266
267                 j = 0;
268                 k = 0;
269                 while (i < strLength && j < 2)
270                 {
271                         ch = dtStr[i];
272                         k = k * 10 + ch - '0';
273                         j ++;
274                         if (ch < '0' || ch > '9') break;
275                         i ++;
276                 }
277                 dt.hour = (FX_BYTE)k;
278                 if (i >= strLength || j < 2) return *this;
279
280                 j = 0;
281                 k = 0;
282                 while (i < strLength && j < 2)
283                 {
284                         ch = dtStr[i];
285                         k = k * 10 + ch - '0';
286                         j ++;
287                         if (ch < '0' || ch > '9') break;
288                         i ++;
289                 }
290                 dt.minute = (FX_BYTE)k;
291                 if (i >= strLength || j < 2) return *this;
292
293                 j = 0;
294                 k = 0;
295                 while (i < strLength && j < 2)
296                 {
297                         ch = dtStr[i];
298                         k = k * 10 + ch - '0';
299                         j ++;
300                         if (ch < '0' || ch > '9') break;
301                         i ++;
302                 }
303                 dt.second = (FX_BYTE)k;
304                 if (i >= strLength || j < 2) return *this;
305
306                 ch = dtStr[i ++];
307                 if (ch != '-' && ch != '+') return *this;
308                 if (ch == '-')
309                         dt.tzHour = -1;
310                 else
311                         dt.tzHour = 1;
312                 j = 0;
313                 k = 0;
314                 while (i < strLength && j < 2)
315                 {
316                         ch = dtStr[i];
317                         k = k * 10 + ch - '0';
318                         j ++;
319                         if (ch < '0' || ch > '9') break;
320                         i ++;
321                 }
322                 dt.tzHour *= (FX_CHAR)k;
323                 if (i >= strLength || j < 2) return *this;
324
325                 ch = dtStr[i ++];
326                 if (ch != '\'') return *this;
327                 j = 0;
328                 k = 0;
329                 while (i < strLength && j < 2)
330                 {
331                         ch = dtStr[i];
332                         k = k * 10 + ch - '0';
333                         j ++;
334                         if (ch < '0' || ch > '9') break;
335                         i ++;
336                 }
337                 dt.tzMinute = (FX_BYTE)k;
338                 if (i >= strLength || j < 2) return *this;
339         }
340
341         return  *this;
342 }
343
344 CFX_ByteString CPDFSDK_DateTime::ToCommonDateTimeString()
345 {
346         CFX_ByteString str1;
347         str1.Format("%04d-%02d-%02d %02d:%02d:%02d ", dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second);
348         if (dt.tzHour < 0)
349                 str1 += "-";
350         else
351                 str1 += "+";
352         CFX_ByteString str2;
353         str2.Format("%02d:%02d", abs(dt.tzHour), dt.tzMinute);
354         return str1 + str2;
355 }
356
357 CFX_ByteString CPDFSDK_DateTime::ToPDFDateTimeString()
358 {
359         CFX_ByteString dtStr;
360         char tempStr[32];
361         memset(tempStr, 0, sizeof(tempStr));
362         FXSYS_snprintf(tempStr, sizeof(tempStr) - 1, "D:%04d%02d%02d%02d%02d%02d",
363                    dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second);
364         dtStr = CFX_ByteString(tempStr);
365         if (dt.tzHour < 0)
366                 dtStr += CFX_ByteString("-");
367         else
368                 dtStr += CFX_ByteString("+");
369         memset(tempStr, 0, sizeof(tempStr));
370         FXSYS_snprintf(tempStr, sizeof(tempStr) - 1, "%02d'%02d'", abs(dt.tzHour), dt.tzMinute);
371         dtStr += CFX_ByteString(tempStr);
372         return dtStr;
373 }
374
375 void CPDFSDK_DateTime::ToSystemTime(FX_SYSTEMTIME& st)
376 {
377         CPDFSDK_DateTime dt = *this;
378         time_t t = (time_t)dt;
379         struct tm* pTime = localtime(&t);
380         if(pTime){ 
381                 st.wYear = (FX_WORD)pTime->tm_year + 1900;
382                 st.wMonth = (FX_WORD)pTime->tm_mon + 1;
383                 st.wDay = (FX_WORD)pTime->tm_mday;
384                 st.wDayOfWeek = (FX_WORD)pTime->tm_wday;
385                 st.wHour = (FX_WORD)pTime->tm_hour;
386                 st.wMinute = (FX_WORD)pTime->tm_min;
387                 st.wSecond = (FX_WORD)pTime->tm_sec;
388                 st.wMilliseconds = 0;
389         }
390 }
391
392 CPDFSDK_DateTime CPDFSDK_DateTime::ToGMT()
393 {
394         CPDFSDK_DateTime dt = *this;
395         dt.AddSeconds(-_gAfxGetTimeZoneInSeconds(dt.dt.tzHour, dt.dt.tzMinute));
396         dt.dt.tzHour = 0;
397         dt.dt.tzMinute = 0;
398         return dt;
399 }
400
401 CPDFSDK_DateTime& CPDFSDK_DateTime::AddDays(short days)
402 {
403         if (days == 0) return *this;
404
405         FX_SHORT        y = dt.year, yy;
406         FX_BYTE         m = dt.month;
407         FX_BYTE         d = dt.day;
408         int                     mdays, ydays, ldays;
409
410         ldays = days;
411         if (ldays > 0)
412         {
413                 yy = y;
414                 if (((FX_WORD)m * 100 + d) > 300) yy ++;
415                 ydays = _gAfxGetYearDays(yy);
416                 while (ldays >= ydays)
417                 {
418                         y ++;
419                         ldays -= ydays;
420                         yy ++;
421                         mdays = _gAfxGetMonthDays(y, m);
422                         if (d > mdays)
423                         {
424                                 m ++;
425                                 d -= mdays;
426                         }
427                         ydays = _gAfxGetYearDays(yy);
428                 }
429                 mdays = _gAfxGetMonthDays(y, m) - d + 1;
430                 while (ldays >= mdays)
431                 {
432                         ldays -= mdays;
433                         m ++;
434                         d = 1;
435                         mdays = _gAfxGetMonthDays(y, m);
436                 }
437                 d += ldays;
438         }
439         else
440         {
441                 ldays *= -1;
442                 yy = y;
443                 if (((FX_WORD)m * 100 + d) < 300) yy --;
444                 ydays = _gAfxGetYearDays(yy);
445                 while (ldays >= ydays)
446                 {
447                         y --;
448                         ldays -= ydays;
449                         yy --;
450                         mdays = _gAfxGetMonthDays(y, m);
451                         if (d > mdays)
452                         {
453                                 m ++;
454                                 d -= mdays;
455                         }
456                         ydays = _gAfxGetYearDays(yy);
457                 }
458                 while (ldays >= d)
459                 {
460                         ldays -= d;
461                         m --;
462                         mdays = _gAfxGetMonthDays(y, m);
463                         d = mdays;
464                 }
465                 d -= ldays;
466         }
467
468         dt.year = y;
469         dt.month = m;
470         dt.day = d;
471
472         return *this;
473 }
474
475 CPDFSDK_DateTime& CPDFSDK_DateTime::AddSeconds(int seconds)
476 {
477         if (seconds == 0) return *this;
478
479         int     n;
480         int     days;
481
482         n = dt.hour * 3600 + dt.minute * 60 + dt.second + seconds;
483         if (n < 0)
484         {
485                 days = (n - 86399) / 86400;
486                 n -= days * 86400;
487         }
488         else
489         {
490                 days = n / 86400;
491                 n %= 86400;
492         }
493         dt.hour = (FX_BYTE)(n / 3600);
494         dt.hour %= 24;
495         n %= 3600;
496         dt.minute = (FX_BYTE)(n / 60);
497         dt.second = (FX_BYTE)(n % 60);
498         if (days != 0) AddDays(days);
499
500         return *this;
501 }
502
503
504 //---------------------------------------------------------------------------
505 //                                                              CPDFSDK_Annot   
506 //---------------------------------------------------------------------------
507 CPDFSDK_Annot::CPDFSDK_Annot(CPDFSDK_PageView* pPageView) :
508 m_pPageView(pPageView),
509 m_bSelected(FALSE),
510 m_nTabOrder(-1)
511 {
512 }
513
514
515 //CPDFSDK_BAAnnot
516 CPDFSDK_BAAnnot::CPDFSDK_BAAnnot(CPDF_Annot* pAnnot, CPDFSDK_PageView* pPageView) :
517         CPDFSDK_Annot(pPageView),
518                 m_pAnnot(pAnnot)
519 {
520
521 }
522
523 CPDFSDK_BAAnnot::~CPDFSDK_BAAnnot()
524 {
525         m_pAnnot = NULL;
526 }
527
528 CPDF_Annot*     CPDFSDK_BAAnnot::GetPDFAnnot()
529 {
530         return m_pAnnot;
531 }
532
533 FX_BOOL CPDFSDK_Annot::IsSelected()
534 {
535         return m_bSelected;
536 }
537
538 void CPDFSDK_Annot::SetSelected(FX_BOOL bSelected)
539 {
540         m_bSelected = bSelected;
541 }
542
543 // Tab Order    
544 int CPDFSDK_Annot::GetTabOrder()
545 {
546         return m_nTabOrder;
547 }
548
549 void CPDFSDK_Annot::SetTabOrder(int iTabOrder)
550 {
551         m_nTabOrder = iTabOrder;
552 }
553
554 CPDF_Dictionary* CPDFSDK_BAAnnot::GetAnnotDict() const
555 {
556         ASSERT(m_pAnnot != NULL);
557         
558         return m_pAnnot->GetAnnotDict();
559 }
560
561 void CPDFSDK_BAAnnot::SetRect(const CPDF_Rect& rect)
562 {
563         ASSERT(rect.right - rect.left >= GetMinWidth());
564         ASSERT(rect.top - rect.bottom >= GetMinHeight());
565         
566         m_pAnnot->GetAnnotDict()->SetAtRect("Rect", rect);
567 }
568
569 CPDF_Rect CPDFSDK_BAAnnot::GetRect() const
570 {
571         ASSERT(m_pAnnot != NULL);
572         
573         CPDF_Rect rect;
574         m_pAnnot->GetRect(rect);
575         
576         return rect;
577 }
578
579 CFX_ByteString CPDFSDK_BAAnnot::GetType() const
580 {
581         ASSERT(m_pAnnot != NULL);
582         
583         return m_pAnnot->GetSubType();
584 }
585
586 CFX_ByteString CPDFSDK_BAAnnot::GetSubType() const
587 {
588         return "";
589 }
590
591 void CPDFSDK_BAAnnot::ResetAppearance()
592 {
593         ASSERT(FALSE);
594 }
595
596 void CPDFSDK_BAAnnot::DrawAppearance(CFX_RenderDevice* pDevice, const CPDF_Matrix* pUser2Device,
597                                                                    CPDF_Annot::AppearanceMode mode, const CPDF_RenderOptions* pOptions) 
598 {
599         ASSERT(m_pPageView != NULL);
600         ASSERT(m_pAnnot != NULL);
601         
602         m_pAnnot->DrawAppearance(m_pPageView->GetPDFPage(), pDevice, pUser2Device, mode, pOptions);
603 }
604
605 FX_BOOL CPDFSDK_BAAnnot::IsAppearanceValid()
606 {
607         return m_pAnnot->GetAnnotDict()->GetDict("AP") != NULL;
608 }
609
610 FX_BOOL CPDFSDK_BAAnnot::IsAppearanceValid(CPDF_Annot::AppearanceMode mode)
611 {
612         CPDF_Dictionary* pAP = m_pAnnot->GetAnnotDict()->GetDict("AP");
613         if (pAP == NULL) return FALSE;
614         
615         // Choose the right sub-ap
616         const FX_CHAR* ap_entry = "N";
617         if (mode == CPDF_Annot::Down)
618                 ap_entry = "D";
619         else if (mode == CPDF_Annot::Rollover)
620                 ap_entry = "R";
621         if (!pAP->KeyExist(ap_entry))
622                 ap_entry = "N";
623         
624         // Get the AP stream or subdirectory
625         CPDF_Object* psub = pAP->GetElementValue(ap_entry);
626         if (psub == NULL) return FALSE;
627         
628         return TRUE;
629 }
630
631 void CPDFSDK_BAAnnot::DrawBorder(CFX_RenderDevice* pDevice, const CPDF_Matrix* pUser2Device,
632                                                    const CPDF_RenderOptions* pOptions)
633 {
634         ASSERT(m_pAnnot != NULL);
635         m_pAnnot->DrawBorder(pDevice, pUser2Device, pOptions); 
636 }
637
638 void CPDFSDK_BAAnnot::ClearCachedAP()
639 {
640         ASSERT(m_pAnnot != NULL);
641         m_pAnnot->ClearCachedAP();
642 }    
643
644 void CPDFSDK_BAAnnot::SetContents(const CFX_WideString& sContents)
645 {
646         if (sContents.IsEmpty())
647                 m_pAnnot->GetAnnotDict()->RemoveAt("Contents");
648         else
649                 m_pAnnot->GetAnnotDict()->SetAtString("Contents", PDF_EncodeText(sContents));
650 }
651
652 CFX_WideString CPDFSDK_BAAnnot::GetContents() const
653 {
654         return m_pAnnot->GetAnnotDict()->GetUnicodeText("Contents");
655 }
656
657 void CPDFSDK_BAAnnot::SetAnnotName(const CFX_WideString& sName)
658 {
659         if (sName.IsEmpty())
660                 m_pAnnot->GetAnnotDict()->RemoveAt("NM");
661         else
662                 m_pAnnot->GetAnnotDict()->SetAtString("NM", PDF_EncodeText(sName));
663 }
664
665 CFX_WideString CPDFSDK_BAAnnot::GetAnnotName() const
666 {
667         return m_pAnnot->GetAnnotDict()->GetUnicodeText("NM");
668 }
669
670 void CPDFSDK_BAAnnot::SetModifiedDate(const FX_SYSTEMTIME& st)
671 {
672         CPDFSDK_DateTime dt(st);
673         CFX_ByteString str = dt.ToPDFDateTimeString();
674         
675         if (str.IsEmpty())
676                 m_pAnnot->GetAnnotDict()->RemoveAt("M");
677         else
678                 m_pAnnot->GetAnnotDict()->SetAtString("M", str);
679 }
680
681 FX_SYSTEMTIME CPDFSDK_BAAnnot::GetModifiedDate() const
682 {
683         FX_SYSTEMTIME systime;  
684         CFX_ByteString str = m_pAnnot->GetAnnotDict()->GetString("M");
685         
686         CPDFSDK_DateTime dt(str);
687         dt.ToSystemTime(systime);
688         
689         return systime;
690 }
691
692 void CPDFSDK_BAAnnot::SetFlags(int nFlags)
693 {
694         m_pAnnot->GetAnnotDict()->SetAtInteger("F", nFlags);
695 }
696
697 int CPDFSDK_BAAnnot::GetFlags() const
698 {
699         return m_pAnnot->GetAnnotDict()->GetInteger("F");
700 }
701
702 void CPDFSDK_BAAnnot::SetAppState(const CFX_ByteString& str)
703 {
704         if (str.IsEmpty())
705                 m_pAnnot->GetAnnotDict()->RemoveAt("AS");
706         else
707                 m_pAnnot->GetAnnotDict()->SetAtString("AS", str);
708 }
709
710 CFX_ByteString CPDFSDK_BAAnnot::GetAppState() const
711 {
712         return m_pAnnot->GetAnnotDict()->GetString("AS");
713 }
714
715 void CPDFSDK_BAAnnot::SetStructParent(int key)
716 {
717         m_pAnnot->GetAnnotDict()->SetAtInteger("StructParent", key);
718 }
719
720 int     CPDFSDK_BAAnnot::GetStructParent() const
721 {
722         return m_pAnnot->GetAnnotDict()->GetInteger("StructParent");
723 }
724
725 //border
726 void CPDFSDK_BAAnnot::SetBorderWidth(int nWidth)
727 {
728         CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArray("Border");
729
730         if (pBorder)
731         {
732                 pBorder->SetAt(2, FX_NEW CPDF_Number(nWidth));
733         }
734         else
735         {
736                 CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDict("BS");
737
738                 if (!pBSDict)
739                 {
740                         pBSDict = FX_NEW CPDF_Dictionary;
741                         m_pAnnot->GetAnnotDict()->SetAt("BS", pBSDict);
742                 }
743
744                 pBSDict->SetAtInteger("W", nWidth);
745         }
746 }
747
748 int     CPDFSDK_BAAnnot::GetBorderWidth() const
749 {
750         CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArray("Border");
751
752         if (pBorder)
753         {
754                 return pBorder->GetInteger(2);
755         }
756         else
757         {
758                 CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDict("BS");
759
760                 if (pBSDict)
761                 {
762                         return pBSDict->GetInteger("W", 1);
763                 }
764         }
765         return 1;
766 }
767
768 void CPDFSDK_BAAnnot::SetBorderStyle(int nStyle)
769 {
770         CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDict("BS");
771         if (!pBSDict)
772         {
773                 pBSDict = new CPDF_Dictionary;
774                 m_pAnnot->GetAnnotDict()->SetAt("BS", pBSDict);
775         }
776
777         switch (nStyle)
778         {
779         case BBS_SOLID:
780                 pBSDict->SetAtName("S", "S");
781                 break;
782         case BBS_DASH:
783                 pBSDict->SetAtName("S", "D");
784                 break;
785         case BBS_BEVELED:
786                 pBSDict->SetAtName("S", "B");
787                 break;
788         case BBS_INSET:
789                 pBSDict->SetAtName("S", "I");
790                 break;
791         case BBS_UNDERLINE:
792                 pBSDict->SetAtName("S", "U");
793                 break;
794         }
795 }
796
797 int     CPDFSDK_BAAnnot::GetBorderStyle() const
798 {
799         CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDict("BS");
800         if (pBSDict)
801         {
802                 CFX_ByteString sBorderStyle = pBSDict->GetString("S", "S");
803                 if (sBorderStyle == "S") return BBS_SOLID;
804                 if (sBorderStyle == "D") return BBS_DASH;
805                 if (sBorderStyle == "B") return BBS_BEVELED;
806                 if (sBorderStyle == "I") return BBS_INSET;
807                 if (sBorderStyle == "U") return BBS_UNDERLINE;
808         }
809
810         CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArray("Border");
811         if (pBorder)
812         {
813                 if (pBorder->GetCount() >= 4) 
814                 { 
815                         CPDF_Array *pDP = pBorder->GetArray(3);
816                         if (pDP && pDP->GetCount() > 0)
817                                 return BBS_DASH;
818                 }
819         }
820
821         return BBS_SOLID;
822 }
823
824 void CPDFSDK_BAAnnot::SetBorderDash(const CFX_IntArray& array)
825 {
826         CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDict("BS");
827         if (!pBSDict)
828         {
829                 pBSDict = new CPDF_Dictionary;
830                 m_pAnnot->GetAnnotDict()->SetAt("BS", pBSDict);
831         }
832
833         CPDF_Array* pArray = FX_NEW CPDF_Array;
834         for (int i=0,sz=array.GetSize(); i<sz; i++)
835         {
836                 pArray->AddInteger(array[i]);
837         }
838
839         pBSDict->SetAt("D", pArray);
840 }
841
842 void CPDFSDK_BAAnnot::GetBorderDash(CFX_IntArray& array) const
843 {
844         CPDF_Array* pDash = NULL;
845
846         CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArray("Border");
847         if (pBorder)
848         {
849                 pDash = pBorder->GetArray(3);
850         }
851         else
852         {
853                 CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDict("BS");
854                 if (pBSDict)
855                 {
856                         pDash = pBSDict->GetArray("D");
857                 }
858         }
859
860         if (pDash)
861         {
862                 for (int i=0,sz=pDash->GetCount(); i<sz; i++)
863                 {
864                         array.Add(pDash->GetInteger(i));
865                 }
866         }
867 }
868
869 void CPDFSDK_BAAnnot::SetColor(FX_COLORREF color)
870 {
871         CPDF_Array* pArray = new CPDF_Array;
872         pArray->AddNumber((FX_FLOAT)FXSYS_GetRValue(color) / 255.0f);
873         pArray->AddNumber((FX_FLOAT)FXSYS_GetGValue(color) / 255.0f);
874         pArray->AddNumber((FX_FLOAT)FXSYS_GetBValue(color) / 255.0f);
875         m_pAnnot->GetAnnotDict()->SetAt("C", pArray);
876 }
877
878 void CPDFSDK_BAAnnot::RemoveColor()
879 {
880         m_pAnnot->GetAnnotDict()->RemoveAt("C");
881 }
882
883 FX_BOOL CPDFSDK_BAAnnot::GetColor(FX_COLORREF& color) const
884 {
885         if (CPDF_Array* pEntry = m_pAnnot->GetAnnotDict()->GetArray("C"))
886         {
887                 int nCount = pEntry->GetCount();
888                 if (nCount == 1)
889                 {
890                         FX_FLOAT g = pEntry->GetNumber(0) * 255;
891
892                         color = FXSYS_RGB((int)g, (int)g, (int)g);
893
894                         return TRUE;
895                 }
896                 else if (nCount == 3)
897                 {
898                         FX_FLOAT r = pEntry->GetNumber(0) * 255;
899                         FX_FLOAT g = pEntry->GetNumber(1) * 255;
900                         FX_FLOAT b = pEntry->GetNumber(2) * 255;
901
902                         color = FXSYS_RGB((int)r, (int)g, (int)b);
903
904                         return TRUE;
905                 }
906                 else if (nCount == 4)
907                 {
908                         FX_FLOAT c = pEntry->GetNumber(0);
909                         FX_FLOAT m = pEntry->GetNumber(1);
910                         FX_FLOAT y = pEntry->GetNumber(2);
911                         FX_FLOAT k = pEntry->GetNumber(3);
912
913                         FX_FLOAT r = 1.0f - FX_MIN(1.0f, c + k);
914                         FX_FLOAT g = 1.0f - FX_MIN(1.0f, m + k);
915                         FX_FLOAT b = 1.0f - FX_MIN(1.0f, y + k);
916
917                         color = FXSYS_RGB((int)(r * 255), (int)(g * 255), (int)(b * 255));
918
919                         return TRUE;
920                 }
921         }
922
923         return FALSE;
924 }
925
926
927 void CPDFSDK_BAAnnot::WriteAppearance(const CFX_ByteString& sAPType, const CPDF_Rect& rcBBox, 
928                                                                 const CPDF_Matrix& matrix, const CFX_ByteString& sContents,
929                                                                 const CFX_ByteString& sAPState)
930 {
931         CPDF_Dictionary* pAPDict = m_pAnnot->GetAnnotDict()->GetDict("AP");
932         
933         if (!pAPDict) 
934         {
935                 pAPDict = new CPDF_Dictionary;
936                 m_pAnnot->GetAnnotDict()->SetAt("AP", pAPDict);
937         }
938         
939         CPDF_Stream* pStream = NULL;
940         CPDF_Dictionary* pParentDict = NULL;
941         
942         if (sAPState.IsEmpty())
943         {
944                 pParentDict = pAPDict;
945                 pStream = pAPDict->GetStream(sAPType);
946         }
947         else
948         {
949                 CPDF_Dictionary* pAPTypeDict = pAPDict->GetDict(sAPType);
950                 if (!pAPTypeDict)
951                 {
952                         pAPTypeDict = FX_NEW CPDF_Dictionary;
953                         pAPDict->SetAt(sAPType, pAPTypeDict);
954                 }
955                 
956                 pParentDict = pAPTypeDict;
957                 pStream = pAPTypeDict->GetStream(sAPState);
958         }
959         
960         if (!pStream) 
961         {
962                 ASSERT(m_pPageView != NULL);
963                 CPDF_Document* pDoc = m_pPageView->GetPDFDocument();
964                 ASSERT(pDoc != NULL);
965                 
966                 pStream = FX_NEW CPDF_Stream(NULL, 0, NULL);
967                 FX_INT32 objnum = pDoc->AddIndirectObject(pStream);
968                 //pAPDict->SetAtReference(sAPType, pDoc, objnum);
969                 ASSERT(pParentDict != NULL);
970                 pParentDict->SetAtReference(sAPType, pDoc, objnum);
971         }
972         
973         CPDF_Dictionary * pStreamDict = pStream->GetDict();
974         
975         if (!pStreamDict)
976         {
977                 pStreamDict = FX_NEW CPDF_Dictionary;
978                 pStreamDict->SetAtName("Type", "XObject");
979                 pStreamDict->SetAtName("Subtype", "Form");
980                 pStreamDict->SetAtInteger("FormType", 1);
981                 pStream->InitStream(NULL,0,pStreamDict);
982         }
983         
984         if (pStreamDict)
985         {
986                 pStreamDict->SetAtMatrix("Matrix",matrix);      
987                 pStreamDict->SetAtRect("BBox", rcBBox);         
988         }
989         
990         pStream->SetData((FX_BYTE*)sContents.c_str(), sContents.GetLength(), FALSE, FALSE);
991 }
992
993 #define BA_ANNOT_MINWIDTH                       1
994 #define BA_ANNOT_MINHEIGHT                      1
995
996 FX_FLOAT CPDFSDK_Annot::GetMinWidth() const
997 {
998         return BA_ANNOT_MINWIDTH;
999 }
1000
1001 FX_FLOAT CPDFSDK_Annot::GetMinHeight() const
1002 {
1003         return BA_ANNOT_MINHEIGHT;
1004 }
1005
1006 FX_BOOL CPDFSDK_BAAnnot::CreateFormFiller()
1007 {
1008         return TRUE;
1009 }
1010 FX_BOOL CPDFSDK_BAAnnot::IsVisible() const
1011 {
1012         int nFlags = GetFlags();
1013         return !((nFlags & ANNOTFLAG_INVISIBLE) || (nFlags & ANNOTFLAG_HIDDEN) || (nFlags & ANNOTFLAG_NOVIEW));
1014 }
1015
1016 CPDF_Action CPDFSDK_BAAnnot::GetAction() const
1017 {
1018         return CPDF_Action(m_pAnnot->GetAnnotDict()->GetDict("A"));
1019 }
1020
1021 void CPDFSDK_BAAnnot::SetAction(const CPDF_Action& action)
1022 {
1023         ASSERT(action);
1024         if ((CPDF_Action&)action != CPDF_Action(m_pAnnot->GetAnnotDict()->GetDict("A")))
1025         {
1026                 CPDF_Document* pDoc = m_pPageView->GetPDFDocument();
1027                 CPDF_Dictionary* pDict = action.GetDict();
1028                 if (pDict && pDict->GetObjNum() == 0) {
1029                         pDoc->AddIndirectObject(pDict);
1030                 }
1031                 m_pAnnot->GetAnnotDict()->SetAtReference("A", pDoc, pDict->GetObjNum());
1032         }
1033 }
1034
1035 void CPDFSDK_BAAnnot::RemoveAction()
1036 {
1037         m_pAnnot->GetAnnotDict()->RemoveAt("A");
1038 }
1039
1040 CPDF_AAction CPDFSDK_BAAnnot::GetAAction() const
1041 {
1042         return m_pAnnot->GetAnnotDict()->GetDict("AA");
1043 }
1044
1045 void CPDFSDK_BAAnnot::SetAAction(const CPDF_AAction& aa)
1046 {
1047         ASSERT(aa != NULL);
1048         
1049         if ((CPDF_AAction&)aa != m_pAnnot->GetAnnotDict()->GetDict("AA"))
1050                 m_pAnnot->GetAnnotDict()->SetAt("AA", (CPDF_AAction&)aa);
1051 }
1052
1053 void CPDFSDK_BAAnnot::RemoveAAction()
1054 {
1055         m_pAnnot->GetAnnotDict()->RemoveAt("AA");
1056 }
1057
1058 CPDF_Action     CPDFSDK_BAAnnot::GetAAction(CPDF_AAction::AActionType eAAT)
1059 {
1060         CPDF_AAction AAction = GetAAction();
1061
1062         if (AAction.ActionExist(eAAT))
1063                 return AAction.GetAction(eAAT);
1064
1065         if (eAAT == CPDF_AAction::ButtonUp)
1066                 return GetAction();
1067
1068         return CPDF_Action();
1069 }
1070
1071 FX_BOOL CPDFSDK_BAAnnot::IsXFAField()
1072 {
1073         return FALSE;
1074 }
1075
1076 void  CPDFSDK_BAAnnot::Annot_OnDraw(CFX_RenderDevice* pDevice, CPDF_Matrix* pUser2Device, CPDF_RenderOptions* pOptions)
1077 {
1078         
1079         m_pAnnot->GetAPForm(m_pPageView->GetPDFPage(), CPDF_Annot::Normal);
1080         m_pAnnot->DrawAppearance(m_pPageView->GetPDFPage(), pDevice, pUser2Device, CPDF_Annot::Normal, NULL);
1081
1082         return ;
1083 }
1084
1085 CPDF_Page* CPDFSDK_Annot::GetPDFPage()
1086 {
1087         if(m_pPageView)
1088                 return m_pPageView->GetPDFPage();
1089         return NULL;
1090 }
1091
1092 CPDFXFA_Page* CPDFSDK_Annot::GetPDFXFAPage()
1093 {
1094         if (m_pPageView)
1095                 return m_pPageView->GetPDFXFAPage();
1096         return NULL;
1097 }
1098