Add FX_OVERRIDE and use it for virtual functions of FX_FINAL classes.
[pdfium.git] / fpdfsdk / src / fpdf_transformpage.cpp
index f171c5e..a666666 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 "../include/fsdk_define.h"
+#include "../include/fpdf_transformpage.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 = FX_NEW CPDF_Array;
+       pMediaBoxArray->Add(FX_NEW CPDF_Number(left));
+       pMediaBoxArray->Add(FX_NEW CPDF_Number(bottom));
+       pMediaBoxArray->Add(FX_NEW CPDF_Number(FX_FLOAT(right)));
+       pMediaBoxArray->Add(FX_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 = FX_NEW CPDF_Array;
+       pCropBoxArray->Add(FX_NEW CPDF_Number(left));
+       pCropBoxArray->Add(FX_NEW CPDF_Number(bottom));
+       pCropBoxArray->Add(FX_NEW CPDF_Number(FX_FLOAT(right)));
+       pCropBoxArray->Add(FX_NEW CPDF_Number(FX_FLOAT(top)));
+       
+       
+       pPageDict->SetAt("CropBox", pCropBoxArray);
+}
+
+
+DLLEXPORT FX_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 = FX_NEW CPDF_Dictionary;
+       CPDF_Stream* pStream = FX_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 = FX_NEW CPDF_Dictionary;
+       CPDF_Stream* pEndStream = FX_NEW CPDF_Stream(NULL,0, pDic);
+       pEndStream->SetData((FX_LPCBYTE)" Q", 2, FALSE, FALSE);
+       pDoc->AddIndirectObject(pEndStream);
+       
+       CPDF_Array* pContentArray = NULL;
+       if (pContentObj && pContentObj->GetType() == PDFOBJ_ARRAY)
+       {
+               pContentArray = (CPDF_Array*)pContentObj;
+               CPDF_Reference* pRef = FX_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 = FX_NEW CPDF_Reference(pDoc, pStream->GetObjNum());
+                               pContentArray->InsertAt(0, pRef);
+                               pContentArray->AddReference(pDoc,pEndStream);
+                               
+                       }
+                       else if(pDirectObj->GetType() == PDFOBJ_STREAM)
+                       {
+                               pContentArray = FX_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 =  FX_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)
+{
+       if(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 = FX_NEW CPDF_Dictionary;
+       CPDF_Stream* pStream = FX_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 = FX_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 = FX_NEW CPDF_Reference(pDoc, pStream->GetObjNum());
+                               pContentArray->InsertAt(0, pRef);
+                               
+                       }
+                       else if(pDirectObj->GetType() == PDFOBJ_STREAM)
+                       {
+                               pContentArray = FX_NEW CPDF_Array();
+                               pContentArray->AddReference(pDoc,pStream->GetObjNum());
+                               pContentArray->AddReference(pDoc,pDirectObj->GetObjNum());
+                               pPageDic->SetAtReference("Contents", pDoc, pDoc->AddIndirectObject(pContentArray));
+                       }
+               }
+       }       
+}
+