Home | History | Annotate | Download | only in fpdfdoc
      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->GetConstString(FX_BSTRC("Subtype"));
    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                 value = pAnnotDict->GetDict(FX_BSTRC("Parent"))->GetString(FX_BSTRC("V"));
    206             }
    207             if (value.IsEmpty() || !((CPDF_Dictionary*)psub)->KeyExist(value)) {
    208                 as = FX_BSTRC("Off");
    209             } else {
    210                 as = value;
    211             }
    212         }
    213         pStream = ((CPDF_Dictionary*)psub)->GetStream(as);
    214     }
    215     return pStream;
    216 }
    217 CPDF_Form* CPDF_Annot::GetAPForm(const CPDF_Page* pPage, AppearanceMode mode)
    218 {
    219     CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(m_pAnnotDict, mode);
    220     if (pStream == NULL) {
    221         return NULL;
    222     }
    223     CPDF_Form* pForm;
    224     if (m_APMap.Lookup(pStream, (void*&)pForm)) {
    225         return pForm;
    226     }
    227     pForm = FX_NEW CPDF_Form(m_pList->m_pDocument, pPage->m_pResources, pStream);
    228     if (pForm == NULL) {
    229         return NULL;
    230     }
    231     pForm->ParseContent(NULL, NULL, NULL, NULL);
    232     m_APMap.SetAt(pStream, pForm);
    233     return pForm;
    234 }
    235 static CPDF_Form* FPDFDOC_Annot_GetMatrix(const CPDF_Page* pPage, CPDF_Annot* pAnnot, CPDF_Annot::AppearanceMode mode, const CFX_AffineMatrix* pUser2Device, CFX_Matrix &matrix)
    236 {
    237     CPDF_Form* pForm = pAnnot->GetAPForm(pPage, mode);
    238     if (!pForm) {
    239         return NULL;
    240     }
    241     CFX_FloatRect form_bbox = pForm->m_pFormDict->GetRect(FX_BSTRC("BBox"));
    242     CFX_Matrix form_matrix = pForm->m_pFormDict->GetMatrix(FX_BSTRC("Matrix"));
    243     form_matrix.TransformRect(form_bbox);
    244     CPDF_Rect arect;
    245     pAnnot->GetRect(arect);
    246     matrix.MatchRect(arect, form_bbox);
    247     matrix.Concat(*pUser2Device);
    248     return pForm;
    249 }
    250 FX_BOOL CPDF_Annot::DrawAppearance(const CPDF_Page* pPage, CFX_RenderDevice* pDevice, const CFX_AffineMatrix* pUser2Device,
    251                                    AppearanceMode mode, const CPDF_RenderOptions* pOptions)
    252 {
    253     CFX_Matrix matrix;
    254     CPDF_Form* pForm = FPDFDOC_Annot_GetMatrix(pPage, this, mode, pUser2Device, matrix);
    255     if (!pForm) {
    256         return FALSE;
    257     }
    258     CPDF_RenderContext context;
    259     context.Create((CPDF_Page*)pPage);
    260     context.DrawObjectList(pDevice, pForm, &matrix, pOptions);
    261     return TRUE;
    262 }
    263 FX_BOOL CPDF_Annot::DrawInContext(const CPDF_Page* pPage, const CPDF_RenderContext* pContext, const CFX_AffineMatrix* pUser2Device, AppearanceMode mode)
    264 {
    265     CFX_Matrix matrix;
    266     CPDF_Form* pForm = FPDFDOC_Annot_GetMatrix(pPage, this, mode, pUser2Device, matrix);
    267     if (!pForm) {
    268         return FALSE;
    269     }
    270     ((CPDF_RenderContext*)pContext)->AppendObjectList(pForm, &matrix);
    271     return TRUE;
    272 }
    273 CPDF_PageObject* CPDF_Annot::GetBorder(FX_BOOL bPrint, const CPDF_RenderOptions* pOptions)
    274 {
    275     if (GetSubType() == "Popup") {
    276         return NULL;
    277     }
    278     FX_DWORD annot_flags = GetFlags();
    279     if (annot_flags & ANNOTFLAG_HIDDEN) {
    280         return NULL;
    281     }
    282     FX_BOOL bPrinting = bPrint || (pOptions && (pOptions->m_Flags & RENDER_PRINTPREVIEW));
    283     if (bPrinting && (annot_flags & ANNOTFLAG_PRINT) == 0) {
    284         return NULL;
    285     }
    286     if (!bPrinting && (annot_flags & ANNOTFLAG_NOVIEW)) {
    287         return NULL;
    288     }
    289     CPDF_Dictionary* pBS = m_pAnnotDict->GetDict("BS");
    290     char style_char;
    291     FX_FLOAT width;
    292     CPDF_Array* pDashArray = NULL;
    293     if (pBS == NULL) {
    294         CPDF_Array* pBorderArray = m_pAnnotDict->GetArray("Border");
    295         style_char = 'S';
    296         if (pBorderArray) {
    297             width = pBorderArray->GetNumber(2);
    298             if (pBorderArray->GetCount() == 4) {
    299                 pDashArray = pBorderArray->GetArray(3);
    300                 if (pDashArray == NULL) {
    301                     return NULL;
    302                 }
    303                 style_char = 'D';
    304             }
    305         } else {
    306             width = 1;
    307         }
    308     } else {
    309         CFX_ByteString style = pBS->GetString("S");
    310         pDashArray = pBS->GetArray("D");
    311         style_char = style[1];
    312         width = pBS->GetNumber("W");
    313     }
    314     if (width <= 0) {
    315         return NULL;
    316     }
    317     CPDF_Array* pColor = m_pAnnotDict->GetArray("C");
    318     FX_DWORD argb = 0xff000000;
    319     if (pColor != NULL) {
    320         int R = (FX_INT32)(pColor->GetNumber(0) * 255);
    321         int G = (FX_INT32)(pColor->GetNumber(1) * 255);
    322         int B = (FX_INT32)(pColor->GetNumber(2) * 255);
    323         argb = ArgbEncode(0xff, R, G, B);
    324     }
    325     CPDF_PathObject *pPathObject = FX_NEW CPDF_PathObject();
    326     if (!pPathObject) {
    327         return NULL;
    328     }
    329     CPDF_GraphStateData *pGraphState = pPathObject->m_GraphState.GetModify();
    330     if (!pGraphState) {
    331         pPathObject->Release();
    332         return NULL;
    333     }
    334     pGraphState->m_LineWidth = width;
    335     CPDF_ColorStateData *pColorData = pPathObject->m_ColorState.GetModify();
    336     if (!pColorData) {
    337         pPathObject->Release();
    338         return NULL;
    339     }
    340     pColorData->m_StrokeRGB = argb;
    341     pPathObject->m_bStroke = TRUE;
    342     pPathObject->m_FillType = 0;
    343     if (style_char == 'D') {
    344         if (pDashArray) {
    345             FX_DWORD dash_count = pDashArray->GetCount();
    346             if (dash_count % 2) {
    347                 dash_count ++;
    348             }
    349             pGraphState->m_DashArray = FX_Alloc(FX_FLOAT, dash_count);
    350             if (pGraphState->m_DashArray == NULL) {
    351                 pPathObject->Release();
    352                 return NULL;
    353             }
    354             pGraphState->m_DashCount = dash_count;
    355             FX_DWORD i;
    356             for (i = 0; i < pDashArray->GetCount(); i ++) {
    357                 pGraphState->m_DashArray[i] = pDashArray->GetNumber(i);
    358             }
    359             if (i < dash_count) {
    360                 pGraphState->m_DashArray[i] = pGraphState->m_DashArray[i - 1];
    361             }
    362         } else {
    363             pGraphState->m_DashArray = FX_Alloc(FX_FLOAT, 2);
    364             if (pGraphState->m_DashArray == NULL) {
    365                 pPathObject->Release();
    366                 return NULL;
    367             }
    368             pGraphState->m_DashCount = 2;
    369             pGraphState->m_DashArray[0] = pGraphState->m_DashArray[1] = 3 * 1.0f;
    370         }
    371     }
    372     CFX_FloatRect rect;
    373     GetRect(rect);
    374     width /= 2;
    375     CPDF_PathData *pPathData = pPathObject->m_Path.GetModify();
    376     if (pPathData) {
    377         pPathData->AppendRect(rect.left + width, rect.bottom + width, rect.right - width, rect.top - width);
    378     }
    379     pPathObject->CalcBoundingBox();
    380     return pPathObject;
    381 }
    382 void CPDF_Annot::DrawBorder(CFX_RenderDevice* pDevice, const CFX_AffineMatrix* pUser2Device, const CPDF_RenderOptions* pOptions)
    383 {
    384     if (GetSubType() == "Popup") {
    385         return;
    386     }
    387     FX_DWORD annot_flags = GetFlags();
    388     if (annot_flags & ANNOTFLAG_HIDDEN) {
    389         return;
    390     }
    391     FX_BOOL bPrinting = pDevice->GetDeviceClass() == FXDC_PRINTER || (pOptions && (pOptions->m_Flags & RENDER_PRINTPREVIEW));
    392     if (bPrinting && (annot_flags & ANNOTFLAG_PRINT) == 0) {
    393         return;
    394     }
    395     if (!bPrinting && (annot_flags & ANNOTFLAG_NOVIEW)) {
    396         return;
    397     }
    398     CPDF_Dictionary* pBS = m_pAnnotDict->GetDict("BS");
    399     char style_char;
    400     FX_FLOAT width;
    401     CPDF_Array* pDashArray = NULL;
    402     if (pBS == NULL) {
    403         CPDF_Array* pBorderArray = m_pAnnotDict->GetArray("Border");
    404         style_char = 'S';
    405         if (pBorderArray) {
    406             width = pBorderArray->GetNumber(2);
    407             if (pBorderArray->GetCount() == 4) {
    408                 pDashArray = pBorderArray->GetArray(3);
    409                 if (pDashArray == NULL) {
    410                     return;
    411                 }
    412                 int nLen = pDashArray->GetCount();
    413                 int i = 0;
    414                 for (; i < nLen; ++i) {
    415                     CPDF_Object*pObj = pDashArray->GetElementValue(i);
    416                     if (pObj && pObj->GetInteger()) {
    417                         break;
    418                     }
    419                 }
    420                 if (i == nLen) {
    421                     return;
    422                 }
    423                 style_char = 'D';
    424             }
    425         } else {
    426             width = 1;
    427         }
    428     } else {
    429         CFX_ByteString style = pBS->GetString("S");
    430         pDashArray = pBS->GetArray("D");
    431         style_char = style[1];
    432         width = pBS->GetNumber("W");
    433     }
    434     if (width <= 0) {
    435         return;
    436     }
    437     CPDF_Array* pColor = m_pAnnotDict->GetArray("C");
    438     FX_DWORD argb = 0xff000000;
    439     if (pColor != NULL) {
    440         int R = (FX_INT32)(pColor->GetNumber(0) * 255);
    441         int G = (FX_INT32)(pColor->GetNumber(1) * 255);
    442         int B = (FX_INT32)(pColor->GetNumber(2) * 255);
    443         argb = ArgbEncode(0xff, R, G, B);
    444     }
    445     CPDF_GraphStateData graph_state;
    446     graph_state.m_LineWidth = width;
    447     if (style_char == 'D') {
    448         if (pDashArray) {
    449             FX_DWORD dash_count = pDashArray->GetCount();
    450             if (dash_count % 2) {
    451                 dash_count ++;
    452             }
    453             graph_state.m_DashArray = FX_Alloc(FX_FLOAT, dash_count);
    454             if (graph_state.m_DashArray == NULL) {
    455                 return ;
    456             }
    457             graph_state.m_DashCount = dash_count;
    458             FX_DWORD i;
    459             for (i = 0; i < pDashArray->GetCount(); i ++) {
    460                 graph_state.m_DashArray[i] = pDashArray->GetNumber(i);
    461             }
    462             if (i < dash_count) {
    463                 graph_state.m_DashArray[i] = graph_state.m_DashArray[i - 1];
    464             }
    465         } else {
    466             graph_state.m_DashArray = FX_Alloc(FX_FLOAT, 2);
    467             if (graph_state.m_DashArray == NULL) {
    468                 return ;
    469             }
    470             graph_state.m_DashCount = 2;
    471             graph_state.m_DashArray[0] = graph_state.m_DashArray[1] = 3 * 1.0f;
    472         }
    473     }
    474     CFX_FloatRect rect;
    475     GetRect(rect);
    476     CPDF_PathData path;
    477     width /= 2;
    478     path.AppendRect(rect.left + width, rect.bottom + width, rect.right - width, rect.top - width);
    479     int fill_type = 0;
    480     if (pOptions && (pOptions->m_Flags & RENDER_NOPATHSMOOTH)) {
    481         fill_type |= FXFILL_NOPATHSMOOTH;
    482     }
    483     pDevice->DrawPath(&path, pUser2Device, &graph_state, argb, argb, fill_type);
    484 }
    485 int CPDF_Annot::CountIRTNotes()
    486 {
    487     int count = 0;
    488     for (int i = 0; i < m_pList->Count(); i ++) {
    489         CPDF_Annot* pAnnot = m_pList->GetAt(i);
    490         if (pAnnot == NULL) {
    491             continue;
    492         }
    493         CPDF_Dictionary* pIRT = pAnnot->m_pAnnotDict->GetDict("IRT");
    494         if (pIRT != m_pAnnotDict) {
    495             continue;
    496         }
    497         count ++;
    498     }
    499     return count;
    500 }
    501 CPDF_Annot* CPDF_Annot::GetIRTNote(int index)
    502 {
    503     int count = 0;
    504     for (int i = 0; i < m_pList->Count(); i ++) {
    505         CPDF_Annot* pAnnot = m_pList->GetAt(i);
    506         if (pAnnot == NULL) {
    507             continue;
    508         }
    509         CPDF_Dictionary* pIRT = pAnnot->m_pAnnotDict->GetDict("IRT");
    510         if (pIRT != m_pAnnotDict) {
    511             continue;
    512         }
    513         if (count == index) {
    514             return pAnnot;
    515         }
    516         count ++;
    517     }
    518     return NULL;
    519 }
    520