• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h"
6 
7 #include "core/fpdfapi/cpdf_modulemgr.h"
8 #include "core/fpdfapi/font/cpdf_font.h"
9 #include "core/fpdfapi/page/cpdf_page.h"
10 #include "core/fpdfapi/page/cpdf_pathobject.h"
11 #include "core/fpdfapi/page/cpdf_textobject.h"
12 #include "core/fpdfapi/parser/cpdf_document.h"
13 #include "core/fpdfapi/parser/cpdf_parser.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/base/ptr_util.h"
16 
17 class CPDF_PageContentGeneratorTest : public testing::Test {
18  protected:
SetUp()19   void SetUp() override { CPDF_ModuleMgr::Get()->InitPageModule(); }
20 
TearDown()21   void TearDown() override { CPDF_ModuleMgr::Destroy(); }
22 
TestProcessPath(CPDF_PageContentGenerator * pGen,CFX_ByteTextBuf * buf,CPDF_PathObject * pPathObj)23   void TestProcessPath(CPDF_PageContentGenerator* pGen,
24                        CFX_ByteTextBuf* buf,
25                        CPDF_PathObject* pPathObj) {
26     pGen->ProcessPath(buf, pPathObj);
27   }
28 
TestGetResource(CPDF_PageContentGenerator * pGen,const CFX_ByteString & type,const CFX_ByteString & name)29   CPDF_Dictionary* TestGetResource(CPDF_PageContentGenerator* pGen,
30                                    const CFX_ByteString& type,
31                                    const CFX_ByteString& name) {
32     return pGen->m_pPage->m_pResources->GetDictFor(type)->GetDictFor(name);
33   }
34 
TestProcessText(CPDF_PageContentGenerator * pGen,CFX_ByteTextBuf * buf,CPDF_TextObject * pTextObj)35   void TestProcessText(CPDF_PageContentGenerator* pGen,
36                        CFX_ByteTextBuf* buf,
37                        CPDF_TextObject* pTextObj) {
38     pGen->ProcessText(buf, pTextObj);
39   }
40 };
41 
TEST_F(CPDF_PageContentGeneratorTest,ProcessRect)42 TEST_F(CPDF_PageContentGeneratorTest, ProcessRect) {
43   auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
44   pPathObj->m_Path.AppendRect(10, 5, 13, 30);
45   pPathObj->m_FillType = FXFILL_ALTERNATE;
46   pPathObj->m_bStroke = true;
47 
48   auto pTestPage = pdfium::MakeUnique<CPDF_Page>(nullptr, nullptr, false);
49   CPDF_PageContentGenerator generator(pTestPage.get());
50   CFX_ByteTextBuf buf;
51   TestProcessPath(&generator, &buf, pPathObj.get());
52   EXPECT_EQ("q 10 5 3 25 re B* Q\n", buf.MakeString());
53 
54   pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
55   pPathObj->m_Path.AppendPoint(CFX_PointF(0, 0), FXPT_TYPE::MoveTo, false);
56   pPathObj->m_Path.AppendPoint(CFX_PointF(5.2f, 0), FXPT_TYPE::LineTo, false);
57   pPathObj->m_Path.AppendPoint(CFX_PointF(5.2f, 3.78f), FXPT_TYPE::LineTo,
58                                false);
59   pPathObj->m_Path.AppendPoint(CFX_PointF(0, 3.78f), FXPT_TYPE::LineTo, true);
60   pPathObj->m_FillType = 0;
61   pPathObj->m_bStroke = false;
62   buf.Clear();
63 
64   TestProcessPath(&generator, &buf, pPathObj.get());
65   EXPECT_EQ("q 0 0 5.2 3.78 re n Q\n", buf.MakeString());
66 }
67 
TEST_F(CPDF_PageContentGeneratorTest,ProcessPath)68 TEST_F(CPDF_PageContentGeneratorTest, ProcessPath) {
69   auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
70   pPathObj->m_Path.AppendPoint(CFX_PointF(3.102f, 4.67f), FXPT_TYPE::MoveTo,
71                                false);
72   pPathObj->m_Path.AppendPoint(CFX_PointF(5.45f, 0.29f), FXPT_TYPE::LineTo,
73                                false);
74   pPathObj->m_Path.AppendPoint(CFX_PointF(4.24f, 3.15f), FXPT_TYPE::BezierTo,
75                                false);
76   pPathObj->m_Path.AppendPoint(CFX_PointF(4.65f, 2.98f), FXPT_TYPE::BezierTo,
77                                false);
78   pPathObj->m_Path.AppendPoint(CFX_PointF(3.456f, 0.24f), FXPT_TYPE::BezierTo,
79                                false);
80   pPathObj->m_Path.AppendPoint(CFX_PointF(10.6f, 11.15f), FXPT_TYPE::LineTo,
81                                false);
82   pPathObj->m_Path.AppendPoint(CFX_PointF(11, 12.5f), FXPT_TYPE::LineTo, false);
83   pPathObj->m_Path.AppendPoint(CFX_PointF(11.46f, 12.67f), FXPT_TYPE::BezierTo,
84                                false);
85   pPathObj->m_Path.AppendPoint(CFX_PointF(11.84f, 12.96f), FXPT_TYPE::BezierTo,
86                                false);
87   pPathObj->m_Path.AppendPoint(CFX_PointF(12, 13.64f), FXPT_TYPE::BezierTo,
88                                true);
89   pPathObj->m_FillType = FXFILL_WINDING;
90   pPathObj->m_bStroke = false;
91 
92   auto pTestPage = pdfium::MakeUnique<CPDF_Page>(nullptr, nullptr, false);
93   CPDF_PageContentGenerator generator(pTestPage.get());
94   CFX_ByteTextBuf buf;
95   TestProcessPath(&generator, &buf, pPathObj.get());
96   EXPECT_EQ(
97       "q 3.102 4.67 m 5.45 0.29 l 4.24 3.15 4.65 2.98 3.456 0.24 c 10.6 11.15 "
98       "l 11 12.5 l 11.46 12.67 11.84 12.96 12 13.64 c h f Q\n",
99       buf.MakeString());
100 }
101 
TEST_F(CPDF_PageContentGeneratorTest,ProcessGraphics)102 TEST_F(CPDF_PageContentGeneratorTest, ProcessGraphics) {
103   auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
104   pPathObj->m_Path.AppendPoint(CFX_PointF(1, 2), FXPT_TYPE::MoveTo, false);
105   pPathObj->m_Path.AppendPoint(CFX_PointF(3, 4), FXPT_TYPE::LineTo, false);
106   pPathObj->m_Path.AppendPoint(CFX_PointF(5, 6), FXPT_TYPE::LineTo, true);
107   pPathObj->m_FillType = FXFILL_WINDING;
108   pPathObj->m_bStroke = true;
109 
110   FX_FLOAT rgb[3] = {0.5f, 0.7f, 0.35f};
111   CPDF_ColorSpace* pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
112   pPathObj->m_ColorState.SetFillColor(pCS, rgb, 3);
113 
114   FX_FLOAT rgb2[3] = {1, 0.9f, 0};
115   pPathObj->m_ColorState.SetStrokeColor(pCS, rgb2, 3);
116   pPathObj->m_GeneralState.SetFillAlpha(0.5f);
117   pPathObj->m_GeneralState.SetStrokeAlpha(0.8f);
118 
119   auto pDoc = pdfium::MakeUnique<CPDF_Document>(nullptr);
120   pDoc->CreateNewDoc();
121   CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(0);
122   auto pTestPage = pdfium::MakeUnique<CPDF_Page>(pDoc.get(), pPageDict, false);
123   CPDF_PageContentGenerator generator(pTestPage.get());
124   CFX_ByteTextBuf buf;
125   TestProcessPath(&generator, &buf, pPathObj.get());
126   CFX_ByteString pathString = buf.MakeString();
127 
128   // Color RGB values used are integers divided by 255.
129   EXPECT_EQ("q 0.501961 0.701961 0.34902 rg 1 0.901961 0 RG /",
130             pathString.Left(48));
131   EXPECT_EQ(" gs 1 2 m 3 4 l 5 6 l h B Q\n", pathString.Right(28));
132   ASSERT_TRUE(pathString.GetLength() > 76);
133   CPDF_Dictionary* externalGS = TestGetResource(
134       &generator, "ExtGState", pathString.Mid(48, pathString.GetLength() - 76));
135   ASSERT_TRUE(externalGS);
136   EXPECT_EQ(0.5f, externalGS->GetNumberFor("ca"));
137   EXPECT_EQ(0.8f, externalGS->GetNumberFor("CA"));
138 
139   // Same path, now with a stroke.
140   pPathObj->m_GraphState.SetLineWidth(10.5f);
141   buf.Clear();
142   TestProcessPath(&generator, &buf, pPathObj.get());
143   CFX_ByteString pathString2 = buf.MakeString();
144   EXPECT_EQ("q 0.501961 0.701961 0.34902 rg 1 0.901961 0 RG 10.5 w /",
145             pathString2.Left(55));
146   EXPECT_EQ(" gs 1 2 m 3 4 l 5 6 l h B Q\n", pathString2.Right(28));
147 
148   // Compare with the previous (should use same dictionary for gs)
149   EXPECT_EQ(pathString.GetLength() + 7, pathString2.GetLength());
150   EXPECT_EQ(pathString.Mid(48, pathString.GetLength() - 76),
151             pathString2.Mid(55, pathString2.GetLength() - 83));
152 }
153 
TEST_F(CPDF_PageContentGeneratorTest,ProcessText)154 TEST_F(CPDF_PageContentGeneratorTest, ProcessText) {
155   auto pDoc = pdfium::MakeUnique<CPDF_Document>(nullptr);
156   pDoc->CreateNewDoc();
157   CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(0);
158   auto pTestPage = pdfium::MakeUnique<CPDF_Page>(pDoc.get(), pPageDict, false);
159   CPDF_PageContentGenerator generator(pTestPage.get());
160   auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
161   CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc.get(), "Times-Roman");
162   pTextObj->m_TextState.SetFont(pFont);
163   pTextObj->m_TextState.SetFontSize(10.0f);
164   pTextObj->Transform(CFX_Matrix(1, 0, 0, 1, 100, 100));
165   pTextObj->SetText("Hello World");
166   CFX_ByteTextBuf buf;
167   TestProcessText(&generator, &buf, pTextObj.get());
168   CFX_ByteString textString = buf.MakeString();
169   EXPECT_LT(61, textString.GetLength());
170   EXPECT_EQ("BT 1 0 0 1 100 100 Tm /", textString.Left(23));
171   EXPECT_EQ(" 10 Tf <48656C6C6F20576F726C64> Tj ET\n", textString.Right(38));
172   CPDF_Dictionary* fontDict = TestGetResource(
173       &generator, "Font", textString.Mid(23, textString.GetLength() - 61));
174   ASSERT_TRUE(fontDict);
175   EXPECT_EQ("Font", fontDict->GetStringFor("Type"));
176   EXPECT_EQ("Type1", fontDict->GetStringFor("Subtype"));
177   EXPECT_EQ("Times-Roman", fontDict->GetStringFor("BaseFont"));
178 }
179