blob: fd913c2df52b218a2cf7c4d90364e44f71428e2c [file] [log] [blame]
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001// Copyright 2017 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "xfa/fxfa/app/cxfa_textlayout.h"
8
9#include <algorithm>
tsepez783a7e02017-01-17 11:05:57 -080010#include <utility>
Dan Sinclair1f5d4982017-01-10 16:37:32 -050011
12#include "third_party/base/ptr_util.h"
13#include "third_party/base/stl_util.h"
14#include "xfa/fde/cfde_path.h"
Dan Sinclair95bec802017-01-19 10:27:58 -050015#include "xfa/fde/css/cfde_csscomputedstyle.h"
16#include "xfa/fde/css/cfde_cssstyleselector.h"
Dan Sinclair1f5d4982017-01-10 16:37:32 -050017#include "xfa/fde/fde_gedevice.h"
18#include "xfa/fde/fde_object.h"
19#include "xfa/fde/xml/fde_xml_imp.h"
20#include "xfa/fxfa/app/cxfa_linkuserdata.h"
21#include "xfa/fxfa/app/cxfa_loadercontext.h"
22#include "xfa/fxfa/app/cxfa_pieceline.h"
23#include "xfa/fxfa/app/cxfa_textparsecontext.h"
24#include "xfa/fxfa/app/cxfa_texttabstopscontext.h"
25#include "xfa/fxfa/app/cxfa_textuserdata.h"
26#include "xfa/fxfa/app/xfa_ffwidgetacc.h"
27#include "xfa/fxfa/app/xfa_textpiece.h"
28#include "xfa/fxfa/parser/cxfa_font.h"
29#include "xfa/fxfa/parser/cxfa_para.h"
30#include "xfa/fxfa/parser/xfa_object.h"
31
32#define XFA_LOADERCNTXTFLG_FILTERSPACE 0x001
33
34CXFA_TextLayout::CXFA_TextLayout(CXFA_TextProvider* pTextProvider)
35 : m_bHasBlock(false),
36 m_pTextProvider(pTextProvider),
37 m_pTextDataNode(nullptr),
38 m_bRichText(false),
39 m_iLines(0),
40 m_fMaxWidth(0),
41 m_bBlockContinue(true) {
42 ASSERT(m_pTextProvider);
43}
44
45CXFA_TextLayout::~CXFA_TextLayout() {
46 m_textParser.Reset();
47 Unload();
48}
49
50void CXFA_TextLayout::Unload() {
tsepez783a7e02017-01-17 11:05:57 -080051 m_pieceLines.clear();
Dan Sinclair1f5d4982017-01-10 16:37:32 -050052 m_pBreak.reset();
Dan Sinclair1f5d4982017-01-10 16:37:32 -050053}
54
Dan Sinclair1f5d4982017-01-10 16:37:32 -050055void CXFA_TextLayout::GetTextDataNode() {
56 if (!m_pTextProvider)
57 return;
58
59 CXFA_Node* pNode = m_pTextProvider->GetTextNode(m_bRichText);
60 if (pNode && m_bRichText)
61 m_textParser.Reset();
62
63 m_pTextDataNode = pNode;
64}
65
66CFDE_XMLNode* CXFA_TextLayout::GetXMLContainerNode() {
67 if (!m_bRichText)
68 return nullptr;
69
70 CFDE_XMLNode* pXMLRoot = m_pTextDataNode->GetXMLMappingNode();
71 if (!pXMLRoot)
72 return nullptr;
73
74 CFDE_XMLNode* pXMLContainer = nullptr;
75 for (CFDE_XMLNode* pXMLChild =
76 pXMLRoot->GetNodeItem(CFDE_XMLNode::FirstChild);
77 pXMLChild;
78 pXMLChild = pXMLChild->GetNodeItem(CFDE_XMLNode::NextSibling)) {
79 if (pXMLChild->GetType() == FDE_XMLNODE_Element) {
80 CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLChild);
81 CFX_WideString wsTag;
82 pXMLElement->GetLocalTagName(wsTag);
dan sinclair65c7c232017-02-02 14:05:30 -080083 if (wsTag == L"body" || wsTag == L"html") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -050084 pXMLContainer = pXMLChild;
85 break;
86 }
87 }
88 }
89 return pXMLContainer;
90}
91
Dan Sinclairb0d31602017-03-01 15:58:32 -050092std::unique_ptr<CFX_RTFBreak> CXFA_TextLayout::CreateBreak(bool bDefault) {
Dan Sinclaire533b932017-03-16 11:47:20 -040093 uint32_t dwStyle = FX_LAYOUTSTYLE_ExpandTab;
Dan Sinclair1f5d4982017-01-10 16:37:32 -050094 if (!bDefault)
Dan Sinclaire533b932017-03-16 11:47:20 -040095 dwStyle |= FX_LAYOUTSTYLE_Pagination;
Dan Sinclair1f5d4982017-01-10 16:37:32 -050096
Dan Sinclairb0d31602017-03-01 15:58:32 -050097 auto pBreak = pdfium::MakeUnique<CFX_RTFBreak>(dwStyle);
Dan Sinclair1f5d4982017-01-10 16:37:32 -050098 pBreak->SetLineBreakTolerance(1);
99 pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr));
100 pBreak->SetFontSize(m_textParser.GetFontSize(m_pTextProvider, nullptr));
101 return pBreak;
102}
103
Dan Sinclair05df0752017-03-14 14:43:42 -0400104void CXFA_TextLayout::InitBreak(float fLineWidth) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500105 CXFA_Font font = m_pTextProvider->GetFontNode();
106 CXFA_Para para = m_pTextProvider->GetParaNode();
Dan Sinclair05df0752017-03-14 14:43:42 -0400107 float fStart = 0;
108 float fStartPos = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500109 if (para) {
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500110 CFX_RTFLineAlignment iAlign = CFX_RTFLineAlignment::Left;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500111 switch (para.GetHorizontalAlign()) {
112 case XFA_ATTRIBUTEENUM_Center:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500113 iAlign = CFX_RTFLineAlignment::Center;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500114 break;
115 case XFA_ATTRIBUTEENUM_Right:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500116 iAlign = CFX_RTFLineAlignment::Right;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500117 break;
118 case XFA_ATTRIBUTEENUM_Justify:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500119 iAlign = CFX_RTFLineAlignment::Justified;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500120 break;
121 case XFA_ATTRIBUTEENUM_JustifyAll:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500122 iAlign = CFX_RTFLineAlignment::Distributed;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500123 break;
124 }
125 m_pBreak->SetAlignment(iAlign);
126
127 fStart = para.GetMarginLeft();
128 if (m_pTextProvider->IsCheckButtonAndAutoWidth()) {
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500129 if (iAlign != CFX_RTFLineAlignment::Left)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500130 fLineWidth -= para.GetMarginRight();
131 } else {
132 fLineWidth -= para.GetMarginRight();
133 }
134 if (fLineWidth < 0)
135 fLineWidth = fStart;
136
137 fStartPos = fStart;
Dan Sinclair05df0752017-03-14 14:43:42 -0400138 float fIndent = para.GetTextIndent();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500139 if (fIndent > 0)
140 fStartPos += fIndent;
141 }
142
143 m_pBreak->SetLineBoundary(fStart, fLineWidth);
144 m_pBreak->SetLineStartPos(fStartPos);
145 if (font) {
146 m_pBreak->SetHorizontalScale((int32_t)font.GetHorizontalScale());
147 m_pBreak->SetVerticalScale((int32_t)font.GetVerticalScale());
148 m_pBreak->SetCharSpace(font.GetLetterSpacing());
149 }
150
Dan Sinclair05df0752017-03-14 14:43:42 -0400151 float fFontSize = m_textParser.GetFontSize(m_pTextProvider, nullptr);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500152 m_pBreak->SetFontSize(fFontSize);
153 m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr));
154 m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
155}
156
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500157void CXFA_TextLayout::InitBreak(CFDE_CSSComputedStyle* pStyle,
Dan Sinclair96f482c2017-01-11 16:31:27 -0500158 FDE_CSSDisplay eDisplay,
Dan Sinclair05df0752017-03-14 14:43:42 -0400159 float fLineWidth,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500160 CFDE_XMLNode* pXMLNode,
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500161 CFDE_CSSComputedStyle* pParentStyle) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500162 if (!pStyle) {
163 InitBreak(fLineWidth);
164 return;
165 }
166
Dan Sinclair96f482c2017-01-11 16:31:27 -0500167 if (eDisplay == FDE_CSSDisplay::Block ||
168 eDisplay == FDE_CSSDisplay::ListItem) {
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500169 CFX_RTFLineAlignment iAlign = CFX_RTFLineAlignment::Left;
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500170 switch (pStyle->GetTextAlign()) {
Dan Sinclair96f482c2017-01-11 16:31:27 -0500171 case FDE_CSSTextAlign::Right:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500172 iAlign = CFX_RTFLineAlignment::Right;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500173 break;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500174 case FDE_CSSTextAlign::Center:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500175 iAlign = CFX_RTFLineAlignment::Center;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500176 break;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500177 case FDE_CSSTextAlign::Justify:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500178 iAlign = CFX_RTFLineAlignment::Justified;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500179 break;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500180 case FDE_CSSTextAlign::JustifyAll:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500181 iAlign = CFX_RTFLineAlignment::Distributed;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500182 break;
183 default:
184 break;
185 }
186 m_pBreak->SetAlignment(iAlign);
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500187
Dan Sinclair05df0752017-03-14 14:43:42 -0400188 float fStart = 0;
Dan Sinclairb9fbe6e2017-01-16 16:07:41 -0500189 const FDE_CSSRect* pRect = pStyle->GetMarginWidth();
190 const FDE_CSSRect* pPaddingRect = pStyle->GetPaddingWidth();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500191 if (pRect) {
192 fStart = pRect->left.GetValue();
193 fLineWidth -= pRect->right.GetValue();
194 if (pPaddingRect) {
195 fStart += pPaddingRect->left.GetValue();
196 fLineWidth -= pPaddingRect->right.GetValue();
197 }
Dan Sinclair96f482c2017-01-11 16:31:27 -0500198 if (eDisplay == FDE_CSSDisplay::ListItem) {
Dan Sinclairb9fbe6e2017-01-16 16:07:41 -0500199 const FDE_CSSRect* pParRect = pParentStyle->GetMarginWidth();
200 const FDE_CSSRect* pParPaddingRect = pParentStyle->GetPaddingWidth();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500201 if (pParRect) {
202 fStart += pParRect->left.GetValue();
203 fLineWidth -= pParRect->right.GetValue();
204 if (pParPaddingRect) {
205 fStart += pParPaddingRect->left.GetValue();
206 fLineWidth -= pParPaddingRect->right.GetValue();
207 }
208 }
Dan Sinclairb9fbe6e2017-01-16 16:07:41 -0500209 FDE_CSSRect pNewRect;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500210 pNewRect.left.Set(FDE_CSSLengthUnit::Point, fStart);
211 pNewRect.right.Set(FDE_CSSLengthUnit::Point, pRect->right.GetValue());
212 pNewRect.top.Set(FDE_CSSLengthUnit::Point, pRect->top.GetValue());
213 pNewRect.bottom.Set(FDE_CSSLengthUnit::Point, pRect->bottom.GetValue());
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500214 pStyle->SetMarginWidth(pNewRect);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500215 }
216 }
217 m_pBreak->SetLineBoundary(fStart, fLineWidth);
Dan Sinclair05df0752017-03-14 14:43:42 -0400218 float fIndent = pStyle->GetTextIndent().GetValue();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500219 if (fIndent > 0)
220 fStart += fIndent;
221
222 m_pBreak->SetLineStartPos(fStart);
223 m_pBreak->SetTabWidth(m_textParser.GetTabInterval(pStyle));
224 if (!m_pTabstopContext)
225 m_pTabstopContext = pdfium::MakeUnique<CXFA_TextTabstopsContext>();
226 m_textParser.GetTabstops(pStyle, m_pTabstopContext.get());
227 for (int32_t i = 0; i < m_pTabstopContext->m_iTabCount; i++) {
228 XFA_TABSTOPS* pTab = m_pTabstopContext->m_tabstops.GetDataPtr(i);
229 m_pBreak->AddPositionedTab(pTab->fTabstops);
230 }
231 }
232
Dan Sinclair05df0752017-03-14 14:43:42 -0400233 float fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500234 m_pBreak->SetFontSize(fFontSize);
235 m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
236 m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, pStyle));
237 m_pBreak->SetHorizontalScale(
238 m_textParser.GetHorScale(m_pTextProvider, pStyle, pXMLNode));
239 m_pBreak->SetVerticalScale(m_textParser.GetVerScale(m_pTextProvider, pStyle));
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500240 m_pBreak->SetCharSpace(pStyle->GetLetterSpacing().GetValue());
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500241}
242
243int32_t CXFA_TextLayout::GetText(CFX_WideString& wsText) {
244 GetTextDataNode();
245 wsText.clear();
246 if (!m_bRichText)
247 wsText = m_pTextDataNode->GetContent();
248 return wsText.GetLength();
249}
250
Dan Sinclair05df0752017-03-14 14:43:42 -0400251float CXFA_TextLayout::GetLayoutHeight() {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500252 if (!m_pLoader)
253 return 0;
254
Tom Sepezfcc309e2017-03-24 14:19:11 -0700255 if (m_pLoader->m_lineHeights.empty() && m_pLoader->m_fWidth > 0) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500256 CFX_SizeF szMax(m_pLoader->m_fWidth, m_pLoader->m_fHeight);
257 CFX_SizeF szDef;
258 m_pLoader->m_bSaveLineHeight = true;
259 m_pLoader->m_fLastPos = 0;
260 CalcSize(szMax, szMax, szDef);
261 m_pLoader->m_bSaveLineHeight = false;
dan sinclair071d7862017-02-07 20:46:32 -0500262 return szDef.height;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500263 }
264
Dan Sinclair05df0752017-03-14 14:43:42 -0400265 float fHeight = m_pLoader->m_fHeight;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500266 if (fHeight < 0.1f) {
267 fHeight = 0;
Tom Sepezfcc309e2017-03-24 14:19:11 -0700268 for (float value : m_pLoader->m_lineHeights)
269 fHeight += value;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500270 }
271 return fHeight;
272}
273
Dan Sinclair05df0752017-03-14 14:43:42 -0400274float CXFA_TextLayout::StartLayout(float fWidth) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500275 if (!m_pLoader)
276 m_pLoader = pdfium::MakeUnique<CXFA_LoaderContext>();
277
278 if (fWidth < 0 || (m_pLoader->m_fWidth > -1 &&
279 FXSYS_fabs(fWidth - m_pLoader->m_fWidth) > 0)) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700280 m_pLoader->m_lineHeights.clear();
281 m_Blocks.clear();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500282 Unload();
283 m_pLoader->m_fStartLineOffset = 0;
284 }
285 m_pLoader->m_fWidth = fWidth;
286
287 if (fWidth < 0) {
288 CFX_SizeF szMax;
289 CFX_SizeF szDef;
290 m_pLoader->m_bSaveLineHeight = true;
291 m_pLoader->m_fLastPos = 0;
292 CalcSize(szMax, szMax, szDef);
293 m_pLoader->m_bSaveLineHeight = false;
dan sinclair071d7862017-02-07 20:46:32 -0500294 fWidth = szDef.width;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500295 }
296 return fWidth;
297}
298
299bool CXFA_TextLayout::DoLayout(int32_t iBlockIndex,
Dan Sinclair05df0752017-03-14 14:43:42 -0400300 float& fCalcHeight,
301 float fContentAreaHeight,
302 float fTextHeight) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500303 if (!m_pLoader)
304 return false;
305
Tom Sepezfcc309e2017-03-24 14:19:11 -0700306 int32_t iBlockCount = pdfium::CollectionSize<int32_t>(m_Blocks);
Dan Sinclair05df0752017-03-14 14:43:42 -0400307 float fHeight = fTextHeight;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500308 if (fHeight < 0)
309 fHeight = GetLayoutHeight();
310
311 m_pLoader->m_fHeight = fHeight;
312 if (fContentAreaHeight < 0)
313 return false;
314
315 m_bHasBlock = true;
316 if (iBlockCount == 0 && fHeight > 0) {
317 fHeight = fTextHeight - GetLayoutHeight();
318 if (fHeight > 0) {
319 int32_t iAlign = m_textParser.GetVAlign(m_pTextProvider);
320 if (iAlign == XFA_ATTRIBUTEENUM_Middle)
321 fHeight /= 2.0f;
322 else if (iAlign != XFA_ATTRIBUTEENUM_Bottom)
323 fHeight = 0;
324 m_pLoader->m_fStartLineOffset = fHeight;
325 }
326 }
327
Dan Sinclair05df0752017-03-14 14:43:42 -0400328 float fLinePos = m_pLoader->m_fStartLineOffset;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500329 int32_t iLineIndex = 0;
330 if (iBlockCount > 1) {
331 if (iBlockCount >= (iBlockIndex + 1) * 2) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700332 iLineIndex = m_Blocks[iBlockIndex * 2];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500333 } else {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700334 iLineIndex = m_Blocks[iBlockCount - 1] + m_Blocks[iBlockCount - 2];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500335 }
336 if (!m_pLoader->m_BlocksHeight.empty()) {
337 for (int32_t i = 0; i < iBlockIndex; i++)
338 fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
339 }
340 }
341
Tom Sepezfcc309e2017-03-24 14:19:11 -0700342 int32_t iCount = pdfium::CollectionSize<int32_t>(m_pLoader->m_lineHeights);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500343 int32_t i = 0;
344 for (i = iLineIndex; i < iCount; i++) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700345 float fLineHeight = m_pLoader->m_lineHeights[i];
346 if (i == iLineIndex && fLineHeight - fContentAreaHeight > 0.001) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500347 fCalcHeight = 0;
348 return true;
349 }
350 if (fLinePos + fLineHeight - fContentAreaHeight > 0.001) {
351 if (iBlockCount >= (iBlockIndex + 1) * 2) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700352 m_Blocks[iBlockIndex * 2] = iLineIndex;
353 m_Blocks[iBlockIndex * 2 + 1] = i - iLineIndex;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500354 } else {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700355 m_Blocks.push_back(iLineIndex);
356 m_Blocks.push_back(i - iLineIndex);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500357 }
358 if (i == iLineIndex) {
359 if (fCalcHeight <= fLinePos) {
360 if (pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight) >
361 iBlockIndex * 2 &&
362 (m_pLoader->m_BlocksHeight[iBlockIndex * 2] == iBlockIndex)) {
363 m_pLoader->m_BlocksHeight[iBlockIndex * 2 + 1] = fCalcHeight;
364 } else {
Dan Sinclair05df0752017-03-14 14:43:42 -0400365 m_pLoader->m_BlocksHeight.push_back((float)iBlockIndex);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500366 m_pLoader->m_BlocksHeight.push_back(fCalcHeight);
367 }
368 }
369 return true;
370 }
371
372 fCalcHeight = fLinePos;
373 return true;
374 }
375 fLinePos += fLineHeight;
376 }
377 return false;
378}
379
380int32_t CXFA_TextLayout::CountBlocks() const {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700381 int32_t iCount = pdfium::CollectionSize<int32_t>(m_Blocks) / 2;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500382 return iCount > 0 ? iCount : 1;
383}
384
385bool CXFA_TextLayout::CalcSize(const CFX_SizeF& minSize,
386 const CFX_SizeF& maxSize,
387 CFX_SizeF& defaultSize) {
dan sinclair071d7862017-02-07 20:46:32 -0500388 defaultSize.width = maxSize.width;
389 if (defaultSize.width < 1)
390 defaultSize.width = 0xFFFF;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500391
Dan Sinclairb0d31602017-03-01 15:58:32 -0500392 m_pBreak = CreateBreak(false);
Dan Sinclair05df0752017-03-14 14:43:42 -0400393 float fLinePos = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500394 m_iLines = 0;
395 m_fMaxWidth = 0;
396 Loader(defaultSize, fLinePos, false);
397 if (fLinePos < 0.1f)
398 fLinePos = m_textParser.GetFontSize(m_pTextProvider, nullptr);
399
400 m_pTabstopContext.reset();
401 defaultSize = CFX_SizeF(m_fMaxWidth, fLinePos);
402 return true;
403}
404
Dan Sinclair05df0752017-03-14 14:43:42 -0400405bool CXFA_TextLayout::Layout(const CFX_SizeF& size, float* fHeight) {
dan sinclair071d7862017-02-07 20:46:32 -0500406 if (size.width < 1)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500407 return false;
408
409 Unload();
Dan Sinclairb0d31602017-03-01 15:58:32 -0500410 m_pBreak = CreateBreak(true);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500411 if (m_pLoader) {
412 m_pLoader->m_iTotalLines = -1;
413 m_pLoader->m_iChar = 0;
414 }
415
416 m_iLines = 0;
Dan Sinclair05df0752017-03-14 14:43:42 -0400417 float fLinePos = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500418 Loader(size, fLinePos, true);
dan sinclair071d7862017-02-07 20:46:32 -0500419 UpdateAlign(size.height, fLinePos);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500420 m_pTabstopContext.reset();
421 if (fHeight)
422 *fHeight = fLinePos;
423 return true;
424}
425
426bool CXFA_TextLayout::Layout(int32_t iBlock) {
427 if (!m_pLoader || iBlock < 0 || iBlock >= CountBlocks())
428 return false;
429 if (m_pLoader->m_fWidth < 1)
430 return false;
431
432 m_pLoader->m_iTotalLines = -1;
433 m_iLines = 0;
Dan Sinclair05df0752017-03-14 14:43:42 -0400434 float fLinePos = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500435 CXFA_Node* pNode = nullptr;
436 CFX_SizeF szText(m_pLoader->m_fWidth, m_pLoader->m_fHeight);
Tom Sepezfcc309e2017-03-24 14:19:11 -0700437 int32_t iCount = pdfium::CollectionSize<int32_t>(m_Blocks);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500438 int32_t iBlocksHeightCount =
439 pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight);
440 iBlocksHeightCount /= 2;
441 if (iBlock < iBlocksHeightCount)
442 return true;
443 if (iBlock == iBlocksHeightCount) {
444 Unload();
Dan Sinclairb0d31602017-03-01 15:58:32 -0500445 m_pBreak = CreateBreak(true);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500446 fLinePos = m_pLoader->m_fStartLineOffset;
447 for (int32_t i = 0; i < iBlocksHeightCount; i++)
448 fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
449
450 m_pLoader->m_iChar = 0;
451 if (iCount > 1)
Tom Sepezfcc309e2017-03-24 14:19:11 -0700452 m_pLoader->m_iTotalLines = m_Blocks[iBlock * 2 + 1];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500453
454 Loader(szText, fLinePos, true);
455 if (iCount == 0 && m_pLoader->m_fStartLineOffset < 0.1f)
dan sinclair071d7862017-02-07 20:46:32 -0500456 UpdateAlign(szText.height, fLinePos);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500457 } else if (m_pTextDataNode) {
458 iBlock *= 2;
459 if (iBlock < iCount - 2)
Tom Sepezfcc309e2017-03-24 14:19:11 -0700460 m_pLoader->m_iTotalLines = m_Blocks[iBlock + 1];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500461
462 m_pBreak->Reset();
463 if (m_bRichText) {
464 CFDE_XMLNode* pContainerNode = GetXMLContainerNode();
465 if (!pContainerNode)
466 return true;
467
468 CFDE_XMLNode* pXMLNode = m_pLoader->m_pXMLNode;
469 if (!pXMLNode)
470 return true;
471
472 CFDE_XMLNode* pSaveXMLNode = m_pLoader->m_pXMLNode;
473 for (; pXMLNode;
474 pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
475 if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle,
Tom Sepez03de8842017-01-24 14:24:36 -0800476 true, nullptr)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500477 break;
478 }
479 }
480 while (!pXMLNode) {
481 pXMLNode = pSaveXMLNode->GetNodeItem(CFDE_XMLNode::Parent);
482 if (pXMLNode == pContainerNode)
483 break;
484 if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle,
485 true, nullptr, false)) {
486 break;
487 }
488 pSaveXMLNode = pXMLNode;
489 pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling);
490 if (!pXMLNode)
491 continue;
492 for (; pXMLNode;
493 pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
494 if (!LoadRichText(pXMLNode, szText, fLinePos,
Tom Sepez03de8842017-01-24 14:24:36 -0800495 m_pLoader->m_pParentStyle, true, nullptr)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500496 break;
497 }
498 }
499 }
500 } else {
501 pNode = m_pLoader->m_pNode;
502 if (!pNode)
503 return true;
504 LoadText(pNode, szText, fLinePos, true);
505 }
506 }
507 if (iBlock == iCount) {
508 m_pTabstopContext.reset();
509 m_pLoader.reset();
510 }
511 return true;
512}
513
514void CXFA_TextLayout::ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex) {
515 if (!m_pLoader)
516 return;
517
Tom Sepezfcc309e2017-03-24 14:19:11 -0700518 int32_t iCountHeight =
519 pdfium::CollectionSize<int32_t>(m_pLoader->m_lineHeights);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500520 if (iCountHeight == 0)
521 return;
522
523 bool bEndItem = true;
Tom Sepezfcc309e2017-03-24 14:19:11 -0700524 int32_t iBlockCount = pdfium::CollectionSize<int32_t>(m_Blocks);
Dan Sinclair05df0752017-03-14 14:43:42 -0400525 float fLinePos = m_pLoader->m_fStartLineOffset;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500526 int32_t iLineIndex = 0;
527 if (iBlockIndex > 0) {
528 int32_t iBlockHeightCount =
529 pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight);
530 iBlockHeightCount /= 2;
531 if (iBlockHeightCount >= iBlockIndex) {
532 for (int32_t i = 0; i < iBlockIndex; i++)
533 fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
534 } else {
535 fLinePos = 0;
536 }
537 iLineIndex = m_Blocks[iBlockCount - 1] + m_Blocks[iBlockCount - 2];
538 }
539
540 int32_t i = 0;
541 for (i = iLineIndex; i < iCountHeight; i++) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700542 float fLineHeight = m_pLoader->m_lineHeights[i];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500543 if (fLinePos + fLineHeight - rtText.height > 0.001) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700544 m_Blocks.push_back(iLineIndex);
545 m_Blocks.push_back(i - iLineIndex);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500546 bEndItem = false;
547 break;
548 }
549 fLinePos += fLineHeight;
550 }
551 if (iCountHeight > 0 && (i - iLineIndex) > 0 && bEndItem) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700552 m_Blocks.push_back(iLineIndex);
553 m_Blocks.push_back(i - iLineIndex);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500554 }
555}
556
557bool CXFA_TextLayout::DrawString(CFX_RenderDevice* pFxDevice,
558 const CFX_Matrix& tmDoc2Device,
559 const CFX_RectF& rtClip,
560 int32_t iBlock) {
561 if (!pFxDevice)
562 return false;
563
564 std::unique_ptr<CFDE_RenderDevice> pDevice(
565 new CFDE_RenderDevice(pFxDevice, false));
566 pDevice->SaveState();
567 pDevice->SetClipRect(rtClip);
568
569 auto pSolidBrush = pdfium::MakeUnique<CFDE_Brush>();
570 auto pPen = pdfium::MakeUnique<CFDE_Pen>();
tsepez783a7e02017-01-17 11:05:57 -0800571 if (m_pieceLines.empty()) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500572 int32_t iBlockCount = CountBlocks();
573 for (int32_t i = 0; i < iBlockCount; i++)
574 Layout(i);
575 }
576
577 FXTEXT_CHARPOS* pCharPos = nullptr;
578 int32_t iCharCount = 0;
579 int32_t iLineStart = 0;
tsepez783a7e02017-01-17 11:05:57 -0800580 int32_t iPieceLines = pdfium::CollectionSize<int32_t>(m_pieceLines);
Tom Sepezfcc309e2017-03-24 14:19:11 -0700581 int32_t iCount = pdfium::CollectionSize<int32_t>(m_Blocks);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500582 if (iCount > 0) {
583 iBlock *= 2;
584 if (iBlock < iCount) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700585 iLineStart = m_Blocks[iBlock];
586 iPieceLines = m_Blocks[iBlock + 1];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500587 } else {
588 iPieceLines = 0;
589 }
590 }
591
592 for (int32_t i = 0; i < iPieceLines; i++) {
tsepez783a7e02017-01-17 11:05:57 -0800593 if (i + iLineStart >= pdfium::CollectionSize<int32_t>(m_pieceLines))
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500594 break;
595
tsepez783a7e02017-01-17 11:05:57 -0800596 CXFA_PieceLine* pPieceLine = m_pieceLines[i + iLineStart].get();
597 int32_t iPieces = pdfium::CollectionSize<int32_t>(pPieceLine->m_textPieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500598 int32_t j = 0;
599 for (j = 0; j < iPieces; j++) {
tsepez783a7e02017-01-17 11:05:57 -0800600 const XFA_TextPiece* pPiece = pPieceLine->m_textPieces[j].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500601 int32_t iChars = pPiece->iChars;
602 if (iCharCount < iChars) {
603 FX_Free(pCharPos);
604 pCharPos = FX_Alloc(FXTEXT_CHARPOS, iChars);
605 iCharCount = iChars;
606 }
607 FXSYS_memset(pCharPos, 0, iCharCount * sizeof(FXTEXT_CHARPOS));
608 RenderString(pDevice.get(), pSolidBrush.get(), pPieceLine, j, pCharPos,
609 tmDoc2Device);
610 }
611 for (j = 0; j < iPieces; j++) {
612 RenderPath(pDevice.get(), pPen.get(), pPieceLine, j, pCharPos,
613 tmDoc2Device);
614 }
615 }
616 pDevice->RestoreState();
617 FX_Free(pCharPos);
618 return iPieceLines > 0;
619}
620
Dan Sinclair05df0752017-03-14 14:43:42 -0400621void CXFA_TextLayout::UpdateAlign(float fHeight, float fBottom) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500622 fHeight -= fBottom;
623 if (fHeight < 0.1f)
624 return;
625
626 switch (m_textParser.GetVAlign(m_pTextProvider)) {
627 case XFA_ATTRIBUTEENUM_Middle:
628 fHeight /= 2.0f;
629 break;
630 case XFA_ATTRIBUTEENUM_Bottom:
631 break;
632 default:
633 return;
634 }
635
tsepez783a7e02017-01-17 11:05:57 -0800636 for (const auto& pPieceLine : m_pieceLines) {
637 for (const auto& pPiece : pPieceLine->m_textPieces)
638 pPiece->rtPiece.top += fHeight;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500639 }
640}
641
642bool CXFA_TextLayout::Loader(const CFX_SizeF& szText,
Dan Sinclair05df0752017-03-14 14:43:42 -0400643 float& fLinePos,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500644 bool bSavePieces) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500645 GetTextDataNode();
646 if (!m_pTextDataNode)
647 return true;
648
649 if (m_bRichText) {
650 CFDE_XMLNode* pXMLContainer = GetXMLContainerNode();
651 if (pXMLContainer) {
652 if (!m_textParser.IsParsed())
653 m_textParser.DoParse(pXMLContainer, m_pTextProvider);
654
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500655 auto pRootStyle = m_textParser.CreateRootStyle(m_pTextProvider);
Tom Sepez03de8842017-01-24 14:24:36 -0800656 LoadRichText(pXMLContainer, szText, fLinePos, pRootStyle, bSavePieces,
657 nullptr);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500658 }
659 } else {
660 LoadText(m_pTextDataNode, szText, fLinePos, bSavePieces);
661 }
662 return true;
663}
664
665void CXFA_TextLayout::LoadText(CXFA_Node* pNode,
666 const CFX_SizeF& szText,
Dan Sinclair05df0752017-03-14 14:43:42 -0400667 float& fLinePos,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500668 bool bSavePieces) {
dan sinclair071d7862017-02-07 20:46:32 -0500669 InitBreak(szText.width);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500670
671 CXFA_Para para = m_pTextProvider->GetParaNode();
Dan Sinclair05df0752017-03-14 14:43:42 -0400672 float fSpaceAbove = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500673 if (para) {
674 fSpaceAbove = para.GetSpaceAbove();
675 if (fSpaceAbove < 0.1f) {
676 fSpaceAbove = 0;
677 }
678 int32_t verAlign = para.GetVerticalAlign();
679 switch (verAlign) {
680 case XFA_ATTRIBUTEENUM_Top:
681 case XFA_ATTRIBUTEENUM_Middle:
682 case XFA_ATTRIBUTEENUM_Bottom: {
683 fLinePos += fSpaceAbove;
684 break;
685 }
686 }
687 }
688
689 CFX_WideString wsText = pNode->GetContent();
690 wsText.TrimRight(L" ");
691 bool bRet = AppendChar(wsText, fLinePos, fSpaceAbove, bSavePieces);
692 if (bRet && m_pLoader)
693 m_pLoader->m_pNode = pNode;
694 else
Dan Sinclairc36fe072017-03-09 16:58:12 -0500695 EndBreak(CFX_BreakType::Paragraph, fLinePos, bSavePieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500696}
697
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500698bool CXFA_TextLayout::LoadRichText(
699 CFDE_XMLNode* pXMLNode,
700 const CFX_SizeF& szText,
Dan Sinclair05df0752017-03-14 14:43:42 -0400701 float& fLinePos,
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500702 const CFX_RetainPtr<CFDE_CSSComputedStyle>& pParentStyle,
703 bool bSavePieces,
Tom Sepez03de8842017-01-24 14:24:36 -0800704 CFX_RetainPtr<CXFA_LinkUserData> pLinkData,
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500705 bool bEndBreak,
706 bool bIsOl,
707 int32_t iLiCount) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500708 if (!pXMLNode)
709 return false;
710
711 CXFA_TextParseContext* pContext =
712 m_textParser.GetParseContextFromMap(pXMLNode);
Dan Sinclair96f482c2017-01-11 16:31:27 -0500713 FDE_CSSDisplay eDisplay = FDE_CSSDisplay::None;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500714 bool bContentNode = false;
Dan Sinclair05df0752017-03-14 14:43:42 -0400715 float fSpaceBelow = 0;
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500716 CFX_RetainPtr<CFDE_CSSComputedStyle> pStyle;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500717 CFX_WideString wsName;
718 if (bEndBreak) {
719 bool bCurOl = false;
720 bool bCurLi = false;
721 CFDE_XMLElement* pElement = nullptr;
722 if (pContext) {
723 if (m_bBlockContinue ||
724 (m_pLoader && pXMLNode == m_pLoader->m_pXMLNode)) {
725 m_bBlockContinue = true;
726 }
727 if (pXMLNode->GetType() == FDE_XMLNODE_Text) {
728 bContentNode = true;
729 } else if (pXMLNode->GetType() == FDE_XMLNODE_Element) {
730 pElement = static_cast<CFDE_XMLElement*>(pXMLNode);
731 pElement->GetLocalTagName(wsName);
732 }
dan sinclair65c7c232017-02-02 14:05:30 -0800733 if (wsName == L"ol") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500734 bIsOl = true;
735 bCurOl = true;
736 }
737 if (m_bBlockContinue || bContentNode == false) {
738 eDisplay = pContext->GetDisplay();
Dan Sinclair96f482c2017-01-11 16:31:27 -0500739 if (eDisplay != FDE_CSSDisplay::Block &&
740 eDisplay != FDE_CSSDisplay::Inline &&
741 eDisplay != FDE_CSSDisplay::ListItem) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500742 return true;
743 }
744
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500745 pStyle = m_textParser.ComputeStyle(pXMLNode, pParentStyle.Get());
746 InitBreak(bContentNode ? pParentStyle.Get() : pStyle.Get(), eDisplay,
dan sinclair071d7862017-02-07 20:46:32 -0500747 szText.width, pXMLNode, pParentStyle.Get());
Dan Sinclair96f482c2017-01-11 16:31:27 -0500748 if ((eDisplay == FDE_CSSDisplay::Block ||
749 eDisplay == FDE_CSSDisplay::ListItem) &&
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500750 pStyle &&
dan sinclair65c7c232017-02-02 14:05:30 -0800751 (wsName.IsEmpty() || (wsName != L"body" && wsName != L"html" &&
752 wsName != L"ol" && wsName != L"ul"))) {
Dan Sinclairb9fbe6e2017-01-16 16:07:41 -0500753 const FDE_CSSRect* pRect = pStyle->GetMarginWidth();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500754 if (pRect) {
755 fLinePos += pRect->top.GetValue();
756 fSpaceBelow = pRect->bottom.GetValue();
757 }
758 }
759
dan sinclair65c7c232017-02-02 14:05:30 -0800760 if (wsName == L"a") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500761 CFX_WideString wsLinkContent;
762 ASSERT(pElement);
763 pElement->GetString(L"href", wsLinkContent);
764 if (!wsLinkContent.IsEmpty()) {
Tom Sepez03de8842017-01-24 14:24:36 -0800765 pLinkData = pdfium::MakeRetain<CXFA_LinkUserData>(
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500766 wsLinkContent.GetBuffer(wsLinkContent.GetLength()));
767 wsLinkContent.ReleaseBuffer(wsLinkContent.GetLength());
768 }
769 }
770
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500771 int32_t iTabCount = m_textParser.CountTabs(
772 bContentNode ? pParentStyle.Get() : pStyle.Get());
773 bool bSpaceRun = m_textParser.IsSpaceRun(
774 bContentNode ? pParentStyle.Get() : pStyle.Get());
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500775 CFX_WideString wsText;
776 if (bContentNode && iTabCount == 0) {
777 static_cast<CFDE_XMLText*>(pXMLNode)->GetText(wsText);
dan sinclair65c7c232017-02-02 14:05:30 -0800778 } else if (wsName == L"br") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500779 wsText = L'\n';
dan sinclair65c7c232017-02-02 14:05:30 -0800780 } else if (wsName == L"li") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500781 bCurLi = true;
782 if (bIsOl)
783 wsText.Format(L"%d. ", iLiCount);
784 else
dan sinclair65c7c232017-02-02 14:05:30 -0800785 wsText = 0x00B7 + CFX_WideStringC(L" ", 1);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500786 } else if (!bContentNode) {
787 if (iTabCount > 0) {
788 while (iTabCount-- > 0)
789 wsText += L'\t';
790 } else {
791 m_textParser.GetEmbbedObj(m_pTextProvider, pXMLNode, wsText);
792 }
793 }
794
795 int32_t iLength = wsText.GetLength();
796 if (iLength > 0 && bContentNode && !bSpaceRun)
797 ProcessText(wsText);
798
799 if (m_pLoader) {
800 if (wsText.GetLength() > 0 &&
801 (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {
802 wsText.TrimLeft(0x20);
803 }
Dan Sinclair96f482c2017-01-11 16:31:27 -0500804 if (FDE_CSSDisplay::Block == eDisplay) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500805 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500806 } else if (FDE_CSSDisplay::Inline == eDisplay &&
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500807 (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {
808 m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
809 } else if (wsText.GetLength() > 0 &&
810 (0x20 == wsText.GetAt(wsText.GetLength() - 1))) {
811 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
812 } else if (wsText.GetLength() != 0) {
813 m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
814 }
815 }
816
817 if (wsText.GetLength() > 0) {
818 if (!m_pLoader || m_pLoader->m_iChar == 0) {
Tom Sepez03de8842017-01-24 14:24:36 -0800819 auto pUserData = pdfium::MakeRetain<CXFA_TextUserData>(
Dan Sinclair0cb9b8c2017-01-10 16:38:10 -0500820 bContentNode ? pParentStyle : pStyle, pLinkData);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500821 m_pBreak->SetUserData(pUserData);
822 }
823
824 if (AppendChar(wsText, fLinePos, 0, bSavePieces)) {
825 if (m_pLoader)
826 m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
827 if (IsEnd(bSavePieces)) {
828 if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
829 m_pLoader->m_pXMLNode = pXMLNode;
830 m_pLoader->m_pParentStyle = pParentStyle;
831 }
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500832 return false;
833 }
834 return true;
835 }
836 }
837 }
838 }
839
840 for (CFDE_XMLNode* pChildNode =
841 pXMLNode->GetNodeItem(CFDE_XMLNode::FirstChild);
842 pChildNode;
843 pChildNode = pChildNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
844 if (bCurOl)
845 iLiCount++;
846
847 if (!LoadRichText(pChildNode, szText, fLinePos,
848 pContext ? pStyle : pParentStyle, bSavePieces,
849 pLinkData, true, bIsOl, iLiCount))
850 return false;
851 }
852
853 if (m_pLoader) {
Dan Sinclair96f482c2017-01-11 16:31:27 -0500854 if (FDE_CSSDisplay::Block == eDisplay)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500855 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
856 }
857 if (bCurLi)
Dan Sinclairc36fe072017-03-09 16:58:12 -0500858 EndBreak(CFX_BreakType::Line, fLinePos, bSavePieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500859 } else {
860 if (pContext)
861 eDisplay = pContext->GetDisplay();
862 }
863
864 if (m_bBlockContinue) {
865 if (pContext && !bContentNode) {
Dan Sinclairc36fe072017-03-09 16:58:12 -0500866 CFX_BreakType dwStatus = (eDisplay == FDE_CSSDisplay::Block)
867 ? CFX_BreakType::Paragraph
868 : CFX_BreakType::Piece;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500869 EndBreak(dwStatus, fLinePos, bSavePieces);
Dan Sinclair96f482c2017-01-11 16:31:27 -0500870 if (eDisplay == FDE_CSSDisplay::Block) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500871 fLinePos += fSpaceBelow;
872 if (m_pTabstopContext)
873 m_pTabstopContext->RemoveAll();
874 }
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500875 if (IsEnd(bSavePieces)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500876 if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
877 m_pLoader->m_pXMLNode =
878 pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling);
879 m_pLoader->m_pParentStyle = pParentStyle;
880 }
881 return false;
882 }
883 }
884 }
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500885 return true;
886}
887
888bool CXFA_TextLayout::AppendChar(const CFX_WideString& wsText,
Dan Sinclair05df0752017-03-14 14:43:42 -0400889 float& fLinePos,
890 float fSpaceAbove,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500891 bool bSavePieces) {
Dan Sinclairc36fe072017-03-09 16:58:12 -0500892 CFX_BreakType dwStatus = CFX_BreakType::None;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500893 int32_t iChar = 0;
894 if (m_pLoader)
895 iChar = m_pLoader->m_iChar;
896
897 int32_t iLength = wsText.GetLength();
898 for (int32_t i = iChar; i < iLength; i++) {
Dan Sinclair812e96c2017-03-13 16:43:37 -0400899 wchar_t wch = wsText.GetAt(i);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500900 if (wch == 0xA0)
901 wch = 0x20;
902
Dan Sinclaird2ee0f32017-02-28 14:46:18 -0500903 dwStatus = m_pBreak->AppendChar(wch);
Dan Sinclairc36fe072017-03-09 16:58:12 -0500904 if (dwStatus != CFX_BreakType::None && dwStatus != CFX_BreakType::Piece) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500905 AppendTextLine(dwStatus, fLinePos, bSavePieces);
906 if (IsEnd(bSavePieces)) {
907 if (m_pLoader)
908 m_pLoader->m_iChar = i;
909 return true;
910 }
Dan Sinclairc36fe072017-03-09 16:58:12 -0500911 if (dwStatus == CFX_BreakType::Paragraph && m_bRichText)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500912 fLinePos += fSpaceAbove;
913 }
914 }
915 if (m_pLoader)
916 m_pLoader->m_iChar = 0;
917
918 return false;
919}
920
921bool CXFA_TextLayout::IsEnd(bool bSavePieces) {
922 if (!bSavePieces)
923 return false;
924 if (m_pLoader && m_pLoader->m_iTotalLines > 0)
925 return m_iLines >= m_pLoader->m_iTotalLines;
926 return false;
927}
928
929void CXFA_TextLayout::ProcessText(CFX_WideString& wsText) {
930 int32_t iLen = wsText.GetLength();
931 if (iLen == 0)
932 return;
933
Dan Sinclair812e96c2017-03-13 16:43:37 -0400934 wchar_t* psz = wsText.GetBuffer(iLen);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500935 int32_t iTrimLeft = 0;
Dan Sinclair812e96c2017-03-13 16:43:37 -0400936 wchar_t wch = 0, wPrev = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500937 for (int32_t i = 0; i < iLen; i++) {
938 wch = psz[i];
939 if (wch < 0x20)
940 wch = 0x20;
941 if (wch == 0x20 && wPrev == 0x20)
942 continue;
943
944 wPrev = wch;
945 psz[iTrimLeft++] = wch;
946 }
947 wsText.ReleaseBuffer(iLen);
948 wsText = wsText.Left(iTrimLeft);
949}
950
Dan Sinclairc36fe072017-03-09 16:58:12 -0500951void CXFA_TextLayout::EndBreak(CFX_BreakType dwStatus,
Dan Sinclair05df0752017-03-14 14:43:42 -0400952 float& fLinePos,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500953 bool bSavePieces) {
954 dwStatus = m_pBreak->EndBreak(dwStatus);
Dan Sinclairc36fe072017-03-09 16:58:12 -0500955 if (dwStatus != CFX_BreakType::None && dwStatus != CFX_BreakType::Piece)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500956 AppendTextLine(dwStatus, fLinePos, bSavePieces, true);
957}
958
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500959void CXFA_TextLayout::DoTabstops(CFDE_CSSComputedStyle* pStyle,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500960 CXFA_PieceLine* pPieceLine) {
961 if (!m_pTabstopContext || m_pTabstopContext->m_iTabCount == 0)
962 return;
963 if (!pStyle || !pPieceLine)
964 return;
965
tsepez783a7e02017-01-17 11:05:57 -0800966 int32_t iPieces = pdfium::CollectionSize<int32_t>(pPieceLine->m_textPieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500967 if (iPieces == 0)
968 return;
969
tsepez783a7e02017-01-17 11:05:57 -0800970 XFA_TextPiece* pPiece = pPieceLine->m_textPieces[iPieces - 1].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500971 int32_t& iTabstopsIndex = m_pTabstopContext->m_iTabIndex;
972 int32_t iCount = m_textParser.CountTabs(pStyle);
973 if (iTabstopsIndex > m_pTabstopContext->m_iTabCount - 1)
974 return;
975
976 if (iCount > 0) {
977 iTabstopsIndex++;
978 m_pTabstopContext->m_bTabstops = true;
Dan Sinclair05df0752017-03-14 14:43:42 -0400979 float fRight = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500980 if (iPieces > 1) {
tsepez783a7e02017-01-17 11:05:57 -0800981 XFA_TextPiece* p = pPieceLine->m_textPieces[iPieces - 2].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500982 fRight = p->rtPiece.right();
983 }
984 m_pTabstopContext->m_fTabWidth =
985 pPiece->rtPiece.width + pPiece->rtPiece.left - fRight;
986 } else if (iTabstopsIndex > -1) {
Dan Sinclair05df0752017-03-14 14:43:42 -0400987 float fLeft = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500988 if (m_pTabstopContext->m_bTabstops) {
989 XFA_TABSTOPS* pTabstops =
990 m_pTabstopContext->m_tabstops.GetDataPtr(iTabstopsIndex);
991 uint32_t dwAlign = pTabstops->dwAlign;
992 if (dwAlign == FX_HashCode_GetW(L"center", false)) {
993 fLeft = pPiece->rtPiece.width / 2.0f;
994 } else if (dwAlign == FX_HashCode_GetW(L"right", false) ||
995 dwAlign == FX_HashCode_GetW(L"before", false)) {
996 fLeft = pPiece->rtPiece.width;
997 } else if (dwAlign == FX_HashCode_GetW(L"decimal", false)) {
998 int32_t iChars = pPiece->iChars;
999 for (int32_t i = 0; i < iChars; i++) {
Dan Sinclairbef73892017-03-01 11:23:14 -05001000 if (pPiece->szText[i] == L'.')
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001001 break;
1002
Dan Sinclairbef73892017-03-01 11:23:14 -05001003 fLeft += pPiece->Widths[i] / 20000.0f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001004 }
1005 }
1006 m_pTabstopContext->m_fLeft =
1007 std::min(fLeft, m_pTabstopContext->m_fTabWidth);
1008 m_pTabstopContext->m_bTabstops = false;
1009 m_pTabstopContext->m_fTabWidth = 0;
1010 }
1011 pPiece->rtPiece.left -= m_pTabstopContext->m_fLeft;
1012 }
1013}
1014
Dan Sinclairc36fe072017-03-09 16:58:12 -05001015void CXFA_TextLayout::AppendTextLine(CFX_BreakType dwStatus,
Dan Sinclair05df0752017-03-14 14:43:42 -04001016 float& fLinePos,
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001017 bool bSavePieces,
1018 bool bEndBreak) {
1019 int32_t iPieces = m_pBreak->CountBreakPieces();
1020 if (iPieces < 1)
1021 return;
1022
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001023 CFX_RetainPtr<CFDE_CSSComputedStyle> pStyle;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001024 if (bSavePieces) {
tsepez783a7e02017-01-17 11:05:57 -08001025 auto pNew = pdfium::MakeUnique<CXFA_PieceLine>();
1026 CXFA_PieceLine* pPieceLine = pNew.get();
1027 m_pieceLines.push_back(std::move(pNew));
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001028 if (m_pTabstopContext)
1029 m_pTabstopContext->Reset();
1030
Dan Sinclair05df0752017-03-14 14:43:42 -04001031 float fLineStep = 0, fBaseLine = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001032 int32_t i = 0;
1033 for (i = 0; i < iPieces; i++) {
Dan Sinclair893822a2017-03-13 15:32:07 -04001034 const CFX_BreakPiece* pPiece = m_pBreak->GetBreakPieceUnstable(i);
Tom Sepez03de8842017-01-24 14:24:36 -08001035 CXFA_TextUserData* pUserData =
1036 static_cast<CXFA_TextUserData*>(pPiece->m_pUserData.Get());
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001037 if (pUserData)
1038 pStyle = pUserData->m_pStyle;
Dan Sinclair05df0752017-03-14 14:43:42 -04001039 float fVerScale = pPiece->m_iVerticalScale / 100.0f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001040
tsepez783a7e02017-01-17 11:05:57 -08001041 auto pTP = pdfium::MakeUnique<XFA_TextPiece>();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001042 pTP->iChars = pPiece->m_iChars;
Dan Sinclairbef73892017-03-01 11:23:14 -05001043 pTP->szText = pPiece->GetString();
1044 pTP->Widths = pPiece->GetWidths();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001045 pTP->iBidiLevel = pPiece->m_iBidiLevel;
1046 pTP->iHorScale = pPiece->m_iHorizontalScale;
1047 pTP->iVerScale = pPiece->m_iVerticalScale;
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001048 m_textParser.GetUnderline(m_pTextProvider, pStyle.Get(), pTP->iUnderline,
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001049 pTP->iPeriod);
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001050 m_textParser.GetLinethrough(m_pTextProvider, pStyle.Get(),
1051 pTP->iLineThrough);
1052 pTP->dwColor = m_textParser.GetColor(m_pTextProvider, pStyle.Get());
1053 pTP->pFont = m_textParser.GetFont(m_pTextProvider, pStyle.Get());
1054 pTP->fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle.Get());
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001055 pTP->rtPiece.left = pPiece->m_iStartPos / 20000.0f;
1056 pTP->rtPiece.width = pPiece->m_iWidth / 20000.0f;
Dan Sinclair05df0752017-03-14 14:43:42 -04001057 pTP->rtPiece.height = (float)pPiece->m_iFontSize * fVerScale / 20.0f;
1058 float fBaseLineTemp =
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001059 m_textParser.GetBaseline(m_pTextProvider, pStyle.Get());
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001060 pTP->rtPiece.top = fBaseLineTemp;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001061
Dan Sinclair05df0752017-03-14 14:43:42 -04001062 float fLineHeight = m_textParser.GetLineHeight(
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001063 m_pTextProvider, pStyle.Get(), m_iLines == 0, fVerScale);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001064 if (fBaseLineTemp > 0) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001065 float fLineHeightTmp = fBaseLineTemp + pTP->rtPiece.height;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001066 if (fLineHeight < fLineHeightTmp)
1067 fLineHeight = fLineHeightTmp;
1068 else
1069 fBaseLineTemp = 0;
1070 } else if (fBaseLine < -fBaseLineTemp) {
1071 fBaseLine = -fBaseLineTemp;
1072 }
1073 fLineStep = std::max(fLineStep, fLineHeight);
Tom Sepez03de8842017-01-24 14:24:36 -08001074 pTP->pLinkData = pUserData ? pUserData->m_pLinkData : nullptr;
tsepez783a7e02017-01-17 11:05:57 -08001075 pPieceLine->m_textPieces.push_back(std::move(pTP));
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001076 DoTabstops(pStyle.Get(), pPieceLine);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001077 }
tsepez783a7e02017-01-17 11:05:57 -08001078 for (const auto& pTP : pPieceLine->m_textPieces) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001079 float& fTop = pTP->rtPiece.top;
1080 float fBaseLineTemp = fTop;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001081 fTop = fLinePos + fLineStep - pTP->rtPiece.height - fBaseLineTemp;
1082 fTop = std::max(0.0f, fTop);
1083 }
1084 fLinePos += fLineStep + fBaseLine;
1085 } else {
Dan Sinclair05df0752017-03-14 14:43:42 -04001086 float fLineStep = 0;
1087 float fLineWidth = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001088 for (int32_t i = 0; i < iPieces; i++) {
Dan Sinclair893822a2017-03-13 15:32:07 -04001089 const CFX_BreakPiece* pPiece = m_pBreak->GetBreakPieceUnstable(i);
Tom Sepez03de8842017-01-24 14:24:36 -08001090 CXFA_TextUserData* pUserData =
1091 static_cast<CXFA_TextUserData*>(pPiece->m_pUserData.Get());
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001092 if (pUserData)
1093 pStyle = pUserData->m_pStyle;
Dan Sinclair05df0752017-03-14 14:43:42 -04001094 float fVerScale = pPiece->m_iVerticalScale / 100.0f;
1095 float fBaseLine = m_textParser.GetBaseline(m_pTextProvider, pStyle.Get());
1096 float fLineHeight = m_textParser.GetLineHeight(
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001097 m_pTextProvider, pStyle.Get(), m_iLines == 0, fVerScale);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001098 if (fBaseLine > 0) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001099 float fLineHeightTmp =
1100 fBaseLine + (float)pPiece->m_iFontSize * fVerScale / 20.0f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001101 if (fLineHeight < fLineHeightTmp) {
1102 fLineHeight = fLineHeightTmp;
1103 }
1104 }
1105 fLineStep = std::max(fLineStep, fLineHeight);
1106 fLineWidth += pPiece->m_iWidth / 20000.0f;
1107 }
1108 fLinePos += fLineStep;
1109 m_fMaxWidth = std::max(m_fMaxWidth, fLineWidth);
1110 if (m_pLoader && m_pLoader->m_bSaveLineHeight) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001111 float fHeight = fLinePos - m_pLoader->m_fLastPos;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001112 m_pLoader->m_fLastPos = fLinePos;
Tom Sepezfcc309e2017-03-24 14:19:11 -07001113 m_pLoader->m_lineHeights.push_back(fHeight);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001114 }
1115 }
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001116
1117 m_pBreak->ClearBreakPieces();
Dan Sinclairc36fe072017-03-09 16:58:12 -05001118 if (dwStatus == CFX_BreakType::Paragraph) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001119 m_pBreak->Reset();
1120 if (!pStyle && bEndBreak) {
1121 CXFA_Para para = m_pTextProvider->GetParaNode();
1122 if (para) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001123 float fStartPos = para.GetMarginLeft();
1124 float fIndent = para.GetTextIndent();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001125 if (fIndent > 0)
1126 fStartPos += fIndent;
1127
Dan Sinclair05df0752017-03-14 14:43:42 -04001128 float fSpaceBelow = para.GetSpaceBelow();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001129 if (fSpaceBelow < 0.1f)
1130 fSpaceBelow = 0;
1131
1132 m_pBreak->SetLineStartPos(fStartPos);
1133 fLinePos += fSpaceBelow;
1134 }
1135 }
1136 }
1137
1138 if (pStyle) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001139 float fStart = 0;
Dan Sinclairb9fbe6e2017-01-16 16:07:41 -05001140 const FDE_CSSRect* pRect = pStyle->GetMarginWidth();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001141 if (pRect)
1142 fStart = pRect->left.GetValue();
1143
Dan Sinclair05df0752017-03-14 14:43:42 -04001144 float fTextIndent = pStyle->GetTextIndent().GetValue();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001145 if (fTextIndent < 0)
1146 fStart -= fTextIndent;
1147
1148 m_pBreak->SetLineStartPos(fStart);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001149 }
1150 m_iLines++;
1151}
1152
1153void CXFA_TextLayout::RenderString(CFDE_RenderDevice* pDevice,
1154 CFDE_Brush* pBrush,
1155 CXFA_PieceLine* pPieceLine,
1156 int32_t iPiece,
1157 FXTEXT_CHARPOS* pCharPos,
1158 const CFX_Matrix& tmDoc2Device) {
tsepez783a7e02017-01-17 11:05:57 -08001159 const XFA_TextPiece* pPiece = pPieceLine->m_textPieces[iPiece].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001160 int32_t iCount = GetDisplayPos(pPiece, pCharPos);
1161 if (iCount > 0) {
1162 pBrush->SetColor(pPiece->dwColor);
1163 pDevice->DrawString(pBrush, pPiece->pFont, pCharPos, iCount,
1164 pPiece->fFontSize, &tmDoc2Device);
1165 }
Tom Sepezfcc309e2017-03-24 14:19:11 -07001166 pPieceLine->m_charCounts.push_back(iCount);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001167}
1168
1169void CXFA_TextLayout::RenderPath(CFDE_RenderDevice* pDevice,
1170 CFDE_Pen* pPen,
1171 CXFA_PieceLine* pPieceLine,
1172 int32_t iPiece,
1173 FXTEXT_CHARPOS* pCharPos,
1174 const CFX_Matrix& tmDoc2Device) {
tsepez783a7e02017-01-17 11:05:57 -08001175 XFA_TextPiece* pPiece = pPieceLine->m_textPieces[iPiece].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001176 bool bNoUnderline = pPiece->iUnderline < 1 || pPiece->iUnderline > 2;
1177 bool bNoLineThrough = pPiece->iLineThrough < 1 || pPiece->iLineThrough > 2;
1178 if (bNoUnderline && bNoLineThrough)
1179 return;
1180
1181 pPen->SetColor(pPiece->dwColor);
1182 std::unique_ptr<CFDE_Path> pPath(new CFDE_Path);
1183 int32_t iChars = GetDisplayPos(pPiece, pCharPos);
1184 if (iChars > 0) {
1185 CFX_PointF pt1, pt2;
Dan Sinclair05df0752017-03-14 14:43:42 -04001186 float fEndY = pCharPos[0].m_Origin.y + 1.05f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001187 if (pPiece->iPeriod == XFA_ATTRIBUTEENUM_Word) {
1188 for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1189 for (int32_t j = 0; j < iChars; j++) {
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001190 pt1.x = pCharPos[j].m_Origin.x;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001191 pt2.x =
1192 pt1.x + pCharPos[j].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1193 pt1.y = pt2.y = fEndY;
1194 pPath->AddLine(pt1, pt2);
1195 }
1196 fEndY += 2.0f;
1197 }
1198 } else {
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001199 pt1.x = pCharPos[0].m_Origin.x;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001200 pt2.x =
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001201 pCharPos[iChars - 1].m_Origin.x +
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001202 pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1203 for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1204 pt1.y = pt2.y = fEndY;
1205 pPath->AddLine(pt1, pt2);
1206 fEndY += 2.0f;
1207 }
1208 }
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001209 fEndY = pCharPos[0].m_Origin.y - pPiece->rtPiece.height * 0.25f;
1210 pt1.x = pCharPos[0].m_Origin.x;
1211 pt2.x = pCharPos[iChars - 1].m_Origin.x +
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001212 pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1213 for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
1214 pt1.y = pt2.y = fEndY;
1215 pPath->AddLine(pt1, pt2);
1216 fEndY += 2.0f;
1217 }
1218 } else {
1219 if (bNoLineThrough &&
1220 (bNoUnderline || pPiece->iPeriod != XFA_ATTRIBUTEENUM_All)) {
1221 return;
1222 }
1223 int32_t iCharsTmp = 0;
Tom Sepezfcc309e2017-03-24 14:19:11 -07001224 int32_t iPiecePrev = iPiece;
1225 int32_t iPieceNext = iPiece;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001226 while (iPiecePrev > 0) {
1227 iPiecePrev--;
Tom Sepezfcc309e2017-03-24 14:19:11 -07001228 iCharsTmp = pPieceLine->m_charCounts[iPiecePrev];
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001229 if (iCharsTmp > 0)
1230 break;
1231 }
1232 if (iCharsTmp == 0)
1233 return;
1234
1235 iCharsTmp = 0;
tsepez783a7e02017-01-17 11:05:57 -08001236 int32_t iPieces = pdfium::CollectionSize<int32_t>(pPieceLine->m_textPieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001237 while (iPieceNext < iPieces - 1) {
1238 iPieceNext++;
Tom Sepezfcc309e2017-03-24 14:19:11 -07001239 iCharsTmp = pPieceLine->m_charCounts[iPieceNext];
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001240 if (iCharsTmp > 0)
1241 break;
1242 }
1243 if (iCharsTmp == 0)
1244 return;
1245
Dan Sinclair05df0752017-03-14 14:43:42 -04001246 float fOrgX = 0.0f;
1247 float fEndX = 0.0f;
tsepez783a7e02017-01-17 11:05:57 -08001248 pPiece = pPieceLine->m_textPieces[iPiecePrev].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001249 iChars = GetDisplayPos(pPiece, pCharPos);
1250 if (iChars < 1)
1251 return;
1252
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001253 fOrgX = pCharPos[iChars - 1].m_Origin.x +
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001254 pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
tsepez783a7e02017-01-17 11:05:57 -08001255 pPiece = pPieceLine->m_textPieces[iPieceNext].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001256 iChars = GetDisplayPos(pPiece, pCharPos);
1257 if (iChars < 1)
1258 return;
1259
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001260 fEndX = pCharPos[0].m_Origin.x;
1261 CFX_PointF pt1;
1262 CFX_PointF pt2;
1263 pt1.x = fOrgX;
1264 pt2.x = fEndX;
Dan Sinclair05df0752017-03-14 14:43:42 -04001265 float fEndY = pCharPos[0].m_Origin.y + 1.05f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001266 for (int32_t i = 0; i < pPiece->iUnderline; i++) {
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001267 pt1.y = fEndY;
1268 pt2.y = fEndY;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001269 pPath->AddLine(pt1, pt2);
1270 fEndY += 2.0f;
1271 }
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001272 fEndY = pCharPos[0].m_Origin.y - pPiece->rtPiece.height * 0.25f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001273 for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001274 pt1.y = fEndY;
1275 pt2.y = fEndY;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001276 pPath->AddLine(pt1, pt2);
1277 fEndY += 2.0f;
1278 }
1279 }
1280 pDevice->DrawPath(pPen, 1, pPath.get(), &tmDoc2Device);
1281}
1282
1283int32_t CXFA_TextLayout::GetDisplayPos(const XFA_TextPiece* pPiece,
1284 FXTEXT_CHARPOS* pCharPos,
1285 bool bCharCode) {
1286 if (!pPiece)
1287 return 0;
1288
1289 FX_RTFTEXTOBJ tr;
tsepez783a7e02017-01-17 11:05:57 -08001290 if (!ToRun(pPiece, &tr))
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001291 return 0;
1292 return m_pBreak->GetDisplayPos(&tr, pCharPos, bCharCode);
1293}
1294
tsepez783a7e02017-01-17 11:05:57 -08001295bool CXFA_TextLayout::ToRun(const XFA_TextPiece* pPiece, FX_RTFTEXTOBJ* tr) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001296 int32_t iLength = pPiece->iChars;
1297 if (iLength < 1)
1298 return false;
1299
Dan Sinclairbef73892017-03-01 11:23:14 -05001300 tr->pStr = pPiece->szText;
tsepez783a7e02017-01-17 11:05:57 -08001301 tr->pFont = pPiece->pFont;
1302 tr->pRect = &pPiece->rtPiece;
Dan Sinclairbef73892017-03-01 11:23:14 -05001303 tr->pWidths = pPiece->Widths;
tsepez783a7e02017-01-17 11:05:57 -08001304 tr->iLength = iLength;
1305 tr->fFontSize = pPiece->fFontSize;
1306 tr->iBidiLevel = pPiece->iBidiLevel;
tsepez783a7e02017-01-17 11:05:57 -08001307 tr->wLineBreakChar = L'\n';
1308 tr->iVerticalScale = pPiece->iVerScale;
tsepez783a7e02017-01-17 11:05:57 -08001309 tr->iHorizontalScale = pPiece->iHorScale;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001310 return true;
1311}