diff options
Diffstat (limited to 'core/fpdfapi/edit')
-rw-r--r-- | core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp | 47 | ||||
-rw-r--r-- | core/fpdfapi/edit/cpdf_pagecontentgenerator.h | 8 | ||||
-rw-r--r-- | core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp | 46 |
3 files changed, 95 insertions, 6 deletions
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp index 9de97ee718..4de89a47de 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp @@ -9,12 +9,14 @@ #include <tuple> #include <utility> +#include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/page/cpdf_docpagedata.h" #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_imageobject.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/page/cpdf_path.h" #include "core/fpdfapi/page/cpdf_pathobject.h" +#include "core/fpdfapi/page/cpdf_textobject.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" @@ -63,6 +65,8 @@ void CPDF_PageContentGenerator::GenerateContent() { ProcessImage(&buf, pImageObject); else if (CPDF_PathObject* pPathObj = pPageObj->AsPath()) ProcessPath(&buf, pPathObj); + else if (CPDF_TextObject* pTextObj = pPageObj->AsText()) + ProcessText(&buf, pTextObj); } CPDF_Dictionary* pPageDict = m_pPage->m_pFormDict; CPDF_Object* pContent = @@ -240,3 +244,46 @@ bool CPDF_PageContentGenerator::GraphicsData::operator<( return fillAlpha < other.fillAlpha; return strokeAlpha < other.strokeAlpha; } + +bool CPDF_PageContentGenerator::FontData::operator<( + const FontData& other) const { + return baseFont < other.baseFont; +} + +// This method adds text to the buffer, BT begins the text object, ET ends it. +// Tm sets the text matrix (allows positioning and transforming text). +// Tf sets the font name (from Font in Resources) and font size. +// Tj sets the actual text, <####...> is used when specifying charcodes. +void CPDF_PageContentGenerator::ProcessText(CFX_ByteTextBuf* buf, + CPDF_TextObject* pTextObj) { + // TODO(npm): Add support for something other than standard type1 fonts. + *buf << "BT " << pTextObj->GetTextMatrix() << " Tm "; + CPDF_Font* pFont = pTextObj->GetFont(); + if (!pFont) + pFont = CPDF_Font::GetStockFont(m_pDocument, "Helvetica"); + FontData fontD; + fontD.baseFont = pFont->GetBaseFont(); + auto it = m_FontsMap.find(fontD); + CFX_ByteString dictName; + if (it != m_FontsMap.end()) { + dictName = it->second; + } else { + auto fontDict = pdfium::MakeUnique<CPDF_Dictionary>(); + fontDict->SetNewFor<CPDF_Name>("Type", "Font"); + fontDict->SetNewFor<CPDF_Name>("Subtype", "Type1"); + fontDict->SetNewFor<CPDF_Name>("BaseFont", fontD.baseFont); + CPDF_Object* pDict = m_pDocument->AddIndirectObject(std::move(fontDict)); + uint32_t dwObjNum = pDict->GetObjNum(); + dictName = RealizeResource(dwObjNum, "Font"); + m_FontsMap[fontD] = dictName; + } + *buf << "/" << PDF_NameEncode(dictName) << " " << pTextObj->GetFontSize() + << " Tf "; + CFX_ByteString text; + for (uint32_t charcode : pTextObj->m_CharCodes) { + if (charcode == CPDF_Font::kInvalidCharCode) + continue; + pFont->AppendChar(text, charcode); + } + *buf << PDF_EncodeString(text, true) << " Tj ET\n"; +} diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h index e48ea4a7c9..fd80bd8f44 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h @@ -18,6 +18,7 @@ class CPDF_ImageObject; class CPDF_Page; class CPDF_PageObject; class CPDF_PathObject; +class CPDF_TextObject; class CPDF_PageContentGenerator { public: @@ -32,6 +33,7 @@ class CPDF_PageContentGenerator { void ProcessPath(CFX_ByteTextBuf* buf, CPDF_PathObject* pPathObj); void ProcessImage(CFX_ByteTextBuf* buf, CPDF_ImageObject* pImageObj); void ProcessGraphics(CFX_ByteTextBuf* buf, CPDF_PageObject* pPageObj); + void ProcessText(CFX_ByteTextBuf* buf, CPDF_TextObject* pTextObj); CFX_ByteString RealizeResource(uint32_t dwResourceObjNum, const CFX_ByteString& bsType); @@ -41,7 +43,13 @@ class CPDF_PageContentGenerator { bool operator<(const GraphicsData& other) const; }; + struct FontData { + CFX_ByteString baseFont; + bool operator<(const FontData& other) const; + }; + std::map<GraphicsData, CFX_ByteString> m_GraphicsMap; + std::map<FontData, CFX_ByteString> m_FontsMap; CPDF_Page* const m_pPage; CPDF_Document* const m_pDocument; std::vector<CPDF_PageObject*> m_pageObjects; diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp index 4846b1bd3c..0a636a1888 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp @@ -5,8 +5,10 @@ #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h" #include "core/fpdfapi/cpdf_modulemgr.h" +#include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/page/cpdf_pathobject.h" +#include "core/fpdfapi/page/cpdf_textobject.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_parser.h" #include "testing/gtest/include/gtest/gtest.h" @@ -24,10 +26,16 @@ class CPDF_PageContentGeneratorTest : public testing::Test { pGen->ProcessPath(buf, pPathObj); } - CPDF_Dictionary* TestGetGS(CPDF_PageContentGenerator* pGen, - const CFX_ByteString& name) { - return pGen->m_pPage->m_pResources->GetDictFor("ExtGState") - ->GetDictFor(name); + CPDF_Dictionary* TestGetResource(CPDF_PageContentGenerator* pGen, + const CFX_ByteString& type, + const CFX_ByteString& name) { + return pGen->m_pPage->m_pResources->GetDictFor(type)->GetDictFor(name); + } + + void TestProcessText(CPDF_PageContentGenerator* pGen, + CFX_ByteTextBuf* buf, + CPDF_TextObject* pTextObj) { + pGen->ProcessText(buf, pTextObj); } }; @@ -162,8 +170,8 @@ TEST_F(CPDF_PageContentGeneratorTest, ProcessGraphics) { pathString.Left(48)); EXPECT_EQ(" gs 1 2 m 3 4 l 5 6 l h B Q\n", pathString.Right(28)); ASSERT_TRUE(pathString.GetLength() > 76); - CPDF_Dictionary* externalGS = - TestGetGS(&generator, pathString.Mid(48, pathString.GetLength() - 76)); + CPDF_Dictionary* externalGS = TestGetResource( + &generator, "ExtGState", pathString.Mid(48, pathString.GetLength() - 76)); ASSERT_TRUE(externalGS); EXPECT_EQ(0.5f, externalGS->GetNumberFor("ca")); EXPECT_EQ(0.8f, externalGS->GetNumberFor("CA")); @@ -181,3 +189,29 @@ TEST_F(CPDF_PageContentGeneratorTest, ProcessGraphics) { EXPECT_EQ(pathString.Mid(48, pathString.GetLength() - 76), pathString2.Mid(55, pathString2.GetLength() - 83)); } + +TEST_F(CPDF_PageContentGeneratorTest, ProcessText) { + auto pDoc = pdfium::MakeUnique<CPDF_Document>(nullptr); + pDoc->CreateNewDoc(); + CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(0); + auto pTestPage = pdfium::MakeUnique<CPDF_Page>(pDoc.get(), pPageDict, false); + CPDF_PageContentGenerator generator(pTestPage.get()); + auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>(); + CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc.get(), "Times-Roman"); + pTextObj->m_TextState.SetFont(pFont); + pTextObj->m_TextState.SetFontSize(10.0f); + pTextObj->Transform(CFX_Matrix(1, 0, 0, 1, 100, 100)); + pTextObj->SetText("Hello World"); + CFX_ByteTextBuf buf; + TestProcessText(&generator, &buf, pTextObj.get()); + CFX_ByteString textString = buf.MakeString(); + EXPECT_LT(61, textString.GetLength()); + EXPECT_EQ("BT 1 0 0 1 100 100 Tm /", textString.Left(23)); + EXPECT_EQ(" 10 Tf <48656C6C6F20576F726C64> Tj ET\n", textString.Right(38)); + CPDF_Dictionary* fontDict = TestGetResource( + &generator, "Font", textString.Mid(23, textString.GetLength() - 61)); + ASSERT_TRUE(fontDict); + EXPECT_EQ("Font", fontDict->GetStringFor("Type")); + EXPECT_EQ("Type1", fontDict->GetStringFor("Subtype")); + EXPECT_EQ("Times-Roman", fontDict->GetStringFor("BaseFont")); +} |