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