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