| 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  | 
|  185 void SetPageContents(CFX_ByteString key, |  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  | 
 |  197 void SetPageContents(const CFX_ByteString& key, | 
|  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, |  | 
|  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 |