1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2014 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker
5*3ac0a46fSAndroid Build Coastguard Worker // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6*3ac0a46fSAndroid Build Coastguard Worker
7*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_flatten.h"
8*3ac0a46fSAndroid Build Coastguard Worker
9*3ac0a46fSAndroid Build Coastguard Worker #include <limits.h>
10*3ac0a46fSAndroid Build Coastguard Worker
11*3ac0a46fSAndroid Build Coastguard Worker #include <algorithm>
12*3ac0a46fSAndroid Build Coastguard Worker #include <sstream>
13*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
14*3ac0a46fSAndroid Build Coastguard Worker #include <vector>
15*3ac0a46fSAndroid Build Coastguard Worker
16*3ac0a46fSAndroid Build Coastguard Worker #include "constants/annotation_common.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "constants/annotation_flags.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "constants/page_object.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/edit/cpdf_contentstream_write_utils.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_page.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_pageobject.h"
22*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_array.h"
23*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_dictionary.h"
24*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_document.h"
25*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_name.h"
26*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_number.h"
27*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_reference.h"
28*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_stream.h"
29*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_stream_acc.h"
30*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/fpdf_parser_utility.h"
31*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfdoc/cpdf_annot.h"
32*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_string_wrappers.h"
33*3ac0a46fSAndroid Build Coastguard Worker #include "fpdfsdk/cpdfsdk_helpers.h"
34*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/notreached.h"
35*3ac0a46fSAndroid Build Coastguard Worker
36*3ac0a46fSAndroid Build Coastguard Worker enum FPDF_TYPE { MAX, MIN };
37*3ac0a46fSAndroid Build Coastguard Worker enum FPDF_VALUE { TOP, LEFT, RIGHT, BOTTOM };
38*3ac0a46fSAndroid Build Coastguard Worker
39*3ac0a46fSAndroid Build Coastguard Worker namespace {
40*3ac0a46fSAndroid Build Coastguard Worker
IsValidRect(const CFX_FloatRect & rect,const CFX_FloatRect & rcPage)41*3ac0a46fSAndroid Build Coastguard Worker bool IsValidRect(const CFX_FloatRect& rect, const CFX_FloatRect& rcPage) {
42*3ac0a46fSAndroid Build Coastguard Worker constexpr float kMinSize = 0.000001f;
43*3ac0a46fSAndroid Build Coastguard Worker if (rect.IsEmpty() || rect.Width() < kMinSize || rect.Height() < kMinSize)
44*3ac0a46fSAndroid Build Coastguard Worker return false;
45*3ac0a46fSAndroid Build Coastguard Worker
46*3ac0a46fSAndroid Build Coastguard Worker if (rcPage.IsEmpty())
47*3ac0a46fSAndroid Build Coastguard Worker return true;
48*3ac0a46fSAndroid Build Coastguard Worker
49*3ac0a46fSAndroid Build Coastguard Worker constexpr float kMinBorderSize = 10.000001f;
50*3ac0a46fSAndroid Build Coastguard Worker return rect.left - rcPage.left >= -kMinBorderSize &&
51*3ac0a46fSAndroid Build Coastguard Worker rect.right - rcPage.right <= kMinBorderSize &&
52*3ac0a46fSAndroid Build Coastguard Worker rect.top - rcPage.top <= kMinBorderSize &&
53*3ac0a46fSAndroid Build Coastguard Worker rect.bottom - rcPage.bottom >= -kMinBorderSize;
54*3ac0a46fSAndroid Build Coastguard Worker }
55*3ac0a46fSAndroid Build Coastguard Worker
GetContentsRect(CPDF_Document * pDoc,RetainPtr<CPDF_Dictionary> pDict,std::vector<CFX_FloatRect> * pRectArray)56*3ac0a46fSAndroid Build Coastguard Worker void GetContentsRect(CPDF_Document* pDoc,
57*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pDict,
58*3ac0a46fSAndroid Build Coastguard Worker std::vector<CFX_FloatRect>* pRectArray) {
59*3ac0a46fSAndroid Build Coastguard Worker auto pPDFPage = pdfium::MakeRetain<CPDF_Page>(pDoc, pDict);
60*3ac0a46fSAndroid Build Coastguard Worker pPDFPage->ParseContent();
61*3ac0a46fSAndroid Build Coastguard Worker
62*3ac0a46fSAndroid Build Coastguard Worker for (const auto& pPageObject : *pPDFPage) {
63*3ac0a46fSAndroid Build Coastguard Worker const CFX_FloatRect& rc = pPageObject->GetRect();
64*3ac0a46fSAndroid Build Coastguard Worker if (IsValidRect(rc, pDict->GetRectFor(pdfium::page_object::kMediaBox)))
65*3ac0a46fSAndroid Build Coastguard Worker pRectArray->push_back(rc);
66*3ac0a46fSAndroid Build Coastguard Worker }
67*3ac0a46fSAndroid Build Coastguard Worker }
68*3ac0a46fSAndroid Build Coastguard Worker
ParserStream(const CPDF_Dictionary * pPageDic,CPDF_Dictionary * pStream,std::vector<CFX_FloatRect> * pRectArray,std::vector<CPDF_Dictionary * > * pObjectArray)69*3ac0a46fSAndroid Build Coastguard Worker void ParserStream(const CPDF_Dictionary* pPageDic,
70*3ac0a46fSAndroid Build Coastguard Worker CPDF_Dictionary* pStream,
71*3ac0a46fSAndroid Build Coastguard Worker std::vector<CFX_FloatRect>* pRectArray,
72*3ac0a46fSAndroid Build Coastguard Worker std::vector<CPDF_Dictionary*>* pObjectArray) {
73*3ac0a46fSAndroid Build Coastguard Worker if (!pStream)
74*3ac0a46fSAndroid Build Coastguard Worker return;
75*3ac0a46fSAndroid Build Coastguard Worker CFX_FloatRect rect;
76*3ac0a46fSAndroid Build Coastguard Worker if (pStream->KeyExist("Rect"))
77*3ac0a46fSAndroid Build Coastguard Worker rect = pStream->GetRectFor("Rect");
78*3ac0a46fSAndroid Build Coastguard Worker else if (pStream->KeyExist("BBox"))
79*3ac0a46fSAndroid Build Coastguard Worker rect = pStream->GetRectFor("BBox");
80*3ac0a46fSAndroid Build Coastguard Worker
81*3ac0a46fSAndroid Build Coastguard Worker if (IsValidRect(rect, pPageDic->GetRectFor(pdfium::page_object::kMediaBox)))
82*3ac0a46fSAndroid Build Coastguard Worker pRectArray->push_back(rect);
83*3ac0a46fSAndroid Build Coastguard Worker
84*3ac0a46fSAndroid Build Coastguard Worker pObjectArray->push_back(pStream);
85*3ac0a46fSAndroid Build Coastguard Worker }
86*3ac0a46fSAndroid Build Coastguard Worker
ParserAnnots(CPDF_Document * pSourceDoc,RetainPtr<CPDF_Dictionary> pPageDic,std::vector<CFX_FloatRect> * pRectArray,std::vector<CPDF_Dictionary * > * pObjectArray,int nUsage)87*3ac0a46fSAndroid Build Coastguard Worker int ParserAnnots(CPDF_Document* pSourceDoc,
88*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pPageDic,
89*3ac0a46fSAndroid Build Coastguard Worker std::vector<CFX_FloatRect>* pRectArray,
90*3ac0a46fSAndroid Build Coastguard Worker std::vector<CPDF_Dictionary*>* pObjectArray,
91*3ac0a46fSAndroid Build Coastguard Worker int nUsage) {
92*3ac0a46fSAndroid Build Coastguard Worker if (!pSourceDoc)
93*3ac0a46fSAndroid Build Coastguard Worker return FLATTEN_FAIL;
94*3ac0a46fSAndroid Build Coastguard Worker
95*3ac0a46fSAndroid Build Coastguard Worker GetContentsRect(pSourceDoc, pPageDic, pRectArray);
96*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Array> pAnnots = pPageDic->GetArrayFor("Annots");
97*3ac0a46fSAndroid Build Coastguard Worker if (!pAnnots)
98*3ac0a46fSAndroid Build Coastguard Worker return FLATTEN_NOTHINGTODO;
99*3ac0a46fSAndroid Build Coastguard Worker
100*3ac0a46fSAndroid Build Coastguard Worker CPDF_ArrayLocker locker(pAnnots);
101*3ac0a46fSAndroid Build Coastguard Worker for (const auto& pAnnot : locker) {
102*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pAnnotDict =
103*3ac0a46fSAndroid Build Coastguard Worker ToDictionary(pAnnot->GetMutableDirect());
104*3ac0a46fSAndroid Build Coastguard Worker if (!pAnnotDict)
105*3ac0a46fSAndroid Build Coastguard Worker continue;
106*3ac0a46fSAndroid Build Coastguard Worker
107*3ac0a46fSAndroid Build Coastguard Worker ByteString sSubtype =
108*3ac0a46fSAndroid Build Coastguard Worker pAnnotDict->GetByteStringFor(pdfium::annotation::kSubtype);
109*3ac0a46fSAndroid Build Coastguard Worker if (sSubtype == "Popup")
110*3ac0a46fSAndroid Build Coastguard Worker continue;
111*3ac0a46fSAndroid Build Coastguard Worker
112*3ac0a46fSAndroid Build Coastguard Worker int nAnnotFlag = pAnnotDict->GetIntegerFor("F");
113*3ac0a46fSAndroid Build Coastguard Worker if (nAnnotFlag & pdfium::annotation_flags::kHidden)
114*3ac0a46fSAndroid Build Coastguard Worker continue;
115*3ac0a46fSAndroid Build Coastguard Worker
116*3ac0a46fSAndroid Build Coastguard Worker bool bParseStream;
117*3ac0a46fSAndroid Build Coastguard Worker if (nUsage == FLAT_NORMALDISPLAY)
118*3ac0a46fSAndroid Build Coastguard Worker bParseStream = !(nAnnotFlag & pdfium::annotation_flags::kInvisible);
119*3ac0a46fSAndroid Build Coastguard Worker else
120*3ac0a46fSAndroid Build Coastguard Worker bParseStream = !!(nAnnotFlag & pdfium::annotation_flags::kPrint);
121*3ac0a46fSAndroid Build Coastguard Worker if (bParseStream)
122*3ac0a46fSAndroid Build Coastguard Worker ParserStream(pPageDic.Get(), pAnnotDict.Get(), pRectArray, pObjectArray);
123*3ac0a46fSAndroid Build Coastguard Worker }
124*3ac0a46fSAndroid Build Coastguard Worker return FLATTEN_SUCCESS;
125*3ac0a46fSAndroid Build Coastguard Worker }
126*3ac0a46fSAndroid Build Coastguard Worker
GetMinMaxValue(const std::vector<CFX_FloatRect> & array,FPDF_TYPE type,FPDF_VALUE value)127*3ac0a46fSAndroid Build Coastguard Worker float GetMinMaxValue(const std::vector<CFX_FloatRect>& array,
128*3ac0a46fSAndroid Build Coastguard Worker FPDF_TYPE type,
129*3ac0a46fSAndroid Build Coastguard Worker FPDF_VALUE value) {
130*3ac0a46fSAndroid Build Coastguard Worker if (array.empty())
131*3ac0a46fSAndroid Build Coastguard Worker return 0.0f;
132*3ac0a46fSAndroid Build Coastguard Worker
133*3ac0a46fSAndroid Build Coastguard Worker size_t nRects = array.size();
134*3ac0a46fSAndroid Build Coastguard Worker std::vector<float> pArray(nRects);
135*3ac0a46fSAndroid Build Coastguard Worker switch (value) {
136*3ac0a46fSAndroid Build Coastguard Worker case LEFT:
137*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < nRects; i++)
138*3ac0a46fSAndroid Build Coastguard Worker pArray[i] = array[i].left;
139*3ac0a46fSAndroid Build Coastguard Worker break;
140*3ac0a46fSAndroid Build Coastguard Worker case TOP:
141*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < nRects; i++)
142*3ac0a46fSAndroid Build Coastguard Worker pArray[i] = array[i].top;
143*3ac0a46fSAndroid Build Coastguard Worker break;
144*3ac0a46fSAndroid Build Coastguard Worker case RIGHT:
145*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < nRects; i++)
146*3ac0a46fSAndroid Build Coastguard Worker pArray[i] = array[i].right;
147*3ac0a46fSAndroid Build Coastguard Worker break;
148*3ac0a46fSAndroid Build Coastguard Worker case BOTTOM:
149*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < nRects; i++)
150*3ac0a46fSAndroid Build Coastguard Worker pArray[i] = array[i].bottom;
151*3ac0a46fSAndroid Build Coastguard Worker break;
152*3ac0a46fSAndroid Build Coastguard Worker }
153*3ac0a46fSAndroid Build Coastguard Worker
154*3ac0a46fSAndroid Build Coastguard Worker float fRet = pArray[0];
155*3ac0a46fSAndroid Build Coastguard Worker if (type == MAX) {
156*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 1; i < nRects; i++)
157*3ac0a46fSAndroid Build Coastguard Worker fRet = std::max(fRet, pArray[i]);
158*3ac0a46fSAndroid Build Coastguard Worker } else {
159*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 1; i < nRects; i++)
160*3ac0a46fSAndroid Build Coastguard Worker fRet = std::min(fRet, pArray[i]);
161*3ac0a46fSAndroid Build Coastguard Worker }
162*3ac0a46fSAndroid Build Coastguard Worker return fRet;
163*3ac0a46fSAndroid Build Coastguard Worker }
164*3ac0a46fSAndroid Build Coastguard Worker
CalculateRect(std::vector<CFX_FloatRect> * pRectArray)165*3ac0a46fSAndroid Build Coastguard Worker CFX_FloatRect CalculateRect(std::vector<CFX_FloatRect>* pRectArray) {
166*3ac0a46fSAndroid Build Coastguard Worker CFX_FloatRect rcRet;
167*3ac0a46fSAndroid Build Coastguard Worker
168*3ac0a46fSAndroid Build Coastguard Worker rcRet.left = GetMinMaxValue(*pRectArray, MIN, LEFT);
169*3ac0a46fSAndroid Build Coastguard Worker rcRet.top = GetMinMaxValue(*pRectArray, MAX, TOP);
170*3ac0a46fSAndroid Build Coastguard Worker rcRet.right = GetMinMaxValue(*pRectArray, MAX, RIGHT);
171*3ac0a46fSAndroid Build Coastguard Worker rcRet.bottom = GetMinMaxValue(*pRectArray, MIN, BOTTOM);
172*3ac0a46fSAndroid Build Coastguard Worker
173*3ac0a46fSAndroid Build Coastguard Worker return rcRet;
174*3ac0a46fSAndroid Build Coastguard Worker }
175*3ac0a46fSAndroid Build Coastguard Worker
GenerateFlattenedContent(const ByteString & key)176*3ac0a46fSAndroid Build Coastguard Worker ByteString GenerateFlattenedContent(const ByteString& key) {
177*3ac0a46fSAndroid Build Coastguard Worker return "q 1 0 0 1 0 0 cm /" + key + " Do Q";
178*3ac0a46fSAndroid Build Coastguard Worker }
179*3ac0a46fSAndroid Build Coastguard Worker
NewIndirectContentsStreamReference(CPDF_Document * pDocument,const ByteString & contents)180*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Reference> NewIndirectContentsStreamReference(
181*3ac0a46fSAndroid Build Coastguard Worker CPDF_Document* pDocument,
182*3ac0a46fSAndroid Build Coastguard Worker const ByteString& contents) {
183*3ac0a46fSAndroid Build Coastguard Worker auto pNewContents =
184*3ac0a46fSAndroid Build Coastguard Worker pDocument->NewIndirect<CPDF_Stream>(pDocument->New<CPDF_Dictionary>());
185*3ac0a46fSAndroid Build Coastguard Worker pNewContents->SetData(contents.raw_span());
186*3ac0a46fSAndroid Build Coastguard Worker return pNewContents->MakeReference(pDocument);
187*3ac0a46fSAndroid Build Coastguard Worker }
188*3ac0a46fSAndroid Build Coastguard Worker
SetPageContents(const ByteString & key,CPDF_Dictionary * pPage,CPDF_Document * pDocument)189*3ac0a46fSAndroid Build Coastguard Worker void SetPageContents(const ByteString& key,
190*3ac0a46fSAndroid Build Coastguard Worker CPDF_Dictionary* pPage,
191*3ac0a46fSAndroid Build Coastguard Worker CPDF_Document* pDocument) {
192*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Array> pContentsArray =
193*3ac0a46fSAndroid Build Coastguard Worker pPage->GetMutableArrayFor(pdfium::page_object::kContents);
194*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Stream> pContentsStream =
195*3ac0a46fSAndroid Build Coastguard Worker pPage->GetMutableStreamFor(pdfium::page_object::kContents);
196*3ac0a46fSAndroid Build Coastguard Worker if (!pContentsStream && !pContentsArray) {
197*3ac0a46fSAndroid Build Coastguard Worker if (!key.IsEmpty()) {
198*3ac0a46fSAndroid Build Coastguard Worker pPage->SetFor(pdfium::page_object::kContents,
199*3ac0a46fSAndroid Build Coastguard Worker NewIndirectContentsStreamReference(
200*3ac0a46fSAndroid Build Coastguard Worker pDocument, GenerateFlattenedContent(key)));
201*3ac0a46fSAndroid Build Coastguard Worker }
202*3ac0a46fSAndroid Build Coastguard Worker return;
203*3ac0a46fSAndroid Build Coastguard Worker }
204*3ac0a46fSAndroid Build Coastguard Worker
205*3ac0a46fSAndroid Build Coastguard Worker pPage->ConvertToIndirectObjectFor(pdfium::page_object::kContents, pDocument);
206*3ac0a46fSAndroid Build Coastguard Worker if (pContentsArray) {
207*3ac0a46fSAndroid Build Coastguard Worker pContentsArray->InsertAt(
208*3ac0a46fSAndroid Build Coastguard Worker 0, NewIndirectContentsStreamReference(pDocument, "q"));
209*3ac0a46fSAndroid Build Coastguard Worker pContentsArray->Append(NewIndirectContentsStreamReference(pDocument, "Q"));
210*3ac0a46fSAndroid Build Coastguard Worker } else {
211*3ac0a46fSAndroid Build Coastguard Worker ByteString sStream = "q\n";
212*3ac0a46fSAndroid Build Coastguard Worker {
213*3ac0a46fSAndroid Build Coastguard Worker auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pContentsStream);
214*3ac0a46fSAndroid Build Coastguard Worker pAcc->LoadAllDataFiltered();
215*3ac0a46fSAndroid Build Coastguard Worker sStream += ByteString(pAcc->GetSpan());
216*3ac0a46fSAndroid Build Coastguard Worker sStream += "\nQ";
217*3ac0a46fSAndroid Build Coastguard Worker }
218*3ac0a46fSAndroid Build Coastguard Worker pContentsStream->SetDataAndRemoveFilter(sStream.raw_span());
219*3ac0a46fSAndroid Build Coastguard Worker pContentsArray = pDocument->NewIndirect<CPDF_Array>();
220*3ac0a46fSAndroid Build Coastguard Worker pContentsArray->AppendNew<CPDF_Reference>(pDocument,
221*3ac0a46fSAndroid Build Coastguard Worker pContentsStream->GetObjNum());
222*3ac0a46fSAndroid Build Coastguard Worker pPage->SetNewFor<CPDF_Reference>(pdfium::page_object::kContents, pDocument,
223*3ac0a46fSAndroid Build Coastguard Worker pContentsArray->GetObjNum());
224*3ac0a46fSAndroid Build Coastguard Worker }
225*3ac0a46fSAndroid Build Coastguard Worker if (!key.IsEmpty()) {
226*3ac0a46fSAndroid Build Coastguard Worker pContentsArray->Append(NewIndirectContentsStreamReference(
227*3ac0a46fSAndroid Build Coastguard Worker pDocument, GenerateFlattenedContent(key)));
228*3ac0a46fSAndroid Build Coastguard Worker }
229*3ac0a46fSAndroid Build Coastguard Worker }
230*3ac0a46fSAndroid Build Coastguard Worker
GetMatrix(const CFX_FloatRect & rcAnnot,const CFX_FloatRect & rcStream,const CFX_Matrix & matrix)231*3ac0a46fSAndroid Build Coastguard Worker CFX_Matrix GetMatrix(const CFX_FloatRect& rcAnnot,
232*3ac0a46fSAndroid Build Coastguard Worker const CFX_FloatRect& rcStream,
233*3ac0a46fSAndroid Build Coastguard Worker const CFX_Matrix& matrix) {
234*3ac0a46fSAndroid Build Coastguard Worker if (rcStream.IsEmpty())
235*3ac0a46fSAndroid Build Coastguard Worker return CFX_Matrix();
236*3ac0a46fSAndroid Build Coastguard Worker
237*3ac0a46fSAndroid Build Coastguard Worker CFX_FloatRect rcTransformed = matrix.TransformRect(rcStream);
238*3ac0a46fSAndroid Build Coastguard Worker rcTransformed.Normalize();
239*3ac0a46fSAndroid Build Coastguard Worker
240*3ac0a46fSAndroid Build Coastguard Worker float a = rcAnnot.Width() / rcTransformed.Width();
241*3ac0a46fSAndroid Build Coastguard Worker float d = rcAnnot.Height() / rcTransformed.Height();
242*3ac0a46fSAndroid Build Coastguard Worker
243*3ac0a46fSAndroid Build Coastguard Worker float e = rcAnnot.left - rcTransformed.left * a;
244*3ac0a46fSAndroid Build Coastguard Worker float f = rcAnnot.bottom - rcTransformed.bottom * d;
245*3ac0a46fSAndroid Build Coastguard Worker return CFX_Matrix(a, 0.0f, 0.0f, d, e, f);
246*3ac0a46fSAndroid Build Coastguard Worker }
247*3ac0a46fSAndroid Build Coastguard Worker
248*3ac0a46fSAndroid Build Coastguard Worker } // namespace
249*3ac0a46fSAndroid Build Coastguard Worker
FPDFPage_Flatten(FPDF_PAGE page,int nFlag)250*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV FPDFPage_Flatten(FPDF_PAGE page, int nFlag) {
251*3ac0a46fSAndroid Build Coastguard Worker CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
252*3ac0a46fSAndroid Build Coastguard Worker if (!page)
253*3ac0a46fSAndroid Build Coastguard Worker return FLATTEN_FAIL;
254*3ac0a46fSAndroid Build Coastguard Worker
255*3ac0a46fSAndroid Build Coastguard Worker CPDF_Document* pDocument = pPage->GetDocument();
256*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pPageDict = pPage->GetMutableDict();
257*3ac0a46fSAndroid Build Coastguard Worker if (!pDocument)
258*3ac0a46fSAndroid Build Coastguard Worker return FLATTEN_FAIL;
259*3ac0a46fSAndroid Build Coastguard Worker
260*3ac0a46fSAndroid Build Coastguard Worker std::vector<CPDF_Dictionary*> ObjectArray;
261*3ac0a46fSAndroid Build Coastguard Worker std::vector<CFX_FloatRect> RectArray;
262*3ac0a46fSAndroid Build Coastguard Worker int iRet =
263*3ac0a46fSAndroid Build Coastguard Worker ParserAnnots(pDocument, pPageDict, &RectArray, &ObjectArray, nFlag);
264*3ac0a46fSAndroid Build Coastguard Worker if (iRet == FLATTEN_NOTHINGTODO || iRet == FLATTEN_FAIL)
265*3ac0a46fSAndroid Build Coastguard Worker return iRet;
266*3ac0a46fSAndroid Build Coastguard Worker
267*3ac0a46fSAndroid Build Coastguard Worker CFX_FloatRect rcMerger = CalculateRect(&RectArray);
268*3ac0a46fSAndroid Build Coastguard Worker CFX_FloatRect rcOriginalMB =
269*3ac0a46fSAndroid Build Coastguard Worker pPageDict->GetRectFor(pdfium::page_object::kMediaBox);
270*3ac0a46fSAndroid Build Coastguard Worker if (pPageDict->KeyExist(pdfium::page_object::kCropBox))
271*3ac0a46fSAndroid Build Coastguard Worker rcOriginalMB = pPageDict->GetRectFor(pdfium::page_object::kCropBox);
272*3ac0a46fSAndroid Build Coastguard Worker
273*3ac0a46fSAndroid Build Coastguard Worker rcOriginalMB.Normalize();
274*3ac0a46fSAndroid Build Coastguard Worker if (rcOriginalMB.IsEmpty())
275*3ac0a46fSAndroid Build Coastguard Worker rcOriginalMB = CFX_FloatRect(0.0f, 0.0f, 612.0f, 792.0f);
276*3ac0a46fSAndroid Build Coastguard Worker
277*3ac0a46fSAndroid Build Coastguard Worker CFX_FloatRect rcOriginalCB;
278*3ac0a46fSAndroid Build Coastguard Worker if (pPageDict->KeyExist(pdfium::page_object::kCropBox)) {
279*3ac0a46fSAndroid Build Coastguard Worker rcOriginalCB = pPageDict->GetRectFor(pdfium::page_object::kCropBox);
280*3ac0a46fSAndroid Build Coastguard Worker rcOriginalCB.Normalize();
281*3ac0a46fSAndroid Build Coastguard Worker }
282*3ac0a46fSAndroid Build Coastguard Worker if (rcOriginalCB.IsEmpty())
283*3ac0a46fSAndroid Build Coastguard Worker rcOriginalCB = rcOriginalMB;
284*3ac0a46fSAndroid Build Coastguard Worker
285*3ac0a46fSAndroid Build Coastguard Worker rcMerger.left = std::max(rcMerger.left, rcOriginalMB.left);
286*3ac0a46fSAndroid Build Coastguard Worker rcMerger.right = std::min(rcMerger.right, rcOriginalMB.right);
287*3ac0a46fSAndroid Build Coastguard Worker rcMerger.bottom = std::max(rcMerger.bottom, rcOriginalMB.bottom);
288*3ac0a46fSAndroid Build Coastguard Worker rcMerger.top = std::min(rcMerger.top, rcOriginalMB.top);
289*3ac0a46fSAndroid Build Coastguard Worker
290*3ac0a46fSAndroid Build Coastguard Worker pPageDict->SetRectFor(pdfium::page_object::kMediaBox, rcOriginalMB);
291*3ac0a46fSAndroid Build Coastguard Worker pPageDict->SetRectFor(pdfium::page_object::kCropBox, rcOriginalCB);
292*3ac0a46fSAndroid Build Coastguard Worker
293*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pRes =
294*3ac0a46fSAndroid Build Coastguard Worker pPageDict->GetOrCreateDictFor(pdfium::page_object::kResources);
295*3ac0a46fSAndroid Build Coastguard Worker auto pNewXObject =
296*3ac0a46fSAndroid Build Coastguard Worker pDocument->NewIndirect<CPDF_Stream>(pDocument->New<CPDF_Dictionary>());
297*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pPageXObject = pRes->GetOrCreateDictFor("XObject");
298*3ac0a46fSAndroid Build Coastguard Worker
299*3ac0a46fSAndroid Build Coastguard Worker ByteString key;
300*3ac0a46fSAndroid Build Coastguard Worker if (!ObjectArray.empty()) {
301*3ac0a46fSAndroid Build Coastguard Worker int i = 0;
302*3ac0a46fSAndroid Build Coastguard Worker while (i < INT_MAX) {
303*3ac0a46fSAndroid Build Coastguard Worker ByteString sKey = ByteString::Format("FFT%d", i);
304*3ac0a46fSAndroid Build Coastguard Worker if (!pPageXObject->KeyExist(sKey)) {
305*3ac0a46fSAndroid Build Coastguard Worker key = std::move(sKey);
306*3ac0a46fSAndroid Build Coastguard Worker break;
307*3ac0a46fSAndroid Build Coastguard Worker }
308*3ac0a46fSAndroid Build Coastguard Worker ++i;
309*3ac0a46fSAndroid Build Coastguard Worker }
310*3ac0a46fSAndroid Build Coastguard Worker }
311*3ac0a46fSAndroid Build Coastguard Worker
312*3ac0a46fSAndroid Build Coastguard Worker SetPageContents(key, pPageDict.Get(), pDocument);
313*3ac0a46fSAndroid Build Coastguard Worker
314*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pNewXORes;
315*3ac0a46fSAndroid Build Coastguard Worker if (!key.IsEmpty()) {
316*3ac0a46fSAndroid Build Coastguard Worker pPageXObject->SetNewFor<CPDF_Reference>(key, pDocument,
317*3ac0a46fSAndroid Build Coastguard Worker pNewXObject->GetObjNum());
318*3ac0a46fSAndroid Build Coastguard Worker
319*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pNewOXbjectDic = pNewXObject->GetMutableDict();
320*3ac0a46fSAndroid Build Coastguard Worker pNewXORes = pNewOXbjectDic->SetNewFor<CPDF_Dictionary>("Resources");
321*3ac0a46fSAndroid Build Coastguard Worker pNewOXbjectDic->SetNewFor<CPDF_Name>("Type", "XObject");
322*3ac0a46fSAndroid Build Coastguard Worker pNewOXbjectDic->SetNewFor<CPDF_Name>("Subtype", "Form");
323*3ac0a46fSAndroid Build Coastguard Worker pNewOXbjectDic->SetNewFor<CPDF_Number>("FormType", 1);
324*3ac0a46fSAndroid Build Coastguard Worker pNewOXbjectDic->SetRectFor("BBox", rcOriginalCB);
325*3ac0a46fSAndroid Build Coastguard Worker }
326*3ac0a46fSAndroid Build Coastguard Worker
327*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < ObjectArray.size(); ++i) {
328*3ac0a46fSAndroid Build Coastguard Worker CPDF_Dictionary* pAnnotDict = ObjectArray[i];
329*3ac0a46fSAndroid Build Coastguard Worker if (!pAnnotDict)
330*3ac0a46fSAndroid Build Coastguard Worker continue;
331*3ac0a46fSAndroid Build Coastguard Worker
332*3ac0a46fSAndroid Build Coastguard Worker CFX_FloatRect rcAnnot = pAnnotDict->GetRectFor(pdfium::annotation::kRect);
333*3ac0a46fSAndroid Build Coastguard Worker rcAnnot.Normalize();
334*3ac0a46fSAndroid Build Coastguard Worker
335*3ac0a46fSAndroid Build Coastguard Worker ByteString sAnnotState = pAnnotDict->GetByteStringFor("AS");
336*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pAnnotAP =
337*3ac0a46fSAndroid Build Coastguard Worker pAnnotDict->GetMutableDictFor(pdfium::annotation::kAP);
338*3ac0a46fSAndroid Build Coastguard Worker if (!pAnnotAP)
339*3ac0a46fSAndroid Build Coastguard Worker continue;
340*3ac0a46fSAndroid Build Coastguard Worker
341*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Stream> pAPStream = pAnnotAP->GetMutableStreamFor("N");
342*3ac0a46fSAndroid Build Coastguard Worker if (!pAPStream) {
343*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pAPDict = pAnnotAP->GetMutableDictFor("N");
344*3ac0a46fSAndroid Build Coastguard Worker if (!pAPDict)
345*3ac0a46fSAndroid Build Coastguard Worker continue;
346*3ac0a46fSAndroid Build Coastguard Worker
347*3ac0a46fSAndroid Build Coastguard Worker if (!sAnnotState.IsEmpty()) {
348*3ac0a46fSAndroid Build Coastguard Worker pAPStream = pAPDict->GetMutableStreamFor(sAnnotState);
349*3ac0a46fSAndroid Build Coastguard Worker } else {
350*3ac0a46fSAndroid Build Coastguard Worker if (pAPDict->size() > 0) {
351*3ac0a46fSAndroid Build Coastguard Worker CPDF_DictionaryLocker locker(pAPDict);
352*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Object> pFirstObj = locker.begin()->second;
353*3ac0a46fSAndroid Build Coastguard Worker if (pFirstObj) {
354*3ac0a46fSAndroid Build Coastguard Worker if (pFirstObj->IsReference())
355*3ac0a46fSAndroid Build Coastguard Worker pFirstObj = pFirstObj->GetMutableDirect();
356*3ac0a46fSAndroid Build Coastguard Worker if (!pFirstObj->IsStream())
357*3ac0a46fSAndroid Build Coastguard Worker continue;
358*3ac0a46fSAndroid Build Coastguard Worker pAPStream.Reset(pFirstObj->AsMutableStream());
359*3ac0a46fSAndroid Build Coastguard Worker }
360*3ac0a46fSAndroid Build Coastguard Worker }
361*3ac0a46fSAndroid Build Coastguard Worker }
362*3ac0a46fSAndroid Build Coastguard Worker }
363*3ac0a46fSAndroid Build Coastguard Worker if (!pAPStream)
364*3ac0a46fSAndroid Build Coastguard Worker continue;
365*3ac0a46fSAndroid Build Coastguard Worker
366*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Dictionary> pAPDict = pAPStream->GetDict();
367*3ac0a46fSAndroid Build Coastguard Worker CFX_FloatRect rcStream;
368*3ac0a46fSAndroid Build Coastguard Worker if (pAPDict->KeyExist("Rect"))
369*3ac0a46fSAndroid Build Coastguard Worker rcStream = pAPDict->GetRectFor("Rect");
370*3ac0a46fSAndroid Build Coastguard Worker else if (pAPDict->KeyExist("BBox"))
371*3ac0a46fSAndroid Build Coastguard Worker rcStream = pAPDict->GetRectFor("BBox");
372*3ac0a46fSAndroid Build Coastguard Worker rcStream.Normalize();
373*3ac0a46fSAndroid Build Coastguard Worker
374*3ac0a46fSAndroid Build Coastguard Worker if (rcStream.IsEmpty())
375*3ac0a46fSAndroid Build Coastguard Worker continue;
376*3ac0a46fSAndroid Build Coastguard Worker
377*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Object> pObj = pAPStream;
378*3ac0a46fSAndroid Build Coastguard Worker if (pObj->IsInline()) {
379*3ac0a46fSAndroid Build Coastguard Worker pObj = pObj->Clone();
380*3ac0a46fSAndroid Build Coastguard Worker pDocument->AddIndirectObject(pObj);
381*3ac0a46fSAndroid Build Coastguard Worker }
382*3ac0a46fSAndroid Build Coastguard Worker
383*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pObjDict = pObj->GetMutableDict();
384*3ac0a46fSAndroid Build Coastguard Worker if (pObjDict) {
385*3ac0a46fSAndroid Build Coastguard Worker pObjDict->SetNewFor<CPDF_Name>("Type", "XObject");
386*3ac0a46fSAndroid Build Coastguard Worker pObjDict->SetNewFor<CPDF_Name>("Subtype", "Form");
387*3ac0a46fSAndroid Build Coastguard Worker }
388*3ac0a46fSAndroid Build Coastguard Worker
389*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pXObject =
390*3ac0a46fSAndroid Build Coastguard Worker pNewXORes->GetOrCreateDictFor("XObject");
391*3ac0a46fSAndroid Build Coastguard Worker ByteString sFormName = ByteString::Format("F%d", i);
392*3ac0a46fSAndroid Build Coastguard Worker pXObject->SetNewFor<CPDF_Reference>(sFormName, pDocument,
393*3ac0a46fSAndroid Build Coastguard Worker pObj->GetObjNum());
394*3ac0a46fSAndroid Build Coastguard Worker
395*3ac0a46fSAndroid Build Coastguard Worker ByteString sStream;
396*3ac0a46fSAndroid Build Coastguard Worker {
397*3ac0a46fSAndroid Build Coastguard Worker auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pNewXObject);
398*3ac0a46fSAndroid Build Coastguard Worker pAcc->LoadAllDataFiltered();
399*3ac0a46fSAndroid Build Coastguard Worker sStream = ByteString(pAcc->GetSpan());
400*3ac0a46fSAndroid Build Coastguard Worker }
401*3ac0a46fSAndroid Build Coastguard Worker CFX_Matrix matrix = pAPDict->GetMatrixFor("Matrix");
402*3ac0a46fSAndroid Build Coastguard Worker CFX_Matrix m = GetMatrix(rcAnnot, rcStream, matrix);
403*3ac0a46fSAndroid Build Coastguard Worker m.b = 0;
404*3ac0a46fSAndroid Build Coastguard Worker m.c = 0;
405*3ac0a46fSAndroid Build Coastguard Worker fxcrt::ostringstream buf;
406*3ac0a46fSAndroid Build Coastguard Worker WriteMatrix(buf, m);
407*3ac0a46fSAndroid Build Coastguard Worker ByteString str(buf);
408*3ac0a46fSAndroid Build Coastguard Worker sStream += ByteString::Format("q %s cm /%s Do Q\n", str.c_str(),
409*3ac0a46fSAndroid Build Coastguard Worker sFormName.c_str());
410*3ac0a46fSAndroid Build Coastguard Worker pNewXObject->SetDataAndRemoveFilter(sStream.raw_span());
411*3ac0a46fSAndroid Build Coastguard Worker }
412*3ac0a46fSAndroid Build Coastguard Worker pPageDict->RemoveFor("Annots");
413*3ac0a46fSAndroid Build Coastguard Worker return FLATTEN_SUCCESS;
414*3ac0a46fSAndroid Build Coastguard Worker }
415