Initial commit.
[pdfium.git] / core / src / fpdfapi / fpdf_page / fpdf_page.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 "../../../include/fpdfapi/fpdf_module.h"\r
9 #include "pageint.h"\r
10 void CPDF_PageObject::Release()\r
11 {\r
12     delete this;\r
13 }\r
14 CPDF_PageObject* CPDF_PageObject::Create(int type)\r
15 {\r
16     switch (type) {\r
17         case PDFPAGE_TEXT:\r
18             return FX_NEW CPDF_TextObject;\r
19         case PDFPAGE_IMAGE:\r
20             return FX_NEW CPDF_ImageObject;\r
21         case PDFPAGE_PATH:\r
22             return FX_NEW CPDF_PathObject;\r
23         case PDFPAGE_SHADING:\r
24             return FX_NEW CPDF_ShadingObject;\r
25         case PDFPAGE_FORM:\r
26             return FX_NEW CPDF_FormObject;\r
27     }\r
28     return NULL;\r
29 }\r
30 CPDF_PageObject* CPDF_PageObject::Clone() const\r
31 {\r
32     CPDF_PageObject* pObj = Create(m_Type);\r
33     pObj->Copy(this);\r
34     return pObj;\r
35 }\r
36 void CPDF_PageObject::Copy(const CPDF_PageObject* pSrc)\r
37 {\r
38     if (m_Type != pSrc->m_Type) {\r
39         return;\r
40     }\r
41     CopyData(pSrc);\r
42     CopyStates(*pSrc);\r
43     m_Left = pSrc->m_Left;\r
44     m_Right = pSrc->m_Right;\r
45     m_Top = pSrc->m_Top;\r
46     m_Bottom = pSrc->m_Bottom;\r
47 }\r
48 void CPDF_PageObject::AppendClipPath(CPDF_Path path, int type, FX_BOOL bAutoMerge)\r
49 {\r
50     m_ClipPath.AppendPath(path, type, bAutoMerge);\r
51 }\r
52 void CPDF_PageObject::CopyClipPath(CPDF_PageObject* pObj)\r
53 {\r
54     m_ClipPath = pObj->m_ClipPath;\r
55 }\r
56 void CPDF_PageObject::RemoveClipPath()\r
57 {\r
58     m_ClipPath.SetNull();\r
59 }\r
60 void CPDF_PageObject::RecalcBBox()\r
61 {\r
62     switch (m_Type) {\r
63         case PDFPAGE_TEXT:\r
64             ((CPDF_TextObject*)this)->RecalcPositionData();\r
65             break;\r
66         case PDFPAGE_PATH:\r
67             ((CPDF_PathObject*)this)->CalcBoundingBox();\r
68             break;\r
69         case PDFPAGE_SHADING:\r
70             ((CPDF_ShadingObject*)this)->CalcBoundingBox();\r
71             break;\r
72     }\r
73 }\r
74 void CPDF_PageObject::TransformClipPath(CFX_AffineMatrix& matrix)\r
75 {\r
76     if (m_ClipPath.IsNull()) {\r
77         return;\r
78     }\r
79     m_ClipPath.GetModify();\r
80     m_ClipPath.Transform(matrix);\r
81 }\r
82 void CPDF_PageObject::TransformGeneralState(CFX_AffineMatrix& matrix)\r
83 {\r
84     if(m_GeneralState.IsNull()) {\r
85         return;\r
86     }\r
87     CPDF_GeneralStateData* pGS = m_GeneralState.GetModify();\r
88     pGS->m_Matrix.Concat(matrix);\r
89 }\r
90 FX_RECT CPDF_PageObject::GetBBox(const CFX_AffineMatrix* pMatrix) const\r
91 {\r
92     CFX_FloatRect rect(m_Left, m_Bottom, m_Right, m_Top);\r
93     if (pMatrix) {\r
94         pMatrix->TransformRect(rect);\r
95     }\r
96     return rect.GetOutterRect();\r
97 }\r
98 CPDF_TextObject::CPDF_TextObject()\r
99 {\r
100     m_Type = PDFPAGE_TEXT;\r
101     m_pCharCodes = NULL;\r
102     m_pCharPos = NULL;\r
103     m_nChars = 0;\r
104     m_PosX = m_PosY = 0;\r
105 }\r
106 CPDF_TextObject::~CPDF_TextObject()\r
107 {\r
108     if (m_nChars > 1 && m_pCharCodes) {\r
109         FX_Free(m_pCharCodes);\r
110     }\r
111     if (m_pCharPos) {\r
112         FX_Free(m_pCharPos);\r
113     }\r
114 }\r
115 void CPDF_TextObject::GetItemInfo(int index, CPDF_TextObjectItem* pInfo) const\r
116 {\r
117     pInfo->m_CharCode = m_nChars == 1 ? (FX_DWORD)(FX_UINTPTR)m_pCharCodes : m_pCharCodes[index];\r
118     pInfo->m_OriginX = index ? m_pCharPos[index - 1] : 0;\r
119     pInfo->m_OriginY = 0;\r
120     if (pInfo->m_CharCode == -1) {\r
121         return;\r
122     }\r
123     CPDF_Font* pFont = m_TextState.GetFont();\r
124     if (pFont->GetFontType() != PDFFONT_CIDFONT) {\r
125         return;\r
126     }\r
127     if (!((CPDF_CIDFont*)pFont)->IsVertWriting()) {\r
128         return;\r
129     }\r
130     FX_WORD CID = ((CPDF_CIDFont*)pFont)->CIDFromCharCode(pInfo->m_CharCode);\r
131     pInfo->m_OriginY = pInfo->m_OriginX;\r
132     pInfo->m_OriginX = 0;\r
133     short vx, vy;\r
134     ((CPDF_CIDFont*)pFont)->GetVertOrigin(CID, vx, vy);\r
135     FX_FLOAT fontsize = m_TextState.GetFontSize();\r
136     pInfo->m_OriginX -= fontsize * vx / 1000;\r
137     pInfo->m_OriginY -= fontsize * vy / 1000;\r
138 }\r
139 int CPDF_TextObject::CountChars() const\r
140 {\r
141     if (m_nChars == 1) {\r
142         return 1;\r
143     }\r
144     int count = 0;\r
145     for (int i = 0; i < m_nChars; i ++)\r
146         if (m_pCharCodes[i] != (FX_DWORD) - 1) {\r
147             count ++;\r
148         }\r
149     return count;\r
150 }\r
151 void CPDF_TextObject::GetCharInfo(int index, FX_DWORD& charcode, FX_FLOAT& kerning) const\r
152 {\r
153     if (m_nChars == 1) {\r
154         charcode = (FX_DWORD)(FX_UINTPTR)m_pCharCodes;\r
155         kerning = 0;\r
156         return;\r
157     }\r
158     int count = 0;\r
159     for (int i = 0; i < m_nChars; i ++) {\r
160         if (m_pCharCodes[i] != (FX_DWORD) - 1) {\r
161             if (count == index) {\r
162                 charcode = m_pCharCodes[i];\r
163                 if (i == m_nChars - 1 || m_pCharCodes[i + 1] != (FX_DWORD) - 1) {\r
164                     kerning = 0;\r
165                 } else {\r
166                     kerning = m_pCharPos[i];\r
167                 }\r
168                 return;\r
169             }\r
170             count ++;\r
171         }\r
172     }\r
173 }\r
174 void CPDF_TextObject::GetCharInfo(int index, CPDF_TextObjectItem* pInfo) const\r
175 {\r
176     if (m_nChars == 1) {\r
177         GetItemInfo(0, pInfo);\r
178         return;\r
179     }\r
180     int count = 0;\r
181     for (int i = 0; i < m_nChars; i ++) {\r
182         FX_DWORD charcode = m_pCharCodes[i];\r
183         if (charcode == (FX_DWORD) - 1) {\r
184             continue;\r
185         }\r
186         if (count == index) {\r
187             GetItemInfo(i, pInfo);\r
188             break;\r
189         }\r
190         count ++;\r
191     }\r
192 }\r
193 void CPDF_TextObject::CopyData(const CPDF_PageObject* pSrc)\r
194 {\r
195     const CPDF_TextObject* pSrcObj = (const CPDF_TextObject*)pSrc;\r
196     if (m_nChars > 1 && m_pCharCodes) {\r
197         FX_Free(m_pCharCodes);\r
198         m_pCharCodes = NULL;\r
199     }\r
200     if (m_pCharPos) {\r
201         FX_Free(m_pCharPos);\r
202         m_pCharPos = NULL;\r
203     }\r
204     m_nChars = pSrcObj->m_nChars;\r
205     if (m_nChars > 1) {\r
206         m_pCharCodes = FX_Alloc(FX_DWORD, m_nChars);\r
207         m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);\r
208         int i;\r
209         for (i = 0; i < m_nChars; i ++) {\r
210             m_pCharCodes[i] = pSrcObj->m_pCharCodes[i];\r
211         }\r
212         for (i = 0; i < m_nChars - 1; i ++) {\r
213             m_pCharPos[i] = pSrcObj->m_pCharPos[i];\r
214         }\r
215     } else {\r
216         m_pCharCodes = pSrcObj->m_pCharCodes;\r
217     }\r
218     m_PosX = pSrcObj->m_PosX;\r
219     m_PosY = pSrcObj->m_PosY;\r
220 }\r
221 void CPDF_TextObject::GetTextMatrix(CFX_AffineMatrix* pMatrix) const\r
222 {\r
223     FX_FLOAT* pTextMatrix = m_TextState.GetMatrix();\r
224     pMatrix->Set(pTextMatrix[0], pTextMatrix[2], pTextMatrix[1], pTextMatrix[3], m_PosX, m_PosY);\r
225 }\r
226 void CPDF_TextObject::SetSegments(const CFX_ByteString* pStrs, FX_FLOAT* pKerning, int nsegs)\r
227 {\r
228     if (m_nChars > 1 && m_pCharCodes) {\r
229         FX_Free(m_pCharCodes);\r
230         m_pCharCodes = NULL;\r
231     }\r
232     if (m_pCharPos) {\r
233         FX_Free(m_pCharPos);\r
234         m_pCharPos = NULL;\r
235     }\r
236     CPDF_Font* pFont = m_TextState.GetFont();\r
237     m_nChars = 0;\r
238     for (int i = 0; i < nsegs; i ++) {\r
239         m_nChars += pFont->CountChar(pStrs[i], pStrs[i].GetLength());\r
240     }\r
241     m_nChars += nsegs - 1;\r
242     if (m_nChars > 1) {\r
243         m_pCharCodes = FX_Alloc(FX_DWORD, m_nChars);\r
244         m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);\r
245         int index = 0;\r
246         for (int i = 0; i < nsegs; i ++) {\r
247             FX_LPCSTR segment = pStrs[i];\r
248             int offset = 0, len = pStrs[i].GetLength();\r
249             while (offset < len) {\r
250                 m_pCharCodes[index++] = pFont->GetNextChar(segment, offset);\r
251             }\r
252             if (i != nsegs - 1) {\r
253                 m_pCharPos[index - 1] = pKerning[i];\r
254                 m_pCharCodes[index ++] = (FX_DWORD) - 1;\r
255             }\r
256         }\r
257     } else {\r
258         int offset = 0;\r
259         m_pCharCodes = (FX_DWORD*)(FX_UINTPTR)pFont->GetNextChar(pStrs[0], offset);\r
260     }\r
261 }\r
262 void CPDF_TextObject::SetText(const CFX_ByteString& str)\r
263 {\r
264     SetSegments(&str, NULL, 1);\r
265     RecalcPositionData();\r
266 }\r
267 void CPDF_TextObject::SetEmpty()\r
268 {\r
269     if (m_nChars > 1 && m_pCharCodes) {\r
270         FX_Free(m_pCharCodes);\r
271     }\r
272     if (m_nChars > 1 && m_pCharPos) {\r
273         FX_Free(m_pCharPos);\r
274     }\r
275     m_nChars = 0;\r
276     m_pCharCodes = NULL;\r
277     m_pCharPos = NULL;\r
278     m_Left = m_Right = m_PosX;\r
279     m_Top = m_Bottom = m_PosY;\r
280 }\r
281 void CPDF_TextObject::SetText(CFX_ByteString* pStrs, FX_FLOAT* pKerning, int nSegs)\r
282 {\r
283     SetSegments(pStrs, pKerning, nSegs);\r
284     RecalcPositionData();\r
285 }\r
286 void CPDF_TextObject::SetText(int nChars, FX_DWORD* pCharCodes, FX_FLOAT* pKernings)\r
287 {\r
288     if (m_nChars > 1 && m_pCharCodes) {\r
289         FX_Free(m_pCharCodes);\r
290         m_pCharCodes = NULL;\r
291     }\r
292     if (m_pCharPos) {\r
293         FX_Free(m_pCharPos);\r
294         m_pCharPos = NULL;\r
295     }\r
296     int nKernings = 0;\r
297     int i;\r
298     for (i = 0; i < nChars - 1; i ++)\r
299         if (pKernings[i] != 0) {\r
300             nKernings ++;\r
301         }\r
302     m_nChars = nChars + nKernings;\r
303     if (m_nChars > 1) {\r
304         m_pCharCodes = FX_Alloc(FX_DWORD, m_nChars);\r
305         m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);\r
306         int index = 0;\r
307         for (int i = 0; i < nChars; i ++) {\r
308             m_pCharCodes[index++] = pCharCodes[i];\r
309             if (pKernings[i] != 0 && i != nChars - 1) {\r
310                 m_pCharCodes[index] = (FX_DWORD) - 1;\r
311                 m_pCharPos[index - 1] = pKernings[i];\r
312                 index ++;\r
313             }\r
314         }\r
315     } else {\r
316         int offset = 0;\r
317         m_pCharCodes = (FX_DWORD*)(FX_UINTPTR)pCharCodes[0];\r
318     }\r
319     RecalcPositionData();\r
320 }\r
321 FX_FLOAT CPDF_TextObject::GetCharWidth(FX_DWORD charcode) const\r
322 {\r
323     FX_FLOAT fontsize = m_TextState.GetFontSize() / 1000;\r
324     CPDF_Font* pFont = m_TextState.GetFont();\r
325     FX_BOOL bVertWriting = FALSE;\r
326     CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();\r
327     if (pCIDFont) {\r
328         bVertWriting = pCIDFont->IsVertWriting();\r
329     }\r
330     if (!bVertWriting) {\r
331         return pFont->GetCharWidthF(charcode, 0) * fontsize;\r
332     } else {\r
333         FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);\r
334         return pCIDFont->GetVertWidth(CID) * fontsize;\r
335     }\r
336 }\r
337 FX_FLOAT CPDF_TextObject::GetSpaceCharWidth() const\r
338 {\r
339     CPDF_Font* pFont = m_TextState.GetFont();\r
340     FX_DWORD charCode = m_TextState.GetFont()->CharCodeFromUnicode(32);\r
341     if (charCode != (FX_DWORD) - 1) {\r
342         return GetCharWidth(charCode);\r
343     }\r
344     FX_FLOAT fontSize = m_TextState.GetFontSize() / 4000.0f;\r
345     FX_BOOL bVertWriting = FALSE;\r
346     CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();\r
347     if (pCIDFont) {\r
348         bVertWriting = pCIDFont->IsVertWriting();\r
349     }\r
350     FX_RECT fontRect;\r
351     pFont->GetFontBBox(fontRect);\r
352     fontSize *= bVertWriting ? (FX_FLOAT)fontRect.Height() : (FX_FLOAT)fontRect.Width();\r
353     return fontSize;\r
354 }\r
355 void CPDF_TextObject::GetCharRect(int index, CFX_FloatRect& rect) const\r
356 {\r
357     FX_FLOAT curpos = 0;\r
358     CPDF_Font* pFont = m_TextState.GetFont();\r
359     FX_BOOL bVertWriting = FALSE;\r
360     CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();\r
361     if (pCIDFont) {\r
362         bVertWriting = pCIDFont->IsVertWriting();\r
363     }\r
364     FX_FLOAT fontsize = m_TextState.GetFontSize() / 1000;\r
365     int count = 0;\r
366     for (int i = 0; i < m_nChars; i ++) {\r
367         FX_DWORD charcode = m_nChars == 1 ? (FX_DWORD)(FX_UINTPTR)m_pCharCodes : m_pCharCodes[i];\r
368         if (charcode == (FX_DWORD) - 1) {\r
369             continue;\r
370         }\r
371         if( count != index) {\r
372             count++;\r
373             continue;\r
374         }\r
375         FX_FLOAT curpos = i > 0 ? m_pCharPos[i - 1] : 0;\r
376         FX_RECT char_rect;\r
377         pFont->GetCharBBox(charcode, char_rect, 0);\r
378         if (!bVertWriting) {\r
379             rect.left = curpos + char_rect.left * fontsize;\r
380             rect.right = curpos + char_rect.right * fontsize;\r
381             rect.top = char_rect.top * fontsize;\r
382             rect.bottom = char_rect.bottom * fontsize;\r
383         } else {\r
384             FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);\r
385             short vx, vy;\r
386             pCIDFont->GetVertOrigin(CID, vx, vy);\r
387             char_rect.left -= vx;\r
388             char_rect.right -= vx;\r
389             char_rect.top -= vy;\r
390             char_rect.bottom -= vy;\r
391             rect.left = char_rect.left * fontsize;\r
392             rect.right = char_rect.right * fontsize;\r
393             rect.top = curpos + char_rect.top * fontsize;\r
394             rect.bottom = curpos + char_rect.bottom * fontsize;\r
395         }\r
396         return;\r
397     }\r
398 }\r
399 void CPDF_TextObject::CalcPositionData(FX_FLOAT* pTextAdvanceX, FX_FLOAT* pTextAdvanceY, FX_FLOAT horz_scale, int level)\r
400 {\r
401     FX_FLOAT curpos = 0;\r
402     FX_FLOAT min_x = 10000 * 1.0f, max_x = -10000 * 1.0f, min_y = 10000 * 1.0f, max_y = -10000 * 1.0f;\r
403     CPDF_Font* pFont = m_TextState.GetFont();\r
404     FX_BOOL bVertWriting = FALSE;\r
405     CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();\r
406     if (pCIDFont) {\r
407         bVertWriting = pCIDFont->IsVertWriting();\r
408     }\r
409     FX_FLOAT fontsize = m_TextState.GetFontSize();\r
410     for (int i = 0; i < m_nChars; i ++) {\r
411         FX_DWORD charcode = m_nChars == 1 ? (FX_DWORD)(FX_UINTPTR)m_pCharCodes : m_pCharCodes[i];\r
412         if (charcode == (FX_DWORD) - 1) {\r
413             curpos -= FXSYS_Mul(m_pCharPos[i - 1], fontsize) / 1000;\r
414             continue;\r
415         }\r
416         if (i) {\r
417             m_pCharPos[i - 1] = curpos;\r
418         }\r
419         FX_RECT char_rect;\r
420         pFont->GetCharBBox(charcode, char_rect, level);\r
421         FX_FLOAT charwidth;\r
422         if (!bVertWriting) {\r
423             if (min_y > char_rect.top) {\r
424                 min_y = (FX_FLOAT)char_rect.top;\r
425             }\r
426             if (max_y < char_rect.top) {\r
427                 max_y = (FX_FLOAT)char_rect.top;\r
428             }\r
429             if (min_y > char_rect.bottom) {\r
430                 min_y = (FX_FLOAT)char_rect.bottom;\r
431             }\r
432             if (max_y < char_rect.bottom) {\r
433                 max_y = (FX_FLOAT)char_rect.bottom;\r
434             }\r
435             FX_FLOAT char_left = curpos + char_rect.left * fontsize / 1000;\r
436             FX_FLOAT char_right = curpos + char_rect.right * fontsize / 1000;\r
437             if (min_x > char_left) {\r
438                 min_x = char_left;\r
439             }\r
440             if (max_x < char_left) {\r
441                 max_x = char_left;\r
442             }\r
443             if (min_x > char_right) {\r
444                 min_x = char_right;\r
445             }\r
446             if (max_x < char_right) {\r
447                 max_x = char_right;\r
448             }\r
449             charwidth = pFont->GetCharWidthF(charcode, level) * fontsize / 1000;\r
450         } else {\r
451             FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);\r
452             short vx, vy;\r
453             pCIDFont->GetVertOrigin(CID, vx, vy);\r
454             char_rect.left -= vx;\r
455             char_rect.right -= vx;\r
456             char_rect.top -= vy;\r
457             char_rect.bottom -= vy;\r
458             if (min_x > char_rect.left) {\r
459                 min_x = (FX_FLOAT)char_rect.left;\r
460             }\r
461             if (max_x < char_rect.left) {\r
462                 max_x = (FX_FLOAT)char_rect.left;\r
463             }\r
464             if (min_x > char_rect.right) {\r
465                 min_x = (FX_FLOAT)char_rect.right;\r
466             }\r
467             if (max_x < char_rect.right) {\r
468                 max_x = (FX_FLOAT)char_rect.right;\r
469             }\r
470             FX_FLOAT char_top = curpos + char_rect.top * fontsize / 1000;\r
471             FX_FLOAT char_bottom = curpos + char_rect.bottom * fontsize / 1000;\r
472             if (min_y > char_top) {\r
473                 min_y = char_top;\r
474             }\r
475             if (max_y < char_top) {\r
476                 max_y = char_top;\r
477             }\r
478             if (min_y > char_bottom) {\r
479                 min_y = char_bottom;\r
480             }\r
481             if (max_y < char_bottom) {\r
482                 max_y = char_bottom;\r
483             }\r
484             charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000;\r
485         }\r
486         curpos += charwidth;\r
487         if (charcode == ' ' && (pCIDFont == NULL || pCIDFont->GetCharSize(32) == 1)) {\r
488             curpos += m_TextState.GetObject()->m_WordSpace;\r
489         }\r
490         curpos += m_TextState.GetObject()->m_CharSpace;\r
491     }\r
492     if (bVertWriting) {\r
493         if (pTextAdvanceX) {\r
494             *pTextAdvanceX = 0;\r
495         }\r
496         if (pTextAdvanceY) {\r
497             *pTextAdvanceY = curpos;\r
498         }\r
499         min_x = min_x * fontsize / 1000;\r
500         max_x = max_x * fontsize / 1000;\r
501     } else {\r
502         if (pTextAdvanceX) {\r
503             *pTextAdvanceX = FXSYS_Mul(curpos, horz_scale);\r
504         }\r
505         if (pTextAdvanceY) {\r
506             *pTextAdvanceY = 0;\r
507         }\r
508         min_y = min_y * fontsize / 1000;\r
509         max_y = max_y * fontsize / 1000;\r
510     }\r
511     CFX_AffineMatrix matrix;\r
512     GetTextMatrix(&matrix);\r
513     m_Left = min_x;\r
514     m_Right = max_x;\r
515     m_Bottom = min_y;\r
516     m_Top = max_y;\r
517     matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom);\r
518     int textmode = m_TextState.GetObject()->m_TextMode;\r
519     if (textmode == 1 || textmode == 2 || textmode == 5 || textmode == 6) {\r
520         FX_FLOAT half_width = m_GraphState.GetObject()->m_LineWidth / 2;\r
521         m_Left -= half_width;\r
522         m_Right += half_width;\r
523         m_Top += half_width;\r
524         m_Bottom -= half_width;\r
525     }\r
526 }\r
527 void CPDF_TextObject::CalcCharPos(FX_FLOAT* pPosArray) const\r
528 {\r
529     FX_FLOAT curpos = 0;\r
530     int count = 0;\r
531     CPDF_Font* pFont = m_TextState.GetFont();\r
532     FX_BOOL bVertWriting = FALSE;\r
533     CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();\r
534     if (pCIDFont) {\r
535         bVertWriting = pCIDFont->IsVertWriting();\r
536     }\r
537     FX_FLOAT fontsize = m_TextState.GetFontSize();\r
538     int index = 0;\r
539     for (int i = 0; i < m_nChars; i ++) {\r
540         FX_DWORD charcode = m_nChars == 1 ? (FX_DWORD)(FX_UINTPTR)m_pCharCodes : m_pCharCodes[i];\r
541         if (charcode == (FX_DWORD) - 1) {\r
542             continue;\r
543         }\r
544         pPosArray[index++] = i ? m_pCharPos[i - 1] : 0;\r
545         FX_FLOAT charwidth;\r
546         if (bVertWriting) {\r
547             FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);\r
548             charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000;\r
549         } else {\r
550             charwidth = pFont->GetCharWidthF(charcode) * fontsize / 1000;\r
551         }\r
552         pPosArray[index] = pPosArray[index - 1] + charwidth;\r
553         index++;\r
554     }\r
555 }\r
556 void CPDF_TextObject::Transform(const CFX_AffineMatrix& matrix)\r
557 {\r
558     m_TextState.GetModify();\r
559     CFX_AffineMatrix text_matrix;\r
560     GetTextMatrix(&text_matrix);\r
561     text_matrix.Concat(matrix);\r
562     FX_FLOAT* pTextMatrix = m_TextState.GetMatrix();\r
563     pTextMatrix[0] = text_matrix.GetA();\r
564     pTextMatrix[1] = text_matrix.GetC();\r
565     pTextMatrix[2] = text_matrix.GetB();\r
566     pTextMatrix[3] = text_matrix.GetD();\r
567     m_PosX = text_matrix.GetE();\r
568     m_PosY = text_matrix.GetF();\r
569     CalcPositionData(NULL, NULL, 0);\r
570 }\r
571 void CPDF_TextObject::SetPosition(FX_FLOAT x, FX_FLOAT y)\r
572 {\r
573     FX_FLOAT dx = x - m_PosX;\r
574     FX_FLOAT dy = y - m_PosY;\r
575     m_PosX = x;\r
576     m_PosY = y;\r
577     m_Left += dx;\r
578     m_Right += dx;\r
579     m_Top += dy;\r
580     m_Bottom += dy;\r
581 }\r
582 void CPDF_TextObject::SetData(int nChars, FX_DWORD* pCharCodes, FX_FLOAT* pCharPos, FX_FLOAT x, FX_FLOAT y)\r
583 {\r
584     ASSERT(m_nChars == 0);\r
585     m_nChars = nChars;\r
586     m_PosX = x;\r
587     m_PosY = y;\r
588     if (nChars == 0) {\r
589         return;\r
590     }\r
591     if (nChars == 1) {\r
592         m_pCharCodes = (FX_DWORD*)(FX_UINTPTR) * pCharCodes;\r
593     } else {\r
594         m_pCharCodes = FX_Alloc(FX_DWORD, nChars);\r
595         FXSYS_memcpy32(m_pCharCodes, pCharCodes, sizeof(FX_DWORD)*nChars);\r
596         m_pCharPos = FX_Alloc(FX_FLOAT, nChars - 1);\r
597         FXSYS_memcpy32(m_pCharPos, pCharPos, sizeof(FX_FLOAT) * (nChars - 1));\r
598     }\r
599     RecalcPositionData();\r
600 }\r
601 void CPDF_TextObject::SetTextState(CPDF_TextState TextState)\r
602 {\r
603     m_TextState = TextState;\r
604     CalcPositionData(NULL, NULL, 0);\r
605 }\r
606 CPDF_ShadingObject::CPDF_ShadingObject()\r
607 {\r
608     m_pShading = NULL;\r
609     m_Type = PDFPAGE_SHADING;\r
610 }\r
611 CPDF_ShadingObject::~CPDF_ShadingObject()\r
612 {\r
613     CPDF_ShadingPattern* pShading = m_pShading;\r
614     if (pShading && pShading->m_pDocument) {\r
615         pShading->m_pDocument->GetPageData()->ReleasePattern(pShading->m_pShadingObj);\r
616     }\r
617 }\r
618 void CPDF_ShadingObject::CopyData(const CPDF_PageObject* pSrc)\r
619 {\r
620     CPDF_ShadingObject* pSrcObj = (CPDF_ShadingObject*)pSrc;\r
621     m_pShading = pSrcObj->m_pShading;\r
622     if (m_pShading && m_pShading->m_pDocument) {\r
623         CPDF_DocPageData* pDocPageData = m_pShading->m_pDocument->GetPageData();\r
624         m_pShading = (CPDF_ShadingPattern*)pDocPageData->GetPattern(m_pShading->m_pShadingObj, m_pShading->m_bShadingObj, &m_pShading->m_ParentMatrix);\r
625     }\r
626     m_Matrix = pSrcObj->m_Matrix;\r
627 }\r
628 void CPDF_ShadingObject::Transform(const CFX_AffineMatrix& matrix)\r
629 {\r
630     if (!m_ClipPath.IsNull()) {\r
631         m_ClipPath.GetModify();\r
632         m_ClipPath.Transform(matrix);\r
633     }\r
634     m_Matrix.Concat(matrix);\r
635     if (!m_ClipPath.IsNull()) {\r
636         CalcBoundingBox();\r
637     } else {\r
638         matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom);\r
639     }\r
640 }\r
641 void CPDF_ShadingObject::CalcBoundingBox()\r
642 {\r
643     if (m_ClipPath.IsNull()) {\r
644         return;\r
645     }\r
646     CFX_FloatRect rect = m_ClipPath.GetClipBox();\r
647     m_Left = rect.left;\r
648     m_Bottom = rect.bottom;\r
649     m_Right = rect.right;\r
650     m_Top = rect.top;\r
651 }\r
652 CPDF_FormObject::~CPDF_FormObject()\r
653 {\r
654     if (m_pForm) {\r
655         delete m_pForm;\r
656     }\r
657 }\r
658 void CPDF_FormObject::Transform(const CFX_AffineMatrix& matrix)\r
659 {\r
660     m_FormMatrix.Concat(matrix);\r
661     CalcBoundingBox();\r
662 }\r
663 void CPDF_FormObject::CopyData(const CPDF_PageObject* pSrc)\r
664 {\r
665     const CPDF_FormObject* pSrcObj = (const CPDF_FormObject*)pSrc;\r
666     if (m_pForm) {\r
667         delete m_pForm;\r
668     }\r
669     m_pForm = pSrcObj->m_pForm->Clone();\r
670     m_FormMatrix = pSrcObj->m_FormMatrix;\r
671 }\r
672 void CPDF_FormObject::CalcBoundingBox()\r
673 {\r
674     CFX_FloatRect form_rect = m_pForm->CalcBoundingBox();\r
675     form_rect.Transform(&m_FormMatrix);\r
676     m_Left = form_rect.left;\r
677     m_Bottom = form_rect.bottom;\r
678     m_Right = form_rect.right;\r
679     m_Top = form_rect.top;\r
680 }\r
681 CPDF_PageObjects::CPDF_PageObjects(FX_BOOL bReleaseMembers) : m_ObjectList(128)\r
682 {\r
683     m_bBackgroundAlphaNeeded = FALSE;\r
684     m_bReleaseMembers = bReleaseMembers;\r
685     m_ParseState = PDF_CONTENT_NOT_PARSED;\r
686     m_pParser = NULL;\r
687     m_pFormStream = NULL;\r
688     m_pResources = NULL;\r
689 }\r
690 CPDF_PageObjects::~CPDF_PageObjects()\r
691 {\r
692     if (m_pParser) {\r
693         delete m_pParser;\r
694     }\r
695     if (!m_bReleaseMembers) {\r
696         return;\r
697     }\r
698     FX_POSITION pos = m_ObjectList.GetHeadPosition();\r
699     while (pos) {\r
700         CPDF_PageObject* pPageObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);\r
701         if (!pPageObj) {\r
702             continue;\r
703         }\r
704         pPageObj->Release();\r
705     }\r
706 }\r
707 void CPDF_PageObjects::ContinueParse(IFX_Pause* pPause)\r
708 {\r
709     if (m_pParser == NULL) {\r
710         return;\r
711     }\r
712     m_pParser->Continue(pPause);\r
713     if (m_pParser->GetStatus() == CPDF_ContentParser::Done) {\r
714         m_ParseState = PDF_CONTENT_PARSED;\r
715         delete m_pParser;\r
716         m_pParser = NULL;\r
717     }\r
718 }\r
719 int CPDF_PageObjects::EstimateParseProgress() const\r
720 {\r
721     if (m_pParser == NULL) {\r
722         return m_ParseState == PDF_CONTENT_PARSED ? 100 : 0;\r
723     }\r
724     return m_pParser->EstimateProgress();\r
725 }\r
726 FX_POSITION CPDF_PageObjects::InsertObject(FX_POSITION posInsertAfter, CPDF_PageObject* pNewObject)\r
727 {\r
728     if (posInsertAfter == NULL) {\r
729         return m_ObjectList.AddHead(pNewObject);\r
730     } else {\r
731         return m_ObjectList.InsertAfter(posInsertAfter, pNewObject);\r
732     }\r
733 }\r
734 int CPDF_PageObjects::GetObjectIndex(CPDF_PageObject* pObj) const\r
735 {\r
736     int index = 0;\r
737     FX_POSITION pos = m_ObjectList.GetHeadPosition();\r
738     while (pos) {\r
739         CPDF_PageObject* pThisObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);\r
740         if (pThisObj == pObj) {\r
741             return index;\r
742         }\r
743         index ++;\r
744     }\r
745     return -1;\r
746 }\r
747 CPDF_PageObject* CPDF_PageObjects::GetObjectByIndex(int index) const\r
748 {\r
749     FX_POSITION pos = m_ObjectList.FindIndex(index);\r
750     if (pos == NULL) {\r
751         return NULL;\r
752     }\r
753     return (CPDF_PageObject*)m_ObjectList.GetAt(pos);\r
754 }\r
755 void CPDF_PageObjects::Transform(const CFX_AffineMatrix& matrix)\r
756 {\r
757     FX_POSITION pos = m_ObjectList.GetHeadPosition();\r
758     while (pos) {\r
759         CPDF_PageObject* pObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);\r
760         pObj->Transform(matrix);\r
761     }\r
762 }\r
763 CFX_FloatRect CPDF_PageObjects::CalcBoundingBox() const\r
764 {\r
765     if (m_ObjectList.GetCount() == 0) {\r
766         return CFX_FloatRect(0, 0, 0, 0);\r
767     }\r
768     FX_FLOAT left, right, top, bottom;\r
769     left = bottom = 1000000 * 1.0f;\r
770     right = top = -1000000 * 1.0f;\r
771     FX_POSITION pos = m_ObjectList.GetHeadPosition();\r
772     while (pos) {\r
773         CPDF_PageObject* pObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);\r
774         if (left > pObj->m_Left) {\r
775             left = pObj->m_Left;\r
776         }\r
777         if (right < pObj->m_Right) {\r
778             right = pObj->m_Right;\r
779         }\r
780         if (top < pObj->m_Top) {\r
781             top = pObj->m_Top;\r
782         }\r
783         if (bottom > pObj->m_Bottom) {\r
784             bottom = pObj->m_Bottom;\r
785         }\r
786     }\r
787     return CFX_FloatRect(left, bottom, right, top);\r
788 }\r
789 void CPDF_PageObjects::LoadTransInfo()\r
790 {\r
791     if (m_pFormDict == NULL) {\r
792         return;\r
793     }\r
794     CPDF_Dictionary* pGroup = m_pFormDict->GetDict(FX_BSTRC("Group"));\r
795     if (pGroup == NULL) {\r
796         return;\r
797     }\r
798     if (pGroup->GetString(FX_BSTRC("S")) != FX_BSTRC("Transparency")) {\r
799         return;\r
800     }\r
801     m_Transparency |= PDFTRANS_GROUP;\r
802     if (pGroup->GetInteger(FX_BSTRC("I"))) {\r
803         m_Transparency |= PDFTRANS_ISOLATED;\r
804     }\r
805     if (pGroup->GetInteger(FX_BSTRC("K"))) {\r
806         m_Transparency |= PDFTRANS_KNOCKOUT;\r
807     }\r
808 }\r
809 void CPDF_PageObjects::ClearCacheObjects()\r
810 {\r
811     m_ParseState = PDF_CONTENT_NOT_PARSED;\r
812     if (m_pParser) {\r
813         delete m_pParser;\r
814     }\r
815     m_pParser = NULL;\r
816     if (m_bReleaseMembers) {\r
817         FX_POSITION pos = m_ObjectList.GetHeadPosition();\r
818         while (pos) {\r
819             CPDF_PageObject* pPageObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);\r
820             if (!pPageObj) {\r
821                 continue;\r
822             }\r
823             pPageObj->Release();\r
824         }\r
825     }\r
826     m_ObjectList.RemoveAll();\r
827 }\r
828 CPDF_Page::CPDF_Page()\r
829 {\r
830     m_pPageRender = NULL;\r
831 }\r
832 void CPDF_Page::Load(CPDF_Document* pDocument, CPDF_Dictionary* pPageDict, FX_BOOL bPageCache)\r
833 {\r
834     m_pDocument = (CPDF_Document*)pDocument;\r
835     m_pFormDict = pPageDict;\r
836     if (bPageCache) {\r
837         m_pPageRender = CPDF_ModuleMgr::Get()->GetRenderModule()->CreatePageCache(this);\r
838     }\r
839     if (pPageDict == NULL) {\r
840         m_PageWidth = m_PageHeight = 100 * 1.0f;\r
841         m_pPageResources = m_pResources = NULL;\r
842         return;\r
843     }\r
844     m_pResources = GetPageAttr(FX_BSTRC("Resources"))->GetDict();\r
845     m_pPageResources = m_pResources;\r
846     CPDF_Object* pRotate = GetPageAttr(FX_BSTRC("Rotate"));\r
847     int rotate = 0;\r
848     if (pRotate) {\r
849         rotate = pRotate->GetInteger() / 90 % 4;\r
850     }\r
851     if (rotate < 0) {\r
852         rotate += 4;\r
853     }\r
854     CPDF_Array* pMediaBox, *pCropBox;\r
855     pMediaBox = (CPDF_Array*)GetPageAttr(FX_BSTRC("MediaBox"));\r
856     CFX_FloatRect mediabox;\r
857     if (pMediaBox) {\r
858         mediabox = pMediaBox->GetRect();\r
859         mediabox.Normalize();\r
860     }\r
861     if (mediabox.IsEmpty()) {\r
862         mediabox = CFX_FloatRect(0, 0, 612, 792);\r
863     }\r
864     pCropBox = (CPDF_Array*)GetPageAttr(FX_BSTRC("CropBox"));\r
865     if (pCropBox) {\r
866         m_BBox = pCropBox->GetRect();\r
867         m_BBox.Normalize();\r
868     }\r
869     if (m_BBox.IsEmpty()) {\r
870         m_BBox = mediabox;\r
871     } else {\r
872         m_BBox.Intersect(mediabox);\r
873     }\r
874     if (rotate % 2) {\r
875         m_PageHeight = m_BBox.right - m_BBox.left;\r
876         m_PageWidth = m_BBox.top - m_BBox.bottom;\r
877     } else {\r
878         m_PageWidth = m_BBox.right - m_BBox.left;\r
879         m_PageHeight = m_BBox.top - m_BBox.bottom;\r
880     }\r
881     switch (rotate) {\r
882         case 0:\r
883             m_PageMatrix.Set(1.0f, 0, 0, 1.0f, -m_BBox.left, -m_BBox.bottom);\r
884             break;\r
885         case 1:\r
886             m_PageMatrix.Set(0, -1.0f, 1.0f, 0, -m_BBox.bottom, m_BBox.right);\r
887             break;\r
888         case 2:\r
889             m_PageMatrix.Set(-1.0f, 0, 0, -1.0f, m_BBox.right, m_BBox.top);\r
890             break;\r
891         case 3:\r
892             m_PageMatrix.Set(0, 1.0f, -1.0f, 0, m_BBox.top, -m_BBox.left);\r
893             break;\r
894     }\r
895     m_Transparency = PDFTRANS_ISOLATED;\r
896     LoadTransInfo();\r
897 }\r
898 void CPDF_Page::StartParse(CPDF_ParseOptions* pOptions, FX_BOOL bReParse)\r
899 {\r
900     if (bReParse) {\r
901         ClearCacheObjects();\r
902     }\r
903     if (m_ParseState == PDF_CONTENT_PARSED || m_ParseState == PDF_CONTENT_PARSING) {\r
904         return;\r
905     }\r
906     m_pParser = FX_NEW CPDF_ContentParser;\r
907     m_pParser->Start(this, pOptions);\r
908     m_ParseState = PDF_CONTENT_PARSING;\r
909 }\r
910 void CPDF_Page::ParseContent(CPDF_ParseOptions* pOptions, FX_BOOL bReParse)\r
911 {\r
912     StartParse(pOptions, bReParse);\r
913     ContinueParse(NULL);\r
914 }\r
915 CPDF_Page::~CPDF_Page()\r
916 {\r
917     if (m_pPageRender) {\r
918         CPDF_RenderModuleDef* pModule = CPDF_ModuleMgr::Get()->GetRenderModule();\r
919         pModule->DestroyPageCache(m_pPageRender);\r
920     }\r
921 }\r
922 CPDF_Object* FPDFAPI_GetPageAttr(CPDF_Dictionary* pPageDict, FX_BSTR name)\r
923 {\r
924     int level = 0;\r
925     while (1) {\r
926         CPDF_Object* pObj = pPageDict->GetElementValue(name);\r
927         if (pObj) {\r
928             return pObj;\r
929         }\r
930         CPDF_Dictionary* pParent = pPageDict->GetDict(FX_BSTRC("Parent"));\r
931         if (!pParent || pParent == pPageDict) {\r
932             return NULL;\r
933         }\r
934         pPageDict = pParent;\r
935         level ++;\r
936         if (level == 1000) {\r
937             return NULL;\r
938         }\r
939     }\r
940 }\r
941 CPDF_Object* CPDF_Page::GetPageAttr(FX_BSTR name) const\r
942 {\r
943     return FPDFAPI_GetPageAttr(m_pFormDict, name);\r
944 }\r
945 CPDF_Form::CPDF_Form(CPDF_Document* pDoc, CPDF_Dictionary* pPageResources, CPDF_Stream* pFormStream, CPDF_Dictionary* pParentResources)\r
946 {\r
947     m_pDocument = pDoc;\r
948     m_pFormStream = pFormStream;\r
949     m_pFormDict = pFormStream->GetDict();\r
950     m_pResources = m_pFormDict->GetDict(FX_BSTRC("Resources"));\r
951     m_pPageResources = pPageResources;\r
952     if (m_pResources == NULL) {\r
953         m_pResources = pParentResources;\r
954     }\r
955     if (m_pResources == NULL) {\r
956         m_pResources = pPageResources;\r
957     }\r
958     m_Transparency = 0;\r
959     LoadTransInfo();\r
960 }\r
961 CPDF_Form::~CPDF_Form()\r
962 {\r
963 }\r
964 void CPDF_Form::StartParse(CPDF_AllStates* pGraphicStates, CFX_AffineMatrix* pParentMatrix,\r
965                            CPDF_Type3Char* pType3Char, CPDF_ParseOptions* pOptions, int level)\r
966 {\r
967     if (m_ParseState == PDF_CONTENT_PARSED || m_ParseState == PDF_CONTENT_PARSING) {\r
968         return;\r
969     }\r
970     m_pParser = FX_NEW CPDF_ContentParser;\r
971     m_pParser->Start(this, pGraphicStates, pParentMatrix, pType3Char, pOptions, level);\r
972     m_ParseState = PDF_CONTENT_PARSING;\r
973 }\r
974 void CPDF_Form::ParseContent(CPDF_AllStates* pGraphicStates, CFX_AffineMatrix* pParentMatrix,\r
975                              CPDF_Type3Char* pType3Char, CPDF_ParseOptions* pOptions, int level)\r
976 {\r
977     StartParse(pGraphicStates, pParentMatrix, pType3Char, pOptions, level);\r
978     ContinueParse(NULL);\r
979 }\r
980 CPDF_Form* CPDF_Form::Clone() const\r
981 {\r
982     CPDF_Form* pClone = FX_NEW CPDF_Form(m_pDocument, m_pPageResources, m_pFormStream, m_pResources);\r
983     FX_POSITION pos = m_ObjectList.GetHeadPosition();\r
984     while (pos) {\r
985         CPDF_PageObject* pObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);\r
986         pClone->m_ObjectList.AddTail(pObj->Clone());\r
987     }\r
988     return pClone;\r
989 }\r
990 void CPDF_Page::GetDisplayMatrix(CFX_AffineMatrix& matrix, int xPos, int yPos,\r
991                                  int xSize, int ySize, int iRotate) const\r
992 {\r
993     if (m_PageWidth == 0 || m_PageHeight == 0) {\r
994         return;\r
995     }\r
996     CFX_AffineMatrix display_matrix;\r
997     int x0, y0, x1, y1, x2, y2;\r
998     iRotate %= 4;\r
999     switch (iRotate) {\r
1000         case 0:\r
1001             x0 = xPos;\r
1002             y0 = yPos + ySize;\r
1003             x1 = xPos;\r
1004             y1 = yPos;\r
1005             x2 = xPos + xSize;\r
1006             y2 = yPos + ySize;\r
1007             break;\r
1008         case 1:\r
1009             x0 = xPos;\r
1010             y0 = yPos;\r
1011             x1 = xPos + xSize;\r
1012             y1 = yPos;\r
1013             x2 = xPos;\r
1014             y2 = yPos + ySize;\r
1015             break;\r
1016         case 2:\r
1017             x0 = xPos + xSize;\r
1018             y0 = yPos;\r
1019             x1 = xPos + xSize;\r
1020             y1 = yPos + ySize;\r
1021             x2 = xPos;\r
1022             y2 = yPos;\r
1023             break;\r
1024         case 3:\r
1025             x0 = xPos + xSize;\r
1026             y0 = yPos + ySize;\r
1027             x1 = xPos;\r
1028             y1 = yPos + ySize;\r
1029             x2 = xPos + xSize;\r
1030             y2 = yPos;\r
1031             break;\r
1032     }\r
1033     display_matrix.Set(FXSYS_Div((FX_FLOAT)(x2 - x0), m_PageWidth),\r
1034                        FXSYS_Div((FX_FLOAT)(y2 - y0), m_PageWidth),\r
1035                        FXSYS_Div((FX_FLOAT)(x1 - x0), m_PageHeight),\r
1036                        FXSYS_Div((FX_FLOAT)(y1 - y0), m_PageHeight),\r
1037                        (FX_FLOAT)x0, (FX_FLOAT)y0);\r
1038     matrix = m_PageMatrix;\r
1039     matrix.Concat(display_matrix);\r
1040 }\r
1041 CPDF_ParseOptions::CPDF_ParseOptions()\r
1042 {\r
1043     m_bTextOnly = FALSE;\r
1044     m_bMarkedContent = TRUE;\r
1045     m_bSeparateForm = TRUE;\r
1046     m_bDecodeInlineImage = FALSE;\r
1047 }\r