xref: /aosp_15_r20/external/pdfium/xfa/fxfa/cxfa_textlayout.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2017 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker 
5*3ac0a46fSAndroid Build Coastguard Worker // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6*3ac0a46fSAndroid Build Coastguard Worker 
7*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_textlayout.h"
8*3ac0a46fSAndroid Build Coastguard Worker 
9*3ac0a46fSAndroid Build Coastguard Worker #include <math.h>
10*3ac0a46fSAndroid Build Coastguard Worker 
11*3ac0a46fSAndroid Build Coastguard Worker #include <algorithm>
12*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
13*3ac0a46fSAndroid Build Coastguard Worker 
14*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/css/cfx_csscomputedstyle.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/css/cfx_cssstyleselector.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/stl_util.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/xml/cfx_xmlelement.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/xml/cfx_xmlnode.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/xml/cfx_xmltext.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/cfx_fillrenderoptions.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/cfx_graphstatedata.h"
22*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/cfx_path.h"
23*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/cfx_renderdevice.h"
24*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/text_char_pos.h"
25*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/xfa/cjx_object.h"
26*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/check.h"
27*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/notreached.h"
28*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fde/cfde_textout.h"
29*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/font/cfgas_gefont.h"
30*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/layout/cfgas_linkuserdata.h"
31*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/layout/cfgas_rtfbreak.h"
32*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/layout/cfgas_textuserdata.h"
33*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_ffdoc.h"
34*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_textparser.h"
35*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_textprovider.h"
36*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_texttabstopscontext.h"
37*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_font.h"
38*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_node.h"
39*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_para.h"
40*3ac0a46fSAndroid Build Coastguard Worker 
41*3ac0a46fSAndroid Build Coastguard Worker namespace {
42*3ac0a46fSAndroid Build Coastguard Worker 
43*3ac0a46fSAndroid Build Coastguard Worker constexpr float kHeightTolerance = 0.001f;
44*3ac0a46fSAndroid Build Coastguard Worker 
ProcessText(WideString * pText)45*3ac0a46fSAndroid Build Coastguard Worker void ProcessText(WideString* pText) {
46*3ac0a46fSAndroid Build Coastguard Worker   size_t iLen = pText->GetLength();
47*3ac0a46fSAndroid Build Coastguard Worker   if (iLen == 0)
48*3ac0a46fSAndroid Build Coastguard Worker     return;
49*3ac0a46fSAndroid Build Coastguard Worker 
50*3ac0a46fSAndroid Build Coastguard Worker   size_t iTrimLeft = 0;
51*3ac0a46fSAndroid Build Coastguard Worker   {
52*3ac0a46fSAndroid Build Coastguard Worker     // Span's lifetime must end before ReleaseBuffer() below.
53*3ac0a46fSAndroid Build Coastguard Worker     pdfium::span<wchar_t> psz = pText->GetBuffer(iLen);
54*3ac0a46fSAndroid Build Coastguard Worker     wchar_t wPrev = 0;
55*3ac0a46fSAndroid Build Coastguard Worker     for (size_t i = 0; i < iLen; i++) {
56*3ac0a46fSAndroid Build Coastguard Worker       wchar_t wch = psz[i];
57*3ac0a46fSAndroid Build Coastguard Worker       if (wch < 0x20)
58*3ac0a46fSAndroid Build Coastguard Worker         wch = 0x20;
59*3ac0a46fSAndroid Build Coastguard Worker       if (wch == 0x20 && wPrev == 0x20)
60*3ac0a46fSAndroid Build Coastguard Worker         continue;
61*3ac0a46fSAndroid Build Coastguard Worker 
62*3ac0a46fSAndroid Build Coastguard Worker       wPrev = wch;
63*3ac0a46fSAndroid Build Coastguard Worker       psz[iTrimLeft++] = wch;
64*3ac0a46fSAndroid Build Coastguard Worker     }
65*3ac0a46fSAndroid Build Coastguard Worker   }
66*3ac0a46fSAndroid Build Coastguard Worker   pText->ReleaseBuffer(iTrimLeft);
67*3ac0a46fSAndroid Build Coastguard Worker }
68*3ac0a46fSAndroid Build Coastguard Worker 
69*3ac0a46fSAndroid Build Coastguard Worker }  // namespace
70*3ac0a46fSAndroid Build Coastguard Worker 
71*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextLayout::TextPiece::TextPiece() = default;
72*3ac0a46fSAndroid Build Coastguard Worker 
73*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextLayout::TextPiece::~TextPiece() = default;
74*3ac0a46fSAndroid Build Coastguard Worker 
75*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextLayout::PieceLine::PieceLine() = default;
76*3ac0a46fSAndroid Build Coastguard Worker 
77*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextLayout::PieceLine::~PieceLine() = default;
78*3ac0a46fSAndroid Build Coastguard Worker 
79*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextLayout::LoaderContext::LoaderContext() = default;
80*3ac0a46fSAndroid Build Coastguard Worker 
81*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextLayout::LoaderContext::~LoaderContext() = default;
82*3ac0a46fSAndroid Build Coastguard Worker 
Trace(cppgc::Visitor * visitor) const83*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::LoaderContext::Trace(cppgc::Visitor* visitor) const {
84*3ac0a46fSAndroid Build Coastguard Worker   visitor->Trace(pNode);
85*3ac0a46fSAndroid Build Coastguard Worker }
86*3ac0a46fSAndroid Build Coastguard Worker 
CXFA_TextLayout(CXFA_FFDoc * doc,CXFA_TextProvider * pTextProvider)87*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextLayout::CXFA_TextLayout(CXFA_FFDoc* doc,
88*3ac0a46fSAndroid Build Coastguard Worker                                  CXFA_TextProvider* pTextProvider)
89*3ac0a46fSAndroid Build Coastguard Worker     : m_pDoc(doc),
90*3ac0a46fSAndroid Build Coastguard Worker       m_pTextProvider(pTextProvider),
91*3ac0a46fSAndroid Build Coastguard Worker       m_pTextParser(cppgc::MakeGarbageCollected<CXFA_TextParser>(
92*3ac0a46fSAndroid Build Coastguard Worker           doc->GetHeap()->GetAllocationHandle())) {
93*3ac0a46fSAndroid Build Coastguard Worker   DCHECK(m_pTextProvider);
94*3ac0a46fSAndroid Build Coastguard Worker }
95*3ac0a46fSAndroid Build Coastguard Worker 
96*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextLayout::~CXFA_TextLayout() = default;
97*3ac0a46fSAndroid Build Coastguard Worker 
Trace(cppgc::Visitor * visitor) const98*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::Trace(cppgc::Visitor* visitor) const {
99*3ac0a46fSAndroid Build Coastguard Worker   visitor->Trace(m_pDoc);
100*3ac0a46fSAndroid Build Coastguard Worker   visitor->Trace(m_pTextProvider);
101*3ac0a46fSAndroid Build Coastguard Worker   visitor->Trace(m_pTextDataNode);
102*3ac0a46fSAndroid Build Coastguard Worker   visitor->Trace(m_pTextParser);
103*3ac0a46fSAndroid Build Coastguard Worker   visitor->Trace(m_pLoader);
104*3ac0a46fSAndroid Build Coastguard Worker }
105*3ac0a46fSAndroid Build Coastguard Worker 
Unload()106*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::Unload() {
107*3ac0a46fSAndroid Build Coastguard Worker   m_pieceLines.clear();
108*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak.reset();
109*3ac0a46fSAndroid Build Coastguard Worker }
110*3ac0a46fSAndroid Build Coastguard Worker 
GetLinkURLAtPoint(const CFX_PointF & point)111*3ac0a46fSAndroid Build Coastguard Worker WideString CXFA_TextLayout::GetLinkURLAtPoint(const CFX_PointF& point) {
112*3ac0a46fSAndroid Build Coastguard Worker   for (const auto& pPieceLine : m_pieceLines) {
113*3ac0a46fSAndroid Build Coastguard Worker     for (const auto& pPiece : pPieceLine->m_textPieces) {
114*3ac0a46fSAndroid Build Coastguard Worker       if (pPiece->pLinkData && pPiece->rtPiece.Contains(point))
115*3ac0a46fSAndroid Build Coastguard Worker         return pPiece->pLinkData->GetLinkURL();
116*3ac0a46fSAndroid Build Coastguard Worker     }
117*3ac0a46fSAndroid Build Coastguard Worker   }
118*3ac0a46fSAndroid Build Coastguard Worker   return WideString();
119*3ac0a46fSAndroid Build Coastguard Worker }
120*3ac0a46fSAndroid Build Coastguard Worker 
GetTextDataNode()121*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::GetTextDataNode() {
122*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Node* pNode = m_pTextProvider->GetTextNode(&m_bRichText);
123*3ac0a46fSAndroid Build Coastguard Worker   if (pNode && m_bRichText)
124*3ac0a46fSAndroid Build Coastguard Worker     m_pTextParser->Reset();
125*3ac0a46fSAndroid Build Coastguard Worker 
126*3ac0a46fSAndroid Build Coastguard Worker   m_pTextDataNode = pNode;
127*3ac0a46fSAndroid Build Coastguard Worker }
128*3ac0a46fSAndroid Build Coastguard Worker 
GetXMLContainerNode()129*3ac0a46fSAndroid Build Coastguard Worker CFX_XMLNode* CXFA_TextLayout::GetXMLContainerNode() {
130*3ac0a46fSAndroid Build Coastguard Worker   if (!m_bRichText)
131*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
132*3ac0a46fSAndroid Build Coastguard Worker 
133*3ac0a46fSAndroid Build Coastguard Worker   CFX_XMLNode* pXMLRoot = m_pTextDataNode->GetXMLMappingNode();
134*3ac0a46fSAndroid Build Coastguard Worker   if (!pXMLRoot)
135*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
136*3ac0a46fSAndroid Build Coastguard Worker 
137*3ac0a46fSAndroid Build Coastguard Worker   for (CFX_XMLNode* pXMLChild = pXMLRoot->GetFirstChild(); pXMLChild;
138*3ac0a46fSAndroid Build Coastguard Worker        pXMLChild = pXMLChild->GetNextSibling()) {
139*3ac0a46fSAndroid Build Coastguard Worker     CFX_XMLElement* pXMLElement = ToXMLElement(pXMLChild);
140*3ac0a46fSAndroid Build Coastguard Worker     if (!pXMLElement)
141*3ac0a46fSAndroid Build Coastguard Worker       continue;
142*3ac0a46fSAndroid Build Coastguard Worker     WideString wsTag = pXMLElement->GetLocalTagName();
143*3ac0a46fSAndroid Build Coastguard Worker     if (wsTag.EqualsASCII("body") || wsTag.EqualsASCII("html"))
144*3ac0a46fSAndroid Build Coastguard Worker       return pXMLChild;
145*3ac0a46fSAndroid Build Coastguard Worker   }
146*3ac0a46fSAndroid Build Coastguard Worker   return nullptr;
147*3ac0a46fSAndroid Build Coastguard Worker }
148*3ac0a46fSAndroid Build Coastguard Worker 
CreateBreak(bool bDefault)149*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<CFGAS_RTFBreak> CXFA_TextLayout::CreateBreak(bool bDefault) {
150*3ac0a46fSAndroid Build Coastguard Worker   Mask<CFGAS_Break::LayoutStyle> dwStyle = CFGAS_Break::LayoutStyle::kExpandTab;
151*3ac0a46fSAndroid Build Coastguard Worker   if (!bDefault)
152*3ac0a46fSAndroid Build Coastguard Worker     dwStyle |= CFGAS_Break::LayoutStyle::kPagination;
153*3ac0a46fSAndroid Build Coastguard Worker 
154*3ac0a46fSAndroid Build Coastguard Worker   auto pBreak = std::make_unique<CFGAS_RTFBreak>(dwStyle);
155*3ac0a46fSAndroid Build Coastguard Worker   pBreak->SetLineBreakTolerance(1);
156*3ac0a46fSAndroid Build Coastguard Worker   pBreak->SetFont(
157*3ac0a46fSAndroid Build Coastguard Worker       m_pTextParser->GetFont(m_pDoc.Get(), m_pTextProvider, nullptr));
158*3ac0a46fSAndroid Build Coastguard Worker   pBreak->SetFontSize(m_pTextParser->GetFontSize(m_pTextProvider, nullptr));
159*3ac0a46fSAndroid Build Coastguard Worker   return pBreak;
160*3ac0a46fSAndroid Build Coastguard Worker }
161*3ac0a46fSAndroid Build Coastguard Worker 
InitBreak(float fLineWidth)162*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::InitBreak(float fLineWidth) {
163*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Para* para = m_pTextProvider->GetParaIfExists();
164*3ac0a46fSAndroid Build Coastguard Worker   float fStart = 0;
165*3ac0a46fSAndroid Build Coastguard Worker   float fStartPos = 0;
166*3ac0a46fSAndroid Build Coastguard Worker   if (para) {
167*3ac0a46fSAndroid Build Coastguard Worker     CFGAS_RTFBreak::LineAlignment iAlign = CFGAS_RTFBreak::LineAlignment::Left;
168*3ac0a46fSAndroid Build Coastguard Worker     switch (para->GetHorizontalAlign()) {
169*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Center:
170*3ac0a46fSAndroid Build Coastguard Worker         iAlign = CFGAS_RTFBreak::LineAlignment::Center;
171*3ac0a46fSAndroid Build Coastguard Worker         break;
172*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Right:
173*3ac0a46fSAndroid Build Coastguard Worker         iAlign = CFGAS_RTFBreak::LineAlignment::Right;
174*3ac0a46fSAndroid Build Coastguard Worker         break;
175*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Justify:
176*3ac0a46fSAndroid Build Coastguard Worker         iAlign = CFGAS_RTFBreak::LineAlignment::Justified;
177*3ac0a46fSAndroid Build Coastguard Worker         break;
178*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::JustifyAll:
179*3ac0a46fSAndroid Build Coastguard Worker         iAlign = CFGAS_RTFBreak::LineAlignment::Distributed;
180*3ac0a46fSAndroid Build Coastguard Worker         break;
181*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Left:
182*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Radix:
183*3ac0a46fSAndroid Build Coastguard Worker         break;
184*3ac0a46fSAndroid Build Coastguard Worker       default:
185*3ac0a46fSAndroid Build Coastguard Worker         NOTREACHED_NORETURN();
186*3ac0a46fSAndroid Build Coastguard Worker     }
187*3ac0a46fSAndroid Build Coastguard Worker     m_pBreak->SetAlignment(iAlign);
188*3ac0a46fSAndroid Build Coastguard Worker 
189*3ac0a46fSAndroid Build Coastguard Worker     fStart = para->GetMarginLeft();
190*3ac0a46fSAndroid Build Coastguard Worker     if (m_pTextProvider->IsCheckButtonAndAutoWidth()) {
191*3ac0a46fSAndroid Build Coastguard Worker       if (iAlign != CFGAS_RTFBreak::LineAlignment::Left)
192*3ac0a46fSAndroid Build Coastguard Worker         fLineWidth -= para->GetMarginRight();
193*3ac0a46fSAndroid Build Coastguard Worker     } else {
194*3ac0a46fSAndroid Build Coastguard Worker       fLineWidth -= para->GetMarginRight();
195*3ac0a46fSAndroid Build Coastguard Worker     }
196*3ac0a46fSAndroid Build Coastguard Worker     if (fLineWidth < 0)
197*3ac0a46fSAndroid Build Coastguard Worker       fLineWidth = fStart;
198*3ac0a46fSAndroid Build Coastguard Worker 
199*3ac0a46fSAndroid Build Coastguard Worker     fStartPos = fStart;
200*3ac0a46fSAndroid Build Coastguard Worker     float fIndent = para->GetTextIndent();
201*3ac0a46fSAndroid Build Coastguard Worker     if (fIndent > 0)
202*3ac0a46fSAndroid Build Coastguard Worker       fStartPos += fIndent;
203*3ac0a46fSAndroid Build Coastguard Worker   }
204*3ac0a46fSAndroid Build Coastguard Worker 
205*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak->SetLineBoundary(fStart, fLineWidth);
206*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak->SetLineStartPos(fStartPos);
207*3ac0a46fSAndroid Build Coastguard Worker 
208*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Font* font = m_pTextProvider->GetFontIfExists();
209*3ac0a46fSAndroid Build Coastguard Worker   if (font) {
210*3ac0a46fSAndroid Build Coastguard Worker     m_pBreak->SetHorizontalScale(
211*3ac0a46fSAndroid Build Coastguard Worker         static_cast<int32_t>(font->GetHorizontalScale()));
212*3ac0a46fSAndroid Build Coastguard Worker     m_pBreak->SetVerticalScale(static_cast<int32_t>(font->GetVerticalScale()));
213*3ac0a46fSAndroid Build Coastguard Worker     m_pBreak->SetCharSpace(font->GetLetterSpacing());
214*3ac0a46fSAndroid Build Coastguard Worker   }
215*3ac0a46fSAndroid Build Coastguard Worker 
216*3ac0a46fSAndroid Build Coastguard Worker   float fFontSize = m_pTextParser->GetFontSize(m_pTextProvider, nullptr);
217*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak->SetFontSize(fFontSize);
218*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak->SetFont(
219*3ac0a46fSAndroid Build Coastguard Worker       m_pTextParser->GetFont(m_pDoc.Get(), m_pTextProvider, nullptr));
220*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
221*3ac0a46fSAndroid Build Coastguard Worker }
222*3ac0a46fSAndroid Build Coastguard Worker 
InitBreak(CFX_CSSComputedStyle * pStyle,CFX_CSSDisplay eDisplay,float fLineWidth,const CFX_XMLNode * pXMLNode,CFX_CSSComputedStyle * pParentStyle)223*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::InitBreak(CFX_CSSComputedStyle* pStyle,
224*3ac0a46fSAndroid Build Coastguard Worker                                 CFX_CSSDisplay eDisplay,
225*3ac0a46fSAndroid Build Coastguard Worker                                 float fLineWidth,
226*3ac0a46fSAndroid Build Coastguard Worker                                 const CFX_XMLNode* pXMLNode,
227*3ac0a46fSAndroid Build Coastguard Worker                                 CFX_CSSComputedStyle* pParentStyle) {
228*3ac0a46fSAndroid Build Coastguard Worker   if (!pStyle) {
229*3ac0a46fSAndroid Build Coastguard Worker     InitBreak(fLineWidth);
230*3ac0a46fSAndroid Build Coastguard Worker     return;
231*3ac0a46fSAndroid Build Coastguard Worker   }
232*3ac0a46fSAndroid Build Coastguard Worker 
233*3ac0a46fSAndroid Build Coastguard Worker   if (eDisplay == CFX_CSSDisplay::Block ||
234*3ac0a46fSAndroid Build Coastguard Worker       eDisplay == CFX_CSSDisplay::ListItem) {
235*3ac0a46fSAndroid Build Coastguard Worker     CFGAS_RTFBreak::LineAlignment iAlign = CFGAS_RTFBreak::LineAlignment::Left;
236*3ac0a46fSAndroid Build Coastguard Worker     switch (pStyle->GetTextAlign()) {
237*3ac0a46fSAndroid Build Coastguard Worker       case CFX_CSSTextAlign::Right:
238*3ac0a46fSAndroid Build Coastguard Worker         iAlign = CFGAS_RTFBreak::LineAlignment::Right;
239*3ac0a46fSAndroid Build Coastguard Worker         break;
240*3ac0a46fSAndroid Build Coastguard Worker       case CFX_CSSTextAlign::Center:
241*3ac0a46fSAndroid Build Coastguard Worker         iAlign = CFGAS_RTFBreak::LineAlignment::Center;
242*3ac0a46fSAndroid Build Coastguard Worker         break;
243*3ac0a46fSAndroid Build Coastguard Worker       case CFX_CSSTextAlign::Justify:
244*3ac0a46fSAndroid Build Coastguard Worker         iAlign = CFGAS_RTFBreak::LineAlignment::Justified;
245*3ac0a46fSAndroid Build Coastguard Worker         break;
246*3ac0a46fSAndroid Build Coastguard Worker       case CFX_CSSTextAlign::JustifyAll:
247*3ac0a46fSAndroid Build Coastguard Worker         iAlign = CFGAS_RTFBreak::LineAlignment::Distributed;
248*3ac0a46fSAndroid Build Coastguard Worker         break;
249*3ac0a46fSAndroid Build Coastguard Worker       default:
250*3ac0a46fSAndroid Build Coastguard Worker         break;
251*3ac0a46fSAndroid Build Coastguard Worker     }
252*3ac0a46fSAndroid Build Coastguard Worker     m_pBreak->SetAlignment(iAlign);
253*3ac0a46fSAndroid Build Coastguard Worker 
254*3ac0a46fSAndroid Build Coastguard Worker     float fStart = 0;
255*3ac0a46fSAndroid Build Coastguard Worker     const CFX_CSSRect* pRect = pStyle->GetMarginWidth();
256*3ac0a46fSAndroid Build Coastguard Worker     const CFX_CSSRect* pPaddingRect = pStyle->GetPaddingWidth();
257*3ac0a46fSAndroid Build Coastguard Worker     if (pRect) {
258*3ac0a46fSAndroid Build Coastguard Worker       fStart = pRect->left.GetValue();
259*3ac0a46fSAndroid Build Coastguard Worker       fLineWidth -= pRect->right.GetValue();
260*3ac0a46fSAndroid Build Coastguard Worker       if (pPaddingRect) {
261*3ac0a46fSAndroid Build Coastguard Worker         fStart += pPaddingRect->left.GetValue();
262*3ac0a46fSAndroid Build Coastguard Worker         fLineWidth -= pPaddingRect->right.GetValue();
263*3ac0a46fSAndroid Build Coastguard Worker       }
264*3ac0a46fSAndroid Build Coastguard Worker       if (eDisplay == CFX_CSSDisplay::ListItem) {
265*3ac0a46fSAndroid Build Coastguard Worker         const CFX_CSSRect* pParRect = pParentStyle->GetMarginWidth();
266*3ac0a46fSAndroid Build Coastguard Worker         const CFX_CSSRect* pParPaddingRect = pParentStyle->GetPaddingWidth();
267*3ac0a46fSAndroid Build Coastguard Worker         if (pParRect) {
268*3ac0a46fSAndroid Build Coastguard Worker           fStart += pParRect->left.GetValue();
269*3ac0a46fSAndroid Build Coastguard Worker           fLineWidth -= pParRect->right.GetValue();
270*3ac0a46fSAndroid Build Coastguard Worker           if (pParPaddingRect) {
271*3ac0a46fSAndroid Build Coastguard Worker             fStart += pParPaddingRect->left.GetValue();
272*3ac0a46fSAndroid Build Coastguard Worker             fLineWidth -= pParPaddingRect->right.GetValue();
273*3ac0a46fSAndroid Build Coastguard Worker           }
274*3ac0a46fSAndroid Build Coastguard Worker         }
275*3ac0a46fSAndroid Build Coastguard Worker         CFX_CSSRect pNewRect;
276*3ac0a46fSAndroid Build Coastguard Worker         pNewRect.left.Set(CFX_CSSLengthUnit::Point, fStart);
277*3ac0a46fSAndroid Build Coastguard Worker         pNewRect.right.Set(CFX_CSSLengthUnit::Point, pRect->right.GetValue());
278*3ac0a46fSAndroid Build Coastguard Worker         pNewRect.top.Set(CFX_CSSLengthUnit::Point, pRect->top.GetValue());
279*3ac0a46fSAndroid Build Coastguard Worker         pNewRect.bottom.Set(CFX_CSSLengthUnit::Point, pRect->bottom.GetValue());
280*3ac0a46fSAndroid Build Coastguard Worker         pStyle->SetMarginWidth(pNewRect);
281*3ac0a46fSAndroid Build Coastguard Worker       }
282*3ac0a46fSAndroid Build Coastguard Worker     }
283*3ac0a46fSAndroid Build Coastguard Worker     m_pBreak->SetLineBoundary(fStart, fLineWidth);
284*3ac0a46fSAndroid Build Coastguard Worker     float fIndent = pStyle->GetTextIndent().GetValue();
285*3ac0a46fSAndroid Build Coastguard Worker     if (fIndent > 0)
286*3ac0a46fSAndroid Build Coastguard Worker       fStart += fIndent;
287*3ac0a46fSAndroid Build Coastguard Worker 
288*3ac0a46fSAndroid Build Coastguard Worker     m_pBreak->SetLineStartPos(fStart);
289*3ac0a46fSAndroid Build Coastguard Worker     m_pBreak->SetTabWidth(m_pTextParser->GetTabInterval(pStyle));
290*3ac0a46fSAndroid Build Coastguard Worker     if (!m_pTabstopContext)
291*3ac0a46fSAndroid Build Coastguard Worker       m_pTabstopContext = std::make_unique<CXFA_TextTabstopsContext>();
292*3ac0a46fSAndroid Build Coastguard Worker     m_pTextParser->GetTabstops(pStyle, m_pTabstopContext.get());
293*3ac0a46fSAndroid Build Coastguard Worker     for (const auto& stop : m_pTabstopContext->m_tabstops)
294*3ac0a46fSAndroid Build Coastguard Worker       m_pBreak->AddPositionedTab(stop.fTabstops);
295*3ac0a46fSAndroid Build Coastguard Worker   }
296*3ac0a46fSAndroid Build Coastguard Worker   float fFontSize = m_pTextParser->GetFontSize(m_pTextProvider, pStyle);
297*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak->SetFontSize(fFontSize);
298*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
299*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak->SetFont(
300*3ac0a46fSAndroid Build Coastguard Worker       m_pTextParser->GetFont(m_pDoc.Get(), m_pTextProvider, pStyle));
301*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak->SetHorizontalScale(
302*3ac0a46fSAndroid Build Coastguard Worker       m_pTextParser->GetHorScale(m_pTextProvider, pStyle, pXMLNode));
303*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak->SetVerticalScale(
304*3ac0a46fSAndroid Build Coastguard Worker       m_pTextParser->GetVerScale(m_pTextProvider, pStyle));
305*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak->SetCharSpace(pStyle->GetLetterSpacing().GetValue());
306*3ac0a46fSAndroid Build Coastguard Worker }
307*3ac0a46fSAndroid Build Coastguard Worker 
GetLayoutHeight()308*3ac0a46fSAndroid Build Coastguard Worker float CXFA_TextLayout::GetLayoutHeight() {
309*3ac0a46fSAndroid Build Coastguard Worker   if (!m_pLoader)
310*3ac0a46fSAndroid Build Coastguard Worker     return 0;
311*3ac0a46fSAndroid Build Coastguard Worker 
312*3ac0a46fSAndroid Build Coastguard Worker   if (m_pLoader->lineHeights.empty() && m_pLoader->fWidth > 0) {
313*3ac0a46fSAndroid Build Coastguard Worker     CFX_SizeF szMax(m_pLoader->fWidth, m_pLoader->fHeight);
314*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->bSaveLineHeight = true;
315*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->fLastPos = 0;
316*3ac0a46fSAndroid Build Coastguard Worker     CFX_SizeF szDef = CalcSize(szMax, szMax);
317*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->bSaveLineHeight = false;
318*3ac0a46fSAndroid Build Coastguard Worker     return szDef.height;
319*3ac0a46fSAndroid Build Coastguard Worker   }
320*3ac0a46fSAndroid Build Coastguard Worker 
321*3ac0a46fSAndroid Build Coastguard Worker   float fHeight = m_pLoader->fHeight;
322*3ac0a46fSAndroid Build Coastguard Worker   if (fHeight < 0.1f) {
323*3ac0a46fSAndroid Build Coastguard Worker     fHeight = 0;
324*3ac0a46fSAndroid Build Coastguard Worker     for (float value : m_pLoader->lineHeights)
325*3ac0a46fSAndroid Build Coastguard Worker       fHeight += value;
326*3ac0a46fSAndroid Build Coastguard Worker   }
327*3ac0a46fSAndroid Build Coastguard Worker   return fHeight;
328*3ac0a46fSAndroid Build Coastguard Worker }
329*3ac0a46fSAndroid Build Coastguard Worker 
StartLayout(float fWidth)330*3ac0a46fSAndroid Build Coastguard Worker float CXFA_TextLayout::StartLayout(float fWidth) {
331*3ac0a46fSAndroid Build Coastguard Worker   if (!m_pLoader)
332*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader = cppgc::MakeGarbageCollected<LoaderContext>(
333*3ac0a46fSAndroid Build Coastguard Worker         m_pDoc->GetHeap()->GetAllocationHandle());
334*3ac0a46fSAndroid Build Coastguard Worker 
335*3ac0a46fSAndroid Build Coastguard Worker   if (fWidth < 0 ||
336*3ac0a46fSAndroid Build Coastguard Worker       (m_pLoader->fWidth > -1 && fabs(fWidth - m_pLoader->fWidth) > 0)) {
337*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->lineHeights.clear();
338*3ac0a46fSAndroid Build Coastguard Worker     m_Blocks.clear();
339*3ac0a46fSAndroid Build Coastguard Worker     Unload();
340*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->fStartLineOffset = 0;
341*3ac0a46fSAndroid Build Coastguard Worker   }
342*3ac0a46fSAndroid Build Coastguard Worker   m_pLoader->fWidth = fWidth;
343*3ac0a46fSAndroid Build Coastguard Worker 
344*3ac0a46fSAndroid Build Coastguard Worker   if (fWidth >= 0)
345*3ac0a46fSAndroid Build Coastguard Worker     return fWidth;
346*3ac0a46fSAndroid Build Coastguard Worker 
347*3ac0a46fSAndroid Build Coastguard Worker   CFX_SizeF szMax;
348*3ac0a46fSAndroid Build Coastguard Worker 
349*3ac0a46fSAndroid Build Coastguard Worker   m_pLoader->bSaveLineHeight = true;
350*3ac0a46fSAndroid Build Coastguard Worker   m_pLoader->fLastPos = 0;
351*3ac0a46fSAndroid Build Coastguard Worker   CFX_SizeF szDef = CalcSize(szMax, szMax);
352*3ac0a46fSAndroid Build Coastguard Worker   m_pLoader->bSaveLineHeight = false;
353*3ac0a46fSAndroid Build Coastguard Worker   return szDef.width;
354*3ac0a46fSAndroid Build Coastguard Worker }
355*3ac0a46fSAndroid Build Coastguard Worker 
DoLayout(float fTextHeight)356*3ac0a46fSAndroid Build Coastguard Worker float CXFA_TextLayout::DoLayout(float fTextHeight) {
357*3ac0a46fSAndroid Build Coastguard Worker   if (!m_pLoader)
358*3ac0a46fSAndroid Build Coastguard Worker     return fTextHeight;
359*3ac0a46fSAndroid Build Coastguard Worker 
360*3ac0a46fSAndroid Build Coastguard Worker   UpdateLoaderHeight(fTextHeight);
361*3ac0a46fSAndroid Build Coastguard Worker   return fTextHeight;
362*3ac0a46fSAndroid Build Coastguard Worker }
363*3ac0a46fSAndroid Build Coastguard Worker 
DoSplitLayout(size_t szBlockIndex,float fCalcHeight,float fTextHeight)364*3ac0a46fSAndroid Build Coastguard Worker float CXFA_TextLayout::DoSplitLayout(size_t szBlockIndex,
365*3ac0a46fSAndroid Build Coastguard Worker                                      float fCalcHeight,
366*3ac0a46fSAndroid Build Coastguard Worker                                      float fTextHeight) {
367*3ac0a46fSAndroid Build Coastguard Worker   if (!m_pLoader)
368*3ac0a46fSAndroid Build Coastguard Worker     return fCalcHeight;
369*3ac0a46fSAndroid Build Coastguard Worker 
370*3ac0a46fSAndroid Build Coastguard Worker   UpdateLoaderHeight(fTextHeight);
371*3ac0a46fSAndroid Build Coastguard Worker 
372*3ac0a46fSAndroid Build Coastguard Worker   if (fCalcHeight < 0)
373*3ac0a46fSAndroid Build Coastguard Worker     return fCalcHeight;
374*3ac0a46fSAndroid Build Coastguard Worker 
375*3ac0a46fSAndroid Build Coastguard Worker   m_bHasBlock = true;
376*3ac0a46fSAndroid Build Coastguard Worker   if (m_Blocks.empty() && m_pLoader->fHeight > 0) {
377*3ac0a46fSAndroid Build Coastguard Worker     float fHeight = fTextHeight - GetLayoutHeight();
378*3ac0a46fSAndroid Build Coastguard Worker     if (fHeight > 0) {
379*3ac0a46fSAndroid Build Coastguard Worker       XFA_AttributeValue iAlign = m_pTextParser->GetVAlign(m_pTextProvider);
380*3ac0a46fSAndroid Build Coastguard Worker       if (iAlign == XFA_AttributeValue::Middle)
381*3ac0a46fSAndroid Build Coastguard Worker         fHeight /= 2.0f;
382*3ac0a46fSAndroid Build Coastguard Worker       else if (iAlign != XFA_AttributeValue::Bottom)
383*3ac0a46fSAndroid Build Coastguard Worker         fHeight = 0;
384*3ac0a46fSAndroid Build Coastguard Worker       m_pLoader->fStartLineOffset = fHeight;
385*3ac0a46fSAndroid Build Coastguard Worker     }
386*3ac0a46fSAndroid Build Coastguard Worker   }
387*3ac0a46fSAndroid Build Coastguard Worker 
388*3ac0a46fSAndroid Build Coastguard Worker   float fLinePos = m_pLoader->fStartLineOffset;
389*3ac0a46fSAndroid Build Coastguard Worker   size_t szLineIndex = 0;
390*3ac0a46fSAndroid Build Coastguard Worker   if (!m_Blocks.empty()) {
391*3ac0a46fSAndroid Build Coastguard Worker     if (szBlockIndex < m_Blocks.size())
392*3ac0a46fSAndroid Build Coastguard Worker       szLineIndex = m_Blocks[szBlockIndex].szIndex;
393*3ac0a46fSAndroid Build Coastguard Worker     else
394*3ac0a46fSAndroid Build Coastguard Worker       szLineIndex = GetNextIndexFromLastBlockData();
395*3ac0a46fSAndroid Build Coastguard Worker     for (size_t i = 0;
396*3ac0a46fSAndroid Build Coastguard Worker          i < std::min(szBlockIndex, m_pLoader->blockHeights.size()); ++i) {
397*3ac0a46fSAndroid Build Coastguard Worker       fLinePos -= m_pLoader->blockHeights[i].fHeight;
398*3ac0a46fSAndroid Build Coastguard Worker     }
399*3ac0a46fSAndroid Build Coastguard Worker   }
400*3ac0a46fSAndroid Build Coastguard Worker 
401*3ac0a46fSAndroid Build Coastguard Worker   if (szLineIndex >= m_pLoader->lineHeights.size())
402*3ac0a46fSAndroid Build Coastguard Worker     return fCalcHeight;
403*3ac0a46fSAndroid Build Coastguard Worker 
404*3ac0a46fSAndroid Build Coastguard Worker   if (m_pLoader->lineHeights[szLineIndex] - fCalcHeight > kHeightTolerance)
405*3ac0a46fSAndroid Build Coastguard Worker     return 0;
406*3ac0a46fSAndroid Build Coastguard Worker 
407*3ac0a46fSAndroid Build Coastguard Worker   for (size_t i = szLineIndex; i < m_pLoader->lineHeights.size(); ++i) {
408*3ac0a46fSAndroid Build Coastguard Worker     float fLineHeight = m_pLoader->lineHeights[i];
409*3ac0a46fSAndroid Build Coastguard Worker     if (fLinePos + fLineHeight - fCalcHeight <= kHeightTolerance) {
410*3ac0a46fSAndroid Build Coastguard Worker       fLinePos += fLineHeight;
411*3ac0a46fSAndroid Build Coastguard Worker       continue;
412*3ac0a46fSAndroid Build Coastguard Worker     }
413*3ac0a46fSAndroid Build Coastguard Worker 
414*3ac0a46fSAndroid Build Coastguard Worker     if (szBlockIndex < m_Blocks.size())
415*3ac0a46fSAndroid Build Coastguard Worker       m_Blocks[szBlockIndex] = {szLineIndex, i - szLineIndex};
416*3ac0a46fSAndroid Build Coastguard Worker     else
417*3ac0a46fSAndroid Build Coastguard Worker       m_Blocks.push_back({szLineIndex, i - szLineIndex});
418*3ac0a46fSAndroid Build Coastguard Worker 
419*3ac0a46fSAndroid Build Coastguard Worker     if (i != szLineIndex)
420*3ac0a46fSAndroid Build Coastguard Worker       return fLinePos;
421*3ac0a46fSAndroid Build Coastguard Worker 
422*3ac0a46fSAndroid Build Coastguard Worker     if (fCalcHeight > fLinePos)
423*3ac0a46fSAndroid Build Coastguard Worker       return fCalcHeight;
424*3ac0a46fSAndroid Build Coastguard Worker 
425*3ac0a46fSAndroid Build Coastguard Worker     if (szBlockIndex < m_pLoader->blockHeights.size() &&
426*3ac0a46fSAndroid Build Coastguard Worker         m_pLoader->blockHeights[szBlockIndex].szBlockIndex == szBlockIndex) {
427*3ac0a46fSAndroid Build Coastguard Worker       m_pLoader->blockHeights[szBlockIndex].fHeight = fCalcHeight;
428*3ac0a46fSAndroid Build Coastguard Worker     } else {
429*3ac0a46fSAndroid Build Coastguard Worker       m_pLoader->blockHeights.push_back({szBlockIndex, fCalcHeight});
430*3ac0a46fSAndroid Build Coastguard Worker     }
431*3ac0a46fSAndroid Build Coastguard Worker     return fCalcHeight;
432*3ac0a46fSAndroid Build Coastguard Worker   }
433*3ac0a46fSAndroid Build Coastguard Worker   return fCalcHeight;
434*3ac0a46fSAndroid Build Coastguard Worker }
435*3ac0a46fSAndroid Build Coastguard Worker 
CountBlocks() const436*3ac0a46fSAndroid Build Coastguard Worker size_t CXFA_TextLayout::CountBlocks() const {
437*3ac0a46fSAndroid Build Coastguard Worker   size_t szCount = m_Blocks.size();
438*3ac0a46fSAndroid Build Coastguard Worker   return szCount > 0 ? szCount : 1;
439*3ac0a46fSAndroid Build Coastguard Worker }
440*3ac0a46fSAndroid Build Coastguard Worker 
GetNextIndexFromLastBlockData() const441*3ac0a46fSAndroid Build Coastguard Worker size_t CXFA_TextLayout::GetNextIndexFromLastBlockData() const {
442*3ac0a46fSAndroid Build Coastguard Worker   return m_Blocks.back().szIndex + m_Blocks.back().szLength;
443*3ac0a46fSAndroid Build Coastguard Worker }
444*3ac0a46fSAndroid Build Coastguard Worker 
UpdateLoaderHeight(float fTextHeight)445*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::UpdateLoaderHeight(float fTextHeight) {
446*3ac0a46fSAndroid Build Coastguard Worker   m_pLoader->fHeight = fTextHeight;
447*3ac0a46fSAndroid Build Coastguard Worker   if (m_pLoader->fHeight < 0)
448*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->fHeight = GetLayoutHeight();
449*3ac0a46fSAndroid Build Coastguard Worker }
450*3ac0a46fSAndroid Build Coastguard Worker 
CalcSize(const CFX_SizeF & minSize,const CFX_SizeF & maxSize)451*3ac0a46fSAndroid Build Coastguard Worker CFX_SizeF CXFA_TextLayout::CalcSize(const CFX_SizeF& minSize,
452*3ac0a46fSAndroid Build Coastguard Worker                                     const CFX_SizeF& maxSize) {
453*3ac0a46fSAndroid Build Coastguard Worker   float width = maxSize.width;
454*3ac0a46fSAndroid Build Coastguard Worker   if (width < 1)
455*3ac0a46fSAndroid Build Coastguard Worker     width = 0xFFFF;
456*3ac0a46fSAndroid Build Coastguard Worker 
457*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak = CreateBreak(false);
458*3ac0a46fSAndroid Build Coastguard Worker   float fLinePos = 0;
459*3ac0a46fSAndroid Build Coastguard Worker   m_iLines = 0;
460*3ac0a46fSAndroid Build Coastguard Worker   m_fMaxWidth = 0;
461*3ac0a46fSAndroid Build Coastguard Worker   Loader(width, &fLinePos, false);
462*3ac0a46fSAndroid Build Coastguard Worker   if (fLinePos < 0.1f)
463*3ac0a46fSAndroid Build Coastguard Worker     fLinePos = m_pTextParser->GetFontSize(m_pTextProvider, nullptr);
464*3ac0a46fSAndroid Build Coastguard Worker 
465*3ac0a46fSAndroid Build Coastguard Worker   m_pTabstopContext.reset();
466*3ac0a46fSAndroid Build Coastguard Worker   return CFX_SizeF(m_fMaxWidth, fLinePos);
467*3ac0a46fSAndroid Build Coastguard Worker }
468*3ac0a46fSAndroid Build Coastguard Worker 
Layout(const CFX_SizeF & size)469*3ac0a46fSAndroid Build Coastguard Worker float CXFA_TextLayout::Layout(const CFX_SizeF& size) {
470*3ac0a46fSAndroid Build Coastguard Worker   if (size.width < 1)
471*3ac0a46fSAndroid Build Coastguard Worker     return 0.f;
472*3ac0a46fSAndroid Build Coastguard Worker 
473*3ac0a46fSAndroid Build Coastguard Worker   Unload();
474*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak = CreateBreak(true);
475*3ac0a46fSAndroid Build Coastguard Worker   if (m_pLoader) {
476*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->iTotalLines = -1;
477*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->nCharIdx = 0;
478*3ac0a46fSAndroid Build Coastguard Worker   }
479*3ac0a46fSAndroid Build Coastguard Worker 
480*3ac0a46fSAndroid Build Coastguard Worker   m_iLines = 0;
481*3ac0a46fSAndroid Build Coastguard Worker   float fLinePos = 0;
482*3ac0a46fSAndroid Build Coastguard Worker   Loader(size.width, &fLinePos, true);
483*3ac0a46fSAndroid Build Coastguard Worker   UpdateAlign(size.height, fLinePos);
484*3ac0a46fSAndroid Build Coastguard Worker   m_pTabstopContext.reset();
485*3ac0a46fSAndroid Build Coastguard Worker   return fLinePos;
486*3ac0a46fSAndroid Build Coastguard Worker }
487*3ac0a46fSAndroid Build Coastguard Worker 
LayoutInternal(size_t szBlockIndex)488*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_TextLayout::LayoutInternal(size_t szBlockIndex) {
489*3ac0a46fSAndroid Build Coastguard Worker   DCHECK(szBlockIndex < CountBlocks());
490*3ac0a46fSAndroid Build Coastguard Worker 
491*3ac0a46fSAndroid Build Coastguard Worker   if (!m_pLoader || m_pLoader->fWidth < 1)
492*3ac0a46fSAndroid Build Coastguard Worker     return false;
493*3ac0a46fSAndroid Build Coastguard Worker 
494*3ac0a46fSAndroid Build Coastguard Worker   m_pLoader->iTotalLines = -1;
495*3ac0a46fSAndroid Build Coastguard Worker   m_iLines = 0;
496*3ac0a46fSAndroid Build Coastguard Worker   float fLinePos = 0;
497*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Node* pNode = nullptr;
498*3ac0a46fSAndroid Build Coastguard Worker   CFX_SizeF szText(m_pLoader->fWidth, m_pLoader->fHeight);
499*3ac0a46fSAndroid Build Coastguard Worker   if (szBlockIndex < m_pLoader->blockHeights.size())
500*3ac0a46fSAndroid Build Coastguard Worker     return true;
501*3ac0a46fSAndroid Build Coastguard Worker   if (szBlockIndex == m_pLoader->blockHeights.size()) {
502*3ac0a46fSAndroid Build Coastguard Worker     Unload();
503*3ac0a46fSAndroid Build Coastguard Worker     m_pBreak = CreateBreak(true);
504*3ac0a46fSAndroid Build Coastguard Worker     fLinePos = m_pLoader->fStartLineOffset;
505*3ac0a46fSAndroid Build Coastguard Worker     for (size_t i = 0; i < m_pLoader->blockHeights.size(); ++i)
506*3ac0a46fSAndroid Build Coastguard Worker       fLinePos -= m_pLoader->blockHeights[i].fHeight;
507*3ac0a46fSAndroid Build Coastguard Worker 
508*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->nCharIdx = 0;
509*3ac0a46fSAndroid Build Coastguard Worker     if (!m_Blocks.empty()) {
510*3ac0a46fSAndroid Build Coastguard Worker       m_pLoader->iTotalLines =
511*3ac0a46fSAndroid Build Coastguard Worker           pdfium::base::checked_cast<int32_t>(m_Blocks[szBlockIndex].szLength);
512*3ac0a46fSAndroid Build Coastguard Worker     }
513*3ac0a46fSAndroid Build Coastguard Worker     Loader(szText.width, &fLinePos, true);
514*3ac0a46fSAndroid Build Coastguard Worker     if (m_Blocks.empty() && m_pLoader->fStartLineOffset < 0.1f)
515*3ac0a46fSAndroid Build Coastguard Worker       UpdateAlign(szText.height, fLinePos);
516*3ac0a46fSAndroid Build Coastguard Worker   } else if (m_pTextDataNode) {
517*3ac0a46fSAndroid Build Coastguard Worker     if (!m_Blocks.empty() && szBlockIndex < m_Blocks.size() - 1) {
518*3ac0a46fSAndroid Build Coastguard Worker       m_pLoader->iTotalLines =
519*3ac0a46fSAndroid Build Coastguard Worker           pdfium::base::checked_cast<int32_t>(m_Blocks[szBlockIndex].szLength);
520*3ac0a46fSAndroid Build Coastguard Worker     }
521*3ac0a46fSAndroid Build Coastguard Worker     m_pBreak->Reset();
522*3ac0a46fSAndroid Build Coastguard Worker     if (m_bRichText) {
523*3ac0a46fSAndroid Build Coastguard Worker       CFX_XMLNode* pContainerNode = GetXMLContainerNode();
524*3ac0a46fSAndroid Build Coastguard Worker       if (!pContainerNode)
525*3ac0a46fSAndroid Build Coastguard Worker         return true;
526*3ac0a46fSAndroid Build Coastguard Worker 
527*3ac0a46fSAndroid Build Coastguard Worker       const CFX_XMLNode* pXMLNode = m_pLoader->pXMLNode;
528*3ac0a46fSAndroid Build Coastguard Worker       if (!pXMLNode)
529*3ac0a46fSAndroid Build Coastguard Worker         return true;
530*3ac0a46fSAndroid Build Coastguard Worker 
531*3ac0a46fSAndroid Build Coastguard Worker       const CFX_XMLNode* pSaveXMLNode = pXMLNode;
532*3ac0a46fSAndroid Build Coastguard Worker       for (; pXMLNode; pXMLNode = pXMLNode->GetNextSibling()) {
533*3ac0a46fSAndroid Build Coastguard Worker         if (!LoadRichText(pXMLNode, szText.width, &fLinePos,
534*3ac0a46fSAndroid Build Coastguard Worker                           m_pLoader->pParentStyle, true, nullptr, true, false,
535*3ac0a46fSAndroid Build Coastguard Worker                           0)) {
536*3ac0a46fSAndroid Build Coastguard Worker           break;
537*3ac0a46fSAndroid Build Coastguard Worker         }
538*3ac0a46fSAndroid Build Coastguard Worker       }
539*3ac0a46fSAndroid Build Coastguard Worker       while (!pXMLNode) {
540*3ac0a46fSAndroid Build Coastguard Worker         pXMLNode = pSaveXMLNode->GetParent();
541*3ac0a46fSAndroid Build Coastguard Worker         if (pXMLNode == pContainerNode)
542*3ac0a46fSAndroid Build Coastguard Worker           break;
543*3ac0a46fSAndroid Build Coastguard Worker         if (!LoadRichText(pXMLNode, szText.width, &fLinePos,
544*3ac0a46fSAndroid Build Coastguard Worker                           m_pLoader->pParentStyle, true, nullptr, false, false,
545*3ac0a46fSAndroid Build Coastguard Worker                           0)) {
546*3ac0a46fSAndroid Build Coastguard Worker           break;
547*3ac0a46fSAndroid Build Coastguard Worker         }
548*3ac0a46fSAndroid Build Coastguard Worker         pSaveXMLNode = pXMLNode;
549*3ac0a46fSAndroid Build Coastguard Worker         pXMLNode = pXMLNode->GetNextSibling();
550*3ac0a46fSAndroid Build Coastguard Worker         if (!pXMLNode)
551*3ac0a46fSAndroid Build Coastguard Worker           continue;
552*3ac0a46fSAndroid Build Coastguard Worker         for (; pXMLNode; pXMLNode = pXMLNode->GetNextSibling()) {
553*3ac0a46fSAndroid Build Coastguard Worker           if (!LoadRichText(pXMLNode, szText.width, &fLinePos,
554*3ac0a46fSAndroid Build Coastguard Worker                             m_pLoader->pParentStyle, true, nullptr, true, false,
555*3ac0a46fSAndroid Build Coastguard Worker                             0)) {
556*3ac0a46fSAndroid Build Coastguard Worker             break;
557*3ac0a46fSAndroid Build Coastguard Worker           }
558*3ac0a46fSAndroid Build Coastguard Worker         }
559*3ac0a46fSAndroid Build Coastguard Worker       }
560*3ac0a46fSAndroid Build Coastguard Worker     } else {
561*3ac0a46fSAndroid Build Coastguard Worker       pNode = m_pLoader->pNode.Get();
562*3ac0a46fSAndroid Build Coastguard Worker       if (!pNode)
563*3ac0a46fSAndroid Build Coastguard Worker         return true;
564*3ac0a46fSAndroid Build Coastguard Worker       LoadText(pNode, szText.width, &fLinePos, true);
565*3ac0a46fSAndroid Build Coastguard Worker     }
566*3ac0a46fSAndroid Build Coastguard Worker   }
567*3ac0a46fSAndroid Build Coastguard Worker   return true;
568*3ac0a46fSAndroid Build Coastguard Worker }
569*3ac0a46fSAndroid Build Coastguard Worker 
ItemBlocks(const CFX_RectF & rtText,size_t szBlockIndex)570*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::ItemBlocks(const CFX_RectF& rtText, size_t szBlockIndex) {
571*3ac0a46fSAndroid Build Coastguard Worker   if (!m_pLoader)
572*3ac0a46fSAndroid Build Coastguard Worker     return;
573*3ac0a46fSAndroid Build Coastguard Worker 
574*3ac0a46fSAndroid Build Coastguard Worker   if (m_pLoader->lineHeights.empty())
575*3ac0a46fSAndroid Build Coastguard Worker     return;
576*3ac0a46fSAndroid Build Coastguard Worker 
577*3ac0a46fSAndroid Build Coastguard Worker   float fLinePos = m_pLoader->fStartLineOffset;
578*3ac0a46fSAndroid Build Coastguard Worker   size_t szLineIndex = 0;
579*3ac0a46fSAndroid Build Coastguard Worker   if (szBlockIndex > 0) {
580*3ac0a46fSAndroid Build Coastguard Worker     if (szBlockIndex <= m_pLoader->blockHeights.size()) {
581*3ac0a46fSAndroid Build Coastguard Worker       for (size_t i = 0; i < szBlockIndex; ++i)
582*3ac0a46fSAndroid Build Coastguard Worker         fLinePos -= m_pLoader->blockHeights[i].fHeight;
583*3ac0a46fSAndroid Build Coastguard Worker     } else {
584*3ac0a46fSAndroid Build Coastguard Worker       fLinePos = 0;
585*3ac0a46fSAndroid Build Coastguard Worker     }
586*3ac0a46fSAndroid Build Coastguard Worker     szLineIndex = GetNextIndexFromLastBlockData();
587*3ac0a46fSAndroid Build Coastguard Worker   }
588*3ac0a46fSAndroid Build Coastguard Worker 
589*3ac0a46fSAndroid Build Coastguard Worker   size_t i;
590*3ac0a46fSAndroid Build Coastguard Worker   for (i = szLineIndex; i < m_pLoader->lineHeights.size(); ++i) {
591*3ac0a46fSAndroid Build Coastguard Worker     float fLineHeight = m_pLoader->lineHeights[i];
592*3ac0a46fSAndroid Build Coastguard Worker     if (fLinePos + fLineHeight - rtText.height > kHeightTolerance) {
593*3ac0a46fSAndroid Build Coastguard Worker       m_Blocks.push_back({szLineIndex, i - szLineIndex});
594*3ac0a46fSAndroid Build Coastguard Worker       return;
595*3ac0a46fSAndroid Build Coastguard Worker     }
596*3ac0a46fSAndroid Build Coastguard Worker     fLinePos += fLineHeight;
597*3ac0a46fSAndroid Build Coastguard Worker   }
598*3ac0a46fSAndroid Build Coastguard Worker   if (i > szLineIndex)
599*3ac0a46fSAndroid Build Coastguard Worker     m_Blocks.push_back({szLineIndex, i - szLineIndex});
600*3ac0a46fSAndroid Build Coastguard Worker }
601*3ac0a46fSAndroid Build Coastguard Worker 
DrawString(CFX_RenderDevice * pFxDevice,const CFX_Matrix & mtDoc2Device,const CFX_RectF & rtClip,size_t szBlockIndex)602*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_TextLayout::DrawString(CFX_RenderDevice* pFxDevice,
603*3ac0a46fSAndroid Build Coastguard Worker                                  const CFX_Matrix& mtDoc2Device,
604*3ac0a46fSAndroid Build Coastguard Worker                                  const CFX_RectF& rtClip,
605*3ac0a46fSAndroid Build Coastguard Worker                                  size_t szBlockIndex) {
606*3ac0a46fSAndroid Build Coastguard Worker   if (!pFxDevice)
607*3ac0a46fSAndroid Build Coastguard Worker     return false;
608*3ac0a46fSAndroid Build Coastguard Worker 
609*3ac0a46fSAndroid Build Coastguard Worker   pFxDevice->SaveState();
610*3ac0a46fSAndroid Build Coastguard Worker   pFxDevice->SetClip_Rect(rtClip.GetOuterRect());
611*3ac0a46fSAndroid Build Coastguard Worker 
612*3ac0a46fSAndroid Build Coastguard Worker   if (m_pieceLines.empty()) {
613*3ac0a46fSAndroid Build Coastguard Worker     size_t szBlockCount = CountBlocks();
614*3ac0a46fSAndroid Build Coastguard Worker     for (size_t i = 0; i < szBlockCount; ++i)
615*3ac0a46fSAndroid Build Coastguard Worker       LayoutInternal(i);
616*3ac0a46fSAndroid Build Coastguard Worker     m_pTabstopContext.reset();
617*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader.Clear();
618*3ac0a46fSAndroid Build Coastguard Worker   }
619*3ac0a46fSAndroid Build Coastguard Worker 
620*3ac0a46fSAndroid Build Coastguard Worker   std::vector<TextCharPos> char_pos(1);
621*3ac0a46fSAndroid Build Coastguard Worker   size_t szLineStart = 0;
622*3ac0a46fSAndroid Build Coastguard Worker   size_t szPieceLines = m_pieceLines.size();
623*3ac0a46fSAndroid Build Coastguard Worker   if (!m_Blocks.empty()) {
624*3ac0a46fSAndroid Build Coastguard Worker     if (szBlockIndex < m_Blocks.size()) {
625*3ac0a46fSAndroid Build Coastguard Worker       szLineStart = m_Blocks[szBlockIndex].szIndex;
626*3ac0a46fSAndroid Build Coastguard Worker       szPieceLines = m_Blocks[szBlockIndex].szLength;
627*3ac0a46fSAndroid Build Coastguard Worker     } else {
628*3ac0a46fSAndroid Build Coastguard Worker       szPieceLines = 0;
629*3ac0a46fSAndroid Build Coastguard Worker     }
630*3ac0a46fSAndroid Build Coastguard Worker   }
631*3ac0a46fSAndroid Build Coastguard Worker 
632*3ac0a46fSAndroid Build Coastguard Worker   for (size_t i = 0; i < szPieceLines; ++i) {
633*3ac0a46fSAndroid Build Coastguard Worker     if (i + szLineStart >= m_pieceLines.size())
634*3ac0a46fSAndroid Build Coastguard Worker       break;
635*3ac0a46fSAndroid Build Coastguard Worker 
636*3ac0a46fSAndroid Build Coastguard Worker     PieceLine* pPieceLine = m_pieceLines[i + szLineStart].get();
637*3ac0a46fSAndroid Build Coastguard Worker     for (size_t j = 0; j < pPieceLine->m_textPieces.size(); ++j) {
638*3ac0a46fSAndroid Build Coastguard Worker       const TextPiece* pPiece = pPieceLine->m_textPieces[j].get();
639*3ac0a46fSAndroid Build Coastguard Worker       int32_t iChars = pPiece->iChars;
640*3ac0a46fSAndroid Build Coastguard Worker       if (fxcrt::CollectionSize<int32_t>(char_pos) < iChars)
641*3ac0a46fSAndroid Build Coastguard Worker         char_pos.resize(iChars);
642*3ac0a46fSAndroid Build Coastguard Worker       RenderString(pFxDevice, pPieceLine, j, &char_pos, mtDoc2Device);
643*3ac0a46fSAndroid Build Coastguard Worker     }
644*3ac0a46fSAndroid Build Coastguard Worker     for (size_t j = 0; j < pPieceLine->m_textPieces.size(); ++j)
645*3ac0a46fSAndroid Build Coastguard Worker       RenderPath(pFxDevice, pPieceLine, j, &char_pos, mtDoc2Device);
646*3ac0a46fSAndroid Build Coastguard Worker   }
647*3ac0a46fSAndroid Build Coastguard Worker   pFxDevice->RestoreState(false);
648*3ac0a46fSAndroid Build Coastguard Worker   return szPieceLines > 0;
649*3ac0a46fSAndroid Build Coastguard Worker }
650*3ac0a46fSAndroid Build Coastguard Worker 
UpdateAlign(float fHeight,float fBottom)651*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::UpdateAlign(float fHeight, float fBottom) {
652*3ac0a46fSAndroid Build Coastguard Worker   fHeight -= fBottom;
653*3ac0a46fSAndroid Build Coastguard Worker   if (fHeight < 0.1f)
654*3ac0a46fSAndroid Build Coastguard Worker     return;
655*3ac0a46fSAndroid Build Coastguard Worker 
656*3ac0a46fSAndroid Build Coastguard Worker   switch (m_pTextParser->GetVAlign(m_pTextProvider)) {
657*3ac0a46fSAndroid Build Coastguard Worker     case XFA_AttributeValue::Middle:
658*3ac0a46fSAndroid Build Coastguard Worker       fHeight /= 2.0f;
659*3ac0a46fSAndroid Build Coastguard Worker       break;
660*3ac0a46fSAndroid Build Coastguard Worker     case XFA_AttributeValue::Bottom:
661*3ac0a46fSAndroid Build Coastguard Worker       break;
662*3ac0a46fSAndroid Build Coastguard Worker     default:
663*3ac0a46fSAndroid Build Coastguard Worker       return;
664*3ac0a46fSAndroid Build Coastguard Worker   }
665*3ac0a46fSAndroid Build Coastguard Worker 
666*3ac0a46fSAndroid Build Coastguard Worker   for (const auto& pPieceLine : m_pieceLines) {
667*3ac0a46fSAndroid Build Coastguard Worker     for (const auto& pPiece : pPieceLine->m_textPieces)
668*3ac0a46fSAndroid Build Coastguard Worker       pPiece->rtPiece.top += fHeight;
669*3ac0a46fSAndroid Build Coastguard Worker   }
670*3ac0a46fSAndroid Build Coastguard Worker }
671*3ac0a46fSAndroid Build Coastguard Worker 
Loader(float textWidth,float * pLinePos,bool bSavePieces)672*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::Loader(float textWidth,
673*3ac0a46fSAndroid Build Coastguard Worker                              float* pLinePos,
674*3ac0a46fSAndroid Build Coastguard Worker                              bool bSavePieces) {
675*3ac0a46fSAndroid Build Coastguard Worker   GetTextDataNode();
676*3ac0a46fSAndroid Build Coastguard Worker   if (!m_pTextDataNode)
677*3ac0a46fSAndroid Build Coastguard Worker     return;
678*3ac0a46fSAndroid Build Coastguard Worker 
679*3ac0a46fSAndroid Build Coastguard Worker   if (!m_bRichText) {
680*3ac0a46fSAndroid Build Coastguard Worker     LoadText(m_pTextDataNode, textWidth, pLinePos, bSavePieces);
681*3ac0a46fSAndroid Build Coastguard Worker     return;
682*3ac0a46fSAndroid Build Coastguard Worker   }
683*3ac0a46fSAndroid Build Coastguard Worker 
684*3ac0a46fSAndroid Build Coastguard Worker   const CFX_XMLNode* pXMLContainer = GetXMLContainerNode();
685*3ac0a46fSAndroid Build Coastguard Worker   if (!pXMLContainer)
686*3ac0a46fSAndroid Build Coastguard Worker     return;
687*3ac0a46fSAndroid Build Coastguard Worker 
688*3ac0a46fSAndroid Build Coastguard Worker   if (!m_pTextParser->IsParsed())
689*3ac0a46fSAndroid Build Coastguard Worker     m_pTextParser->DoParse(pXMLContainer, m_pTextProvider);
690*3ac0a46fSAndroid Build Coastguard Worker 
691*3ac0a46fSAndroid Build Coastguard Worker   auto pRootStyle = m_pTextParser->CreateRootStyle(m_pTextProvider);
692*3ac0a46fSAndroid Build Coastguard Worker   LoadRichText(pXMLContainer, textWidth, pLinePos, std::move(pRootStyle),
693*3ac0a46fSAndroid Build Coastguard Worker                bSavePieces, nullptr, true, false, 0);
694*3ac0a46fSAndroid Build Coastguard Worker }
695*3ac0a46fSAndroid Build Coastguard Worker 
LoadText(CXFA_Node * pNode,float textWidth,float * pLinePos,bool bSavePieces)696*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::LoadText(CXFA_Node* pNode,
697*3ac0a46fSAndroid Build Coastguard Worker                                float textWidth,
698*3ac0a46fSAndroid Build Coastguard Worker                                float* pLinePos,
699*3ac0a46fSAndroid Build Coastguard Worker                                bool bSavePieces) {
700*3ac0a46fSAndroid Build Coastguard Worker   InitBreak(textWidth);
701*3ac0a46fSAndroid Build Coastguard Worker 
702*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Para* para = m_pTextProvider->GetParaIfExists();
703*3ac0a46fSAndroid Build Coastguard Worker   float fSpaceAbove = 0;
704*3ac0a46fSAndroid Build Coastguard Worker   if (para) {
705*3ac0a46fSAndroid Build Coastguard Worker     fSpaceAbove = para->GetSpaceAbove();
706*3ac0a46fSAndroid Build Coastguard Worker     if (fSpaceAbove < 0.1f)
707*3ac0a46fSAndroid Build Coastguard Worker       fSpaceAbove = 0;
708*3ac0a46fSAndroid Build Coastguard Worker 
709*3ac0a46fSAndroid Build Coastguard Worker     switch (para->GetVerticalAlign()) {
710*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Top:
711*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Middle:
712*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Bottom: {
713*3ac0a46fSAndroid Build Coastguard Worker         *pLinePos += fSpaceAbove;
714*3ac0a46fSAndroid Build Coastguard Worker         break;
715*3ac0a46fSAndroid Build Coastguard Worker       }
716*3ac0a46fSAndroid Build Coastguard Worker       default:
717*3ac0a46fSAndroid Build Coastguard Worker         NOTREACHED_NORETURN();
718*3ac0a46fSAndroid Build Coastguard Worker     }
719*3ac0a46fSAndroid Build Coastguard Worker   }
720*3ac0a46fSAndroid Build Coastguard Worker 
721*3ac0a46fSAndroid Build Coastguard Worker   WideString wsText = pNode->JSObject()->GetContent(false);
722*3ac0a46fSAndroid Build Coastguard Worker   wsText.TrimRight(L" ");
723*3ac0a46fSAndroid Build Coastguard Worker   bool bRet = AppendChar(wsText, pLinePos, fSpaceAbove, bSavePieces);
724*3ac0a46fSAndroid Build Coastguard Worker   if (bRet && m_pLoader)
725*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->pNode = pNode;
726*3ac0a46fSAndroid Build Coastguard Worker   else
727*3ac0a46fSAndroid Build Coastguard Worker     EndBreak(CFGAS_Char::BreakType::kParagraph, pLinePos, bSavePieces);
728*3ac0a46fSAndroid Build Coastguard Worker }
729*3ac0a46fSAndroid Build Coastguard Worker 
LoadRichText(const CFX_XMLNode * pXMLNode,float textWidth,float * pLinePos,RetainPtr<CFX_CSSComputedStyle> pParentStyle,bool bSavePieces,RetainPtr<CFGAS_LinkUserData> pLinkData,bool bEndBreak,bool bIsOl,int32_t iLiCount)730*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_TextLayout::LoadRichText(const CFX_XMLNode* pXMLNode,
731*3ac0a46fSAndroid Build Coastguard Worker                                    float textWidth,
732*3ac0a46fSAndroid Build Coastguard Worker                                    float* pLinePos,
733*3ac0a46fSAndroid Build Coastguard Worker                                    RetainPtr<CFX_CSSComputedStyle> pParentStyle,
734*3ac0a46fSAndroid Build Coastguard Worker                                    bool bSavePieces,
735*3ac0a46fSAndroid Build Coastguard Worker                                    RetainPtr<CFGAS_LinkUserData> pLinkData,
736*3ac0a46fSAndroid Build Coastguard Worker                                    bool bEndBreak,
737*3ac0a46fSAndroid Build Coastguard Worker                                    bool bIsOl,
738*3ac0a46fSAndroid Build Coastguard Worker                                    int32_t iLiCount) {
739*3ac0a46fSAndroid Build Coastguard Worker   if (!pXMLNode)
740*3ac0a46fSAndroid Build Coastguard Worker     return false;
741*3ac0a46fSAndroid Build Coastguard Worker 
742*3ac0a46fSAndroid Build Coastguard Worker   CXFA_TextParser::Context* pContext =
743*3ac0a46fSAndroid Build Coastguard Worker       m_pTextParser->GetParseContextFromMap(pXMLNode);
744*3ac0a46fSAndroid Build Coastguard Worker   CFX_CSSDisplay eDisplay = CFX_CSSDisplay::None;
745*3ac0a46fSAndroid Build Coastguard Worker   bool bContentNode = false;
746*3ac0a46fSAndroid Build Coastguard Worker   float fSpaceBelow = 0;
747*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CFX_CSSComputedStyle> pStyle;
748*3ac0a46fSAndroid Build Coastguard Worker   WideString wsName;
749*3ac0a46fSAndroid Build Coastguard Worker   if (bEndBreak) {
750*3ac0a46fSAndroid Build Coastguard Worker     bool bCurOl = false;
751*3ac0a46fSAndroid Build Coastguard Worker     bool bCurLi = false;
752*3ac0a46fSAndroid Build Coastguard Worker     const CFX_XMLElement* pElement = nullptr;
753*3ac0a46fSAndroid Build Coastguard Worker     if (pContext) {
754*3ac0a46fSAndroid Build Coastguard Worker       if (pXMLNode->GetType() == CFX_XMLNode::Type::kText) {
755*3ac0a46fSAndroid Build Coastguard Worker         bContentNode = true;
756*3ac0a46fSAndroid Build Coastguard Worker       } else if (pXMLNode->GetType() == CFX_XMLNode::Type::kElement) {
757*3ac0a46fSAndroid Build Coastguard Worker         pElement = static_cast<const CFX_XMLElement*>(pXMLNode);
758*3ac0a46fSAndroid Build Coastguard Worker         wsName = pElement->GetLocalTagName();
759*3ac0a46fSAndroid Build Coastguard Worker       }
760*3ac0a46fSAndroid Build Coastguard Worker       if (wsName.EqualsASCII("ol")) {
761*3ac0a46fSAndroid Build Coastguard Worker         bIsOl = true;
762*3ac0a46fSAndroid Build Coastguard Worker         bCurOl = true;
763*3ac0a46fSAndroid Build Coastguard Worker       }
764*3ac0a46fSAndroid Build Coastguard Worker 
765*3ac0a46fSAndroid Build Coastguard Worker       eDisplay = pContext->GetDisplay();
766*3ac0a46fSAndroid Build Coastguard Worker       if (eDisplay != CFX_CSSDisplay::Block &&
767*3ac0a46fSAndroid Build Coastguard Worker           eDisplay != CFX_CSSDisplay::Inline &&
768*3ac0a46fSAndroid Build Coastguard Worker           eDisplay != CFX_CSSDisplay::ListItem) {
769*3ac0a46fSAndroid Build Coastguard Worker         return true;
770*3ac0a46fSAndroid Build Coastguard Worker       }
771*3ac0a46fSAndroid Build Coastguard Worker 
772*3ac0a46fSAndroid Build Coastguard Worker       pStyle = m_pTextParser->ComputeStyle(pXMLNode, pParentStyle);
773*3ac0a46fSAndroid Build Coastguard Worker       InitBreak(bContentNode ? pParentStyle.Get() : pStyle.Get(), eDisplay,
774*3ac0a46fSAndroid Build Coastguard Worker                 textWidth, pXMLNode, pParentStyle.Get());
775*3ac0a46fSAndroid Build Coastguard Worker       if ((eDisplay == CFX_CSSDisplay::Block ||
776*3ac0a46fSAndroid Build Coastguard Worker            eDisplay == CFX_CSSDisplay::ListItem) &&
777*3ac0a46fSAndroid Build Coastguard Worker           pStyle &&
778*3ac0a46fSAndroid Build Coastguard Worker           (wsName.IsEmpty() ||
779*3ac0a46fSAndroid Build Coastguard Worker            !(wsName.EqualsASCII("body") || wsName.EqualsASCII("html") ||
780*3ac0a46fSAndroid Build Coastguard Worker              wsName.EqualsASCII("ol") || wsName.EqualsASCII("ul")))) {
781*3ac0a46fSAndroid Build Coastguard Worker         const CFX_CSSRect* pRect = pStyle->GetMarginWidth();
782*3ac0a46fSAndroid Build Coastguard Worker         if (pRect) {
783*3ac0a46fSAndroid Build Coastguard Worker           *pLinePos += pRect->top.GetValue();
784*3ac0a46fSAndroid Build Coastguard Worker           fSpaceBelow = pRect->bottom.GetValue();
785*3ac0a46fSAndroid Build Coastguard Worker         }
786*3ac0a46fSAndroid Build Coastguard Worker       }
787*3ac0a46fSAndroid Build Coastguard Worker 
788*3ac0a46fSAndroid Build Coastguard Worker       if (wsName.EqualsASCII("a")) {
789*3ac0a46fSAndroid Build Coastguard Worker         WideString wsLinkContent = pElement->GetAttribute(L"href");
790*3ac0a46fSAndroid Build Coastguard Worker         if (!wsLinkContent.IsEmpty())
791*3ac0a46fSAndroid Build Coastguard Worker           pLinkData = pdfium::MakeRetain<CFGAS_LinkUserData>(wsLinkContent);
792*3ac0a46fSAndroid Build Coastguard Worker       }
793*3ac0a46fSAndroid Build Coastguard Worker 
794*3ac0a46fSAndroid Build Coastguard Worker       int32_t iTabCount = m_pTextParser->CountTabs(
795*3ac0a46fSAndroid Build Coastguard Worker           bContentNode ? pParentStyle.Get() : pStyle.Get());
796*3ac0a46fSAndroid Build Coastguard Worker       bool bSpaceRun = m_pTextParser->IsSpaceRun(
797*3ac0a46fSAndroid Build Coastguard Worker           bContentNode ? pParentStyle.Get() : pStyle.Get());
798*3ac0a46fSAndroid Build Coastguard Worker       WideString wsText;
799*3ac0a46fSAndroid Build Coastguard Worker       if (bContentNode && iTabCount == 0) {
800*3ac0a46fSAndroid Build Coastguard Worker         wsText = ToXMLText(pXMLNode)->GetText();
801*3ac0a46fSAndroid Build Coastguard Worker       } else if (wsName.EqualsASCII("br")) {
802*3ac0a46fSAndroid Build Coastguard Worker         wsText = WideString(L'\n');
803*3ac0a46fSAndroid Build Coastguard Worker       } else if (wsName.EqualsASCII("li")) {
804*3ac0a46fSAndroid Build Coastguard Worker         bCurLi = true;
805*3ac0a46fSAndroid Build Coastguard Worker         if (bIsOl)
806*3ac0a46fSAndroid Build Coastguard Worker           wsText = WideString::Format(L"%d.  ", iLiCount);
807*3ac0a46fSAndroid Build Coastguard Worker         else
808*3ac0a46fSAndroid Build Coastguard Worker           wsText = 0x00B7 + WideStringView(L"  ", 1);
809*3ac0a46fSAndroid Build Coastguard Worker       } else if (!bContentNode) {
810*3ac0a46fSAndroid Build Coastguard Worker         if (iTabCount > 0) {
811*3ac0a46fSAndroid Build Coastguard Worker           while (iTabCount-- > 0)
812*3ac0a46fSAndroid Build Coastguard Worker             wsText += L'\t';
813*3ac0a46fSAndroid Build Coastguard Worker         } else {
814*3ac0a46fSAndroid Build Coastguard Worker           absl::optional<WideString> obj =
815*3ac0a46fSAndroid Build Coastguard Worker               m_pTextParser->GetEmbeddedObj(m_pTextProvider, pXMLNode);
816*3ac0a46fSAndroid Build Coastguard Worker           if (obj.has_value())
817*3ac0a46fSAndroid Build Coastguard Worker             wsText = obj.value();
818*3ac0a46fSAndroid Build Coastguard Worker         }
819*3ac0a46fSAndroid Build Coastguard Worker       }
820*3ac0a46fSAndroid Build Coastguard Worker 
821*3ac0a46fSAndroid Build Coastguard Worker       if (!wsText.IsEmpty() && bContentNode && !bSpaceRun)
822*3ac0a46fSAndroid Build Coastguard Worker         ProcessText(&wsText);
823*3ac0a46fSAndroid Build Coastguard Worker 
824*3ac0a46fSAndroid Build Coastguard Worker       if (m_pLoader) {
825*3ac0a46fSAndroid Build Coastguard Worker         if (wsText.GetLength() > 0 && m_pLoader->bFilterSpace) {
826*3ac0a46fSAndroid Build Coastguard Worker           wsText.TrimLeft(L" ");
827*3ac0a46fSAndroid Build Coastguard Worker         }
828*3ac0a46fSAndroid Build Coastguard Worker         if (CFX_CSSDisplay::Block == eDisplay) {
829*3ac0a46fSAndroid Build Coastguard Worker           m_pLoader->bFilterSpace = true;
830*3ac0a46fSAndroid Build Coastguard Worker         } else if (CFX_CSSDisplay::Inline == eDisplay &&
831*3ac0a46fSAndroid Build Coastguard Worker                    m_pLoader->bFilterSpace) {
832*3ac0a46fSAndroid Build Coastguard Worker           m_pLoader->bFilterSpace = false;
833*3ac0a46fSAndroid Build Coastguard Worker         } else if (wsText.GetLength() > 0 && wsText.Back() == 0x20) {
834*3ac0a46fSAndroid Build Coastguard Worker           m_pLoader->bFilterSpace = true;
835*3ac0a46fSAndroid Build Coastguard Worker         } else if (wsText.GetLength() != 0) {
836*3ac0a46fSAndroid Build Coastguard Worker           m_pLoader->bFilterSpace = false;
837*3ac0a46fSAndroid Build Coastguard Worker         }
838*3ac0a46fSAndroid Build Coastguard Worker       }
839*3ac0a46fSAndroid Build Coastguard Worker 
840*3ac0a46fSAndroid Build Coastguard Worker       if (wsText.GetLength() > 0) {
841*3ac0a46fSAndroid Build Coastguard Worker         if (!m_pLoader || m_pLoader->nCharIdx == 0) {
842*3ac0a46fSAndroid Build Coastguard Worker           auto pUserData = pdfium::MakeRetain<CFGAS_TextUserData>(
843*3ac0a46fSAndroid Build Coastguard Worker               bContentNode ? pParentStyle : pStyle, pLinkData);
844*3ac0a46fSAndroid Build Coastguard Worker           m_pBreak->SetUserData(pUserData);
845*3ac0a46fSAndroid Build Coastguard Worker         }
846*3ac0a46fSAndroid Build Coastguard Worker 
847*3ac0a46fSAndroid Build Coastguard Worker         if (AppendChar(wsText, pLinePos, 0, bSavePieces)) {
848*3ac0a46fSAndroid Build Coastguard Worker           if (m_pLoader)
849*3ac0a46fSAndroid Build Coastguard Worker             m_pLoader->bFilterSpace = false;
850*3ac0a46fSAndroid Build Coastguard Worker           if (!IsEnd(bSavePieces))
851*3ac0a46fSAndroid Build Coastguard Worker             return true;
852*3ac0a46fSAndroid Build Coastguard Worker           if (m_pLoader && m_pLoader->iTotalLines > -1) {
853*3ac0a46fSAndroid Build Coastguard Worker             m_pLoader->pXMLNode = pXMLNode;
854*3ac0a46fSAndroid Build Coastguard Worker             m_pLoader->pParentStyle = pParentStyle;
855*3ac0a46fSAndroid Build Coastguard Worker           }
856*3ac0a46fSAndroid Build Coastguard Worker           return false;
857*3ac0a46fSAndroid Build Coastguard Worker         }
858*3ac0a46fSAndroid Build Coastguard Worker       }
859*3ac0a46fSAndroid Build Coastguard Worker     }
860*3ac0a46fSAndroid Build Coastguard Worker 
861*3ac0a46fSAndroid Build Coastguard Worker     for (CFX_XMLNode* pChildNode = pXMLNode->GetFirstChild(); pChildNode;
862*3ac0a46fSAndroid Build Coastguard Worker          pChildNode = pChildNode->GetNextSibling()) {
863*3ac0a46fSAndroid Build Coastguard Worker       if (bCurOl)
864*3ac0a46fSAndroid Build Coastguard Worker         iLiCount++;
865*3ac0a46fSAndroid Build Coastguard Worker 
866*3ac0a46fSAndroid Build Coastguard Worker       if (!LoadRichText(pChildNode, textWidth, pLinePos,
867*3ac0a46fSAndroid Build Coastguard Worker                         pContext ? pStyle : pParentStyle, bSavePieces,
868*3ac0a46fSAndroid Build Coastguard Worker                         pLinkData, true, bIsOl, iLiCount))
869*3ac0a46fSAndroid Build Coastguard Worker         return false;
870*3ac0a46fSAndroid Build Coastguard Worker     }
871*3ac0a46fSAndroid Build Coastguard Worker 
872*3ac0a46fSAndroid Build Coastguard Worker     if (m_pLoader) {
873*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_CSSDisplay::Block == eDisplay)
874*3ac0a46fSAndroid Build Coastguard Worker         m_pLoader->bFilterSpace = true;
875*3ac0a46fSAndroid Build Coastguard Worker     }
876*3ac0a46fSAndroid Build Coastguard Worker     if (bCurLi)
877*3ac0a46fSAndroid Build Coastguard Worker       EndBreak(CFGAS_Char::BreakType::kLine, pLinePos, bSavePieces);
878*3ac0a46fSAndroid Build Coastguard Worker   } else {
879*3ac0a46fSAndroid Build Coastguard Worker     if (pContext)
880*3ac0a46fSAndroid Build Coastguard Worker       eDisplay = pContext->GetDisplay();
881*3ac0a46fSAndroid Build Coastguard Worker   }
882*3ac0a46fSAndroid Build Coastguard Worker 
883*3ac0a46fSAndroid Build Coastguard Worker   if (!pContext || bContentNode)
884*3ac0a46fSAndroid Build Coastguard Worker     return true;
885*3ac0a46fSAndroid Build Coastguard Worker 
886*3ac0a46fSAndroid Build Coastguard Worker   CFGAS_Char::BreakType dwStatus = (eDisplay == CFX_CSSDisplay::Block)
887*3ac0a46fSAndroid Build Coastguard Worker                                        ? CFGAS_Char::BreakType::kParagraph
888*3ac0a46fSAndroid Build Coastguard Worker                                        : CFGAS_Char::BreakType::kPiece;
889*3ac0a46fSAndroid Build Coastguard Worker   EndBreak(dwStatus, pLinePos, bSavePieces);
890*3ac0a46fSAndroid Build Coastguard Worker   if (eDisplay == CFX_CSSDisplay::Block) {
891*3ac0a46fSAndroid Build Coastguard Worker     *pLinePos += fSpaceBelow;
892*3ac0a46fSAndroid Build Coastguard Worker     if (m_pTabstopContext)
893*3ac0a46fSAndroid Build Coastguard Worker       m_pTabstopContext->RemoveAll();
894*3ac0a46fSAndroid Build Coastguard Worker   }
895*3ac0a46fSAndroid Build Coastguard Worker   if (!IsEnd(bSavePieces))
896*3ac0a46fSAndroid Build Coastguard Worker     return true;
897*3ac0a46fSAndroid Build Coastguard Worker 
898*3ac0a46fSAndroid Build Coastguard Worker   if (m_pLoader && m_pLoader->iTotalLines > -1) {
899*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->pXMLNode = pXMLNode->GetNextSibling();
900*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->pParentStyle = pParentStyle;
901*3ac0a46fSAndroid Build Coastguard Worker   }
902*3ac0a46fSAndroid Build Coastguard Worker   return false;
903*3ac0a46fSAndroid Build Coastguard Worker }
904*3ac0a46fSAndroid Build Coastguard Worker 
AppendChar(const WideString & wsText,float * pLinePos,float fSpaceAbove,bool bSavePieces)905*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_TextLayout::AppendChar(const WideString& wsText,
906*3ac0a46fSAndroid Build Coastguard Worker                                  float* pLinePos,
907*3ac0a46fSAndroid Build Coastguard Worker                                  float fSpaceAbove,
908*3ac0a46fSAndroid Build Coastguard Worker                                  bool bSavePieces) {
909*3ac0a46fSAndroid Build Coastguard Worker   CFGAS_Char::BreakType dwStatus = CFGAS_Char::BreakType::kNone;
910*3ac0a46fSAndroid Build Coastguard Worker   size_t iChar = m_pLoader ? m_pLoader->nCharIdx : 0;
911*3ac0a46fSAndroid Build Coastguard Worker   size_t iLength = wsText.GetLength();
912*3ac0a46fSAndroid Build Coastguard Worker   for (size_t i = iChar; i < iLength; i++) {
913*3ac0a46fSAndroid Build Coastguard Worker     wchar_t wch = wsText[i];
914*3ac0a46fSAndroid Build Coastguard Worker     if (wch == 0xA0)
915*3ac0a46fSAndroid Build Coastguard Worker       wch = 0x20;
916*3ac0a46fSAndroid Build Coastguard Worker 
917*3ac0a46fSAndroid Build Coastguard Worker     dwStatus = m_pBreak->AppendChar(wch);
918*3ac0a46fSAndroid Build Coastguard Worker     if (dwStatus != CFGAS_Char::BreakType::kNone &&
919*3ac0a46fSAndroid Build Coastguard Worker         dwStatus != CFGAS_Char::BreakType::kPiece) {
920*3ac0a46fSAndroid Build Coastguard Worker       AppendTextLine(dwStatus, pLinePos, bSavePieces, false);
921*3ac0a46fSAndroid Build Coastguard Worker       if (IsEnd(bSavePieces)) {
922*3ac0a46fSAndroid Build Coastguard Worker         if (m_pLoader)
923*3ac0a46fSAndroid Build Coastguard Worker           m_pLoader->nCharIdx = i;
924*3ac0a46fSAndroid Build Coastguard Worker         return true;
925*3ac0a46fSAndroid Build Coastguard Worker       }
926*3ac0a46fSAndroid Build Coastguard Worker       if (dwStatus == CFGAS_Char::BreakType::kParagraph && m_bRichText)
927*3ac0a46fSAndroid Build Coastguard Worker         *pLinePos += fSpaceAbove;
928*3ac0a46fSAndroid Build Coastguard Worker     }
929*3ac0a46fSAndroid Build Coastguard Worker   }
930*3ac0a46fSAndroid Build Coastguard Worker   if (m_pLoader)
931*3ac0a46fSAndroid Build Coastguard Worker     m_pLoader->nCharIdx = 0;
932*3ac0a46fSAndroid Build Coastguard Worker 
933*3ac0a46fSAndroid Build Coastguard Worker   return false;
934*3ac0a46fSAndroid Build Coastguard Worker }
935*3ac0a46fSAndroid Build Coastguard Worker 
IsEnd(bool bSavePieces)936*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_TextLayout::IsEnd(bool bSavePieces) {
937*3ac0a46fSAndroid Build Coastguard Worker   if (!bSavePieces)
938*3ac0a46fSAndroid Build Coastguard Worker     return false;
939*3ac0a46fSAndroid Build Coastguard Worker   if (m_pLoader && m_pLoader->iTotalLines > 0)
940*3ac0a46fSAndroid Build Coastguard Worker     return m_iLines >= m_pLoader->iTotalLines;
941*3ac0a46fSAndroid Build Coastguard Worker   return false;
942*3ac0a46fSAndroid Build Coastguard Worker }
943*3ac0a46fSAndroid Build Coastguard Worker 
EndBreak(CFGAS_Char::BreakType dwStatus,float * pLinePos,bool bSavePieces)944*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::EndBreak(CFGAS_Char::BreakType dwStatus,
945*3ac0a46fSAndroid Build Coastguard Worker                                float* pLinePos,
946*3ac0a46fSAndroid Build Coastguard Worker                                bool bSavePieces) {
947*3ac0a46fSAndroid Build Coastguard Worker   dwStatus = m_pBreak->EndBreak(dwStatus);
948*3ac0a46fSAndroid Build Coastguard Worker   if (dwStatus != CFGAS_Char::BreakType::kNone &&
949*3ac0a46fSAndroid Build Coastguard Worker       dwStatus != CFGAS_Char::BreakType::kPiece)
950*3ac0a46fSAndroid Build Coastguard Worker     AppendTextLine(dwStatus, pLinePos, bSavePieces, true);
951*3ac0a46fSAndroid Build Coastguard Worker }
952*3ac0a46fSAndroid Build Coastguard Worker 
DoTabstops(CFX_CSSComputedStyle * pStyle,PieceLine * pPieceLine)953*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::DoTabstops(CFX_CSSComputedStyle* pStyle,
954*3ac0a46fSAndroid Build Coastguard Worker                                  PieceLine* pPieceLine) {
955*3ac0a46fSAndroid Build Coastguard Worker   if (!pStyle || !pPieceLine)
956*3ac0a46fSAndroid Build Coastguard Worker     return;
957*3ac0a46fSAndroid Build Coastguard Worker 
958*3ac0a46fSAndroid Build Coastguard Worker   if (!m_pTabstopContext || m_pTabstopContext->m_tabstops.empty())
959*3ac0a46fSAndroid Build Coastguard Worker     return;
960*3ac0a46fSAndroid Build Coastguard Worker 
961*3ac0a46fSAndroid Build Coastguard Worker   int32_t iPieces = fxcrt::CollectionSize<int32_t>(pPieceLine->m_textPieces);
962*3ac0a46fSAndroid Build Coastguard Worker   if (iPieces == 0)
963*3ac0a46fSAndroid Build Coastguard Worker     return;
964*3ac0a46fSAndroid Build Coastguard Worker 
965*3ac0a46fSAndroid Build Coastguard Worker   TextPiece* pPiece = pPieceLine->m_textPieces[iPieces - 1].get();
966*3ac0a46fSAndroid Build Coastguard Worker   int32_t& iTabstopsIndex = m_pTabstopContext->m_iTabIndex;
967*3ac0a46fSAndroid Build Coastguard Worker   int32_t iCount = m_pTextParser->CountTabs(pStyle);
968*3ac0a46fSAndroid Build Coastguard Worker   if (!fxcrt::IndexInBounds(m_pTabstopContext->m_tabstops, iTabstopsIndex))
969*3ac0a46fSAndroid Build Coastguard Worker     return;
970*3ac0a46fSAndroid Build Coastguard Worker 
971*3ac0a46fSAndroid Build Coastguard Worker   if (iCount > 0) {
972*3ac0a46fSAndroid Build Coastguard Worker     iTabstopsIndex++;
973*3ac0a46fSAndroid Build Coastguard Worker     m_pTabstopContext->m_bHasTabstops = true;
974*3ac0a46fSAndroid Build Coastguard Worker     float fRight = 0;
975*3ac0a46fSAndroid Build Coastguard Worker     if (iPieces > 1) {
976*3ac0a46fSAndroid Build Coastguard Worker       const TextPiece* p = pPieceLine->m_textPieces[iPieces - 2].get();
977*3ac0a46fSAndroid Build Coastguard Worker       fRight = p->rtPiece.right();
978*3ac0a46fSAndroid Build Coastguard Worker     }
979*3ac0a46fSAndroid Build Coastguard Worker     m_pTabstopContext->m_fTabWidth =
980*3ac0a46fSAndroid Build Coastguard Worker         pPiece->rtPiece.width + pPiece->rtPiece.left - fRight;
981*3ac0a46fSAndroid Build Coastguard Worker   } else if (iTabstopsIndex > -1) {
982*3ac0a46fSAndroid Build Coastguard Worker     float fLeft = 0;
983*3ac0a46fSAndroid Build Coastguard Worker     if (m_pTabstopContext->m_bHasTabstops) {
984*3ac0a46fSAndroid Build Coastguard Worker       uint32_t dwAlign = m_pTabstopContext->m_tabstops[iTabstopsIndex].dwAlign;
985*3ac0a46fSAndroid Build Coastguard Worker       if (dwAlign == FX_HashCode_GetW(L"center")) {
986*3ac0a46fSAndroid Build Coastguard Worker         fLeft = pPiece->rtPiece.width / 2.0f;
987*3ac0a46fSAndroid Build Coastguard Worker       } else if (dwAlign == FX_HashCode_GetW(L"right") ||
988*3ac0a46fSAndroid Build Coastguard Worker                  dwAlign == FX_HashCode_GetW(L"before")) {
989*3ac0a46fSAndroid Build Coastguard Worker         fLeft = pPiece->rtPiece.width;
990*3ac0a46fSAndroid Build Coastguard Worker       } else if (dwAlign == FX_HashCode_GetW(L"decimal")) {
991*3ac0a46fSAndroid Build Coastguard Worker         int32_t iChars = pPiece->iChars;
992*3ac0a46fSAndroid Build Coastguard Worker         for (int32_t i = 0; i < iChars; i++) {
993*3ac0a46fSAndroid Build Coastguard Worker           if (pPiece->szText[i] == L'.')
994*3ac0a46fSAndroid Build Coastguard Worker             break;
995*3ac0a46fSAndroid Build Coastguard Worker 
996*3ac0a46fSAndroid Build Coastguard Worker           fLeft += pPiece->Widths[i] / 20000.0f;
997*3ac0a46fSAndroid Build Coastguard Worker         }
998*3ac0a46fSAndroid Build Coastguard Worker       }
999*3ac0a46fSAndroid Build Coastguard Worker       m_pTabstopContext->m_fLeft =
1000*3ac0a46fSAndroid Build Coastguard Worker           std::min(fLeft, m_pTabstopContext->m_fTabWidth);
1001*3ac0a46fSAndroid Build Coastguard Worker       m_pTabstopContext->m_bHasTabstops = false;
1002*3ac0a46fSAndroid Build Coastguard Worker       m_pTabstopContext->m_fTabWidth = 0;
1003*3ac0a46fSAndroid Build Coastguard Worker     }
1004*3ac0a46fSAndroid Build Coastguard Worker     pPiece->rtPiece.left -= m_pTabstopContext->m_fLeft;
1005*3ac0a46fSAndroid Build Coastguard Worker   }
1006*3ac0a46fSAndroid Build Coastguard Worker }
1007*3ac0a46fSAndroid Build Coastguard Worker 
AppendTextLine(CFGAS_Char::BreakType dwStatus,float * pLinePos,bool bSavePieces,bool bEndBreak)1008*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::AppendTextLine(CFGAS_Char::BreakType dwStatus,
1009*3ac0a46fSAndroid Build Coastguard Worker                                      float* pLinePos,
1010*3ac0a46fSAndroid Build Coastguard Worker                                      bool bSavePieces,
1011*3ac0a46fSAndroid Build Coastguard Worker                                      bool bEndBreak) {
1012*3ac0a46fSAndroid Build Coastguard Worker   int32_t iPieces = m_pBreak->CountBreakPieces();
1013*3ac0a46fSAndroid Build Coastguard Worker   if (iPieces < 1)
1014*3ac0a46fSAndroid Build Coastguard Worker     return;
1015*3ac0a46fSAndroid Build Coastguard Worker 
1016*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CFX_CSSComputedStyle> pStyle;
1017*3ac0a46fSAndroid Build Coastguard Worker   if (bSavePieces) {
1018*3ac0a46fSAndroid Build Coastguard Worker     auto pNew = std::make_unique<PieceLine>();
1019*3ac0a46fSAndroid Build Coastguard Worker     PieceLine* pPieceLine = pNew.get();
1020*3ac0a46fSAndroid Build Coastguard Worker     m_pieceLines.push_back(std::move(pNew));
1021*3ac0a46fSAndroid Build Coastguard Worker     if (m_pTabstopContext)
1022*3ac0a46fSAndroid Build Coastguard Worker       m_pTabstopContext->Reset();
1023*3ac0a46fSAndroid Build Coastguard Worker 
1024*3ac0a46fSAndroid Build Coastguard Worker     float fLineStep = 0;
1025*3ac0a46fSAndroid Build Coastguard Worker     float fBaseLine = 0;
1026*3ac0a46fSAndroid Build Coastguard Worker     int32_t i = 0;
1027*3ac0a46fSAndroid Build Coastguard Worker     for (i = 0; i < iPieces; i++) {
1028*3ac0a46fSAndroid Build Coastguard Worker       const CFGAS_BreakPiece* pPiece = m_pBreak->GetBreakPieceUnstable(i);
1029*3ac0a46fSAndroid Build Coastguard Worker       const CFGAS_TextUserData* pUserData = pPiece->GetUserData();
1030*3ac0a46fSAndroid Build Coastguard Worker       if (pUserData)
1031*3ac0a46fSAndroid Build Coastguard Worker         pStyle = pUserData->m_pStyle;
1032*3ac0a46fSAndroid Build Coastguard Worker       float fVerScale = pPiece->GetVerticalScale() / 100.0f;
1033*3ac0a46fSAndroid Build Coastguard Worker 
1034*3ac0a46fSAndroid Build Coastguard Worker       auto pTP = std::make_unique<TextPiece>();
1035*3ac0a46fSAndroid Build Coastguard Worker       pTP->iChars = pPiece->GetCharCount();
1036*3ac0a46fSAndroid Build Coastguard Worker       pTP->szText = pPiece->GetString();
1037*3ac0a46fSAndroid Build Coastguard Worker       pTP->Widths = pPiece->GetWidths();
1038*3ac0a46fSAndroid Build Coastguard Worker       pTP->iBidiLevel = pPiece->GetBidiLevel();
1039*3ac0a46fSAndroid Build Coastguard Worker       pTP->iHorScale = pPiece->GetHorizontalScale();
1040*3ac0a46fSAndroid Build Coastguard Worker       pTP->iVerScale = pPiece->GetVerticalScale();
1041*3ac0a46fSAndroid Build Coastguard Worker       pTP->iUnderline =
1042*3ac0a46fSAndroid Build Coastguard Worker           m_pTextParser->GetUnderline(m_pTextProvider, pStyle.Get());
1043*3ac0a46fSAndroid Build Coastguard Worker       pTP->iPeriod =
1044*3ac0a46fSAndroid Build Coastguard Worker           m_pTextParser->GetUnderlinePeriod(m_pTextProvider, pStyle.Get());
1045*3ac0a46fSAndroid Build Coastguard Worker       pTP->iLineThrough =
1046*3ac0a46fSAndroid Build Coastguard Worker           m_pTextParser->GetLinethrough(m_pTextProvider, pStyle.Get());
1047*3ac0a46fSAndroid Build Coastguard Worker       pTP->dwColor = m_pTextParser->GetColor(m_pTextProvider, pStyle.Get());
1048*3ac0a46fSAndroid Build Coastguard Worker       pTP->pFont =
1049*3ac0a46fSAndroid Build Coastguard Worker           m_pTextParser->GetFont(m_pDoc.Get(), m_pTextProvider, pStyle.Get());
1050*3ac0a46fSAndroid Build Coastguard Worker       pTP->fFontSize =
1051*3ac0a46fSAndroid Build Coastguard Worker           m_pTextParser->GetFontSize(m_pTextProvider, pStyle.Get());
1052*3ac0a46fSAndroid Build Coastguard Worker       pTP->rtPiece.left = pPiece->GetStartPos() / 20000.0f;
1053*3ac0a46fSAndroid Build Coastguard Worker       pTP->rtPiece.width = pPiece->GetWidth() / 20000.0f;
1054*3ac0a46fSAndroid Build Coastguard Worker       pTP->rtPiece.height =
1055*3ac0a46fSAndroid Build Coastguard Worker           static_cast<float>(pPiece->GetFontSize()) * fVerScale / 20.0f;
1056*3ac0a46fSAndroid Build Coastguard Worker       float fBaseLineTemp =
1057*3ac0a46fSAndroid Build Coastguard Worker           m_pTextParser->GetBaseline(m_pTextProvider, pStyle.Get());
1058*3ac0a46fSAndroid Build Coastguard Worker       pTP->rtPiece.top = fBaseLineTemp;
1059*3ac0a46fSAndroid Build Coastguard Worker 
1060*3ac0a46fSAndroid Build Coastguard Worker       float fLineHeight = m_pTextParser->GetLineHeight(
1061*3ac0a46fSAndroid Build Coastguard Worker           m_pTextProvider, pStyle.Get(), m_iLines == 0, fVerScale);
1062*3ac0a46fSAndroid Build Coastguard Worker       if (fBaseLineTemp > 0) {
1063*3ac0a46fSAndroid Build Coastguard Worker         float fLineHeightTmp = fBaseLineTemp + pTP->rtPiece.height;
1064*3ac0a46fSAndroid Build Coastguard Worker         if (fLineHeight < fLineHeightTmp)
1065*3ac0a46fSAndroid Build Coastguard Worker           fLineHeight = fLineHeightTmp;
1066*3ac0a46fSAndroid Build Coastguard Worker       }
1067*3ac0a46fSAndroid Build Coastguard Worker       fLineStep = std::max(fLineStep, fLineHeight);
1068*3ac0a46fSAndroid Build Coastguard Worker       pTP->pLinkData = pUserData ? pUserData->m_pLinkData : nullptr;
1069*3ac0a46fSAndroid Build Coastguard Worker       pPieceLine->m_textPieces.push_back(std::move(pTP));
1070*3ac0a46fSAndroid Build Coastguard Worker       DoTabstops(pStyle.Get(), pPieceLine);
1071*3ac0a46fSAndroid Build Coastguard Worker     }
1072*3ac0a46fSAndroid Build Coastguard Worker     for (const auto& pTP : pPieceLine->m_textPieces) {
1073*3ac0a46fSAndroid Build Coastguard Worker       float& fTop = pTP->rtPiece.top;
1074*3ac0a46fSAndroid Build Coastguard Worker       float fBaseLineTemp = fTop;
1075*3ac0a46fSAndroid Build Coastguard Worker       fTop = *pLinePos + fLineStep - pTP->rtPiece.height - fBaseLineTemp;
1076*3ac0a46fSAndroid Build Coastguard Worker       fTop = std::max(0.0f, fTop);
1077*3ac0a46fSAndroid Build Coastguard Worker     }
1078*3ac0a46fSAndroid Build Coastguard Worker     *pLinePos += fLineStep + fBaseLine;
1079*3ac0a46fSAndroid Build Coastguard Worker   } else {
1080*3ac0a46fSAndroid Build Coastguard Worker     float fLineStep = 0;
1081*3ac0a46fSAndroid Build Coastguard Worker     float fLineWidth = 0;
1082*3ac0a46fSAndroid Build Coastguard Worker     for (int32_t i = 0; i < iPieces; i++) {
1083*3ac0a46fSAndroid Build Coastguard Worker       const CFGAS_BreakPiece* pPiece = m_pBreak->GetBreakPieceUnstable(i);
1084*3ac0a46fSAndroid Build Coastguard Worker       const CFGAS_TextUserData* pUserData = pPiece->GetUserData();
1085*3ac0a46fSAndroid Build Coastguard Worker       if (pUserData)
1086*3ac0a46fSAndroid Build Coastguard Worker         pStyle = pUserData->m_pStyle;
1087*3ac0a46fSAndroid Build Coastguard Worker       float fVerScale = pPiece->GetVerticalScale() / 100.0f;
1088*3ac0a46fSAndroid Build Coastguard Worker       float fBaseLine =
1089*3ac0a46fSAndroid Build Coastguard Worker           m_pTextParser->GetBaseline(m_pTextProvider, pStyle.Get());
1090*3ac0a46fSAndroid Build Coastguard Worker       float fLineHeight = m_pTextParser->GetLineHeight(
1091*3ac0a46fSAndroid Build Coastguard Worker           m_pTextProvider, pStyle.Get(), m_iLines == 0, fVerScale);
1092*3ac0a46fSAndroid Build Coastguard Worker       if (fBaseLine > 0) {
1093*3ac0a46fSAndroid Build Coastguard Worker         float fLineHeightTmp =
1094*3ac0a46fSAndroid Build Coastguard Worker             fBaseLine +
1095*3ac0a46fSAndroid Build Coastguard Worker             static_cast<float>(pPiece->GetFontSize()) * fVerScale / 20.0f;
1096*3ac0a46fSAndroid Build Coastguard Worker         if (fLineHeight < fLineHeightTmp) {
1097*3ac0a46fSAndroid Build Coastguard Worker           fLineHeight = fLineHeightTmp;
1098*3ac0a46fSAndroid Build Coastguard Worker         }
1099*3ac0a46fSAndroid Build Coastguard Worker       }
1100*3ac0a46fSAndroid Build Coastguard Worker       fLineStep = std::max(fLineStep, fLineHeight);
1101*3ac0a46fSAndroid Build Coastguard Worker       fLineWidth += pPiece->GetWidth() / 20000.0f;
1102*3ac0a46fSAndroid Build Coastguard Worker     }
1103*3ac0a46fSAndroid Build Coastguard Worker     *pLinePos += fLineStep;
1104*3ac0a46fSAndroid Build Coastguard Worker     m_fMaxWidth = std::max(m_fMaxWidth, fLineWidth);
1105*3ac0a46fSAndroid Build Coastguard Worker     if (m_pLoader && m_pLoader->bSaveLineHeight) {
1106*3ac0a46fSAndroid Build Coastguard Worker       float fHeight = *pLinePos - m_pLoader->fLastPos;
1107*3ac0a46fSAndroid Build Coastguard Worker       m_pLoader->fLastPos = *pLinePos;
1108*3ac0a46fSAndroid Build Coastguard Worker       m_pLoader->lineHeights.push_back(fHeight);
1109*3ac0a46fSAndroid Build Coastguard Worker     }
1110*3ac0a46fSAndroid Build Coastguard Worker   }
1111*3ac0a46fSAndroid Build Coastguard Worker 
1112*3ac0a46fSAndroid Build Coastguard Worker   m_pBreak->ClearBreakPieces();
1113*3ac0a46fSAndroid Build Coastguard Worker   if (dwStatus == CFGAS_Char::BreakType::kParagraph) {
1114*3ac0a46fSAndroid Build Coastguard Worker     m_pBreak->Reset();
1115*3ac0a46fSAndroid Build Coastguard Worker     if (!pStyle && bEndBreak) {
1116*3ac0a46fSAndroid Build Coastguard Worker       CXFA_Para* para = m_pTextProvider->GetParaIfExists();
1117*3ac0a46fSAndroid Build Coastguard Worker       if (para) {
1118*3ac0a46fSAndroid Build Coastguard Worker         float fStartPos = para->GetMarginLeft();
1119*3ac0a46fSAndroid Build Coastguard Worker         float fIndent = para->GetTextIndent();
1120*3ac0a46fSAndroid Build Coastguard Worker         if (fIndent > 0)
1121*3ac0a46fSAndroid Build Coastguard Worker           fStartPos += fIndent;
1122*3ac0a46fSAndroid Build Coastguard Worker 
1123*3ac0a46fSAndroid Build Coastguard Worker         float fSpaceBelow = para->GetSpaceBelow();
1124*3ac0a46fSAndroid Build Coastguard Worker         if (fSpaceBelow < 0.1f)
1125*3ac0a46fSAndroid Build Coastguard Worker           fSpaceBelow = 0;
1126*3ac0a46fSAndroid Build Coastguard Worker 
1127*3ac0a46fSAndroid Build Coastguard Worker         m_pBreak->SetLineStartPos(fStartPos);
1128*3ac0a46fSAndroid Build Coastguard Worker         *pLinePos += fSpaceBelow;
1129*3ac0a46fSAndroid Build Coastguard Worker       }
1130*3ac0a46fSAndroid Build Coastguard Worker     }
1131*3ac0a46fSAndroid Build Coastguard Worker   }
1132*3ac0a46fSAndroid Build Coastguard Worker 
1133*3ac0a46fSAndroid Build Coastguard Worker   if (pStyle) {
1134*3ac0a46fSAndroid Build Coastguard Worker     float fStart = 0;
1135*3ac0a46fSAndroid Build Coastguard Worker     const CFX_CSSRect* pRect = pStyle->GetMarginWidth();
1136*3ac0a46fSAndroid Build Coastguard Worker     if (pRect)
1137*3ac0a46fSAndroid Build Coastguard Worker       fStart = pRect->left.GetValue();
1138*3ac0a46fSAndroid Build Coastguard Worker 
1139*3ac0a46fSAndroid Build Coastguard Worker     float fTextIndent = pStyle->GetTextIndent().GetValue();
1140*3ac0a46fSAndroid Build Coastguard Worker     if (fTextIndent < 0)
1141*3ac0a46fSAndroid Build Coastguard Worker       fStart -= fTextIndent;
1142*3ac0a46fSAndroid Build Coastguard Worker 
1143*3ac0a46fSAndroid Build Coastguard Worker     m_pBreak->SetLineStartPos(fStart);
1144*3ac0a46fSAndroid Build Coastguard Worker   }
1145*3ac0a46fSAndroid Build Coastguard Worker   m_iLines++;
1146*3ac0a46fSAndroid Build Coastguard Worker }
1147*3ac0a46fSAndroid Build Coastguard Worker 
RenderString(CFX_RenderDevice * pDevice,PieceLine * pPieceLine,size_t szPiece,std::vector<TextCharPos> * pCharPos,const CFX_Matrix & mtDoc2Device)1148*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::RenderString(CFX_RenderDevice* pDevice,
1149*3ac0a46fSAndroid Build Coastguard Worker                                    PieceLine* pPieceLine,
1150*3ac0a46fSAndroid Build Coastguard Worker                                    size_t szPiece,
1151*3ac0a46fSAndroid Build Coastguard Worker                                    std::vector<TextCharPos>* pCharPos,
1152*3ac0a46fSAndroid Build Coastguard Worker                                    const CFX_Matrix& mtDoc2Device) {
1153*3ac0a46fSAndroid Build Coastguard Worker   const TextPiece* pPiece = pPieceLine->m_textPieces[szPiece].get();
1154*3ac0a46fSAndroid Build Coastguard Worker   size_t szCount = GetDisplayPos(pPiece, pCharPos);
1155*3ac0a46fSAndroid Build Coastguard Worker   if (szCount > 0) {
1156*3ac0a46fSAndroid Build Coastguard Worker     auto span = pdfium::make_span(pCharPos->data(), szCount);
1157*3ac0a46fSAndroid Build Coastguard Worker     CFDE_TextOut::DrawString(pDevice, pPiece->dwColor, pPiece->pFont, span,
1158*3ac0a46fSAndroid Build Coastguard Worker                              pPiece->fFontSize, mtDoc2Device);
1159*3ac0a46fSAndroid Build Coastguard Worker   }
1160*3ac0a46fSAndroid Build Coastguard Worker   pPieceLine->m_charCounts.push_back(szCount);
1161*3ac0a46fSAndroid Build Coastguard Worker }
1162*3ac0a46fSAndroid Build Coastguard Worker 
RenderPath(CFX_RenderDevice * pDevice,const PieceLine * pPieceLine,size_t szPiece,std::vector<TextCharPos> * pCharPos,const CFX_Matrix & mtDoc2Device)1163*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextLayout::RenderPath(CFX_RenderDevice* pDevice,
1164*3ac0a46fSAndroid Build Coastguard Worker                                  const PieceLine* pPieceLine,
1165*3ac0a46fSAndroid Build Coastguard Worker                                  size_t szPiece,
1166*3ac0a46fSAndroid Build Coastguard Worker                                  std::vector<TextCharPos>* pCharPos,
1167*3ac0a46fSAndroid Build Coastguard Worker                                  const CFX_Matrix& mtDoc2Device) {
1168*3ac0a46fSAndroid Build Coastguard Worker   const TextPiece* pPiece = pPieceLine->m_textPieces[szPiece].get();
1169*3ac0a46fSAndroid Build Coastguard Worker   bool bNoUnderline = pPiece->iUnderline < 1 || pPiece->iUnderline > 2;
1170*3ac0a46fSAndroid Build Coastguard Worker   bool bNoLineThrough = pPiece->iLineThrough < 1 || pPiece->iLineThrough > 2;
1171*3ac0a46fSAndroid Build Coastguard Worker   if (bNoUnderline && bNoLineThrough)
1172*3ac0a46fSAndroid Build Coastguard Worker     return;
1173*3ac0a46fSAndroid Build Coastguard Worker 
1174*3ac0a46fSAndroid Build Coastguard Worker   CFX_Path path;
1175*3ac0a46fSAndroid Build Coastguard Worker   size_t szChars = GetDisplayPos(pPiece, pCharPos);
1176*3ac0a46fSAndroid Build Coastguard Worker   if (szChars > 0) {
1177*3ac0a46fSAndroid Build Coastguard Worker     CFX_PointF pt1;
1178*3ac0a46fSAndroid Build Coastguard Worker     CFX_PointF pt2;
1179*3ac0a46fSAndroid Build Coastguard Worker     float fEndY = (*pCharPos)[0].m_Origin.y + 1.05f;
1180*3ac0a46fSAndroid Build Coastguard Worker     if (pPiece->iPeriod == XFA_AttributeValue::Word) {
1181*3ac0a46fSAndroid Build Coastguard Worker       for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1182*3ac0a46fSAndroid Build Coastguard Worker         for (size_t j = 0; j < szChars; j++) {
1183*3ac0a46fSAndroid Build Coastguard Worker           pt1.x = (*pCharPos)[j].m_Origin.x;
1184*3ac0a46fSAndroid Build Coastguard Worker           pt2.x = pt1.x +
1185*3ac0a46fSAndroid Build Coastguard Worker                   (*pCharPos)[j].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1186*3ac0a46fSAndroid Build Coastguard Worker           pt1.y = pt2.y = fEndY;
1187*3ac0a46fSAndroid Build Coastguard Worker           path.AppendLine(pt1, pt2);
1188*3ac0a46fSAndroid Build Coastguard Worker         }
1189*3ac0a46fSAndroid Build Coastguard Worker         fEndY += 2.0f;
1190*3ac0a46fSAndroid Build Coastguard Worker       }
1191*3ac0a46fSAndroid Build Coastguard Worker     } else {
1192*3ac0a46fSAndroid Build Coastguard Worker       pt1.x = (*pCharPos)[0].m_Origin.x;
1193*3ac0a46fSAndroid Build Coastguard Worker       pt2.x = (*pCharPos)[szChars - 1].m_Origin.x +
1194*3ac0a46fSAndroid Build Coastguard Worker               (*pCharPos)[szChars - 1].m_FontCharWidth * pPiece->fFontSize /
1195*3ac0a46fSAndroid Build Coastguard Worker                   1000.0f;
1196*3ac0a46fSAndroid Build Coastguard Worker       for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1197*3ac0a46fSAndroid Build Coastguard Worker         pt1.y = pt2.y = fEndY;
1198*3ac0a46fSAndroid Build Coastguard Worker         path.AppendLine(pt1, pt2);
1199*3ac0a46fSAndroid Build Coastguard Worker         fEndY += 2.0f;
1200*3ac0a46fSAndroid Build Coastguard Worker       }
1201*3ac0a46fSAndroid Build Coastguard Worker     }
1202*3ac0a46fSAndroid Build Coastguard Worker     fEndY = (*pCharPos)[0].m_Origin.y - pPiece->rtPiece.height * 0.25f;
1203*3ac0a46fSAndroid Build Coastguard Worker     pt1.x = (*pCharPos)[0].m_Origin.x;
1204*3ac0a46fSAndroid Build Coastguard Worker     pt2.x =
1205*3ac0a46fSAndroid Build Coastguard Worker         (*pCharPos)[szChars - 1].m_Origin.x +
1206*3ac0a46fSAndroid Build Coastguard Worker         (*pCharPos)[szChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1207*3ac0a46fSAndroid Build Coastguard Worker     for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
1208*3ac0a46fSAndroid Build Coastguard Worker       pt1.y = pt2.y = fEndY;
1209*3ac0a46fSAndroid Build Coastguard Worker       path.AppendLine(pt1, pt2);
1210*3ac0a46fSAndroid Build Coastguard Worker       fEndY += 2.0f;
1211*3ac0a46fSAndroid Build Coastguard Worker     }
1212*3ac0a46fSAndroid Build Coastguard Worker   } else {
1213*3ac0a46fSAndroid Build Coastguard Worker     if (bNoLineThrough &&
1214*3ac0a46fSAndroid Build Coastguard Worker         (bNoUnderline || pPiece->iPeriod != XFA_AttributeValue::All)) {
1215*3ac0a46fSAndroid Build Coastguard Worker       return;
1216*3ac0a46fSAndroid Build Coastguard Worker     }
1217*3ac0a46fSAndroid Build Coastguard Worker     bool bHasCount = false;
1218*3ac0a46fSAndroid Build Coastguard Worker     size_t szPiecePrev = szPiece;
1219*3ac0a46fSAndroid Build Coastguard Worker     size_t szPieceNext = szPiece;
1220*3ac0a46fSAndroid Build Coastguard Worker     while (szPiecePrev > 0) {
1221*3ac0a46fSAndroid Build Coastguard Worker       szPiecePrev--;
1222*3ac0a46fSAndroid Build Coastguard Worker       if (pPieceLine->m_charCounts[szPiecePrev] > 0) {
1223*3ac0a46fSAndroid Build Coastguard Worker         bHasCount = true;
1224*3ac0a46fSAndroid Build Coastguard Worker         break;
1225*3ac0a46fSAndroid Build Coastguard Worker       }
1226*3ac0a46fSAndroid Build Coastguard Worker     }
1227*3ac0a46fSAndroid Build Coastguard Worker     if (!bHasCount)
1228*3ac0a46fSAndroid Build Coastguard Worker       return;
1229*3ac0a46fSAndroid Build Coastguard Worker 
1230*3ac0a46fSAndroid Build Coastguard Worker     bHasCount = false;
1231*3ac0a46fSAndroid Build Coastguard Worker     while (szPieceNext < pPieceLine->m_textPieces.size() - 1) {
1232*3ac0a46fSAndroid Build Coastguard Worker       szPieceNext++;
1233*3ac0a46fSAndroid Build Coastguard Worker       if (pPieceLine->m_charCounts[szPieceNext] > 0) {
1234*3ac0a46fSAndroid Build Coastguard Worker         bHasCount = true;
1235*3ac0a46fSAndroid Build Coastguard Worker         break;
1236*3ac0a46fSAndroid Build Coastguard Worker       }
1237*3ac0a46fSAndroid Build Coastguard Worker     }
1238*3ac0a46fSAndroid Build Coastguard Worker     if (!bHasCount)
1239*3ac0a46fSAndroid Build Coastguard Worker       return;
1240*3ac0a46fSAndroid Build Coastguard Worker 
1241*3ac0a46fSAndroid Build Coastguard Worker     float fOrgX = 0.0f;
1242*3ac0a46fSAndroid Build Coastguard Worker     float fEndX = 0.0f;
1243*3ac0a46fSAndroid Build Coastguard Worker     pPiece = pPieceLine->m_textPieces[szPiecePrev].get();
1244*3ac0a46fSAndroid Build Coastguard Worker     szChars = GetDisplayPos(pPiece, pCharPos);
1245*3ac0a46fSAndroid Build Coastguard Worker     if (szChars < 1)
1246*3ac0a46fSAndroid Build Coastguard Worker       return;
1247*3ac0a46fSAndroid Build Coastguard Worker 
1248*3ac0a46fSAndroid Build Coastguard Worker     fOrgX =
1249*3ac0a46fSAndroid Build Coastguard Worker         (*pCharPos)[szChars - 1].m_Origin.x +
1250*3ac0a46fSAndroid Build Coastguard Worker         (*pCharPos)[szChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1251*3ac0a46fSAndroid Build Coastguard Worker     pPiece = pPieceLine->m_textPieces[szPieceNext].get();
1252*3ac0a46fSAndroid Build Coastguard Worker     szChars = GetDisplayPos(pPiece, pCharPos);
1253*3ac0a46fSAndroid Build Coastguard Worker     if (szChars < 1)
1254*3ac0a46fSAndroid Build Coastguard Worker       return;
1255*3ac0a46fSAndroid Build Coastguard Worker 
1256*3ac0a46fSAndroid Build Coastguard Worker     fEndX = (*pCharPos)[0].m_Origin.x;
1257*3ac0a46fSAndroid Build Coastguard Worker     CFX_PointF pt1;
1258*3ac0a46fSAndroid Build Coastguard Worker     CFX_PointF pt2;
1259*3ac0a46fSAndroid Build Coastguard Worker     pt1.x = fOrgX;
1260*3ac0a46fSAndroid Build Coastguard Worker     pt2.x = fEndX;
1261*3ac0a46fSAndroid Build Coastguard Worker     float fEndY = (*pCharPos)[0].m_Origin.y + 1.05f;
1262*3ac0a46fSAndroid Build Coastguard Worker     for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1263*3ac0a46fSAndroid Build Coastguard Worker       pt1.y = fEndY;
1264*3ac0a46fSAndroid Build Coastguard Worker       pt2.y = fEndY;
1265*3ac0a46fSAndroid Build Coastguard Worker       path.AppendLine(pt1, pt2);
1266*3ac0a46fSAndroid Build Coastguard Worker       fEndY += 2.0f;
1267*3ac0a46fSAndroid Build Coastguard Worker     }
1268*3ac0a46fSAndroid Build Coastguard Worker     fEndY = (*pCharPos)[0].m_Origin.y - pPiece->rtPiece.height * 0.25f;
1269*3ac0a46fSAndroid Build Coastguard Worker     for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
1270*3ac0a46fSAndroid Build Coastguard Worker       pt1.y = fEndY;
1271*3ac0a46fSAndroid Build Coastguard Worker       pt2.y = fEndY;
1272*3ac0a46fSAndroid Build Coastguard Worker       path.AppendLine(pt1, pt2);
1273*3ac0a46fSAndroid Build Coastguard Worker       fEndY += 2.0f;
1274*3ac0a46fSAndroid Build Coastguard Worker     }
1275*3ac0a46fSAndroid Build Coastguard Worker   }
1276*3ac0a46fSAndroid Build Coastguard Worker 
1277*3ac0a46fSAndroid Build Coastguard Worker   CFX_GraphStateData graphState;
1278*3ac0a46fSAndroid Build Coastguard Worker   graphState.m_LineCap = CFX_GraphStateData::LineCap::kButt;
1279*3ac0a46fSAndroid Build Coastguard Worker   graphState.m_LineJoin = CFX_GraphStateData::LineJoin::kMiter;
1280*3ac0a46fSAndroid Build Coastguard Worker   graphState.m_LineWidth = 1;
1281*3ac0a46fSAndroid Build Coastguard Worker   graphState.m_MiterLimit = 10;
1282*3ac0a46fSAndroid Build Coastguard Worker   graphState.m_DashPhase = 0;
1283*3ac0a46fSAndroid Build Coastguard Worker   pDevice->DrawPath(path, &mtDoc2Device, &graphState, 0, pPiece->dwColor,
1284*3ac0a46fSAndroid Build Coastguard Worker                     CFX_FillRenderOptions());
1285*3ac0a46fSAndroid Build Coastguard Worker }
1286*3ac0a46fSAndroid Build Coastguard Worker 
GetDisplayPos(const TextPiece * pPiece,std::vector<TextCharPos> * pCharPos)1287*3ac0a46fSAndroid Build Coastguard Worker size_t CXFA_TextLayout::GetDisplayPos(const TextPiece* pPiece,
1288*3ac0a46fSAndroid Build Coastguard Worker                                       std::vector<TextCharPos>* pCharPos) {
1289*3ac0a46fSAndroid Build Coastguard Worker   if (!pPiece || pPiece->iChars < 1)
1290*3ac0a46fSAndroid Build Coastguard Worker     return 0;
1291*3ac0a46fSAndroid Build Coastguard Worker   return m_pBreak->GetDisplayPos(pPiece, pCharPos);
1292*3ac0a46fSAndroid Build Coastguard Worker }
1293