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