Home | History | Annotate | Download | only in fpdf_render
      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 "render_int.h"
      8 
      9 #include "core/include/fpdfapi/fpdf_module.h"
     10 #include "core/include/fpdfapi/fpdf_render.h"
     11 #include "core/include/fxge/fx_ge.h"
     12 #include "core/src/fpdfapi/fpdf_page/pageint.h"
     13 
     14 CPDF_DocRenderData::CPDF_DocRenderData(CPDF_Document* pPDFDoc)
     15     : m_pPDFDoc(pPDFDoc), m_pFontCache(new CFX_FontCache) {}
     16 
     17 CPDF_DocRenderData::~CPDF_DocRenderData() {
     18   Clear(TRUE);
     19 }
     20 
     21 void CPDF_DocRenderData::Clear(FX_BOOL bRelease) {
     22   for (auto it = m_Type3FaceMap.begin(); it != m_Type3FaceMap.end();) {
     23     auto curr_it = it++;
     24     CPDF_CountedObject<CPDF_Type3Cache>* cache = curr_it->second;
     25     if (bRelease || cache->use_count() < 2) {
     26       delete cache->get();
     27       delete cache;
     28       m_Type3FaceMap.erase(curr_it);
     29     }
     30   }
     31 
     32   for (auto it = m_TransferFuncMap.begin(); it != m_TransferFuncMap.end();) {
     33     auto curr_it = it++;
     34     CPDF_CountedObject<CPDF_TransferFunc>* value = curr_it->second;
     35     if (bRelease || value->use_count() < 2) {
     36       delete value->get();
     37       delete value;
     38       m_TransferFuncMap.erase(curr_it);
     39     }
     40   }
     41 
     42   if (m_pFontCache) {
     43     if (bRelease) {
     44       delete m_pFontCache;
     45       m_pFontCache = NULL;
     46     } else {
     47       m_pFontCache->FreeCache(FALSE);
     48     }
     49   }
     50 }
     51 
     52 CPDF_Type3Cache* CPDF_DocRenderData::GetCachedType3(CPDF_Type3Font* pFont) {
     53   CPDF_CountedObject<CPDF_Type3Cache>* pCache;
     54   auto it = m_Type3FaceMap.find(pFont);
     55   if (it == m_Type3FaceMap.end()) {
     56     CPDF_Type3Cache* pType3 = new CPDF_Type3Cache(pFont);
     57     pCache = new CPDF_CountedObject<CPDF_Type3Cache>(pType3);
     58     m_Type3FaceMap[pFont] = pCache;
     59   } else {
     60     pCache = it->second;
     61   }
     62   return pCache->AddRef();
     63 }
     64 
     65 void CPDF_DocRenderData::ReleaseCachedType3(CPDF_Type3Font* pFont) {
     66   auto it = m_Type3FaceMap.find(pFont);
     67   if (it != m_Type3FaceMap.end())
     68     it->second->RemoveRef();
     69 }
     70 
     71 class CPDF_RenderModule : public IPDF_RenderModule {
     72  public:
     73   CPDF_RenderModule() {}
     74 
     75  private:
     76   ~CPDF_RenderModule() override {}
     77 
     78   CPDF_DocRenderData* CreateDocData(CPDF_Document* pDoc) override;
     79   void DestroyDocData(CPDF_DocRenderData* p) override;
     80   void ClearDocData(CPDF_DocRenderData* p) override;
     81 
     82   CPDF_DocRenderData* GetRenderData() override { return &m_RenderData; }
     83 
     84   CPDF_PageRenderCache* CreatePageCache(CPDF_Page* pPage) override {
     85     return new CPDF_PageRenderCache(pPage);
     86   }
     87 
     88   void DestroyPageCache(CPDF_PageRenderCache* pCache) override;
     89 
     90   CPDF_RenderConfig* GetConfig() override { return &m_RenderConfig; }
     91 
     92   CPDF_DocRenderData m_RenderData;
     93   CPDF_RenderConfig m_RenderConfig;
     94 };
     95 
     96 CPDF_DocRenderData* CPDF_RenderModule::CreateDocData(CPDF_Document* pDoc) {
     97   return new CPDF_DocRenderData(pDoc);
     98 }
     99 void CPDF_RenderModule::DestroyDocData(CPDF_DocRenderData* pDocData) {
    100   delete pDocData;
    101 }
    102 void CPDF_RenderModule::ClearDocData(CPDF_DocRenderData* p) {
    103   if (p) {
    104     p->Clear(FALSE);
    105   }
    106 }
    107 void CPDF_RenderModule::DestroyPageCache(CPDF_PageRenderCache* pCache) {
    108   delete pCache;
    109 }
    110 
    111 void CPDF_ModuleMgr::InitRenderModule() {
    112   m_pRenderModule.reset(new CPDF_RenderModule);
    113 }
    114 
    115 CPDF_RenderOptions::CPDF_RenderOptions()
    116     : m_ColorMode(RENDER_COLOR_NORMAL),
    117       m_Flags(RENDER_CLEARTYPE),
    118       m_Interpolation(0),
    119       m_AddFlags(0),
    120       m_pOCContext(NULL),
    121       m_dwLimitCacheSize(1024 * 1024 * 100),
    122       m_HalftoneLimit(-1) {}
    123 FX_ARGB CPDF_RenderOptions::TranslateColor(FX_ARGB argb) const {
    124   if (m_ColorMode == RENDER_COLOR_NORMAL) {
    125     return argb;
    126   }
    127   if (m_ColorMode == RENDER_COLOR_ALPHA) {
    128     return argb;
    129   }
    130   int a, r, g, b;
    131   ArgbDecode(argb, a, r, g, b);
    132   int gray = FXRGB2GRAY(r, g, b);
    133   if (m_ColorMode == RENDER_COLOR_TWOCOLOR) {
    134     int color = (r - gray) * (r - gray) + (g - gray) * (g - gray) +
    135                 (b - gray) * (b - gray);
    136     if (gray < 35 && color < 20) {
    137       return ArgbEncode(a, m_ForeColor);
    138     }
    139     if (gray > 221 && color < 20) {
    140       return ArgbEncode(a, m_BackColor);
    141     }
    142     return argb;
    143   }
    144   int fr = FXSYS_GetRValue(m_ForeColor);
    145   int fg = FXSYS_GetGValue(m_ForeColor);
    146   int fb = FXSYS_GetBValue(m_ForeColor);
    147   int br = FXSYS_GetRValue(m_BackColor);
    148   int bg = FXSYS_GetGValue(m_BackColor);
    149   int bb = FXSYS_GetBValue(m_BackColor);
    150   r = (br - fr) * gray / 255 + fr;
    151   g = (bg - fg) * gray / 255 + fg;
    152   b = (bb - fb) * gray / 255 + fb;
    153   return ArgbEncode(a, r, g, b);
    154 }
    155 
    156 // static
    157 int CPDF_RenderStatus::s_CurrentRecursionDepth = 0;
    158 
    159 CPDF_RenderStatus::CPDF_RenderStatus()
    160     : m_pFormResource(nullptr),
    161       m_pPageResource(nullptr),
    162       m_pContext(nullptr),
    163       m_bStopped(FALSE),
    164       m_pDevice(nullptr),
    165       m_pCurObj(nullptr),
    166       m_pStopObj(nullptr),
    167       m_HalftoneLimit(0),
    168       m_bPrint(FALSE),
    169       m_Transparency(0),
    170       m_DitherBits(0),
    171       m_bDropObjects(FALSE),
    172       m_bStdCS(FALSE),
    173       m_GroupFamily(0),
    174       m_bLoadMask(FALSE),
    175       m_pType3Char(nullptr),
    176       m_T3FillColor(0),
    177       m_curBlend(FXDIB_BLEND_NORMAL) {}
    178 
    179 CPDF_RenderStatus::~CPDF_RenderStatus() {
    180 }
    181 
    182 FX_BOOL CPDF_RenderStatus::Initialize(CPDF_RenderContext* pContext,
    183                                       CFX_RenderDevice* pDevice,
    184                                       const CFX_Matrix* pDeviceMatrix,
    185                                       const CPDF_PageObject* pStopObj,
    186                                       const CPDF_RenderStatus* pParentState,
    187                                       const CPDF_GraphicStates* pInitialStates,
    188                                       const CPDF_RenderOptions* pOptions,
    189                                       int transparency,
    190                                       FX_BOOL bDropObjects,
    191                                       CPDF_Dictionary* pFormResource,
    192                                       FX_BOOL bStdCS,
    193                                       CPDF_Type3Char* pType3Char,
    194                                       FX_ARGB fill_color,
    195                                       FX_DWORD GroupFamily,
    196                                       FX_BOOL bLoadMask) {
    197   m_pContext = pContext;
    198   m_pDevice = pDevice;
    199   m_DitherBits = pDevice->GetDeviceCaps(FXDC_DITHER_BITS);
    200   m_bPrint = m_pDevice->GetDeviceClass() != FXDC_DISPLAY;
    201   if (pDeviceMatrix) {
    202     m_DeviceMatrix = *pDeviceMatrix;
    203   }
    204   m_pStopObj = pStopObj;
    205   if (pOptions) {
    206     m_Options = *pOptions;
    207   }
    208   m_bDropObjects = bDropObjects;
    209   m_bStdCS = bStdCS;
    210   m_T3FillColor = fill_color;
    211   m_pType3Char = pType3Char;
    212   m_GroupFamily = GroupFamily;
    213   m_bLoadMask = bLoadMask;
    214   m_pFormResource = pFormResource;
    215   m_pPageResource = m_pContext->m_pPageResources;
    216   if (pInitialStates && !m_pType3Char) {
    217     m_InitialStates.CopyStates(*pInitialStates);
    218     if (pParentState) {
    219       CPDF_ColorStateData* pColorData =
    220           (CPDF_ColorStateData*)(const CPDF_ColorStateData*)
    221               m_InitialStates.m_ColorState;
    222       CPDF_ColorStateData* pParentData =
    223           (CPDF_ColorStateData*)(const CPDF_ColorStateData*)
    224               pParentState->m_InitialStates.m_ColorState;
    225       if (!pColorData || pColorData->m_FillColor.IsNull()) {
    226         CPDF_ColorStateData* pData = m_InitialStates.m_ColorState.GetModify();
    227         pData->m_FillRGB = pParentData->m_FillRGB;
    228         pData->m_FillColor.Copy(&pParentData->m_FillColor);
    229       }
    230       if (!pColorData || pColorData->m_StrokeColor.IsNull()) {
    231         CPDF_ColorStateData* pData = m_InitialStates.m_ColorState.GetModify();
    232         pData->m_StrokeRGB = pParentData->m_FillRGB;
    233         pData->m_StrokeColor.Copy(&pParentData->m_StrokeColor);
    234       }
    235     }
    236   } else {
    237     m_InitialStates.DefaultStates();
    238   }
    239   m_pObjectRenderer.reset();
    240   m_Transparency = transparency;
    241   return TRUE;
    242 }
    243 void CPDF_RenderStatus::RenderObjectList(const CPDF_PageObjects* pObjs,
    244                                          const CFX_Matrix* pObj2Device) {
    245   CFX_FloatRect clip_rect = m_pDevice->GetClipBox();
    246   CFX_Matrix device2object;
    247   device2object.SetReverse(*pObj2Device);
    248   device2object.TransformRect(clip_rect);
    249   int index = 0;
    250   FX_POSITION pos = pObjs->GetFirstObjectPosition();
    251   while (pos) {
    252     index++;
    253     CPDF_PageObject* pCurObj = pObjs->GetNextObject(pos);
    254     if (pCurObj == m_pStopObj) {
    255       m_bStopped = TRUE;
    256       return;
    257     }
    258     if (!pCurObj) {
    259       continue;
    260     }
    261     if (!pCurObj || pCurObj->m_Left > clip_rect.right ||
    262         pCurObj->m_Right < clip_rect.left ||
    263         pCurObj->m_Bottom > clip_rect.top ||
    264         pCurObj->m_Top < clip_rect.bottom) {
    265       continue;
    266     }
    267     RenderSingleObject(pCurObj, pObj2Device);
    268     if (m_bStopped) {
    269       return;
    270     }
    271   }
    272 }
    273 void CPDF_RenderStatus::RenderSingleObject(const CPDF_PageObject* pObj,
    274                                            const CFX_Matrix* pObj2Device) {
    275   CFX_AutoRestorer<int> restorer(&s_CurrentRecursionDepth);
    276   if (++s_CurrentRecursionDepth > kRenderMaxRecursionDepth) {
    277     return;
    278   }
    279   m_pCurObj = pObj;
    280   if (m_Options.m_pOCContext && pObj->m_ContentMark.NotNull()) {
    281     if (!m_Options.m_pOCContext->CheckObjectVisible(pObj)) {
    282       return;
    283     }
    284   }
    285   ProcessClipPath(pObj->m_ClipPath, pObj2Device);
    286   if (ProcessTransparency(pObj, pObj2Device)) {
    287     return;
    288   }
    289   ProcessObjectNoClip(pObj, pObj2Device);
    290 }
    291 
    292 FX_BOOL CPDF_RenderStatus::ContinueSingleObject(const CPDF_PageObject* pObj,
    293                                                 const CFX_Matrix* pObj2Device,
    294                                                 IFX_Pause* pPause) {
    295   if (m_pObjectRenderer) {
    296     if (m_pObjectRenderer->Continue(pPause))
    297       return TRUE;
    298 
    299     if (!m_pObjectRenderer->m_Result)
    300       DrawObjWithBackground(pObj, pObj2Device);
    301     m_pObjectRenderer.reset();
    302     return FALSE;
    303   }
    304 
    305   m_pCurObj = pObj;
    306   if (m_Options.m_pOCContext && pObj->m_ContentMark.NotNull() &&
    307       !m_Options.m_pOCContext->CheckObjectVisible(pObj)) {
    308     return FALSE;
    309   }
    310 
    311   ProcessClipPath(pObj->m_ClipPath, pObj2Device);
    312   if (ProcessTransparency(pObj, pObj2Device))
    313     return FALSE;
    314 
    315   if (pObj->m_Type == PDFPAGE_IMAGE) {
    316     m_pObjectRenderer.reset(IPDF_ObjectRenderer::Create(pObj->m_Type));
    317     if (!m_pObjectRenderer->Start(this, pObj, pObj2Device, FALSE)) {
    318       if (!m_pObjectRenderer->m_Result)
    319         DrawObjWithBackground(pObj, pObj2Device);
    320       m_pObjectRenderer.reset();
    321       return FALSE;
    322     }
    323     return ContinueSingleObject(pObj, pObj2Device, pPause);
    324   }
    325 
    326   ProcessObjectNoClip(pObj, pObj2Device);
    327   return FALSE;
    328 }
    329 
    330 IPDF_ObjectRenderer* IPDF_ObjectRenderer::Create(int type) {
    331   if (type != PDFPAGE_IMAGE) {
    332     return NULL;
    333   }
    334   return new CPDF_ImageRenderer;
    335 }
    336 FX_BOOL CPDF_RenderStatus::GetObjectClippedRect(const CPDF_PageObject* pObj,
    337                                                 const CFX_Matrix* pObj2Device,
    338                                                 FX_BOOL bLogical,
    339                                                 FX_RECT& rect) const {
    340   rect = pObj->GetBBox(pObj2Device);
    341   FX_RECT rtClip = m_pDevice->GetClipBox();
    342   if (!bLogical) {
    343     CFX_Matrix dCTM = m_pDevice->GetCTM();
    344     FX_FLOAT a = FXSYS_fabs(dCTM.a);
    345     FX_FLOAT d = FXSYS_fabs(dCTM.d);
    346     if (a != 1.0f || d != 1.0f) {
    347       rect.right = rect.left + (int32_t)FXSYS_ceil((FX_FLOAT)rect.Width() * a);
    348       rect.bottom = rect.top + (int32_t)FXSYS_ceil((FX_FLOAT)rect.Height() * d);
    349       rtClip.right =
    350           rtClip.left + (int32_t)FXSYS_ceil((FX_FLOAT)rtClip.Width() * a);
    351       rtClip.bottom =
    352           rtClip.top + (int32_t)FXSYS_ceil((FX_FLOAT)rtClip.Height() * d);
    353     }
    354   }
    355   rect.Intersect(rtClip);
    356   return rect.IsEmpty();
    357 }
    358 void CPDF_RenderStatus::DitherObjectArea(const CPDF_PageObject* pObj,
    359                                          const CFX_Matrix* pObj2Device) {
    360   CFX_DIBitmap* pBitmap = m_pDevice->GetBitmap();
    361   if (!pBitmap) {
    362     return;
    363   }
    364   FX_RECT rect;
    365   if (GetObjectClippedRect(pObj, pObj2Device, FALSE, rect)) {
    366     return;
    367   }
    368   if (m_DitherBits == 2) {
    369     static FX_ARGB pal[4] = {0, 85, 170, 255};
    370     pBitmap->DitherFS(pal, 4, &rect);
    371   } else if (m_DitherBits == 3) {
    372     static FX_ARGB pal[8] = {0, 36, 73, 109, 146, 182, 219, 255};
    373     pBitmap->DitherFS(pal, 8, &rect);
    374   } else if (m_DitherBits == 4) {
    375     static FX_ARGB pal[16] = {0,   17,  34,  51,  68,  85,  102, 119,
    376                               136, 153, 170, 187, 204, 221, 238, 255};
    377     pBitmap->DitherFS(pal, 16, &rect);
    378   }
    379 }
    380 void CPDF_RenderStatus::ProcessObjectNoClip(const CPDF_PageObject* pObj,
    381                                             const CFX_Matrix* pObj2Device) {
    382   FX_BOOL bRet = FALSE;
    383   switch (pObj->m_Type) {
    384     case PDFPAGE_TEXT:
    385       bRet = ProcessText((CPDF_TextObject*)pObj, pObj2Device, NULL);
    386       break;
    387     case PDFPAGE_PATH:
    388       bRet = ProcessPath((CPDF_PathObject*)pObj, pObj2Device);
    389       break;
    390     case PDFPAGE_IMAGE:
    391       bRet = ProcessImage((CPDF_ImageObject*)pObj, pObj2Device);
    392       break;
    393     case PDFPAGE_SHADING:
    394       bRet = ProcessShading((CPDF_ShadingObject*)pObj, pObj2Device);
    395       break;
    396     case PDFPAGE_FORM:
    397       bRet = ProcessForm((CPDF_FormObject*)pObj, pObj2Device);
    398       break;
    399   }
    400   if (!bRet) {
    401     DrawObjWithBackground(pObj, pObj2Device);
    402   }
    403 }
    404 FX_BOOL CPDF_RenderStatus::DrawObjWithBlend(const CPDF_PageObject* pObj,
    405                                             const CFX_Matrix* pObj2Device) {
    406   FX_BOOL bRet = FALSE;
    407   switch (pObj->m_Type) {
    408     case PDFPAGE_PATH:
    409       bRet = ProcessPath((CPDF_PathObject*)pObj, pObj2Device);
    410       break;
    411     case PDFPAGE_IMAGE:
    412       bRet = ProcessImage((CPDF_ImageObject*)pObj, pObj2Device);
    413       break;
    414     case PDFPAGE_FORM:
    415       bRet = ProcessForm((CPDF_FormObject*)pObj, pObj2Device);
    416       break;
    417   }
    418   return bRet;
    419 }
    420 void CPDF_RenderStatus::GetScaledMatrix(CFX_Matrix& matrix) const {
    421   CFX_Matrix dCTM = m_pDevice->GetCTM();
    422   matrix.a *= FXSYS_fabs(dCTM.a);
    423   matrix.d *= FXSYS_fabs(dCTM.d);
    424 }
    425 void CPDF_RenderStatus::DrawObjWithBackground(const CPDF_PageObject* pObj,
    426                                               const CFX_Matrix* pObj2Device) {
    427   FX_RECT rect;
    428   if (GetObjectClippedRect(pObj, pObj2Device, FALSE, rect)) {
    429     return;
    430   }
    431   int res = 300;
    432   if (pObj->m_Type == PDFPAGE_IMAGE &&
    433       m_pDevice->GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) {
    434     res = 0;
    435   }
    436   CPDF_ScaledRenderBuffer buffer;
    437   if (!buffer.Initialize(m_pContext, m_pDevice, rect, pObj, &m_Options, res)) {
    438     return;
    439   }
    440   CFX_Matrix matrix = *pObj2Device;
    441   matrix.Concat(*buffer.GetMatrix());
    442   GetScaledMatrix(matrix);
    443   CPDF_Dictionary* pFormResource = NULL;
    444   if (pObj->m_Type == PDFPAGE_FORM) {
    445     CPDF_FormObject* pFormObj = (CPDF_FormObject*)pObj;
    446     if (pFormObj->m_pForm && pFormObj->m_pForm->m_pFormDict) {
    447       pFormResource = pFormObj->m_pForm->m_pFormDict->GetDict("Resources");
    448     }
    449   }
    450   CPDF_RenderStatus status;
    451   status.Initialize(m_pContext, buffer.GetDevice(), buffer.GetMatrix(), NULL,
    452                     NULL, NULL, &m_Options, m_Transparency, m_bDropObjects,
    453                     pFormResource);
    454   status.RenderSingleObject(pObj, &matrix);
    455   buffer.OutputToDevice();
    456 }
    457 FX_BOOL CPDF_RenderStatus::ProcessForm(CPDF_FormObject* pFormObj,
    458                                        const CFX_Matrix* pObj2Device) {
    459   CPDF_Dictionary* pOC = pFormObj->m_pForm->m_pFormDict->GetDict("OC");
    460   if (pOC && m_Options.m_pOCContext &&
    461       !m_Options.m_pOCContext->CheckOCGVisible(pOC)) {
    462     return TRUE;
    463   }
    464   CFX_Matrix matrix = pFormObj->m_FormMatrix;
    465   matrix.Concat(*pObj2Device);
    466   CPDF_Dictionary* pResources = NULL;
    467   if (pFormObj->m_pForm && pFormObj->m_pForm->m_pFormDict) {
    468     pResources = pFormObj->m_pForm->m_pFormDict->GetDict("Resources");
    469   }
    470   CPDF_RenderStatus status;
    471   status.Initialize(m_pContext, m_pDevice, NULL, m_pStopObj, this, pFormObj,
    472                     &m_Options, m_Transparency, m_bDropObjects, pResources,
    473                     FALSE);
    474   status.m_curBlend = m_curBlend;
    475   m_pDevice->SaveState();
    476   status.RenderObjectList(pFormObj->m_pForm, &matrix);
    477   m_bStopped = status.m_bStopped;
    478   m_pDevice->RestoreState();
    479   return TRUE;
    480 }
    481 FX_BOOL IsAvailableMatrix(const CFX_Matrix& matrix) {
    482   if (matrix.a == 0 || matrix.d == 0) {
    483     return matrix.b != 0 && matrix.c != 0;
    484   }
    485   if (matrix.b == 0 || matrix.c == 0) {
    486     return matrix.a != 0 && matrix.d != 0;
    487   }
    488   return TRUE;
    489 }
    490 FX_BOOL CPDF_RenderStatus::ProcessPath(CPDF_PathObject* pPathObj,
    491                                        const CFX_Matrix* pObj2Device) {
    492   int FillType = pPathObj->m_FillType;
    493   FX_BOOL bStroke = pPathObj->m_bStroke;
    494   ProcessPathPattern(pPathObj, pObj2Device, FillType, bStroke);
    495   if (FillType == 0 && !bStroke) {
    496     return TRUE;
    497   }
    498   FX_DWORD fill_argb = 0;
    499   if (FillType) {
    500     fill_argb = GetFillArgb(pPathObj);
    501   }
    502   FX_DWORD stroke_argb = 0;
    503   if (bStroke) {
    504     stroke_argb = GetStrokeArgb(pPathObj);
    505   }
    506   CFX_Matrix path_matrix = pPathObj->m_Matrix;
    507   path_matrix.Concat(*pObj2Device);
    508   if (!IsAvailableMatrix(path_matrix)) {
    509     return TRUE;
    510   }
    511   if (FillType && (m_Options.m_Flags & RENDER_RECT_AA)) {
    512     FillType |= FXFILL_RECT_AA;
    513   }
    514   if (m_Options.m_Flags & RENDER_FILL_FULLCOVER) {
    515     FillType |= FXFILL_FULLCOVER;
    516   }
    517   if (m_Options.m_Flags & RENDER_NOPATHSMOOTH) {
    518     FillType |= FXFILL_NOPATHSMOOTH;
    519   }
    520   if (bStroke) {
    521     FillType |= FX_FILL_STROKE;
    522   }
    523   const CPDF_GeneralStateData* pGeneralData =
    524       ((CPDF_PageObject*)pPathObj)->m_GeneralState;
    525   if (pGeneralData && pGeneralData->m_StrokeAdjust) {
    526     FillType |= FX_STROKE_ADJUST;
    527   }
    528   if (m_pType3Char) {
    529     FillType |= FX_FILL_TEXT_MODE;
    530   }
    531   CFX_GraphStateData graphState(*pPathObj->m_GraphState);
    532   if (m_Options.m_Flags & RENDER_THINLINE) {
    533     graphState.m_LineWidth = 0;
    534   }
    535   return m_pDevice->DrawPath(pPathObj->m_Path, &path_matrix, &graphState,
    536                              fill_argb, stroke_argb, FillType, 0, NULL,
    537                              m_curBlend);
    538 }
    539 CPDF_TransferFunc* CPDF_RenderStatus::GetTransferFunc(CPDF_Object* pObj) const {
    540   ASSERT(pObj);
    541   CPDF_DocRenderData* pDocCache = m_pContext->m_pDocument->GetRenderData();
    542   return pDocCache ? pDocCache->GetTransferFunc(pObj) : nullptr;
    543 }
    544 FX_ARGB CPDF_RenderStatus::GetFillArgb(const CPDF_PageObject* pObj,
    545                                        FX_BOOL bType3) const {
    546   CPDF_ColorStateData* pColorData =
    547       (CPDF_ColorStateData*)(const CPDF_ColorStateData*)pObj->m_ColorState;
    548   if (m_pType3Char && !bType3 &&
    549       (!m_pType3Char->m_bColored ||
    550        (m_pType3Char->m_bColored &&
    551         (!pColorData || pColorData->m_FillColor.IsNull())))) {
    552     return m_T3FillColor;
    553   }
    554   if (!pColorData || pColorData->m_FillColor.IsNull()) {
    555     pColorData = (CPDF_ColorStateData*)(const CPDF_ColorStateData*)
    556                      m_InitialStates.m_ColorState;
    557   }
    558   FX_COLORREF rgb = pColorData->m_FillRGB;
    559   if (rgb == (FX_DWORD)-1) {
    560     return 0;
    561   }
    562   const CPDF_GeneralStateData* pGeneralData = pObj->m_GeneralState;
    563   int alpha;
    564   if (pGeneralData) {
    565     alpha = (int32_t)(pGeneralData->m_FillAlpha * 255);
    566     if (pGeneralData->m_pTR) {
    567       if (!pGeneralData->m_pTransferFunc) {
    568         ((CPDF_GeneralStateData*)pGeneralData)->m_pTransferFunc =
    569             GetTransferFunc(pGeneralData->m_pTR);
    570       }
    571       if (pGeneralData->m_pTransferFunc) {
    572         rgb = pGeneralData->m_pTransferFunc->TranslateColor(rgb);
    573       }
    574     }
    575   } else {
    576     alpha = 255;
    577   }
    578   return m_Options.TranslateColor(ArgbEncode(alpha, rgb));
    579 }
    580 FX_ARGB CPDF_RenderStatus::GetStrokeArgb(const CPDF_PageObject* pObj) const {
    581   CPDF_ColorStateData* pColorData =
    582       (CPDF_ColorStateData*)(const CPDF_ColorStateData*)pObj->m_ColorState;
    583   if (m_pType3Char && (!m_pType3Char->m_bColored ||
    584                        (m_pType3Char->m_bColored &&
    585                         (!pColorData || pColorData->m_StrokeColor.IsNull())))) {
    586     return m_T3FillColor;
    587   }
    588   if (!pColorData || pColorData->m_StrokeColor.IsNull()) {
    589     pColorData = (CPDF_ColorStateData*)(const CPDF_ColorStateData*)
    590                      m_InitialStates.m_ColorState;
    591   }
    592   FX_COLORREF rgb = pColorData->m_StrokeRGB;
    593   if (rgb == (FX_DWORD)-1) {
    594     return 0;
    595   }
    596   const CPDF_GeneralStateData* pGeneralData = pObj->m_GeneralState;
    597   int alpha;
    598   if (pGeneralData) {
    599     alpha = (int32_t)(pGeneralData->m_StrokeAlpha * 255);
    600     if (pGeneralData->m_pTR) {
    601       if (!pGeneralData->m_pTransferFunc) {
    602         ((CPDF_GeneralStateData*)pGeneralData)->m_pTransferFunc =
    603             GetTransferFunc(pGeneralData->m_pTR);
    604       }
    605       if (pGeneralData->m_pTransferFunc) {
    606         rgb = pGeneralData->m_pTransferFunc->TranslateColor(rgb);
    607       }
    608     }
    609   } else {
    610     alpha = 255;
    611   }
    612   return m_Options.TranslateColor(ArgbEncode(alpha, rgb));
    613 }
    614 void CPDF_RenderStatus::ProcessClipPath(CPDF_ClipPath ClipPath,
    615                                         const CFX_Matrix* pObj2Device) {
    616   if (ClipPath.IsNull()) {
    617     if (!m_LastClipPath.IsNull()) {
    618       m_pDevice->RestoreState(TRUE);
    619       m_LastClipPath.SetNull();
    620     }
    621     return;
    622   }
    623   if (m_LastClipPath == ClipPath)
    624     return;
    625 
    626   m_LastClipPath = ClipPath;
    627   m_pDevice->RestoreState(TRUE);
    628   int nClipPath = ClipPath.GetPathCount();
    629   for (int i = 0; i < nClipPath; ++i) {
    630     const CFX_PathData* pPathData = ClipPath.GetPath(i);
    631     if (!pPathData)
    632       continue;
    633 
    634     if (pPathData->GetPointCount() == 0) {
    635       CFX_PathData EmptyPath;
    636       EmptyPath.AppendRect(-1, -1, 0, 0);
    637       int fill_mode = FXFILL_WINDING;
    638       m_pDevice->SetClip_PathFill(&EmptyPath, nullptr, fill_mode);
    639     } else {
    640       int ClipType = ClipPath.GetClipType(i);
    641       m_pDevice->SetClip_PathFill(pPathData, pObj2Device, ClipType);
    642     }
    643   }
    644   int textcount = ClipPath.GetTextCount();
    645   if (textcount == 0)
    646     return;
    647 
    648   if (m_pDevice->GetDeviceClass() == FXDC_DISPLAY &&
    649       !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)) {
    650     return;
    651   }
    652 
    653   std::unique_ptr<CFX_PathData> pTextClippingPath;
    654   for (int i = 0; i < textcount; ++i) {
    655     CPDF_TextObject* pText = ClipPath.GetText(i);
    656     if (pText) {
    657       if (!pTextClippingPath)
    658         pTextClippingPath.reset(new CFX_PathData);
    659       ProcessText(pText, pObj2Device, pTextClippingPath.get());
    660       continue;
    661     }
    662 
    663     if (!pTextClippingPath)
    664       continue;
    665 
    666     int fill_mode = FXFILL_WINDING;
    667     if (m_Options.m_Flags & RENDER_NOTEXTSMOOTH)
    668       fill_mode |= FXFILL_NOPATHSMOOTH;
    669     m_pDevice->SetClip_PathFill(pTextClippingPath.get(), nullptr, fill_mode);
    670     pTextClippingPath.reset();
    671   }
    672 }
    673 
    674 void CPDF_RenderStatus::DrawClipPath(CPDF_ClipPath ClipPath,
    675                                      const CFX_Matrix* pObj2Device) {
    676   if (ClipPath.IsNull()) {
    677     return;
    678   }
    679   int fill_mode = 0;
    680   if (m_Options.m_Flags & RENDER_NOPATHSMOOTH) {
    681     fill_mode |= FXFILL_NOPATHSMOOTH;
    682   }
    683   int nClipPath = ClipPath.GetPathCount();
    684   int i;
    685   for (i = 0; i < nClipPath; i++) {
    686     const CFX_PathData* pPathData = ClipPath.GetPath(i);
    687     if (!pPathData) {
    688       continue;
    689     }
    690     CFX_GraphStateData stroke_state;
    691     if (m_Options.m_Flags & RENDER_THINLINE) {
    692       stroke_state.m_LineWidth = 0;
    693     }
    694     m_pDevice->DrawPath(pPathData, pObj2Device, &stroke_state, 0, 0xffff0000,
    695                         fill_mode);
    696   }
    697 }
    698 FX_BOOL CPDF_RenderStatus::SelectClipPath(CPDF_PathObject* pPathObj,
    699                                           const CFX_Matrix* pObj2Device,
    700                                           FX_BOOL bStroke) {
    701   CFX_Matrix path_matrix = pPathObj->m_Matrix;
    702   path_matrix.Concat(*pObj2Device);
    703   if (bStroke) {
    704     CFX_GraphStateData graphState(*pPathObj->m_GraphState);
    705     if (m_Options.m_Flags & RENDER_THINLINE) {
    706       graphState.m_LineWidth = 0;
    707     }
    708     return m_pDevice->SetClip_PathStroke(pPathObj->m_Path, &path_matrix,
    709                                          &graphState);
    710   }
    711   int fill_mode = pPathObj->m_FillType;
    712   if (m_Options.m_Flags & RENDER_NOPATHSMOOTH) {
    713     fill_mode |= FXFILL_NOPATHSMOOTH;
    714   }
    715   return m_pDevice->SetClip_PathFill(pPathObj->m_Path, &path_matrix, fill_mode);
    716 }
    717 FX_BOOL CPDF_RenderStatus::ProcessTransparency(const CPDF_PageObject* pPageObj,
    718                                                const CFX_Matrix* pObj2Device) {
    719   const CPDF_GeneralStateData* pGeneralState = pPageObj->m_GeneralState;
    720   int blend_type =
    721       pGeneralState ? pGeneralState->m_BlendType : FXDIB_BLEND_NORMAL;
    722   if (blend_type == FXDIB_BLEND_UNSUPPORTED) {
    723     return TRUE;
    724   }
    725   CPDF_Dictionary* pSMaskDict =
    726       pGeneralState ? ToDictionary(pGeneralState->m_pSoftMask) : NULL;
    727   if (pSMaskDict) {
    728     if (pPageObj->m_Type == PDFPAGE_IMAGE &&
    729         ((CPDF_ImageObject*)pPageObj)->m_pImage->GetDict()->KeyExist("SMask")) {
    730       pSMaskDict = NULL;
    731     }
    732   }
    733   CPDF_Dictionary* pFormResource = NULL;
    734   FX_FLOAT group_alpha = 1.0f;
    735   int Transparency = m_Transparency;
    736   FX_BOOL bGroupTransparent = FALSE;
    737   if (pPageObj->m_Type == PDFPAGE_FORM) {
    738     CPDF_FormObject* pFormObj = (CPDF_FormObject*)pPageObj;
    739     const CPDF_GeneralStateData* pStateData =
    740         pFormObj->m_GeneralState.GetObject();
    741     if (pStateData) {
    742       group_alpha = pStateData->m_FillAlpha;
    743     }
    744     Transparency = pFormObj->m_pForm->m_Transparency;
    745     bGroupTransparent = !!(Transparency & PDFTRANS_ISOLATED);
    746     if (pFormObj->m_pForm->m_pFormDict) {
    747       pFormResource = pFormObj->m_pForm->m_pFormDict->GetDict("Resources");
    748     }
    749   }
    750   FX_BOOL bTextClip = FALSE;
    751   if (pPageObj->m_ClipPath.NotNull() && pPageObj->m_ClipPath.GetTextCount() &&
    752       m_pDevice->GetDeviceClass() == FXDC_DISPLAY &&
    753       !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)) {
    754     bTextClip = TRUE;
    755   }
    756   if ((m_Options.m_Flags & RENDER_OVERPRINT) &&
    757       pPageObj->m_Type == PDFPAGE_IMAGE && pGeneralState &&
    758       pGeneralState->m_FillOP && pGeneralState->m_StrokeOP) {
    759     CPDF_Document* pDocument = NULL;
    760     CPDF_Page* pPage = NULL;
    761     if (m_pContext->m_pPageCache) {
    762       pPage = m_pContext->m_pPageCache->GetPage();
    763       pDocument = pPage->m_pDocument;
    764     } else {
    765       pDocument = ((CPDF_ImageObject*)pPageObj)->m_pImage->GetDocument();
    766     }
    767     CPDF_Dictionary* pPageResources = pPage ? pPage->m_pPageResources : NULL;
    768     CPDF_Object* pCSObj = ((CPDF_ImageObject*)pPageObj)
    769                               ->m_pImage->GetStream()
    770                               ->GetDict()
    771                               ->GetElementValue("ColorSpace");
    772     CPDF_ColorSpace* pColorSpace =
    773         pDocument->LoadColorSpace(pCSObj, pPageResources);
    774     if (pColorSpace) {
    775       int format = pColorSpace->GetFamily();
    776       if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION ||
    777           format == PDFCS_DEVICEN) {
    778         blend_type = FXDIB_BLEND_DARKEN;
    779       }
    780       pDocument->GetPageData()->ReleaseColorSpace(pCSObj);
    781     }
    782   }
    783   if (!pSMaskDict && group_alpha == 1.0f && blend_type == FXDIB_BLEND_NORMAL &&
    784       !bTextClip && !bGroupTransparent) {
    785     return FALSE;
    786   }
    787   FX_BOOL isolated = Transparency & PDFTRANS_ISOLATED;
    788   if (m_bPrint) {
    789     FX_BOOL bRet = FALSE;
    790     int rendCaps = m_pDevice->GetRenderCaps();
    791     if (!((Transparency & PDFTRANS_ISOLATED) || pSMaskDict || bTextClip) &&
    792         (rendCaps & FXRC_BLEND_MODE)) {
    793       int oldBlend = m_curBlend;
    794       m_curBlend = blend_type;
    795       bRet = DrawObjWithBlend(pPageObj, pObj2Device);
    796       m_curBlend = oldBlend;
    797     }
    798     if (!bRet) {
    799       DrawObjWithBackground(pPageObj, pObj2Device);
    800     }
    801     return TRUE;
    802   }
    803   FX_RECT rect = pPageObj->GetBBox(pObj2Device);
    804   rect.Intersect(m_pDevice->GetClipBox());
    805   if (rect.IsEmpty()) {
    806     return TRUE;
    807   }
    808   CFX_Matrix deviceCTM = m_pDevice->GetCTM();
    809   FX_FLOAT scaleX = FXSYS_fabs(deviceCTM.a);
    810   FX_FLOAT scaleY = FXSYS_fabs(deviceCTM.d);
    811   int width = FXSYS_round((FX_FLOAT)rect.Width() * scaleX);
    812   int height = FXSYS_round((FX_FLOAT)rect.Height() * scaleY);
    813   CFX_FxgeDevice bitmap_device;
    814   std::unique_ptr<CFX_DIBitmap> oriDevice;
    815   if (!isolated && (m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) {
    816     oriDevice.reset(new CFX_DIBitmap);
    817     if (!m_pDevice->CreateCompatibleBitmap(oriDevice.get(), width, height))
    818       return TRUE;
    819 
    820     m_pDevice->GetDIBits(oriDevice.get(), rect.left, rect.top);
    821   }
    822   if (!bitmap_device.Create(width, height, FXDIB_Argb, 0, oriDevice.get()))
    823     return TRUE;
    824 
    825   CFX_DIBitmap* bitmap = bitmap_device.GetBitmap();
    826   bitmap->Clear(0);
    827   CFX_Matrix new_matrix = *pObj2Device;
    828   new_matrix.TranslateI(-rect.left, -rect.top);
    829   new_matrix.Scale(scaleX, scaleY);
    830   std::unique_ptr<CFX_DIBitmap> pTextMask;
    831   if (bTextClip) {
    832     pTextMask.reset(new CFX_DIBitmap);
    833     if (!pTextMask->Create(width, height, FXDIB_8bppMask))
    834       return TRUE;
    835 
    836     pTextMask->Clear(0);
    837     CFX_FxgeDevice text_device;
    838     text_device.Attach(pTextMask.get());
    839     for (FX_DWORD i = 0; i < pPageObj->m_ClipPath.GetTextCount(); i++) {
    840       CPDF_TextObject* textobj = pPageObj->m_ClipPath.GetText(i);
    841       if (!textobj) {
    842         break;
    843       }
    844       CFX_Matrix text_matrix;
    845       textobj->GetTextMatrix(&text_matrix);
    846       CPDF_TextRenderer::DrawTextPath(
    847           &text_device, textobj->m_nChars, textobj->m_pCharCodes,
    848           textobj->m_pCharPos, textobj->m_TextState.GetFont(),
    849           textobj->m_TextState.GetFontSize(), &text_matrix, &new_matrix,
    850           textobj->m_GraphState, (FX_ARGB)-1, 0, NULL);
    851     }
    852   }
    853   CPDF_RenderStatus bitmap_render;
    854   bitmap_render.Initialize(m_pContext, &bitmap_device, NULL, m_pStopObj, NULL,
    855                            NULL, &m_Options, 0, m_bDropObjects, pFormResource,
    856                            TRUE);
    857   bitmap_render.ProcessObjectNoClip(pPageObj, &new_matrix);
    858   m_bStopped = bitmap_render.m_bStopped;
    859   if (pSMaskDict) {
    860     CFX_Matrix smask_matrix;
    861     FXSYS_memcpy(&smask_matrix, pGeneralState->m_SMaskMatrix,
    862                  sizeof smask_matrix);
    863     smask_matrix.Concat(*pObj2Device);
    864     std::unique_ptr<CFX_DIBSource> pSMaskSource(
    865         LoadSMask(pSMaskDict, &rect, &smask_matrix));
    866     if (pSMaskSource)
    867       bitmap->MultiplyAlpha(pSMaskSource.get());
    868   }
    869   if (pTextMask) {
    870     bitmap->MultiplyAlpha(pTextMask.get());
    871     pTextMask.reset();
    872   }
    873   if (Transparency & PDFTRANS_GROUP && group_alpha != 1.0f) {
    874     bitmap->MultiplyAlpha((int32_t)(group_alpha * 255));
    875   }
    876   Transparency = m_Transparency;
    877   if (pPageObj->m_Type == PDFPAGE_FORM) {
    878     Transparency |= PDFTRANS_GROUP;
    879   }
    880   CompositeDIBitmap(bitmap, rect.left, rect.top, 0, 255, blend_type,
    881                     Transparency);
    882   return TRUE;
    883 }
    884 
    885 CFX_DIBitmap* CPDF_RenderStatus::GetBackdrop(const CPDF_PageObject* pObj,
    886                                              const FX_RECT& rect,
    887                                              int& left,
    888                                              int& top,
    889                                              FX_BOOL bBackAlphaRequired) {
    890   FX_RECT bbox = rect;
    891   bbox.Intersect(m_pDevice->GetClipBox());
    892   left = bbox.left;
    893   top = bbox.top;
    894   CFX_Matrix deviceCTM = m_pDevice->GetCTM();
    895   FX_FLOAT scaleX = FXSYS_fabs(deviceCTM.a);
    896   FX_FLOAT scaleY = FXSYS_fabs(deviceCTM.d);
    897   int width = FXSYS_round(bbox.Width() * scaleX);
    898   int height = FXSYS_round(bbox.Height() * scaleY);
    899   std::unique_ptr<CFX_DIBitmap> pBackdrop(new CFX_DIBitmap);
    900   if (bBackAlphaRequired && !m_bDropObjects)
    901     pBackdrop->Create(width, height, FXDIB_Argb);
    902   else
    903     m_pDevice->CreateCompatibleBitmap(pBackdrop.get(), width, height);
    904 
    905   if (!pBackdrop->GetBuffer())
    906     return nullptr;
    907 
    908   FX_BOOL bNeedDraw;
    909   if (pBackdrop->HasAlpha())
    910     bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT);
    911   else
    912     bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS);
    913 
    914   if (!bNeedDraw) {
    915     m_pDevice->GetDIBits(pBackdrop.get(), left, top);
    916     return pBackdrop.release();
    917   }
    918 
    919   CFX_Matrix FinalMatrix = m_DeviceMatrix;
    920   FinalMatrix.TranslateI(-left, -top);
    921   FinalMatrix.Scale(scaleX, scaleY);
    922   pBackdrop->Clear(pBackdrop->HasAlpha() ? 0 : 0xffffffff);
    923   CFX_FxgeDevice device;
    924   device.Attach(pBackdrop.get());
    925   m_pContext->Render(&device, pObj, &m_Options, &FinalMatrix);
    926   return pBackdrop.release();
    927 }
    928 
    929 void CPDF_RenderContext::GetBackground(CFX_DIBitmap* pBuffer,
    930                                        const CPDF_PageObject* pObj,
    931                                        const CPDF_RenderOptions* pOptions,
    932                                        CFX_Matrix* pFinalMatrix) {
    933   CFX_FxgeDevice device;
    934   device.Attach(pBuffer);
    935 
    936   FX_RECT rect(0, 0, device.GetWidth(), device.GetHeight());
    937   device.FillRect(&rect, 0xffffffff);
    938   Render(&device, pObj, pOptions, pFinalMatrix);
    939 }
    940 CPDF_GraphicStates* CPDF_RenderStatus::CloneObjStates(
    941     const CPDF_GraphicStates* pSrcStates,
    942     FX_BOOL bStroke) {
    943   if (!pSrcStates) {
    944     return NULL;
    945   }
    946   CPDF_GraphicStates* pStates = new CPDF_GraphicStates;
    947   pStates->CopyStates(*pSrcStates);
    948   CPDF_Color* pObjColor = bStroke ? pSrcStates->m_ColorState.GetStrokeColor()
    949                                   : pSrcStates->m_ColorState.GetFillColor();
    950   if (!pObjColor->IsNull()) {
    951     CPDF_ColorStateData* pColorData = pStates->m_ColorState.GetModify();
    952     pColorData->m_FillRGB =
    953         bStroke ? pSrcStates->m_ColorState.GetObject()->m_StrokeRGB
    954                 : pSrcStates->m_ColorState.GetObject()->m_FillRGB;
    955     pColorData->m_StrokeRGB = pColorData->m_FillRGB;
    956   }
    957   return pStates;
    958 }
    959 CPDF_RenderContext::CPDF_RenderContext(CPDF_Page* pPage)
    960     : m_pDocument(pPage->m_pDocument),
    961       m_pPageResources(pPage->m_pPageResources),
    962       m_pPageCache(pPage->GetRenderCache()),
    963       m_bFirstLayer(TRUE) {}
    964 CPDF_RenderContext::CPDF_RenderContext(CPDF_Document* pDoc,
    965                                        CPDF_PageRenderCache* pPageCache)
    966     : m_pDocument(pDoc),
    967       m_pPageResources(nullptr),
    968       m_pPageCache(pPageCache),
    969       m_bFirstLayer(TRUE) {}
    970 CPDF_RenderContext::~CPDF_RenderContext() {}
    971 void CPDF_RenderContext::AppendObjectList(CPDF_PageObjects* pObjs,
    972                                           const CFX_Matrix* pObject2Device) {
    973   _PDF_RenderItem* pItem = m_ContentList.AddSpace();
    974   pItem->m_pObjectList = pObjs;
    975   if (pObject2Device) {
    976     pItem->m_Matrix = *pObject2Device;
    977   } else {
    978     pItem->m_Matrix.SetIdentity();
    979   }
    980 }
    981 void CPDF_RenderContext::Render(CFX_RenderDevice* pDevice,
    982                                 const CPDF_RenderOptions* pOptions,
    983                                 const CFX_Matrix* pLastMatrix) {
    984   Render(pDevice, NULL, pOptions, pLastMatrix);
    985 }
    986 void CPDF_RenderContext::Render(CFX_RenderDevice* pDevice,
    987                                 const CPDF_PageObject* pStopObj,
    988                                 const CPDF_RenderOptions* pOptions,
    989                                 const CFX_Matrix* pLastMatrix) {
    990   int count = m_ContentList.GetSize();
    991   for (int j = 0; j < count; j++) {
    992     pDevice->SaveState();
    993     _PDF_RenderItem* pItem = m_ContentList.GetDataPtr(j);
    994     if (pLastMatrix) {
    995       CFX_Matrix FinalMatrix = pItem->m_Matrix;
    996       FinalMatrix.Concat(*pLastMatrix);
    997       CPDF_RenderStatus status;
    998       status.Initialize(this, pDevice, pLastMatrix, pStopObj, NULL, NULL,
    999                         pOptions, pItem->m_pObjectList->m_Transparency, FALSE,
   1000                         NULL);
   1001       status.RenderObjectList(pItem->m_pObjectList, &FinalMatrix);
   1002       if (status.m_Options.m_Flags & RENDER_LIMITEDIMAGECACHE) {
   1003         m_pPageCache->CacheOptimization(status.m_Options.m_dwLimitCacheSize);
   1004       }
   1005       if (status.m_bStopped) {
   1006         pDevice->RestoreState();
   1007         break;
   1008       }
   1009     } else {
   1010       CPDF_RenderStatus status;
   1011       status.Initialize(this, pDevice, NULL, pStopObj, NULL, NULL, pOptions,
   1012                         pItem->m_pObjectList->m_Transparency, FALSE, NULL);
   1013       status.RenderObjectList(pItem->m_pObjectList, &pItem->m_Matrix);
   1014       if (status.m_Options.m_Flags & RENDER_LIMITEDIMAGECACHE) {
   1015         m_pPageCache->CacheOptimization(status.m_Options.m_dwLimitCacheSize);
   1016       }
   1017       if (status.m_bStopped) {
   1018         pDevice->RestoreState();
   1019         break;
   1020       }
   1021     }
   1022     pDevice->RestoreState();
   1023   }
   1024 }
   1025 void CPDF_RenderContext::DrawObjectList(CFX_RenderDevice* pDevice,
   1026                                         CPDF_PageObjects* pObjs,
   1027                                         const CFX_Matrix* pObject2Device,
   1028                                         const CPDF_RenderOptions* pOptions) {
   1029   AppendObjectList(pObjs, pObject2Device);
   1030   Render(pDevice, pOptions);
   1031 }
   1032 
   1033 CPDF_ProgressiveRenderer::CPDF_ProgressiveRenderer(
   1034     CPDF_RenderContext* pContext,
   1035     CFX_RenderDevice* pDevice,
   1036     const CPDF_RenderOptions* pOptions)
   1037     : m_Status(Ready),
   1038       m_pContext(pContext),
   1039       m_pDevice(pDevice),
   1040       m_pOptions(pOptions),
   1041       m_LayerIndex(0),
   1042       m_ObjectIndex(0),
   1043       m_ObjectPos(nullptr),
   1044       m_PrevLastPos(nullptr) {
   1045 }
   1046 
   1047 CPDF_ProgressiveRenderer::~CPDF_ProgressiveRenderer() {
   1048   if (m_pRenderStatus)
   1049     m_pDevice->RestoreState();
   1050 }
   1051 
   1052 void CPDF_ProgressiveRenderer::Start(IFX_Pause* pPause) {
   1053   if (!m_pContext || !m_pDevice || m_Status != Ready) {
   1054     m_Status = Failed;
   1055     return;
   1056   }
   1057   m_Status = ToBeContinued;
   1058   Continue(pPause);
   1059 }
   1060 
   1061 #define RENDER_STEP_LIMIT 100
   1062 void CPDF_ProgressiveRenderer::Continue(IFX_Pause* pPause) {
   1063   if (m_Status != ToBeContinued) {
   1064     return;
   1065   }
   1066   FX_DWORD nLayers = m_pContext->m_ContentList.GetSize();
   1067   for (; m_LayerIndex < nLayers; m_LayerIndex++) {
   1068     _PDF_RenderItem* pItem = m_pContext->m_ContentList.GetDataPtr(m_LayerIndex);
   1069     FX_POSITION LastPos = pItem->m_pObjectList->GetLastObjectPosition();
   1070     if (!m_ObjectPos) {
   1071       if (LastPos == m_PrevLastPos) {
   1072         if (!pItem->m_pObjectList->IsParsed()) {
   1073           pItem->m_pObjectList->ContinueParse(pPause);
   1074           if (!pItem->m_pObjectList->IsParsed()) {
   1075             return;
   1076           }
   1077           LastPos = pItem->m_pObjectList->GetLastObjectPosition();
   1078         }
   1079       }
   1080       if (LastPos == m_PrevLastPos) {
   1081         if (m_pRenderStatus) {
   1082           m_pRenderStatus.reset();
   1083           m_pDevice->RestoreState();
   1084           m_ObjectPos = NULL;
   1085           m_PrevLastPos = NULL;
   1086         }
   1087         continue;
   1088       }
   1089       if (m_PrevLastPos) {
   1090         m_ObjectPos = m_PrevLastPos;
   1091         pItem->m_pObjectList->GetNextObject(m_ObjectPos);
   1092       } else {
   1093         m_ObjectPos = pItem->m_pObjectList->GetFirstObjectPosition();
   1094       }
   1095       m_PrevLastPos = LastPos;
   1096     }
   1097     if (!m_pRenderStatus) {
   1098       m_ObjectPos = pItem->m_pObjectList->GetFirstObjectPosition();
   1099       m_ObjectIndex = 0;
   1100       m_pRenderStatus.reset(new CPDF_RenderStatus());
   1101       m_pRenderStatus->Initialize(
   1102           m_pContext, m_pDevice, NULL, NULL, NULL, NULL, m_pOptions,
   1103           pItem->m_pObjectList->m_Transparency, FALSE, NULL);
   1104       m_pDevice->SaveState();
   1105       m_ClipRect = m_pDevice->GetClipBox();
   1106       CFX_Matrix device2object;
   1107       device2object.SetReverse(pItem->m_Matrix);
   1108       device2object.TransformRect(m_ClipRect);
   1109     }
   1110     int objs_to_go = CPDF_ModuleMgr::Get()
   1111                          ->GetRenderModule()
   1112                          ->GetConfig()
   1113                          ->m_RenderStepLimit;
   1114     while (m_ObjectPos) {
   1115       CPDF_PageObject* pCurObj = pItem->m_pObjectList->GetObjectAt(m_ObjectPos);
   1116       if (pCurObj && pCurObj->m_Left <= m_ClipRect.right &&
   1117           pCurObj->m_Right >= m_ClipRect.left &&
   1118           pCurObj->m_Bottom <= m_ClipRect.top &&
   1119           pCurObj->m_Top >= m_ClipRect.bottom) {
   1120         if (m_pRenderStatus->ContinueSingleObject(pCurObj, &pItem->m_Matrix,
   1121                                                   pPause)) {
   1122           return;
   1123         }
   1124         if (pCurObj->m_Type == PDFPAGE_IMAGE &&
   1125             m_pRenderStatus->m_Options.m_Flags & RENDER_LIMITEDIMAGECACHE) {
   1126           m_pContext->GetPageCache()->CacheOptimization(
   1127               m_pRenderStatus->m_Options.m_dwLimitCacheSize);
   1128         }
   1129         if (pCurObj->m_Type == PDFPAGE_FORM ||
   1130             pCurObj->m_Type == PDFPAGE_SHADING) {
   1131           objs_to_go = 0;
   1132         } else {
   1133           objs_to_go--;
   1134         }
   1135       }
   1136       m_ObjectIndex++;
   1137       pItem->m_pObjectList->GetNextObject(m_ObjectPos);
   1138       if (objs_to_go == 0) {
   1139         if (pPause && pPause->NeedToPauseNow()) {
   1140           return;
   1141         }
   1142         objs_to_go = CPDF_ModuleMgr::Get()
   1143                          ->GetRenderModule()
   1144                          ->GetConfig()
   1145                          ->m_RenderStepLimit;
   1146       }
   1147     }
   1148     if (!pItem->m_pObjectList->IsParsed()) {
   1149       return;
   1150     }
   1151     m_pRenderStatus.reset();
   1152     m_pDevice->RestoreState();
   1153     m_ObjectPos = NULL;
   1154     m_PrevLastPos = NULL;
   1155     if (pPause && pPause->NeedToPauseNow()) {
   1156       m_LayerIndex++;
   1157       return;
   1158     }
   1159   }
   1160   m_Status = Done;
   1161 }
   1162 int CPDF_ProgressiveRenderer::EstimateProgress() {
   1163   if (!m_pContext) {
   1164     return 0;
   1165   }
   1166   FX_DWORD nLayers = m_pContext->m_ContentList.GetSize();
   1167   int nTotal = 0, nRendered = 0;
   1168   for (FX_DWORD layer = 0; layer < nLayers; layer++) {
   1169     _PDF_RenderItem* pItem = m_pContext->m_ContentList.GetDataPtr(layer);
   1170     int nObjs = pItem->m_pObjectList->CountObjects();
   1171     if (layer == m_LayerIndex) {
   1172       nRendered += m_ObjectIndex;
   1173     } else if (layer < m_LayerIndex) {
   1174       nRendered += nObjs;
   1175     }
   1176     nTotal += nObjs;
   1177   }
   1178   if (nTotal == 0) {
   1179     return 0;
   1180   }
   1181   return 100 * nRendered / nTotal;
   1182 }
   1183 CPDF_TransferFunc* CPDF_DocRenderData::GetTransferFunc(CPDF_Object* pObj) {
   1184   if (!pObj)
   1185     return nullptr;
   1186 
   1187   auto it = m_TransferFuncMap.find(pObj);
   1188   if (it != m_TransferFuncMap.end()) {
   1189     CPDF_CountedObject<CPDF_TransferFunc>* pTransferCounter = it->second;
   1190     return pTransferCounter->AddRef();
   1191   }
   1192 
   1193   std::unique_ptr<CPDF_Function> pFuncs[3];
   1194   FX_BOOL bUniTransfer = TRUE;
   1195   FX_BOOL bIdentity = TRUE;
   1196   if (CPDF_Array* pArray = pObj->AsArray()) {
   1197     bUniTransfer = FALSE;
   1198     if (pArray->GetCount() < 3)
   1199       return nullptr;
   1200 
   1201     for (FX_DWORD i = 0; i < 3; ++i) {
   1202       pFuncs[2 - i].reset(CPDF_Function::Load(pArray->GetElementValue(i)));
   1203       if (!pFuncs[2 - i])
   1204         return nullptr;
   1205     }
   1206   } else {
   1207     pFuncs[0].reset(CPDF_Function::Load(pObj));
   1208     if (!pFuncs[0])
   1209       return nullptr;
   1210   }
   1211   CPDF_TransferFunc* pTransfer = new CPDF_TransferFunc(m_pPDFDoc);
   1212   CPDF_CountedObject<CPDF_TransferFunc>* pTransferCounter =
   1213       new CPDF_CountedObject<CPDF_TransferFunc>(pTransfer);
   1214   m_TransferFuncMap[pObj] = pTransferCounter;
   1215   static const int kMaxOutputs = 16;
   1216   FX_FLOAT output[kMaxOutputs];
   1217   FXSYS_memset(output, 0, sizeof(output));
   1218   FX_FLOAT input;
   1219   int noutput;
   1220   for (int v = 0; v < 256; ++v) {
   1221     input = (FX_FLOAT)v / 255.0f;
   1222     if (bUniTransfer) {
   1223       if (pFuncs[0] && pFuncs[0]->CountOutputs() <= kMaxOutputs)
   1224         pFuncs[0]->Call(&input, 1, output, noutput);
   1225       int o = FXSYS_round(output[0] * 255);
   1226       if (o != v)
   1227         bIdentity = FALSE;
   1228       for (int i = 0; i < 3; ++i) {
   1229         pTransfer->m_Samples[i * 256 + v] = o;
   1230       }
   1231     } else {
   1232       for (int i = 0; i < 3; ++i) {
   1233         if (pFuncs[i] && pFuncs[i]->CountOutputs() <= kMaxOutputs) {
   1234           pFuncs[i]->Call(&input, 1, output, noutput);
   1235           int o = FXSYS_round(output[0] * 255);
   1236           if (o != v)
   1237             bIdentity = FALSE;
   1238           pTransfer->m_Samples[i * 256 + v] = o;
   1239         } else {
   1240           pTransfer->m_Samples[i * 256 + v] = v;
   1241         }
   1242       }
   1243     }
   1244   }
   1245 
   1246   pTransfer->m_bIdentity = bIdentity;
   1247   return pTransferCounter->AddRef();
   1248 }
   1249 
   1250 void CPDF_DocRenderData::ReleaseTransferFunc(CPDF_Object* pObj) {
   1251   auto it = m_TransferFuncMap.find(pObj);
   1252   if (it != m_TransferFuncMap.end())
   1253     it->second->RemoveRef();
   1254 }
   1255 CPDF_RenderConfig::CPDF_RenderConfig() {
   1256   m_HalftoneLimit = 0;
   1257   m_RenderStepLimit = 100;
   1258 }
   1259 CPDF_RenderConfig::~CPDF_RenderConfig() {}
   1260 
   1261 CPDF_DeviceBuffer::CPDF_DeviceBuffer()
   1262     : m_pDevice(nullptr), m_pContext(nullptr), m_pObject(nullptr) {}
   1263 
   1264 CPDF_DeviceBuffer::~CPDF_DeviceBuffer() {
   1265 }
   1266 
   1267 FX_BOOL CPDF_DeviceBuffer::Initialize(CPDF_RenderContext* pContext,
   1268                                       CFX_RenderDevice* pDevice,
   1269                                       FX_RECT* pRect,
   1270                                       const CPDF_PageObject* pObj,
   1271                                       int max_dpi) {
   1272   m_pDevice = pDevice;
   1273   m_pContext = pContext;
   1274   m_Rect = *pRect;
   1275   m_pObject = pObj;
   1276   m_Matrix.TranslateI(-pRect->left, -pRect->top);
   1277 #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
   1278   int horz_size = pDevice->GetDeviceCaps(FXDC_HORZ_SIZE);
   1279   int vert_size = pDevice->GetDeviceCaps(FXDC_VERT_SIZE);
   1280   if (horz_size && vert_size && max_dpi) {
   1281     int dpih =
   1282         pDevice->GetDeviceCaps(FXDC_PIXEL_WIDTH) * 254 / (horz_size * 10);
   1283     int dpiv =
   1284         pDevice->GetDeviceCaps(FXDC_PIXEL_HEIGHT) * 254 / (vert_size * 10);
   1285     if (dpih > max_dpi) {
   1286       m_Matrix.Scale((FX_FLOAT)(max_dpi) / dpih, 1.0f);
   1287     }
   1288     if (dpiv > max_dpi) {
   1289       m_Matrix.Scale(1.0f, (FX_FLOAT)(max_dpi) / (FX_FLOAT)dpiv);
   1290     }
   1291   }
   1292 #endif
   1293   CFX_Matrix ctm = m_pDevice->GetCTM();
   1294   FX_FLOAT fScaleX = FXSYS_fabs(ctm.a);
   1295   FX_FLOAT fScaleY = FXSYS_fabs(ctm.d);
   1296   m_Matrix.Concat(fScaleX, 0, 0, fScaleY, 0, 0);
   1297   CFX_FloatRect rect(*pRect);
   1298   m_Matrix.TransformRect(rect);
   1299   FX_RECT bitmap_rect = rect.GetOutterRect();
   1300   m_pBitmap.reset(new CFX_DIBitmap);
   1301   m_pBitmap->Create(bitmap_rect.Width(), bitmap_rect.Height(), FXDIB_Argb);
   1302   return TRUE;
   1303 }
   1304 void CPDF_DeviceBuffer::OutputToDevice() {
   1305   if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_GET_BITS) {
   1306     if (m_Matrix.a == 1.0f && m_Matrix.d == 1.0f) {
   1307       m_pDevice->SetDIBits(m_pBitmap.get(), m_Rect.left, m_Rect.top);
   1308     } else {
   1309       m_pDevice->StretchDIBits(m_pBitmap.get(), m_Rect.left, m_Rect.top,
   1310                                m_Rect.Width(), m_Rect.Height());
   1311     }
   1312   } else {
   1313     CFX_DIBitmap buffer;
   1314     m_pDevice->CreateCompatibleBitmap(&buffer, m_pBitmap->GetWidth(),
   1315                                       m_pBitmap->GetHeight());
   1316     m_pContext->GetBackground(&buffer, m_pObject, NULL, &m_Matrix);
   1317     buffer.CompositeBitmap(0, 0, buffer.GetWidth(), buffer.GetHeight(),
   1318                            m_pBitmap.get(), 0, 0);
   1319     m_pDevice->StretchDIBits(&buffer, m_Rect.left, m_Rect.top, m_Rect.Width(),
   1320                              m_Rect.Height());
   1321   }
   1322 }
   1323 
   1324 CPDF_ScaledRenderBuffer::CPDF_ScaledRenderBuffer() {}
   1325 
   1326 CPDF_ScaledRenderBuffer::~CPDF_ScaledRenderBuffer() {}
   1327 
   1328 #define _FPDFAPI_IMAGESIZE_LIMIT_ (30 * 1024 * 1024)
   1329 FX_BOOL CPDF_ScaledRenderBuffer::Initialize(CPDF_RenderContext* pContext,
   1330                                             CFX_RenderDevice* pDevice,
   1331                                             const FX_RECT& pRect,
   1332                                             const CPDF_PageObject* pObj,
   1333                                             const CPDF_RenderOptions* pOptions,
   1334                                             int max_dpi) {
   1335   m_pDevice = pDevice;
   1336   if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_GET_BITS) {
   1337     return TRUE;
   1338   }
   1339   m_pContext = pContext;
   1340   m_Rect = pRect;
   1341   m_pObject = pObj;
   1342   m_Matrix.TranslateI(-pRect.left, -pRect.top);
   1343   int horz_size = pDevice->GetDeviceCaps(FXDC_HORZ_SIZE);
   1344   int vert_size = pDevice->GetDeviceCaps(FXDC_VERT_SIZE);
   1345   if (horz_size && vert_size && max_dpi) {
   1346     int dpih =
   1347         pDevice->GetDeviceCaps(FXDC_PIXEL_WIDTH) * 254 / (horz_size * 10);
   1348     int dpiv =
   1349         pDevice->GetDeviceCaps(FXDC_PIXEL_HEIGHT) * 254 / (vert_size * 10);
   1350     if (dpih > max_dpi) {
   1351       m_Matrix.Scale((FX_FLOAT)(max_dpi) / dpih, 1.0f);
   1352     }
   1353     if (dpiv > max_dpi) {
   1354       m_Matrix.Scale(1.0f, (FX_FLOAT)(max_dpi) / (FX_FLOAT)dpiv);
   1355     }
   1356   }
   1357   m_pBitmapDevice.reset(new CFX_FxgeDevice);
   1358   FXDIB_Format dibFormat = FXDIB_Rgb;
   1359   int32_t bpp = 24;
   1360   if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_ALPHA_OUTPUT) {
   1361     dibFormat = FXDIB_Argb;
   1362     bpp = 32;
   1363   }
   1364   CFX_FloatRect rect;
   1365   int32_t iWidth, iHeight, iPitch;
   1366   while (1) {
   1367     rect = pRect;
   1368     m_Matrix.TransformRect(rect);
   1369     FX_RECT bitmap_rect = rect.GetOutterRect();
   1370     iWidth = bitmap_rect.Width();
   1371     iHeight = bitmap_rect.Height();
   1372     iPitch = (iWidth * bpp + 31) / 32 * 4;
   1373     if (iWidth * iHeight < 1) {
   1374       return FALSE;
   1375     }
   1376     if (iPitch * iHeight <= _FPDFAPI_IMAGESIZE_LIMIT_ &&
   1377         m_pBitmapDevice->Create(iWidth, iHeight, dibFormat)) {
   1378       break;
   1379     }
   1380     m_Matrix.Scale(0.5f, 0.5f);
   1381   }
   1382   m_pContext->GetBackground(m_pBitmapDevice->GetBitmap(), m_pObject, pOptions,
   1383                             &m_Matrix);
   1384   return TRUE;
   1385 }
   1386 void CPDF_ScaledRenderBuffer::OutputToDevice() {
   1387   if (m_pBitmapDevice) {
   1388     m_pDevice->StretchDIBits(m_pBitmapDevice->GetBitmap(), m_Rect.left,
   1389                              m_Rect.top, m_Rect.Width(), m_Rect.Height());
   1390   }
   1391 }
   1392 FX_BOOL IPDF_OCContext::CheckObjectVisible(const CPDF_PageObject* pObj) {
   1393   const CPDF_ContentMarkData* pData = pObj->m_ContentMark;
   1394   int nItems = pData->CountItems();
   1395   for (int i = 0; i < nItems; i++) {
   1396     CPDF_ContentMarkItem& item = pData->GetItem(i);
   1397     if (item.GetName() == "OC" &&
   1398         item.GetParamType() == CPDF_ContentMarkItem::PropertiesDict) {
   1399       CPDF_Dictionary* pOCG =
   1400           ToDictionary(static_cast<CPDF_Object*>(item.GetParam()));
   1401       if (!CheckOCGVisible(pOCG)) {
   1402         return FALSE;
   1403       }
   1404     }
   1405   }
   1406   return TRUE;
   1407 }
   1408