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 "pageint.h"
8
9 #include "core/include/fpdfapi/fpdf_module.h"
10 #include "core/include/fpdfapi/fpdf_page.h"
11
Create(int type)12 CPDF_PageObject* CPDF_PageObject::Create(int type) {
13 switch (type) {
14 case PDFPAGE_TEXT:
15 return new CPDF_TextObject;
16 case PDFPAGE_IMAGE:
17 return new CPDF_ImageObject;
18 case PDFPAGE_PATH:
19 return new CPDF_PathObject;
20 case PDFPAGE_SHADING:
21 return new CPDF_ShadingObject;
22 case PDFPAGE_FORM:
23 return new CPDF_FormObject;
24 }
25 return NULL;
26 }
~CPDF_PageObject()27 CPDF_PageObject::~CPDF_PageObject() {}
Clone() const28 CPDF_PageObject* CPDF_PageObject::Clone() const {
29 CPDF_PageObject* pObj = Create(m_Type);
30 pObj->Copy(this);
31 return pObj;
32 }
Copy(const CPDF_PageObject * pSrc)33 void CPDF_PageObject::Copy(const CPDF_PageObject* pSrc) {
34 if (m_Type != pSrc->m_Type) {
35 return;
36 }
37 CopyData(pSrc);
38 CopyStates(*pSrc);
39 m_Left = pSrc->m_Left;
40 m_Right = pSrc->m_Right;
41 m_Top = pSrc->m_Top;
42 m_Bottom = pSrc->m_Bottom;
43 }
AppendClipPath(CPDF_Path path,int type,FX_BOOL bAutoMerge)44 void CPDF_PageObject::AppendClipPath(CPDF_Path path,
45 int type,
46 FX_BOOL bAutoMerge) {
47 m_ClipPath.AppendPath(path, type, bAutoMerge);
48 }
CopyClipPath(CPDF_PageObject * pObj)49 void CPDF_PageObject::CopyClipPath(CPDF_PageObject* pObj) {
50 m_ClipPath = pObj->m_ClipPath;
51 }
RemoveClipPath()52 void CPDF_PageObject::RemoveClipPath() {
53 m_ClipPath.SetNull();
54 }
RecalcBBox()55 void CPDF_PageObject::RecalcBBox() {
56 switch (m_Type) {
57 case PDFPAGE_TEXT:
58 ((CPDF_TextObject*)this)->RecalcPositionData();
59 break;
60 case PDFPAGE_PATH:
61 ((CPDF_PathObject*)this)->CalcBoundingBox();
62 break;
63 case PDFPAGE_SHADING:
64 ((CPDF_ShadingObject*)this)->CalcBoundingBox();
65 break;
66 }
67 }
TransformClipPath(CFX_Matrix & matrix)68 void CPDF_PageObject::TransformClipPath(CFX_Matrix& matrix) {
69 if (m_ClipPath.IsNull()) {
70 return;
71 }
72 m_ClipPath.GetModify();
73 m_ClipPath.Transform(matrix);
74 }
TransformGeneralState(CFX_Matrix & matrix)75 void CPDF_PageObject::TransformGeneralState(CFX_Matrix& matrix) {
76 if (m_GeneralState.IsNull()) {
77 return;
78 }
79 CPDF_GeneralStateData* pGS = m_GeneralState.GetModify();
80 pGS->m_Matrix.Concat(matrix);
81 }
GetBBox(const CFX_Matrix * pMatrix) const82 FX_RECT CPDF_PageObject::GetBBox(const CFX_Matrix* pMatrix) const {
83 CFX_FloatRect rect(m_Left, m_Bottom, m_Right, m_Top);
84 if (pMatrix) {
85 pMatrix->TransformRect(rect);
86 }
87 return rect.GetOutterRect();
88 }
89
CPDF_TextObject()90 CPDF_TextObject::CPDF_TextObject()
91 : m_PosX(0),
92 m_PosY(0),
93 m_nChars(0),
94 m_pCharCodes(nullptr),
95 m_pCharPos(nullptr) {
96 m_Type = PDFPAGE_TEXT;
97 }
98
~CPDF_TextObject()99 CPDF_TextObject::~CPDF_TextObject() {
100 if (m_nChars > 1) {
101 FX_Free(m_pCharCodes);
102 }
103 FX_Free(m_pCharPos);
104 }
105
GetItemInfo(int index,CPDF_TextObjectItem * pInfo) const106 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
CountChars() const131 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
GetCharInfo(int index,FX_DWORD & charcode,FX_FLOAT & kerning) const143 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
GetCharInfo(int index,CPDF_TextObjectItem * pInfo) const168 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
CopyData(const CPDF_PageObject * pSrc)187 void CPDF_TextObject::CopyData(const CPDF_PageObject* pSrc) {
188 const CPDF_TextObject* pSrcObj = (const CPDF_TextObject*)pSrc;
189 if (m_nChars > 1) {
190 FX_Free(m_pCharCodes);
191 m_pCharCodes = nullptr;
192 }
193 FX_Free(m_pCharPos);
194 m_pCharPos = nullptr;
195 m_nChars = pSrcObj->m_nChars;
196 if (m_nChars > 1) {
197 m_pCharCodes = FX_Alloc(FX_DWORD, m_nChars);
198 m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);
199 for (int i = 0; i < m_nChars; ++i) {
200 m_pCharCodes[i] = pSrcObj->m_pCharCodes[i];
201 }
202 for (int i = 0; i < m_nChars - 1; ++i) {
203 m_pCharPos[i] = pSrcObj->m_pCharPos[i];
204 }
205 } else {
206 m_pCharCodes = pSrcObj->m_pCharCodes;
207 }
208 m_PosX = pSrcObj->m_PosX;
209 m_PosY = pSrcObj->m_PosY;
210 }
211
GetTextMatrix(CFX_Matrix * pMatrix) const212 void CPDF_TextObject::GetTextMatrix(CFX_Matrix* pMatrix) const {
213 FX_FLOAT* pTextMatrix = m_TextState.GetMatrix();
214 pMatrix->Set(pTextMatrix[0], pTextMatrix[2], pTextMatrix[1], pTextMatrix[3],
215 m_PosX, m_PosY);
216 }
217
SetSegments(const CFX_ByteString * pStrs,FX_FLOAT * pKerning,int nsegs)218 void CPDF_TextObject::SetSegments(const CFX_ByteString* pStrs,
219 FX_FLOAT* pKerning,
220 int nsegs) {
221 if (m_nChars > 1) {
222 FX_Free(m_pCharCodes);
223 m_pCharCodes = nullptr;
224 }
225 FX_Free(m_pCharPos);
226 m_pCharPos = nullptr;
227 CPDF_Font* pFont = m_TextState.GetFont();
228 m_nChars = 0;
229 for (int i = 0; i < nsegs; ++i) {
230 m_nChars += pFont->CountChar(pStrs[i], pStrs[i].GetLength());
231 }
232 m_nChars += nsegs - 1;
233 if (m_nChars > 1) {
234 m_pCharCodes = FX_Alloc(FX_DWORD, m_nChars);
235 m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);
236 int index = 0;
237 for (int i = 0; i < nsegs; ++i) {
238 const FX_CHAR* segment = pStrs[i];
239 int offset = 0, len = pStrs[i].GetLength();
240 while (offset < len) {
241 m_pCharCodes[index++] = pFont->GetNextChar(segment, len, offset);
242 }
243 if (i != nsegs - 1) {
244 m_pCharPos[index - 1] = pKerning[i];
245 m_pCharCodes[index++] = (FX_DWORD)-1;
246 }
247 }
248 } else {
249 int offset = 0;
250 m_pCharCodes = (FX_DWORD*)(uintptr_t)pFont->GetNextChar(
251 pStrs[0], pStrs[0].GetLength(), offset);
252 }
253 }
254
SetText(const CFX_ByteString & str)255 void CPDF_TextObject::SetText(const CFX_ByteString& str) {
256 SetSegments(&str, nullptr, 1);
257 RecalcPositionData();
258 }
259
SetEmpty()260 void CPDF_TextObject::SetEmpty() {
261 if (m_nChars > 1) {
262 FX_Free(m_pCharCodes);
263 }
264 if (m_nChars > 1) {
265 FX_Free(m_pCharPos);
266 }
267 m_nChars = 0;
268 m_pCharCodes = nullptr;
269 m_pCharPos = nullptr;
270 m_Left = m_Right = m_PosX;
271 m_Top = m_Bottom = m_PosY;
272 }
273
SetText(CFX_ByteString * pStrs,FX_FLOAT * pKerning,int nSegs)274 void CPDF_TextObject::SetText(CFX_ByteString* pStrs,
275 FX_FLOAT* pKerning,
276 int nSegs) {
277 SetSegments(pStrs, pKerning, nSegs);
278 RecalcPositionData();
279 }
280
SetText(int nChars,FX_DWORD * pCharCodes,FX_FLOAT * pKernings)281 void CPDF_TextObject::SetText(int nChars,
282 FX_DWORD* pCharCodes,
283 FX_FLOAT* pKernings) {
284 if (m_nChars > 1) {
285 FX_Free(m_pCharCodes);
286 m_pCharCodes = nullptr;
287 }
288 FX_Free(m_pCharPos);
289 m_pCharPos = nullptr;
290 int nKernings = 0;
291 int i;
292 for (i = 0; i < nChars - 1; ++i) {
293 if (pKernings[i] != 0) {
294 ++nKernings;
295 }
296 }
297 m_nChars = nChars + nKernings;
298 if (m_nChars > 1) {
299 m_pCharCodes = FX_Alloc(FX_DWORD, m_nChars);
300 m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1);
301 for (int i = 0, index = 0; i < nChars; ++i) {
302 m_pCharCodes[index++] = pCharCodes[i];
303 if (pKernings[i] != 0 && i != nChars - 1) {
304 m_pCharCodes[index] = (FX_DWORD)-1;
305 m_pCharPos[index - 1] = pKernings[i];
306 ++index;
307 }
308 }
309 } else {
310 m_pCharCodes = (FX_DWORD*)(uintptr_t)pCharCodes[0];
311 }
312 RecalcPositionData();
313 }
314
GetCharWidth(FX_DWORD charcode) const315 FX_FLOAT CPDF_TextObject::GetCharWidth(FX_DWORD charcode) const {
316 FX_FLOAT fontsize = m_TextState.GetFontSize() / 1000;
317 CPDF_Font* pFont = m_TextState.GetFont();
318 FX_BOOL bVertWriting = FALSE;
319 CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();
320 if (pCIDFont) {
321 bVertWriting = pCIDFont->IsVertWriting();
322 }
323 if (!bVertWriting)
324 return pFont->GetCharWidthF(charcode, 0) * fontsize;
325
326 FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);
327 return pCIDFont->GetVertWidth(CID) * fontsize;
328 }
329
GetSpaceCharWidth() const330 FX_FLOAT CPDF_TextObject::GetSpaceCharWidth() const {
331 CPDF_Font* pFont = m_TextState.GetFont();
332 FX_DWORD charCode = m_TextState.GetFont()->CharCodeFromUnicode(32);
333 if (charCode != (FX_DWORD)-1) {
334 return GetCharWidth(charCode);
335 }
336 FX_FLOAT fontSize = m_TextState.GetFontSize() / 4000.0f;
337 FX_BOOL bVertWriting = FALSE;
338 CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();
339 if (pCIDFont) {
340 bVertWriting = pCIDFont->IsVertWriting();
341 }
342 FX_RECT fontRect;
343 pFont->GetFontBBox(fontRect);
344 fontSize *=
345 bVertWriting ? (FX_FLOAT)fontRect.Height() : (FX_FLOAT)fontRect.Width();
346 return fontSize;
347 }
348
GetCharRect(int index,CFX_FloatRect & rect) const349 void CPDF_TextObject::GetCharRect(int index, CFX_FloatRect& rect) const {
350 CPDF_Font* pFont = m_TextState.GetFont();
351 FX_BOOL bVertWriting = FALSE;
352 CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();
353 if (pCIDFont) {
354 bVertWriting = pCIDFont->IsVertWriting();
355 }
356 FX_FLOAT fontsize = m_TextState.GetFontSize() / 1000;
357 int count = 0;
358 for (int i = 0; i < m_nChars; ++i) {
359 FX_DWORD charcode =
360 m_nChars == 1 ? (FX_DWORD)(uintptr_t)m_pCharCodes : m_pCharCodes[i];
361 if (charcode == (FX_DWORD)-1) {
362 continue;
363 }
364 if (count != index) {
365 ++count;
366 continue;
367 }
368 FX_FLOAT curpos = i > 0 ? m_pCharPos[i - 1] : 0;
369 FX_RECT char_rect;
370 pFont->GetCharBBox(charcode, char_rect, 0);
371 if (!bVertWriting) {
372 rect.left = curpos + char_rect.left * fontsize;
373 rect.right = curpos + char_rect.right * fontsize;
374 rect.top = char_rect.top * fontsize;
375 rect.bottom = char_rect.bottom * fontsize;
376 } else {
377 FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);
378 short vx, vy;
379 pCIDFont->GetVertOrigin(CID, vx, vy);
380 char_rect.left -= vx;
381 char_rect.right -= vx;
382 char_rect.top -= vy;
383 char_rect.bottom -= vy;
384 rect.left = char_rect.left * fontsize;
385 rect.right = char_rect.right * fontsize;
386 rect.top = curpos + char_rect.top * fontsize;
387 rect.bottom = curpos + char_rect.bottom * fontsize;
388 }
389 return;
390 }
391 }
392
CalcPositionData(FX_FLOAT * pTextAdvanceX,FX_FLOAT * pTextAdvanceY,FX_FLOAT horz_scale,int level)393 void CPDF_TextObject::CalcPositionData(FX_FLOAT* pTextAdvanceX,
394 FX_FLOAT* pTextAdvanceY,
395 FX_FLOAT horz_scale,
396 int level) {
397 FX_FLOAT curpos = 0;
398 FX_FLOAT min_x = 10000 * 1.0f;
399 FX_FLOAT max_x = -10000 * 1.0f;
400 FX_FLOAT min_y = 10000 * 1.0f;
401 FX_FLOAT max_y = -10000 * 1.0f;
402 CPDF_Font* pFont = m_TextState.GetFont();
403 FX_BOOL bVertWriting = FALSE;
404 CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();
405 if (pCIDFont) {
406 bVertWriting = pCIDFont->IsVertWriting();
407 }
408 FX_FLOAT fontsize = m_TextState.GetFontSize();
409 for (int i = 0; i < m_nChars; ++i) {
410 FX_DWORD charcode =
411 m_nChars == 1 ? (FX_DWORD)(uintptr_t)m_pCharCodes : m_pCharCodes[i];
412 if (i > 0) {
413 if (charcode == (FX_DWORD)-1) {
414 curpos -= FXSYS_Mul(m_pCharPos[i - 1], fontsize) / 1000;
415 continue;
416 }
417 m_pCharPos[i - 1] = curpos;
418 }
419 FX_RECT char_rect;
420 pFont->GetCharBBox(charcode, char_rect, level);
421 FX_FLOAT charwidth;
422 if (!bVertWriting) {
423 if (min_y > char_rect.top) {
424 min_y = (FX_FLOAT)char_rect.top;
425 }
426 if (max_y < char_rect.top) {
427 max_y = (FX_FLOAT)char_rect.top;
428 }
429 if (min_y > char_rect.bottom) {
430 min_y = (FX_FLOAT)char_rect.bottom;
431 }
432 if (max_y < char_rect.bottom) {
433 max_y = (FX_FLOAT)char_rect.bottom;
434 }
435 FX_FLOAT char_left = curpos + char_rect.left * fontsize / 1000;
436 FX_FLOAT char_right = curpos + char_rect.right * fontsize / 1000;
437 if (min_x > char_left) {
438 min_x = char_left;
439 }
440 if (max_x < char_left) {
441 max_x = char_left;
442 }
443 if (min_x > char_right) {
444 min_x = char_right;
445 }
446 if (max_x < char_right) {
447 max_x = char_right;
448 }
449 charwidth = pFont->GetCharWidthF(charcode, level) * fontsize / 1000;
450 } else {
451 FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);
452 short vx;
453 short vy;
454 pCIDFont->GetVertOrigin(CID, vx, vy);
455 char_rect.left -= vx;
456 char_rect.right -= vx;
457 char_rect.top -= vy;
458 char_rect.bottom -= vy;
459 if (min_x > char_rect.left) {
460 min_x = (FX_FLOAT)char_rect.left;
461 }
462 if (max_x < char_rect.left) {
463 max_x = (FX_FLOAT)char_rect.left;
464 }
465 if (min_x > char_rect.right) {
466 min_x = (FX_FLOAT)char_rect.right;
467 }
468 if (max_x < char_rect.right) {
469 max_x = (FX_FLOAT)char_rect.right;
470 }
471 FX_FLOAT char_top = curpos + char_rect.top * fontsize / 1000;
472 FX_FLOAT char_bottom = curpos + char_rect.bottom * fontsize / 1000;
473 if (min_y > char_top) {
474 min_y = char_top;
475 }
476 if (max_y < char_top) {
477 max_y = char_top;
478 }
479 if (min_y > char_bottom) {
480 min_y = char_bottom;
481 }
482 if (max_y < char_bottom) {
483 max_y = char_bottom;
484 }
485 charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000;
486 }
487 curpos += charwidth;
488 if (charcode == ' ' && (!pCIDFont || pCIDFont->GetCharSize(32) == 1)) {
489 curpos += m_TextState.GetObject()->m_WordSpace;
490 }
491 curpos += m_TextState.GetObject()->m_CharSpace;
492 }
493 if (bVertWriting) {
494 if (pTextAdvanceX) {
495 *pTextAdvanceX = 0;
496 }
497 if (pTextAdvanceY) {
498 *pTextAdvanceY = curpos;
499 }
500 min_x = min_x * fontsize / 1000;
501 max_x = max_x * fontsize / 1000;
502 } else {
503 if (pTextAdvanceX) {
504 *pTextAdvanceX = FXSYS_Mul(curpos, horz_scale);
505 }
506 if (pTextAdvanceY) {
507 *pTextAdvanceY = 0;
508 }
509 min_y = min_y * fontsize / 1000;
510 max_y = max_y * fontsize / 1000;
511 }
512 CFX_Matrix matrix;
513 GetTextMatrix(&matrix);
514 m_Left = min_x;
515 m_Right = max_x;
516 m_Bottom = min_y;
517 m_Top = max_y;
518 matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom);
519 int textmode = m_TextState.GetObject()->m_TextMode;
520 if (textmode == 1 || textmode == 2 || textmode == 5 || textmode == 6) {
521 FX_FLOAT half_width = m_GraphState.GetObject()->m_LineWidth / 2;
522 m_Left -= half_width;
523 m_Right += half_width;
524 m_Top += half_width;
525 m_Bottom -= half_width;
526 }
527 }
528
CalcCharPos(FX_FLOAT * pPosArray) const529 void CPDF_TextObject::CalcCharPos(FX_FLOAT* pPosArray) const {
530 CPDF_Font* pFont = m_TextState.GetFont();
531 FX_BOOL bVertWriting = FALSE;
532 CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();
533 if (pCIDFont) {
534 bVertWriting = pCIDFont->IsVertWriting();
535 }
536 FX_FLOAT fontsize = m_TextState.GetFontSize();
537 for (int i = 0, index = 0; i < m_nChars; ++i) {
538 FX_DWORD charcode =
539 m_nChars == 1 ? (FX_DWORD)(uintptr_t)m_pCharCodes : m_pCharCodes[i];
540 if (charcode == (FX_DWORD)-1) {
541 continue;
542 }
543 pPosArray[index++] = i ? m_pCharPos[i - 1] : 0;
544 FX_FLOAT charwidth;
545 if (bVertWriting) {
546 FX_WORD CID = pCIDFont->CIDFromCharCode(charcode);
547 charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000;
548 } else {
549 charwidth = pFont->GetCharWidthF(charcode) * fontsize / 1000;
550 }
551 pPosArray[index] = pPosArray[index - 1] + charwidth;
552 index++;
553 }
554 }
555
Transform(const CFX_Matrix & matrix)556 void CPDF_TextObject::Transform(const CFX_Matrix& matrix) {
557 m_TextState.GetModify();
558 CFX_Matrix text_matrix;
559 GetTextMatrix(&text_matrix);
560 text_matrix.Concat(matrix);
561 FX_FLOAT* pTextMatrix = m_TextState.GetMatrix();
562 pTextMatrix[0] = text_matrix.GetA();
563 pTextMatrix[1] = text_matrix.GetC();
564 pTextMatrix[2] = text_matrix.GetB();
565 pTextMatrix[3] = text_matrix.GetD();
566 m_PosX = text_matrix.GetE();
567 m_PosY = text_matrix.GetF();
568 CalcPositionData(nullptr, nullptr, 0);
569 }
570
SetPosition(FX_FLOAT x,FX_FLOAT y)571 void CPDF_TextObject::SetPosition(FX_FLOAT x, FX_FLOAT y) {
572 FX_FLOAT dx = x - m_PosX;
573 FX_FLOAT dy = y - m_PosY;
574 m_PosX = x;
575 m_PosY = y;
576 m_Left += dx;
577 m_Right += dx;
578 m_Top += dy;
579 m_Bottom += dy;
580 }
581
SetData(int nChars,FX_DWORD * pCharCodes,FX_FLOAT * pCharPos,FX_FLOAT x,FX_FLOAT y)582 void CPDF_TextObject::SetData(int nChars,
583 FX_DWORD* pCharCodes,
584 FX_FLOAT* pCharPos,
585 FX_FLOAT x,
586 FX_FLOAT y) {
587 ASSERT(m_nChars == 0);
588 m_nChars = nChars;
589 m_PosX = x;
590 m_PosY = y;
591 if (nChars == 0) {
592 return;
593 }
594 if (nChars == 1) {
595 m_pCharCodes = (FX_DWORD*)(uintptr_t)*pCharCodes;
596 } else {
597 m_pCharCodes = FX_Alloc(FX_DWORD, nChars);
598 FXSYS_memcpy(m_pCharCodes, pCharCodes, sizeof(FX_DWORD) * nChars);
599 m_pCharPos = FX_Alloc(FX_FLOAT, nChars - 1);
600 FXSYS_memcpy(m_pCharPos, pCharPos, sizeof(FX_FLOAT) * (nChars - 1));
601 }
602 RecalcPositionData();
603 }
604
SetTextState(CPDF_TextState TextState)605 void CPDF_TextObject::SetTextState(CPDF_TextState TextState) {
606 m_TextState = TextState;
607 CalcPositionData(nullptr, nullptr, 0);
608 }
609
CPDF_ShadingObject()610 CPDF_ShadingObject::CPDF_ShadingObject() {
611 m_pShading = NULL;
612 m_Type = PDFPAGE_SHADING;
613 }
~CPDF_ShadingObject()614 CPDF_ShadingObject::~CPDF_ShadingObject() {}
CopyData(const CPDF_PageObject * pSrc)615 void CPDF_ShadingObject::CopyData(const CPDF_PageObject* pSrc) {
616 CPDF_ShadingObject* pSrcObj = (CPDF_ShadingObject*)pSrc;
617 m_pShading = pSrcObj->m_pShading;
618 if (m_pShading && m_pShading->m_pDocument) {
619 CPDF_DocPageData* pDocPageData = m_pShading->m_pDocument->GetPageData();
620 m_pShading = (CPDF_ShadingPattern*)pDocPageData->GetPattern(
621 m_pShading->m_pShadingObj, m_pShading->m_bShadingObj,
622 &m_pShading->m_ParentMatrix);
623 }
624 m_Matrix = pSrcObj->m_Matrix;
625 }
Transform(const CFX_Matrix & matrix)626 void CPDF_ShadingObject::Transform(const CFX_Matrix& matrix) {
627 if (!m_ClipPath.IsNull()) {
628 m_ClipPath.GetModify();
629 m_ClipPath.Transform(matrix);
630 }
631 m_Matrix.Concat(matrix);
632 if (!m_ClipPath.IsNull()) {
633 CalcBoundingBox();
634 } else {
635 matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom);
636 }
637 }
CalcBoundingBox()638 void CPDF_ShadingObject::CalcBoundingBox() {
639 if (m_ClipPath.IsNull()) {
640 return;
641 }
642 CFX_FloatRect rect = m_ClipPath.GetClipBox();
643 m_Left = rect.left;
644 m_Bottom = rect.bottom;
645 m_Right = rect.right;
646 m_Top = rect.top;
647 }
~CPDF_FormObject()648 CPDF_FormObject::~CPDF_FormObject() {
649 delete m_pForm;
650 }
Transform(const CFX_Matrix & matrix)651 void CPDF_FormObject::Transform(const CFX_Matrix& matrix) {
652 m_FormMatrix.Concat(matrix);
653 CalcBoundingBox();
654 }
CopyData(const CPDF_PageObject * pSrc)655 void CPDF_FormObject::CopyData(const CPDF_PageObject* pSrc) {
656 const CPDF_FormObject* pSrcObj = (const CPDF_FormObject*)pSrc;
657 delete m_pForm;
658 m_pForm = pSrcObj->m_pForm->Clone();
659 m_FormMatrix = pSrcObj->m_FormMatrix;
660 }
CalcBoundingBox()661 void CPDF_FormObject::CalcBoundingBox() {
662 CFX_FloatRect form_rect = m_pForm->CalcBoundingBox();
663 form_rect.Transform(&m_FormMatrix);
664 m_Left = form_rect.left;
665 m_Bottom = form_rect.bottom;
666 m_Right = form_rect.right;
667 m_Top = form_rect.top;
668 }
CPDF_PageObjects(FX_BOOL bReleaseMembers)669 CPDF_PageObjects::CPDF_PageObjects(FX_BOOL bReleaseMembers)
670 : m_pFormDict(nullptr),
671 m_pFormStream(nullptr),
672 m_pDocument(nullptr),
673 m_pPageResources(nullptr),
674 m_pResources(nullptr),
675 m_Transparency(0),
676 m_ObjectList(128),
677 m_bBackgroundAlphaNeeded(FALSE),
678 m_bHasImageMask(FALSE),
679 m_bReleaseMembers(bReleaseMembers),
680 m_pParser(nullptr),
681 m_ParseState(CONTENT_NOT_PARSED) {}
~CPDF_PageObjects()682 CPDF_PageObjects::~CPDF_PageObjects() {
683 delete m_pParser;
684 if (!m_bReleaseMembers) {
685 return;
686 }
687 FX_POSITION pos = m_ObjectList.GetHeadPosition();
688 while (pos) {
689 delete (CPDF_PageObject*)m_ObjectList.GetNext(pos);
690 }
691 }
ContinueParse(IFX_Pause * pPause)692 void CPDF_PageObjects::ContinueParse(IFX_Pause* pPause) {
693 if (!m_pParser) {
694 return;
695 }
696 m_pParser->Continue(pPause);
697 if (m_pParser->GetStatus() == CPDF_ContentParser::Done) {
698 m_ParseState = CONTENT_PARSED;
699 delete m_pParser;
700 m_pParser = NULL;
701 }
702 }
InsertObject(FX_POSITION posInsertAfter,CPDF_PageObject * pNewObject)703 FX_POSITION CPDF_PageObjects::InsertObject(FX_POSITION posInsertAfter,
704 CPDF_PageObject* pNewObject) {
705 if (!posInsertAfter) {
706 return m_ObjectList.AddHead(pNewObject);
707 }
708 return m_ObjectList.InsertAfter(posInsertAfter, pNewObject);
709 }
GetObjectIndex(CPDF_PageObject * pObj) const710 int CPDF_PageObjects::GetObjectIndex(CPDF_PageObject* pObj) const {
711 int index = 0;
712 FX_POSITION pos = m_ObjectList.GetHeadPosition();
713 while (pos) {
714 CPDF_PageObject* pThisObj = (CPDF_PageObject*)m_ObjectList.GetNext(pos);
715 if (pThisObj == pObj) {
716 return index;
717 }
718 index++;
719 }
720 return -1;
721 }
GetObjectByIndex(int index) const722 CPDF_PageObject* CPDF_PageObjects::GetObjectByIndex(int index) const {
723 FX_POSITION pos = m_ObjectList.FindIndex(index);
724 return pos ? static_cast<CPDF_PageObject*>(m_ObjectList.GetAt(pos)) : nullptr;
725 }
Transform(const CFX_Matrix & matrix)726 void CPDF_PageObjects::Transform(const CFX_Matrix& 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 }
CalcBoundingBox() const733 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 }
LoadTransInfo()758 void CPDF_PageObjects::LoadTransInfo() {
759 if (!m_pFormDict) {
760 return;
761 }
762 CPDF_Dictionary* pGroup = m_pFormDict->GetDict("Group");
763 if (!pGroup) {
764 return;
765 }
766 if (pGroup->GetString("S") != "Transparency") {
767 return;
768 }
769 m_Transparency |= PDFTRANS_GROUP;
770 if (pGroup->GetInteger("I")) {
771 m_Transparency |= PDFTRANS_ISOLATED;
772 }
773 if (pGroup->GetInteger("K")) {
774 m_Transparency |= PDFTRANS_KNOCKOUT;
775 }
776 }
ClearCacheObjects()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 }
CPDF_Page()789 CPDF_Page::CPDF_Page() {
790 m_pPageRender = NULL;
791 }
Load(CPDF_Document * pDocument,CPDF_Dictionary * pPageDict,FX_BOOL bPageCache)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) {
802 m_PageWidth = m_PageHeight = 100 * 1.0f;
803 m_pPageResources = m_pResources = NULL;
804 return;
805 }
806 CPDF_Object* pageAttr = GetPageAttr("Resources");
807 m_pResources = pageAttr ? pageAttr->GetDict() : NULL;
808 m_pPageResources = m_pResources;
809 CPDF_Object* pRotate = GetPageAttr("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("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("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 }
StartParse(CPDF_ParseOptions * pOptions,FX_BOOL bReParse)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 }
ParseContent(CPDF_ParseOptions * pOptions,FX_BOOL bReParse)872 void CPDF_Page::ParseContent(CPDF_ParseOptions* pOptions, FX_BOOL bReParse) {
873 StartParse(pOptions, bReParse);
874 ContinueParse(NULL);
875 }
~CPDF_Page()876 CPDF_Page::~CPDF_Page() {
877 if (m_pPageRender) {
878 IPDF_RenderModule* pModule = CPDF_ModuleMgr::Get()->GetRenderModule();
879 pModule->DestroyPageCache(m_pPageRender);
880 }
881 }
FPDFAPI_GetPageAttr(CPDF_Dictionary * pPageDict,const CFX_ByteStringC & name)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("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 }
GetPageAttr(const CFX_ByteStringC & name) const901 CPDF_Object* CPDF_Page::GetPageAttr(const CFX_ByteStringC& name) const {
902 return FPDFAPI_GetPageAttr(m_pFormDict, name);
903 }
CPDF_Form(CPDF_Document * pDoc,CPDF_Dictionary * pPageResources,CPDF_Stream * pFormStream,CPDF_Dictionary * pParentResources)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("Resources");
912 m_pPageResources = pPageResources;
913 if (!m_pResources) {
914 m_pResources = pParentResources;
915 }
916 if (!m_pResources) {
917 m_pResources = pPageResources;
918 }
919 m_Transparency = 0;
920 LoadTransInfo();
921 }
~CPDF_Form()922 CPDF_Form::~CPDF_Form() {}
StartParse(CPDF_AllStates * pGraphicStates,CFX_Matrix * pParentMatrix,CPDF_Type3Char * pType3Char,CPDF_ParseOptions * pOptions,int level)923 void CPDF_Form::StartParse(CPDF_AllStates* pGraphicStates,
924 CFX_Matrix* 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 }
ParseContent(CPDF_AllStates * pGraphicStates,CFX_Matrix * pParentMatrix,CPDF_Type3Char * pType3Char,CPDF_ParseOptions * pOptions,int level)936 void CPDF_Form::ParseContent(CPDF_AllStates* pGraphicStates,
937 CFX_Matrix* pParentMatrix,
938 CPDF_Type3Char* pType3Char,
939 CPDF_ParseOptions* pOptions,
940 int level) {
941 StartParse(pGraphicStates, pParentMatrix, pType3Char, pOptions, level);
942 ContinueParse(NULL);
943 }
Clone() const944 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 }
GetDisplayMatrix(CFX_Matrix & matrix,int xPos,int yPos,int xSize,int ySize,int iRotate) const954 void CPDF_Page::GetDisplayMatrix(CFX_Matrix& 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_Matrix 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 }
CPDF_ParseOptions()1008 CPDF_ParseOptions::CPDF_ParseOptions() {
1009 m_bTextOnly = FALSE;
1010 m_bMarkedContent = TRUE;
1011 m_bSeparateForm = TRUE;
1012 m_bDecodeInlineImage = FALSE;
1013 }
1014