Kill JS_TIMER_MAPARRAY
[pdfium.git] / fpdfsdk / src / fpdf_transformpage.cpp
index f171c5e..71ba48e 100644 (file)
-// Copyright 2014 PDFium Authors. All rights reserved.\r
-// Use of this source code is governed by a BSD-style license that can be\r
-// found in the LICENSE file.\r
\r
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
-\r
-#include "../include/fsdk_define.h"\r
-#include "../include/fpdf_transformpage.h"\r
-\r
-DLLEXPORT void STDCALL FPDFPage_SetMediaBox(FPDF_PAGE page, float left, float bottom, float right, float top)\r
-{\r
-       if(!page)\r
-               return;\r
-       CPDF_Page* pPage = (CPDF_Page*)page;\r
-       CPDF_Dictionary* pPageDict = pPage->m_pFormDict;\r
-       CPDF_Array* pMediaBoxArray = FX_NEW CPDF_Array;\r
-       pMediaBoxArray->Add(FX_NEW CPDF_Number(left));\r
-       pMediaBoxArray->Add(FX_NEW CPDF_Number(bottom));\r
-       pMediaBoxArray->Add(FX_NEW CPDF_Number(FX_FLOAT(right)));\r
-       pMediaBoxArray->Add(FX_NEW CPDF_Number(FX_FLOAT(top)));\r
-       \r
-       pPageDict->SetAt("MediaBox", pMediaBoxArray);\r
-}\r
-\r
-\r
-DLLEXPORT void STDCALL FPDFPage_SetCropBox(FPDF_PAGE page, float left, float bottom, float right, float top)\r
-{\r
-       if(!page)\r
-               return;\r
-       CPDF_Page* pPage = (CPDF_Page*)page;\r
-       CPDF_Dictionary* pPageDict = pPage->m_pFormDict;\r
-       CPDF_Array* pCropBoxArray = FX_NEW CPDF_Array;\r
-       pCropBoxArray->Add(FX_NEW CPDF_Number(left));\r
-       pCropBoxArray->Add(FX_NEW CPDF_Number(bottom));\r
-       pCropBoxArray->Add(FX_NEW CPDF_Number(FX_FLOAT(right)));\r
-       pCropBoxArray->Add(FX_NEW CPDF_Number(FX_FLOAT(top)));\r
-       \r
-       \r
-       pPageDict->SetAt("CropBox", pCropBoxArray);\r
-}\r
-\r
-\r
-DLLEXPORT FX_BOOL STDCALL FPDFPage_GetMediaBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top)\r
-{\r
-       if(!page)\r
-               return FALSE;\r
-       CPDF_Page* pPage = (CPDF_Page*)page;\r
-       CPDF_Dictionary* pPageDict = pPage->m_pFormDict;\r
-       CPDF_Array* pArray = pPageDict->GetArray("MediaBox");\r
-       if(pArray)\r
-       {\r
-               *left = pArray->GetFloat(0);\r
-               *bottom = pArray->GetFloat(1);\r
-               *right = pArray->GetFloat(2);\r
-               *top = pArray->GetFloat(3);\r
-               return TRUE;\r
-       }\r
-       return FALSE;\r
-}\r
-\r
-DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GetCropBox(FPDF_PAGE page, float* left, float* bottom, float* right, float* top)\r
-{\r
-       if(!page)\r
-               return FALSE;\r
-       CPDF_Page* pPage = (CPDF_Page*)page;\r
-       CPDF_Dictionary* pPageDict = pPage->m_pFormDict;\r
-       CPDF_Array* pArray = pPageDict->GetArray("CropBox");\r
-       if(pArray)\r
-       {\r
-               *left = pArray->GetFloat(0);\r
-               *bottom = pArray->GetFloat(1);\r
-               *right = pArray->GetFloat(2);\r
-               *top = pArray->GetFloat(3);\r
-               return TRUE;\r
-       }\r
-       return FALSE;\r
-}\r
-\r
-DLLEXPORT FPDF_BOOL STDCALL FPDFPage_TransFormWithClip(FPDF_PAGE page, FS_MATRIX* matrix, FS_RECTF* clipRect)\r
-{\r
-       if(!page)\r
-               return FALSE;\r
-\r
-       CFX_ByteTextBuf textBuf;\r
-       textBuf<<"q ";\r
-       CFX_FloatRect rect(clipRect->left, clipRect->bottom, clipRect->right, clipRect->top);\r
-       rect.Normalize();\r
-       CFX_ByteString bsClipping;\r
-       bsClipping.Format("%f %f %f %f re W* n ", rect.left, rect.bottom, rect.Width(), rect.Height());\r
-       textBuf<<bsClipping;\r
-\r
-       CFX_ByteString bsMatix;\r
-       bsMatix.Format("%f %f %f %f %f %f cm ", matrix->a, matrix->b,matrix->c,matrix->d,matrix->e,matrix->f);\r
-       textBuf<<bsMatix;\r
-       \r
-\r
-       CPDF_Page* pPage = (CPDF_Page*)page;\r
-       CPDF_Dictionary* pPageDic = pPage->m_pFormDict;\r
-       CPDF_Object* pContentObj = pPageDic->GetElement("Contents");\r
-       if(!pContentObj)\r
-               pContentObj = pPageDic->GetArray("Contents");\r
-       if(!pContentObj)\r
-               return FALSE;\r
-       \r
-       CPDF_Dictionary* pDic = FX_NEW CPDF_Dictionary;\r
-       CPDF_Stream* pStream = FX_NEW CPDF_Stream(NULL,0, pDic);\r
-       pStream->SetData(textBuf.GetBuffer(), textBuf.GetSize(), FALSE, FALSE);\r
-       CPDF_Document* pDoc = pPage->m_pDocument;\r
-       if(!pDoc)\r
-               return FALSE;\r
-       pDoc->AddIndirectObject(pStream);\r
-\r
-       pDic = FX_NEW CPDF_Dictionary;\r
-       CPDF_Stream* pEndStream = FX_NEW CPDF_Stream(NULL,0, pDic);\r
-       pEndStream->SetData((FX_LPCBYTE)" Q", 2, FALSE, FALSE);\r
-       pDoc->AddIndirectObject(pEndStream);\r
-       \r
-       CPDF_Array* pContentArray = NULL;\r
-       if (pContentObj && pContentObj->GetType() == PDFOBJ_ARRAY)\r
-       {\r
-               pContentArray = (CPDF_Array*)pContentObj;\r
-               CPDF_Reference* pRef = FX_NEW CPDF_Reference(pDoc, pStream->GetObjNum());\r
-               pContentArray->InsertAt(0, pRef);\r
-               pContentArray->AddReference(pDoc,pEndStream);\r
-               \r
-       }\r
-       else if(pContentObj && pContentObj->GetType() == PDFOBJ_REFERENCE)\r
-       {\r
-               CPDF_Reference* pReference = (CPDF_Reference*)pContentObj;\r
-               CPDF_Object* pDirectObj = pReference->GetDirect();\r
-               if(pDirectObj != NULL)\r
-               {\r
-                       if(pDirectObj->GetType() == PDFOBJ_ARRAY)\r
-                       {\r
-                               pContentArray = (CPDF_Array*)pDirectObj;\r
-                               CPDF_Reference* pRef = FX_NEW CPDF_Reference(pDoc, pStream->GetObjNum());\r
-                               pContentArray->InsertAt(0, pRef);\r
-                               pContentArray->AddReference(pDoc,pEndStream);\r
-                               \r
-                       }\r
-                       else if(pDirectObj->GetType() == PDFOBJ_STREAM)\r
-                       {\r
-                               pContentArray = FX_NEW CPDF_Array();\r
-                               pContentArray->AddReference(pDoc,pStream->GetObjNum());\r
-                               pContentArray->AddReference(pDoc,pDirectObj->GetObjNum());\r
-                               pContentArray->AddReference(pDoc, pEndStream);\r
-                               pPageDic->SetAtReference("Contents", pDoc, pDoc->AddIndirectObject(pContentArray));\r
-                       }\r
-               }\r
-       }       \r
-\r
-       //Need to transform the patterns as well.\r
-       CPDF_Dictionary* pRes = pPageDic->GetDict(FX_BSTRC("Resources"));\r
-       if(pRes)\r
-       {\r
-               CPDF_Dictionary* pPattenDict = pRes->GetDict(FX_BSTRC("Pattern"));\r
-               if(pPattenDict)\r
-               {\r
-                       FX_POSITION pos = pPattenDict->GetStartPos();\r
-                       while(pos)\r
-                       {\r
-                               CPDF_Dictionary* pDict = NULL;\r
-                               CFX_ByteString key;\r
-                               CPDF_Object* pObj = pPattenDict->GetNextElement(pos, key);\r
-                               if(pObj->GetType() == PDFOBJ_REFERENCE)\r
-                                       pObj = pObj->GetDirect();\r
-                               if(pObj->GetType() == PDFOBJ_DICTIONARY)\r
-                               {\r
-                                       pDict = (CPDF_Dictionary*)pObj;\r
-                               }\r
-                               else if(pObj->GetType() == PDFOBJ_STREAM)\r
-                               {\r
-                                       pDict = ((CPDF_Stream*)pObj)->GetDict();\r
-                               }\r
-                               else\r
-                                       continue;\r
-                               \r
-                               CFX_AffineMatrix m = pDict->GetMatrix(FX_BSTRC("Matrix"));\r
-                               CFX_AffineMatrix t = *(CFX_AffineMatrix*)matrix;\r
-                               m.Concat(t);\r
-                               pDict->SetAtMatrix(FX_BSTRC("Matrix"), m);\r
-                       }\r
-               }\r
-       }\r
-\r
-       return TRUE;\r
-}\r
-\r
-DLLEXPORT void STDCALL FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,double a, double b, double c, double d, double e, double f)\r
-{\r
-       CPDF_PageObject* pPageObj = (CPDF_PageObject*)page_object;\r
-       if(pPageObj == NULL)\r
-               return;\r
-       CFX_AffineMatrix matrix((FX_FLOAT)a,(FX_FLOAT)b,(FX_FLOAT)c,(FX_FLOAT)d,(FX_FLOAT)e,(FX_FLOAT)f);\r
-       \r
-       //Special treatment to shading object, because the ClipPath for shading object is already transformed.\r
-       if(pPageObj->m_Type != PDFPAGE_SHADING)\r
-               pPageObj->TransformClipPath(matrix);\r
-       pPageObj->TransformGeneralState(matrix);\r
-}\r
-\r
-\r
-DLLEXPORT FPDF_CLIPPATH STDCALL FPDF_CreateClipPath(float left, float bottom, float right, float top)\r
-{\r
-       CPDF_ClipPath* pNewClipPath =  FX_NEW CPDF_ClipPath();\r
-       pNewClipPath->GetModify();\r
-       CPDF_Path Path;\r
-       Path.GetModify();\r
-       Path.AppendRect(left, bottom, right, top);\r
-       pNewClipPath->AppendPath(Path, FXFILL_ALTERNATE, FALSE);\r
-       return pNewClipPath;\r
-}\r
-\r
-DLLEXPORT void STDCALL FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath)\r
-{\r
-       if(clipPath)\r
-               delete (CPDF_ClipPath*)clipPath;\r
-}\r
-\r
-void OutputPath(CFX_ByteTextBuf& buf, CPDF_Path path)\r
-{\r
-       const CFX_PathData* pPathData = path;\r
-       if (pPathData == NULL) return;\r
-       \r
-       FX_PATHPOINT* pPoints = pPathData->GetPoints();\r
-       \r
-       if (path.IsRect()) {\r
-               buf << (pPoints[0].m_PointX) << " " << (pPoints[0].m_PointY) << " " \r
-                       << (pPoints[2].m_PointX - pPoints[0].m_PointX) << " " \r
-                       << (pPoints[2].m_PointY - pPoints[0].m_PointY) << " re\n";\r
-               return;\r
-       }\r
-       \r
-       CFX_ByteString temp;\r
-       for (int i = 0; i < pPathData->GetPointCount(); i ++) {\r
-               buf << (pPoints[i].m_PointX) << " " << (pPoints[i].m_PointY);\r
-               int point_type = pPoints[i].m_Flag & FXPT_TYPE;\r
-               if (point_type == FXPT_MOVETO)\r
-                       buf << " m\n";\r
-               else if (point_type == FXPT_BEZIERTO) {\r
-                       buf << " " << (pPoints[i+1].m_PointX) << " " << (pPoints[i+1].m_PointY) << " " << \r
-                               (pPoints[i+2].m_PointX) << " " << (pPoints[i+2].m_PointY);\r
-                       if (pPoints[i+2].m_Flag & FXPT_CLOSEFIGURE)\r
-                               buf << " c h\n";\r
-                       else\r
-                               buf << " c\n";\r
-                       i += 2;\r
-               } else if (point_type == FXPT_LINETO) {\r
-                       if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE)\r
-                               buf << " l h\n";\r
-                       else\r
-                               buf << " l\n";\r
-               }\r
-       }\r
-}\r
-\r
-DLLEXPORT void STDCALL FPDFPage_InsertClipPath(FPDF_PAGE page,FPDF_CLIPPATH clipPath)\r
-{\r
-       if(!page)\r
-               return;\r
-       CPDF_Page* pPage = (CPDF_Page*)page;\r
-       CPDF_Dictionary* pPageDic = pPage->m_pFormDict;\r
-       CPDF_Object* pContentObj = pPageDic->GetElement("Contents");\r
-       if(!pContentObj)\r
-               pContentObj = pPageDic->GetArray("Contents");\r
-       if(!pContentObj)\r
-               return;\r
-\r
-       CFX_ByteTextBuf strClip;\r
-       CPDF_ClipPath* pClipPath = (CPDF_ClipPath*)clipPath;\r
-       FX_DWORD i;\r
-       for (i = 0; i < pClipPath->GetPathCount(); i ++) {\r
-               CPDF_Path path = pClipPath->GetPath(i);\r
-               int iClipType = pClipPath->GetClipType(i);\r
-               if (path.GetPointCount() == 0) {\r
-                       // Empty clipping (totally clipped out)\r
-                       strClip << "0 0 m W n ";\r
-               } else {\r
-                       OutputPath(strClip, path);\r
-                       if (iClipType == FXFILL_WINDING)\r
-                               strClip << "W n\n";\r
-                       else\r
-                               strClip << "W* n\n";\r
-               }\r
-       }\r
-       CPDF_Dictionary* pDic = FX_NEW CPDF_Dictionary;\r
-       CPDF_Stream* pStream = FX_NEW CPDF_Stream(NULL,0, pDic);\r
-       pStream->SetData(strClip.GetBuffer(), strClip.GetSize(), FALSE, FALSE);\r
-       CPDF_Document* pDoc = pPage->m_pDocument;\r
-       if(!pDoc)\r
-               return;\r
-       pDoc->AddIndirectObject(pStream);\r
-       \r
-       CPDF_Array* pContentArray = NULL;\r
-       if (pContentObj && pContentObj->GetType() == PDFOBJ_ARRAY)\r
-       {\r
-               pContentArray = (CPDF_Array*)pContentObj;\r
-               CPDF_Reference* pRef = FX_NEW CPDF_Reference(pDoc, pStream->GetObjNum());\r
-               pContentArray->InsertAt(0, pRef);\r
-               \r
-       }\r
-       else if(pContentObj && pContentObj->GetType() == PDFOBJ_REFERENCE)\r
-       {\r
-               CPDF_Reference* pReference = (CPDF_Reference*)pContentObj;\r
-               CPDF_Object* pDirectObj = pReference->GetDirect();\r
-               if(pDirectObj != NULL)\r
-               {\r
-                       if(pDirectObj->GetType() == PDFOBJ_ARRAY)\r
-                       {\r
-                               pContentArray = (CPDF_Array*)pDirectObj;\r
-                               CPDF_Reference* pRef = FX_NEW CPDF_Reference(pDoc, pStream->GetObjNum());\r
-                               pContentArray->InsertAt(0, pRef);\r
-                               \r
-                       }\r
-                       else if(pDirectObj->GetType() == PDFOBJ_STREAM)\r
-                       {\r
-                               pContentArray = FX_NEW CPDF_Array();\r
-                               pContentArray->AddReference(pDoc,pStream->GetObjNum());\r
-                               pContentArray->AddReference(pDoc,pDirectObj->GetObjNum());\r
-                               pPageDic->SetAtReference("Contents", pDoc, pDoc->AddIndirectObject(pContentArray));\r
-                       }\r
-               }\r
-       }       \r
-}\r
-\r
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "../../public/fpdf_transformpage.h"
+#include "../include/fsdk_define.h"
+
+DLLEXPORT void STDCALL FPDFPage_SetMediaBox(FPDF_PAGE page,
+                                            float left,
+                                            float bottom,
+                                            float right,
+                                            float top) {
+  if (!page)
+    return;
+
+  CPDF_Page* pPage = (CPDF_Page*)page;
+  CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
+  CPDF_Array* pMediaBoxArray = new CPDF_Array;
+  pMediaBoxArray->Add(new CPDF_Number(left));
+  pMediaBoxArray->Add(new CPDF_Number(bottom));
+  pMediaBoxArray->Add(new CPDF_Number(FX_FLOAT(right)));
+  pMediaBoxArray->Add(new CPDF_Number(FX_FLOAT(top)));
+  pPageDict->SetAt("MediaBox", pMediaBoxArray);
+}
+
+DLLEXPORT void STDCALL FPDFPage_SetCropBox(FPDF_PAGE page,
+                                           float left,
+                                           float bottom,
+                                           float right,
+                                           float top) {
+  if (!page)
+    return;
+
+  CPDF_Page* pPage = (CPDF_Page*)page;
+  CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
+  CPDF_Array* pCropBoxArray = new CPDF_Array;
+  pCropBoxArray->Add(new CPDF_Number(left));
+  pCropBoxArray->Add(new CPDF_Number(bottom));
+  pCropBoxArray->Add(new CPDF_Number(FX_FLOAT(right)));
+  pCropBoxArray->Add(new CPDF_Number(FX_FLOAT(top)));
+  pPageDict->SetAt("CropBox", pCropBoxArray);
+}
+
+DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GetMediaBox(FPDF_PAGE page,
+                                                 float* left,
+                                                 float* bottom,
+                                                 float* right,
+                                                 float* top) {
+  if (!page)
+    return FALSE;
+  CPDF_Page* pPage = (CPDF_Page*)page;
+  CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
+  CPDF_Array* pArray = pPageDict->GetArray("MediaBox");
+  if (pArray) {
+    *left = pArray->GetFloat(0);
+    *bottom = pArray->GetFloat(1);
+    *right = pArray->GetFloat(2);
+    *top = pArray->GetFloat(3);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GetCropBox(FPDF_PAGE page,
+                                                float* left,
+                                                float* bottom,
+                                                float* right,
+                                                float* top) {
+  if (!page)
+    return FALSE;
+  CPDF_Page* pPage = (CPDF_Page*)page;
+  CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
+  CPDF_Array* pArray = pPageDict->GetArray("CropBox");
+  if (pArray) {
+    *left = pArray->GetFloat(0);
+    *bottom = pArray->GetFloat(1);
+    *right = pArray->GetFloat(2);
+    *top = pArray->GetFloat(3);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+DLLEXPORT FPDF_BOOL STDCALL FPDFPage_TransFormWithClip(FPDF_PAGE page,
+                                                       FS_MATRIX* matrix,
+                                                       FS_RECTF* clipRect) {
+  if (!page)
+    return FALSE;
+
+  CFX_ByteTextBuf textBuf;
+  textBuf << "q ";
+  CFX_FloatRect rect(clipRect->left, clipRect->bottom, clipRect->right,
+                     clipRect->top);
+  rect.Normalize();
+  CFX_ByteString bsClipping;
+  bsClipping.Format("%f %f %f %f re W* n ", rect.left, rect.bottom,
+                    rect.Width(), rect.Height());
+  textBuf << bsClipping;
+
+  CFX_ByteString bsMatix;
+  bsMatix.Format("%f %f %f %f %f %f cm ", matrix->a, matrix->b, matrix->c,
+                 matrix->d, matrix->e, matrix->f);
+  textBuf << bsMatix;
+
+  CPDF_Page* pPage = (CPDF_Page*)page;
+  CPDF_Dictionary* pPageDic = pPage->m_pFormDict;
+  CPDF_Object* pContentObj = pPageDic ? pPageDic->GetElement("Contents") : NULL;
+  if (!pContentObj)
+    pContentObj = pPageDic ? pPageDic->GetArray("Contents") : NULL;
+  if (!pContentObj)
+    return FALSE;
+
+  CPDF_Dictionary* pDic = new CPDF_Dictionary;
+  CPDF_Stream* pStream = new CPDF_Stream(NULL, 0, pDic);
+  pStream->SetData(textBuf.GetBuffer(), textBuf.GetSize(), FALSE, FALSE);
+  CPDF_Document* pDoc = pPage->m_pDocument;
+  if (!pDoc)
+    return FALSE;
+  pDoc->AddIndirectObject(pStream);
+
+  pDic = new CPDF_Dictionary;
+  CPDF_Stream* pEndStream = new CPDF_Stream(NULL, 0, pDic);
+  pEndStream->SetData((const uint8_t*)" Q", 2, FALSE, FALSE);
+  pDoc->AddIndirectObject(pEndStream);
+
+  CPDF_Array* pContentArray = NULL;
+  if (pContentObj && pContentObj->GetType() == PDFOBJ_ARRAY) {
+    pContentArray = (CPDF_Array*)pContentObj;
+    CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum());
+    pContentArray->InsertAt(0, pRef);
+    pContentArray->AddReference(pDoc, pEndStream);
+
+  } else if (pContentObj && pContentObj->GetType() == PDFOBJ_REFERENCE) {
+    CPDF_Reference* pReference = (CPDF_Reference*)pContentObj;
+    CPDF_Object* pDirectObj = pReference->GetDirect();
+    if (pDirectObj != NULL) {
+      if (pDirectObj->GetType() == PDFOBJ_ARRAY) {
+        pContentArray = (CPDF_Array*)pDirectObj;
+        CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum());
+        pContentArray->InsertAt(0, pRef);
+        pContentArray->AddReference(pDoc, pEndStream);
+      } else if (pDirectObj->GetType() == PDFOBJ_STREAM) {
+        pContentArray = new CPDF_Array();
+        pContentArray->AddReference(pDoc, pStream->GetObjNum());
+        pContentArray->AddReference(pDoc, pDirectObj->GetObjNum());
+        pContentArray->AddReference(pDoc, pEndStream);
+        pPageDic->SetAtReference("Contents", pDoc,
+                                 pDoc->AddIndirectObject(pContentArray));
+      }
+    }
+  }
+
+  // Need to transform the patterns as well.
+  CPDF_Dictionary* pRes = pPageDic->GetDict(FX_BSTRC("Resources"));
+  if (pRes) {
+    CPDF_Dictionary* pPattenDict = pRes->GetDict(FX_BSTRC("Pattern"));
+    if (pPattenDict) {
+      FX_POSITION pos = pPattenDict->GetStartPos();
+      while (pos) {
+        CPDF_Dictionary* pDict = NULL;
+        CFX_ByteString key;
+        CPDF_Object* pObj = pPattenDict->GetNextElement(pos, key);
+        if (pObj->GetType() == PDFOBJ_REFERENCE)
+          pObj = pObj->GetDirect();
+        if (pObj->GetType() == PDFOBJ_DICTIONARY) {
+          pDict = (CPDF_Dictionary*)pObj;
+        } else if (pObj->GetType() == PDFOBJ_STREAM) {
+          pDict = ((CPDF_Stream*)pObj)->GetDict();
+        } else
+          continue;
+
+        CFX_AffineMatrix m = pDict->GetMatrix(FX_BSTRC("Matrix"));
+        CFX_AffineMatrix t = *(CFX_AffineMatrix*)matrix;
+        m.Concat(t);
+        pDict->SetAtMatrix(FX_BSTRC("Matrix"), m);
+      }
+    }
+  }
+
+  return TRUE;
+}
+
+DLLEXPORT void STDCALL
+FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,
+                              double a,
+                              double b,
+                              double c,
+                              double d,
+                              double e,
+                              double f) {
+  CPDF_PageObject* pPageObj = (CPDF_PageObject*)page_object;
+  if (pPageObj == NULL)
+    return;
+  CFX_AffineMatrix matrix((FX_FLOAT)a, (FX_FLOAT)b, (FX_FLOAT)c, (FX_FLOAT)d,
+                          (FX_FLOAT)e, (FX_FLOAT)f);
+
+  // Special treatment to shading object, because the ClipPath for shading
+  // object is already transformed.
+  if (pPageObj->m_Type != PDFPAGE_SHADING)
+    pPageObj->TransformClipPath(matrix);
+  pPageObj->TransformGeneralState(matrix);
+}
+
+DLLEXPORT FPDF_CLIPPATH STDCALL FPDF_CreateClipPath(float left,
+                                                    float bottom,
+                                                    float right,
+                                                    float top) {
+  CPDF_ClipPath* pNewClipPath = new CPDF_ClipPath();
+  pNewClipPath->GetModify();
+  CPDF_Path Path;
+  Path.GetModify();
+  Path.AppendRect(left, bottom, right, top);
+  pNewClipPath->AppendPath(Path, FXFILL_ALTERNATE, FALSE);
+  return pNewClipPath;
+}
+
+DLLEXPORT void STDCALL FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath) {
+  delete (CPDF_ClipPath*)clipPath;
+}
+
+void OutputPath(CFX_ByteTextBuf& buf, CPDF_Path path) {
+  const CFX_PathData* pPathData = path;
+  if (pPathData == NULL)
+    return;
+
+  FX_PATHPOINT* pPoints = pPathData->GetPoints();
+
+  if (path.IsRect()) {
+    buf << (pPoints[0].m_PointX) << " " << (pPoints[0].m_PointY) << " "
+        << (pPoints[2].m_PointX - pPoints[0].m_PointX) << " "
+        << (pPoints[2].m_PointY - pPoints[0].m_PointY) << " re\n";
+    return;
+  }
+
+  CFX_ByteString temp;
+  for (int i = 0; i < pPathData->GetPointCount(); i++) {
+    buf << (pPoints[i].m_PointX) << " " << (pPoints[i].m_PointY);
+    int point_type = pPoints[i].m_Flag & FXPT_TYPE;
+    if (point_type == FXPT_MOVETO)
+      buf << " m\n";
+    else if (point_type == FXPT_BEZIERTO) {
+      buf << " " << (pPoints[i + 1].m_PointX) << " "
+          << (pPoints[i + 1].m_PointY) << " " << (pPoints[i + 2].m_PointX)
+          << " " << (pPoints[i + 2].m_PointY);
+      if (pPoints[i + 2].m_Flag & FXPT_CLOSEFIGURE)
+        buf << " c h\n";
+      else
+        buf << " c\n";
+      i += 2;
+    } else if (point_type == FXPT_LINETO) {
+      if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE)
+        buf << " l h\n";
+      else
+        buf << " l\n";
+    }
+  }
+}
+
+DLLEXPORT void STDCALL FPDFPage_InsertClipPath(FPDF_PAGE page,
+                                               FPDF_CLIPPATH clipPath) {
+  if (!page)
+    return;
+  CPDF_Page* pPage = (CPDF_Page*)page;
+  CPDF_Dictionary* pPageDic = pPage->m_pFormDict;
+  CPDF_Object* pContentObj = pPageDic ? pPageDic->GetElement("Contents") : NULL;
+  if (!pContentObj)
+    pContentObj = pPageDic ? pPageDic->GetArray("Contents") : NULL;
+  if (!pContentObj)
+    return;
+
+  CFX_ByteTextBuf strClip;
+  CPDF_ClipPath* pClipPath = (CPDF_ClipPath*)clipPath;
+  FX_DWORD i;
+  for (i = 0; i < pClipPath->GetPathCount(); i++) {
+    CPDF_Path path = pClipPath->GetPath(i);
+    int iClipType = pClipPath->GetClipType(i);
+    if (path.GetPointCount() == 0) {
+      // Empty clipping (totally clipped out)
+      strClip << "0 0 m W n ";
+    } else {
+      OutputPath(strClip, path);
+      if (iClipType == FXFILL_WINDING)
+        strClip << "W n\n";
+      else
+        strClip << "W* n\n";
+    }
+  }
+  CPDF_Dictionary* pDic = new CPDF_Dictionary;
+  CPDF_Stream* pStream = new CPDF_Stream(NULL, 0, pDic);
+  pStream->SetData(strClip.GetBuffer(), strClip.GetSize(), FALSE, FALSE);
+  CPDF_Document* pDoc = pPage->m_pDocument;
+  if (!pDoc)
+    return;
+  pDoc->AddIndirectObject(pStream);
+
+  CPDF_Array* pContentArray = NULL;
+  if (pContentObj && pContentObj->GetType() == PDFOBJ_ARRAY) {
+    pContentArray = (CPDF_Array*)pContentObj;
+    CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum());
+    pContentArray->InsertAt(0, pRef);
+  } else if (pContentObj && pContentObj->GetType() == PDFOBJ_REFERENCE) {
+    CPDF_Reference* pReference = (CPDF_Reference*)pContentObj;
+    CPDF_Object* pDirectObj = pReference->GetDirect();
+    if (pDirectObj != NULL) {
+      if (pDirectObj->GetType() == PDFOBJ_ARRAY) {
+        pContentArray = (CPDF_Array*)pDirectObj;
+        CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum());
+        pContentArray->InsertAt(0, pRef);
+      } else if (pDirectObj->GetType() == PDFOBJ_STREAM) {
+        pContentArray = new CPDF_Array();
+        pContentArray->AddReference(pDoc, pStream->GetObjNum());
+        pContentArray->AddReference(pDoc, pDirectObj->GetObjNum());
+        pPageDic->SetAtReference("Contents", pDoc,
+                                 pDoc->AddIndirectObject(pContentArray));
+      }
+    }
+  }
+}