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_docrenderdata.h"
8 
9 #include <array>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13 
14 #include "core/fpdfapi/font/cpdf_type3font.h"
15 #include "core/fpdfapi/page/cpdf_dib.h"
16 #include "core/fpdfapi/page/cpdf_function.h"
17 #include "core/fpdfapi/page/cpdf_transferfunc.h"
18 #include "core/fpdfapi/parser/cpdf_array.h"
19 #include "core/fpdfapi/parser/cpdf_document.h"
20 #include "core/fpdfapi/render/cpdf_type3cache.h"
21 
22 namespace {
23 
24 const int kMaxOutputs = 16;
25 
26 }  // namespace
27 
28 // static
FromDocument(const CPDF_Document * pDoc)29 CPDF_DocRenderData* CPDF_DocRenderData::FromDocument(
30     const CPDF_Document* pDoc) {
31   return static_cast<CPDF_DocRenderData*>(pDoc->GetRenderData());
32 }
33 
34 CPDF_DocRenderData::CPDF_DocRenderData() = default;
35 
36 CPDF_DocRenderData::~CPDF_DocRenderData() = default;
37 
GetCachedType3(CPDF_Type3Font * pFont)38 RetainPtr<CPDF_Type3Cache> CPDF_DocRenderData::GetCachedType3(
39     CPDF_Type3Font* pFont) {
40   auto it = m_Type3FaceMap.find(pFont);
41   if (it != m_Type3FaceMap.end() && it->second)
42     return pdfium::WrapRetain(it->second.Get());
43 
44   auto pCache = pdfium::MakeRetain<CPDF_Type3Cache>(pFont);
45   m_Type3FaceMap[pFont].Reset(pCache.Get());
46   return pCache;
47 }
48 
GetTransferFunc(const CPDF_Object * pObj)49 RetainPtr<CPDF_TransferFunc> CPDF_DocRenderData::GetTransferFunc(
50     const CPDF_Object* pObj) {
51   if (!pObj)
52     return nullptr;
53 
54   auto it = m_TransferFuncMap.find(pObj);
55   if (it != m_TransferFuncMap.end() && it->second)
56     return pdfium::WrapRetain(it->second.Get());
57 
58   auto pFunc = CreateTransferFunc(pObj);
59   m_TransferFuncMap[pObj].Reset(pFunc.Get());
60   return pFunc;
61 }
62 
CreateTransferFunc(const CPDF_Object * pObj) const63 RetainPtr<CPDF_TransferFunc> CPDF_DocRenderData::CreateTransferFunc(
64     const CPDF_Object* pObj) const {
65   std::unique_ptr<CPDF_Function> pFuncs[3];
66   const CPDF_Array* pArray = pObj->AsArray();
67   if (pArray) {
68     if (pArray->size() < 3)
69       return nullptr;
70 
71     for (uint32_t i = 0; i < 3; ++i) {
72       pFuncs[2 - i] = CPDF_Function::Load(pArray->GetDirectObjectAt(i));
73       if (!pFuncs[2 - i])
74         return nullptr;
75     }
76   } else {
77     pFuncs[0] = CPDF_Function::Load(pObj);
78     if (!pFuncs[0])
79       return nullptr;
80   }
81 
82   int noutput;
83   float output[kMaxOutputs];
84   memset(output, 0, sizeof(output));
85 
86   bool bIdentity = true;
87   std::vector<uint8_t, FxAllocAllocator<uint8_t>> samples_r(
88       CPDF_TransferFunc::kChannelSampleSize);
89   std::vector<uint8_t, FxAllocAllocator<uint8_t>> samples_g(
90       CPDF_TransferFunc::kChannelSampleSize);
91   std::vector<uint8_t, FxAllocAllocator<uint8_t>> samples_b(
92       CPDF_TransferFunc::kChannelSampleSize);
93   std::array<pdfium::span<uint8_t>, 3> samples = {samples_r, samples_g,
94                                                   samples_b};
95   for (size_t v = 0; v < CPDF_TransferFunc::kChannelSampleSize; ++v) {
96     float input = static_cast<float>(v) / 255.0f;
97     if (pArray) {
98       for (int i = 0; i < 3; ++i) {
99         if (pFuncs[i]->CountOutputs() > kMaxOutputs) {
100           samples[i][v] = v;
101           continue;
102         }
103         pFuncs[i]->Call(&input, 1, output, &noutput);
104         size_t o = FXSYS_roundf(output[0] * 255);
105         if (o != v)
106           bIdentity = false;
107         samples[i][v] = o;
108       }
109       continue;
110     }
111     if (pFuncs[0]->CountOutputs() <= kMaxOutputs)
112       pFuncs[0]->Call(&input, 1, output, &noutput);
113     size_t o = FXSYS_roundf(output[0] * 255);
114     if (o != v)
115       bIdentity = false;
116     for (auto& channel : samples)
117       channel[v] = o;
118   }
119 
120   return pdfium::MakeRetain<CPDF_TransferFunc>(
121       GetDocument(), bIdentity, std::move(samples_r), std::move(samples_g),
122       std::move(samples_b));
123 }
124