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