blob: ce4085ae982fbeb1e8d0d417da27738018b81887 [file] [log] [blame]
// Copyright 2016 PDFium Authors. All rights reserved.
// 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_docrenderdata.h"
#include <array>
#include <memory>
#include <utility>
#include <vector>
#include "core/fpdfapi/font/cpdf_type3font.h"
#include "core/fpdfapi/page/cpdf_function.h"
#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_document.h"
#include "core/fpdfapi/render/cpdf_dibbase.h"
#include "core/fpdfapi/render/cpdf_transferfunc.h"
#include "core/fpdfapi/render/cpdf_type3cache.h"
namespace {
const int kMaxOutputs = 16;
} // namespace
CPDF_DocRenderData::CPDF_DocRenderData(CPDF_Document* pPDFDoc)
: m_pPDFDoc(pPDFDoc) {}
CPDF_DocRenderData::~CPDF_DocRenderData() = default;
RetainPtr<CPDF_Type3Cache> CPDF_DocRenderData::GetCachedType3(
CPDF_Type3Font* pFont) {
auto it = m_Type3FaceMap.find(pFont);
if (it != m_Type3FaceMap.end())
return it->second;
auto pCache = pdfium::MakeRetain<CPDF_Type3Cache>(pFont);
m_Type3FaceMap[pFont] = pCache;
return pCache;
}
void CPDF_DocRenderData::MaybePurgeCachedType3(CPDF_Type3Font* pFont) {
auto it = m_Type3FaceMap.find(pFont);
if (it != m_Type3FaceMap.end() && it->second->HasOneRef())
m_Type3FaceMap.erase(it);
}
RetainPtr<CPDF_TransferFunc> CPDF_DocRenderData::GetTransferFunc(
const CPDF_Object* pObj) {
if (!pObj)
return nullptr;
auto it = m_TransferFuncMap.find(pObj);
if (it != m_TransferFuncMap.end())
return it->second;
m_TransferFuncMap[pObj] = CreateTransferFunc(pObj);
return m_TransferFuncMap[pObj];
}
void CPDF_DocRenderData::MaybePurgeTransferFunc(const CPDF_Object* pObj) {
auto it = m_TransferFuncMap.find(pObj);
if (it != m_TransferFuncMap.end() && it->second->HasOneRef())
m_TransferFuncMap.erase(it);
}
RetainPtr<CPDF_TransferFunc> CPDF_DocRenderData::CreateTransferFunc(
const CPDF_Object* pObj) const {
std::unique_ptr<CPDF_Function> pFuncs[3];
const CPDF_Array* pArray = pObj->AsArray();
if (pArray) {
if (pArray->size() < 3)
return nullptr;
for (uint32_t i = 0; i < 3; ++i) {
pFuncs[2 - i] = CPDF_Function::Load(pArray->GetDirectObjectAt(i));
if (!pFuncs[2 - i])
return nullptr;
}
} else {
pFuncs[0] = CPDF_Function::Load(pObj);
if (!pFuncs[0])
return nullptr;
}
int noutput;
float output[kMaxOutputs];
memset(output, 0, sizeof(output));
bool bIdentity = true;
std::vector<uint8_t> samples_r(CPDF_TransferFunc::kChannelSampleSize);
std::vector<uint8_t> samples_g(CPDF_TransferFunc::kChannelSampleSize);
std::vector<uint8_t> samples_b(CPDF_TransferFunc::kChannelSampleSize);
std::array<pdfium::span<uint8_t>, 3> samples = {samples_r, samples_g,
samples_b};
for (size_t v = 0; v < CPDF_TransferFunc::kChannelSampleSize; ++v) {
float input = static_cast<float>(v) / 255.0f;
if (pArray) {
for (int i = 0; i < 3; ++i) {
if (pFuncs[i]->CountOutputs() > kMaxOutputs) {
samples[i][v] = v;
continue;
}
pFuncs[i]->Call(&input, 1, output, &noutput);
size_t o = FXSYS_round(output[0] * 255);
if (o != v)
bIdentity = false;
samples[i][v] = o;
}
continue;
}
if (pFuncs[0]->CountOutputs() <= kMaxOutputs)
pFuncs[0]->Call(&input, 1, output, &noutput);
size_t o = FXSYS_round(output[0] * 255);
if (o != v)
bIdentity = false;
for (auto& channel : samples)
channel[v] = o;
}
return pdfium::MakeRetain<CPDF_TransferFunc>(
m_pPDFDoc.Get(), bIdentity, std::move(samples_r), std::move(samples_g),
std::move(samples_b));
}