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