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/page/cpdf_pageobjectholder.h"
8
9 #include <algorithm>
10 #include <utility>
11
12 #include "constants/transparency.h"
13 #include "core/fpdfapi/page/cpdf_allstates.h"
14 #include "core/fpdfapi/page/cpdf_contentparser.h"
15 #include "core/fpdfapi/page/cpdf_pageobject.h"
16 #include "core/fpdfapi/parser/cpdf_dictionary.h"
17 #include "core/fpdfapi/parser/cpdf_document.h"
18 #include "core/fxcrt/check.h"
19 #include "core/fxcrt/check_op.h"
20 #include "core/fxcrt/fx_extension.h"
21 #include "core/fxcrt/stl_util.h"
22
operator <(const GraphicsData & other) const23 bool GraphicsData::operator<(const GraphicsData& other) const {
24 if (!FXSYS_SafeEQ(fillAlpha, other.fillAlpha))
25 return FXSYS_SafeLT(fillAlpha, other.fillAlpha);
26 if (!FXSYS_SafeEQ(strokeAlpha, other.strokeAlpha))
27 return FXSYS_SafeLT(strokeAlpha, other.strokeAlpha);
28 return blendType < other.blendType;
29 }
30
operator <(const FontData & other) const31 bool FontData::operator<(const FontData& other) const {
32 if (baseFont != other.baseFont)
33 return baseFont < other.baseFont;
34 return type < other.type;
35 }
36
CPDF_PageObjectHolder(CPDF_Document * pDoc,RetainPtr<CPDF_Dictionary> pDict,RetainPtr<CPDF_Dictionary> pPageResources,RetainPtr<CPDF_Dictionary> pResources)37 CPDF_PageObjectHolder::CPDF_PageObjectHolder(
38 CPDF_Document* pDoc,
39 RetainPtr<CPDF_Dictionary> pDict,
40 RetainPtr<CPDF_Dictionary> pPageResources,
41 RetainPtr<CPDF_Dictionary> pResources)
42 : m_pPageResources(std::move(pPageResources)),
43 m_pResources(std::move(pResources)),
44 m_pDict(std::move(pDict)),
45 m_pDocument(pDoc) {
46 DCHECK(m_pDict);
47 }
48
49 CPDF_PageObjectHolder::~CPDF_PageObjectHolder() = default;
50
IsPage() const51 bool CPDF_PageObjectHolder::IsPage() const {
52 return false;
53 }
54
StartParse(std::unique_ptr<CPDF_ContentParser> pParser)55 void CPDF_PageObjectHolder::StartParse(
56 std::unique_ptr<CPDF_ContentParser> pParser) {
57 DCHECK_EQ(m_ParseState, ParseState::kNotParsed);
58 m_pParser = std::move(pParser);
59 m_ParseState = ParseState::kParsing;
60 }
61
ContinueParse(PauseIndicatorIface * pPause)62 void CPDF_PageObjectHolder::ContinueParse(PauseIndicatorIface* pPause) {
63 if (m_ParseState == ParseState::kParsed)
64 return;
65
66 DCHECK_EQ(m_ParseState, ParseState::kParsing);
67 if (m_pParser->Continue(pPause))
68 return;
69
70 m_ParseState = ParseState::kParsed;
71 m_pDocument->IncrementParsedPageCount();
72 m_AllCTMs = m_pParser->TakeAllCTMs();
73
74 m_pParser.reset();
75 }
76
AddImageMaskBoundingBox(const CFX_FloatRect & box)77 void CPDF_PageObjectHolder::AddImageMaskBoundingBox(const CFX_FloatRect& box) {
78 m_MaskBoundingBoxes.push_back(box);
79 }
80
TakeDirtyStreams()81 std::set<int32_t> CPDF_PageObjectHolder::TakeDirtyStreams() {
82 auto dirty_streams = std::move(m_DirtyStreams);
83 m_DirtyStreams.clear();
84 return dirty_streams;
85 }
86
GraphicsMapSearch(const GraphicsData & gd)87 std::optional<ByteString> CPDF_PageObjectHolder::GraphicsMapSearch(
88 const GraphicsData& gd) {
89 auto it = m_GraphicsMap.find(gd);
90 if (it == m_GraphicsMap.end())
91 return std::nullopt;
92
93 return it->second;
94 }
95
GraphicsMapInsert(const GraphicsData & gd,const ByteString & str)96 void CPDF_PageObjectHolder::GraphicsMapInsert(const GraphicsData& gd,
97 const ByteString& str) {
98 m_GraphicsMap[gd] = str;
99 }
100
FontsMapSearch(const FontData & fd)101 std::optional<ByteString> CPDF_PageObjectHolder::FontsMapSearch(
102 const FontData& fd) {
103 auto it = m_FontsMap.find(fd);
104 if (it == m_FontsMap.end())
105 return std::nullopt;
106
107 return it->second;
108 }
109
FontsMapInsert(const FontData & fd,const ByteString & str)110 void CPDF_PageObjectHolder::FontsMapInsert(const FontData& fd,
111 const ByteString& str) {
112 m_FontsMap[fd] = str;
113 }
114
GetCTMAtBeginningOfStream(int32_t stream)115 CFX_Matrix CPDF_PageObjectHolder::GetCTMAtBeginningOfStream(int32_t stream) {
116 CHECK(stream >= 0 || stream == CPDF_PageObject::kNoContentStream);
117
118 if (stream == 0 || m_AllCTMs.empty()) {
119 return CFX_Matrix();
120 }
121
122 if (stream == CPDF_PageObject::kNoContentStream) {
123 return m_AllCTMs.rbegin()->second;
124 }
125
126 // For all other cases, CTM at beginning of `stream` is the same value as CTM
127 // at the end of the previous stream.
128 return GetCTMAtEndOfStream(stream - 1);
129 }
130
GetCTMAtEndOfStream(int32_t stream)131 CFX_Matrix CPDF_PageObjectHolder::GetCTMAtEndOfStream(int32_t stream) {
132 // This code should never need to calculate the CTM for the end of
133 // `CPDF_PageObject::kNoContentStream`, which uses a negative sentinel value.
134 // All other streams have a non-negative index.
135 CHECK_GE(stream, 0);
136
137 if (m_AllCTMs.empty()) {
138 return CFX_Matrix();
139 }
140
141 const auto it = m_AllCTMs.lower_bound(stream);
142 return it != m_AllCTMs.end() ? it->second : m_AllCTMs.rbegin()->second;
143 }
144
LoadTransparencyInfo()145 void CPDF_PageObjectHolder::LoadTransparencyInfo() {
146 RetainPtr<const CPDF_Dictionary> pGroup = m_pDict->GetDictFor("Group");
147 if (!pGroup)
148 return;
149
150 if (pGroup->GetByteStringFor(pdfium::transparency::kGroupSubType) !=
151 pdfium::transparency::kTransparency) {
152 return;
153 }
154 m_Transparency.SetGroup();
155 if (pGroup->GetIntegerFor(pdfium::transparency::kI))
156 m_Transparency.SetIsolated();
157 }
158
GetActivePageObjectCount() const159 size_t CPDF_PageObjectHolder::GetActivePageObjectCount() const {
160 size_t count = 0;
161 for (const auto& page_object : m_PageObjectList) {
162 if (page_object->IsActive()) {
163 ++count;
164 }
165 }
166 return count;
167 }
168
GetPageObjectByIndex(size_t index) const169 CPDF_PageObject* CPDF_PageObjectHolder::GetPageObjectByIndex(
170 size_t index) const {
171 return fxcrt::IndexInBounds(m_PageObjectList, index)
172 ? m_PageObjectList[index].get()
173 : nullptr;
174 }
175
AppendPageObject(std::unique_ptr<CPDF_PageObject> pPageObj)176 void CPDF_PageObjectHolder::AppendPageObject(
177 std::unique_ptr<CPDF_PageObject> pPageObj) {
178 CHECK(pPageObj);
179 m_PageObjectList.push_back(std::move(pPageObj));
180 }
181
RemovePageObject(CPDF_PageObject * pPageObj)182 std::unique_ptr<CPDF_PageObject> CPDF_PageObjectHolder::RemovePageObject(
183 CPDF_PageObject* pPageObj) {
184 auto it = std::find(std::begin(m_PageObjectList), std::end(m_PageObjectList),
185 fxcrt::MakeFakeUniquePtr(pPageObj));
186 if (it == std::end(m_PageObjectList))
187 return nullptr;
188
189 std::unique_ptr<CPDF_PageObject> result = std::move(*it);
190 m_PageObjectList.erase(it);
191
192 int32_t content_stream = pPageObj->GetContentStream();
193 if (content_stream >= 0)
194 m_DirtyStreams.insert(content_stream);
195
196 return result;
197 }
198
ErasePageObjectAtIndex(size_t index)199 bool CPDF_PageObjectHolder::ErasePageObjectAtIndex(size_t index) {
200 if (index >= m_PageObjectList.size())
201 return false;
202
203 m_PageObjectList.erase(m_PageObjectList.begin() + index);
204 return true;
205 }
206