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 "core/fpdfapi/cpdf_pagerendercontext.h"
13#include "core/fpdfapi/page/cpdf_contentparser.h"
14#include "core/fpdfapi/page/cpdf_pageobject.h"
15#include "core/fpdfapi/page/pageint.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 "core/fpdfapi/render/cpdf_pagerendercache.h"
20#include "third_party/base/ptr_util.h"
21#include "third_party/base/stl_util.h"
22
23CPDF_Page::CPDF_Page(CPDF_Document* pDocument,
24                     CPDF_Dictionary* pPageDict,
25                     bool bPageCache)
26    : m_PageWidth(100),
27      m_PageHeight(100),
28      m_pView(nullptr),
29      m_pPageRender(bPageCache ? new CPDF_PageRenderCache(this) : nullptr) {
30  m_pFormDict = pPageDict;
31  m_pDocument = pDocument;
32  if (!pPageDict)
33    return;
34
35  CPDF_Object* pageAttr = GetPageAttr("Resources");
36  m_pResources = pageAttr ? pageAttr->GetDict() : nullptr;
37  m_pPageResources = m_pResources;
38  CPDF_Object* pRotate = GetPageAttr("Rotate");
39  int rotate = pRotate ? pRotate->GetInteger() / 90 % 4 : 0;
40  if (rotate < 0)
41    rotate += 4;
42
43  CPDF_Array* pMediaBox = ToArray(GetPageAttr("MediaBox"));
44  CFX_FloatRect mediabox;
45  if (pMediaBox) {
46    mediabox = pMediaBox->GetRect();
47    mediabox.Normalize();
48  }
49  if (mediabox.IsEmpty())
50    mediabox = CFX_FloatRect(0, 0, 612, 792);
51
52  CPDF_Array* pCropBox = ToArray(GetPageAttr("CropBox"));
53  if (pCropBox) {
54    m_BBox = pCropBox->GetRect();
55    m_BBox.Normalize();
56  }
57  if (m_BBox.IsEmpty())
58    m_BBox = mediabox;
59  else
60    m_BBox.Intersect(mediabox);
61
62  m_PageWidth = m_BBox.right - m_BBox.left;
63  m_PageHeight = m_BBox.top - m_BBox.bottom;
64  if (rotate % 2)
65    std::swap(m_PageWidth, m_PageHeight);
66
67  switch (rotate) {
68    case 0:
69      m_PageMatrix = CFX_Matrix(1.0f, 0, 0, 1.0f, -m_BBox.left, -m_BBox.bottom);
70      break;
71    case 1:
72      m_PageMatrix =
73          CFX_Matrix(0, -1.0f, 1.0f, 0, -m_BBox.bottom, m_BBox.right);
74      break;
75    case 2:
76      m_PageMatrix = CFX_Matrix(-1.0f, 0, 0, -1.0f, m_BBox.right, m_BBox.top);
77      break;
78    case 3:
79      m_PageMatrix = CFX_Matrix(0, 1.0f, -1.0f, 0, m_BBox.top, -m_BBox.left);
80      break;
81  }
82
83  m_Transparency = PDFTRANS_ISOLATED;
84  LoadTransInfo();
85}
86
87CPDF_Page::~CPDF_Page() {}
88
89void CPDF_Page::StartParse() {
90  if (m_ParseState == CONTENT_PARSED || m_ParseState == CONTENT_PARSING)
91    return;
92
93  m_pParser = pdfium::MakeUnique<CPDF_ContentParser>();
94  m_pParser->Start(this);
95  m_ParseState = CONTENT_PARSING;
96}
97
98void CPDF_Page::ParseContent() {
99  StartParse();
100  ContinueParse(nullptr);
101}
102
103void CPDF_Page::SetRenderContext(
104    std::unique_ptr<CPDF_PageRenderContext> pContext) {
105  m_pRenderContext = std::move(pContext);
106}
107
108CPDF_Object* CPDF_Page::GetPageAttr(const CFX_ByteString& name) const {
109  CPDF_Dictionary* pPageDict = m_pFormDict;
110  std::set<CPDF_Dictionary*> visited;
111  while (1) {
112    visited.insert(pPageDict);
113    if (CPDF_Object* pObj = pPageDict->GetDirectObjectFor(name))
114      return pObj;
115
116    pPageDict = pPageDict->GetDictFor("Parent");
117    if (!pPageDict || pdfium::ContainsKey(visited, pPageDict))
118      break;
119  }
120  return nullptr;
121}
122
123CFX_Matrix CPDF_Page::GetDisplayMatrix(int xPos,
124                                       int yPos,
125                                       int xSize,
126                                       int ySize,
127                                       int iRotate) const {
128  if (m_PageWidth == 0 || m_PageHeight == 0)
129    return CFX_Matrix();
130
131  float x0 = 0;
132  float y0 = 0;
133  float x1 = 0;
134  float y1 = 0;
135  float x2 = 0;
136  float y2 = 0;
137  iRotate %= 4;
138  switch (iRotate) {
139    case 0:
140      x0 = xPos;
141      y0 = yPos + ySize;
142      x1 = xPos;
143      y1 = yPos;
144      x2 = xPos + xSize;
145      y2 = yPos + ySize;
146      break;
147    case 1:
148      x0 = xPos;
149      y0 = yPos;
150      x1 = xPos + xSize;
151      y1 = yPos;
152      x2 = xPos;
153      y2 = yPos + ySize;
154      break;
155    case 2:
156      x0 = xPos + xSize;
157      y0 = yPos;
158      x1 = xPos + xSize;
159      y1 = yPos + ySize;
160      x2 = xPos;
161      y2 = yPos;
162      break;
163    case 3:
164      x0 = xPos + xSize;
165      y0 = yPos + ySize;
166      x1 = xPos;
167      y1 = yPos + ySize;
168      x2 = xPos + xSize;
169      y2 = yPos;
170      break;
171  }
172  CFX_Matrix matrix = m_PageMatrix;
173  matrix.Concat(CFX_Matrix((x2 - x0) / m_PageWidth, (y2 - y0) / m_PageWidth,
174                           (x1 - x0) / m_PageHeight, (y1 - y0) / m_PageHeight,
175                           x0, y0));
176  return matrix;
177}
178
179bool GraphicsData::operator<(const GraphicsData& other) const {
180  if (fillAlpha != other.fillAlpha)
181    return fillAlpha < other.fillAlpha;
182  return strokeAlpha < other.strokeAlpha;
183}
184
185bool FontData::operator<(const FontData& other) const {
186  return baseFont < other.baseFont;
187}
188