Initial commit.
[pdfium.git] / core / src / fpdfapi / fpdf_page / fpdf_page_pattern.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4  \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../../include/fpdfapi/fpdf_page.h"\r
8 #include "pageint.h"\r
9 CPDF_TilingPattern::CPDF_TilingPattern(CPDF_Document* pDoc, CPDF_Object* pPatternObj, const CFX_AffineMatrix* parentMatrix) :\r
10     CPDF_Pattern(parentMatrix)\r
11 {\r
12     m_PatternType = PATTERN_TILING;\r
13     m_pPatternObj = pPatternObj;\r
14     m_pDocument = pDoc;\r
15     CPDF_Dictionary* pDict = m_pPatternObj->GetDict();\r
16     ASSERT(pDict != NULL);\r
17     m_Pattern2Form = pDict->GetMatrix(FX_BSTRC("Matrix"));\r
18     m_bColored = pDict->GetInteger(FX_BSTRC("PaintType")) == 1;\r
19     if (parentMatrix) {\r
20         m_Pattern2Form.Concat(*parentMatrix);\r
21     }\r
22     m_pForm = NULL;\r
23 }\r
24 CPDF_TilingPattern::~CPDF_TilingPattern()\r
25 {\r
26     if (m_pForm) {\r
27         delete m_pForm;\r
28     }\r
29 }\r
30 FX_BOOL CPDF_TilingPattern::Load()\r
31 {\r
32     if (m_pForm != NULL) {\r
33         return TRUE;\r
34     }\r
35     CPDF_Dictionary* pDict = m_pPatternObj->GetDict();\r
36     if (pDict == NULL) {\r
37         return FALSE;\r
38     }\r
39     m_bColored = pDict->GetInteger(FX_BSTRC("PaintType")) == 1;\r
40     m_XStep = (FX_FLOAT)FXSYS_fabs(pDict->GetNumber(FX_BSTRC("XStep")));\r
41     m_YStep = (FX_FLOAT)FXSYS_fabs(pDict->GetNumber(FX_BSTRC("YStep")));\r
42     if (m_pPatternObj->GetType() != PDFOBJ_STREAM) {\r
43         return FALSE;\r
44     }\r
45     CPDF_Stream* pStream = (CPDF_Stream*)m_pPatternObj;\r
46     m_pForm = FX_NEW CPDF_Form(m_pDocument, NULL, pStream);\r
47     m_pForm->ParseContent(NULL, &m_ParentMatrix, NULL, NULL);\r
48     m_BBox = pDict->GetRect(FX_BSTRC("BBox"));\r
49     return TRUE;\r
50 }\r
51 CPDF_ShadingPattern::CPDF_ShadingPattern(CPDF_Document* pDoc, CPDF_Object* pPatternObj, FX_BOOL bShading, const CFX_AffineMatrix* parentMatrix) : CPDF_Pattern(parentMatrix)\r
52 {\r
53     m_PatternType = PATTERN_SHADING;\r
54     m_pPatternObj = bShading ? NULL : pPatternObj;\r
55     m_pDocument = pDoc;\r
56     m_bShadingObj = bShading;\r
57     if (!bShading) {\r
58         CPDF_Dictionary* pDict = m_pPatternObj->GetDict();\r
59         ASSERT(pDict != NULL);\r
60         m_Pattern2Form = pDict->GetMatrix(FX_BSTRC("Matrix"));\r
61         m_pShadingObj = pDict->GetElementValue(FX_BSTRC("Shading"));\r
62         if (parentMatrix) {\r
63             m_Pattern2Form.Concat(*parentMatrix);\r
64         }\r
65     } else {\r
66         m_pShadingObj = pPatternObj;\r
67     }\r
68     m_ShadingType = 0;\r
69     m_pCS = NULL;\r
70     m_nFuncs = 0;\r
71     for (int i = 0; i < 4; i ++) {\r
72         m_pFunctions[i] = NULL;\r
73     }\r
74 }\r
75 CPDF_ShadingPattern::~CPDF_ShadingPattern()\r
76 {\r
77     Clear();\r
78 }\r
79 void CPDF_ShadingPattern::Clear()\r
80 {\r
81     for (int i = 0; i < m_nFuncs; i ++) {\r
82         if (m_pFunctions[i]) {\r
83             delete m_pFunctions[i];\r
84         }\r
85         m_pFunctions[i] = NULL;\r
86     }\r
87     CPDF_ColorSpace* pCS = m_pCS;\r
88     if (pCS && m_pDocument) {\r
89         m_pDocument->GetPageData()->ReleaseColorSpace(pCS->GetArray());\r
90     }\r
91     m_ShadingType = 0;\r
92     m_pCS = NULL;\r
93     m_nFuncs = 0;\r
94 }\r
95 FX_BOOL CPDF_ShadingPattern::Load()\r
96 {\r
97     if (m_ShadingType != 0) {\r
98         return TRUE;\r
99     }\r
100     CPDF_Dictionary* pShadingDict = m_pShadingObj->GetDict();\r
101     if (pShadingDict == NULL) {\r
102         return FALSE;\r
103     }\r
104     if (m_nFuncs) {\r
105         for (int i = 0; i < m_nFuncs; i ++)\r
106             if (m_pFunctions[i]) {\r
107                 delete m_pFunctions[i];\r
108             }\r
109         m_nFuncs = 0;\r
110     }\r
111     CPDF_Object* pFunc = pShadingDict->GetElementValue(FX_BSTRC("Function"));\r
112     if (pFunc) {\r
113         if (pFunc->GetType() == PDFOBJ_ARRAY) {\r
114             m_nFuncs = ((CPDF_Array*)pFunc)->GetCount();\r
115             if (m_nFuncs > 4) {\r
116                 m_nFuncs = 4;\r
117             }\r
118             for (int i = 0; i < m_nFuncs; i ++) {\r
119                 m_pFunctions[i] = CPDF_Function::Load(((CPDF_Array*)pFunc)->GetElementValue(i));\r
120             }\r
121         } else {\r
122             m_pFunctions[0] = CPDF_Function::Load(pFunc);\r
123             m_nFuncs = 1;\r
124         }\r
125     }\r
126     CPDF_Object* pCSObj = pShadingDict->GetElementValue(FX_BSTRC("ColorSpace"));\r
127     if (pCSObj == NULL) {\r
128         return FALSE;\r
129     }\r
130     CPDF_DocPageData* pDocPageData = m_pDocument->GetPageData();\r
131     m_pCS = pDocPageData->GetColorSpace(pCSObj, NULL);\r
132     m_ShadingType = pShadingDict->GetInteger(FX_BSTRC("ShadingType"));\r
133     return TRUE;\r
134 }\r
135 FX_BOOL CPDF_ShadingPattern::Reload()\r
136 {\r
137     Clear();\r
138     return Load();\r
139 }\r
140 FX_BOOL CPDF_MeshStream::Load(CPDF_Stream* pShadingStream, CPDF_Function** pFuncs, int nFuncs, CPDF_ColorSpace* pCS)\r
141 {\r
142     m_Stream.LoadAllData(pShadingStream);\r
143     m_BitStream.Init(m_Stream.GetData(), m_Stream.GetSize());\r
144     m_pFuncs = pFuncs;\r
145     m_nFuncs = nFuncs;\r
146     m_pCS = pCS;\r
147     CPDF_Dictionary* pDict = pShadingStream->GetDict();\r
148     m_nCoordBits = pDict->GetInteger(FX_BSTRC("BitsPerCoordinate"));\r
149     m_nCompBits = pDict->GetInteger(FX_BSTRC("BitsPerComponent"));\r
150     m_nFlagBits = pDict->GetInteger(FX_BSTRC("BitsPerFlag"));\r
151     if (!m_nCoordBits || !m_nCompBits) {\r
152         return FALSE;\r
153     }\r
154     int nComps = pCS->CountComponents();\r
155     if (nComps > 8) {\r
156         return FALSE;\r
157     }\r
158     m_nComps = nFuncs ? 1 : nComps;\r
159     if (((int)m_nComps < 0) || m_nComps > 8) {\r
160         return FALSE;\r
161     }\r
162     m_CoordMax = m_nCoordBits == 32 ? -1 : (1 << m_nCoordBits) - 1;\r
163     m_CompMax = (1 << m_nCompBits) - 1;\r
164     CPDF_Array* pDecode = pDict->GetArray(FX_BSTRC("Decode"));\r
165     if (pDecode == NULL || pDecode->GetCount() != 4 + m_nComps * 2) {\r
166         return FALSE;\r
167     }\r
168     m_xmin = pDecode->GetNumber(0);\r
169     m_xmax = pDecode->GetNumber(1);\r
170     m_ymin = pDecode->GetNumber(2);\r
171     m_ymax = pDecode->GetNumber(3);\r
172     for (FX_DWORD i = 0; i < m_nComps; i ++) {\r
173         m_ColorMin[i] = pDecode->GetNumber(i * 2 + 4);\r
174         m_ColorMax[i] = pDecode->GetNumber(i * 2 + 5);\r
175     }\r
176     return TRUE;\r
177 }\r
178 FX_DWORD CPDF_MeshStream::GetFlag()\r
179 {\r
180     return m_BitStream.GetBits(m_nFlagBits) & 0x03;\r
181 }\r
182 void CPDF_MeshStream::GetCoords(FX_FLOAT& x, FX_FLOAT& y)\r
183 {\r
184     if (m_nCoordBits == 32) {\r
185         x = m_xmin + (FX_FLOAT)(m_BitStream.GetBits(m_nCoordBits) * (m_xmax - m_xmin) / (double)m_CoordMax);\r
186         y = m_ymin + (FX_FLOAT)(m_BitStream.GetBits(m_nCoordBits) * (m_ymax - m_ymin) / (double)m_CoordMax);\r
187     } else {\r
188         x = m_xmin + m_BitStream.GetBits(m_nCoordBits) * (m_xmax - m_xmin) / m_CoordMax;\r
189         y = m_ymin + m_BitStream.GetBits(m_nCoordBits) * (m_ymax - m_ymin) / m_CoordMax;\r
190     }\r
191 }\r
192 void CPDF_MeshStream::GetColor(FX_FLOAT& r, FX_FLOAT& g, FX_FLOAT& b)\r
193 {\r
194     FX_DWORD i;\r
195     FX_FLOAT color_value[8];\r
196     for (i = 0; i < m_nComps; i ++) {\r
197         color_value[i] = m_ColorMin[i] + m_BitStream.GetBits(m_nCompBits) * (m_ColorMax[i] - m_ColorMin[i]) / m_CompMax;\r
198     }\r
199     if (m_nFuncs) {\r
200         static const int kMaxResults = 8;\r
201         FX_FLOAT result[kMaxResults];\r
202         int nResults;\r
203         FXSYS_memset32(result, 0, sizeof(result));\r
204         for (FX_DWORD i = 0; i < m_nFuncs; i ++) {\r
205             if (m_pFuncs[i] && m_pFuncs[i]->CountOutputs() <= kMaxResults) {\r
206                 m_pFuncs[i]->Call(color_value, 1, result, nResults);\r
207             }\r
208         }\r
209         m_pCS->GetRGB(result, r, g, b);\r
210     } else {\r
211         m_pCS->GetRGB(color_value, r, g, b);\r
212     }\r
213 }\r
214 FX_DWORD CPDF_MeshStream::GetVertex(CPDF_MeshVertex& vertex, CFX_AffineMatrix* pObject2Bitmap)\r
215 {\r
216     FX_DWORD flag = GetFlag();\r
217     GetCoords(vertex.x, vertex.y);\r
218     pObject2Bitmap->Transform(vertex.x, vertex.y);\r
219     GetColor(vertex.r, vertex.g, vertex.b);\r
220     m_BitStream.ByteAlign();\r
221     return flag;\r
222 }\r
223 FX_BOOL CPDF_MeshStream::GetVertexRow(CPDF_MeshVertex* vertex, int count, CFX_AffineMatrix* pObject2Bitmap)\r
224 {\r
225     for (int i = 0; i < count; i ++) {\r
226         if (m_BitStream.IsEOF()) {\r
227             return FALSE;\r
228         }\r
229         GetCoords(vertex[i].x, vertex[i].y);\r
230         pObject2Bitmap->Transform(vertex[i].x, vertex[i].y);\r
231         GetColor(vertex[i].r, vertex[i].g, vertex[i].b);\r
232         m_BitStream.ByteAlign();\r
233     }\r
234     return TRUE;\r
235 }\r
236 CFX_FloatRect _GetShadingBBox(CPDF_Stream* pStream, int type, const CFX_AffineMatrix* pMatrix,\r
237                               CPDF_Function** pFuncs, int nFuncs, CPDF_ColorSpace* pCS)\r
238 {\r
239     if (pStream == NULL || pStream->GetType() != PDFOBJ_STREAM || pFuncs == NULL || pCS == NULL) {\r
240         return CFX_FloatRect(0, 0, 0, 0);\r
241     }\r
242     CPDF_MeshStream stream;\r
243     if (!stream.Load(pStream, pFuncs, nFuncs, pCS)) {\r
244         return CFX_FloatRect(0, 0, 0, 0);\r
245     }\r
246     CFX_FloatRect rect;\r
247     FX_BOOL bStarted = FALSE;\r
248     FX_BOOL bGouraud = type == 4 || type == 5;\r
249     int full_point_count = type == 7 ? 16 : (type == 6 ? 12 : 1);\r
250     int full_color_count = (type == 6 || type == 7) ? 4 : 1;\r
251     while (!stream.m_BitStream.IsEOF()) {\r
252         FX_DWORD flag;\r
253         if (type != 5) {\r
254             flag = stream.GetFlag();\r
255         }\r
256         int point_count = full_point_count, color_count = full_color_count;\r
257         if (!bGouraud && flag) {\r
258             point_count -= 4;\r
259             color_count -= 2;\r
260         }\r
261         for (int i = 0; i < point_count; i ++) {\r
262             FX_FLOAT x, y;\r
263             stream.GetCoords(x, y);\r
264             if (bStarted) {\r
265                 rect.UpdateRect(x, y);\r
266             } else {\r
267                 rect.InitRect(x, y);\r
268                 bStarted = TRUE;\r
269             }\r
270         }\r
271         stream.m_BitStream.SkipBits(stream.m_nComps * stream.m_nCompBits * color_count);\r
272         if (bGouraud) {\r
273             stream.m_BitStream.ByteAlign();\r
274         }\r
275     }\r
276     rect.Transform(pMatrix);\r
277     return rect;\r
278 }\r