• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_page.h"
8 
9 #include <set>
10 #include <utility>
11 
12 #include "constants/page_object.h"
13 #include "core/fpdfapi/page/cpdf_contentparser.h"
14 #include "core/fpdfapi/page/cpdf_pageimagecache.h"
15 #include "core/fpdfapi/page/cpdf_pageobject.h"
16 #include "core/fpdfapi/parser/cpdf_array.h"
17 #include "core/fpdfapi/parser/cpdf_dictionary.h"
18 #include "core/fpdfapi/parser/cpdf_object.h"
19 #include "third_party/base/check.h"
20 #include "third_party/base/check_op.h"
21 #include "third_party/base/containers/contains.h"
22 
CPDF_Page(CPDF_Document * pDocument,RetainPtr<CPDF_Dictionary> pPageDict)23 CPDF_Page::CPDF_Page(CPDF_Document* pDocument,
24                      RetainPtr<CPDF_Dictionary> pPageDict)
25     : CPDF_PageObjectHolder(pDocument, std::move(pPageDict), nullptr, nullptr),
26       m_PageSize(100, 100),
27       m_pPDFDocument(pDocument) {
28   // Cannot initialize |m_pResources| and |m_pPageResources| via the
29   // CPDF_PageObjectHolder ctor because GetPageAttr() requires
30   // CPDF_PageObjectHolder to finish initializing first.
31   RetainPtr<CPDF_Object> pPageAttr =
32       GetMutablePageAttr(pdfium::page_object::kResources);
33   m_pResources = pPageAttr ? pPageAttr->GetMutableDict() : nullptr;
34   m_pPageResources = m_pResources;
35 
36   UpdateDimensions();
37   m_Transparency.SetIsolated();
38   LoadTransparencyInfo();
39 }
40 
41 CPDF_Page::~CPDF_Page() = default;
42 
AsPDFPage()43 CPDF_Page* CPDF_Page::AsPDFPage() {
44   return this;
45 }
46 
AsXFAPage()47 CPDFXFA_Page* CPDF_Page::AsXFAPage() {
48   return nullptr;
49 }
50 
GetDocument() const51 CPDF_Document* CPDF_Page::GetDocument() const {
52   return m_pPDFDocument;
53 }
54 
GetPageWidth() const55 float CPDF_Page::GetPageWidth() const {
56   return m_PageSize.width;
57 }
58 
GetPageHeight() const59 float CPDF_Page::GetPageHeight() const {
60   return m_PageSize.height;
61 }
62 
IsPage() const63 bool CPDF_Page::IsPage() const {
64   return true;
65 }
66 
ParseContent()67 void CPDF_Page::ParseContent() {
68   if (GetParseState() == ParseState::kParsed)
69     return;
70 
71   if (GetParseState() == ParseState::kNotParsed)
72     StartParse(std::make_unique<CPDF_ContentParser>(this));
73 
74   DCHECK_EQ(GetParseState(), ParseState::kParsing);
75   ContinueParse(nullptr);
76 }
77 
GetMutablePageAttr(const ByteString & name)78 RetainPtr<CPDF_Object> CPDF_Page::GetMutablePageAttr(const ByteString& name) {
79   return pdfium::WrapRetain(const_cast<CPDF_Object*>(GetPageAttr(name).Get()));
80 }
81 
GetPageAttr(const ByteString & name) const82 RetainPtr<const CPDF_Object> CPDF_Page::GetPageAttr(
83     const ByteString& name) const {
84   std::set<RetainPtr<const CPDF_Dictionary>> visited;
85   RetainPtr<const CPDF_Dictionary> pPageDict = GetDict();
86   while (pPageDict && !pdfium::Contains(visited, pPageDict)) {
87     RetainPtr<const CPDF_Object> pObj = pPageDict->GetDirectObjectFor(name);
88     if (pObj)
89       return pObj;
90 
91     visited.insert(pPageDict);
92     pPageDict = pPageDict->GetDictFor(pdfium::page_object::kParent);
93   }
94   return nullptr;
95 }
96 
GetBox(const ByteString & name) const97 CFX_FloatRect CPDF_Page::GetBox(const ByteString& name) const {
98   CFX_FloatRect box;
99   RetainPtr<const CPDF_Array> pBox = ToArray(GetPageAttr(name));
100   if (pBox) {
101     box = pBox->GetRect();
102     box.Normalize();
103   }
104   return box;
105 }
106 
DeviceToPage(const FX_RECT & rect,int rotate,const CFX_PointF & device_point) const107 absl::optional<CFX_PointF> CPDF_Page::DeviceToPage(
108     const FX_RECT& rect,
109     int rotate,
110     const CFX_PointF& device_point) const {
111   CFX_Matrix page2device = GetDisplayMatrix(rect, rotate);
112   return page2device.GetInverse().Transform(device_point);
113 }
114 
PageToDevice(const FX_RECT & rect,int rotate,const CFX_PointF & page_point) const115 absl::optional<CFX_PointF> CPDF_Page::PageToDevice(
116     const FX_RECT& rect,
117     int rotate,
118     const CFX_PointF& page_point) const {
119   CFX_Matrix page2device = GetDisplayMatrix(rect, rotate);
120   return page2device.Transform(page_point);
121 }
122 
GetDisplayMatrix(const FX_RECT & rect,int iRotate) const123 CFX_Matrix CPDF_Page::GetDisplayMatrix(const FX_RECT& rect, int iRotate) const {
124   if (m_PageSize.width == 0 || m_PageSize.height == 0)
125     return CFX_Matrix();
126 
127   float x0 = 0;
128   float y0 = 0;
129   float x1 = 0;
130   float y1 = 0;
131   float x2 = 0;
132   float y2 = 0;
133   iRotate %= 4;
134   // This code implicitly inverts the y-axis to account for page coordinates
135   // pointing up and bitmap coordinates pointing down. (x0, y0) is the base
136   // point, (x1, y1) is that point translated on y and (x2, y2) is the point
137   // translated on x. On iRotate = 0, y0 is rect.bottom and the translation
138   // to get y1 is performed as negative. This results in the desired
139   // transformation.
140   switch (iRotate) {
141     case 0:
142       x0 = rect.left;
143       y0 = rect.bottom;
144       x1 = rect.left;
145       y1 = rect.top;
146       x2 = rect.right;
147       y2 = rect.bottom;
148       break;
149     case 1:
150       x0 = rect.left;
151       y0 = rect.top;
152       x1 = rect.right;
153       y1 = rect.top;
154       x2 = rect.left;
155       y2 = rect.bottom;
156       break;
157     case 2:
158       x0 = rect.right;
159       y0 = rect.top;
160       x1 = rect.right;
161       y1 = rect.bottom;
162       x2 = rect.left;
163       y2 = rect.top;
164       break;
165     case 3:
166       x0 = rect.right;
167       y0 = rect.bottom;
168       x1 = rect.left;
169       y1 = rect.bottom;
170       x2 = rect.right;
171       y2 = rect.top;
172       break;
173   }
174   CFX_Matrix matrix((x2 - x0) / m_PageSize.width, (y2 - y0) / m_PageSize.width,
175                     (x1 - x0) / m_PageSize.height,
176                     (y1 - y0) / m_PageSize.height, x0, y0);
177   return m_PageMatrix * matrix;
178 }
179 
GetPageRotation() const180 int CPDF_Page::GetPageRotation() const {
181   RetainPtr<const CPDF_Object> pRotate =
182       GetPageAttr(pdfium::page_object::kRotate);
183   int rotate = pRotate ? (pRotate->GetInteger() / 90) % 4 : 0;
184   return (rotate < 0) ? (rotate + 4) : rotate;
185 }
186 
GetOrCreateAnnotsArray()187 RetainPtr<CPDF_Array> CPDF_Page::GetOrCreateAnnotsArray() {
188   return GetMutableDict()->GetOrCreateArrayFor("Annots");
189 }
190 
GetMutableAnnotsArray()191 RetainPtr<CPDF_Array> CPDF_Page::GetMutableAnnotsArray() {
192   return GetMutableDict()->GetMutableArrayFor("Annots");
193 }
194 
GetAnnotsArray() const195 RetainPtr<const CPDF_Array> CPDF_Page::GetAnnotsArray() const {
196   return GetDict()->GetArrayFor("Annots");
197 }
198 
AddPageImageCache()199 void CPDF_Page::AddPageImageCache() {
200   m_pPageImageCache = std::make_unique<CPDF_PageImageCache>(this);
201 }
202 
SetRenderContext(std::unique_ptr<RenderContextIface> pContext)203 void CPDF_Page::SetRenderContext(std::unique_ptr<RenderContextIface> pContext) {
204   DCHECK(!m_pRenderContext);
205   DCHECK(pContext);
206   m_pRenderContext = std::move(pContext);
207 }
208 
ClearRenderContext()209 void CPDF_Page::ClearRenderContext() {
210   m_pRenderContext.reset();
211 }
212 
ClearView()213 void CPDF_Page::ClearView() {
214   if (m_pView)
215     m_pView->ClearPage(this);
216 }
217 
UpdateDimensions()218 void CPDF_Page::UpdateDimensions() {
219   CFX_FloatRect mediabox = GetBox(pdfium::page_object::kMediaBox);
220   if (mediabox.IsEmpty())
221     mediabox = CFX_FloatRect(0, 0, 612, 792);
222 
223   m_BBox = GetBox(pdfium::page_object::kCropBox);
224   if (m_BBox.IsEmpty())
225     m_BBox = mediabox;
226   else
227     m_BBox.Intersect(mediabox);
228 
229   m_PageSize.width = m_BBox.Width();
230   m_PageSize.height = m_BBox.Height();
231 
232   switch (GetPageRotation()) {
233     case 0:
234       m_PageMatrix = CFX_Matrix(1.0f, 0, 0, 1.0f, -m_BBox.left, -m_BBox.bottom);
235       break;
236     case 1:
237       std::swap(m_PageSize.width, m_PageSize.height);
238       m_PageMatrix =
239           CFX_Matrix(0, -1.0f, 1.0f, 0, -m_BBox.bottom, m_BBox.right);
240       break;
241     case 2:
242       m_PageMatrix = CFX_Matrix(-1.0f, 0, 0, -1.0f, m_BBox.right, m_BBox.top);
243       break;
244     case 3:
245       std::swap(m_PageSize.width, m_PageSize.height);
246       m_PageMatrix = CFX_Matrix(0, 1.0f, -1.0f, 0, m_BBox.top, -m_BBox.left);
247       break;
248   }
249 }
250 
RenderContextClearer(CPDF_Page * pPage)251 CPDF_Page::RenderContextClearer::RenderContextClearer(CPDF_Page* pPage)
252     : m_pPage(pPage) {}
253 
~RenderContextClearer()254 CPDF_Page::RenderContextClearer::~RenderContextClearer() {
255   if (m_pPage)
256     m_pPage->ClearRenderContext();
257 }
258