Home | History | Annotate | Download | only in fxedit
      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