blob: 19b620ddf64e4edd005d1a6d2215a59bd27dc5c0 [file] [log] [blame]
// Copyright 2016 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "core/fpdfapi/render/cpdf_progressiverenderer.h"
#include "build/build_config.h"
#include "core/fpdfapi/page/cpdf_image.h"
#include "core/fpdfapi/page/cpdf_imageobject.h"
#include "core/fpdfapi/page/cpdf_pageimagecache.h"
#include "core/fpdfapi/page/cpdf_pageobject.h"
#include "core/fpdfapi/page/cpdf_pageobjectholder.h"
#include "core/fpdfapi/render/cpdf_renderoptions.h"
#include "core/fpdfapi/render/cpdf_renderstatus.h"
#include "core/fxcrt/check.h"
#include "core/fxcrt/pauseindicator_iface.h"
#include "core/fxge/cfx_renderdevice.h"
CPDF_ProgressiveRenderer::CPDF_ProgressiveRenderer(
CPDF_RenderContext* pContext,
CFX_RenderDevice* pDevice,
const CPDF_RenderOptions* pOptions)
: context_(pContext), device_(pDevice), options_(pOptions) {
CHECK(context_);
CHECK(device_);
}
CPDF_ProgressiveRenderer::~CPDF_ProgressiveRenderer() {
if (render_status_) {
render_status_.reset(); // Release first.
device_->RestoreState(false);
}
}
void CPDF_ProgressiveRenderer::Start(PauseIndicatorIface* pPause) {
if (status_ != kReady) {
status_ = kFailed;
return;
}
status_ = kToBeContinued;
Continue(pPause);
}
void CPDF_ProgressiveRenderer::Continue(PauseIndicatorIface* pPause) {
while (status_ == kToBeContinued) {
if (!current_layer_) {
if (layer_index_ >= context_->CountLayers()) {
status_ = kDone;
return;
}
current_layer_ = context_->GetLayer(layer_index_);
last_object_rendered_ = current_layer_->GetObjectHolder()->end();
render_status_ = std::make_unique<CPDF_RenderStatus>(context_, device_);
if (options_) {
render_status_->SetOptions(*options_);
}
render_status_->SetTransparency(
current_layer_->GetObjectHolder()->GetTransparency());
render_status_->Initialize(nullptr, nullptr);
device_->SaveState();
clip_rect_ = current_layer_->GetMatrix().GetInverse().TransformRect(
CFX_FloatRect(device_->GetClipBox()));
}
CPDF_PageObjectHolder::const_iterator iter;
CPDF_PageObjectHolder::const_iterator iterEnd =
current_layer_->GetObjectHolder()->end();
if (last_object_rendered_ != iterEnd) {
iter = last_object_rendered_;
++iter;
} else {
iter = current_layer_->GetObjectHolder()->begin();
}
int nObjsToGo = kStepLimit;
bool is_mask = false;
while (iter != iterEnd) {
CPDF_PageObject* pCurObj = iter->get();
if (pCurObj->IsActive() && pCurObj->GetRect().left <= clip_rect_.right &&
pCurObj->GetRect().right >= clip_rect_.left &&
pCurObj->GetRect().bottom <= clip_rect_.top &&
pCurObj->GetRect().top >= clip_rect_.bottom) {
if (options_->GetOptions().bBreakForMasks && pCurObj->IsImage() &&
pCurObj->AsImage()->GetImage()->IsMask()) {
#if BUILDFLAG(IS_WIN)
if (device_->GetDeviceType() == DeviceType::kPrinter) {
last_object_rendered_ = iter;
render_status_->ProcessClipPath(pCurObj->clip_path(),
current_layer_->GetMatrix());
return;
}
#endif
is_mask = true;
}
if (render_status_->ContinueSingleObject(
pCurObj, current_layer_->GetMatrix(), pPause)) {
return;
}
if (pCurObj->IsImage() && render_status_->GetRenderOptions()
.GetOptions()
.bLimitedImageCache) {
context_->GetPageCache()->CacheOptimization(
render_status_->GetRenderOptions().GetCacheSizeLimit());
}
if (pCurObj->IsForm() || pCurObj->IsShading()) {
nObjsToGo = 0;
} else {
--nObjsToGo;
}
}
last_object_rendered_ = iter;
if (nObjsToGo == 0) {
if (pPause && pPause->NeedToPauseNow()) {
return;
}
nObjsToGo = kStepLimit;
}
++iter;
if (is_mask && iter != iterEnd) {
return;
}
}
if (current_layer_->GetObjectHolder()->GetParseState() ==
CPDF_PageObjectHolder::ParseState::kParsed) {
render_status_.reset();
device_->RestoreState(false);
current_layer_ = nullptr;
layer_index_++;
if (is_mask || (pPause && pPause->NeedToPauseNow())) {
return;
}
} else if (is_mask) {
return;
} else {
current_layer_->GetObjectHolder()->ContinueParse(pPause);
if (current_layer_->GetObjectHolder()->GetParseState() !=
CPDF_PageObjectHolder::ParseState::kParsed) {
return;
}
}
}
}