summaryrefslogtreecommitdiff
path: root/core/fpdfapi/fpdf_page
diff options
context:
space:
mode:
authorDan Sinclair <dsinclair@chromium.org>2016-03-14 13:35:12 -0400
committerDan Sinclair <dsinclair@chromium.org>2016-03-14 13:35:12 -0400
commit764ec513eecbebd12781bcc96ce81ed5e736ee92 (patch)
tree12763fde4be1f10ea1183d92185917b2b587e00b /core/fpdfapi/fpdf_page
parent97da97662417085774f75c26e535c6fbe70266ae (diff)
downloadpdfium-764ec513eecbebd12781bcc96ce81ed5e736ee92.tar.xz
Move core/src/ up to core/.
This CL moves the core/src/ files up to core/ and fixes up the include guards, includes and build files. R=tsepez@chromium.org Review URL: https://codereview.chromium.org/1800523005 .
Diffstat (limited to 'core/fpdfapi/fpdf_page')
-rw-r--r--core/fpdfapi/fpdf_page/fpdf_page.cpp764
-rw-r--r--core/fpdfapi/fpdf_page/fpdf_page_colors.cpp1550
-rw-r--r--core/fpdfapi/fpdf_page/fpdf_page_doc.cpp610
-rw-r--r--core/fpdfapi/fpdf_page/fpdf_page_func.cpp966
-rw-r--r--core/fpdfapi/fpdf_page/fpdf_page_func_embeddertest.cpp20
-rw-r--r--core/fpdfapi/fpdf_page/fpdf_page_graph_state.cpp697
-rw-r--r--core/fpdfapi/fpdf_page/fpdf_page_image.cpp100
-rw-r--r--core/fpdfapi/fpdf_page/fpdf_page_parser.cpp1819
-rw-r--r--core/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp888
-rw-r--r--core/fpdfapi/fpdf_page/fpdf_page_parser_old_unittest.cpp47
-rw-r--r--core/fpdfapi/fpdf_page/fpdf_page_path.cpp55
-rw-r--r--core/fpdfapi/fpdf_page/fpdf_page_pattern.cpp320
-rw-r--r--core/fpdfapi/fpdf_page/pageint.h459
13 files changed, 8295 insertions, 0 deletions
diff --git a/core/fpdfapi/fpdf_page/fpdf_page.cpp b/core/fpdfapi/fpdf_page/fpdf_page.cpp
new file mode 100644
index 0000000000..5d4a584349
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/fpdf_page.cpp
@@ -0,0 +1,764 @@
+// Copyright 2014 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/fpdf_page/pageint.h"
+
+#include <algorithm>
+
+#include "core/include/fpdfapi/cpdf_array.h"
+#include "core/include/fpdfapi/cpdf_dictionary.h"
+#include "core/include/fpdfapi/cpdf_document.h"
+#include "core/include/fpdfapi/fpdf_module.h"
+#include "core/include/fpdfapi/fpdf_page.h"
+#include "third_party/base/stl_util.h"
+
+CPDF_PageObject::CPDF_PageObject() {}
+
+CPDF_PageObject::~CPDF_PageObject() {}
+
+void CPDF_PageObject::CopyData(const CPDF_PageObject* pSrc) {
+ CopyStates(*pSrc);
+ m_Left = pSrc->m_Left;
+ m_Right = pSrc->m_Right;
+ m_Top = pSrc->m_Top;
+ m_Bottom = pSrc->m_Bottom;
+}
+
+void CPDF_PageObject::TransformClipPath(CFX_Matrix& matrix) {
+ if (m_ClipPath.IsNull()) {
+ return;
+ }
+ m_ClipPath.GetModify();
+ m_ClipPath.Transform(matrix);
+}
+
+void CPDF_PageObject::TransformGeneralState(CFX_Matrix& matrix) {
+ if (m_GeneralState.IsNull()) {
+ return;
+ }
+ CPDF_GeneralStateData* pGS = m_GeneralState.GetModify();
+ pGS->m_Matrix.Concat(matrix);
+}
+
+FX_RECT CPDF_PageObject::GetBBox(const CFX_Matrix* pMatrix) const {
+ CFX_FloatRect rect(m_Left, m_Bottom, m_Right, m_Top);
+ if (pMatrix) {
+ pMatrix->TransformRect(rect);
+ }
+ return rect.GetOutterRect();
+}
+
+CPDF_TextObject::CPDF_TextObject()
+ : m_PosX(0),
+ m_PosY(0),
+ m_nChars(0),
+ m_pCharCodes(nullptr),
+ m_pCharPos(nullptr) {}
+
+CPDF_TextObject::~CPDF_TextObject() {
+ if (m_nChars > 1) {
+ FX_Free(m_pCharCodes);
+ }
+ FX_Free(m_pCharPos);
+}
+
+void CPDF_TextObject::GetItemInfo(int index, CPDF_TextObjectItem* pInfo) const {
+ pInfo->m_CharCode =
+ m_nChars == 1 ? (FX_DWORD)(uintptr_t)m_pCharCodes : m_pCharCodes[index];
+ pInfo->m_OriginX = index ? m_pCharPos[index - 1] : 0;
+ pInfo->m_OriginY = 0;
+ if (pInfo->m_CharCode == -1) {
+ return;
+ }
+ CPDF_Font* pFont = m_TextState.GetFont();
+ if (!pFont->IsCIDFont()) {
+ return;
+ }
+ if (!pFont->AsCIDFont()->IsVertWriting()) {
+ return;
+ }
+ FX_WORD CID = pFont->AsCIDFont()->CIDFromCharCode(pInfo->m_CharCode);
+ pInfo->m_OriginY = pInfo->m_OriginX;
+ pInfo->m_OriginX = 0;
+ short vx, vy;
+ pFont->AsCIDFont()->GetVertOrigin(CID, vx, vy);
+ FX_FLOAT fontsize = m_TextState.GetFontSize();
+ pInfo->m_OriginX -= fontsize * vx / 1000;
+ pInfo->m_OriginY -= fontsize * vy / 1000;
+}
+
+int CPDF_TextObject::CountChars() const {
+ if (m_nChars == 1) {
+ return 1;
+ }
+ int count = 0;
+ for (int i = 0; i < m_nChars; ++i)
+ if (m_pCharCodes[i] != (FX_DWORD)-1) {
+ ++count;
+ }
+ return count;
+}
+
+void CPDF_TextObject::GetCharInfo(int index,
+ FX_DWORD& charcode,
+ FX_FLOAT& kerning) const {
+ if (m_nChars == 1) {
+ charcode = (FX_DWORD)(uintptr_t)m_pCharCodes;
+ kerning = 0;
+ return;
+ }
+ int count = 0;
+ for (int i = 0; i < m_nChars; ++i) {
+ if (m_pCharCodes[i] != (FX_DWORD)-1) {
+ if (count == index) {
+ charcode = m_pCharCodes[i];
+ if (i == m_nChars - 1 || m_pCharCodes[i + 1] != (FX_DWORD)-1) {
+ kerning = 0;
+ } else {
+ kerning = m_pCharPos[i];
+ }
+ return;
+ }
+ ++count;
+ }
+ }
+}
+
+void CPDF_TextObject::GetCharInfo(int index, CPDF_TextObjectItem* pInfo) const {
+ if (m_nChars == 1) {
+ GetItemInfo(0, pInfo);
+ return;
+ }
+ int count = 0;
+ for (int i = 0; i < m_nChars; ++i) {
+ FX_DWORD charcode = m_pCharCodes[i];
+ if (charcode == (FX_DWORD)-1) {
+ continue;
+ }
+ if (count == index) {
+ GetItemInfo(i, pInfo);
+ break;
+ }
+ ++count;
+ }
+}
+
+CPDF_TextObject* CPDF_TextObject::Clone() const {
+ CPDF_TextObject* obj = new CPDF_TextObject;
+ obj->CopyData(this);
+
+ obj->m_nChars = m_nChars;
+ if (m_nChars > 1) {
+ obj->m_pCharCodes = FX_Alloc(FX_DWORD, m_nChars);
+ FXSYS_memcpy(obj->m_pCharCodes, m_pCharCodes, m_nChars * sizeof(FX_DWORD));
+ obj->m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);
+ FXSYS_memcpy(obj->m_pCharPos, m_pCharPos,
+ (m_nChars - 1) * sizeof(FX_FLOAT));
+ } else {
+ obj->m_pCharCodes = m_pCharCodes;
+ }
+ obj->m_PosX = m_PosX;
+ obj->m_PosY = m_PosY;
+ return obj;
+}
+
+void CPDF_TextObject::GetTextMatrix(CFX_Matrix* pMatrix) const {
+ FX_FLOAT* pTextMatrix = m_TextState.GetMatrix();
+ pMatrix->Set(pTextMatrix[0], pTextMatrix[2], pTextMatrix[1], pTextMatrix[3],
+ m_PosX, m_PosY);
+}
+
+void CPDF_TextObject::SetSegments(const CFX_ByteString* pStrs,
+ FX_FLOAT* pKerning,
+ int nsegs) {
+ if (m_nChars > 1) {
+ FX_Free(m_pCharCodes);
+ m_pCharCodes = nullptr;
+ }
+ FX_Free(m_pCharPos);
+ m_pCharPos = nullptr;
+ CPDF_Font* pFont = m_TextState.GetFont();
+ m_nChars = 0;
+ for (int i = 0; i < nsegs; ++i) {
+ m_nChars += pFont->CountChar(pStrs[i], pStrs[i].GetLength());
+ }
+ m_nChars += nsegs - 1;
+ if (m_nChars > 1) {
+ m_pCharCodes = FX_Alloc(FX_DWORD, m_nChars);
+ m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);
+ int index = 0;
+ for (int i = 0; i < nsegs; ++i) {
+ const FX_CHAR* segment = pStrs[i];
+ int offset = 0, len = pStrs[i].GetLength();
+ while (offset < len) {
+ m_pCharCodes[index++] = pFont->GetNextChar(segment, len, offset);
+ }
+ if (i != nsegs - 1) {
+ m_pCharPos[index - 1] = pKerning[i];
+ m_pCharCodes[index++] = (FX_DWORD)-1;
+ }
+ }
+ } else {
+ int offset = 0;
+ m_pCharCodes = (FX_DWORD*)(uintptr_t)pFont->GetNextChar(
+ pStrs[0], pStrs[0].GetLength(), offset);
+ }
+}
+
+void CPDF_TextObject::SetText(const CFX_ByteString& str) {
+ SetSegments(&str, nullptr, 1);
+ RecalcPositionData();
+}
+
+FX_FLOAT CPDF_TextObject::GetCharWidth(FX_DWORD charcode) const {
+ FX_FLOAT fontsize = m_TextState.GetFontSize() / 1000;
+ CPDF_Font* pFont = m_TextState.GetFont();
+ FX_BOOL bVertWriting = FALSE;
+ CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
+ if (pCIDFont) {
+ bVertWriting = pCIDFont->IsVertWriting();
+ }
+ if (!bVertWriting)
+ return pFont->GetCharWidthF(charcode, 0) * fontsize;
+
+ FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);
+ return pCIDFont->GetVertWidth(CID) * fontsize;
+}
+
+void CPDF_TextObject::CalcPositionData(FX_FLOAT* pTextAdvanceX,
+ FX_FLOAT* pTextAdvanceY,
+ FX_FLOAT horz_scale,
+ int level) {
+ FX_FLOAT curpos = 0;
+ FX_FLOAT min_x = 10000 * 1.0f;
+ FX_FLOAT max_x = -10000 * 1.0f;
+ FX_FLOAT min_y = 10000 * 1.0f;
+ FX_FLOAT max_y = -10000 * 1.0f;
+ CPDF_Font* pFont = m_TextState.GetFont();
+ FX_BOOL bVertWriting = FALSE;
+ CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
+ if (pCIDFont) {
+ bVertWriting = pCIDFont->IsVertWriting();
+ }
+ FX_FLOAT fontsize = m_TextState.GetFontSize();
+ for (int i = 0; i < m_nChars; ++i) {
+ FX_DWORD charcode =
+ m_nChars == 1 ? (FX_DWORD)(uintptr_t)m_pCharCodes : m_pCharCodes[i];
+ if (i > 0) {
+ if (charcode == (FX_DWORD)-1) {
+ curpos -= (m_pCharPos[i - 1] * fontsize) / 1000;
+ continue;
+ }
+ m_pCharPos[i - 1] = curpos;
+ }
+ FX_RECT char_rect = pFont->GetCharBBox(charcode, level);
+ FX_FLOAT charwidth;
+ if (!bVertWriting) {
+ if (min_y > char_rect.top) {
+ min_y = (FX_FLOAT)char_rect.top;
+ }
+ if (max_y < char_rect.top) {
+ max_y = (FX_FLOAT)char_rect.top;
+ }
+ if (min_y > char_rect.bottom) {
+ min_y = (FX_FLOAT)char_rect.bottom;
+ }
+ if (max_y < char_rect.bottom) {
+ max_y = (FX_FLOAT)char_rect.bottom;
+ }
+ FX_FLOAT char_left = curpos + char_rect.left * fontsize / 1000;
+ FX_FLOAT char_right = curpos + char_rect.right * fontsize / 1000;
+ if (min_x > char_left) {
+ min_x = char_left;
+ }
+ if (max_x < char_left) {
+ max_x = char_left;
+ }
+ if (min_x > char_right) {
+ min_x = char_right;
+ }
+ if (max_x < char_right) {
+ max_x = char_right;
+ }
+ charwidth = pFont->GetCharWidthF(charcode, level) * fontsize / 1000;
+ } else {
+ FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);
+ short vx;
+ short vy;
+ pCIDFont->GetVertOrigin(CID, vx, vy);
+ char_rect.left -= vx;
+ char_rect.right -= vx;
+ char_rect.top -= vy;
+ char_rect.bottom -= vy;
+ if (min_x > char_rect.left) {
+ min_x = (FX_FLOAT)char_rect.left;
+ }
+ if (max_x < char_rect.left) {
+ max_x = (FX_FLOAT)char_rect.left;
+ }
+ if (min_x > char_rect.right) {
+ min_x = (FX_FLOAT)char_rect.right;
+ }
+ if (max_x < char_rect.right) {
+ max_x = (FX_FLOAT)char_rect.right;
+ }
+ FX_FLOAT char_top = curpos + char_rect.top * fontsize / 1000;
+ FX_FLOAT char_bottom = curpos + char_rect.bottom * fontsize / 1000;
+ if (min_y > char_top) {
+ min_y = char_top;
+ }
+ if (max_y < char_top) {
+ max_y = char_top;
+ }
+ if (min_y > char_bottom) {
+ min_y = char_bottom;
+ }
+ if (max_y < char_bottom) {
+ max_y = char_bottom;
+ }
+ charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000;
+ }
+ curpos += charwidth;
+ if (charcode == ' ' && (!pCIDFont || pCIDFont->GetCharSize(32) == 1)) {
+ curpos += m_TextState.GetObject()->m_WordSpace;
+ }
+ curpos += m_TextState.GetObject()->m_CharSpace;
+ }
+ if (bVertWriting) {
+ if (pTextAdvanceX) {
+ *pTextAdvanceX = 0;
+ }
+ if (pTextAdvanceY) {
+ *pTextAdvanceY = curpos;
+ }
+ min_x = min_x * fontsize / 1000;
+ max_x = max_x * fontsize / 1000;
+ } else {
+ if (pTextAdvanceX) {
+ *pTextAdvanceX = curpos * horz_scale;
+ }
+ if (pTextAdvanceY) {
+ *pTextAdvanceY = 0;
+ }
+ min_y = min_y * fontsize / 1000;
+ max_y = max_y * fontsize / 1000;
+ }
+ CFX_Matrix matrix;
+ GetTextMatrix(&matrix);
+ m_Left = min_x;
+ m_Right = max_x;
+ m_Bottom = min_y;
+ m_Top = max_y;
+ matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom);
+ int textmode = m_TextState.GetObject()->m_TextMode;
+ if (textmode == 1 || textmode == 2 || textmode == 5 || textmode == 6) {
+ FX_FLOAT half_width = m_GraphState.GetObject()->m_LineWidth / 2;
+ m_Left -= half_width;
+ m_Right += half_width;
+ m_Top += half_width;
+ m_Bottom -= half_width;
+ }
+}
+
+void CPDF_TextObject::Transform(const CFX_Matrix& matrix) {
+ m_TextState.GetModify();
+ CFX_Matrix text_matrix;
+ GetTextMatrix(&text_matrix);
+ text_matrix.Concat(matrix);
+ FX_FLOAT* pTextMatrix = m_TextState.GetMatrix();
+ pTextMatrix[0] = text_matrix.GetA();
+ pTextMatrix[1] = text_matrix.GetC();
+ pTextMatrix[2] = text_matrix.GetB();
+ pTextMatrix[3] = text_matrix.GetD();
+ m_PosX = text_matrix.GetE();
+ m_PosY = text_matrix.GetF();
+ CalcPositionData(nullptr, nullptr, 0);
+}
+
+void CPDF_TextObject::SetPosition(FX_FLOAT x, FX_FLOAT y) {
+ FX_FLOAT dx = x - m_PosX;
+ FX_FLOAT dy = y - m_PosY;
+ m_PosX = x;
+ m_PosY = y;
+ m_Left += dx;
+ m_Right += dx;
+ m_Top += dy;
+ m_Bottom += dy;
+}
+
+CPDF_ShadingObject::CPDF_ShadingObject() : m_pShading(nullptr) {}
+
+CPDF_ShadingObject::~CPDF_ShadingObject() {}
+
+CPDF_ShadingObject* CPDF_ShadingObject::Clone() const {
+ CPDF_ShadingObject* obj = new CPDF_ShadingObject;
+ obj->CopyData(this);
+
+ obj->m_pShading = m_pShading;
+ if (obj->m_pShading && obj->m_pShading->m_pDocument) {
+ CPDF_DocPageData* pDocPageData =
+ obj->m_pShading->m_pDocument->GetPageData();
+ obj->m_pShading = (CPDF_ShadingPattern*)pDocPageData->GetPattern(
+ obj->m_pShading->m_pShadingObj, m_pShading->m_bShadingObj,
+ &obj->m_pShading->m_ParentMatrix);
+ }
+ obj->m_Matrix = m_Matrix;
+ return obj;
+}
+
+void CPDF_ShadingObject::Transform(const CFX_Matrix& matrix) {
+ if (!m_ClipPath.IsNull()) {
+ m_ClipPath.GetModify();
+ m_ClipPath.Transform(matrix);
+ }
+ m_Matrix.Concat(matrix);
+ if (!m_ClipPath.IsNull()) {
+ CalcBoundingBox();
+ } else {
+ matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom);
+ }
+}
+
+void CPDF_ShadingObject::CalcBoundingBox() {
+ if (m_ClipPath.IsNull()) {
+ return;
+ }
+ CFX_FloatRect rect = m_ClipPath.GetClipBox();
+ m_Left = rect.left;
+ m_Bottom = rect.bottom;
+ m_Right = rect.right;
+ m_Top = rect.top;
+}
+
+CPDF_FormObject::CPDF_FormObject() : m_pForm(nullptr) {}
+
+CPDF_FormObject::~CPDF_FormObject() {
+ delete m_pForm;
+}
+
+void CPDF_FormObject::Transform(const CFX_Matrix& matrix) {
+ m_FormMatrix.Concat(matrix);
+ CalcBoundingBox();
+}
+
+CPDF_FormObject* CPDF_FormObject::Clone() const {
+ CPDF_FormObject* obj = new CPDF_FormObject;
+ obj->CopyData(this);
+
+ obj->m_pForm = m_pForm->Clone();
+ obj->m_FormMatrix = m_FormMatrix;
+ return obj;
+}
+
+void CPDF_FormObject::CalcBoundingBox() {
+ CFX_FloatRect form_rect = m_pForm->CalcBoundingBox();
+ form_rect.Transform(&m_FormMatrix);
+ m_Left = form_rect.left;
+ m_Bottom = form_rect.bottom;
+ m_Right = form_rect.right;
+ m_Top = form_rect.top;
+}
+
+CPDF_PageObject* CPDF_PageObjectList::GetPageObjectByIndex(int index) {
+ if (index < 0 || index >= pdfium::CollectionSize<int>(*this))
+ return nullptr;
+ return (*this)[index].get();
+}
+
+CPDF_PageObjectHolder::CPDF_PageObjectHolder()
+ : m_pFormDict(nullptr),
+ m_pFormStream(nullptr),
+ m_pDocument(nullptr),
+ m_pPageResources(nullptr),
+ m_pResources(nullptr),
+ m_Transparency(0),
+ m_bBackgroundAlphaNeeded(FALSE),
+ m_bHasImageMask(FALSE),
+ m_ParseState(CONTENT_NOT_PARSED) {}
+
+void CPDF_PageObjectHolder::ContinueParse(IFX_Pause* pPause) {
+ if (!m_pParser) {
+ return;
+ }
+ m_pParser->Continue(pPause);
+ if (m_pParser->GetStatus() == CPDF_ContentParser::Done) {
+ m_ParseState = CONTENT_PARSED;
+ m_pParser.reset();
+ }
+}
+
+void CPDF_PageObjectHolder::Transform(const CFX_Matrix& matrix) {
+ for (auto& pObj : m_PageObjectList)
+ pObj->Transform(matrix);
+}
+
+CFX_FloatRect CPDF_PageObjectHolder::CalcBoundingBox() const {
+ if (m_PageObjectList.empty())
+ return CFX_FloatRect(0, 0, 0, 0);
+
+ FX_FLOAT left = 1000000.0f;
+ FX_FLOAT right = -1000000.0f;
+ FX_FLOAT bottom = 1000000.0f;
+ FX_FLOAT top = -1000000.0f;
+ for (const auto& pObj : m_PageObjectList) {
+ left = std::min(left, pObj->m_Left);
+ right = std::max(right, pObj->m_Right);
+ bottom = std::min(bottom, pObj->m_Bottom);
+ top = std::max(top, pObj->m_Top);
+ }
+ return CFX_FloatRect(left, bottom, right, top);
+}
+
+void CPDF_PageObjectHolder::LoadTransInfo() {
+ if (!m_pFormDict) {
+ return;
+ }
+ CPDF_Dictionary* pGroup = m_pFormDict->GetDictBy("Group");
+ if (!pGroup) {
+ return;
+ }
+ if (pGroup->GetStringBy("S") != "Transparency") {
+ return;
+ }
+ m_Transparency |= PDFTRANS_GROUP;
+ if (pGroup->GetIntegerBy("I")) {
+ m_Transparency |= PDFTRANS_ISOLATED;
+ }
+ if (pGroup->GetIntegerBy("K")) {
+ m_Transparency |= PDFTRANS_KNOCKOUT;
+ }
+}
+
+CPDF_Page::CPDF_Page() : m_pPageRender(nullptr) {}
+
+void CPDF_Page::Load(CPDF_Document* pDocument,
+ CPDF_Dictionary* pPageDict,
+ FX_BOOL bPageCache) {
+ m_pDocument = (CPDF_Document*)pDocument;
+ m_pFormDict = pPageDict;
+ if (bPageCache) {
+ m_pPageRender =
+ CPDF_ModuleMgr::Get()->GetRenderModule()->CreatePageCache(this);
+ }
+ if (!pPageDict) {
+ m_PageWidth = m_PageHeight = 100 * 1.0f;
+ m_pPageResources = m_pResources = NULL;
+ return;
+ }
+ CPDF_Object* pageAttr = GetPageAttr("Resources");
+ m_pResources = pageAttr ? pageAttr->GetDict() : NULL;
+ m_pPageResources = m_pResources;
+ CPDF_Object* pRotate = GetPageAttr("Rotate");
+ int rotate = 0;
+ if (pRotate) {
+ rotate = pRotate->GetInteger() / 90 % 4;
+ }
+ if (rotate < 0) {
+ rotate += 4;
+ }
+ CPDF_Array* pMediaBox = ToArray(GetPageAttr("MediaBox"));
+ CFX_FloatRect mediabox;
+ if (pMediaBox) {
+ mediabox = pMediaBox->GetRect();
+ mediabox.Normalize();
+ }
+ if (mediabox.IsEmpty()) {
+ mediabox = CFX_FloatRect(0, 0, 612, 792);
+ }
+
+ CPDF_Array* pCropBox = ToArray(GetPageAttr("CropBox"));
+ if (pCropBox) {
+ m_BBox = pCropBox->GetRect();
+ m_BBox.Normalize();
+ }
+ if (m_BBox.IsEmpty()) {
+ m_BBox = mediabox;
+ } else {
+ m_BBox.Intersect(mediabox);
+ }
+ if (rotate % 2) {
+ m_PageHeight = m_BBox.right - m_BBox.left;
+ m_PageWidth = m_BBox.top - m_BBox.bottom;
+ } else {
+ m_PageWidth = m_BBox.right - m_BBox.left;
+ m_PageHeight = m_BBox.top - m_BBox.bottom;
+ }
+ switch (rotate) {
+ case 0:
+ m_PageMatrix.Set(1.0f, 0, 0, 1.0f, -m_BBox.left, -m_BBox.bottom);
+ break;
+ case 1:
+ m_PageMatrix.Set(0, -1.0f, 1.0f, 0, -m_BBox.bottom, m_BBox.right);
+ break;
+ case 2:
+ m_PageMatrix.Set(-1.0f, 0, 0, -1.0f, m_BBox.right, m_BBox.top);
+ break;
+ case 3:
+ m_PageMatrix.Set(0, 1.0f, -1.0f, 0, m_BBox.top, -m_BBox.left);
+ break;
+ }
+ m_Transparency = PDFTRANS_ISOLATED;
+ LoadTransInfo();
+}
+
+void CPDF_Page::StartParse(CPDF_ParseOptions* pOptions) {
+ if (m_ParseState == CONTENT_PARSED || m_ParseState == CONTENT_PARSING) {
+ return;
+ }
+ m_pParser.reset(new CPDF_ContentParser);
+ m_pParser->Start(this, pOptions);
+ m_ParseState = CONTENT_PARSING;
+}
+
+void CPDF_Page::ParseContent(CPDF_ParseOptions* pOptions) {
+ StartParse(pOptions);
+ ContinueParse(nullptr);
+}
+
+CPDF_Page::~CPDF_Page() {
+ if (m_pPageRender) {
+ IPDF_RenderModule* pModule = CPDF_ModuleMgr::Get()->GetRenderModule();
+ pModule->DestroyPageCache(m_pPageRender);
+ }
+}
+
+CPDF_Object* FPDFAPI_GetPageAttr(CPDF_Dictionary* pPageDict,
+ const CFX_ByteStringC& name) {
+ int level = 0;
+ while (1) {
+ CPDF_Object* pObj = pPageDict->GetElementValue(name);
+ if (pObj) {
+ return pObj;
+ }
+ CPDF_Dictionary* pParent = pPageDict->GetDictBy("Parent");
+ if (!pParent || pParent == pPageDict) {
+ return NULL;
+ }
+ pPageDict = pParent;
+ level++;
+ if (level == 1000) {
+ return NULL;
+ }
+ }
+}
+
+CPDF_Object* CPDF_Page::GetPageAttr(const CFX_ByteStringC& name) const {
+ return FPDFAPI_GetPageAttr(m_pFormDict, name);
+}
+
+CPDF_Form::CPDF_Form(CPDF_Document* pDoc,
+ CPDF_Dictionary* pPageResources,
+ CPDF_Stream* pFormStream,
+ CPDF_Dictionary* pParentResources) {
+ m_pDocument = pDoc;
+ m_pFormStream = pFormStream;
+ m_pFormDict = pFormStream ? pFormStream->GetDict() : NULL;
+ m_pResources = m_pFormDict->GetDictBy("Resources");
+ m_pPageResources = pPageResources;
+ if (!m_pResources) {
+ m_pResources = pParentResources;
+ }
+ if (!m_pResources) {
+ m_pResources = pPageResources;
+ }
+ m_Transparency = 0;
+ LoadTransInfo();
+}
+
+CPDF_Form::~CPDF_Form() {}
+
+void CPDF_Form::StartParse(CPDF_AllStates* pGraphicStates,
+ CFX_Matrix* pParentMatrix,
+ CPDF_Type3Char* pType3Char,
+ CPDF_ParseOptions* pOptions,
+ int level) {
+ if (m_ParseState == CONTENT_PARSED || m_ParseState == CONTENT_PARSING) {
+ return;
+ }
+ m_pParser.reset(new CPDF_ContentParser);
+ m_pParser->Start(this, pGraphicStates, pParentMatrix, pType3Char, pOptions,
+ level);
+ m_ParseState = CONTENT_PARSING;
+}
+
+void CPDF_Form::ParseContent(CPDF_AllStates* pGraphicStates,
+ CFX_Matrix* pParentMatrix,
+ CPDF_Type3Char* pType3Char,
+ CPDF_ParseOptions* pOptions,
+ int level) {
+ StartParse(pGraphicStates, pParentMatrix, pType3Char, pOptions, level);
+ ContinueParse(NULL);
+}
+
+CPDF_Form* CPDF_Form::Clone() const {
+ CPDF_Form* pCloneForm =
+ new CPDF_Form(m_pDocument, m_pPageResources, m_pFormStream, m_pResources);
+ for (const auto& pObj : m_PageObjectList)
+ pCloneForm->m_PageObjectList.emplace_back(pObj->Clone());
+
+ return pCloneForm;
+}
+
+void CPDF_Page::GetDisplayMatrix(CFX_Matrix& matrix,
+ int xPos,
+ int yPos,
+ int xSize,
+ int ySize,
+ int iRotate) const {
+ if (m_PageWidth == 0 || m_PageHeight == 0) {
+ return;
+ }
+ CFX_Matrix display_matrix;
+ int x0, y0, x1, y1, x2, y2;
+ 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;
+ }
+ display_matrix.Set(
+ ((FX_FLOAT)(x2 - x0)) / m_PageWidth, ((FX_FLOAT)(y2 - y0)) / m_PageWidth,
+ ((FX_FLOAT)(x1 - x0)) / m_PageHeight,
+ ((FX_FLOAT)(y1 - y0)) / m_PageHeight, (FX_FLOAT)x0, (FX_FLOAT)y0);
+ matrix = m_PageMatrix;
+ matrix.Concat(display_matrix);
+}
+
+CPDF_ParseOptions::CPDF_ParseOptions() {
+ m_bTextOnly = FALSE;
+ m_bMarkedContent = TRUE;
+ m_bSeparateForm = TRUE;
+ m_bDecodeInlineImage = FALSE;
+}
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_colors.cpp b/core/fpdfapi/fpdf_page/fpdf_page_colors.cpp
new file mode 100644
index 0000000000..f557669a77
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/fpdf_page_colors.cpp
@@ -0,0 +1,1550 @@
+// Copyright 2014 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/fpdf_page/pageint.h"
+
+#include <limits.h>
+
+#include <algorithm>
+
+#include "core/include/fpdfapi/cpdf_array.h"
+#include "core/include/fpdfapi/cpdf_dictionary.h"
+#include "core/include/fpdfapi/cpdf_document.h"
+#include "core/include/fpdfapi/cpdf_string.h"
+#include "core/include/fpdfapi/fpdf_module.h"
+#include "core/include/fpdfapi/fpdf_page.h"
+#include "core/include/fxcodec/fx_codec.h"
+
+namespace {
+
+void sRGB_to_AdobeCMYK(FX_FLOAT R,
+ FX_FLOAT G,
+ FX_FLOAT B,
+ FX_FLOAT& c,
+ FX_FLOAT& m,
+ FX_FLOAT& y,
+ FX_FLOAT& k) {
+ c = 1.0f - R;
+ m = 1.0f - G;
+ y = 1.0f - B;
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+}
+
+FX_DWORD ComponentsForFamily(int family) {
+ if (family == PDFCS_DEVICERGB)
+ return 3;
+ if (family == PDFCS_DEVICEGRAY)
+ return 1;
+ return 4;
+}
+
+void ReverseRGB(uint8_t* pDestBuf, const uint8_t* pSrcBuf, int pixels) {
+ if (pDestBuf == pSrcBuf) {
+ for (int i = 0; i < pixels; i++) {
+ uint8_t temp = pDestBuf[2];
+ pDestBuf[2] = pDestBuf[0];
+ pDestBuf[0] = temp;
+ pDestBuf += 3;
+ }
+ } else {
+ for (int i = 0; i < pixels; i++) {
+ *pDestBuf++ = pSrcBuf[2];
+ *pDestBuf++ = pSrcBuf[1];
+ *pDestBuf++ = pSrcBuf[0];
+ pSrcBuf += 3;
+ }
+ }
+}
+
+} // namespace
+
+CPDF_DeviceCS::CPDF_DeviceCS(CPDF_Document* pDoc, int family)
+ : CPDF_ColorSpace(pDoc, family, ComponentsForFamily(family)) {}
+
+FX_BOOL CPDF_DeviceCS::GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const {
+ if (m_Family == PDFCS_DEVICERGB) {
+ R = pBuf[0];
+ if (R < 0) {
+ R = 0;
+ } else if (R > 1) {
+ R = 1;
+ }
+ G = pBuf[1];
+ if (G < 0) {
+ G = 0;
+ } else if (G > 1) {
+ G = 1;
+ }
+ B = pBuf[2];
+ if (B < 0) {
+ B = 0;
+ } else if (B > 1) {
+ B = 1;
+ }
+ } else if (m_Family == PDFCS_DEVICEGRAY) {
+ R = *pBuf;
+ if (R < 0) {
+ R = 0;
+ } else if (R > 1) {
+ R = 1;
+ }
+ G = B = R;
+ } else if (m_Family == PDFCS_DEVICECMYK) {
+ if (!m_dwStdConversion) {
+ AdobeCMYK_to_sRGB(pBuf[0], pBuf[1], pBuf[2], pBuf[3], R, G, B);
+ } else {
+ FX_FLOAT k = pBuf[3];
+ R = 1.0f - std::min(1.0f, pBuf[0] + k);
+ G = 1.0f - std::min(1.0f, pBuf[1] + k);
+ B = 1.0f - std::min(1.0f, pBuf[2] + k);
+ }
+ } else {
+ ASSERT(m_Family == PDFCS_PATTERN);
+ R = G = B = 0;
+ return FALSE;
+ }
+ return TRUE;
+}
+FX_BOOL CPDF_DeviceCS::v_GetCMYK(FX_FLOAT* pBuf,
+ FX_FLOAT& c,
+ FX_FLOAT& m,
+ FX_FLOAT& y,
+ FX_FLOAT& k) const {
+ if (m_Family != PDFCS_DEVICECMYK) {
+ return FALSE;
+ }
+ c = pBuf[0];
+ m = pBuf[1];
+ y = pBuf[2];
+ k = pBuf[3];
+ return TRUE;
+}
+FX_BOOL CPDF_DeviceCS::SetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT R,
+ FX_FLOAT G,
+ FX_FLOAT B) const {
+ if (m_Family == PDFCS_DEVICERGB) {
+ pBuf[0] = R;
+ pBuf[1] = G;
+ pBuf[2] = B;
+ return TRUE;
+ }
+ if (m_Family == PDFCS_DEVICEGRAY) {
+ if (R == G && R == B) {
+ *pBuf = R;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ if (m_Family == PDFCS_DEVICECMYK) {
+ sRGB_to_AdobeCMYK(R, G, B, pBuf[0], pBuf[1], pBuf[2], pBuf[3]);
+ return TRUE;
+ }
+ return FALSE;
+}
+FX_BOOL CPDF_DeviceCS::v_SetCMYK(FX_FLOAT* pBuf,
+ FX_FLOAT c,
+ FX_FLOAT m,
+ FX_FLOAT y,
+ FX_FLOAT k) const {
+ if (m_Family == PDFCS_DEVICERGB) {
+ AdobeCMYK_to_sRGB(c, m, y, k, pBuf[0], pBuf[1], pBuf[2]);
+ return TRUE;
+ }
+ if (m_Family == PDFCS_DEVICECMYK) {
+ pBuf[0] = c;
+ pBuf[1] = m;
+ pBuf[2] = y;
+ pBuf[3] = k;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void CPDF_DeviceCS::TranslateImageLine(uint8_t* pDestBuf,
+ const uint8_t* pSrcBuf,
+ int pixels,
+ int image_width,
+ int image_height,
+ FX_BOOL bTransMask) const {
+ if (bTransMask && m_Family == PDFCS_DEVICECMYK) {
+ for (int i = 0; i < pixels; i++) {
+ int k = 255 - pSrcBuf[3];
+ pDestBuf[0] = ((255 - pSrcBuf[0]) * k) / 255;
+ pDestBuf[1] = ((255 - pSrcBuf[1]) * k) / 255;
+ pDestBuf[2] = ((255 - pSrcBuf[2]) * k) / 255;
+ pDestBuf += 3;
+ pSrcBuf += 4;
+ }
+ return;
+ }
+ if (m_Family == PDFCS_DEVICERGB) {
+ ReverseRGB(pDestBuf, pSrcBuf, pixels);
+ } else if (m_Family == PDFCS_DEVICEGRAY) {
+ for (int i = 0; i < pixels; i++) {
+ *pDestBuf++ = pSrcBuf[i];
+ *pDestBuf++ = pSrcBuf[i];
+ *pDestBuf++ = pSrcBuf[i];
+ }
+ } else {
+ for (int i = 0; i < pixels; i++) {
+ if (!m_dwStdConversion) {
+ AdobeCMYK_to_sRGB1(pSrcBuf[0], pSrcBuf[1], pSrcBuf[2], pSrcBuf[3],
+ pDestBuf[2], pDestBuf[1], pDestBuf[0]);
+ } else {
+ uint8_t k = pSrcBuf[3];
+ pDestBuf[2] = 255 - std::min(255, pSrcBuf[0] + k);
+ pDestBuf[1] = 255 - std::min(255, pSrcBuf[1] + k);
+ pDestBuf[0] = 255 - std::min(255, pSrcBuf[2] + k);
+ }
+ pSrcBuf += 4;
+ pDestBuf += 3;
+ }
+ }
+}
+const uint8_t g_sRGBSamples1[] = {
+ 0, 3, 6, 10, 13, 15, 18, 20, 22, 23, 25, 27, 28, 30, 31,
+ 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 49, 50, 51, 52, 53, 53, 54, 55, 56, 56, 57, 58, 58,
+ 59, 60, 61, 61, 62, 62, 63, 64, 64, 65, 66, 66, 67, 67, 68,
+ 68, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 76, 76,
+ 77, 77, 78, 78, 79, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83,
+ 84, 84, 85, 85, 85, 86, 86, 87, 87, 88, 88, 88, 89, 89, 90,
+ 90, 91, 91, 91, 92, 92, 93, 93, 93, 94, 94, 95, 95, 95, 96,
+ 96, 97, 97, 97, 98, 98, 98, 99, 99, 99, 100, 100, 101, 101, 101,
+ 102, 102, 102, 103, 103, 103, 104, 104, 104, 105, 105, 106, 106, 106, 107,
+ 107, 107, 108, 108, 108, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111,
+ 112, 112, 112, 113, 113, 113, 114, 114, 114, 115, 115, 115, 115, 116, 116,
+ 116, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 120,
+};
+const uint8_t g_sRGBSamples2[] = {
+ 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149,
+ 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162,
+ 163, 163, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173,
+ 174, 175, 175, 176, 177, 178, 178, 179, 180, 180, 181, 182, 182, 183, 184,
+ 185, 185, 186, 187, 187, 188, 189, 189, 190, 190, 191, 192, 192, 193, 194,
+ 194, 195, 196, 196, 197, 197, 198, 199, 199, 200, 200, 201, 202, 202, 203,
+ 203, 204, 205, 205, 206, 206, 207, 208, 208, 209, 209, 210, 210, 211, 212,
+ 212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 218, 218, 219, 219, 220,
+ 220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 226, 226, 227, 227, 228,
+ 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235,
+ 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242,
+ 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, 248, 249, 249,
+ 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255,
+};
+
+static FX_FLOAT RGB_Conversion(FX_FLOAT colorComponent) {
+ if (colorComponent > 1) {
+ colorComponent = 1;
+ }
+ if (colorComponent < 0) {
+ colorComponent = 0;
+ }
+ int scale = (int)(colorComponent * 1023);
+ if (scale < 0) {
+ scale = 0;
+ }
+ if (scale < 192) {
+ colorComponent = (g_sRGBSamples1[scale] / 255.0f);
+ } else {
+ colorComponent = (g_sRGBSamples2[scale / 4 - 48] / 255.0f);
+ }
+ return colorComponent;
+}
+
+static void XYZ_to_sRGB(FX_FLOAT X,
+ FX_FLOAT Y,
+ FX_FLOAT Z,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) {
+ FX_FLOAT R1 = 3.2410f * X - 1.5374f * Y - 0.4986f * Z;
+ FX_FLOAT G1 = -0.9692f * X + 1.8760f * Y + 0.0416f * Z;
+ FX_FLOAT B1 = 0.0556f * X - 0.2040f * Y + 1.0570f * Z;
+
+ R = RGB_Conversion(R1);
+ G = RGB_Conversion(G1);
+ B = RGB_Conversion(B1);
+}
+
+static void XYZ_to_sRGB_WhitePoint(FX_FLOAT X,
+ FX_FLOAT Y,
+ FX_FLOAT Z,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B,
+ FX_FLOAT Xw,
+ FX_FLOAT Yw,
+ FX_FLOAT Zw) {
+ // The following RGB_xyz is based on
+ // sRGB value {Rx,Ry}={0.64, 0.33}, {Gx,Gy}={0.30, 0.60}, {Bx,By}={0.15, 0.06}
+
+ FX_FLOAT Rx = 0.64f, Ry = 0.33f;
+ FX_FLOAT Gx = 0.30f, Gy = 0.60f;
+ FX_FLOAT Bx = 0.15f, By = 0.06f;
+ CFX_Matrix_3by3 RGB_xyz(Rx, Gx, Bx, Ry, Gy, By, 1 - Rx - Ry, 1 - Gx - Gy,
+ 1 - Bx - By);
+ CFX_Vector_3by1 whitePoint(Xw, Yw, Zw);
+ CFX_Vector_3by1 XYZ(X, Y, Z);
+
+ CFX_Vector_3by1 RGB_Sum_XYZ = RGB_xyz.Inverse().TransformVector(whitePoint);
+ CFX_Matrix_3by3 RGB_SUM_XYZ_DIAG(RGB_Sum_XYZ.a, 0, 0, 0, RGB_Sum_XYZ.b, 0, 0,
+ 0, RGB_Sum_XYZ.c);
+ CFX_Matrix_3by3 M = RGB_xyz.Multiply(RGB_SUM_XYZ_DIAG);
+ CFX_Vector_3by1 RGB = M.Inverse().TransformVector(XYZ);
+
+ R = RGB_Conversion(RGB.a);
+ G = RGB_Conversion(RGB.b);
+ B = RGB_Conversion(RGB.c);
+}
+class CPDF_CalGray : public CPDF_ColorSpace {
+ public:
+ explicit CPDF_CalGray(CPDF_Document* pDoc)
+ : CPDF_ColorSpace(pDoc, PDFCS_CALGRAY, 1) {}
+ FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
+ FX_BOOL GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const override;
+ FX_BOOL SetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT R,
+ FX_FLOAT G,
+ FX_FLOAT B) const override;
+ void TranslateImageLine(uint8_t* pDestBuf,
+ const uint8_t* pSrcBuf,
+ int pixels,
+ int image_width,
+ int image_height,
+ FX_BOOL bTransMask = FALSE) const override;
+
+ private:
+ FX_FLOAT m_WhitePoint[3];
+ FX_FLOAT m_BlackPoint[3];
+ FX_FLOAT m_Gamma;
+};
+
+FX_BOOL CPDF_CalGray::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
+ CPDF_Dictionary* pDict = pArray->GetDictAt(1);
+ if (!pDict)
+ return FALSE;
+
+ CPDF_Array* pParam = pDict->GetArrayBy("WhitePoint");
+ int i;
+ for (i = 0; i < 3; i++) {
+ m_WhitePoint[i] = pParam ? pParam->GetNumberAt(i) : 0;
+ }
+ pParam = pDict->GetArrayBy("BlackPoint");
+ for (i = 0; i < 3; i++) {
+ m_BlackPoint[i] = pParam ? pParam->GetNumberAt(i) : 0;
+ }
+ m_Gamma = pDict->GetNumberBy("Gamma");
+ if (m_Gamma == 0) {
+ m_Gamma = 1.0f;
+ }
+ return TRUE;
+}
+FX_BOOL CPDF_CalGray::GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const {
+ R = G = B = *pBuf;
+ return TRUE;
+}
+FX_BOOL CPDF_CalGray::SetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT R,
+ FX_FLOAT G,
+ FX_FLOAT B) const {
+ if (R == G && R == B) {
+ *pBuf = R;
+ return TRUE;
+ }
+ return FALSE;
+}
+void CPDF_CalGray::TranslateImageLine(uint8_t* pDestBuf,
+ const uint8_t* pSrcBuf,
+ int pixels,
+ int image_width,
+ int image_height,
+ FX_BOOL bTransMask) const {
+ for (int i = 0; i < pixels; i++) {
+ *pDestBuf++ = pSrcBuf[i];
+ *pDestBuf++ = pSrcBuf[i];
+ *pDestBuf++ = pSrcBuf[i];
+ }
+}
+class CPDF_CalRGB : public CPDF_ColorSpace {
+ public:
+ explicit CPDF_CalRGB(CPDF_Document* pDoc)
+ : CPDF_ColorSpace(pDoc, PDFCS_CALRGB, 3) {}
+ FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
+ FX_BOOL GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const override;
+ FX_BOOL SetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT R,
+ FX_FLOAT G,
+ FX_FLOAT B) const override;
+ void TranslateImageLine(uint8_t* pDestBuf,
+ const uint8_t* pSrcBuf,
+ int pixels,
+ int image_width,
+ int image_height,
+ FX_BOOL bTransMask = FALSE) const override;
+
+ FX_FLOAT m_WhitePoint[3];
+ FX_FLOAT m_BlackPoint[3];
+ FX_FLOAT m_Gamma[3];
+ FX_FLOAT m_Matrix[9];
+ FX_BOOL m_bGamma;
+ FX_BOOL m_bMatrix;
+};
+FX_BOOL CPDF_CalRGB::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
+ CPDF_Dictionary* pDict = pArray->GetDictAt(1);
+ if (!pDict)
+ return FALSE;
+
+ CPDF_Array* pParam = pDict->GetArrayBy("WhitePoint");
+ int i;
+ for (i = 0; i < 3; i++) {
+ m_WhitePoint[i] = pParam ? pParam->GetNumberAt(i) : 0;
+ }
+ pParam = pDict->GetArrayBy("BlackPoint");
+ for (i = 0; i < 3; i++) {
+ m_BlackPoint[i] = pParam ? pParam->GetNumberAt(i) : 0;
+ }
+ pParam = pDict->GetArrayBy("Gamma");
+ if (pParam) {
+ m_bGamma = TRUE;
+ for (i = 0; i < 3; i++) {
+ m_Gamma[i] = pParam->GetNumberAt(i);
+ }
+ } else {
+ m_bGamma = FALSE;
+ }
+ pParam = pDict->GetArrayBy("Matrix");
+ if (pParam) {
+ m_bMatrix = TRUE;
+ for (i = 0; i < 9; i++) {
+ m_Matrix[i] = pParam->GetNumberAt(i);
+ }
+ } else {
+ m_bMatrix = FALSE;
+ }
+ return TRUE;
+}
+FX_BOOL CPDF_CalRGB::GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const {
+ FX_FLOAT A_ = pBuf[0];
+ FX_FLOAT B_ = pBuf[1];
+ FX_FLOAT C_ = pBuf[2];
+ if (m_bGamma) {
+ A_ = (FX_FLOAT)FXSYS_pow(A_, m_Gamma[0]);
+ B_ = (FX_FLOAT)FXSYS_pow(B_, m_Gamma[1]);
+ C_ = (FX_FLOAT)FXSYS_pow(C_, m_Gamma[2]);
+ }
+ FX_FLOAT X, Y, Z;
+ if (m_bMatrix) {
+ X = m_Matrix[0] * A_ + m_Matrix[3] * B_ + m_Matrix[6] * C_;
+ Y = m_Matrix[1] * A_ + m_Matrix[4] * B_ + m_Matrix[7] * C_;
+ Z = m_Matrix[2] * A_ + m_Matrix[5] * B_ + m_Matrix[8] * C_;
+ } else {
+ X = A_;
+ Y = B_;
+ Z = C_;
+ }
+ XYZ_to_sRGB_WhitePoint(X, Y, Z, R, G, B, m_WhitePoint[0], m_WhitePoint[1],
+ m_WhitePoint[2]);
+ return TRUE;
+}
+FX_BOOL CPDF_CalRGB::SetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT R,
+ FX_FLOAT G,
+ FX_FLOAT B) const {
+ pBuf[0] = R;
+ pBuf[1] = G;
+ pBuf[2] = B;
+ return TRUE;
+}
+void CPDF_CalRGB::TranslateImageLine(uint8_t* pDestBuf,
+ const uint8_t* pSrcBuf,
+ int pixels,
+ int image_width,
+ int image_height,
+ FX_BOOL bTransMask) const {
+ if (bTransMask) {
+ FX_FLOAT Cal[3];
+ FX_FLOAT R, G, B;
+ for (int i = 0; i < pixels; i++) {
+ Cal[0] = ((FX_FLOAT)pSrcBuf[2]) / 255;
+ Cal[1] = ((FX_FLOAT)pSrcBuf[1]) / 255;
+ Cal[2] = ((FX_FLOAT)pSrcBuf[0]) / 255;
+ GetRGB(Cal, R, G, B);
+ pDestBuf[0] = FXSYS_round(B * 255);
+ pDestBuf[1] = FXSYS_round(G * 255);
+ pDestBuf[2] = FXSYS_round(R * 255);
+ pSrcBuf += 3;
+ pDestBuf += 3;
+ }
+ }
+ ReverseRGB(pDestBuf, pSrcBuf, pixels);
+}
+class CPDF_LabCS : public CPDF_ColorSpace {
+ public:
+ explicit CPDF_LabCS(CPDF_Document* pDoc)
+ : CPDF_ColorSpace(pDoc, PDFCS_LAB, 3) {}
+ void GetDefaultValue(int iComponent,
+ FX_FLOAT& value,
+ FX_FLOAT& min,
+ FX_FLOAT& max) const override;
+ FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
+ FX_BOOL GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const override;
+ FX_BOOL SetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT R,
+ FX_FLOAT G,
+ FX_FLOAT B) const override;
+ void TranslateImageLine(uint8_t* pDestBuf,
+ const uint8_t* pSrcBuf,
+ int pixels,
+ int image_width,
+ int image_height,
+ FX_BOOL bTransMask = FALSE) const override;
+
+ FX_FLOAT m_WhitePoint[3];
+ FX_FLOAT m_BlackPoint[3];
+ FX_FLOAT m_Ranges[4];
+};
+FX_BOOL CPDF_LabCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
+ CPDF_Dictionary* pDict = pArray->GetDictAt(1);
+ if (!pDict) {
+ return FALSE;
+ }
+ CPDF_Array* pParam = pDict->GetArrayBy("WhitePoint");
+ int i;
+ for (i = 0; i < 3; i++) {
+ m_WhitePoint[i] = pParam ? pParam->GetNumberAt(i) : 0;
+ }
+ pParam = pDict->GetArrayBy("BlackPoint");
+ for (i = 0; i < 3; i++) {
+ m_BlackPoint[i] = pParam ? pParam->GetNumberAt(i) : 0;
+ }
+ pParam = pDict->GetArrayBy("Range");
+ const FX_FLOAT def_ranges[4] = {-100 * 1.0f, 100 * 1.0f, -100 * 1.0f,
+ 100 * 1.0f};
+ for (i = 0; i < 4; i++) {
+ m_Ranges[i] = pParam ? pParam->GetNumberAt(i) : def_ranges[i];
+ }
+ return TRUE;
+}
+void CPDF_LabCS::GetDefaultValue(int iComponent,
+ FX_FLOAT& value,
+ FX_FLOAT& min,
+ FX_FLOAT& max) const {
+ assert(iComponent < 3);
+ value = 0;
+ if (iComponent == 0) {
+ min = 0;
+ max = 100 * 1.0f;
+ } else {
+ min = m_Ranges[iComponent * 2 - 2];
+ max = m_Ranges[iComponent * 2 - 1];
+ if (value < min) {
+ value = min;
+ } else if (value > max) {
+ value = max;
+ }
+ }
+}
+FX_BOOL CPDF_LabCS::GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const {
+ FX_FLOAT Lstar = pBuf[0];
+ FX_FLOAT astar = pBuf[1];
+ FX_FLOAT bstar = pBuf[2];
+ FX_FLOAT M = (Lstar + 16.0f) / 116.0f;
+ FX_FLOAT L = M + astar / 500.0f;
+ FX_FLOAT N = M - bstar / 200.0f;
+ FX_FLOAT X, Y, Z;
+ if (L < 0.2069f) {
+ X = 0.957f * 0.12842f * (L - 0.1379f);
+ } else {
+ X = 0.957f * L * L * L;
+ }
+ if (M < 0.2069f) {
+ Y = 0.12842f * (M - 0.1379f);
+ } else {
+ Y = M * M * M;
+ }
+ if (N < 0.2069f) {
+ Z = 1.0889f * 0.12842f * (N - 0.1379f);
+ } else {
+ Z = 1.0889f * N * N * N;
+ }
+ XYZ_to_sRGB(X, Y, Z, R, G, B);
+ return TRUE;
+}
+FX_BOOL CPDF_LabCS::SetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT R,
+ FX_FLOAT G,
+ FX_FLOAT B) const {
+ return FALSE;
+}
+void CPDF_LabCS::TranslateImageLine(uint8_t* pDestBuf,
+ const uint8_t* pSrcBuf,
+ int pixels,
+ int image_width,
+ int image_height,
+ FX_BOOL bTransMask) const {
+ for (int i = 0; i < pixels; i++) {
+ FX_FLOAT lab[3];
+ FX_FLOAT R, G, B;
+ lab[0] = (pSrcBuf[0] * 100 / 255.0f);
+ lab[1] = (FX_FLOAT)(pSrcBuf[1] - 128);
+ lab[2] = (FX_FLOAT)(pSrcBuf[2] - 128);
+ GetRGB(lab, R, G, B);
+ pDestBuf[0] = (int32_t)(B * 255);
+ pDestBuf[1] = (int32_t)(G * 255);
+ pDestBuf[2] = (int32_t)(R * 255);
+ pDestBuf += 3;
+ pSrcBuf += 3;
+ }
+}
+CPDF_IccProfile::CPDF_IccProfile(const uint8_t* pData, FX_DWORD dwSize)
+ : m_bsRGB(FALSE), m_pTransform(NULL), m_nSrcComponents(0) {
+ if (dwSize == 3144 &&
+ FXSYS_memcmp(pData + 0x190, "sRGB IEC61966-2.1", 17) == 0) {
+ m_bsRGB = TRUE;
+ m_nSrcComponents = 3;
+ } else if (CPDF_ModuleMgr::Get()->GetIccModule()) {
+ m_pTransform = CPDF_ModuleMgr::Get()->GetIccModule()->CreateTransform_sRGB(
+ pData, dwSize, m_nSrcComponents);
+ }
+}
+CPDF_IccProfile::~CPDF_IccProfile() {
+ if (m_pTransform) {
+ CPDF_ModuleMgr::Get()->GetIccModule()->DestroyTransform(m_pTransform);
+ }
+}
+class CPDF_ICCBasedCS : public CPDF_ColorSpace {
+ public:
+ explicit CPDF_ICCBasedCS(CPDF_Document* pDoc)
+ : CPDF_ColorSpace(pDoc, PDFCS_ICCBASED, 0),
+ m_pAlterCS(nullptr),
+ m_pProfile(nullptr),
+ m_pCache(nullptr),
+ m_pRanges(nullptr),
+ m_bOwn(FALSE) {}
+ ~CPDF_ICCBasedCS() override;
+
+ FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
+ FX_BOOL GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const override;
+ FX_BOOL SetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT R,
+ FX_FLOAT G,
+ FX_FLOAT B) const override;
+ FX_BOOL v_GetCMYK(FX_FLOAT* pBuf,
+ FX_FLOAT& c,
+ FX_FLOAT& m,
+ FX_FLOAT& y,
+ FX_FLOAT& k) const override;
+ void EnableStdConversion(FX_BOOL bEnabled) override;
+ void TranslateImageLine(uint8_t* pDestBuf,
+ const uint8_t* pSrcBuf,
+ int pixels,
+ int image_width,
+ int image_height,
+ FX_BOOL bTransMask = FALSE) const override;
+
+ CPDF_ColorSpace* m_pAlterCS;
+ CPDF_IccProfile* m_pProfile;
+ uint8_t* m_pCache;
+ FX_FLOAT* m_pRanges;
+ FX_BOOL m_bOwn;
+};
+
+CPDF_ICCBasedCS::~CPDF_ICCBasedCS() {
+ FX_Free(m_pCache);
+ FX_Free(m_pRanges);
+ if (m_pAlterCS && m_bOwn) {
+ m_pAlterCS->ReleaseCS();
+ }
+ if (m_pProfile && m_pDocument) {
+ m_pDocument->GetPageData()->ReleaseIccProfile(m_pProfile);
+ }
+}
+
+FX_BOOL CPDF_ICCBasedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
+ CPDF_Stream* pStream = pArray->GetStreamAt(1);
+ if (!pStream) {
+ return FALSE;
+ }
+ m_pProfile = pDoc->LoadIccProfile(pStream);
+ if (!m_pProfile) {
+ return FALSE;
+ }
+ m_nComponents =
+ m_pProfile
+ ->GetComponents(); // Try using the nComponents from ICC profile
+ CPDF_Dictionary* pDict = pStream->GetDict();
+ if (!m_pProfile->m_pTransform) { // No valid ICC profile or using sRGB
+ CPDF_Object* pAlterCSObj =
+ pDict ? pDict->GetElementValue("Alternate") : NULL;
+ if (pAlterCSObj) {
+ CPDF_ColorSpace* pAlterCS = CPDF_ColorSpace::Load(pDoc, pAlterCSObj);
+ if (pAlterCS) {
+ if (m_nComponents == 0) { // NO valid ICC profile
+ if (pAlterCS->CountComponents() > 0) { // Use Alternative colorspace
+ m_nComponents = pAlterCS->CountComponents();
+ m_pAlterCS = pAlterCS;
+ m_bOwn = TRUE;
+ } else { // No valid alternative colorspace
+ pAlterCS->ReleaseCS();
+ int32_t nDictComponents = pDict ? pDict->GetIntegerBy("N") : 0;
+ if (nDictComponents != 1 && nDictComponents != 3 &&
+ nDictComponents != 4) {
+ return FALSE;
+ }
+ m_nComponents = nDictComponents;
+ }
+
+ } else { // Using sRGB
+ if (pAlterCS->CountComponents() != m_nComponents) {
+ pAlterCS->ReleaseCS();
+ } else {
+ m_pAlterCS = pAlterCS;
+ m_bOwn = TRUE;
+ }
+ }
+ }
+ }
+ if (!m_pAlterCS) {
+ if (m_nComponents == 1) {
+ m_pAlterCS = GetStockCS(PDFCS_DEVICEGRAY);
+ } else if (m_nComponents == 3) {
+ m_pAlterCS = GetStockCS(PDFCS_DEVICERGB);
+ } else if (m_nComponents == 4) {
+ m_pAlterCS = GetStockCS(PDFCS_DEVICECMYK);
+ }
+ }
+ }
+ CPDF_Array* pRanges = pDict->GetArrayBy("Range");
+ m_pRanges = FX_Alloc2D(FX_FLOAT, m_nComponents, 2);
+ for (int i = 0; i < m_nComponents * 2; i++) {
+ if (pRanges) {
+ m_pRanges[i] = pRanges->GetNumberAt(i);
+ } else if (i % 2) {
+ m_pRanges[i] = 1.0f;
+ } else {
+ m_pRanges[i] = 0;
+ }
+ }
+ return TRUE;
+}
+FX_BOOL CPDF_ICCBasedCS::GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const {
+ if (m_pProfile && m_pProfile->m_bsRGB) {
+ R = pBuf[0];
+ G = pBuf[1];
+ B = pBuf[2];
+ return TRUE;
+ }
+ ICodec_IccModule* pIccModule = CPDF_ModuleMgr::Get()->GetIccModule();
+ if (!m_pProfile->m_pTransform || !pIccModule) {
+ if (m_pAlterCS) {
+ return m_pAlterCS->GetRGB(pBuf, R, G, B);
+ }
+ R = G = B = 0.0f;
+ return TRUE;
+ }
+ FX_FLOAT rgb[3];
+ pIccModule->SetComponents(m_nComponents);
+ pIccModule->Translate(m_pProfile->m_pTransform, pBuf, rgb);
+ R = rgb[0];
+ G = rgb[1];
+ B = rgb[2];
+ return TRUE;
+}
+FX_BOOL CPDF_ICCBasedCS::v_GetCMYK(FX_FLOAT* pBuf,
+ FX_FLOAT& c,
+ FX_FLOAT& m,
+ FX_FLOAT& y,
+ FX_FLOAT& k) const {
+ if (m_nComponents != 4) {
+ return FALSE;
+ }
+ c = pBuf[0];
+ m = pBuf[1];
+ y = pBuf[2];
+ k = pBuf[3];
+ return TRUE;
+}
+FX_BOOL CPDF_ICCBasedCS::SetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT R,
+ FX_FLOAT G,
+ FX_FLOAT B) const {
+ return FALSE;
+}
+void CPDF_ICCBasedCS::EnableStdConversion(FX_BOOL bEnabled) {
+ CPDF_ColorSpace::EnableStdConversion(bEnabled);
+ if (m_pAlterCS) {
+ m_pAlterCS->EnableStdConversion(bEnabled);
+ }
+}
+void CPDF_ICCBasedCS::TranslateImageLine(uint8_t* pDestBuf,
+ const uint8_t* pSrcBuf,
+ int pixels,
+ int image_width,
+ int image_height,
+ FX_BOOL bTransMask) const {
+ if (m_pProfile->m_bsRGB) {
+ ReverseRGB(pDestBuf, pSrcBuf, pixels);
+ } else if (m_pProfile->m_pTransform) {
+ int nMaxColors = 1;
+ for (int i = 0; i < m_nComponents; i++) {
+ nMaxColors *= 52;
+ }
+ if (m_nComponents > 3 || image_width * image_height < nMaxColors * 3 / 2) {
+ CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
+ m_pProfile->m_pTransform, pDestBuf, pSrcBuf, pixels);
+ } else {
+ if (!m_pCache) {
+ ((CPDF_ICCBasedCS*)this)->m_pCache = FX_Alloc2D(uint8_t, nMaxColors, 3);
+ uint8_t* temp_src = FX_Alloc2D(uint8_t, nMaxColors, m_nComponents);
+ uint8_t* pSrc = temp_src;
+ for (int i = 0; i < nMaxColors; i++) {
+ FX_DWORD color = i;
+ FX_DWORD order = nMaxColors / 52;
+ for (int c = 0; c < m_nComponents; c++) {
+ *pSrc++ = (uint8_t)(color / order * 5);
+ color %= order;
+ order /= 52;
+ }
+ }
+ CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline(
+ m_pProfile->m_pTransform, m_pCache, temp_src, nMaxColors);
+ FX_Free(temp_src);
+ }
+ for (int i = 0; i < pixels; i++) {
+ int index = 0;
+ for (int c = 0; c < m_nComponents; c++) {
+ index = index * 52 + (*pSrcBuf) / 5;
+ pSrcBuf++;
+ }
+ index *= 3;
+ *pDestBuf++ = m_pCache[index];
+ *pDestBuf++ = m_pCache[index + 1];
+ *pDestBuf++ = m_pCache[index + 2];
+ }
+ }
+ } else if (m_pAlterCS) {
+ m_pAlterCS->TranslateImageLine(pDestBuf, pSrcBuf, pixels, image_width,
+ image_height);
+ }
+}
+class CPDF_IndexedCS : public CPDF_ColorSpace {
+ public:
+ explicit CPDF_IndexedCS(CPDF_Document* pDoc)
+ : CPDF_ColorSpace(pDoc, PDFCS_INDEXED, 1),
+ m_pBaseCS(nullptr),
+ m_pCountedBaseCS(nullptr),
+ m_pCompMinMax(nullptr) {}
+ ~CPDF_IndexedCS() override;
+
+ FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
+ FX_BOOL GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const override;
+ CPDF_ColorSpace* GetBaseCS() const override;
+ void EnableStdConversion(FX_BOOL bEnabled) override;
+
+ CPDF_ColorSpace* m_pBaseCS;
+ CPDF_CountedColorSpace* m_pCountedBaseCS;
+ int m_nBaseComponents;
+ int m_MaxIndex;
+ CFX_ByteString m_Table;
+ FX_FLOAT* m_pCompMinMax;
+};
+CPDF_IndexedCS::~CPDF_IndexedCS() {
+ FX_Free(m_pCompMinMax);
+ CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
+ if (pCS && m_pDocument) {
+ m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
+ }
+}
+FX_BOOL CPDF_IndexedCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
+ if (pArray->GetCount() < 4) {
+ return FALSE;
+ }
+ CPDF_Object* pBaseObj = pArray->GetElementValue(1);
+ if (pBaseObj == m_pArray) {
+ return FALSE;
+ }
+ CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
+ m_pBaseCS = pDocPageData->GetColorSpace(pBaseObj, NULL);
+ if (!m_pBaseCS) {
+ return FALSE;
+ }
+ m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
+ m_nBaseComponents = m_pBaseCS->CountComponents();
+ m_pCompMinMax = FX_Alloc2D(FX_FLOAT, m_nBaseComponents, 2);
+ FX_FLOAT defvalue;
+ for (int i = 0; i < m_nBaseComponents; i++) {
+ m_pBaseCS->GetDefaultValue(i, defvalue, m_pCompMinMax[i * 2],
+ m_pCompMinMax[i * 2 + 1]);
+ m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2];
+ }
+ m_MaxIndex = pArray->GetIntegerAt(2);
+
+ CPDF_Object* pTableObj = pArray->GetElementValue(3);
+ if (!pTableObj)
+ return FALSE;
+
+ if (CPDF_String* pString = pTableObj->AsString()) {
+ m_Table = pString->GetString();
+ } else if (CPDF_Stream* pStream = pTableObj->AsStream()) {
+ CPDF_StreamAcc acc;
+ acc.LoadAllData(pStream, FALSE);
+ m_Table = CFX_ByteStringC(acc.GetData(), acc.GetSize());
+ }
+ return TRUE;
+}
+
+FX_BOOL CPDF_IndexedCS::GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const {
+ int index = (int32_t)(*pBuf);
+ if (index < 0 || index > m_MaxIndex) {
+ return FALSE;
+ }
+ if (m_nBaseComponents) {
+ if (index == INT_MAX || (index + 1) > INT_MAX / m_nBaseComponents ||
+ (index + 1) * m_nBaseComponents > (int)m_Table.GetLength()) {
+ R = G = B = 0;
+ return FALSE;
+ }
+ }
+ CFX_FixedBufGrow<FX_FLOAT, 16> Comps(m_nBaseComponents);
+ FX_FLOAT* comps = Comps;
+ const uint8_t* pTable = m_Table;
+ for (int i = 0; i < m_nBaseComponents; i++) {
+ comps[i] =
+ m_pCompMinMax[i * 2] +
+ m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255;
+ }
+ return m_pBaseCS->GetRGB(comps, R, G, B);
+}
+CPDF_ColorSpace* CPDF_IndexedCS::GetBaseCS() const {
+ return m_pBaseCS;
+}
+void CPDF_IndexedCS::EnableStdConversion(FX_BOOL bEnabled) {
+ CPDF_ColorSpace::EnableStdConversion(bEnabled);
+ if (m_pBaseCS) {
+ m_pBaseCS->EnableStdConversion(bEnabled);
+ }
+}
+
+#define MAX_PATTERN_COLORCOMPS 16
+struct PatternValue {
+ CPDF_Pattern* m_pPattern;
+ CPDF_CountedPattern* m_pCountedPattern;
+ int m_nComps;
+ FX_FLOAT m_Comps[MAX_PATTERN_COLORCOMPS];
+};
+
+CPDF_PatternCS::~CPDF_PatternCS() {
+ CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : NULL;
+ if (pCS && m_pDocument) {
+ m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
+ }
+}
+FX_BOOL CPDF_PatternCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
+ CPDF_Object* pBaseCS = pArray->GetElementValue(1);
+ if (pBaseCS == m_pArray) {
+ return FALSE;
+ }
+ CPDF_DocPageData* pDocPageData = pDoc->GetPageData();
+ m_pBaseCS = pDocPageData->GetColorSpace(pBaseCS, NULL);
+ if (m_pBaseCS) {
+ if (m_pBaseCS->GetFamily() == PDFCS_PATTERN) {
+ return FALSE;
+ }
+ m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray());
+ m_nComponents = m_pBaseCS->CountComponents() + 1;
+ if (m_pBaseCS->CountComponents() > MAX_PATTERN_COLORCOMPS) {
+ return FALSE;
+ }
+ } else {
+ m_nComponents = 1;
+ }
+ return TRUE;
+}
+FX_BOOL CPDF_PatternCS::GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const {
+ if (m_pBaseCS) {
+ ASSERT(m_pBaseCS->GetFamily() != PDFCS_PATTERN);
+ PatternValue* pvalue = (PatternValue*)pBuf;
+ if (m_pBaseCS->GetRGB(pvalue->m_Comps, R, G, B)) {
+ return TRUE;
+ }
+ }
+ R = G = B = 0.75f;
+ return FALSE;
+}
+CPDF_ColorSpace* CPDF_PatternCS::GetBaseCS() const {
+ return m_pBaseCS;
+}
+class CPDF_SeparationCS : public CPDF_ColorSpace {
+ public:
+ explicit CPDF_SeparationCS(CPDF_Document* pDoc)
+ : CPDF_ColorSpace(pDoc, PDFCS_SEPARATION, 1),
+ m_pAltCS(nullptr),
+ m_pFunc(nullptr) {}
+ ~CPDF_SeparationCS() override;
+
+ // CPDF_ColorSpace:
+ void GetDefaultValue(int iComponent,
+ FX_FLOAT& value,
+ FX_FLOAT& min,
+ FX_FLOAT& max) const override;
+ FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
+ FX_BOOL GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const override;
+ void EnableStdConversion(FX_BOOL bEnabled) override;
+
+ CPDF_ColorSpace* m_pAltCS;
+ CPDF_Function* m_pFunc;
+ enum { None, All, Colorant } m_Type;
+};
+CPDF_SeparationCS::~CPDF_SeparationCS() {
+ if (m_pAltCS) {
+ m_pAltCS->ReleaseCS();
+ }
+ delete m_pFunc;
+}
+void CPDF_SeparationCS::GetDefaultValue(int iComponent,
+ FX_FLOAT& value,
+ FX_FLOAT& min,
+ FX_FLOAT& max) const {
+ value = 1.0f;
+ min = 0;
+ max = 1.0f;
+}
+FX_BOOL CPDF_SeparationCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
+ CFX_ByteString name = pArray->GetStringAt(1);
+ if (name == "None") {
+ m_Type = None;
+ } else {
+ m_Type = Colorant;
+ CPDF_Object* pAltCS = pArray->GetElementValue(2);
+ if (pAltCS == m_pArray) {
+ return FALSE;
+ }
+ m_pAltCS = Load(pDoc, pAltCS);
+ if (!m_pAltCS) {
+ return FALSE;
+ }
+ CPDF_Object* pFuncObj = pArray->GetElementValue(3);
+ if (pFuncObj && !pFuncObj->IsName())
+ m_pFunc = CPDF_Function::Load(pFuncObj);
+
+ if (m_pFunc && m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
+ delete m_pFunc;
+ m_pFunc = NULL;
+ }
+ }
+ return TRUE;
+}
+FX_BOOL CPDF_SeparationCS::GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const {
+ if (m_Type == None) {
+ return FALSE;
+ }
+ if (!m_pFunc) {
+ if (!m_pAltCS) {
+ return FALSE;
+ }
+ int nComps = m_pAltCS->CountComponents();
+ CFX_FixedBufGrow<FX_FLOAT, 16> results(nComps);
+ for (int i = 0; i < nComps; i++) {
+ results[i] = *pBuf;
+ }
+ return m_pAltCS->GetRGB(results, R, G, B);
+ }
+ CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
+ int nresults = 0;
+ m_pFunc->Call(pBuf, 1, results, nresults);
+ if (nresults == 0) {
+ return FALSE;
+ }
+ if (m_pAltCS) {
+ return m_pAltCS->GetRGB(results, R, G, B);
+ }
+ R = G = B = 0;
+ return FALSE;
+}
+void CPDF_SeparationCS::EnableStdConversion(FX_BOOL bEnabled) {
+ CPDF_ColorSpace::EnableStdConversion(bEnabled);
+ if (m_pAltCS) {
+ m_pAltCS->EnableStdConversion(bEnabled);
+ }
+}
+class CPDF_DeviceNCS : public CPDF_ColorSpace {
+ public:
+ explicit CPDF_DeviceNCS(CPDF_Document* pDoc)
+ : CPDF_ColorSpace(pDoc, PDFCS_DEVICEN, 0),
+ m_pAltCS(nullptr),
+ m_pFunc(nullptr) {}
+ ~CPDF_DeviceNCS() override;
+
+ // CPDF_ColorSpace:
+ void GetDefaultValue(int iComponent,
+ FX_FLOAT& value,
+ FX_FLOAT& min,
+ FX_FLOAT& max) const override;
+ FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
+ FX_BOOL GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const override;
+ void EnableStdConversion(FX_BOOL bEnabled) override;
+
+ CPDF_ColorSpace* m_pAltCS;
+ CPDF_Function* m_pFunc;
+};
+CPDF_DeviceNCS::~CPDF_DeviceNCS() {
+ delete m_pFunc;
+ if (m_pAltCS) {
+ m_pAltCS->ReleaseCS();
+ }
+}
+void CPDF_DeviceNCS::GetDefaultValue(int iComponent,
+ FX_FLOAT& value,
+ FX_FLOAT& min,
+ FX_FLOAT& max) const {
+ value = 1.0f;
+ min = 0;
+ max = 1.0f;
+}
+FX_BOOL CPDF_DeviceNCS::v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) {
+ CPDF_Array* pObj = ToArray(pArray->GetElementValue(1));
+ if (!pObj)
+ return FALSE;
+
+ m_nComponents = pObj->GetCount();
+ CPDF_Object* pAltCS = pArray->GetElementValue(2);
+ if (!pAltCS || pAltCS == m_pArray) {
+ return FALSE;
+ }
+ m_pAltCS = Load(pDoc, pAltCS);
+ m_pFunc = CPDF_Function::Load(pArray->GetElementValue(3));
+ if (!m_pAltCS || !m_pFunc) {
+ return FALSE;
+ }
+ if (m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) {
+ return FALSE;
+ }
+ return TRUE;
+}
+FX_BOOL CPDF_DeviceNCS::GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const {
+ if (!m_pFunc) {
+ return FALSE;
+ }
+ CFX_FixedBufGrow<FX_FLOAT, 16> results(m_pFunc->CountOutputs());
+ int nresults = 0;
+ m_pFunc->Call(pBuf, m_nComponents, results, nresults);
+ if (nresults == 0) {
+ return FALSE;
+ }
+ return m_pAltCS->GetRGB(results, R, G, B);
+}
+void CPDF_DeviceNCS::EnableStdConversion(FX_BOOL bEnabled) {
+ CPDF_ColorSpace::EnableStdConversion(bEnabled);
+ if (m_pAltCS) {
+ m_pAltCS->EnableStdConversion(bEnabled);
+ }
+}
+
+CPDF_ColorSpace* CPDF_ColorSpace::GetStockCS(int family) {
+ return CPDF_ModuleMgr::Get()->GetPageModule()->GetStockCS(family);
+}
+
+CPDF_ColorSpace* _CSFromName(const CFX_ByteString& name) {
+ if (name == "DeviceRGB" || name == "RGB") {
+ return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
+ }
+ if (name == "DeviceGray" || name == "G") {
+ return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
+ }
+ if (name == "DeviceCMYK" || name == "CMYK") {
+ return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
+ }
+ if (name == "Pattern") {
+ return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
+ }
+ return NULL;
+}
+CPDF_ColorSpace* CPDF_ColorSpace::Load(CPDF_Document* pDoc, CPDF_Object* pObj) {
+ if (!pObj)
+ return nullptr;
+ if (pObj->IsName())
+ return _CSFromName(pObj->GetString());
+
+ if (CPDF_Stream* pStream = pObj->AsStream()) {
+ CPDF_Dictionary* pDict = pStream->GetDict();
+ if (!pDict)
+ return nullptr;
+
+ for (const auto& it : *pDict) {
+ CPDF_ColorSpace* pRet = nullptr;
+ CPDF_Object* pValue = it.second;
+ if (ToName(pValue))
+ pRet = _CSFromName(pValue->GetString());
+ if (pRet)
+ return pRet;
+ }
+ return nullptr;
+ }
+
+ CPDF_Array* pArray = pObj->AsArray();
+ if (!pArray || pArray->GetCount() == 0)
+ return nullptr;
+
+ CPDF_Object* pFamilyObj = pArray->GetElementValue(0);
+ if (!pFamilyObj)
+ return nullptr;
+
+ CFX_ByteString familyname = pFamilyObj->GetString();
+ if (pArray->GetCount() == 1)
+ return _CSFromName(familyname);
+
+ CPDF_ColorSpace* pCS = NULL;
+ FX_DWORD id = familyname.GetID();
+ if (id == FXBSTR_ID('C', 'a', 'l', 'G')) {
+ pCS = new CPDF_CalGray(pDoc);
+ } else if (id == FXBSTR_ID('C', 'a', 'l', 'R')) {
+ pCS = new CPDF_CalRGB(pDoc);
+ } else if (id == FXBSTR_ID('L', 'a', 'b', 0)) {
+ pCS = new CPDF_LabCS(pDoc);
+ } else if (id == FXBSTR_ID('I', 'C', 'C', 'B')) {
+ pCS = new CPDF_ICCBasedCS(pDoc);
+ } else if (id == FXBSTR_ID('I', 'n', 'd', 'e') ||
+ id == FXBSTR_ID('I', 0, 0, 0)) {
+ pCS = new CPDF_IndexedCS(pDoc);
+ } else if (id == FXBSTR_ID('S', 'e', 'p', 'a')) {
+ pCS = new CPDF_SeparationCS(pDoc);
+ } else if (id == FXBSTR_ID('D', 'e', 'v', 'i')) {
+ pCS = new CPDF_DeviceNCS(pDoc);
+ } else if (id == FXBSTR_ID('P', 'a', 't', 't')) {
+ pCS = new CPDF_PatternCS(pDoc);
+ } else {
+ return NULL;
+ }
+ pCS->m_pArray = pArray;
+ if (!pCS->v_Load(pDoc, pArray)) {
+ pCS->ReleaseCS();
+ return NULL;
+ }
+ return pCS;
+}
+void CPDF_ColorSpace::ReleaseCS() {
+ if (this == GetStockCS(PDFCS_DEVICERGB)) {
+ return;
+ }
+ if (this == GetStockCS(PDFCS_DEVICEGRAY)) {
+ return;
+ }
+ if (this == GetStockCS(PDFCS_DEVICECMYK)) {
+ return;
+ }
+ if (this == GetStockCS(PDFCS_PATTERN)) {
+ return;
+ }
+ delete this;
+}
+int CPDF_ColorSpace::GetBufSize() const {
+ if (m_Family == PDFCS_PATTERN) {
+ return sizeof(PatternValue);
+ }
+ return m_nComponents * sizeof(FX_FLOAT);
+}
+FX_FLOAT* CPDF_ColorSpace::CreateBuf() {
+ int size = GetBufSize();
+ uint8_t* pBuf = FX_Alloc(uint8_t, size);
+ return (FX_FLOAT*)pBuf;
+}
+FX_BOOL CPDF_ColorSpace::sRGB() const {
+ if (m_Family == PDFCS_DEVICERGB) {
+ return TRUE;
+ }
+ if (m_Family != PDFCS_ICCBASED) {
+ return FALSE;
+ }
+ CPDF_ICCBasedCS* pCS = (CPDF_ICCBasedCS*)this;
+ return pCS->m_pProfile->m_bsRGB;
+}
+FX_BOOL CPDF_ColorSpace::GetCMYK(FX_FLOAT* pBuf,
+ FX_FLOAT& c,
+ FX_FLOAT& m,
+ FX_FLOAT& y,
+ FX_FLOAT& k) const {
+ if (v_GetCMYK(pBuf, c, m, y, k)) {
+ return TRUE;
+ }
+ FX_FLOAT R, G, B;
+ if (!GetRGB(pBuf, R, G, B)) {
+ return FALSE;
+ }
+ sRGB_to_AdobeCMYK(R, G, B, c, m, y, k);
+ return TRUE;
+}
+FX_BOOL CPDF_ColorSpace::SetCMYK(FX_FLOAT* pBuf,
+ FX_FLOAT c,
+ FX_FLOAT m,
+ FX_FLOAT y,
+ FX_FLOAT k) const {
+ if (v_SetCMYK(pBuf, c, m, y, k)) {
+ return TRUE;
+ }
+ FX_FLOAT R, G, B;
+ AdobeCMYK_to_sRGB(c, m, y, k, R, G, B);
+ return SetRGB(pBuf, R, G, B);
+}
+void CPDF_ColorSpace::GetDefaultColor(FX_FLOAT* buf) const {
+ if (!buf || m_Family == PDFCS_PATTERN) {
+ return;
+ }
+ FX_FLOAT min, max;
+ for (int i = 0; i < m_nComponents; i++) {
+ GetDefaultValue(i, buf[i], min, max);
+ }
+}
+int CPDF_ColorSpace::GetMaxIndex() const {
+ if (m_Family != PDFCS_INDEXED) {
+ return 0;
+ }
+ CPDF_IndexedCS* pCS = (CPDF_IndexedCS*)this;
+ return pCS->m_MaxIndex;
+}
+void CPDF_ColorSpace::TranslateImageLine(uint8_t* dest_buf,
+ const uint8_t* src_buf,
+ int pixels,
+ int image_width,
+ int image_height,
+ FX_BOOL bTransMask) const {
+ CFX_FixedBufGrow<FX_FLOAT, 16> srcbuf(m_nComponents);
+ FX_FLOAT* src = srcbuf;
+ FX_FLOAT R, G, B;
+ for (int i = 0; i < pixels; i++) {
+ for (int j = 0; j < m_nComponents; j++)
+ if (m_Family == PDFCS_INDEXED) {
+ src[j] = (FX_FLOAT)(*src_buf++);
+ } else {
+ src[j] = (FX_FLOAT)(*src_buf++) / 255;
+ }
+ GetRGB(src, R, G, B);
+ *dest_buf++ = (int32_t)(B * 255);
+ *dest_buf++ = (int32_t)(G * 255);
+ *dest_buf++ = (int32_t)(R * 255);
+ }
+}
+void CPDF_ColorSpace::EnableStdConversion(FX_BOOL bEnabled) {
+ if (bEnabled) {
+ m_dwStdConversion++;
+ } else if (m_dwStdConversion) {
+ m_dwStdConversion--;
+ }
+}
+CPDF_Color::CPDF_Color(int family) {
+ m_pCS = CPDF_ColorSpace::GetStockCS(family);
+ int nComps = 3;
+ if (family == PDFCS_DEVICEGRAY) {
+ nComps = 1;
+ } else if (family == PDFCS_DEVICECMYK) {
+ nComps = 4;
+ }
+ m_pBuffer = FX_Alloc(FX_FLOAT, nComps);
+ for (int i = 0; i < nComps; i++) {
+ m_pBuffer[i] = 0;
+ }
+}
+CPDF_Color::~CPDF_Color() {
+ ReleaseBuffer();
+ ReleaseColorSpace();
+}
+void CPDF_Color::ReleaseBuffer() {
+ if (!m_pBuffer) {
+ return;
+ }
+ if (m_pCS->GetFamily() == PDFCS_PATTERN) {
+ PatternValue* pvalue = (PatternValue*)m_pBuffer;
+ CPDF_Pattern* pPattern =
+ pvalue->m_pCountedPattern ? pvalue->m_pCountedPattern->get() : NULL;
+ if (pPattern && pPattern->m_pDocument) {
+ CPDF_DocPageData* pPageData = pPattern->m_pDocument->GetPageData();
+ if (pPageData) {
+ pPageData->ReleasePattern(pPattern->m_pPatternObj);
+ }
+ }
+ }
+ FX_Free(m_pBuffer);
+ m_pBuffer = NULL;
+}
+void CPDF_Color::ReleaseColorSpace() {
+ if (m_pCS && m_pCS->m_pDocument && m_pCS->GetArray()) {
+ m_pCS->m_pDocument->GetPageData()->ReleaseColorSpace(m_pCS->GetArray());
+ m_pCS = NULL;
+ }
+}
+void CPDF_Color::SetColorSpace(CPDF_ColorSpace* pCS) {
+ if (m_pCS == pCS) {
+ if (!m_pBuffer) {
+ m_pBuffer = pCS->CreateBuf();
+ }
+ ReleaseColorSpace();
+ m_pCS = pCS;
+ return;
+ }
+ ReleaseBuffer();
+ ReleaseColorSpace();
+ m_pCS = pCS;
+ if (m_pCS) {
+ m_pBuffer = pCS->CreateBuf();
+ pCS->GetDefaultColor(m_pBuffer);
+ }
+}
+void CPDF_Color::SetValue(FX_FLOAT* comps) {
+ if (!m_pBuffer) {
+ return;
+ }
+ if (m_pCS->GetFamily() != PDFCS_PATTERN) {
+ FXSYS_memcpy(m_pBuffer, comps, m_pCS->CountComponents() * sizeof(FX_FLOAT));
+ }
+}
+void CPDF_Color::SetValue(CPDF_Pattern* pPattern, FX_FLOAT* comps, int ncomps) {
+ if (ncomps > MAX_PATTERN_COLORCOMPS) {
+ return;
+ }
+ if (!m_pCS || m_pCS->GetFamily() != PDFCS_PATTERN) {
+ FX_Free(m_pBuffer);
+ m_pCS = CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
+ m_pBuffer = m_pCS->CreateBuf();
+ }
+ CPDF_DocPageData* pDocPageData = NULL;
+ PatternValue* pvalue = (PatternValue*)m_pBuffer;
+ if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
+ pDocPageData = pvalue->m_pPattern->m_pDocument->GetPageData();
+ if (pDocPageData) {
+ pDocPageData->ReleasePattern(pvalue->m_pPattern->m_pPatternObj);
+ }
+ }
+ pvalue->m_nComps = ncomps;
+ pvalue->m_pPattern = pPattern;
+ if (ncomps) {
+ FXSYS_memcpy(pvalue->m_Comps, comps, ncomps * sizeof(FX_FLOAT));
+ }
+ pvalue->m_pCountedPattern = NULL;
+ if (pPattern && pPattern->m_pDocument) {
+ if (!pDocPageData) {
+ pDocPageData = pPattern->m_pDocument->GetPageData();
+ }
+ pvalue->m_pCountedPattern =
+ pDocPageData->FindPatternPtr(pPattern->m_pPatternObj);
+ }
+}
+void CPDF_Color::Copy(const CPDF_Color* pSrc) {
+ ReleaseBuffer();
+ ReleaseColorSpace();
+ m_pCS = pSrc->m_pCS;
+ if (m_pCS && m_pCS->m_pDocument) {
+ CPDF_Array* pArray = m_pCS->GetArray();
+ if (pArray) {
+ m_pCS = m_pCS->m_pDocument->GetPageData()->GetCopiedColorSpace(pArray);
+ }
+ }
+ if (!m_pCS) {
+ return;
+ }
+ m_pBuffer = m_pCS->CreateBuf();
+ FXSYS_memcpy(m_pBuffer, pSrc->m_pBuffer, m_pCS->GetBufSize());
+ if (m_pCS->GetFamily() == PDFCS_PATTERN) {
+ PatternValue* pvalue = (PatternValue*)m_pBuffer;
+ if (pvalue->m_pPattern && pvalue->m_pPattern->m_pDocument) {
+ pvalue->m_pPattern =
+ pvalue->m_pPattern->m_pDocument->GetPageData()->GetPattern(
+ pvalue->m_pPattern->m_pPatternObj, FALSE,
+ &pvalue->m_pPattern->m_ParentMatrix);
+ }
+ }
+}
+FX_BOOL CPDF_Color::GetRGB(int& R, int& G, int& B) const {
+ if (!m_pCS || !m_pBuffer) {
+ return FALSE;
+ }
+ FX_FLOAT r = 0.0f, g = 0.0f, b = 0.0f;
+ if (!m_pCS->GetRGB(m_pBuffer, r, g, b)) {
+ return FALSE;
+ }
+ R = (int32_t)(r * 255 + 0.5f);
+ G = (int32_t)(g * 255 + 0.5f);
+ B = (int32_t)(b * 255 + 0.5f);
+ return TRUE;
+}
+CPDF_Pattern* CPDF_Color::GetPattern() const {
+ if (!m_pBuffer || m_pCS->GetFamily() != PDFCS_PATTERN) {
+ return NULL;
+ }
+ PatternValue* pvalue = (PatternValue*)m_pBuffer;
+ return pvalue->m_pPattern;
+}
+CPDF_ColorSpace* CPDF_Color::GetPatternCS() const {
+ if (!m_pBuffer || m_pCS->GetFamily() != PDFCS_PATTERN) {
+ return NULL;
+ }
+ return m_pCS->GetBaseCS();
+}
+FX_FLOAT* CPDF_Color::GetPatternColor() const {
+ if (!m_pBuffer || m_pCS->GetFamily() != PDFCS_PATTERN) {
+ return NULL;
+ }
+ PatternValue* pvalue = (PatternValue*)m_pBuffer;
+ return pvalue->m_nComps ? pvalue->m_Comps : NULL;
+}
+FX_BOOL CPDF_Color::IsEqual(const CPDF_Color& other) const {
+ return m_pCS && m_pCS == other.m_pCS &&
+ FXSYS_memcmp(m_pBuffer, other.m_pBuffer, m_pCS->GetBufSize()) == 0;
+}
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_doc.cpp b/core/fpdfapi/fpdf_page/fpdf_page_doc.cpp
new file mode 100644
index 0000000000..1a31364b1c
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/fpdf_page_doc.cpp
@@ -0,0 +1,610 @@
+// Copyright 2014 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/fpdf_page/pageint.h"
+
+#include "core/fpdfapi/fpdf_font/font_int.h"
+#include "core/include/fdrm/fx_crypt.h"
+#include "core/include/fpdfapi/cpdf_array.h"
+#include "core/include/fpdfapi/cpdf_dictionary.h"
+#include "core/include/fpdfapi/cpdf_document.h"
+#include "core/include/fpdfapi/fpdf_module.h"
+#include "core/include/fpdfapi/fpdf_page.h"
+
+class CPDF_PageModule : public IPDF_PageModule {
+ public:
+ CPDF_PageModule()
+ : m_StockGrayCS(nullptr, PDFCS_DEVICEGRAY),
+ m_StockRGBCS(nullptr, PDFCS_DEVICERGB),
+ m_StockCMYKCS(nullptr, PDFCS_DEVICECMYK),
+ m_StockPatternCS(nullptr) {}
+
+ private:
+ ~CPDF_PageModule() override {}
+
+ CPDF_DocPageData* CreateDocData(CPDF_Document* pDoc) override {
+ return new CPDF_DocPageData(pDoc);
+ }
+
+ void ReleaseDoc(CPDF_Document* pDoc) override;
+ void ClearDoc(CPDF_Document* pDoc) override;
+
+ CPDF_FontGlobals* GetFontGlobals() override { return &m_FontGlobals; }
+
+ void ClearStockFont(CPDF_Document* pDoc) override {
+ m_FontGlobals.Clear(pDoc);
+ }
+
+ CPDF_ColorSpace* GetStockCS(int family) override;
+ void NotifyCJKAvailable() override;
+
+ CPDF_FontGlobals m_FontGlobals;
+ CPDF_DeviceCS m_StockGrayCS;
+ CPDF_DeviceCS m_StockRGBCS;
+ CPDF_DeviceCS m_StockCMYKCS;
+ CPDF_PatternCS m_StockPatternCS;
+};
+
+CPDF_ColorSpace* CPDF_PageModule::GetStockCS(int family) {
+ if (family == PDFCS_DEVICEGRAY) {
+ return &m_StockGrayCS;
+ }
+ if (family == PDFCS_DEVICERGB) {
+ return &m_StockRGBCS;
+ }
+ if (family == PDFCS_DEVICECMYK) {
+ return &m_StockCMYKCS;
+ }
+ if (family == PDFCS_PATTERN) {
+ return &m_StockPatternCS;
+ }
+ return NULL;
+}
+
+void CPDF_ModuleMgr::InitPageModule() {
+ m_pPageModule.reset(new CPDF_PageModule);
+}
+
+void CPDF_PageModule::ReleaseDoc(CPDF_Document* pDoc) {
+ delete pDoc->GetPageData();
+}
+void CPDF_PageModule::ClearDoc(CPDF_Document* pDoc) {
+ pDoc->GetPageData()->Clear(FALSE);
+}
+void CPDF_PageModule::NotifyCJKAvailable() {
+ m_FontGlobals.m_CMapManager.ReloadAll();
+}
+
+CPDF_Font* CPDF_Document::LoadFont(CPDF_Dictionary* pFontDict) {
+ ASSERT(pFontDict);
+ return GetValidatePageData()->GetFont(pFontDict, FALSE);
+}
+
+CPDF_StreamAcc* CPDF_Document::LoadFontFile(CPDF_Stream* pStream) {
+ return GetValidatePageData()->GetFontFileStreamAcc(pStream);
+}
+
+CPDF_ColorSpace* _CSFromName(const CFX_ByteString& name);
+CPDF_ColorSpace* CPDF_Document::LoadColorSpace(CPDF_Object* pCSObj,
+ CPDF_Dictionary* pResources) {
+ return GetValidatePageData()->GetColorSpace(pCSObj, pResources);
+}
+CPDF_Pattern* CPDF_Document::LoadPattern(CPDF_Object* pPatternObj,
+ FX_BOOL bShading,
+ const CFX_Matrix* matrix) {
+ return GetValidatePageData()->GetPattern(pPatternObj, bShading, matrix);
+}
+CPDF_IccProfile* CPDF_Document::LoadIccProfile(CPDF_Stream* pStream) {
+ return GetValidatePageData()->GetIccProfile(pStream);
+}
+CPDF_Image* CPDF_Document::LoadImageF(CPDF_Object* pObj) {
+ if (!pObj) {
+ return NULL;
+ }
+ FXSYS_assert(pObj->GetObjNum());
+ return GetValidatePageData()->GetImage(pObj);
+}
+void CPDF_Document::RemoveColorSpaceFromPageData(CPDF_Object* pCSObj) {
+ if (!pCSObj) {
+ return;
+ }
+ GetPageData()->ReleaseColorSpace(pCSObj);
+}
+CPDF_DocPageData::CPDF_DocPageData(CPDF_Document* pPDFDoc)
+ : m_pPDFDoc(pPDFDoc), m_bForceClear(FALSE) {}
+
+CPDF_DocPageData::~CPDF_DocPageData() {
+ Clear(FALSE);
+ Clear(TRUE);
+
+ for (auto& it : m_PatternMap)
+ delete it.second;
+ m_PatternMap.clear();
+
+ for (auto& it : m_FontMap)
+ delete it.second;
+ m_FontMap.clear();
+
+ for (auto& it : m_ColorSpaceMap)
+ delete it.second;
+ m_ColorSpaceMap.clear();
+}
+
+void CPDF_DocPageData::Clear(FX_BOOL bForceRelease) {
+ m_bForceClear = bForceRelease;
+
+ for (auto& it : m_PatternMap) {
+ CPDF_CountedPattern* ptData = it.second;
+ if (!ptData->get())
+ continue;
+
+ if (bForceRelease || ptData->use_count() < 2) {
+ ptData->get()->SetForceClear(bForceRelease);
+ ptData->clear();
+ }
+ }
+
+ for (auto& it : m_FontMap) {
+ CPDF_CountedFont* fontData = it.second;
+ if (!fontData->get())
+ continue;
+
+ if (bForceRelease || fontData->use_count() < 2) {
+ fontData->clear();
+ }
+ }
+
+ for (auto& it : m_ColorSpaceMap) {
+ CPDF_CountedColorSpace* csData = it.second;
+ if (!csData->get())
+ continue;
+
+ if (bForceRelease || csData->use_count() < 2) {
+ csData->get()->ReleaseCS();
+ csData->reset(nullptr);
+ }
+ }
+
+ for (auto it = m_IccProfileMap.begin(); it != m_IccProfileMap.end();) {
+ auto curr_it = it++;
+ CPDF_CountedIccProfile* ipData = curr_it->second;
+ if (!ipData->get())
+ continue;
+
+ if (bForceRelease || ipData->use_count() < 2) {
+ for (auto hash_it = m_HashProfileMap.begin();
+ hash_it != m_HashProfileMap.end(); ++hash_it) {
+ if (curr_it->first == hash_it->second) {
+ m_HashProfileMap.erase(hash_it);
+ break;
+ }
+ }
+ delete ipData->get();
+ delete ipData;
+ m_IccProfileMap.erase(curr_it);
+ }
+ }
+
+ for (auto it = m_FontFileMap.begin(); it != m_FontFileMap.end();) {
+ auto curr_it = it++;
+ CPDF_CountedStreamAcc* ftData = curr_it->second;
+ if (!ftData->get())
+ continue;
+
+ if (bForceRelease || ftData->use_count() < 2) {
+ delete ftData->get();
+ delete ftData;
+ m_FontFileMap.erase(curr_it);
+ }
+ }
+
+ for (auto it = m_ImageMap.begin(); it != m_ImageMap.end();) {
+ auto curr_it = it++;
+ CPDF_CountedImage* imageData = curr_it->second;
+ if (!imageData->get())
+ continue;
+
+ if (bForceRelease || imageData->use_count() < 2) {
+ delete imageData->get();
+ delete imageData;
+ m_ImageMap.erase(curr_it);
+ }
+ }
+}
+
+CPDF_Font* CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict,
+ FX_BOOL findOnly) {
+ if (!pFontDict) {
+ return NULL;
+ }
+ if (findOnly) {
+ auto it = m_FontMap.find(pFontDict);
+ if (it != m_FontMap.end() && it->second->get()) {
+ return it->second->AddRef();
+ }
+ return nullptr;
+ }
+
+ CPDF_CountedFont* fontData = nullptr;
+ auto it = m_FontMap.find(pFontDict);
+ if (it != m_FontMap.end()) {
+ fontData = it->second;
+ if (fontData->get()) {
+ return fontData->AddRef();
+ }
+ }
+
+ CPDF_Font* pFont = CPDF_Font::CreateFontF(m_pPDFDoc, pFontDict);
+ if (!pFont) {
+ return nullptr;
+ }
+ if (!fontData) {
+ fontData = new CPDF_CountedFont(pFont);
+ m_FontMap[pFontDict] = fontData;
+ } else {
+ fontData->reset(pFont);
+ }
+ return fontData->AddRef();
+}
+
+CPDF_Font* CPDF_DocPageData::GetStandardFont(const CFX_ByteStringC& fontName,
+ CPDF_FontEncoding* pEncoding) {
+ if (fontName.IsEmpty())
+ return nullptr;
+
+ for (auto& it : m_FontMap) {
+ CPDF_CountedFont* fontData = it.second;
+ CPDF_Font* pFont = fontData->get();
+ if (!pFont)
+ continue;
+ if (pFont->GetBaseFont() != fontName)
+ continue;
+ if (pFont->IsEmbedded())
+ continue;
+ if (!pFont->IsType1Font())
+ continue;
+ if (pFont->GetFontDict()->KeyExist("Widths"))
+ continue;
+
+ CPDF_Type1Font* pT1Font = pFont->AsType1Font();
+ if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding))
+ continue;
+
+ return fontData->AddRef();
+ }
+
+ CPDF_Dictionary* pDict = new CPDF_Dictionary;
+ pDict->SetAtName("Type", "Font");
+ pDict->SetAtName("Subtype", "Type1");
+ pDict->SetAtName("BaseFont", fontName);
+ if (pEncoding) {
+ pDict->SetAt("Encoding", pEncoding->Realize());
+ }
+ m_pPDFDoc->AddIndirectObject(pDict);
+ CPDF_Font* pFont = CPDF_Font::CreateFontF(m_pPDFDoc, pDict);
+ if (!pFont) {
+ return nullptr;
+ }
+ CPDF_CountedFont* fontData = new CPDF_CountedFont(pFont);
+ m_FontMap[pDict] = fontData;
+ return fontData->AddRef();
+}
+
+void CPDF_DocPageData::ReleaseFont(CPDF_Dictionary* pFontDict) {
+ if (!pFontDict)
+ return;
+
+ auto it = m_FontMap.find(pFontDict);
+ if (it == m_FontMap.end())
+ return;
+
+ CPDF_CountedFont* fontData = it->second;
+ if (fontData->get()) {
+ fontData->RemoveRef();
+ if (fontData->use_count() == 0) {
+ fontData->clear();
+ }
+ }
+}
+
+CPDF_ColorSpace* CPDF_DocPageData::GetColorSpace(
+ CPDF_Object* pCSObj,
+ const CPDF_Dictionary* pResources) {
+ if (!pCSObj)
+ return nullptr;
+
+ if (pCSObj->IsName()) {
+ CFX_ByteString name = pCSObj->GetConstString();
+ CPDF_ColorSpace* pCS = _CSFromName(name);
+ if (!pCS && pResources) {
+ CPDF_Dictionary* pList = pResources->GetDictBy("ColorSpace");
+ if (pList) {
+ pCSObj = pList->GetElementValue(name);
+ return GetColorSpace(pCSObj, nullptr);
+ }
+ }
+ if (!pCS || !pResources)
+ return pCS;
+
+ CPDF_Dictionary* pColorSpaces = pResources->GetDictBy("ColorSpace");
+ if (!pColorSpaces)
+ return pCS;
+
+ CPDF_Object* pDefaultCS = nullptr;
+ switch (pCS->GetFamily()) {
+ case PDFCS_DEVICERGB:
+ pDefaultCS = pColorSpaces->GetElementValue("DefaultRGB");
+ break;
+ case PDFCS_DEVICEGRAY:
+ pDefaultCS = pColorSpaces->GetElementValue("DefaultGray");
+ break;
+ case PDFCS_DEVICECMYK:
+ pDefaultCS = pColorSpaces->GetElementValue("DefaultCMYK");
+ break;
+ }
+ return pDefaultCS ? GetColorSpace(pDefaultCS, nullptr) : pCS;
+ }
+
+ CPDF_Array* pArray = pCSObj->AsArray();
+ if (!pArray || pArray->GetCount() == 0)
+ return nullptr;
+ if (pArray->GetCount() == 1)
+ return GetColorSpace(pArray->GetElementValue(0), pResources);
+
+ CPDF_CountedColorSpace* csData = nullptr;
+ auto it = m_ColorSpaceMap.find(pCSObj);
+ if (it != m_ColorSpaceMap.end()) {
+ csData = it->second;
+ if (csData->get()) {
+ return csData->AddRef();
+ }
+ }
+
+ CPDF_ColorSpace* pCS = CPDF_ColorSpace::Load(m_pPDFDoc, pArray);
+ if (!pCS)
+ return nullptr;
+
+ if (!csData) {
+ csData = new CPDF_CountedColorSpace(pCS);
+ m_ColorSpaceMap[pCSObj] = csData;
+ } else {
+ csData->reset(pCS);
+ }
+ return csData->AddRef();
+}
+
+CPDF_ColorSpace* CPDF_DocPageData::GetCopiedColorSpace(CPDF_Object* pCSObj) {
+ if (!pCSObj)
+ return nullptr;
+
+ auto it = m_ColorSpaceMap.find(pCSObj);
+ if (it != m_ColorSpaceMap.end())
+ return it->second->AddRef();
+
+ return nullptr;
+}
+
+void CPDF_DocPageData::ReleaseColorSpace(CPDF_Object* pColorSpace) {
+ if (!pColorSpace)
+ return;
+
+ auto it = m_ColorSpaceMap.find(pColorSpace);
+ if (it == m_ColorSpaceMap.end())
+ return;
+
+ CPDF_CountedColorSpace* csData = it->second;
+ if (csData->get()) {
+ csData->RemoveRef();
+ if (csData->use_count() == 0) {
+ csData->get()->ReleaseCS();
+ csData->reset(nullptr);
+ }
+ }
+}
+
+CPDF_Pattern* CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj,
+ FX_BOOL bShading,
+ const CFX_Matrix* matrix) {
+ if (!pPatternObj)
+ return nullptr;
+
+ CPDF_CountedPattern* ptData = nullptr;
+ auto it = m_PatternMap.find(pPatternObj);
+ if (it != m_PatternMap.end()) {
+ ptData = it->second;
+ if (ptData->get()) {
+ return ptData->AddRef();
+ }
+ }
+ CPDF_Pattern* pPattern = nullptr;
+ if (bShading) {
+ pPattern =
+ new CPDF_ShadingPattern(m_pPDFDoc, pPatternObj, bShading, matrix);
+ } else {
+ CPDF_Dictionary* pDict = pPatternObj ? pPatternObj->GetDict() : nullptr;
+ if (pDict) {
+ int type = pDict->GetIntegerBy("PatternType");
+ if (type == 1) {
+ pPattern = new CPDF_TilingPattern(m_pPDFDoc, pPatternObj, matrix);
+ } else if (type == 2) {
+ pPattern =
+ new CPDF_ShadingPattern(m_pPDFDoc, pPatternObj, FALSE, matrix);
+ }
+ }
+ }
+ if (!pPattern)
+ return nullptr;
+
+ if (!ptData) {
+ ptData = new CPDF_CountedPattern(pPattern);
+ m_PatternMap[pPatternObj] = ptData;
+ } else {
+ ptData->reset(pPattern);
+ }
+ return ptData->AddRef();
+}
+
+void CPDF_DocPageData::ReleasePattern(CPDF_Object* pPatternObj) {
+ if (!pPatternObj)
+ return;
+
+ auto it = m_PatternMap.find(pPatternObj);
+ if (it == m_PatternMap.end())
+ return;
+
+ CPDF_CountedPattern* ptData = it->second;
+ if (ptData->get()) {
+ ptData->RemoveRef();
+ if (ptData->use_count() == 0) {
+ ptData->clear();
+ }
+ }
+}
+
+CPDF_Image* CPDF_DocPageData::GetImage(CPDF_Object* pImageStream) {
+ if (!pImageStream)
+ return nullptr;
+
+ const FX_DWORD dwImageObjNum = pImageStream->GetObjNum();
+ auto it = m_ImageMap.find(dwImageObjNum);
+ if (it != m_ImageMap.end()) {
+ return it->second->AddRef();
+ }
+
+ CPDF_Image* pImage = new CPDF_Image(m_pPDFDoc);
+ pImage->LoadImageF(pImageStream->AsStream(), FALSE);
+
+ CPDF_CountedImage* imageData = new CPDF_CountedImage(pImage);
+ m_ImageMap[dwImageObjNum] = imageData;
+ return imageData->AddRef();
+}
+
+void CPDF_DocPageData::ReleaseImage(CPDF_Object* pImageStream) {
+ if (!pImageStream || !pImageStream->GetObjNum())
+ return;
+
+ auto it = m_ImageMap.find(pImageStream->GetObjNum());
+ if (it == m_ImageMap.end())
+ return;
+
+ CPDF_CountedImage* image = it->second;
+ if (!image)
+ return;
+
+ image->RemoveRef();
+ if (image->use_count() == 0) {
+ delete image->get();
+ delete image;
+ m_ImageMap.erase(it);
+ }
+}
+
+CPDF_IccProfile* CPDF_DocPageData::GetIccProfile(
+ CPDF_Stream* pIccProfileStream) {
+ if (!pIccProfileStream)
+ return NULL;
+
+ auto it = m_IccProfileMap.find(pIccProfileStream);
+ if (it != m_IccProfileMap.end()) {
+ return it->second->AddRef();
+ }
+
+ CPDF_StreamAcc stream;
+ stream.LoadAllData(pIccProfileStream, FALSE);
+ uint8_t digest[20];
+ CRYPT_SHA1Generate(stream.GetData(), stream.GetSize(), digest);
+ auto hash_it = m_HashProfileMap.find(CFX_ByteStringC(digest, 20));
+ if (hash_it != m_HashProfileMap.end()) {
+ auto it_copied_stream = m_IccProfileMap.find(hash_it->second);
+ return it_copied_stream->second->AddRef();
+ }
+ CPDF_IccProfile* pProfile =
+ new CPDF_IccProfile(stream.GetData(), stream.GetSize());
+ CPDF_CountedIccProfile* ipData = new CPDF_CountedIccProfile(pProfile);
+ m_IccProfileMap[pIccProfileStream] = ipData;
+ m_HashProfileMap[CFX_ByteStringC(digest, 20)] = pIccProfileStream;
+ return ipData->AddRef();
+}
+
+void CPDF_DocPageData::ReleaseIccProfile(CPDF_IccProfile* pIccProfile) {
+ ASSERT(pIccProfile);
+
+ for (auto it = m_IccProfileMap.begin(); it != m_IccProfileMap.end(); ++it) {
+ CPDF_CountedIccProfile* profile = it->second;
+ if (profile->get() != pIccProfile)
+ continue;
+
+ profile->RemoveRef();
+ if (profile->use_count() == 0) {
+ delete profile->get();
+ delete profile;
+ m_IccProfileMap.erase(it);
+ return;
+ }
+ }
+}
+
+CPDF_StreamAcc* CPDF_DocPageData::GetFontFileStreamAcc(
+ CPDF_Stream* pFontStream) {
+ ASSERT(pFontStream);
+
+ auto it = m_FontFileMap.find(pFontStream);
+ if (it != m_FontFileMap.end())
+ return it->second->AddRef();
+
+ CPDF_Dictionary* pFontDict = pFontStream->GetDict();
+ int32_t org_size = pFontDict->GetIntegerBy("Length1") +
+ pFontDict->GetIntegerBy("Length2") +
+ pFontDict->GetIntegerBy("Length3");
+ if (org_size < 0)
+ org_size = 0;
+
+ CPDF_StreamAcc* pFontFile = new CPDF_StreamAcc;
+ pFontFile->LoadAllData(pFontStream, FALSE, org_size);
+
+ CPDF_CountedStreamAcc* ftData = new CPDF_CountedStreamAcc(pFontFile);
+ m_FontFileMap[pFontStream] = ftData;
+ return ftData->AddRef();
+}
+
+void CPDF_DocPageData::ReleaseFontFileStreamAcc(CPDF_Stream* pFontStream,
+ FX_BOOL bForce) {
+ if (!pFontStream)
+ return;
+
+ auto it = m_FontFileMap.find(pFontStream);
+ if (it == m_FontFileMap.end())
+ return;
+
+ CPDF_CountedStreamAcc* findData = it->second;
+ if (!findData)
+ return;
+
+ findData->RemoveRef();
+ if (findData->use_count() == 0 || bForce) {
+ delete findData->get();
+ delete findData;
+ m_FontFileMap.erase(it);
+ }
+}
+
+CPDF_CountedColorSpace* CPDF_DocPageData::FindColorSpacePtr(
+ CPDF_Object* pCSObj) const {
+ if (!pCSObj)
+ return nullptr;
+
+ auto it = m_ColorSpaceMap.find(pCSObj);
+ return it != m_ColorSpaceMap.end() ? it->second : nullptr;
+}
+
+CPDF_CountedPattern* CPDF_DocPageData::FindPatternPtr(
+ CPDF_Object* pPatternObj) const {
+ if (!pPatternObj)
+ return nullptr;
+
+ auto it = m_PatternMap.find(pPatternObj);
+ return it != m_PatternMap.end() ? it->second : nullptr;
+}
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_func.cpp b/core/fpdfapi/fpdf_page/fpdf_page_func.cpp
new file mode 100644
index 0000000000..fd37e1d3e4
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/fpdf_page_func.cpp
@@ -0,0 +1,966 @@
+// Copyright 2014 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/fpdf_page/pageint.h"
+
+#include <limits.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "core/include/fpdfapi/cpdf_array.h"
+#include "core/include/fpdfapi/cpdf_dictionary.h"
+#include "core/include/fpdfapi/cpdf_simple_parser.h"
+#include "core/include/fpdfapi/fpdf_module.h"
+#include "core/include/fpdfapi/fpdf_page.h"
+#include "core/include/fxcrt/fx_safe_types.h"
+#include "third_party/base/numerics/safe_conversions_impl.h"
+
+namespace {
+
+enum PDF_PSOP {
+ PSOP_ADD,
+ PSOP_SUB,
+ PSOP_MUL,
+ PSOP_DIV,
+ PSOP_IDIV,
+ PSOP_MOD,
+ PSOP_NEG,
+ PSOP_ABS,
+ PSOP_CEILING,
+ PSOP_FLOOR,
+ PSOP_ROUND,
+ PSOP_TRUNCATE,
+ PSOP_SQRT,
+ PSOP_SIN,
+ PSOP_COS,
+ PSOP_ATAN,
+ PSOP_EXP,
+ PSOP_LN,
+ PSOP_LOG,
+ PSOP_CVI,
+ PSOP_CVR,
+ PSOP_EQ,
+ PSOP_NE,
+ PSOP_GT,
+ PSOP_GE,
+ PSOP_LT,
+ PSOP_LE,
+ PSOP_AND,
+ PSOP_OR,
+ PSOP_XOR,
+ PSOP_NOT,
+ PSOP_BITSHIFT,
+ PSOP_TRUE,
+ PSOP_FALSE,
+ PSOP_IF,
+ PSOP_IFELSE,
+ PSOP_POP,
+ PSOP_EXCH,
+ PSOP_DUP,
+ PSOP_COPY,
+ PSOP_INDEX,
+ PSOP_ROLL,
+ PSOP_PROC,
+ PSOP_CONST
+};
+
+class CPDF_PSEngine;
+class CPDF_PSProc;
+
+class CPDF_PSOP {
+ public:
+ explicit CPDF_PSOP(PDF_PSOP op) : m_op(op), m_value(0) {
+ ASSERT(m_op != PSOP_CONST);
+ ASSERT(m_op != PSOP_PROC);
+ }
+ explicit CPDF_PSOP(FX_FLOAT value) : m_op(PSOP_CONST), m_value(value) {}
+ explicit CPDF_PSOP(std::unique_ptr<CPDF_PSProc> proc)
+ : m_op(PSOP_PROC), m_value(0), m_proc(std::move(proc)) {}
+
+ FX_FLOAT GetFloatValue() const {
+ if (m_op == PSOP_CONST)
+ return m_value;
+
+ ASSERT(false);
+ return 0;
+ }
+ CPDF_PSProc* GetProc() const {
+ if (m_op == PSOP_PROC)
+ return m_proc.get();
+ ASSERT(false);
+ return nullptr;
+ }
+
+ PDF_PSOP GetOp() const { return m_op; }
+
+ private:
+ const PDF_PSOP m_op;
+ const FX_FLOAT m_value;
+ std::unique_ptr<CPDF_PSProc> m_proc;
+};
+
+class CPDF_PSProc {
+ public:
+ CPDF_PSProc() {}
+ ~CPDF_PSProc() {}
+
+ FX_BOOL Parse(CPDF_SimpleParser* parser);
+ FX_BOOL Execute(CPDF_PSEngine* pEngine);
+
+ private:
+ std::vector<std::unique_ptr<CPDF_PSOP>> m_Operators;
+};
+
+const size_t PSENGINE_STACKSIZE = 100;
+
+class CPDF_PSEngine {
+ public:
+ CPDF_PSEngine();
+ ~CPDF_PSEngine();
+
+ FX_BOOL Parse(const FX_CHAR* str, int size);
+ FX_BOOL Execute() { return m_MainProc.Execute(this); }
+ FX_BOOL DoOperator(PDF_PSOP op);
+ void Reset() { m_StackCount = 0; }
+ void Push(FX_FLOAT value);
+ void Push(int value) { Push((FX_FLOAT)value); }
+ FX_FLOAT Pop();
+ int GetStackSize() const { return m_StackCount; }
+
+ private:
+ FX_FLOAT m_Stack[PSENGINE_STACKSIZE];
+ int m_StackCount;
+ CPDF_PSProc m_MainProc;
+};
+
+FX_BOOL CPDF_PSProc::Execute(CPDF_PSEngine* pEngine) {
+ for (size_t i = 0; i < m_Operators.size(); ++i) {
+ const PDF_PSOP op = m_Operators[i]->GetOp();
+ if (op == PSOP_PROC)
+ continue;
+
+ if (op == PSOP_CONST) {
+ pEngine->Push(m_Operators[i]->GetFloatValue());
+ continue;
+ }
+
+ if (op == PSOP_IF) {
+ if (i == 0 || m_Operators[i - 1]->GetOp() != PSOP_PROC)
+ return FALSE;
+
+ if (static_cast<int>(pEngine->Pop()))
+ m_Operators[i - 1]->GetProc()->Execute(pEngine);
+ } else if (op == PSOP_IFELSE) {
+ if (i < 2 || m_Operators[i - 1]->GetOp() != PSOP_PROC ||
+ m_Operators[i - 2]->GetOp() != PSOP_PROC) {
+ return FALSE;
+ }
+ size_t offset = static_cast<int>(pEngine->Pop()) ? 2 : 1;
+ m_Operators[i - offset]->GetProc()->Execute(pEngine);
+ } else {
+ pEngine->DoOperator(op);
+ }
+ }
+ return TRUE;
+}
+
+CPDF_PSEngine::CPDF_PSEngine() {
+ m_StackCount = 0;
+}
+CPDF_PSEngine::~CPDF_PSEngine() {}
+void CPDF_PSEngine::Push(FX_FLOAT v) {
+ if (m_StackCount == PSENGINE_STACKSIZE) {
+ return;
+ }
+ m_Stack[m_StackCount++] = v;
+}
+FX_FLOAT CPDF_PSEngine::Pop() {
+ if (m_StackCount == 0) {
+ return 0;
+ }
+ return m_Stack[--m_StackCount];
+}
+const struct PDF_PSOpName {
+ const FX_CHAR* name;
+ PDF_PSOP op;
+} PDF_PSOpNames[] = {{"add", PSOP_ADD}, {"sub", PSOP_SUB},
+ {"mul", PSOP_MUL}, {"div", PSOP_DIV},
+ {"idiv", PSOP_IDIV}, {"mod", PSOP_MOD},
+ {"neg", PSOP_NEG}, {"abs", PSOP_ABS},
+ {"ceiling", PSOP_CEILING}, {"floor", PSOP_FLOOR},
+ {"round", PSOP_ROUND}, {"truncate", PSOP_TRUNCATE},
+ {"sqrt", PSOP_SQRT}, {"sin", PSOP_SIN},
+ {"cos", PSOP_COS}, {"atan", PSOP_ATAN},
+ {"exp", PSOP_EXP}, {"ln", PSOP_LN},
+ {"log", PSOP_LOG}, {"cvi", PSOP_CVI},
+ {"cvr", PSOP_CVR}, {"eq", PSOP_EQ},
+ {"ne", PSOP_NE}, {"gt", PSOP_GT},
+ {"ge", PSOP_GE}, {"lt", PSOP_LT},
+ {"le", PSOP_LE}, {"and", PSOP_AND},
+ {"or", PSOP_OR}, {"xor", PSOP_XOR},
+ {"not", PSOP_NOT}, {"bitshift", PSOP_BITSHIFT},
+ {"true", PSOP_TRUE}, {"false", PSOP_FALSE},
+ {"if", PSOP_IF}, {"ifelse", PSOP_IFELSE},
+ {"pop", PSOP_POP}, {"exch", PSOP_EXCH},
+ {"dup", PSOP_DUP}, {"copy", PSOP_COPY},
+ {"index", PSOP_INDEX}, {"roll", PSOP_ROLL}};
+
+FX_BOOL CPDF_PSEngine::Parse(const FX_CHAR* str, int size) {
+ CPDF_SimpleParser parser((uint8_t*)str, size);
+ CFX_ByteStringC word = parser.GetWord();
+ if (word != "{") {
+ return FALSE;
+ }
+ return m_MainProc.Parse(&parser);
+}
+FX_BOOL CPDF_PSProc::Parse(CPDF_SimpleParser* parser) {
+ while (1) {
+ CFX_ByteStringC word = parser->GetWord();
+ if (word.IsEmpty()) {
+ return FALSE;
+ }
+ if (word == "}") {
+ return TRUE;
+ }
+ if (word == "{") {
+ std::unique_ptr<CPDF_PSProc> proc(new CPDF_PSProc);
+ std::unique_ptr<CPDF_PSOP> op(new CPDF_PSOP(std::move(proc)));
+ m_Operators.push_back(std::move(op));
+ if (!m_Operators.back()->GetProc()->Parse(parser)) {
+ return FALSE;
+ }
+ } else {
+ bool found = false;
+ for (const PDF_PSOpName& op_name : PDF_PSOpNames) {
+ if (word == CFX_ByteStringC(op_name.name)) {
+ std::unique_ptr<CPDF_PSOP> op(new CPDF_PSOP(op_name.op));
+ m_Operators.push_back(std::move(op));
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ std::unique_ptr<CPDF_PSOP> op(new CPDF_PSOP(FX_atof(word)));
+ m_Operators.push_back(std::move(op));
+ }
+ }
+ }
+}
+
+FX_BOOL CPDF_PSEngine::DoOperator(PDF_PSOP op) {
+ int i1, i2;
+ FX_FLOAT d1, d2;
+ switch (op) {
+ case PSOP_ADD:
+ d1 = Pop();
+ d2 = Pop();
+ Push(d1 + d2);
+ break;
+ case PSOP_SUB:
+ d2 = Pop();
+ d1 = Pop();
+ Push(d1 - d2);
+ break;
+ case PSOP_MUL:
+ d1 = Pop();
+ d2 = Pop();
+ Push(d1 * d2);
+ break;
+ case PSOP_DIV:
+ d2 = Pop();
+ d1 = Pop();
+ Push(d1 / d2);
+ break;
+ case PSOP_IDIV:
+ i2 = (int)Pop();
+ i1 = (int)Pop();
+ Push(i1 / i2);
+ break;
+ case PSOP_MOD:
+ i2 = (int)Pop();
+ i1 = (int)Pop();
+ Push(i1 % i2);
+ break;
+ case PSOP_NEG:
+ d1 = Pop();
+ Push(-d1);
+ break;
+ case PSOP_ABS:
+ d1 = Pop();
+ Push((FX_FLOAT)FXSYS_fabs(d1));
+ break;
+ case PSOP_CEILING:
+ d1 = Pop();
+ Push((FX_FLOAT)FXSYS_ceil(d1));
+ break;
+ case PSOP_FLOOR:
+ d1 = Pop();
+ Push((FX_FLOAT)FXSYS_floor(d1));
+ break;
+ case PSOP_ROUND:
+ d1 = Pop();
+ Push(FXSYS_round(d1));
+ break;
+ case PSOP_TRUNCATE:
+ i1 = (int)Pop();
+ Push(i1);
+ break;
+ case PSOP_SQRT:
+ d1 = Pop();
+ Push((FX_FLOAT)FXSYS_sqrt(d1));
+ break;
+ case PSOP_SIN:
+ d1 = Pop();
+ Push((FX_FLOAT)FXSYS_sin(d1 * FX_PI / 180.0f));
+ break;
+ case PSOP_COS:
+ d1 = Pop();
+ Push((FX_FLOAT)FXSYS_cos(d1 * FX_PI / 180.0f));
+ break;
+ case PSOP_ATAN:
+ d2 = Pop();
+ d1 = Pop();
+ d1 = (FX_FLOAT)(FXSYS_atan2(d1, d2) * 180.0 / FX_PI);
+ if (d1 < 0) {
+ d1 += 360;
+ }
+ Push(d1);
+ break;
+ case PSOP_EXP:
+ d2 = Pop();
+ d1 = Pop();
+ Push((FX_FLOAT)FXSYS_pow(d1, d2));
+ break;
+ case PSOP_LN:
+ d1 = Pop();
+ Push((FX_FLOAT)FXSYS_log(d1));
+ break;
+ case PSOP_LOG:
+ d1 = Pop();
+ Push((FX_FLOAT)FXSYS_log10(d1));
+ break;
+ case PSOP_CVI:
+ i1 = (int)Pop();
+ Push(i1);
+ break;
+ case PSOP_CVR:
+ break;
+ case PSOP_EQ:
+ d2 = Pop();
+ d1 = Pop();
+ Push((int)(d1 == d2));
+ break;
+ case PSOP_NE:
+ d2 = Pop();
+ d1 = Pop();
+ Push((int)(d1 != d2));
+ break;
+ case PSOP_GT:
+ d2 = Pop();
+ d1 = Pop();
+ Push((int)(d1 > d2));
+ break;
+ case PSOP_GE:
+ d2 = Pop();
+ d1 = Pop();
+ Push((int)(d1 >= d2));
+ break;
+ case PSOP_LT:
+ d2 = Pop();
+ d1 = Pop();
+ Push((int)(d1 < d2));
+ break;
+ case PSOP_LE:
+ d2 = Pop();
+ d1 = Pop();
+ Push((int)(d1 <= d2));
+ break;
+ case PSOP_AND:
+ i1 = (int)Pop();
+ i2 = (int)Pop();
+ Push(i1 & i2);
+ break;
+ case PSOP_OR:
+ i1 = (int)Pop();
+ i2 = (int)Pop();
+ Push(i1 | i2);
+ break;
+ case PSOP_XOR:
+ i1 = (int)Pop();
+ i2 = (int)Pop();
+ Push(i1 ^ i2);
+ break;
+ case PSOP_NOT:
+ i1 = (int)Pop();
+ Push((int)!i1);
+ break;
+ case PSOP_BITSHIFT: {
+ int shift = (int)Pop();
+ int i = (int)Pop();
+ if (shift > 0) {
+ Push(i << shift);
+ } else {
+ Push(i >> -shift);
+ }
+ break;
+ }
+ case PSOP_TRUE:
+ Push(1);
+ break;
+ case PSOP_FALSE:
+ Push(0);
+ break;
+ case PSOP_POP:
+ Pop();
+ break;
+ case PSOP_EXCH:
+ d2 = Pop();
+ d1 = Pop();
+ Push(d2);
+ Push(d1);
+ break;
+ case PSOP_DUP:
+ d1 = Pop();
+ Push(d1);
+ Push(d1);
+ break;
+ case PSOP_COPY: {
+ int n = (int)Pop();
+ if (n < 0 || n > PSENGINE_STACKSIZE ||
+ m_StackCount + n > PSENGINE_STACKSIZE || n > m_StackCount) {
+ break;
+ }
+ for (int i = 0; i < n; i++) {
+ m_Stack[m_StackCount + i] = m_Stack[m_StackCount + i - n];
+ }
+ m_StackCount += n;
+ break;
+ }
+ case PSOP_INDEX: {
+ int n = (int)Pop();
+ if (n < 0 || n >= m_StackCount) {
+ break;
+ }
+ Push(m_Stack[m_StackCount - n - 1]);
+ break;
+ }
+ case PSOP_ROLL: {
+ int j = (int)Pop();
+ int n = (int)Pop();
+ if (m_StackCount == 0) {
+ break;
+ }
+ if (n < 0 || n > m_StackCount) {
+ break;
+ }
+ if (j < 0) {
+ for (int i = 0; i < -j; i++) {
+ FX_FLOAT first = m_Stack[m_StackCount - n];
+ for (int ii = 0; ii < n - 1; ii++) {
+ m_Stack[m_StackCount - n + ii] = m_Stack[m_StackCount - n + ii + 1];
+ }
+ m_Stack[m_StackCount - 1] = first;
+ }
+ } else {
+ for (int i = 0; i < j; i++) {
+ FX_FLOAT last = m_Stack[m_StackCount - 1];
+ int ii;
+ for (ii = 0; ii < n - 1; ii++) {
+ m_Stack[m_StackCount - ii - 1] = m_Stack[m_StackCount - ii - 2];
+ }
+ m_Stack[m_StackCount - ii - 1] = last;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return TRUE;
+}
+static FX_FLOAT PDF_Interpolate(FX_FLOAT x,
+ FX_FLOAT xmin,
+ FX_FLOAT xmax,
+ FX_FLOAT ymin,
+ FX_FLOAT ymax) {
+ return ((x - xmin) * (ymax - ymin) / (xmax - xmin)) + ymin;
+}
+static FX_DWORD _GetBits32(const uint8_t* pData, int bitpos, int nbits) {
+ int result = 0;
+ for (int i = 0; i < nbits; i++)
+ if (pData[(bitpos + i) / 8] & (1 << (7 - (bitpos + i) % 8))) {
+ result |= 1 << (nbits - i - 1);
+ }
+ return result;
+}
+typedef struct {
+ FX_FLOAT encode_max, encode_min;
+ int sizes;
+} SampleEncodeInfo;
+typedef struct { FX_FLOAT decode_max, decode_min; } SampleDecodeInfo;
+
+class CPDF_SampledFunc : public CPDF_Function {
+ public:
+ CPDF_SampledFunc();
+ ~CPDF_SampledFunc() override;
+
+ // CPDF_Function
+ FX_BOOL v_Init(CPDF_Object* pObj) override;
+ FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
+
+ SampleEncodeInfo* m_pEncodeInfo;
+ SampleDecodeInfo* m_pDecodeInfo;
+ FX_DWORD m_nBitsPerSample;
+ FX_DWORD m_SampleMax;
+ CPDF_StreamAcc* m_pSampleStream;
+};
+
+CPDF_SampledFunc::CPDF_SampledFunc() {
+ m_pSampleStream = NULL;
+ m_pEncodeInfo = NULL;
+ m_pDecodeInfo = NULL;
+}
+CPDF_SampledFunc::~CPDF_SampledFunc() {
+ delete m_pSampleStream;
+ FX_Free(m_pEncodeInfo);
+ FX_Free(m_pDecodeInfo);
+}
+FX_BOOL CPDF_SampledFunc::v_Init(CPDF_Object* pObj) {
+ CPDF_Stream* pStream = pObj->AsStream();
+ if (!pStream)
+ return false;
+
+ CPDF_Dictionary* pDict = pStream->GetDict();
+ CPDF_Array* pSize = pDict->GetArrayBy("Size");
+ CPDF_Array* pEncode = pDict->GetArrayBy("Encode");
+ CPDF_Array* pDecode = pDict->GetArrayBy("Decode");
+ m_nBitsPerSample = pDict->GetIntegerBy("BitsPerSample");
+ if (m_nBitsPerSample > 32) {
+ return FALSE;
+ }
+ m_SampleMax = 0xffffffff >> (32 - m_nBitsPerSample);
+ m_pSampleStream = new CPDF_StreamAcc;
+ m_pSampleStream->LoadAllData(pStream, FALSE);
+ m_pEncodeInfo = FX_Alloc(SampleEncodeInfo, m_nInputs);
+ FX_SAFE_DWORD nTotalSampleBits = 1;
+ for (int i = 0; i < m_nInputs; i++) {
+ m_pEncodeInfo[i].sizes = pSize ? pSize->GetIntegerAt(i) : 0;
+ if (!pSize && i == 0) {
+ m_pEncodeInfo[i].sizes = pDict->GetIntegerBy("Size");
+ }
+ nTotalSampleBits *= m_pEncodeInfo[i].sizes;
+ if (pEncode) {
+ m_pEncodeInfo[i].encode_min = pEncode->GetFloatAt(i * 2);
+ m_pEncodeInfo[i].encode_max = pEncode->GetFloatAt(i * 2 + 1);
+ } else {
+ m_pEncodeInfo[i].encode_min = 0;
+ if (m_pEncodeInfo[i].sizes == 1) {
+ m_pEncodeInfo[i].encode_max = 1;
+ } else {
+ m_pEncodeInfo[i].encode_max = (FX_FLOAT)m_pEncodeInfo[i].sizes - 1;
+ }
+ }
+ }
+ nTotalSampleBits *= m_nBitsPerSample;
+ nTotalSampleBits *= m_nOutputs;
+ FX_SAFE_DWORD nTotalSampleBytes = nTotalSampleBits;
+ nTotalSampleBytes += 7;
+ nTotalSampleBytes /= 8;
+ if (!nTotalSampleBytes.IsValid() || nTotalSampleBytes.ValueOrDie() == 0 ||
+ nTotalSampleBytes.ValueOrDie() > m_pSampleStream->GetSize()) {
+ return FALSE;
+ }
+ m_pDecodeInfo = FX_Alloc(SampleDecodeInfo, m_nOutputs);
+ for (int i = 0; i < m_nOutputs; i++) {
+ if (pDecode) {
+ m_pDecodeInfo[i].decode_min = pDecode->GetFloatAt(2 * i);
+ m_pDecodeInfo[i].decode_max = pDecode->GetFloatAt(2 * i + 1);
+ } else {
+ m_pDecodeInfo[i].decode_min = m_pRanges[i * 2];
+ m_pDecodeInfo[i].decode_max = m_pRanges[i * 2 + 1];
+ }
+ }
+ return TRUE;
+}
+FX_BOOL CPDF_SampledFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const {
+ int pos = 0;
+ CFX_FixedBufGrow<FX_FLOAT, 16> encoded_input_buf(m_nInputs);
+ FX_FLOAT* encoded_input = encoded_input_buf;
+ CFX_FixedBufGrow<int, 32> int_buf(m_nInputs * 2);
+ int* index = int_buf;
+ int* blocksize = index + m_nInputs;
+ for (int i = 0; i < m_nInputs; i++) {
+ if (i == 0) {
+ blocksize[i] = 1;
+ } else {
+ blocksize[i] = blocksize[i - 1] * m_pEncodeInfo[i - 1].sizes;
+ }
+ encoded_input[i] = PDF_Interpolate(
+ inputs[i], m_pDomains[i * 2], m_pDomains[i * 2 + 1],
+ m_pEncodeInfo[i].encode_min, m_pEncodeInfo[i].encode_max);
+ index[i] = (int)encoded_input[i];
+ if (index[i] < 0) {
+ index[i] = 0;
+ } else if (index[i] > m_pEncodeInfo[i].sizes - 1) {
+ index[i] = m_pEncodeInfo[i].sizes - 1;
+ }
+ pos += index[i] * blocksize[i];
+ }
+ FX_SAFE_INT32 bits_to_output = m_nOutputs;
+ bits_to_output *= m_nBitsPerSample;
+ if (!bits_to_output.IsValid()) {
+ return FALSE;
+ }
+ FX_SAFE_INT32 bitpos = pos;
+ bitpos *= bits_to_output.ValueOrDie();
+ if (!bitpos.IsValid()) {
+ return FALSE;
+ }
+ FX_SAFE_INT32 range_check = bitpos;
+ range_check += bits_to_output.ValueOrDie();
+ if (!range_check.IsValid()) {
+ return FALSE;
+ }
+ const uint8_t* pSampleData = m_pSampleStream->GetData();
+ if (!pSampleData) {
+ return FALSE;
+ }
+ for (int j = 0; j < m_nOutputs; j++) {
+ FX_DWORD sample =
+ _GetBits32(pSampleData, bitpos.ValueOrDie() + j * m_nBitsPerSample,
+ m_nBitsPerSample);
+ FX_FLOAT encoded = (FX_FLOAT)sample;
+ for (int i = 0; i < m_nInputs; i++) {
+ if (index[i] == m_pEncodeInfo[i].sizes - 1) {
+ if (index[i] == 0) {
+ encoded = encoded_input[i] * (FX_FLOAT)sample;
+ }
+ } else {
+ FX_SAFE_INT32 bitpos2 = blocksize[i];
+ bitpos2 += pos;
+ bitpos2 *= m_nOutputs;
+ bitpos2 += j;
+ bitpos2 *= m_nBitsPerSample;
+ if (!bitpos2.IsValid()) {
+ return FALSE;
+ }
+ FX_DWORD sample1 =
+ _GetBits32(pSampleData, bitpos2.ValueOrDie(), m_nBitsPerSample);
+ encoded += (encoded_input[i] - index[i]) *
+ ((FX_FLOAT)sample1 - (FX_FLOAT)sample);
+ }
+ }
+ results[j] = PDF_Interpolate(encoded, 0, (FX_FLOAT)m_SampleMax,
+ m_pDecodeInfo[j].decode_min,
+ m_pDecodeInfo[j].decode_max);
+ }
+ return TRUE;
+}
+
+class CPDF_PSFunc : public CPDF_Function {
+ public:
+ // CPDF_Function
+ FX_BOOL v_Init(CPDF_Object* pObj) override;
+ FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
+
+ CPDF_PSEngine m_PS;
+};
+
+FX_BOOL CPDF_PSFunc::v_Init(CPDF_Object* pObj) {
+ CPDF_Stream* pStream = pObj->AsStream();
+ CPDF_StreamAcc acc;
+ acc.LoadAllData(pStream, FALSE);
+ return m_PS.Parse((const FX_CHAR*)acc.GetData(), acc.GetSize());
+}
+FX_BOOL CPDF_PSFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const {
+ CPDF_PSEngine& PS = (CPDF_PSEngine&)m_PS;
+ PS.Reset();
+ int i;
+ for (i = 0; i < m_nInputs; i++) {
+ PS.Push(inputs[i]);
+ }
+ PS.Execute();
+ if (PS.GetStackSize() < m_nOutputs) {
+ return FALSE;
+ }
+ for (i = 0; i < m_nOutputs; i++) {
+ results[m_nOutputs - i - 1] = PS.Pop();
+ }
+ return TRUE;
+}
+
+class CPDF_ExpIntFunc : public CPDF_Function {
+ public:
+ CPDF_ExpIntFunc();
+ ~CPDF_ExpIntFunc() override;
+
+ // CPDF_Function
+ FX_BOOL v_Init(CPDF_Object* pObj) override;
+ FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
+
+ FX_FLOAT m_Exponent;
+ FX_FLOAT* m_pBeginValues;
+ FX_FLOAT* m_pEndValues;
+ int m_nOrigOutputs;
+};
+
+CPDF_ExpIntFunc::CPDF_ExpIntFunc() {
+ m_pBeginValues = NULL;
+ m_pEndValues = NULL;
+}
+CPDF_ExpIntFunc::~CPDF_ExpIntFunc() {
+ FX_Free(m_pBeginValues);
+ FX_Free(m_pEndValues);
+}
+FX_BOOL CPDF_ExpIntFunc::v_Init(CPDF_Object* pObj) {
+ CPDF_Dictionary* pDict = pObj->GetDict();
+ if (!pDict) {
+ return FALSE;
+ }
+ CPDF_Array* pArray0 = pDict->GetArrayBy("C0");
+ if (m_nOutputs == 0) {
+ m_nOutputs = 1;
+ if (pArray0) {
+ m_nOutputs = pArray0->GetCount();
+ }
+ }
+ CPDF_Array* pArray1 = pDict->GetArrayBy("C1");
+ m_pBeginValues = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
+ m_pEndValues = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
+ for (int i = 0; i < m_nOutputs; i++) {
+ m_pBeginValues[i] = pArray0 ? pArray0->GetFloatAt(i) : 0.0f;
+ m_pEndValues[i] = pArray1 ? pArray1->GetFloatAt(i) : 1.0f;
+ }
+ m_Exponent = pDict->GetFloatBy("N");
+ m_nOrigOutputs = m_nOutputs;
+ if (m_nOutputs && m_nInputs > INT_MAX / m_nOutputs) {
+ return FALSE;
+ }
+ m_nOutputs *= m_nInputs;
+ return TRUE;
+}
+FX_BOOL CPDF_ExpIntFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const {
+ for (int i = 0; i < m_nInputs; i++)
+ for (int j = 0; j < m_nOrigOutputs; j++) {
+ results[i * m_nOrigOutputs + j] =
+ m_pBeginValues[j] +
+ (FX_FLOAT)FXSYS_pow(inputs[i], m_Exponent) *
+ (m_pEndValues[j] - m_pBeginValues[j]);
+ }
+ return TRUE;
+}
+
+class CPDF_StitchFunc : public CPDF_Function {
+ public:
+ CPDF_StitchFunc();
+ ~CPDF_StitchFunc() override;
+
+ // CPDF_Function
+ FX_BOOL v_Init(CPDF_Object* pObj) override;
+ FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
+
+ std::vector<CPDF_Function*> m_pSubFunctions;
+ FX_FLOAT* m_pBounds;
+ FX_FLOAT* m_pEncode;
+
+ static const int kRequiredNumInputs = 1;
+};
+
+CPDF_StitchFunc::CPDF_StitchFunc() {
+ m_pBounds = NULL;
+ m_pEncode = NULL;
+}
+CPDF_StitchFunc::~CPDF_StitchFunc() {
+ for (auto& sub : m_pSubFunctions) {
+ delete sub;
+ }
+ FX_Free(m_pBounds);
+ FX_Free(m_pEncode);
+}
+FX_BOOL CPDF_StitchFunc::v_Init(CPDF_Object* pObj) {
+ CPDF_Dictionary* pDict = pObj->GetDict();
+ if (!pDict) {
+ return FALSE;
+ }
+ if (m_nInputs != kRequiredNumInputs) {
+ return FALSE;
+ }
+ CPDF_Array* pArray = pDict->GetArrayBy("Functions");
+ if (!pArray) {
+ return FALSE;
+ }
+ FX_DWORD nSubs = pArray->GetCount();
+ if (nSubs == 0) {
+ return FALSE;
+ }
+ m_nOutputs = 0;
+ for (FX_DWORD i = 0; i < nSubs; i++) {
+ CPDF_Object* pSub = pArray->GetElementValue(i);
+ if (pSub == pObj) {
+ return FALSE;
+ }
+ std::unique_ptr<CPDF_Function> pFunc(CPDF_Function::Load(pSub));
+ if (!pFunc) {
+ return FALSE;
+ }
+ // Check that the input dimensionality is 1, and that all output
+ // dimensionalities are the same.
+ if (pFunc->CountInputs() != kRequiredNumInputs) {
+ return FALSE;
+ }
+ if (pFunc->CountOutputs() != m_nOutputs) {
+ if (m_nOutputs)
+ return FALSE;
+
+ m_nOutputs = pFunc->CountOutputs();
+ }
+
+ m_pSubFunctions.push_back(pFunc.release());
+ }
+ m_pBounds = FX_Alloc(FX_FLOAT, nSubs + 1);
+ m_pBounds[0] = m_pDomains[0];
+ pArray = pDict->GetArrayBy("Bounds");
+ if (!pArray) {
+ return FALSE;
+ }
+ for (FX_DWORD i = 0; i < nSubs - 1; i++) {
+ m_pBounds[i + 1] = pArray->GetFloatAt(i);
+ }
+ m_pBounds[nSubs] = m_pDomains[1];
+ m_pEncode = FX_Alloc2D(FX_FLOAT, nSubs, 2);
+ pArray = pDict->GetArrayBy("Encode");
+ if (!pArray) {
+ return FALSE;
+ }
+ for (FX_DWORD i = 0; i < nSubs * 2; i++) {
+ m_pEncode[i] = pArray->GetFloatAt(i);
+ }
+ return TRUE;
+}
+FX_BOOL CPDF_StitchFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* outputs) const {
+ FX_FLOAT input = inputs[0];
+ size_t i;
+ for (i = 0; i < m_pSubFunctions.size() - 1; i++)
+ if (input < m_pBounds[i + 1]) {
+ break;
+ }
+ if (!m_pSubFunctions[i]) {
+ return FALSE;
+ }
+ input = PDF_Interpolate(input, m_pBounds[i], m_pBounds[i + 1],
+ m_pEncode[i * 2], m_pEncode[i * 2 + 1]);
+ int nresults;
+ m_pSubFunctions[i]->Call(&input, kRequiredNumInputs, outputs, nresults);
+ return TRUE;
+}
+
+} // namespace
+
+CPDF_Function* CPDF_Function::Load(CPDF_Object* pFuncObj) {
+ if (!pFuncObj) {
+ return NULL;
+ }
+ CPDF_Function* pFunc = NULL;
+ int type;
+ if (CPDF_Stream* pStream = pFuncObj->AsStream()) {
+ type = pStream->GetDict()->GetIntegerBy("FunctionType");
+ } else if (CPDF_Dictionary* pDict = pFuncObj->AsDictionary()) {
+ type = pDict->GetIntegerBy("FunctionType");
+ } else {
+ return NULL;
+ }
+ if (type == 0) {
+ pFunc = new CPDF_SampledFunc;
+ } else if (type == 2) {
+ pFunc = new CPDF_ExpIntFunc;
+ } else if (type == 3) {
+ pFunc = new CPDF_StitchFunc;
+ } else if (type == 4) {
+ pFunc = new CPDF_PSFunc;
+ } else {
+ return NULL;
+ }
+ if (!pFunc->Init(pFuncObj)) {
+ delete pFunc;
+ return NULL;
+ }
+ return pFunc;
+}
+CPDF_Function::CPDF_Function() {
+ m_pDomains = NULL;
+ m_pRanges = NULL;
+}
+CPDF_Function::~CPDF_Function() {
+ FX_Free(m_pDomains);
+ FX_Free(m_pRanges);
+}
+FX_BOOL CPDF_Function::Init(CPDF_Object* pObj) {
+ CPDF_Stream* pStream = pObj->AsStream();
+ CPDF_Dictionary* pDict = pStream ? pStream->GetDict() : pObj->AsDictionary();
+
+ CPDF_Array* pDomains = pDict->GetArrayBy("Domain");
+ if (!pDomains)
+ return FALSE;
+
+ m_nInputs = pDomains->GetCount() / 2;
+ if (m_nInputs == 0)
+ return FALSE;
+
+ m_pDomains = FX_Alloc2D(FX_FLOAT, m_nInputs, 2);
+ for (int i = 0; i < m_nInputs * 2; i++) {
+ m_pDomains[i] = pDomains->GetFloatAt(i);
+ }
+ CPDF_Array* pRanges = pDict->GetArrayBy("Range");
+ m_nOutputs = 0;
+ if (pRanges) {
+ m_nOutputs = pRanges->GetCount() / 2;
+ m_pRanges = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
+ for (int i = 0; i < m_nOutputs * 2; i++) {
+ m_pRanges[i] = pRanges->GetFloatAt(i);
+ }
+ }
+ FX_DWORD old_outputs = m_nOutputs;
+ if (!v_Init(pObj)) {
+ return FALSE;
+ }
+ if (m_pRanges && m_nOutputs > (int)old_outputs) {
+ m_pRanges = FX_Realloc(FX_FLOAT, m_pRanges, m_nOutputs * 2);
+ if (m_pRanges) {
+ FXSYS_memset(m_pRanges + (old_outputs * 2), 0,
+ sizeof(FX_FLOAT) * (m_nOutputs - old_outputs) * 2);
+ }
+ }
+ return TRUE;
+}
+FX_BOOL CPDF_Function::Call(FX_FLOAT* inputs,
+ int ninputs,
+ FX_FLOAT* results,
+ int& nresults) const {
+ if (m_nInputs != ninputs) {
+ return FALSE;
+ }
+ nresults = m_nOutputs;
+ for (int i = 0; i < m_nInputs; i++) {
+ if (inputs[i] < m_pDomains[i * 2]) {
+ inputs[i] = m_pDomains[i * 2];
+ } else if (inputs[i] > m_pDomains[i * 2 + 1]) {
+ inputs[i] = m_pDomains[i * 2] + 1;
+ }
+ }
+ v_Call(inputs, results);
+ if (m_pRanges) {
+ for (int i = 0; i < m_nOutputs; i++) {
+ if (results[i] < m_pRanges[i * 2]) {
+ results[i] = m_pRanges[i * 2];
+ } else if (results[i] > m_pRanges[i * 2 + 1]) {
+ results[i] = m_pRanges[i * 2 + 1];
+ }
+ }
+ }
+ return TRUE;
+}
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_func_embeddertest.cpp b/core/fpdfapi/fpdf_page/fpdf_page_func_embeddertest.cpp
new file mode 100644
index 0000000000..2892036882
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/fpdf_page_func_embeddertest.cpp
@@ -0,0 +1,20 @@
+// Copyright 2015 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.
+
+#include "testing/embedder_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class FPDFPageFuncEmbeddertest : public EmbedderTest {};
+
+TEST_F(FPDFPageFuncEmbeddertest, Bug_551460) {
+ // Should not crash under ASan.
+ // Tests that the number of inputs is not simply calculated from the domain
+ // and trusted. The number of inputs has to be 1.
+ EXPECT_TRUE(OpenDocument("bug_551460.pdf"));
+ FPDF_PAGE page = LoadPage(0);
+ EXPECT_NE(nullptr, page);
+ FPDF_BITMAP bitmap = RenderPage(page);
+ FPDFBitmap_Destroy(bitmap);
+ UnloadPage(page);
+}
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_graph_state.cpp b/core/fpdfapi/fpdf_page/fpdf_page_graph_state.cpp
new file mode 100644
index 0000000000..76753d2965
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/fpdf_page_graph_state.cpp
@@ -0,0 +1,697 @@
+// Copyright 2014 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/fpdf_page/pageint.h"
+
+#include <algorithm>
+
+#include "core/fpdfapi/fpdf_render/render_int.h"
+#include "core/include/fpdfapi/cpdf_array.h"
+#include "core/include/fpdfapi/cpdf_dictionary.h"
+#include "core/include/fpdfapi/cpdf_document.h"
+#include "core/include/fpdfapi/fpdf_module.h"
+#include "core/include/fpdfapi/fpdf_page.h"
+#include "core/include/fpdfapi/fpdf_pageobj.h"
+#include "core/include/fpdfapi/fpdf_render.h"
+#include "third_party/base/stl_util.h"
+
+namespace {
+
+FX_FLOAT ClipFloat(FX_FLOAT f) {
+ return std::max(0.0f, std::min(1.0f, f));
+}
+
+} // namespace
+
+void CPDF_GraphicStates::DefaultStates() {
+ m_ColorState.New()->Default();
+}
+void CPDF_GraphicStates::CopyStates(const CPDF_GraphicStates& src) {
+ m_ClipPath = src.m_ClipPath;
+ m_GraphState = src.m_GraphState;
+ m_ColorState = src.m_ColorState;
+ m_TextState = src.m_TextState;
+ m_GeneralState = src.m_GeneralState;
+}
+CPDF_ClipPathData::CPDF_ClipPathData() {
+ m_PathCount = 0;
+ m_pPathList = NULL;
+ m_pTypeList = NULL;
+ m_TextCount = 0;
+ m_pTextList = NULL;
+}
+CPDF_ClipPathData::~CPDF_ClipPathData() {
+ int i;
+ delete[] m_pPathList;
+ FX_Free(m_pTypeList);
+ for (i = m_TextCount - 1; i > -1; i--)
+ delete m_pTextList[i];
+ FX_Free(m_pTextList);
+}
+CPDF_ClipPathData::CPDF_ClipPathData(const CPDF_ClipPathData& src) {
+ m_pPathList = NULL;
+ m_pPathList = NULL;
+ m_pTextList = NULL;
+ m_PathCount = src.m_PathCount;
+ if (m_PathCount) {
+ int alloc_size = m_PathCount;
+ if (alloc_size % 8) {
+ alloc_size += 8 - (alloc_size % 8);
+ }
+ m_pPathList = new CPDF_Path[alloc_size];
+ for (int i = 0; i < m_PathCount; i++) {
+ m_pPathList[i] = src.m_pPathList[i];
+ }
+ m_pTypeList = FX_Alloc(uint8_t, alloc_size);
+ FXSYS_memcpy(m_pTypeList, src.m_pTypeList, m_PathCount);
+ } else {
+ m_pPathList = NULL;
+ m_pTypeList = NULL;
+ }
+ m_TextCount = src.m_TextCount;
+ if (m_TextCount) {
+ m_pTextList = FX_Alloc(CPDF_TextObject*, m_TextCount);
+ for (int i = 0; i < m_TextCount; i++) {
+ if (src.m_pTextList[i]) {
+ m_pTextList[i] = src.m_pTextList[i]->Clone();
+ } else {
+ m_pTextList[i] = NULL;
+ }
+ }
+ } else {
+ m_pTextList = NULL;
+ }
+}
+void CPDF_ClipPathData::SetCount(int path_count, int text_count) {
+ ASSERT(m_TextCount == 0 && m_PathCount == 0);
+ if (path_count) {
+ m_PathCount = path_count;
+ int alloc_size = (path_count + 7) / 8 * 8;
+ m_pPathList = new CPDF_Path[alloc_size];
+ m_pTypeList = FX_Alloc(uint8_t, alloc_size);
+ }
+ if (text_count) {
+ m_TextCount = text_count;
+ m_pTextList = FX_Alloc(CPDF_TextObject*, text_count);
+ }
+}
+CFX_FloatRect CPDF_ClipPath::GetClipBox() const {
+ CFX_FloatRect rect;
+ FX_BOOL bStarted = FALSE;
+ int count = GetPathCount();
+ if (count) {
+ rect = GetPath(0).GetBoundingBox();
+ for (int i = 1; i < count; i++) {
+ CFX_FloatRect path_rect = GetPath(i).GetBoundingBox();
+ rect.Intersect(path_rect);
+ }
+ bStarted = TRUE;
+ }
+ count = GetTextCount();
+ if (count) {
+ CFX_FloatRect layer_rect;
+ FX_BOOL bLayerStarted = FALSE;
+ for (int i = 0; i < count; i++) {
+ CPDF_TextObject* pTextObj = GetText(i);
+ if (!pTextObj) {
+ if (!bStarted) {
+ rect = layer_rect;
+ bStarted = TRUE;
+ } else {
+ rect.Intersect(layer_rect);
+ }
+ bLayerStarted = FALSE;
+ } else {
+ if (!bLayerStarted) {
+ layer_rect = CFX_FloatRect(pTextObj->GetBBox(nullptr));
+ bLayerStarted = TRUE;
+ } else {
+ layer_rect.Union(CFX_FloatRect(pTextObj->GetBBox(nullptr)));
+ }
+ }
+ }
+ }
+ return rect;
+}
+void CPDF_ClipPath::AppendPath(CPDF_Path path, int type, FX_BOOL bAutoMerge) {
+ CPDF_ClipPathData* pData = GetModify();
+ if (pData->m_PathCount && bAutoMerge) {
+ CPDF_Path old_path = pData->m_pPathList[pData->m_PathCount - 1];
+ if (old_path.IsRect()) {
+ CFX_FloatRect old_rect(old_path.GetPointX(0), old_path.GetPointY(0),
+ old_path.GetPointX(2), old_path.GetPointY(2));
+ CFX_FloatRect new_rect = path.GetBoundingBox();
+ if (old_rect.Contains(new_rect)) {
+ pData->m_PathCount--;
+ pData->m_pPathList[pData->m_PathCount].SetNull();
+ }
+ }
+ }
+ if (pData->m_PathCount % 8 == 0) {
+ CPDF_Path* pNewPath = new CPDF_Path[pData->m_PathCount + 8];
+ for (int i = 0; i < pData->m_PathCount; i++) {
+ pNewPath[i] = pData->m_pPathList[i];
+ }
+ delete[] pData->m_pPathList;
+ uint8_t* pNewType = FX_Alloc(uint8_t, pData->m_PathCount + 8);
+ FXSYS_memcpy(pNewType, pData->m_pTypeList, pData->m_PathCount);
+ FX_Free(pData->m_pTypeList);
+ pData->m_pPathList = pNewPath;
+ pData->m_pTypeList = pNewType;
+ }
+ pData->m_pPathList[pData->m_PathCount] = path;
+ pData->m_pTypeList[pData->m_PathCount] = (uint8_t)type;
+ pData->m_PathCount++;
+}
+void CPDF_ClipPath::DeletePath(int index) {
+ CPDF_ClipPathData* pData = GetModify();
+ if (index >= pData->m_PathCount) {
+ return;
+ }
+ pData->m_pPathList[index].SetNull();
+ for (int i = index; i < pData->m_PathCount - 1; i++) {
+ pData->m_pPathList[i] = pData->m_pPathList[i + 1];
+ }
+ pData->m_pPathList[pData->m_PathCount - 1].SetNull();
+ FXSYS_memmove(pData->m_pTypeList + index, pData->m_pTypeList + index + 1,
+ pData->m_PathCount - index - 1);
+ pData->m_PathCount--;
+}
+#define FPDF_CLIPPATH_MAX_TEXTS 1024
+void CPDF_ClipPath::AppendTexts(CPDF_TextObject** pTexts, int count) {
+ CPDF_ClipPathData* pData = GetModify();
+ if (pData->m_TextCount + count > FPDF_CLIPPATH_MAX_TEXTS) {
+ for (int i = 0; i < count; i++) {
+ delete pTexts[i];
+ }
+ return;
+ }
+ CPDF_TextObject** pNewList =
+ FX_Alloc(CPDF_TextObject*, pData->m_TextCount + count + 1);
+ if (pData->m_pTextList) {
+ FXSYS_memcpy(pNewList, pData->m_pTextList,
+ pData->m_TextCount * sizeof(CPDF_TextObject*));
+ FX_Free(pData->m_pTextList);
+ }
+ pData->m_pTextList = pNewList;
+ for (int i = 0; i < count; i++) {
+ pData->m_pTextList[pData->m_TextCount + i] = pTexts[i];
+ }
+ pData->m_pTextList[pData->m_TextCount + count] = NULL;
+ pData->m_TextCount += count + 1;
+}
+void CPDF_ClipPath::Transform(const CFX_Matrix& matrix) {
+ CPDF_ClipPathData* pData = GetModify();
+ int i;
+ for (i = 0; i < pData->m_PathCount; i++) {
+ pData->m_pPathList[i].Transform(&matrix);
+ }
+ for (i = 0; i < pData->m_TextCount; i++)
+ if (pData->m_pTextList[i]) {
+ pData->m_pTextList[i]->Transform(matrix);
+ }
+}
+CPDF_ColorStateData::CPDF_ColorStateData(const CPDF_ColorStateData& src) {
+ m_FillColor.Copy(&src.m_FillColor);
+ m_FillRGB = src.m_FillRGB;
+ m_StrokeColor.Copy(&src.m_StrokeColor);
+ m_StrokeRGB = src.m_StrokeRGB;
+}
+void CPDF_ColorStateData::Default() {
+ m_FillRGB = m_StrokeRGB = 0;
+ m_FillColor.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));
+ m_StrokeColor.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));
+}
+void CPDF_ColorState::SetFillColor(CPDF_ColorSpace* pCS,
+ FX_FLOAT* pValue,
+ int nValues) {
+ CPDF_ColorStateData* pData = GetModify();
+ SetColor(pData->m_FillColor, pData->m_FillRGB, pCS, pValue, nValues);
+}
+void CPDF_ColorState::SetStrokeColor(CPDF_ColorSpace* pCS,
+ FX_FLOAT* pValue,
+ int nValues) {
+ CPDF_ColorStateData* pData = GetModify();
+ SetColor(pData->m_StrokeColor, pData->m_StrokeRGB, pCS, pValue, nValues);
+}
+void CPDF_ColorState::SetColor(CPDF_Color& color,
+ FX_DWORD& rgb,
+ CPDF_ColorSpace* pCS,
+ FX_FLOAT* pValue,
+ int nValues) {
+ if (pCS) {
+ color.SetColorSpace(pCS);
+ } else if (color.IsNull()) {
+ color.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));
+ }
+ if (color.m_pCS->CountComponents() > nValues) {
+ return;
+ }
+ color.SetValue(pValue);
+ int R, G, B;
+ rgb = color.GetRGB(R, G, B) ? FXSYS_RGB(R, G, B) : (FX_DWORD)-1;
+}
+void CPDF_ColorState::SetFillPattern(CPDF_Pattern* pPattern,
+ FX_FLOAT* pValue,
+ int nValues) {
+ CPDF_ColorStateData* pData = GetModify();
+ pData->m_FillColor.SetValue(pPattern, pValue, nValues);
+ int R, G, B;
+ FX_BOOL ret = pData->m_FillColor.GetRGB(R, G, B);
+ if (pPattern->m_PatternType == 1 &&
+ ((CPDF_TilingPattern*)pPattern)->m_bColored && !ret) {
+ pData->m_FillRGB = 0x00BFBFBF;
+ return;
+ }
+ pData->m_FillRGB = ret ? FXSYS_RGB(R, G, B) : (FX_DWORD)-1;
+}
+void CPDF_ColorState::SetStrokePattern(CPDF_Pattern* pPattern,
+ FX_FLOAT* pValue,
+ int nValues) {
+ CPDF_ColorStateData* pData = GetModify();
+ pData->m_StrokeColor.SetValue(pPattern, pValue, nValues);
+ int R, G, B;
+ FX_BOOL ret = pData->m_StrokeColor.GetRGB(R, G, B);
+ if (pPattern->m_PatternType == 1 &&
+ ((CPDF_TilingPattern*)pPattern)->m_bColored && !ret) {
+ pData->m_StrokeRGB = 0x00BFBFBF;
+ return;
+ }
+ pData->m_StrokeRGB =
+ pData->m_StrokeColor.GetRGB(R, G, B) ? FXSYS_RGB(R, G, B) : (FX_DWORD)-1;
+}
+CPDF_TextStateData::CPDF_TextStateData() {
+ m_pFont = NULL;
+ m_pDocument = NULL;
+ m_FontSize = 1.0f;
+ m_WordSpace = 0;
+ m_CharSpace = 0;
+ m_TextMode = 0;
+ m_Matrix[0] = m_Matrix[3] = 1.0f;
+ m_Matrix[1] = m_Matrix[2] = 0;
+ m_CTM[0] = m_CTM[3] = 1.0f;
+ m_CTM[1] = m_CTM[2] = 0;
+}
+CPDF_TextStateData::CPDF_TextStateData(const CPDF_TextStateData& src) {
+ if (this == &src) {
+ return;
+ }
+ FXSYS_memcpy(this, &src, sizeof(CPDF_TextStateData));
+ if (m_pDocument && m_pFont) {
+ m_pFont =
+ m_pDocument->GetPageData()->GetFont(m_pFont->GetFontDict(), FALSE);
+ }
+}
+CPDF_TextStateData::~CPDF_TextStateData() {
+ if (m_pDocument && m_pFont) {
+ CPDF_DocPageData* pPageData = m_pDocument->GetPageData();
+ if (pPageData && !pPageData->IsForceClear()) {
+ pPageData->ReleaseFont(m_pFont->GetFontDict());
+ }
+ }
+}
+void CPDF_TextState::SetFont(CPDF_Font* pFont) {
+ CPDF_TextStateData* pStateData = GetModify();
+ if (pStateData) {
+ CPDF_Document* pDoc = pStateData->m_pDocument;
+ CPDF_DocPageData* pPageData = pDoc ? pDoc->GetPageData() : NULL;
+ if (pPageData && pStateData->m_pFont && !pPageData->IsForceClear()) {
+ pPageData->ReleaseFont(pStateData->m_pFont->GetFontDict());
+ }
+ pStateData->m_pDocument = pFont ? pFont->m_pDocument : NULL;
+ pStateData->m_pFont = pFont;
+ }
+}
+FX_FLOAT CPDF_TextState::GetFontSizeV() const {
+ FX_FLOAT* pMatrix = GetMatrix();
+ FX_FLOAT unit = FXSYS_sqrt2(pMatrix[1], pMatrix[3]);
+ FX_FLOAT size = unit * GetFontSize();
+ return (FX_FLOAT)FXSYS_fabs(size);
+}
+FX_FLOAT CPDF_TextState::GetFontSizeH() const {
+ FX_FLOAT* pMatrix = GetMatrix();
+ FX_FLOAT unit = FXSYS_sqrt2(pMatrix[0], pMatrix[2]);
+ FX_FLOAT size = unit * GetFontSize();
+ return (FX_FLOAT)FXSYS_fabs(size);
+}
+FX_FLOAT CPDF_TextState::GetBaselineAngle() const {
+ FX_FLOAT* m_Matrix = GetMatrix();
+ return FXSYS_atan2(m_Matrix[2], m_Matrix[0]);
+}
+FX_FLOAT CPDF_TextState::GetShearAngle() const {
+ FX_FLOAT* m_Matrix = GetMatrix();
+ FX_FLOAT shear_angle = FXSYS_atan2(m_Matrix[1], m_Matrix[3]);
+ return GetBaselineAngle() + shear_angle;
+}
+CPDF_GeneralStateData::CPDF_GeneralStateData() {
+ FXSYS_memset(this, 0, sizeof(CPDF_GeneralStateData));
+ FXSYS_strcpy((FX_CHAR*)m_BlendMode, "Normal");
+ m_StrokeAlpha = 1.0f;
+ m_FillAlpha = 1.0f;
+ m_Flatness = 1.0f;
+ m_Matrix.SetIdentity();
+}
+CPDF_GeneralStateData::CPDF_GeneralStateData(const CPDF_GeneralStateData& src) {
+ FXSYS_memcpy(this, &src, sizeof(CPDF_GeneralStateData));
+ if (src.m_pTransferFunc && src.m_pTransferFunc->m_pPDFDoc) {
+ CPDF_DocRenderData* pDocCache =
+ src.m_pTransferFunc->m_pPDFDoc->GetRenderData();
+ if (!pDocCache) {
+ return;
+ }
+ m_pTransferFunc = pDocCache->GetTransferFunc(m_pTR);
+ }
+}
+CPDF_GeneralStateData::~CPDF_GeneralStateData() {
+ if (m_pTransferFunc && m_pTransferFunc->m_pPDFDoc) {
+ CPDF_DocRenderData* pDocCache = m_pTransferFunc->m_pPDFDoc->GetRenderData();
+ if (!pDocCache) {
+ return;
+ }
+ pDocCache->ReleaseTransferFunc(m_pTR);
+ }
+}
+static int GetBlendType(const CFX_ByteStringC& mode) {
+ switch (mode.GetID()) {
+ case FXBSTR_ID('N', 'o', 'r', 'm'):
+ case FXBSTR_ID('C', 'o', 'm', 'p'):
+ return FXDIB_BLEND_NORMAL;
+ case FXBSTR_ID('M', 'u', 'l', 't'):
+ return FXDIB_BLEND_MULTIPLY;
+ case FXBSTR_ID('S', 'c', 'r', 'e'):
+ return FXDIB_BLEND_SCREEN;
+ case FXBSTR_ID('O', 'v', 'e', 'r'):
+ return FXDIB_BLEND_OVERLAY;
+ case FXBSTR_ID('D', 'a', 'r', 'k'):
+ return FXDIB_BLEND_DARKEN;
+ case FXBSTR_ID('L', 'i', 'g', 'h'):
+ return FXDIB_BLEND_LIGHTEN;
+ case FXBSTR_ID('C', 'o', 'l', 'o'):
+ if (mode.GetLength() == 10) {
+ return FXDIB_BLEND_COLORDODGE;
+ }
+ if (mode.GetLength() == 9) {
+ return FXDIB_BLEND_COLORBURN;
+ }
+ return FXDIB_BLEND_COLOR;
+ case FXBSTR_ID('H', 'a', 'r', 'd'):
+ return FXDIB_BLEND_HARDLIGHT;
+ case FXBSTR_ID('S', 'o', 'f', 't'):
+ return FXDIB_BLEND_SOFTLIGHT;
+ case FXBSTR_ID('D', 'i', 'f', 'f'):
+ return FXDIB_BLEND_DIFFERENCE;
+ case FXBSTR_ID('E', 'x', 'c', 'l'):
+ return FXDIB_BLEND_EXCLUSION;
+ case FXBSTR_ID('H', 'u', 'e', 0):
+ return FXDIB_BLEND_HUE;
+ case FXBSTR_ID('S', 'a', 't', 'u'):
+ return FXDIB_BLEND_SATURATION;
+ case FXBSTR_ID('L', 'u', 'm', 'i'):
+ return FXDIB_BLEND_LUMINOSITY;
+ }
+ return FXDIB_BLEND_NORMAL;
+}
+void CPDF_GeneralStateData::SetBlendMode(const CFX_ByteStringC& blend_mode) {
+ if (blend_mode.GetLength() > 15) {
+ return;
+ }
+ FXSYS_memcpy(m_BlendMode, blend_mode.GetPtr(), blend_mode.GetLength());
+ m_BlendMode[blend_mode.GetLength()] = 0;
+ m_BlendType = ::GetBlendType(blend_mode);
+}
+int RI_StringToId(const CFX_ByteString& ri) {
+ FX_DWORD id = ri.GetID();
+ if (id == FXBSTR_ID('A', 'b', 's', 'o')) {
+ return 1;
+ }
+ if (id == FXBSTR_ID('S', 'a', 't', 'u')) {
+ return 2;
+ }
+ if (id == FXBSTR_ID('P', 'e', 'r', 'c')) {
+ return 3;
+ }
+ return 0;
+}
+void CPDF_GeneralState::SetRenderIntent(const CFX_ByteString& ri) {
+ GetModify()->m_RenderIntent = RI_StringToId(ri);
+}
+CPDF_AllStates::CPDF_AllStates() {
+ m_TextX = m_TextY = m_TextLineX = m_TextLineY = 0;
+ m_TextLeading = 0;
+ m_TextRise = 0;
+ m_TextHorzScale = 1.0f;
+}
+CPDF_AllStates::~CPDF_AllStates() {}
+void CPDF_AllStates::Copy(const CPDF_AllStates& src) {
+ CopyStates(src);
+ m_TextMatrix.Copy(src.m_TextMatrix);
+ m_ParentMatrix.Copy(src.m_ParentMatrix);
+ m_CTM.Copy(src.m_CTM);
+ m_TextX = src.m_TextX;
+ m_TextY = src.m_TextY;
+ m_TextLineX = src.m_TextLineX;
+ m_TextLineY = src.m_TextLineY;
+ m_TextLeading = src.m_TextLeading;
+ m_TextRise = src.m_TextRise;
+ m_TextHorzScale = src.m_TextHorzScale;
+}
+void CPDF_AllStates::SetLineDash(CPDF_Array* pArray,
+ FX_FLOAT phase,
+ FX_FLOAT scale) {
+ CFX_GraphStateData* pData = m_GraphState.GetModify();
+ pData->m_DashPhase = phase * scale;
+ pData->SetDashCount(pArray->GetCount());
+ for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
+ pData->m_DashArray[i] = pArray->GetNumberAt(i) * scale;
+ }
+}
+void CPDF_AllStates::ProcessExtGS(CPDF_Dictionary* pGS,
+ CPDF_StreamContentParser* pParser) {
+ CPDF_GeneralStateData* pGeneralState = m_GeneralState.GetModify();
+ for (const auto& it : *pGS) {
+ const CFX_ByteString& key_str = it.first;
+ CPDF_Object* pElement = it.second;
+ CPDF_Object* pObject = pElement ? pElement->GetDirect() : nullptr;
+ if (!pObject)
+ continue;
+
+ FX_DWORD key = key_str.GetID();
+ switch (key) {
+ case FXBSTR_ID('L', 'W', 0, 0):
+ m_GraphState.GetModify()->m_LineWidth = pObject->GetNumber();
+ break;
+ case FXBSTR_ID('L', 'C', 0, 0):
+ m_GraphState.GetModify()->m_LineCap =
+ (CFX_GraphStateData::LineCap)pObject->GetInteger();
+ break;
+ case FXBSTR_ID('L', 'J', 0, 0):
+ m_GraphState.GetModify()->m_LineJoin =
+ (CFX_GraphStateData::LineJoin)pObject->GetInteger();
+ break;
+ case FXBSTR_ID('M', 'L', 0, 0):
+ m_GraphState.GetModify()->m_MiterLimit = pObject->GetNumber();
+ break;
+ case FXBSTR_ID('D', 0, 0, 0): {
+ CPDF_Array* pDash = pObject->AsArray();
+ if (!pDash)
+ break;
+
+ CPDF_Array* pArray = pDash->GetArrayAt(0);
+ if (!pArray)
+ break;
+
+ SetLineDash(pArray, pDash->GetNumberAt(1), 1.0f);
+ break;
+ }
+ case FXBSTR_ID('R', 'I', 0, 0):
+ m_GeneralState.SetRenderIntent(pObject->GetString());
+ break;
+ case FXBSTR_ID('F', 'o', 'n', 't'): {
+ CPDF_Array* pFont = pObject->AsArray();
+ if (!pFont)
+ break;
+
+ m_TextState.GetModify()->m_FontSize = pFont->GetNumberAt(1);
+ m_TextState.SetFont(pParser->FindFont(pFont->GetStringAt(0)));
+ break;
+ }
+ case FXBSTR_ID('T', 'R', 0, 0):
+ if (pGS->KeyExist("TR2")) {
+ continue;
+ }
+ case FXBSTR_ID('T', 'R', '2', 0):
+ pGeneralState->m_pTR =
+ (pObject && !pObject->IsName()) ? pObject : nullptr;
+ break;
+ case FXBSTR_ID('B', 'M', 0, 0): {
+ CPDF_Array* pArray = pObject->AsArray();
+ CFX_ByteString mode =
+ pArray ? pArray->GetStringAt(0) : pObject->GetString();
+
+ pGeneralState->SetBlendMode(mode);
+ if (pGeneralState->m_BlendType > FXDIB_BLEND_MULTIPLY) {
+ pParser->GetPageObjectHolder()->SetBackgroundAlphaNeeded(TRUE);
+ }
+ break;
+ }
+ case FXBSTR_ID('S', 'M', 'a', 's'):
+ if (ToDictionary(pObject)) {
+ pGeneralState->m_pSoftMask = pObject;
+ FXSYS_memcpy(pGeneralState->m_SMaskMatrix,
+ &pParser->GetCurStates()->m_CTM, sizeof(CFX_Matrix));
+ } else {
+ pGeneralState->m_pSoftMask = NULL;
+ }
+ break;
+ case FXBSTR_ID('C', 'A', 0, 0):
+ pGeneralState->m_StrokeAlpha = ClipFloat(pObject->GetNumber());
+ break;
+ case FXBSTR_ID('c', 'a', 0, 0):
+ pGeneralState->m_FillAlpha = ClipFloat(pObject->GetNumber());
+ break;
+ case FXBSTR_ID('O', 'P', 0, 0):
+ pGeneralState->m_StrokeOP = pObject->GetInteger();
+ if (!pGS->KeyExist("op")) {
+ pGeneralState->m_FillOP = pObject->GetInteger();
+ }
+ break;
+ case FXBSTR_ID('o', 'p', 0, 0):
+ pGeneralState->m_FillOP = pObject->GetInteger();
+ break;
+ case FXBSTR_ID('O', 'P', 'M', 0):
+ pGeneralState->m_OPMode = pObject->GetInteger();
+ break;
+ case FXBSTR_ID('B', 'G', 0, 0):
+ if (pGS->KeyExist("BG2")) {
+ continue;
+ }
+ case FXBSTR_ID('B', 'G', '2', 0):
+ pGeneralState->m_pBG = pObject;
+ break;
+ case FXBSTR_ID('U', 'C', 'R', 0):
+ if (pGS->KeyExist("UCR2")) {
+ continue;
+ }
+ case FXBSTR_ID('U', 'C', 'R', '2'):
+ pGeneralState->m_pUCR = pObject;
+ break;
+ case FXBSTR_ID('H', 'T', 0, 0):
+ pGeneralState->m_pHT = pObject;
+ break;
+ case FXBSTR_ID('F', 'L', 0, 0):
+ pGeneralState->m_Flatness = pObject->GetNumber();
+ break;
+ case FXBSTR_ID('S', 'M', 0, 0):
+ pGeneralState->m_Smoothness = pObject->GetNumber();
+ break;
+ case FXBSTR_ID('S', 'A', 0, 0):
+ pGeneralState->m_StrokeAdjust = pObject->GetInteger();
+ break;
+ case FXBSTR_ID('A', 'I', 'S', 0):
+ pGeneralState->m_AlphaSource = pObject->GetInteger();
+ break;
+ case FXBSTR_ID('T', 'K', 0, 0):
+ pGeneralState->m_TextKnockout = pObject->GetInteger();
+ break;
+ }
+ }
+ pGeneralState->m_Matrix = m_CTM;
+}
+CPDF_ContentMarkItem::CPDF_ContentMarkItem() {
+ m_ParamType = None;
+}
+CPDF_ContentMarkItem::CPDF_ContentMarkItem(const CPDF_ContentMarkItem& src) {
+ m_MarkName = src.m_MarkName;
+ m_ParamType = src.m_ParamType;
+ if (m_ParamType == DirectDict) {
+ m_pParam = ToDictionary(src.m_pParam->Clone());
+ } else {
+ m_pParam = src.m_pParam;
+ }
+}
+CPDF_ContentMarkItem::~CPDF_ContentMarkItem() {
+ if (m_ParamType == DirectDict && m_pParam)
+ m_pParam->Release();
+}
+FX_BOOL CPDF_ContentMarkItem::HasMCID() const {
+ if (m_pParam &&
+ (m_ParamType == DirectDict || m_ParamType == PropertiesDict)) {
+ return m_pParam->KeyExist("MCID");
+ }
+ return FALSE;
+}
+
+CPDF_ContentMarkData::CPDF_ContentMarkData(const CPDF_ContentMarkData& src)
+ : m_Marks(src.m_Marks) {}
+
+int CPDF_ContentMarkData::CountItems() const {
+ return pdfium::CollectionSize<int>(m_Marks);
+}
+
+int CPDF_ContentMarkData::GetMCID() const {
+ for (const auto& mark : m_Marks) {
+ CPDF_ContentMarkItem::ParamType type = mark.GetParamType();
+ if (type == CPDF_ContentMarkItem::PropertiesDict ||
+ type == CPDF_ContentMarkItem::DirectDict) {
+ CPDF_Dictionary* pDict = mark.GetParam();
+ if (pDict->KeyExist("MCID"))
+ return pDict->GetIntegerBy("MCID");
+ }
+ }
+ return -1;
+}
+
+void CPDF_ContentMarkData::AddMark(const CFX_ByteString& name,
+ CPDF_Dictionary* pDict,
+ FX_BOOL bDirect) {
+ CPDF_ContentMarkItem item;
+ item.SetName(name);
+ if (pDict) {
+ if (bDirect) {
+ item.SetParam(CPDF_ContentMarkItem::DirectDict,
+ ToDictionary(pDict->Clone()));
+ } else {
+ item.SetParam(CPDF_ContentMarkItem::PropertiesDict, pDict);
+ }
+ }
+ m_Marks.push_back(item);
+}
+
+void CPDF_ContentMarkData::DeleteLastMark() {
+ if (!m_Marks.empty())
+ m_Marks.pop_back();
+}
+
+FX_BOOL CPDF_ContentMark::HasMark(const CFX_ByteStringC& mark) const {
+ if (!m_pObject) {
+ return FALSE;
+ }
+ for (int i = 0; i < m_pObject->CountItems(); i++) {
+ CPDF_ContentMarkItem& item = m_pObject->GetItem(i);
+ if (item.GetName() == mark) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+FX_BOOL CPDF_ContentMark::LookupMark(const CFX_ByteStringC& mark,
+ CPDF_Dictionary*& pDict) const {
+ if (!m_pObject) {
+ return FALSE;
+ }
+ for (int i = 0; i < m_pObject->CountItems(); i++) {
+ CPDF_ContentMarkItem& item = m_pObject->GetItem(i);
+ if (item.GetName() == mark) {
+ pDict = NULL;
+ if (item.GetParamType() == CPDF_ContentMarkItem::PropertiesDict ||
+ item.GetParamType() == CPDF_ContentMarkItem::DirectDict) {
+ pDict = item.GetParam();
+ }
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_image.cpp b/core/fpdfapi/fpdf_page/fpdf_page_image.cpp
new file mode 100644
index 0000000000..a88d2b30bd
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/fpdf_page_image.cpp
@@ -0,0 +1,100 @@
+// Copyright 2014 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/fpdf_page/pageint.h"
+
+#include "core/include/fpdfapi/cpdf_dictionary.h"
+#include "core/include/fpdfapi/cpdf_document.h"
+#include "core/include/fpdfapi/fpdf_page.h"
+#include "core/include/fpdfapi/fpdf_pageobj.h"
+
+CPDF_ImageObject::CPDF_ImageObject() : m_pImage(nullptr) {}
+
+CPDF_ImageObject::~CPDF_ImageObject() {
+ if (!m_pImage) {
+ return;
+ }
+ if (m_pImage->IsInline() ||
+ (m_pImage->GetStream() && m_pImage->GetStream()->GetObjNum() == 0)) {
+ delete m_pImage;
+ } else {
+ m_pImage->GetDocument()->GetPageData()->ReleaseImage(m_pImage->GetStream());
+ }
+}
+
+CPDF_ImageObject* CPDF_ImageObject::Clone() const {
+ CPDF_ImageObject* obj = new CPDF_ImageObject;
+ obj->CopyData(this);
+
+ obj->m_pImage = m_pImage->Clone();
+ obj->m_Matrix = m_Matrix;
+ return obj;
+}
+
+void CPDF_ImageObject::Transform(const CFX_Matrix& matrix) {
+ m_Matrix.Concat(matrix);
+ CalcBoundingBox();
+}
+void CPDF_ImageObject::CalcBoundingBox() {
+ m_Left = m_Bottom = 0;
+ m_Right = m_Top = 1.0f;
+ m_Matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom);
+}
+void CPDF_Image::Release() {
+ if (m_bInline || (m_pStream && m_pStream->GetObjNum() == 0)) {
+ delete this;
+ }
+}
+CPDF_Image* CPDF_Image::Clone() {
+ if (m_pStream->GetObjNum())
+ return m_pDocument->GetPageData()->GetImage(m_pStream);
+
+ CPDF_Image* pImage = new CPDF_Image(m_pDocument);
+ pImage->LoadImageF(ToStream(m_pStream->Clone()), m_bInline);
+ if (m_bInline)
+ pImage->SetInlineDict(ToDictionary(m_pInlineDict->Clone(TRUE)));
+
+ return pImage;
+}
+CPDF_Image::CPDF_Image(CPDF_Document* pDoc) {
+ m_pDocument = pDoc;
+ m_pStream = NULL;
+ m_pOC = NULL;
+ m_bInline = FALSE;
+ m_pInlineDict = NULL;
+ m_pDIBSource = NULL;
+ m_pMask = NULL;
+ m_MatteColor = 0;
+}
+CPDF_Image::~CPDF_Image() {
+ if (m_bInline) {
+ if (m_pStream) {
+ m_pStream->Release();
+ }
+ if (m_pInlineDict) {
+ m_pInlineDict->Release();
+ }
+ }
+}
+FX_BOOL CPDF_Image::LoadImageF(CPDF_Stream* pStream, FX_BOOL bInline) {
+ m_pStream = pStream;
+ if (m_bInline && m_pInlineDict) {
+ m_pInlineDict->Release();
+ m_pInlineDict = NULL;
+ }
+ m_bInline = bInline;
+ CPDF_Dictionary* pDict = pStream->GetDict();
+ if (m_bInline) {
+ m_pInlineDict = ToDictionary(pDict->Clone());
+ }
+ m_pOC = pDict->GetDictBy("OC");
+ m_bIsMask =
+ !pDict->KeyExist("ColorSpace") || pDict->GetIntegerBy("ImageMask");
+ m_bInterpolate = pDict->GetIntegerBy("Interpolate");
+ m_Height = pDict->GetIntegerBy("Height");
+ m_Width = pDict->GetIntegerBy("Width");
+ return TRUE;
+}
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_parser.cpp b/core/fpdfapi/fpdf_page/fpdf_page_parser.cpp
new file mode 100644
index 0000000000..e4cdaba9d0
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/fpdf_page_parser.cpp
@@ -0,0 +1,1819 @@
+// Copyright 2014 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/fpdf_page/pageint.h"
+
+#include <vector>
+
+#include "core/include/fpdfapi/cpdf_array.h"
+#include "core/include/fpdfapi/cpdf_dictionary.h"
+#include "core/include/fpdfapi/cpdf_document.h"
+#include "core/include/fpdfapi/cpdf_name.h"
+#include "core/include/fpdfapi/cpdf_number.h"
+#include "core/include/fpdfapi/cpdf_reference.h"
+#include "core/include/fpdfapi/fpdf_module.h"
+#include "core/include/fpdfapi/fpdf_page.h"
+#include "core/include/fpdfapi/fpdf_parser_decode.h"
+#include "core/include/fpdfapi/fpdf_serial.h"
+
+namespace {
+
+const char kPathOperatorSubpath = 'm';
+const char kPathOperatorLine = 'l';
+const char kPathOperatorCubicBezier1 = 'c';
+const char kPathOperatorCubicBezier2 = 'v';
+const char kPathOperatorCubicBezier3 = 'y';
+const char kPathOperatorClosePath = 'h';
+const char kPathOperatorRectangle[] = "re";
+
+struct _FX_BSTR {
+ const FX_CHAR* m_Ptr;
+ int m_Size;
+};
+#define _FX_BSTRC(str) \
+ { str, sizeof(str) - 1 }
+
+struct PDF_AbbrPairs {
+ _FX_BSTR full_name;
+ _FX_BSTR abbr;
+};
+
+const PDF_AbbrPairs PDF_InlineKeyAbbr[] = {
+ {_FX_BSTRC("BitsPerComponent"), _FX_BSTRC("BPC")},
+ {_FX_BSTRC("ColorSpace"), _FX_BSTRC("CS")},
+ {_FX_BSTRC("Decode"), _FX_BSTRC("D")},
+ {_FX_BSTRC("DecodeParms"), _FX_BSTRC("DP")},
+ {_FX_BSTRC("Filter"), _FX_BSTRC("F")},
+ {_FX_BSTRC("Height"), _FX_BSTRC("H")},
+ {_FX_BSTRC("ImageMask"), _FX_BSTRC("IM")},
+ {_FX_BSTRC("Interpolate"), _FX_BSTRC("I")},
+ {_FX_BSTRC("Width"), _FX_BSTRC("W")},
+};
+
+const PDF_AbbrPairs PDF_InlineValueAbbr[] = {
+ {_FX_BSTRC("DeviceGray"), _FX_BSTRC("G")},
+ {_FX_BSTRC("DeviceRGB"), _FX_BSTRC("RGB")},
+ {_FX_BSTRC("DeviceCMYK"), _FX_BSTRC("CMYK")},
+ {_FX_BSTRC("Indexed"), _FX_BSTRC("I")},
+ {_FX_BSTRC("ASCIIHexDecode"), _FX_BSTRC("AHx")},
+ {_FX_BSTRC("ASCII85Decode"), _FX_BSTRC("A85")},
+ {_FX_BSTRC("LZWDecode"), _FX_BSTRC("LZW")},
+ {_FX_BSTRC("FlateDecode"), _FX_BSTRC("Fl")},
+ {_FX_BSTRC("RunLengthDecode"), _FX_BSTRC("RL")},
+ {_FX_BSTRC("CCITTFaxDecode"), _FX_BSTRC("CCF")},
+ {_FX_BSTRC("DCTDecode"), _FX_BSTRC("DCT")},
+};
+
+struct AbbrReplacementOp {
+ bool is_replace_key;
+ CFX_ByteString key;
+ CFX_ByteStringC replacement;
+};
+
+class CPDF_StreamParserAutoClearer {
+ public:
+ CPDF_StreamParserAutoClearer(CPDF_StreamParser** scoped_variable,
+ CPDF_StreamParser* new_parser)
+ : scoped_variable_(scoped_variable) {
+ *scoped_variable_ = new_parser;
+ }
+ ~CPDF_StreamParserAutoClearer() { *scoped_variable_ = NULL; }
+
+ private:
+ CPDF_StreamParser** scoped_variable_;
+};
+
+CFX_ByteStringC PDF_FindFullName(const PDF_AbbrPairs* table,
+ size_t count,
+ const CFX_ByteStringC& abbr) {
+ for (size_t i = 0; i < count; ++i) {
+ if (abbr.GetLength() != table[i].abbr.m_Size)
+ continue;
+ if (memcmp(abbr.GetPtr(), table[i].abbr.m_Ptr, abbr.GetLength()))
+ continue;
+ return CFX_ByteStringC(table[i].full_name.m_Ptr, table[i].full_name.m_Size);
+ }
+ return CFX_ByteStringC();
+}
+
+} // namespace
+
+bool IsPathOperator(const uint8_t* buf, size_t len) {
+ if (len == 1) {
+ uint8_t op = buf[0];
+ if (op == kPathOperatorSubpath || op == kPathOperatorLine ||
+ op == kPathOperatorCubicBezier1 || op == kPathOperatorCubicBezier2 ||
+ op == kPathOperatorCubicBezier3) {
+ return true;
+ }
+ } else if (len == 2) {
+ if (buf[0] == kPathOperatorRectangle[0] &&
+ buf[1] == kPathOperatorRectangle[1]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+CPDF_StreamContentParser::CPDF_StreamContentParser(
+ CPDF_Document* pDocument,
+ CPDF_Dictionary* pPageResources,
+ CPDF_Dictionary* pParentResources,
+ CFX_Matrix* pmtContentToUser,
+ CPDF_PageObjectHolder* pObjHolder,
+ CPDF_Dictionary* pResources,
+ CFX_FloatRect* pBBox,
+ CPDF_ParseOptions* pOptions,
+ CPDF_AllStates* pStates,
+ int level)
+ : m_pDocument(pDocument),
+ m_pPageResources(pPageResources),
+ m_pParentResources(pParentResources),
+ m_pResources(pResources),
+ m_pObjectHolder(pObjHolder),
+ m_Level(level),
+ m_ParamStartPos(0),
+ m_ParamCount(0),
+ m_pCurStates(new CPDF_AllStates),
+ m_pLastTextObject(nullptr),
+ m_DefFontSize(0),
+ m_pPathPoints(nullptr),
+ m_PathPointCount(0),
+ m_PathAllocSize(0),
+ m_PathCurrentX(0.0f),
+ m_PathCurrentY(0.0f),
+ m_PathClipType(0),
+ m_pLastImage(nullptr),
+ m_pLastImageDict(nullptr),
+ m_pLastCloneImageDict(nullptr),
+ m_bReleaseLastDict(TRUE),
+ m_bColored(FALSE),
+ m_bResourceMissing(FALSE) {
+ if (pmtContentToUser) {
+ m_mtContentToUser = *pmtContentToUser;
+ }
+ if (pOptions) {
+ m_Options = *pOptions;
+ }
+ if (!m_pResources) {
+ m_pResources = m_pParentResources;
+ }
+ if (!m_pResources) {
+ m_pResources = m_pPageResources;
+ }
+ if (pBBox) {
+ m_BBox = *pBBox;
+ }
+ if (pStates) {
+ m_pCurStates->Copy(*pStates);
+ } else {
+ m_pCurStates->m_GeneralState.New();
+ m_pCurStates->m_GraphState.New();
+ m_pCurStates->m_TextState.New();
+ m_pCurStates->m_ColorState.New();
+ }
+ for (size_t i = 0; i < FX_ArraySize(m_Type3Data); ++i) {
+ m_Type3Data[i] = 0.0;
+ }
+}
+
+CPDF_StreamContentParser::~CPDF_StreamContentParser() {
+ ClearAllParams();
+ FX_Free(m_pPathPoints);
+ if (m_pLastImageDict) {
+ m_pLastImageDict->Release();
+ }
+ if (m_pLastCloneImageDict) {
+ m_pLastCloneImageDict->Release();
+ }
+}
+
+int CPDF_StreamContentParser::GetNextParamPos() {
+ if (m_ParamCount == PARAM_BUF_SIZE) {
+ m_ParamStartPos++;
+ if (m_ParamStartPos == PARAM_BUF_SIZE) {
+ m_ParamStartPos = 0;
+ }
+ if (m_ParamBuf[m_ParamStartPos].m_Type == 0) {
+ if (CPDF_Object* pObject = m_ParamBuf[m_ParamStartPos].m_pObject)
+ pObject->Release();
+ }
+ return m_ParamStartPos;
+ }
+ int index = m_ParamStartPos + m_ParamCount;
+ if (index >= PARAM_BUF_SIZE) {
+ index -= PARAM_BUF_SIZE;
+ }
+ m_ParamCount++;
+ return index;
+}
+
+void CPDF_StreamContentParser::AddNameParam(const FX_CHAR* name, int len) {
+ int index = GetNextParamPos();
+ if (len > 32) {
+ m_ParamBuf[index].m_Type = ContentParam::OBJECT;
+ m_ParamBuf[index].m_pObject =
+ new CPDF_Name(PDF_NameDecode(CFX_ByteStringC(name, len)));
+ } else {
+ m_ParamBuf[index].m_Type = ContentParam::NAME;
+ if (!FXSYS_memchr(name, '#', len)) {
+ FXSYS_memcpy(m_ParamBuf[index].m_Name.m_Buffer, name, len);
+ m_ParamBuf[index].m_Name.m_Len = len;
+ } else {
+ CFX_ByteString str = PDF_NameDecode(CFX_ByteStringC(name, len));
+ FXSYS_memcpy(m_ParamBuf[index].m_Name.m_Buffer, str.c_str(),
+ str.GetLength());
+ m_ParamBuf[index].m_Name.m_Len = str.GetLength();
+ }
+ }
+}
+
+void CPDF_StreamContentParser::AddNumberParam(const FX_CHAR* str, int len) {
+ int index = GetNextParamPos();
+ m_ParamBuf[index].m_Type = ContentParam::NUMBER;
+ FX_atonum(CFX_ByteStringC(str, len), m_ParamBuf[index].m_Number.m_bInteger,
+ &m_ParamBuf[index].m_Number.m_Integer);
+}
+void CPDF_StreamContentParser::AddObjectParam(CPDF_Object* pObj) {
+ int index = GetNextParamPos();
+ m_ParamBuf[index].m_Type = ContentParam::OBJECT;
+ m_ParamBuf[index].m_pObject = pObj;
+}
+void CPDF_StreamContentParser::ClearAllParams() {
+ FX_DWORD index = m_ParamStartPos;
+ for (FX_DWORD i = 0; i < m_ParamCount; i++) {
+ if (m_ParamBuf[index].m_Type == 0) {
+ if (CPDF_Object* pObject = m_ParamBuf[index].m_pObject)
+ pObject->Release();
+ }
+ index++;
+ if (index == PARAM_BUF_SIZE) {
+ index = 0;
+ }
+ }
+ m_ParamStartPos = 0;
+ m_ParamCount = 0;
+}
+
+CPDF_Object* CPDF_StreamContentParser::GetObject(FX_DWORD index) {
+ if (index >= m_ParamCount) {
+ return NULL;
+ }
+ int real_index = m_ParamStartPos + m_ParamCount - index - 1;
+ if (real_index >= PARAM_BUF_SIZE) {
+ real_index -= PARAM_BUF_SIZE;
+ }
+ ContentParam& param = m_ParamBuf[real_index];
+ if (param.m_Type == ContentParam::NUMBER) {
+ CPDF_Number* pNumber = param.m_Number.m_bInteger
+ ? new CPDF_Number(param.m_Number.m_Integer)
+ : new CPDF_Number(param.m_Number.m_Float);
+
+ param.m_Type = ContentParam::OBJECT;
+ param.m_pObject = pNumber;
+ return pNumber;
+ }
+ if (param.m_Type == ContentParam::NAME) {
+ CPDF_Name* pName = new CPDF_Name(
+ CFX_ByteString(param.m_Name.m_Buffer, param.m_Name.m_Len));
+ param.m_Type = ContentParam::OBJECT;
+ param.m_pObject = pName;
+ return pName;
+ }
+ if (param.m_Type == ContentParam::OBJECT) {
+ return param.m_pObject;
+ }
+ ASSERT(FALSE);
+ return NULL;
+}
+
+CFX_ByteString CPDF_StreamContentParser::GetString(FX_DWORD index) {
+ if (index >= m_ParamCount) {
+ return CFX_ByteString();
+ }
+ int real_index = m_ParamStartPos + m_ParamCount - index - 1;
+ if (real_index >= PARAM_BUF_SIZE) {
+ real_index -= PARAM_BUF_SIZE;
+ }
+ ContentParam& param = m_ParamBuf[real_index];
+ if (param.m_Type == ContentParam::NAME) {
+ return CFX_ByteString(param.m_Name.m_Buffer, param.m_Name.m_Len);
+ }
+ if (param.m_Type == 0 && param.m_pObject) {
+ return param.m_pObject->GetString();
+ }
+ return CFX_ByteString();
+}
+
+FX_FLOAT CPDF_StreamContentParser::GetNumber(FX_DWORD index) {
+ if (index >= m_ParamCount) {
+ return 0;
+ }
+ int real_index = m_ParamStartPos + m_ParamCount - index - 1;
+ if (real_index >= PARAM_BUF_SIZE) {
+ real_index -= PARAM_BUF_SIZE;
+ }
+ ContentParam& param = m_ParamBuf[real_index];
+ if (param.m_Type == ContentParam::NUMBER) {
+ return param.m_Number.m_bInteger ? (FX_FLOAT)param.m_Number.m_Integer
+ : param.m_Number.m_Float;
+ }
+ if (param.m_Type == 0 && param.m_pObject) {
+ return param.m_pObject->GetNumber();
+ }
+ return 0;
+}
+
+FX_FLOAT CPDF_StreamContentParser::GetNumber16(FX_DWORD index) {
+ return GetNumber(index);
+}
+
+void CPDF_StreamContentParser::SetGraphicStates(CPDF_PageObject* pObj,
+ FX_BOOL bColor,
+ FX_BOOL bText,
+ FX_BOOL bGraph) {
+ pObj->m_GeneralState = m_pCurStates->m_GeneralState;
+ pObj->m_ClipPath = m_pCurStates->m_ClipPath;
+ pObj->m_ContentMark = m_CurContentMark;
+ if (bColor) {
+ pObj->m_ColorState = m_pCurStates->m_ColorState;
+ }
+ if (bGraph) {
+ pObj->m_GraphState = m_pCurStates->m_GraphState;
+ }
+ if (bText) {
+ pObj->m_TextState = m_pCurStates->m_TextState;
+ }
+}
+
+// static
+CPDF_StreamContentParser::OpCodes
+CPDF_StreamContentParser::InitializeOpCodes() {
+ return OpCodes({
+ {FXBSTR_ID('"', 0, 0, 0),
+ &CPDF_StreamContentParser::Handle_NextLineShowText_Space},
+ {FXBSTR_ID('\'', 0, 0, 0),
+ &CPDF_StreamContentParser::Handle_NextLineShowText},
+ {FXBSTR_ID('B', 0, 0, 0),
+ &CPDF_StreamContentParser::Handle_FillStrokePath},
+ {FXBSTR_ID('B', '*', 0, 0),
+ &CPDF_StreamContentParser::Handle_EOFillStrokePath},
+ {FXBSTR_ID('B', 'D', 'C', 0),
+ &CPDF_StreamContentParser::Handle_BeginMarkedContent_Dictionary},
+ {FXBSTR_ID('B', 'I', 0, 0), &CPDF_StreamContentParser::Handle_BeginImage},
+ {FXBSTR_ID('B', 'M', 'C', 0),
+ &CPDF_StreamContentParser::Handle_BeginMarkedContent},
+ {FXBSTR_ID('B', 'T', 0, 0), &CPDF_StreamContentParser::Handle_BeginText},
+ {FXBSTR_ID('C', 'S', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetColorSpace_Stroke},
+ {FXBSTR_ID('D', 'P', 0, 0),
+ &CPDF_StreamContentParser::Handle_MarkPlace_Dictionary},
+ {FXBSTR_ID('D', 'o', 0, 0),
+ &CPDF_StreamContentParser::Handle_ExecuteXObject},
+ {FXBSTR_ID('E', 'I', 0, 0), &CPDF_StreamContentParser::Handle_EndImage},
+ {FXBSTR_ID('E', 'M', 'C', 0),
+ &CPDF_StreamContentParser::Handle_EndMarkedContent},
+ {FXBSTR_ID('E', 'T', 0, 0), &CPDF_StreamContentParser::Handle_EndText},
+ {FXBSTR_ID('F', 0, 0, 0), &CPDF_StreamContentParser::Handle_FillPathOld},
+ {FXBSTR_ID('G', 0, 0, 0),
+ &CPDF_StreamContentParser::Handle_SetGray_Stroke},
+ {FXBSTR_ID('I', 'D', 0, 0),
+ &CPDF_StreamContentParser::Handle_BeginImageData},
+ {FXBSTR_ID('J', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetLineCap},
+ {FXBSTR_ID('K', 0, 0, 0),
+ &CPDF_StreamContentParser::Handle_SetCMYKColor_Stroke},
+ {FXBSTR_ID('M', 0, 0, 0),
+ &CPDF_StreamContentParser::Handle_SetMiterLimit},
+ {FXBSTR_ID('M', 'P', 0, 0), &CPDF_StreamContentParser::Handle_MarkPlace},
+ {FXBSTR_ID('Q', 0, 0, 0),
+ &CPDF_StreamContentParser::Handle_RestoreGraphState},
+ {FXBSTR_ID('R', 'G', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetRGBColor_Stroke},
+ {FXBSTR_ID('S', 0, 0, 0), &CPDF_StreamContentParser::Handle_StrokePath},
+ {FXBSTR_ID('S', 'C', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetColor_Stroke},
+ {FXBSTR_ID('S', 'C', 'N', 0),
+ &CPDF_StreamContentParser::Handle_SetColorPS_Stroke},
+ {FXBSTR_ID('T', '*', 0, 0),
+ &CPDF_StreamContentParser::Handle_MoveToNextLine},
+ {FXBSTR_ID('T', 'D', 0, 0),
+ &CPDF_StreamContentParser::Handle_MoveTextPoint_SetLeading},
+ {FXBSTR_ID('T', 'J', 0, 0),
+ &CPDF_StreamContentParser::Handle_ShowText_Positioning},
+ {FXBSTR_ID('T', 'L', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetTextLeading},
+ {FXBSTR_ID('T', 'c', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetCharSpace},
+ {FXBSTR_ID('T', 'd', 0, 0),
+ &CPDF_StreamContentParser::Handle_MoveTextPoint},
+ {FXBSTR_ID('T', 'f', 0, 0), &CPDF_StreamContentParser::Handle_SetFont},
+ {FXBSTR_ID('T', 'j', 0, 0), &CPDF_StreamContentParser::Handle_ShowText},
+ {FXBSTR_ID('T', 'm', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetTextMatrix},
+ {FXBSTR_ID('T', 'r', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetTextRenderMode},
+ {FXBSTR_ID('T', 's', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetTextRise},
+ {FXBSTR_ID('T', 'w', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetWordSpace},
+ {FXBSTR_ID('T', 'z', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetHorzScale},
+ {FXBSTR_ID('W', 0, 0, 0), &CPDF_StreamContentParser::Handle_Clip},
+ {FXBSTR_ID('W', '*', 0, 0), &CPDF_StreamContentParser::Handle_EOClip},
+ {FXBSTR_ID('b', 0, 0, 0),
+ &CPDF_StreamContentParser::Handle_CloseFillStrokePath},
+ {FXBSTR_ID('b', '*', 0, 0),
+ &CPDF_StreamContentParser::Handle_CloseEOFillStrokePath},
+ {FXBSTR_ID('c', 0, 0, 0), &CPDF_StreamContentParser::Handle_CurveTo_123},
+ {FXBSTR_ID('c', 'm', 0, 0),
+ &CPDF_StreamContentParser::Handle_ConcatMatrix},
+ {FXBSTR_ID('c', 's', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetColorSpace_Fill},
+ {FXBSTR_ID('d', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetDash},
+ {FXBSTR_ID('d', '0', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetCharWidth},
+ {FXBSTR_ID('d', '1', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetCachedDevice},
+ {FXBSTR_ID('f', 0, 0, 0), &CPDF_StreamContentParser::Handle_FillPath},
+ {FXBSTR_ID('f', '*', 0, 0), &CPDF_StreamContentParser::Handle_EOFillPath},
+ {FXBSTR_ID('g', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetGray_Fill},
+ {FXBSTR_ID('g', 's', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetExtendGraphState},
+ {FXBSTR_ID('h', 0, 0, 0), &CPDF_StreamContentParser::Handle_ClosePath},
+ {FXBSTR_ID('i', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetFlat},
+ {FXBSTR_ID('j', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetLineJoin},
+ {FXBSTR_ID('k', 0, 0, 0),
+ &CPDF_StreamContentParser::Handle_SetCMYKColor_Fill},
+ {FXBSTR_ID('l', 0, 0, 0), &CPDF_StreamContentParser::Handle_LineTo},
+ {FXBSTR_ID('m', 0, 0, 0), &CPDF_StreamContentParser::Handle_MoveTo},
+ {FXBSTR_ID('n', 0, 0, 0), &CPDF_StreamContentParser::Handle_EndPath},
+ {FXBSTR_ID('q', 0, 0, 0),
+ &CPDF_StreamContentParser::Handle_SaveGraphState},
+ {FXBSTR_ID('r', 'e', 0, 0), &CPDF_StreamContentParser::Handle_Rectangle},
+ {FXBSTR_ID('r', 'g', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetRGBColor_Fill},
+ {FXBSTR_ID('r', 'i', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetRenderIntent},
+ {FXBSTR_ID('s', 0, 0, 0),
+ &CPDF_StreamContentParser::Handle_CloseStrokePath},
+ {FXBSTR_ID('s', 'c', 0, 0),
+ &CPDF_StreamContentParser::Handle_SetColor_Fill},
+ {FXBSTR_ID('s', 'c', 'n', 0),
+ &CPDF_StreamContentParser::Handle_SetColorPS_Fill},
+ {FXBSTR_ID('s', 'h', 0, 0), &CPDF_StreamContentParser::Handle_ShadeFill},
+ {FXBSTR_ID('v', 0, 0, 0), &CPDF_StreamContentParser::Handle_CurveTo_23},
+ {FXBSTR_ID('w', 0, 0, 0), &CPDF_StreamContentParser::Handle_SetLineWidth},
+ {FXBSTR_ID('y', 0, 0, 0), &CPDF_StreamContentParser::Handle_CurveTo_13},
+ });
+}
+
+void CPDF_StreamContentParser::OnOperator(const FX_CHAR* op) {
+ int i = 0;
+ FX_DWORD opid = 0;
+ while (i < 4 && op[i]) {
+ opid = (opid << 8) + op[i];
+ i++;
+ }
+ while (i < 4) {
+ opid <<= 8;
+ i++;
+ }
+
+ static const OpCodes s_OpCodes = InitializeOpCodes();
+
+ auto it = s_OpCodes.find(opid);
+ if (it != s_OpCodes.end())
+ (this->*it->second)();
+}
+
+void CPDF_StreamContentParser::Handle_CloseFillStrokePath() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ Handle_ClosePath();
+ AddPathObject(FXFILL_WINDING, TRUE);
+}
+
+void CPDF_StreamContentParser::Handle_FillStrokePath() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ AddPathObject(FXFILL_WINDING, TRUE);
+}
+
+void CPDF_StreamContentParser::Handle_CloseEOFillStrokePath() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ AddPathPoint(m_PathStartX, m_PathStartY, FXPT_LINETO | FXPT_CLOSEFIGURE);
+ AddPathObject(FXFILL_ALTERNATE, TRUE);
+}
+
+void CPDF_StreamContentParser::Handle_EOFillStrokePath() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ AddPathObject(FXFILL_ALTERNATE, TRUE);
+}
+
+void CPDF_StreamContentParser::Handle_BeginMarkedContent_Dictionary() {
+ if (!m_Options.m_bMarkedContent) {
+ return;
+ }
+ CFX_ByteString tag = GetString(1);
+ CPDF_Object* pProperty = GetObject(0);
+ if (!pProperty) {
+ return;
+ }
+ FX_BOOL bDirect = TRUE;
+ if (pProperty->IsName()) {
+ pProperty = FindResourceObj("Properties", pProperty->GetString());
+ if (!pProperty)
+ return;
+ bDirect = FALSE;
+ }
+ if (CPDF_Dictionary* pDict = pProperty->AsDictionary()) {
+ m_CurContentMark.GetModify()->AddMark(tag, pDict, bDirect);
+ }
+}
+
+void CPDF_StreamContentParser::Handle_BeginImage() {
+ FX_FILESIZE savePos = m_pSyntax->GetPos();
+ CPDF_Dictionary* pDict = new CPDF_Dictionary;
+ while (1) {
+ CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement();
+ if (type == CPDF_StreamParser::Keyword) {
+ CFX_ByteString bsKeyword(m_pSyntax->GetWordBuf(),
+ m_pSyntax->GetWordSize());
+ if (bsKeyword != "ID") {
+ m_pSyntax->SetPos(savePos);
+ pDict->Release();
+ return;
+ }
+ }
+ if (type != CPDF_StreamParser::Name) {
+ break;
+ }
+ CFX_ByteString key((const FX_CHAR*)m_pSyntax->GetWordBuf() + 1,
+ m_pSyntax->GetWordSize() - 1);
+ std::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> pObj(
+ m_pSyntax->ReadNextObject());
+ if (!key.IsEmpty()) {
+ FX_DWORD dwObjNum = pObj ? pObj->GetObjNum() : 0;
+ if (dwObjNum)
+ pDict->SetAtReference(key, m_pDocument, dwObjNum);
+ else
+ pDict->SetAt(key, pObj.release());
+ }
+ }
+ PDF_ReplaceAbbr(pDict);
+ CPDF_Object* pCSObj = NULL;
+ if (pDict->KeyExist("ColorSpace")) {
+ pCSObj = pDict->GetElementValue("ColorSpace");
+ if (pCSObj->IsName()) {
+ CFX_ByteString name = pCSObj->GetString();
+ if (name != "DeviceRGB" && name != "DeviceGray" && name != "DeviceCMYK") {
+ pCSObj = FindResourceObj("ColorSpace", name);
+ if (pCSObj && !pCSObj->GetObjNum()) {
+ pCSObj = pCSObj->Clone();
+ pDict->SetAt("ColorSpace", pCSObj);
+ }
+ }
+ }
+ }
+ CPDF_Stream* pStream = m_pSyntax->ReadInlineStream(
+ m_pDocument, pDict, pCSObj, m_Options.m_bDecodeInlineImage);
+ while (1) {
+ CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement();
+ if (type == CPDF_StreamParser::EndOfData) {
+ break;
+ }
+ if (type != CPDF_StreamParser::Keyword) {
+ continue;
+ }
+ if (m_pSyntax->GetWordSize() == 2 && m_pSyntax->GetWordBuf()[0] == 'E' &&
+ m_pSyntax->GetWordBuf()[1] == 'I') {
+ break;
+ }
+ }
+ if (m_Options.m_bTextOnly) {
+ if (pStream) {
+ pStream->Release();
+ } else {
+ pDict->Release();
+ }
+ return;
+ }
+ pDict->SetAtName("Subtype", "Image");
+ CPDF_ImageObject* pImgObj = AddImage(pStream, NULL, TRUE);
+ if (!pImgObj) {
+ if (pStream) {
+ pStream->Release();
+ } else {
+ pDict->Release();
+ }
+ }
+}
+
+void CPDF_StreamContentParser::Handle_BeginMarkedContent() {
+ if (!m_Options.m_bMarkedContent) {
+ return;
+ }
+ CFX_ByteString tag = GetString(0);
+ m_CurContentMark.GetModify()->AddMark(tag, NULL, FALSE);
+}
+
+void CPDF_StreamContentParser::Handle_BeginText() {
+ m_pCurStates->m_TextMatrix.Set(1.0f, 0, 0, 1.0f, 0, 0);
+ OnChangeTextMatrix();
+ m_pCurStates->m_TextX = 0;
+ m_pCurStates->m_TextY = 0;
+ m_pCurStates->m_TextLineX = 0;
+ m_pCurStates->m_TextLineY = 0;
+}
+
+void CPDF_StreamContentParser::Handle_CurveTo_123() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ AddPathPoint(GetNumber(5), GetNumber(4), FXPT_BEZIERTO);
+ AddPathPoint(GetNumber(3), GetNumber(2), FXPT_BEZIERTO);
+ AddPathPoint(GetNumber(1), GetNumber(0), FXPT_BEZIERTO);
+}
+
+void CPDF_StreamContentParser::Handle_ConcatMatrix() {
+ FX_FLOAT a2 = GetNumber16(5), b2 = GetNumber16(4), c2 = GetNumber16(3),
+ d2 = GetNumber16(2);
+ FX_FLOAT e2 = GetNumber(1), f2 = GetNumber(0);
+ CFX_Matrix new_matrix(a2, b2, c2, d2, e2, f2);
+ new_matrix.Concat(m_pCurStates->m_CTM);
+ m_pCurStates->m_CTM = new_matrix;
+ OnChangeTextMatrix();
+}
+
+void CPDF_StreamContentParser::Handle_SetColorSpace_Fill() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ CFX_ByteString csname = GetString(0);
+ CPDF_ColorSpace* pCS = FindColorSpace(csname);
+ if (!pCS) {
+ return;
+ }
+ m_pCurStates->m_ColorState.GetModify()->m_FillColor.SetColorSpace(pCS);
+}
+
+void CPDF_StreamContentParser::Handle_SetColorSpace_Stroke() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ CFX_ByteString csname = GetString(0);
+ CPDF_ColorSpace* pCS = FindColorSpace(csname);
+ if (!pCS) {
+ return;
+ }
+ m_pCurStates->m_ColorState.GetModify()->m_StrokeColor.SetColorSpace(pCS);
+}
+
+void CPDF_StreamContentParser::Handle_SetDash() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ CPDF_Array* pArray = GetObject(1) ? GetObject(1)->GetArray() : NULL;
+ if (!pArray) {
+ return;
+ }
+ m_pCurStates->SetLineDash(pArray, GetNumber(0), 1.0f);
+}
+
+void CPDF_StreamContentParser::Handle_SetCharWidth() {
+ m_Type3Data[0] = GetNumber(1);
+ m_Type3Data[1] = GetNumber(0);
+ m_bColored = TRUE;
+}
+
+void CPDF_StreamContentParser::Handle_SetCachedDevice() {
+ for (int i = 0; i < 6; i++) {
+ m_Type3Data[i] = GetNumber(5 - i);
+ }
+ m_bColored = FALSE;
+}
+
+void CPDF_StreamContentParser::Handle_ExecuteXObject() {
+ CFX_ByteString name = GetString(0);
+ if (name == m_LastImageName && m_pLastImage && m_pLastImage->GetStream() &&
+ m_pLastImage->GetStream()->GetObjNum()) {
+ AddImage(nullptr, m_pLastImage, FALSE);
+ return;
+ }
+
+ if (m_Options.m_bTextOnly) {
+ if (!m_pResources)
+ return;
+
+ CPDF_Dictionary* pList = m_pResources->GetDictBy("XObject");
+ if (!pList && m_pPageResources && m_pResources != m_pPageResources)
+ pList = m_pPageResources->GetDictBy("XObject");
+ if (!pList)
+ return;
+ CPDF_Reference* pRes = ToReference(pList->GetElement(name));
+ if (!pRes)
+ return;
+
+ FX_BOOL bForm;
+ if (m_pDocument->IsFormStream(pRes->GetRefObjNum(), bForm) && !bForm)
+ return;
+ }
+
+ CPDF_Stream* pXObject = ToStream(FindResourceObj("XObject", name));
+ if (!pXObject) {
+ m_bResourceMissing = TRUE;
+ return;
+ }
+
+ CFX_ByteStringC type = pXObject->GetDict()
+ ? pXObject->GetDict()->GetConstStringBy("Subtype")
+ : CFX_ByteStringC();
+ if (type == "Image") {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ CPDF_ImageObject* pObj = AddImage(pXObject, NULL, FALSE);
+ m_LastImageName = name;
+ m_pLastImage = pObj->m_pImage;
+ if (!m_pObjectHolder->HasImageMask())
+ m_pObjectHolder->SetHasImageMask(m_pLastImage->IsMask());
+ } else if (type == "Form") {
+ AddForm(pXObject);
+ } else {
+ return;
+ }
+}
+
+void CPDF_StreamContentParser::AddForm(CPDF_Stream* pStream) {
+ if (!m_Options.m_bSeparateForm) {
+ CPDF_Dictionary* pResources = pStream->GetDict()->GetDictBy("Resources");
+ CFX_Matrix form_matrix = pStream->GetDict()->GetMatrixBy("Matrix");
+ form_matrix.Concat(m_pCurStates->m_CTM);
+ CPDF_Array* pBBox = pStream->GetDict()->GetArrayBy("BBox");
+ CFX_FloatRect form_bbox;
+ CPDF_Path ClipPath;
+ if (pBBox) {
+ form_bbox = pStream->GetDict()->GetRectBy("BBox");
+ ClipPath.New();
+ ClipPath.AppendRect(form_bbox.left, form_bbox.bottom, form_bbox.right,
+ form_bbox.top);
+ ClipPath.Transform(&form_matrix);
+ form_bbox.Transform(&form_matrix);
+ }
+ CPDF_StreamContentParser parser(m_pDocument, m_pPageResources, m_pResources,
+ &m_mtContentToUser, m_pObjectHolder,
+ pResources, &form_bbox, &m_Options,
+ m_pCurStates.get(), m_Level + 1);
+ parser.m_pCurStates->m_CTM = form_matrix;
+ if (ClipPath.NotNull()) {
+ parser.m_pCurStates->m_ClipPath.AppendPath(ClipPath, FXFILL_WINDING,
+ TRUE);
+ }
+ CPDF_StreamAcc stream;
+ stream.LoadAllData(pStream, FALSE);
+ if (stream.GetSize() == 0) {
+ return;
+ }
+ parser.Parse(stream.GetData(), stream.GetSize(), 0);
+ return;
+ }
+ std::unique_ptr<CPDF_FormObject> pFormObj(new CPDF_FormObject);
+ pFormObj->m_pForm =
+ new CPDF_Form(m_pDocument, m_pPageResources, pStream, m_pResources);
+ pFormObj->m_FormMatrix = m_pCurStates->m_CTM;
+ pFormObj->m_FormMatrix.Concat(m_mtContentToUser);
+ CPDF_AllStates status;
+ status.m_GeneralState = m_pCurStates->m_GeneralState;
+ status.m_GraphState = m_pCurStates->m_GraphState;
+ status.m_ColorState = m_pCurStates->m_ColorState;
+ status.m_TextState = m_pCurStates->m_TextState;
+ pFormObj->m_pForm->ParseContent(&status, NULL, NULL, &m_Options, m_Level + 1);
+ if (!m_pObjectHolder->BackgroundAlphaNeeded() &&
+ pFormObj->m_pForm->BackgroundAlphaNeeded()) {
+ m_pObjectHolder->SetBackgroundAlphaNeeded(TRUE);
+ }
+ pFormObj->CalcBoundingBox();
+ SetGraphicStates(pFormObj.get(), TRUE, TRUE, TRUE);
+ m_pObjectHolder->GetPageObjectList()->push_back(std::move(pFormObj));
+}
+
+CPDF_ImageObject* CPDF_StreamContentParser::AddImage(CPDF_Stream* pStream,
+ CPDF_Image* pImage,
+ FX_BOOL bInline) {
+ if (!pStream && !pImage) {
+ return NULL;
+ }
+ CFX_Matrix ImageMatrix;
+ ImageMatrix.Copy(m_pCurStates->m_CTM);
+ ImageMatrix.Concat(m_mtContentToUser);
+
+ std::unique_ptr<CPDF_ImageObject> pImageObj(new CPDF_ImageObject);
+ if (pImage) {
+ pImageObj->m_pImage =
+ m_pDocument->GetPageData()->GetImage(pImage->GetStream());
+ } else if (pStream->GetObjNum()) {
+ pImageObj->m_pImage = m_pDocument->LoadImageF(pStream);
+ } else {
+ pImageObj->m_pImage = new CPDF_Image(m_pDocument);
+ pImageObj->m_pImage->LoadImageF(pStream, bInline);
+ }
+ SetGraphicStates(pImageObj.get(), pImageObj->m_pImage->IsMask(), FALSE,
+ FALSE);
+ pImageObj->m_Matrix = ImageMatrix;
+ pImageObj->CalcBoundingBox();
+ CPDF_ImageObject* pRet = pImageObj.get();
+ m_pObjectHolder->GetPageObjectList()->push_back(std::move(pImageObj));
+ return pRet;
+}
+
+void CPDF_StreamContentParser::Handle_MarkPlace_Dictionary() {}
+
+void CPDF_StreamContentParser::Handle_EndImage() {}
+
+void CPDF_StreamContentParser::Handle_EndMarkedContent() {
+ if (!m_Options.m_bMarkedContent) {
+ return;
+ }
+ if (m_CurContentMark.IsNull()) {
+ return;
+ }
+ int count = m_CurContentMark.GetObject()->CountItems();
+ if (count == 1) {
+ m_CurContentMark.SetNull();
+ return;
+ }
+ m_CurContentMark.GetModify()->DeleteLastMark();
+}
+
+void CPDF_StreamContentParser::Handle_EndText() {
+ int count = m_ClipTextList.GetSize();
+ if (count == 0) {
+ return;
+ }
+ if (m_pCurStates->m_TextState.GetObject()->m_TextMode < 4) {
+ for (int i = 0; i < count; i++) {
+ delete m_ClipTextList.GetAt(i);
+ }
+ } else {
+ m_pCurStates->m_ClipPath.AppendTexts(m_ClipTextList.GetData(), count);
+ }
+ m_ClipTextList.RemoveAll();
+}
+
+void CPDF_StreamContentParser::Handle_FillPath() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ AddPathObject(FXFILL_WINDING, FALSE);
+}
+
+void CPDF_StreamContentParser::Handle_FillPathOld() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ AddPathObject(FXFILL_WINDING, FALSE);
+}
+
+void CPDF_StreamContentParser::Handle_EOFillPath() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ AddPathObject(FXFILL_ALTERNATE, FALSE);
+}
+
+void CPDF_StreamContentParser::Handle_SetGray_Fill() {
+ FX_FLOAT value = GetNumber(0);
+ CPDF_ColorSpace* pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
+ m_pCurStates->m_ColorState.SetFillColor(pCS, &value, 1);
+}
+
+void CPDF_StreamContentParser::Handle_SetGray_Stroke() {
+ FX_FLOAT value = GetNumber(0);
+ CPDF_ColorSpace* pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
+ m_pCurStates->m_ColorState.SetStrokeColor(pCS, &value, 1);
+}
+
+void CPDF_StreamContentParser::Handle_SetExtendGraphState() {
+ CFX_ByteString name = GetString(0);
+ CPDF_Dictionary* pGS = ToDictionary(FindResourceObj("ExtGState", name));
+ if (!pGS) {
+ m_bResourceMissing = TRUE;
+ return;
+ }
+ m_pCurStates->ProcessExtGS(pGS, this);
+}
+
+void CPDF_StreamContentParser::Handle_ClosePath() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ if (m_PathPointCount == 0) {
+ return;
+ }
+ if (m_PathStartX != m_PathCurrentX || m_PathStartY != m_PathCurrentY) {
+ AddPathPoint(m_PathStartX, m_PathStartY, FXPT_LINETO | FXPT_CLOSEFIGURE);
+ } else if (m_pPathPoints[m_PathPointCount - 1].m_Flag != FXPT_MOVETO) {
+ m_pPathPoints[m_PathPointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
+ }
+}
+
+void CPDF_StreamContentParser::Handle_SetFlat() {
+ m_pCurStates->m_GeneralState.GetModify()->m_Flatness = GetNumber(0);
+}
+
+void CPDF_StreamContentParser::Handle_BeginImageData() {}
+
+void CPDF_StreamContentParser::Handle_SetLineJoin() {
+ m_pCurStates->m_GraphState.GetModify()->m_LineJoin =
+ (CFX_GraphStateData::LineJoin)GetInteger(0);
+}
+
+void CPDF_StreamContentParser::Handle_SetLineCap() {
+ m_pCurStates->m_GraphState.GetModify()->m_LineCap =
+ (CFX_GraphStateData::LineCap)GetInteger(0);
+}
+
+void CPDF_StreamContentParser::Handle_SetCMYKColor_Fill() {
+ if (m_ParamCount != 4)
+ return;
+
+ FX_FLOAT values[4];
+ for (int i = 0; i < 4; i++) {
+ values[i] = GetNumber(3 - i);
+ }
+ CPDF_ColorSpace* pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
+ m_pCurStates->m_ColorState.SetFillColor(pCS, values, 4);
+}
+
+void CPDF_StreamContentParser::Handle_SetCMYKColor_Stroke() {
+ if (m_ParamCount != 4)
+ return;
+
+ FX_FLOAT values[4];
+ for (int i = 0; i < 4; i++) {
+ values[i] = GetNumber(3 - i);
+ }
+ CPDF_ColorSpace* pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
+ m_pCurStates->m_ColorState.SetStrokeColor(pCS, values, 4);
+}
+
+void CPDF_StreamContentParser::Handle_LineTo() {
+ if (m_ParamCount != 2)
+ return;
+
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ AddPathPoint(GetNumber(1), GetNumber(0), FXPT_LINETO);
+}
+
+void CPDF_StreamContentParser::Handle_MoveTo() {
+ if (m_ParamCount != 2)
+ return;
+
+ if (m_Options.m_bTextOnly) {
+ m_pSyntax->SkipPathObject();
+ return;
+ }
+ AddPathPoint(GetNumber(1), GetNumber(0), FXPT_MOVETO);
+ ParsePathObject();
+}
+
+void CPDF_StreamContentParser::Handle_SetMiterLimit() {
+ m_pCurStates->m_GraphState.GetModify()->m_MiterLimit = GetNumber(0);
+}
+
+void CPDF_StreamContentParser::Handle_MarkPlace() {}
+
+void CPDF_StreamContentParser::Handle_EndPath() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ AddPathObject(0, FALSE);
+}
+
+void CPDF_StreamContentParser::Handle_SaveGraphState() {
+ std::unique_ptr<CPDF_AllStates> pStates(new CPDF_AllStates);
+ pStates->Copy(*m_pCurStates);
+ m_StateStack.push_back(std::move(pStates));
+}
+
+void CPDF_StreamContentParser::Handle_RestoreGraphState() {
+ if (m_StateStack.empty())
+ return;
+ std::unique_ptr<CPDF_AllStates> pStates = std::move(m_StateStack.back());
+ m_StateStack.pop_back();
+ m_pCurStates->Copy(*pStates);
+}
+
+void CPDF_StreamContentParser::Handle_Rectangle() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ FX_FLOAT x = GetNumber(3), y = GetNumber(2);
+ FX_FLOAT w = GetNumber(1), h = GetNumber(0);
+ AddPathRect(x, y, w, h);
+}
+
+void CPDF_StreamContentParser::AddPathRect(FX_FLOAT x,
+ FX_FLOAT y,
+ FX_FLOAT w,
+ FX_FLOAT h) {
+ AddPathPoint(x, y, FXPT_MOVETO);
+ AddPathPoint(x + w, y, FXPT_LINETO);
+ AddPathPoint(x + w, y + h, FXPT_LINETO);
+ AddPathPoint(x, y + h, FXPT_LINETO);
+ AddPathPoint(x, y, FXPT_LINETO | FXPT_CLOSEFIGURE);
+}
+
+void CPDF_StreamContentParser::Handle_SetRGBColor_Fill() {
+ if (m_ParamCount != 3)
+ return;
+
+ FX_FLOAT values[3];
+ for (int i = 0; i < 3; i++) {
+ values[i] = GetNumber(2 - i);
+ }
+ CPDF_ColorSpace* pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
+ m_pCurStates->m_ColorState.SetFillColor(pCS, values, 3);
+}
+
+void CPDF_StreamContentParser::Handle_SetRGBColor_Stroke() {
+ if (m_ParamCount != 3)
+ return;
+
+ FX_FLOAT values[3];
+ for (int i = 0; i < 3; i++) {
+ values[i] = GetNumber(2 - i);
+ }
+ CPDF_ColorSpace* pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
+ m_pCurStates->m_ColorState.SetStrokeColor(pCS, values, 3);
+}
+
+void CPDF_StreamContentParser::Handle_SetRenderIntent() {}
+
+void CPDF_StreamContentParser::Handle_CloseStrokePath() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ Handle_ClosePath();
+ AddPathObject(0, TRUE);
+}
+
+void CPDF_StreamContentParser::Handle_StrokePath() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ AddPathObject(0, TRUE);
+}
+
+void CPDF_StreamContentParser::Handle_SetColor_Fill() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ FX_FLOAT values[4];
+ int nargs = m_ParamCount;
+ if (nargs > 4) {
+ nargs = 4;
+ }
+ for (int i = 0; i < nargs; i++) {
+ values[i] = GetNumber(nargs - i - 1);
+ }
+ m_pCurStates->m_ColorState.SetFillColor(NULL, values, nargs);
+}
+
+void CPDF_StreamContentParser::Handle_SetColor_Stroke() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ FX_FLOAT values[4];
+ int nargs = m_ParamCount;
+ if (nargs > 4) {
+ nargs = 4;
+ }
+ for (int i = 0; i < nargs; i++) {
+ values[i] = GetNumber(nargs - i - 1);
+ }
+ m_pCurStates->m_ColorState.SetStrokeColor(NULL, values, nargs);
+}
+
+void CPDF_StreamContentParser::Handle_SetColorPS_Fill() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ CPDF_Object* pLastParam = GetObject(0);
+ if (!pLastParam) {
+ return;
+ }
+ int nargs = m_ParamCount;
+ int nvalues = nargs;
+ if (pLastParam->IsName()) {
+ nvalues--;
+ }
+ FX_FLOAT* values = NULL;
+ if (nvalues) {
+ values = FX_Alloc(FX_FLOAT, nvalues);
+ for (int i = 0; i < nvalues; i++) {
+ values[i] = GetNumber(nargs - i - 1);
+ }
+ }
+ if (nvalues != nargs) {
+ CPDF_Pattern* pPattern = FindPattern(GetString(0), FALSE);
+ if (pPattern) {
+ m_pCurStates->m_ColorState.SetFillPattern(pPattern, values, nvalues);
+ }
+ } else {
+ m_pCurStates->m_ColorState.SetFillColor(NULL, values, nvalues);
+ }
+ FX_Free(values);
+}
+
+void CPDF_StreamContentParser::Handle_SetColorPS_Stroke() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ CPDF_Object* pLastParam = GetObject(0);
+ if (!pLastParam) {
+ return;
+ }
+ int nargs = m_ParamCount;
+ int nvalues = nargs;
+ if (pLastParam->IsName())
+ nvalues--;
+
+ FX_FLOAT* values = NULL;
+ if (nvalues) {
+ values = FX_Alloc(FX_FLOAT, nvalues);
+ for (int i = 0; i < nvalues; i++) {
+ values[i] = GetNumber(nargs - i - 1);
+ }
+ }
+ if (nvalues != nargs) {
+ CPDF_Pattern* pPattern = FindPattern(GetString(0), FALSE);
+ if (pPattern) {
+ m_pCurStates->m_ColorState.SetStrokePattern(pPattern, values, nvalues);
+ }
+ } else {
+ m_pCurStates->m_ColorState.SetStrokeColor(NULL, values, nvalues);
+ }
+ FX_Free(values);
+}
+
+CFX_FloatRect GetShadingBBox(CPDF_Stream* pStream,
+ ShadingType type,
+ const CFX_Matrix* pMatrix,
+ CPDF_Function** pFuncs,
+ int nFuncs,
+ CPDF_ColorSpace* pCS);
+
+void CPDF_StreamContentParser::Handle_ShadeFill() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ CPDF_Pattern* pPattern = FindPattern(GetString(0), TRUE);
+ if (!pPattern) {
+ return;
+ }
+ if (pPattern->m_PatternType != CPDF_Pattern::SHADING) {
+ return;
+ }
+ CPDF_ShadingPattern* pShading = static_cast<CPDF_ShadingPattern*>(pPattern);
+ if (!pShading->m_bShadingObj) {
+ return;
+ }
+ if (!pShading->Load()) {
+ return;
+ }
+ std::unique_ptr<CPDF_ShadingObject> pObj(new CPDF_ShadingObject);
+ pObj->m_pShading = pShading;
+ SetGraphicStates(pObj.get(), FALSE, FALSE, FALSE);
+ pObj->m_Matrix = m_pCurStates->m_CTM;
+ pObj->m_Matrix.Concat(m_mtContentToUser);
+ CFX_FloatRect bbox;
+ if (!pObj->m_ClipPath.IsNull()) {
+ bbox = pObj->m_ClipPath.GetClipBox();
+ } else {
+ bbox = m_BBox;
+ }
+ if (pShading->IsMeshShading()) {
+ bbox.Intersect(GetShadingBBox(ToStream(pShading->m_pShadingObj),
+ pShading->m_ShadingType, &pObj->m_Matrix,
+ pShading->m_pFunctions, pShading->m_nFuncs,
+ pShading->m_pCS));
+ }
+ pObj->m_Left = bbox.left;
+ pObj->m_Right = bbox.right;
+ pObj->m_Top = bbox.top;
+ pObj->m_Bottom = bbox.bottom;
+ m_pObjectHolder->GetPageObjectList()->push_back(std::move(pObj));
+}
+
+void CPDF_StreamContentParser::Handle_SetCharSpace() {
+ m_pCurStates->m_TextState.GetModify()->m_CharSpace = GetNumber(0);
+}
+
+void CPDF_StreamContentParser::Handle_MoveTextPoint() {
+ m_pCurStates->m_TextLineX += GetNumber(1);
+ m_pCurStates->m_TextLineY += GetNumber(0);
+ m_pCurStates->m_TextX = m_pCurStates->m_TextLineX;
+ m_pCurStates->m_TextY = m_pCurStates->m_TextLineY;
+}
+
+void CPDF_StreamContentParser::Handle_MoveTextPoint_SetLeading() {
+ Handle_MoveTextPoint();
+ m_pCurStates->m_TextLeading = -GetNumber(0);
+}
+
+void CPDF_StreamContentParser::Handle_SetFont() {
+ FX_FLOAT fs = GetNumber(0);
+ if (fs == 0) {
+ fs = m_DefFontSize;
+ }
+ m_pCurStates->m_TextState.GetModify()->m_FontSize = fs;
+ CPDF_Font* pFont = FindFont(GetString(1));
+ if (pFont) {
+ m_pCurStates->m_TextState.SetFont(pFont);
+ }
+}
+
+CPDF_Object* CPDF_StreamContentParser::FindResourceObj(
+ const CFX_ByteStringC& type,
+ const CFX_ByteString& name) {
+ if (!m_pResources) {
+ return NULL;
+ }
+ if (m_pResources == m_pPageResources) {
+ CPDF_Dictionary* pList = m_pResources->GetDictBy(type);
+ if (!pList) {
+ return NULL;
+ }
+ CPDF_Object* pRes = pList->GetElementValue(name);
+ return pRes;
+ }
+ CPDF_Dictionary* pList = m_pResources->GetDictBy(type);
+ if (!pList) {
+ if (!m_pPageResources) {
+ return NULL;
+ }
+ CPDF_Dictionary* pList = m_pPageResources->GetDictBy(type);
+ if (!pList) {
+ return NULL;
+ }
+ CPDF_Object* pRes = pList->GetElementValue(name);
+ return pRes;
+ }
+ CPDF_Object* pRes = pList->GetElementValue(name);
+ return pRes;
+}
+
+CPDF_Font* CPDF_StreamContentParser::FindFont(const CFX_ByteString& name) {
+ CPDF_Dictionary* pFontDict = ToDictionary(FindResourceObj("Font", name));
+ if (!pFontDict) {
+ m_bResourceMissing = TRUE;
+ return CPDF_Font::GetStockFont(m_pDocument, "Helvetica");
+ }
+
+ CPDF_Font* pFont = m_pDocument->LoadFont(pFontDict);
+ if (pFont && pFont->IsType3Font()) {
+ pFont->AsType3Font()->SetPageResources(m_pResources);
+ pFont->AsType3Font()->CheckType3FontMetrics();
+ }
+ return pFont;
+}
+
+CPDF_ColorSpace* CPDF_StreamContentParser::FindColorSpace(
+ const CFX_ByteString& name) {
+ if (name == "Pattern") {
+ return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
+ }
+ if (name == "DeviceGray" || name == "DeviceCMYK" || name == "DeviceRGB") {
+ CFX_ByteString defname = "Default";
+ defname += name.Mid(7);
+ CPDF_Object* pDefObj = FindResourceObj("ColorSpace", defname);
+ if (!pDefObj) {
+ if (name == "DeviceGray") {
+ return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
+ }
+ if (name == "DeviceRGB") {
+ return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
+ }
+ return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
+ }
+ return m_pDocument->LoadColorSpace(pDefObj);
+ }
+ CPDF_Object* pCSObj = FindResourceObj("ColorSpace", name);
+ if (!pCSObj) {
+ m_bResourceMissing = TRUE;
+ return NULL;
+ }
+ return m_pDocument->LoadColorSpace(pCSObj);
+}
+
+CPDF_Pattern* CPDF_StreamContentParser::FindPattern(const CFX_ByteString& name,
+ FX_BOOL bShading) {
+ CPDF_Object* pPattern =
+ FindResourceObj(bShading ? "Shading" : "Pattern", name);
+ if (!pPattern || (!pPattern->IsDictionary() && !pPattern->IsStream())) {
+ m_bResourceMissing = TRUE;
+ return NULL;
+ }
+ return m_pDocument->LoadPattern(pPattern, bShading,
+ &m_pCurStates->m_ParentMatrix);
+}
+
+void CPDF_StreamContentParser::ConvertTextSpace(FX_FLOAT& x, FX_FLOAT& y) {
+ m_pCurStates->m_TextMatrix.Transform(x, y, x, y);
+ ConvertUserSpace(x, y);
+}
+
+void CPDF_StreamContentParser::ConvertUserSpace(FX_FLOAT& x, FX_FLOAT& y) {
+ m_pCurStates->m_CTM.Transform(x, y, x, y);
+ m_mtContentToUser.Transform(x, y, x, y);
+}
+
+void CPDF_StreamContentParser::AddTextObject(CFX_ByteString* pStrs,
+ FX_FLOAT fInitKerning,
+ FX_FLOAT* pKerning,
+ int nsegs) {
+ CPDF_Font* pFont = m_pCurStates->m_TextState.GetFont();
+ if (!pFont) {
+ return;
+ }
+ if (fInitKerning != 0) {
+ if (!pFont->IsVertWriting()) {
+ m_pCurStates->m_TextX -=
+ (fInitKerning * m_pCurStates->m_TextState.GetFontSize()) / 1000;
+ } else {
+ m_pCurStates->m_TextY -=
+ (fInitKerning * m_pCurStates->m_TextState.GetFontSize()) / 1000;
+ }
+ }
+ if (nsegs == 0) {
+ return;
+ }
+ int textmode;
+ if (pFont->IsType3Font()) {
+ textmode = 0;
+ } else {
+ textmode = m_pCurStates->m_TextState.GetObject()->m_TextMode;
+ }
+ {
+ std::unique_ptr<CPDF_TextObject> pText(new CPDF_TextObject);
+ m_pLastTextObject = pText.get();
+ SetGraphicStates(m_pLastTextObject, TRUE, TRUE, TRUE);
+ if (textmode && textmode != 3 && textmode != 4 && textmode != 7) {
+ FX_FLOAT* pCTM = pText->m_TextState.GetModify()->m_CTM;
+ pCTM[0] = m_pCurStates->m_CTM.a;
+ pCTM[1] = m_pCurStates->m_CTM.c;
+ pCTM[2] = m_pCurStates->m_CTM.b;
+ pCTM[3] = m_pCurStates->m_CTM.d;
+ }
+ pText->SetSegments(pStrs, pKerning, nsegs);
+ pText->m_PosX = m_pCurStates->m_TextX;
+ pText->m_PosY = m_pCurStates->m_TextY + m_pCurStates->m_TextRise;
+ ConvertTextSpace(pText->m_PosX, pText->m_PosY);
+ FX_FLOAT x_advance;
+ FX_FLOAT y_advance;
+ pText->CalcPositionData(&x_advance, &y_advance,
+ m_pCurStates->m_TextHorzScale, m_Level);
+ m_pCurStates->m_TextX += x_advance;
+ m_pCurStates->m_TextY += y_advance;
+ if (textmode > 3)
+ m_ClipTextList.Add(pText->Clone());
+ m_pObjectHolder->GetPageObjectList()->push_back(std::move(pText));
+ }
+ if (pKerning && pKerning[nsegs - 1] != 0) {
+ if (!pFont->IsVertWriting()) {
+ m_pCurStates->m_TextX -=
+ (pKerning[nsegs - 1] * m_pCurStates->m_TextState.GetFontSize()) /
+ 1000;
+ } else {
+ m_pCurStates->m_TextY -=
+ (pKerning[nsegs - 1] * m_pCurStates->m_TextState.GetFontSize()) /
+ 1000;
+ }
+ }
+}
+
+void CPDF_StreamContentParser::Handle_ShowText() {
+ CFX_ByteString str = GetString(0);
+ if (str.IsEmpty()) {
+ return;
+ }
+ AddTextObject(&str, 0, NULL, 1);
+}
+
+void CPDF_StreamContentParser::Handle_ShowText_Positioning() {
+ CPDF_Array* pArray = GetObject(0) ? GetObject(0)->GetArray() : NULL;
+ if (!pArray) {
+ return;
+ }
+ int n = pArray->GetCount();
+ int nsegs = 0;
+ for (int i = 0; i < n; i++) {
+ if (pArray->GetElementValue(i)->IsString())
+ nsegs++;
+ }
+ if (nsegs == 0) {
+ for (int i = 0; i < n; i++) {
+ m_pCurStates->m_TextX -=
+ (pArray->GetNumberAt(i) * m_pCurStates->m_TextState.GetFontSize()) /
+ 1000;
+ }
+ return;
+ }
+ CFX_ByteString* pStrs = new CFX_ByteString[nsegs];
+ FX_FLOAT* pKerning = FX_Alloc(FX_FLOAT, nsegs);
+ int iSegment = 0;
+ FX_FLOAT fInitKerning = 0;
+ for (int i = 0; i < n; i++) {
+ CPDF_Object* pObj = pArray->GetElementValue(i);
+ if (pObj->IsString()) {
+ CFX_ByteString str = pObj->GetString();
+ if (str.IsEmpty()) {
+ continue;
+ }
+ pStrs[iSegment] = str;
+ pKerning[iSegment++] = 0;
+ } else {
+ FX_FLOAT num = pObj ? pObj->GetNumber() : 0;
+ if (iSegment == 0) {
+ fInitKerning += num;
+ } else {
+ pKerning[iSegment - 1] += num;
+ }
+ }
+ }
+ AddTextObject(pStrs, fInitKerning, pKerning, iSegment);
+ delete[] pStrs;
+ FX_Free(pKerning);
+}
+
+void CPDF_StreamContentParser::Handle_SetTextLeading() {
+ m_pCurStates->m_TextLeading = GetNumber(0);
+}
+
+void CPDF_StreamContentParser::Handle_SetTextMatrix() {
+ m_pCurStates->m_TextMatrix.Set(GetNumber16(5), GetNumber16(4), GetNumber16(3),
+ GetNumber16(2), GetNumber(1), GetNumber(0));
+ OnChangeTextMatrix();
+ m_pCurStates->m_TextX = 0;
+ m_pCurStates->m_TextY = 0;
+ m_pCurStates->m_TextLineX = 0;
+ m_pCurStates->m_TextLineY = 0;
+}
+
+void CPDF_StreamContentParser::OnChangeTextMatrix() {
+ CFX_Matrix text_matrix(m_pCurStates->m_TextHorzScale, 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f);
+ text_matrix.Concat(m_pCurStates->m_TextMatrix);
+ text_matrix.Concat(m_pCurStates->m_CTM);
+ text_matrix.Concat(m_mtContentToUser);
+ FX_FLOAT* pTextMatrix = m_pCurStates->m_TextState.GetModify()->m_Matrix;
+ pTextMatrix[0] = text_matrix.a;
+ pTextMatrix[1] = text_matrix.c;
+ pTextMatrix[2] = text_matrix.b;
+ pTextMatrix[3] = text_matrix.d;
+}
+
+void CPDF_StreamContentParser::Handle_SetTextRenderMode() {
+ int mode = GetInteger(0);
+ if (mode < 0 || mode > 7) {
+ return;
+ }
+ m_pCurStates->m_TextState.GetModify()->m_TextMode = mode;
+}
+
+void CPDF_StreamContentParser::Handle_SetTextRise() {
+ m_pCurStates->m_TextRise = GetNumber(0);
+}
+
+void CPDF_StreamContentParser::Handle_SetWordSpace() {
+ m_pCurStates->m_TextState.GetModify()->m_WordSpace = GetNumber(0);
+}
+
+void CPDF_StreamContentParser::Handle_SetHorzScale() {
+ if (m_ParamCount != 1) {
+ return;
+ }
+ m_pCurStates->m_TextHorzScale = GetNumber(0) / 100;
+ OnChangeTextMatrix();
+}
+
+void CPDF_StreamContentParser::Handle_MoveToNextLine() {
+ m_pCurStates->m_TextLineY -= m_pCurStates->m_TextLeading;
+ m_pCurStates->m_TextX = m_pCurStates->m_TextLineX;
+ m_pCurStates->m_TextY = m_pCurStates->m_TextLineY;
+}
+
+void CPDF_StreamContentParser::Handle_CurveTo_23() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ AddPathPoint(m_PathCurrentX, m_PathCurrentY, FXPT_BEZIERTO);
+ AddPathPoint(GetNumber(3), GetNumber(2), FXPT_BEZIERTO);
+ AddPathPoint(GetNumber(1), GetNumber(0), FXPT_BEZIERTO);
+}
+
+void CPDF_StreamContentParser::Handle_SetLineWidth() {
+ FX_FLOAT width = GetNumber(0);
+ m_pCurStates->m_GraphState.GetModify()->m_LineWidth = width;
+}
+
+void CPDF_StreamContentParser::Handle_Clip() {
+ m_PathClipType = FXFILL_WINDING;
+}
+
+void CPDF_StreamContentParser::Handle_EOClip() {
+ m_PathClipType = FXFILL_ALTERNATE;
+}
+
+void CPDF_StreamContentParser::Handle_CurveTo_13() {
+ if (m_Options.m_bTextOnly) {
+ return;
+ }
+ AddPathPoint(GetNumber(3), GetNumber(2), FXPT_BEZIERTO);
+ AddPathPoint(GetNumber(1), GetNumber(0), FXPT_BEZIERTO);
+ AddPathPoint(GetNumber(1), GetNumber(0), FXPT_BEZIERTO);
+}
+
+void CPDF_StreamContentParser::Handle_NextLineShowText() {
+ Handle_MoveToNextLine();
+ Handle_ShowText();
+}
+
+void CPDF_StreamContentParser::Handle_NextLineShowText_Space() {
+ m_pCurStates->m_TextState.GetModify()->m_WordSpace = GetNumber(2);
+ m_pCurStates->m_TextState.GetModify()->m_CharSpace = GetNumber(1);
+ Handle_NextLineShowText();
+}
+
+void CPDF_StreamContentParser::Handle_Invalid() {}
+
+void CPDF_StreamContentParser::AddPathPoint(FX_FLOAT x, FX_FLOAT y, int flag) {
+ m_PathCurrentX = x;
+ m_PathCurrentY = y;
+ if (flag == FXPT_MOVETO) {
+ m_PathStartX = x;
+ m_PathStartY = y;
+ if (m_PathPointCount &&
+ m_pPathPoints[m_PathPointCount - 1].m_Flag == FXPT_MOVETO) {
+ m_pPathPoints[m_PathPointCount - 1].m_PointX = x;
+ m_pPathPoints[m_PathPointCount - 1].m_PointY = y;
+ return;
+ }
+ } else if (m_PathPointCount == 0) {
+ return;
+ }
+ m_PathPointCount++;
+ if (m_PathPointCount > m_PathAllocSize) {
+ int newsize = m_PathPointCount + 256;
+ FX_PATHPOINT* pNewPoints = FX_Alloc(FX_PATHPOINT, newsize);
+ if (m_PathAllocSize) {
+ FXSYS_memcpy(pNewPoints, m_pPathPoints,
+ m_PathAllocSize * sizeof(FX_PATHPOINT));
+ FX_Free(m_pPathPoints);
+ }
+ m_pPathPoints = pNewPoints;
+ m_PathAllocSize = newsize;
+ }
+ m_pPathPoints[m_PathPointCount - 1].m_Flag = flag;
+ m_pPathPoints[m_PathPointCount - 1].m_PointX = x;
+ m_pPathPoints[m_PathPointCount - 1].m_PointY = y;
+}
+
+void CPDF_StreamContentParser::AddPathObject(int FillType, FX_BOOL bStroke) {
+ int PathPointCount = m_PathPointCount, PathClipType = m_PathClipType;
+ m_PathPointCount = 0;
+ m_PathClipType = 0;
+ if (PathPointCount <= 1) {
+ if (PathPointCount && PathClipType) {
+ CPDF_Path path;
+ path.New()->AppendRect(0, 0, 0, 0);
+ m_pCurStates->m_ClipPath.AppendPath(path, FXFILL_WINDING, TRUE);
+ }
+ return;
+ }
+ if (PathPointCount &&
+ m_pPathPoints[PathPointCount - 1].m_Flag == FXPT_MOVETO) {
+ PathPointCount--;
+ }
+ CPDF_Path Path;
+ CFX_PathData* pPathData = Path.New();
+ pPathData->SetPointCount(PathPointCount);
+ FXSYS_memcpy(pPathData->GetPoints(), m_pPathPoints,
+ sizeof(FX_PATHPOINT) * PathPointCount);
+ CFX_Matrix matrix = m_pCurStates->m_CTM;
+ matrix.Concat(m_mtContentToUser);
+ if (bStroke || FillType) {
+ std::unique_ptr<CPDF_PathObject> pPathObj(new CPDF_PathObject);
+ pPathObj->m_bStroke = bStroke;
+ pPathObj->m_FillType = FillType;
+ pPathObj->m_Path = Path;
+ pPathObj->m_Matrix = matrix;
+ SetGraphicStates(pPathObj.get(), TRUE, FALSE, TRUE);
+ pPathObj->CalcBoundingBox();
+ m_pObjectHolder->GetPageObjectList()->push_back(std::move(pPathObj));
+ }
+ if (PathClipType) {
+ if (!matrix.IsIdentity()) {
+ Path.Transform(&matrix);
+ matrix.SetIdentity();
+ }
+ m_pCurStates->m_ClipPath.AppendPath(Path, PathClipType, TRUE);
+ }
+}
+
+FX_DWORD CPDF_StreamContentParser::Parse(const uint8_t* pData,
+ FX_DWORD dwSize,
+ FX_DWORD max_cost) {
+ if (m_Level > _FPDF_MAX_FORM_LEVEL_) {
+ return dwSize;
+ }
+ FX_DWORD InitObjCount = m_pObjectHolder->GetPageObjectList()->size();
+ CPDF_StreamParser syntax(pData, dwSize);
+ CPDF_StreamParserAutoClearer auto_clearer(&m_pSyntax, &syntax);
+ while (1) {
+ FX_DWORD cost = m_pObjectHolder->GetPageObjectList()->size() - InitObjCount;
+ if (max_cost && cost >= max_cost) {
+ break;
+ }
+ switch (syntax.ParseNextElement()) {
+ case CPDF_StreamParser::EndOfData:
+ return m_pSyntax->GetPos();
+ case CPDF_StreamParser::Keyword:
+ OnOperator((char*)syntax.GetWordBuf());
+ ClearAllParams();
+ break;
+ case CPDF_StreamParser::Number:
+ AddNumberParam((char*)syntax.GetWordBuf(), syntax.GetWordSize());
+ break;
+ case CPDF_StreamParser::Name:
+ AddNameParam((const FX_CHAR*)syntax.GetWordBuf() + 1,
+ syntax.GetWordSize() - 1);
+ break;
+ default:
+ AddObjectParam(syntax.GetObject());
+ }
+ }
+ return m_pSyntax->GetPos();
+}
+
+void CPDF_StreamContentParser::ParsePathObject() {
+ FX_FLOAT params[6] = {};
+ int nParams = 0;
+ int last_pos = m_pSyntax->GetPos();
+ while (1) {
+ CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement();
+ FX_BOOL bProcessed = TRUE;
+ switch (type) {
+ case CPDF_StreamParser::EndOfData:
+ return;
+ case CPDF_StreamParser::Keyword: {
+ int len = m_pSyntax->GetWordSize();
+ if (len == 1) {
+ switch (m_pSyntax->GetWordBuf()[0]) {
+ case kPathOperatorSubpath:
+ AddPathPoint(params[0], params[1], FXPT_MOVETO);
+ nParams = 0;
+ break;
+ case kPathOperatorLine:
+ AddPathPoint(params[0], params[1], FXPT_LINETO);
+ nParams = 0;
+ break;
+ case kPathOperatorCubicBezier1:
+ AddPathPoint(params[0], params[1], FXPT_BEZIERTO);
+ AddPathPoint(params[2], params[3], FXPT_BEZIERTO);
+ AddPathPoint(params[4], params[5], FXPT_BEZIERTO);
+ nParams = 0;
+ break;
+ case kPathOperatorCubicBezier2:
+ AddPathPoint(m_PathCurrentX, m_PathCurrentY, FXPT_BEZIERTO);
+ AddPathPoint(params[0], params[1], FXPT_BEZIERTO);
+ AddPathPoint(params[2], params[3], FXPT_BEZIERTO);
+ nParams = 0;
+ break;
+ case kPathOperatorCubicBezier3:
+ AddPathPoint(params[0], params[1], FXPT_BEZIERTO);
+ AddPathPoint(params[2], params[3], FXPT_BEZIERTO);
+ AddPathPoint(params[2], params[3], FXPT_BEZIERTO);
+ nParams = 0;
+ break;
+ case kPathOperatorClosePath:
+ Handle_ClosePath();
+ nParams = 0;
+ break;
+ default:
+ bProcessed = FALSE;
+ break;
+ }
+ } else if (len == 2) {
+ if (m_pSyntax->GetWordBuf()[0] == kPathOperatorRectangle[0] &&
+ m_pSyntax->GetWordBuf()[1] == kPathOperatorRectangle[1]) {
+ AddPathRect(params[0], params[1], params[2], params[3]);
+ nParams = 0;
+ } else {
+ bProcessed = FALSE;
+ }
+ } else {
+ bProcessed = FALSE;
+ }
+ if (bProcessed) {
+ last_pos = m_pSyntax->GetPos();
+ }
+ break;
+ }
+ case CPDF_StreamParser::Number: {
+ if (nParams == 6) {
+ break;
+ }
+ FX_BOOL bInteger;
+ int value;
+ FX_atonum(
+ CFX_ByteStringC(m_pSyntax->GetWordBuf(), m_pSyntax->GetWordSize()),
+ bInteger, &value);
+ params[nParams++] = bInteger ? (FX_FLOAT)value : *(FX_FLOAT*)&value;
+ break;
+ }
+ default:
+ bProcessed = FALSE;
+ }
+ if (!bProcessed) {
+ m_pSyntax->SetPos(last_pos);
+ return;
+ }
+ }
+}
+
+void PDF_ReplaceAbbr(CPDF_Object* pObj) {
+ switch (pObj->GetType()) {
+ case CPDF_Object::DICTIONARY: {
+ CPDF_Dictionary* pDict = pObj->AsDictionary();
+ std::vector<AbbrReplacementOp> replacements;
+ for (const auto& it : *pDict) {
+ CFX_ByteString key = it.first;
+ CPDF_Object* value = it.second;
+ CFX_ByteStringC fullname = PDF_FindFullName(
+ PDF_InlineKeyAbbr, FX_ArraySize(PDF_InlineKeyAbbr), key);
+ if (!fullname.IsEmpty()) {
+ AbbrReplacementOp op;
+ op.is_replace_key = true;
+ op.key = key;
+ op.replacement = fullname;
+ replacements.push_back(op);
+ key = fullname;
+ }
+
+ if (value->IsName()) {
+ CFX_ByteString name = value->GetString();
+ fullname = PDF_FindFullName(PDF_InlineValueAbbr,
+ FX_ArraySize(PDF_InlineValueAbbr), name);
+ if (!fullname.IsEmpty()) {
+ AbbrReplacementOp op;
+ op.is_replace_key = false;
+ op.key = key;
+ op.replacement = fullname;
+ replacements.push_back(op);
+ }
+ } else {
+ PDF_ReplaceAbbr(value);
+ }
+ }
+ for (const auto& op : replacements) {
+ if (op.is_replace_key)
+ pDict->ReplaceKey(op.key, op.replacement);
+ else
+ pDict->SetAtName(op.key, op.replacement);
+ }
+ break;
+ }
+ case CPDF_Object::ARRAY: {
+ CPDF_Array* pArray = pObj->AsArray();
+ for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
+ CPDF_Object* pElement = pArray->GetElement(i);
+ if (pElement->IsName()) {
+ CFX_ByteString name = pElement->GetString();
+ CFX_ByteStringC fullname = PDF_FindFullName(
+ PDF_InlineValueAbbr, FX_ArraySize(PDF_InlineValueAbbr), name);
+ if (!fullname.IsEmpty()) {
+ pArray->SetAt(i, new CPDF_Name(fullname));
+ }
+ } else {
+ PDF_ReplaceAbbr(pElement);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp b/core/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp
new file mode 100644
index 0000000000..13c56b4718
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp
@@ -0,0 +1,888 @@
+// Copyright 2014 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/fpdf_page/pageint.h"
+
+#include <limits.h>
+
+#include "core/fpdfapi/fpdf_parser/fpdf_parser_utility.h"
+#include "core/include/fpdfapi/cpdf_array.h"
+#include "core/include/fpdfapi/cpdf_boolean.h"
+#include "core/include/fpdfapi/cpdf_dictionary.h"
+#include "core/include/fpdfapi/cpdf_document.h"
+#include "core/include/fpdfapi/cpdf_name.h"
+#include "core/include/fpdfapi/cpdf_null.h"
+#include "core/include/fpdfapi/cpdf_number.h"
+#include "core/include/fpdfapi/cpdf_string.h"
+#include "core/include/fpdfapi/fpdf_module.h"
+#include "core/include/fpdfapi/fpdf_page.h"
+#include "core/include/fpdfapi/fpdf_parser_decode.h"
+#include "core/include/fxcodec/fx_codec.h"
+#include "core/include/fxcrt/fx_ext.h"
+#include "core/include/fxcrt/fx_safe_types.h"
+
+CPDF_StreamParser::CPDF_StreamParser(const uint8_t* pData, FX_DWORD dwSize) {
+ m_pBuf = pData;
+ m_Size = dwSize;
+ m_Pos = 0;
+ m_pLastObj = NULL;
+}
+
+CPDF_StreamParser::~CPDF_StreamParser() {
+ if (m_pLastObj) {
+ m_pLastObj->Release();
+ }
+}
+
+FX_DWORD _DecodeAllScanlines(ICodec_ScanlineDecoder* pDecoder,
+ uint8_t*& dest_buf,
+ FX_DWORD& dest_size) {
+ if (!pDecoder) {
+ return (FX_DWORD)-1;
+ }
+ int ncomps = pDecoder->CountComps();
+ int bpc = pDecoder->GetBPC();
+ int width = pDecoder->GetWidth();
+ int height = pDecoder->GetHeight();
+ int pitch = (width * ncomps * bpc + 7) / 8;
+ if (height == 0 || pitch > (1 << 30) / height) {
+ delete pDecoder;
+ return -1;
+ }
+ dest_buf = FX_Alloc2D(uint8_t, pitch, height);
+ dest_size = pitch * height; // Safe since checked alloc returned.
+ for (int row = 0; row < height; row++) {
+ const uint8_t* pLine = pDecoder->GetScanline(row);
+ if (!pLine)
+ break;
+
+ FXSYS_memcpy(dest_buf + row * pitch, pLine, pitch);
+ }
+ FX_DWORD srcoff = pDecoder->GetSrcOffset();
+ delete pDecoder;
+ return srcoff;
+}
+
+ICodec_ScanlineDecoder* FPDFAPI_CreateFaxDecoder(
+ const uint8_t* src_buf,
+ FX_DWORD src_size,
+ int width,
+ int height,
+ const CPDF_Dictionary* pParams);
+
+FX_DWORD PDF_DecodeInlineStream(const uint8_t* src_buf,
+ FX_DWORD limit,
+ int width,
+ int height,
+ CFX_ByteString& decoder,
+ CPDF_Dictionary* pParam,
+ uint8_t*& dest_buf,
+ FX_DWORD& dest_size) {
+ if (decoder == "CCITTFaxDecode" || decoder == "CCF") {
+ ICodec_ScanlineDecoder* pDecoder =
+ FPDFAPI_CreateFaxDecoder(src_buf, limit, width, height, pParam);
+ return _DecodeAllScanlines(pDecoder, dest_buf, dest_size);
+ }
+ if (decoder == "ASCII85Decode" || decoder == "A85") {
+ return A85Decode(src_buf, limit, dest_buf, dest_size);
+ }
+ if (decoder == "ASCIIHexDecode" || decoder == "AHx") {
+ return HexDecode(src_buf, limit, dest_buf, dest_size);
+ }
+ if (decoder == "FlateDecode" || decoder == "Fl") {
+ return FPDFAPI_FlateOrLZWDecode(FALSE, src_buf, limit, pParam, dest_size,
+ dest_buf, dest_size);
+ }
+ if (decoder == "LZWDecode" || decoder == "LZW") {
+ return FPDFAPI_FlateOrLZWDecode(TRUE, src_buf, limit, pParam, 0, dest_buf,
+ dest_size);
+ }
+ if (decoder == "DCTDecode" || decoder == "DCT") {
+ ICodec_ScanlineDecoder* pDecoder =
+ CPDF_ModuleMgr::Get()->GetJpegModule()->CreateDecoder(
+ src_buf, limit, width, height, 0,
+ pParam ? pParam->GetIntegerBy("ColorTransform", 1) : 1);
+ return _DecodeAllScanlines(pDecoder, dest_buf, dest_size);
+ }
+ if (decoder == "RunLengthDecode" || decoder == "RL") {
+ return RunLengthDecode(src_buf, limit, dest_buf, dest_size);
+ }
+ dest_size = 0;
+ dest_buf = 0;
+ return (FX_DWORD)-1;
+}
+
+CPDF_Stream* CPDF_StreamParser::ReadInlineStream(CPDF_Document* pDoc,
+ CPDF_Dictionary* pDict,
+ CPDF_Object* pCSObj,
+ FX_BOOL bDecode) {
+ if (m_Pos == m_Size)
+ return nullptr;
+
+ if (PDFCharIsWhitespace(m_pBuf[m_Pos]))
+ m_Pos++;
+
+ CFX_ByteString Decoder;
+ CPDF_Dictionary* pParam = nullptr;
+ CPDF_Object* pFilter = pDict->GetElementValue("Filter");
+ if (pFilter) {
+ if (CPDF_Array* pArray = pFilter->AsArray()) {
+ Decoder = pArray->GetStringAt(0);
+ CPDF_Array* pParams = pDict->GetArrayBy("DecodeParms");
+ if (pParams)
+ pParam = pParams->GetDictAt(0);
+ } else {
+ Decoder = pFilter->GetString();
+ pParam = pDict->GetDictBy("DecodeParms");
+ }
+ }
+ FX_DWORD width = pDict->GetIntegerBy("Width");
+ FX_DWORD height = pDict->GetIntegerBy("Height");
+ FX_DWORD OrigSize = 0;
+ if (pCSObj) {
+ FX_DWORD bpc = pDict->GetIntegerBy("BitsPerComponent");
+ FX_DWORD nComponents = 1;
+ CPDF_ColorSpace* pCS = pDoc->LoadColorSpace(pCSObj);
+ if (!pCS) {
+ nComponents = 3;
+ } else {
+ nComponents = pCS->CountComponents();
+ pDoc->GetPageData()->ReleaseColorSpace(pCSObj);
+ }
+ FX_DWORD pitch = width;
+ if (bpc && pitch > INT_MAX / bpc) {
+ return NULL;
+ }
+ pitch *= bpc;
+ if (nComponents && pitch > INT_MAX / nComponents) {
+ return NULL;
+ }
+ pitch *= nComponents;
+ if (pitch > INT_MAX - 7) {
+ return NULL;
+ }
+ pitch += 7;
+ pitch /= 8;
+ OrigSize = pitch;
+ } else {
+ if (width > INT_MAX - 7) {
+ return NULL;
+ }
+ OrigSize = ((width + 7) / 8);
+ }
+ if (height && OrigSize > INT_MAX / height) {
+ return NULL;
+ }
+ OrigSize *= height;
+ uint8_t* pData = NULL;
+ FX_DWORD dwStreamSize;
+ if (Decoder.IsEmpty()) {
+ if (OrigSize > m_Size - m_Pos) {
+ OrigSize = m_Size - m_Pos;
+ }
+ pData = FX_Alloc(uint8_t, OrigSize);
+ FXSYS_memcpy(pData, m_pBuf + m_Pos, OrigSize);
+ dwStreamSize = OrigSize;
+ m_Pos += OrigSize;
+ } else {
+ FX_DWORD dwDestSize = OrigSize;
+ dwStreamSize =
+ PDF_DecodeInlineStream(m_pBuf + m_Pos, m_Size - m_Pos, width, height,
+ Decoder, pParam, pData, dwDestSize);
+ if ((int)dwStreamSize < 0) {
+ FX_Free(pData);
+ return NULL;
+ }
+ if (bDecode) {
+ m_Pos += dwStreamSize;
+ dwStreamSize = dwDestSize;
+ if (CPDF_Array* pArray = pFilter->AsArray()) {
+ pArray->RemoveAt(0);
+ CPDF_Array* pParams = pDict->GetArrayBy("DecodeParms");
+ if (pParams)
+ pParams->RemoveAt(0);
+ } else {
+ pDict->RemoveAt("Filter");
+ pDict->RemoveAt("DecodeParms");
+ }
+ } else {
+ FX_Free(pData);
+ FX_DWORD dwSavePos = m_Pos;
+ m_Pos += dwStreamSize;
+ while (1) {
+ FX_DWORD dwPrevPos = m_Pos;
+ CPDF_StreamParser::SyntaxType type = ParseNextElement();
+ if (type == CPDF_StreamParser::EndOfData) {
+ break;
+ }
+ if (type != CPDF_StreamParser::Keyword) {
+ dwStreamSize += m_Pos - dwPrevPos;
+ continue;
+ }
+ if (GetWordSize() == 2 && GetWordBuf()[0] == 'E' &&
+ GetWordBuf()[1] == 'I') {
+ m_Pos = dwPrevPos;
+ break;
+ }
+ dwStreamSize += m_Pos - dwPrevPos;
+ }
+ m_Pos = dwSavePos;
+ pData = FX_Alloc(uint8_t, dwStreamSize);
+ FXSYS_memcpy(pData, m_pBuf + m_Pos, dwStreamSize);
+ m_Pos += dwStreamSize;
+ }
+ }
+ pDict->SetAtInteger("Length", (int)dwStreamSize);
+ return new CPDF_Stream(pData, dwStreamSize, pDict);
+}
+
+#define MAX_WORD_BUFFER 256
+#define MAX_STRING_LENGTH 32767
+#define FXDWORD_TRUE FXDWORD_FROM_LSBFIRST(0x65757274)
+#define FXDWORD_NULL FXDWORD_FROM_LSBFIRST(0x6c6c756e)
+#define FXDWORD_FALS FXDWORD_FROM_LSBFIRST(0x736c6166)
+CPDF_StreamParser::SyntaxType CPDF_StreamParser::ParseNextElement() {
+ if (m_pLastObj) {
+ m_pLastObj->Release();
+ m_pLastObj = nullptr;
+ }
+
+ m_WordSize = 0;
+ FX_BOOL bIsNumber = TRUE;
+ if (!PositionIsInBounds())
+ return EndOfData;
+
+ int ch = m_pBuf[m_Pos++];
+ while (1) {
+ while (PDFCharIsWhitespace(ch)) {
+ if (!PositionIsInBounds())
+ return EndOfData;
+
+ ch = m_pBuf[m_Pos++];
+ }
+
+ if (ch != '%')
+ break;
+
+ while (1) {
+ if (!PositionIsInBounds())
+ return EndOfData;
+
+ ch = m_pBuf[m_Pos++];
+ if (PDFCharIsLineEnding(ch))
+ break;
+ }
+ }
+
+ if (PDFCharIsDelimiter(ch) && ch != '/') {
+ m_Pos--;
+ m_pLastObj = ReadNextObject();
+ return Others;
+ }
+
+ while (1) {
+ if (m_WordSize < MAX_WORD_BUFFER)
+ m_WordBuffer[m_WordSize++] = ch;
+
+ if (!PDFCharIsNumeric(ch))
+ bIsNumber = FALSE;
+
+ if (!PositionIsInBounds())
+ break;
+
+ ch = m_pBuf[m_Pos++];
+
+ if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) {
+ m_Pos--;
+ break;
+ }
+ }
+
+ m_WordBuffer[m_WordSize] = 0;
+ if (bIsNumber)
+ return Number;
+ if (m_WordBuffer[0] == '/')
+ return Name;
+
+ if (m_WordSize == 4) {
+ if (*(FX_DWORD*)m_WordBuffer == FXDWORD_TRUE) {
+ m_pLastObj = new CPDF_Boolean(TRUE);
+ return Others;
+ }
+ if (*(FX_DWORD*)m_WordBuffer == FXDWORD_NULL) {
+ m_pLastObj = new CPDF_Null;
+ return Others;
+ }
+ } else if (m_WordSize == 5) {
+ if (*(FX_DWORD*)m_WordBuffer == FXDWORD_FALS && m_WordBuffer[4] == 'e') {
+ m_pLastObj = new CPDF_Boolean(FALSE);
+ return Others;
+ }
+ }
+ return Keyword;
+}
+
+void CPDF_StreamParser::SkipPathObject() {
+ FX_DWORD command_startpos = m_Pos;
+ if (!PositionIsInBounds())
+ return;
+
+ int ch = m_pBuf[m_Pos++];
+ while (1) {
+ while (PDFCharIsWhitespace(ch)) {
+ if (!PositionIsInBounds())
+ return;
+ ch = m_pBuf[m_Pos++];
+ }
+
+ if (!PDFCharIsNumeric(ch)) {
+ m_Pos = command_startpos;
+ return;
+ }
+
+ while (1) {
+ while (!PDFCharIsWhitespace(ch)) {
+ if (!PositionIsInBounds())
+ return;
+ ch = m_pBuf[m_Pos++];
+ }
+
+ while (PDFCharIsWhitespace(ch)) {
+ if (!PositionIsInBounds())
+ return;
+ ch = m_pBuf[m_Pos++];
+ }
+
+ if (PDFCharIsNumeric(ch))
+ continue;
+
+ FX_DWORD op_startpos = m_Pos - 1;
+ while (!PDFCharIsWhitespace(ch) && !PDFCharIsDelimiter(ch)) {
+ if (!PositionIsInBounds())
+ return;
+ ch = m_pBuf[m_Pos++];
+ }
+
+ if (IsPathOperator(&m_pBuf[op_startpos], m_Pos - 1 - op_startpos)) {
+ command_startpos = m_Pos;
+ break;
+ }
+ m_Pos = command_startpos;
+ return;
+ }
+ }
+}
+
+CPDF_Object* CPDF_StreamParser::ReadNextObject(FX_BOOL bAllowNestedArray,
+ FX_BOOL bInArray) {
+ FX_BOOL bIsNumber;
+ GetNextWord(bIsNumber);
+ if (m_WordSize == 0) {
+ return NULL;
+ }
+ if (bIsNumber) {
+ m_WordBuffer[m_WordSize] = 0;
+ return new CPDF_Number(CFX_ByteStringC(m_WordBuffer, m_WordSize));
+ }
+ int first_char = m_WordBuffer[0];
+ if (first_char == '/') {
+ return new CPDF_Name(
+ PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)));
+ }
+ if (first_char == '(') {
+ return new CPDF_String(ReadString(), FALSE);
+ }
+ if (first_char == '<') {
+ if (m_WordSize == 1) {
+ return new CPDF_String(ReadHexString(), TRUE);
+ }
+ CPDF_Dictionary* pDict = new CPDF_Dictionary;
+ while (1) {
+ GetNextWord(bIsNumber);
+ if (m_WordSize == 0) {
+ pDict->Release();
+ return nullptr;
+ }
+ if (m_WordSize == 2 && m_WordBuffer[0] == '>') {
+ break;
+ }
+ if (m_WordBuffer[0] != '/') {
+ pDict->Release();
+ return nullptr;
+ }
+ CFX_ByteString key =
+ PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1));
+ CPDF_Object* pObj = ReadNextObject(TRUE);
+ if (!pObj) {
+ pDict->Release();
+ return nullptr;
+ }
+ if (!key.IsEmpty()) {
+ pDict->SetAt(key, pObj);
+ } else {
+ pObj->Release();
+ }
+ }
+ return pDict;
+ }
+ if (first_char == '[') {
+ if (!bAllowNestedArray && bInArray) {
+ return NULL;
+ }
+ CPDF_Array* pArray = new CPDF_Array;
+ while (1) {
+ CPDF_Object* pObj = ReadNextObject(bAllowNestedArray, TRUE);
+ if (pObj) {
+ pArray->Add(pObj);
+ continue;
+ }
+
+ if (m_WordSize == 0 || m_WordBuffer[0] == ']')
+ break;
+ }
+ return pArray;
+ }
+ if (m_WordSize == 4) {
+ if (*(FX_DWORD*)m_WordBuffer == FXDWORD_TRUE) {
+ return new CPDF_Boolean(TRUE);
+ }
+ if (*(FX_DWORD*)m_WordBuffer == FXDWORD_NULL) {
+ return new CPDF_Null;
+ }
+ } else if (m_WordSize == 5) {
+ if (*(FX_DWORD*)m_WordBuffer == FXDWORD_FALS && m_WordBuffer[4] == 'e') {
+ return new CPDF_Boolean(FALSE);
+ }
+ }
+ return NULL;
+}
+
+void CPDF_StreamParser::GetNextWord(FX_BOOL& bIsNumber) {
+ m_WordSize = 0;
+ bIsNumber = TRUE;
+ if (!PositionIsInBounds())
+ return;
+
+ int ch = m_pBuf[m_Pos++];
+ while (1) {
+ while (PDFCharIsWhitespace(ch)) {
+ if (!PositionIsInBounds()) {
+ return;
+ }
+ ch = m_pBuf[m_Pos++];
+ }
+
+ if (ch != '%')
+ break;
+
+ while (1) {
+ if (!PositionIsInBounds())
+ return;
+ ch = m_pBuf[m_Pos++];
+ if (PDFCharIsLineEnding(ch))
+ break;
+ }
+ }
+
+ if (PDFCharIsDelimiter(ch)) {
+ bIsNumber = FALSE;
+ m_WordBuffer[m_WordSize++] = ch;
+ if (ch == '/') {
+ while (1) {
+ if (!PositionIsInBounds())
+ return;
+ ch = m_pBuf[m_Pos++];
+ if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) {
+ m_Pos--;
+ return;
+ }
+
+ if (m_WordSize < MAX_WORD_BUFFER)
+ m_WordBuffer[m_WordSize++] = ch;
+ }
+ } else if (ch == '<') {
+ if (!PositionIsInBounds())
+ return;
+ ch = m_pBuf[m_Pos++];
+ if (ch == '<')
+ m_WordBuffer[m_WordSize++] = ch;
+ else
+ m_Pos--;
+ } else if (ch == '>') {
+ if (!PositionIsInBounds())
+ return;
+ ch = m_pBuf[m_Pos++];
+ if (ch == '>')
+ m_WordBuffer[m_WordSize++] = ch;
+ else
+ m_Pos--;
+ }
+ return;
+ }
+
+ while (1) {
+ if (m_WordSize < MAX_WORD_BUFFER)
+ m_WordBuffer[m_WordSize++] = ch;
+ if (!PDFCharIsNumeric(ch))
+ bIsNumber = FALSE;
+
+ if (!PositionIsInBounds())
+ return;
+ ch = m_pBuf[m_Pos++];
+ if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) {
+ m_Pos--;
+ break;
+ }
+ }
+}
+
+CFX_ByteString CPDF_StreamParser::ReadString() {
+ if (!PositionIsInBounds())
+ return CFX_ByteString();
+
+ uint8_t ch = m_pBuf[m_Pos++];
+ CFX_ByteTextBuf buf;
+ int parlevel = 0;
+ int status = 0;
+ int iEscCode = 0;
+ while (1) {
+ switch (status) {
+ case 0:
+ if (ch == ')') {
+ if (parlevel == 0) {
+ if (buf.GetLength() > MAX_STRING_LENGTH) {
+ return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH);
+ }
+ return buf.GetByteString();
+ }
+ parlevel--;
+ buf.AppendChar(')');
+ } else if (ch == '(') {
+ parlevel++;
+ buf.AppendChar('(');
+ } else if (ch == '\\') {
+ status = 1;
+ } else {
+ buf.AppendChar((char)ch);
+ }
+ break;
+ case 1:
+ if (ch >= '0' && ch <= '7') {
+ iEscCode = FXSYS_toDecimalDigit(static_cast<FX_WCHAR>(ch));
+ status = 2;
+ break;
+ }
+ if (ch == 'n') {
+ buf.AppendChar('\n');
+ } else if (ch == 'r') {
+ buf.AppendChar('\r');
+ } else if (ch == 't') {
+ buf.AppendChar('\t');
+ } else if (ch == 'b') {
+ buf.AppendChar('\b');
+ } else if (ch == 'f') {
+ buf.AppendChar('\f');
+ } else if (ch == '\r') {
+ status = 4;
+ break;
+ } else if (ch == '\n') {
+ } else {
+ buf.AppendChar(ch);
+ }
+ status = 0;
+ break;
+ case 2:
+ if (ch >= '0' && ch <= '7') {
+ iEscCode =
+ iEscCode * 8 + FXSYS_toDecimalDigit(static_cast<FX_WCHAR>(ch));
+ status = 3;
+ } else {
+ buf.AppendChar(iEscCode);
+ status = 0;
+ continue;
+ }
+ break;
+ case 3:
+ if (ch >= '0' && ch <= '7') {
+ iEscCode =
+ iEscCode * 8 + FXSYS_toDecimalDigit(static_cast<FX_WCHAR>(ch));
+ buf.AppendChar(iEscCode);
+ status = 0;
+ } else {
+ buf.AppendChar(iEscCode);
+ status = 0;
+ continue;
+ }
+ break;
+ case 4:
+ status = 0;
+ if (ch != '\n') {
+ continue;
+ }
+ break;
+ }
+ if (!PositionIsInBounds())
+ break;
+
+ ch = m_pBuf[m_Pos++];
+ }
+ if (PositionIsInBounds())
+ ++m_Pos;
+
+ if (buf.GetLength() > MAX_STRING_LENGTH) {
+ return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH);
+ }
+ return buf.GetByteString();
+}
+
+CFX_ByteString CPDF_StreamParser::ReadHexString() {
+ if (!PositionIsInBounds())
+ return CFX_ByteString();
+
+ CFX_ByteTextBuf buf;
+ bool bFirst = true;
+ int code = 0;
+ while (PositionIsInBounds()) {
+ int ch = m_pBuf[m_Pos++];
+
+ if (ch == '>')
+ break;
+
+ if (!std::isxdigit(ch))
+ continue;
+
+ int val = FXSYS_toHexDigit(ch);
+ if (bFirst) {
+ code = val * 16;
+ } else {
+ code += val;
+ buf.AppendByte((uint8_t)code);
+ }
+ bFirst = !bFirst;
+ }
+ if (!bFirst)
+ buf.AppendChar((char)code);
+
+ if (buf.GetLength() > MAX_STRING_LENGTH)
+ return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH);
+
+ return buf.GetByteString();
+}
+
+bool CPDF_StreamParser::PositionIsInBounds() const {
+ return m_Pos < m_Size;
+}
+
+CPDF_ContentParser::CPDF_ContentParser()
+ : m_Status(Ready),
+ m_InternalStage(STAGE_GETCONTENT),
+ m_pObjectHolder(nullptr),
+ m_bForm(false),
+ m_pType3Char(nullptr),
+ m_pData(nullptr),
+ m_Size(0),
+ m_CurrentOffset(0) {}
+
+CPDF_ContentParser::~CPDF_ContentParser() {
+ if (!m_pSingleStream)
+ FX_Free(m_pData);
+}
+
+void CPDF_ContentParser::Start(CPDF_Page* pPage, CPDF_ParseOptions* pOptions) {
+ if (m_Status != Ready || !pPage || !pPage->m_pDocument ||
+ !pPage->m_pFormDict) {
+ m_Status = Done;
+ return;
+ }
+ m_pObjectHolder = pPage;
+ m_bForm = FALSE;
+ if (pOptions) {
+ m_Options = *pOptions;
+ }
+ m_Status = ToBeContinued;
+ m_InternalStage = STAGE_GETCONTENT;
+ m_CurrentOffset = 0;
+
+ CPDF_Object* pContent = pPage->m_pFormDict->GetElementValue("Contents");
+ if (!pContent) {
+ m_Status = Done;
+ return;
+ }
+ if (CPDF_Stream* pStream = pContent->AsStream()) {
+ m_nStreams = 0;
+ m_pSingleStream.reset(new CPDF_StreamAcc);
+ m_pSingleStream->LoadAllData(pStream, FALSE);
+ } else if (CPDF_Array* pArray = pContent->AsArray()) {
+ m_nStreams = pArray->GetCount();
+ if (m_nStreams)
+ m_StreamArray.resize(m_nStreams);
+ else
+ m_Status = Done;
+ } else {
+ m_Status = Done;
+ }
+}
+
+void CPDF_ContentParser::Start(CPDF_Form* pForm,
+ CPDF_AllStates* pGraphicStates,
+ CFX_Matrix* pParentMatrix,
+ CPDF_Type3Char* pType3Char,
+ CPDF_ParseOptions* pOptions,
+ int level) {
+ m_pType3Char = pType3Char;
+ m_pObjectHolder = pForm;
+ m_bForm = TRUE;
+ CFX_Matrix form_matrix = pForm->m_pFormDict->GetMatrixBy("Matrix");
+ if (pGraphicStates) {
+ form_matrix.Concat(pGraphicStates->m_CTM);
+ }
+ CPDF_Array* pBBox = pForm->m_pFormDict->GetArrayBy("BBox");
+ CFX_FloatRect form_bbox;
+ CPDF_Path ClipPath;
+ if (pBBox) {
+ form_bbox = pBBox->GetRect();
+ ClipPath.New();
+ ClipPath.AppendRect(form_bbox.left, form_bbox.bottom, form_bbox.right,
+ form_bbox.top);
+ ClipPath.Transform(&form_matrix);
+ if (pParentMatrix) {
+ ClipPath.Transform(pParentMatrix);
+ }
+ form_bbox.Transform(&form_matrix);
+ if (pParentMatrix) {
+ form_bbox.Transform(pParentMatrix);
+ }
+ }
+ CPDF_Dictionary* pResources = pForm->m_pFormDict->GetDictBy("Resources");
+ m_pParser.reset(new CPDF_StreamContentParser(
+ pForm->m_pDocument, pForm->m_pPageResources, pForm->m_pResources,
+ pParentMatrix, pForm, pResources, &form_bbox, pOptions, pGraphicStates,
+ level));
+ m_pParser->GetCurStates()->m_CTM = form_matrix;
+ m_pParser->GetCurStates()->m_ParentMatrix = form_matrix;
+ if (ClipPath.NotNull()) {
+ m_pParser->GetCurStates()->m_ClipPath.AppendPath(ClipPath, FXFILL_WINDING,
+ TRUE);
+ }
+ if (pForm->m_Transparency & PDFTRANS_GROUP) {
+ CPDF_GeneralStateData* pData =
+ m_pParser->GetCurStates()->m_GeneralState.GetModify();
+ pData->m_BlendType = FXDIB_BLEND_NORMAL;
+ pData->m_StrokeAlpha = 1.0f;
+ pData->m_FillAlpha = 1.0f;
+ pData->m_pSoftMask = NULL;
+ }
+ m_nStreams = 0;
+ m_pSingleStream.reset(new CPDF_StreamAcc);
+ m_pSingleStream->LoadAllData(pForm->m_pFormStream, FALSE);
+ m_pData = (uint8_t*)m_pSingleStream->GetData();
+ m_Size = m_pSingleStream->GetSize();
+ m_Status = ToBeContinued;
+ m_InternalStage = STAGE_PARSE;
+ m_CurrentOffset = 0;
+}
+
+void CPDF_ContentParser::Continue(IFX_Pause* pPause) {
+ int steps = 0;
+ while (m_Status == ToBeContinued) {
+ if (m_InternalStage == STAGE_GETCONTENT) {
+ if (m_CurrentOffset == m_nStreams) {
+ if (!m_StreamArray.empty()) {
+ FX_SAFE_DWORD safeSize = 0;
+ for (const auto& stream : m_StreamArray) {
+ safeSize += stream->GetSize();
+ safeSize += 1;
+ }
+ if (!safeSize.IsValid()) {
+ m_Status = Done;
+ return;
+ }
+ m_Size = safeSize.ValueOrDie();
+ m_pData = FX_Alloc(uint8_t, m_Size);
+ FX_DWORD pos = 0;
+ for (const auto& stream : m_StreamArray) {
+ FXSYS_memcpy(m_pData + pos, stream->GetData(), stream->GetSize());
+ pos += stream->GetSize();
+ m_pData[pos++] = ' ';
+ }
+ m_StreamArray.clear();
+ } else {
+ m_pData = (uint8_t*)m_pSingleStream->GetData();
+ m_Size = m_pSingleStream->GetSize();
+ }
+ m_InternalStage = STAGE_PARSE;
+ m_CurrentOffset = 0;
+ } else {
+ CPDF_Array* pContent =
+ m_pObjectHolder->m_pFormDict->GetArrayBy("Contents");
+ m_StreamArray[m_CurrentOffset].reset(new CPDF_StreamAcc);
+ CPDF_Stream* pStreamObj = ToStream(
+ pContent ? pContent->GetElementValue(m_CurrentOffset) : nullptr);
+ m_StreamArray[m_CurrentOffset]->LoadAllData(pStreamObj, FALSE);
+ m_CurrentOffset++;
+ }
+ }
+ if (m_InternalStage == STAGE_PARSE) {
+ if (!m_pParser) {
+ m_pParser.reset(new CPDF_StreamContentParser(
+ m_pObjectHolder->m_pDocument, m_pObjectHolder->m_pPageResources,
+ nullptr, nullptr, m_pObjectHolder, m_pObjectHolder->m_pResources,
+ &m_pObjectHolder->m_BBox, &m_Options, nullptr, 0));
+ m_pParser->GetCurStates()->m_ColorState.GetModify()->Default();
+ }
+ if (m_CurrentOffset >= m_Size) {
+ m_InternalStage = STAGE_CHECKCLIP;
+ } else {
+ m_CurrentOffset +=
+ m_pParser->Parse(m_pData + m_CurrentOffset,
+ m_Size - m_CurrentOffset, PARSE_STEP_LIMIT);
+ }
+ }
+ if (m_InternalStage == STAGE_CHECKCLIP) {
+ if (m_pType3Char) {
+ m_pType3Char->m_bColored = m_pParser->IsColored();
+ m_pType3Char->m_Width =
+ FXSYS_round(m_pParser->GetType3Data()[0] * 1000);
+ m_pType3Char->m_BBox.left =
+ FXSYS_round(m_pParser->GetType3Data()[2] * 1000);
+ m_pType3Char->m_BBox.bottom =
+ FXSYS_round(m_pParser->GetType3Data()[3] * 1000);
+ m_pType3Char->m_BBox.right =
+ FXSYS_round(m_pParser->GetType3Data()[4] * 1000);
+ m_pType3Char->m_BBox.top =
+ FXSYS_round(m_pParser->GetType3Data()[5] * 1000);
+ }
+ for (auto& pObj : *m_pObjectHolder->GetPageObjectList()) {
+ if (pObj->m_ClipPath.IsNull()) {
+ continue;
+ }
+ if (pObj->m_ClipPath.GetPathCount() != 1) {
+ continue;
+ }
+ if (pObj->m_ClipPath.GetTextCount()) {
+ continue;
+ }
+ CPDF_Path ClipPath = pObj->m_ClipPath.GetPath(0);
+ if (!ClipPath.IsRect() || pObj->IsShading()) {
+ continue;
+ }
+ CFX_FloatRect old_rect(ClipPath.GetPointX(0), ClipPath.GetPointY(0),
+ ClipPath.GetPointX(2), ClipPath.GetPointY(2));
+ CFX_FloatRect obj_rect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right,
+ pObj->m_Top);
+ if (old_rect.Contains(obj_rect)) {
+ pObj->m_ClipPath.SetNull();
+ }
+ }
+ m_Status = Done;
+ return;
+ }
+ steps++;
+ if (pPause && pPause->NeedToPauseNow()) {
+ break;
+ }
+ }
+}
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_parser_old_unittest.cpp b/core/fpdfapi/fpdf_page/fpdf_page_parser_old_unittest.cpp
new file mode 100644
index 0000000000..f4c33d2811
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/fpdf_page_parser_old_unittest.cpp
@@ -0,0 +1,47 @@
+// Copyright 2015 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.
+
+#include "core/fpdfapi/fpdf_page/pageint.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(fpdf_page_parser_old, ReadHexString) {
+ {
+ // Position out of bounds.
+ uint8_t data[] = "12ab>";
+ CPDF_StreamParser parser(data, 5);
+ parser.SetPos(6);
+ EXPECT_EQ("", parser.ReadHexString());
+ }
+
+ {
+ // Regular conversion.
+ uint8_t data[] = "1A2b>abcd";
+ CPDF_StreamParser parser(data, 5);
+ EXPECT_EQ("\x1a\x2b", parser.ReadHexString());
+ EXPECT_EQ(5, parser.GetPos());
+ }
+
+ {
+ // Missing ending >
+ uint8_t data[] = "1A2b";
+ CPDF_StreamParser parser(data, 5);
+ EXPECT_EQ("\x1a\x2b", parser.ReadHexString());
+ EXPECT_EQ(5, parser.GetPos());
+ }
+
+ {
+ // Uneven number of bytes.
+ uint8_t data[] = "1A2>asdf";
+ CPDF_StreamParser parser(data, 5);
+ EXPECT_EQ("\x1a\x20", parser.ReadHexString());
+ EXPECT_EQ(4, parser.GetPos());
+ }
+
+ {
+ uint8_t data[] = ">";
+ CPDF_StreamParser parser(data, 5);
+ EXPECT_EQ("", parser.ReadHexString());
+ EXPECT_EQ(1, parser.GetPos());
+ }
+}
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_path.cpp b/core/fpdfapi/fpdf_page/fpdf_page_path.cpp
new file mode 100644
index 0000000000..c2b6f13ca0
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/fpdf_page_path.cpp
@@ -0,0 +1,55 @@
+// Copyright 2014 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/fpdf_page/pageint.h"
+
+#include "core/include/fpdfapi/fpdf_module.h"
+#include "core/include/fpdfapi/fpdf_page.h"
+#include "core/include/fpdfapi/fpdf_pageobj.h"
+
+CPDF_PathObject::CPDF_PathObject() {}
+
+CPDF_PathObject::~CPDF_PathObject() {}
+
+CPDF_PathObject* CPDF_PathObject::Clone() const {
+ CPDF_PathObject* obj = new CPDF_PathObject;
+ obj->CopyData(this);
+
+ obj->m_Path = m_Path;
+ obj->m_FillType = m_FillType;
+ obj->m_bStroke = m_bStroke;
+ obj->m_Matrix = m_Matrix;
+ return obj;
+}
+
+void CPDF_PathObject::Transform(const CFX_Matrix& matrix) {
+ m_Matrix.Concat(matrix);
+ CalcBoundingBox();
+}
+
+void CPDF_PathObject::CalcBoundingBox() {
+ if (m_Path.IsNull()) {
+ return;
+ }
+ CFX_FloatRect rect;
+ FX_FLOAT width = m_GraphState.GetObject()->m_LineWidth;
+ if (m_bStroke && width != 0) {
+ rect = m_Path.GetBoundingBox(width, m_GraphState.GetObject()->m_MiterLimit);
+ } else {
+ rect = m_Path.GetBoundingBox();
+ }
+ rect.Transform(&m_Matrix);
+ if (width == 0 && m_bStroke) {
+ rect.left += -0.5f;
+ rect.right += 0.5f;
+ rect.bottom += -0.5f;
+ rect.top += 0.5f;
+ }
+ m_Left = rect.left;
+ m_Right = rect.right;
+ m_Top = rect.top;
+ m_Bottom = rect.bottom;
+}
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_pattern.cpp b/core/fpdfapi/fpdf_page/fpdf_page_pattern.cpp
new file mode 100644
index 0000000000..6bb64292a3
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/fpdf_page_pattern.cpp
@@ -0,0 +1,320 @@
+// Copyright 2014 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/fpdf_page/pageint.h"
+
+#include <algorithm>
+
+#include "core/include/fpdfapi/cpdf_array.h"
+#include "core/include/fpdfapi/cpdf_dictionary.h"
+#include "core/include/fpdfapi/cpdf_document.h"
+#include "core/include/fpdfapi/fpdf_page.h"
+
+namespace {
+
+const int kSingleCoordinatePair = 1;
+const int kTensorCoordinatePairs = 16;
+const int kCoonsCoordinatePairs = 12;
+
+const int kSingleColorPerPatch = 1;
+const int kQuadColorsPerPatch = 4;
+
+ShadingType ToShadingType(int type) {
+ return (type > static_cast<int>(kInvalidShading) &&
+ type < static_cast<int>(kMaxShading))
+ ? static_cast<ShadingType>(type)
+ : kInvalidShading;
+}
+
+} // namespace
+
+CPDF_Pattern::CPDF_Pattern(PatternType type,
+ CPDF_Document* pDoc,
+ CPDF_Object* pObj,
+ const CFX_Matrix* pParentMatrix)
+ : m_PatternType(type),
+ m_pDocument(pDoc),
+ m_pPatternObj(pObj),
+ m_bForceClear(FALSE) {
+ if (pParentMatrix)
+ m_ParentMatrix = *pParentMatrix;
+}
+CPDF_Pattern::~CPDF_Pattern() {}
+CPDF_TilingPattern::CPDF_TilingPattern(CPDF_Document* pDoc,
+ CPDF_Object* pPatternObj,
+ const CFX_Matrix* parentMatrix)
+ : CPDF_Pattern(TILING, pDoc, pPatternObj, parentMatrix) {
+ CPDF_Dictionary* pDict = m_pPatternObj->GetDict();
+ m_Pattern2Form = pDict->GetMatrixBy("Matrix");
+ m_bColored = pDict->GetIntegerBy("PaintType") == 1;
+ if (parentMatrix) {
+ m_Pattern2Form.Concat(*parentMatrix);
+ }
+ m_pForm = NULL;
+}
+CPDF_TilingPattern::~CPDF_TilingPattern() {
+ delete m_pForm;
+ m_pForm = NULL;
+}
+FX_BOOL CPDF_TilingPattern::Load() {
+ if (m_pForm)
+ return TRUE;
+
+ CPDF_Dictionary* pDict = m_pPatternObj->GetDict();
+ if (!pDict)
+ return FALSE;
+
+ m_bColored = pDict->GetIntegerBy("PaintType") == 1;
+ m_XStep = (FX_FLOAT)FXSYS_fabs(pDict->GetNumberBy("XStep"));
+ m_YStep = (FX_FLOAT)FXSYS_fabs(pDict->GetNumberBy("YStep"));
+
+ CPDF_Stream* pStream = m_pPatternObj->AsStream();
+ if (!pStream)
+ return FALSE;
+
+ m_pForm = new CPDF_Form(m_pDocument, NULL, pStream);
+ m_pForm->ParseContent(NULL, &m_ParentMatrix, NULL, NULL);
+ m_BBox = pDict->GetRectBy("BBox");
+ return TRUE;
+}
+CPDF_ShadingPattern::CPDF_ShadingPattern(CPDF_Document* pDoc,
+ CPDF_Object* pPatternObj,
+ FX_BOOL bShading,
+ const CFX_Matrix* parentMatrix)
+ : CPDF_Pattern(SHADING,
+ pDoc,
+ bShading ? nullptr : pPatternObj,
+ parentMatrix),
+ m_ShadingType(kInvalidShading),
+ m_bShadingObj(bShading),
+ m_pShadingObj(pPatternObj),
+ m_pCS(nullptr),
+ m_pCountedCS(nullptr),
+ m_nFuncs(0) {
+ if (!bShading) {
+ CPDF_Dictionary* pDict = m_pPatternObj->GetDict();
+ m_Pattern2Form = pDict->GetMatrixBy("Matrix");
+ m_pShadingObj = pDict->GetElementValue("Shading");
+ if (parentMatrix)
+ m_Pattern2Form.Concat(*parentMatrix);
+ }
+ for (int i = 0; i < FX_ArraySize(m_pFunctions); ++i)
+ m_pFunctions[i] = nullptr;
+}
+
+CPDF_ShadingPattern::~CPDF_ShadingPattern() {
+ for (int i = 0; i < m_nFuncs; ++i)
+ delete m_pFunctions[i];
+
+ CPDF_ColorSpace* pCS = m_pCountedCS ? m_pCountedCS->get() : NULL;
+ if (pCS && m_pDocument)
+ m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());
+}
+
+FX_BOOL CPDF_ShadingPattern::Load() {
+ if (m_ShadingType != kInvalidShading)
+ return TRUE;
+
+ CPDF_Dictionary* pShadingDict =
+ m_pShadingObj ? m_pShadingObj->GetDict() : NULL;
+ if (!pShadingDict) {
+ return FALSE;
+ }
+ if (m_nFuncs) {
+ for (int i = 0; i < m_nFuncs; i++)
+ delete m_pFunctions[i];
+ m_nFuncs = 0;
+ }
+ CPDF_Object* pFunc = pShadingDict->GetElementValue("Function");
+ if (pFunc) {
+ if (CPDF_Array* pArray = pFunc->AsArray()) {
+ m_nFuncs = std::min<int>(pArray->GetCount(), 4);
+
+ for (int i = 0; i < m_nFuncs; i++) {
+ m_pFunctions[i] = CPDF_Function::Load(pArray->GetElementValue(i));
+ }
+ } else {
+ m_pFunctions[0] = CPDF_Function::Load(pFunc);
+ m_nFuncs = 1;
+ }
+ }
+ CPDF_Object* pCSObj = pShadingDict->GetElementValue("ColorSpace");
+ if (!pCSObj) {
+ return FALSE;
+ }
+ CPDF_DocPageData* pDocPageData = m_pDocument->GetPageData();
+ m_pCS = pDocPageData->GetColorSpace(pCSObj, NULL);
+ if (m_pCS) {
+ m_pCountedCS = pDocPageData->FindColorSpacePtr(m_pCS->GetArray());
+ }
+
+ m_ShadingType = ToShadingType(pShadingDict->GetIntegerBy("ShadingType"));
+
+ // We expect to have a stream if our shading type is a mesh.
+ if (IsMeshShading() && !ToStream(m_pShadingObj))
+ return FALSE;
+
+ return TRUE;
+}
+FX_BOOL CPDF_MeshStream::Load(CPDF_Stream* pShadingStream,
+ CPDF_Function** pFuncs,
+ int nFuncs,
+ CPDF_ColorSpace* pCS) {
+ m_Stream.LoadAllData(pShadingStream);
+ m_BitStream.Init(m_Stream.GetData(), m_Stream.GetSize());
+ m_pFuncs = pFuncs;
+ m_nFuncs = nFuncs;
+ m_pCS = pCS;
+ CPDF_Dictionary* pDict = pShadingStream->GetDict();
+ m_nCoordBits = pDict->GetIntegerBy("BitsPerCoordinate");
+ m_nCompBits = pDict->GetIntegerBy("BitsPerComponent");
+ m_nFlagBits = pDict->GetIntegerBy("BitsPerFlag");
+ if (!m_nCoordBits || !m_nCompBits) {
+ return FALSE;
+ }
+ FX_DWORD nComps = pCS->CountComponents();
+ if (nComps > 8) {
+ return FALSE;
+ }
+ m_nComps = nFuncs ? 1 : nComps;
+ if (((int)m_nComps < 0) || m_nComps > 8) {
+ return FALSE;
+ }
+ m_CoordMax = m_nCoordBits == 32 ? -1 : (1 << m_nCoordBits) - 1;
+ m_CompMax = (1 << m_nCompBits) - 1;
+ CPDF_Array* pDecode = pDict->GetArrayBy("Decode");
+ if (!pDecode || pDecode->GetCount() != 4 + m_nComps * 2) {
+ return FALSE;
+ }
+ m_xmin = pDecode->GetNumberAt(0);
+ m_xmax = pDecode->GetNumberAt(1);
+ m_ymin = pDecode->GetNumberAt(2);
+ m_ymax = pDecode->GetNumberAt(3);
+ for (FX_DWORD i = 0; i < m_nComps; i++) {
+ m_ColorMin[i] = pDecode->GetNumberAt(i * 2 + 4);
+ m_ColorMax[i] = pDecode->GetNumberAt(i * 2 + 5);
+ }
+ return TRUE;
+}
+FX_DWORD CPDF_MeshStream::GetFlag() {
+ return m_BitStream.GetBits(m_nFlagBits) & 0x03;
+}
+void CPDF_MeshStream::GetCoords(FX_FLOAT& x, FX_FLOAT& y) {
+ if (m_nCoordBits == 32) {
+ x = m_xmin + (FX_FLOAT)(m_BitStream.GetBits(m_nCoordBits) *
+ (m_xmax - m_xmin) / (double)m_CoordMax);
+ y = m_ymin + (FX_FLOAT)(m_BitStream.GetBits(m_nCoordBits) *
+ (m_ymax - m_ymin) / (double)m_CoordMax);
+ } else {
+ x = m_xmin +
+ m_BitStream.GetBits(m_nCoordBits) * (m_xmax - m_xmin) / m_CoordMax;
+ y = m_ymin +
+ m_BitStream.GetBits(m_nCoordBits) * (m_ymax - m_ymin) / m_CoordMax;
+ }
+}
+void CPDF_MeshStream::GetColor(FX_FLOAT& r, FX_FLOAT& g, FX_FLOAT& b) {
+ FX_DWORD i;
+ FX_FLOAT color_value[8];
+ for (i = 0; i < m_nComps; i++) {
+ color_value[i] = m_ColorMin[i] +
+ m_BitStream.GetBits(m_nCompBits) *
+ (m_ColorMax[i] - m_ColorMin[i]) / m_CompMax;
+ }
+ if (m_nFuncs) {
+ static const int kMaxResults = 8;
+ FX_FLOAT result[kMaxResults];
+ int nResults;
+ FXSYS_memset(result, 0, sizeof(result));
+ for (FX_DWORD i = 0; i < m_nFuncs; i++) {
+ if (m_pFuncs[i] && m_pFuncs[i]->CountOutputs() <= kMaxResults) {
+ m_pFuncs[i]->Call(color_value, 1, result, nResults);
+ }
+ }
+ m_pCS->GetRGB(result, r, g, b);
+ } else {
+ m_pCS->GetRGB(color_value, r, g, b);
+ }
+}
+FX_DWORD CPDF_MeshStream::GetVertex(CPDF_MeshVertex& vertex,
+ CFX_Matrix* pObject2Bitmap) {
+ FX_DWORD flag = GetFlag();
+ GetCoords(vertex.x, vertex.y);
+ pObject2Bitmap->Transform(vertex.x, vertex.y);
+ GetColor(vertex.r, vertex.g, vertex.b);
+ m_BitStream.ByteAlign();
+ return flag;
+}
+FX_BOOL CPDF_MeshStream::GetVertexRow(CPDF_MeshVertex* vertex,
+ int count,
+ CFX_Matrix* pObject2Bitmap) {
+ for (int i = 0; i < count; i++) {
+ if (m_BitStream.IsEOF()) {
+ return FALSE;
+ }
+ GetCoords(vertex[i].x, vertex[i].y);
+ pObject2Bitmap->Transform(vertex[i].x, vertex[i].y);
+ GetColor(vertex[i].r, vertex[i].g, vertex[i].b);
+ m_BitStream.ByteAlign();
+ }
+ return TRUE;
+}
+
+CFX_FloatRect GetShadingBBox(CPDF_Stream* pStream,
+ ShadingType type,
+ const CFX_Matrix* pMatrix,
+ CPDF_Function** pFuncs,
+ int nFuncs,
+ CPDF_ColorSpace* pCS) {
+ if (!pStream || !pStream->IsStream() || !pFuncs || !pCS)
+ return CFX_FloatRect(0, 0, 0, 0);
+
+ CPDF_MeshStream stream;
+ if (!stream.Load(pStream, pFuncs, nFuncs, pCS))
+ return CFX_FloatRect(0, 0, 0, 0);
+
+ CFX_FloatRect rect;
+ bool bStarted = false;
+ bool bGouraud = type == kFreeFormGouraudTriangleMeshShading ||
+ type == kLatticeFormGouraudTriangleMeshShading;
+
+ int point_count = kSingleCoordinatePair;
+ if (type == kTensorProductPatchMeshShading)
+ point_count = kTensorCoordinatePairs;
+ else if (type == kCoonsPatchMeshShading)
+ point_count = kCoonsCoordinatePairs;
+
+ int color_count = kSingleColorPerPatch;
+ if (type == kCoonsPatchMeshShading || type == kTensorProductPatchMeshShading)
+ color_count = kQuadColorsPerPatch;
+
+ while (!stream.m_BitStream.IsEOF()) {
+ FX_DWORD flag = 0;
+ if (type != kLatticeFormGouraudTriangleMeshShading)
+ flag = stream.GetFlag();
+
+ if (!bGouraud && flag) {
+ point_count -= 4;
+ color_count -= 2;
+ }
+
+ for (int i = 0; i < point_count; i++) {
+ FX_FLOAT x, y;
+ stream.GetCoords(x, y);
+ if (bStarted) {
+ rect.UpdateRect(x, y);
+ } else {
+ rect.InitRect(x, y);
+ bStarted = TRUE;
+ }
+ }
+ stream.m_BitStream.SkipBits(stream.m_nComps * stream.m_nCompBits *
+ color_count);
+ if (bGouraud)
+ stream.m_BitStream.ByteAlign();
+ }
+ rect.Transform(pMatrix);
+ return rect;
+}
diff --git a/core/fpdfapi/fpdf_page/pageint.h b/core/fpdfapi/fpdf_page/pageint.h
new file mode 100644
index 0000000000..8818bc9af0
--- /dev/null
+++ b/core/fpdfapi/fpdf_page/pageint.h
@@ -0,0 +1,459 @@
+// Copyright 2014 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
+
+#ifndef CORE_FPDFAPI_FPDF_PAGE_PAGEINT_H_
+#define CORE_FPDFAPI_FPDF_PAGE_PAGEINT_H_
+
+#include <map>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "core/include/fpdfapi/fpdf_page.h"
+#include "core/include/fpdfapi/fpdf_pageobj.h"
+
+class CPDF_AllStates;
+class CPDF_ParseOptions;
+class CPDF_IccProfile;
+
+#define PARSE_STEP_LIMIT 100
+
+class CPDF_StreamParser {
+ public:
+ enum SyntaxType { EndOfData, Number, Keyword, Name, Others };
+
+ CPDF_StreamParser(const uint8_t* pData, FX_DWORD dwSize);
+ ~CPDF_StreamParser();
+
+ CPDF_Stream* ReadInlineStream(CPDF_Document* pDoc,
+ CPDF_Dictionary* pDict,
+ CPDF_Object* pCSObj,
+ FX_BOOL bDecode);
+ SyntaxType ParseNextElement();
+ uint8_t* GetWordBuf() { return m_WordBuffer; }
+ FX_DWORD GetWordSize() const { return m_WordSize; }
+ CPDF_Object* GetObject() {
+ CPDF_Object* pObj = m_pLastObj;
+ m_pLastObj = NULL;
+ return pObj;
+ }
+ FX_DWORD GetPos() const { return m_Pos; }
+ void SetPos(FX_DWORD pos) { m_Pos = pos; }
+ CPDF_Object* ReadNextObject(FX_BOOL bAllowNestedArray = FALSE,
+ FX_BOOL bInArray = FALSE);
+ void SkipPathObject();
+
+ protected:
+ friend class fpdf_page_parser_old_ReadHexString_Test;
+
+ void GetNextWord(FX_BOOL& bIsNumber);
+ CFX_ByteString ReadString();
+ CFX_ByteString ReadHexString();
+ const uint8_t* m_pBuf;
+
+ // Length in bytes of m_pBuf.
+ FX_DWORD m_Size;
+
+ // Current byte position within m_pBuf.
+ FX_DWORD m_Pos;
+
+ uint8_t m_WordBuffer[256];
+ FX_DWORD m_WordSize;
+ CPDF_Object* m_pLastObj;
+
+ private:
+ bool PositionIsInBounds() const;
+};
+
+#define PARAM_BUF_SIZE 16
+struct ContentParam {
+ enum Type { OBJECT = 0, NUMBER, NAME };
+ Type m_Type;
+ union {
+ struct {
+ FX_BOOL m_bInteger;
+ union {
+ int m_Integer;
+ FX_FLOAT m_Float;
+ };
+ } m_Number;
+ CPDF_Object* m_pObject;
+ struct {
+ int m_Len;
+ char m_Buffer[32];
+ } m_Name;
+ };
+};
+#define _FPDF_MAX_FORM_LEVEL_ 30
+#define _FPDF_MAX_TYPE3_FORM_LEVEL_ 4
+#define _FPDF_MAX_OBJECT_STACK_SIZE_ 512
+class CPDF_StreamContentParser {
+ public:
+ CPDF_StreamContentParser(CPDF_Document* pDoc,
+ CPDF_Dictionary* pPageResources,
+ CPDF_Dictionary* pParentResources,
+ CFX_Matrix* pmtContentToUser,
+ CPDF_PageObjectHolder* pObjectHolder,
+ CPDF_Dictionary* pResources,
+ CFX_FloatRect* pBBox,
+ CPDF_ParseOptions* pOptions,
+ CPDF_AllStates* pAllStates,
+ int level);
+ ~CPDF_StreamContentParser();
+
+ CPDF_PageObjectHolder* GetPageObjectHolder() const { return m_pObjectHolder; }
+ CPDF_AllStates* GetCurStates() const { return m_pCurStates.get(); }
+ FX_BOOL IsColored() const { return m_bColored; }
+ const FX_FLOAT* GetType3Data() const { return m_Type3Data; }
+
+ void AddNumberParam(const FX_CHAR* str, int len);
+ void AddObjectParam(CPDF_Object* pObj);
+ void AddNameParam(const FX_CHAR* name, int size);
+ int GetNextParamPos();
+ void ClearAllParams();
+ CPDF_Object* GetObject(FX_DWORD index);
+ CFX_ByteString GetString(FX_DWORD index);
+ FX_FLOAT GetNumber(FX_DWORD index);
+ FX_FLOAT GetNumber16(FX_DWORD index);
+ int GetInteger(FX_DWORD index) { return (int32_t)(GetNumber(index)); }
+ void OnOperator(const FX_CHAR* op);
+ void BigCaseCaller(int index);
+ FX_DWORD GetParsePos() { return m_pSyntax->GetPos(); }
+ void AddTextObject(CFX_ByteString* pText,
+ FX_FLOAT fInitKerning,
+ FX_FLOAT* pKerning,
+ int count);
+
+ void ConvertUserSpace(FX_FLOAT& x, FX_FLOAT& y);
+ void ConvertTextSpace(FX_FLOAT& x, FX_FLOAT& y);
+ void OnChangeTextMatrix();
+ FX_DWORD Parse(const uint8_t* pData, FX_DWORD dwSize, FX_DWORD max_cost);
+ void ParsePathObject();
+ void AddPathPoint(FX_FLOAT x, FX_FLOAT y, int flag);
+ void AddPathRect(FX_FLOAT x, FX_FLOAT y, FX_FLOAT w, FX_FLOAT h);
+ void AddPathObject(int FillType, FX_BOOL bStroke);
+ CPDF_ImageObject* AddImage(CPDF_Stream* pStream,
+ CPDF_Image* pImage,
+ FX_BOOL bInline);
+ void AddDuplicateImage();
+ void AddForm(CPDF_Stream* pStream);
+ void SetGraphicStates(CPDF_PageObject* pObj,
+ FX_BOOL bColor,
+ FX_BOOL bText,
+ FX_BOOL bGraph);
+ void SaveStates(CPDF_AllStates* pState);
+ void RestoreStates(CPDF_AllStates* pState);
+ CPDF_Font* FindFont(const CFX_ByteString& name);
+ CPDF_ColorSpace* FindColorSpace(const CFX_ByteString& name);
+ CPDF_Pattern* FindPattern(const CFX_ByteString& name, FX_BOOL bShading);
+ CPDF_Object* FindResourceObj(const CFX_ByteStringC& type,
+ const CFX_ByteString& name);
+
+ protected:
+ using OpCodes =
+ std::unordered_map<FX_DWORD, void (CPDF_StreamContentParser::*)()>;
+ static OpCodes InitializeOpCodes();
+
+ void Handle_CloseFillStrokePath();
+ void Handle_FillStrokePath();
+ void Handle_CloseEOFillStrokePath();
+ void Handle_EOFillStrokePath();
+ void Handle_BeginMarkedContent_Dictionary();
+ void Handle_BeginImage();
+ void Handle_BeginMarkedContent();
+ void Handle_BeginText();
+ void Handle_CurveTo_123();
+ void Handle_ConcatMatrix();
+ void Handle_SetColorSpace_Fill();
+ void Handle_SetColorSpace_Stroke();
+ void Handle_SetDash();
+ void Handle_SetCharWidth();
+ void Handle_SetCachedDevice();
+ void Handle_ExecuteXObject();
+ void Handle_MarkPlace_Dictionary();
+ void Handle_EndImage();
+ void Handle_EndMarkedContent();
+ void Handle_EndText();
+ void Handle_FillPath();
+ void Handle_FillPathOld();
+ void Handle_EOFillPath();
+ void Handle_SetGray_Fill();
+ void Handle_SetGray_Stroke();
+ void Handle_SetExtendGraphState();
+ void Handle_ClosePath();
+ void Handle_SetFlat();
+ void Handle_BeginImageData();
+ void Handle_SetLineJoin();
+ void Handle_SetLineCap();
+ void Handle_SetCMYKColor_Fill();
+ void Handle_SetCMYKColor_Stroke();
+ void Handle_LineTo();
+ void Handle_MoveTo();
+ void Handle_SetMiterLimit();
+ void Handle_MarkPlace();
+ void Handle_EndPath();
+ void Handle_SaveGraphState();
+ void Handle_RestoreGraphState();
+ void Handle_Rectangle();
+ void Handle_SetRGBColor_Fill();
+ void Handle_SetRGBColor_Stroke();
+ void Handle_SetRenderIntent();
+ void Handle_CloseStrokePath();
+ void Handle_StrokePath();
+ void Handle_SetColor_Fill();
+ void Handle_SetColor_Stroke();
+ void Handle_SetColorPS_Fill();
+ void Handle_SetColorPS_Stroke();
+ void Handle_ShadeFill();
+ void Handle_SetCharSpace();
+ void Handle_MoveTextPoint();
+ void Handle_MoveTextPoint_SetLeading();
+ void Handle_SetFont();
+ void Handle_ShowText();
+ void Handle_ShowText_Positioning();
+ void Handle_SetTextLeading();
+ void Handle_SetTextMatrix();
+ void Handle_SetTextRenderMode();
+ void Handle_SetTextRise();
+ void Handle_SetWordSpace();
+ void Handle_SetHorzScale();
+ void Handle_MoveToNextLine();
+ void Handle_CurveTo_23();
+ void Handle_SetLineWidth();
+ void Handle_Clip();
+ void Handle_EOClip();
+ void Handle_CurveTo_13();
+ void Handle_NextLineShowText();
+ void Handle_NextLineShowText_Space();
+ void Handle_Invalid();
+
+ CPDF_Document* const m_pDocument;
+ CPDF_Dictionary* m_pPageResources;
+ CPDF_Dictionary* m_pParentResources;
+ CPDF_Dictionary* m_pResources;
+ CPDF_PageObjectHolder* m_pObjectHolder;
+ int m_Level;
+ CFX_Matrix m_mtContentToUser;
+ CFX_FloatRect m_BBox;
+ CPDF_ParseOptions m_Options;
+ ContentParam m_ParamBuf[PARAM_BUF_SIZE];
+ FX_DWORD m_ParamStartPos;
+ FX_DWORD m_ParamCount;
+ CPDF_StreamParser* m_pSyntax;
+ std::unique_ptr<CPDF_AllStates> m_pCurStates;
+ CPDF_ContentMark m_CurContentMark;
+ CFX_ArrayTemplate<CPDF_TextObject*> m_ClipTextList;
+ CPDF_TextObject* m_pLastTextObject;
+ FX_FLOAT m_DefFontSize;
+ FX_PATHPOINT* m_pPathPoints;
+ int m_PathPointCount;
+ int m_PathAllocSize;
+ FX_FLOAT m_PathStartX;
+ FX_FLOAT m_PathStartY;
+ FX_FLOAT m_PathCurrentX;
+ FX_FLOAT m_PathCurrentY;
+ int m_PathClipType;
+ CFX_ByteString m_LastImageName;
+ CPDF_Image* m_pLastImage;
+ CFX_BinaryBuf m_LastImageDict;
+ CFX_BinaryBuf m_LastImageData;
+ CPDF_Dictionary* m_pLastImageDict;
+ CPDF_Dictionary* m_pLastCloneImageDict;
+ FX_BOOL m_bReleaseLastDict;
+ FX_BOOL m_bSameLastDict;
+ FX_BOOL m_bColored;
+ FX_FLOAT m_Type3Data[6];
+ FX_BOOL m_bResourceMissing;
+ std::vector<std::unique_ptr<CPDF_AllStates>> m_StateStack;
+};
+class CPDF_ContentParser {
+ public:
+ enum ParseStatus { Ready, ToBeContinued, Done };
+
+ CPDF_ContentParser();
+ ~CPDF_ContentParser();
+
+ ParseStatus GetStatus() const { return m_Status; }
+ void Start(CPDF_Page* pPage, CPDF_ParseOptions* pOptions);
+ void Start(CPDF_Form* pForm,
+ CPDF_AllStates* pGraphicStates,
+ CFX_Matrix* pParentMatrix,
+ CPDF_Type3Char* pType3Char,
+ CPDF_ParseOptions* pOptions,
+ int level);
+ void Continue(IFX_Pause* pPause);
+
+ private:
+ enum InternalStage {
+ STAGE_GETCONTENT = 1,
+ STAGE_PARSE,
+ STAGE_CHECKCLIP,
+ };
+
+ ParseStatus m_Status;
+ InternalStage m_InternalStage;
+ CPDF_PageObjectHolder* m_pObjectHolder;
+ FX_BOOL m_bForm;
+ CPDF_ParseOptions m_Options;
+ CPDF_Type3Char* m_pType3Char;
+ FX_DWORD m_nStreams;
+ std::unique_ptr<CPDF_StreamAcc> m_pSingleStream;
+ std::vector<std::unique_ptr<CPDF_StreamAcc>> m_StreamArray;
+ uint8_t* m_pData;
+ FX_DWORD m_Size;
+ FX_DWORD m_CurrentOffset;
+ std::unique_ptr<CPDF_StreamContentParser> m_pParser;
+};
+class CPDF_AllStates : public CPDF_GraphicStates {
+ public:
+ CPDF_AllStates();
+ ~CPDF_AllStates();
+ void Copy(const CPDF_AllStates& src);
+ void ProcessExtGS(CPDF_Dictionary* pGS, CPDF_StreamContentParser* pParser);
+ void SetLineDash(CPDF_Array*, FX_FLOAT, FX_FLOAT scale);
+ CFX_Matrix m_TextMatrix, m_CTM, m_ParentMatrix;
+ FX_FLOAT m_TextX, m_TextY, m_TextLineX, m_TextLineY;
+ FX_FLOAT m_TextLeading, m_TextRise, m_TextHorzScale;
+};
+
+class CPDF_DocPageData {
+ public:
+ explicit CPDF_DocPageData(CPDF_Document* pPDFDoc);
+ ~CPDF_DocPageData();
+
+ void Clear(FX_BOOL bRelease = FALSE);
+ CPDF_Font* GetFont(CPDF_Dictionary* pFontDict, FX_BOOL findOnly);
+ CPDF_Font* GetStandardFont(const CFX_ByteStringC& fontName,
+ CPDF_FontEncoding* pEncoding);
+ void ReleaseFont(CPDF_Dictionary* pFontDict);
+ CPDF_ColorSpace* GetColorSpace(CPDF_Object* pCSObj,
+ const CPDF_Dictionary* pResources);
+ CPDF_ColorSpace* GetCopiedColorSpace(CPDF_Object* pCSObj);
+ void ReleaseColorSpace(CPDF_Object* pColorSpace);
+ CPDF_Pattern* GetPattern(CPDF_Object* pPatternObj,
+ FX_BOOL bShading,
+ const CFX_Matrix* matrix);
+ void ReleasePattern(CPDF_Object* pPatternObj);
+ CPDF_Image* GetImage(CPDF_Object* pImageStream);
+ void ReleaseImage(CPDF_Object* pImageStream);
+ CPDF_IccProfile* GetIccProfile(CPDF_Stream* pIccProfileStream);
+ void ReleaseIccProfile(CPDF_IccProfile* pIccProfile);
+ CPDF_StreamAcc* GetFontFileStreamAcc(CPDF_Stream* pFontStream);
+ void ReleaseFontFileStreamAcc(CPDF_Stream* pFontStream,
+ FX_BOOL bForce = FALSE);
+ FX_BOOL IsForceClear() const { return m_bForceClear; }
+ CPDF_CountedColorSpace* FindColorSpacePtr(CPDF_Object* pCSObj) const;
+ CPDF_CountedPattern* FindPatternPtr(CPDF_Object* pPatternObj) const;
+
+ private:
+ using CPDF_CountedFont = CPDF_CountedObject<CPDF_Font>;
+ using CPDF_CountedIccProfile = CPDF_CountedObject<CPDF_IccProfile>;
+ using CPDF_CountedImage = CPDF_CountedObject<CPDF_Image>;
+ using CPDF_CountedStreamAcc = CPDF_CountedObject<CPDF_StreamAcc>;
+
+ using CPDF_ColorSpaceMap = std::map<CPDF_Object*, CPDF_CountedColorSpace*>;
+ using CPDF_FontFileMap = std::map<CPDF_Stream*, CPDF_CountedStreamAcc*>;
+ using CPDF_FontMap = std::map<CPDF_Dictionary*, CPDF_CountedFont*>;
+ using CPDF_IccProfileMap = std::map<CPDF_Stream*, CPDF_CountedIccProfile*>;
+ using CPDF_ImageMap = std::map<FX_DWORD, CPDF_CountedImage*>;
+ using CPDF_PatternMap = std::map<CPDF_Object*, CPDF_CountedPattern*>;
+
+ CPDF_Document* const m_pPDFDoc;
+ FX_BOOL m_bForceClear;
+ std::map<CFX_ByteString, CPDF_Stream*> m_HashProfileMap;
+ CPDF_ColorSpaceMap m_ColorSpaceMap;
+ CPDF_FontFileMap m_FontFileMap;
+ CPDF_FontMap m_FontMap;
+ CPDF_IccProfileMap m_IccProfileMap;
+ CPDF_ImageMap m_ImageMap;
+ CPDF_PatternMap m_PatternMap;
+};
+
+class CPDF_Function {
+ public:
+ static CPDF_Function* Load(CPDF_Object* pFuncObj);
+ virtual ~CPDF_Function();
+ FX_BOOL Call(FX_FLOAT* inputs,
+ int ninputs,
+ FX_FLOAT* results,
+ int& nresults) const;
+ int CountInputs() { return m_nInputs; }
+ int CountOutputs() { return m_nOutputs; }
+
+ protected:
+ CPDF_Function();
+ int m_nInputs, m_nOutputs;
+ FX_FLOAT* m_pDomains;
+ FX_FLOAT* m_pRanges;
+ FX_BOOL Init(CPDF_Object* pObj);
+ virtual FX_BOOL v_Init(CPDF_Object* pObj) = 0;
+ virtual FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const = 0;
+};
+class CPDF_IccProfile {
+ public:
+ CPDF_IccProfile(const uint8_t* pData, FX_DWORD dwSize);
+ ~CPDF_IccProfile();
+ FX_DWORD GetComponents() const { return m_nSrcComponents; }
+ FX_BOOL m_bsRGB;
+ void* m_pTransform;
+
+ private:
+ FX_DWORD m_nSrcComponents;
+};
+
+class CPDF_DeviceCS : public CPDF_ColorSpace {
+ public:
+ CPDF_DeviceCS(CPDF_Document* pDoc, int family);
+
+ FX_BOOL GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const override;
+ FX_BOOL SetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT R,
+ FX_FLOAT G,
+ FX_FLOAT B) const override;
+ FX_BOOL v_GetCMYK(FX_FLOAT* pBuf,
+ FX_FLOAT& c,
+ FX_FLOAT& m,
+ FX_FLOAT& y,
+ FX_FLOAT& k) const override;
+ FX_BOOL v_SetCMYK(FX_FLOAT* pBuf,
+ FX_FLOAT c,
+ FX_FLOAT m,
+ FX_FLOAT y,
+ FX_FLOAT k) const override;
+ void TranslateImageLine(uint8_t* pDestBuf,
+ const uint8_t* pSrcBuf,
+ int pixels,
+ int image_width,
+ int image_height,
+ FX_BOOL bTransMask = FALSE) const override;
+};
+
+class CPDF_PatternCS : public CPDF_ColorSpace {
+ public:
+ explicit CPDF_PatternCS(CPDF_Document* pDoc)
+ : CPDF_ColorSpace(pDoc, PDFCS_PATTERN, 1),
+ m_pBaseCS(nullptr),
+ m_pCountedBaseCS(nullptr) {}
+ ~CPDF_PatternCS() override;
+ FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
+ FX_BOOL GetRGB(FX_FLOAT* pBuf,
+ FX_FLOAT& R,
+ FX_FLOAT& G,
+ FX_FLOAT& B) const override;
+ CPDF_ColorSpace* GetBaseCS() const override;
+
+ private:
+ CPDF_ColorSpace* m_pBaseCS;
+ CPDF_CountedColorSpace* m_pCountedBaseCS;
+};
+
+void PDF_ReplaceAbbr(CPDF_Object* pObj);
+bool IsPathOperator(const uint8_t* buf, size_t len);
+
+#endif // CORE_FPDFAPI_FPDF_PAGE_PAGEINT_H_