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