From 381fc833ac9e6ea58762b7e7ac8b7f2129e8477f Mon Sep 17 00:00:00 2001 From: tsepez Date: Mon, 10 Oct 2016 14:06:44 -0700 Subject: Add method to convert to an indirect object in a dictionary. Avoid an assert which previously could only be overcome by removing/re-inserting. Back-fill a unit test for the equivalent Array method. BUG=654387 Review-Url: https://codereview.chromium.org/2403143002 --- core/fpdfapi/parser/cpdf_dictionary.cpp | 11 +++ core/fpdfapi/parser/cpdf_dictionary.h | 3 + core/fpdfapi/parser/cpdf_object_unittest.cpp | 30 ++++++ fpdfsdk/fpdf_flatten.cpp | 131 ++++++++------------------- 4 files changed, 82 insertions(+), 93 deletions(-) diff --git a/core/fpdfapi/parser/cpdf_dictionary.cpp b/core/fpdfapi/parser/cpdf_dictionary.cpp index 7ef5a53551..54aafd43b1 100644 --- a/core/fpdfapi/parser/cpdf_dictionary.cpp +++ b/core/fpdfapi/parser/cpdf_dictionary.cpp @@ -192,6 +192,17 @@ void CPDF_Dictionary::SetFor(const CFX_ByteString& key, CPDF_Object* pObj) { m_Map.erase(it); } +void CPDF_Dictionary::ConvertToIndirectObjectFor( + const CFX_ByteString& key, + CPDF_IndirectObjectHolder* pHolder) { + auto it = m_Map.find(key); + if (it == m_Map.end() || it->second->IsReference()) + return; + + uint32_t objnum = pHolder->AddIndirectObject(it->second); + it->second = new CPDF_Reference(pHolder, objnum); +} + void CPDF_Dictionary::RemoveFor(const CFX_ByteString& key) { auto it = m_Map.find(key); if (it == m_Map.end()) diff --git a/core/fpdfapi/parser/cpdf_dictionary.h b/core/fpdfapi/parser/cpdf_dictionary.h index 23f2e0e3ca..b56e40a6ef 100644 --- a/core/fpdfapi/parser/cpdf_dictionary.h +++ b/core/fpdfapi/parser/cpdf_dictionary.h @@ -70,6 +70,9 @@ class CPDF_Dictionary : public CPDF_Object { void SetMatrixFor(const CFX_ByteString& key, const CFX_Matrix& matrix); void SetBooleanFor(const CFX_ByteString& key, bool bValue); + void ConvertToIndirectObjectFor(const CFX_ByteString& key, + CPDF_IndirectObjectHolder* pHolder); + // Invalidates iterators for the element with the key |key|. void RemoveFor(const CFX_ByteString& key); diff --git a/core/fpdfapi/parser/cpdf_object_unittest.cpp b/core/fpdfapi/parser/cpdf_object_unittest.cpp index b2177afd8a..502d2a06d2 100644 --- a/core/fpdfapi/parser/cpdf_object_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_object_unittest.cpp @@ -766,6 +766,21 @@ TEST(PDFArrayTest, CloneDirectObject) { EXPECT_FALSE(cloned_obj); } +TEST(PDFArrayTest, ConvertIndirect) { + CPDF_IndirectObjectHolder objects_holder; + ScopedArray array(new CPDF_Array); + CPDF_Object* pObj = new CPDF_Number(42); + array->Add(pObj); + array->ConvertToIndirectObjectAt(0, &objects_holder); + CPDF_Object* pRef = array->GetObjectAt(0); + CPDF_Object* pNum = array->GetDirectObjectAt(0); + EXPECT_TRUE(pRef->IsReference()); + EXPECT_TRUE(pNum->IsNumber()); + EXPECT_NE(pObj, pRef); + EXPECT_EQ(pObj, pNum); + EXPECT_EQ(42, array->GetIntegerAt(0)); +} + TEST(PDFDictionaryTest, CloneDirectObject) { CPDF_IndirectObjectHolder objects_holder; ScopedDict dict(new CPDF_Dictionary()); @@ -833,3 +848,18 @@ TEST(PDFObjectTest, CloneCheckLoop) { EXPECT_EQ(nullptr, cloned_arr->AsArray()->GetObjectAt(0)); } } + +TEST(PDFDictionaryTest, ConvertIndirect) { + CPDF_IndirectObjectHolder objects_holder; + ScopedDict dict(new CPDF_Dictionary); + CPDF_Object* pObj = new CPDF_Number(42); + dict->SetFor("clams", pObj); + dict->ConvertToIndirectObjectFor("clams", &objects_holder); + CPDF_Object* pRef = dict->GetObjectFor("clams"); + CPDF_Object* pNum = dict->GetDirectObjectFor("clams"); + EXPECT_TRUE(pRef->IsReference()); + EXPECT_TRUE(pNum->IsNumber()); + EXPECT_NE(pObj, pRef); + EXPECT_EQ(pObj, pNum); + EXPECT_EQ(42, dict->GetIntegerFor("clams")); +} diff --git a/fpdfsdk/fpdf_flatten.cpp b/fpdfsdk/fpdf_flatten.cpp index 854a99258f..251da34d39 100644 --- a/fpdfsdk/fpdf_flatten.cpp +++ b/fpdfsdk/fpdf_flatten.cpp @@ -24,6 +24,8 @@ typedef CFX_ArrayTemplate CPDF_RectArray; enum FPDF_TYPE { MAX, MIN }; enum FPDF_VALUE { TOP, LEFT, RIGHT, BOTTOM }; +namespace { + FX_BOOL IsValiableRect(CFX_FloatRect rect, CFX_FloatRect rcPage) { if (rect.left - rect.right > 0.000001f || rect.bottom - rect.top > 0.000001f) return FALSE; @@ -182,67 +184,48 @@ CFX_FloatRect CalculateRect(CPDF_RectArray* pRectArray) { return rcRet; } -void SetPageContents(CFX_ByteString key, +uint32_t NewIndirectContentsStream(const CFX_ByteString& key, + CPDF_Document* pDocument) { + CPDF_Stream* pNewContents = new CPDF_Stream( + nullptr, 0, new CPDF_Dictionary(pDocument->GetByteStringPool())); + CFX_ByteString sStream; + sStream.Format("q 1 0 0 1 0 0 cm /%s Do Q", key.c_str()); + pNewContents->SetData(sStream.raw_str(), sStream.GetLength()); + return pDocument->AddIndirectObject(pNewContents); +} + +void SetPageContents(const CFX_ByteString& key, CPDF_Dictionary* pPage, CPDF_Document* pDocument) { - CPDF_Object* pContentsObj = pPage->GetStreamFor("Contents"); - if (!pContentsObj) { - pContentsObj = pPage->GetArrayFor("Contents"); - } - - if (!pContentsObj) { - // Create a new contents dictionary - if (!key.IsEmpty()) { - CPDF_Stream* pNewContents = new CPDF_Stream( - nullptr, 0, new CPDF_Dictionary(pDocument->GetByteStringPool())); - CFX_ByteString sStream; - sStream.Format("q 1 0 0 1 0 0 cm /%s Do Q", key.c_str()); - pNewContents->SetData(sStream.raw_str(), sStream.GetLength()); - pPage->SetReferenceFor("Contents", pDocument, - pDocument->AddIndirectObject(pNewContents)); - } - return; - } - CPDF_Array* pContentsArray = nullptr; - switch (pContentsObj->GetType()) { - case CPDF_Object::STREAM: { - pContentsArray = new CPDF_Array; - CPDF_Stream* pContents = pContentsObj->AsStream(); - uint32_t dwObjNum = pDocument->AddIndirectObject(pContents); - CPDF_StreamAcc acc; - acc.LoadAllData(pContents); - CFX_ByteString sStream = "q\n"; - CFX_ByteString sBody = - CFX_ByteString((const FX_CHAR*)acc.GetData(), acc.GetSize()); - sStream = sStream + sBody + "\nQ"; - pContents->SetData(sStream.raw_str(), sStream.GetLength()); - pContentsArray->AddReference(pDocument, dwObjNum); - break; - } - - case CPDF_Object::ARRAY: { - pContentsArray = pContentsObj->AsArray(); - break; + CPDF_Stream* pContentsStream = pPage->GetStreamFor("Contents"); + if (!pContentsStream) { + pContentsArray = pPage->GetArrayFor("Contents"); + if (!pContentsArray) { + if (!key.IsEmpty()) { + pPage->SetReferenceFor("Contents", pDocument, + NewIndirectContentsStream(key, pDocument)); + } + return; } - default: - break; } - - if (!pContentsArray) - return; - - pPage->SetReferenceFor("Contents", pDocument, - pDocument->AddIndirectObject(pContentsArray)); - + pPage->ConvertToIndirectObjectFor("Contents", pDocument); + if (!pContentsArray) { + pContentsArray = new CPDF_Array; + CPDF_StreamAcc acc; + acc.LoadAllData(pContentsStream); + CFX_ByteString sStream = "q\n"; + CFX_ByteString sBody = + CFX_ByteString((const FX_CHAR*)acc.GetData(), acc.GetSize()); + sStream = sStream + sBody + "\nQ"; + pContentsStream->SetData(sStream.raw_str(), sStream.GetLength()); + pContentsArray->AddReference(pDocument, pContentsStream->GetObjNum()); + pPage->SetReferenceFor("Contents", pDocument, + pDocument->AddIndirectObject(pContentsArray)); + } if (!key.IsEmpty()) { - CPDF_Stream* pNewContents = new CPDF_Stream( - nullptr, 0, new CPDF_Dictionary(pDocument->GetByteStringPool())); - CFX_ByteString sStream; - sStream.Format("q 1 0 0 1 0 0 cm /%s Do Q", key.c_str()); - pNewContents->SetData(sStream.raw_str(), sStream.GetLength()); pContentsArray->AddReference(pDocument, - pDocument->AddIndirectObject(pNewContents)); + NewIndirectContentsStream(key, pDocument)); } } @@ -263,45 +246,7 @@ CFX_Matrix GetMatrix(CFX_FloatRect rcAnnot, return CFX_Matrix(a, 0, 0, d, e, f); } -void GetOffset(FX_FLOAT& fa, - FX_FLOAT& fd, - FX_FLOAT& fe, - FX_FLOAT& ff, - CFX_FloatRect rcAnnot, - CFX_FloatRect rcStream, - const CFX_Matrix& matrix) { - FX_FLOAT fStreamWidth = 0.0f; - FX_FLOAT fStreamHeight = 0.0f; - - if (matrix.a != 0 && matrix.d != 0) { - fStreamWidth = rcStream.right - rcStream.left; - fStreamHeight = rcStream.top - rcStream.bottom; - } else { - fStreamWidth = rcStream.top - rcStream.bottom; - fStreamHeight = rcStream.right - rcStream.left; - } - - FX_FLOAT x1 = - matrix.a * rcStream.left + matrix.c * rcStream.bottom + matrix.e; - FX_FLOAT y1 = - matrix.b * rcStream.left + matrix.d * rcStream.bottom + matrix.f; - FX_FLOAT x2 = matrix.a * rcStream.left + matrix.c * rcStream.top + matrix.e; - FX_FLOAT y2 = matrix.b * rcStream.left + matrix.d * rcStream.top + matrix.f; - FX_FLOAT x3 = - matrix.a * rcStream.right + matrix.c * rcStream.bottom + matrix.e; - FX_FLOAT y3 = - matrix.b * rcStream.right + matrix.d * rcStream.bottom + matrix.f; - FX_FLOAT x4 = matrix.a * rcStream.right + matrix.c * rcStream.top + matrix.e; - FX_FLOAT y4 = matrix.b * rcStream.right + matrix.d * rcStream.top + matrix.f; - - FX_FLOAT left = std::min(std::min(x1, x2), std::min(x3, x4)); - FX_FLOAT bottom = std::min(std::min(y1, y2), std::min(y3, y4)); - - fa = (rcAnnot.right - rcAnnot.left) / fStreamWidth; - fd = (rcAnnot.top - rcAnnot.bottom) / fStreamHeight; - fe = rcAnnot.left - left * fa; - ff = rcAnnot.bottom - bottom * fd; -} +} // namespace DLLEXPORT int STDCALL FPDFPage_Flatten(FPDF_PAGE page, int nFlag) { CPDF_Page* pPage = CPDFPageFromFPDFPage(page); -- cgit v1.2.3