| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 PDFium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| 6 | |
| 7 #include "public/fpdf_transformpage.h" | |
| 8 | |
| 9 #include "core/include/fpdfapi/cpdf_array.h" | |
| 10 #include "core/include/fpdfapi/cpdf_document.h" | |
| 11 #include "core/include/fpdfapi/cpdf_number.h" | |
| 12 #include "core/include/fpdfapi/cpdf_reference.h" | |
| 13 #include "fpdfsdk/include/fsdk_define.h" | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 void SetBoundingBox(CPDF_Page* page, | |
| 18 const CFX_ByteStringC& key, | |
| 19 float left, | |
| 20 float bottom, | |
| 21 float right, | |
| 22 float top) { | |
| 23 CPDF_Dictionary* pPageDict = page->m_pFormDict; | |
| 24 CPDF_Array* pBoundingBoxArray = new CPDF_Array; | |
| 25 pBoundingBoxArray->Add(new CPDF_Number(left)); | |
| 26 pBoundingBoxArray->Add(new CPDF_Number(bottom)); | |
| 27 pBoundingBoxArray->Add(new CPDF_Number(right)); | |
| 28 pBoundingBoxArray->Add(new CPDF_Number(top)); | |
| 29 pPageDict->SetAt(key, pBoundingBoxArray); | |
| 30 } | |
| 31 | |
| 32 FPDF_BOOL GetBoundingBox(CPDF_Page* page, | |
| 33 const CFX_ByteStringC& key, | |
| 34 float* left, | |
| 35 float* bottom, | |
| 36 float* right, | |
| 37 float* top) { | |
| 38 CPDF_Dictionary* pPageDict = page->m_pFormDict; | |
| 39 CPDF_Array* pArray = pPageDict->GetArrayBy(key); | |
| 40 if (!pArray) | |
| 41 return FALSE; | |
| 42 | |
| 43 *left = pArray->GetFloatAt(0); | |
| 44 *bottom = pArray->GetFloatAt(1); | |
| 45 *right = pArray->GetFloatAt(2); | |
| 46 *top = pArray->GetFloatAt(3); | |
| 47 return TRUE; | |
| 48 } | |
| 49 | |
| 50 } // namespace | |
| 51 | |
| 52 DLLEXPORT void STDCALL FPDFPage_SetMediaBox(FPDF_PAGE page, | |
| 53 float left, | |
| 54 float bottom, | |
| 55 float right, | |
| 56 float top) { | |
| 57 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | |
| 58 if (!pPage) | |
| 59 return; | |
| 60 | |
| 61 SetBoundingBox(pPage, "MediaBox", left, bottom, right, top); | |
| 62 } | |
| 63 | |
| 64 DLLEXPORT void STDCALL FPDFPage_SetCropBox(FPDF_PAGE page, | |
| 65 float left, | |
| 66 float bottom, | |
| 67 float right, | |
| 68 float top) { | |
| 69 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | |
| 70 if (!pPage) | |
| 71 return; | |
| 72 | |
| 73 SetBoundingBox(pPage, "CropBox", left, bottom, right, top); | |
| 74 } | |
| 75 | |
| 76 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GetMediaBox(FPDF_PAGE page, | |
| 77 float* left, | |
| 78 float* bottom, | |
| 79 float* right, | |
| 80 float* top) { | |
| 81 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | |
| 82 return pPage && GetBoundingBox(pPage, "MediaBox", left, bottom, right, top); | |
| 83 } | |
| 84 | |
| 85 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GetCropBox(FPDF_PAGE page, | |
| 86 float* left, | |
| 87 float* bottom, | |
| 88 float* right, | |
| 89 float* top) { | |
| 90 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | |
| 91 return pPage && GetBoundingBox(pPage, "CropBox", left, bottom, right, top); | |
| 92 } | |
| 93 | |
| 94 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_TransFormWithClip(FPDF_PAGE page, | |
| 95 FS_MATRIX* matrix, | |
| 96 FS_RECTF* clipRect) { | |
| 97 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | |
| 98 if (!pPage) | |
| 99 return FALSE; | |
| 100 | |
| 101 CFX_ByteTextBuf textBuf; | |
| 102 textBuf << "q "; | |
| 103 CFX_FloatRect rect(clipRect->left, clipRect->bottom, clipRect->right, | |
| 104 clipRect->top); | |
| 105 rect.Normalize(); | |
| 106 CFX_ByteString bsClipping; | |
| 107 bsClipping.Format("%f %f %f %f re W* n ", rect.left, rect.bottom, | |
| 108 rect.Width(), rect.Height()); | |
| 109 textBuf << bsClipping; | |
| 110 | |
| 111 CFX_ByteString bsMatix; | |
| 112 bsMatix.Format("%f %f %f %f %f %f cm ", matrix->a, matrix->b, matrix->c, | |
| 113 matrix->d, matrix->e, matrix->f); | |
| 114 textBuf << bsMatix; | |
| 115 | |
| 116 CPDF_Dictionary* pPageDic = pPage->m_pFormDict; | |
| 117 CPDF_Object* pContentObj = | |
| 118 pPageDic ? pPageDic->GetElement("Contents") : nullptr; | |
| 119 if (!pContentObj) | |
| 120 pContentObj = pPageDic ? pPageDic->GetArrayBy("Contents") : nullptr; | |
| 121 if (!pContentObj) | |
| 122 return FALSE; | |
| 123 | |
| 124 CPDF_Dictionary* pDic = new CPDF_Dictionary; | |
| 125 CPDF_Stream* pStream = new CPDF_Stream(nullptr, 0, pDic); | |
| 126 pStream->SetData(textBuf.GetBuffer(), textBuf.GetSize(), FALSE, FALSE); | |
| 127 CPDF_Document* pDoc = pPage->m_pDocument; | |
| 128 if (!pDoc) | |
| 129 return FALSE; | |
| 130 pDoc->AddIndirectObject(pStream); | |
| 131 | |
| 132 pDic = new CPDF_Dictionary; | |
| 133 CPDF_Stream* pEndStream = new CPDF_Stream(nullptr, 0, pDic); | |
| 134 pEndStream->SetData((const uint8_t*)" Q", 2, FALSE, FALSE); | |
| 135 pDoc->AddIndirectObject(pEndStream); | |
| 136 | |
| 137 CPDF_Array* pContentArray = nullptr; | |
| 138 if (CPDF_Array* pArray = ToArray(pContentObj)) { | |
| 139 pContentArray = pArray; | |
| 140 CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum()); | |
| 141 pContentArray->InsertAt(0, pRef); | |
| 142 pContentArray->AddReference(pDoc, pEndStream); | |
| 143 } else if (CPDF_Reference* pReference = ToReference(pContentObj)) { | |
| 144 CPDF_Object* pDirectObj = pReference->GetDirect(); | |
| 145 if (pDirectObj) { | |
| 146 if (CPDF_Array* pArray = pDirectObj->AsArray()) { | |
| 147 pContentArray = pArray; | |
| 148 CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum()); | |
| 149 pContentArray->InsertAt(0, pRef); | |
| 150 pContentArray->AddReference(pDoc, pEndStream); | |
| 151 } else if (pDirectObj->IsStream()) { | |
| 152 pContentArray = new CPDF_Array(); | |
| 153 pContentArray->AddReference(pDoc, pStream->GetObjNum()); | |
| 154 pContentArray->AddReference(pDoc, pDirectObj->GetObjNum()); | |
| 155 pContentArray->AddReference(pDoc, pEndStream); | |
| 156 pPageDic->SetAtReference("Contents", pDoc, | |
| 157 pDoc->AddIndirectObject(pContentArray)); | |
| 158 } | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 // Need to transform the patterns as well. | |
| 163 CPDF_Dictionary* pRes = pPageDic->GetDictBy("Resources"); | |
| 164 if (pRes) { | |
| 165 CPDF_Dictionary* pPattenDict = pRes->GetDictBy("Pattern"); | |
| 166 if (pPattenDict) { | |
| 167 for (const auto& it : *pPattenDict) { | |
| 168 CPDF_Object* pObj = it.second; | |
| 169 if (pObj->IsReference()) | |
| 170 pObj = pObj->GetDirect(); | |
| 171 | |
| 172 CPDF_Dictionary* pDict = nullptr; | |
| 173 if (pObj->IsDictionary()) | |
| 174 pDict = pObj->AsDictionary(); | |
| 175 else if (CPDF_Stream* pStream = pObj->AsStream()) | |
| 176 pDict = pStream->GetDict(); | |
| 177 else | |
| 178 continue; | |
| 179 | |
| 180 CFX_Matrix m = pDict->GetMatrixBy("Matrix"); | |
| 181 CFX_Matrix t = *(CFX_Matrix*)matrix; | |
| 182 m.Concat(t); | |
| 183 pDict->SetAtMatrix("Matrix", m); | |
| 184 } | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 return TRUE; | |
| 189 } | |
| 190 | |
| 191 DLLEXPORT void STDCALL | |
| 192 FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object, | |
| 193 double a, | |
| 194 double b, | |
| 195 double c, | |
| 196 double d, | |
| 197 double e, | |
| 198 double f) { | |
| 199 CPDF_PageObject* pPageObj = (CPDF_PageObject*)page_object; | |
| 200 if (!pPageObj) | |
| 201 return; | |
| 202 CFX_Matrix matrix((FX_FLOAT)a, (FX_FLOAT)b, (FX_FLOAT)c, (FX_FLOAT)d, | |
| 203 (FX_FLOAT)e, (FX_FLOAT)f); | |
| 204 | |
| 205 // Special treatment to shading object, because the ClipPath for shading | |
| 206 // object is already transformed. | |
| 207 if (!pPageObj->IsShading()) | |
| 208 pPageObj->TransformClipPath(matrix); | |
| 209 pPageObj->TransformGeneralState(matrix); | |
| 210 } | |
| 211 | |
| 212 DLLEXPORT FPDF_CLIPPATH STDCALL FPDF_CreateClipPath(float left, | |
| 213 float bottom, | |
| 214 float right, | |
| 215 float top) { | |
| 216 CPDF_ClipPath* pNewClipPath = new CPDF_ClipPath(); | |
| 217 pNewClipPath->GetModify(); | |
| 218 CPDF_Path Path; | |
| 219 Path.GetModify(); | |
| 220 Path.AppendRect(left, bottom, right, top); | |
| 221 pNewClipPath->AppendPath(Path, FXFILL_ALTERNATE, FALSE); | |
| 222 return pNewClipPath; | |
| 223 } | |
| 224 | |
| 225 DLLEXPORT void STDCALL FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath) { | |
| 226 delete (CPDF_ClipPath*)clipPath; | |
| 227 } | |
| 228 | |
| 229 void OutputPath(CFX_ByteTextBuf& buf, CPDF_Path path) { | |
| 230 const CFX_PathData* pPathData = path; | |
| 231 if (!pPathData) | |
| 232 return; | |
| 233 | |
| 234 FX_PATHPOINT* pPoints = pPathData->GetPoints(); | |
| 235 | |
| 236 if (path.IsRect()) { | |
| 237 buf << (pPoints[0].m_PointX) << " " << (pPoints[0].m_PointY) << " " | |
| 238 << (pPoints[2].m_PointX - pPoints[0].m_PointX) << " " | |
| 239 << (pPoints[2].m_PointY - pPoints[0].m_PointY) << " re\n"; | |
| 240 return; | |
| 241 } | |
| 242 | |
| 243 CFX_ByteString temp; | |
| 244 for (int i = 0; i < pPathData->GetPointCount(); i++) { | |
| 245 buf << (pPoints[i].m_PointX) << " " << (pPoints[i].m_PointY); | |
| 246 int point_type = pPoints[i].m_Flag & FXPT_TYPE; | |
| 247 if (point_type == FXPT_MOVETO) { | |
| 248 buf << " m\n"; | |
| 249 } else if (point_type == FXPT_BEZIERTO) { | |
| 250 buf << " " << (pPoints[i + 1].m_PointX) << " " | |
| 251 << (pPoints[i + 1].m_PointY) << " " << (pPoints[i + 2].m_PointX) | |
| 252 << " " << (pPoints[i + 2].m_PointY); | |
| 253 if (pPoints[i + 2].m_Flag & FXPT_CLOSEFIGURE) | |
| 254 buf << " c h\n"; | |
| 255 else | |
| 256 buf << " c\n"; | |
| 257 i += 2; | |
| 258 } else if (point_type == FXPT_LINETO) { | |
| 259 if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE) | |
| 260 buf << " l h\n"; | |
| 261 else | |
| 262 buf << " l\n"; | |
| 263 } | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 DLLEXPORT void STDCALL FPDFPage_InsertClipPath(FPDF_PAGE page, | |
| 268 FPDF_CLIPPATH clipPath) { | |
| 269 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | |
| 270 if (!pPage) | |
| 271 return; | |
| 272 | |
| 273 CPDF_Dictionary* pPageDic = pPage->m_pFormDict; | |
| 274 CPDF_Object* pContentObj = | |
| 275 pPageDic ? pPageDic->GetElement("Contents") : nullptr; | |
| 276 if (!pContentObj) | |
| 277 pContentObj = pPageDic ? pPageDic->GetArrayBy("Contents") : nullptr; | |
| 278 if (!pContentObj) | |
| 279 return; | |
| 280 | |
| 281 CFX_ByteTextBuf strClip; | |
| 282 CPDF_ClipPath* pClipPath = (CPDF_ClipPath*)clipPath; | |
| 283 FX_DWORD i; | |
| 284 for (i = 0; i < pClipPath->GetPathCount(); i++) { | |
| 285 CPDF_Path path = pClipPath->GetPath(i); | |
| 286 int iClipType = pClipPath->GetClipType(i); | |
| 287 if (path.GetPointCount() == 0) { | |
| 288 // Empty clipping (totally clipped out) | |
| 289 strClip << "0 0 m W n "; | |
| 290 } else { | |
| 291 OutputPath(strClip, path); | |
| 292 if (iClipType == FXFILL_WINDING) | |
| 293 strClip << "W n\n"; | |
| 294 else | |
| 295 strClip << "W* n\n"; | |
| 296 } | |
| 297 } | |
| 298 CPDF_Dictionary* pDic = new CPDF_Dictionary; | |
| 299 CPDF_Stream* pStream = new CPDF_Stream(nullptr, 0, pDic); | |
| 300 pStream->SetData(strClip.GetBuffer(), strClip.GetSize(), FALSE, FALSE); | |
| 301 CPDF_Document* pDoc = pPage->m_pDocument; | |
| 302 if (!pDoc) | |
| 303 return; | |
| 304 pDoc->AddIndirectObject(pStream); | |
| 305 | |
| 306 CPDF_Array* pContentArray = nullptr; | |
| 307 if (CPDF_Array* pArray = ToArray(pContentObj)) { | |
| 308 pContentArray = pArray; | |
| 309 CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum()); | |
| 310 pContentArray->InsertAt(0, pRef); | |
| 311 } else if (CPDF_Reference* pReference = ToReference(pContentObj)) { | |
| 312 CPDF_Object* pDirectObj = pReference->GetDirect(); | |
| 313 if (pDirectObj) { | |
| 314 if (CPDF_Array* pArray = pDirectObj->AsArray()) { | |
| 315 pContentArray = pArray; | |
| 316 CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum()); | |
| 317 pContentArray->InsertAt(0, pRef); | |
| 318 } else if (pDirectObj->IsStream()) { | |
| 319 pContentArray = new CPDF_Array(); | |
| 320 pContentArray->AddReference(pDoc, pStream->GetObjNum()); | |
| 321 pContentArray->AddReference(pDoc, pDirectObj->GetObjNum()); | |
| 322 pPageDic->SetAtReference("Contents", pDoc, | |
| 323 pDoc->AddIndirectObject(pContentArray)); | |
| 324 } | |
| 325 } | |
| 326 } | |
| 327 } | |
| OLD | NEW |