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 17 CPDF_TextObjectItem::CPDF_TextObjectItem() : m_CharCode(0) {} 18 19 CPDF_TextObjectItem::~CPDF_TextObjectItem() = default; 20 21 CPDF_TextObject::CPDF_TextObject() {} 22 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 29 size_t CPDF_TextObject::CountItems() const { 30 return m_CharCodes.size(); 31 } 32 33 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 58 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 67 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 87 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 101 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 110 CPDF_PageObject::Type CPDF_TextObject::GetType() const { 111 return TEXT; 112 } 113 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 128 bool CPDF_TextObject::IsText() const { 129 return true; 130 } 131 132 CPDF_TextObject* CPDF_TextObject::AsText() { 133 return this; 134 } 135 136 const CPDF_TextObject* CPDF_TextObject::AsText() const { 137 return this; 138 } 139 140 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 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 172 void CPDF_TextObject::SetText(const ByteString& str) { 173 SetSegments(&str, nullptr, 1); 174 RecalcPositionData(); 175 SetDirty(true); 176 } 177 178 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 192 CPDF_Font* CPDF_TextObject::GetFont() const { 193 return m_TextState.GetFont(); 194 } 195 196 float CPDF_TextObject::GetFontSize() const { 197 return m_TextState.GetFontSize(); 198 } 199 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 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 297 void CPDF_TextObject::RecalcPositionData() { 298 CalcPositionData(1); 299 } 300