| OLD | NEW |
| (Empty) |
| 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/fpdf_page/cpdf_textobject.h" | |
| 8 | |
| 9 #include "core/fpdfapi/font/cpdf_cidfont.h" | |
| 10 #include "core/fpdfapi/font/cpdf_font.h" | |
| 11 | |
| 12 CPDF_TextObject::CPDF_TextObject() | |
| 13 : m_PosX(0), | |
| 14 m_PosY(0), | |
| 15 m_nChars(0), | |
| 16 m_pCharCodes(nullptr), | |
| 17 m_pCharPos(nullptr) {} | |
| 18 | |
| 19 CPDF_TextObject::~CPDF_TextObject() { | |
| 20 if (m_nChars > 1) { | |
| 21 FX_Free(m_pCharCodes); | |
| 22 } | |
| 23 FX_Free(m_pCharPos); | |
| 24 } | |
| 25 | |
| 26 int CPDF_TextObject::CountItems() const { | |
| 27 return m_nChars; | |
| 28 } | |
| 29 | |
| 30 void CPDF_TextObject::GetItemInfo(int index, CPDF_TextObjectItem* pInfo) const { | |
| 31 pInfo->m_CharCode = | |
| 32 m_nChars == 1 ? (uint32_t)(uintptr_t)m_pCharCodes : m_pCharCodes[index]; | |
| 33 pInfo->m_OriginX = index ? m_pCharPos[index - 1] : 0; | |
| 34 pInfo->m_OriginY = 0; | |
| 35 if (pInfo->m_CharCode == CPDF_Font::kInvalidCharCode) { | |
| 36 return; | |
| 37 } | |
| 38 CPDF_Font* pFont = m_TextState.GetFont(); | |
| 39 if (!pFont->IsCIDFont()) { | |
| 40 return; | |
| 41 } | |
| 42 if (!pFont->AsCIDFont()->IsVertWriting()) { | |
| 43 return; | |
| 44 } | |
| 45 uint16_t CID = pFont->AsCIDFont()->CIDFromCharCode(pInfo->m_CharCode); | |
| 46 pInfo->m_OriginY = pInfo->m_OriginX; | |
| 47 pInfo->m_OriginX = 0; | |
| 48 short vx, vy; | |
| 49 pFont->AsCIDFont()->GetVertOrigin(CID, vx, vy); | |
| 50 FX_FLOAT fontsize = m_TextState.GetFontSize(); | |
| 51 pInfo->m_OriginX -= fontsize * vx / 1000; | |
| 52 pInfo->m_OriginY -= fontsize * vy / 1000; | |
| 53 } | |
| 54 | |
| 55 int CPDF_TextObject::CountChars() const { | |
| 56 if (m_nChars == 1) { | |
| 57 return 1; | |
| 58 } | |
| 59 int count = 0; | |
| 60 for (int i = 0; i < m_nChars; ++i) | |
| 61 if (m_pCharCodes[i] != CPDF_Font::kInvalidCharCode) { | |
| 62 ++count; | |
| 63 } | |
| 64 return count; | |
| 65 } | |
| 66 | |
| 67 void CPDF_TextObject::GetCharInfo(int index, | |
| 68 uint32_t& charcode, | |
| 69 FX_FLOAT& kerning) const { | |
| 70 if (m_nChars == 1) { | |
| 71 charcode = (uint32_t)(uintptr_t)m_pCharCodes; | |
| 72 kerning = 0; | |
| 73 return; | |
| 74 } | |
| 75 int count = 0; | |
| 76 for (int i = 0; i < m_nChars; ++i) { | |
| 77 if (m_pCharCodes[i] != CPDF_Font::kInvalidCharCode) { | |
| 78 if (count == index) { | |
| 79 charcode = m_pCharCodes[i]; | |
| 80 if (i == m_nChars - 1 || | |
| 81 m_pCharCodes[i + 1] != CPDF_Font::kInvalidCharCode) { | |
| 82 kerning = 0; | |
| 83 } else { | |
| 84 kerning = m_pCharPos[i]; | |
| 85 } | |
| 86 return; | |
| 87 } | |
| 88 ++count; | |
| 89 } | |
| 90 } | |
| 91 } | |
| 92 | |
| 93 void CPDF_TextObject::GetCharInfo(int index, CPDF_TextObjectItem* pInfo) const { | |
| 94 if (m_nChars == 1) { | |
| 95 GetItemInfo(0, pInfo); | |
| 96 return; | |
| 97 } | |
| 98 int count = 0; | |
| 99 for (int i = 0; i < m_nChars; ++i) { | |
| 100 uint32_t charcode = m_pCharCodes[i]; | |
| 101 if (charcode == CPDF_Font::kInvalidCharCode) { | |
| 102 continue; | |
| 103 } | |
| 104 if (count == index) { | |
| 105 GetItemInfo(i, pInfo); | |
| 106 break; | |
| 107 } | |
| 108 ++count; | |
| 109 } | |
| 110 } | |
| 111 | |
| 112 CPDF_TextObject* CPDF_TextObject::Clone() const { | |
| 113 CPDF_TextObject* obj = new CPDF_TextObject; | |
| 114 obj->CopyData(this); | |
| 115 | |
| 116 obj->m_nChars = m_nChars; | |
| 117 if (m_nChars > 1) { | |
| 118 obj->m_pCharCodes = FX_Alloc(uint32_t, m_nChars); | |
| 119 FXSYS_memcpy(obj->m_pCharCodes, m_pCharCodes, m_nChars * sizeof(uint32_t)); | |
| 120 obj->m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1); | |
| 121 FXSYS_memcpy(obj->m_pCharPos, m_pCharPos, | |
| 122 (m_nChars - 1) * sizeof(FX_FLOAT)); | |
| 123 } else { | |
| 124 obj->m_pCharCodes = m_pCharCodes; | |
| 125 } | |
| 126 obj->m_PosX = m_PosX; | |
| 127 obj->m_PosY = m_PosY; | |
| 128 return obj; | |
| 129 } | |
| 130 | |
| 131 CPDF_PageObject::Type CPDF_TextObject::GetType() const { | |
| 132 return TEXT; | |
| 133 } | |
| 134 | |
| 135 void CPDF_TextObject::Transform(const CFX_Matrix& matrix) { | |
| 136 CFX_Matrix text_matrix; | |
| 137 GetTextMatrix(&text_matrix); | |
| 138 text_matrix.Concat(matrix); | |
| 139 | |
| 140 FX_FLOAT* pTextMatrix = m_TextState.GetMutableMatrix(); | |
| 141 pTextMatrix[0] = text_matrix.GetA(); | |
| 142 pTextMatrix[1] = text_matrix.GetC(); | |
| 143 pTextMatrix[2] = text_matrix.GetB(); | |
| 144 pTextMatrix[3] = text_matrix.GetD(); | |
| 145 m_PosX = text_matrix.GetE(); | |
| 146 m_PosY = text_matrix.GetF(); | |
| 147 CalcPositionData(nullptr, nullptr, 0); | |
| 148 } | |
| 149 | |
| 150 bool CPDF_TextObject::IsText() const { | |
| 151 return true; | |
| 152 } | |
| 153 | |
| 154 CPDF_TextObject* CPDF_TextObject::AsText() { | |
| 155 return this; | |
| 156 } | |
| 157 | |
| 158 const CPDF_TextObject* CPDF_TextObject::AsText() const { | |
| 159 return this; | |
| 160 } | |
| 161 | |
| 162 void CPDF_TextObject::GetTextMatrix(CFX_Matrix* pMatrix) const { | |
| 163 const FX_FLOAT* pTextMatrix = m_TextState.GetMatrix(); | |
| 164 pMatrix->Set(pTextMatrix[0], pTextMatrix[2], pTextMatrix[1], pTextMatrix[3], | |
| 165 m_PosX, m_PosY); | |
| 166 } | |
| 167 | |
| 168 void CPDF_TextObject::SetSegments(const CFX_ByteString* pStrs, | |
| 169 FX_FLOAT* pKerning, | |
| 170 int nsegs) { | |
| 171 if (m_nChars > 1) { | |
| 172 FX_Free(m_pCharCodes); | |
| 173 m_pCharCodes = nullptr; | |
| 174 } | |
| 175 FX_Free(m_pCharPos); | |
| 176 m_pCharPos = nullptr; | |
| 177 CPDF_Font* pFont = m_TextState.GetFont(); | |
| 178 m_nChars = 0; | |
| 179 for (int i = 0; i < nsegs; ++i) { | |
| 180 m_nChars += pFont->CountChar(pStrs[i].c_str(), pStrs[i].GetLength()); | |
| 181 } | |
| 182 m_nChars += nsegs - 1; | |
| 183 if (m_nChars > 1) { | |
| 184 m_pCharCodes = FX_Alloc(uint32_t, m_nChars); | |
| 185 m_pCharPos = FX_Alloc(FX_FLOAT, m_nChars - 1); | |
| 186 int index = 0; | |
| 187 for (int i = 0; i < nsegs; ++i) { | |
| 188 const FX_CHAR* segment = pStrs[i].c_str(); | |
| 189 int len = pStrs[i].GetLength(); | |
| 190 int offset = 0; | |
| 191 while (offset < len) { | |
| 192 m_pCharCodes[index++] = pFont->GetNextChar(segment, len, offset); | |
| 193 } | |
| 194 if (i != nsegs - 1) { | |
| 195 m_pCharPos[index - 1] = pKerning[i]; | |
| 196 m_pCharCodes[index++] = CPDF_Font::kInvalidCharCode; | |
| 197 } | |
| 198 } | |
| 199 } else { | |
| 200 int offset = 0; | |
| 201 m_pCharCodes = (uint32_t*)(uintptr_t)pFont->GetNextChar( | |
| 202 pStrs[0].c_str(), pStrs[0].GetLength(), offset); | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 void CPDF_TextObject::SetText(const CFX_ByteString& str) { | |
| 207 SetSegments(&str, nullptr, 1); | |
| 208 RecalcPositionData(); | |
| 209 } | |
| 210 | |
| 211 FX_FLOAT CPDF_TextObject::GetCharWidth(uint32_t charcode) const { | |
| 212 FX_FLOAT fontsize = m_TextState.GetFontSize() / 1000; | |
| 213 CPDF_Font* pFont = m_TextState.GetFont(); | |
| 214 FX_BOOL bVertWriting = FALSE; | |
| 215 CPDF_CIDFont* pCIDFont = pFont->AsCIDFont(); | |
| 216 if (pCIDFont) { | |
| 217 bVertWriting = pCIDFont->IsVertWriting(); | |
| 218 } | |
| 219 if (!bVertWriting) | |
| 220 return pFont->GetCharWidthF(charcode) * fontsize; | |
| 221 | |
| 222 uint16_t CID = pCIDFont->CIDFromCharCode(charcode); | |
| 223 return pCIDFont->GetVertWidth(CID) * fontsize; | |
| 224 } | |
| 225 | |
| 226 FX_FLOAT CPDF_TextObject::GetPosX() const { | |
| 227 return m_PosX; | |
| 228 } | |
| 229 | |
| 230 FX_FLOAT CPDF_TextObject::GetPosY() const { | |
| 231 return m_PosY; | |
| 232 } | |
| 233 | |
| 234 CPDF_Font* CPDF_TextObject::GetFont() const { | |
| 235 return m_TextState.GetFont(); | |
| 236 } | |
| 237 | |
| 238 FX_FLOAT CPDF_TextObject::GetFontSize() const { | |
| 239 return m_TextState.GetFontSize(); | |
| 240 } | |
| 241 | |
| 242 void CPDF_TextObject::CalcPositionData(FX_FLOAT* pTextAdvanceX, | |
| 243 FX_FLOAT* pTextAdvanceY, | |
| 244 FX_FLOAT horz_scale) { | |
| 245 FX_FLOAT curpos = 0; | |
| 246 FX_FLOAT min_x = 10000 * 1.0f; | |
| 247 FX_FLOAT max_x = -10000 * 1.0f; | |
| 248 FX_FLOAT min_y = 10000 * 1.0f; | |
| 249 FX_FLOAT max_y = -10000 * 1.0f; | |
| 250 CPDF_Font* pFont = m_TextState.GetFont(); | |
| 251 FX_BOOL bVertWriting = FALSE; | |
| 252 CPDF_CIDFont* pCIDFont = pFont->AsCIDFont(); | |
| 253 if (pCIDFont) { | |
| 254 bVertWriting = pCIDFont->IsVertWriting(); | |
| 255 } | |
| 256 FX_FLOAT fontsize = m_TextState.GetFontSize(); | |
| 257 for (int i = 0; i < m_nChars; ++i) { | |
| 258 uint32_t charcode = | |
| 259 m_nChars == 1 ? (uint32_t)(uintptr_t)m_pCharCodes : m_pCharCodes[i]; | |
| 260 if (i > 0) { | |
| 261 if (charcode == CPDF_Font::kInvalidCharCode) { | |
| 262 curpos -= (m_pCharPos[i - 1] * fontsize) / 1000; | |
| 263 continue; | |
| 264 } | |
| 265 m_pCharPos[i - 1] = curpos; | |
| 266 } | |
| 267 FX_RECT char_rect = pFont->GetCharBBox(charcode); | |
| 268 FX_FLOAT charwidth; | |
| 269 if (!bVertWriting) { | |
| 270 if (min_y > char_rect.top) { | |
| 271 min_y = (FX_FLOAT)char_rect.top; | |
| 272 } | |
| 273 if (max_y < char_rect.top) { | |
| 274 max_y = (FX_FLOAT)char_rect.top; | |
| 275 } | |
| 276 if (min_y > char_rect.bottom) { | |
| 277 min_y = (FX_FLOAT)char_rect.bottom; | |
| 278 } | |
| 279 if (max_y < char_rect.bottom) { | |
| 280 max_y = (FX_FLOAT)char_rect.bottom; | |
| 281 } | |
| 282 FX_FLOAT char_left = curpos + char_rect.left * fontsize / 1000; | |
| 283 FX_FLOAT char_right = curpos + char_rect.right * fontsize / 1000; | |
| 284 if (min_x > char_left) { | |
| 285 min_x = char_left; | |
| 286 } | |
| 287 if (max_x < char_left) { | |
| 288 max_x = char_left; | |
| 289 } | |
| 290 if (min_x > char_right) { | |
| 291 min_x = char_right; | |
| 292 } | |
| 293 if (max_x < char_right) { | |
| 294 max_x = char_right; | |
| 295 } | |
| 296 charwidth = pFont->GetCharWidthF(charcode) * fontsize / 1000; | |
| 297 } else { | |
| 298 uint16_t CID = pCIDFont->CIDFromCharCode(charcode); | |
| 299 short vx; | |
| 300 short vy; | |
| 301 pCIDFont->GetVertOrigin(CID, vx, vy); | |
| 302 char_rect.left -= vx; | |
| 303 char_rect.right -= vx; | |
| 304 char_rect.top -= vy; | |
| 305 char_rect.bottom -= vy; | |
| 306 if (min_x > char_rect.left) { | |
| 307 min_x = (FX_FLOAT)char_rect.left; | |
| 308 } | |
| 309 if (max_x < char_rect.left) { | |
| 310 max_x = (FX_FLOAT)char_rect.left; | |
| 311 } | |
| 312 if (min_x > char_rect.right) { | |
| 313 min_x = (FX_FLOAT)char_rect.right; | |
| 314 } | |
| 315 if (max_x < char_rect.right) { | |
| 316 max_x = (FX_FLOAT)char_rect.right; | |
| 317 } | |
| 318 FX_FLOAT char_top = curpos + char_rect.top * fontsize / 1000; | |
| 319 FX_FLOAT char_bottom = curpos + char_rect.bottom * fontsize / 1000; | |
| 320 if (min_y > char_top) { | |
| 321 min_y = char_top; | |
| 322 } | |
| 323 if (max_y < char_top) { | |
| 324 max_y = char_top; | |
| 325 } | |
| 326 if (min_y > char_bottom) { | |
| 327 min_y = char_bottom; | |
| 328 } | |
| 329 if (max_y < char_bottom) { | |
| 330 max_y = char_bottom; | |
| 331 } | |
| 332 charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000; | |
| 333 } | |
| 334 curpos += charwidth; | |
| 335 if (charcode == ' ' && (!pCIDFont || pCIDFont->GetCharSize(32) == 1)) { | |
| 336 curpos += m_TextState.GetWordSpace(); | |
| 337 } | |
| 338 curpos += m_TextState.GetCharSpace(); | |
| 339 } | |
| 340 if (bVertWriting) { | |
| 341 if (pTextAdvanceX) { | |
| 342 *pTextAdvanceX = 0; | |
| 343 } | |
| 344 if (pTextAdvanceY) { | |
| 345 *pTextAdvanceY = curpos; | |
| 346 } | |
| 347 min_x = min_x * fontsize / 1000; | |
| 348 max_x = max_x * fontsize / 1000; | |
| 349 } else { | |
| 350 if (pTextAdvanceX) { | |
| 351 *pTextAdvanceX = curpos * horz_scale; | |
| 352 } | |
| 353 if (pTextAdvanceY) { | |
| 354 *pTextAdvanceY = 0; | |
| 355 } | |
| 356 min_y = min_y * fontsize / 1000; | |
| 357 max_y = max_y * fontsize / 1000; | |
| 358 } | |
| 359 CFX_Matrix matrix; | |
| 360 GetTextMatrix(&matrix); | |
| 361 m_Left = min_x; | |
| 362 m_Right = max_x; | |
| 363 m_Bottom = min_y; | |
| 364 m_Top = max_y; | |
| 365 matrix.TransformRect(m_Left, m_Right, m_Top, m_Bottom); | |
| 366 if (TextRenderingModeIsStrokeMode(m_TextState.GetTextMode())) { | |
| 367 FX_FLOAT half_width = m_GraphState.GetLineWidth() / 2; | |
| 368 m_Left -= half_width; | |
| 369 m_Right += half_width; | |
| 370 m_Top += half_width; | |
| 371 m_Bottom -= half_width; | |
| 372 } | |
| 373 } | |
| 374 | |
| 375 void CPDF_TextObject::SetPosition(FX_FLOAT x, FX_FLOAT y) { | |
| 376 FX_FLOAT dx = x - m_PosX; | |
| 377 FX_FLOAT dy = y - m_PosY; | |
| 378 m_PosX = x; | |
| 379 m_PosY = y; | |
| 380 m_Left += dx; | |
| 381 m_Right += dx; | |
| 382 m_Top += dy; | |
| 383 m_Bottom += dy; | |
| 384 } | |
| 385 | |
| 386 void CPDF_TextObject::RecalcPositionData() { | |
| 387 CalcPositionData(nullptr, nullptr, 1); | |
| 388 } | |
| OLD | NEW |