Remove "this==NULL" and adjust corresponding callers
[pdfium.git] / core / src / fpdfdoc / doc_annot.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/fpdfdoc/fpdf_doc.h"
8 #include "../../include/fpdfapi/fpdf_pageobj.h"
9 CPDF_AnnotList::CPDF_AnnotList(CPDF_Page* pPage)
10 {
11     ASSERT(pPage != NULL);
12     m_pPageDict = pPage->m_pFormDict;
13     if (m_pPageDict == NULL) {
14         return;
15     }
16     m_pDocument = pPage->m_pDocument;
17     CPDF_Array* pAnnots = m_pPageDict->GetArray("Annots");
18     if (pAnnots == NULL) {
19         return;
20     }
21     CPDF_Dictionary* pRoot = m_pDocument->GetRoot();
22     CPDF_Dictionary* pAcroForm = pRoot->GetDict("AcroForm");
23     FX_BOOL bRegenerateAP = pAcroForm && pAcroForm->GetBoolean("NeedAppearances");
24     for (FX_DWORD i = 0; i < pAnnots->GetCount(); i ++) {
25         CPDF_Dictionary* pDict = (CPDF_Dictionary*)pAnnots->GetElementValue(i);
26         if (pDict == NULL || pDict->GetType() != PDFOBJ_DICTIONARY) {
27             continue;
28         }
29         FX_DWORD dwObjNum = pDict->GetObjNum();
30         if (dwObjNum == 0) {
31             dwObjNum = m_pDocument->AddIndirectObject(pDict);
32             CPDF_Reference* pAction = CPDF_Reference::Create(m_pDocument, dwObjNum);
33             if (pAction == NULL) {
34                 break;
35             }
36             pAnnots->InsertAt(i, pAction);
37             pAnnots->RemoveAt(i + 1);
38             pDict = pAnnots->GetDict(i);
39         }
40         CPDF_Annot* pAnnot = FX_NEW CPDF_Annot(pDict);
41         if (pAnnot == NULL) {
42             break;
43         }
44         pAnnot->m_pList = this;
45         m_AnnotList.Add(pAnnot);
46         if (bRegenerateAP && pDict->GetConstString(FX_BSTRC("Subtype")) == FX_BSTRC("Widget"))
47             if (CPDF_InterForm::UpdatingAPEnabled()) {
48                 FPDF_GenerateAP(m_pDocument, pDict);
49             }
50     }
51 }
52 CPDF_AnnotList::~CPDF_AnnotList()
53 {
54     int i = 0;
55     for (i = 0; i < m_AnnotList.GetSize(); i ++) {
56         delete (CPDF_Annot*)m_AnnotList[i];
57     }
58     for (i = 0; i < m_Borders.GetSize(); ++i) {
59         delete (CPDF_PageObjects*)m_Borders[i];
60     }
61 }
62 void CPDF_AnnotList::DisplayPass(const CPDF_Page* pPage, CFX_RenderDevice* pDevice,
63                                  CPDF_RenderContext* pContext, FX_BOOL bPrinting, CFX_AffineMatrix* pMatrix,
64                                  FX_BOOL bWidgetPass, CPDF_RenderOptions* pOptions, FX_RECT* clip_rect)
65 {
66     for (int i = 0; i < m_AnnotList.GetSize(); i ++) {
67         CPDF_Annot* pAnnot = (CPDF_Annot*)m_AnnotList[i];
68         FX_BOOL bWidget = pAnnot->GetSubType() == "Widget";
69         if ((bWidgetPass && !bWidget) || (!bWidgetPass && bWidget)) {
70             continue;
71         }
72         FX_DWORD annot_flags = pAnnot->GetFlags();
73         if (annot_flags & ANNOTFLAG_HIDDEN) {
74             continue;
75         }
76         if (bPrinting && (annot_flags & ANNOTFLAG_PRINT) == 0) {
77             continue;
78         }
79         if (!bPrinting && (annot_flags & ANNOTFLAG_NOVIEW)) {
80             continue;
81         }
82         if (pOptions != NULL) {
83             IPDF_OCContext* pOCContext = pOptions->m_pOCContext;
84             CPDF_Dictionary* pAnnotDict = pAnnot->m_pAnnotDict;
85             if (pOCContext != NULL && pAnnotDict != NULL &&
86                     !pOCContext->CheckOCGVisible(pAnnotDict->GetDict(FX_BSTRC("OC")))) {
87                 continue;
88             }
89         }
90         CPDF_Rect annot_rect_f;
91         pAnnot->GetRect(annot_rect_f);
92         CFX_Matrix matrix;
93         matrix = *pMatrix;
94         if (clip_rect) {
95             annot_rect_f.Transform(&matrix);
96             FX_RECT annot_rect = annot_rect_f.GetOutterRect();
97             annot_rect.Intersect(*clip_rect);
98             if (annot_rect.IsEmpty()) {
99                 continue;
100             }
101         }
102         if (pContext) {
103             pAnnot->DrawInContext(pPage, pContext, &matrix, CPDF_Annot::Normal);
104         } else if (!pAnnot->DrawAppearance(pPage, pDevice, &matrix, CPDF_Annot::Normal, pOptions)) {
105             pAnnot->DrawBorder(pDevice, &matrix, pOptions);
106         }
107     }
108 }
109 void CPDF_AnnotList::DisplayAnnots(const CPDF_Page* pPage, CFX_RenderDevice* pDevice,
110                                    CFX_AffineMatrix* pUser2Device,
111                                    FX_BOOL bShowWidget, CPDF_RenderOptions* pOptions)
112 {
113     FX_RECT clip_rect;
114     if (pDevice) {
115         clip_rect = pDevice->GetClipBox();
116     }
117     FX_BOOL bPrinting = pDevice->GetDeviceClass() == FXDC_PRINTER || (pOptions && (pOptions->m_Flags & RENDER_PRINTPREVIEW));
118     DisplayAnnots(pPage, pDevice, NULL, bPrinting, pUser2Device, bShowWidget ? 3 : 1, pOptions, &clip_rect);
119 }
120 void CPDF_AnnotList::DisplayAnnots(const CPDF_Page* pPage, CFX_RenderDevice* pDevice, CPDF_RenderContext* pContext,
121                                    FX_BOOL bPrinting, CFX_AffineMatrix* pUser2Device, FX_DWORD dwAnnotFlags,
122                                    CPDF_RenderOptions* pOptions, FX_RECT* pClipRect)
123 {
124     if (dwAnnotFlags & 0x01) {
125         DisplayPass(pPage, pDevice, pContext, bPrinting, pUser2Device, FALSE, pOptions, pClipRect);
126     }
127     if (dwAnnotFlags & 0x02) {
128         DisplayPass(pPage, pDevice, pContext, bPrinting, pUser2Device, TRUE, pOptions, pClipRect);
129     }
130 }
131 int CPDF_AnnotList::GetIndex(CPDF_Annot* pAnnot)
132 {
133     for (int i = 0; i < m_AnnotList.GetSize(); i ++)
134         if (m_AnnotList[i] == (FX_LPVOID)pAnnot) {
135             return i;
136         }
137     return -1;
138 }
139 CPDF_Annot::CPDF_Annot(CPDF_Dictionary* pDict)
140 {
141     m_pList = NULL;
142     m_pAnnotDict = pDict;
143 }
144 CPDF_Annot::~CPDF_Annot()
145 {
146     ClearCachedAP();
147 }
148 CPDF_Reference* CPDF_Annot::NewAnnotRef()
149 {
150     if (m_pAnnotDict->GetObjNum() == 0) {
151         m_pList->m_pDocument->AddIndirectObject(m_pAnnotDict);
152     }
153     return CPDF_Reference::Create(m_pList->m_pDocument, m_pAnnotDict->GetObjNum());
154 }
155 void CPDF_Annot::ClearCachedAP()
156 {
157     FX_POSITION pos = m_APMap.GetStartPosition();
158     while (pos) {
159         void* pForm;
160         void* pObjects;
161         m_APMap.GetNextAssoc(pos, pForm, pObjects);
162         delete (CPDF_PageObjects*)pObjects;
163     }
164     m_APMap.RemoveAll();
165 }
166 CFX_ByteString CPDF_Annot::GetSubType() const
167 {
168     return m_pAnnotDict ? m_pAnnotDict->GetConstString(FX_BSTRC("Subtype")) : CFX_ByteStringC();
169 }
170 void CPDF_Annot::GetRect(CPDF_Rect& rect) const
171 {
172     if (m_pAnnotDict == NULL) {
173         return;
174     }
175     rect = m_pAnnotDict->GetRect("Rect");
176     rect.Normalize();
177 }
178 CPDF_Stream* FPDFDOC_GetAnnotAP(CPDF_Dictionary* pAnnotDict, CPDF_Annot::AppearanceMode mode)
179 {
180     CPDF_Dictionary* pAP = pAnnotDict->GetDict("AP");
181     if (pAP == NULL) {
182         return NULL;
183     }
184     const FX_CHAR* ap_entry = "N";
185     if (mode == CPDF_Annot::Down) {
186         ap_entry = "D";
187     } else if (mode == CPDF_Annot::Rollover) {
188         ap_entry = "R";
189     }
190     if (!pAP->KeyExist(ap_entry)) {
191         ap_entry = "N";
192     }
193     CPDF_Object* psub = pAP->GetElementValue(ap_entry);
194     if (psub == NULL) {
195         return NULL;
196     }
197     CPDF_Stream* pStream = NULL;
198     if (psub->GetType() == PDFOBJ_STREAM) {
199         pStream = (CPDF_Stream*)psub;
200     } else if (psub->GetType() == PDFOBJ_DICTIONARY) {
201         CFX_ByteString as = pAnnotDict->GetString("AS");
202         if (as.IsEmpty()) {
203             CFX_ByteString value = pAnnotDict->GetString(FX_BSTRC("V"));
204             if (value.IsEmpty()) {
205                 CPDF_Dictionary* pDict = pAnnotDict->GetDict(FX_BSTRC("Parent"));
206                 value = pDict ? pDict->GetString(FX_BSTRC("V")) : CFX_ByteString();
207             }
208             if (value.IsEmpty() || !((CPDF_Dictionary*)psub)->KeyExist(value)) {
209                 as = FX_BSTRC("Off");
210             } else {
211                 as = value;
212             }
213         }
214         pStream = ((CPDF_Dictionary*)psub)->GetStream(as);
215     }
216     return pStream;
217 }
218 CPDF_Form* CPDF_Annot::GetAPForm(const CPDF_Page* pPage, AppearanceMode mode)
219 {
220     CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(m_pAnnotDict, mode);
221     if (pStream == NULL) {
222         return NULL;
223     }
224     CPDF_Form* pForm;
225     if (m_APMap.Lookup(pStream, (void*&)pForm)) {
226         return pForm;
227     }
228     pForm = FX_NEW CPDF_Form(m_pList->m_pDocument, pPage->m_pResources, pStream);
229     if (pForm == NULL) {
230         return NULL;
231     }
232     pForm->ParseContent(NULL, NULL, NULL, NULL);
233     m_APMap.SetAt(pStream, pForm);
234     return pForm;
235 }
236 static CPDF_Form* FPDFDOC_Annot_GetMatrix(const CPDF_Page* pPage, CPDF_Annot* pAnnot, CPDF_Annot::AppearanceMode mode, const CFX_AffineMatrix* pUser2Device, CFX_Matrix &matrix)
237 {
238     CPDF_Form* pForm = pAnnot->GetAPForm(pPage, mode);
239     if (!pForm) {
240         return NULL;
241     }
242     CFX_FloatRect form_bbox = pForm->m_pFormDict->GetRect(FX_BSTRC("BBox"));
243     CFX_Matrix form_matrix = pForm->m_pFormDict->GetMatrix(FX_BSTRC("Matrix"));
244     form_matrix.TransformRect(form_bbox);
245     CPDF_Rect arect;
246     pAnnot->GetRect(arect);
247     matrix.MatchRect(arect, form_bbox);
248     matrix.Concat(*pUser2Device);
249     return pForm;
250 }
251 FX_BOOL CPDF_Annot::DrawAppearance(const CPDF_Page* pPage, CFX_RenderDevice* pDevice, const CFX_AffineMatrix* pUser2Device,
252                                    AppearanceMode mode, const CPDF_RenderOptions* pOptions)
253 {
254     CFX_Matrix matrix;
255     CPDF_Form* pForm = FPDFDOC_Annot_GetMatrix(pPage, this, mode, pUser2Device, matrix);
256     if (!pForm) {
257         return FALSE;
258     }
259     CPDF_RenderContext context;
260     context.Create((CPDF_Page*)pPage);
261     context.DrawObjectList(pDevice, pForm, &matrix, pOptions);
262     return TRUE;
263 }
264 FX_BOOL CPDF_Annot::DrawInContext(const CPDF_Page* pPage, const CPDF_RenderContext* pContext, const CFX_AffineMatrix* pUser2Device, AppearanceMode mode)
265 {
266     CFX_Matrix matrix;
267     CPDF_Form* pForm = FPDFDOC_Annot_GetMatrix(pPage, this, mode, pUser2Device, matrix);
268     if (!pForm) {
269         return FALSE;
270     }
271     ((CPDF_RenderContext*)pContext)->AppendObjectList(pForm, &matrix);
272     return TRUE;
273 }
274 CPDF_PageObject* CPDF_Annot::GetBorder(FX_BOOL bPrint, const CPDF_RenderOptions* pOptions)
275 {
276     if (GetSubType() == "Popup") {
277         return NULL;
278     }
279     FX_DWORD annot_flags = GetFlags();
280     if (annot_flags & ANNOTFLAG_HIDDEN) {
281         return NULL;
282     }
283     FX_BOOL bPrinting = bPrint || (pOptions && (pOptions->m_Flags & RENDER_PRINTPREVIEW));
284     if (bPrinting && (annot_flags & ANNOTFLAG_PRINT) == 0) {
285         return NULL;
286     }
287     if (!bPrinting && (annot_flags & ANNOTFLAG_NOVIEW)) {
288         return NULL;
289     }
290     CPDF_Dictionary* pBS = m_pAnnotDict->GetDict("BS");
291     char style_char;
292     FX_FLOAT width;
293     CPDF_Array* pDashArray = NULL;
294     if (pBS == NULL) {
295         CPDF_Array* pBorderArray = m_pAnnotDict->GetArray("Border");
296         style_char = 'S';
297         if (pBorderArray) {
298             width = pBorderArray->GetNumber(2);
299             if (pBorderArray->GetCount() == 4) {
300                 pDashArray = pBorderArray->GetArray(3);
301                 if (pDashArray == NULL) {
302                     return NULL;
303                 }
304                 style_char = 'D';
305             }
306         } else {
307             width = 1;
308         }
309     } else {
310         CFX_ByteString style = pBS->GetString("S");
311         pDashArray = pBS->GetArray("D");
312         style_char = style[1];
313         width = pBS->GetNumber("W");
314     }
315     if (width <= 0) {
316         return NULL;
317     }
318     CPDF_Array* pColor = m_pAnnotDict->GetArray("C");
319     FX_DWORD argb = 0xff000000;
320     if (pColor != NULL) {
321         int R = (FX_INT32)(pColor->GetNumber(0) * 255);
322         int G = (FX_INT32)(pColor->GetNumber(1) * 255);
323         int B = (FX_INT32)(pColor->GetNumber(2) * 255);
324         argb = ArgbEncode(0xff, R, G, B);
325     }
326     CPDF_PathObject *pPathObject = FX_NEW CPDF_PathObject();
327     if (!pPathObject) {
328         return NULL;
329     }
330     CPDF_GraphStateData *pGraphState = pPathObject->m_GraphState.GetModify();
331     if (!pGraphState) {
332         pPathObject->Release();
333         return NULL;
334     }
335     pGraphState->m_LineWidth = width;
336     CPDF_ColorStateData *pColorData = pPathObject->m_ColorState.GetModify();
337     if (!pColorData) {
338         pPathObject->Release();
339         return NULL;
340     }
341     pColorData->m_StrokeRGB = argb;
342     pPathObject->m_bStroke = TRUE;
343     pPathObject->m_FillType = 0;
344     if (style_char == 'D') {
345         if (pDashArray) {
346             FX_DWORD dash_count = pDashArray->GetCount();
347             if (dash_count % 2) {
348                 dash_count ++;
349             }
350             pGraphState->m_DashArray = FX_Alloc(FX_FLOAT, dash_count);
351             if (pGraphState->m_DashArray == NULL) {
352                 pPathObject->Release();
353                 return NULL;
354             }
355             pGraphState->m_DashCount = dash_count;
356             FX_DWORD i;
357             for (i = 0; i < pDashArray->GetCount(); i ++) {
358                 pGraphState->m_DashArray[i] = pDashArray->GetNumber(i);
359             }
360             if (i < dash_count) {
361                 pGraphState->m_DashArray[i] = pGraphState->m_DashArray[i - 1];
362             }
363         } else {
364             pGraphState->m_DashArray = FX_Alloc(FX_FLOAT, 2);
365             if (pGraphState->m_DashArray == NULL) {
366                 pPathObject->Release();
367                 return NULL;
368             }
369             pGraphState->m_DashCount = 2;
370             pGraphState->m_DashArray[0] = pGraphState->m_DashArray[1] = 3 * 1.0f;
371         }
372     }
373     CFX_FloatRect rect;
374     GetRect(rect);
375     width /= 2;
376     CPDF_PathData *pPathData = pPathObject->m_Path.GetModify();
377     if (pPathData) {
378         pPathData->AppendRect(rect.left + width, rect.bottom + width, rect.right - width, rect.top - width);
379     }
380     pPathObject->CalcBoundingBox();
381     return pPathObject;
382 }
383 void CPDF_Annot::DrawBorder(CFX_RenderDevice* pDevice, const CFX_AffineMatrix* pUser2Device, const CPDF_RenderOptions* pOptions)
384 {
385     if (GetSubType() == "Popup") {
386         return;
387     }
388     FX_DWORD annot_flags = GetFlags();
389     if (annot_flags & ANNOTFLAG_HIDDEN) {
390         return;
391     }
392     FX_BOOL bPrinting = pDevice->GetDeviceClass() == FXDC_PRINTER || (pOptions && (pOptions->m_Flags & RENDER_PRINTPREVIEW));
393     if (bPrinting && (annot_flags & ANNOTFLAG_PRINT) == 0) {
394         return;
395     }
396     if (!bPrinting && (annot_flags & ANNOTFLAG_NOVIEW)) {
397         return;
398     }
399     CPDF_Dictionary* pBS = m_pAnnotDict->GetDict("BS");
400     char style_char;
401     FX_FLOAT width;
402     CPDF_Array* pDashArray = NULL;
403     if (pBS == NULL) {
404         CPDF_Array* pBorderArray = m_pAnnotDict->GetArray("Border");
405         style_char = 'S';
406         if (pBorderArray) {
407             width = pBorderArray->GetNumber(2);
408             if (pBorderArray->GetCount() == 4) {
409                 pDashArray = pBorderArray->GetArray(3);
410                 if (pDashArray == NULL) {
411                     return;
412                 }
413                 int nLen = pDashArray->GetCount();
414                 int i = 0;
415                 for (; i < nLen; ++i) {
416                     CPDF_Object*pObj = pDashArray->GetElementValue(i);
417                     if (pObj && pObj->GetInteger()) {
418                         break;
419                     }
420                 }
421                 if (i == nLen) {
422                     return;
423                 }
424                 style_char = 'D';
425             }
426         } else {
427             width = 1;
428         }
429     } else {
430         CFX_ByteString style = pBS->GetString("S");
431         pDashArray = pBS->GetArray("D");
432         style_char = style[1];
433         width = pBS->GetNumber("W");
434     }
435     if (width <= 0) {
436         return;
437     }
438     CPDF_Array* pColor = m_pAnnotDict->GetArray("C");
439     FX_DWORD argb = 0xff000000;
440     if (pColor != NULL) {
441         int R = (FX_INT32)(pColor->GetNumber(0) * 255);
442         int G = (FX_INT32)(pColor->GetNumber(1) * 255);
443         int B = (FX_INT32)(pColor->GetNumber(2) * 255);
444         argb = ArgbEncode(0xff, R, G, B);
445     }
446     CPDF_GraphStateData graph_state;
447     graph_state.m_LineWidth = width;
448     if (style_char == 'D') {
449         if (pDashArray) {
450             FX_DWORD dash_count = pDashArray->GetCount();
451             if (dash_count % 2) {
452                 dash_count ++;
453             }
454             graph_state.m_DashArray = FX_Alloc(FX_FLOAT, dash_count);
455             if (graph_state.m_DashArray == NULL) {
456                 return ;
457             }
458             graph_state.m_DashCount = dash_count;
459             FX_DWORD i;
460             for (i = 0; i < pDashArray->GetCount(); i ++) {
461                 graph_state.m_DashArray[i] = pDashArray->GetNumber(i);
462             }
463             if (i < dash_count) {
464                 graph_state.m_DashArray[i] = graph_state.m_DashArray[i - 1];
465             }
466         } else {
467             graph_state.m_DashArray = FX_Alloc(FX_FLOAT, 2);
468             if (graph_state.m_DashArray == NULL) {
469                 return ;
470             }
471             graph_state.m_DashCount = 2;
472             graph_state.m_DashArray[0] = graph_state.m_DashArray[1] = 3 * 1.0f;
473         }
474     }
475     CFX_FloatRect rect;
476     GetRect(rect);
477     CPDF_PathData path;
478     width /= 2;
479     path.AppendRect(rect.left + width, rect.bottom + width, rect.right - width, rect.top - width);
480     int fill_type = 0;
481     if (pOptions && (pOptions->m_Flags & RENDER_NOPATHSMOOTH)) {
482         fill_type |= FXFILL_NOPATHSMOOTH;
483     }
484     pDevice->DrawPath(&path, pUser2Device, &graph_state, argb, argb, fill_type);
485 }
486 int CPDF_Annot::CountIRTNotes()
487 {
488     int count = 0;
489     for (int i = 0; i < m_pList->Count(); i ++) {
490         CPDF_Annot* pAnnot = m_pList->GetAt(i);
491         if (pAnnot == NULL) {
492             continue;
493         }
494         CPDF_Dictionary* pIRT = pAnnot->m_pAnnotDict->GetDict("IRT");
495         if (pIRT != m_pAnnotDict) {
496             continue;
497         }
498         count ++;
499     }
500     return count;
501 }
502 CPDF_Annot* CPDF_Annot::GetIRTNote(int index)
503 {
504     int count = 0;
505     for (int i = 0; i < m_pList->Count(); i ++) {
506         CPDF_Annot* pAnnot = m_pList->GetAt(i);
507         if (pAnnot == NULL) {
508             continue;
509         }
510         CPDF_Dictionary* pIRT = pAnnot->m_pAnnotDict->GetDict("IRT");
511         if (pIRT != m_pAnnotDict) {
512             continue;
513         }
514         if (count == index) {
515             return pAnnot;
516         }
517         count ++;
518     }
519     return NULL;
520 }