diff options
Diffstat (limited to 'xfa/fxfa/app/cxfa_textlayout.cpp')
-rw-r--r-- | xfa/fxfa/app/cxfa_textlayout.cpp | 1370 |
1 files changed, 1370 insertions, 0 deletions
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 <algorithm> + +#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_PieceLine*>* 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<CFDE_XMLElement*>(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<CXFA_TextTabstopsContext>(); + 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<CXFA_LoaderContext>(); + + 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<int32_t>(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<int32_t>(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<int32_t>(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<CFDE_RenderDevice> pDevice( + new CFDE_RenderDevice(pFxDevice, false)); + pDevice->SaveState(); + pDevice->SetClipRect(rtClip); + + auto pSolidBrush = pdfium::MakeUnique<CFDE_Brush>(); + auto pPen = pdfium::MakeUnique<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<CFDE_XMLElement*>(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<CFDE_XMLText*>(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<CFDE_Path> 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; +} |