From 1f5d4988dcdac125e3e822d37c9086a5e4a3e224 Mon Sep 17 00:00:00 2001 From: Dan Sinclair Date: Tue, 10 Jan 2017 16:37:32 -0500 Subject: Split xfa_textlayout apart. This CL splits the xfa_texlayout.{cpp|h} files into individual class files. Minor reformatting was done in the new clasess. Change-Id: Id79ffcb8dca3fcf287a2e6dec78fd2b1f990a542 Reviewed-on: https://pdfium-review.googlesource.com/2162 Commit-Queue: dsinclair Reviewed-by: Tom Sepez --- xfa/fde/css/cfde_cssrulecollection.cpp | 1 - xfa/fde/css/fde_csscache.cpp | 2 +- xfa/fde/css/fde_cssstyleselector.cpp | 2 +- xfa/fxfa/app/cxfa_csstagprovider.cpp | 12 + xfa/fxfa/app/cxfa_csstagprovider.h | 42 + xfa/fxfa/app/cxfa_linkuserdata.cpp | 28 + xfa/fxfa/app/cxfa_linkuserdata.h | 34 + xfa/fxfa/app/cxfa_loadercontext.cpp | 22 + xfa/fxfa/app/cxfa_loadercontext.h | 40 + xfa/fxfa/app/cxfa_pieceline.cpp | 11 + xfa/fxfa/app/cxfa_pieceline.h | 24 + xfa/fxfa/app/cxfa_textlayout.cpp | 1370 +++++++++++++++++++ xfa/fxfa/app/cxfa_textlayout.h | 135 ++ xfa/fxfa/app/cxfa_textparsecontext.cpp | 32 + xfa/fxfa/app/cxfa_textparsecontext.h | 38 + xfa/fxfa/app/cxfa_textparser.cpp | 659 +++++++++ xfa/fxfa/app/cxfa_textparser.h | 101 ++ xfa/fxfa/app/cxfa_textparser_unittest.cpp | 40 + xfa/fxfa/app/cxfa_texttabstopscontext.cpp | 44 + xfa/fxfa/app/cxfa_texttabstopscontext.h | 34 + xfa/fxfa/app/cxfa_textuserdata.cpp | 51 + xfa/fxfa/app/cxfa_textuserdata.h | 38 + xfa/fxfa/app/xfa_ffdocview.cpp | 1 - xfa/fxfa/app/xfa_fffield.cpp | 2 +- xfa/fxfa/app/xfa_ffnotify.cpp | 2 +- xfa/fxfa/app/xfa_ffpushbutton.cpp | 2 +- xfa/fxfa/app/xfa_fftext.cpp | 8 +- xfa/fxfa/app/xfa_fftextedit.cpp | 1 - xfa/fxfa/app/xfa_ffwidget.cpp | 2 +- xfa/fxfa/app/xfa_ffwidgetacc.cpp | 1 - xfa/fxfa/app/xfa_ffwidgetacc.h | 9 +- xfa/fxfa/app/xfa_textlayout.cpp | 2111 ----------------------------- xfa/fxfa/app/xfa_textlayout.h | 354 ----- xfa/fxfa/app/xfa_textlayout_unittest.cpp | 40 - xfa/fxfa/app/xfa_textpiece.cpp | 17 + xfa/fxfa/app/xfa_textpiece.h | 39 + 36 files changed, 2831 insertions(+), 2518 deletions(-) create mode 100644 xfa/fxfa/app/cxfa_csstagprovider.cpp create mode 100644 xfa/fxfa/app/cxfa_csstagprovider.h create mode 100644 xfa/fxfa/app/cxfa_linkuserdata.cpp create mode 100644 xfa/fxfa/app/cxfa_linkuserdata.h create mode 100644 xfa/fxfa/app/cxfa_loadercontext.cpp create mode 100644 xfa/fxfa/app/cxfa_loadercontext.h create mode 100644 xfa/fxfa/app/cxfa_pieceline.cpp create mode 100644 xfa/fxfa/app/cxfa_pieceline.h create mode 100644 xfa/fxfa/app/cxfa_textlayout.cpp create mode 100644 xfa/fxfa/app/cxfa_textlayout.h create mode 100644 xfa/fxfa/app/cxfa_textparsecontext.cpp create mode 100644 xfa/fxfa/app/cxfa_textparsecontext.h create mode 100644 xfa/fxfa/app/cxfa_textparser.cpp create mode 100644 xfa/fxfa/app/cxfa_textparser.h create mode 100644 xfa/fxfa/app/cxfa_textparser_unittest.cpp create mode 100644 xfa/fxfa/app/cxfa_texttabstopscontext.cpp create mode 100644 xfa/fxfa/app/cxfa_texttabstopscontext.h create mode 100644 xfa/fxfa/app/cxfa_textuserdata.cpp create mode 100644 xfa/fxfa/app/cxfa_textuserdata.h delete mode 100644 xfa/fxfa/app/xfa_textlayout.cpp delete mode 100644 xfa/fxfa/app/xfa_textlayout.h delete mode 100644 xfa/fxfa/app/xfa_textlayout_unittest.cpp create mode 100644 xfa/fxfa/app/xfa_textpiece.cpp create mode 100644 xfa/fxfa/app/xfa_textpiece.h (limited to 'xfa') diff --git a/xfa/fde/css/cfde_cssrulecollection.cpp b/xfa/fde/css/cfde_cssrulecollection.cpp index 5a439724a0..8c22c9a99e 100644 --- a/xfa/fde/css/cfde_cssrulecollection.cpp +++ b/xfa/fde/css/cfde_cssrulecollection.cpp @@ -14,7 +14,6 @@ #include "xfa/fde/css/fde_cssdeclaration.h" #include "xfa/fde/css/fde_cssstylesheet.h" #include "xfa/fde/css/fde_csssyntax.h" -#include "xfa/fxfa/app/xfa_textlayout.h" #define FDE_CSSUNIVERSALHASH ('*') diff --git a/xfa/fde/css/fde_csscache.cpp b/xfa/fde/css/fde_csscache.cpp index be5fc7105c..bf00fbbd46 100644 --- a/xfa/fde/css/fde_csscache.cpp +++ b/xfa/fde/css/fde_csscache.cpp @@ -9,7 +9,7 @@ #include #include "core/fxcrt/fx_ext.h" -#include "xfa/fxfa/app/xfa_textlayout.h" +#include "xfa/fxfa/app/cxfa_csstagprovider.h" FDE_CSSCacheItem::FDE_CSSCacheItem(IFDE_CSSStyleSheet* p) : pStylesheet(p), dwActivity(0) { diff --git a/xfa/fde/css/fde_cssstyleselector.cpp b/xfa/fde/css/fde_cssstyleselector.cpp index 681d189fcc..ae928dbd12 100644 --- a/xfa/fde/css/fde_cssstyleselector.cpp +++ b/xfa/fde/css/fde_cssstyleselector.cpp @@ -15,7 +15,7 @@ #include "xfa/fde/css/fde_cssdeclaration.h" #include "xfa/fde/css/fde_cssstylesheet.h" #include "xfa/fde/css/fde_csssyntax.h" -#include "xfa/fxfa/app/xfa_textlayout.h" +#include "xfa/fxfa/app/cxfa_csstagprovider.h" #define FDE_CSSUNIVERSALHASH ('*') diff --git a/xfa/fxfa/app/cxfa_csstagprovider.cpp b/xfa/fxfa/app/cxfa_csstagprovider.cpp new file mode 100644 index 0000000000..ef5133e104 --- /dev/null +++ b/xfa/fxfa/app/cxfa_csstagprovider.cpp @@ -0,0 +1,12 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "xfa/fxfa/app/cxfa_csstagprovider.h" + +CXFA_CSSTagProvider::CXFA_CSSTagProvider() + : m_bTagAvailable(false), m_bContent(false) {} + +CXFA_CSSTagProvider::~CXFA_CSSTagProvider() {} diff --git a/xfa/fxfa/app/cxfa_csstagprovider.h b/xfa/fxfa/app/cxfa_csstagprovider.h new file mode 100644 index 0000000000..3c23784403 --- /dev/null +++ b/xfa/fxfa/app/cxfa_csstagprovider.h @@ -0,0 +1,42 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef XFA_FXFA_APP_CXFA_CSSTAGPROVIDER_H_ +#define XFA_FXFA_APP_CXFA_CSSTAGPROVIDER_H_ + +#include + +#include "core/fxcrt/fx_string.h" + +class CXFA_CSSTagProvider { + public: + using AttributeMap = std::map; + + CXFA_CSSTagProvider(); + ~CXFA_CSSTagProvider(); + + CFX_WideString GetTagName() { return m_wsTagName; } + + AttributeMap::iterator begin() { return m_Attributes.begin(); } + AttributeMap::iterator end() { return m_Attributes.end(); } + + bool empty() const { return m_Attributes.empty(); } + + void SetTagNameObj(const CFX_WideString& wsName) { m_wsTagName = wsName; } + void SetAttribute(const CFX_WideString& wsAttr, + const CFX_WideString& wsValue) { + m_Attributes.insert({wsAttr, wsValue}); + } + + bool m_bTagAvailable; + bool m_bContent; + + protected: + CFX_WideString m_wsTagName; + AttributeMap m_Attributes; +}; + +#endif // XFA_FXFA_APP_CXFA_CSSTAGPROVIDER_H_ diff --git a/xfa/fxfa/app/cxfa_linkuserdata.cpp b/xfa/fxfa/app/cxfa_linkuserdata.cpp new file mode 100644 index 0000000000..62a2938d95 --- /dev/null +++ b/xfa/fxfa/app/cxfa_linkuserdata.cpp @@ -0,0 +1,28 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "xfa/fxfa/app/cxfa_linkuserdata.h" + +CXFA_LinkUserData::CXFA_LinkUserData(IFX_MemoryAllocator* pAllocator, + FX_WCHAR* pszText) + : m_pAllocator(pAllocator), m_dwRefCount(1), m_wsURLContent(pszText) {} + +CXFA_LinkUserData::~CXFA_LinkUserData() {} + +uint32_t CXFA_LinkUserData::Retain() { + return ++m_dwRefCount; +} + +uint32_t CXFA_LinkUserData::Release() { + uint32_t dwRefCount = --m_dwRefCount; + if (dwRefCount <= 0) + FXTARGET_DeleteWith(CXFA_LinkUserData, m_pAllocator, this); + return dwRefCount; +} + +const FX_WCHAR* CXFA_LinkUserData::GetLinkURL() { + return m_wsURLContent.c_str(); +} diff --git a/xfa/fxfa/app/cxfa_linkuserdata.h b/xfa/fxfa/app/cxfa_linkuserdata.h new file mode 100644 index 0000000000..d5ec14e17e --- /dev/null +++ b/xfa/fxfa/app/cxfa_linkuserdata.h @@ -0,0 +1,34 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef XFA_FXFA_APP_CXFA_LINKUSERDATA_H_ +#define XFA_FXFA_APP_CXFA_LINKUSERDATA_H_ + +#include "core/fxcrt/fx_basic.h" +#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/fx_system.h" +#include "xfa/fgas/crt/fgas_memory.h" + +class IFX_MemoryAllocator; + +class CXFA_LinkUserData : public IFX_Retainable, public CFX_Target { + public: + CXFA_LinkUserData(IFX_MemoryAllocator* pAllocator, FX_WCHAR* pszText); + ~CXFA_LinkUserData() override; + + // IFX_Retainable: + uint32_t Retain() override; + uint32_t Release() override; + + const FX_WCHAR* GetLinkURL(); + + protected: + IFX_MemoryAllocator* m_pAllocator; + uint32_t m_dwRefCount; + CFX_WideString m_wsURLContent; +}; + +#endif // XFA_FXFA_APP_CXFA_LINKUSERDATA_H_ diff --git a/xfa/fxfa/app/cxfa_loadercontext.cpp b/xfa/fxfa/app/cxfa_loadercontext.cpp new file mode 100644 index 0000000000..56ac71bfb4 --- /dev/null +++ b/xfa/fxfa/app/cxfa_loadercontext.cpp @@ -0,0 +1,22 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "xfa/fxfa/app/cxfa_loadercontext.h" + +CXFA_LoaderContext::CXFA_LoaderContext() + : m_bSaveLineHeight(false), + m_fWidth(0), + m_fHeight(0), + m_fLastPos(0), + m_fStartLineOffset(0), + m_iChar(0), + m_iTotalLines(-1), + m_pXMLNode(nullptr), + m_pNode(nullptr), + m_pParentStyle(nullptr), + m_dwFlags(0) {} + +CXFA_LoaderContext::~CXFA_LoaderContext() {} diff --git a/xfa/fxfa/app/cxfa_loadercontext.h b/xfa/fxfa/app/cxfa_loadercontext.h new file mode 100644 index 0000000000..39d2adc74d --- /dev/null +++ b/xfa/fxfa/app/cxfa_loadercontext.h @@ -0,0 +1,40 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef XFA_FXFA_APP_CXFA_LOADERCONTEXT_H_ +#define XFA_FXFA_APP_CXFA_LOADERCONTEXT_H_ + +#include + +#include "core/fxcrt/fx_basic.h" +#include "core/fxcrt/fx_system.h" + +class CFDE_XMLNode; +class CXFA_Node; +class IFDE_CSSComputedStyle; + +class CXFA_LoaderContext { + public: + CXFA_LoaderContext(); + ~CXFA_LoaderContext(); + + bool m_bSaveLineHeight; + FX_FLOAT m_fWidth; + FX_FLOAT m_fHeight; + FX_FLOAT m_fLastPos; + FX_FLOAT m_fStartLineOffset; + int32_t m_iChar; + int32_t m_iLines; + int32_t m_iTotalLines; + CFDE_XMLNode* m_pXMLNode; + CXFA_Node* m_pNode; + IFDE_CSSComputedStyle* m_pParentStyle; + CFX_ArrayTemplate m_lineHeights; + uint32_t m_dwFlags; + std::vector m_BlocksHeight; +}; + +#endif // XFA_FXFA_APP_CXFA_LOADERCONTEXT_H_ diff --git a/xfa/fxfa/app/cxfa_pieceline.cpp b/xfa/fxfa/app/cxfa_pieceline.cpp new file mode 100644 index 0000000000..465896fd18 --- /dev/null +++ b/xfa/fxfa/app/cxfa_pieceline.cpp @@ -0,0 +1,11 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "xfa/fxfa/app/cxfa_pieceline.h" + +CXFA_PieceLine::CXFA_PieceLine() {} + +CXFA_PieceLine::~CXFA_PieceLine() {} diff --git a/xfa/fxfa/app/cxfa_pieceline.h b/xfa/fxfa/app/cxfa_pieceline.h new file mode 100644 index 0000000000..88642d38bc --- /dev/null +++ b/xfa/fxfa/app/cxfa_pieceline.h @@ -0,0 +1,24 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef XFA_FXFA_APP_CXFA_PIECELINE_H_ +#define XFA_FXFA_APP_CXFA_PIECELINE_H_ + +#include "core/fxcrt/fx_basic.h" +#include "xfa/fgas/crt/fgas_memory.h" + +class XFA_TextPiece; + +class CXFA_PieceLine : public CFX_Target { + public: + CXFA_PieceLine(); + ~CXFA_PieceLine() override; + + CFX_ArrayTemplate m_textPieces; + CFX_ArrayTemplate m_charCounts; +}; + +#endif // XFA_FXFA_APP_CXFA_PIECELINE_H_ diff --git a/xfa/fxfa/app/cxfa_textlayout.cpp b/xfa/fxfa/app/cxfa_textlayout.cpp new file mode 100644 index 0000000000..c4c2712386 --- /dev/null +++ b/xfa/fxfa/app/cxfa_textlayout.cpp @@ -0,0 +1,1370 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "xfa/fxfa/app/cxfa_textlayout.h" + +#include + +#include "third_party/base/ptr_util.h" +#include "third_party/base/stl_util.h" +#include "xfa/fde/cfde_path.h" +#include "xfa/fde/fde_gedevice.h" +#include "xfa/fde/fde_object.h" +#include "xfa/fde/xml/fde_xml_imp.h" +#include "xfa/fxfa/app/cxfa_linkuserdata.h" +#include "xfa/fxfa/app/cxfa_loadercontext.h" +#include "xfa/fxfa/app/cxfa_pieceline.h" +#include "xfa/fxfa/app/cxfa_textparsecontext.h" +#include "xfa/fxfa/app/cxfa_texttabstopscontext.h" +#include "xfa/fxfa/app/cxfa_textuserdata.h" +#include "xfa/fxfa/app/xfa_ffwidgetacc.h" +#include "xfa/fxfa/app/xfa_textpiece.h" +#include "xfa/fxfa/parser/cxfa_font.h" +#include "xfa/fxfa/parser/cxfa_para.h" +#include "xfa/fxfa/parser/xfa_object.h" + +#define XFA_LOADERCNTXTFLG_FILTERSPACE 0x001 + +CXFA_TextLayout::CXFA_TextLayout(CXFA_TextProvider* pTextProvider) + : m_bHasBlock(false), + m_pTextProvider(pTextProvider), + m_pTextDataNode(nullptr), + m_bRichText(false), + m_iLines(0), + m_fMaxWidth(0), + m_bBlockContinue(true) { + ASSERT(m_pTextProvider); +} + +CXFA_TextLayout::~CXFA_TextLayout() { + m_textParser.Reset(); + Unload(); +} + +void CXFA_TextLayout::Unload() { + for (int32_t i = 0; i < m_pieceLines.GetSize(); i++) { + CXFA_PieceLine* pLine = m_pieceLines.GetAt(i); + for (int32_t i = 0; i < pLine->m_textPieces.GetSize(); i++) { + XFA_TextPiece* pPiece = pLine->m_textPieces.GetAt(i); + // Release text and widths in a text piece. + m_pAllocator->Free(pPiece->pszText); + m_pAllocator->Free(pPiece->pWidths); + // Release text piece. + FXTARGET_DeleteWith(XFA_TextPiece, m_pAllocator.get(), pPiece); + } + pLine->m_textPieces.RemoveAll(); + // Release line. + FXTARGET_DeleteWith(CXFA_PieceLine, m_pAllocator.get(), pLine); + } + m_pieceLines.RemoveAll(); + m_pBreak.reset(); + m_pAllocator.reset(); +} + +const CFX_ArrayTemplate* CXFA_TextLayout::GetPieceLines() { + return &m_pieceLines; +} + +void CXFA_TextLayout::GetTextDataNode() { + if (!m_pTextProvider) + return; + + CXFA_Node* pNode = m_pTextProvider->GetTextNode(m_bRichText); + if (pNode && m_bRichText) + m_textParser.Reset(); + + m_pTextDataNode = pNode; +} + +CFDE_XMLNode* CXFA_TextLayout::GetXMLContainerNode() { + if (!m_bRichText) + return nullptr; + + CFDE_XMLNode* pXMLRoot = m_pTextDataNode->GetXMLMappingNode(); + if (!pXMLRoot) + return nullptr; + + CFDE_XMLNode* pXMLContainer = nullptr; + for (CFDE_XMLNode* pXMLChild = + pXMLRoot->GetNodeItem(CFDE_XMLNode::FirstChild); + pXMLChild; + pXMLChild = pXMLChild->GetNodeItem(CFDE_XMLNode::NextSibling)) { + if (pXMLChild->GetType() == FDE_XMLNODE_Element) { + CFDE_XMLElement* pXMLElement = static_cast(pXMLChild); + CFX_WideString wsTag; + pXMLElement->GetLocalTagName(wsTag); + if (wsTag == FX_WSTRC(L"body") || wsTag == FX_WSTRC(L"html")) { + pXMLContainer = pXMLChild; + break; + } + } + } + return pXMLContainer; +} + +CFX_RTFBreak* CXFA_TextLayout::CreateBreak(bool bDefault) { + uint32_t dwStyle = FX_RTFLAYOUTSTYLE_ExpandTab; + if (!bDefault) + dwStyle |= FX_RTFLAYOUTSTYLE_Pagination; + + CFX_RTFBreak* pBreak = new CFX_RTFBreak(0); + pBreak->SetLayoutStyles(dwStyle); + pBreak->SetLineBreakChar(L'\n'); + pBreak->SetLineBreakTolerance(1); + pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr)); + pBreak->SetFontSize(m_textParser.GetFontSize(m_pTextProvider, nullptr)); + return pBreak; +} + +void CXFA_TextLayout::InitBreak(FX_FLOAT fLineWidth) { + CXFA_Font font = m_pTextProvider->GetFontNode(); + CXFA_Para para = m_pTextProvider->GetParaNode(); + FX_FLOAT fStart = 0; + FX_FLOAT fStartPos = 0; + if (para) { + int32_t iAlign = FX_RTFLINEALIGNMENT_Left; + switch (para.GetHorizontalAlign()) { + case XFA_ATTRIBUTEENUM_Center: + iAlign = FX_RTFLINEALIGNMENT_Center; + break; + case XFA_ATTRIBUTEENUM_Right: + iAlign = FX_RTFLINEALIGNMENT_Right; + break; + case XFA_ATTRIBUTEENUM_Justify: + iAlign = FX_RTFLINEALIGNMENT_Justified; + break; + case XFA_ATTRIBUTEENUM_JustifyAll: + iAlign = FX_RTFLINEALIGNMENT_Distributed; + break; + } + m_pBreak->SetAlignment(iAlign); + + fStart = para.GetMarginLeft(); + if (m_pTextProvider->IsCheckButtonAndAutoWidth()) { + if (iAlign != FX_RTFLINEALIGNMENT_Left) + fLineWidth -= para.GetMarginRight(); + } else { + fLineWidth -= para.GetMarginRight(); + } + if (fLineWidth < 0) + fLineWidth = fStart; + + fStartPos = fStart; + FX_FLOAT fIndent = para.GetTextIndent(); + if (fIndent > 0) + fStartPos += fIndent; + } + + m_pBreak->SetLineBoundary(fStart, fLineWidth); + m_pBreak->SetLineStartPos(fStartPos); + if (font) { + m_pBreak->SetHorizontalScale((int32_t)font.GetHorizontalScale()); + m_pBreak->SetVerticalScale((int32_t)font.GetVerticalScale()); + m_pBreak->SetCharSpace(font.GetLetterSpacing()); + } + + FX_FLOAT fFontSize = m_textParser.GetFontSize(m_pTextProvider, nullptr); + m_pBreak->SetFontSize(fFontSize); + m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr)); + m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f); +} + +void CXFA_TextLayout::InitBreak(IFDE_CSSComputedStyle* pStyle, + FDE_CSSDISPLAY eDisplay, + FX_FLOAT fLineWidth, + CFDE_XMLNode* pXMLNode, + IFDE_CSSComputedStyle* pParentStyle) { + if (!pStyle) { + InitBreak(fLineWidth); + return; + } + + IFDE_CSSParagraphStyle* pParaStyle = pStyle->GetParagraphStyles(); + if (eDisplay == FDE_CSSDISPLAY_Block || eDisplay == FDE_CSSDISPLAY_ListItem) { + int32_t iAlign = FX_RTFLINEALIGNMENT_Left; + switch (pParaStyle->GetTextAlign()) { + case FDE_CSSTEXTALIGN_Right: + iAlign = FX_RTFLINEALIGNMENT_Right; + break; + case FDE_CSSTEXTALIGN_Center: + iAlign = FX_RTFLINEALIGNMENT_Center; + break; + case FDE_CSSTEXTALIGN_Justify: + iAlign = FX_RTFLINEALIGNMENT_Justified; + break; + case FDE_CSSTEXTALIGN_JustifyAll: + iAlign = FX_RTFLINEALIGNMENT_Distributed; + break; + default: + break; + } + m_pBreak->SetAlignment(iAlign); + FX_FLOAT fStart = 0; + const FDE_CSSRECT* pRect = pStyle->GetBoundaryStyles()->GetMarginWidth(); + const FDE_CSSRECT* pPaddingRect = + pStyle->GetBoundaryStyles()->GetPaddingWidth(); + if (pRect) { + fStart = pRect->left.GetValue(); + fLineWidth -= pRect->right.GetValue(); + if (pPaddingRect) { + fStart += pPaddingRect->left.GetValue(); + fLineWidth -= pPaddingRect->right.GetValue(); + } + if (eDisplay == FDE_CSSDISPLAY_ListItem) { + const FDE_CSSRECT* pParRect = + pParentStyle->GetBoundaryStyles()->GetMarginWidth(); + const FDE_CSSRECT* pParPaddingRect = + pParentStyle->GetBoundaryStyles()->GetPaddingWidth(); + if (pParRect) { + fStart += pParRect->left.GetValue(); + fLineWidth -= pParRect->right.GetValue(); + if (pParPaddingRect) { + fStart += pParPaddingRect->left.GetValue(); + fLineWidth -= pParPaddingRect->right.GetValue(); + } + } + FDE_CSSRECT pNewRect; + pNewRect.left.Set(FDE_CSSLENGTHUNIT_Point, fStart); + pNewRect.right.Set(FDE_CSSLENGTHUNIT_Point, pRect->right.GetValue()); + pNewRect.top.Set(FDE_CSSLENGTHUNIT_Point, pRect->top.GetValue()); + pNewRect.bottom.Set(FDE_CSSLENGTHUNIT_Point, pRect->bottom.GetValue()); + pStyle->GetBoundaryStyles()->SetMarginWidth(pNewRect); + } + } + m_pBreak->SetLineBoundary(fStart, fLineWidth); + FX_FLOAT fIndent = pParaStyle->GetTextIndent().GetValue(); + if (fIndent > 0) + fStart += fIndent; + + m_pBreak->SetLineStartPos(fStart); + m_pBreak->SetTabWidth(m_textParser.GetTabInterval(pStyle)); + if (!m_pTabstopContext) + m_pTabstopContext = pdfium::MakeUnique(); + m_textParser.GetTabstops(pStyle, m_pTabstopContext.get()); + for (int32_t i = 0; i < m_pTabstopContext->m_iTabCount; i++) { + XFA_TABSTOPS* pTab = m_pTabstopContext->m_tabstops.GetDataPtr(i); + m_pBreak->AddPositionedTab(pTab->fTabstops); + } + } + + FX_FLOAT fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle); + m_pBreak->SetFontSize(fFontSize); + m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f); + m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, pStyle)); + m_pBreak->SetHorizontalScale( + m_textParser.GetHorScale(m_pTextProvider, pStyle, pXMLNode)); + m_pBreak->SetVerticalScale(m_textParser.GetVerScale(m_pTextProvider, pStyle)); + m_pBreak->SetCharSpace(pParaStyle->GetLetterSpacing().GetValue()); +} + +int32_t CXFA_TextLayout::GetText(CFX_WideString& wsText) { + GetTextDataNode(); + wsText.clear(); + if (!m_bRichText) + wsText = m_pTextDataNode->GetContent(); + return wsText.GetLength(); +} + +FX_FLOAT CXFA_TextLayout::GetLayoutHeight() { + if (!m_pLoader) + return 0; + + int32_t iCount = m_pLoader->m_lineHeights.GetSize(); + if (iCount == 0 && m_pLoader->m_fWidth > 0) { + CFX_SizeF szMax(m_pLoader->m_fWidth, m_pLoader->m_fHeight); + CFX_SizeF szDef; + m_pLoader->m_bSaveLineHeight = true; + m_pLoader->m_fLastPos = 0; + CalcSize(szMax, szMax, szDef); + m_pLoader->m_bSaveLineHeight = false; + return szDef.y; + } + + FX_FLOAT fHeight = m_pLoader->m_fHeight; + if (fHeight < 0.1f) { + fHeight = 0; + for (int32_t i = 0; i < iCount; i++) + fHeight += m_pLoader->m_lineHeights.ElementAt(i); + } + return fHeight; +} + +FX_FLOAT CXFA_TextLayout::StartLayout(FX_FLOAT fWidth) { + if (!m_pLoader) + m_pLoader = pdfium::MakeUnique(); + + if (fWidth < 0 || (m_pLoader->m_fWidth > -1 && + FXSYS_fabs(fWidth - m_pLoader->m_fWidth) > 0)) { + m_pLoader->m_lineHeights.RemoveAll(); + m_Blocks.RemoveAll(); + Unload(); + m_pLoader->m_fStartLineOffset = 0; + } + m_pLoader->m_fWidth = fWidth; + + if (fWidth < 0) { + CFX_SizeF szMax; + CFX_SizeF szDef; + m_pLoader->m_bSaveLineHeight = true; + m_pLoader->m_fLastPos = 0; + CalcSize(szMax, szMax, szDef); + m_pLoader->m_bSaveLineHeight = false; + fWidth = szDef.x; + } + return fWidth; +} + +bool CXFA_TextLayout::DoLayout(int32_t iBlockIndex, + FX_FLOAT& fCalcHeight, + FX_FLOAT fContentAreaHeight, + FX_FLOAT fTextHeight) { + if (!m_pLoader) + return false; + + int32_t iBlockCount = m_Blocks.GetSize(); + FX_FLOAT fHeight = fTextHeight; + if (fHeight < 0) + fHeight = GetLayoutHeight(); + + m_pLoader->m_fHeight = fHeight; + if (fContentAreaHeight < 0) + return false; + + m_bHasBlock = true; + if (iBlockCount == 0 && fHeight > 0) { + fHeight = fTextHeight - GetLayoutHeight(); + if (fHeight > 0) { + int32_t iAlign = m_textParser.GetVAlign(m_pTextProvider); + if (iAlign == XFA_ATTRIBUTEENUM_Middle) + fHeight /= 2.0f; + else if (iAlign != XFA_ATTRIBUTEENUM_Bottom) + fHeight = 0; + m_pLoader->m_fStartLineOffset = fHeight; + } + } + + FX_FLOAT fLinePos = m_pLoader->m_fStartLineOffset; + int32_t iLineIndex = 0; + if (iBlockCount > 1) { + if (iBlockCount >= (iBlockIndex + 1) * 2) { + iLineIndex = m_Blocks.ElementAt(iBlockIndex * 2); + } else { + iLineIndex = m_Blocks.ElementAt(iBlockCount - 1) + + m_Blocks.ElementAt(iBlockCount - 2); + } + if (!m_pLoader->m_BlocksHeight.empty()) { + for (int32_t i = 0; i < iBlockIndex; i++) + fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1]; + } + } + + int32_t iCount = m_pLoader->m_lineHeights.GetSize(); + int32_t i = 0; + for (i = iLineIndex; i < iCount; i++) { + FX_FLOAT fLineHeight = m_pLoader->m_lineHeights.ElementAt(i); + if ((i == iLineIndex) && (fLineHeight - fContentAreaHeight > 0.001)) { + fCalcHeight = 0; + return true; + } + if (fLinePos + fLineHeight - fContentAreaHeight > 0.001) { + if (iBlockCount >= (iBlockIndex + 1) * 2) { + m_Blocks.SetAt(iBlockIndex * 2, iLineIndex); + m_Blocks.SetAt(iBlockIndex * 2 + 1, i - iLineIndex); + } else { + m_Blocks.Add(iLineIndex); + m_Blocks.Add(i - iLineIndex); + } + if (i == iLineIndex) { + if (fCalcHeight <= fLinePos) { + if (pdfium::CollectionSize(m_pLoader->m_BlocksHeight) > + iBlockIndex * 2 && + (m_pLoader->m_BlocksHeight[iBlockIndex * 2] == iBlockIndex)) { + m_pLoader->m_BlocksHeight[iBlockIndex * 2 + 1] = fCalcHeight; + } else { + m_pLoader->m_BlocksHeight.push_back((FX_FLOAT)iBlockIndex); + m_pLoader->m_BlocksHeight.push_back(fCalcHeight); + } + } + return true; + } + + fCalcHeight = fLinePos; + return true; + } + fLinePos += fLineHeight; + } + return false; +} + +int32_t CXFA_TextLayout::CountBlocks() const { + int32_t iCount = m_Blocks.GetSize() / 2; + return iCount > 0 ? iCount : 1; +} + +bool CXFA_TextLayout::CalcSize(const CFX_SizeF& minSize, + const CFX_SizeF& maxSize, + CFX_SizeF& defaultSize) { + defaultSize.x = maxSize.x; + if (defaultSize.x < 1) + defaultSize.x = 0xFFFF; + + m_pBreak.reset(CreateBreak(false)); + FX_FLOAT fLinePos = 0; + m_iLines = 0; + m_fMaxWidth = 0; + Loader(defaultSize, fLinePos, false); + if (fLinePos < 0.1f) + fLinePos = m_textParser.GetFontSize(m_pTextProvider, nullptr); + + m_pTabstopContext.reset(); + defaultSize = CFX_SizeF(m_fMaxWidth, fLinePos); + return true; +} + +bool CXFA_TextLayout::Layout(const CFX_SizeF& size, FX_FLOAT* fHeight) { + if (size.x < 1) + return false; + + Unload(); + m_pBreak.reset(CreateBreak(true)); + if (m_pLoader) { + m_pLoader->m_iTotalLines = -1; + m_pLoader->m_iChar = 0; + } + + m_iLines = 0; + FX_FLOAT fLinePos = 0; + Loader(size, fLinePos, true); + UpdateAlign(size.y, fLinePos); + m_pTabstopContext.reset(); + if (fHeight) + *fHeight = fLinePos; + return true; +} + +bool CXFA_TextLayout::Layout(int32_t iBlock) { + if (!m_pLoader || iBlock < 0 || iBlock >= CountBlocks()) + return false; + if (m_pLoader->m_fWidth < 1) + return false; + + m_pLoader->m_iTotalLines = -1; + m_iLines = 0; + FX_FLOAT fLinePos = 0; + CXFA_Node* pNode = nullptr; + CFX_SizeF szText(m_pLoader->m_fWidth, m_pLoader->m_fHeight); + int32_t iCount = m_Blocks.GetSize(); + int32_t iBlocksHeightCount = + pdfium::CollectionSize(m_pLoader->m_BlocksHeight); + iBlocksHeightCount /= 2; + if (iBlock < iBlocksHeightCount) + return true; + if (iBlock == iBlocksHeightCount) { + Unload(); + m_pBreak.reset(CreateBreak(true)); + fLinePos = m_pLoader->m_fStartLineOffset; + for (int32_t i = 0; i < iBlocksHeightCount; i++) + fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1]; + + m_pLoader->m_iChar = 0; + if (iCount > 1) + m_pLoader->m_iTotalLines = m_Blocks.ElementAt(iBlock * 2 + 1); + + Loader(szText, fLinePos, true); + if (iCount == 0 && m_pLoader->m_fStartLineOffset < 0.1f) + UpdateAlign(szText.y, fLinePos); + } else if (m_pTextDataNode) { + iBlock *= 2; + if (iBlock < iCount - 2) + m_pLoader->m_iTotalLines = m_Blocks.ElementAt(iBlock + 1); + + m_pBreak->Reset(); + if (m_bRichText) { + CFDE_XMLNode* pContainerNode = GetXMLContainerNode(); + if (!pContainerNode) + return true; + + CFDE_XMLNode* pXMLNode = m_pLoader->m_pXMLNode; + if (!pXMLNode) + return true; + + CFDE_XMLNode* pSaveXMLNode = m_pLoader->m_pXMLNode; + for (; pXMLNode; + pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) { + if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle, + true)) { + break; + } + } + while (!pXMLNode) { + pXMLNode = pSaveXMLNode->GetNodeItem(CFDE_XMLNode::Parent); + if (pXMLNode == pContainerNode) + break; + if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle, + true, nullptr, false)) { + break; + } + pSaveXMLNode = pXMLNode; + pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling); + if (!pXMLNode) + continue; + for (; pXMLNode; + pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) { + if (!LoadRichText(pXMLNode, szText, fLinePos, + m_pLoader->m_pParentStyle, true)) { + break; + } + } + } + } else { + pNode = m_pLoader->m_pNode; + if (!pNode) + return true; + LoadText(pNode, szText, fLinePos, true); + } + } + if (iBlock == iCount) { + m_pTabstopContext.reset(); + m_pLoader.reset(); + } + return true; +} + +void CXFA_TextLayout::ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex) { + if (!m_pLoader) + return; + + int32_t iCountHeight = m_pLoader->m_lineHeights.GetSize(); + if (iCountHeight == 0) + return; + + bool bEndItem = true; + int32_t iBlockCount = m_Blocks.GetSize(); + FX_FLOAT fLinePos = m_pLoader->m_fStartLineOffset; + int32_t iLineIndex = 0; + if (iBlockIndex > 0) { + int32_t iBlockHeightCount = + pdfium::CollectionSize(m_pLoader->m_BlocksHeight); + iBlockHeightCount /= 2; + if (iBlockHeightCount >= iBlockIndex) { + for (int32_t i = 0; i < iBlockIndex; i++) + fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1]; + } else { + fLinePos = 0; + } + iLineIndex = m_Blocks[iBlockCount - 1] + m_Blocks[iBlockCount - 2]; + } + + int32_t i = 0; + for (i = iLineIndex; i < iCountHeight; i++) { + FX_FLOAT fLineHeight = m_pLoader->m_lineHeights.ElementAt(i); + if (fLinePos + fLineHeight - rtText.height > 0.001) { + m_Blocks.Add(iLineIndex); + m_Blocks.Add(i - iLineIndex); + bEndItem = false; + break; + } + fLinePos += fLineHeight; + } + if (iCountHeight > 0 && (i - iLineIndex) > 0 && bEndItem) { + m_Blocks.Add(iLineIndex); + m_Blocks.Add(i - iLineIndex); + } +} + +bool CXFA_TextLayout::DrawString(CFX_RenderDevice* pFxDevice, + const CFX_Matrix& tmDoc2Device, + const CFX_RectF& rtClip, + int32_t iBlock) { + if (!pFxDevice) + return false; + + std::unique_ptr pDevice( + new CFDE_RenderDevice(pFxDevice, false)); + pDevice->SaveState(); + pDevice->SetClipRect(rtClip); + + auto pSolidBrush = pdfium::MakeUnique(); + auto pPen = pdfium::MakeUnique(); + if (m_pieceLines.GetSize() == 0) { + int32_t iBlockCount = CountBlocks(); + for (int32_t i = 0; i < iBlockCount; i++) + Layout(i); + } + + FXTEXT_CHARPOS* pCharPos = nullptr; + int32_t iCharCount = 0; + int32_t iLineStart = 0; + int32_t iPieceLines = m_pieceLines.GetSize(); + int32_t iCount = m_Blocks.GetSize(); + if (iCount > 0) { + iBlock *= 2; + if (iBlock < iCount) { + iLineStart = m_Blocks.ElementAt(iBlock); + iPieceLines = m_Blocks.ElementAt(iBlock + 1); + } else { + iPieceLines = 0; + } + } + + for (int32_t i = 0; i < iPieceLines; i++) { + if (i + iLineStart >= m_pieceLines.GetSize()) + break; + + CXFA_PieceLine* pPieceLine = m_pieceLines.GetAt(i + iLineStart); + int32_t iPieces = pPieceLine->m_textPieces.GetSize(); + int32_t j = 0; + for (j = 0; j < iPieces; j++) { + const XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(j); + int32_t iChars = pPiece->iChars; + if (iCharCount < iChars) { + FX_Free(pCharPos); + pCharPos = FX_Alloc(FXTEXT_CHARPOS, iChars); + iCharCount = iChars; + } + FXSYS_memset(pCharPos, 0, iCharCount * sizeof(FXTEXT_CHARPOS)); + RenderString(pDevice.get(), pSolidBrush.get(), pPieceLine, j, pCharPos, + tmDoc2Device); + } + for (j = 0; j < iPieces; j++) { + RenderPath(pDevice.get(), pPen.get(), pPieceLine, j, pCharPos, + tmDoc2Device); + } + } + pDevice->RestoreState(); + FX_Free(pCharPos); + return iPieceLines > 0; +} + +void CXFA_TextLayout::UpdateAlign(FX_FLOAT fHeight, FX_FLOAT fBottom) { + fHeight -= fBottom; + if (fHeight < 0.1f) + return; + + switch (m_textParser.GetVAlign(m_pTextProvider)) { + case XFA_ATTRIBUTEENUM_Middle: + fHeight /= 2.0f; + break; + case XFA_ATTRIBUTEENUM_Bottom: + break; + default: + return; + } + + int32_t iCount = m_pieceLines.GetSize(); + for (int32_t i = 0; i < iCount; i++) { + CXFA_PieceLine* pPieceLine = m_pieceLines.GetAt(i); + int32_t iPieces = pPieceLine->m_textPieces.GetSize(); + for (int32_t j = 0; j < iPieces; j++) { + XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(j); + CFX_RectF& rect = pPiece->rtPiece; + rect.top += fHeight; + } + } +} + +bool CXFA_TextLayout::Loader(const CFX_SizeF& szText, + FX_FLOAT& fLinePos, + bool bSavePieces) { + if (!m_pAllocator) + m_pAllocator = IFX_MemoryAllocator::Create(FX_ALLOCTYPE_Static, 256, 0); + + GetTextDataNode(); + if (!m_pTextDataNode) + return true; + + if (m_bRichText) { + CFDE_XMLNode* pXMLContainer = GetXMLContainerNode(); + if (pXMLContainer) { + if (!m_textParser.IsParsed()) + m_textParser.DoParse(pXMLContainer, m_pTextProvider); + + IFDE_CSSComputedStyle* pRootStyle = + m_textParser.CreateRootStyle(m_pTextProvider); + LoadRichText(pXMLContainer, szText, fLinePos, pRootStyle, bSavePieces); + pRootStyle->Release(); + } + } else { + LoadText(m_pTextDataNode, szText, fLinePos, bSavePieces); + } + return true; +} + +void CXFA_TextLayout::LoadText(CXFA_Node* pNode, + const CFX_SizeF& szText, + FX_FLOAT& fLinePos, + bool bSavePieces) { + InitBreak(szText.x); + + CXFA_Para para = m_pTextProvider->GetParaNode(); + FX_FLOAT fSpaceAbove = 0; + if (para) { + fSpaceAbove = para.GetSpaceAbove(); + if (fSpaceAbove < 0.1f) { + fSpaceAbove = 0; + } + int32_t verAlign = para.GetVerticalAlign(); + switch (verAlign) { + case XFA_ATTRIBUTEENUM_Top: + case XFA_ATTRIBUTEENUM_Middle: + case XFA_ATTRIBUTEENUM_Bottom: { + fLinePos += fSpaceAbove; + break; + } + } + } + + CFX_WideString wsText = pNode->GetContent(); + wsText.TrimRight(L" "); + bool bRet = AppendChar(wsText, fLinePos, fSpaceAbove, bSavePieces); + if (bRet && m_pLoader) + m_pLoader->m_pNode = pNode; + else + EndBreak(FX_RTFBREAK_ParagraphBreak, fLinePos, bSavePieces); +} + +bool CXFA_TextLayout::LoadRichText(CFDE_XMLNode* pXMLNode, + const CFX_SizeF& szText, + FX_FLOAT& fLinePos, + IFDE_CSSComputedStyle* pParentStyle, + bool bSavePieces, + CXFA_LinkUserData* pLinkData, + bool bEndBreak, + bool bIsOl, + int32_t iLiCount) { + if (!pXMLNode) + return false; + + CXFA_TextParseContext* pContext = + m_textParser.GetParseContextFromMap(pXMLNode); + FDE_CSSDISPLAY eDisplay = FDE_CSSDISPLAY_None; + bool bContentNode = false; + FX_FLOAT fSpaceBelow = 0; + IFDE_CSSComputedStyle* pStyle = nullptr; + CFX_WideString wsName; + if (bEndBreak) { + bool bCurOl = false; + bool bCurLi = false; + CFDE_XMLElement* pElement = nullptr; + if (pContext) { + if (m_bBlockContinue || + (m_pLoader && pXMLNode == m_pLoader->m_pXMLNode)) { + m_bBlockContinue = true; + } + if (pXMLNode->GetType() == FDE_XMLNODE_Text) { + bContentNode = true; + } else if (pXMLNode->GetType() == FDE_XMLNODE_Element) { + pElement = static_cast(pXMLNode); + pElement->GetLocalTagName(wsName); + } + if (wsName == FX_WSTRC(L"ol")) { + bIsOl = true; + bCurOl = true; + } + if (m_bBlockContinue || bContentNode == false) { + eDisplay = pContext->GetDisplay(); + if (eDisplay != FDE_CSSDISPLAY_Block && + eDisplay != FDE_CSSDISPLAY_Inline && + eDisplay != FDE_CSSDISPLAY_ListItem) { + return true; + } + + pStyle = m_textParser.ComputeStyle(pXMLNode, pParentStyle); + InitBreak(bContentNode ? pParentStyle : pStyle, eDisplay, szText.x, + pXMLNode, pParentStyle); + if ((eDisplay == FDE_CSSDISPLAY_Block || + eDisplay == FDE_CSSDISPLAY_ListItem) && + pStyle && + (wsName.IsEmpty() || + (wsName != FX_WSTRC(L"body") && wsName != FX_WSTRC(L"html") && + wsName != FX_WSTRC(L"ol") && wsName != FX_WSTRC(L"ul")))) { + const FDE_CSSRECT* pRect = + pStyle->GetBoundaryStyles()->GetMarginWidth(); + if (pRect) { + fLinePos += pRect->top.GetValue(); + fSpaceBelow = pRect->bottom.GetValue(); + } + } + + if (wsName == FX_WSTRC(L"a")) { + CFX_WideString wsLinkContent; + ASSERT(pElement); + pElement->GetString(L"href", wsLinkContent); + if (!wsLinkContent.IsEmpty()) { + pLinkData = FXTARGET_NewWith(m_pAllocator.get()) CXFA_LinkUserData( + m_pAllocator.get(), + wsLinkContent.GetBuffer(wsLinkContent.GetLength())); + wsLinkContent.ReleaseBuffer(wsLinkContent.GetLength()); + } + } + + int32_t iTabCount = + m_textParser.CountTabs(bContentNode ? pParentStyle : pStyle); + bool bSpaceRun = + m_textParser.IsSpaceRun(bContentNode ? pParentStyle : pStyle); + CFX_WideString wsText; + if (bContentNode && iTabCount == 0) { + static_cast(pXMLNode)->GetText(wsText); + } else if (wsName == FX_WSTRC(L"br")) { + wsText = L'\n'; + } else if (wsName == FX_WSTRC(L"li")) { + bCurLi = true; + if (bIsOl) + wsText.Format(L"%d. ", iLiCount); + else + wsText = 0x00B7 + FX_WSTRC(L" "); + } else if (!bContentNode) { + if (iTabCount > 0) { + while (iTabCount-- > 0) + wsText += L'\t'; + } else { + m_textParser.GetEmbbedObj(m_pTextProvider, pXMLNode, wsText); + } + } + + int32_t iLength = wsText.GetLength(); + if (iLength > 0 && bContentNode && !bSpaceRun) + ProcessText(wsText); + + if (m_pLoader) { + if (wsText.GetLength() > 0 && + (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) { + wsText.TrimLeft(0x20); + } + if (FDE_CSSDISPLAY_Block == eDisplay) { + m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE; + } else if (FDE_CSSDISPLAY_Inline == eDisplay && + (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) { + m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE; + } else if (wsText.GetLength() > 0 && + (0x20 == wsText.GetAt(wsText.GetLength() - 1))) { + m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE; + } else if (wsText.GetLength() != 0) { + m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE; + } + } + + if (wsText.GetLength() > 0) { + if (!m_pLoader || m_pLoader->m_iChar == 0) { + if (pLinkData) + pLinkData->Retain(); + + CXFA_TextUserData* pUserData = FXTARGET_NewWith(m_pAllocator.get()) + CXFA_TextUserData(m_pAllocator.get(), + bContentNode ? pParentStyle : pStyle, + pLinkData); + m_pBreak->SetUserData(pUserData); + } + + if (AppendChar(wsText, fLinePos, 0, bSavePieces)) { + if (m_pLoader) + m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE; + if (IsEnd(bSavePieces)) { + if (m_pLoader && m_pLoader->m_iTotalLines > -1) { + m_pLoader->m_pXMLNode = pXMLNode; + m_pLoader->m_pParentStyle = pParentStyle; + } + if (pStyle) + pStyle->Release(); + return false; + } + return true; + } + } + } + } + + for (CFDE_XMLNode* pChildNode = + pXMLNode->GetNodeItem(CFDE_XMLNode::FirstChild); + pChildNode; + pChildNode = pChildNode->GetNodeItem(CFDE_XMLNode::NextSibling)) { + if (bCurOl) + iLiCount++; + + if (!LoadRichText(pChildNode, szText, fLinePos, + pContext ? pStyle : pParentStyle, bSavePieces, + pLinkData, true, bIsOl, iLiCount)) + return false; + } + + if (m_pLoader) { + if (FDE_CSSDISPLAY_Block == eDisplay) + m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE; + } + if (bCurLi) + EndBreak(FX_RTFBREAK_LineBreak, fLinePos, bSavePieces); + } else { + if (pContext) + eDisplay = pContext->GetDisplay(); + } + + if (m_bBlockContinue) { + if (pContext && !bContentNode) { + uint32_t dwStatus = (eDisplay == FDE_CSSDISPLAY_Block) + ? FX_RTFBREAK_ParagraphBreak + : FX_RTFBREAK_PieceBreak; + EndBreak(dwStatus, fLinePos, bSavePieces); + if (eDisplay == FDE_CSSDISPLAY_Block) { + fLinePos += fSpaceBelow; + if (m_pTabstopContext) + m_pTabstopContext->RemoveAll(); + } + if (wsName == FX_WSTRC(L"a")) { + if (pLinkData) { + pLinkData->Release(); + pLinkData = nullptr; + } + } + if (IsEnd(bSavePieces)) { + if (pStyle) + pStyle->Release(); + + if (m_pLoader && m_pLoader->m_iTotalLines > -1) { + m_pLoader->m_pXMLNode = + pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling); + m_pLoader->m_pParentStyle = pParentStyle; + } + return false; + } + } + } + if (pStyle) + pStyle->Release(); + + return true; +} + +bool CXFA_TextLayout::AppendChar(const CFX_WideString& wsText, + FX_FLOAT& fLinePos, + FX_FLOAT fSpaceAbove, + bool bSavePieces) { + uint32_t dwStatus = 0; + int32_t iChar = 0; + if (m_pLoader) + iChar = m_pLoader->m_iChar; + + int32_t iLength = wsText.GetLength(); + for (int32_t i = iChar; i < iLength; i++) { + FX_WCHAR wch = wsText.GetAt(i); + if (wch == 0xA0) + wch = 0x20; + + if ((dwStatus = m_pBreak->AppendChar(wch)) > FX_RTFBREAK_PieceBreak) { + AppendTextLine(dwStatus, fLinePos, bSavePieces); + if (IsEnd(bSavePieces)) { + if (m_pLoader) + m_pLoader->m_iChar = i; + return true; + } + if (dwStatus == FX_RTFBREAK_ParagraphBreak && m_bRichText) + fLinePos += fSpaceAbove; + } + } + if (m_pLoader) + m_pLoader->m_iChar = 0; + + return false; +} + +bool CXFA_TextLayout::IsEnd(bool bSavePieces) { + if (!bSavePieces) + return false; + if (m_pLoader && m_pLoader->m_iTotalLines > 0) + return m_iLines >= m_pLoader->m_iTotalLines; + return false; +} + +void CXFA_TextLayout::ProcessText(CFX_WideString& wsText) { + int32_t iLen = wsText.GetLength(); + if (iLen == 0) + return; + + FX_WCHAR* psz = wsText.GetBuffer(iLen); + int32_t iTrimLeft = 0; + FX_WCHAR wch = 0, wPrev = 0; + for (int32_t i = 0; i < iLen; i++) { + wch = psz[i]; + if (wch < 0x20) + wch = 0x20; + if (wch == 0x20 && wPrev == 0x20) + continue; + + wPrev = wch; + psz[iTrimLeft++] = wch; + } + wsText.ReleaseBuffer(iLen); + wsText = wsText.Left(iTrimLeft); +} + +void CXFA_TextLayout::EndBreak(uint32_t dwStatus, + FX_FLOAT& fLinePos, + bool bSavePieces) { + dwStatus = m_pBreak->EndBreak(dwStatus); + if (dwStatus > FX_RTFBREAK_PieceBreak) + AppendTextLine(dwStatus, fLinePos, bSavePieces, true); +} + +void CXFA_TextLayout::DoTabstops(IFDE_CSSComputedStyle* pStyle, + CXFA_PieceLine* pPieceLine) { + if (!m_pTabstopContext || m_pTabstopContext->m_iTabCount == 0) + return; + if (!pStyle || !pPieceLine) + return; + + int32_t iPieces = pPieceLine->m_textPieces.GetSize(); + if (iPieces == 0) + return; + + XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(iPieces - 1); + int32_t& iTabstopsIndex = m_pTabstopContext->m_iTabIndex; + int32_t iCount = m_textParser.CountTabs(pStyle); + if (iTabstopsIndex > m_pTabstopContext->m_iTabCount - 1) + return; + + if (iCount > 0) { + iTabstopsIndex++; + m_pTabstopContext->m_bTabstops = true; + FX_FLOAT fRight = 0; + if (iPieces > 1) { + XFA_TextPiece* p = pPieceLine->m_textPieces.GetAt(iPieces - 2); + fRight = p->rtPiece.right(); + } + m_pTabstopContext->m_fTabWidth = + pPiece->rtPiece.width + pPiece->rtPiece.left - fRight; + } else if (iTabstopsIndex > -1) { + FX_FLOAT fLeft = 0; + if (m_pTabstopContext->m_bTabstops) { + XFA_TABSTOPS* pTabstops = + m_pTabstopContext->m_tabstops.GetDataPtr(iTabstopsIndex); + uint32_t dwAlign = pTabstops->dwAlign; + if (dwAlign == FX_HashCode_GetW(L"center", false)) { + fLeft = pPiece->rtPiece.width / 2.0f; + } else if (dwAlign == FX_HashCode_GetW(L"right", false) || + dwAlign == FX_HashCode_GetW(L"before", false)) { + fLeft = pPiece->rtPiece.width; + } else if (dwAlign == FX_HashCode_GetW(L"decimal", false)) { + int32_t iChars = pPiece->iChars; + for (int32_t i = 0; i < iChars; i++) { + if (pPiece->pszText[i] == L'.') + break; + + fLeft += pPiece->pWidths[i] / 20000.0f; + } + } + m_pTabstopContext->m_fLeft = + std::min(fLeft, m_pTabstopContext->m_fTabWidth); + m_pTabstopContext->m_bTabstops = false; + m_pTabstopContext->m_fTabWidth = 0; + } + pPiece->rtPiece.left -= m_pTabstopContext->m_fLeft; + } +} + +void CXFA_TextLayout::AppendTextLine(uint32_t dwStatus, + FX_FLOAT& fLinePos, + bool bSavePieces, + bool bEndBreak) { + int32_t iPieces = m_pBreak->CountBreakPieces(); + if (iPieces < 1) + return; + + IFDE_CSSComputedStyle* pStyle = nullptr; + if (bSavePieces) { + CXFA_PieceLine* pPieceLine = + FXTARGET_NewWith(m_pAllocator.get()) CXFA_PieceLine; + m_pieceLines.Add(pPieceLine); + if (m_pTabstopContext) + m_pTabstopContext->Reset(); + + FX_FLOAT fLineStep = 0, fBaseLine = 0; + int32_t i = 0; + for (i = 0; i < iPieces; i++) { + const CFX_RTFPiece* pPiece = m_pBreak->GetBreakPiece(i); + CXFA_TextUserData* pUserData = (CXFA_TextUserData*)pPiece->m_pUserData; + if (pUserData) + pStyle = pUserData->m_pStyle; + FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f; + + XFA_TextPiece* pTP = FXTARGET_NewWith(m_pAllocator.get()) XFA_TextPiece(); + pTP->pszText = + (FX_WCHAR*)m_pAllocator->Alloc(pPiece->m_iChars * sizeof(FX_WCHAR)); + pTP->pWidths = + (int32_t*)m_pAllocator->Alloc(pPiece->m_iChars * sizeof(int32_t)); + pTP->iChars = pPiece->m_iChars; + pPiece->GetString(pTP->pszText); + pPiece->GetWidths(pTP->pWidths); + pTP->iBidiLevel = pPiece->m_iBidiLevel; + pTP->iHorScale = pPiece->m_iHorizontalScale; + pTP->iVerScale = pPiece->m_iVerticalScale; + m_textParser.GetUnderline(m_pTextProvider, pStyle, pTP->iUnderline, + pTP->iPeriod); + m_textParser.GetLinethrough(m_pTextProvider, pStyle, pTP->iLineThrough); + pTP->dwColor = m_textParser.GetColor(m_pTextProvider, pStyle); + pTP->pFont = m_textParser.GetFont(m_pTextProvider, pStyle); + pTP->fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle); + pTP->rtPiece.left = pPiece->m_iStartPos / 20000.0f; + pTP->rtPiece.width = pPiece->m_iWidth / 20000.0f; + pTP->rtPiece.height = (FX_FLOAT)pPiece->m_iFontSize * fVerScale / 20.0f; + FX_FLOAT fBaseLineTemp = + m_textParser.GetBaseline(m_pTextProvider, pStyle); + pTP->rtPiece.top = fBaseLineTemp; + pPieceLine->m_textPieces.Add(pTP); + + FX_FLOAT fLineHeight = m_textParser.GetLineHeight( + m_pTextProvider, pStyle, m_iLines == 0, fVerScale); + if (fBaseLineTemp > 0) { + FX_FLOAT fLineHeightTmp = fBaseLineTemp + pTP->rtPiece.height; + if (fLineHeight < fLineHeightTmp) + fLineHeight = fLineHeightTmp; + else + fBaseLineTemp = 0; + } else if (fBaseLine < -fBaseLineTemp) { + fBaseLine = -fBaseLineTemp; + } + fLineStep = std::max(fLineStep, fLineHeight); + if (pUserData && pUserData->m_pLinkData) { + pUserData->m_pLinkData->Retain(); + pTP->pLinkData = pUserData->m_pLinkData; + } else { + pTP->pLinkData = nullptr; + } + DoTabstops(pStyle, pPieceLine); + } + for (i = 0; i < iPieces; i++) { + XFA_TextPiece* pTP = pPieceLine->m_textPieces.GetAt(i); + FX_FLOAT& fTop = pTP->rtPiece.top; + FX_FLOAT fBaseLineTemp = fTop; + fTop = fLinePos + fLineStep - pTP->rtPiece.height - fBaseLineTemp; + fTop = std::max(0.0f, fTop); + } + fLinePos += fLineStep + fBaseLine; + } else { + FX_FLOAT fLineStep = 0; + FX_FLOAT fLineWidth = 0; + for (int32_t i = 0; i < iPieces; i++) { + const CFX_RTFPiece* pPiece = m_pBreak->GetBreakPiece(i); + CXFA_TextUserData* pUserData = (CXFA_TextUserData*)pPiece->m_pUserData; + if (pUserData) + pStyle = pUserData->m_pStyle; + FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f; + FX_FLOAT fBaseLine = m_textParser.GetBaseline(m_pTextProvider, pStyle); + FX_FLOAT fLineHeight = m_textParser.GetLineHeight( + m_pTextProvider, pStyle, m_iLines == 0, fVerScale); + if (fBaseLine > 0) { + FX_FLOAT fLineHeightTmp = + fBaseLine + (FX_FLOAT)pPiece->m_iFontSize * fVerScale / 20.0f; + if (fLineHeight < fLineHeightTmp) { + fLineHeight = fLineHeightTmp; + } + } + fLineStep = std::max(fLineStep, fLineHeight); + fLineWidth += pPiece->m_iWidth / 20000.0f; + } + fLinePos += fLineStep; + m_fMaxWidth = std::max(m_fMaxWidth, fLineWidth); + if (m_pLoader && m_pLoader->m_bSaveLineHeight) { + FX_FLOAT fHeight = fLinePos - m_pLoader->m_fLastPos; + m_pLoader->m_fLastPos = fLinePos; + m_pLoader->m_lineHeights.Add(fHeight); + } + } + if (pStyle) + pStyle->Retain(); + + m_pBreak->ClearBreakPieces(); + if (dwStatus == FX_RTFBREAK_ParagraphBreak) { + m_pBreak->Reset(); + if (!pStyle && bEndBreak) { + CXFA_Para para = m_pTextProvider->GetParaNode(); + if (para) { + FX_FLOAT fStartPos = para.GetMarginLeft(); + FX_FLOAT fIndent = para.GetTextIndent(); + if (fIndent > 0) + fStartPos += fIndent; + + FX_FLOAT fSpaceBelow = para.GetSpaceBelow(); + if (fSpaceBelow < 0.1f) + fSpaceBelow = 0; + + m_pBreak->SetLineStartPos(fStartPos); + fLinePos += fSpaceBelow; + } + } + } + + if (pStyle) { + FX_FLOAT fStart = 0; + const FDE_CSSRECT* pRect = pStyle->GetBoundaryStyles()->GetMarginWidth(); + if (pRect) + fStart = pRect->left.GetValue(); + + FX_FLOAT fTextIndent = + pStyle->GetParagraphStyles()->GetTextIndent().GetValue(); + if (fTextIndent < 0) + fStart -= fTextIndent; + + m_pBreak->SetLineStartPos(fStart); + pStyle->Release(); + } + m_iLines++; +} + +void CXFA_TextLayout::RenderString(CFDE_RenderDevice* pDevice, + CFDE_Brush* pBrush, + CXFA_PieceLine* pPieceLine, + int32_t iPiece, + FXTEXT_CHARPOS* pCharPos, + const CFX_Matrix& tmDoc2Device) { + const XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(iPiece); + int32_t iCount = GetDisplayPos(pPiece, pCharPos); + if (iCount > 0) { + pBrush->SetColor(pPiece->dwColor); + pDevice->DrawString(pBrush, pPiece->pFont, pCharPos, iCount, + pPiece->fFontSize, &tmDoc2Device); + } + pPieceLine->m_charCounts.Add(iCount); +} + +void CXFA_TextLayout::RenderPath(CFDE_RenderDevice* pDevice, + CFDE_Pen* pPen, + CXFA_PieceLine* pPieceLine, + int32_t iPiece, + FXTEXT_CHARPOS* pCharPos, + const CFX_Matrix& tmDoc2Device) { + XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(iPiece); + bool bNoUnderline = pPiece->iUnderline < 1 || pPiece->iUnderline > 2; + bool bNoLineThrough = pPiece->iLineThrough < 1 || pPiece->iLineThrough > 2; + if (bNoUnderline && bNoLineThrough) + return; + + pPen->SetColor(pPiece->dwColor); + std::unique_ptr pPath(new CFDE_Path); + int32_t iChars = GetDisplayPos(pPiece, pCharPos); + if (iChars > 0) { + CFX_PointF pt1, pt2; + FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f; + if (pPiece->iPeriod == XFA_ATTRIBUTEENUM_Word) { + for (int32_t i = 0; i < pPiece->iUnderline; i++) { + for (int32_t j = 0; j < iChars; j++) { + pt1.x = pCharPos[j].m_OriginX; + pt2.x = + pt1.x + pCharPos[j].m_FontCharWidth * pPiece->fFontSize / 1000.0f; + pt1.y = pt2.y = fEndY; + pPath->AddLine(pt1, pt2); + } + fEndY += 2.0f; + } + } else { + pt1.x = pCharPos[0].m_OriginX; + pt2.x = + pCharPos[iChars - 1].m_OriginX + + pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f; + for (int32_t i = 0; i < pPiece->iUnderline; i++) { + pt1.y = pt2.y = fEndY; + pPath->AddLine(pt1, pt2); + fEndY += 2.0f; + } + } + fEndY = pCharPos[0].m_OriginY - pPiece->rtPiece.height * 0.25f; + pt1.x = pCharPos[0].m_OriginX; + pt2.x = pCharPos[iChars - 1].m_OriginX + + pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f; + for (int32_t i = 0; i < pPiece->iLineThrough; i++) { + pt1.y = pt2.y = fEndY; + pPath->AddLine(pt1, pt2); + fEndY += 2.0f; + } + } else { + if (bNoLineThrough && + (bNoUnderline || pPiece->iPeriod != XFA_ATTRIBUTEENUM_All)) { + return; + } + int32_t iCharsTmp = 0; + int32_t iPiecePrev = iPiece, iPieceNext = iPiece; + while (iPiecePrev > 0) { + iPiecePrev--; + iCharsTmp = pPieceLine->m_charCounts.GetAt(iPiecePrev); + if (iCharsTmp > 0) + break; + } + if (iCharsTmp == 0) + return; + + iCharsTmp = 0; + int32_t iPieces = pPieceLine->m_textPieces.GetSize(); + while (iPieceNext < iPieces - 1) { + iPieceNext++; + iCharsTmp = pPieceLine->m_charCounts.GetAt(iPieceNext); + if (iCharsTmp > 0) + break; + } + if (iCharsTmp == 0) + return; + + FX_FLOAT fOrgX = 0.0f; + FX_FLOAT fEndX = 0.0f; + pPiece = pPieceLine->m_textPieces.GetAt(iPiecePrev); + iChars = GetDisplayPos(pPiece, pCharPos); + if (iChars < 1) + return; + + fOrgX = pCharPos[iChars - 1].m_OriginX + + pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f; + pPiece = pPieceLine->m_textPieces.GetAt(iPieceNext); + iChars = GetDisplayPos(pPiece, pCharPos); + if (iChars < 1) + return; + + fEndX = pCharPos[0].m_OriginX; + CFX_PointF pt1, pt2; + pt1.x = fOrgX, pt2.x = fEndX; + FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f; + for (int32_t i = 0; i < pPiece->iUnderline; i++) { + pt1.y = pt2.y = fEndY; + pPath->AddLine(pt1, pt2); + fEndY += 2.0f; + } + fEndY = pCharPos[0].m_OriginY - pPiece->rtPiece.height * 0.25f; + for (int32_t i = 0; i < pPiece->iLineThrough; i++) { + pt1.y = pt2.y = fEndY; + pPath->AddLine(pt1, pt2); + fEndY += 2.0f; + } + } + pDevice->DrawPath(pPen, 1, pPath.get(), &tmDoc2Device); +} + +int32_t CXFA_TextLayout::GetDisplayPos(const XFA_TextPiece* pPiece, + FXTEXT_CHARPOS* pCharPos, + bool bCharCode) { + if (!pPiece) + return 0; + + FX_RTFTEXTOBJ tr; + if (!ToRun(pPiece, tr)) + return 0; + return m_pBreak->GetDisplayPos(&tr, pCharPos, bCharCode); +} + +bool CXFA_TextLayout::ToRun(const XFA_TextPiece* pPiece, FX_RTFTEXTOBJ& tr) { + int32_t iLength = pPiece->iChars; + if (iLength < 1) + return false; + + tr.pStr = pPiece->pszText; + tr.pFont = pPiece->pFont; + tr.pRect = &pPiece->rtPiece; + tr.pWidths = pPiece->pWidths; + tr.iLength = iLength; + tr.fFontSize = pPiece->fFontSize; + tr.iBidiLevel = pPiece->iBidiLevel; + tr.iCharRotation = 0; + tr.wLineBreakChar = L'\n'; + tr.iVerticalScale = pPiece->iVerScale; + tr.dwLayoutStyles = FX_RTFLAYOUTSTYLE_ExpandTab; + tr.iHorizontalScale = pPiece->iHorScale; + return true; +} diff --git a/xfa/fxfa/app/cxfa_textlayout.h b/xfa/fxfa/app/cxfa_textlayout.h new file mode 100644 index 0000000000..e21a5de424 --- /dev/null +++ b/xfa/fxfa/app/cxfa_textlayout.h @@ -0,0 +1,135 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef XFA_FXFA_APP_CXFA_TEXTLAYOUT_H_ +#define XFA_FXFA_APP_CXFA_TEXTLAYOUT_H_ + +#include + +#include "core/fxcrt/fx_basic.h" +#include "core/fxcrt/fx_coordinates.h" +#include "core/fxcrt/fx_string.h" +#include "xfa/fde/css/fde_css.h" +#include "xfa/fgas/layout/fgas_rtfbreak.h" +#include "xfa/fxfa/app/cxfa_textparser.h" + +class CFDE_Brush; +class CFDE_Pen; +class CFDE_RenderDevice; +class CFDE_XMLNode; +class CFX_RTFBreak; +class CXFA_LoaderContext; +class CXFA_LinkUserData; +class CXFA_Node; +class CXFA_PieceLine; +class CXFA_TextProvider; +class CXFA_TextTabstopsContext; +class IFDE_CSSComputedStyle; +class IFX_MemoryAllocator; +class XFA_TextPiece; + +class CXFA_TextLayout { + public: + explicit CXFA_TextLayout(CXFA_TextProvider* pTextProvider); + ~CXFA_TextLayout(); + + int32_t GetText(CFX_WideString& wsText); + FX_FLOAT GetLayoutHeight(); + FX_FLOAT StartLayout(FX_FLOAT fWidth = -1); + bool DoLayout(int32_t iBlockIndex, + FX_FLOAT& fCalcHeight, + FX_FLOAT fContentAreaHeight = -1, + FX_FLOAT fTextHeight = -1); + + bool CalcSize(const CFX_SizeF& minSize, + const CFX_SizeF& maxSize, + CFX_SizeF& defaultSize); + bool Layout(const CFX_SizeF& size, FX_FLOAT* fHeight = nullptr); + void ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex); + bool DrawString(CFX_RenderDevice* pFxDevice, + const CFX_Matrix& tmDoc2Device, + const CFX_RectF& rtClip, + int32_t iBlock = 0); + bool IsLoaded() const { return m_pieceLines.GetSize() > 0; } + void Unload(); + const CFX_ArrayTemplate* GetPieceLines(); + + bool m_bHasBlock; + CFX_Int32Array m_Blocks; + + private: + void GetTextDataNode(); + CFDE_XMLNode* GetXMLContainerNode(); + CFX_RTFBreak* CreateBreak(bool bDefault); + void InitBreak(FX_FLOAT fLineWidth); + void InitBreak(IFDE_CSSComputedStyle* pStyle, + FDE_CSSDISPLAY eDisplay, + FX_FLOAT fLineWidth, + CFDE_XMLNode* pXMLNode, + IFDE_CSSComputedStyle* pParentStyle = nullptr); + bool Loader(const CFX_SizeF& szText, + FX_FLOAT& fLinePos, + bool bSavePieces = true); + void LoadText(CXFA_Node* pNode, + const CFX_SizeF& szText, + FX_FLOAT& fLinePos, + bool bSavePieces); + bool LoadRichText(CFDE_XMLNode* pXMLNode, + const CFX_SizeF& szText, + FX_FLOAT& fLinePos, + IFDE_CSSComputedStyle* pParentStyle, + bool bSavePieces, + CXFA_LinkUserData* pLinkData = nullptr, + bool bEndBreak = true, + bool bIsOl = false, + int32_t iLiCount = 0); + bool AppendChar(const CFX_WideString& wsText, + FX_FLOAT& fLinePos, + FX_FLOAT fSpaceAbove, + bool bSavePieces); + void AppendTextLine(uint32_t dwStatus, + FX_FLOAT& fLinePos, + bool bSavePieces, + bool bEndBreak = false); + void EndBreak(uint32_t dwStatus, FX_FLOAT& fLinePos, bool bDefault); + bool IsEnd(bool bSavePieces); + void ProcessText(CFX_WideString& wsText); + void UpdateAlign(FX_FLOAT fHeight, FX_FLOAT fBottom); + void RenderString(CFDE_RenderDevice* pDevice, + CFDE_Brush* pBrush, + CXFA_PieceLine* pPieceLine, + int32_t iPiece, + FXTEXT_CHARPOS* pCharPos, + const CFX_Matrix& tmDoc2Device); + void RenderPath(CFDE_RenderDevice* pDevice, + CFDE_Pen* pPen, + CXFA_PieceLine* pPieceLine, + int32_t iPiece, + FXTEXT_CHARPOS* pCharPos, + const CFX_Matrix& tmDoc2Device); + int32_t GetDisplayPos(const XFA_TextPiece* pPiece, + FXTEXT_CHARPOS* pCharPos, + bool bCharCode = false); + bool ToRun(const XFA_TextPiece* pPiece, FX_RTFTEXTOBJ& tr); + void DoTabstops(IFDE_CSSComputedStyle* pStyle, CXFA_PieceLine* pPieceLine); + bool Layout(int32_t iBlock); + int32_t CountBlocks() const; + + CXFA_TextProvider* m_pTextProvider; + CXFA_Node* m_pTextDataNode; + bool m_bRichText; + std::unique_ptr m_pAllocator; + std::unique_ptr m_pBreak; + std::unique_ptr m_pLoader; + int32_t m_iLines; + FX_FLOAT m_fMaxWidth; + CXFA_TextParser m_textParser; + CFX_ArrayTemplate m_pieceLines; + std::unique_ptr m_pTabstopContext; + bool m_bBlockContinue; +}; + +#endif // XFA_FXFA_APP_CXFA_TEXTLAYOUT_H_ diff --git a/xfa/fxfa/app/cxfa_textparsecontext.cpp b/xfa/fxfa/app/cxfa_textparsecontext.cpp new file mode 100644 index 0000000000..b0dc655f00 --- /dev/null +++ b/xfa/fxfa/app/cxfa_textparsecontext.cpp @@ -0,0 +1,32 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "xfa/fxfa/app/cxfa_textparsecontext.h" + +#include "xfa/fde/css/fde_cssdeclaration.h" + +CXFA_TextParseContext::CXFA_TextParseContext() + : m_pParentStyle(nullptr), + m_ppMatchedDecls(nullptr), + m_dwMatchedDecls(0), + m_eDisplay(FDE_CSSDISPLAY_None) {} + +CXFA_TextParseContext::~CXFA_TextParseContext() { + if (m_pParentStyle) + m_pParentStyle->Release(); + FX_Free(m_ppMatchedDecls); +} + +void CXFA_TextParseContext::SetDecls(const CFDE_CSSDeclaration** ppDeclArray, + int32_t iDeclCount) { + if (iDeclCount <= 0 || !ppDeclArray) + return; + + m_dwMatchedDecls = iDeclCount; + m_ppMatchedDecls = FX_Alloc(CFDE_CSSDeclaration*, iDeclCount); + FXSYS_memcpy(m_ppMatchedDecls, ppDeclArray, + iDeclCount * sizeof(CFDE_CSSDeclaration*)); +} diff --git a/xfa/fxfa/app/cxfa_textparsecontext.h b/xfa/fxfa/app/cxfa_textparsecontext.h new file mode 100644 index 0000000000..2eafacc8fe --- /dev/null +++ b/xfa/fxfa/app/cxfa_textparsecontext.h @@ -0,0 +1,38 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef XFA_FXFA_APP_CXFA_TEXTPARSECONTEXT_H_ +#define XFA_FXFA_APP_CXFA_TEXTPARSECONTEXT_H_ + +#include "xfa/fde/css/fde_css.h" +#include "xfa/fgas/crt/fgas_memory.h" + +class CFDE_CSSDeclaration; +class IFDE_CSSComputedStyle; + +class CXFA_TextParseContext : public CFX_Target { + public: + CXFA_TextParseContext(); + ~CXFA_TextParseContext() override; + + void SetDisplay(FDE_CSSDISPLAY eDisplay) { m_eDisplay = eDisplay; } + FDE_CSSDISPLAY GetDisplay() const { return m_eDisplay; } + + void SetDecls(const CFDE_CSSDeclaration** ppDeclArray, int32_t iDeclCount); + const CFDE_CSSDeclaration** GetDecls() { + return const_cast(m_ppMatchedDecls); + } + uint32_t CountDecls() const { return m_dwMatchedDecls; } + + IFDE_CSSComputedStyle* m_pParentStyle; + + protected: + CFDE_CSSDeclaration** m_ppMatchedDecls; + uint32_t m_dwMatchedDecls; + FDE_CSSDISPLAY m_eDisplay; +}; + +#endif // XFA_FXFA_APP_CXFA_TEXTPARSECONTEXT_H_ diff --git a/xfa/fxfa/app/cxfa_textparser.cpp b/xfa/fxfa/app/cxfa_textparser.cpp new file mode 100644 index 0000000000..b865e5e576 --- /dev/null +++ b/xfa/fxfa/app/cxfa_textparser.cpp @@ -0,0 +1,659 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "xfa/fxfa/app/cxfa_textparser.h" + +#include + +#include "third_party/base/ptr_util.h" +#include "xfa/fde/css/fde_css.h" +#include "xfa/fde/css/fde_cssstyleselector.h" +#include "xfa/fgas/crt/fgas_codepage.h" +#include "xfa/fgas/font/cfgas_fontmgr.h" +#include "xfa/fxfa/app/cxfa_csstagprovider.h" +#include "xfa/fxfa/app/cxfa_textparsecontext.h" +#include "xfa/fxfa/app/cxfa_texttabstopscontext.h" +#include "xfa/fxfa/app/xfa_ffwidgetacc.h" +#include "xfa/fxfa/parser/cxfa_measurement.h" +#include "xfa/fxfa/xfa_ffapp.h" +#include "xfa/fxfa/xfa_ffdoc.h" +#include "xfa/fxfa/xfa_fontmgr.h" + +namespace { + +enum class TabStopStatus { + Error, + EOS, + None, + Alignment, + StartLeader, + Leader, + Location, +}; + +} // namespace + +CXFA_TextParser::CXFA_TextParser() : m_pUASheet(nullptr) {} + +CXFA_TextParser::~CXFA_TextParser() { + if (m_pUASheet) + m_pUASheet->Release(); + + for (auto& pair : m_mapXMLNodeToParseContext) { + if (pair.second) { + FXTARGET_DeleteWith(CXFA_TextParseContext, m_pAllocator.get(), + pair.second); + } + } +} + +void CXFA_TextParser::Reset() { + for (auto& pair : m_mapXMLNodeToParseContext) { + if (pair.second) { + FXTARGET_DeleteWith(CXFA_TextParseContext, m_pAllocator.get(), + pair.second); + } + } + m_mapXMLNodeToParseContext.clear(); + m_pAllocator.reset(); +} +void CXFA_TextParser::InitCSSData(CXFA_TextProvider* pTextProvider) { + if (!pTextProvider) + return; + + if (!m_pSelector) { + CXFA_FFDoc* pDoc = pTextProvider->GetDocNode(); + CFGAS_FontMgr* pFontMgr = pDoc->GetApp()->GetFDEFontMgr(); + ASSERT(pFontMgr); + m_pSelector = pdfium::MakeUnique(pFontMgr); + FX_FLOAT fFontSize = 10; + CXFA_Font font = pTextProvider->GetFontNode(); + if (font) { + fFontSize = font.GetFontSize(); + } + m_pSelector->SetDefFontSize(fFontSize); + } + + if (!m_pUASheet) { + m_pUASheet = LoadDefaultSheetStyle(); + m_pSelector->SetStyleSheet(FDE_CSSSTYLESHEETGROUP_UserAgent, m_pUASheet); + m_pSelector->UpdateStyleIndex(FDE_CSSMEDIATYPE_ALL); + } +} + +IFDE_CSSStyleSheet* CXFA_TextParser::LoadDefaultSheetStyle() { + static const FX_WCHAR s_pStyle[] = + L"html,body,ol,p,ul{display:block}" + L"li{display:list-item}" + L"ol,ul{padding-left:33px}ol{list-style-type:decimal}ol,ul{margin-top:0;" + L"margin-bottom:0}ul,ol{margin:1.12em 0}" + L"a{color:#0000ff;text-decoration:underline}b{font-weight:bolder}i{font-" + L"style:italic}" + L"sup{vertical-align:+15em;font-size:.66em}sub{vertical-align:-15em;font-" + L"size:.66em}"; + return IFDE_CSSStyleSheet::LoadFromBuffer( + CFX_WideString(), s_pStyle, FXSYS_wcslen(s_pStyle), FX_CODEPAGE_UTF8); +} + +IFDE_CSSComputedStyle* CXFA_TextParser::CreateRootStyle( + CXFA_TextProvider* pTextProvider) { + CXFA_Font font = pTextProvider->GetFontNode(); + CXFA_Para para = pTextProvider->GetParaNode(); + IFDE_CSSComputedStyle* pStyle = m_pSelector->CreateComputedStyle(nullptr); + IFDE_CSSFontStyle* pFontStyle = pStyle->GetFontStyles(); + IFDE_CSSParagraphStyle* pParaStyle = pStyle->GetParagraphStyles(); + FX_FLOAT fLineHeight = 0; + FX_FLOAT fFontSize = 10; + + if (para) { + fLineHeight = para.GetLineHeight(); + FDE_CSSLENGTH indent; + indent.Set(FDE_CSSLENGTHUNIT_Point, para.GetTextIndent()); + pParaStyle->SetTextIndent(indent); + FDE_CSSTEXTALIGN hAlign = FDE_CSSTEXTALIGN_Left; + switch (para.GetHorizontalAlign()) { + case XFA_ATTRIBUTEENUM_Center: + hAlign = FDE_CSSTEXTALIGN_Center; + break; + case XFA_ATTRIBUTEENUM_Right: + hAlign = FDE_CSSTEXTALIGN_Right; + break; + case XFA_ATTRIBUTEENUM_Justify: + hAlign = FDE_CSSTEXTALIGN_Justify; + break; + case XFA_ATTRIBUTEENUM_JustifyAll: + hAlign = FDE_CSSTEXTALIGN_JustifyAll; + break; + } + pParaStyle->SetTextAlign(hAlign); + FDE_CSSRECT rtMarginWidth; + rtMarginWidth.left.Set(FDE_CSSLENGTHUNIT_Point, para.GetMarginLeft()); + rtMarginWidth.top.Set(FDE_CSSLENGTHUNIT_Point, para.GetSpaceAbove()); + rtMarginWidth.right.Set(FDE_CSSLENGTHUNIT_Point, para.GetMarginRight()); + rtMarginWidth.bottom.Set(FDE_CSSLENGTHUNIT_Point, para.GetSpaceBelow()); + pStyle->GetBoundaryStyles()->SetMarginWidth(rtMarginWidth); + } + + if (font) { + pFontStyle->SetColor(font.GetColor()); + pFontStyle->SetFontStyle(font.IsItalic() ? FDE_CSSFONTSTYLE_Italic + : FDE_CSSFONTSTYLE_Normal); + pFontStyle->SetFontWeight(font.IsBold() ? FXFONT_FW_BOLD + : FXFONT_FW_NORMAL); + pParaStyle->SetNumberVerticalAlign(-font.GetBaselineShift()); + fFontSize = font.GetFontSize(); + FDE_CSSLENGTH letterSpacing; + letterSpacing.Set(FDE_CSSLENGTHUNIT_Point, font.GetLetterSpacing()); + pParaStyle->SetLetterSpacing(letterSpacing); + uint32_t dwDecoration = 0; + if (font.GetLineThrough() > 0) + dwDecoration |= FDE_CSSTEXTDECORATION_LineThrough; + if (font.GetUnderline() > 1) + dwDecoration |= FDE_CSSTEXTDECORATION_Double; + else if (font.GetUnderline() > 0) + dwDecoration |= FDE_CSSTEXTDECORATION_Underline; + + pParaStyle->SetTextDecoration(dwDecoration); + } + pParaStyle->SetLineHeight(fLineHeight); + pFontStyle->SetFontSize(fFontSize); + return pStyle; +} + +IFDE_CSSComputedStyle* CXFA_TextParser::CreateStyle( + IFDE_CSSComputedStyle* pParentStyle) { + IFDE_CSSComputedStyle* pNewStyle = + m_pSelector->CreateComputedStyle(pParentStyle); + ASSERT(pNewStyle); + if (!pParentStyle) + return pNewStyle; + + IFDE_CSSParagraphStyle* pParaStyle = pParentStyle->GetParagraphStyles(); + uint32_t dwDecoration = pParaStyle->GetTextDecoration(); + FX_FLOAT fBaseLine = 0; + if (pParaStyle->GetVerticalAlign() == FDE_CSSVERTICALALIGN_Number) + fBaseLine = pParaStyle->GetNumberVerticalAlign(); + + pParaStyle = pNewStyle->GetParagraphStyles(); + pParaStyle->SetTextDecoration(dwDecoration); + pParaStyle->SetNumberVerticalAlign(fBaseLine); + + IFDE_CSSBoundaryStyle* pBoundarytyle = pParentStyle->GetBoundaryStyles(); + const FDE_CSSRECT* pRect = pBoundarytyle->GetMarginWidth(); + if (pRect) { + pBoundarytyle = pNewStyle->GetBoundaryStyles(); + pBoundarytyle->SetMarginWidth(*pRect); + } + return pNewStyle; +} + +IFDE_CSSComputedStyle* CXFA_TextParser::ComputeStyle( + CFDE_XMLNode* pXMLNode, + IFDE_CSSComputedStyle* pParentStyle) { + auto it = m_mapXMLNodeToParseContext.find(pXMLNode); + if (it == m_mapXMLNodeToParseContext.end()) + return nullptr; + + CXFA_TextParseContext* pContext = it->second; + if (!pContext) + return nullptr; + + pContext->m_pParentStyle = pParentStyle; + pParentStyle->Retain(); + + CXFA_CSSTagProvider tagProvider; + ParseTagInfo(pXMLNode, tagProvider); + if (tagProvider.m_bContent) + return nullptr; + + IFDE_CSSComputedStyle* pStyle = CreateStyle(pParentStyle); + CFDE_CSSAccelerator* pCSSAccel = m_pSelector->InitAccelerator(); + pCSSAccel->OnEnterTag(&tagProvider); + m_pSelector->ComputeStyle(&tagProvider, pContext->GetDecls(), + pContext->CountDecls(), pStyle); + pCSSAccel->OnLeaveTag(&tagProvider); + return pStyle; +} + +void CXFA_TextParser::DoParse(CFDE_XMLNode* pXMLContainer, + CXFA_TextProvider* pTextProvider) { + if (!pXMLContainer || !pTextProvider || m_pAllocator) + return; + + m_pAllocator = IFX_MemoryAllocator::Create(FX_ALLOCTYPE_Fixed, 32, + sizeof(CXFA_CSSTagProvider)); + InitCSSData(pTextProvider); + IFDE_CSSComputedStyle* pRootStyle = CreateRootStyle(pTextProvider); + ParseRichText(pXMLContainer, pRootStyle); + pRootStyle->Release(); +} + +void CXFA_TextParser::ParseRichText(CFDE_XMLNode* pXMLNode, + IFDE_CSSComputedStyle* pParentStyle) { + if (!pXMLNode) + return; + + CXFA_CSSTagProvider tagProvider; + ParseTagInfo(pXMLNode, tagProvider); + if (!tagProvider.m_bTagAvailable) + return; + + IFDE_CSSComputedStyle* pNewStyle = nullptr; + if ((tagProvider.GetTagName() != FX_WSTRC(L"body")) || + (tagProvider.GetTagName() != FX_WSTRC(L"html"))) { + CXFA_TextParseContext* pTextContext = + FXTARGET_NewWith(m_pAllocator.get()) CXFA_TextParseContext; + FDE_CSSDISPLAY eDisplay = FDE_CSSDISPLAY_Inline; + if (!tagProvider.m_bContent) { + pNewStyle = CreateStyle(pParentStyle); + CFDE_CSSAccelerator* pCSSAccel = m_pSelector->InitAccelerator(); + pCSSAccel->OnEnterTag(&tagProvider); + CFDE_CSSDeclarationArray DeclArray; + int32_t iMatchedDecls = + m_pSelector->MatchDeclarations(&tagProvider, DeclArray); + const CFDE_CSSDeclaration** ppMatchDecls = + const_cast(DeclArray.GetData()); + m_pSelector->ComputeStyle(&tagProvider, ppMatchDecls, iMatchedDecls, + pNewStyle); + pCSSAccel->OnLeaveTag(&tagProvider); + if (iMatchedDecls > 0) + pTextContext->SetDecls(ppMatchDecls, iMatchedDecls); + + eDisplay = pNewStyle->GetPositionStyles()->GetDisplay(); + } + pTextContext->SetDisplay(eDisplay); + m_mapXMLNodeToParseContext[pXMLNode] = pTextContext; + } + + for (CFDE_XMLNode* pXMLChild = + pXMLNode->GetNodeItem(CFDE_XMLNode::FirstChild); + pXMLChild; + pXMLChild = pXMLChild->GetNodeItem(CFDE_XMLNode::NextSibling)) { + ParseRichText(pXMLChild, pNewStyle); + } + if (pNewStyle) + pNewStyle->Release(); +} + +bool CXFA_TextParser::TagValidate(const CFX_WideString& wsName) const { + static const uint32_t s_XFATagName[] = { + 0x61, // a + 0x62, // b + 0x69, // i + 0x70, // p + 0x0001f714, // br + 0x00022a55, // li + 0x000239bb, // ol + 0x00025881, // ul + 0x0bd37faa, // sub + 0x0bd37fb8, // sup + 0xa73e3af2, // span + 0xb182eaae, // body + 0xdb8ac455, // html + }; + static const int32_t s_iCount = FX_ArraySize(s_XFATagName); + + return std::binary_search(s_XFATagName, s_XFATagName + s_iCount, + FX_HashCode_GetW(wsName.AsStringC(), true)); +} + +void CXFA_TextParser::ParseTagInfo(CFDE_XMLNode* pXMLNode, + CXFA_CSSTagProvider& tagProvider) { + CFX_WideString wsName; + if (pXMLNode->GetType() == FDE_XMLNODE_Element) { + CFDE_XMLElement* pXMLElement = static_cast(pXMLNode); + pXMLElement->GetLocalTagName(wsName); + tagProvider.SetTagNameObj(wsName); + tagProvider.m_bTagAvailable = TagValidate(wsName); + + CFX_WideString wsValue; + pXMLElement->GetString(L"style", wsValue); + if (!wsValue.IsEmpty()) + tagProvider.SetAttribute(L"style", wsValue); + } else if (pXMLNode->GetType() == FDE_XMLNODE_Text) { + tagProvider.m_bTagAvailable = true; + tagProvider.m_bContent = true; + } +} + +int32_t CXFA_TextParser::GetVAlign(CXFA_TextProvider* pTextProvider) const { + CXFA_Para para = pTextProvider->GetParaNode(); + return para ? para.GetVerticalAlign() : XFA_ATTRIBUTEENUM_Top; +} + +FX_FLOAT CXFA_TextParser::GetTabInterval(IFDE_CSSComputedStyle* pStyle) const { + CFX_WideString wsValue; + if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"tab-interval"), wsValue)) + return CXFA_Measurement(wsValue.AsStringC()).ToUnit(XFA_UNIT_Pt); + return 36; +} + +int32_t CXFA_TextParser::CountTabs(IFDE_CSSComputedStyle* pStyle) const { + CFX_WideString wsValue; + if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"xfa-tab-count"), wsValue)) + return wsValue.GetInteger(); + return 0; +} + +bool CXFA_TextParser::IsSpaceRun(IFDE_CSSComputedStyle* pStyle) const { + CFX_WideString wsValue; + if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"xfa-spacerun"), wsValue)) { + wsValue.MakeLower(); + return wsValue == FX_WSTRC(L"yes"); + } + return false; +} + +CFX_RetainPtr CXFA_TextParser::GetFont( + CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle) const { + CFX_WideStringC wsFamily = FX_WSTRC(L"Courier"); + uint32_t dwStyle = 0; + CXFA_Font font = pTextProvider->GetFontNode(); + if (font) { + font.GetTypeface(wsFamily); + if (font.IsBold()) + dwStyle |= FX_FONTSTYLE_Bold; + if (font.IsItalic()) + dwStyle |= FX_FONTSTYLE_Italic; + } + + if (pStyle) { + IFDE_CSSFontStyle* pFontStyle = pStyle->GetFontStyles(); + int32_t iCount = pFontStyle->CountFontFamilies(); + if (iCount > 0) + wsFamily = pFontStyle->GetFontFamily(iCount - 1); + + dwStyle = 0; + if (pFontStyle->GetFontWeight() > FXFONT_FW_NORMAL) + dwStyle |= FX_FONTSTYLE_Bold; + if (pFontStyle->GetFontStyle() == FDE_CSSFONTSTYLE_Italic) + dwStyle |= FX_FONTSTYLE_Italic; + } + + CXFA_FFDoc* pDoc = pTextProvider->GetDocNode(); + CXFA_FontMgr* pFontMgr = pDoc->GetApp()->GetXFAFontMgr(); + return pFontMgr->GetFont(pDoc, wsFamily, dwStyle); +} + +FX_FLOAT CXFA_TextParser::GetFontSize(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle) const { + if (pStyle) + return pStyle->GetFontStyles()->GetFontSize(); + + CXFA_Font font = pTextProvider->GetFontNode(); + if (font) + return font.GetFontSize(); + return 10; +} + +int32_t CXFA_TextParser::GetHorScale(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle, + CFDE_XMLNode* pXMLNode) const { + if (pStyle) { + CFX_WideString wsValue; + if (pStyle->GetCustomStyle(L"xfa-font-horizontal-scale", wsValue)) + return wsValue.GetInteger(); + + while (pXMLNode) { + auto it = m_mapXMLNodeToParseContext.find(pXMLNode); + if (it != m_mapXMLNodeToParseContext.end()) { + CXFA_TextParseContext* pContext = it->second; + if (pContext && pContext->m_pParentStyle && + pContext->m_pParentStyle->GetCustomStyle( + L"xfa-font-horizontal-scale", wsValue)) { + return wsValue.GetInteger(); + } + } + pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::Parent); + } + } + + if (CXFA_Font font = pTextProvider->GetFontNode()) + return static_cast(font.GetHorizontalScale()); + return 100; +} + +int32_t CXFA_TextParser::GetVerScale(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle) const { + if (pStyle) { + CFX_WideString wsValue; + if (pStyle->GetCustomStyle(FX_WSTRC(L"xfa-font-vertical-scale"), wsValue)) + return wsValue.GetInteger(); + } + + if (CXFA_Font font = pTextProvider->GetFontNode()) + return (int32_t)font.GetVerticalScale(); + return 100; +} + +void CXFA_TextParser::GetUnderline(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle, + int32_t& iUnderline, + int32_t& iPeriod) const { + iUnderline = 0; + iPeriod = XFA_ATTRIBUTEENUM_All; + if (!pStyle) { + CXFA_Font font = pTextProvider->GetFontNode(); + if (font) { + iUnderline = font.GetUnderline(); + iPeriod = font.GetUnderlinePeriod(); + } + return; + } + + uint32_t dwDecoration = pStyle->GetParagraphStyles()->GetTextDecoration(); + if (dwDecoration & FDE_CSSTEXTDECORATION_Double) + iUnderline = 2; + else if (dwDecoration & FDE_CSSTEXTDECORATION_Underline) + iUnderline = 1; + + CFX_WideString wsValue; + if (pStyle->GetCustomStyle(FX_WSTRC(L"underlinePeriod"), wsValue)) { + if (wsValue == FX_WSTRC(L"word")) + iPeriod = XFA_ATTRIBUTEENUM_Word; + } else if (CXFA_Font font = pTextProvider->GetFontNode()) { + iPeriod = font.GetUnderlinePeriod(); + } +} + +void CXFA_TextParser::GetLinethrough(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle, + int32_t& iLinethrough) const { + if (pStyle) { + uint32_t dwDecoration = pStyle->GetParagraphStyles()->GetTextDecoration(); + iLinethrough = (dwDecoration & FDE_CSSTEXTDECORATION_LineThrough) ? 1 : 0; + return; + } + + CXFA_Font font = pTextProvider->GetFontNode(); + if (font) + iLinethrough = font.GetLineThrough(); +} + +FX_ARGB CXFA_TextParser::GetColor(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle) const { + if (pStyle) + return pStyle->GetFontStyles()->GetColor(); + if (CXFA_Font font = pTextProvider->GetFontNode()) + return font.GetColor(); + + return 0xFF000000; +} + +FX_FLOAT CXFA_TextParser::GetBaseline(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle) const { + if (pStyle) { + IFDE_CSSParagraphStyle* pParaStyle = pStyle->GetParagraphStyles(); + if (pParaStyle->GetVerticalAlign() == FDE_CSSVERTICALALIGN_Number) + return pParaStyle->GetNumberVerticalAlign(); + } else if (CXFA_Font font = pTextProvider->GetFontNode()) { + return font.GetBaselineShift(); + } + return 0; +} + +FX_FLOAT CXFA_TextParser::GetLineHeight(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle, + bool bFirst, + FX_FLOAT fVerScale) const { + FX_FLOAT fLineHeight = 0; + if (pStyle) + fLineHeight = pStyle->GetParagraphStyles()->GetLineHeight(); + else if (CXFA_Para para = pTextProvider->GetParaNode()) + fLineHeight = para.GetLineHeight(); + + if (bFirst) { + FX_FLOAT fFontSize = GetFontSize(pTextProvider, pStyle); + if (fLineHeight < 0.1f) + fLineHeight = fFontSize; + else + fLineHeight = std::min(fLineHeight, fFontSize); + } else if (fLineHeight < 0.1f) { + fLineHeight = GetFontSize(pTextProvider, pStyle) * 1.2f; + } + fLineHeight *= fVerScale; + return fLineHeight; +} + +bool CXFA_TextParser::GetEmbbedObj(CXFA_TextProvider* pTextProvider, + CFDE_XMLNode* pXMLNode, + CFX_WideString& wsValue) { + wsValue.clear(); + if (!pXMLNode) + return false; + + bool bRet = false; + if (pXMLNode->GetType() == FDE_XMLNODE_Element) { + CFDE_XMLElement* pElement = static_cast(pXMLNode); + CFX_WideString wsAttr; + pElement->GetString(L"xfa:embed", wsAttr); + if (wsAttr.IsEmpty()) + return false; + if (wsAttr.GetAt(0) == L'#') + wsAttr.Delete(0); + + CFX_WideString ws; + pElement->GetString(L"xfa:embedType", ws); + if (ws.IsEmpty()) + ws = L"som"; + else + ws.MakeLower(); + + bool bURI = (ws == FX_WSTRC(L"uri")); + if (!bURI && ws != FX_WSTRC(L"som")) + return false; + + ws.clear(); + pElement->GetString(L"xfa:embedMode", ws); + if (ws.IsEmpty()) + ws = L"formatted"; + else + ws.MakeLower(); + + bool bRaw = (ws == FX_WSTRC(L"raw")); + if (!bRaw && ws != FX_WSTRC(L"formatted")) + return false; + + bRet = pTextProvider->GetEmbbedObj(bURI, bRaw, wsAttr, wsValue); + } + return bRet; +} + +CXFA_TextParseContext* CXFA_TextParser::GetParseContextFromMap( + CFDE_XMLNode* pXMLNode) { + auto it = m_mapXMLNodeToParseContext.find(pXMLNode); + return it != m_mapXMLNodeToParseContext.end() ? it->second : nullptr; +} + +bool CXFA_TextParser::GetTabstops(IFDE_CSSComputedStyle* pStyle, + CXFA_TextTabstopsContext* pTabstopContext) { + if (!pStyle || !pTabstopContext) + return false; + + CFX_WideString wsValue; + if (!pStyle->GetCustomStyle(FX_WSTRC(L"xfa-tab-stops"), wsValue) && + !pStyle->GetCustomStyle(FX_WSTRC(L"tab-stops"), wsValue)) { + return false; + } + + int32_t iLength = wsValue.GetLength(); + const FX_WCHAR* pTabStops = wsValue.c_str(); + int32_t iCur = 0; + int32_t iLast = 0; + CFX_WideString wsAlign; + TabStopStatus eStatus = TabStopStatus::None; + FX_WCHAR ch; + while (iCur < iLength) { + ch = pTabStops[iCur]; + switch (eStatus) { + case TabStopStatus::None: + if (ch <= ' ') { + iCur++; + } else { + eStatus = TabStopStatus::Alignment; + iLast = iCur; + } + break; + case TabStopStatus::Alignment: + if (ch == ' ') { + wsAlign = CFX_WideStringC(pTabStops + iLast, iCur - iLast); + eStatus = TabStopStatus::StartLeader; + iCur++; + while (iCur < iLength && pTabStops[iCur] <= ' ') + iCur++; + iLast = iCur; + } else { + iCur++; + } + break; + case TabStopStatus::StartLeader: + if (ch != 'l') { + eStatus = TabStopStatus::Location; + } else { + int32_t iCount = 0; + while (iCur < iLength) { + ch = pTabStops[iCur]; + iCur++; + if (ch == '(') { + iCount++; + } else if (ch == ')') { + iCount--; + if (iCount == 0) + break; + } + } + while (iCur < iLength && pTabStops[iCur] <= ' ') + iCur++; + + iLast = iCur; + eStatus = TabStopStatus::Location; + } + break; + case TabStopStatus::Location: + if (ch == ' ') { + uint32_t dwHashCode = FX_HashCode_GetW(wsAlign.AsStringC(), true); + CXFA_Measurement ms(CFX_WideStringC(pTabStops + iLast, iCur - iLast)); + FX_FLOAT fPos = ms.ToUnit(XFA_UNIT_Pt); + pTabstopContext->Append(dwHashCode, fPos); + wsAlign.clear(); + eStatus = TabStopStatus::None; + } + iCur++; + break; + default: + break; + } + } + + if (!wsAlign.IsEmpty()) { + uint32_t dwHashCode = FX_HashCode_GetW(wsAlign.AsStringC(), true); + CXFA_Measurement ms(CFX_WideStringC(pTabStops + iLast, iCur - iLast)); + FX_FLOAT fPos = ms.ToUnit(XFA_UNIT_Pt); + pTabstopContext->Append(dwHashCode, fPos); + } + return true; +} diff --git a/xfa/fxfa/app/cxfa_textparser.h b/xfa/fxfa/app/cxfa_textparser.h new file mode 100644 index 0000000000..e793c0c9fe --- /dev/null +++ b/xfa/fxfa/app/cxfa_textparser.h @@ -0,0 +1,101 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef XFA_FXFA_APP_CXFA_TEXTPARSER_H_ +#define XFA_FXFA_APP_CXFA_TEXTPARSER_H_ + +#include +#include + +#include "core/fxcrt/cfx_retain_ptr.h" +#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/fx_system.h" +#include "core/fxge/fx_dib.h" +#include "xfa/fgas/font/cfgas_gefont.h" + +class CFDE_CSSStyleSelector; +class CFDE_XMLNode; +class CXFA_CSSTagProvider; +class CXFA_TextParseContext; +class CXFA_TextProvider; +class CXFA_TextTabstopsContext; +class IFDE_CSSComputedStyle; +class IFDE_CSSStyleSheet; +class IFX_MemoryAllocator; + +class CXFA_TextParser { + public: + CXFA_TextParser(); + virtual ~CXFA_TextParser(); + + void Reset(); + void DoParse(CFDE_XMLNode* pXMLContainer, CXFA_TextProvider* pTextProvider); + + IFDE_CSSComputedStyle* CreateRootStyle(CXFA_TextProvider* pTextProvider); + IFDE_CSSComputedStyle* ComputeStyle(CFDE_XMLNode* pXMLNode, + IFDE_CSSComputedStyle* pParentStyle); + + bool IsParsed() const { return !!m_pAllocator; } + + int32_t GetVAlign(CXFA_TextProvider* pTextProvider) const; + + FX_FLOAT GetTabInterval(IFDE_CSSComputedStyle* pStyle) const; + int32_t CountTabs(IFDE_CSSComputedStyle* pStyle) const; + + bool IsSpaceRun(IFDE_CSSComputedStyle* pStyle) const; + bool GetTabstops(IFDE_CSSComputedStyle* pStyle, + CXFA_TextTabstopsContext* pTabstopContext); + + CFX_RetainPtr GetFont(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle) const; + FX_FLOAT GetFontSize(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle) const; + + int32_t GetHorScale(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle, + CFDE_XMLNode* pXMLNode) const; + int32_t GetVerScale(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle) const; + + void GetUnderline(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle, + int32_t& iUnderline, + int32_t& iPeriod) const; + void GetLinethrough(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle, + int32_t& iLinethrough) const; + FX_ARGB GetColor(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle) const; + FX_FLOAT GetBaseline(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle) const; + FX_FLOAT GetLineHeight(CXFA_TextProvider* pTextProvider, + IFDE_CSSComputedStyle* pStyle, + bool bFirst, + FX_FLOAT fVerScale) const; + + bool GetEmbbedObj(CXFA_TextProvider* pTextProvider, + CFDE_XMLNode* pXMLNode, + CFX_WideString& wsValue); + CXFA_TextParseContext* GetParseContextFromMap(CFDE_XMLNode* pXMLNode); + + protected: + bool TagValidate(const CFX_WideString& str) const; + + private: + void InitCSSData(CXFA_TextProvider* pTextProvider); + void ParseRichText(CFDE_XMLNode* pXMLNode, + IFDE_CSSComputedStyle* pParentStyle); + void ParseTagInfo(CFDE_XMLNode* pXMLNode, CXFA_CSSTagProvider& tagProvider); + IFDE_CSSStyleSheet* LoadDefaultSheetStyle(); + IFDE_CSSComputedStyle* CreateStyle(IFDE_CSSComputedStyle* pParentStyle); + + std::unique_ptr m_pAllocator; + std::unique_ptr m_pSelector; + IFDE_CSSStyleSheet* m_pUASheet; + std::map m_mapXMLNodeToParseContext; +}; + +#endif // XFA_FXFA_APP_CXFA_TEXTPARSER_H_ diff --git a/xfa/fxfa/app/cxfa_textparser_unittest.cpp b/xfa/fxfa/app/cxfa_textparser_unittest.cpp new file mode 100644 index 0000000000..82a0110468 --- /dev/null +++ b/xfa/fxfa/app/cxfa_textparser_unittest.cpp @@ -0,0 +1,40 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "xfa/fxfa/app/cxfa_textparser.h" + +#include "testing/gtest/include/gtest/gtest.h" + +class CXFA_TestTextParser : public CXFA_TextParser { + public: + CXFA_TestTextParser() : CXFA_TextParser() {} + + private: + // Add test cases as friends to access protected member functions. + FRIEND_TEST(CXFA_TextParser, TagValidate); +}; + +TEST(CXFA_TextParser, TagValidate) { + CXFA_TestTextParser parser; + EXPECT_TRUE(parser.TagValidate(L"br")); + EXPECT_TRUE(parser.TagValidate(L"Br")); + EXPECT_TRUE(parser.TagValidate(L"BR")); + EXPECT_TRUE(parser.TagValidate(L"a")); + EXPECT_TRUE(parser.TagValidate(L"b")); + EXPECT_TRUE(parser.TagValidate(L"i")); + EXPECT_TRUE(parser.TagValidate(L"p")); + EXPECT_TRUE(parser.TagValidate(L"li")); + EXPECT_TRUE(parser.TagValidate(L"ol")); + EXPECT_TRUE(parser.TagValidate(L"ul")); + EXPECT_TRUE(parser.TagValidate(L"sub")); + EXPECT_TRUE(parser.TagValidate(L"sup")); + EXPECT_TRUE(parser.TagValidate(L"span")); + EXPECT_TRUE(parser.TagValidate(L"body")); + EXPECT_TRUE(parser.TagValidate(L"html")); + + EXPECT_FALSE(parser.TagValidate(L"")); + EXPECT_FALSE(parser.TagValidate(L"tml")); + EXPECT_FALSE(parser.TagValidate(L"xhtml")); + EXPECT_FALSE(parser.TagValidate(L"htmlx")); +} diff --git a/xfa/fxfa/app/cxfa_texttabstopscontext.cpp b/xfa/fxfa/app/cxfa_texttabstopscontext.cpp new file mode 100644 index 0000000000..3209603af3 --- /dev/null +++ b/xfa/fxfa/app/cxfa_texttabstopscontext.cpp @@ -0,0 +1,44 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "xfa/fxfa/app/cxfa_texttabstopscontext.h" + +CXFA_TextTabstopsContext::CXFA_TextTabstopsContext() + : m_iTabCount(0), + m_iTabIndex(-1), + m_bTabstops(false), + m_fTabWidth(0), + m_fLeft(0) {} + +CXFA_TextTabstopsContext::~CXFA_TextTabstopsContext() {} + +void CXFA_TextTabstopsContext::Append(uint32_t dwAlign, FX_FLOAT fTabstops) { + int32_t i = 0; + for (i = 0; i < m_iTabCount; i++) { + XFA_TABSTOPS* pTabstop = m_tabstops.GetDataPtr(i); + if (fTabstops < pTabstop->fTabstops) { + break; + } + } + m_tabstops.InsertSpaceAt(i, 1); + XFA_TABSTOPS tabstop; + tabstop.dwAlign = dwAlign; + tabstop.fTabstops = fTabstops; + m_tabstops.SetAt(i, tabstop); + m_iTabCount++; +} + +void CXFA_TextTabstopsContext::RemoveAll() { + m_tabstops.RemoveAll(); + m_iTabCount = 0; +} + +void CXFA_TextTabstopsContext::Reset() { + m_iTabIndex = -1; + m_bTabstops = false; + m_fTabWidth = 0; + m_fLeft = 0; +} diff --git a/xfa/fxfa/app/cxfa_texttabstopscontext.h b/xfa/fxfa/app/cxfa_texttabstopscontext.h new file mode 100644 index 0000000000..8fe0e6273f --- /dev/null +++ b/xfa/fxfa/app/cxfa_texttabstopscontext.h @@ -0,0 +1,34 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef XFA_FXFA_APP_CXFA_TEXTTABSTOPSCONTEXT_H_ +#define XFA_FXFA_APP_CXFA_TEXTTABSTOPSCONTEXT_H_ + +#include "core/fxcrt/fx_basic.h" + +struct XFA_TABSTOPS { + uint32_t dwAlign; + FX_FLOAT fTabstops; +}; + +class CXFA_TextTabstopsContext { + public: + CXFA_TextTabstopsContext(); + ~CXFA_TextTabstopsContext(); + + void Append(uint32_t dwAlign, FX_FLOAT fTabstops); + void RemoveAll(); + void Reset(); + + CFX_ArrayTemplate m_tabstops; + int32_t m_iTabCount; + int32_t m_iTabIndex; + bool m_bTabstops; + FX_FLOAT m_fTabWidth; + FX_FLOAT m_fLeft; +}; + +#endif // XFA_FXFA_APP_CXFA_TEXTTABSTOPSCONTEXT_H_ diff --git a/xfa/fxfa/app/cxfa_textuserdata.cpp b/xfa/fxfa/app/cxfa_textuserdata.cpp new file mode 100644 index 0000000000..209e4f2c21 --- /dev/null +++ b/xfa/fxfa/app/cxfa_textuserdata.cpp @@ -0,0 +1,51 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "xfa/fxfa/app/cxfa_textuserdata.h" + +#include "xfa/fde/css/fde_css.h" +#include "xfa/fxfa/app/cxfa_linkuserdata.h" + +CXFA_TextUserData::CXFA_TextUserData(IFX_MemoryAllocator* pAllocator, + IFDE_CSSComputedStyle* pStyle) + : m_pStyle(pStyle), + m_pLinkData(nullptr), + m_pAllocator(pAllocator), + m_dwRefCount(0) { + ASSERT(m_pAllocator); + if (m_pStyle) + m_pStyle->Retain(); +} + +CXFA_TextUserData::CXFA_TextUserData(IFX_MemoryAllocator* pAllocator, + IFDE_CSSComputedStyle* pStyle, + CXFA_LinkUserData* pLinkData) + : m_pStyle(pStyle), + m_pLinkData(pLinkData), + m_pAllocator(pAllocator), + m_dwRefCount(0) { + ASSERT(m_pAllocator); + if (m_pStyle) + m_pStyle->Retain(); +} + +CXFA_TextUserData::~CXFA_TextUserData() { + if (m_pStyle) + m_pStyle->Release(); + if (m_pLinkData) + m_pLinkData->Release(); +} + +uint32_t CXFA_TextUserData::Retain() { + return ++m_dwRefCount; +} + +uint32_t CXFA_TextUserData::Release() { + uint32_t dwRefCount = --m_dwRefCount; + if (dwRefCount == 0) + FXTARGET_DeleteWith(CXFA_TextUserData, m_pAllocator, this); + return dwRefCount; +} diff --git a/xfa/fxfa/app/cxfa_textuserdata.h b/xfa/fxfa/app/cxfa_textuserdata.h new file mode 100644 index 0000000000..f9e76f94d8 --- /dev/null +++ b/xfa/fxfa/app/cxfa_textuserdata.h @@ -0,0 +1,38 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef XFA_FXFA_APP_CXFA_TEXTUSERDATA_H_ +#define XFA_FXFA_APP_CXFA_TEXTUSERDATA_H_ + +#include "core/fxcrt/fx_basic.h" +#include "xfa/fgas/crt/fgas_memory.h" + +class CXFA_LinkUserData; +class IFDE_CSSComputedStyle; +class IFX_MemoryAllocator; + +class CXFA_TextUserData : public IFX_Retainable, public CFX_Target { + public: + CXFA_TextUserData(IFX_MemoryAllocator* pAllocator, + IFDE_CSSComputedStyle* pStyle); + CXFA_TextUserData(IFX_MemoryAllocator* pAllocator, + IFDE_CSSComputedStyle* pStyle, + CXFA_LinkUserData* pLinkData); + ~CXFA_TextUserData() override; + + // IFX_Retainable: + uint32_t Retain() override; + uint32_t Release() override; + + IFDE_CSSComputedStyle* m_pStyle; + CXFA_LinkUserData* m_pLinkData; + + protected: + IFX_MemoryAllocator* m_pAllocator; + uint32_t m_dwRefCount; +}; + +#endif // XFA_FXFA_APP_CXFA_TEXTUSERDATA_H_ diff --git a/xfa/fxfa/app/xfa_ffdocview.cpp b/xfa/fxfa/app/xfa_ffdocview.cpp index 4a3465bd9d..bf91baf082 100644 --- a/xfa/fxfa/app/xfa_ffdocview.cpp +++ b/xfa/fxfa/app/xfa_ffdocview.cpp @@ -25,7 +25,6 @@ #include "xfa/fxfa/app/xfa_fftextedit.h" #include "xfa/fxfa/app/xfa_ffwidgetacc.h" #include "xfa/fxfa/app/xfa_fwladapter.h" -#include "xfa/fxfa/app/xfa_textlayout.h" #include "xfa/fxfa/parser/cxfa_binditems.h" #include "xfa/fxfa/parser/cxfa_layoutprocessor.h" #include "xfa/fxfa/parser/cxfa_scriptcontext.h" diff --git a/xfa/fxfa/app/xfa_fffield.cpp b/xfa/fxfa/app/xfa_fffield.cpp index 0bd6160944..aa8abbde86 100644 --- a/xfa/fxfa/app/xfa_fffield.cpp +++ b/xfa/fxfa/app/xfa_fffield.cpp @@ -15,8 +15,8 @@ #include "xfa/fwl/cfwl_messagesetfocus.h" #include "xfa/fwl/cfwl_picturebox.h" #include "xfa/fwl/cfwl_widgetmgr.h" +#include "xfa/fxfa/app/cxfa_textlayout.h" #include "xfa/fxfa/app/xfa_fwltheme.h" -#include "xfa/fxfa/app/xfa_textlayout.h" #include "xfa/fxfa/xfa_ffapp.h" #include "xfa/fxfa/xfa_ffdoc.h" #include "xfa/fxfa/xfa_ffdocview.h" diff --git a/xfa/fxfa/app/xfa_ffnotify.cpp b/xfa/fxfa/app/xfa_ffnotify.cpp index cb1964cb45..3aef5fcbfd 100644 --- a/xfa/fxfa/app/xfa_ffnotify.cpp +++ b/xfa/fxfa/app/xfa_ffnotify.cpp @@ -7,6 +7,7 @@ #include "xfa/fxfa/app/xfa_ffnotify.h" #include "fxjs/cfxjse_value.h" +#include "xfa/fxfa/app/cxfa_textlayout.h" #include "xfa/fxfa/app/xfa_ffbarcode.h" #include "xfa/fxfa/app/xfa_ffcheckbutton.h" #include "xfa/fxfa/app/xfa_ffchoicelist.h" @@ -23,7 +24,6 @@ #include "xfa/fxfa/app/xfa_fftextedit.h" #include "xfa/fxfa/app/xfa_ffwidgetacc.h" #include "xfa/fxfa/app/xfa_fwladapter.h" -#include "xfa/fxfa/app/xfa_textlayout.h" #include "xfa/fxfa/xfa_ffapp.h" #include "xfa/fxfa/xfa_ffdoc.h" #include "xfa/fxfa/xfa_ffdocview.h" diff --git a/xfa/fxfa/app/xfa_ffpushbutton.cpp b/xfa/fxfa/app/xfa_ffpushbutton.cpp index c12aa48d1a..4d4d1aad2d 100644 --- a/xfa/fxfa/app/xfa_ffpushbutton.cpp +++ b/xfa/fxfa/app/xfa_ffpushbutton.cpp @@ -9,9 +9,9 @@ #include "xfa/fwl/cfwl_notedriver.h" #include "xfa/fwl/cfwl_pushbutton.h" #include "xfa/fwl/cfwl_widgetmgr.h" +#include "xfa/fxfa/app/cxfa_textlayout.h" #include "xfa/fxfa/app/xfa_fffield.h" #include "xfa/fxfa/app/xfa_ffwidgetacc.h" -#include "xfa/fxfa/app/xfa_textlayout.h" #include "xfa/fxfa/xfa_ffapp.h" #include "xfa/fxfa/xfa_ffpageview.h" #include "xfa/fxfa/xfa_ffwidget.h" diff --git a/xfa/fxfa/app/xfa_fftext.cpp b/xfa/fxfa/app/xfa_fftext.cpp index cc7b65cabc..2307ea0dc4 100644 --- a/xfa/fxfa/app/xfa_fftext.cpp +++ b/xfa/fxfa/app/xfa_fftext.cpp @@ -8,8 +8,11 @@ #include "xfa/fwl/fwl_widgetdef.h" #include "xfa/fwl/fwl_widgethit.h" +#include "xfa/fxfa/app/cxfa_linkuserdata.h" +#include "xfa/fxfa/app/cxfa_pieceline.h" +#include "xfa/fxfa/app/cxfa_textlayout.h" #include "xfa/fxfa/app/xfa_ffdraw.h" -#include "xfa/fxfa/app/xfa_textlayout.h" +#include "xfa/fxfa/app/xfa_textpiece.h" #include "xfa/fxfa/xfa_ffapp.h" #include "xfa/fxfa/xfa_ffdoc.h" #include "xfa/fxfa/xfa_ffpageview.h" @@ -155,7 +158,8 @@ const FX_WCHAR* CXFA_FFText::GetLinkURLAtPoint(FX_FLOAT fx, FX_FLOAT fy) { } FX_FLOAT x(fx), y(fy); FWLToClient(x, y); - const CXFA_PieceLineArray* pPieceLines = pTextLayout->GetPieceLines(); + const CFX_ArrayTemplate* pPieceLines = + pTextLayout->GetPieceLines(); int32_t iCount = pPieceLines->GetSize(); for (int32_t i = 0; i < iCount; i++) { CXFA_PieceLine* pPieceLine = pPieceLines->GetAt(i); diff --git a/xfa/fxfa/app/xfa_fftextedit.cpp b/xfa/fxfa/app/xfa_fftextedit.cpp index 26e3512c40..1088afdb6a 100644 --- a/xfa/fxfa/app/xfa_fftextedit.cpp +++ b/xfa/fxfa/app/xfa_fftextedit.cpp @@ -20,7 +20,6 @@ #include "xfa/fwl/cfwl_notedriver.h" #include "xfa/fxfa/app/xfa_fffield.h" #include "xfa/fxfa/app/xfa_fwladapter.h" -#include "xfa/fxfa/app/xfa_textlayout.h" #include "xfa/fxfa/cxfa_eventparam.h" #include "xfa/fxfa/parser/xfa_localevalue.h" #include "xfa/fxfa/xfa_ffapp.h" diff --git a/xfa/fxfa/app/xfa_ffwidget.cpp b/xfa/fxfa/app/xfa_ffwidget.cpp index f46c6a0381..64aed4f328 100644 --- a/xfa/fxfa/app/xfa_ffwidget.cpp +++ b/xfa/fxfa/app/xfa_ffwidget.cpp @@ -18,7 +18,7 @@ #include "core/fxge/cfx_pathdata.h" #include "core/fxge/cfx_renderdevice.h" #include "xfa/fwl/fwl_widgethit.h" -#include "xfa/fxfa/app/xfa_textlayout.h" +#include "xfa/fxfa/app/cxfa_textlayout.h" #include "xfa/fxfa/cxfa_eventparam.h" #include "xfa/fxfa/fxfa_widget.h" #include "xfa/fxfa/parser/cxfa_corner.h" diff --git a/xfa/fxfa/app/xfa_ffwidgetacc.cpp b/xfa/fxfa/app/xfa_ffwidgetacc.cpp index e62ebca302..d4d9949c3e 100644 --- a/xfa/fxfa/app/xfa_ffwidgetacc.cpp +++ b/xfa/fxfa/app/xfa_ffwidgetacc.cpp @@ -19,7 +19,6 @@ #include "xfa/fxfa/app/xfa_ffchoicelist.h" #include "xfa/fxfa/app/xfa_fffield.h" #include "xfa/fxfa/app/xfa_fwladapter.h" -#include "xfa/fxfa/app/xfa_textlayout.h" #include "xfa/fxfa/cxfa_eventparam.h" #include "xfa/fxfa/parser/cxfa_layoutprocessor.h" #include "xfa/fxfa/parser/cxfa_scriptcontext.h" diff --git a/xfa/fxfa/app/xfa_ffwidgetacc.h b/xfa/fxfa/app/xfa_ffwidgetacc.h index 092254b2d8..2daa35e6cd 100644 --- a/xfa/fxfa/app/xfa_ffwidgetacc.h +++ b/xfa/fxfa/app/xfa_ffwidgetacc.h @@ -7,7 +7,14 @@ #ifndef XFA_FXFA_APP_XFA_FFWIDGETACC_H_ #define XFA_FXFA_APP_XFA_FFWIDGETACC_H_ -#include "xfa/fxfa/app/xfa_textlayout.h" +#include "core/fxcrt/fx_string.h" +#include "xfa/fxfa/app/cxfa_textlayout.h" +#include "xfa/fxfa/fxfa_widget.h" +#include "xfa/fxfa/parser/cxfa_font.h" +#include "xfa/fxfa/parser/cxfa_para.h" + +class CXFA_FFDoc; +class CXFA_Node; enum XFA_TEXTPROVIDERTYPE { XFA_TEXTPROVIDERTYPE_Text, diff --git a/xfa/fxfa/app/xfa_textlayout.cpp b/xfa/fxfa/app/xfa_textlayout.cpp deleted file mode 100644 index 826fefcfbc..0000000000 --- a/xfa/fxfa/app/xfa_textlayout.cpp +++ /dev/null @@ -1,2111 +0,0 @@ -// Copyright 2014 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#include "xfa/fxfa/app/xfa_textlayout.h" - -#include - -#include "core/fxcrt/fx_ext.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" -#include "xfa/fde/cfde_path.h" -#include "xfa/fde/css/fde_csscache.h" -#include "xfa/fde/css/fde_cssstyleselector.h" -#include "xfa/fde/fde_gedevice.h" -#include "xfa/fde/fde_object.h" -#include "xfa/fde/xml/fde_xml_imp.h" -#include "xfa/fgas/crt/fgas_codepage.h" -#include "xfa/fxfa/app/xfa_ffwidgetacc.h" -#include "xfa/fxfa/parser/cxfa_measurement.h" -#include "xfa/fxfa/xfa_ffapp.h" -#include "xfa/fxfa/xfa_ffdoc.h" -#include "xfa/fxfa/xfa_fontmgr.h" - -CXFA_CSSTagProvider::CXFA_CSSTagProvider() - : m_bTagAvailable(false), m_bContent(false) {} - -CXFA_CSSTagProvider::~CXFA_CSSTagProvider() {} - -XFA_TextPiece::XFA_TextPiece() - : pszText(nullptr), pFont(nullptr), pLinkData(nullptr) {} - -XFA_TextPiece::~XFA_TextPiece() { - if (pLinkData) - pLinkData->Release(); -} - -CXFA_TextParseContext::CXFA_TextParseContext() - : m_pParentStyle(nullptr), - m_ppMatchedDecls(nullptr), - m_dwMatchedDecls(0), - m_eDisplay(FDE_CSSDISPLAY_None) {} - -CXFA_TextParseContext::~CXFA_TextParseContext() { - if (m_pParentStyle) - m_pParentStyle->Release(); - FX_Free(m_ppMatchedDecls); -} - -void CXFA_TextParseContext::SetDecls(const CFDE_CSSDeclaration** ppDeclArray, - int32_t iDeclCount) { - if (iDeclCount <= 0 || !ppDeclArray) - return; - - m_dwMatchedDecls = iDeclCount; - m_ppMatchedDecls = FX_Alloc(CFDE_CSSDeclaration*, iDeclCount); - FXSYS_memcpy(m_ppMatchedDecls, ppDeclArray, - iDeclCount * sizeof(CFDE_CSSDeclaration*)); -} - -CXFA_TextParser::CXFA_TextParser() : m_pUASheet(nullptr) {} - -CXFA_TextParser::~CXFA_TextParser() { - if (m_pUASheet) - m_pUASheet->Release(); - - for (auto& pair : m_mapXMLNodeToParseContext) { - if (pair.second) { - FXTARGET_DeleteWith(CXFA_TextParseContext, m_pAllocator.get(), - pair.second); - } - } -} - -void CXFA_TextParser::Reset() { - for (auto& pair : m_mapXMLNodeToParseContext) { - if (pair.second) { - FXTARGET_DeleteWith(CXFA_TextParseContext, m_pAllocator.get(), - pair.second); - } - } - m_mapXMLNodeToParseContext.clear(); - m_pAllocator.reset(); -} -void CXFA_TextParser::InitCSSData(CXFA_TextProvider* pTextProvider) { - if (!pTextProvider) - return; - - if (!m_pSelector) { - CXFA_FFDoc* pDoc = pTextProvider->GetDocNode(); - CFGAS_FontMgr* pFontMgr = pDoc->GetApp()->GetFDEFontMgr(); - ASSERT(pFontMgr); - m_pSelector = pdfium::MakeUnique(pFontMgr); - FX_FLOAT fFontSize = 10; - CXFA_Font font = pTextProvider->GetFontNode(); - if (font) { - fFontSize = font.GetFontSize(); - } - m_pSelector->SetDefFontSize(fFontSize); - } - if (!m_pUASheet) { - m_pUASheet = LoadDefaultSheetStyle(); - m_pSelector->SetStyleSheet(FDE_CSSSTYLESHEETGROUP_UserAgent, m_pUASheet); - m_pSelector->UpdateStyleIndex(FDE_CSSMEDIATYPE_ALL); - } -} - -CXFA_LoaderContext::CXFA_LoaderContext() - : m_bSaveLineHeight(false), - m_fWidth(0), - m_fHeight(0), - m_fLastPos(0), - m_fStartLineOffset(0), - m_iChar(0), - m_iTotalLines(-1), - m_pXMLNode(nullptr), - m_pNode(nullptr), - m_pParentStyle(nullptr), - m_dwFlags(0) {} - -CXFA_LoaderContext::~CXFA_LoaderContext() {} - -IFDE_CSSStyleSheet* CXFA_TextParser::LoadDefaultSheetStyle() { - static const FX_WCHAR s_pStyle[] = - L"html,body,ol,p,ul{display:block}" - L"li{display:list-item}" - L"ol,ul{padding-left:33px}ol{list-style-type:decimal}ol,ul{margin-top:0;" - L"margin-bottom:0}ul,ol{margin:1.12em 0}" - L"a{color:#0000ff;text-decoration:underline}b{font-weight:bolder}i{font-" - L"style:italic}" - L"sup{vertical-align:+15em;font-size:.66em}sub{vertical-align:-15em;font-" - L"size:.66em}"; - return IFDE_CSSStyleSheet::LoadFromBuffer( - CFX_WideString(), s_pStyle, FXSYS_wcslen(s_pStyle), FX_CODEPAGE_UTF8); -} -IFDE_CSSComputedStyle* CXFA_TextParser::CreateRootStyle( - CXFA_TextProvider* pTextProvider) { - CXFA_Font font = pTextProvider->GetFontNode(); - CXFA_Para para = pTextProvider->GetParaNode(); - IFDE_CSSComputedStyle* pStyle = m_pSelector->CreateComputedStyle(nullptr); - IFDE_CSSFontStyle* pFontStyle = pStyle->GetFontStyles(); - IFDE_CSSParagraphStyle* pParaStyle = pStyle->GetParagraphStyles(); - FX_FLOAT fLineHeight = 0, fFontSize = 10; - if (para) { - fLineHeight = para.GetLineHeight(); - FDE_CSSLENGTH indent; - indent.Set(FDE_CSSLENGTHUNIT_Point, para.GetTextIndent()); - pParaStyle->SetTextIndent(indent); - FDE_CSSTEXTALIGN hAlign = FDE_CSSTEXTALIGN_Left; - switch (para.GetHorizontalAlign()) { - case XFA_ATTRIBUTEENUM_Center: - hAlign = FDE_CSSTEXTALIGN_Center; - break; - case XFA_ATTRIBUTEENUM_Right: - hAlign = FDE_CSSTEXTALIGN_Right; - break; - case XFA_ATTRIBUTEENUM_Justify: - hAlign = FDE_CSSTEXTALIGN_Justify; - break; - case XFA_ATTRIBUTEENUM_JustifyAll: - hAlign = FDE_CSSTEXTALIGN_JustifyAll; - break; - } - pParaStyle->SetTextAlign(hAlign); - FDE_CSSRECT rtMarginWidth; - rtMarginWidth.left.Set(FDE_CSSLENGTHUNIT_Point, para.GetMarginLeft()); - rtMarginWidth.top.Set(FDE_CSSLENGTHUNIT_Point, para.GetSpaceAbove()); - rtMarginWidth.right.Set(FDE_CSSLENGTHUNIT_Point, para.GetMarginRight()); - rtMarginWidth.bottom.Set(FDE_CSSLENGTHUNIT_Point, para.GetSpaceBelow()); - pStyle->GetBoundaryStyles()->SetMarginWidth(rtMarginWidth); - } - if (font) { - pFontStyle->SetColor(font.GetColor()); - pFontStyle->SetFontStyle(font.IsItalic() ? FDE_CSSFONTSTYLE_Italic - : FDE_CSSFONTSTYLE_Normal); - pFontStyle->SetFontWeight(font.IsBold() ? FXFONT_FW_BOLD - : FXFONT_FW_NORMAL); - pParaStyle->SetNumberVerticalAlign(-font.GetBaselineShift()); - fFontSize = font.GetFontSize(); - FDE_CSSLENGTH letterSpacing; - letterSpacing.Set(FDE_CSSLENGTHUNIT_Point, font.GetLetterSpacing()); - pParaStyle->SetLetterSpacing(letterSpacing); - uint32_t dwDecoration = 0; - if (font.GetLineThrough() > 0) { - dwDecoration |= FDE_CSSTEXTDECORATION_LineThrough; - } - if (font.GetUnderline() > 1) { - dwDecoration |= FDE_CSSTEXTDECORATION_Double; - } else if (font.GetUnderline() > 0) { - dwDecoration |= FDE_CSSTEXTDECORATION_Underline; - } - pParaStyle->SetTextDecoration(dwDecoration); - } - pParaStyle->SetLineHeight(fLineHeight); - pFontStyle->SetFontSize(fFontSize); - return pStyle; -} -IFDE_CSSComputedStyle* CXFA_TextParser::CreateStyle( - IFDE_CSSComputedStyle* pParentStyle) { - IFDE_CSSComputedStyle* pNewStyle = - m_pSelector->CreateComputedStyle(pParentStyle); - ASSERT(pNewStyle); - if (pParentStyle) { - IFDE_CSSParagraphStyle* pParaStyle = pParentStyle->GetParagraphStyles(); - uint32_t dwDecoration = pParaStyle->GetTextDecoration(); - FX_FLOAT fBaseLine = 0; - if (pParaStyle->GetVerticalAlign() == FDE_CSSVERTICALALIGN_Number) { - fBaseLine = pParaStyle->GetNumberVerticalAlign(); - } - pParaStyle = pNewStyle->GetParagraphStyles(); - pParaStyle->SetTextDecoration(dwDecoration); - pParaStyle->SetNumberVerticalAlign(fBaseLine); - IFDE_CSSBoundaryStyle* pBoundarytyle = pParentStyle->GetBoundaryStyles(); - const FDE_CSSRECT* pRect = pBoundarytyle->GetMarginWidth(); - if (pRect) { - pBoundarytyle = pNewStyle->GetBoundaryStyles(); - pBoundarytyle->SetMarginWidth(*pRect); - } - } - return pNewStyle; -} - -IFDE_CSSComputedStyle* CXFA_TextParser::ComputeStyle( - CFDE_XMLNode* pXMLNode, - IFDE_CSSComputedStyle* pParentStyle) { - auto it = m_mapXMLNodeToParseContext.find(pXMLNode); - if (it == m_mapXMLNodeToParseContext.end()) - return nullptr; - - CXFA_TextParseContext* pContext = it->second; - if (!pContext) - return nullptr; - - pContext->m_pParentStyle = pParentStyle; - pParentStyle->Retain(); - - CXFA_CSSTagProvider tagProvider; - ParseTagInfo(pXMLNode, tagProvider); - if (tagProvider.m_bContent) - return nullptr; - - IFDE_CSSComputedStyle* pStyle = CreateStyle(pParentStyle); - CFDE_CSSAccelerator* pCSSAccel = m_pSelector->InitAccelerator(); - pCSSAccel->OnEnterTag(&tagProvider); - m_pSelector->ComputeStyle(&tagProvider, pContext->GetDecls(), - pContext->CountDecls(), pStyle); - pCSSAccel->OnLeaveTag(&tagProvider); - return pStyle; -} -void CXFA_TextParser::DoParse(CFDE_XMLNode* pXMLContainer, - CXFA_TextProvider* pTextProvider) { - if (!pXMLContainer || !pTextProvider || m_pAllocator) { - return; - } - m_pAllocator = IFX_MemoryAllocator::Create(FX_ALLOCTYPE_Fixed, 32, - sizeof(CXFA_CSSTagProvider)); - InitCSSData(pTextProvider); - IFDE_CSSComputedStyle* pRootStyle = CreateRootStyle(pTextProvider); - ParseRichText(pXMLContainer, pRootStyle); - pRootStyle->Release(); -} -void CXFA_TextParser::ParseRichText(CFDE_XMLNode* pXMLNode, - IFDE_CSSComputedStyle* pParentStyle) { - if (!pXMLNode) - return; - - CXFA_CSSTagProvider tagProvider; - ParseTagInfo(pXMLNode, tagProvider); - if (!tagProvider.m_bTagAvailable) - return; - - IFDE_CSSComputedStyle* pNewStyle = nullptr; - if ((tagProvider.GetTagName() != FX_WSTRC(L"body")) || - (tagProvider.GetTagName() != FX_WSTRC(L"html"))) { - CXFA_TextParseContext* pTextContext = - FXTARGET_NewWith(m_pAllocator.get()) CXFA_TextParseContext; - FDE_CSSDISPLAY eDisplay = FDE_CSSDISPLAY_Inline; - if (!tagProvider.m_bContent) { - pNewStyle = CreateStyle(pParentStyle); - CFDE_CSSAccelerator* pCSSAccel = m_pSelector->InitAccelerator(); - pCSSAccel->OnEnterTag(&tagProvider); - CFDE_CSSDeclarationArray DeclArray; - int32_t iMatchedDecls = - m_pSelector->MatchDeclarations(&tagProvider, DeclArray); - const CFDE_CSSDeclaration** ppMatchDecls = - const_cast(DeclArray.GetData()); - m_pSelector->ComputeStyle(&tagProvider, ppMatchDecls, iMatchedDecls, - pNewStyle); - pCSSAccel->OnLeaveTag(&tagProvider); - if (iMatchedDecls > 0) { - pTextContext->SetDecls(ppMatchDecls, iMatchedDecls); - } - eDisplay = pNewStyle->GetPositionStyles()->GetDisplay(); - } - pTextContext->SetDisplay(eDisplay); - m_mapXMLNodeToParseContext[pXMLNode] = pTextContext; - } - for (CFDE_XMLNode* pXMLChild = - pXMLNode->GetNodeItem(CFDE_XMLNode::FirstChild); - pXMLChild; - pXMLChild = pXMLChild->GetNodeItem(CFDE_XMLNode::NextSibling)) { - ParseRichText(pXMLChild, pNewStyle); - } - if (pNewStyle) - pNewStyle->Release(); -} - -bool CXFA_TextParser::TagValidate(const CFX_WideString& wsName) const { - static const uint32_t s_XFATagName[] = { - 0x61, // a - 0x62, // b - 0x69, // i - 0x70, // p - 0x0001f714, // br - 0x00022a55, // li - 0x000239bb, // ol - 0x00025881, // ul - 0x0bd37faa, // sub - 0x0bd37fb8, // sup - 0xa73e3af2, // span - 0xb182eaae, // body - 0xdb8ac455, // html - }; - static const int32_t s_iCount = FX_ArraySize(s_XFATagName); - - return std::binary_search(s_XFATagName, s_XFATagName + s_iCount, - FX_HashCode_GetW(wsName.AsStringC(), true)); -} - -void CXFA_TextParser::ParseTagInfo(CFDE_XMLNode* pXMLNode, - CXFA_CSSTagProvider& tagProvider) { - CFX_WideString wsName; - if (pXMLNode->GetType() == FDE_XMLNODE_Element) { - CFDE_XMLElement* pXMLElement = static_cast(pXMLNode); - pXMLElement->GetLocalTagName(wsName); - tagProvider.SetTagNameObj(wsName); - tagProvider.m_bTagAvailable = TagValidate(wsName); - - CFX_WideString wsValue; - pXMLElement->GetString(L"style", wsValue); - if (!wsValue.IsEmpty()) { - tagProvider.SetAttribute(L"style", wsValue); - } - } else if (pXMLNode->GetType() == FDE_XMLNODE_Text) { - tagProvider.m_bTagAvailable = true; - tagProvider.m_bContent = true; - } -} - -int32_t CXFA_TextParser::GetVAlign(CXFA_TextProvider* pTextProvider) const { - CXFA_Para para = pTextProvider->GetParaNode(); - return para ? para.GetVerticalAlign() : XFA_ATTRIBUTEENUM_Top; -} - -FX_FLOAT CXFA_TextParser::GetTabInterval(IFDE_CSSComputedStyle* pStyle) const { - CFX_WideString wsValue; - if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"tab-interval"), wsValue)) - return CXFA_Measurement(wsValue.AsStringC()).ToUnit(XFA_UNIT_Pt); - return 36; -} - -int32_t CXFA_TextParser::CountTabs(IFDE_CSSComputedStyle* pStyle) const { - CFX_WideString wsValue; - if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"xfa-tab-count"), wsValue)) - return wsValue.GetInteger(); - return 0; -} - -bool CXFA_TextParser::IsSpaceRun(IFDE_CSSComputedStyle* pStyle) const { - CFX_WideString wsValue; - if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"xfa-spacerun"), wsValue)) { - wsValue.MakeLower(); - return wsValue == FX_WSTRC(L"yes"); - } - return false; -} - -CFX_RetainPtr CXFA_TextParser::GetFont( - CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle) const { - CFX_WideStringC wsFamily = FX_WSTRC(L"Courier"); - uint32_t dwStyle = 0; - CXFA_Font font = pTextProvider->GetFontNode(); - if (font) { - font.GetTypeface(wsFamily); - if (font.IsBold()) { - dwStyle |= FX_FONTSTYLE_Bold; - } - if (font.IsItalic()) { - dwStyle |= FX_FONTSTYLE_Italic; - } - } - if (pStyle) { - IFDE_CSSFontStyle* pFontStyle = pStyle->GetFontStyles(); - int32_t iCount = pFontStyle->CountFontFamilies(); - if (iCount > 0) { - wsFamily = pFontStyle->GetFontFamily(iCount - 1); - } - dwStyle = 0; - if (pFontStyle->GetFontWeight() > FXFONT_FW_NORMAL) { - dwStyle |= FX_FONTSTYLE_Bold; - } - if (pFontStyle->GetFontStyle() == FDE_CSSFONTSTYLE_Italic) { - dwStyle |= FX_FONTSTYLE_Italic; - } - } - CXFA_FFDoc* pDoc = pTextProvider->GetDocNode(); - CXFA_FontMgr* pFontMgr = pDoc->GetApp()->GetXFAFontMgr(); - return pFontMgr->GetFont(pDoc, wsFamily, dwStyle); -} -FX_FLOAT CXFA_TextParser::GetFontSize(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle) const { - if (pStyle) - return pStyle->GetFontStyles()->GetFontSize(); - - CXFA_Font font = pTextProvider->GetFontNode(); - if (font) { - return font.GetFontSize(); - } - return 10; -} -int32_t CXFA_TextParser::GetHorScale(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle, - CFDE_XMLNode* pXMLNode) const { - if (pStyle) { - CFX_WideString wsValue; - if (pStyle->GetCustomStyle(L"xfa-font-horizontal-scale", wsValue)) { - return wsValue.GetInteger(); - } - while (pXMLNode) { - auto it = m_mapXMLNodeToParseContext.find(pXMLNode); - if (it != m_mapXMLNodeToParseContext.end()) { - CXFA_TextParseContext* pContext = it->second; - if (pContext && pContext->m_pParentStyle && - pContext->m_pParentStyle->GetCustomStyle( - L"xfa-font-horizontal-scale", wsValue)) { - return wsValue.GetInteger(); - } - } - pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::Parent); - } - } - if (CXFA_Font font = pTextProvider->GetFontNode()) { - return static_cast(font.GetHorizontalScale()); - } - return 100; -} -int32_t CXFA_TextParser::GetVerScale(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle) const { - if (pStyle) { - CFX_WideString wsValue; - if (pStyle->GetCustomStyle(FX_WSTRC(L"xfa-font-vertical-scale"), wsValue)) { - return wsValue.GetInteger(); - } - } - if (CXFA_Font font = pTextProvider->GetFontNode()) { - return (int32_t)font.GetVerticalScale(); - } - return 100; -} -void CXFA_TextParser::GetUnderline(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle, - int32_t& iUnderline, - int32_t& iPeriod) const { - iUnderline = 0; - iPeriod = XFA_ATTRIBUTEENUM_All; - if (pStyle) { - uint32_t dwDecoration = pStyle->GetParagraphStyles()->GetTextDecoration(); - if (dwDecoration & FDE_CSSTEXTDECORATION_Double) { - iUnderline = 2; - } else if (dwDecoration & FDE_CSSTEXTDECORATION_Underline) { - iUnderline = 1; - } - CFX_WideString wsValue; - if (pStyle->GetCustomStyle(FX_WSTRC(L"underlinePeriod"), wsValue)) { - if (wsValue == FX_WSTRC(L"word")) { - iPeriod = XFA_ATTRIBUTEENUM_Word; - } - } else if (CXFA_Font font = pTextProvider->GetFontNode()) { - iPeriod = font.GetUnderlinePeriod(); - } - } else { - CXFA_Font font = pTextProvider->GetFontNode(); - if (font) { - iUnderline = font.GetUnderline(); - iPeriod = font.GetUnderlinePeriod(); - } - } -} -void CXFA_TextParser::GetLinethrough(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle, - int32_t& iLinethrough) const { - if (pStyle) { - uint32_t dwDecoration = pStyle->GetParagraphStyles()->GetTextDecoration(); - iLinethrough = (dwDecoration & FDE_CSSTEXTDECORATION_LineThrough) ? 1 : 0; - } else { - CXFA_Font font = pTextProvider->GetFontNode(); - if (font) { - iLinethrough = font.GetLineThrough(); - } - } -} -FX_ARGB CXFA_TextParser::GetColor(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle) const { - if (pStyle) - return pStyle->GetFontStyles()->GetColor(); - - if (CXFA_Font font = pTextProvider->GetFontNode()) - return font.GetColor(); - - return 0xFF000000; -} -FX_FLOAT CXFA_TextParser::GetBaseline(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle) const { - if (pStyle) { - IFDE_CSSParagraphStyle* pParaStyle = pStyle->GetParagraphStyles(); - if (pParaStyle->GetVerticalAlign() == FDE_CSSVERTICALALIGN_Number) { - return pParaStyle->GetNumberVerticalAlign(); - } - } else if (CXFA_Font font = pTextProvider->GetFontNode()) { - return font.GetBaselineShift(); - } - return 0; -} -FX_FLOAT CXFA_TextParser::GetLineHeight(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle, - bool bFirst, - FX_FLOAT fVerScale) const { - FX_FLOAT fLineHeight = 0; - if (pStyle) { - fLineHeight = pStyle->GetParagraphStyles()->GetLineHeight(); - } else if (CXFA_Para para = pTextProvider->GetParaNode()) { - fLineHeight = para.GetLineHeight(); - } - if (bFirst) { - FX_FLOAT fFontSize = GetFontSize(pTextProvider, pStyle); - if (fLineHeight < 0.1f) { - fLineHeight = fFontSize; - } else { - fLineHeight = std::min(fLineHeight, fFontSize); - } - } else if (fLineHeight < 0.1f) { - fLineHeight = GetFontSize(pTextProvider, pStyle) * 1.2f; - } - fLineHeight *= fVerScale; - return fLineHeight; -} -bool CXFA_TextParser::GetEmbbedObj(CXFA_TextProvider* pTextProvider, - CFDE_XMLNode* pXMLNode, - CFX_WideString& wsValue) { - wsValue.clear(); - if (!pXMLNode) { - return false; - } - bool bRet = false; - if (pXMLNode->GetType() == FDE_XMLNODE_Element) { - CFDE_XMLElement* pElement = static_cast(pXMLNode); - CFX_WideString wsAttr; - pElement->GetString(L"xfa:embed", wsAttr); - if (wsAttr.IsEmpty()) { - return false; - } - if (wsAttr.GetAt(0) == L'#') { - wsAttr.Delete(0); - } - CFX_WideString ws; - pElement->GetString(L"xfa:embedType", ws); - if (ws.IsEmpty()) { - ws = L"som"; - } else { - ws.MakeLower(); - } - bool bURI = (ws == FX_WSTRC(L"uri")); - if (!bURI && ws != FX_WSTRC(L"som")) { - return false; - } - ws.clear(); - pElement->GetString(L"xfa:embedMode", ws); - if (ws.IsEmpty()) { - ws = L"formatted"; - } else { - ws.MakeLower(); - } - bool bRaw = (ws == FX_WSTRC(L"raw")); - if (!bRaw && ws != FX_WSTRC(L"formatted")) { - return false; - } - bRet = pTextProvider->GetEmbbedObj(bURI, bRaw, wsAttr, wsValue); - } - return bRet; -} - -CXFA_TextParseContext* CXFA_TextParser::GetParseContextFromMap( - CFDE_XMLNode* pXMLNode) { - auto it = m_mapXMLNodeToParseContext.find(pXMLNode); - return it != m_mapXMLNodeToParseContext.end() ? it->second : nullptr; -} - -enum XFA_TABSTOPSSTATUS { - XFA_TABSTOPSSTATUS_Error, - XFA_TABSTOPSSTATUS_EOS, - XFA_TABSTOPSSTATUS_None, - XFA_TABSTOPSSTATUS_Alignment, - XFA_TABSTOPSSTATUS_StartLeader, - XFA_TABSTOPSSTATUS_Leader, - XFA_TABSTOPSSTATUS_Location, -}; -bool CXFA_TextParser::GetTabstops(IFDE_CSSComputedStyle* pStyle, - CXFA_TextTabstopsContext* pTabstopContext) { - if (!pStyle || !pTabstopContext) { - return false; - } - CFX_WideString wsValue; - if (!pStyle->GetCustomStyle(FX_WSTRC(L"xfa-tab-stops"), wsValue) && - !pStyle->GetCustomStyle(FX_WSTRC(L"tab-stops"), wsValue)) { - return false; - } - int32_t iLength = wsValue.GetLength(); - const FX_WCHAR* pTabStops = wsValue.c_str(); - int32_t iCur = 0; - int32_t iLast = 0; - CFX_WideString wsAlign; - XFA_TABSTOPSSTATUS eStatus = XFA_TABSTOPSSTATUS_None; - FX_WCHAR ch; - while (iCur < iLength) { - ch = pTabStops[iCur]; - switch (eStatus) { - case XFA_TABSTOPSSTATUS_None: - if (ch <= ' ') { - iCur++; - } else { - eStatus = XFA_TABSTOPSSTATUS_Alignment; - iLast = iCur; - } - break; - case XFA_TABSTOPSSTATUS_Alignment: - if (ch == ' ') { - wsAlign = CFX_WideStringC(pTabStops + iLast, iCur - iLast); - eStatus = XFA_TABSTOPSSTATUS_StartLeader; - iCur++; - while (iCur < iLength && pTabStops[iCur] <= ' ') { - iCur++; - } - iLast = iCur; - } else { - iCur++; - } - break; - case XFA_TABSTOPSSTATUS_StartLeader: - if (ch != 'l') { - eStatus = XFA_TABSTOPSSTATUS_Location; - } else { - int32_t iCount = 0; - while (iCur < iLength) { - ch = pTabStops[iCur]; - iCur++; - if (ch == '(') { - iCount++; - } else if (ch == ')') { - iCount--; - if (iCount == 0) { - break; - } - } - } - while (iCur < iLength && pTabStops[iCur] <= ' ') { - iCur++; - } - iLast = iCur; - eStatus = XFA_TABSTOPSSTATUS_Location; - } - break; - case XFA_TABSTOPSSTATUS_Location: - if (ch == ' ') { - uint32_t dwHashCode = FX_HashCode_GetW(wsAlign.AsStringC(), true); - CXFA_Measurement ms(CFX_WideStringC(pTabStops + iLast, iCur - iLast)); - FX_FLOAT fPos = ms.ToUnit(XFA_UNIT_Pt); - pTabstopContext->Append(dwHashCode, fPos); - wsAlign.clear(); - eStatus = XFA_TABSTOPSSTATUS_None; - } - iCur++; - break; - default: - break; - } - } - if (!wsAlign.IsEmpty()) { - uint32_t dwHashCode = FX_HashCode_GetW(wsAlign.AsStringC(), true); - CXFA_Measurement ms(CFX_WideStringC(pTabStops + iLast, iCur - iLast)); - FX_FLOAT fPos = ms.ToUnit(XFA_UNIT_Pt); - pTabstopContext->Append(dwHashCode, fPos); - } - return true; -} - -CXFA_TextLayout::CXFA_TextLayout(CXFA_TextProvider* pTextProvider) - : m_bHasBlock(false), - m_pTextProvider(pTextProvider), - m_pTextDataNode(nullptr), - m_bRichText(false), - m_iLines(0), - m_fMaxWidth(0), - m_bBlockContinue(true) { - ASSERT(m_pTextProvider); -} - -CXFA_TextLayout::~CXFA_TextLayout() { - m_textParser.Reset(); - Unload(); -} - -void CXFA_TextLayout::Unload() { - for (int32_t i = 0; i < m_pieceLines.GetSize(); i++) { - CXFA_PieceLine* pLine = m_pieceLines.GetAt(i); - for (int32_t i = 0; i < pLine->m_textPieces.GetSize(); i++) { - XFA_TextPiece* pPiece = pLine->m_textPieces.GetAt(i); - // Release text and widths in a text piece. - m_pAllocator->Free(pPiece->pszText); - m_pAllocator->Free(pPiece->pWidths); - // Release text piece. - FXTARGET_DeleteWith(XFA_TextPiece, m_pAllocator.get(), pPiece); - } - pLine->m_textPieces.RemoveAll(); - // Release line. - FXTARGET_DeleteWith(CXFA_PieceLine, m_pAllocator.get(), pLine); - } - m_pieceLines.RemoveAll(); - m_pBreak.reset(); - m_pAllocator.reset(); -} - -const CXFA_PieceLineArray* CXFA_TextLayout::GetPieceLines() { - return &m_pieceLines; -} - -void CXFA_TextLayout::GetTextDataNode() { - if (!m_pTextProvider) { - return; - } - CXFA_Node* pNode = m_pTextProvider->GetTextNode(m_bRichText); - if (pNode && m_bRichText) { - m_textParser.Reset(); - } - m_pTextDataNode = pNode; -} -CFDE_XMLNode* CXFA_TextLayout::GetXMLContainerNode() { - CFDE_XMLNode* pXMLContainer = nullptr; - if (m_bRichText) { - CFDE_XMLNode* pXMLRoot = m_pTextDataNode->GetXMLMappingNode(); - if (!pXMLRoot) { - return pXMLContainer; - } - for (CFDE_XMLNode* pXMLChild = - pXMLRoot->GetNodeItem(CFDE_XMLNode::FirstChild); - pXMLChild; - pXMLChild = pXMLChild->GetNodeItem(CFDE_XMLNode::NextSibling)) { - if (pXMLChild->GetType() == FDE_XMLNODE_Element) { - CFDE_XMLElement* pXMLElement = static_cast(pXMLChild); - CFX_WideString wsTag; - pXMLElement->GetLocalTagName(wsTag); - if (wsTag == FX_WSTRC(L"body") || wsTag == FX_WSTRC(L"html")) { - pXMLContainer = pXMLChild; - break; - } - } - } - } - return pXMLContainer; -} -CFX_RTFBreak* CXFA_TextLayout::CreateBreak(bool bDefault) { - uint32_t dwStyle = FX_RTFLAYOUTSTYLE_ExpandTab; - if (!bDefault) { - dwStyle |= FX_RTFLAYOUTSTYLE_Pagination; - } - CFX_RTFBreak* pBreak = new CFX_RTFBreak(0); - pBreak->SetLayoutStyles(dwStyle); - pBreak->SetLineBreakChar(L'\n'); - pBreak->SetLineBreakTolerance(1); - pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr)); - pBreak->SetFontSize(m_textParser.GetFontSize(m_pTextProvider, nullptr)); - return pBreak; -} -void CXFA_TextLayout::InitBreak(FX_FLOAT fLineWidth) { - CXFA_Font font = m_pTextProvider->GetFontNode(); - CXFA_Para para = m_pTextProvider->GetParaNode(); - FX_FLOAT fStart = 0; - FX_FLOAT fStartPos = 0; - if (para) { - int32_t iAlign = FX_RTFLINEALIGNMENT_Left; - switch (para.GetHorizontalAlign()) { - case XFA_ATTRIBUTEENUM_Center: - iAlign = FX_RTFLINEALIGNMENT_Center; - break; - case XFA_ATTRIBUTEENUM_Right: - iAlign = FX_RTFLINEALIGNMENT_Right; - break; - case XFA_ATTRIBUTEENUM_Justify: - iAlign = FX_RTFLINEALIGNMENT_Justified; - break; - case XFA_ATTRIBUTEENUM_JustifyAll: - iAlign = FX_RTFLINEALIGNMENT_Distributed; - break; - } - m_pBreak->SetAlignment(iAlign); - fStart = para.GetMarginLeft(); - if (m_pTextProvider->IsCheckButtonAndAutoWidth()) { - if (iAlign != FX_RTFLINEALIGNMENT_Left) { - fLineWidth -= para.GetMarginRight(); - } - } else { - fLineWidth -= para.GetMarginRight(); - } - if (fLineWidth < 0) { - fLineWidth = fStart; - } - fStartPos = fStart; - FX_FLOAT fIndent = para.GetTextIndent(); - if (fIndent > 0) { - fStartPos += fIndent; - } - } - m_pBreak->SetLineBoundary(fStart, fLineWidth); - m_pBreak->SetLineStartPos(fStartPos); - if (font) { - m_pBreak->SetHorizontalScale((int32_t)font.GetHorizontalScale()); - m_pBreak->SetVerticalScale((int32_t)font.GetVerticalScale()); - m_pBreak->SetCharSpace(font.GetLetterSpacing()); - } - FX_FLOAT fFontSize = m_textParser.GetFontSize(m_pTextProvider, nullptr); - m_pBreak->SetFontSize(fFontSize); - m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr)); - m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f); -} -void CXFA_TextLayout::InitBreak(IFDE_CSSComputedStyle* pStyle, - FDE_CSSDISPLAY eDisplay, - FX_FLOAT fLineWidth, - CFDE_XMLNode* pXMLNode, - IFDE_CSSComputedStyle* pParentStyle) { - if (!pStyle) { - InitBreak(fLineWidth); - return; - } - IFDE_CSSParagraphStyle* pParaStyle = pStyle->GetParagraphStyles(); - if (eDisplay == FDE_CSSDISPLAY_Block || eDisplay == FDE_CSSDISPLAY_ListItem) { - int32_t iAlign = FX_RTFLINEALIGNMENT_Left; - switch (pParaStyle->GetTextAlign()) { - case FDE_CSSTEXTALIGN_Right: - iAlign = FX_RTFLINEALIGNMENT_Right; - break; - case FDE_CSSTEXTALIGN_Center: - iAlign = FX_RTFLINEALIGNMENT_Center; - break; - case FDE_CSSTEXTALIGN_Justify: - iAlign = FX_RTFLINEALIGNMENT_Justified; - break; - case FDE_CSSTEXTALIGN_JustifyAll: - iAlign = FX_RTFLINEALIGNMENT_Distributed; - break; - default: - break; - } - m_pBreak->SetAlignment(iAlign); - FX_FLOAT fStart = 0; - const FDE_CSSRECT* pRect = pStyle->GetBoundaryStyles()->GetMarginWidth(); - const FDE_CSSRECT* pPaddingRect = - pStyle->GetBoundaryStyles()->GetPaddingWidth(); - if (pRect) { - fStart = pRect->left.GetValue(); - fLineWidth -= pRect->right.GetValue(); - if (pPaddingRect) { - fStart += pPaddingRect->left.GetValue(); - fLineWidth -= pPaddingRect->right.GetValue(); - } - if (eDisplay == FDE_CSSDISPLAY_ListItem) { - const FDE_CSSRECT* pParRect = - pParentStyle->GetBoundaryStyles()->GetMarginWidth(); - const FDE_CSSRECT* pParPaddingRect = - pParentStyle->GetBoundaryStyles()->GetPaddingWidth(); - if (pParRect) { - fStart += pParRect->left.GetValue(); - fLineWidth -= pParRect->right.GetValue(); - if (pParPaddingRect) { - fStart += pParPaddingRect->left.GetValue(); - fLineWidth -= pParPaddingRect->right.GetValue(); - } - } - FDE_CSSRECT pNewRect; - pNewRect.left.Set(FDE_CSSLENGTHUNIT_Point, fStart); - pNewRect.right.Set(FDE_CSSLENGTHUNIT_Point, pRect->right.GetValue()); - pNewRect.top.Set(FDE_CSSLENGTHUNIT_Point, pRect->top.GetValue()); - pNewRect.bottom.Set(FDE_CSSLENGTHUNIT_Point, pRect->bottom.GetValue()); - pStyle->GetBoundaryStyles()->SetMarginWidth(pNewRect); - } - } - m_pBreak->SetLineBoundary(fStart, fLineWidth); - FX_FLOAT fIndent = pParaStyle->GetTextIndent().GetValue(); - if (fIndent > 0) { - fStart += fIndent; - } - m_pBreak->SetLineStartPos(fStart); - m_pBreak->SetTabWidth(m_textParser.GetTabInterval(pStyle)); - if (!m_pTabstopContext) - m_pTabstopContext = pdfium::MakeUnique(); - m_textParser.GetTabstops(pStyle, m_pTabstopContext.get()); - for (int32_t i = 0; i < m_pTabstopContext->m_iTabCount; i++) { - XFA_TABSTOPS* pTab = m_pTabstopContext->m_tabstops.GetDataPtr(i); - m_pBreak->AddPositionedTab(pTab->fTabstops); - } - } - FX_FLOAT fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle); - m_pBreak->SetFontSize(fFontSize); - m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f); - m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, pStyle)); - m_pBreak->SetHorizontalScale( - m_textParser.GetHorScale(m_pTextProvider, pStyle, pXMLNode)); - m_pBreak->SetVerticalScale(m_textParser.GetVerScale(m_pTextProvider, pStyle)); - m_pBreak->SetCharSpace(pParaStyle->GetLetterSpacing().GetValue()); -} -int32_t CXFA_TextLayout::GetText(CFX_WideString& wsText) { - GetTextDataNode(); - wsText.clear(); - if (m_bRichText) { - } else { - wsText = m_pTextDataNode->GetContent(); - } - return wsText.GetLength(); -} -FX_FLOAT CXFA_TextLayout::GetLayoutHeight() { - if (!m_pLoader) { - return 0; - } - int32_t iCount = m_pLoader->m_lineHeights.GetSize(); - if (iCount == 0 && m_pLoader->m_fWidth > 0) { - CFX_SizeF szMax(m_pLoader->m_fWidth, m_pLoader->m_fHeight); - CFX_SizeF szDef; - m_pLoader->m_bSaveLineHeight = true; - m_pLoader->m_fLastPos = 0; - CalcSize(szMax, szMax, szDef); - m_pLoader->m_bSaveLineHeight = false; - return szDef.y; - } - FX_FLOAT fHeight = m_pLoader->m_fHeight; - if (fHeight < 0.1f) { - fHeight = 0; - for (int32_t i = 0; i < iCount; i++) { - fHeight += m_pLoader->m_lineHeights.ElementAt(i); - } - } - return fHeight; -} -FX_FLOAT CXFA_TextLayout::StartLayout(FX_FLOAT fWidth) { - if (!m_pLoader) - m_pLoader = pdfium::MakeUnique(); - - if (fWidth < 0 || (m_pLoader->m_fWidth > -1 && - FXSYS_fabs(fWidth - m_pLoader->m_fWidth) > 0)) { - m_pLoader->m_lineHeights.RemoveAll(); - m_Blocks.RemoveAll(); - Unload(); - m_pLoader->m_fStartLineOffset = 0; - } - m_pLoader->m_fWidth = fWidth; - if (fWidth < 0) { - CFX_SizeF szMax; - CFX_SizeF szDef; - m_pLoader->m_bSaveLineHeight = true; - m_pLoader->m_fLastPos = 0; - CalcSize(szMax, szMax, szDef); - m_pLoader->m_bSaveLineHeight = false; - fWidth = szDef.x; - } - return fWidth; -} -bool CXFA_TextLayout::DoLayout(int32_t iBlockIndex, - FX_FLOAT& fCalcHeight, - FX_FLOAT fContentAreaHeight, - FX_FLOAT fTextHeight) { - if (!m_pLoader) { - return false; - } - int32_t iBlockCount = m_Blocks.GetSize(); - FX_FLOAT fHeight = fTextHeight; - if (fHeight < 0) { - fHeight = GetLayoutHeight(); - } - m_pLoader->m_fHeight = fHeight; - if (fContentAreaHeight < 0) { - return false; - } - m_bHasBlock = true; - if (iBlockCount == 0 && fHeight > 0) { - fHeight = fTextHeight - GetLayoutHeight(); - if (fHeight > 0) { - int32_t iAlign = m_textParser.GetVAlign(m_pTextProvider); - if (iAlign == XFA_ATTRIBUTEENUM_Middle) { - fHeight /= 2.0f; - } else if (iAlign != XFA_ATTRIBUTEENUM_Bottom) { - fHeight = 0; - } - m_pLoader->m_fStartLineOffset = fHeight; - } - } - FX_FLOAT fLinePos = m_pLoader->m_fStartLineOffset; - int32_t iLineIndex = 0; - if (iBlockCount > 1) { - if (iBlockCount >= (iBlockIndex + 1) * 2) { - iLineIndex = m_Blocks.ElementAt(iBlockIndex * 2); - } else { - iLineIndex = m_Blocks.ElementAt(iBlockCount - 1) + - m_Blocks.ElementAt(iBlockCount - 2); - } - if (!m_pLoader->m_BlocksHeight.empty()) { - for (int32_t i = 0; i < iBlockIndex; i++) - fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1]; - } - } - int32_t iCount = m_pLoader->m_lineHeights.GetSize(); - int32_t i = 0; - for (i = iLineIndex; i < iCount; i++) { - FX_FLOAT fLineHeight = m_pLoader->m_lineHeights.ElementAt(i); - if ((i == iLineIndex) && (fLineHeight - fContentAreaHeight > 0.001)) { - fCalcHeight = 0; - return true; - } - if (fLinePos + fLineHeight - fContentAreaHeight > 0.001) { - if (iBlockCount >= (iBlockIndex + 1) * 2) { - m_Blocks.SetAt(iBlockIndex * 2, iLineIndex); - m_Blocks.SetAt(iBlockIndex * 2 + 1, i - iLineIndex); - } else { - m_Blocks.Add(iLineIndex); - m_Blocks.Add(i - iLineIndex); - } - if (i == iLineIndex) { - if (fCalcHeight <= fLinePos) { - if (pdfium::CollectionSize(m_pLoader->m_BlocksHeight) > - iBlockIndex * 2 && - (m_pLoader->m_BlocksHeight[iBlockIndex * 2] == iBlockIndex)) { - m_pLoader->m_BlocksHeight[iBlockIndex * 2 + 1] = fCalcHeight; - } else { - m_pLoader->m_BlocksHeight.push_back((FX_FLOAT)iBlockIndex); - m_pLoader->m_BlocksHeight.push_back(fCalcHeight); - } - } - return true; - } - fCalcHeight = fLinePos; - return true; - } - fLinePos += fLineHeight; - } - return false; -} -int32_t CXFA_TextLayout::CountBlocks() const { - int32_t iCount = m_Blocks.GetSize() / 2; - return iCount > 0 ? iCount : 1; -} - -bool CXFA_TextLayout::CalcSize(const CFX_SizeF& minSize, - const CFX_SizeF& maxSize, - CFX_SizeF& defaultSize) { - defaultSize.x = maxSize.x; - if (defaultSize.x < 1) - defaultSize.x = 0xFFFF; - - m_pBreak.reset(CreateBreak(false)); - FX_FLOAT fLinePos = 0; - m_iLines = 0; - m_fMaxWidth = 0; - Loader(defaultSize, fLinePos, false); - if (fLinePos < 0.1f) - fLinePos = m_textParser.GetFontSize(m_pTextProvider, nullptr); - - m_pTabstopContext.reset(); - defaultSize = CFX_SizeF(m_fMaxWidth, fLinePos); - return true; -} - -bool CXFA_TextLayout::Layout(const CFX_SizeF& size, FX_FLOAT* fHeight) { - if (size.x < 1) - return false; - - Unload(); - m_pBreak.reset(CreateBreak(true)); - if (m_pLoader) { - m_pLoader->m_iTotalLines = -1; - m_pLoader->m_iChar = 0; - } - m_iLines = 0; - FX_FLOAT fLinePos = 0; - Loader(size, fLinePos, true); - UpdateAlign(size.y, fLinePos); - m_pTabstopContext.reset(); - if (fHeight) - *fHeight = fLinePos; - return true; -} - -bool CXFA_TextLayout::Layout(int32_t iBlock) { - if (!m_pLoader || iBlock < 0 || iBlock >= CountBlocks()) - return false; - if (m_pLoader->m_fWidth < 1) - return false; - - m_pLoader->m_iTotalLines = -1; - m_iLines = 0; - FX_FLOAT fLinePos = 0; - CXFA_Node* pNode = nullptr; - CFX_SizeF szText(m_pLoader->m_fWidth, m_pLoader->m_fHeight); - int32_t iCount = m_Blocks.GetSize(); - int32_t iBlocksHeightCount = - pdfium::CollectionSize(m_pLoader->m_BlocksHeight); - iBlocksHeightCount /= 2; - if (iBlock < iBlocksHeightCount) - return true; - if (iBlock == iBlocksHeightCount) { - Unload(); - m_pBreak.reset(CreateBreak(true)); - fLinePos = m_pLoader->m_fStartLineOffset; - for (int32_t i = 0; i < iBlocksHeightCount; i++) { - fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1]; - } - m_pLoader->m_iChar = 0; - if (iCount > 1) - m_pLoader->m_iTotalLines = m_Blocks.ElementAt(iBlock * 2 + 1); - Loader(szText, fLinePos, true); - if (iCount == 0 && m_pLoader->m_fStartLineOffset < 0.1f) - UpdateAlign(szText.y, fLinePos); - } else if (m_pTextDataNode) { - iBlock *= 2; - if (iBlock < iCount - 2) - m_pLoader->m_iTotalLines = m_Blocks.ElementAt(iBlock + 1); - m_pBreak->Reset(); - if (m_bRichText) { - CFDE_XMLNode* pContainerNode = GetXMLContainerNode(); - if (!pContainerNode) { - return true; - } - CFDE_XMLNode* pXMLNode = m_pLoader->m_pXMLNode; - if (!pXMLNode) - return true; - CFDE_XMLNode* pSaveXMLNode = m_pLoader->m_pXMLNode; - for (; pXMLNode; - pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) { - if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle, - true)) { - break; - } - } - while (!pXMLNode) { - pXMLNode = pSaveXMLNode->GetNodeItem(CFDE_XMLNode::Parent); - if (pXMLNode == pContainerNode) - break; - if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle, - true, nullptr, false)) { - break; - } - pSaveXMLNode = pXMLNode; - pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling); - if (!pXMLNode) - continue; - for (; pXMLNode; - pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) { - if (!LoadRichText(pXMLNode, szText, fLinePos, - m_pLoader->m_pParentStyle, true)) { - break; - } - } - } - } else { - pNode = m_pLoader->m_pNode; - if (!pNode) - return true; - LoadText(pNode, szText, fLinePos, true); - } - } - if (iBlock == iCount) { - m_pTabstopContext.reset(); - m_pLoader.reset(); - } - return true; -} -void CXFA_TextLayout::ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex) { - if (!m_pLoader) { - return; - } - int32_t iCountHeight = m_pLoader->m_lineHeights.GetSize(); - if (iCountHeight == 0) { - return; - } - bool bEndItem = true; - int32_t iBlockCount = m_Blocks.GetSize(); - FX_FLOAT fLinePos = m_pLoader->m_fStartLineOffset; - int32_t iLineIndex = 0; - if (iBlockIndex > 0) { - int32_t iBlockHeightCount = - pdfium::CollectionSize(m_pLoader->m_BlocksHeight); - iBlockHeightCount /= 2; - if (iBlockHeightCount >= iBlockIndex) { - for (int32_t i = 0; i < iBlockIndex; i++) { - fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1]; - } - } else { - fLinePos = 0; - } - iLineIndex = m_Blocks[iBlockCount - 1] + m_Blocks[iBlockCount - 2]; - } - int32_t i = 0; - for (i = iLineIndex; i < iCountHeight; i++) { - FX_FLOAT fLineHeight = m_pLoader->m_lineHeights.ElementAt(i); - if (fLinePos + fLineHeight - rtText.height > 0.001) { - m_Blocks.Add(iLineIndex); - m_Blocks.Add(i - iLineIndex); - bEndItem = false; - break; - } - fLinePos += fLineHeight; - } - if (iCountHeight > 0 && (i - iLineIndex) > 0 && bEndItem) { - m_Blocks.Add(iLineIndex); - m_Blocks.Add(i - iLineIndex); - } -} -bool CXFA_TextLayout::DrawString(CFX_RenderDevice* pFxDevice, - const CFX_Matrix& tmDoc2Device, - const CFX_RectF& rtClip, - int32_t iBlock) { - if (!pFxDevice) - return false; - - std::unique_ptr pDevice( - new CFDE_RenderDevice(pFxDevice, false)); - pDevice->SaveState(); - pDevice->SetClipRect(rtClip); - - std::unique_ptr pSolidBrush(new CFDE_Brush); - std::unique_ptr pPen(new CFDE_Pen); - if (m_pieceLines.GetSize() == 0) { - int32_t iBlockCount = CountBlocks(); - for (int32_t i = 0; i < iBlockCount; i++) { - Layout(i); - } - } - FXTEXT_CHARPOS* pCharPos = nullptr; - int32_t iCharCount = 0; - int32_t iLineStart = 0; - int32_t iPieceLines = m_pieceLines.GetSize(); - int32_t iCount = m_Blocks.GetSize(); - if (iCount > 0) { - iBlock *= 2; - if (iBlock < iCount) { - iLineStart = m_Blocks.ElementAt(iBlock); - iPieceLines = m_Blocks.ElementAt(iBlock + 1); - } else { - iPieceLines = 0; - } - } - for (int32_t i = 0; i < iPieceLines; i++) { - if (i + iLineStart >= m_pieceLines.GetSize()) { - break; - } - CXFA_PieceLine* pPieceLine = m_pieceLines.GetAt(i + iLineStart); - int32_t iPieces = pPieceLine->m_textPieces.GetSize(); - int32_t j = 0; - for (j = 0; j < iPieces; j++) { - const XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(j); - int32_t iChars = pPiece->iChars; - if (iCharCount < iChars) { - FX_Free(pCharPos); - pCharPos = FX_Alloc(FXTEXT_CHARPOS, iChars); - iCharCount = iChars; - } - FXSYS_memset(pCharPos, 0, iCharCount * sizeof(FXTEXT_CHARPOS)); - RenderString(pDevice.get(), pSolidBrush.get(), pPieceLine, j, pCharPos, - tmDoc2Device); - } - for (j = 0; j < iPieces; j++) { - RenderPath(pDevice.get(), pPen.get(), pPieceLine, j, pCharPos, - tmDoc2Device); - } - } - pDevice->RestoreState(); - FX_Free(pCharPos); - return iPieceLines > 0; -} -void CXFA_TextLayout::UpdateAlign(FX_FLOAT fHeight, FX_FLOAT fBottom) { - fHeight -= fBottom; - if (fHeight < 0.1f) { - return; - } - switch (m_textParser.GetVAlign(m_pTextProvider)) { - case XFA_ATTRIBUTEENUM_Middle: - fHeight /= 2.0f; - break; - case XFA_ATTRIBUTEENUM_Bottom: - break; - default: - return; - } - int32_t iCount = m_pieceLines.GetSize(); - for (int32_t i = 0; i < iCount; i++) { - CXFA_PieceLine* pPieceLine = m_pieceLines.GetAt(i); - int32_t iPieces = pPieceLine->m_textPieces.GetSize(); - for (int32_t j = 0; j < iPieces; j++) { - XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(j); - CFX_RectF& rect = pPiece->rtPiece; - rect.top += fHeight; - } - } -} -bool CXFA_TextLayout::Loader(const CFX_SizeF& szText, - FX_FLOAT& fLinePos, - bool bSavePieces) { - if (!m_pAllocator) { - m_pAllocator = IFX_MemoryAllocator::Create(FX_ALLOCTYPE_Static, 256, 0); - } - GetTextDataNode(); - if (!m_pTextDataNode) - return true; - - if (m_bRichText) { - CFDE_XMLNode* pXMLContainer = GetXMLContainerNode(); - if (pXMLContainer) { - if (!m_textParser.IsParsed()) { - m_textParser.DoParse(pXMLContainer, m_pTextProvider); - } - IFDE_CSSComputedStyle* pRootStyle = - m_textParser.CreateRootStyle(m_pTextProvider); - LoadRichText(pXMLContainer, szText, fLinePos, pRootStyle, bSavePieces); - pRootStyle->Release(); - } - } else { - LoadText(m_pTextDataNode, szText, fLinePos, bSavePieces); - } - return true; -} -void CXFA_TextLayout::LoadText(CXFA_Node* pNode, - const CFX_SizeF& szText, - FX_FLOAT& fLinePos, - bool bSavePieces) { - InitBreak(szText.x); - CXFA_Para para = m_pTextProvider->GetParaNode(); - FX_FLOAT fSpaceAbove = 0; - if (para) { - fSpaceAbove = para.GetSpaceAbove(); - if (fSpaceAbove < 0.1f) { - fSpaceAbove = 0; - } - int32_t verAlign = para.GetVerticalAlign(); - switch (verAlign) { - case XFA_ATTRIBUTEENUM_Top: - case XFA_ATTRIBUTEENUM_Middle: - case XFA_ATTRIBUTEENUM_Bottom: { - fLinePos += fSpaceAbove; - break; - } - } - } - CFX_WideString wsText = pNode->GetContent(); - wsText.TrimRight(L" "); - bool bRet = AppendChar(wsText, fLinePos, fSpaceAbove, bSavePieces); - if (bRet && m_pLoader) { - m_pLoader->m_pNode = pNode; - } else { - EndBreak(FX_RTFBREAK_ParagraphBreak, fLinePos, bSavePieces); - } -} -bool CXFA_TextLayout::LoadRichText(CFDE_XMLNode* pXMLNode, - const CFX_SizeF& szText, - FX_FLOAT& fLinePos, - IFDE_CSSComputedStyle* pParentStyle, - bool bSavePieces, - CXFA_LinkUserData* pLinkData, - bool bEndBreak, - bool bIsOl, - int32_t iLiCount) { - if (!pXMLNode) { - return false; - } - CXFA_TextParseContext* pContext = - m_textParser.GetParseContextFromMap(pXMLNode); - FDE_CSSDISPLAY eDisplay = FDE_CSSDISPLAY_None; - bool bContentNode = false; - FX_FLOAT fSpaceBelow = 0; - IFDE_CSSComputedStyle* pStyle = nullptr; - CFX_WideString wsName; - if (bEndBreak) { - bool bCurOl = false; - bool bCurLi = false; - CFDE_XMLElement* pElement = nullptr; - if (pContext) { - if (m_bBlockContinue || - (m_pLoader && pXMLNode == m_pLoader->m_pXMLNode)) { - m_bBlockContinue = true; - } - if (pXMLNode->GetType() == FDE_XMLNODE_Text) { - bContentNode = true; - } else if (pXMLNode->GetType() == FDE_XMLNODE_Element) { - pElement = static_cast(pXMLNode); - pElement->GetLocalTagName(wsName); - } - if (wsName == FX_WSTRC(L"ol")) { - bIsOl = true; - bCurOl = true; - } - if (m_bBlockContinue || bContentNode == false) { - eDisplay = pContext->GetDisplay(); - if (eDisplay != FDE_CSSDISPLAY_Block && - eDisplay != FDE_CSSDISPLAY_Inline && - eDisplay != FDE_CSSDISPLAY_ListItem) { - return true; - } - pStyle = m_textParser.ComputeStyle(pXMLNode, pParentStyle); - InitBreak(bContentNode ? pParentStyle : pStyle, eDisplay, szText.x, - pXMLNode, pParentStyle); - if ((eDisplay == FDE_CSSDISPLAY_Block || - eDisplay == FDE_CSSDISPLAY_ListItem) && - pStyle && - (wsName.IsEmpty() || - (wsName != FX_WSTRC(L"body") && wsName != FX_WSTRC(L"html") && - wsName != FX_WSTRC(L"ol") && wsName != FX_WSTRC(L"ul")))) { - const FDE_CSSRECT* pRect = - pStyle->GetBoundaryStyles()->GetMarginWidth(); - if (pRect) { - fLinePos += pRect->top.GetValue(); - fSpaceBelow = pRect->bottom.GetValue(); - } - } - if (wsName == FX_WSTRC(L"a")) { - CFX_WideString wsLinkContent; - ASSERT(pElement); - pElement->GetString(L"href", wsLinkContent); - if (!wsLinkContent.IsEmpty()) { - pLinkData = FXTARGET_NewWith(m_pAllocator.get()) CXFA_LinkUserData( - m_pAllocator.get(), - wsLinkContent.GetBuffer(wsLinkContent.GetLength())); - wsLinkContent.ReleaseBuffer(wsLinkContent.GetLength()); - } - } - int32_t iTabCount = - m_textParser.CountTabs(bContentNode ? pParentStyle : pStyle); - bool bSpaceRun = - m_textParser.IsSpaceRun(bContentNode ? pParentStyle : pStyle); - CFX_WideString wsText; - if (bContentNode && iTabCount == 0) { - static_cast(pXMLNode)->GetText(wsText); - } else if (wsName == FX_WSTRC(L"br")) { - wsText = L'\n'; - } else if (wsName == FX_WSTRC(L"li")) { - bCurLi = true; - if (bIsOl) { - wsText.Format(L"%d. ", iLiCount); - } else { - wsText = 0x00B7 + FX_WSTRC(L" "); - } - } else if (!bContentNode) { - if (iTabCount > 0) { - while (iTabCount-- > 0) - wsText += L'\t'; - } else { - m_textParser.GetEmbbedObj(m_pTextProvider, pXMLNode, wsText); - } - } - int32_t iLength = wsText.GetLength(); - if (iLength > 0 && bContentNode && !bSpaceRun) { - ProcessText(wsText); - } - if (m_pLoader) { - if (wsText.GetLength() > 0 && - (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) { - wsText.TrimLeft(0x20); - } - if (FDE_CSSDISPLAY_Block == eDisplay) { - m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE; - } else if (FDE_CSSDISPLAY_Inline == eDisplay && - (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) { - m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE; - } else if (wsText.GetLength() > 0 && - (0x20 == wsText.GetAt(wsText.GetLength() - 1))) { - m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE; - } else if (wsText.GetLength() != 0) { - m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE; - } - } - if (wsText.GetLength() > 0) { - if (!m_pLoader || m_pLoader->m_iChar == 0) { - if (pLinkData) { - pLinkData->Retain(); - } - CXFA_TextUserData* pUserData = FXTARGET_NewWith(m_pAllocator.get()) - CXFA_TextUserData(m_pAllocator.get(), - bContentNode ? pParentStyle : pStyle, - pLinkData); - m_pBreak->SetUserData(pUserData); - } - if (AppendChar(wsText, fLinePos, 0, bSavePieces)) { - if (m_pLoader) { - m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE; - } - if (IsEnd(bSavePieces)) { - if (m_pLoader && m_pLoader->m_iTotalLines > -1) { - m_pLoader->m_pXMLNode = pXMLNode; - m_pLoader->m_pParentStyle = pParentStyle; - } - if (pStyle) - pStyle->Release(); - return false; - } - return true; - } - } - } - } - bool ret = true; - for (CFDE_XMLNode* pChildNode = - pXMLNode->GetNodeItem(CFDE_XMLNode::FirstChild); - pChildNode; - pChildNode = pChildNode->GetNodeItem(CFDE_XMLNode::NextSibling)) { - if (bCurOl) { - iLiCount++; - } - ret = LoadRichText(pChildNode, szText, fLinePos, - pContext ? pStyle : pParentStyle, bSavePieces, - pLinkData, true, bIsOl, iLiCount); - if (ret == false) { - return false; - } - } - if (m_pLoader) { - if (FDE_CSSDISPLAY_Block == eDisplay) { - m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE; - } - } - if (bCurLi) { - EndBreak(FX_RTFBREAK_LineBreak, fLinePos, bSavePieces); - } - } else { - if (pContext) { - eDisplay = pContext->GetDisplay(); - } - } - if (m_bBlockContinue) { - if (pContext && !bContentNode) { - uint32_t dwStatus = (eDisplay == FDE_CSSDISPLAY_Block) - ? FX_RTFBREAK_ParagraphBreak - : FX_RTFBREAK_PieceBreak; - EndBreak(dwStatus, fLinePos, bSavePieces); - if (eDisplay == FDE_CSSDISPLAY_Block) { - fLinePos += fSpaceBelow; - if (m_pTabstopContext) { - m_pTabstopContext->RemoveAll(); - } - } - if (wsName == FX_WSTRC(L"a")) { - if (pLinkData) { - pLinkData->Release(); - pLinkData = nullptr; - } - } - if (IsEnd(bSavePieces)) { - if (pStyle) { - pStyle->Release(); - } - if (m_pLoader && m_pLoader->m_iTotalLines > -1) { - m_pLoader->m_pXMLNode = - pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling); - m_pLoader->m_pParentStyle = pParentStyle; - } - return false; - } - } - } - if (pStyle) - pStyle->Release(); - return true; -} -bool CXFA_TextLayout::AppendChar(const CFX_WideString& wsText, - FX_FLOAT& fLinePos, - FX_FLOAT fSpaceAbove, - bool bSavePieces) { - uint32_t dwStatus = 0; - int32_t iChar = 0; - if (m_pLoader) { - iChar = m_pLoader->m_iChar; - } - int32_t iLength = wsText.GetLength(); - for (int32_t i = iChar; i < iLength; i++) { - FX_WCHAR wch = wsText.GetAt(i); - if (wch == 0xA0) { - wch = 0x20; - } - if ((dwStatus = m_pBreak->AppendChar(wch)) > FX_RTFBREAK_PieceBreak) { - AppendTextLine(dwStatus, fLinePos, bSavePieces); - if (IsEnd(bSavePieces)) { - if (m_pLoader) - m_pLoader->m_iChar = i; - return true; - } - if (dwStatus == FX_RTFBREAK_ParagraphBreak && m_bRichText) { - fLinePos += fSpaceAbove; - } - } - } - if (m_pLoader) { - m_pLoader->m_iChar = 0; - } - return false; -} -bool CXFA_TextLayout::IsEnd(bool bSavePieces) { - if (!bSavePieces) { - return false; - } - if (m_pLoader && m_pLoader->m_iTotalLines > 0) { - return m_iLines >= m_pLoader->m_iTotalLines; - } - return false; -} -void CXFA_TextLayout::ProcessText(CFX_WideString& wsText) { - int32_t iLen = wsText.GetLength(); - if (iLen == 0) { - return; - } - FX_WCHAR* psz = wsText.GetBuffer(iLen); - int32_t iTrimLeft = 0; - FX_WCHAR wch = 0, wPrev = 0; - for (int32_t i = 0; i < iLen; i++) { - wch = psz[i]; - if (wch < 0x20) { - wch = 0x20; - } - if (wch == 0x20 && wPrev == 0x20) { - continue; - } - wPrev = wch; - psz[iTrimLeft++] = wch; - } - wsText.ReleaseBuffer(iLen); - wsText = wsText.Left(iTrimLeft); -} -void CXFA_TextLayout::EndBreak(uint32_t dwStatus, - FX_FLOAT& fLinePos, - bool bSavePieces) { - dwStatus = m_pBreak->EndBreak(dwStatus); - if (dwStatus > FX_RTFBREAK_PieceBreak) { - AppendTextLine(dwStatus, fLinePos, bSavePieces, true); - } -} -void CXFA_TextLayout::DoTabstops(IFDE_CSSComputedStyle* pStyle, - CXFA_PieceLine* pPieceLine) { - if (!m_pTabstopContext || m_pTabstopContext->m_iTabCount == 0) { - return; - } - if (!pStyle || !pPieceLine) { - return; - } - int32_t iPieces = pPieceLine->m_textPieces.GetSize(); - if (iPieces == 0) { - return; - } - XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(iPieces - 1); - int32_t& iTabstopsIndex = m_pTabstopContext->m_iTabIndex; - int32_t iCount = m_textParser.CountTabs(pStyle); - if (iTabstopsIndex > m_pTabstopContext->m_iTabCount - 1) { - return; - } - if (iCount > 0) { - iTabstopsIndex++; - m_pTabstopContext->m_bTabstops = true; - FX_FLOAT fRight = 0; - if (iPieces > 1) { - XFA_TextPiece* p = pPieceLine->m_textPieces.GetAt(iPieces - 2); - fRight = p->rtPiece.right(); - } - m_pTabstopContext->m_fTabWidth = - pPiece->rtPiece.width + pPiece->rtPiece.left - fRight; - } else if (iTabstopsIndex > -1) { - FX_FLOAT fLeft = 0; - if (m_pTabstopContext->m_bTabstops) { - XFA_TABSTOPS* pTabstops = - m_pTabstopContext->m_tabstops.GetDataPtr(iTabstopsIndex); - uint32_t dwAlign = pTabstops->dwAlign; - if (dwAlign == FX_HashCode_GetW(L"center", false)) { - fLeft = pPiece->rtPiece.width / 2.0f; - } else if (dwAlign == FX_HashCode_GetW(L"right", false) || - dwAlign == FX_HashCode_GetW(L"before", false)) { - fLeft = pPiece->rtPiece.width; - } else if (dwAlign == FX_HashCode_GetW(L"decimal", false)) { - int32_t iChars = pPiece->iChars; - for (int32_t i = 0; i < iChars; i++) { - if (pPiece->pszText[i] == L'.') { - break; - } - fLeft += pPiece->pWidths[i] / 20000.0f; - } - } - m_pTabstopContext->m_fLeft = - std::min(fLeft, m_pTabstopContext->m_fTabWidth); - m_pTabstopContext->m_bTabstops = false; - m_pTabstopContext->m_fTabWidth = 0; - } - pPiece->rtPiece.left -= m_pTabstopContext->m_fLeft; - } -} -void CXFA_TextLayout::AppendTextLine(uint32_t dwStatus, - FX_FLOAT& fLinePos, - bool bSavePieces, - bool bEndBreak) { - int32_t iPieces = m_pBreak->CountBreakPieces(); - if (iPieces < 1) { - return; - } - IFDE_CSSComputedStyle* pStyle = nullptr; - if (bSavePieces) { - CXFA_PieceLine* pPieceLine = - FXTARGET_NewWith(m_pAllocator.get()) CXFA_PieceLine; - m_pieceLines.Add(pPieceLine); - if (m_pTabstopContext) { - m_pTabstopContext->Reset(); - } - FX_FLOAT fLineStep = 0, fBaseLine = 0; - int32_t i = 0; - for (i = 0; i < iPieces; i++) { - const CFX_RTFPiece* pPiece = m_pBreak->GetBreakPiece(i); - CXFA_TextUserData* pUserData = (CXFA_TextUserData*)pPiece->m_pUserData; - if (pUserData) - pStyle = pUserData->m_pStyle; - FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f; - XFA_TextPiece* pTP = FXTARGET_NewWith(m_pAllocator.get()) XFA_TextPiece(); - pTP->pszText = - (FX_WCHAR*)m_pAllocator->Alloc(pPiece->m_iChars * sizeof(FX_WCHAR)); - pTP->pWidths = - (int32_t*)m_pAllocator->Alloc(pPiece->m_iChars * sizeof(int32_t)); - pTP->iChars = pPiece->m_iChars; - pPiece->GetString(pTP->pszText); - pPiece->GetWidths(pTP->pWidths); - pTP->iBidiLevel = pPiece->m_iBidiLevel; - pTP->iHorScale = pPiece->m_iHorizontalScale; - pTP->iVerScale = pPiece->m_iVerticalScale; - m_textParser.GetUnderline(m_pTextProvider, pStyle, pTP->iUnderline, - pTP->iPeriod); - m_textParser.GetLinethrough(m_pTextProvider, pStyle, pTP->iLineThrough); - pTP->dwColor = m_textParser.GetColor(m_pTextProvider, pStyle); - pTP->pFont = m_textParser.GetFont(m_pTextProvider, pStyle); - pTP->fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle); - pTP->rtPiece.left = pPiece->m_iStartPos / 20000.0f; - pTP->rtPiece.width = pPiece->m_iWidth / 20000.0f; - pTP->rtPiece.height = (FX_FLOAT)pPiece->m_iFontSize * fVerScale / 20.0f; - FX_FLOAT fBaseLineTemp = - m_textParser.GetBaseline(m_pTextProvider, pStyle); - pTP->rtPiece.top = fBaseLineTemp; - pPieceLine->m_textPieces.Add(pTP); - FX_FLOAT fLineHeight = m_textParser.GetLineHeight( - m_pTextProvider, pStyle, m_iLines == 0, fVerScale); - if (fBaseLineTemp > 0) { - FX_FLOAT fLineHeightTmp = fBaseLineTemp + pTP->rtPiece.height; - if (fLineHeight < fLineHeightTmp) { - fLineHeight = fLineHeightTmp; - } else { - fBaseLineTemp = 0; - } - } else if (fBaseLine < -fBaseLineTemp) { - fBaseLine = -fBaseLineTemp; - } - fLineStep = std::max(fLineStep, fLineHeight); - if (pUserData && pUserData->m_pLinkData) { - pUserData->m_pLinkData->Retain(); - pTP->pLinkData = pUserData->m_pLinkData; - } else { - pTP->pLinkData = nullptr; - } - DoTabstops(pStyle, pPieceLine); - } - for (i = 0; i < iPieces; i++) { - XFA_TextPiece* pTP = pPieceLine->m_textPieces.GetAt(i); - FX_FLOAT& fTop = pTP->rtPiece.top; - FX_FLOAT fBaseLineTemp = fTop; - fTop = fLinePos + fLineStep - pTP->rtPiece.height - fBaseLineTemp; - fTop = std::max(0.0f, fTop); - } - fLinePos += fLineStep + fBaseLine; - } else { - FX_FLOAT fLineStep = 0; - FX_FLOAT fLineWidth = 0; - for (int32_t i = 0; i < iPieces; i++) { - const CFX_RTFPiece* pPiece = m_pBreak->GetBreakPiece(i); - CXFA_TextUserData* pUserData = (CXFA_TextUserData*)pPiece->m_pUserData; - if (pUserData) - pStyle = pUserData->m_pStyle; - FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f; - FX_FLOAT fBaseLine = m_textParser.GetBaseline(m_pTextProvider, pStyle); - FX_FLOAT fLineHeight = m_textParser.GetLineHeight( - m_pTextProvider, pStyle, m_iLines == 0, fVerScale); - if (fBaseLine > 0) { - FX_FLOAT fLineHeightTmp = - fBaseLine + (FX_FLOAT)pPiece->m_iFontSize * fVerScale / 20.0f; - if (fLineHeight < fLineHeightTmp) { - fLineHeight = fLineHeightTmp; - } - } - fLineStep = std::max(fLineStep, fLineHeight); - fLineWidth += pPiece->m_iWidth / 20000.0f; - } - fLinePos += fLineStep; - m_fMaxWidth = std::max(m_fMaxWidth, fLineWidth); - if (m_pLoader && m_pLoader->m_bSaveLineHeight) { - FX_FLOAT fHeight = fLinePos - m_pLoader->m_fLastPos; - m_pLoader->m_fLastPos = fLinePos; - m_pLoader->m_lineHeights.Add(fHeight); - } - } - if (pStyle) { - pStyle->Retain(); - } - m_pBreak->ClearBreakPieces(); - if (dwStatus == FX_RTFBREAK_ParagraphBreak) { - m_pBreak->Reset(); - if (!pStyle && bEndBreak) { - CXFA_Para para = m_pTextProvider->GetParaNode(); - if (para) { - FX_FLOAT fStartPos = para.GetMarginLeft(); - FX_FLOAT fIndent = para.GetTextIndent(); - if (fIndent > 0) { - fStartPos += fIndent; - } - FX_FLOAT fSpaceBelow = para.GetSpaceBelow(); - if (fSpaceBelow < 0.1f) { - fSpaceBelow = 0; - } - m_pBreak->SetLineStartPos(fStartPos); - fLinePos += fSpaceBelow; - } - } - } - if (pStyle) { - FX_FLOAT fStart = 0; - const FDE_CSSRECT* pRect = pStyle->GetBoundaryStyles()->GetMarginWidth(); - if (pRect) { - fStart = pRect->left.GetValue(); - } - FX_FLOAT fTextIndent = - pStyle->GetParagraphStyles()->GetTextIndent().GetValue(); - if (fTextIndent < 0) { - fStart -= fTextIndent; - } - m_pBreak->SetLineStartPos(fStart); - pStyle->Release(); - } - m_iLines++; -} -void CXFA_TextLayout::RenderString(CFDE_RenderDevice* pDevice, - CFDE_Brush* pBrush, - CXFA_PieceLine* pPieceLine, - int32_t iPiece, - FXTEXT_CHARPOS* pCharPos, - const CFX_Matrix& tmDoc2Device) { - const XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(iPiece); - int32_t iCount = GetDisplayPos(pPiece, pCharPos); - if (iCount > 0) { - pBrush->SetColor(pPiece->dwColor); - pDevice->DrawString(pBrush, pPiece->pFont, pCharPos, iCount, - pPiece->fFontSize, &tmDoc2Device); - } - pPieceLine->m_charCounts.Add(iCount); -} - -void CXFA_TextLayout::RenderPath(CFDE_RenderDevice* pDevice, - CFDE_Pen* pPen, - CXFA_PieceLine* pPieceLine, - int32_t iPiece, - FXTEXT_CHARPOS* pCharPos, - const CFX_Matrix& tmDoc2Device) { - XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(iPiece); - bool bNoUnderline = pPiece->iUnderline < 1 || pPiece->iUnderline > 2; - bool bNoLineThrough = pPiece->iLineThrough < 1 || pPiece->iLineThrough > 2; - if (bNoUnderline && bNoLineThrough) { - return; - } - pPen->SetColor(pPiece->dwColor); - std::unique_ptr pPath(new CFDE_Path); - int32_t iChars = GetDisplayPos(pPiece, pCharPos); - if (iChars > 0) { - CFX_PointF pt1, pt2; - FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f; - if (pPiece->iPeriod == XFA_ATTRIBUTEENUM_Word) { - for (int32_t i = 0; i < pPiece->iUnderline; i++) { - for (int32_t j = 0; j < iChars; j++) { - pt1.x = pCharPos[j].m_OriginX; - pt2.x = - pt1.x + pCharPos[j].m_FontCharWidth * pPiece->fFontSize / 1000.0f; - pt1.y = pt2.y = fEndY; - pPath->AddLine(pt1, pt2); - } - fEndY += 2.0f; - } - } else { - pt1.x = pCharPos[0].m_OriginX; - pt2.x = - pCharPos[iChars - 1].m_OriginX + - pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f; - for (int32_t i = 0; i < pPiece->iUnderline; i++) { - pt1.y = pt2.y = fEndY; - pPath->AddLine(pt1, pt2); - fEndY += 2.0f; - } - } - fEndY = pCharPos[0].m_OriginY - pPiece->rtPiece.height * 0.25f; - pt1.x = pCharPos[0].m_OriginX; - pt2.x = pCharPos[iChars - 1].m_OriginX + - pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f; - for (int32_t i = 0; i < pPiece->iLineThrough; i++) { - pt1.y = pt2.y = fEndY; - pPath->AddLine(pt1, pt2); - fEndY += 2.0f; - } - } else { - if (bNoLineThrough && - (bNoUnderline || pPiece->iPeriod != XFA_ATTRIBUTEENUM_All)) { - return; - } - int32_t iCharsTmp = 0; - int32_t iPiecePrev = iPiece, iPieceNext = iPiece; - while (iPiecePrev > 0) { - iPiecePrev--; - iCharsTmp = pPieceLine->m_charCounts.GetAt(iPiecePrev); - if (iCharsTmp > 0) { - break; - } - } - if (iCharsTmp == 0) { - return; - } - iCharsTmp = 0; - int32_t iPieces = pPieceLine->m_textPieces.GetSize(); - while (iPieceNext < iPieces - 1) { - iPieceNext++; - iCharsTmp = pPieceLine->m_charCounts.GetAt(iPieceNext); - if (iCharsTmp > 0) { - break; - } - } - if (iCharsTmp == 0) { - return; - } - FX_FLOAT fOrgX = 0.0f, fEndX = 0.0f; - pPiece = pPieceLine->m_textPieces.GetAt(iPiecePrev); - iChars = GetDisplayPos(pPiece, pCharPos); - if (iChars < 1) { - return; - } - fOrgX = pCharPos[iChars - 1].m_OriginX + - pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f; - pPiece = pPieceLine->m_textPieces.GetAt(iPieceNext); - iChars = GetDisplayPos(pPiece, pCharPos); - if (iChars < 1) { - return; - } - fEndX = pCharPos[0].m_OriginX; - CFX_PointF pt1, pt2; - pt1.x = fOrgX, pt2.x = fEndX; - FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f; - for (int32_t i = 0; i < pPiece->iUnderline; i++) { - pt1.y = pt2.y = fEndY; - pPath->AddLine(pt1, pt2); - fEndY += 2.0f; - } - fEndY = pCharPos[0].m_OriginY - pPiece->rtPiece.height * 0.25f; - for (int32_t i = 0; i < pPiece->iLineThrough; i++) { - pt1.y = pt2.y = fEndY; - pPath->AddLine(pt1, pt2); - fEndY += 2.0f; - } - } - pDevice->DrawPath(pPen, 1, pPath.get(), &tmDoc2Device); -} - -int32_t CXFA_TextLayout::GetDisplayPos(const XFA_TextPiece* pPiece, - FXTEXT_CHARPOS* pCharPos, - bool bCharCode) { - if (!pPiece) { - return 0; - } - FX_RTFTEXTOBJ tr; - if (!ToRun(pPiece, tr)) { - return 0; - } - return m_pBreak->GetDisplayPos(&tr, pCharPos, bCharCode); -} -bool CXFA_TextLayout::ToRun(const XFA_TextPiece* pPiece, FX_RTFTEXTOBJ& tr) { - int32_t iLength = pPiece->iChars; - if (iLength < 1) { - return false; - } - tr.pStr = pPiece->pszText; - tr.pFont = pPiece->pFont; - tr.pRect = &pPiece->rtPiece; - tr.pWidths = pPiece->pWidths; - tr.iLength = iLength; - tr.fFontSize = pPiece->fFontSize; - tr.iBidiLevel = pPiece->iBidiLevel; - tr.iCharRotation = 0; - tr.wLineBreakChar = L'\n'; - tr.iVerticalScale = pPiece->iVerScale; - tr.dwLayoutStyles = FX_RTFLAYOUTSTYLE_ExpandTab; - tr.iHorizontalScale = pPiece->iHorScale; - return true; -} - -CXFA_LinkUserData::CXFA_LinkUserData(IFX_MemoryAllocator* pAllocator, - FX_WCHAR* pszText) - : m_pAllocator(pAllocator), m_dwRefCount(1), m_wsURLContent(pszText) {} - -CXFA_LinkUserData::~CXFA_LinkUserData() {} - -uint32_t CXFA_LinkUserData::Retain() { - return ++m_dwRefCount; -} - -uint32_t CXFA_LinkUserData::Release() { - uint32_t dwRefCount = --m_dwRefCount; - if (dwRefCount <= 0) - FXTARGET_DeleteWith(CXFA_LinkUserData, m_pAllocator, this); - return dwRefCount; -} - -const FX_WCHAR* CXFA_LinkUserData::GetLinkURL() { - return m_wsURLContent.c_str(); -} - -CXFA_TextUserData::CXFA_TextUserData(IFX_MemoryAllocator* pAllocator, - IFDE_CSSComputedStyle* pStyle) - : m_pStyle(pStyle), - m_pLinkData(nullptr), - m_pAllocator(pAllocator), - m_dwRefCount(0) { - ASSERT(m_pAllocator); - if (m_pStyle) - m_pStyle->Retain(); -} - -CXFA_TextUserData::CXFA_TextUserData(IFX_MemoryAllocator* pAllocator, - IFDE_CSSComputedStyle* pStyle, - CXFA_LinkUserData* pLinkData) - : m_pStyle(pStyle), - m_pLinkData(pLinkData), - m_pAllocator(pAllocator), - m_dwRefCount(0) { - ASSERT(m_pAllocator); - if (m_pStyle) - m_pStyle->Retain(); -} - -CXFA_TextUserData::~CXFA_TextUserData() { - if (m_pStyle) - m_pStyle->Release(); - if (m_pLinkData) - m_pLinkData->Release(); -} - -uint32_t CXFA_TextUserData::Retain() { - return ++m_dwRefCount; -} - -uint32_t CXFA_TextUserData::Release() { - uint32_t dwRefCount = --m_dwRefCount; - if (dwRefCount == 0) - FXTARGET_DeleteWith(CXFA_TextUserData, m_pAllocator, this); - return dwRefCount; -} - -CXFA_PieceLine::CXFA_PieceLine() {} - -CXFA_PieceLine::~CXFA_PieceLine() {} - -CXFA_TextTabstopsContext::CXFA_TextTabstopsContext() - : m_iTabCount(0), - m_iTabIndex(-1), - m_bTabstops(false), - m_fTabWidth(0), - m_fLeft(0) {} - -CXFA_TextTabstopsContext::~CXFA_TextTabstopsContext() {} - -void CXFA_TextTabstopsContext::Append(uint32_t dwAlign, FX_FLOAT fTabstops) { - int32_t i = 0; - for (i = 0; i < m_iTabCount; i++) { - XFA_TABSTOPS* pTabstop = m_tabstops.GetDataPtr(i); - if (fTabstops < pTabstop->fTabstops) { - break; - } - } - m_tabstops.InsertSpaceAt(i, 1); - XFA_TABSTOPS tabstop; - tabstop.dwAlign = dwAlign; - tabstop.fTabstops = fTabstops; - m_tabstops.SetAt(i, tabstop); - m_iTabCount++; -} - -void CXFA_TextTabstopsContext::RemoveAll() { - m_tabstops.RemoveAll(); - m_iTabCount = 0; -} - -void CXFA_TextTabstopsContext::Reset() { - m_iTabIndex = -1; - m_bTabstops = false; - m_fTabWidth = 0; - m_fLeft = 0; -} diff --git a/xfa/fxfa/app/xfa_textlayout.h b/xfa/fxfa/app/xfa_textlayout.h deleted file mode 100644 index fa0ca668ca..0000000000 --- a/xfa/fxfa/app/xfa_textlayout.h +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright 2014 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#ifndef XFA_FXFA_APP_XFA_TEXTLAYOUT_H_ -#define XFA_FXFA_APP_XFA_TEXTLAYOUT_H_ - -#include -#include -#include - -#include "xfa/fde/css/fde_css.h" -#include "xfa/fde/fde_gedevice.h" -#include "xfa/fgas/layout/fgas_rtfbreak.h" -#include "xfa/fxfa/parser/xfa_object.h" -#include "xfa/fxfa/xfa_ffdoc.h" - -#define XFA_LOADERCNTXTFLG_FILTERSPACE 0x001 - -class CFDE_CSSStyleSelector; -class CXFA_Para; -class CXFA_Font; -class CXFA_TextProvider; -class CXFA_TextTabstopsContext; - -class CXFA_CSSTagProvider { - public: - using AttributeMap = std::map; - - CXFA_CSSTagProvider(); - ~CXFA_CSSTagProvider(); - - CFX_WideString GetTagName() { return m_wsTagName; } - - AttributeMap::iterator begin() { return m_Attributes.begin(); } - AttributeMap::iterator end() { return m_Attributes.end(); } - - bool empty() const { return m_Attributes.empty(); } - - void SetTagNameObj(const CFX_WideString& wsName) { m_wsTagName = wsName; } - void SetAttribute(const CFX_WideString& wsAttr, - const CFX_WideString& wsValue) { - m_Attributes.insert({wsAttr, wsValue}); - } - - bool m_bTagAvailable; - bool m_bContent; - - protected: - CFX_WideString m_wsTagName; - AttributeMap m_Attributes; -}; - -class CXFA_TextParseContext : public CFX_Target { - public: - CXFA_TextParseContext(); - ~CXFA_TextParseContext() override; - - void SetDisplay(FDE_CSSDISPLAY eDisplay) { m_eDisplay = eDisplay; } - FDE_CSSDISPLAY GetDisplay() const { return m_eDisplay; } - void SetDecls(const CFDE_CSSDeclaration** ppDeclArray, int32_t iDeclCount); - const CFDE_CSSDeclaration** GetDecls() { - return const_cast(m_ppMatchedDecls); - } - uint32_t CountDecls() const { return m_dwMatchedDecls; } - - IFDE_CSSComputedStyle* m_pParentStyle; - - protected: - CFDE_CSSDeclaration** m_ppMatchedDecls; - uint32_t m_dwMatchedDecls; - FDE_CSSDISPLAY m_eDisplay; -}; - -class CXFA_TextParser { - public: - CXFA_TextParser(); - virtual ~CXFA_TextParser(); - - void Reset(); - void DoParse(CFDE_XMLNode* pXMLContainer, CXFA_TextProvider* pTextProvider); - IFDE_CSSComputedStyle* CreateRootStyle(CXFA_TextProvider* pTextProvider); - IFDE_CSSComputedStyle* ComputeStyle(CFDE_XMLNode* pXMLNode, - IFDE_CSSComputedStyle* pParentStyle); - bool IsParsed() const { return !!m_pAllocator; } - - int32_t GetVAlign(CXFA_TextProvider* pTextProvider) const; - FX_FLOAT GetTabInterval(IFDE_CSSComputedStyle* pStyle) const; - int32_t CountTabs(IFDE_CSSComputedStyle* pStyle) const; - bool IsSpaceRun(IFDE_CSSComputedStyle* pStyle) const; - bool GetTabstops(IFDE_CSSComputedStyle* pStyle, - CXFA_TextTabstopsContext* pTabstopContext); - CFX_RetainPtr GetFont(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle) const; - FX_FLOAT GetFontSize(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle) const; - int32_t GetHorScale(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle, - CFDE_XMLNode* pXMLNode) const; - int32_t GetVerScale(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle) const; - void GetUnderline(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle, - int32_t& iUnderline, - int32_t& iPeriod) const; - void GetLinethrough(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle, - int32_t& iLinethrough) const; - FX_ARGB GetColor(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle) const; - FX_FLOAT GetBaseline(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle) const; - FX_FLOAT GetLineHeight(CXFA_TextProvider* pTextProvider, - IFDE_CSSComputedStyle* pStyle, - bool bFirst, - FX_FLOAT fVerScale) const; - bool GetEmbbedObj(CXFA_TextProvider* pTextProvider, - CFDE_XMLNode* pXMLNode, - CFX_WideString& wsValue); - CXFA_TextParseContext* GetParseContextFromMap(CFDE_XMLNode* pXMLNode); - - protected: - bool TagValidate(const CFX_WideString& str) const; - - private: - void InitCSSData(CXFA_TextProvider* pTextProvider); - void ParseRichText(CFDE_XMLNode* pXMLNode, - IFDE_CSSComputedStyle* pParentStyle); - void ParseTagInfo(CFDE_XMLNode* pXMLNode, CXFA_CSSTagProvider& tagProvider); - IFDE_CSSStyleSheet* LoadDefaultSheetStyle(); - IFDE_CSSComputedStyle* CreateStyle(IFDE_CSSComputedStyle* pParentStyle); - std::unique_ptr m_pAllocator; - std::unique_ptr m_pSelector; - IFDE_CSSStyleSheet* m_pUASheet; - std::map m_mapXMLNodeToParseContext; -}; - -class CXFA_LoaderContext { - public: - CXFA_LoaderContext(); - ~CXFA_LoaderContext(); - - bool m_bSaveLineHeight; - FX_FLOAT m_fWidth; - FX_FLOAT m_fHeight; - FX_FLOAT m_fLastPos; - FX_FLOAT m_fStartLineOffset; - int32_t m_iChar; - int32_t m_iLines; - int32_t m_iTotalLines; - CFDE_XMLNode* m_pXMLNode; - CXFA_Node* m_pNode; - IFDE_CSSComputedStyle* m_pParentStyle; - CFX_ArrayTemplate m_lineHeights; - uint32_t m_dwFlags; - std::vector m_BlocksHeight; -}; - -class CXFA_LinkUserData : public IFX_Retainable, public CFX_Target { - public: - CXFA_LinkUserData(IFX_MemoryAllocator* pAllocator, FX_WCHAR* pszText); - ~CXFA_LinkUserData() override; - - // IFX_Retainable: - uint32_t Retain() override; - uint32_t Release() override; - - const FX_WCHAR* GetLinkURL(); - - protected: - IFX_MemoryAllocator* m_pAllocator; - uint32_t m_dwRefCount; - CFX_WideString m_wsURLContent; -}; - -class CXFA_TextUserData : public IFX_Retainable, public CFX_Target { - public: - CXFA_TextUserData(IFX_MemoryAllocator* pAllocator, - IFDE_CSSComputedStyle* pStyle); - CXFA_TextUserData(IFX_MemoryAllocator* pAllocator, - IFDE_CSSComputedStyle* pStyle, - CXFA_LinkUserData* pLinkData); - ~CXFA_TextUserData() override; - - // IFX_Retainable: - uint32_t Retain() override; - uint32_t Release() override; - - IFDE_CSSComputedStyle* m_pStyle; - CXFA_LinkUserData* m_pLinkData; - - protected: - IFX_MemoryAllocator* m_pAllocator; - uint32_t m_dwRefCount; -}; - -class XFA_TextPiece : public CFX_Target { - public: - XFA_TextPiece(); - ~XFA_TextPiece() override; - - FX_WCHAR* pszText; - int32_t iChars; - int32_t* pWidths; - int32_t iHorScale; - int32_t iVerScale; - int32_t iBidiLevel; - int32_t iUnderline; - int32_t iPeriod; - int32_t iLineThrough; - CFX_RetainPtr pFont; - FX_ARGB dwColor; - FX_FLOAT fFontSize; - CFX_RectF rtPiece; - CXFA_LinkUserData* pLinkData; -}; -typedef CFX_ArrayTemplate CXFA_PieceArray; - -class CXFA_PieceLine : public CFX_Target { - public: - CXFA_PieceLine(); - ~CXFA_PieceLine() override; - - CXFA_PieceArray m_textPieces; - CFX_Int32Array m_charCounts; -}; -typedef CFX_ArrayTemplate CXFA_PieceLineArray; - -struct XFA_TABSTOPS { - uint32_t dwAlign; - FX_FLOAT fTabstops; -}; - -class CXFA_TextTabstopsContext { - public: - CXFA_TextTabstopsContext(); - ~CXFA_TextTabstopsContext(); - - void Append(uint32_t dwAlign, FX_FLOAT fTabstops); - void RemoveAll(); - void Reset(); - - CFX_ArrayTemplate m_tabstops; - int32_t m_iTabCount; - int32_t m_iTabIndex; - bool m_bTabstops; - FX_FLOAT m_fTabWidth; - FX_FLOAT m_fLeft; -}; - -class CXFA_TextLayout { - public: - explicit CXFA_TextLayout(CXFA_TextProvider* pTextProvider); - ~CXFA_TextLayout(); - - int32_t GetText(CFX_WideString& wsText); - FX_FLOAT GetLayoutHeight(); - FX_FLOAT StartLayout(FX_FLOAT fWidth = -1); - bool DoLayout(int32_t iBlockIndex, - FX_FLOAT& fCalcHeight, - FX_FLOAT fContentAreaHeight = -1, - FX_FLOAT fTextHeight = -1); - - bool CalcSize(const CFX_SizeF& minSize, - const CFX_SizeF& maxSize, - CFX_SizeF& defaultSize); - bool Layout(const CFX_SizeF& size, FX_FLOAT* fHeight = nullptr); - void ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex); - bool DrawString(CFX_RenderDevice* pFxDevice, - const CFX_Matrix& tmDoc2Device, - const CFX_RectF& rtClip, - int32_t iBlock = 0); - bool IsLoaded() const { return m_pieceLines.GetSize() > 0; } - void Unload(); - const CXFA_PieceLineArray* GetPieceLines(); - - bool m_bHasBlock; - CFX_Int32Array m_Blocks; - - private: - void GetTextDataNode(); - CFDE_XMLNode* GetXMLContainerNode(); - CFX_RTFBreak* CreateBreak(bool bDefault); - void InitBreak(FX_FLOAT fLineWidth); - void InitBreak(IFDE_CSSComputedStyle* pStyle, - FDE_CSSDISPLAY eDisplay, - FX_FLOAT fLineWidth, - CFDE_XMLNode* pXMLNode, - IFDE_CSSComputedStyle* pParentStyle = nullptr); - bool Loader(const CFX_SizeF& szText, - FX_FLOAT& fLinePos, - bool bSavePieces = true); - void LoadText(CXFA_Node* pNode, - const CFX_SizeF& szText, - FX_FLOAT& fLinePos, - bool bSavePieces); - bool LoadRichText(CFDE_XMLNode* pXMLNode, - const CFX_SizeF& szText, - FX_FLOAT& fLinePos, - IFDE_CSSComputedStyle* pParentStyle, - bool bSavePieces, - CXFA_LinkUserData* pLinkData = nullptr, - bool bEndBreak = true, - bool bIsOl = false, - int32_t iLiCount = 0); - bool AppendChar(const CFX_WideString& wsText, - FX_FLOAT& fLinePos, - FX_FLOAT fSpaceAbove, - bool bSavePieces); - void AppendTextLine(uint32_t dwStatus, - FX_FLOAT& fLinePos, - bool bSavePieces, - bool bEndBreak = false); - void EndBreak(uint32_t dwStatus, FX_FLOAT& fLinePos, bool bDefault); - bool IsEnd(bool bSavePieces); - void ProcessText(CFX_WideString& wsText); - void UpdateAlign(FX_FLOAT fHeight, FX_FLOAT fBottom); - void RenderString(CFDE_RenderDevice* pDevice, - CFDE_Brush* pBrush, - CXFA_PieceLine* pPieceLine, - int32_t iPiece, - FXTEXT_CHARPOS* pCharPos, - const CFX_Matrix& tmDoc2Device); - void RenderPath(CFDE_RenderDevice* pDevice, - CFDE_Pen* pPen, - CXFA_PieceLine* pPieceLine, - int32_t iPiece, - FXTEXT_CHARPOS* pCharPos, - const CFX_Matrix& tmDoc2Device); - int32_t GetDisplayPos(const XFA_TextPiece* pPiece, - FXTEXT_CHARPOS* pCharPos, - bool bCharCode = false); - bool ToRun(const XFA_TextPiece* pPiece, FX_RTFTEXTOBJ& tr); - void DoTabstops(IFDE_CSSComputedStyle* pStyle, CXFA_PieceLine* pPieceLine); - bool Layout(int32_t iBlock); - int32_t CountBlocks() const; - - CXFA_TextProvider* m_pTextProvider; - CXFA_Node* m_pTextDataNode; - bool m_bRichText; - std::unique_ptr m_pAllocator; - std::unique_ptr m_pBreak; - std::unique_ptr m_pLoader; - int32_t m_iLines; - FX_FLOAT m_fMaxWidth; - CXFA_TextParser m_textParser; - CXFA_PieceLineArray m_pieceLines; - std::unique_ptr m_pTabstopContext; - bool m_bBlockContinue; -}; - -#endif // XFA_FXFA_APP_XFA_TEXTLAYOUT_H_ diff --git a/xfa/fxfa/app/xfa_textlayout_unittest.cpp b/xfa/fxfa/app/xfa_textlayout_unittest.cpp deleted file mode 100644 index 7354631dbb..0000000000 --- a/xfa/fxfa/app/xfa_textlayout_unittest.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "xfa/fxfa/app/xfa_textlayout.h" - -#include "testing/gtest/include/gtest/gtest.h" - -class CXFA_TestTextParser : public CXFA_TextParser { - public: - CXFA_TestTextParser() : CXFA_TextParser() {} - - private: - // Add test cases as friends to access protected member functions. - FRIEND_TEST(CXFA_TextParser, TagValidate); -}; - -TEST(CXFA_TextParser, TagValidate) { - CXFA_TestTextParser parser; - EXPECT_TRUE(parser.TagValidate(L"br")); - EXPECT_TRUE(parser.TagValidate(L"Br")); - EXPECT_TRUE(parser.TagValidate(L"BR")); - EXPECT_TRUE(parser.TagValidate(L"a")); - EXPECT_TRUE(parser.TagValidate(L"b")); - EXPECT_TRUE(parser.TagValidate(L"i")); - EXPECT_TRUE(parser.TagValidate(L"p")); - EXPECT_TRUE(parser.TagValidate(L"li")); - EXPECT_TRUE(parser.TagValidate(L"ol")); - EXPECT_TRUE(parser.TagValidate(L"ul")); - EXPECT_TRUE(parser.TagValidate(L"sub")); - EXPECT_TRUE(parser.TagValidate(L"sup")); - EXPECT_TRUE(parser.TagValidate(L"span")); - EXPECT_TRUE(parser.TagValidate(L"body")); - EXPECT_TRUE(parser.TagValidate(L"html")); - - EXPECT_FALSE(parser.TagValidate(L"")); - EXPECT_FALSE(parser.TagValidate(L"tml")); - EXPECT_FALSE(parser.TagValidate(L"xhtml")); - EXPECT_FALSE(parser.TagValidate(L"htmlx")); -} diff --git a/xfa/fxfa/app/xfa_textpiece.cpp b/xfa/fxfa/app/xfa_textpiece.cpp new file mode 100644 index 0000000000..4b57aa82d9 --- /dev/null +++ b/xfa/fxfa/app/xfa_textpiece.cpp @@ -0,0 +1,17 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "xfa/fxfa/app/xfa_textpiece.h" + +#include "xfa/fxfa/app/cxfa_linkuserdata.h" + +XFA_TextPiece::XFA_TextPiece() + : pszText(nullptr), pFont(nullptr), pLinkData(nullptr) {} + +XFA_TextPiece::~XFA_TextPiece() { + if (pLinkData) + pLinkData->Release(); +} diff --git a/xfa/fxfa/app/xfa_textpiece.h b/xfa/fxfa/app/xfa_textpiece.h new file mode 100644 index 0000000000..4047cd2d7f --- /dev/null +++ b/xfa/fxfa/app/xfa_textpiece.h @@ -0,0 +1,39 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef XFA_FXFA_APP_XFA_TEXTPIECE_H_ +#define XFA_FXFA_APP_XFA_TEXTPIECE_H_ + +#include "core/fxcrt/fx_basic.h" +#include "core/fxcrt/fx_coordinates.h" +#include "core/fxcrt/fx_string.h" +#include "core/fxge/fx_dib.h" +#include "xfa/fgas/font/cfgas_gefont.h" + +class CXFA_LinkUserData; + +class XFA_TextPiece : public CFX_Target { + public: + XFA_TextPiece(); + ~XFA_TextPiece() override; + + FX_WCHAR* pszText; + int32_t iChars; + int32_t* pWidths; + int32_t iHorScale; + int32_t iVerScale; + int32_t iBidiLevel; + int32_t iUnderline; + int32_t iPeriod; + int32_t iLineThrough; + CFX_RetainPtr pFont; + FX_ARGB dwColor; + FX_FLOAT fFontSize; + CFX_RectF rtPiece; + CXFA_LinkUserData* pLinkData; +}; + +#endif // XFA_FXFA_APP_XFA_TEXTPIECE_H_ -- cgit v1.2.3