• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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 "core/fpdfapi/page/cpdf_textobject.h"
8 
9 #include <algorithm>
10 
11 #include "core/fpdfapi/font/cpdf_cidfont.h"
12 #include "core/fpdfapi/font/cpdf_font.h"
13 #include "third_party/base/ptr_util.h"
14 #include "third_party/base/stl_util.h"
15 
CPDF_TextObjectItem()16 CPDF_TextObjectItem::CPDF_TextObjectItem() : m_CharCode(0) {}
17 
18 CPDF_TextObjectItem::~CPDF_TextObjectItem() = default;
19 
CPDF_TextObject()20 CPDF_TextObject::CPDF_TextObject() {}
21 
~CPDF_TextObject()22 CPDF_TextObject::~CPDF_TextObject() {}
23 
CountItems() const24 int CPDF_TextObject::CountItems() const {
25   return pdfium::CollectionSize<int>(m_CharCodes);
26 }
27 
GetItemInfo(int index,CPDF_TextObjectItem * pInfo) const28 void CPDF_TextObject::GetItemInfo(int index, CPDF_TextObjectItem* pInfo) const {
29   pInfo->m_CharCode = m_CharCodes[index];
30   pInfo->m_Origin = CFX_PointF(index ? m_CharPos[index - 1] : 0, 0);
31   if (pInfo->m_CharCode == CPDF_Font::kInvalidCharCode)
32     return;
33 
34   CPDF_Font* pFont = m_TextState.GetFont();
35   if (!pFont->IsCIDFont())
36     return;
37   if (!pFont->AsCIDFont()->IsVertWriting())
38     return;
39 
40   uint16_t CID = pFont->AsCIDFont()->CIDFromCharCode(pInfo->m_CharCode);
41   pInfo->m_Origin = CFX_PointF(0, pInfo->m_Origin.x);
42 
43   short vx;
44   short vy;
45   pFont->AsCIDFont()->GetVertOrigin(CID, vx, vy);
46 
47   FX_FLOAT fontsize = m_TextState.GetFontSize();
48   pInfo->m_Origin.x -= fontsize * vx / 1000;
49   pInfo->m_Origin.y -= fontsize * vy / 1000;
50 }
51 
CountChars() const52 int CPDF_TextObject::CountChars() const {
53   int count = 0;
54   for (uint32_t charcode : m_CharCodes) {
55     if (charcode != CPDF_Font::kInvalidCharCode)
56       count++;
57   }
58   return count;
59 }
60 
GetCharInfo(int index,uint32_t * charcode,FX_FLOAT * kerning) const61 void CPDF_TextObject::GetCharInfo(int index,
62                                   uint32_t* charcode,
63                                   FX_FLOAT* kerning) const {
64   int count = 0;
65   for (size_t i = 0; i < m_CharCodes.size(); ++i) {
66     if (m_CharCodes[i] == CPDF_Font::kInvalidCharCode)
67       continue;
68     if (count++ != index)
69       continue;
70     *charcode = m_CharCodes[i];
71     if (i == m_CharCodes.size() - 1 ||
72         m_CharCodes[i + 1] != CPDF_Font::kInvalidCharCode) {
73       *kerning = 0;
74     } else {
75       *kerning = m_CharPos[i];
76     }
77     return;
78   }
79 }
80 
GetCharInfo(int index,CPDF_TextObjectItem * pInfo) const81 void CPDF_TextObject::GetCharInfo(int index, CPDF_TextObjectItem* pInfo) const {
82   int count = 0;
83   for (int i = 0; i < pdfium::CollectionSize<int>(m_CharCodes); ++i) {
84     uint32_t charcode = m_CharCodes[i];
85     if (charcode == CPDF_Font::kInvalidCharCode)
86       continue;
87     if (count++ != index)
88       continue;
89     GetItemInfo(i, pInfo);
90     break;
91   }
92 }
93 
Clone() const94 std::unique_ptr<CPDF_TextObject> CPDF_TextObject::Clone() const {
95   auto obj = pdfium::MakeUnique<CPDF_TextObject>();
96   obj->CopyData(this);
97   obj->m_CharCodes = m_CharCodes;
98   obj->m_CharPos = m_CharPos;
99   obj->m_Pos = m_Pos;
100   return obj;
101 }
102 
GetType() const103 CPDF_PageObject::Type CPDF_TextObject::GetType() const {
104   return TEXT;
105 }
106 
Transform(const CFX_Matrix & matrix)107 void CPDF_TextObject::Transform(const CFX_Matrix& matrix) {
108   CFX_Matrix text_matrix = GetTextMatrix();
109   text_matrix.Concat(matrix);
110 
111   FX_FLOAT* pTextMatrix = m_TextState.GetMutableMatrix();
112   pTextMatrix[0] = text_matrix.a;
113   pTextMatrix[1] = text_matrix.c;
114   pTextMatrix[2] = text_matrix.b;
115   pTextMatrix[3] = text_matrix.d;
116   m_Pos = CFX_PointF(text_matrix.e, text_matrix.f);
117   CalcPositionData(0);
118 }
119 
IsText() const120 bool CPDF_TextObject::IsText() const {
121   return true;
122 }
123 
AsText()124 CPDF_TextObject* CPDF_TextObject::AsText() {
125   return this;
126 }
127 
AsText() const128 const CPDF_TextObject* CPDF_TextObject::AsText() const {
129   return this;
130 }
131 
GetTextMatrix() const132 CFX_Matrix CPDF_TextObject::GetTextMatrix() const {
133   const FX_FLOAT* pTextMatrix = m_TextState.GetMatrix();
134   return CFX_Matrix(pTextMatrix[0], pTextMatrix[2], pTextMatrix[1],
135                     pTextMatrix[3], m_Pos.x, m_Pos.y);
136 }
137 
SetSegments(const CFX_ByteString * pStrs,const FX_FLOAT * pKerning,int nsegs)138 void CPDF_TextObject::SetSegments(const CFX_ByteString* pStrs,
139                                   const FX_FLOAT* pKerning,
140                                   int nsegs) {
141   m_CharCodes.clear();
142   m_CharPos.clear();
143   CPDF_Font* pFont = m_TextState.GetFont();
144   int nChars = 0;
145   for (int i = 0; i < nsegs; ++i)
146     nChars += pFont->CountChar(pStrs[i].c_str(), pStrs[i].GetLength());
147   nChars += nsegs - 1;
148   m_CharCodes.resize(nChars);
149   m_CharPos.resize(nChars - 1);
150   int index = 0;
151   for (int i = 0; i < nsegs; ++i) {
152     const FX_CHAR* segment = pStrs[i].c_str();
153     int len = pStrs[i].GetLength();
154     int offset = 0;
155     while (offset < len)
156       m_CharCodes[index++] = pFont->GetNextChar(segment, len, offset);
157     if (i != nsegs - 1) {
158       m_CharPos[index - 1] = pKerning[i];
159       m_CharCodes[index++] = CPDF_Font::kInvalidCharCode;
160     }
161   }
162 }
163 
SetText(const CFX_ByteString & str)164 void CPDF_TextObject::SetText(const CFX_ByteString& str) {
165   SetSegments(&str, nullptr, 1);
166   RecalcPositionData();
167 }
168 
GetCharWidth(uint32_t charcode) const169 FX_FLOAT CPDF_TextObject::GetCharWidth(uint32_t charcode) const {
170   FX_FLOAT fontsize = m_TextState.GetFontSize() / 1000;
171   CPDF_Font* pFont = m_TextState.GetFont();
172   bool bVertWriting = false;
173   CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
174   if (pCIDFont)
175     bVertWriting = pCIDFont->IsVertWriting();
176   if (!bVertWriting)
177     return pFont->GetCharWidthF(charcode) * fontsize;
178 
179   uint16_t CID = pCIDFont->CIDFromCharCode(charcode);
180   return pCIDFont->GetVertWidth(CID) * fontsize;
181 }
182 
GetFont() const183 CPDF_Font* CPDF_TextObject::GetFont() const {
184   return m_TextState.GetFont();
185 }
186 
GetFontSize() const187 FX_FLOAT CPDF_TextObject::GetFontSize() const {
188   return m_TextState.GetFontSize();
189 }
190 
CalcPositionData(FX_FLOAT horz_scale)191 CFX_PointF CPDF_TextObject::CalcPositionData(FX_FLOAT horz_scale) {
192   FX_FLOAT curpos = 0;
193   FX_FLOAT min_x = 10000 * 1.0f;
194   FX_FLOAT max_x = -10000 * 1.0f;
195   FX_FLOAT min_y = 10000 * 1.0f;
196   FX_FLOAT max_y = -10000 * 1.0f;
197   CPDF_Font* pFont = m_TextState.GetFont();
198   bool bVertWriting = false;
199   CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
200   if (pCIDFont)
201     bVertWriting = pCIDFont->IsVertWriting();
202 
203   FX_FLOAT fontsize = m_TextState.GetFontSize();
204   for (int i = 0; i < pdfium::CollectionSize<int>(m_CharCodes); ++i) {
205     uint32_t charcode = m_CharCodes[i];
206     if (i > 0) {
207       if (charcode == CPDF_Font::kInvalidCharCode) {
208         curpos -= (m_CharPos[i - 1] * fontsize) / 1000;
209         continue;
210       }
211       m_CharPos[i - 1] = curpos;
212     }
213 
214     FX_RECT char_rect = pFont->GetCharBBox(charcode);
215     FX_FLOAT charwidth;
216     if (!bVertWriting) {
217       min_y = std::min(min_y, static_cast<FX_FLOAT>(
218                                   std::min(char_rect.top, char_rect.bottom)));
219       max_y = std::max(max_y, static_cast<FX_FLOAT>(
220                                   std::max(char_rect.top, char_rect.bottom)));
221       FX_FLOAT char_left = curpos + char_rect.left * fontsize / 1000;
222       FX_FLOAT char_right = curpos + char_rect.right * fontsize / 1000;
223       min_x = std::min(min_x, std::min(char_left, char_right));
224       max_x = std::max(max_x, std::max(char_left, char_right));
225       charwidth = pFont->GetCharWidthF(charcode) * fontsize / 1000;
226     } else {
227       uint16_t CID = pCIDFont->CIDFromCharCode(charcode);
228       short vx;
229       short vy;
230       pCIDFont->GetVertOrigin(CID, vx, vy);
231       char_rect.left -= vx;
232       char_rect.right -= vx;
233       char_rect.top -= vy;
234       char_rect.bottom -= vy;
235       min_x = std::min(min_x, static_cast<FX_FLOAT>(
236                                   std::min(char_rect.left, char_rect.right)));
237       max_x = std::max(max_x, static_cast<FX_FLOAT>(
238                                   std::max(char_rect.left, char_rect.right)));
239       FX_FLOAT char_top = curpos + char_rect.top * fontsize / 1000;
240       FX_FLOAT char_bottom = curpos + char_rect.bottom * fontsize / 1000;
241       min_y = std::min(min_y, std::min(char_top, char_bottom));
242       max_y = std::max(max_y, std::max(char_top, char_bottom));
243       charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000;
244     }
245     curpos += charwidth;
246     if (charcode == ' ' && (!pCIDFont || pCIDFont->GetCharSize(' ') == 1))
247       curpos += m_TextState.GetWordSpace();
248 
249     curpos += m_TextState.GetCharSpace();
250   }
251 
252   CFX_PointF ret;
253   if (bVertWriting) {
254     ret.y = curpos;
255     min_x = min_x * fontsize / 1000;
256     max_x = max_x * fontsize / 1000;
257   } else {
258     ret.x = curpos * horz_scale;
259     min_y = min_y * fontsize / 1000;
260     max_y = max_y * fontsize / 1000;
261   }
262 
263   m_Left = min_x;
264   m_Right = max_x;
265   m_Bottom = min_y;
266   m_Top = max_y;
267   GetTextMatrix().TransformRect(m_Left, m_Right, m_Top, m_Bottom);
268 
269   if (!TextRenderingModeIsStrokeMode(m_TextState.GetTextMode()))
270     return ret;
271 
272   FX_FLOAT half_width = m_GraphState.GetLineWidth() / 2;
273   m_Left -= half_width;
274   m_Right += half_width;
275   m_Top += half_width;
276   m_Bottom -= half_width;
277 
278   return ret;
279 }
280 
SetPosition(FX_FLOAT x,FX_FLOAT y)281 void CPDF_TextObject::SetPosition(FX_FLOAT x, FX_FLOAT y) {
282   FX_FLOAT dx = x - m_Pos.x;
283   FX_FLOAT dy = y - m_Pos.y;
284   m_Pos.x = x;
285   m_Pos.y = y;
286   m_Left += dx;
287   m_Right += dx;
288   m_Top += dy;
289   m_Bottom += dy;
290 }
291 
RecalcPositionData()292 void CPDF_TextObject::RecalcPositionData() {
293   CalcPositionData(1);
294 }
295