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 "reflowedtextpage.h" 8 IPDF_TextPage* IPDF_TextPage::CreateReflowTextPage(IPDF_ReflowedPage* pRefPage) 9 { 10 return FX_NEW CRF_TextPage(pRefPage); 11 } 12 CRF_TextPage::CRF_TextPage(IPDF_ReflowedPage* pRefPage) 13 { 14 m_pRefPage = (CPDF_ReflowedPage*)(pRefPage); 15 m_pDataList = NULL; 16 m_CountBSArray = NULL; 17 } 18 CRF_TextPage::~CRF_TextPage() 19 { 20 if(m_pDataList) { 21 delete m_pDataList; 22 m_pDataList = NULL; 23 } 24 if(m_CountBSArray) { 25 delete m_CountBSArray; 26 m_CountBSArray = NULL; 27 } 28 } 29 FX_BOOL CRF_TextPage::ParseTextPage() 30 { 31 if(!m_pRefPage) { 32 return FALSE; 33 } 34 int count = m_pRefPage->m_pReflowed->GetSize(); 35 if(count < 500) { 36 m_pDataList = FX_NEW CRF_CharDataPtrArray(count); 37 } else { 38 m_pDataList = FX_NEW CRF_CharDataPtrArray(500); 39 } 40 if (NULL == m_pDataList) { 41 return FALSE; 42 } 43 for(int i = 0; i < count; i++) { 44 CRF_Data* pData = (*(m_pRefPage->m_pReflowed))[i]; 45 if(pData->GetType() == CRF_Data::Text) { 46 m_pDataList->Add((CRF_CharData*)pData); 47 } 48 } 49 m_CountBSArray = FX_NEW CFX_CountBSINT32Array(20); 50 if(NULL == m_CountBSArray) { 51 return FALSE; 52 } 53 return TRUE; 54 } 55 FX_BOOL CRF_TextPage::IsParsered() const 56 { 57 if(m_pDataList) { 58 return TRUE; 59 } 60 return FALSE; 61 } 62 int CRF_TextPage::CharIndexFromTextIndex(int TextIndex) const 63 { 64 return TextIndex; 65 } 66 int CRF_TextPage::TextIndexFromCharIndex(int CharIndex) const 67 { 68 return CharIndex; 69 } 70 71 int CRF_TextPage::CountChars() const 72 { 73 if (NULL == m_pDataList) { 74 return -1; 75 } 76 return m_pDataList->GetSize(); 77 } 78 void CRF_TextPage::GetCharInfo(int index, FPDF_CHAR_INFO & info) const 79 { 80 if(index >= CountChars() || index < 0 || !m_pDataList) { 81 return; 82 } 83 CRF_CharData* pData = (*m_pDataList)[index]; 84 FX_FLOAT ReltiveCorddDs = pData->m_pCharState->m_fDescent; 85 FX_FLOAT ReltiveCorddAs = pData->m_pCharState->m_fAscent; 86 info.m_Flag = CHAR_NORMAL; 87 info.m_pTextObj = pData->m_pCharState->m_pTextObj; 88 info.m_OriginX = pData->m_PosX; 89 info.m_OriginY = pData->m_PosY - ReltiveCorddDs; 90 info.m_FontSize = pData->m_pCharState->m_fFontSize; 91 CFX_FloatRect FloatRectTmp(pData->m_PosX, pData->m_PosY, pData->m_PosX + pData->m_Width, pData->m_PosY + ReltiveCorddAs - ReltiveCorddDs); 92 info.m_CharBox = FloatRectTmp; 93 CFX_WideString str = pData->m_pCharState->m_pFont->UnicodeFromCharCode(pData->m_CharCode); 94 if(!str.IsEmpty()) { 95 info.m_Unicode = str.GetAt(0); 96 } else { 97 info.m_Unicode = -1; 98 } 99 info.m_Charcode = (FX_WCHAR)pData->m_CharCode; 100 info.m_Matrix = CFX_Matrix(1, 0, 0, 1, 0, 0); 101 } 102 extern FX_BOOL GetIntersection(FX_FLOAT low1, FX_FLOAT high1, FX_FLOAT low2, FX_FLOAT high2, FX_FLOAT& interlow, FX_FLOAT& interhigh); 103 inline FX_BOOL _IsInsameline(const CFX_FloatRect& rectA, const CFX_FloatRect& rectB) 104 { 105 if((rectA.top >= rectB.bottom && rectB.top >= rectA.bottom)) { 106 return TRUE; 107 } else { 108 return FALSE; 109 } 110 } 111 inline FX_BOOL _IsIntersect(const CFX_FloatRect& rectA, const CFX_FloatRect& rectB) 112 { 113 FX_FLOAT interlow = .0f, interhigh = .0f; 114 if(GetIntersection(rectA.bottom, rectA.top, rectB.bottom, rectB.top, interlow, interhigh)) { 115 if(GetIntersection(rectA.left, rectA.right, rectB.left, rectB.right, interlow, interhigh)) { 116 return TRUE; 117 } else { 118 return FALSE; 119 } 120 } 121 return FALSE; 122 } 123 void CRF_TextPage::GetRectArray(int start, int nCount, CFX_RectArray& rectArray) const 124 { 125 int indexlen = start + nCount; 126 FPDF_CHAR_INFO info; 127 FX_BOOL bstart = TRUE; 128 CFX_FloatRect recttmp; 129 int i; 130 for(i = start; i < indexlen; i++) { 131 GetCharInfo(i, info); 132 if(bstart) { 133 recttmp = info.m_CharBox; 134 bstart = FALSE; 135 } else if(_IsInsameline(recttmp, info.m_CharBox)) { 136 recttmp.right = info.m_CharBox.right; 137 if(info.m_CharBox.top > recttmp.top) { 138 recttmp.top = info.m_CharBox.top; 139 } 140 if(info.m_CharBox.bottom < recttmp.bottom) { 141 recttmp.bottom = info.m_CharBox.bottom; 142 } 143 } else { 144 rectArray.Add(recttmp); 145 recttmp = info.m_CharBox; 146 } 147 } 148 rectArray.Add(recttmp); 149 } 150 inline FX_FLOAT _GetDistance(CFX_FloatRect floatRect, CPDF_Point point) 151 { 152 if(floatRect.right < point.x && floatRect.bottom > point.y) { 153 return FXSYS_sqrt(FXSYS_pow(point.x - floatRect.right, 2) + FXSYS_pow(floatRect.bottom - point.y, 2)); 154 } 155 if (floatRect.right < point.x && floatRect.top < point.y) { 156 return FXSYS_sqrt(FXSYS_pow(point.x - floatRect.right, 2) + FXSYS_pow(point.y - floatRect.top, 2)); 157 } 158 if(floatRect.left > point.x && floatRect.bottom > point.y) { 159 return FXSYS_sqrt(FXSYS_pow(floatRect.bottom - point.y, 2) + FXSYS_pow(floatRect.left - point.x, 2)); 160 } 161 if((floatRect.right > point.x || FXSYS_fabs(floatRect.right - point.x) <= 0.0001f) && 162 (floatRect.left < point.x || FXSYS_fabs(floatRect.left - point.x) <= 0.0001f) && floatRect.bottom > point.y) { 163 return FXSYS_fabs(floatRect.bottom - point.y); 164 } 165 if(floatRect.left > point.x && (floatRect.bottom < point.y || FXSYS_fabs(floatRect.bottom - point.y) <= 0.0001f) && 166 (floatRect.top > point.y || FXSYS_fabs(floatRect.top - point.y) <= 0.0001f)) { 167 return FXSYS_fabs(floatRect.left - point.x); 168 } 169 if(floatRect.left > point.x && floatRect.top < point.y) { 170 return FXSYS_sqrt(FXSYS_pow(floatRect.left - point.x, 2) + FXSYS_pow(point.y - floatRect.top, 2)); 171 } 172 if ((floatRect.left < point.x || FXSYS_fabs(floatRect.left - point.x) <= 0.0001f) && 173 (floatRect.right > point.x || FXSYS_fabs(floatRect.right - point.x) <= 0.0001f) && floatRect.top < point.y) { 174 return FXSYS_fabs(point.y - floatRect.top); 175 } 176 if(floatRect.right < point.x && (floatRect.top > point.y || FXSYS_fabs(floatRect.top - point.y) <= 0.0001f) && 177 (floatRect.bottom < point.y || FXSYS_fabs(floatRect.bottom - point.y) <= 0.0001f)) { 178 return point.x - floatRect.right; 179 } 180 return .0f; 181 } 182 int CRF_TextPage::GetIndexAtPos(CPDF_Point point, FX_FLOAT xTorelance, FX_FLOAT yTorelance) const 183 { 184 int index = -1, i = 0, j = 0; 185 FPDF_CHAR_INFO info; 186 CFX_FloatRect rectTmp; 187 FX_FLOAT MinDistance = 1000, DistanceTmp = 0; 188 FX_FLOAT rect_bottom = point.x - xTorelance; 189 CFX_FloatRect TorelanceRect(rect_bottom <= 0 ? 0 : rect_bottom, point.y - yTorelance, point.x + xTorelance, point.y + yTorelance); 190 int count = CountChars(); 191 for(i = 0; i < count; i++) { 192 GetCharInfo(i, info); 193 rectTmp = info.m_CharBox; 194 if(rectTmp.Contains(point.x, point.y)) { 195 index = i; 196 break; 197 } else if(_IsIntersect(rectTmp, TorelanceRect)) { 198 DistanceTmp = _GetDistance(rectTmp, point); 199 if(DistanceTmp < MinDistance) { 200 MinDistance = DistanceTmp; 201 index = i; 202 } 203 } 204 } 205 return index; 206 } 207 int CRF_TextPage::GetIndexAtPos(FX_FLOAT x, FX_FLOAT y, FX_FLOAT xTorelance, FX_FLOAT yTorelance) const 208 { 209 int index = 0; 210 CPDF_Point point(x, y); 211 if((index = GetIndexAtPos(point, xTorelance, yTorelance)) < 0) { 212 return -1; 213 } else { 214 return index; 215 } 216 } 217 int CRF_TextPage::GetOrderByDirection(int index, int direction) const 218 { 219 return -1; 220 } 221 CFX_WideString CRF_TextPage::GetTextByRect(CFX_FloatRect rect) const 222 { 223 int count; 224 FPDF_CHAR_INFO info; 225 CFX_WideString str; 226 CFX_FloatRect Recttmp; 227 FX_BOOL bstart = TRUE; 228 count = CountChars(); 229 if(rect.IsEmpty()) { 230 return L""; 231 } 232 for(int i = 0; i < count; i++) { 233 GetCharInfo(i, info); 234 if(_IsIntersect(rect, info.m_CharBox)) { 235 if(bstart) { 236 Recttmp = info.m_CharBox; 237 str += info.m_Unicode; 238 bstart = FALSE; 239 } else if(_IsInsameline(Recttmp, info.m_CharBox)) { 240 str += info.m_Unicode; 241 } else { 242 str += L"\r\n"; 243 Recttmp = info.m_CharBox; 244 str += info.m_Unicode; 245 } 246 } 247 } 248 if(str.IsEmpty()) { 249 return L""; 250 } else { 251 return str; 252 } 253 } 254 void CRF_TextPage::GetRectsArrayByRect(CFX_FloatRect rect, CFX_RectArray& resRectArray) const 255 { 256 int count, i; 257 FX_BOOL bstart = TRUE; 258 FPDF_CHAR_INFO info; 259 CFX_FloatRect recttmp; 260 count = CountChars(); 261 for(i = 0; i < count; i++) { 262 GetCharInfo(i, info); 263 if(_IsIntersect(rect, info.m_CharBox)) { 264 if(bstart) { 265 recttmp = info.m_CharBox; 266 bstart = FALSE; 267 } else if(_IsInsameline(recttmp, info.m_CharBox)) { 268 recttmp.right = info.m_CharBox.right; 269 if(info.m_CharBox.top > recttmp.top) { 270 recttmp.top = info.m_CharBox.top; 271 } 272 if(info.m_CharBox.bottom < recttmp.bottom) { 273 recttmp.bottom = info.m_CharBox.bottom; 274 } 275 } else { 276 resRectArray.Add(recttmp); 277 recttmp = info.m_CharBox; 278 } 279 } 280 } 281 resRectArray.Add(recttmp); 282 } 283 int CRF_TextPage::CountRects(int start, int nCount) 284 { 285 m_rectArray.RemoveAll(); 286 GetRectArray(start, nCount, m_rectArray); 287 return m_rectArray.GetSize(); 288 } 289 void CRF_TextPage::GetRect(int rectIndex, FX_FLOAT& left, FX_FLOAT& top, FX_FLOAT& right, FX_FLOAT &bottom) const 290 { 291 if(m_rectArray.GetSize() <= rectIndex) { 292 return; 293 } 294 left = m_rectArray[rectIndex].left; 295 top = m_rectArray[rectIndex].top; 296 right = m_rectArray[rectIndex].right; 297 bottom = m_rectArray[rectIndex].bottom; 298 } 299 FX_BOOL CRF_TextPage::GetBaselineRotate(int rectIndex, int& Rotate) 300 { 301 Rotate = 0; 302 return TRUE; 303 } 304 FX_BOOL CRF_TextPage::GetBaselineRotate(CFX_FloatRect rect, int& Rotate) 305 { 306 Rotate = 0; 307 return TRUE; 308 } 309 int CRF_TextPage::CountBoundedSegments(FX_FLOAT left, FX_FLOAT top, FX_FLOAT right, FX_FLOAT bottom, FX_BOOL bContains) 310 { 311 if (!m_CountBSArray) { 312 return -1; 313 } 314 m_CountBSArray->RemoveAll(); 315 CFX_FloatRect floatrect(left, bottom, right, top); 316 int totalcount, i, j = 0, counttmp = 0; 317 FX_BOOL bstart = TRUE; 318 FPDF_CHAR_INFO info; 319 CFX_FloatRect recttmp; 320 totalcount = CountChars(); 321 for(i = 0; i < totalcount; i++) { 322 GetCharInfo(i, info); 323 if(_IsIntersect(floatrect, info.m_CharBox)) { 324 if(bstart) { 325 m_CountBSArray->Add(i); 326 counttmp = 1; 327 recttmp = info.m_CharBox; 328 bstart = FALSE; 329 } else if(_IsInsameline(recttmp, info.m_CharBox)) { 330 recttmp.right = info.m_CharBox.right; 331 if(info.m_CharBox.top > recttmp.top) { 332 recttmp.top = info.m_CharBox.top; 333 } 334 if(info.m_CharBox.bottom < recttmp.bottom) { 335 recttmp.bottom = info.m_CharBox.bottom; 336 } 337 counttmp ++; 338 } else { 339 m_CountBSArray->Add(counttmp); 340 m_CountBSArray->Add(i); 341 counttmp = 1; 342 j++; 343 recttmp = info.m_CharBox; 344 } 345 } 346 } 347 m_CountBSArray->Add(counttmp); 348 j++; 349 return j; 350 } 351 void CRF_TextPage::GetBoundedSegment(int index, int& start, int& count) const 352 { 353 if (!m_CountBSArray) { 354 return; 355 } 356 if(m_CountBSArray->GetSize() <= index * 2) { 357 start = 0; 358 count = 0; 359 return; 360 } 361 start = *(int *)m_CountBSArray->GetAt(index * 2); 362 count = *(int *)m_CountBSArray->GetAt(index * 2 + 1); 363 } 364 365 int CRF_TextPage::GetWordBreak(int index, int direction) const 366 { 367 return -1; 368 } 369 CFX_WideString CRF_TextPage::GetPageText(int start, int nCount ) const 370 { 371 if(nCount == -1) { 372 nCount = CountChars(); 373 start = 0; 374 } else if(nCount < 1) { 375 return L""; 376 } else if(start >= CountChars()) { 377 return L""; 378 } 379 int i, index = start + nCount; 380 FPDF_CHAR_INFO info; 381 CFX_WideString str; 382 CFX_FloatRect recttmp; 383 FX_BOOL bstart = TRUE; 384 for(i = start; i < index; i++) { 385 GetCharInfo(i, info); 386 if(bstart) { 387 recttmp = info.m_CharBox; 388 str += info.m_Unicode; 389 bstart = FALSE; 390 } else if (_IsInsameline(recttmp, info.m_CharBox)) { 391 str += info.m_Unicode; 392 } else { 393 str += L"\r\n"; 394 recttmp = info.m_CharBox; 395 str += info.m_Unicode; 396 } 397 } 398 if(str.IsEmpty()) { 399 return L""; 400 } 401 return str; 402 } 403