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