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