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 
GetUnderLineRect(const CPVT_Word & word)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 
GetCrossoutRect(const CPVT_Word & word)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 
DrawTextString(CFX_RenderDevice * pDevice,const CPDF_Point & pt,CPDF_Font * pFont,FX_FLOAT fFontSize,CFX_Matrix * pUser2Device,const CFX_ByteString & str,FX_ARGB crTextFill,FX_ARGB crTextStroke,int32_t nHorzScale)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 
DrawUnderline(CFX_RenderDevice * pDevice,CFX_Matrix * pUser2Device,IFX_Edit * pEdit,FX_COLORREF color,const CPDF_Rect & rcClip,const CPDF_Point & ptOffset,const CPVT_WordRange * pRange)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 
DrawEdit(CFX_RenderDevice * pDevice,CFX_Matrix * pUser2Device,IFX_Edit * pEdit,FX_COLORREF crTextFill,FX_COLORREF crTextStroke,const CPDF_Rect & rcClip,const CPDF_Point & ptOffset,const CPVT_WordRange * pRange,IFX_SystemHandler * pSystemHandler,void * pFFLData)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 
DrawRichEdit(CFX_RenderDevice * pDevice,CFX_Matrix * pUser2Device,IFX_Edit * pEdit,const CPDF_Rect & rcClip,const CPDF_Point & ptOffset,const CPVT_WordRange * pRange)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 
AddRectToPageObjects(CPDF_PageObjects * pPageObjs,FX_COLORREF crFill,const CPDF_Rect & rcFill)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 
AddTextObjToPageObjects(CPDF_PageObjects * pPageObjs,FX_COLORREF crText,CPDF_Font * pFont,FX_FLOAT fFontSize,FX_FLOAT fCharSpace,int32_t nHorzScale,const CPDF_Point & point,const CFX_ByteString & text)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 
GeneratePageObjects(CPDF_PageObjects * pPageObjects,IFX_Edit * pEdit,const CPDF_Point & ptOffset,const CPVT_WordRange * pRange,FX_COLORREF crText,CFX_ArrayTemplate<CPDF_TextObject * > & ObjArray)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 
GenerateRichPageObjects(CPDF_PageObjects * pPageObjects,IFX_Edit * pEdit,const CPDF_Point & ptOffset,const CPVT_WordRange * pRange,CFX_ArrayTemplate<CPDF_TextObject * > & ObjArray)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 
GenerateUnderlineObjects(CPDF_PageObjects * pPageObjects,IFX_Edit * pEdit,const CPDF_Point & ptOffset,const CPVT_WordRange * pRange,FX_COLORREF color)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