From e858aa4b70db7408bda1aed71827d9eee1dd98c5 Mon Sep 17 00:00:00 2001 From: wileyrya Date: Wed, 31 May 2017 14:49:05 -0500 Subject: Fix content generation to only generate dirty page objects. BUG=pdfium:717 R=dsinclair@chromium.org,thestig@chromium.org Change-Id: I7e0e6fd301d40f9b5341d40cf11167b7748af243 Reviewed-on: https://pdfium-review.googlesource.com/6071 Reviewed-by: dsinclair Reviewed-by: Lei Zhang Commit-Queue: dsinclair --- core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp | 68 +++++++++++++++---- core/fpdfapi/edit/cpdf_pagecontentgenerator.h | 1 + core/fpdfapi/page/cpdf_imageobject.cpp | 1 + core/fpdfapi/page/cpdf_pageobject.cpp | 5 +- core/fpdfapi/page/cpdf_pageobject.h | 4 ++ core/fpdfapi/page/cpdf_pathobject.cpp | 1 + core/fpdfapi/page/cpdf_textobject.cpp | 2 + fpdfsdk/fpdfedit_embeddertest.cpp | 84 ++++++++++++++++++++++++ fpdfsdk/fpdfeditimg.cpp | 4 +- fpdfsdk/fpdfeditpage.cpp | 66 ++++++++++--------- fpdfsdk/fpdfeditpath.cpp | 9 +++ testing/resources/bug_717.pdf | Bin 0 -> 79942 bytes 12 files changed, 201 insertions(+), 44 deletions(-) create mode 100644 testing/resources/bug_717.pdf diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp index 2cf10bd7cb..7abf7a4964 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp @@ -17,6 +17,7 @@ #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_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" @@ -59,23 +60,49 @@ CPDF_PageContentGenerator::CPDF_PageContentGenerator(CPDF_Page* pPage) CPDF_PageContentGenerator::~CPDF_PageContentGenerator() {} void CPDF_PageContentGenerator::GenerateContent() { + CPDF_Document* pDoc = m_pDocument.Get(); CFX_ByteTextBuf buf; - for (auto& pPageObj : m_pageObjects) { - if (CPDF_ImageObject* pImageObject = pPageObj->AsImage()) - ProcessImage(&buf, pImageObject); - else if (CPDF_PathObject* pPathObj = pPageObj->AsPath()) - ProcessPath(&buf, pPathObj); - else if (CPDF_TextObject* pTextObj = pPageObj->AsText()) - ProcessText(&buf, pTextObj); + if (!m_pageObjects.empty()) { + if (!ProcessPageObjects(&buf)) + return; } CPDF_Dictionary* pPageDict = m_pPage->m_pFormDict.Get(); CPDF_Object* pContent = - pPageDict ? pPageDict->GetDirectObjectFor("Contents") : nullptr; - if (pContent) - pPageDict->RemoveFor("Contents"); - - CPDF_Stream* pStream = m_pDocument->NewIndirect(); + pPageDict ? pPageDict->GetObjectFor("Contents") : nullptr; + CPDF_Stream* pStream = pDoc->NewIndirect(); pStream->SetData(buf.GetBuffer(), buf.GetLength()); + if (pContent) { + CPDF_Array* pArray = ToArray(pContent); + if (pArray) { + pArray->AddNew(pDoc, pStream->GetObjNum()); + return; + } + CPDF_Reference* pReference = ToReference(pContent); + if (!pReference) { + pPageDict->SetNewFor("Contents", m_pDocument.Get(), + pStream->GetObjNum()); + return; + } + CPDF_Object* pDirectObj = pReference->GetDirect(); + if (!pDirectObj) { + pPageDict->SetNewFor("Contents", m_pDocument.Get(), + pStream->GetObjNum()); + return; + } + CPDF_Array* pObjArray = pDirectObj->AsArray(); + if (pObjArray) { + pObjArray->AddNew(pDoc, pStream->GetObjNum()); + return; + } + if (pDirectObj->IsStream()) { + CPDF_Array* pContentArray = pDoc->NewIndirect(); + pContentArray->AddNew(pDoc, pDirectObj->GetObjNum()); + pContentArray->AddNew(pDoc, pStream->GetObjNum()); + pPageDict->SetNewFor("Contents", pDoc, + pContentArray->GetObjNum()); + return; + } + } pPageDict->SetNewFor("Contents", m_pDocument.Get(), pStream->GetObjNum()); } @@ -107,6 +134,23 @@ CFX_ByteString CPDF_PageContentGenerator::RealizeResource( return name; } +bool CPDF_PageContentGenerator::ProcessPageObjects(CFX_ByteTextBuf* buf) { + bool bDirty = false; + for (auto& pPageObj : m_pageObjects) { + if (!pPageObj->IsDirty()) + continue; + bDirty = true; + if (CPDF_ImageObject* pImageObject = pPageObj->AsImage()) + ProcessImage(buf, pImageObject); + else if (CPDF_PathObject* pPathObj = pPageObj->AsPath()) + ProcessPath(buf, pPathObj); + else if (CPDF_TextObject* pTextObj = pPageObj->AsText()) + ProcessText(buf, pTextObj); + pPageObj->SetDirty(false); + } + return bDirty; +} + void CPDF_PageContentGenerator::ProcessImage(CFX_ByteTextBuf* buf, CPDF_ImageObject* pImageObj) { if ((pImageObj->matrix().a == 0 && pImageObj->matrix().b == 0) || diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h index 6c54d3130e..302375d536 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h @@ -30,6 +30,7 @@ class CPDF_PageContentGenerator { private: friend class CPDF_PageContentGeneratorTest; + bool ProcessPageObjects(CFX_ByteTextBuf* buf); void ProcessPath(CFX_ByteTextBuf* buf, CPDF_PathObject* pPathObj); void ProcessImage(CFX_ByteTextBuf* buf, CPDF_ImageObject* pImageObj); void ProcessGraphics(CFX_ByteTextBuf* buf, CPDF_PageObject* pPageObj); diff --git a/core/fpdfapi/page/cpdf_imageobject.cpp b/core/fpdfapi/page/cpdf_imageobject.cpp index 8732c00954..a74ac4802c 100644 --- a/core/fpdfapi/page/cpdf_imageobject.cpp +++ b/core/fpdfapi/page/cpdf_imageobject.cpp @@ -25,6 +25,7 @@ CPDF_PageObject::Type CPDF_ImageObject::GetType() const { void CPDF_ImageObject::Transform(const CFX_Matrix& matrix) { m_Matrix.Concat(matrix); CalcBoundingBox(); + SetDirty(true); } bool CPDF_ImageObject::IsImage() const { diff --git a/core/fpdfapi/page/cpdf_pageobject.cpp b/core/fpdfapi/page/cpdf_pageobject.cpp index 09a98eee7d..79d9bbc540 100644 --- a/core/fpdfapi/page/cpdf_pageobject.cpp +++ b/core/fpdfapi/page/cpdf_pageobject.cpp @@ -6,7 +6,7 @@ #include "core/fpdfapi/page/cpdf_pageobject.h" -CPDF_PageObject::CPDF_PageObject() {} +CPDF_PageObject::CPDF_PageObject() : m_bDirty(false) {} CPDF_PageObject::~CPDF_PageObject() {} @@ -76,18 +76,21 @@ void CPDF_PageObject::CopyData(const CPDF_PageObject* pSrc) { m_Right = pSrc->m_Right; m_Top = pSrc->m_Top; m_Bottom = pSrc->m_Bottom; + m_bDirty = true; } void CPDF_PageObject::TransformClipPath(CFX_Matrix& matrix) { if (!m_ClipPath.HasRef()) return; m_ClipPath.Transform(matrix); + SetDirty(true); } void CPDF_PageObject::TransformGeneralState(CFX_Matrix& matrix) { if (!m_GeneralState.HasRef()) return; m_GeneralState.GetMutableMatrix()->Concat(matrix); + SetDirty(true); } FX_RECT CPDF_PageObject::GetBBox(const CFX_Matrix* pMatrix) const { diff --git a/core/fpdfapi/page/cpdf_pageobject.h b/core/fpdfapi/page/cpdf_pageobject.h index 668621ff51..d23cd971f8 100644 --- a/core/fpdfapi/page/cpdf_pageobject.h +++ b/core/fpdfapi/page/cpdf_pageobject.h @@ -49,6 +49,8 @@ class CPDF_PageObject : public CPDF_GraphicStates { virtual CPDF_FormObject* AsForm(); virtual const CPDF_FormObject* AsForm() const; + void SetDirty(bool value) { m_bDirty = value; } + bool IsDirty() const { return m_bDirty; } void TransformClipPath(CFX_Matrix& matrix); void TransformGeneralState(CFX_Matrix& matrix); @@ -69,6 +71,8 @@ class CPDF_PageObject : public CPDF_GraphicStates { private: CPDF_PageObject(const CPDF_PageObject& src) = delete; void operator=(const CPDF_PageObject& src) = delete; + + bool m_bDirty; }; #endif // CORE_FPDFAPI_PAGE_CPDF_PAGEOBJECT_H_ diff --git a/core/fpdfapi/page/cpdf_pathobject.cpp b/core/fpdfapi/page/cpdf_pathobject.cpp index c4d55bc20f..b54ad6e151 100644 --- a/core/fpdfapi/page/cpdf_pathobject.cpp +++ b/core/fpdfapi/page/cpdf_pathobject.cpp @@ -17,6 +17,7 @@ CPDF_PageObject::Type CPDF_PathObject::GetType() const { void CPDF_PathObject::Transform(const CFX_Matrix& matrix) { m_Matrix.Concat(matrix); CalcBoundingBox(); + SetDirty(true); } bool CPDF_PathObject::IsPath() const { diff --git a/core/fpdfapi/page/cpdf_textobject.cpp b/core/fpdfapi/page/cpdf_textobject.cpp index b8f3f61073..7a70101789 100644 --- a/core/fpdfapi/page/cpdf_textobject.cpp +++ b/core/fpdfapi/page/cpdf_textobject.cpp @@ -115,6 +115,7 @@ void CPDF_TextObject::Transform(const CFX_Matrix& matrix) { pTextMatrix[3] = text_matrix.d; m_Pos = CFX_PointF(text_matrix.e, text_matrix.f); CalcPositionData(0); + SetDirty(true); } bool CPDF_TextObject::IsText() const { @@ -164,6 +165,7 @@ void CPDF_TextObject::SetSegments(const CFX_ByteString* pStrs, void CPDF_TextObject::SetText(const CFX_ByteString& str) { SetSegments(&str, nullptr, 1); RecalcPositionData(); + SetDirty(true); } float CPDF_TextObject::GetCharWidth(uint32_t charcode) const { diff --git a/fpdfsdk/fpdfedit_embeddertest.cpp b/fpdfsdk/fpdfedit_embeddertest.cpp index 6045618411..f52848c81d 100644 --- a/fpdfsdk/fpdfedit_embeddertest.cpp +++ b/fpdfsdk/fpdfedit_embeddertest.cpp @@ -368,6 +368,90 @@ TEST_F(FPDFEditEmbeddertest, PathOnTopOfText) { UnloadPage(page); } +TEST_F(FPDFEditEmbeddertest, EditOverExistingContent) { + // Load document with existing content + EXPECT_TRUE(OpenDocument("bug_717.pdf")); + FPDF_PAGE page = LoadPage(0); + EXPECT_NE(nullptr, page); + + // Add a transparent rectangle on top of the existing content + FPDF_PAGEOBJECT red_rect2 = FPDFPageObj_CreateNewRect(90, 700, 25, 50); + EXPECT_TRUE(FPDFPath_SetFillColor(red_rect2, 255, 0, 0, 100)); + EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect2, FPDF_FILLMODE_ALTERNATE, 0)); + FPDFPage_InsertObject(page, red_rect2); + + // Add an opaque rectangle on top of the existing content + FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(115, 700, 25, 50); + EXPECT_TRUE(FPDFPath_SetFillColor(red_rect, 255, 0, 0, 255)); + EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0)); + FPDFPage_InsertObject(page, red_rect); + + FPDF_BITMAP bitmap = RenderPage(page); + CompareBitmap(bitmap, 612, 792, "ad04e5bd0f471a9a564fb034bd0fb073"); + FPDFBitmap_Destroy(bitmap); + EXPECT_TRUE(FPDFPage_GenerateContent(page)); + + // Now save the result, closing the page and document + EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0)); + FPDF_ClosePage(page); + + // Render the saved result + std::string new_file = GetString(); + FPDF_FILEACCESS file_access; + memset(&file_access, 0, sizeof(file_access)); + file_access.m_FileLen = new_file.size(); + file_access.m_GetBlock = GetBlockFromString; + file_access.m_Param = &new_file; + FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr); + ASSERT_NE(nullptr, new_doc); + EXPECT_EQ(1, FPDF_GetPageCount(new_doc)); + FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0); + ASSERT_NE(nullptr, new_page); + FPDF_BITMAP new_bitmap = RenderPage(new_page); + CompareBitmap(new_bitmap, 612, 792, "ad04e5bd0f471a9a564fb034bd0fb073"); + FPDFBitmap_Destroy(new_bitmap); + + ClearString(); + // Add another opaque rectangle on top of the existing content + FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(150, 700, 25, 50); + EXPECT_TRUE(FPDFPath_SetFillColor(green_rect, 0, 255, 0, 255)); + EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_ALTERNATE, 0)); + FPDFPage_InsertObject(new_page, green_rect); + + // Add another transparent rectangle on top of existing content + FPDF_PAGEOBJECT green_rect2 = FPDFPageObj_CreateNewRect(175, 700, 25, 50); + EXPECT_TRUE(FPDFPath_SetFillColor(green_rect2, 0, 255, 0, 100)); + EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect2, FPDF_FILLMODE_ALTERNATE, 0)); + FPDFPage_InsertObject(new_page, green_rect2); + new_bitmap = RenderPage(new_page); + CompareBitmap(new_bitmap, 612, 792, "4b5b00f824620f8c9b8801ebb98e1cdd"); + FPDFBitmap_Destroy(new_bitmap); + EXPECT_TRUE(FPDFPage_GenerateContent(new_page)); + + // Now save the result, closing the page and document + EXPECT_TRUE(FPDF_SaveAsCopy(new_doc, this, 0)); + FPDF_ClosePage(new_page); + FPDF_CloseDocument(new_doc); + + // Render the saved result + new_file = GetString(); + memset(&file_access, 0, sizeof(file_access)); + file_access.m_FileLen = new_file.size(); + file_access.m_GetBlock = GetBlockFromString; + file_access.m_Param = &new_file; + new_doc = FPDF_LoadCustomDocument(&file_access, nullptr); + ASSERT_NE(nullptr, new_doc); + EXPECT_EQ(1, FPDF_GetPageCount(new_doc)); + new_page = FPDF_LoadPage(new_doc, 0); + ASSERT_NE(nullptr, new_page); + new_bitmap = RenderPage(new_page); + CompareBitmap(new_bitmap, 612, 792, "4b5b00f824620f8c9b8801ebb98e1cdd"); + FPDFBitmap_Destroy(new_bitmap); + + FPDF_ClosePage(new_page); + FPDF_CloseDocument(new_doc); +} + TEST_F(FPDFEditEmbeddertest, AddStrokedPaths) { // Start with a blank page FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792); diff --git a/fpdfsdk/fpdfeditimg.cpp b/fpdfsdk/fpdfeditimg.cpp index 9f4b2968ee..fdc98e06e9 100644 --- a/fpdfsdk/fpdfeditimg.cpp +++ b/fpdfsdk/fpdfeditimg.cpp @@ -39,7 +39,7 @@ bool LoadJpegHelper(FPDF_PAGE* pages, pImgObj->GetImage()->SetJpegImageInline(pFile); else pImgObj->GetImage()->SetJpegImage(pFile); - + pImgObj->SetDirty(true); return true; } @@ -87,6 +87,7 @@ DLLEXPORT FPDF_BOOL STDCALL FPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object, static_cast(c), static_cast(d), static_cast(e), static_cast(f))); pImgObj->CalcBoundingBox(); + pImgObj->SetDirty(true); return true; } @@ -106,5 +107,6 @@ DLLEXPORT FPDF_BOOL STDCALL FPDFImageObj_SetBitmap(FPDF_PAGE* pages, CFX_RetainPtr holder(CFXBitmapFromFPDFBitmap(bitmap)); pImgObj->GetImage()->SetImage(holder); pImgObj->CalcBoundingBox(); + pImgObj->SetDirty(true); return true; } diff --git a/fpdfsdk/fpdfeditpage.cpp b/fpdfsdk/fpdfeditpage.cpp index a474414435..da156cd790 100644 --- a/fpdfsdk/fpdfeditpage.cpp +++ b/fpdfsdk/fpdfeditpage.cpp @@ -61,6 +61,38 @@ bool IsPageObject(CPDF_Page* pPage) { return pObject && !pObject->GetString().Compare("Page"); } +void CalcBoundingBox(CPDF_PageObject* pPageObj) { + switch (pPageObj->GetType()) { + case CPDF_PageObject::TEXT: { + break; + } + case CPDF_PageObject::PATH: { + CPDF_PathObject* pPathObj = pPageObj->AsPath(); + pPathObj->CalcBoundingBox(); + break; + } + case CPDF_PageObject::IMAGE: { + CPDF_ImageObject* pImageObj = pPageObj->AsImage(); + pImageObj->CalcBoundingBox(); + break; + } + case CPDF_PageObject::SHADING: { + CPDF_ShadingObject* pShadingObj = pPageObj->AsShading(); + pShadingObj->CalcBoundingBox(); + break; + } + case CPDF_PageObject::FORM: { + CPDF_FormObject* pFormObj = pPageObj->AsForm(); + pFormObj->CalcBoundingBox(); + break; + } + default: { + NOTREACHED(); + break; + } + } +} + } // namespace DLLEXPORT FPDF_DOCUMENT STDCALL FPDF_CreateNewDocument() { @@ -144,37 +176,9 @@ DLLEXPORT void STDCALL FPDFPage_InsertObject(FPDF_PAGE page, CPDF_Page* pPage = CPDFPageFromFPDFPage(page); if (!IsPageObject(pPage)) return; - + pPageObj->SetDirty(true); pPage->GetPageObjectList()->push_back(std::move(pPageObjHolder)); - switch (pPageObj->GetType()) { - case CPDF_PageObject::TEXT: { - break; - } - case CPDF_PageObject::PATH: { - CPDF_PathObject* pPathObj = pPageObj->AsPath(); - pPathObj->CalcBoundingBox(); - break; - } - case CPDF_PageObject::IMAGE: { - CPDF_ImageObject* pImageObj = pPageObj->AsImage(); - pImageObj->CalcBoundingBox(); - break; - } - case CPDF_PageObject::SHADING: { - CPDF_ShadingObject* pShadingObj = pPageObj->AsShading(); - pShadingObj->CalcBoundingBox(); - break; - } - case CPDF_PageObject::FORM: { - CPDF_FormObject* pFormObj = pPageObj->AsForm(); - pFormObj->CalcBoundingBox(); - break; - } - default: { - NOTREACHED(); - break; - } - } + CalcBoundingBox(pPageObj); } DLLEXPORT int STDCALL FPDFPage_CountObject(FPDF_PAGE page) { @@ -271,6 +275,7 @@ DLLEXPORT void STDCALL FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object, return; pPageObj->m_GeneralState.SetBlendMode(blend_mode); + pPageObj->SetDirty(true); } DLLEXPORT void STDCALL FPDFPage_TransformAnnots(FPDF_PAGE page, @@ -327,6 +332,7 @@ FPDF_BOOL FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object, pPageObj->m_GeneralState.SetFillAlpha(A / 255.f); pPageObj->m_ColorState.SetFillColor( CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3); + pPageObj->SetDirty(true); return true; } diff --git a/fpdfsdk/fpdfeditpath.cpp b/fpdfsdk/fpdfeditpath.cpp index ad5ca9433f..f58d1e18a9 100644 --- a/fpdfsdk/fpdfeditpath.cpp +++ b/fpdfsdk/fpdfeditpath.cpp @@ -40,6 +40,7 @@ DLLEXPORT FPDF_BOOL FPDFPath_SetStrokeColor(FPDF_PAGEOBJECT path, pPathObj->m_GeneralState.SetStrokeAlpha(A / 255.f); pPathObj->m_ColorState.SetStrokeColor( CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3); + pPathObj->SetDirty(true); return true; } @@ -49,6 +50,7 @@ DLLEXPORT FPDF_BOOL FPDFPath_SetStrokeWidth(FPDF_PAGEOBJECT path, float width) { auto* pPathObj = static_cast(path); pPathObj->m_GraphState.SetLineWidth(width); + pPathObj->SetDirty(true); return true; } @@ -84,6 +86,7 @@ DLLEXPORT FPDF_BOOL FPDFPath_MoveTo(FPDF_PAGEOBJECT path, float x, float y) { auto* pPathObj = static_cast(path); pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::MoveTo, false); + pPathObj->SetDirty(true); return true; } @@ -93,6 +96,7 @@ DLLEXPORT FPDF_BOOL FPDFPath_LineTo(FPDF_PAGEOBJECT path, float x, float y) { auto* pPathObj = static_cast(path); pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::LineTo, false); + pPathObj->SetDirty(true); return true; } @@ -110,6 +114,7 @@ DLLEXPORT FPDF_BOOL FPDFPath_BezierTo(FPDF_PAGEOBJECT path, pPathObj->m_Path.AppendPoint(CFX_PointF(x1, y1), FXPT_TYPE::BezierTo, false); pPathObj->m_Path.AppendPoint(CFX_PointF(x2, y2), FXPT_TYPE::BezierTo, false); pPathObj->m_Path.AppendPoint(CFX_PointF(x3, y3), FXPT_TYPE::BezierTo, false); + pPathObj->SetDirty(true); return true; } @@ -122,6 +127,7 @@ DLLEXPORT FPDF_BOOL FPDFPath_Close(FPDF_PAGEOBJECT path) { return false; pPathObj->m_Path.ClosePath(); + pPathObj->SetDirty(true); return true; } @@ -140,6 +146,7 @@ DLLEXPORT FPDF_BOOL FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path, else pPathObj->m_FillType = 0; pPathObj->m_bStroke = stroke != 0; + pPathObj->SetDirty(true); return true; } @@ -157,6 +164,7 @@ DLLEXPORT void STDCALL FPDFPath_SetLineJoin(FPDF_PAGEOBJECT path, CFX_GraphStateData::LineJoin lineJoin = static_cast(line_join); pPathObj->m_GraphState.SetLineJoin(lineJoin); + pPathObj->SetDirty(true); } DLLEXPORT void STDCALL FPDFPath_SetLineCap(FPDF_PAGEOBJECT path, int line_cap) { @@ -170,4 +178,5 @@ DLLEXPORT void STDCALL FPDFPath_SetLineCap(FPDF_PAGEOBJECT path, int line_cap) { CFX_GraphStateData::LineCap lineCap = static_cast(line_cap); pPathObj->m_GraphState.SetLineCap(lineCap); + pPathObj->SetDirty(true); } diff --git a/testing/resources/bug_717.pdf b/testing/resources/bug_717.pdf new file mode 100644 index 0000000000..e3abd00e9e Binary files /dev/null and b/testing/resources/bug_717.pdf differ -- cgit v1.2.3