xref: /aosp_15_r20/external/pdfium/fpdfsdk/fpdf_flatten.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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