| // 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_dib.h" | |
| #include "core/fpdfapi/page/cpdf_function.h" | |
| #include "core/fpdfapi/page/cpdf_transferfunc.h" | |
| #include "core/fpdfapi/parser/cpdf_array.h" | |
| #include "core/fpdfapi/parser/cpdf_document.h" | |
| #include "core/fpdfapi/render/cpdf_type3cache.h" | |
| namespace { | |
| const int kMaxOutputs = 16; | |
| } // namespace | |
| // static | |
| CPDF_DocRenderData* CPDF_DocRenderData::FromDocument( | |
| const CPDF_Document* pDoc) { | |
| return static_cast<CPDF_DocRenderData*>(pDoc->GetRenderData()); | |
| } | |
| CPDF_DocRenderData::CPDF_DocRenderData() = default; | |
| 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() && it->second) | |
| return pdfium::WrapRetain(it->second.Get()); | |
| auto pCache = pdfium::MakeRetain<CPDF_Type3Cache>(pFont); | |
| m_Type3FaceMap[pFont].Reset(pCache.Get()); | |
| return pCache; | |
| } | |
| 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() && it->second) | |
| return pdfium::WrapRetain(it->second.Get()); | |
| auto pFunc = CreateTransferFunc(pObj); | |
| m_TransferFuncMap[pObj].Reset(pFunc.Get()); | |
| return pFunc; | |
| } | |
| 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, FxAllocAllocator<uint8_t>> samples_r( | |
| CPDF_TransferFunc::kChannelSampleSize); | |
| std::vector<uint8_t, FxAllocAllocator<uint8_t>> samples_g( | |
| CPDF_TransferFunc::kChannelSampleSize); | |
| std::vector<uint8_t, FxAllocAllocator<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_roundf(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_roundf(output[0] * 255); | |
| if (o != v) | |
| bIdentity = false; | |
| for (auto& channel : samples) | |
| channel[v] = o; | |
| } | |
| return pdfium::MakeRetain<CPDF_TransferFunc>( | |
| GetDocument(), bIdentity, std::move(samples_r), std::move(samples_g), | |
| std::move(samples_b)); | |
| } |