1 // Copyright 2016 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 "core/fpdfapi/render/cpdf_progressiverenderer.h" 8 9 #include "core/fpdfapi/page/cpdf_image.h" 10 #include "core/fpdfapi/page/cpdf_imageobject.h" 11 #include "core/fpdfapi/page/cpdf_pageobject.h" 12 #include "core/fpdfapi/page/cpdf_pageobjectholder.h" 13 #include "core/fpdfapi/render/cpdf_pagerendercache.h" 14 #include "core/fpdfapi/render/cpdf_renderoptions.h" 15 #include "core/fpdfapi/render/cpdf_renderstatus.h" 16 #include "core/fxcrt/ifx_pauseindicator.h" 17 #include "core/fxge/cfx_renderdevice.h" 18 #include "third_party/base/ptr_util.h" 19 20 CPDF_ProgressiveRenderer::CPDF_ProgressiveRenderer( 21 CPDF_RenderContext* pContext, 22 CFX_RenderDevice* pDevice, 23 const CPDF_RenderOptions* pOptions) 24 : m_Status(Ready), 25 m_pContext(pContext), 26 m_pDevice(pDevice), 27 m_pOptions(pOptions), 28 m_LayerIndex(0), 29 m_pCurrentLayer(nullptr) {} 30 31 CPDF_ProgressiveRenderer::~CPDF_ProgressiveRenderer() { 32 if (m_pRenderStatus) { 33 m_pRenderStatus.reset(); // Release first. 34 m_pDevice->RestoreState(false); 35 } 36 } 37 38 void CPDF_ProgressiveRenderer::Start(IFX_PauseIndicator* pPause) { 39 if (!m_pContext || !m_pDevice || m_Status != Ready) { 40 m_Status = Failed; 41 return; 42 } 43 m_Status = ToBeContinued; 44 Continue(pPause); 45 } 46 47 void CPDF_ProgressiveRenderer::Continue(IFX_PauseIndicator* pPause) { 48 while (m_Status == ToBeContinued) { 49 if (!m_pCurrentLayer) { 50 if (m_LayerIndex >= m_pContext->CountLayers()) { 51 m_Status = Done; 52 return; 53 } 54 m_pCurrentLayer = m_pContext->GetLayer(m_LayerIndex); 55 m_LastObjectRendered = 56 m_pCurrentLayer->m_pObjectHolder->GetPageObjectList()->end(); 57 m_pRenderStatus = pdfium::MakeUnique<CPDF_RenderStatus>(); 58 m_pRenderStatus->Initialize( 59 m_pContext.Get(), m_pDevice.Get(), nullptr, nullptr, nullptr, nullptr, 60 m_pOptions, m_pCurrentLayer->m_pObjectHolder->m_iTransparency, false, 61 nullptr); 62 m_pDevice->SaveState(); 63 m_ClipRect = m_pCurrentLayer->m_Matrix.GetInverse().TransformRect( 64 CFX_FloatRect(m_pDevice->GetClipBox())); 65 } 66 CPDF_PageObjectList::iterator iter; 67 CPDF_PageObjectList::iterator iterEnd = 68 m_pCurrentLayer->m_pObjectHolder->GetPageObjectList()->end(); 69 if (m_LastObjectRendered != iterEnd) { 70 iter = m_LastObjectRendered; 71 ++iter; 72 } else { 73 iter = m_pCurrentLayer->m_pObjectHolder->GetPageObjectList()->begin(); 74 } 75 int nObjsToGo = kStepLimit; 76 bool is_mask = false; 77 while (iter != iterEnd) { 78 CPDF_PageObject* pCurObj = iter->get(); 79 if (pCurObj && pCurObj->m_Left <= m_ClipRect.right && 80 pCurObj->m_Right >= m_ClipRect.left && 81 pCurObj->m_Bottom <= m_ClipRect.top && 82 pCurObj->m_Top >= m_ClipRect.bottom) { 83 if (m_pOptions->HasFlag(RENDER_BREAKFORMASKS) && pCurObj->IsImage() && 84 pCurObj->AsImage()->GetImage()->IsMask()) { 85 if (m_pDevice->GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) { 86 m_LastObjectRendered = iter; 87 m_pRenderStatus->ProcessClipPath(pCurObj->m_ClipPath, 88 &m_pCurrentLayer->m_Matrix); 89 return; 90 } 91 is_mask = true; 92 } 93 if (m_pRenderStatus->ContinueSingleObject( 94 pCurObj, &m_pCurrentLayer->m_Matrix, pPause)) { 95 return; 96 } 97 if (pCurObj->IsImage() && m_pRenderStatus->GetRenderOptions()->HasFlag( 98 RENDER_LIMITEDIMAGECACHE)) { 99 m_pContext->GetPageCache()->CacheOptimization( 100 m_pRenderStatus->GetRenderOptions()->GetCacheSizeLimit()); 101 } 102 if (pCurObj->IsForm() || pCurObj->IsShading()) 103 nObjsToGo = 0; 104 else 105 --nObjsToGo; 106 } 107 m_LastObjectRendered = iter; 108 if (nObjsToGo == 0) { 109 if (pPause && pPause->NeedToPauseNow()) 110 return; 111 nObjsToGo = kStepLimit; 112 } 113 ++iter; 114 if (is_mask && iter != iterEnd) 115 return; 116 } 117 if (m_pCurrentLayer->m_pObjectHolder->IsParsed()) { 118 m_pRenderStatus.reset(); 119 m_pDevice->RestoreState(false); 120 m_pCurrentLayer = nullptr; 121 m_LayerIndex++; 122 if (is_mask || (pPause && pPause->NeedToPauseNow())) { 123 return; 124 } 125 } else if (is_mask) { 126 return; 127 } else { 128 m_pCurrentLayer->m_pObjectHolder->ContinueParse(pPause); 129 if (!m_pCurrentLayer->m_pObjectHolder->IsParsed()) 130 return; 131 } 132 } 133 } 134