Cleanup casting of FX_Alloc() return values.
[pdfium.git] / core / src / fpdfapi / fpdf_edit / fpdf_edit_content.cpp
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 "../../../include/fpdfapi/fpdf_page.h"
8 #include "../../../include/fpdfapi/fpdf_serial.h"
9 #include "../../../include/fpdfapi/fpdf_module.h"
10 #include "../fpdf_page/pageint.h"
11
12 CFX_ByteTextBuf& operator<<(CFX_ByteTextBuf& ar, CFX_AffineMatrix& matrix) {
13   ar << matrix.a << " " << matrix.b << " " << matrix.c << " " << matrix.d << " "
14      << matrix.e << " " << matrix.f;
15   return ar;
16 }
17 CPDF_PageContentGenerate::CPDF_PageContentGenerate(CPDF_Page* pPage)
18     : m_pPage(pPage) {
19   m_pDocument = NULL;
20   if (m_pPage) {
21     m_pDocument = m_pPage->m_pDocument;
22   }
23   FX_POSITION pos = pPage->GetFirstObjectPosition();
24   while (pos) {
25     InsertPageObject(pPage->GetNextObject(pos));
26   }
27 }
28 CPDF_PageContentGenerate::~CPDF_PageContentGenerate() {}
29 FX_BOOL CPDF_PageContentGenerate::InsertPageObject(
30     CPDF_PageObject* pPageObject) {
31   if (!pPageObject) {
32     return FALSE;
33   }
34   return m_pageObjects.Add(pPageObject);
35 }
36 void CPDF_PageContentGenerate::GenerateContent() {
37   CFX_ByteTextBuf buf;
38   CPDF_Dictionary* pPageDict = m_pPage->m_pFormDict;
39   for (int i = 0; i < m_pageObjects.GetSize(); ++i) {
40     CPDF_PageObject* pPageObj = (CPDF_PageObject*)m_pageObjects[i];
41     if (!pPageObj || pPageObj->m_Type != PDFPAGE_IMAGE) {
42       continue;
43     }
44     ProcessImage(buf, (CPDF_ImageObject*)pPageObj);
45   }
46   CPDF_Object* pContent =
47       pPageDict ? pPageDict->GetElementValue("Contents") : NULL;
48   if (pContent != NULL) {
49     pPageDict->RemoveAt("Contents");
50   }
51   CPDF_Stream* pStream = new CPDF_Stream(NULL, 0, NULL);
52   pStream->SetData(buf.GetBuffer(), buf.GetLength(), FALSE, FALSE);
53   m_pDocument->AddIndirectObject(pStream);
54   pPageDict->SetAtReference("Contents", m_pDocument, pStream->GetObjNum());
55 }
56 CFX_ByteString CPDF_PageContentGenerate::RealizeResource(
57     CPDF_Object* pResourceObj,
58     const FX_CHAR* szType) {
59   if (m_pPage->m_pResources == NULL) {
60     m_pPage->m_pResources = new CPDF_Dictionary;
61     int objnum = m_pDocument->AddIndirectObject(m_pPage->m_pResources);
62     m_pPage->m_pFormDict->SetAtReference("Resources", m_pDocument, objnum);
63   }
64   CPDF_Dictionary* pResList = m_pPage->m_pResources->GetDict(szType);
65   if (pResList == NULL) {
66     pResList = new CPDF_Dictionary;
67     m_pPage->m_pResources->SetAt(szType, pResList);
68   }
69   m_pDocument->AddIndirectObject(pResourceObj);
70   CFX_ByteString name;
71   int idnum = 1;
72   while (1) {
73     name.Format("FX%c%d", szType[0], idnum);
74     if (!pResList->KeyExist(name)) {
75       break;
76     }
77     idnum++;
78   }
79   pResList->AddReference(name, m_pDocument, pResourceObj->GetObjNum());
80   return name;
81 }
82 void CPDF_PageContentGenerate::ProcessImage(CFX_ByteTextBuf& buf,
83                                             CPDF_ImageObject* pImageObj) {
84   if ((pImageObj->m_Matrix.a == 0 && pImageObj->m_Matrix.b == 0) ||
85       (pImageObj->m_Matrix.c == 0 && pImageObj->m_Matrix.d == 0)) {
86     return;
87   }
88   buf << "q " << pImageObj->m_Matrix << " cm ";
89   if (!pImageObj->m_pImage->IsInline()) {
90     CPDF_Stream* pStream = pImageObj->m_pImage->GetStream();
91     FX_DWORD dwSavedObjNum = pStream->GetObjNum();
92     CFX_ByteString name = RealizeResource(pStream, "XObject");
93     if (dwSavedObjNum == 0) {
94       if (pImageObj->m_pImage)
95         pImageObj->m_pImage->Release();
96       pImageObj->m_pImage = m_pDocument->GetPageData()->GetImage(pStream);
97     }
98     buf << "/" << PDF_NameEncode(name) << " Do Q\n";
99   }
100 }
101 void CPDF_PageContentGenerate::ProcessForm(CFX_ByteTextBuf& buf,
102                                            const uint8_t* data,
103                                            FX_DWORD size,
104                                            CFX_Matrix& matrix) {
105   if (!data || !size) {
106     return;
107   }
108   CPDF_Stream* pStream = new CPDF_Stream(NULL, 0, NULL);
109   CPDF_Dictionary* pFormDict = CPDF_Dictionary::Create();
110   pFormDict->SetAtName("Type", "XObject");
111   pFormDict->SetAtName("Subtype", "Form");
112   CFX_FloatRect bbox = m_pPage->GetPageBBox();
113   matrix.TransformRect(bbox);
114   pFormDict->SetAtRect("BBox", bbox);
115   pStream->InitStream((uint8_t*)data, size, pFormDict);
116   buf << "q " << matrix << " cm ";
117   CFX_ByteString name = RealizeResource(pStream, "XObject");
118   buf << "/" << PDF_NameEncode(name) << " Do Q\n";
119 }
120 void CPDF_PageContentGenerate::TransformContent(CFX_Matrix& matrix) {
121   CPDF_Dictionary* pDict = m_pPage->m_pFormDict;
122   CPDF_Object* pContent = pDict ? pDict->GetElementValue("Contents") : NULL;
123   if (!pContent) {
124     return;
125   }
126   CFX_ByteTextBuf buf;
127   int type = pContent->GetType();
128   if (type == PDFOBJ_ARRAY) {
129     CPDF_Array* pArray = (CPDF_Array*)pContent;
130     int iCount = pArray->GetCount();
131     CPDF_StreamAcc** pContentArray = FX_Alloc(CPDF_StreamAcc*, iCount);
132     int size = 0;
133     int i = 0;
134     for (i = 0; i < iCount; ++i) {
135       pContent = pArray->GetElement(i);
136       if (!pContent || pContent->GetType() != PDFOBJ_STREAM) {
137         continue;
138       }
139       CPDF_StreamAcc* pStream = new CPDF_StreamAcc();
140       pStream->LoadAllData((CPDF_Stream*)pContent);
141       pContentArray[i] = pStream;
142       size += pContentArray[i]->GetSize() + 1;
143     }
144     int pos = 0;
145     uint8_t* pBuf = FX_Alloc(uint8_t, size);
146     for (i = 0; i < iCount; ++i) {
147       FXSYS_memcpy(pBuf + pos, pContentArray[i]->GetData(),
148                    pContentArray[i]->GetSize());
149       pos += pContentArray[i]->GetSize() + 1;
150       pBuf[pos - 1] = ' ';
151       delete pContentArray[i];
152     }
153     ProcessForm(buf, pBuf, size, matrix);
154     FX_Free(pBuf);
155     FX_Free(pContentArray);
156   } else if (type == PDFOBJ_STREAM) {
157     CPDF_StreamAcc contentStream;
158     contentStream.LoadAllData((CPDF_Stream*)pContent);
159     ProcessForm(buf, contentStream.GetData(), contentStream.GetSize(), matrix);
160   }
161   CPDF_Stream* pStream = new CPDF_Stream(NULL, 0, NULL);
162   pStream->SetData(buf.GetBuffer(), buf.GetLength(), FALSE, FALSE);
163   m_pDocument->AddIndirectObject(pStream);
164   m_pPage->m_pFormDict->SetAtReference("Contents", m_pDocument,
165                                        pStream->GetObjNum());
166 }