Merge to XFA: Remove typdefs for pointer types in fx_system.h.
[pdfium.git] / xfa / src / fxfa / src / app / xfa_textlayout.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../../foxitlib.h"\r
8 #include "../common/xfa_common.h"\r
9 #include "xfa_textlayout.h"\r
10 #include "xfa_ffapp.h"\r
11 #include "xfa_ffdoc.h"\r
12 #include "xfa_fontmgr.h"\r
13 CXFA_CSSTagProvider::~CXFA_CSSTagProvider()\r
14 {\r
15     FX_POSITION pos = m_Attributes.GetStartPosition();\r
16     while (pos) {\r
17         CFX_WideString* pName = NULL, *pValue = NULL;\r
18         m_Attributes.GetNextAssoc(pos, (void*&)pName, (void*&)pValue);\r
19         if (pName != NULL)      {\r
20             delete pName;\r
21         }\r
22         if (pValue != NULL) {\r
23             delete pValue;\r
24         }\r
25     }\r
26 }\r
27 void CXFA_CSSTagProvider::GetNextAttribute(FX_POSITION &pos, CFX_WideStringC &wsAttr, CFX_WideStringC &wsValue)\r
28 {\r
29     if (pos == NULL) {\r
30         return;\r
31     }\r
32     CFX_WideString *pName       = NULL;\r
33     CFX_WideString *pValue      = NULL;\r
34     m_Attributes.GetNextAssoc(pos, (void*&)pName, (void*&)pValue);\r
35     wsAttr      = *pName;\r
36     wsValue     = *pValue;\r
37 }\r
38 void CXFA_CSSTagProvider::SetAttribute(const CFX_WideString &wsAttr, const CFX_WideString &wsValue)\r
39 {\r
40     CFX_WideString *pName       = FX_NEW CFX_WideString();\r
41     CFX_WideString *pValue      = FX_NEW CFX_WideString();\r
42     *pName      = wsAttr;\r
43     *pValue     = wsValue;\r
44     m_Attributes.SetAt(pName, pValue);\r
45 }\r
46 void CXFA_TextParseContext::SetDecls(const IFDE_CSSDeclaration **ppDeclArray, int32_t iDeclCount)\r
47 {\r
48     if (iDeclCount <= 0 || ppDeclArray == NULL) {\r
49         return;\r
50     }\r
51     m_dwMatchedDecls = iDeclCount;\r
52     int32_t iBytes       = iDeclCount * sizeof(IFDE_CSSDeclaration*);\r
53     m_ppMatchedDecls = (IFDE_CSSDeclaration**)FDE_Alloc(iBytes);\r
54     FX_memcpy(m_ppMatchedDecls, ppDeclArray, iBytes);\r
55 }\r
56 CXFA_TextParser::~CXFA_TextParser()\r
57 {\r
58     if (m_pUASheet != NULL) {\r
59         m_pUASheet->Release();\r
60     }\r
61     if (m_pSelector != NULL)    {\r
62         m_pSelector->Release();\r
63     }\r
64     if (m_pAllocator != NULL)   {\r
65         m_pAllocator->Release();\r
66     }\r
67     FX_POSITION ps = m_mapXMLNodeToParseContext.GetStartPosition();\r
68     while (ps) {\r
69         IFDE_XMLNode *pXMLNode;\r
70         CXFA_TextParseContext *pParseContext;\r
71         m_mapXMLNodeToParseContext.GetNextAssoc(ps, pXMLNode, pParseContext);\r
72         if (pParseContext != NULL) {\r
73             FDE_DeleteWith(CXFA_TextParseContext, m_pAllocator, pParseContext);\r
74         }\r
75     }\r
76     m_mapXMLNodeToParseContext.RemoveAll();\r
77 }\r
78 void CXFA_TextParser::Reset()\r
79 {\r
80     FX_POSITION ps = m_mapXMLNodeToParseContext.GetStartPosition();\r
81     while (ps) {\r
82         IFDE_XMLNode *pXMLNode;\r
83         CXFA_TextParseContext *pParseContext;\r
84         m_mapXMLNodeToParseContext.GetNextAssoc(ps, pXMLNode, pParseContext);\r
85         if (pParseContext != NULL) {\r
86             FDE_DeleteWith(CXFA_TextParseContext, m_pAllocator, pParseContext);\r
87         }\r
88     }\r
89     m_mapXMLNodeToParseContext.RemoveAll();\r
90     if (m_pAllocator != NULL) {\r
91         m_pAllocator->Release();\r
92         m_pAllocator = NULL;\r
93     }\r
94 }\r
95 void CXFA_TextParser::InitCSSData(IXFA_TextProvider *pTextProvider)\r
96 {\r
97     if (pTextProvider == NULL) {\r
98         return;\r
99     }\r
100     if (m_pSelector == NULL) {\r
101         CXFA_FFDoc *pDoc = pTextProvider->GetDocNode();\r
102         IFX_FontMgr *pFontMgr = pDoc->GetApp()->GetFDEFontMgr();\r
103         FXSYS_assert(pFontMgr != NULL);\r
104         m_pSelector = IFDE_CSSStyleSelector::Create();\r
105         m_pSelector->SetFontMgr(pFontMgr);\r
106         FX_FLOAT fFontSize = 10;\r
107         CXFA_Font font = pTextProvider->GetFontNode();\r
108         if (font.IsExistInXML()) {\r
109             fFontSize = font.GetFontSize();\r
110         }\r
111         m_pSelector->SetDefFontSize(fFontSize);\r
112     }\r
113     if (m_pUASheet == NULL) {\r
114         m_pUASheet = LoadDefaultSheetStyle();\r
115         m_pSelector->SetStyleSheet(FDE_CSSSTYLESHEETGROUP_UserAgent, m_pUASheet);\r
116         m_pSelector->UpdateStyleIndex(FDE_CSSMEDIATYPE_ALL);\r
117     }\r
118 }\r
119 IFDE_CSSStyleSheet*     CXFA_TextParser::LoadDefaultSheetStyle()\r
120 {\r
121     static const FX_WCHAR s_pStyle[] =\r
122             L"html,body,ol,p,ul{display:block}"\r
123             L"li{display:list-item}"\r
124             L"ol,ul{padding-left:33px}ol{list-style-type:decimal}ol,ul{margin-top:0;margin-bottom:0}ul,ol{margin:1.12em 0}"\r
125             L"a{color:#0000ff;text-decoration:underline}b{font-weight:bolder}i{font-style:italic}"\r
126             L"sup{vertical-align:+15em;font-size:.66em}sub{vertical-align:-15em;font-size:.66em}";\r
127     return IFDE_CSSStyleSheet::LoadFromBuffer(CFX_WideString(), s_pStyle, FXSYS_wcslen(s_pStyle), FX_CODEPAGE_UTF8);\r
128 }\r
129 IFDE_CSSComputedStyle* CXFA_TextParser::CreateRootStyle(IXFA_TextProvider *pTextProvider)\r
130 {\r
131     CXFA_Font font = pTextProvider->GetFontNode();\r
132     CXFA_Para para = pTextProvider->GetParaNode();\r
133     IFDE_CSSComputedStyle *pStyle = m_pSelector->CreateComputedStyle(NULL);\r
134     IFDE_CSSFontStyle *pFontStyle = pStyle->GetFontStyles();\r
135     IFDE_CSSParagraphStyle *pParaStyle = pStyle->GetParagraphStyles();\r
136     FX_FLOAT fLineHeight = 0, fFontSize = 10;\r
137     if (para.IsExistInXML()) {\r
138         fLineHeight = para.GetLineHeight();\r
139         FDE_CSSLENGTH indent;\r
140         indent.Set(FDE_CSSLENGTHUNIT_Point, para.GetTextIndent());\r
141         pParaStyle->SetTextIndent(indent);\r
142         FDE_CSSTEXTALIGN hAlgin = FDE_CSSTEXTALIGN_Left;\r
143         switch (para.GetHorizontalAlign()) {\r
144             case XFA_ATTRIBUTEENUM_Center:\r
145                 hAlgin = FDE_CSSTEXTALIGN_Center;\r
146                 break;\r
147             case XFA_ATTRIBUTEENUM_Right:\r
148                 hAlgin = FDE_CSSTEXTALIGN_Right;\r
149                 break;\r
150             case XFA_ATTRIBUTEENUM_Justify:\r
151                 hAlgin = FDE_CSSTEXTALIGN_Justify;\r
152                 break;\r
153             case XFA_ATTRIBUTEENUM_JustifyAll:\r
154                 hAlgin = FDE_CSSTEXTALIGN_JustifyAll;\r
155                 break;\r
156         }\r
157         pParaStyle->SetTextAlign(hAlgin);\r
158         FDE_CSSRECT rtMarginWidth;\r
159         rtMarginWidth.left.Set(FDE_CSSLENGTHUNIT_Point, para.GetMarginLeft());\r
160         rtMarginWidth.top.Set(FDE_CSSLENGTHUNIT_Point, para.GetSpaceAbove());\r
161         rtMarginWidth.right.Set(FDE_CSSLENGTHUNIT_Point, para.GetMarginRight());\r
162         rtMarginWidth.bottom.Set(FDE_CSSLENGTHUNIT_Point, para.GetSpaceBelow());\r
163         pStyle->GetBoundaryStyles()->SetMarginWidth(rtMarginWidth);\r
164     }\r
165     if (font.IsExistInXML()) {\r
166         pFontStyle->SetColor(font.GetColor());\r
167         pFontStyle->SetFontStyle(font.IsItalic() ? FDE_CSSFONTSTYLE_Italic : FDE_CSSFONTSTYLE_Normal);\r
168         pFontStyle->SetFontWeight(font.IsBold() ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL);\r
169         pParaStyle->SetNumberVerticalAlign(-font.GetBaselineShift());\r
170         fFontSize = font.GetFontSize();\r
171         FDE_CSSLENGTH letterSpacing;\r
172         letterSpacing.Set(FDE_CSSLENGTHUNIT_Point, font.GetLetterSpacing());\r
173         pParaStyle->SetLetterSpacing(letterSpacing);\r
174         FX_DWORD dwDecoration = 0;\r
175         if (font.GetLineThrough() > 0)  {\r
176             dwDecoration |= FDE_CSSTEXTDECORATION_LineThrough;\r
177         }\r
178         if (font.GetUnderline() > 1) {\r
179             dwDecoration |= FDE_CSSTEXTDECORATION_Double;\r
180         } else if (font.GetUnderline() > 0) {\r
181             dwDecoration |= FDE_CSSTEXTDECORATION_Underline;\r
182         }\r
183         pParaStyle->SetTextDecoration(dwDecoration);\r
184     }\r
185     pParaStyle->SetLineHeight(fLineHeight);\r
186     pFontStyle->SetFontSize(fFontSize);\r
187     return pStyle;\r
188 }\r
189 IFDE_CSSComputedStyle* CXFA_TextParser::CreateStyle(IFDE_CSSComputedStyle *pParentStyle)\r
190 {\r
191     IFDE_CSSComputedStyle *pNewStyle = m_pSelector->CreateComputedStyle(pParentStyle);\r
192     FXSYS_assert(pNewStyle != NULL);\r
193     if (pParentStyle) {\r
194         IFDE_CSSParagraphStyle *pParaStyle = pParentStyle->GetParagraphStyles();\r
195         FX_DWORD dwDecoration = pParaStyle->GetTextDecoration();\r
196         FX_FLOAT fBaseLine = 0;\r
197         if (pParaStyle->GetVerticalAlign() == FDE_CSSVERTICALALIGN_Number) {\r
198             fBaseLine = pParaStyle->GetNumberVerticalAlign();\r
199         }\r
200         pParaStyle = pNewStyle->GetParagraphStyles();\r
201         pParaStyle->SetTextDecoration(dwDecoration);\r
202         pParaStyle->SetNumberVerticalAlign(fBaseLine);\r
203         IFDE_CSSBoundaryStyle *pBoundarytyle = pParentStyle->GetBoundaryStyles();\r
204         const FDE_CSSRECT *pRect = pBoundarytyle->GetMarginWidth();\r
205         if (pRect != NULL) {\r
206             pBoundarytyle = pNewStyle->GetBoundaryStyles();\r
207             pBoundarytyle->SetMarginWidth(*pRect);\r
208         }\r
209     }\r
210     return pNewStyle;\r
211 }\r
212 IFDE_CSSComputedStyle* CXFA_TextParser::ComputeStyle(IFDE_XMLNode *pXMLNode, IFDE_CSSComputedStyle *pParentStyle)\r
213 {\r
214     CXFA_TextParseContext *pContext = (CXFA_TextParseContext*)m_mapXMLNodeToParseContext.GetValueAt(pXMLNode);\r
215     if (pContext == NULL) {\r
216         return NULL;\r
217     }\r
218     pContext->m_pParentStyle = pParentStyle;\r
219     CXFA_CSSTagProvider tagProvider;\r
220     ParseTagInfo(pXMLNode, tagProvider);\r
221     if (tagProvider.m_bContent) {\r
222         return NULL;\r
223     }\r
224     IFDE_CSSComputedStyle *pStyle       = CreateStyle(pParentStyle);\r
225     IFDE_CSSAccelerator *pCSSAccel      = m_pSelector->InitAccelerator();\r
226     pCSSAccel->OnEnterTag(&tagProvider);\r
227     m_pSelector->ComputeStyle(&tagProvider, pContext->GetDecls(), pContext->CountDecls(), pStyle);\r
228     pCSSAccel->OnLeaveTag(&tagProvider);\r
229     return pStyle;\r
230 }\r
231 void CXFA_TextParser::DoParse(IFDE_XMLNode *pXMLContainer, IXFA_TextProvider *pTextProvider)\r
232 {\r
233     if (pXMLContainer == NULL || pTextProvider == NULL || m_pAllocator != NULL) {\r
234         return;\r
235     }\r
236     m_pAllocator = FX_CreateAllocator(FX_ALLOCTYPE_Fixed, 32, sizeof(CXFA_CSSTagProvider));\r
237     InitCSSData(pTextProvider);\r
238     IFDE_CSSComputedStyle *pRootStyle = CreateRootStyle(pTextProvider);\r
239     ParseRichText(pXMLContainer, pRootStyle);\r
240     pRootStyle->Release();\r
241 }\r
242 void CXFA_TextParser::ParseRichText(IFDE_XMLNode *pXMLNode, IFDE_CSSComputedStyle *pParentStyle)\r
243 {\r
244     if (pXMLNode == NULL) {\r
245         return;\r
246     }\r
247     CXFA_CSSTagProvider tagProvider;\r
248     ParseTagInfo(pXMLNode, tagProvider);\r
249     if (!tagProvider.m_bTagAviliable) {\r
250         return;\r
251     }\r
252     IFDE_CSSComputedStyle *pNewStyle = NULL;\r
253     if ((tagProvider.GetTagName() != FX_WSTRC(L"body")) || (tagProvider.GetTagName() != FX_WSTRC(L"html")) ) {\r
254         CXFA_TextParseContext *pTextContext = FDE_NewWith(m_pAllocator)CXFA_TextParseContext;\r
255         FDE_CSSDISPLAY eDisplay = FDE_CSSDISPLAY_Inline;\r
256         if (!tagProvider.m_bContent) {\r
257             pNewStyle = CreateStyle(pParentStyle);\r
258             IFDE_CSSAccelerator *pCSSAccel = m_pSelector->InitAccelerator();\r
259             pCSSAccel->OnEnterTag(&tagProvider);\r
260             CFDE_CSSDeclarationArray DeclArray;\r
261             int32_t iMatchedDecls = m_pSelector->MatchDeclarations(&tagProvider, DeclArray);\r
262             const IFDE_CSSDeclaration **ppMatchDecls = (const IFDE_CSSDeclaration **)DeclArray.GetData();\r
263             m_pSelector->ComputeStyle(&tagProvider, ppMatchDecls, iMatchedDecls, pNewStyle);\r
264             pCSSAccel->OnLeaveTag(&tagProvider);\r
265             if (iMatchedDecls > 0) {\r
266                 pTextContext->SetDecls(ppMatchDecls, iMatchedDecls);\r
267             }\r
268             eDisplay = pNewStyle->GetPositionStyles()->GetDisplay();\r
269         }\r
270         pTextContext->SetDisplay(eDisplay);\r
271         m_mapXMLNodeToParseContext.SetAt(pXMLNode, pTextContext);\r
272     }\r
273     for(IFDE_XMLNode *pXMLChild = pXMLNode->GetNodeItem(IFDE_XMLNode::FirstChild); pXMLChild; pXMLChild = pXMLChild->GetNodeItem(IFDE_XMLNode::NextSibling)) {\r
274         ParseRichText(pXMLChild, pNewStyle);\r
275     }\r
276     if (pNewStyle != NULL) {\r
277         pNewStyle->Release();\r
278     }\r
279 }\r
280 void CXFA_TextParser::ParseTagInfo(IFDE_XMLNode *pXMLNode, CXFA_CSSTagProvider &tagProvider)\r
281 {\r
282     static const FX_DWORD s_XFATagName[] = {\r
283         0x61,\r
284         0x62,\r
285         0x69,\r
286         0x70,\r
287         0x0001f714,\r
288         0x00022a55,\r
289         0x000239bb,\r
290         0x00025881,\r
291         0x0bd37faa,\r
292         0x0bd37fb8,\r
293         0xa73e3af2,\r
294         0xb182eaae,\r
295         0xdb8ac455,\r
296     };\r
297     CFX_WideString wsName;\r
298     if (pXMLNode->GetType() == FDE_XMLNODE_Element) {\r
299         IFDE_XMLElement *pXMLElement = (IFDE_XMLElement *)pXMLNode;\r
300         pXMLElement->GetLocalTagName(wsName);\r
301         tagProvider.SetTagNameObj(wsName);\r
302         FX_DWORD dwHashCode = FX_HashCode_String_GetW(wsName, wsName.GetLength(), TRUE);\r
303         static const int32_t s_iCount = sizeof(s_XFATagName) / sizeof(FX_DWORD);\r
304         CFX_DSPATemplate<FX_DWORD> lookup;\r
305         tagProvider.m_bTagAviliable = lookup.Lookup(dwHashCode, s_XFATagName, s_iCount) > -1;\r
306         CFX_WideString wsValue;\r
307         pXMLElement->GetString(FX_WSTRC(L"style").GetPtr(), wsValue);\r
308         if (!wsValue.IsEmpty()) {\r
309             tagProvider.SetAttribute(FX_WSTRC(L"style"), wsValue);\r
310         }\r
311     } else if (pXMLNode->GetType() == FDE_XMLNODE_Text) {\r
312         tagProvider.m_bTagAviliable = TRUE;\r
313         tagProvider.m_bContent = TRUE;\r
314     }\r
315 }\r
316 int32_t CXFA_TextParser::GetVAlgin(IXFA_TextProvider *pTextProvider) const\r
317 {\r
318     int32_t iAlign = XFA_ATTRIBUTEENUM_Top;\r
319     CXFA_Para para = pTextProvider->GetParaNode();\r
320     if (para.IsExistInXML()) {\r
321         iAlign = para.GetVerticalAlign();\r
322     }\r
323     return iAlign;\r
324 }\r
325 FX_FLOAT CXFA_TextParser::GetTabInterval(IFDE_CSSComputedStyle *pStyle) const\r
326 {\r
327     CFX_WideString wsValue;\r
328     if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"tab-interval"), wsValue)) {\r
329         CXFA_Measurement ms(wsValue);\r
330         return ms.ToUnit(XFA_UNIT_Pt);\r
331     }\r
332     return 36;\r
333 }\r
334 int32_t CXFA_TextParser::CountTabs(IFDE_CSSComputedStyle *pStyle) const\r
335 {\r
336     CFX_WideString wsValue;\r
337     if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"xfa-tab-count"), wsValue)) {\r
338         return wsValue.GetInteger();\r
339     }\r
340     return 0;\r
341 }\r
342 FX_BOOL CXFA_TextParser::IsSpaceRun(IFDE_CSSComputedStyle *pStyle) const\r
343 {\r
344     CFX_WideString wsValue;\r
345     if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"xfa-spacerun"), wsValue)) {\r
346         wsValue.MakeLower();\r
347         return wsValue == FX_WSTRC(L"yes");\r
348     }\r
349     return FALSE;\r
350 }\r
351 IFX_Font* CXFA_TextParser::GetFont(IXFA_TextProvider *pTextProvider, IFDE_CSSComputedStyle *pStyle) const\r
352 {\r
353     CFX_WideStringC wsFamily = FX_WSTRC(L"Courier");\r
354     FX_DWORD dwStyle = 0;\r
355     CXFA_Font font = pTextProvider->GetFontNode();\r
356     if (font.IsExistInXML()) {\r
357         font.GetTypeface(wsFamily);\r
358         if (font.IsBold()) {\r
359             dwStyle |= FX_FONTSTYLE_Bold;\r
360         }\r
361         if (font.IsItalic()) {\r
362             dwStyle |= FX_FONTSTYLE_Italic;\r
363         }\r
364     }\r
365     if (pStyle) {\r
366         IFDE_CSSFontStyle *pFontStyle = pStyle->GetFontStyles();\r
367         int32_t iCount = pFontStyle->CountFontFamilies();\r
368         if (iCount > 0) {\r
369             wsFamily = pFontStyle->GetFontFamily(iCount - 1);\r
370         }\r
371         dwStyle = 0;\r
372         if (pFontStyle->GetFontWeight() > FXFONT_FW_NORMAL) {\r
373             dwStyle |= FX_FONTSTYLE_Bold;\r
374         }\r
375         if (pFontStyle->GetFontStyle() == FDE_CSSFONTSTYLE_Italic)      {\r
376             dwStyle |= FX_FONTSTYLE_Italic;\r
377         }\r
378     }\r
379     CXFA_FFDoc *pDoc = pTextProvider->GetDocNode();\r
380     FXSYS_assert(pDoc != NULL);\r
381     CXFA_FontMgr *pFontMgr = pDoc->GetApp()->GetXFAFontMgr();\r
382     return pFontMgr->GetFont(pDoc, wsFamily, dwStyle);\r
383 }\r
384 FX_FLOAT CXFA_TextParser::GetFontSize(IXFA_TextProvider *pTextProvider, IFDE_CSSComputedStyle *pStyle) const\r
385 {\r
386     if (pStyle != NULL) {\r
387         return pStyle->GetFontStyles()->GetFontSize();\r
388     }\r
389     CXFA_Font font = pTextProvider->GetFontNode();\r
390     if (font.IsExistInXML()) {\r
391         return font.GetFontSize();\r
392     }\r
393     return 10;\r
394 }\r
395 int32_t CXFA_TextParser::GetHorScale(IXFA_TextProvider *pTextProvider, IFDE_CSSComputedStyle *pStyle, IFDE_XMLNode *pXMLNode) const\r
396 {\r
397     if (pStyle != NULL) {\r
398         CFX_WideString wsValue;\r
399         if (pStyle->GetCustomStyle(FX_WSTRC(L"xfa-font-horizontal-scale"), wsValue)) {\r
400             return wsValue.GetInteger();\r
401         }\r
402         while (pXMLNode) {\r
403             CXFA_TextParseContext *pContext = (CXFA_TextParseContext*)m_mapXMLNodeToParseContext.GetValueAt(pXMLNode);\r
404             if (pContext && pContext->m_pParentStyle && pContext->m_pParentStyle->GetCustomStyle(FX_WSTRC(L"xfa-font-horizontal-scale"), wsValue)) {\r
405                 return wsValue.GetInteger();\r
406             }\r
407             pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::Parent);\r
408         }\r
409     }\r
410     if (CXFA_Font font = pTextProvider->GetFontNode()) {\r
411         return (int32_t)font.GetHorizontalScale();\r
412     }\r
413     return 100;\r
414 }\r
415 int32_t CXFA_TextParser::GetVerScale(IXFA_TextProvider *pTextProvider, IFDE_CSSComputedStyle *pStyle) const\r
416 {\r
417     if (pStyle != NULL) {\r
418         CFX_WideString wsValue;\r
419         if (pStyle->GetCustomStyle(FX_WSTRC(L"xfa-font-vertical-scale"), wsValue)) {\r
420             return wsValue.GetInteger();\r
421         }\r
422     }\r
423     if (CXFA_Font font = pTextProvider->GetFontNode()) {\r
424         return (int32_t)font.GetVerticalScale();\r
425     }\r
426     return 100;\r
427 }\r
428 void CXFA_TextParser::GetUnderline(IXFA_TextProvider *pTextProvider, IFDE_CSSComputedStyle *pStyle, int32_t &iUnderline, int32_t &iPeriod) const\r
429 {\r
430     iUnderline = 0;\r
431     iPeriod = XFA_ATTRIBUTEENUM_All;\r
432     if (pStyle) {\r
433         FX_DWORD dwDecoration = pStyle->GetParagraphStyles()->GetTextDecoration();\r
434         if (dwDecoration & FDE_CSSTEXTDECORATION_Double) {\r
435             iUnderline = 2;\r
436         } else if (dwDecoration & FDE_CSSTEXTDECORATION_Underline) {\r
437             iUnderline = 1;\r
438         }\r
439         CFX_WideString wsValue;\r
440         if (pStyle->GetCustomStyle(FX_WSTRC(L"underlinePeriod"), wsValue)) {\r
441             if (wsValue == FX_WSTRC(L"word")) {\r
442                 iPeriod = XFA_ATTRIBUTEENUM_Word;\r
443             }\r
444         } else if (CXFA_Font font = pTextProvider->GetFontNode()) {\r
445             iPeriod = font.GetUnderlinePeriod();\r
446         }\r
447     } else {\r
448         CXFA_Font font = pTextProvider->GetFontNode();\r
449         if (font.IsExistInXML()) {\r
450             iUnderline = font.GetUnderline();\r
451             iPeriod = font.GetUnderlinePeriod();\r
452         }\r
453     }\r
454 }\r
455 void CXFA_TextParser::GetLinethrough(IXFA_TextProvider *pTextProvider, IFDE_CSSComputedStyle *pStyle, int32_t &iLinethrough) const\r
456 {\r
457     if (pStyle) {\r
458         FX_DWORD dwDecoration = pStyle->GetParagraphStyles()->GetTextDecoration();\r
459         iLinethrough = (dwDecoration & FDE_CSSTEXTDECORATION_LineThrough) ? 1 : 0;\r
460     } else {\r
461         CXFA_Font font = pTextProvider->GetFontNode();\r
462         if (font.IsExistInXML()) {\r
463             iLinethrough = font.GetLineThrough();\r
464         }\r
465     }\r
466 }\r
467 FX_ARGB CXFA_TextParser::GetColor(IXFA_TextProvider *pTextProvider, IFDE_CSSComputedStyle *pStyle) const\r
468 {\r
469     if (pStyle != NULL) {\r
470         return pStyle->GetFontStyles()->GetColor();\r
471     }\r
472     if (CXFA_Font font = pTextProvider->GetFontNode()) {\r
473         return font.GetColor();\r
474     }\r
475     return 0xFF000000;\r
476 }\r
477 FX_FLOAT CXFA_TextParser::GetBaseline(IXFA_TextProvider *pTextProvider, IFDE_CSSComputedStyle *pStyle) const\r
478 {\r
479     if (pStyle != NULL) {\r
480         IFDE_CSSParagraphStyle *pParaStyle = pStyle->GetParagraphStyles();\r
481         if (pParaStyle->GetVerticalAlign() == FDE_CSSVERTICALALIGN_Number) {\r
482             return pParaStyle->GetNumberVerticalAlign();\r
483         }\r
484     } else if (CXFA_Font font = pTextProvider->GetFontNode()) {\r
485         return font.GetBaselineShift();\r
486     }\r
487     return 0;\r
488 }\r
489 FX_FLOAT CXFA_TextParser::GetLineHeight(IXFA_TextProvider *pTextProvider, IFDE_CSSComputedStyle *pStyle, FX_BOOL bFirst, FX_FLOAT fVerScale) const\r
490 {\r
491     FX_FLOAT fLineHeight = 0;\r
492     if (pStyle != NULL) {\r
493         fLineHeight = pStyle->GetParagraphStyles()->GetLineHeight();\r
494     } else if (CXFA_Para para = pTextProvider->GetParaNode()) {\r
495         fLineHeight = para.GetLineHeight();\r
496     }\r
497     if (bFirst) {\r
498         FX_FLOAT fFontSize = GetFontSize(pTextProvider, pStyle);\r
499         if (fLineHeight < 0.1f) {\r
500             fLineHeight = fFontSize;\r
501         } else {\r
502             fLineHeight = FX_MIN(fLineHeight, fFontSize);\r
503         }\r
504     } else if (fLineHeight < 0.1f) {\r
505         fLineHeight = GetFontSize(pTextProvider, pStyle) * 1.2f;\r
506     }\r
507     fLineHeight *= fVerScale;\r
508     return fLineHeight;\r
509 }\r
510 FX_BOOL CXFA_TextParser::GetEmbbedObj(IXFA_TextProvider *pTextProvider, IFDE_XMLNode *pXMLNode, CFX_WideString &wsValue)\r
511 {\r
512     wsValue.Empty();\r
513     if (pXMLNode == NULL) {\r
514         return FALSE;\r
515     }\r
516     FX_BOOL bRet = FALSE;\r
517     if (pXMLNode->GetType() == FDE_XMLNODE_Element) {\r
518         IFDE_XMLElement* pElement = (IFDE_XMLElement *)pXMLNode;\r
519         CFX_WideString wsAttr;\r
520         pElement->GetString(FX_WSTRC(L"xfa:embed").GetPtr(), wsAttr);\r
521         if (wsAttr.IsEmpty()) {\r
522             return FALSE;\r
523         }\r
524         if (wsAttr.GetAt(0) == L'#') {\r
525             wsAttr.Delete(0);\r
526         }\r
527         CFX_WideString ws;\r
528         pElement->GetString(FX_WSTRC(L"xfa:embedType").GetPtr(), ws);\r
529         if (ws.IsEmpty()) {\r
530             ws = L"som";\r
531         } else {\r
532             ws.MakeLower();\r
533         }\r
534         FX_BOOL bURI = (ws == FX_WSTRC(L"uri"));\r
535         if (!bURI && ws != FX_WSTRC(L"som")) {\r
536             return FALSE;\r
537         }\r
538         ws.Empty();\r
539         pElement->GetString(FX_WSTRC(L"xfa:embedMode").GetPtr(), ws);\r
540         if (ws.IsEmpty()) {\r
541             ws = L"formatted";\r
542         } else {\r
543             ws.MakeLower();\r
544         }\r
545         FX_BOOL bRaw = (ws == FX_WSTRC(L"raw"));\r
546         if (!bRaw && ws != FX_WSTRC(L"formatted")) {\r
547             return FALSE;\r
548         }\r
549         bRet = pTextProvider->GetEmbbedObj(bURI, bRaw, wsAttr, wsValue);\r
550     }\r
551     return bRet;\r
552 }\r
553 CXFA_TextParseContext* CXFA_TextParser::GetParseContextFromMap(IFDE_XMLNode *pXMLNode)\r
554 {\r
555     return (CXFA_TextParseContext*)m_mapXMLNodeToParseContext.GetValueAt(pXMLNode);\r
556 }\r
557 enum XFA_TABSTOPSSTATUS {\r
558     XFA_TABSTOPSSTATUS_Error,\r
559     XFA_TABSTOPSSTATUS_EOS,\r
560     XFA_TABSTOPSSTATUS_None,\r
561     XFA_TABSTOPSSTATUS_Alignment,\r
562     XFA_TABSTOPSSTATUS_StartLeader,\r
563     XFA_TABSTOPSSTATUS_Leader,\r
564     XFA_TABSTOPSSTATUS_Location,\r
565 };\r
566 FX_BOOL CXFA_TextParser::GetTabstops(IFDE_CSSComputedStyle *pStyle, CXFA_TextTabstopsContext *pTabstopContext)\r
567 {\r
568     if (pStyle == NULL || pTabstopContext == NULL) {\r
569         return FALSE;\r
570     }\r
571     CFX_WideString wsValue;\r
572     if (!pStyle->GetCustomStyle(FX_WSTRC(L"xfa-tab-stops"), wsValue)\r
573             && !pStyle->GetCustomStyle(FX_WSTRC(L"tab-stops"), wsValue)) {\r
574         return FALSE;\r
575     }\r
576     int32_t iLength = wsValue.GetLength();\r
577     const FX_WCHAR* pTabStops = wsValue;\r
578     int32_t iCur = 0;\r
579     int32_t iLast = 0;\r
580     CFX_WideString wsAlign;\r
581     XFA_TABSTOPSSTATUS eStatus = XFA_TABSTOPSSTATUS_None;\r
582     FX_WCHAR ch;\r
583     while (iCur < iLength) {\r
584         ch = pTabStops[iCur];\r
585         switch (eStatus) {\r
586             case XFA_TABSTOPSSTATUS_None:\r
587                 if (ch <= ' ') {\r
588                     iCur++;\r
589                 } else {\r
590                     eStatus = XFA_TABSTOPSSTATUS_Alignment;\r
591                     iLast = iCur;\r
592                 }\r
593                 break;\r
594             case XFA_TABSTOPSSTATUS_Alignment:\r
595                 if (ch == ' ') {\r
596                     wsAlign = CFX_WideStringC(pTabStops + iLast, iCur - iLast);\r
597                     eStatus = XFA_TABSTOPSSTATUS_StartLeader;\r
598                     iCur++;\r
599                     while (iCur < iLength && pTabStops[iCur] <= ' ') {\r
600                         iCur++;\r
601                     }\r
602                     iLast = iCur;\r
603                 } else {\r
604                     iCur++;\r
605                 }\r
606                 break;\r
607             case XFA_TABSTOPSSTATUS_StartLeader:\r
608                 if (ch != 'l') {\r
609                     eStatus = XFA_TABSTOPSSTATUS_Location;\r
610                 } else {\r
611                     int32_t iCount = 0;\r
612                     while (iCur < iLength) {\r
613                         ch = pTabStops[iCur];\r
614                         iCur++;\r
615                         if (ch == '(') {\r
616                             iCount++;\r
617                         } else if (ch == ')') {\r
618                             iCount--;\r
619                             if (iCount == 0) {\r
620                                 break;\r
621                             }\r
622                         }\r
623                     }\r
624                     while (iCur < iLength && pTabStops[iCur] <= ' ') {\r
625                         iCur++;\r
626                     }\r
627                     iLast = iCur;\r
628                     eStatus = XFA_TABSTOPSSTATUS_Location;\r
629                 }\r
630                 break;\r
631             case XFA_TABSTOPSSTATUS_Location:\r
632                 if (ch == ' ') {\r
633                     FX_DWORD dwHashCode = FX_HashCode_String_GetW(wsAlign, wsAlign.GetLength(), TRUE);\r
634                     CXFA_Measurement ms(CFX_WideStringC(pTabStops + iLast, iCur - iLast));\r
635                     FX_FLOAT fPos = ms.ToUnit(XFA_UNIT_Pt);\r
636                     pTabstopContext->Append(dwHashCode, fPos);\r
637                     wsAlign.Empty();\r
638                     eStatus = XFA_TABSTOPSSTATUS_None;\r
639                 }\r
640                 iCur++;\r
641                 break;\r
642             default:\r
643                 break;\r
644         }\r
645     }\r
646     if (!wsAlign.IsEmpty()) {\r
647         FX_DWORD dwHashCode = FX_HashCode_String_GetW(wsAlign, wsAlign.GetLength(), TRUE);\r
648         CXFA_Measurement ms(CFX_WideStringC(pTabStops + iLast, iCur - iLast));\r
649         FX_FLOAT fPos = ms.ToUnit(XFA_UNIT_Pt);\r
650         pTabstopContext->Append(dwHashCode, fPos);\r
651     }\r
652     return TRUE;\r
653 }\r
654 CXFA_TextLayout::CXFA_TextLayout(IXFA_TextProvider *pTextProvider)\r
655     : m_pTextProvider(pTextProvider)\r
656     , m_pTextDataNode(NULL)\r
657     , m_pAllocator(NULL)\r
658     , m_pBreak(NULL)\r
659     , m_dwTextData(0)\r
660     , m_pLoader(NULL)\r
661     , m_iLines(0)\r
662     , m_fMaxWidth(0)\r
663     , m_pTabstopContext(NULL)\r
664     , m_bBlockContinue(TRUE)\r
665     , m_bRichText(FALSE)\r
666     , m_bHasBlock(FALSE)\r
667 {\r
668     FXSYS_assert(m_pTextProvider != NULL);\r
669 }\r
670 CXFA_TextLayout::~CXFA_TextLayout()\r
671 {\r
672     m_textParser.Reset();\r
673     if (m_pLoader != NULL) {\r
674         delete m_pLoader;\r
675     }\r
676     if (m_pTabstopContext != NULL)      {\r
677         delete m_pTabstopContext;\r
678     }\r
679     Unload();\r
680 }\r
681 void CXFA_TextLayout::Unload()\r
682 {\r
683     int32_t iCount = m_pieceLines.GetSize();\r
684     for (int32_t i = 0; i < iCount; i++) {\r
685         CXFA_PieceLine *pLine = m_pieceLines.GetAt(i);\r
686         FDE_DeleteWith(CXFA_PieceLine, m_pAllocator, pLine);\r
687     }\r
688     m_pieceLines.RemoveAll();\r
689     if (m_pBreak != NULL) {\r
690         m_pBreak->Release();\r
691         m_pBreak = NULL;\r
692     }\r
693     if (m_pAllocator != NULL) {\r
694         m_pAllocator->Release();\r
695         m_pAllocator = NULL;\r
696     }\r
697 }\r
698 const CXFA_PieceLineArray* CXFA_TextLayout::GetPieceLines()\r
699 {\r
700     return &m_pieceLines;\r
701 }\r
702 void CXFA_TextLayout::GetTextDataNode()\r
703 {\r
704     if (m_pTextProvider == NULL) {\r
705         return;\r
706     }\r
707     CXFA_Node *pNode = m_pTextProvider->GetTextNode(m_bRichText);\r
708     if (pNode && m_bRichText) {\r
709         m_textParser.Reset();\r
710     }\r
711     m_pTextDataNode = pNode;\r
712 }\r
713 IFDE_XMLNode* CXFA_TextLayout::GetXMLContainerNode()\r
714 {\r
715     IFDE_XMLNode* pXMLContainer = NULL;\r
716     if (m_bRichText) {\r
717         IFDE_XMLNode *pXMLRoot = m_pTextDataNode->GetXMLMappingNode();\r
718         if (!pXMLRoot) {\r
719             return pXMLContainer;\r
720         }\r
721         for (IFDE_XMLNode *pXMLChild = pXMLRoot->GetNodeItem(IFDE_XMLNode::FirstChild); pXMLChild; pXMLChild = pXMLChild->GetNodeItem(IFDE_XMLNode::NextSibling)) {\r
722             if (pXMLChild->GetType() == FDE_XMLNODE_Element) {\r
723                 IFDE_XMLElement *pXMLElement = (IFDE_XMLElement*)pXMLChild;\r
724                 CFX_WideString wsTag;\r
725                 pXMLElement->GetLocalTagName(wsTag);\r
726                 if (wsTag.Equal(FX_WSTRC(L"body")) || wsTag.Equal(FX_WSTRC(L"html"))) {\r
727                     pXMLContainer = pXMLChild;\r
728                     break;\r
729                 }\r
730             }\r
731         }\r
732     }\r
733     return pXMLContainer;\r
734 }\r
735 IFX_RTFBreak* CXFA_TextLayout::CreateBreak(FX_BOOL bDefault)\r
736 {\r
737     FX_DWORD dwStyle = FX_RTFLAYOUTSTYLE_ExpandTab;\r
738     if (!bDefault) {\r
739         dwStyle |= FX_RTFLAYOUTSTYLE_Pagination;\r
740     }\r
741     IFX_RTFBreak *pBreak = IFX_RTFBreak::Create(0);\r
742     pBreak->SetLayoutStyles(dwStyle);\r
743     pBreak->SetLineBreakChar(L'\n');\r
744     pBreak->SetLineBreakTolerance(1);\r
745     pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, NULL));\r
746     pBreak->SetFontSize(m_textParser.GetFontSize(m_pTextProvider, NULL));\r
747     return pBreak;\r
748 }\r
749 void CXFA_TextLayout::InitBreak(FX_FLOAT fLineWidth)\r
750 {\r
751     CXFA_Font font = m_pTextProvider->GetFontNode();\r
752     CXFA_Para para = m_pTextProvider->GetParaNode();\r
753     FX_FLOAT fStart = 0;\r
754     FX_FLOAT fStartPos = 0;\r
755     if (para.IsExistInXML()) {\r
756         int32_t iAlign = FX_RTFLINEALIGNMENT_Left;\r
757         switch (para.GetHorizontalAlign()) {\r
758             case XFA_ATTRIBUTEENUM_Center:\r
759                 iAlign = FX_RTFLINEALIGNMENT_Center;\r
760                 break;\r
761             case XFA_ATTRIBUTEENUM_Right:\r
762                 iAlign = FX_RTFLINEALIGNMENT_Right;\r
763                 break;\r
764             case XFA_ATTRIBUTEENUM_Justify:\r
765                 iAlign = FX_RTFLINEALIGNMENT_Justified;\r
766                 break;\r
767             case XFA_ATTRIBUTEENUM_JustifyAll:\r
768                 iAlign = FX_RTFLINEALIGNMENT_Distributed;\r
769                 break;\r
770         }\r
771         m_pBreak->SetAlignment(iAlign);\r
772         fStart = para.GetMarginLeft();\r
773         if (m_pTextProvider->IsCheckButtonAndAutoWidth()) {\r
774             if (iAlign != FX_RTFLINEALIGNMENT_Left) {\r
775                 fLineWidth -= para.GetMarginRight();\r
776             }\r
777         } else {\r
778             fLineWidth -= para.GetMarginRight();\r
779         }\r
780         if (fLineWidth < 0) {\r
781             fLineWidth = fStart;\r
782         }\r
783         fStartPos = fStart;\r
784         FX_FLOAT fIndent = para.GetTextIndent();\r
785         if (fIndent > 0) {\r
786             fStartPos += fIndent;\r
787         }\r
788     }\r
789     m_pBreak->SetLineWidth(fStart, fLineWidth);\r
790     m_pBreak->SetLinePos(fStartPos);\r
791     if (font.IsExistInXML()) {\r
792         m_pBreak->SetHorizontalScale((int32_t)font.GetHorizontalScale());\r
793         m_pBreak->SetVerticalScale((int32_t)font.GetVerticalScale());\r
794         m_pBreak->SetCharSpace(font.GetLetterSpacing());\r
795     }\r
796     FX_FLOAT fFontSize = m_textParser.GetFontSize(m_pTextProvider, NULL);\r
797     m_pBreak->SetFontSize(fFontSize);\r
798     m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, NULL));\r
799     m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);\r
800 }\r
801 void CXFA_TextLayout::InitBreak(IFDE_CSSComputedStyle *pStyle, FDE_CSSDISPLAY eDisplay, FX_FLOAT fLineWidth, IFDE_XMLNode *pXMLNode, IFDE_CSSComputedStyle *pParentStyle)\r
802 {\r
803     if (pStyle == NULL) {\r
804         InitBreak(fLineWidth);\r
805         return;\r
806     }\r
807     IFDE_CSSParagraphStyle *pParaStyle = pStyle->GetParagraphStyles();\r
808     if (eDisplay == FDE_CSSDISPLAY_Block || eDisplay == FDE_CSSDISPLAY_ListItem) {\r
809         int32_t iAlign = FX_RTFLINEALIGNMENT_Left;\r
810         switch (pParaStyle->GetTextAlign()) {\r
811             case FDE_CSSTEXTALIGN_Right:\r
812                 iAlign = FX_RTFLINEALIGNMENT_Right;\r
813                 break;\r
814             case FDE_CSSTEXTALIGN_Center:\r
815                 iAlign = FX_RTFLINEALIGNMENT_Center;\r
816                 break;\r
817             case FDE_CSSTEXTALIGN_Justify:\r
818                 iAlign = FX_RTFLINEALIGNMENT_Justified;\r
819                 break;\r
820             case FDE_CSSTEXTALIGN_JustifyAll:\r
821                 iAlign = FX_RTFLINEALIGNMENT_Distributed;\r
822                 break;\r
823             default:\r
824                 break;\r
825         }\r
826         m_pBreak->SetAlignment(iAlign);\r
827         FX_FLOAT fStart = 0;\r
828         const FDE_CSSRECT *pRect = pStyle->GetBoundaryStyles()->GetMarginWidth();\r
829         const FDE_CSSRECT *pPaddingRect = pStyle->GetBoundaryStyles()->GetPaddingWidth();\r
830         if (pRect != NULL) {\r
831             fStart = pRect->left.GetValue();\r
832             fLineWidth -= pRect->right.GetValue();\r
833             if (pPaddingRect != NULL) {\r
834                 fStart += pPaddingRect->left.GetValue();\r
835                 fLineWidth -= pPaddingRect->right.GetValue();\r
836             }\r
837             if (eDisplay == FDE_CSSDISPLAY_ListItem) {\r
838                 const FDE_CSSRECT *pParRect = pParentStyle->GetBoundaryStyles()->GetMarginWidth();\r
839                 const FDE_CSSRECT *pParPaddingRect = pParentStyle->GetBoundaryStyles()->GetPaddingWidth();\r
840                 if (pParRect != NULL) {\r
841                     fStart += pParRect->left.GetValue();\r
842                     fLineWidth -= pParRect->right.GetValue();\r
843                     if (pParPaddingRect != NULL) {\r
844                         fStart += pParPaddingRect->left.GetValue();\r
845                         fLineWidth -= pParPaddingRect->right.GetValue();\r
846                     }\r
847                 }\r
848                 FDE_CSSRECT pNewRect;\r
849                 pNewRect.left.Set(FDE_CSSLENGTHUNIT_Point, fStart);\r
850                 pNewRect.right.Set(FDE_CSSLENGTHUNIT_Point, pRect->right.GetValue());\r
851                 pNewRect.top.Set(FDE_CSSLENGTHUNIT_Point, pRect->top.GetValue());\r
852                 pNewRect.bottom.Set(FDE_CSSLENGTHUNIT_Point, pRect->bottom.GetValue());\r
853                 pStyle->GetBoundaryStyles()->SetMarginWidth(pNewRect);\r
854             }\r
855         }\r
856         m_pBreak->SetLineWidth(fStart, fLineWidth);\r
857         FX_FLOAT fIndent = pParaStyle->GetTextIndent().GetValue();\r
858         if (fIndent > 0) {\r
859             fStart += fIndent;\r
860         }\r
861         m_pBreak->SetLinePos(fStart);\r
862         m_pBreak->SetTabWidth(m_textParser.GetTabInterval(pStyle));\r
863         if (m_pTabstopContext == NULL) {\r
864             m_pTabstopContext = FX_NEW CXFA_TextTabstopsContext;\r
865         }\r
866         m_textParser.GetTabstops(pStyle, m_pTabstopContext);\r
867         for (int32_t i = 0; i < m_pTabstopContext->m_iTabCount; i++) {\r
868             XFA_TABSTOPS *pTab = m_pTabstopContext->m_tabstops.GetDataPtr(i);\r
869             m_pBreak->AddPositionedTab(pTab->fTabstops);\r
870         }\r
871     }\r
872     FX_FLOAT fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle);\r
873     m_pBreak->SetFontSize(fFontSize);\r
874     m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);\r
875     m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, pStyle));\r
876     m_pBreak->SetHorizontalScale(m_textParser.GetHorScale(m_pTextProvider, pStyle, pXMLNode));\r
877     m_pBreak->SetVerticalScale(m_textParser.GetVerScale(m_pTextProvider, pStyle));\r
878     m_pBreak->SetCharSpace(pParaStyle->GetLetterSpacing().GetValue());\r
879 }\r
880 int32_t CXFA_TextLayout::GetText(CFX_WideString &wsText)\r
881 {\r
882     GetTextDataNode();\r
883     wsText.Empty();\r
884     if (m_bRichText) {\r
885     } else {\r
886         wsText = m_pTextDataNode->GetContent();\r
887     }\r
888     return wsText.GetLength();\r
889 }\r
890 FX_FLOAT CXFA_TextLayout::GetLayoutHeight()\r
891 {\r
892     if (m_pLoader == NULL) {\r
893         return 0;\r
894     }\r
895     int32_t iCount = m_pLoader->m_lineHeights.GetSize();\r
896     if (iCount == 0 && m_pLoader->m_fWidth > 0) {\r
897         CFX_SizeF szMax, szDef;\r
898         szMax.Set(m_pLoader->m_fWidth, m_pLoader->m_fHeight);\r
899         szDef.Set(0, 0);\r
900         m_pLoader->m_bSaveLineHeight = TRUE;\r
901         m_pLoader->m_fLastPos = 0;\r
902         CalcSize(szMax, szMax, szDef);\r
903         m_pLoader->m_bSaveLineHeight = FALSE;\r
904         return szDef.y;\r
905     }\r
906     FX_FLOAT fHeight = m_pLoader->m_fHeight;\r
907     if (fHeight < 0.1f) {\r
908         fHeight = 0;\r
909         for (int32_t i = 0; i < iCount; i++) {\r
910             fHeight += m_pLoader->m_lineHeights.ElementAt(i);\r
911         }\r
912     }\r
913     return fHeight;\r
914 }\r
915 FX_FLOAT CXFA_TextLayout::StartLayout(FX_FLOAT fWidth )\r
916 {\r
917     if (m_pLoader == NULL) {\r
918         m_pLoader = FX_NEW CXFA_LoaderContext;\r
919     }\r
920     if (fWidth < 0 || (m_pLoader->m_fWidth > -1 && FXSYS_fabs(fWidth - m_pLoader->m_fWidth) > 0)) {\r
921         m_pLoader->m_lineHeights.RemoveAll();\r
922         m_Blocks.RemoveAll();\r
923         Unload();\r
924         m_pLoader->m_fStartLineOffset = 0;\r
925     }\r
926     m_pLoader->m_fWidth = fWidth;\r
927     if (fWidth < 0) {\r
928         CFX_SizeF szMax, szDef;\r
929         szMax.Set(0, 0);\r
930         szDef.Set(0, 0);\r
931         m_pLoader->m_bSaveLineHeight = TRUE;\r
932         m_pLoader->m_fLastPos = 0;\r
933         CalcSize(szMax, szMax, szDef);\r
934         m_pLoader->m_bSaveLineHeight = FALSE;\r
935         fWidth = szDef.x;\r
936     }\r
937     return fWidth;\r
938 }\r
939 FX_BOOL CXFA_TextLayout::DoLayout(int32_t iBlockIndex, FX_FLOAT &fCalcHeight, FX_FLOAT fContentAreaHeight , FX_FLOAT fTextHeight )\r
940 {\r
941     if (m_pLoader == NULL) {\r
942         return FALSE;\r
943     }\r
944     int32_t iBlockCount = m_Blocks.GetSize();\r
945     FX_FLOAT fHeight = fTextHeight;\r
946     if (fHeight < 0) {\r
947         fHeight = GetLayoutHeight();\r
948     }\r
949     m_pLoader->m_fHeight = fHeight;\r
950     if (fContentAreaHeight < 0) {\r
951         return FALSE;\r
952     }\r
953     m_bHasBlock = TRUE;\r
954     if (iBlockCount == 0 && fHeight > 0) {\r
955         fHeight = fTextHeight - GetLayoutHeight();\r
956         if (fHeight > 0) {\r
957             int32_t iAlign = m_textParser.GetVAlgin(m_pTextProvider);\r
958             if (iAlign == XFA_ATTRIBUTEENUM_Middle) {\r
959                 fHeight /= 2.0f;\r
960             } else if (iAlign != XFA_ATTRIBUTEENUM_Bottom) {\r
961                 fHeight = 0;\r
962             }\r
963             m_pLoader->m_fStartLineOffset = fHeight;\r
964         }\r
965     }\r
966     FX_FLOAT fLinePos = m_pLoader->m_fStartLineOffset;\r
967     int32_t iLineIndex = 0;\r
968     if (iBlockCount > 1) {\r
969         if (iBlockCount >= (iBlockIndex + 1) * 2) {\r
970             iLineIndex = m_Blocks.ElementAt(iBlockIndex * 2);\r
971         } else {\r
972             iLineIndex = m_Blocks.ElementAt(iBlockCount - 1) + m_Blocks.ElementAt(iBlockCount - 2);\r
973         }\r
974         if (m_pLoader->m_BlocksHeight.GetSize() > 0) {\r
975             for (int32_t i = 0; i < iBlockIndex; i++) {\r
976                 fLinePos -= m_pLoader->m_BlocksHeight.ElementAt(i * 2 + 1);\r
977             }\r
978         }\r
979     }\r
980     int32_t iCount = m_pLoader->m_lineHeights.GetSize();\r
981     int32_t i = 0;\r
982     for (i = iLineIndex; i < iCount; i++) {\r
983         FX_FLOAT fLineHeight = m_pLoader->m_lineHeights.ElementAt(i);\r
984         if ((i == iLineIndex) && (fLineHeight - fContentAreaHeight > 0.001)) {\r
985             fCalcHeight = 0;\r
986             return TRUE;\r
987         }\r
988         if (fLinePos + fLineHeight - fContentAreaHeight > 0.001) {\r
989             if (iBlockCount >= (iBlockIndex + 1) * 2) {\r
990                 m_Blocks.SetAt(iBlockIndex * 2, iLineIndex);\r
991                 m_Blocks.SetAt(iBlockIndex * 2 + 1, i - iLineIndex);\r
992             } else {\r
993                 m_Blocks.Add(iLineIndex);\r
994                 m_Blocks.Add(i - iLineIndex);\r
995             }\r
996             if (i == iLineIndex) {\r
997                 if (fCalcHeight <= fLinePos) {\r
998                     if (m_pLoader->m_BlocksHeight.GetSize() > iBlockIndex * 2 && (m_pLoader->m_BlocksHeight.GetAt(iBlockIndex * 2) == iBlockIndex)) {\r
999                         m_pLoader->m_BlocksHeight.SetAt(iBlockIndex * 2 + 1, fCalcHeight);\r
1000                     } else {\r
1001                         m_pLoader->m_BlocksHeight.Add((FX_FLOAT)iBlockIndex);\r
1002                         m_pLoader->m_BlocksHeight.Add(fCalcHeight);\r
1003                     }\r
1004                 }\r
1005                 return TRUE;\r
1006             }\r
1007             fCalcHeight = fLinePos;\r
1008             return TRUE;\r
1009         }\r
1010         fLinePos += fLineHeight;\r
1011     }\r
1012     return FALSE;\r
1013 }\r
1014 int32_t CXFA_TextLayout::CountBlocks() const\r
1015 {\r
1016     int32_t iCount = m_Blocks.GetSize() / 2;\r
1017     return iCount > 0 ? iCount : 1;\r
1018 }\r
1019 FX_BOOL CXFA_TextLayout::CalcSize(const CFX_SizeF &minSize, const CFX_SizeF &maxSize, CFX_SizeF &defaultSize)\r
1020 {\r
1021     defaultSize.x = maxSize.x;\r
1022     if (defaultSize.x < 1) {\r
1023         defaultSize.x = 0xFFFF;\r
1024     }\r
1025     if (m_pBreak != NULL) {\r
1026         m_pBreak->Release();\r
1027     }\r
1028     m_pBreak = CreateBreak(FALSE);\r
1029     FX_FLOAT fLinePos = 0;\r
1030     m_iLines = 0;\r
1031     m_fMaxWidth = 0;\r
1032     Loader(defaultSize, fLinePos, FALSE);\r
1033     if (fLinePos < 0.1f) {\r
1034         fLinePos = m_textParser.GetFontSize(m_pTextProvider, NULL);\r
1035     }\r
1036     if (m_pTabstopContext) {\r
1037         delete m_pTabstopContext;\r
1038         m_pTabstopContext = NULL;\r
1039     }\r
1040     defaultSize.Set(m_fMaxWidth, fLinePos);\r
1041     return TRUE;\r
1042 }\r
1043 FX_BOOL CXFA_TextLayout::Layout(const CFX_SizeF &size, FX_FLOAT* fHeight)\r
1044 {\r
1045     if (size.x < 1) {\r
1046         return FALSE;\r
1047     }\r
1048     Unload();\r
1049     m_pBreak = CreateBreak(TRUE);\r
1050     if (m_pLoader != NULL) {\r
1051         m_pLoader->m_iTotalLines = -1;\r
1052         m_pLoader->m_iChar = 0;\r
1053     }\r
1054     m_iLines = 0;\r
1055     FX_FLOAT fLinePos = 0;\r
1056     Loader(size, fLinePos, TRUE);\r
1057     UpdateAlign(size.y, fLinePos);\r
1058     if (m_pTabstopContext) {\r
1059         delete m_pTabstopContext;\r
1060         m_pTabstopContext = NULL;\r
1061     }\r
1062     if (fHeight) {\r
1063         *fHeight = fLinePos;\r
1064     }\r
1065     return TRUE;\r
1066 }\r
1067 FX_BOOL CXFA_TextLayout::Layout(int32_t iBlock)\r
1068 {\r
1069     if (m_pLoader == NULL || iBlock < 0 || iBlock >= CountBlocks()) {\r
1070         return FALSE;\r
1071     }\r
1072     if (m_pLoader->m_fWidth < 1) {\r
1073         return FALSE;\r
1074     }\r
1075     m_pLoader->m_iTotalLines = -1;\r
1076     m_iLines = 0;\r
1077     FX_FLOAT fLinePos = 0;\r
1078     CXFA_Node *pNode = NULL;\r
1079     CFX_SizeF szText;\r
1080     szText.Set(m_pLoader->m_fWidth, m_pLoader->m_fHeight);\r
1081     int32_t iCount = m_Blocks.GetSize();\r
1082     int32_t iBlocksHeightCount = m_pLoader->m_BlocksHeight.GetSize();\r
1083     iBlocksHeightCount /= 2;\r
1084     if (iBlock < iBlocksHeightCount) {\r
1085         return TRUE;\r
1086     }\r
1087     if (iBlock == iBlocksHeightCount) {\r
1088         Unload();\r
1089         m_pBreak = CreateBreak(TRUE);\r
1090         fLinePos = m_pLoader->m_fStartLineOffset;\r
1091         for (int32_t i = 0; i < iBlocksHeightCount; i++) {\r
1092             fLinePos -= m_pLoader->m_BlocksHeight.ElementAt(i * 2 + 1);\r
1093         }\r
1094         m_pLoader->m_iChar = 0;\r
1095         if (iCount > 1) {\r
1096             m_pLoader->m_iTotalLines = m_Blocks.ElementAt(iBlock * 2 + 1);\r
1097         }\r
1098         Loader(szText, fLinePos, TRUE);\r
1099         if (iCount == 0 && m_pLoader->m_fStartLineOffset < 0.1f) {\r
1100             UpdateAlign(szText.y, fLinePos);\r
1101         }\r
1102     } else if (m_pTextDataNode != NULL) {\r
1103         iBlock *= 2;\r
1104         if (iBlock < iCount - 2) {\r
1105             m_pLoader->m_iTotalLines = m_Blocks.ElementAt(iBlock + 1);\r
1106         }\r
1107         m_pBreak->Reset();\r
1108         if (m_bRichText) {\r
1109             IFDE_XMLNode* pContainerNode = GetXMLContainerNode();\r
1110             if (!pContainerNode) {\r
1111                 return TRUE;\r
1112             }\r
1113             IFDE_XMLNode *pXMLNode = m_pLoader->m_pXMLNode;\r
1114             if (pXMLNode == NULL) {\r
1115                 return TRUE;\r
1116             }\r
1117             IFDE_XMLNode* pSaveXMLNode = m_pLoader->m_pXMLNode;\r
1118             for (; pXMLNode; pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling)) {\r
1119                 FX_BOOL bFlag = LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle, TRUE);\r
1120                 if (!bFlag) {\r
1121                     break;\r
1122                 }\r
1123             }\r
1124             while (pXMLNode == NULL) {\r
1125                 pXMLNode = pSaveXMLNode->GetNodeItem(IFDE_XMLNode::Parent);\r
1126                 if (pXMLNode == pContainerNode) {\r
1127                     break;\r
1128                 }\r
1129                 FX_BOOL bFlag = LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle, TRUE, NULL , FALSE);\r
1130                 if (!bFlag) {\r
1131                     break;\r
1132                 }\r
1133                 pSaveXMLNode = pXMLNode;\r
1134                 pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling);\r
1135                 if (!pXMLNode) {\r
1136                     continue;\r
1137                 }\r
1138                 for (; pXMLNode; pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling)) {\r
1139                     FX_BOOL bFlag = LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle, TRUE);\r
1140                     if (!bFlag) {\r
1141                         break;\r
1142                     }\r
1143                 }\r
1144             }\r
1145         } else {\r
1146             pNode = m_pLoader->m_pNode;\r
1147             if (pNode == NULL) {\r
1148                 return TRUE;\r
1149             }\r
1150             LoadText(pNode, szText, fLinePos, TRUE);\r
1151         }\r
1152     }\r
1153     if (iBlock == iCount) {\r
1154         if (m_pTabstopContext != NULL) {\r
1155             delete m_pTabstopContext;\r
1156             m_pTabstopContext = NULL;\r
1157         }\r
1158         if (m_pLoader != NULL) {\r
1159             delete m_pLoader;\r
1160             m_pLoader = NULL;\r
1161         }\r
1162     }\r
1163     return TRUE;\r
1164 }\r
1165 void CXFA_TextLayout::ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex)\r
1166 {\r
1167     if (!m_pLoader) {\r
1168         return;\r
1169     }\r
1170     int32_t iCountHeight = m_pLoader->m_lineHeights.GetSize();\r
1171     if (iCountHeight == 0) {\r
1172         return;\r
1173     }\r
1174     FX_BOOL bEndItem = TRUE;\r
1175     int32_t iBlockCount = m_Blocks.GetSize();\r
1176     FX_FLOAT fLinePos = m_pLoader->m_fStartLineOffset;\r
1177     int32_t iLineIndex = 0;\r
1178     if (iBlockIndex > 0) {\r
1179         int32_t iBlockHeightCount = m_pLoader->m_BlocksHeight.GetSize();\r
1180         iBlockHeightCount /= 2;\r
1181         if (iBlockHeightCount >= iBlockIndex) {\r
1182             for (int32_t i = 0; i < iBlockIndex; i++) {\r
1183                 fLinePos -= m_pLoader->m_BlocksHeight.ElementAt(i * 2 + 1);\r
1184             }\r
1185         } else {\r
1186             fLinePos = 0;\r
1187         }\r
1188         iLineIndex = m_Blocks.ElementAt(iBlockCount - 1) + m_Blocks.ElementAt(iBlockCount - 2);\r
1189     }\r
1190     int32_t i = 0;\r
1191     for (i = iLineIndex; i < iCountHeight; i++) {\r
1192         FX_FLOAT fLineHeight = m_pLoader->m_lineHeights.ElementAt(i);\r
1193         if (fLinePos + fLineHeight - rtText.height > 0.001) {\r
1194             m_Blocks.Add(iLineIndex);\r
1195             m_Blocks.Add(i - iLineIndex);\r
1196             bEndItem = FALSE;\r
1197             break;\r
1198         }\r
1199         fLinePos += fLineHeight;\r
1200     }\r
1201     if (iCountHeight > 0 && (i - iLineIndex) > 0 && bEndItem) {\r
1202         m_Blocks.Add(iLineIndex);\r
1203         m_Blocks.Add(i - iLineIndex);\r
1204     }\r
1205 }\r
1206 FX_BOOL CXFA_TextLayout::DrawString(CFX_RenderDevice *pFxDevice, const CFX_Matrix &tmDoc2Device, const CFX_RectF &rtClip, int32_t iBlock )\r
1207 {\r
1208     IFDE_RenderDevice *pDevice = IFDE_RenderDevice::Create(pFxDevice);\r
1209     if (pDevice == NULL) {\r
1210         return FALSE;\r
1211     }\r
1212     FDE_HDEVICESTATE state = pDevice->SaveState();\r
1213     pDevice->SetClipRect(rtClip);\r
1214     IFDE_SolidBrush *pSolidBrush = (IFDE_SolidBrush*)IFDE_Brush::Create(FDE_BRUSHTYPE_Solid);\r
1215     IFDE_Pen *pPen = IFDE_Pen::Create();\r
1216     FXSYS_assert(pDevice != NULL && pSolidBrush != NULL && pPen != NULL);\r
1217     if (m_pieceLines.GetSize() == 0) {\r
1218         int32_t iBlockCount = CountBlocks();\r
1219         for (int32_t i = 0; i < iBlockCount; i++) {\r
1220             Layout(i);\r
1221         }\r
1222     }\r
1223     FXTEXT_CHARPOS *pCharPos = NULL;\r
1224     int32_t iCharCount = 0;\r
1225     int32_t iLineStart = 0;\r
1226     int32_t iPieceLines = m_pieceLines.GetSize();\r
1227     int32_t iCount = m_Blocks.GetSize();\r
1228     if (iCount > 0) {\r
1229         iBlock *= 2;\r
1230         if (iBlock < iCount) {\r
1231             iLineStart = m_Blocks.ElementAt(iBlock);\r
1232             iPieceLines = m_Blocks.ElementAt(iBlock + 1);\r
1233         } else {\r
1234             iPieceLines = 0;\r
1235         }\r
1236     }\r
1237     for (int32_t i = 0; i < iPieceLines; i++) {\r
1238         if(i + iLineStart >= m_pieceLines.GetSize()) {\r
1239             break;\r
1240         }\r
1241         CXFA_PieceLine *pPieceLine = m_pieceLines.GetAt(i + iLineStart);\r
1242         int32_t iPieces = pPieceLine->m_textPieces.GetSize();\r
1243         int32_t j = 0;\r
1244         for (j = 0; j < iPieces; j++) {\r
1245             XFA_LPCTEXTPIECE pPiece = pPieceLine->m_textPieces.GetAt(j);\r
1246             int32_t iChars = pPiece->iChars;\r
1247             if (iCharCount < iChars) {\r
1248                 if (pCharPos != NULL) {\r
1249                     FDE_Free(pCharPos);\r
1250                 }\r
1251                 pCharPos = (FXTEXT_CHARPOS*)FDE_Alloc(iChars * sizeof(FXTEXT_CHARPOS));\r
1252                 iCharCount = iChars;\r
1253             }\r
1254             FXSYS_memset(pCharPos, 0, iCharCount * sizeof(FXTEXT_CHARPOS));\r
1255             RenderString(pDevice, pSolidBrush, pPieceLine, j, pCharPos, tmDoc2Device);\r
1256         }\r
1257         for (j = 0; j < iPieces; j++) {\r
1258             RenderPath(pDevice, pPen, pPieceLine, j, pCharPos, tmDoc2Device);\r
1259         }\r
1260     }\r
1261     pDevice->RestoreState(state);\r
1262     if (pCharPos != NULL) {\r
1263         FDE_Free(pCharPos);\r
1264     }\r
1265     pSolidBrush->Release();\r
1266     pPen->Release();\r
1267     pDevice->Release();\r
1268     return iPieceLines;\r
1269 }\r
1270 void CXFA_TextLayout::UpdateAlign(FX_FLOAT fHeight, FX_FLOAT fBottom)\r
1271 {\r
1272     fHeight -= fBottom;\r
1273     if (fHeight < 0.1f) {\r
1274         return;\r
1275     }\r
1276     switch (m_textParser.GetVAlgin(m_pTextProvider)) {\r
1277         case XFA_ATTRIBUTEENUM_Middle:\r
1278             fHeight /= 2.0f;\r
1279             break;\r
1280         case XFA_ATTRIBUTEENUM_Bottom:\r
1281             break;\r
1282         default:\r
1283             return;\r
1284     }\r
1285     int32_t iCount = m_pieceLines.GetSize();\r
1286     for (int32_t i = 0; i < iCount; i++) {\r
1287         CXFA_PieceLine *pPieceLine = m_pieceLines.GetAt(i);\r
1288         int32_t iPieces = pPieceLine->m_textPieces.GetSize();\r
1289         for (int32_t j = 0; j < iPieces; j++) {\r
1290             XFA_LPTEXTPIECE pPiece = pPieceLine->m_textPieces.GetAt(j);\r
1291             CFX_RectF &rect = pPiece->rtPiece;\r
1292             rect.top += fHeight;\r
1293         }\r
1294     }\r
1295 }\r
1296 FX_BOOL CXFA_TextLayout::Loader(const CFX_SizeF &szText, FX_FLOAT &fLinePos, FX_BOOL bSavePieces )\r
1297 {\r
1298     if (m_pAllocator == NULL) {\r
1299         m_pAllocator = FX_CreateAllocator(FX_ALLOCTYPE_Static, 256, 0);\r
1300     }\r
1301     GetTextDataNode();\r
1302     if (m_pTextDataNode == NULL) {\r
1303         return TRUE;\r
1304     }\r
1305     if (m_bRichText) {\r
1306         IFDE_XMLNode *pXMLContainer = GetXMLContainerNode();\r
1307         if (pXMLContainer) {\r
1308             if (!m_textParser.IsParsed()) {\r
1309                 m_textParser.DoParse(pXMLContainer, m_pTextProvider);\r
1310             }\r
1311             IFDE_CSSComputedStyle *pRootStyle = m_textParser.CreateRootStyle(m_pTextProvider);\r
1312             LoadRichText(pXMLContainer, szText, fLinePos, pRootStyle, bSavePieces);\r
1313             pRootStyle->Release();\r
1314         }\r
1315     } else {\r
1316         LoadText(m_pTextDataNode, szText, fLinePos, bSavePieces);\r
1317     }\r
1318     return TRUE;\r
1319 }\r
1320 void CXFA_TextLayout::LoadText(CXFA_Node *pNode, const CFX_SizeF &szText, FX_FLOAT &fLinePos, FX_BOOL bSavePieces)\r
1321 {\r
1322     InitBreak(szText.x);\r
1323     CXFA_Para para = m_pTextProvider->GetParaNode();\r
1324     FX_FLOAT fSpaceAbove = 0;\r
1325     if (para.IsExistInXML()) {\r
1326         fSpaceAbove = para.GetSpaceAbove();\r
1327         if (fSpaceAbove < 0.1f) {\r
1328             fSpaceAbove = 0;\r
1329         }\r
1330         int32_t verAlign = para.GetVerticalAlign();\r
1331         switch (verAlign) {\r
1332             case XFA_ATTRIBUTEENUM_Top:\r
1333             case XFA_ATTRIBUTEENUM_Middle:\r
1334             case XFA_ATTRIBUTEENUM_Bottom: {\r
1335                     fLinePos += fSpaceAbove;\r
1336                     break;\r
1337                 }\r
1338         }\r
1339     }\r
1340     CFX_WideString wsText = pNode->GetContent();\r
1341     wsText.TrimRight(L" ");\r
1342     FX_BOOL bRet = AppendChar(wsText, fLinePos, fSpaceAbove, bSavePieces);\r
1343     if (bRet && m_pLoader != NULL) {\r
1344         m_pLoader->m_pNode = pNode;\r
1345     } else {\r
1346         EndBreak(FX_RTFBREAK_ParagraphBreak, fLinePos, bSavePieces);\r
1347     }\r
1348 }\r
1349 FX_BOOL  CXFA_TextLayout::LoadRichText(IFDE_XMLNode *pXMLNode, const CFX_SizeF &szText, FX_FLOAT &fLinePos, IFDE_CSSComputedStyle *pParentStyle, FX_BOOL bSavePieces, CXFA_LinkUserData* pLinkData, FX_BOOL bEndBreak, FX_BOOL bIsOl, int32_t iLiCount)\r
1350 {\r
1351     if (pXMLNode == NULL) {\r
1352         return FALSE;\r
1353     }\r
1354     CXFA_TextParseContext *pContext = m_textParser.GetParseContextFromMap(pXMLNode);\r
1355     FDE_CSSDISPLAY eDisplay = FDE_CSSDISPLAY_None;\r
1356     FX_BOOL bContentNode        = FALSE;\r
1357     FX_FLOAT fSpaceBelow        = 0;\r
1358     IFDE_CSSComputedStyle *pStyle = NULL;\r
1359     CFX_WideString wsName;\r
1360     if (bEndBreak) {\r
1361         FX_BOOL bCurOl = FALSE;\r
1362         FX_BOOL bCurLi = FALSE;\r
1363         IFDE_XMLElement *pElement = NULL;\r
1364         if (pContext != NULL) {\r
1365             if(m_bBlockContinue || (m_pLoader && pXMLNode == m_pLoader->m_pXMLNode)) {\r
1366                 m_bBlockContinue = TRUE;\r
1367             }\r
1368             if(pXMLNode->GetType() == FDE_XMLNODE_Text) {\r
1369                 bContentNode = TRUE;\r
1370             } else if (pXMLNode->GetType() == FDE_XMLNODE_Element) {\r
1371                 pElement = (IFDE_XMLElement *)pXMLNode;\r
1372                 pElement->GetLocalTagName(wsName);\r
1373             }\r
1374             if (wsName == FX_WSTRC(L"ol")) {\r
1375                 bIsOl = TRUE;\r
1376                 bCurOl = TRUE;\r
1377             }\r
1378             if(m_bBlockContinue || bContentNode == FALSE) {\r
1379                 eDisplay = pContext->GetDisplay();\r
1380                 if (eDisplay != FDE_CSSDISPLAY_Block && eDisplay != FDE_CSSDISPLAY_Inline && eDisplay != FDE_CSSDISPLAY_ListItem) {\r
1381                     return TRUE;\r
1382                 }\r
1383                 pStyle = m_textParser.ComputeStyle(pXMLNode, pParentStyle);\r
1384                 InitBreak(bContentNode ? pParentStyle : pStyle, eDisplay, szText.x, pXMLNode, pParentStyle);\r
1385                 if ((eDisplay == FDE_CSSDISPLAY_Block || eDisplay == FDE_CSSDISPLAY_ListItem) && (pStyle != NULL)\r
1386                         && (wsName.IsEmpty() || (wsName != FX_WSTRC(L"body") && wsName != FX_WSTRC(L"html") && wsName != FX_WSTRC(L"ol") && wsName != FX_WSTRC(L"ul")))) {\r
1387                     const FDE_CSSRECT *pRect = pStyle->GetBoundaryStyles()->GetMarginWidth();\r
1388                     if (pRect) {\r
1389                         fLinePos += pRect->top.GetValue();\r
1390                         fSpaceBelow = pRect->bottom.GetValue();\r
1391                     }\r
1392                 }\r
1393                 if (wsName == FX_WSTRC(L"a")) {\r
1394                     CFX_WideString wsLinkContent;\r
1395                     FXSYS_assert(pElement);\r
1396                     pElement->GetString(FX_WSTRC(L"href").GetPtr(), wsLinkContent);\r
1397                     if (!wsLinkContent.IsEmpty()) {\r
1398                         pLinkData = FDE_NewWith(m_pAllocator)CXFA_LinkUserData(m_pAllocator, wsLinkContent.GetBuffer(wsLinkContent.GetLength()));\r
1399                         wsLinkContent.ReleaseBuffer(wsLinkContent.GetLength());\r
1400                     }\r
1401                 }\r
1402                 int32_t iTabCount = m_textParser.CountTabs(bContentNode ? pParentStyle : pStyle);\r
1403                 FX_BOOL bSpaceRun = m_textParser.IsSpaceRun(bContentNode ? pParentStyle : pStyle);\r
1404                 CFX_WideString wsText;\r
1405                 if (bContentNode && iTabCount == 0) {\r
1406                     ((IFDE_XMLText *)pXMLNode)->GetText(wsText);\r
1407                 } else if (wsName == FX_WSTRC(L"br")) {\r
1408                     wsText = L'\n';\r
1409                 } else if (wsName == FX_WSTRC(L"li")) {\r
1410                     bCurLi = TRUE;\r
1411                     if (bIsOl) {\r
1412                         wsText.Format(L"%d.  ", iLiCount);\r
1413                     } else {\r
1414                         wsText = 0x00B7 + FX_WSTRC(L"  ");\r
1415                     }\r
1416                 } else if (!bContentNode) {\r
1417                     if (iTabCount > 0)\r
1418                         while (iTabCount-- > 0) {\r
1419                             wsText += L'\t';\r
1420                         }\r
1421                     else {\r
1422                         m_textParser.GetEmbbedObj(m_pTextProvider, pXMLNode, wsText);\r
1423                     }\r
1424                 }\r
1425                 int32_t iLength = wsText.GetLength();\r
1426                 if (iLength > 0 && bContentNode && !bSpaceRun) {\r
1427                     ProcessText(wsText);\r
1428                 }\r
1429                 if (m_pLoader) {\r
1430                     if (wsText.GetLength() > 0 && (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {\r
1431                         wsText.TrimLeft(0x20);\r
1432                     }\r
1433                     if (FDE_CSSDISPLAY_Block == eDisplay) {\r
1434                         m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;\r
1435                     } else if (FDE_CSSDISPLAY_Inline == eDisplay && (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {\r
1436                         m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;\r
1437                     } else if (wsText.GetLength() > 0 && (0x20 == wsText.GetAt(wsText.GetLength() - 1))) {\r
1438                         m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;\r
1439                     } else if (wsText.GetLength() == 0)\r
1440                         ;\r
1441                     else {\r
1442                         m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;\r
1443                     }\r
1444                 }\r
1445                 if (wsText.GetLength() > 0) {\r
1446                     if (m_pLoader == NULL || m_pLoader->m_iChar == 0) {\r
1447                         if (pLinkData) {\r
1448                             pLinkData->AddRef();\r
1449                         }\r
1450                         CXFA_TextUserData *pUserData = FDE_NewWith(m_pAllocator)CXFA_TextUserData(m_pAllocator, bContentNode ? pParentStyle : pStyle, pLinkData);\r
1451                         m_pBreak->SetUserData(pUserData);\r
1452                     }\r
1453                     if (AppendChar(wsText, fLinePos, 0, bSavePieces)) {\r
1454                         if ( m_pLoader) {\r
1455                             m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;\r
1456                         }\r
1457                         if (IsEnd(bSavePieces)) {\r
1458                             if (m_pLoader && m_pLoader->m_iTotalLines > -1) {\r
1459                                 m_pLoader->m_pXMLNode = pXMLNode;\r
1460                                 m_pLoader->m_pParentStyle = pParentStyle;\r
1461                             }\r
1462                             if (pStyle != NULL) {\r
1463                                 pStyle->Release();\r
1464                             }\r
1465                             return FALSE;\r
1466                         }\r
1467                         return TRUE;\r
1468                     }\r
1469                 }\r
1470             }\r
1471         }\r
1472         FX_BOOL ret = TRUE;\r
1473         for (IFDE_XMLNode *pChildNode = pXMLNode->GetNodeItem(IFDE_XMLNode::FirstChild); pChildNode; pChildNode = pChildNode->GetNodeItem(IFDE_XMLNode::NextSibling)) {\r
1474             if (bCurOl) {\r
1475                 iLiCount++;\r
1476             }\r
1477             ret = LoadRichText(pChildNode, szText, fLinePos, pContext ? pStyle : pParentStyle, bSavePieces, pLinkData, TRUE, bIsOl, iLiCount);\r
1478             if(ret == FALSE) {\r
1479                 return FALSE;\r
1480             }\r
1481         }\r
1482         if (m_pLoader) {\r
1483             if (FDE_CSSDISPLAY_Block == eDisplay) {\r
1484                 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;\r
1485             }\r
1486         }\r
1487         if (bCurLi) {\r
1488             EndBreak(FX_RTFBREAK_LineBreak, fLinePos, bSavePieces);\r
1489         }\r
1490     } else {\r
1491         if (pContext != NULL) {\r
1492             eDisplay = pContext->GetDisplay();\r
1493         }\r
1494     }\r
1495     if(m_bBlockContinue) {\r
1496         if (pContext != NULL && !bContentNode) {\r
1497             FX_DWORD dwStatus = (eDisplay == FDE_CSSDISPLAY_Block) ? FX_RTFBREAK_ParagraphBreak : FX_RTFBREAK_PieceBreak;\r
1498             EndBreak(dwStatus, fLinePos, bSavePieces);\r
1499             if (eDisplay == FDE_CSSDISPLAY_Block) {\r
1500                 fLinePos += fSpaceBelow;\r
1501                 if (m_pTabstopContext) {\r
1502                     m_pTabstopContext->RemoveAll();\r
1503                 }\r
1504             }\r
1505             if ( wsName == FX_WSTRC(L"a")) {\r
1506                 if (pLinkData != NULL) {\r
1507                     FX_DWORD dwRefCount = pLinkData->Release();\r
1508                     pLinkData = NULL;\r
1509                 }\r
1510             }\r
1511             if (IsEnd(bSavePieces)) {\r
1512                 if (pStyle) {\r
1513                     pStyle->Release();\r
1514                 }\r
1515                 if (m_pLoader && m_pLoader->m_iTotalLines > -1) {\r
1516                     m_pLoader->m_pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling);\r
1517                     m_pLoader->m_pParentStyle = pParentStyle;\r
1518                 }\r
1519                 return FALSE;\r
1520             }\r
1521         }\r
1522     }\r
1523     if (pStyle != NULL) {\r
1524         pStyle->Release();\r
1525     }\r
1526     return TRUE;\r
1527 }\r
1528 FX_BOOL CXFA_TextLayout::AppendChar(const CFX_WideString &wsText, FX_FLOAT &fLinePos, FX_FLOAT fSpaceAbove, FX_BOOL bSavePieces)\r
1529 {\r
1530     FX_DWORD dwStatus = 0;\r
1531     int32_t iChar = 0;\r
1532     if (m_pLoader) {\r
1533         iChar = m_pLoader->m_iChar;\r
1534     }\r
1535     int32_t iLength = wsText.GetLength();\r
1536     for (int32_t i = iChar; i < iLength; i++) {\r
1537         FX_WCHAR wch = wsText.GetAt(i);\r
1538         if (wch == 0xA0) {\r
1539             wch = 0x20;\r
1540         }\r
1541         if ((dwStatus = m_pBreak->AppendChar(wch)) > FX_RTFBREAK_PieceBreak) {\r
1542             AppendTextLine(dwStatus, fLinePos, bSavePieces);\r
1543             if (IsEnd(bSavePieces)) {\r
1544                 if (m_pLoader != NULL) {\r
1545                     m_pLoader->m_iChar = i;\r
1546                 }\r
1547                 return TRUE;\r
1548             }\r
1549             if (dwStatus == FX_RTFBREAK_ParagraphBreak && m_bRichText) {\r
1550                 fLinePos += fSpaceAbove;\r
1551             }\r
1552         }\r
1553     }\r
1554     if(m_pLoader) {\r
1555         m_pLoader->m_iChar = 0;\r
1556     }\r
1557     return FALSE;\r
1558 }\r
1559 FX_BOOL CXFA_TextLayout::IsEnd(FX_BOOL bSavePieces)\r
1560 {\r
1561     if (!bSavePieces) {\r
1562         return FALSE;\r
1563     }\r
1564     if (m_pLoader && m_pLoader->m_iTotalLines > 0) {\r
1565         return m_iLines >= m_pLoader->m_iTotalLines;\r
1566     }\r
1567     return FALSE;\r
1568 }\r
1569 void CXFA_TextLayout::ProcessText(CFX_WideString &wsText)\r
1570 {\r
1571     int32_t iLen = wsText.GetLength();\r
1572     if (iLen == 0) {\r
1573         return;\r
1574     }\r
1575     FX_WCHAR* psz = wsText.GetBuffer(iLen);\r
1576     int32_t iTrimLeft = 0;\r
1577     FX_WCHAR wch = 0, wPrev = 0;\r
1578     for (int32_t i = 0; i < iLen; i++) {\r
1579         wch = psz[i];\r
1580         if (wch < 0x20) {\r
1581             wch = 0x20;\r
1582         }\r
1583         if (wch == 0x20 && wPrev == 0x20) {\r
1584             continue;\r
1585         }\r
1586         wPrev = wch;\r
1587         psz[iTrimLeft++] = wch;\r
1588     }\r
1589     wsText.ReleaseBuffer(iLen);\r
1590     wsText = wsText.Left(iTrimLeft);\r
1591 }\r
1592 void CXFA_TextLayout::EndBreak(FX_DWORD dwStatus, FX_FLOAT &fLinePos, FX_BOOL bSavePieces)\r
1593 {\r
1594     dwStatus = m_pBreak->EndBreak(dwStatus);\r
1595     if (dwStatus > FX_RTFBREAK_PieceBreak) {\r
1596         AppendTextLine(dwStatus, fLinePos, bSavePieces, TRUE);\r
1597     }\r
1598 }\r
1599 void CXFA_TextLayout::DoTabstops(IFDE_CSSComputedStyle *pStyle, CXFA_PieceLine *pPieceLine)\r
1600 {\r
1601     if (m_pTabstopContext == NULL || m_pTabstopContext->m_iTabCount == 0) {\r
1602         return;\r
1603     }\r
1604     if (pStyle == NULL || pPieceLine == NULL) {\r
1605         return;\r
1606     }\r
1607     int32_t iPieces = pPieceLine->m_textPieces.GetSize();\r
1608     if (iPieces == 0) {\r
1609         return;\r
1610     }\r
1611     XFA_LPTEXTPIECE pPiece = pPieceLine->m_textPieces.GetAt(iPieces - 1);\r
1612     int32_t &iTabstopsIndex = m_pTabstopContext->m_iTabIndex;\r
1613     int32_t iCount = m_textParser.CountTabs(pStyle);\r
1614     if (iTabstopsIndex > m_pTabstopContext->m_iTabCount - 1) {\r
1615         return;\r
1616     }\r
1617     if (iCount > 0) {\r
1618         iTabstopsIndex++;\r
1619         m_pTabstopContext->m_bTabstops = TRUE;\r
1620         FX_FLOAT fRight = 0;\r
1621         if (iPieces > 1) {\r
1622             XFA_LPTEXTPIECE p = pPieceLine->m_textPieces.GetAt(iPieces - 2);\r
1623             fRight = p->rtPiece.right();\r
1624         }\r
1625         m_pTabstopContext->m_fTabWidth = pPiece->rtPiece.width + pPiece->rtPiece.left - fRight;\r
1626     } else if (iTabstopsIndex > -1) {\r
1627         FX_FLOAT fLeft = 0;\r
1628         if (m_pTabstopContext->m_bTabstops) {\r
1629             XFA_TABSTOPS *pTabstops = m_pTabstopContext->m_tabstops.GetDataPtr(iTabstopsIndex);\r
1630             FX_DWORD dwAlgin = pTabstops->dwAlign;\r
1631             if (dwAlgin == FX_HashCode_String_GetW(L"center", 6)) {\r
1632                 fLeft = pPiece->rtPiece.width / 2.0f;\r
1633             } else if (dwAlgin == FX_HashCode_String_GetW(L"right", 5)\r
1634                        || dwAlgin == FX_HashCode_String_GetW(L"before", 6)) {\r
1635                 fLeft = pPiece->rtPiece.width;\r
1636             } else if (dwAlgin == FX_HashCode_String_GetW(L"decimal", 7)) {\r
1637                 int32_t iChars = pPiece->iChars;\r
1638                 for (int32_t i = 0; i < iChars; i++) {\r
1639                     if (pPiece->pszText[i] == L'.') {\r
1640                         break;\r
1641                     }\r
1642                     fLeft += pPiece->pWidths[i] / 20000.0f;\r
1643                 }\r
1644             }\r
1645             m_pTabstopContext->m_fLeft = FX_MIN(fLeft, m_pTabstopContext->m_fTabWidth);\r
1646             m_pTabstopContext->m_bTabstops = FALSE;\r
1647             m_pTabstopContext->m_fTabWidth = 0;\r
1648         }\r
1649         pPiece->rtPiece.left -= m_pTabstopContext->m_fLeft;\r
1650     }\r
1651 }\r
1652 void CXFA_TextLayout::AppendTextLine(FX_DWORD dwStatus, FX_FLOAT &fLinePos, FX_BOOL bSavePieces, FX_BOOL bEndBreak)\r
1653 {\r
1654     int32_t iPieces = m_pBreak->CountBreakPieces();\r
1655     if (iPieces < 1) {\r
1656         return;\r
1657     }\r
1658     IFDE_CSSComputedStyle *pStyle = NULL;\r
1659     if (bSavePieces) {\r
1660         CXFA_PieceLine *pPieceLine = FDE_NewWith(m_pAllocator)CXFA_PieceLine;\r
1661         m_pieceLines.Add(pPieceLine);\r
1662         if (m_pTabstopContext) {\r
1663             m_pTabstopContext->Reset();\r
1664         }\r
1665         FX_FLOAT fLineStep = 0, fBaseLine = 0;\r
1666         int32_t i = 0;\r
1667         for (i = 0; i < iPieces; i++) {\r
1668             const CFX_RTFPiece *pPiece = m_pBreak->GetBreakPiece(i);\r
1669             CXFA_TextUserData *pUserData = (CXFA_TextUserData*)pPiece->m_pUserData;\r
1670             if (pUserData != NULL) {\r
1671                 pStyle = pUserData->m_pStyle;\r
1672             }\r
1673             FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f;\r
1674             XFA_LPTEXTPIECE pTP = (XFA_LPTEXTPIECE)m_pAllocator->Alloc(sizeof(XFA_TEXTPIECE));\r
1675             pTP->pszText = (FX_WCHAR*)m_pAllocator->Alloc(pPiece->m_iChars * sizeof(FX_WCHAR));\r
1676             pTP->pWidths = (int32_t*)m_pAllocator->Alloc(pPiece->m_iChars * sizeof(int32_t));\r
1677             pTP->iChars = pPiece->m_iChars;\r
1678             pPiece->GetString(pTP->pszText);\r
1679             pPiece->GetWidths(pTP->pWidths);\r
1680             pTP->iBidiLevel = pPiece->m_iBidiLevel;\r
1681             pTP->iHorScale      = pPiece->m_iHorizontalScale;\r
1682             pTP->iVerScale      = pPiece->m_iVerticalScale;\r
1683             m_textParser.GetUnderline(m_pTextProvider, pStyle, pTP->iUnderline, pTP->iPeriod);\r
1684             m_textParser.GetLinethrough(m_pTextProvider, pStyle, pTP->iLineThrough);\r
1685             pTP->dwColor        = m_textParser.GetColor(m_pTextProvider, pStyle);\r
1686             pTP->pFont          = m_textParser.GetFont(m_pTextProvider, pStyle);\r
1687             pTP->fFontSize      = m_textParser.GetFontSize(m_pTextProvider, pStyle);\r
1688             pTP->rtPiece.left = pPiece->m_iStartPos / 20000.0f;\r
1689             pTP->rtPiece.width = pPiece->m_iWidth / 20000.0f;\r
1690             pTP->rtPiece.height = (FX_FLOAT)pPiece->m_iFontSize * fVerScale / 20.0f;\r
1691             FX_FLOAT fBaseLineTemp = m_textParser.GetBaseline(m_pTextProvider, pStyle);\r
1692             pTP->rtPiece.top = fBaseLineTemp;\r
1693             pPieceLine->m_textPieces.Add(pTP);\r
1694             FX_FLOAT fLineHeight = m_textParser.GetLineHeight(m_pTextProvider, pStyle, m_iLines == 0, fVerScale);\r
1695             if (fBaseLineTemp > 0) {\r
1696                 FX_FLOAT fLineHeightTmp = fBaseLineTemp + pTP->rtPiece.height;\r
1697                 if (fLineHeight < fLineHeightTmp) {\r
1698                     fLineHeight = fLineHeightTmp;\r
1699                 } else {\r
1700                     fBaseLineTemp = 0;\r
1701                 }\r
1702             } else if (fBaseLine < -fBaseLineTemp) {\r
1703                 fBaseLine = -fBaseLineTemp;\r
1704             }\r
1705             fLineStep = FX_MAX(fLineStep, fLineHeight);\r
1706             if ( pUserData != NULL && pUserData->m_pLinkData != NULL) {\r
1707                 pUserData->m_pLinkData->AddRef();\r
1708                 pTP->pLinkData = pUserData->m_pLinkData;\r
1709             } else {\r
1710                 pTP->pLinkData = NULL;\r
1711             }\r
1712             DoTabstops(pStyle, pPieceLine);\r
1713         }\r
1714         for (i = 0; i < iPieces; i++) {\r
1715             XFA_LPTEXTPIECE pTP = pPieceLine->m_textPieces.GetAt(i);\r
1716             FX_FLOAT &fTop = pTP->rtPiece.top;\r
1717             FX_FLOAT fBaseLineTemp = fTop;\r
1718             fTop = fLinePos + fLineStep - pTP->rtPiece.height - fBaseLineTemp;\r
1719             fTop = FX_MAX(0, fTop);\r
1720         }\r
1721         fLinePos += fLineStep + fBaseLine;\r
1722     } else {\r
1723         FX_FLOAT fLineStep = 0;\r
1724         FX_FLOAT fLineWidth = 0;\r
1725         for (int32_t i = 0; i < iPieces; i++) {\r
1726             const CFX_RTFPiece *pPiece = m_pBreak->GetBreakPiece(i);\r
1727             CXFA_TextUserData *pUserData = (CXFA_TextUserData*)pPiece->m_pUserData;\r
1728             if (pUserData != NULL) {\r
1729                 pStyle = pUserData->m_pStyle;\r
1730             }\r
1731             FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f;\r
1732             FX_FLOAT fBaseLine = m_textParser.GetBaseline(m_pTextProvider, pStyle);\r
1733             FX_FLOAT fLineHeight = m_textParser.GetLineHeight(m_pTextProvider, pStyle, m_iLines == 0, fVerScale);\r
1734             if (fBaseLine > 0) {\r
1735                 FX_FLOAT fLineHeightTmp = fBaseLine + (FX_FLOAT)pPiece->m_iFontSize * fVerScale / 20.0f;\r
1736                 if (fLineHeight < fLineHeightTmp) {\r
1737                     fLineHeight = fLineHeightTmp;\r
1738                 }\r
1739             }\r
1740             fLineStep = FX_MAX(fLineStep, fLineHeight);\r
1741             fLineWidth += pPiece->m_iWidth / 20000.0f;\r
1742         }\r
1743         fLinePos += fLineStep;\r
1744         m_fMaxWidth = FX_MAX(m_fMaxWidth, fLineWidth);\r
1745         if (m_pLoader && m_pLoader->m_bSaveLineHeight) {\r
1746             FX_FLOAT fHeight = fLinePos - m_pLoader->m_fLastPos;\r
1747             m_pLoader->m_fLastPos = fLinePos;\r
1748             m_pLoader->m_lineHeights.Add(fHeight);\r
1749         }\r
1750     }\r
1751     m_pBreak->ClearBreakPieces();\r
1752     if (dwStatus == FX_RTFBREAK_ParagraphBreak) {\r
1753         m_pBreak->Reset();\r
1754         if (pStyle == NULL && bEndBreak) {\r
1755             CXFA_Para para = m_pTextProvider->GetParaNode();\r
1756             if (para.IsExistInXML()) {\r
1757                 FX_FLOAT fStartPos = para.GetMarginLeft();\r
1758                 FX_FLOAT fIndent = para.GetTextIndent();\r
1759                 if (fIndent > 0) {\r
1760                     fStartPos += fIndent;\r
1761                 }\r
1762                 FX_FLOAT fSpaceBelow = para.GetSpaceBelow();\r
1763                 if (fSpaceBelow < 0.1f) {\r
1764                     fSpaceBelow = 0;\r
1765                 }\r
1766                 m_pBreak->SetLinePos(fStartPos);\r
1767                 fLinePos += fSpaceBelow;\r
1768             }\r
1769         }\r
1770     }\r
1771     if (pStyle != NULL) {\r
1772         FX_FLOAT fStart = 0;\r
1773         const FDE_CSSRECT *pRect = pStyle->GetBoundaryStyles()->GetMarginWidth();\r
1774         if (pRect) {\r
1775             fStart = pRect->left.GetValue();\r
1776         }\r
1777         FX_FLOAT fTextIndent = pStyle->GetParagraphStyles()->GetTextIndent().GetValue();\r
1778         if (fTextIndent < 0) {\r
1779             fStart -= fTextIndent;\r
1780         }\r
1781         m_pBreak->SetLinePos(fStart);\r
1782     }\r
1783     m_iLines++;\r
1784 }\r
1785 void CXFA_TextLayout::RenderString(IFDE_RenderDevice *pDevice, IFDE_SolidBrush *pBrush, CXFA_PieceLine *pPieceLine, int32_t iPiece, FXTEXT_CHARPOS *pCharPos, const CFX_Matrix &tmDoc2Device)\r
1786 {\r
1787     XFA_LPCTEXTPIECE pPiece = pPieceLine->m_textPieces.GetAt(iPiece);\r
1788     int32_t iCount = GetDisplayPos(pPiece, pCharPos);\r
1789     if (iCount > 0) {\r
1790         pBrush->SetColor(pPiece->dwColor);\r
1791         pDevice->DrawString(pBrush, pPiece->pFont, pCharPos, iCount, pPiece->fFontSize, &tmDoc2Device);\r
1792     }\r
1793     pPieceLine->m_charCounts.Add(iCount);\r
1794 }\r
1795 void CXFA_TextLayout::RenderPath(IFDE_RenderDevice *pDevice, IFDE_Pen *pPen, CXFA_PieceLine *pPieceLine, int32_t iPiece, FXTEXT_CHARPOS *pCharPos, const CFX_Matrix &tmDoc2Device)\r
1796 {\r
1797     XFA_TEXTPIECE *pPiece = pPieceLine->m_textPieces.GetAt(iPiece);\r
1798     FX_BOOL bNoUnderline = pPiece->iUnderline < 1 || pPiece->iUnderline > 2;\r
1799     FX_BOOL bNoLineThrough = pPiece->iLineThrough < 1 || pPiece->iLineThrough > 2;\r
1800     if (bNoUnderline && bNoLineThrough) {\r
1801         return;\r
1802     }\r
1803     pPen->SetColor(pPiece->dwColor);\r
1804     IFDE_Path *pPath = IFDE_Path::Create();\r
1805     int32_t iChars = GetDisplayPos(pPiece, pCharPos);\r
1806     if (iChars > 0) {\r
1807         CFX_PointF pt1, pt2;\r
1808         FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f;\r
1809         int32_t i = 0;\r
1810         if (pPiece->iPeriod == XFA_ATTRIBUTEENUM_Word) {\r
1811             for (int32_t i = 0; i < pPiece->iUnderline; i++) {\r
1812                 for (int32_t j = 0; j < iChars; j++) {\r
1813                     pt1.x = pCharPos[j].m_OriginX;\r
1814                     pt2.x = pt1.x + pCharPos[j].m_FontCharWidth * pPiece->fFontSize / 1000.0f;\r
1815                     pt1.y = pt2.y = fEndY;\r
1816                     pPath->AddLine(pt1, pt2);\r
1817                 }\r
1818                 fEndY += 2.0f;\r
1819             }\r
1820         } else {\r
1821             pt1.x = pCharPos[0].m_OriginX;\r
1822             pt2.x = pCharPos[iChars - 1].m_OriginX + pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;\r
1823             for (int32_t i = 0; i < pPiece->iUnderline; i++) {\r
1824                 pt1.y = pt2.y = fEndY;\r
1825                 pPath->AddLine(pt1, pt2);\r
1826                 fEndY += 2.0f;\r
1827             }\r
1828         }\r
1829         fEndY = pCharPos[0].m_OriginY - pPiece->rtPiece.height * 0.25f;\r
1830         pt1.x = pCharPos[0].m_OriginX;\r
1831         pt2.x = pCharPos[iChars - 1].m_OriginX + pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;\r
1832         for (i = 0; i < pPiece->iLineThrough; i++) {\r
1833             pt1.y = pt2.y = fEndY;\r
1834             pPath->AddLine(pt1, pt2);\r
1835             fEndY += 2.0f;\r
1836         }\r
1837     } else {\r
1838         if (bNoLineThrough && (bNoUnderline || pPiece->iPeriod != XFA_ATTRIBUTEENUM_All)) {\r
1839             goto XFA_RenderPathRet;\r
1840         }\r
1841         int32_t iCharsTmp = 0;\r
1842         int32_t iPiecePrev = iPiece, iPieceNext = iPiece;\r
1843         while (iPiecePrev > 0) {\r
1844             iPiecePrev--;\r
1845             iCharsTmp = pPieceLine->m_charCounts.GetAt(iPiecePrev);\r
1846             if (iCharsTmp > 0) {\r
1847                 break;\r
1848             }\r
1849         }\r
1850         if (iCharsTmp == 0) {\r
1851             goto XFA_RenderPathRet;\r
1852         }\r
1853         iCharsTmp = 0;\r
1854         int32_t iPieces = pPieceLine->m_textPieces.GetSize();\r
1855         while (iPieceNext < iPieces - 1) {\r
1856             iPieceNext++;\r
1857             iCharsTmp = pPieceLine->m_charCounts.GetAt(iPieceNext);\r
1858             if (iCharsTmp > 0) {\r
1859                 break;\r
1860             }\r
1861         }\r
1862         if (iCharsTmp == 0) {\r
1863             goto XFA_RenderPathRet;\r
1864         }\r
1865         FX_FLOAT fOrgX = 0.0f, fEndX = 0.0f;\r
1866         pPiece = pPieceLine->m_textPieces.GetAt(iPiecePrev);\r
1867         iChars = GetDisplayPos(pPiece, pCharPos);\r
1868         if (iChars < 1) {\r
1869             goto XFA_RenderPathRet;\r
1870         }\r
1871         fOrgX = pCharPos[iChars - 1].m_OriginX + pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;\r
1872         pPiece = pPieceLine->m_textPieces.GetAt(iPieceNext);\r
1873         iChars = GetDisplayPos(pPiece, pCharPos);\r
1874         if (iChars < 1) {\r
1875             goto XFA_RenderPathRet;\r
1876         }\r
1877         fEndX = pCharPos[0].m_OriginX;\r
1878         CFX_PointF pt1, pt2;\r
1879         pt1.x = fOrgX, pt2.x = fEndX;\r
1880         FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f;\r
1881         int32_t i = 0;\r
1882         for (i = 0; i < pPiece->iUnderline; i++) {\r
1883             pt1.y = pt2.y = fEndY;\r
1884             pPath->AddLine(pt1, pt2);\r
1885             fEndY += 2.0f;\r
1886         }\r
1887         fEndY = pCharPos[0].m_OriginY - pPiece->rtPiece.height * 0.25f;\r
1888         for (i = 0; i < pPiece->iLineThrough; i++) {\r
1889             pt1.y = pt2.y = fEndY;\r
1890             pPath->AddLine(pt1, pt2);\r
1891             fEndY += 2.0f;\r
1892         }\r
1893     }\r
1894     pDevice->DrawPath(pPen, 1, pPath, &tmDoc2Device);\r
1895 XFA_RenderPathRet:\r
1896     pPath->Release();\r
1897 }\r
1898 int32_t CXFA_TextLayout::GetDisplayPos(XFA_LPCTEXTPIECE pPiece, FXTEXT_CHARPOS *pCharPos, FX_BOOL bCharCode )\r
1899 {\r
1900     if (pPiece == NULL) {\r
1901         return 0;\r
1902     }\r
1903     FX_RTFTEXTOBJ tr;\r
1904     if (!ToRun(pPiece, tr)) {\r
1905         return 0;\r
1906     }\r
1907     return m_pBreak->GetDisplayPos(&tr, pCharPos, bCharCode);\r
1908 }\r
1909 FX_BOOL CXFA_TextLayout::ToRun(XFA_LPCTEXTPIECE pPiece, FX_RTFTEXTOBJ &tr)\r
1910 {\r
1911     int32_t iLength = pPiece->iChars;\r
1912     if (iLength < 1) {\r
1913         return FALSE;\r
1914     }\r
1915     tr.pStr             = pPiece->pszText;\r
1916     tr.pFont    = pPiece->pFont;\r
1917     tr.pRect    = &pPiece->rtPiece;\r
1918     tr.pWidths  = pPiece->pWidths;\r
1919     tr.iLength  = iLength;\r
1920     tr.fFontSize        = pPiece->fFontSize;\r
1921     tr.iBidiLevel       = pPiece->iBidiLevel;\r
1922     tr.iCharRotation = 0;\r
1923     tr.wLineBreakChar = L'\n';\r
1924     tr.iVerticalScale = pPiece->iVerScale;\r
1925     tr.dwLayoutStyles = FX_RTFLAYOUTSTYLE_ExpandTab;\r
1926     tr.iHorizontalScale = pPiece->iHorScale;\r
1927     return TRUE;\r
1928 }\r