Chromium Code Reviews| 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_number.h" | 15 #include "core/fpdfapi/parser/cpdf_number.h" | 
| 16 #include "core/fpdfapi/parser/cpdf_stream.h" | 16 #include "core/fpdfapi/parser/cpdf_stream.h" | 
| 17 #include "core/fpdfapi/parser/cpdf_stream_acc.h" | 17 #include "core/fpdfapi/parser/cpdf_stream_acc.h" | 
| 18 #include "core/fpdfdoc/cpdf_annot.h" | 18 #include "core/fpdfdoc/cpdf_annot.h" | 
| 19 #include "fpdfsdk/fsdk_define.h" | 19 #include "fpdfsdk/fsdk_define.h" | 
| 20 | 20 | 
| 21 typedef CFX_ArrayTemplate<CPDF_Dictionary*> CPDF_ObjectArray; | 21 typedef CFX_ArrayTemplate<CPDF_Dictionary*> CPDF_ObjectArray; | 
| 22 typedef CFX_ArrayTemplate<CFX_FloatRect> CPDF_RectArray; | 22 typedef CFX_ArrayTemplate<CFX_FloatRect> CPDF_RectArray; | 
| 23 | 23 | 
| 24 enum FPDF_TYPE { MAX, MIN }; | 24 enum FPDF_TYPE { MAX, MIN }; | 
| 25 enum FPDF_VALUE { TOP, LEFT, RIGHT, BOTTOM }; | 25 enum FPDF_VALUE { TOP, LEFT, RIGHT, BOTTOM }; | 
| 26 | 26 | 
| 27 namespace { | |
| 28 | |
| 27 FX_BOOL IsValiableRect(CFX_FloatRect rect, CFX_FloatRect rcPage) { | 29 FX_BOOL IsValiableRect(CFX_FloatRect rect, CFX_FloatRect rcPage) { | 
| 28 if (rect.left - rect.right > 0.000001f || rect.bottom - rect.top > 0.000001f) | 30 if (rect.left - rect.right > 0.000001f || rect.bottom - rect.top > 0.000001f) | 
| 29 return FALSE; | 31 return FALSE; | 
| 30 | 32 | 
| 31 if (rect.left == 0.0f && rect.top == 0.0f && rect.right == 0.0f && | 33 if (rect.left == 0.0f && rect.top == 0.0f && rect.right == 0.0f && | 
| 32 rect.bottom == 0.0f) | 34 rect.bottom == 0.0f) | 
| 33 return FALSE; | 35 return FALSE; | 
| 34 | 36 | 
| 35 if (!rcPage.IsEmpty()) { | 37 if (!rcPage.IsEmpty()) { | 
| 36 if (rect.left - rcPage.left < -10.000001f || | 38 if (rect.left - rcPage.left < -10.000001f || | 
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 CFX_FloatRect rcRet; | 177 CFX_FloatRect rcRet; | 
| 176 | 178 | 
| 177 rcRet.left = GetMinMaxValue(*pRectArray, MIN, LEFT); | 179 rcRet.left = GetMinMaxValue(*pRectArray, MIN, LEFT); | 
| 178 rcRet.top = GetMinMaxValue(*pRectArray, MAX, TOP); | 180 rcRet.top = GetMinMaxValue(*pRectArray, MAX, TOP); | 
| 179 rcRet.right = GetMinMaxValue(*pRectArray, MAX, RIGHT); | 181 rcRet.right = GetMinMaxValue(*pRectArray, MAX, RIGHT); | 
| 180 rcRet.bottom = GetMinMaxValue(*pRectArray, MIN, BOTTOM); | 182 rcRet.bottom = GetMinMaxValue(*pRectArray, MIN, BOTTOM); | 
| 181 | 183 | 
| 182 return rcRet; | 184 return rcRet; | 
| 183 } | 185 } | 
| 184 | 186 | 
| 187 uint32_t NewIndirectContentsStream(const CFX_ByteString& key, | |
| 188 CPDF_Document* pDocument) { | |
| 189 CPDF_Stream* pNewContents = new CPDF_Stream( | |
| 190 nullptr, 0, new CPDF_Dictionary(pDocument->GetByteStringPool())); | |
| 191 CFX_ByteString sStream; | |
| 192 sStream.Format("q 1 0 0 1 0 0 cm /%s Do Q", key.c_str()); | |
| 193 pNewContents->SetData(sStream.raw_str(), sStream.GetLength()); | |
| 194 return pDocument->AddIndirectObject(pNewContents); | |
| 195 } | |
| 196 | |
| 185 void SetPageContents(CFX_ByteString key, | 197 void SetPageContents(CFX_ByteString key, | 
| 
 
Lei Zhang
2016/10/10 20:48:25
Pass by ref while we are here?
 
Tom Sepez
2016/10/10 20:51:45
Done.
 
 | |
| 186 CPDF_Dictionary* pPage, | 198 CPDF_Dictionary* pPage, | 
| 187 CPDF_Document* pDocument) { | 199 CPDF_Document* pDocument) { | 
| 188 CPDF_Object* pContentsObj = pPage->GetStreamFor("Contents"); | 200 CPDF_Array* pContentsArray = nullptr; | 
| 189 if (!pContentsObj) { | 201 CPDF_Stream* pContentsStream = pPage->GetStreamFor("Contents"); | 
| 190 pContentsObj = pPage->GetArrayFor("Contents"); | 202 if (!pContentsStream) { | 
| 203 pContentsArray = pPage->GetArrayFor("Contents"); | |
| 204 if (!pContentsArray) { | |
| 205 if (!key.IsEmpty()) { | |
| 206 pPage->SetReferenceFor("Contents", pDocument, | |
| 207 NewIndirectContentsStream(key, pDocument)); | |
| 208 } | |
| 209 return; | |
| 210 } | |
| 191 } | 211 } | 
| 192 | 212 pPage->ConvertToIndirectObjectFor("Contents", pDocument); | 
| 193 if (!pContentsObj) { | 213 if (!pContentsArray) { | 
| 194 // Create a new contents dictionary | 214 pContentsArray = new CPDF_Array; | 
| 195 if (!key.IsEmpty()) { | 215 CPDF_StreamAcc acc; | 
| 196 CPDF_Stream* pNewContents = new CPDF_Stream( | 216 acc.LoadAllData(pContentsStream); | 
| 197 nullptr, 0, new CPDF_Dictionary(pDocument->GetByteStringPool())); | 217 CFX_ByteString sStream = "q\n"; | 
| 198 CFX_ByteString sStream; | 218 CFX_ByteString sBody = | 
| 199 sStream.Format("q 1 0 0 1 0 0 cm /%s Do Q", key.c_str()); | 219 CFX_ByteString((const FX_CHAR*)acc.GetData(), acc.GetSize()); | 
| 200 pNewContents->SetData(sStream.raw_str(), sStream.GetLength()); | 220 sStream = sStream + sBody + "\nQ"; | 
| 201 pPage->SetReferenceFor("Contents", pDocument, | 221 pContentsStream->SetData(sStream.raw_str(), sStream.GetLength()); | 
| 202 pDocument->AddIndirectObject(pNewContents)); | 222 pContentsArray->AddReference(pDocument, pContentsStream->GetObjNum()); | 
| 203 } | 223 pPage->SetReferenceFor("Contents", pDocument, | 
| 204 return; | 224 pDocument->AddIndirectObject(pContentsArray)); | 
| 205 } | 225 } | 
| 206 | |
| 207 CPDF_Array* pContentsArray = nullptr; | |
| 208 switch (pContentsObj->GetType()) { | |
| 209 case CPDF_Object::STREAM: { | |
| 210 pContentsArray = new CPDF_Array; | |
| 211 CPDF_Stream* pContents = pContentsObj->AsStream(); | |
| 212 uint32_t dwObjNum = pDocument->AddIndirectObject(pContents); | |
| 213 CPDF_StreamAcc acc; | |
| 214 acc.LoadAllData(pContents); | |
| 215 CFX_ByteString sStream = "q\n"; | |
| 216 CFX_ByteString sBody = | |
| 217 CFX_ByteString((const FX_CHAR*)acc.GetData(), acc.GetSize()); | |
| 218 sStream = sStream + sBody + "\nQ"; | |
| 219 pContents->SetData(sStream.raw_str(), sStream.GetLength()); | |
| 220 pContentsArray->AddReference(pDocument, dwObjNum); | |
| 221 break; | |
| 222 } | |
| 223 | |
| 224 case CPDF_Object::ARRAY: { | |
| 225 pContentsArray = pContentsObj->AsArray(); | |
| 226 break; | |
| 227 } | |
| 228 default: | |
| 229 break; | |
| 230 } | |
| 231 | |
| 232 if (!pContentsArray) | |
| 233 return; | |
| 234 | |
| 235 pPage->SetReferenceFor("Contents", pDocument, | |
| 
 
Tom Sepez
2016/10/10 20:23:59
Noted: Order of make unique, delete, insert here w
 
 | |
| 236 pDocument->AddIndirectObject(pContentsArray)); | |
| 237 | |
| 238 if (!key.IsEmpty()) { | 226 if (!key.IsEmpty()) { | 
| 239 CPDF_Stream* pNewContents = new CPDF_Stream( | |
| 240 nullptr, 0, new CPDF_Dictionary(pDocument->GetByteStringPool())); | |
| 241 CFX_ByteString sStream; | |
| 242 sStream.Format("q 1 0 0 1 0 0 cm /%s Do Q", key.c_str()); | |
| 243 pNewContents->SetData(sStream.raw_str(), sStream.GetLength()); | |
| 244 pContentsArray->AddReference(pDocument, | 227 pContentsArray->AddReference(pDocument, | 
| 245 pDocument->AddIndirectObject(pNewContents)); | 228 NewIndirectContentsStream(key, pDocument)); | 
| 246 } | 229 } | 
| 247 } | 230 } | 
| 248 | 231 | 
| 249 CFX_Matrix GetMatrix(CFX_FloatRect rcAnnot, | 232 CFX_Matrix GetMatrix(CFX_FloatRect rcAnnot, | 
| 250 CFX_FloatRect rcStream, | 233 CFX_FloatRect rcStream, | 
| 251 const CFX_Matrix& matrix) { | 234 const CFX_Matrix& matrix) { | 
| 252 if (rcStream.IsEmpty()) | 235 if (rcStream.IsEmpty()) | 
| 253 return CFX_Matrix(); | 236 return CFX_Matrix(); | 
| 254 | 237 | 
| 255 matrix.TransformRect(rcStream); | 238 matrix.TransformRect(rcStream); | 
| 256 rcStream.Normalize(); | 239 rcStream.Normalize(); | 
| 257 | 240 | 
| 258 FX_FLOAT a = rcAnnot.Width() / rcStream.Width(); | 241 FX_FLOAT a = rcAnnot.Width() / rcStream.Width(); | 
| 259 FX_FLOAT d = rcAnnot.Height() / rcStream.Height(); | 242 FX_FLOAT d = rcAnnot.Height() / rcStream.Height(); | 
| 260 | 243 | 
| 261 FX_FLOAT e = rcAnnot.left - rcStream.left * a; | 244 FX_FLOAT e = rcAnnot.left - rcStream.left * a; | 
| 262 FX_FLOAT f = rcAnnot.bottom - rcStream.bottom * d; | 245 FX_FLOAT f = rcAnnot.bottom - rcStream.bottom * d; | 
| 263 return CFX_Matrix(a, 0, 0, d, e, f); | 246 return CFX_Matrix(a, 0, 0, d, e, f); | 
| 264 } | 247 } | 
| 265 | 248 | 
| 266 void GetOffset(FX_FLOAT& fa, | 249 } // namespace | 
| 267 FX_FLOAT& fd, | |
| 268 FX_FLOAT& fe, | |
| 269 FX_FLOAT& ff, | |
| 270 CFX_FloatRect rcAnnot, | |
| 271 CFX_FloatRect rcStream, | |
| 272 const CFX_Matrix& matrix) { | |
| 273 FX_FLOAT fStreamWidth = 0.0f; | |
| 274 FX_FLOAT fStreamHeight = 0.0f; | |
| 275 | |
| 276 if (matrix.a != 0 && matrix.d != 0) { | |
| 277 fStreamWidth = rcStream.right - rcStream.left; | |
| 278 fStreamHeight = rcStream.top - rcStream.bottom; | |
| 279 } else { | |
| 280 fStreamWidth = rcStream.top - rcStream.bottom; | |
| 281 fStreamHeight = rcStream.right - rcStream.left; | |
| 282 } | |
| 283 | |
| 284 FX_FLOAT x1 = | |
| 285 matrix.a * rcStream.left + matrix.c * rcStream.bottom + matrix.e; | |
| 286 FX_FLOAT y1 = | |
| 287 matrix.b * rcStream.left + matrix.d * rcStream.bottom + matrix.f; | |
| 288 FX_FLOAT x2 = matrix.a * rcStream.left + matrix.c * rcStream.top + matrix.e; | |
| 289 FX_FLOAT y2 = matrix.b * rcStream.left + matrix.d * rcStream.top + matrix.f; | |
| 290 FX_FLOAT x3 = | |
| 291 matrix.a * rcStream.right + matrix.c * rcStream.bottom + matrix.e; | |
| 292 FX_FLOAT y3 = | |
| 293 matrix.b * rcStream.right + matrix.d * rcStream.bottom + matrix.f; | |
| 294 FX_FLOAT x4 = matrix.a * rcStream.right + matrix.c * rcStream.top + matrix.e; | |
| 295 FX_FLOAT y4 = matrix.b * rcStream.right + matrix.d * rcStream.top + matrix.f; | |
| 296 | |
| 297 FX_FLOAT left = std::min(std::min(x1, x2), std::min(x3, x4)); | |
| 298 FX_FLOAT bottom = std::min(std::min(y1, y2), std::min(y3, y4)); | |
| 299 | |
| 300 fa = (rcAnnot.right - rcAnnot.left) / fStreamWidth; | |
| 301 fd = (rcAnnot.top - rcAnnot.bottom) / fStreamHeight; | |
| 302 fe = rcAnnot.left - left * fa; | |
| 303 ff = rcAnnot.bottom - bottom * fd; | |
| 304 } | |
| 305 | 250 | 
| 306 DLLEXPORT int STDCALL FPDFPage_Flatten(FPDF_PAGE page, int nFlag) { | 251 DLLEXPORT int STDCALL FPDFPage_Flatten(FPDF_PAGE page, int nFlag) { | 
| 307 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | 252 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | 
| 308 if (!page) { | 253 if (!page) { | 
| 309 return FLATTEN_FAIL; | 254 return FLATTEN_FAIL; | 
| 310 } | 255 } | 
| 311 | 256 | 
| 312 CPDF_Document* pDocument = pPage->m_pDocument; | 257 CPDF_Document* pDocument = pPage->m_pDocument; | 
| 313 CPDF_Dictionary* pPageDict = pPage->m_pFormDict; | 258 CPDF_Dictionary* pPageDict = pPage->m_pFormDict; | 
| 314 | 259 | 
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 506 sStream += sTemp; | 451 sStream += sTemp; | 
| 507 pNewXObject->SetData(sStream.raw_str(), sStream.GetLength()); | 452 pNewXObject->SetData(sStream.raw_str(), sStream.GetLength()); | 
| 508 } | 453 } | 
| 509 pPageDict->RemoveFor("Annots"); | 454 pPageDict->RemoveFor("Annots"); | 
| 510 | 455 | 
| 511 ObjectArray.RemoveAll(); | 456 ObjectArray.RemoveAll(); | 
| 512 RectArray.RemoveAll(); | 457 RectArray.RemoveAll(); | 
| 513 | 458 | 
| 514 return FLATTEN_SUCCESS; | 459 return FLATTEN_SUCCESS; | 
| 515 } | 460 } | 
| OLD | NEW |