7#include "public/fpdf_flatten.h"
16#include "constants/annotation_common.h"
17#include "constants/annotation_flags.h"
18#include "constants/page_object.h"
19#include "core/fpdfapi/edit/cpdf_contentstream_write_utils.h"
20#include "core/fpdfapi/page/cpdf_page.h"
21#include "core/fpdfapi/page/cpdf_pageobject.h"
22#include "core/fpdfapi/parser/cpdf_array.h"
23#include "core/fpdfapi/parser/cpdf_dictionary.h"
24#include "core/fpdfapi/parser/cpdf_document.h"
25#include "core/fpdfapi/parser/cpdf_name.h"
26#include "core/fpdfapi/parser/cpdf_number.h"
27#include "core/fpdfapi/parser/cpdf_reference.h"
28#include "core/fpdfapi/parser/cpdf_stream.h"
29#include "core/fpdfapi/parser/cpdf_stream_acc.h"
30#include "core/fpdfapi/parser/fpdf_parser_utility.h"
31#include "core/fpdfdoc/cpdf_annot.h"
32#include "core/fxcrt/fx_string_wrappers.h"
33#include "fpdfsdk/cpdfsdk_helpers.h"
34#include "third_party/base/notreached.h"
42 constexpr float kMinSize = 0.000001f;
49 constexpr float kMinBorderSize = 10.000001f;
50 return rect
.left - rcPage
.left >= -kMinBorderSize &&
52 rect
.top - rcPage
.top <= kMinBorderSize &&
58 std::vector<CFX_FloatRect>* pRectArray) {
59 auto pPDFPage = pdfium::MakeRetain<CPDF_Page>(pDoc, pDict);
60 pPDFPage->ParseContent();
62 for (
const auto& pPageObject : *pPDFPage) {
63 const CFX_FloatRect& rc = pPageObject->GetRect();
64 if (IsValidRect(rc, pDict->GetRectFor(pdfium::page_object::kMediaBox)))
65 pRectArray->push_back(rc);
69void ParserStream(
const CPDF_Dictionary* pPageDic,
70 CPDF_Dictionary* pStream,
71 std::vector<CFX_FloatRect>* pRectArray,
72 std::vector<CPDF_Dictionary*>* pObjectArray) {
82 pRectArray->push_back(rect);
84 pObjectArray->push_back(pStream);
89 std::vector<CFX_FloatRect>* pRectArray,
90 std::vector<CPDF_Dictionary*>* pObjectArray,
95 GetContentsRect(pSourceDoc, pPageDic, pRectArray);
96 RetainPtr<
const CPDF_Array> pAnnots = pPageDic->GetArrayFor(
"Annots");
101 for (
const auto& pAnnot : locker) {
102 RetainPtr<CPDF_Dictionary> pAnnotDict =
103 ToDictionary(pAnnot->GetMutableDirect());
107 ByteString sSubtype =
108 pAnnotDict->GetByteStringFor(pdfium::annotation::kSubtype);
109 if (sSubtype ==
"Popup")
112 int nAnnotFlag = pAnnotDict->GetIntegerFor(
"F");
113 if (nAnnotFlag & pdfium::annotation_flags::kHidden)
118 bParseStream = !(nAnnotFlag & pdfium::annotation_flags::kInvisible);
120 bParseStream = !!(nAnnotFlag & pdfium::annotation_flags::kPrint);
122 ParserStream(pPageDic.Get(), pAnnotDict.Get(), pRectArray, pObjectArray);
127float GetMinMaxValue(
const std::vector<CFX_FloatRect>& array,
133 size_t nRects = array.size();
134 std::vector<
float> pArray(nRects);
137 for (size_t i = 0; i < nRects; i++)
138 pArray[i] = array[i].left;
141 for (size_t i = 0; i < nRects; i++)
142 pArray[i] = array[i].top;
145 for (size_t i = 0; i < nRects; i++)
146 pArray[i] = array[i].right;
149 for (size_t i = 0; i < nRects; i++)
150 pArray[i] = array[i].bottom;
154 float fRet = pArray[0];
156 for (size_t i = 1; i < nRects; i++)
157 fRet =
std::max(fRet, pArray[i]);
159 for (size_t i = 1; i < nRects; i++)
160 fRet =
std::min(fRet, pArray[i]);
165CFX_FloatRect CalculateRect(std::vector<CFX_FloatRect>* pRectArray) {
168 rcRet.left = GetMinMaxValue(*pRectArray, MIN, LEFT);
169 rcRet.top = GetMinMaxValue(*pRectArray, MAX, TOP);
170 rcRet.right = GetMinMaxValue(*pRectArray, MAX, RIGHT);
171 rcRet.bottom = GetMinMaxValue(*pRectArray, MIN, BOTTOM);
176ByteString GenerateFlattenedContent(
const ByteString& key) {
177 return "q 1 0 0 1 0 0 cm /" + key
+ " Do Q";
180RetainPtr<CPDF_Reference> NewIndirectContentsStreamReference(
182 const ByteString& contents) {
184 pDocument->NewIndirect<CPDF_Stream>(pDocument->New<CPDF_Dictionary>());
185 pNewContents->SetData(contents.raw_span());
186 return pNewContents->MakeReference(pDocument);
189void SetPageContents(
const ByteString& key,
190 CPDF_Dictionary* pPage,
193 pPage->GetMutableArrayFor(pdfium::page_object::kContents);
195 pPage->GetMutableStreamFor(pdfium::page_object::kContents);
196 if (!pContentsStream && !pContentsArray) {
198 pPage->SetFor(pdfium::page_object::kContents,
199 NewIndirectContentsStreamReference(
200 pDocument, GenerateFlattenedContent(key)));
206 if (pContentsArray) {
207 pContentsArray->InsertAt(
208 0, NewIndirectContentsStreamReference(pDocument,
"q"));
209 pContentsArray->Append(NewIndirectContentsStreamReference(pDocument,
"Q"));
211 ByteString sStream =
"q\n";
213 auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pContentsStream);
214 pAcc->LoadAllDataFiltered();
215 sStream
+= ByteString(pAcc->GetSpan());
218 pContentsStream->SetDataAndRemoveFilter(sStream.raw_span());
219 pContentsArray = pDocument->NewIndirect<CPDF_Array>();
220 pContentsArray->AppendNew<CPDF_Reference>(pDocument,
221 pContentsStream->GetObjNum());
223 pContentsArray->GetObjNum());
226 pContentsArray->Append(NewIndirectContentsStreamReference(
227 pDocument, GenerateFlattenedContent(key)));
243 float e = rcAnnot
.left - rcTransformed
.left * a;
256 RetainPtr<CPDF_Dictionary> pPageDict = pPage->GetMutableDict();
260 std::vector<CPDF_Dictionary*> ObjectArray;
261 std::vector<CFX_FloatRect> RectArray;
263 ParserAnnots(pDocument, pPageDict, &RectArray, &ObjectArray, nFlag);
283 rcOriginalCB
= rcOriginalMB;
294 pPageDict->GetOrCreateDictFor(pdfium::page_object::kResources);
296 pDocument->NewIndirect<CPDF_Stream>(pDocument->New<CPDF_Dictionary>());
297 RetainPtr<CPDF_Dictionary> pPageXObject = pRes->GetOrCreateDictFor(
"XObject");
300 if (!ObjectArray.empty()) {
302 while (i < INT_MAX) {
304 if (!pPageXObject->KeyExist(sKey)) {
305 key =
std::move(sKey);
312 SetPageContents(key, pPageDict.Get(), pDocument);
316 pPageXObject->SetNewFor<CPDF_Reference>(key, pDocument,
317 pNewXObject->GetObjNum());
319 RetainPtr<CPDF_Dictionary> pNewOXbjectDic = pNewXObject->GetMutableDict();
320 pNewXORes = pNewOXbjectDic->SetNewFor<CPDF_Dictionary>(
"Resources");
321 pNewOXbjectDic->SetNewFor<CPDF_Name>(
"Type",
"XObject");
322 pNewOXbjectDic->SetNewFor<CPDF_Name>(
"Subtype",
"Form");
323 pNewOXbjectDic->SetNewFor<CPDF_Number>(
"FormType", 1);
324 pNewOXbjectDic->SetRectFor(
"BBox", rcOriginalCB);
327 for (size_t i = 0; i < ObjectArray.size(); ++i) {
328 CPDF_Dictionary* pAnnotDict = ObjectArray[i];
337 pAnnotDict->GetMutableDictFor(pdfium::annotation::kAP);
341 RetainPtr<CPDF_Stream> pAPStream = pAnnotAP->GetMutableStreamFor(
"N");
343 RetainPtr<CPDF_Dictionary> pAPDict = pAnnotAP->GetMutableDictFor(
"N");
348 pAPStream = pAPDict->GetMutableStreamFor(sAnnotState);
350 if (pAPDict->size() > 0) {
354 if (pFirstObj->IsReference())
355 pFirstObj = pFirstObj->GetMutableDirect();
356 if (!pFirstObj->IsStream())
358 pAPStream.Reset(pFirstObj->AsMutableStream());
366 RetainPtr<
const CPDF_Dictionary> pAPDict = pAPStream->GetDict();
368 if (pAPDict->KeyExist(
"Rect"))
369 rcStream = pAPDict->GetRectFor(
"Rect");
370 else if (pAPDict->KeyExist(
"BBox"))
371 rcStream = pAPDict->GetRectFor(
"BBox");
378 if (pObj->IsInline()) {
379 pObj = pObj->Clone();
383 RetainPtr<CPDF_Dictionary> pObjDict = pObj->GetMutableDict();
385 pObjDict->SetNewFor<CPDF_Name>(
"Type",
"XObject");
386 pObjDict->SetNewFor<CPDF_Name>(
"Subtype",
"Form");
390 pNewXORes->GetOrCreateDictFor(
"XObject");
391 ByteString sFormName = ByteString
::Format("F%d", i
);
392 pXObject->SetNewFor<CPDF_Reference>(sFormName, pDocument,
397 auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pNewXObject);
398 pAcc->LoadAllDataFiltered();
399 sStream
= ByteString(pAcc->GetSpan());
401 CFX_Matrix matrix = pAPDict->GetMatrixFor(
"Matrix");
402 CFX_Matrix m = GetMatrix(rcAnnot, rcStream, matrix);
405 fxcrt::ostringstream buf;
410 pNewXObject->SetDataAndRemoveFilter(sStream.raw_span());
412 pPageDict->RemoveFor(
"Annots");
constexpr CFX_FloatRect(float l, float b, float r, float t)
CFX_FloatRect & operator=(const CFX_FloatRect &that)=default
CFX_FloatRect TransformRect(const CFX_FloatRect &rect) const
CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1)
bool KeyExist(const ByteString &key) const
void ConvertToIndirectObjectFor(const ByteString &key, CPDF_IndirectObjectHolder *pHolder)
ByteString GetByteStringFor(const ByteString &key) const
CFX_FloatRect GetRectFor(const ByteString &key) const
uint32_t AddIndirectObject(RetainPtr< CPDF_Object > pObj)
CPDF_Document * GetDocument() const override
static ByteString Format(const char *pFormat,...)
ByteString & operator+=(const ByteString &str)
ByteString & operator+=(const char *str)
const char * c_str() const
ByteString & operator=(ByteString &&that) noexcept
CPDF_Page * CPDFPageFromFPDFPage(FPDF_PAGE page)
FPDF_EXPORT int FPDF_CALLCONV FPDFPage_Flatten(FPDF_PAGE page, int nFlag)
#define FLATTEN_NOTHINGTODO
#define FLAT_NORMALDISPLAY
ByteString operator+(const ByteString &str1, const char *str2)
ByteString operator+(const char *str1, const ByteString &str2)