OLD | NEW |
1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
6 | 6 |
7 #include "public/fpdf_flatten.h" | 7 #include "public/fpdf_flatten.h" |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 | 10 |
11 #include "core/fpdfapi/page/cpdf_page.h" | 11 #include "core/fpdfapi/page/cpdf_page.h" |
12 #include "core/fpdfapi/page/cpdf_pageobject.h" | 12 #include "core/fpdfapi/page/cpdf_pageobject.h" |
13 #include "core/fpdfapi/parser/cpdf_array.h" | 13 #include "core/fpdfapi/parser/cpdf_array.h" |
14 #include "core/fpdfapi/parser/cpdf_document.h" | 14 #include "core/fpdfapi/parser/cpdf_document.h" |
| 15 #include "core/fpdfapi/parser/cpdf_name.h" |
15 #include "core/fpdfapi/parser/cpdf_number.h" | 16 #include "core/fpdfapi/parser/cpdf_number.h" |
16 #include "core/fpdfapi/parser/cpdf_reference.h" | 17 #include "core/fpdfapi/parser/cpdf_reference.h" |
17 #include "core/fpdfapi/parser/cpdf_stream.h" | 18 #include "core/fpdfapi/parser/cpdf_stream.h" |
18 #include "core/fpdfapi/parser/cpdf_stream_acc.h" | 19 #include "core/fpdfapi/parser/cpdf_stream_acc.h" |
19 #include "core/fpdfdoc/cpdf_annot.h" | 20 #include "core/fpdfdoc/cpdf_annot.h" |
20 #include "fpdfsdk/fsdk_define.h" | 21 #include "fpdfsdk/fsdk_define.h" |
21 #include "third_party/base/stl_util.h" | 22 #include "third_party/base/stl_util.h" |
22 | 23 |
23 enum FPDF_TYPE { MAX, MIN }; | 24 enum FPDF_TYPE { MAX, MIN }; |
24 enum FPDF_VALUE { TOP, LEFT, RIGHT, BOTTOM }; | 25 enum FPDF_VALUE { TOP, LEFT, RIGHT, BOTTOM }; |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 | 184 |
184 void SetPageContents(const CFX_ByteString& key, | 185 void SetPageContents(const CFX_ByteString& key, |
185 CPDF_Dictionary* pPage, | 186 CPDF_Dictionary* pPage, |
186 CPDF_Document* pDocument) { | 187 CPDF_Document* pDocument) { |
187 CPDF_Array* pContentsArray = nullptr; | 188 CPDF_Array* pContentsArray = nullptr; |
188 CPDF_Stream* pContentsStream = pPage->GetStreamFor("Contents"); | 189 CPDF_Stream* pContentsStream = pPage->GetStreamFor("Contents"); |
189 if (!pContentsStream) { | 190 if (!pContentsStream) { |
190 pContentsArray = pPage->GetArrayFor("Contents"); | 191 pContentsArray = pPage->GetArrayFor("Contents"); |
191 if (!pContentsArray) { | 192 if (!pContentsArray) { |
192 if (!key.IsEmpty()) { | 193 if (!key.IsEmpty()) { |
193 pPage->SetReferenceFor("Contents", pDocument, | 194 pPage->SetNewFor<CPDF_Reference>( |
194 NewIndirectContentsStream(key, pDocument)); | 195 "Contents", pDocument, NewIndirectContentsStream(key, pDocument)); |
195 } | 196 } |
196 return; | 197 return; |
197 } | 198 } |
198 } | 199 } |
199 pPage->ConvertToIndirectObjectFor("Contents", pDocument); | 200 pPage->ConvertToIndirectObjectFor("Contents", pDocument); |
200 if (!pContentsArray) { | 201 if (!pContentsArray) { |
201 pContentsArray = pDocument->NewIndirect<CPDF_Array>(); | 202 pContentsArray = pDocument->NewIndirect<CPDF_Array>(); |
202 CPDF_StreamAcc acc; | 203 CPDF_StreamAcc acc; |
203 acc.LoadAllData(pContentsStream); | 204 acc.LoadAllData(pContentsStream); |
204 CFX_ByteString sStream = "q\n"; | 205 CFX_ByteString sStream = "q\n"; |
205 CFX_ByteString sBody = | 206 CFX_ByteString sBody = |
206 CFX_ByteString((const FX_CHAR*)acc.GetData(), acc.GetSize()); | 207 CFX_ByteString((const FX_CHAR*)acc.GetData(), acc.GetSize()); |
207 sStream = sStream + sBody + "\nQ"; | 208 sStream = sStream + sBody + "\nQ"; |
208 pContentsStream->SetData(sStream.raw_str(), sStream.GetLength()); | 209 pContentsStream->SetData(sStream.raw_str(), sStream.GetLength()); |
209 pContentsArray->AddNew<CPDF_Reference>(pDocument, | 210 pContentsArray->AddNew<CPDF_Reference>(pDocument, |
210 pContentsStream->GetObjNum()); | 211 pContentsStream->GetObjNum()); |
211 pPage->SetReferenceFor("Contents", pDocument, pContentsArray); | 212 pPage->SetNewFor<CPDF_Reference>("Contents", pDocument, |
| 213 pContentsArray->GetObjNum()); |
212 } | 214 } |
213 if (!key.IsEmpty()) { | 215 if (!key.IsEmpty()) { |
214 pContentsArray->AddNew<CPDF_Reference>( | 216 pContentsArray->AddNew<CPDF_Reference>( |
215 pDocument, NewIndirectContentsStream(key, pDocument)); | 217 pDocument, NewIndirectContentsStream(key, pDocument)); |
216 } | 218 } |
217 } | 219 } |
218 | 220 |
219 CFX_Matrix GetMatrix(CFX_FloatRect rcAnnot, | 221 CFX_Matrix GetMatrix(CFX_FloatRect rcAnnot, |
220 CFX_FloatRect rcStream, | 222 CFX_FloatRect rcStream, |
221 const CFX_Matrix& matrix) { | 223 const CFX_Matrix& matrix) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 rcMerger.left = std::max(rcMerger.left, rcOriginalMB.left); | 266 rcMerger.left = std::max(rcMerger.left, rcOriginalMB.left); |
265 rcMerger.right = std::min(rcMerger.right, rcOriginalMB.right); | 267 rcMerger.right = std::min(rcMerger.right, rcOriginalMB.right); |
266 rcMerger.bottom = std::max(rcMerger.bottom, rcOriginalMB.bottom); | 268 rcMerger.bottom = std::max(rcMerger.bottom, rcOriginalMB.bottom); |
267 rcMerger.top = std::min(rcMerger.top, rcOriginalMB.top); | 269 rcMerger.top = std::min(rcMerger.top, rcOriginalMB.top); |
268 if (pPageDict->KeyExist("ArtBox")) | 270 if (pPageDict->KeyExist("ArtBox")) |
269 rcOriginalCB = pPageDict->GetRectFor("ArtBox"); | 271 rcOriginalCB = pPageDict->GetRectFor("ArtBox"); |
270 else | 272 else |
271 rcOriginalCB = rcOriginalMB; | 273 rcOriginalCB = rcOriginalMB; |
272 | 274 |
273 if (!rcOriginalMB.IsEmpty()) { | 275 if (!rcOriginalMB.IsEmpty()) { |
274 CPDF_Array* pMediaBox = new CPDF_Array(); | 276 CPDF_Array* pMediaBox = pPageDict->SetNewFor<CPDF_Array>("MediaBox"); |
275 pMediaBox->AddNew<CPDF_Number>(rcOriginalMB.left); | 277 pMediaBox->AddNew<CPDF_Number>(rcOriginalMB.left); |
276 pMediaBox->AddNew<CPDF_Number>(rcOriginalMB.bottom); | 278 pMediaBox->AddNew<CPDF_Number>(rcOriginalMB.bottom); |
277 pMediaBox->AddNew<CPDF_Number>(rcOriginalMB.right); | 279 pMediaBox->AddNew<CPDF_Number>(rcOriginalMB.right); |
278 pMediaBox->AddNew<CPDF_Number>(rcOriginalMB.top); | 280 pMediaBox->AddNew<CPDF_Number>(rcOriginalMB.top); |
279 pPageDict->SetFor("MediaBox", pMediaBox); | |
280 } | 281 } |
281 | 282 |
282 if (!rcOriginalCB.IsEmpty()) { | 283 if (!rcOriginalCB.IsEmpty()) { |
283 CPDF_Array* pCropBox = new CPDF_Array(); | 284 CPDF_Array* pCropBox = pPageDict->SetNewFor<CPDF_Array>("ArtBox"); |
284 pCropBox->AddNew<CPDF_Number>(rcOriginalCB.left); | 285 pCropBox->AddNew<CPDF_Number>(rcOriginalCB.left); |
285 pCropBox->AddNew<CPDF_Number>(rcOriginalCB.bottom); | 286 pCropBox->AddNew<CPDF_Number>(rcOriginalCB.bottom); |
286 pCropBox->AddNew<CPDF_Number>(rcOriginalCB.right); | 287 pCropBox->AddNew<CPDF_Number>(rcOriginalCB.right); |
287 pCropBox->AddNew<CPDF_Number>(rcOriginalCB.top); | 288 pCropBox->AddNew<CPDF_Number>(rcOriginalCB.top); |
288 pPageDict->SetFor("ArtBox", pCropBox); | |
289 } | 289 } |
290 | 290 |
291 CPDF_Dictionary* pRes = pPageDict->GetDictFor("Resources"); | 291 CPDF_Dictionary* pRes = pPageDict->GetDictFor("Resources"); |
292 if (!pRes) { | 292 if (!pRes) |
293 pRes = new CPDF_Dictionary(pDocument->GetByteStringPool()); | 293 pRes = pPageDict->SetNewFor<CPDF_Dictionary>("Resources"); |
294 pPageDict->SetFor("Resources", pRes); | |
295 } | |
296 | 294 |
297 CPDF_Stream* pNewXObject = pDocument->NewIndirect<CPDF_Stream>( | 295 CPDF_Stream* pNewXObject = pDocument->NewIndirect<CPDF_Stream>( |
298 nullptr, 0, new CPDF_Dictionary(pDocument->GetByteStringPool())); | 296 nullptr, 0, new CPDF_Dictionary(pDocument->GetByteStringPool())); |
299 | 297 |
300 uint32_t dwObjNum = pNewXObject->GetObjNum(); | 298 uint32_t dwObjNum = pNewXObject->GetObjNum(); |
301 CPDF_Dictionary* pPageXObject = pRes->GetDictFor("XObject"); | 299 CPDF_Dictionary* pPageXObject = pRes->GetDictFor("XObject"); |
302 if (!pPageXObject) { | 300 if (!pPageXObject) |
303 pPageXObject = new CPDF_Dictionary(pDocument->GetByteStringPool()); | 301 pPageXObject = pRes->SetNewFor<CPDF_Dictionary>("XObject"); |
304 pRes->SetFor("XObject", pPageXObject); | |
305 } | |
306 | 302 |
307 CFX_ByteString key = ""; | 303 CFX_ByteString key = ""; |
308 int nStreams = pdfium::CollectionSize<int>(ObjectArray); | 304 int nStreams = pdfium::CollectionSize<int>(ObjectArray); |
309 if (nStreams > 0) { | 305 if (nStreams > 0) { |
310 for (int iKey = 0; /*iKey < 100*/; iKey++) { | 306 for (int iKey = 0; /*iKey < 100*/; iKey++) { |
311 char sExtend[5] = {}; | 307 char sExtend[5] = {}; |
312 FXSYS_itoa(iKey, sExtend, 10); | 308 FXSYS_itoa(iKey, sExtend, 10); |
313 key = CFX_ByteString("FFT") + CFX_ByteString(sExtend); | 309 key = CFX_ByteString("FFT") + CFX_ByteString(sExtend); |
314 if (!pPageXObject->KeyExist(key)) | 310 if (!pPageXObject->KeyExist(key)) |
315 break; | 311 break; |
316 } | 312 } |
317 } | 313 } |
318 | 314 |
319 SetPageContents(key, pPageDict, pDocument); | 315 SetPageContents(key, pPageDict, pDocument); |
320 | 316 |
321 CPDF_Dictionary* pNewXORes = nullptr; | 317 CPDF_Dictionary* pNewXORes = nullptr; |
322 if (!key.IsEmpty()) { | 318 if (!key.IsEmpty()) { |
323 pPageXObject->SetReferenceFor(key, pDocument, dwObjNum); | 319 pPageXObject->SetNewFor<CPDF_Reference>(key, pDocument, dwObjNum); |
324 CPDF_Dictionary* pNewOXbjectDic = pNewXObject->GetDict(); | 320 CPDF_Dictionary* pNewOXbjectDic = pNewXObject->GetDict(); |
325 pNewXORes = new CPDF_Dictionary(pDocument->GetByteStringPool()); | 321 pNewXORes = pNewOXbjectDic->SetNewFor<CPDF_Dictionary>("Resources"); |
326 pNewOXbjectDic->SetFor("Resources", pNewXORes); | 322 pNewOXbjectDic->SetNewFor<CPDF_Name>("Type", "XObject"); |
327 pNewOXbjectDic->SetNameFor("Type", "XObject"); | 323 pNewOXbjectDic->SetNewFor<CPDF_Name>("Subtype", "Form"); |
328 pNewOXbjectDic->SetNameFor("Subtype", "Form"); | 324 pNewOXbjectDic->SetNewFor<CPDF_Number>("FormType", 1); |
329 pNewOXbjectDic->SetIntegerFor("FormType", 1); | 325 pNewOXbjectDic->SetNewFor<CPDF_Name>("Name", "FRM"); |
330 pNewOXbjectDic->SetNameFor("Name", "FRM"); | |
331 CFX_FloatRect rcBBox = pPageDict->GetRectFor("ArtBox"); | 326 CFX_FloatRect rcBBox = pPageDict->GetRectFor("ArtBox"); |
332 pNewOXbjectDic->SetRectFor("BBox", rcBBox); | 327 pNewOXbjectDic->SetRectFor("BBox", rcBBox); |
333 } | 328 } |
334 | 329 |
335 for (int i = 0; i < nStreams; i++) { | 330 for (int i = 0; i < nStreams; i++) { |
336 CPDF_Dictionary* pAnnotDic = ObjectArray[i]; | 331 CPDF_Dictionary* pAnnotDic = ObjectArray[i]; |
337 if (!pAnnotDic) | 332 if (!pAnnotDic) |
338 continue; | 333 continue; |
339 | 334 |
340 CFX_FloatRect rcAnnot = pAnnotDic->GetRectFor("Rect"); | 335 CFX_FloatRect rcAnnot = pAnnotDic->GetRectFor("Rect"); |
341 rcAnnot.Normalize(); | 336 rcAnnot.Normalize(); |
342 | 337 |
343 CFX_ByteString sAnnotState = pAnnotDic->GetStringFor("AS"); | 338 CFX_ByteString sAnnotState = pAnnotDic->GetStringFor("AS"); |
344 CPDF_Dictionary* pAnnotAP = pAnnotDic->GetDictFor("AP"); | 339 CPDF_Dictionary* pAnnotAP = pAnnotDic->GetDictFor("AP"); |
345 if (!pAnnotAP) | 340 if (!pAnnotAP) |
346 continue; | 341 continue; |
347 | 342 |
348 CPDF_Stream* pAPStream = pAnnotAP->GetStreamFor("N"); | 343 CPDF_Stream* pAPStream = pAnnotAP->GetStreamFor("N"); |
349 if (!pAPStream) { | 344 if (!pAPStream) { |
350 CPDF_Dictionary* pAPDic = pAnnotAP->GetDictFor("N"); | 345 CPDF_Dictionary* pAPDic = pAnnotAP->GetDictFor("N"); |
351 if (!pAPDic) | 346 if (!pAPDic) |
352 continue; | 347 continue; |
353 | 348 |
354 if (!sAnnotState.IsEmpty()) { | 349 if (!sAnnotState.IsEmpty()) { |
355 pAPStream = pAPDic->GetStreamFor(sAnnotState); | 350 pAPStream = pAPDic->GetStreamFor(sAnnotState); |
356 } else { | 351 } else { |
357 auto it = pAPDic->begin(); | 352 auto it = pAPDic->begin(); |
358 if (it != pAPDic->end()) { | 353 if (it != pAPDic->end()) { |
359 CPDF_Object* pFirstObj = it->second; | 354 CPDF_Object* pFirstObj = it->second.get(); |
360 if (pFirstObj) { | 355 if (pFirstObj) { |
361 if (pFirstObj->IsReference()) | 356 if (pFirstObj->IsReference()) |
362 pFirstObj = pFirstObj->GetDirect(); | 357 pFirstObj = pFirstObj->GetDirect(); |
363 if (!pFirstObj->IsStream()) | 358 if (!pFirstObj->IsStream()) |
364 continue; | 359 continue; |
365 pAPStream = pFirstObj->AsStream(); | 360 pAPStream = pFirstObj->AsStream(); |
366 } | 361 } |
367 } | 362 } |
368 } | 363 } |
369 } | 364 } |
(...skipping 12 matching lines...) Expand all Loading... |
382 | 377 |
383 CPDF_Object* pObj = pAPStream; | 378 CPDF_Object* pObj = pAPStream; |
384 if (pObj->IsInline()) { | 379 if (pObj->IsInline()) { |
385 std::unique_ptr<CPDF_Object> pNew = pObj->Clone(); | 380 std::unique_ptr<CPDF_Object> pNew = pObj->Clone(); |
386 pObj = pNew.get(); | 381 pObj = pNew.get(); |
387 pDocument->AddIndirectObject(std::move(pNew)); | 382 pDocument->AddIndirectObject(std::move(pNew)); |
388 } | 383 } |
389 | 384 |
390 CPDF_Dictionary* pObjDic = pObj->GetDict(); | 385 CPDF_Dictionary* pObjDic = pObj->GetDict(); |
391 if (pObjDic) { | 386 if (pObjDic) { |
392 pObjDic->SetNameFor("Type", "XObject"); | 387 pObjDic->SetNewFor<CPDF_Name>("Type", "XObject"); |
393 pObjDic->SetNameFor("Subtype", "Form"); | 388 pObjDic->SetNewFor<CPDF_Name>("Subtype", "Form"); |
394 } | 389 } |
395 | 390 |
396 CPDF_Dictionary* pXObject = pNewXORes->GetDictFor("XObject"); | 391 CPDF_Dictionary* pXObject = pNewXORes->GetDictFor("XObject"); |
397 if (!pXObject) { | 392 if (!pXObject) |
398 pXObject = new CPDF_Dictionary(pDocument->GetByteStringPool()); | 393 pXObject = pNewXORes->SetNewFor<CPDF_Dictionary>("XObject"); |
399 pNewXORes->SetFor("XObject", pXObject); | |
400 } | |
401 | 394 |
402 CFX_ByteString sFormName; | 395 CFX_ByteString sFormName; |
403 sFormName.Format("F%d", i); | 396 sFormName.Format("F%d", i); |
404 pXObject->SetReferenceFor(sFormName, pDocument, pObj->GetObjNum()); | 397 pXObject->SetNewFor<CPDF_Reference>(sFormName, pDocument, |
| 398 pObj->GetObjNum()); |
405 | 399 |
406 CPDF_StreamAcc acc; | 400 CPDF_StreamAcc acc; |
407 acc.LoadAllData(pNewXObject); | 401 acc.LoadAllData(pNewXObject); |
408 | 402 |
409 const uint8_t* pData = acc.GetData(); | 403 const uint8_t* pData = acc.GetData(); |
410 CFX_ByteString sStream(pData, acc.GetSize()); | 404 CFX_ByteString sStream(pData, acc.GetSize()); |
411 CFX_Matrix matrix = pAPDic->GetMatrixFor("Matrix"); | 405 CFX_Matrix matrix = pAPDic->GetMatrixFor("Matrix"); |
412 if (matrix.IsIdentity()) { | 406 if (matrix.IsIdentity()) { |
413 matrix.a = 1.0f; | 407 matrix.a = 1.0f; |
414 matrix.b = 0.0f; | 408 matrix.b = 0.0f; |
415 matrix.c = 0.0f; | 409 matrix.c = 0.0f; |
416 matrix.d = 1.0f; | 410 matrix.d = 1.0f; |
417 matrix.e = 0.0f; | 411 matrix.e = 0.0f; |
418 matrix.f = 0.0f; | 412 matrix.f = 0.0f; |
419 } | 413 } |
420 | 414 |
421 CFX_ByteString sTemp; | 415 CFX_ByteString sTemp; |
422 CFX_Matrix m = GetMatrix(rcAnnot, rcStream, matrix); | 416 CFX_Matrix m = GetMatrix(rcAnnot, rcStream, matrix); |
423 sTemp.Format("q %f 0 0 %f %f %f cm /%s Do Q\n", m.a, m.d, m.e, m.f, | 417 sTemp.Format("q %f 0 0 %f %f %f cm /%s Do Q\n", m.a, m.d, m.e, m.f, |
424 sFormName.c_str()); | 418 sFormName.c_str()); |
425 sStream += sTemp; | 419 sStream += sTemp; |
426 pNewXObject->SetData(sStream.raw_str(), sStream.GetLength()); | 420 pNewXObject->SetData(sStream.raw_str(), sStream.GetLength()); |
427 } | 421 } |
428 pPageDict->RemoveFor("Annots"); | 422 pPageDict->RemoveFor("Annots"); |
429 return FLATTEN_SUCCESS; | 423 return FLATTEN_SUCCESS; |
430 } | 424 } |
OLD | NEW |