• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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_pageobject.h"
15 #include "core/fpdfapi/parser/cpdf_array.h"
16 #include "core/fpdfapi/parser/cpdf_dictionary.h"
17 #include "core/fpdfapi/parser/cpdf_object.h"
18 #include "third_party/base/ptr_util.h"
19 #include "third_party/base/stl_util.h"
20 
CPDF_Page(CPDF_Document * pDocument,CPDF_Dictionary * pPageDict)21 CPDF_Page::CPDF_Page(CPDF_Document* pDocument, CPDF_Dictionary* pPageDict)
22     : CPDF_PageObjectHolder(pDocument, pPageDict, nullptr, nullptr),
23       m_PageSize(100, 100),
24       m_pPDFDocument(pDocument) {
25   ASSERT(pPageDict);
26 
27   // Cannot initialize |m_pResources| and |m_pPageResources| via the
28   // CPDF_PageObjectHolder ctor because GetPageAttr() requires
29   // CPDF_PageObjectHolder to finish initializing first.
30   CPDF_Object* pPageAttr = GetPageAttr(pdfium::page_object::kResources);
31   m_pResources.Reset(pPageAttr ? pPageAttr->GetDict() : nullptr);
32   m_pPageResources = m_pResources;
33 
34   UpdateDimensions();
35   m_Transparency.SetIsolated();
36   LoadTransparencyInfo();
37 }
38 
~CPDF_Page()39 CPDF_Page::~CPDF_Page() {}
40 
AsPDFPage()41 CPDF_Page* CPDF_Page::AsPDFPage() {
42   return this;
43 }
44 
AsXFAPage()45 CPDFXFA_Page* CPDF_Page::AsXFAPage() {
46   return nullptr;
47 }
48 
GetDocument() const49 CPDF_Document* CPDF_Page::GetDocument() const {
50   return GetPDFDocument();
51 }
52 
GetPageWidth() const53 float CPDF_Page::GetPageWidth() const {
54   return m_PageSize.width;
55 }
56 
GetPageHeight() const57 float CPDF_Page::GetPageHeight() const {
58   return m_PageSize.height;
59 }
60 
IsPage() const61 bool CPDF_Page::IsPage() const {
62   return true;
63 }
64 
ParseContent()65 void CPDF_Page::ParseContent() {
66   if (GetParseState() == ParseState::kParsed)
67     return;
68 
69   if (GetParseState() == ParseState::kNotParsed)
70     StartParse(pdfium::MakeUnique<CPDF_ContentParser>(this));
71 
72   ASSERT(GetParseState() == ParseState::kParsing);
73   ContinueParse(nullptr);
74 }
75 
GetPageAttr(const ByteString & name) const76 CPDF_Object* CPDF_Page::GetPageAttr(const ByteString& name) const {
77   CPDF_Dictionary* pPageDict = GetDict();
78   std::set<CPDF_Dictionary*> visited;
79   while (1) {
80     visited.insert(pPageDict);
81     if (CPDF_Object* pObj = pPageDict->GetDirectObjectFor(name))
82       return pObj;
83 
84     pPageDict = pPageDict->GetDictFor(pdfium::page_object::kParent);
85     if (!pPageDict || pdfium::ContainsKey(visited, pPageDict))
86       break;
87   }
88   return nullptr;
89 }
90 
GetBox(const ByteString & name) const91 CFX_FloatRect CPDF_Page::GetBox(const ByteString& name) const {
92   CFX_FloatRect box;
93   CPDF_Array* pBox = ToArray(GetPageAttr(name));
94   if (pBox) {
95     box = pBox->GetRect();
96     box.Normalize();
97   }
98   return box;
99 }
100 
DeviceToPage(const FX_RECT & rect,int rotate,const CFX_PointF & device_point) const101 Optional<CFX_PointF> CPDF_Page::DeviceToPage(
102     const FX_RECT& rect,
103     int rotate,
104     const CFX_PointF& device_point) const {
105   CFX_Matrix page2device = GetDisplayMatrix(rect, rotate);
106   return page2device.GetInverse().Transform(device_point);
107 }
108 
PageToDevice(const FX_RECT & rect,int rotate,const CFX_PointF & page_point) const109 Optional<CFX_PointF> CPDF_Page::PageToDevice(
110     const FX_RECT& rect,
111     int rotate,
112     const CFX_PointF& page_point) const {
113   CFX_Matrix page2device = GetDisplayMatrix(rect, rotate);
114   return page2device.Transform(page_point);
115 }
116 
GetDisplayMatrix(const FX_RECT & rect,int iRotate) const117 CFX_Matrix CPDF_Page::GetDisplayMatrix(const FX_RECT& rect, int iRotate) const {
118   if (m_PageSize.width == 0 || m_PageSize.height == 0)
119     return CFX_Matrix();
120 
121   float x0 = 0;
122   float y0 = 0;
123   float x1 = 0;
124   float y1 = 0;
125   float x2 = 0;
126   float y2 = 0;
127   iRotate %= 4;
128   // This code implicitly inverts the y-axis to account for page coordinates
129   // pointing up and bitmap coordinates pointing down. (x0, y0) is the base
130   // point, (x1, y1) is that point translated on y and (x2, y2) is the point
131   // translated on x. On iRotate = 0, y0 is rect.bottom and the translation
132   // to get y1 is performed as negative. This results in the desired
133   // transformation.
134   switch (iRotate) {
135     case 0:
136       x0 = rect.left;
137       y0 = rect.bottom;
138       x1 = rect.left;
139       y1 = rect.top;
140       x2 = rect.right;
141       y2 = rect.bottom;
142       break;
143     case 1:
144       x0 = rect.left;
145       y0 = rect.top;
146       x1 = rect.right;
147       y1 = rect.top;
148       x2 = rect.left;
149       y2 = rect.bottom;
150       break;
151     case 2:
152       x0 = rect.right;
153       y0 = rect.top;
154       x1 = rect.right;
155       y1 = rect.bottom;
156       x2 = rect.left;
157       y2 = rect.top;
158       break;
159     case 3:
160       x0 = rect.right;
161       y0 = rect.bottom;
162       x1 = rect.left;
163       y1 = rect.bottom;
164       x2 = rect.right;
165       y2 = rect.top;
166       break;
167   }
168   CFX_Matrix matrix((x2 - x0) / m_PageSize.width, (y2 - y0) / m_PageSize.width,
169                     (x1 - x0) / m_PageSize.height,
170                     (y1 - y0) / m_PageSize.height, x0, y0);
171   return m_PageMatrix * matrix;
172 }
173 
GetPageRotation() const174 int CPDF_Page::GetPageRotation() const {
175   CPDF_Object* pRotate = GetPageAttr(pdfium::page_object::kRotate);
176   int rotate = pRotate ? (pRotate->GetInteger() / 90) % 4 : 0;
177   return (rotate < 0) ? (rotate + 4) : rotate;
178 }
179 
UpdateDimensions()180 void CPDF_Page::UpdateDimensions() {
181   CFX_FloatRect mediabox = GetBox(pdfium::page_object::kMediaBox);
182   if (mediabox.IsEmpty())
183     mediabox = CFX_FloatRect(0, 0, 612, 792);
184 
185   m_BBox = GetBox(pdfium::page_object::kCropBox);
186   if (m_BBox.IsEmpty())
187     m_BBox = mediabox;
188   else
189     m_BBox.Intersect(mediabox);
190 
191   m_PageSize.width = m_BBox.Width();
192   m_PageSize.height = m_BBox.Height();
193 
194   switch (GetPageRotation()) {
195     case 0:
196       m_PageMatrix = CFX_Matrix(1.0f, 0, 0, 1.0f, -m_BBox.left, -m_BBox.bottom);
197       break;
198     case 1:
199       std::swap(m_PageSize.width, m_PageSize.height);
200       m_PageMatrix =
201           CFX_Matrix(0, -1.0f, 1.0f, 0, -m_BBox.bottom, m_BBox.right);
202       break;
203     case 2:
204       m_PageMatrix = CFX_Matrix(-1.0f, 0, 0, -1.0f, m_BBox.right, m_BBox.top);
205       break;
206     case 3:
207       std::swap(m_PageSize.width, m_PageSize.height);
208       m_PageMatrix = CFX_Matrix(0, 1.0f, -1.0f, 0, m_BBox.top, -m_BBox.left);
209       break;
210   }
211 }
212 
RenderContextClearer(CPDF_Page * pPage)213 CPDF_Page::RenderContextClearer::RenderContextClearer(CPDF_Page* pPage)
214     : m_pPage(pPage) {}
215 
~RenderContextClearer()216 CPDF_Page::RenderContextClearer::~RenderContextClearer() {
217   m_pPage->SetRenderContext(nullptr);
218 }
219