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