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