blob: 6213e5fccb77ef9a553a12ca1386e5b9cb611bad [file] [log] [blame]
// Copyright 2016 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "core/fpdfapi/page/cpdf_page.h"
#include <set>
#include <utility>
#include "core/fpdfapi/cpdf_pagerendercontext.h"
#include "core/fpdfapi/page/cpdf_contentparser.h"
#include "core/fpdfapi/page/cpdf_pageobject.h"
#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_object.h"
#include "core/fpdfapi/render/cpdf_pagerendercache.h"
#include "third_party/base/ptr_util.h"
#include "third_party/base/stl_util.h"
CPDF_Page::CPDF_Page(CPDF_Document* pDocument,
CPDF_Dictionary* pPageDict,
bool bPageCache)
: CPDF_PageObjectHolder(pDocument, pPageDict),
m_PageWidth(100),
m_PageHeight(100),
m_pView(nullptr) {
if (bPageCache)
m_pPageRender = pdfium::MakeUnique<CPDF_PageRenderCache>(this);
if (!pPageDict)
return;
CPDF_Object* pPageAttr = GetPageAttr("Resources");
m_pResources = pPageAttr ? pPageAttr->GetDict() : nullptr;
m_pPageResources = m_pResources;
CFX_FloatRect mediabox = GetBox("MediaBox");
if (mediabox.IsEmpty())
mediabox = CFX_FloatRect(0, 0, 612, 792);
m_BBox = GetBox("CropBox");
if (m_BBox.IsEmpty())
m_BBox = mediabox;
else
m_BBox.Intersect(mediabox);
m_PageWidth = m_BBox.Width();
m_PageHeight = m_BBox.Height();
int rotate = GetPageRotation();
if (rotate % 2)
std::swap(m_PageWidth, m_PageHeight);
switch (rotate) {
case 0:
m_PageMatrix = CFX_Matrix(1.0f, 0, 0, 1.0f, -m_BBox.left, -m_BBox.bottom);
break;
case 1:
m_PageMatrix =
CFX_Matrix(0, -1.0f, 1.0f, 0, -m_BBox.bottom, m_BBox.right);
break;
case 2:
m_PageMatrix = CFX_Matrix(-1.0f, 0, 0, -1.0f, m_BBox.right, m_BBox.top);
break;
case 3:
m_PageMatrix = CFX_Matrix(0, 1.0f, -1.0f, 0, m_BBox.top, -m_BBox.left);
break;
}
m_Transparency = PDFTRANS_ISOLATED;
LoadTransInfo();
}
CPDF_Page::~CPDF_Page() {}
bool CPDF_Page::IsPage() const {
return true;
}
void CPDF_Page::StartParse() {
if (m_ParseState == CONTENT_PARSED || m_ParseState == CONTENT_PARSING)
return;
m_pParser = pdfium::MakeUnique<CPDF_ContentParser>();
m_pParser->Start(this);
m_ParseState = CONTENT_PARSING;
}
void CPDF_Page::ParseContent() {
StartParse();
ContinueParse(nullptr);
}
void CPDF_Page::SetRenderContext(
std::unique_ptr<CPDF_PageRenderContext> pContext) {
m_pRenderContext = std::move(pContext);
}
CPDF_Object* CPDF_Page::GetPageAttr(const CFX_ByteString& name) const {
CPDF_Dictionary* pPageDict = m_pFormDict.Get();
std::set<CPDF_Dictionary*> visited;
while (1) {
visited.insert(pPageDict);
if (CPDF_Object* pObj = pPageDict->GetDirectObjectFor(name))
return pObj;
pPageDict = pPageDict->GetDictFor("Parent");
if (!pPageDict || pdfium::ContainsKey(visited, pPageDict))
break;
}
return nullptr;
}
CFX_FloatRect CPDF_Page::GetBox(const CFX_ByteString& name) const {
CFX_FloatRect box;
CPDF_Array* pBox = ToArray(GetPageAttr(name));
if (pBox) {
box = pBox->GetRect();
box.Normalize();
}
return box;
}
CFX_Matrix CPDF_Page::GetDisplayMatrix(int xPos,
int yPos,
int xSize,
int ySize,
int iRotate) const {
if (m_PageWidth == 0 || m_PageHeight == 0)
return CFX_Matrix();
float x0 = 0;
float y0 = 0;
float x1 = 0;
float y1 = 0;
float x2 = 0;
float y2 = 0;
iRotate %= 4;
switch (iRotate) {
case 0:
x0 = xPos;
y0 = yPos + ySize;
x1 = xPos;
y1 = yPos;
x2 = xPos + xSize;
y2 = yPos + ySize;
break;
case 1:
x0 = xPos;
y0 = yPos;
x1 = xPos + xSize;
y1 = yPos;
x2 = xPos;
y2 = yPos + ySize;
break;
case 2:
x0 = xPos + xSize;
y0 = yPos;
x1 = xPos + xSize;
y1 = yPos + ySize;
x2 = xPos;
y2 = yPos;
break;
case 3:
x0 = xPos + xSize;
y0 = yPos + ySize;
x1 = xPos;
y1 = yPos + ySize;
x2 = xPos + xSize;
y2 = yPos;
break;
}
CFX_Matrix matrix = m_PageMatrix;
matrix.Concat(CFX_Matrix((x2 - x0) / m_PageWidth, (y2 - y0) / m_PageWidth,
(x1 - x0) / m_PageHeight, (y1 - y0) / m_PageHeight,
x0, y0));
return matrix;
}
// This method follows the same apparent logic as GetDisplayMatrix(). For
// example, consider point 0. First, take the top left coordinate of the
// rectangle in the transformed space. Now, calculate what this point was in the
// original space by inverting. Note that this is not necessarily the same as
// the top left corner of the original rectangle.
CFX_Matrix CPDF_Page::GetDisplayMatrixWithTransformation(
int xPos,
int yPos,
int xSize,
int ySize,
const CFX_Matrix& transformation) {
CFX_FloatRect rect(xPos, yPos, xPos + xSize, yPos + ySize);
rect = transformation.TransformRect(rect);
CFX_Matrix inverse = transformation.GetInverse();
CFX_PointF point0(rect.left, rect.top);
CFX_PointF point1(rect.left, rect.bottom);
CFX_PointF point2(rect.right, rect.top);
point0 = inverse.Transform(point0);
point1 = inverse.Transform(point1);
point2 = inverse.Transform(point2);
CFX_Matrix matrix = m_PageMatrix;
matrix.Concat(CFX_Matrix(
(point2.x - point0.x) / m_PageWidth, (point2.y - point0.y) / m_PageWidth,
(point1.x - point0.x) / m_PageHeight,
(point1.y - point0.y) / m_PageHeight, point0.x, point0.y));
return matrix;
}
int CPDF_Page::GetPageRotation() const {
CPDF_Object* pRotate = GetPageAttr("Rotate");
int rotate = pRotate ? (pRotate->GetInteger() / 90) % 4 : 0;
return (rotate < 0) ? (rotate + 4) : rotate;
}
bool GraphicsData::operator<(const GraphicsData& other) const {
if (fillAlpha != other.fillAlpha)
return fillAlpha < other.fillAlpha;
if (strokeAlpha != other.strokeAlpha)
return strokeAlpha < other.strokeAlpha;
return blendType < other.blendType;
}
bool FontData::operator<(const FontData& other) const {
if (baseFont != other.baseFont)
return baseFont < other.baseFont;
return type < other.type;
}