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 "core/include/fpdfapi/fpdf_pageobj.h" 8 #include "core/include/fpdfapi/fpdf_render.h" 9 #include "fpdfsdk/include/fx_systemhandler.h" 10 #include "fpdfsdk/include/fxedit/fx_edit.h" 11 #include "fpdfsdk/include/fxedit/fxet_edit.h" 12 13 #define FX_EDIT_UNDERLINEHALFWIDTH 0.5f 14 #define FX_EDIT_CROSSOUTHALFWIDTH 0.5f 15 16 CPDF_Rect GetUnderLineRect(const CPVT_Word& word) { 17 return CPDF_Rect(word.ptWord.x, word.ptWord.y + word.fDescent * 0.5f, 18 word.ptWord.x + word.fWidth, 19 word.ptWord.y + word.fDescent * 0.25f); 20 } 21 22 CPDF_Rect GetCrossoutRect(const CPVT_Word& word) { 23 return CPDF_Rect(word.ptWord.x, 24 word.ptWord.y + (word.fAscent + word.fDescent) * 0.5f + 25 word.fDescent * 0.25f, 26 word.ptWord.x + word.fWidth, 27 word.ptWord.y + (word.fAscent + word.fDescent) * 0.5f); 28 } 29 30 static void DrawTextString(CFX_RenderDevice* pDevice, 31 const CPDF_Point& pt, 32 CPDF_Font* pFont, 33 FX_FLOAT fFontSize, 34 CFX_Matrix* pUser2Device, 35 const CFX_ByteString& str, 36 FX_ARGB crTextFill, 37 FX_ARGB crTextStroke, 38 int32_t nHorzScale) { 39 FX_FLOAT x = pt.x, y = pt.y; 40 pUser2Device->Transform(x, y); 41 42 if (pFont) { 43 if (nHorzScale != 100) { 44 CFX_Matrix mt(nHorzScale / 100.0f, 0, 0, 1, 0, 0); 45 mt.Concat(*pUser2Device); 46 47 CPDF_RenderOptions ro; 48 ro.m_Flags = RENDER_CLEARTYPE; 49 ro.m_ColorMode = RENDER_COLOR_NORMAL; 50 51 if (crTextStroke != 0) { 52 CPDF_Point pt1(0, 0), pt2(1, 0); 53 pUser2Device->Transform(pt1.x, pt1.y); 54 pUser2Device->Transform(pt2.x, pt2.y); 55 CFX_GraphStateData gsd; 56 gsd.m_LineWidth = 57 (FX_FLOAT)FXSYS_fabs((pt2.x + pt2.y) - (pt1.x + pt1.y)); 58 59 CPDF_TextRenderer::DrawTextString(pDevice, x, y, pFont, fFontSize, &mt, 60 str, crTextFill, crTextStroke, &gsd, 61 &ro); 62 } else { 63 CPDF_TextRenderer::DrawTextString(pDevice, x, y, pFont, fFontSize, &mt, 64 str, crTextFill, 0, NULL, &ro); 65 } 66 } else { 67 CPDF_RenderOptions ro; 68 ro.m_Flags = RENDER_CLEARTYPE; 69 ro.m_ColorMode = RENDER_COLOR_NORMAL; 70 71 if (crTextStroke != 0) { 72 CPDF_Point pt1(0, 0), pt2(1, 0); 73 pUser2Device->Transform(pt1.x, pt1.y); 74 pUser2Device->Transform(pt2.x, pt2.y); 75 CFX_GraphStateData gsd; 76 gsd.m_LineWidth = 77 (FX_FLOAT)FXSYS_fabs((pt2.x + pt2.y) - (pt1.x + pt1.y)); 78 79 CPDF_TextRenderer::DrawTextString(pDevice, x, y, pFont, fFontSize, 80 pUser2Device, str, crTextFill, 81 crTextStroke, &gsd, &ro); 82 } else { 83 CPDF_TextRenderer::DrawTextString(pDevice, x, y, pFont, fFontSize, 84 pUser2Device, str, crTextFill, 0, 85 NULL, &ro); 86 } 87 } 88 } 89 } 90 91 void IFX_Edit::DrawUnderline(CFX_RenderDevice* pDevice, 92 CFX_Matrix* pUser2Device, 93 IFX_Edit* pEdit, 94 FX_COLORREF color, 95 const CPDF_Rect& rcClip, 96 const CPDF_Point& ptOffset, 97 const CPVT_WordRange* pRange) { 98 pDevice->SaveState(); 99 100 if (!rcClip.IsEmpty()) { 101 CPDF_Rect rcTemp = rcClip; 102 pUser2Device->TransformRect(rcTemp); 103 FX_RECT rcDevClip; 104 rcDevClip.left = (int32_t)rcTemp.left; 105 rcDevClip.right = (int32_t)rcTemp.right; 106 rcDevClip.top = (int32_t)rcTemp.top; 107 rcDevClip.bottom = (int32_t)rcTemp.bottom; 108 pDevice->SetClip_Rect(&rcDevClip); 109 } 110 111 if (IFX_Edit_Iterator* pIterator = pEdit->GetIterator()) { 112 if (pEdit->GetFontMap()) { 113 if (pRange) 114 pIterator->SetAt(pRange->BeginPos); 115 else 116 pIterator->SetAt(0); 117 118 while (pIterator->NextWord()) { 119 CPVT_WordPlace place = pIterator->GetAt(); 120 if (pRange && place.WordCmp(pRange->EndPos) > 0) 121 break; 122 123 CPVT_Word word; 124 if (pIterator->GetWord(word)) { 125 CFX_PathData pathUnderline; 126 CPDF_Rect rcUnderline = GetUnderLineRect(word); 127 rcUnderline.left += ptOffset.x; 128 rcUnderline.right += ptOffset.x; 129 rcUnderline.top += ptOffset.y; 130 rcUnderline.bottom += ptOffset.y; 131 pathUnderline.AppendRect(rcUnderline.left, rcUnderline.bottom, 132 rcUnderline.right, rcUnderline.top); 133 134 pDevice->DrawPath(&pathUnderline, pUser2Device, NULL, color, 0, 135 FXFILL_WINDING); 136 } 137 } 138 } 139 } 140 141 pDevice->RestoreState(); 142 } 143 144 void IFX_Edit::DrawEdit(CFX_RenderDevice* pDevice, 145 CFX_Matrix* pUser2Device, 146 IFX_Edit* pEdit, 147 FX_COLORREF crTextFill, 148 FX_COLORREF crTextStroke, 149 const CPDF_Rect& rcClip, 150 const CPDF_Point& ptOffset, 151 const CPVT_WordRange* pRange, 152 IFX_SystemHandler* pSystemHandler, 153 void* pFFLData) { 154 FX_BOOL bContinuous = pEdit->GetCharArray() == 0; 155 if (pEdit->GetCharSpace() > 0.0f) 156 bContinuous = FALSE; 157 158 FX_WORD SubWord = pEdit->GetPasswordChar(); 159 FX_FLOAT fFontSize = pEdit->GetFontSize(); 160 CPVT_WordRange wrSelect = pEdit->GetSelectWordRange(); 161 int32_t nHorzScale = pEdit->GetHorzScale(); 162 163 FX_COLORREF crCurFill = crTextFill; 164 FX_COLORREF crOldFill = crCurFill; 165 166 FX_BOOL bSelect = FALSE; 167 const FX_COLORREF crWhite = ArgbEncode(255, 255, 255, 255); 168 const FX_COLORREF crSelBK = ArgbEncode(255, 0, 51, 113); 169 170 CFX_ByteTextBuf sTextBuf; 171 int32_t nFontIndex = -1; 172 CPDF_Point ptBT(0.0f, 0.0f); 173 174 pDevice->SaveState(); 175 176 if (!rcClip.IsEmpty()) { 177 CPDF_Rect rcTemp = rcClip; 178 pUser2Device->TransformRect(rcTemp); 179 FX_RECT rcDevClip; 180 rcDevClip.left = (int32_t)rcTemp.left; 181 rcDevClip.right = (int32_t)rcTemp.right; 182 rcDevClip.top = (int32_t)rcTemp.top; 183 rcDevClip.bottom = (int32_t)rcTemp.bottom; 184 pDevice->SetClip_Rect(&rcDevClip); 185 } 186 187 if (IFX_Edit_Iterator* pIterator = pEdit->GetIterator()) { 188 if (IFX_Edit_FontMap* pFontMap = pEdit->GetFontMap()) { 189 if (pRange) 190 pIterator->SetAt(pRange->BeginPos); 191 else 192 pIterator->SetAt(0); 193 194 CPVT_WordPlace oldplace; 195 196 while (pIterator->NextWord()) { 197 CPVT_WordPlace place = pIterator->GetAt(); 198 if (pRange && place.WordCmp(pRange->EndPos) > 0) 199 break; 200 201 if (wrSelect.IsExist()) { 202 bSelect = place.WordCmp(wrSelect.BeginPos) > 0 && 203 place.WordCmp(wrSelect.EndPos) <= 0; 204 if (bSelect) { 205 crCurFill = crWhite; 206 } else { 207 crCurFill = crTextFill; 208 } 209 } 210 if (pSystemHandler && pSystemHandler->IsSelectionImplemented()) { 211 crCurFill = crTextFill; 212 crOldFill = crCurFill; 213 } 214 CPVT_Word word; 215 if (pIterator->GetWord(word)) { 216 if (bSelect) { 217 CPVT_Line line; 218 pIterator->GetLine(line); 219 220 if (pSystemHandler && pSystemHandler->IsSelectionImplemented()) { 221 CPDF_Rect rc(word.ptWord.x, line.ptLine.y + line.fLineDescent, 222 word.ptWord.x + word.fWidth, 223 line.ptLine.y + line.fLineAscent); 224 rc.Intersect(rcClip); 225 pSystemHandler->OutputSelectedRect(pFFLData, rc); 226 } else { 227 CFX_PathData pathSelBK; 228 pathSelBK.AppendRect(word.ptWord.x, 229 line.ptLine.y + line.fLineDescent, 230 word.ptWord.x + word.fWidth, 231 line.ptLine.y + line.fLineAscent); 232 233 pDevice->DrawPath(&pathSelBK, pUser2Device, NULL, crSelBK, 0, 234 FXFILL_WINDING); 235 } 236 } 237 238 if (bContinuous) { 239 if (place.LineCmp(oldplace) != 0 || word.nFontIndex != nFontIndex || 240 crOldFill != crCurFill) { 241 if (sTextBuf.GetLength() > 0) { 242 DrawTextString(pDevice, CPDF_Point(ptBT.x + ptOffset.x, 243 ptBT.y + ptOffset.y), 244 pFontMap->GetPDFFont(nFontIndex), fFontSize, 245 pUser2Device, sTextBuf.GetByteString(), 246 crOldFill, crTextStroke, nHorzScale); 247 248 sTextBuf.Clear(); 249 } 250 nFontIndex = word.nFontIndex; 251 ptBT = word.ptWord; 252 crOldFill = crCurFill; 253 } 254 255 sTextBuf << GetPDFWordString(pFontMap, word.nFontIndex, word.Word, 256 SubWord); 257 } else { 258 DrawTextString( 259 pDevice, CPDF_Point(word.ptWord.x + ptOffset.x, 260 word.ptWord.y + ptOffset.y), 261 pFontMap->GetPDFFont(word.nFontIndex), fFontSize, pUser2Device, 262 GetPDFWordString(pFontMap, word.nFontIndex, word.Word, SubWord), 263 crCurFill, crTextStroke, nHorzScale); 264 } 265 oldplace = place; 266 } 267 } 268 269 if (sTextBuf.GetLength() > 0) { 270 DrawTextString( 271 pDevice, CPDF_Point(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y), 272 pFontMap->GetPDFFont(nFontIndex), fFontSize, pUser2Device, 273 sTextBuf.GetByteString(), crOldFill, crTextStroke, nHorzScale); 274 } 275 } 276 } 277 278 pDevice->RestoreState(); 279 } 280 281 void IFX_Edit::DrawRichEdit(CFX_RenderDevice* pDevice, 282 CFX_Matrix* pUser2Device, 283 IFX_Edit* pEdit, 284 const CPDF_Rect& rcClip, 285 const CPDF_Point& ptOffset, 286 const CPVT_WordRange* pRange) { 287 CPVT_WordRange wrSelect = pEdit->GetSelectWordRange(); 288 289 FX_COLORREF crCurText = ArgbEncode(255, 0, 0, 0); 290 FX_COLORREF crOld = crCurText; 291 FX_BOOL bSelect = FALSE; 292 const FX_COLORREF crWhite = ArgbEncode(255, 255, 255, 255); 293 const FX_COLORREF crSelBK = ArgbEncode(255, 0, 51, 113); 294 295 CFX_ByteTextBuf sTextBuf; 296 CPVT_WordProps wp; 297 CPDF_Point ptBT(0.0f, 0.0f); 298 299 pDevice->SaveState(); 300 301 if (!rcClip.IsEmpty()) { 302 CPDF_Rect rcTemp = rcClip; 303 pUser2Device->TransformRect(rcTemp); 304 FX_RECT rcDevClip; 305 rcDevClip.left = (int32_t)rcTemp.left; 306 rcDevClip.right = (int32_t)rcTemp.right; 307 rcDevClip.top = (int32_t)rcTemp.top; 308 rcDevClip.bottom = (int32_t)rcTemp.bottom; 309 pDevice->SetClip_Rect(&rcDevClip); 310 } 311 312 if (IFX_Edit_Iterator* pIterator = pEdit->GetIterator()) { 313 if (IFX_Edit_FontMap* pFontMap = pEdit->GetFontMap()) { 314 if (pRange) 315 pIterator->SetAt(pRange->BeginPos); 316 else 317 pIterator->SetAt(0); 318 319 CPVT_WordPlace oldplace; 320 321 while (pIterator->NextWord()) { 322 CPVT_WordPlace place = pIterator->GetAt(); 323 if (pRange && place.WordCmp(pRange->EndPos) > 0) 324 break; 325 326 CPVT_Word word; 327 if (pIterator->GetWord(word)) { 328 word.WordProps.fFontSize = word.fFontSize; 329 330 crCurText = ArgbEncode(255, word.WordProps.dwWordColor); 331 332 if (wrSelect.IsExist()) { 333 bSelect = place.WordCmp(wrSelect.BeginPos) > 0 && 334 place.WordCmp(wrSelect.EndPos) <= 0; 335 if (bSelect) { 336 crCurText = crWhite; 337 } 338 } 339 340 if (bSelect) { 341 CPVT_Line line; 342 pIterator->GetLine(line); 343 344 CFX_PathData pathSelBK; 345 pathSelBK.AppendRect(word.ptWord.x + ptOffset.x, 346 line.ptLine.y + line.fLineDescent + ptOffset.y, 347 word.ptWord.x + word.fWidth + ptOffset.x, 348 line.ptLine.y + line.fLineAscent + ptOffset.y); 349 350 pDevice->DrawPath(&pathSelBK, pUser2Device, NULL, crSelBK, 0, 351 FXFILL_WINDING); 352 } 353 354 if (place.LineCmp(oldplace) != 0 || 355 word.WordProps.fCharSpace > 0.0f || 356 word.WordProps.nHorzScale != 100 || 357 FXSYS_memcmp(&word.WordProps, &wp, sizeof(CPVT_WordProps)) != 0 || 358 crOld != crCurText) { 359 if (sTextBuf.GetLength() > 0) { 360 DrawTextString( 361 pDevice, CPDF_Point(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y), 362 pFontMap->GetPDFFont(wp.nFontIndex), wp.fFontSize, 363 pUser2Device, sTextBuf.GetByteString(), crOld, 0, 364 wp.nHorzScale); 365 366 sTextBuf.Clear(); 367 } 368 wp = word.WordProps; 369 ptBT = word.ptWord; 370 crOld = crCurText; 371 } 372 373 sTextBuf << GetPDFWordString(pFontMap, word.WordProps.nFontIndex, 374 word.Word, 0); 375 376 if (word.WordProps.nWordStyle & PVTWORD_STYLE_UNDERLINE) { 377 CFX_PathData pathUnderline; 378 CPDF_Rect rcUnderline = GetUnderLineRect(word); 379 pathUnderline.AppendRect(rcUnderline.left, rcUnderline.bottom, 380 rcUnderline.right, rcUnderline.top); 381 382 pDevice->DrawPath(&pathUnderline, pUser2Device, NULL, crCurText, 0, 383 FXFILL_WINDING); 384 } 385 386 if (word.WordProps.nWordStyle & PVTWORD_STYLE_CROSSOUT) { 387 CFX_PathData pathCrossout; 388 CPDF_Rect rcCrossout = GetCrossoutRect(word); 389 pathCrossout.AppendRect(rcCrossout.left, rcCrossout.bottom, 390 rcCrossout.right, rcCrossout.top); 391 392 pDevice->DrawPath(&pathCrossout, pUser2Device, NULL, crCurText, 0, 393 FXFILL_WINDING); 394 } 395 396 oldplace = place; 397 } 398 } 399 400 if (sTextBuf.GetLength() > 0) { 401 DrawTextString( 402 pDevice, CPDF_Point(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y), 403 pFontMap->GetPDFFont(wp.nFontIndex), wp.fFontSize, pUser2Device, 404 sTextBuf.GetByteString(), crOld, 0, wp.nHorzScale); 405 } 406 } 407 } 408 409 pDevice->RestoreState(); 410 } 411 412 static void AddRectToPageObjects(CPDF_PageObjects* pPageObjs, 413 FX_COLORREF crFill, 414 const CPDF_Rect& rcFill) { 415 CPDF_PathObject* pPathObj = new CPDF_PathObject; 416 CPDF_PathData* pPathData = pPathObj->m_Path.GetModify(); 417 pPathData->AppendRect(rcFill.left, rcFill.bottom, rcFill.right, rcFill.top); 418 419 FX_FLOAT rgb[3]; 420 rgb[0] = FXARGB_R(crFill) / 255.0f; 421 rgb[1] = FXARGB_G(crFill) / 255.0f; 422 rgb[2] = FXARGB_B(crFill) / 255.0f; 423 pPathObj->m_ColorState.SetFillColor( 424 CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3); 425 426 pPathObj->m_FillType = FXFILL_ALTERNATE; 427 pPathObj->m_bStroke = FALSE; 428 429 pPageObjs->InsertObject(pPageObjs->GetLastObjectPosition(), pPathObj); 430 } 431 432 static CPDF_TextObject* AddTextObjToPageObjects(CPDF_PageObjects* pPageObjs, 433 FX_COLORREF crText, 434 CPDF_Font* pFont, 435 FX_FLOAT fFontSize, 436 FX_FLOAT fCharSpace, 437 int32_t nHorzScale, 438 const CPDF_Point& point, 439 const CFX_ByteString& text) { 440 CPDF_TextObject* pTxtObj = new CPDF_TextObject; 441 442 CPDF_TextStateData* pTextStateData = pTxtObj->m_TextState.GetModify(); 443 pTextStateData->m_pFont = pFont; 444 pTextStateData->m_FontSize = fFontSize; 445 pTextStateData->m_CharSpace = fCharSpace; 446 pTextStateData->m_WordSpace = 0; 447 pTextStateData->m_TextMode = 0; 448 pTextStateData->m_Matrix[0] = nHorzScale / 100.0f; 449 pTextStateData->m_Matrix[1] = 0; 450 pTextStateData->m_Matrix[2] = 0; 451 pTextStateData->m_Matrix[3] = 1; 452 453 FX_FLOAT rgb[3]; 454 rgb[0] = FXARGB_R(crText) / 255.0f; 455 rgb[1] = FXARGB_G(crText) / 255.0f; 456 rgb[2] = FXARGB_B(crText) / 255.0f; 457 pTxtObj->m_ColorState.SetFillColor( 458 CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3); 459 pTxtObj->m_ColorState.SetStrokeColor( 460 CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3); 461 462 pTxtObj->SetPosition(point.x, point.y); 463 pTxtObj->SetText(text); 464 465 pPageObjs->InsertObject(pPageObjs->GetLastObjectPosition(), pTxtObj); 466 467 return pTxtObj; 468 } 469 470 void IFX_Edit::GeneratePageObjects( 471 CPDF_PageObjects* pPageObjects, 472 IFX_Edit* pEdit, 473 const CPDF_Point& ptOffset, 474 const CPVT_WordRange* pRange, 475 FX_COLORREF crText, 476 CFX_ArrayTemplate<CPDF_TextObject*>& ObjArray) { 477 FX_FLOAT fFontSize = pEdit->GetFontSize(); 478 479 int32_t nOldFontIndex = -1; 480 481 CFX_ByteTextBuf sTextBuf; 482 CPDF_Point ptBT(0.0f, 0.0f); 483 484 ObjArray.RemoveAll(); 485 486 if (IFX_Edit_Iterator* pIterator = pEdit->GetIterator()) { 487 if (IFX_Edit_FontMap* pFontMap = pEdit->GetFontMap()) { 488 if (pRange) 489 pIterator->SetAt(pRange->BeginPos); 490 else 491 pIterator->SetAt(0); 492 493 CPVT_WordPlace oldplace; 494 495 while (pIterator->NextWord()) { 496 CPVT_WordPlace place = pIterator->GetAt(); 497 if (pRange && place.WordCmp(pRange->EndPos) > 0) 498 break; 499 500 CPVT_Word word; 501 if (pIterator->GetWord(word)) { 502 if (place.LineCmp(oldplace) != 0 || 503 nOldFontIndex != word.nFontIndex) { 504 if (sTextBuf.GetLength() > 0) { 505 ObjArray.Add(AddTextObjToPageObjects( 506 pPageObjects, crText, pFontMap->GetPDFFont(nOldFontIndex), 507 fFontSize, 0.0f, 100, 508 CPDF_Point(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y), 509 sTextBuf.GetByteString())); 510 511 sTextBuf.Clear(); 512 } 513 514 ptBT = word.ptWord; 515 nOldFontIndex = word.nFontIndex; 516 } 517 518 sTextBuf << GetPDFWordString(pFontMap, word.nFontIndex, word.Word, 0); 519 oldplace = place; 520 } 521 } 522 523 if (sTextBuf.GetLength() > 0) { 524 ObjArray.Add(AddTextObjToPageObjects( 525 pPageObjects, crText, pFontMap->GetPDFFont(nOldFontIndex), 526 fFontSize, 0.0f, 100, 527 CPDF_Point(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y), 528 sTextBuf.GetByteString())); 529 } 530 } 531 } 532 } 533 534 void IFX_Edit::GenerateRichPageObjects( 535 CPDF_PageObjects* pPageObjects, 536 IFX_Edit* pEdit, 537 const CPDF_Point& ptOffset, 538 const CPVT_WordRange* pRange, 539 CFX_ArrayTemplate<CPDF_TextObject*>& ObjArray) { 540 FX_COLORREF crCurText = ArgbEncode(255, 0, 0, 0); 541 FX_COLORREF crOld = crCurText; 542 543 CFX_ByteTextBuf sTextBuf; 544 CPVT_WordProps wp; 545 CPDF_Point ptBT(0.0f, 0.0f); 546 547 ObjArray.RemoveAll(); 548 549 if (IFX_Edit_Iterator* pIterator = pEdit->GetIterator()) { 550 if (IFX_Edit_FontMap* pFontMap = pEdit->GetFontMap()) { 551 if (pRange) 552 pIterator->SetAt(pRange->BeginPos); 553 else 554 pIterator->SetAt(0); 555 556 CPVT_WordPlace oldplace; 557 558 while (pIterator->NextWord()) { 559 CPVT_WordPlace place = pIterator->GetAt(); 560 if (pRange && place.WordCmp(pRange->EndPos) > 0) 561 break; 562 563 CPVT_Word word; 564 if (pIterator->GetWord(word)) { 565 word.WordProps.fFontSize = word.fFontSize; 566 567 crCurText = ArgbEncode(255, word.WordProps.dwWordColor); 568 569 if (place.LineCmp(oldplace) != 0 || 570 word.WordProps.fCharSpace > 0.0f || 571 word.WordProps.nHorzScale != 100 || 572 FXSYS_memcmp(&word.WordProps, &wp, sizeof(CPVT_WordProps)) != 0 || 573 crOld != crCurText) { 574 if (sTextBuf.GetLength() > 0) { 575 ObjArray.Add(AddTextObjToPageObjects( 576 pPageObjects, crOld, pFontMap->GetPDFFont(wp.nFontIndex), 577 wp.fFontSize, wp.fCharSpace, wp.nHorzScale, 578 CPDF_Point(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y), 579 sTextBuf.GetByteString())); 580 581 sTextBuf.Clear(); 582 } 583 584 wp = word.WordProps; 585 ptBT = word.ptWord; 586 crOld = crCurText; 587 } 588 589 sTextBuf << GetPDFWordString(pFontMap, word.WordProps.nFontIndex, 590 word.Word, 0); 591 592 if (word.WordProps.nWordStyle & PVTWORD_STYLE_UNDERLINE) { 593 CPDF_Rect rcUnderline = GetUnderLineRect(word); 594 rcUnderline.left += ptOffset.x; 595 rcUnderline.right += ptOffset.x; 596 rcUnderline.top += ptOffset.y; 597 rcUnderline.bottom += ptOffset.y; 598 599 AddRectToPageObjects(pPageObjects, crCurText, rcUnderline); 600 } 601 602 if (word.WordProps.nWordStyle & PVTWORD_STYLE_CROSSOUT) { 603 CPDF_Rect rcCrossout = GetCrossoutRect(word); 604 rcCrossout.left += ptOffset.x; 605 rcCrossout.right += ptOffset.x; 606 rcCrossout.top += ptOffset.y; 607 rcCrossout.bottom += ptOffset.y; 608 609 AddRectToPageObjects(pPageObjects, crCurText, rcCrossout); 610 } 611 612 oldplace = place; 613 } 614 } 615 616 if (sTextBuf.GetLength() > 0) { 617 ObjArray.Add(AddTextObjToPageObjects( 618 pPageObjects, crOld, pFontMap->GetPDFFont(wp.nFontIndex), 619 wp.fFontSize, wp.fCharSpace, wp.nHorzScale, 620 CPDF_Point(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y), 621 sTextBuf.GetByteString())); 622 } 623 } 624 } 625 } 626 627 void IFX_Edit::GenerateUnderlineObjects(CPDF_PageObjects* pPageObjects, 628 IFX_Edit* pEdit, 629 const CPDF_Point& ptOffset, 630 const CPVT_WordRange* pRange, 631 FX_COLORREF color) { 632 if (IFX_Edit_Iterator* pIterator = pEdit->GetIterator()) { 633 if (pEdit->GetFontMap()) { 634 if (pRange) 635 pIterator->SetAt(pRange->BeginPos); 636 else 637 pIterator->SetAt(0); 638 639 CPVT_WordPlace oldplace; 640 641 while (pIterator->NextWord()) { 642 CPVT_WordPlace place = pIterator->GetAt(); 643 if (pRange && place.WordCmp(pRange->EndPos) > 0) 644 break; 645 646 CPVT_Word word; 647 if (pIterator->GetWord(word)) { 648 CPDF_Rect rcUnderline = GetUnderLineRect(word); 649 rcUnderline.left += ptOffset.x; 650 rcUnderline.right += ptOffset.x; 651 rcUnderline.top += ptOffset.y; 652 rcUnderline.bottom += ptOffset.y; 653 AddRectToPageObjects(pPageObjects, color, rcUnderline); 654 } 655 } 656 } 657 } 658 } 659