| // 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 <algorithm> | |
| #include "xfa/src/foxitlib.h" | |
| #include "xfa/src/fxfa/src/common/xfa_common.h" | |
| #include "xfa_textlayout.h" | |
| #include "xfa_ffapp.h" | |
| #include "xfa_ffdoc.h" | |
| #include "xfa_fontmgr.h" | |
| CXFA_CSSTagProvider::~CXFA_CSSTagProvider() { | |
| FX_POSITION pos = m_Attributes.GetStartPosition(); | |
| while (pos) { | |
| CFX_WideString *pName = NULL, *pValue = NULL; | |
| m_Attributes.GetNextAssoc(pos, (void*&)pName, (void*&)pValue); | |
| if (pName != NULL) { | |
| delete pName; | |
| } | |
| if (pValue != NULL) { | |
| delete pValue; | |
| } | |
| } | |
| } | |
| void CXFA_CSSTagProvider::GetNextAttribute(FX_POSITION& pos, | |
| CFX_WideStringC& wsAttr, | |
| CFX_WideStringC& wsValue) { | |
| if (pos == NULL) { | |
| return; | |
| } | |
| CFX_WideString* pName = NULL; | |
| CFX_WideString* pValue = NULL; | |
| m_Attributes.GetNextAssoc(pos, (void*&)pName, (void*&)pValue); | |
| wsAttr = *pName; | |
| wsValue = *pValue; | |
| } | |
| void CXFA_CSSTagProvider::SetAttribute(const CFX_WideString& wsAttr, | |
| const CFX_WideString& wsValue) { | |
| CFX_WideString* pName = new CFX_WideString(); | |
| CFX_WideString* pValue = new CFX_WideString(); | |
| *pName = wsAttr; | |
| *pValue = wsValue; | |
| m_Attributes.SetAt(pName, pValue); | |
| } | |
| void CXFA_TextParseContext::SetDecls(const IFDE_CSSDeclaration** ppDeclArray, | |
| int32_t iDeclCount) { | |
| if (iDeclCount <= 0 || ppDeclArray == NULL) { | |
| return; | |
| } | |
| m_dwMatchedDecls = iDeclCount; | |
| m_ppMatchedDecls = FX_Alloc(IFDE_CSSDeclaration*, iDeclCount); | |
| FX_memcpy(m_ppMatchedDecls, ppDeclArray, | |
| iDeclCount * sizeof(IFDE_CSSDeclaration*)); | |
| } | |
| CXFA_TextParser::~CXFA_TextParser() { | |
| if (m_pUASheet != NULL) { | |
| m_pUASheet->Release(); | |
| } | |
| if (m_pSelector != NULL) { | |
| m_pSelector->Release(); | |
| } | |
| if (m_pAllocator != NULL) { | |
| m_pAllocator->Release(); | |
| } | |
| FX_POSITION ps = m_mapXMLNodeToParseContext.GetStartPosition(); | |
| while (ps) { | |
| IFDE_XMLNode* pXMLNode; | |
| CXFA_TextParseContext* pParseContext; | |
| m_mapXMLNodeToParseContext.GetNextAssoc(ps, pXMLNode, pParseContext); | |
| if (pParseContext != NULL) { | |
| FDE_DeleteWith(CXFA_TextParseContext, m_pAllocator, pParseContext); | |
| } | |
| } | |
| m_mapXMLNodeToParseContext.RemoveAll(); | |
| } | |
| void CXFA_TextParser::Reset() { | |
| FX_POSITION ps = m_mapXMLNodeToParseContext.GetStartPosition(); | |
| while (ps) { | |
| IFDE_XMLNode* pXMLNode; | |
| CXFA_TextParseContext* pParseContext; | |
| m_mapXMLNodeToParseContext.GetNextAssoc(ps, pXMLNode, pParseContext); | |
| if (pParseContext != NULL) { | |
| FDE_DeleteWith(CXFA_TextParseContext, m_pAllocator, pParseContext); | |
| } | |
| } | |
| m_mapXMLNodeToParseContext.RemoveAll(); | |
| if (m_pAllocator != NULL) { | |
| m_pAllocator->Release(); | |
| m_pAllocator = NULL; | |
| } | |
| } | |
| void CXFA_TextParser::InitCSSData(IXFA_TextProvider* pTextProvider) { | |
| if (pTextProvider == NULL) { | |
| return; | |
| } | |
| if (m_pSelector == NULL) { | |
| CXFA_FFDoc* pDoc = pTextProvider->GetDocNode(); | |
| IFX_FontMgr* pFontMgr = pDoc->GetApp()->GetFDEFontMgr(); | |
| FXSYS_assert(pFontMgr != NULL); | |
| m_pSelector = IFDE_CSSStyleSelector::Create(); | |
| m_pSelector->SetFontMgr(pFontMgr); | |
| FX_FLOAT fFontSize = 10; | |
| CXFA_Font font = pTextProvider->GetFontNode(); | |
| if (font.IsExistInXML()) { | |
| fFontSize = font.GetFontSize(); | |
| } | |
| m_pSelector->SetDefFontSize(fFontSize); | |
| } | |
| if (m_pUASheet == NULL) { | |
| 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( | |
| IXFA_TextProvider* pTextProvider) { | |
| CXFA_Font font = pTextProvider->GetFontNode(); | |
| CXFA_Para para = pTextProvider->GetParaNode(); | |
| IFDE_CSSComputedStyle* pStyle = m_pSelector->CreateComputedStyle(NULL); | |
| IFDE_CSSFontStyle* pFontStyle = pStyle->GetFontStyles(); | |
| IFDE_CSSParagraphStyle* pParaStyle = pStyle->GetParagraphStyles(); | |
| FX_FLOAT fLineHeight = 0, fFontSize = 10; | |
| if (para.IsExistInXML()) { | |
| fLineHeight = para.GetLineHeight(); | |
| FDE_CSSLENGTH indent; | |
| indent.Set(FDE_CSSLENGTHUNIT_Point, para.GetTextIndent()); | |
| pParaStyle->SetTextIndent(indent); | |
| FDE_CSSTEXTALIGN hAlgin = FDE_CSSTEXTALIGN_Left; | |
| switch (para.GetHorizontalAlign()) { | |
| case XFA_ATTRIBUTEENUM_Center: | |
| hAlgin = FDE_CSSTEXTALIGN_Center; | |
| break; | |
| case XFA_ATTRIBUTEENUM_Right: | |
| hAlgin = FDE_CSSTEXTALIGN_Right; | |
| break; | |
| case XFA_ATTRIBUTEENUM_Justify: | |
| hAlgin = FDE_CSSTEXTALIGN_Justify; | |
| break; | |
| case XFA_ATTRIBUTEENUM_JustifyAll: | |
| hAlgin = FDE_CSSTEXTALIGN_JustifyAll; | |
| break; | |
| } | |
| pParaStyle->SetTextAlign(hAlgin); | |
| 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.IsExistInXML()) { | |
| 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); | |
| FX_DWORD 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); | |
| FXSYS_assert(pNewStyle != NULL); | |
| if (pParentStyle) { | |
| IFDE_CSSParagraphStyle* pParaStyle = pParentStyle->GetParagraphStyles(); | |
| FX_DWORD 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 != NULL) { | |
| pBoundarytyle = pNewStyle->GetBoundaryStyles(); | |
| pBoundarytyle->SetMarginWidth(*pRect); | |
| } | |
| } | |
| return pNewStyle; | |
| } | |
| IFDE_CSSComputedStyle* CXFA_TextParser::ComputeStyle( | |
| IFDE_XMLNode* pXMLNode, | |
| IFDE_CSSComputedStyle* pParentStyle) { | |
| CXFA_TextParseContext* pContext = static_cast<CXFA_TextParseContext*>( | |
| m_mapXMLNodeToParseContext.GetValueAt(pXMLNode)); | |
| if (!pContext) | |
| return nullptr; | |
| pContext->m_pParentStyle = pParentStyle; | |
| pParentStyle->AddRef(); | |
| CXFA_CSSTagProvider tagProvider; | |
| ParseTagInfo(pXMLNode, tagProvider); | |
| if (tagProvider.m_bContent) | |
| return nullptr; | |
| IFDE_CSSComputedStyle* pStyle = CreateStyle(pParentStyle); | |
| IFDE_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(IFDE_XMLNode* pXMLContainer, | |
| IXFA_TextProvider* pTextProvider) { | |
| if (pXMLContainer == NULL || pTextProvider == NULL || m_pAllocator != NULL) { | |
| return; | |
| } | |
| m_pAllocator = | |
| FX_CreateAllocator(FX_ALLOCTYPE_Fixed, 32, sizeof(CXFA_CSSTagProvider)); | |
| InitCSSData(pTextProvider); | |
| IFDE_CSSComputedStyle* pRootStyle = CreateRootStyle(pTextProvider); | |
| ParseRichText(pXMLContainer, pRootStyle); | |
| pRootStyle->Release(); | |
| } | |
| void CXFA_TextParser::ParseRichText(IFDE_XMLNode* pXMLNode, | |
| IFDE_CSSComputedStyle* pParentStyle) { | |
| if (pXMLNode == NULL) { | |
| return; | |
| } | |
| CXFA_CSSTagProvider tagProvider; | |
| ParseTagInfo(pXMLNode, tagProvider); | |
| if (!tagProvider.m_bTagAviliable) { | |
| return; | |
| } | |
| IFDE_CSSComputedStyle* pNewStyle = NULL; | |
| if ((tagProvider.GetTagName() != FX_WSTRC(L"body")) || | |
| (tagProvider.GetTagName() != FX_WSTRC(L"html"))) { | |
| CXFA_TextParseContext* pTextContext = | |
| FDE_NewWith(m_pAllocator) CXFA_TextParseContext; | |
| FDE_CSSDISPLAY eDisplay = FDE_CSSDISPLAY_Inline; | |
| if (!tagProvider.m_bContent) { | |
| pNewStyle = CreateStyle(pParentStyle); | |
| IFDE_CSSAccelerator* pCSSAccel = m_pSelector->InitAccelerator(); | |
| pCSSAccel->OnEnterTag(&tagProvider); | |
| CFDE_CSSDeclarationArray DeclArray; | |
| int32_t iMatchedDecls = | |
| m_pSelector->MatchDeclarations(&tagProvider, DeclArray); | |
| const IFDE_CSSDeclaration** ppMatchDecls = | |
| (const IFDE_CSSDeclaration**)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.SetAt(pXMLNode, pTextContext); | |
| } | |
| for (IFDE_XMLNode* pXMLChild = | |
| pXMLNode->GetNodeItem(IFDE_XMLNode::FirstChild); | |
| pXMLChild; | |
| pXMLChild = pXMLChild->GetNodeItem(IFDE_XMLNode::NextSibling)) { | |
| ParseRichText(pXMLChild, pNewStyle); | |
| } | |
| if (pNewStyle != NULL) { | |
| pNewStyle->Release(); | |
| } | |
| } | |
| void CXFA_TextParser::ParseTagInfo(IFDE_XMLNode* pXMLNode, | |
| CXFA_CSSTagProvider& tagProvider) { | |
| static const FX_DWORD s_XFATagName[] = { | |
| 0x61, 0x62, 0x69, 0x70, 0x0001f714, | |
| 0x00022a55, 0x000239bb, 0x00025881, 0x0bd37faa, 0x0bd37fb8, | |
| 0xa73e3af2, 0xb182eaae, 0xdb8ac455, | |
| }; | |
| CFX_WideString wsName; | |
| if (pXMLNode->GetType() == FDE_XMLNODE_Element) { | |
| IFDE_XMLElement* pXMLElement = (IFDE_XMLElement*)pXMLNode; | |
| pXMLElement->GetLocalTagName(wsName); | |
| tagProvider.SetTagNameObj(wsName); | |
| FX_DWORD dwHashCode = | |
| FX_HashCode_String_GetW(wsName, wsName.GetLength(), TRUE); | |
| static const int32_t s_iCount = sizeof(s_XFATagName) / sizeof(FX_DWORD); | |
| CFX_DSPATemplate<FX_DWORD> lookup; | |
| tagProvider.m_bTagAviliable = | |
| lookup.Lookup(dwHashCode, s_XFATagName, s_iCount) > -1; | |
| CFX_WideString wsValue; | |
| pXMLElement->GetString(FX_WSTRC(L"style").GetPtr(), wsValue); | |
| if (!wsValue.IsEmpty()) { | |
| tagProvider.SetAttribute(FX_WSTRC(L"style"), wsValue); | |
| } | |
| } else if (pXMLNode->GetType() == FDE_XMLNODE_Text) { | |
| tagProvider.m_bTagAviliable = TRUE; | |
| tagProvider.m_bContent = TRUE; | |
| } | |
| } | |
| int32_t CXFA_TextParser::GetVAlgin(IXFA_TextProvider* pTextProvider) const { | |
| int32_t iAlign = XFA_ATTRIBUTEENUM_Top; | |
| CXFA_Para para = pTextProvider->GetParaNode(); | |
| if (para.IsExistInXML()) { | |
| iAlign = para.GetVerticalAlign(); | |
| } | |
| return iAlign; | |
| } | |
| FX_FLOAT CXFA_TextParser::GetTabInterval(IFDE_CSSComputedStyle* pStyle) const { | |
| CFX_WideString wsValue; | |
| if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"tab-interval"), wsValue)) { | |
| CXFA_Measurement ms(wsValue); | |
| return ms.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; | |
| } | |
| FX_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; | |
| } | |
| IFX_Font* CXFA_TextParser::GetFont(IXFA_TextProvider* pTextProvider, | |
| IFDE_CSSComputedStyle* pStyle) const { | |
| CFX_WideStringC wsFamily = FX_WSTRC(L"Courier"); | |
| FX_DWORD dwStyle = 0; | |
| CXFA_Font font = pTextProvider->GetFontNode(); | |
| if (font.IsExistInXML()) { | |
| 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(); | |
| FXSYS_assert(pDoc != NULL); | |
| CXFA_FontMgr* pFontMgr = pDoc->GetApp()->GetXFAFontMgr(); | |
| return pFontMgr->GetFont(pDoc, wsFamily, dwStyle); | |
| } | |
| FX_FLOAT CXFA_TextParser::GetFontSize(IXFA_TextProvider* pTextProvider, | |
| IFDE_CSSComputedStyle* pStyle) const { | |
| if (pStyle != NULL) { | |
| return pStyle->GetFontStyles()->GetFontSize(); | |
| } | |
| CXFA_Font font = pTextProvider->GetFontNode(); | |
| if (font.IsExistInXML()) { | |
| return font.GetFontSize(); | |
| } | |
| return 10; | |
| } | |
| int32_t CXFA_TextParser::GetHorScale(IXFA_TextProvider* pTextProvider, | |
| IFDE_CSSComputedStyle* pStyle, | |
| IFDE_XMLNode* pXMLNode) const { | |
| if (pStyle) { | |
| CFX_WideString wsValue; | |
| if (pStyle->GetCustomStyle(FX_WSTRC(L"xfa-font-horizontal-scale"), | |
| wsValue)) { | |
| return wsValue.GetInteger(); | |
| } | |
| while (pXMLNode) { | |
| CXFA_TextParseContext* pContext = static_cast<CXFA_TextParseContext*>( | |
| m_mapXMLNodeToParseContext.GetValueAt(pXMLNode)); | |
| if (pContext && pContext->m_pParentStyle && | |
| pContext->m_pParentStyle->GetCustomStyle( | |
| FX_WSTRC(L"xfa-font-horizontal-scale"), wsValue)) { | |
| return wsValue.GetInteger(); | |
| } | |
| pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::Parent); | |
| } | |
| } | |
| if (CXFA_Font font = pTextProvider->GetFontNode()) { | |
| return static_cast<int32_t>(font.GetHorizontalScale()); | |
| } | |
| return 100; | |
| } | |
| int32_t CXFA_TextParser::GetVerScale(IXFA_TextProvider* pTextProvider, | |
| IFDE_CSSComputedStyle* pStyle) const { | |
| if (pStyle != NULL) { | |
| 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(IXFA_TextProvider* pTextProvider, | |
| IFDE_CSSComputedStyle* pStyle, | |
| int32_t& iUnderline, | |
| int32_t& iPeriod) const { | |
| iUnderline = 0; | |
| iPeriod = XFA_ATTRIBUTEENUM_All; | |
| if (pStyle) { | |
| FX_DWORD 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.IsExistInXML()) { | |
| iUnderline = font.GetUnderline(); | |
| iPeriod = font.GetUnderlinePeriod(); | |
| } | |
| } | |
| } | |
| void CXFA_TextParser::GetLinethrough(IXFA_TextProvider* pTextProvider, | |
| IFDE_CSSComputedStyle* pStyle, | |
| int32_t& iLinethrough) const { | |
| if (pStyle) { | |
| FX_DWORD dwDecoration = pStyle->GetParagraphStyles()->GetTextDecoration(); | |
| iLinethrough = (dwDecoration & FDE_CSSTEXTDECORATION_LineThrough) ? 1 : 0; | |
| } else { | |
| CXFA_Font font = pTextProvider->GetFontNode(); | |
| if (font.IsExistInXML()) { | |
| iLinethrough = font.GetLineThrough(); | |
| } | |
| } | |
| } | |
| FX_ARGB CXFA_TextParser::GetColor(IXFA_TextProvider* pTextProvider, | |
| IFDE_CSSComputedStyle* pStyle) const { | |
| if (pStyle != NULL) { | |
| return pStyle->GetFontStyles()->GetColor(); | |
| } | |
| if (CXFA_Font font = pTextProvider->GetFontNode()) { | |
| return font.GetColor(); | |
| } | |
| return 0xFF000000; | |
| } | |
| FX_FLOAT CXFA_TextParser::GetBaseline(IXFA_TextProvider* pTextProvider, | |
| IFDE_CSSComputedStyle* pStyle) const { | |
| if (pStyle != NULL) { | |
| 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(IXFA_TextProvider* pTextProvider, | |
| IFDE_CSSComputedStyle* pStyle, | |
| FX_BOOL bFirst, | |
| FX_FLOAT fVerScale) const { | |
| FX_FLOAT fLineHeight = 0; | |
| if (pStyle != NULL) { | |
| 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; | |
| } | |
| FX_BOOL CXFA_TextParser::GetEmbbedObj(IXFA_TextProvider* pTextProvider, | |
| IFDE_XMLNode* pXMLNode, | |
| CFX_WideString& wsValue) { | |
| wsValue.Empty(); | |
| if (pXMLNode == NULL) { | |
| return FALSE; | |
| } | |
| FX_BOOL bRet = FALSE; | |
| if (pXMLNode->GetType() == FDE_XMLNODE_Element) { | |
| IFDE_XMLElement* pElement = (IFDE_XMLElement*)pXMLNode; | |
| CFX_WideString wsAttr; | |
| pElement->GetString(FX_WSTRC(L"xfa:embed").GetPtr(), wsAttr); | |
| if (wsAttr.IsEmpty()) { | |
| return FALSE; | |
| } | |
| if (wsAttr.GetAt(0) == L'#') { | |
| wsAttr.Delete(0); | |
| } | |
| CFX_WideString ws; | |
| pElement->GetString(FX_WSTRC(L"xfa:embedType").GetPtr(), ws); | |
| if (ws.IsEmpty()) { | |
| ws = L"som"; | |
| } else { | |
| ws.MakeLower(); | |
| } | |
| FX_BOOL bURI = (ws == FX_WSTRC(L"uri")); | |
| if (!bURI && ws != FX_WSTRC(L"som")) { | |
| return FALSE; | |
| } | |
| ws.Empty(); | |
| pElement->GetString(FX_WSTRC(L"xfa:embedMode").GetPtr(), ws); | |
| if (ws.IsEmpty()) { | |
| ws = L"formatted"; | |
| } else { | |
| ws.MakeLower(); | |
| } | |
| FX_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( | |
| IFDE_XMLNode* pXMLNode) { | |
| return (CXFA_TextParseContext*)m_mapXMLNodeToParseContext.GetValueAt( | |
| pXMLNode); | |
| } | |
| enum XFA_TABSTOPSSTATUS { | |
| XFA_TABSTOPSSTATUS_Error, | |
| XFA_TABSTOPSSTATUS_EOS, | |
| XFA_TABSTOPSSTATUS_None, | |
| XFA_TABSTOPSSTATUS_Alignment, | |
| XFA_TABSTOPSSTATUS_StartLeader, | |
| XFA_TABSTOPSSTATUS_Leader, | |
| XFA_TABSTOPSSTATUS_Location, | |
| }; | |
| FX_BOOL CXFA_TextParser::GetTabstops( | |
| IFDE_CSSComputedStyle* pStyle, | |
| CXFA_TextTabstopsContext* pTabstopContext) { | |
| if (pStyle == NULL || pTabstopContext == NULL) { | |
| 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; | |
| 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 == ' ') { | |
| FX_DWORD dwHashCode = | |
| FX_HashCode_String_GetW(wsAlign, wsAlign.GetLength(), TRUE); | |
| CXFA_Measurement ms(CFX_WideStringC(pTabStops + iLast, iCur - iLast)); | |
| FX_FLOAT fPos = ms.ToUnit(XFA_UNIT_Pt); | |
| pTabstopContext->Append(dwHashCode, fPos); | |
| wsAlign.Empty(); | |
| eStatus = XFA_TABSTOPSSTATUS_None; | |
| } | |
| iCur++; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| if (!wsAlign.IsEmpty()) { | |
| FX_DWORD dwHashCode = | |
| FX_HashCode_String_GetW(wsAlign, wsAlign.GetLength(), 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(IXFA_TextProvider* pTextProvider) | |
| : m_bHasBlock(FALSE), | |
| m_pTextProvider(pTextProvider), | |
| m_pTextDataNode(nullptr), | |
| m_bRichText(FALSE), | |
| m_pAllocator(nullptr), | |
| m_pBreak(nullptr), | |
| m_pLoader(nullptr), | |
| m_iLines(0), | |
| m_fMaxWidth(0), | |
| m_pTabstopContext(nullptr), | |
| m_bBlockContinue(TRUE) { | |
| FXSYS_assert(m_pTextProvider); | |
| } | |
| CXFA_TextLayout::~CXFA_TextLayout() { | |
| m_textParser.Reset(); | |
| delete m_pLoader; | |
| delete m_pTabstopContext; | |
| Unload(); | |
| } | |
| void CXFA_TextLayout::Unload() { | |
| int32_t iCount = m_pieceLines.GetSize(); | |
| for (int32_t i = 0; i < iCount; i++) { | |
| CXFA_PieceLine* pLine = m_pieceLines.GetAt(i); | |
| FDE_DeleteWith(CXFA_PieceLine, m_pAllocator, pLine); | |
| } | |
| m_pieceLines.RemoveAll(); | |
| if (m_pBreak != NULL) { | |
| m_pBreak->Release(); | |
| m_pBreak = NULL; | |
| } | |
| if (m_pAllocator != NULL) { | |
| m_pAllocator->Release(); | |
| m_pAllocator = NULL; | |
| } | |
| } | |
| const CXFA_PieceLineArray* CXFA_TextLayout::GetPieceLines() { | |
| return &m_pieceLines; | |
| } | |
| void CXFA_TextLayout::GetTextDataNode() { | |
| if (m_pTextProvider == NULL) { | |
| return; | |
| } | |
| CXFA_Node* pNode = m_pTextProvider->GetTextNode(m_bRichText); | |
| if (pNode && m_bRichText) { | |
| m_textParser.Reset(); | |
| } | |
| m_pTextDataNode = pNode; | |
| } | |
| IFDE_XMLNode* CXFA_TextLayout::GetXMLContainerNode() { | |
| IFDE_XMLNode* pXMLContainer = NULL; | |
| if (m_bRichText) { | |
| IFDE_XMLNode* pXMLRoot = m_pTextDataNode->GetXMLMappingNode(); | |
| if (!pXMLRoot) { | |
| return pXMLContainer; | |
| } | |
| for (IFDE_XMLNode* pXMLChild = | |
| pXMLRoot->GetNodeItem(IFDE_XMLNode::FirstChild); | |
| pXMLChild; | |
| pXMLChild = pXMLChild->GetNodeItem(IFDE_XMLNode::NextSibling)) { | |
| if (pXMLChild->GetType() == FDE_XMLNODE_Element) { | |
| IFDE_XMLElement* pXMLElement = (IFDE_XMLElement*)pXMLChild; | |
| CFX_WideString wsTag; | |
| pXMLElement->GetLocalTagName(wsTag); | |
| if (wsTag.Equal(FX_WSTRC(L"body")) || wsTag.Equal(FX_WSTRC(L"html"))) { | |
| pXMLContainer = pXMLChild; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| return pXMLContainer; | |
| } | |
| IFX_RTFBreak* CXFA_TextLayout::CreateBreak(FX_BOOL bDefault) { | |
| FX_DWORD dwStyle = FX_RTFLAYOUTSTYLE_ExpandTab; | |
| if (!bDefault) { | |
| dwStyle |= FX_RTFLAYOUTSTYLE_Pagination; | |
| } | |
| IFX_RTFBreak* pBreak = IFX_RTFBreak::Create(0); | |
| pBreak->SetLayoutStyles(dwStyle); | |
| pBreak->SetLineBreakChar(L'\n'); | |
| pBreak->SetLineBreakTolerance(1); | |
| pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, NULL)); | |
| pBreak->SetFontSize(m_textParser.GetFontSize(m_pTextProvider, NULL)); | |
| 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.IsExistInXML()) { | |
| 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->SetLineWidth(fStart, fLineWidth); | |
| m_pBreak->SetLinePos(fStartPos); | |
| if (font.IsExistInXML()) { | |
| 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, NULL); | |
| m_pBreak->SetFontSize(fFontSize); | |
| m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, NULL)); | |
| m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f); | |
| } | |
| void CXFA_TextLayout::InitBreak(IFDE_CSSComputedStyle* pStyle, | |
| FDE_CSSDISPLAY eDisplay, | |
| FX_FLOAT fLineWidth, | |
| IFDE_XMLNode* pXMLNode, | |
| IFDE_CSSComputedStyle* pParentStyle) { | |
| if (pStyle == NULL) { | |
| 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 != NULL) { | |
| fStart = pRect->left.GetValue(); | |
| fLineWidth -= pRect->right.GetValue(); | |
| if (pPaddingRect != NULL) { | |
| 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 != NULL) { | |
| fStart += pParRect->left.GetValue(); | |
| fLineWidth -= pParRect->right.GetValue(); | |
| if (pParPaddingRect != NULL) { | |
| 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->SetLineWidth(fStart, fLineWidth); | |
| FX_FLOAT fIndent = pParaStyle->GetTextIndent().GetValue(); | |
| if (fIndent > 0) { | |
| fStart += fIndent; | |
| } | |
| m_pBreak->SetLinePos(fStart); | |
| m_pBreak->SetTabWidth(m_textParser.GetTabInterval(pStyle)); | |
| if (m_pTabstopContext == NULL) { | |
| m_pTabstopContext = new CXFA_TextTabstopsContext; | |
| } | |
| m_textParser.GetTabstops(pStyle, m_pTabstopContext); | |
| 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.Empty(); | |
| if (m_bRichText) { | |
| } else { | |
| wsText = m_pTextDataNode->GetContent(); | |
| } | |
| return wsText.GetLength(); | |
| } | |
| FX_FLOAT CXFA_TextLayout::GetLayoutHeight() { | |
| if (m_pLoader == NULL) { | |
| return 0; | |
| } | |
| int32_t iCount = m_pLoader->m_lineHeights.GetSize(); | |
| if (iCount == 0 && m_pLoader->m_fWidth > 0) { | |
| CFX_SizeF szMax, szDef; | |
| szMax.Set(m_pLoader->m_fWidth, m_pLoader->m_fHeight); | |
| szDef.Set(0, 0); | |
| 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 == NULL) { | |
| m_pLoader = new 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, szDef; | |
| szMax.Set(0, 0); | |
| szDef.Set(0, 0); | |
| m_pLoader->m_bSaveLineHeight = TRUE; | |
| m_pLoader->m_fLastPos = 0; | |
| CalcSize(szMax, szMax, szDef); | |
| m_pLoader->m_bSaveLineHeight = FALSE; | |
| fWidth = szDef.x; | |
| } | |
| return fWidth; | |
| } | |
| FX_BOOL CXFA_TextLayout::DoLayout(int32_t iBlockIndex, | |
| FX_FLOAT& fCalcHeight, | |
| FX_FLOAT fContentAreaHeight, | |
| FX_FLOAT fTextHeight) { | |
| if (m_pLoader == NULL) { | |
| 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.GetVAlgin(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.GetSize() > 0) { | |
| for (int32_t i = 0; i < iBlockIndex; i++) { | |
| fLinePos -= m_pLoader->m_BlocksHeight.ElementAt(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 (m_pLoader->m_BlocksHeight.GetSize() > iBlockIndex * 2 && | |
| (m_pLoader->m_BlocksHeight.GetAt(iBlockIndex * 2) == | |
| iBlockIndex)) { | |
| m_pLoader->m_BlocksHeight.SetAt(iBlockIndex * 2 + 1, fCalcHeight); | |
| } else { | |
| m_pLoader->m_BlocksHeight.Add((FX_FLOAT)iBlockIndex); | |
| m_pLoader->m_BlocksHeight.Add(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; | |
| } | |
| FX_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; | |
| } | |
| if (m_pBreak != NULL) { | |
| m_pBreak->Release(); | |
| } | |
| m_pBreak = 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, NULL); | |
| } | |
| if (m_pTabstopContext) { | |
| delete m_pTabstopContext; | |
| m_pTabstopContext = NULL; | |
| } | |
| defaultSize.Set(m_fMaxWidth, fLinePos); | |
| return TRUE; | |
| } | |
| FX_BOOL CXFA_TextLayout::Layout(const CFX_SizeF& size, FX_FLOAT* fHeight) { | |
| if (size.x < 1) { | |
| return FALSE; | |
| } | |
| Unload(); | |
| m_pBreak = CreateBreak(TRUE); | |
| if (m_pLoader != NULL) { | |
| 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); | |
| if (m_pTabstopContext) { | |
| delete m_pTabstopContext; | |
| m_pTabstopContext = NULL; | |
| } | |
| if (fHeight) { | |
| *fHeight = fLinePos; | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CXFA_TextLayout::Layout(int32_t iBlock) { | |
| if (m_pLoader == NULL || 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 = NULL; | |
| CFX_SizeF szText; | |
| szText.Set(m_pLoader->m_fWidth, m_pLoader->m_fHeight); | |
| int32_t iCount = m_Blocks.GetSize(); | |
| int32_t iBlocksHeightCount = m_pLoader->m_BlocksHeight.GetSize(); | |
| iBlocksHeightCount /= 2; | |
| if (iBlock < iBlocksHeightCount) { | |
| return TRUE; | |
| } | |
| if (iBlock == iBlocksHeightCount) { | |
| Unload(); | |
| m_pBreak = CreateBreak(TRUE); | |
| fLinePos = m_pLoader->m_fStartLineOffset; | |
| for (int32_t i = 0; i < iBlocksHeightCount; i++) { | |
| fLinePos -= m_pLoader->m_BlocksHeight.ElementAt(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 != NULL) { | |
| iBlock *= 2; | |
| if (iBlock < iCount - 2) { | |
| m_pLoader->m_iTotalLines = m_Blocks.ElementAt(iBlock + 1); | |
| } | |
| m_pBreak->Reset(); | |
| if (m_bRichText) { | |
| IFDE_XMLNode* pContainerNode = GetXMLContainerNode(); | |
| if (!pContainerNode) { | |
| return TRUE; | |
| } | |
| IFDE_XMLNode* pXMLNode = m_pLoader->m_pXMLNode; | |
| if (pXMLNode == NULL) { | |
| return TRUE; | |
| } | |
| IFDE_XMLNode* pSaveXMLNode = m_pLoader->m_pXMLNode; | |
| for (; pXMLNode; | |
| pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling)) { | |
| FX_BOOL bFlag = LoadRichText(pXMLNode, szText, fLinePos, | |
| m_pLoader->m_pParentStyle, TRUE); | |
| if (!bFlag) { | |
| break; | |
| } | |
| } | |
| while (pXMLNode == NULL) { | |
| pXMLNode = pSaveXMLNode->GetNodeItem(IFDE_XMLNode::Parent); | |
| if (pXMLNode == pContainerNode) { | |
| break; | |
| } | |
| FX_BOOL bFlag = | |
| LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle, | |
| TRUE, NULL, FALSE); | |
| if (!bFlag) { | |
| break; | |
| } | |
| pSaveXMLNode = pXMLNode; | |
| pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling); | |
| if (!pXMLNode) { | |
| continue; | |
| } | |
| for (; pXMLNode; | |
| pXMLNode = pXMLNode->GetNodeItem(IFDE_XMLNode::NextSibling)) { | |
| FX_BOOL bFlag = LoadRichText(pXMLNode, szText, fLinePos, | |
| m_pLoader->m_pParentStyle, TRUE); | |
| if (!bFlag) { | |
| break; | |
| } | |
| } | |
| } | |
| } else { | |
| pNode = m_pLoader->m_pNode; | |
| if (pNode == NULL) { | |
| return TRUE; | |
| } | |
| LoadText(pNode, szText, fLinePos, TRUE); | |
| } | |
| } | |
| if (iBlock == iCount) { | |
| if (m_pTabstopContext != NULL) { | |
| delete m_pTabstopContext; | |
| m_pTabstopContext = NULL; | |
| } | |
| if (m_pLoader != NULL) { | |
| delete m_pLoader; | |
| m_pLoader = NULL; | |
| } | |
| } | |
| 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; | |
| } | |
| FX_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 = m_pLoader->m_BlocksHeight.GetSize(); | |
| iBlockHeightCount /= 2; | |
| if (iBlockHeightCount >= iBlockIndex) { | |
| for (int32_t i = 0; i < iBlockIndex; i++) { | |
| fLinePos -= m_pLoader->m_BlocksHeight.ElementAt(i * 2 + 1); | |
| } | |
| } else { | |
| fLinePos = 0; | |
| } | |
| iLineIndex = m_Blocks.ElementAt(iBlockCount - 1) + | |
| m_Blocks.ElementAt(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); | |
| } | |
| } | |
| FX_BOOL CXFA_TextLayout::DrawString(CFX_RenderDevice* pFxDevice, | |
| const CFX_Matrix& tmDoc2Device, | |
| const CFX_RectF& rtClip, | |
| int32_t iBlock) { | |
| IFDE_RenderDevice* pDevice = IFDE_RenderDevice::Create(pFxDevice); | |
| if (pDevice == NULL) { | |
| return FALSE; | |
| } | |
| FDE_HDEVICESTATE state = pDevice->SaveState(); | |
| pDevice->SetClipRect(rtClip); | |
| IFDE_SolidBrush* pSolidBrush = | |
| (IFDE_SolidBrush*)IFDE_Brush::Create(FDE_BRUSHTYPE_Solid); | |
| IFDE_Pen* pPen = IFDE_Pen::Create(); | |
| FXSYS_assert(pDevice != NULL && pSolidBrush != NULL && pPen != NULL); | |
| if (m_pieceLines.GetSize() == 0) { | |
| int32_t iBlockCount = CountBlocks(); | |
| for (int32_t i = 0; i < iBlockCount; i++) { | |
| Layout(i); | |
| } | |
| } | |
| FXTEXT_CHARPOS* pCharPos = NULL; | |
| 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++) { | |
| XFA_LPCTEXTPIECE 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, pSolidBrush, pPieceLine, j, pCharPos, tmDoc2Device); | |
| } | |
| for (j = 0; j < iPieces; j++) { | |
| RenderPath(pDevice, pPen, pPieceLine, j, pCharPos, tmDoc2Device); | |
| } | |
| } | |
| pDevice->RestoreState(state); | |
| FX_Free(pCharPos); | |
| pSolidBrush->Release(); | |
| pPen->Release(); | |
| pDevice->Release(); | |
| return iPieceLines; | |
| } | |
| void CXFA_TextLayout::UpdateAlign(FX_FLOAT fHeight, FX_FLOAT fBottom) { | |
| fHeight -= fBottom; | |
| if (fHeight < 0.1f) { | |
| return; | |
| } | |
| switch (m_textParser.GetVAlgin(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_LPTEXTPIECE pPiece = pPieceLine->m_textPieces.GetAt(j); | |
| CFX_RectF& rect = pPiece->rtPiece; | |
| rect.top += fHeight; | |
| } | |
| } | |
| } | |
| FX_BOOL CXFA_TextLayout::Loader(const CFX_SizeF& szText, | |
| FX_FLOAT& fLinePos, | |
| FX_BOOL bSavePieces) { | |
| if (m_pAllocator == NULL) { | |
| m_pAllocator = FX_CreateAllocator(FX_ALLOCTYPE_Static, 256, 0); | |
| } | |
| GetTextDataNode(); | |
| if (m_pTextDataNode == NULL) { | |
| return TRUE; | |
| } | |
| if (m_bRichText) { | |
| IFDE_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, | |
| FX_BOOL bSavePieces) { | |
| InitBreak(szText.x); | |
| CXFA_Para para = m_pTextProvider->GetParaNode(); | |
| FX_FLOAT fSpaceAbove = 0; | |
| if (para.IsExistInXML()) { | |
| 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" "); | |
| FX_BOOL bRet = AppendChar(wsText, fLinePos, fSpaceAbove, bSavePieces); | |
| if (bRet && m_pLoader != NULL) { | |
| m_pLoader->m_pNode = pNode; | |
| } else { | |
| EndBreak(FX_RTFBREAK_ParagraphBreak, fLinePos, bSavePieces); | |
| } | |
| } | |
| FX_BOOL CXFA_TextLayout::LoadRichText(IFDE_XMLNode* pXMLNode, | |
| const CFX_SizeF& szText, | |
| FX_FLOAT& fLinePos, | |
| IFDE_CSSComputedStyle* pParentStyle, | |
| FX_BOOL bSavePieces, | |
| CXFA_LinkUserData* pLinkData, | |
| FX_BOOL bEndBreak, | |
| FX_BOOL bIsOl, | |
| int32_t iLiCount) { | |
| if (pXMLNode == NULL) { | |
| return FALSE; | |
| } | |
| CXFA_TextParseContext* pContext = | |
| m_textParser.GetParseContextFromMap(pXMLNode); | |
| FDE_CSSDISPLAY eDisplay = FDE_CSSDISPLAY_None; | |
| FX_BOOL bContentNode = FALSE; | |
| FX_FLOAT fSpaceBelow = 0; | |
| IFDE_CSSComputedStyle* pStyle = NULL; | |
| CFX_WideString wsName; | |
| if (bEndBreak) { | |
| FX_BOOL bCurOl = FALSE; | |
| FX_BOOL bCurLi = FALSE; | |
| IFDE_XMLElement* pElement = NULL; | |
| if (pContext != NULL) { | |
| 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 = (IFDE_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 != NULL) && | |
| (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; | |
| FXSYS_assert(pElement); | |
| pElement->GetString(FX_WSTRC(L"href").GetPtr(), wsLinkContent); | |
| if (!wsLinkContent.IsEmpty()) { | |
| pLinkData = FDE_NewWith(m_pAllocator) CXFA_LinkUserData( | |
| m_pAllocator, | |
| wsLinkContent.GetBuffer(wsLinkContent.GetLength())); | |
| wsLinkContent.ReleaseBuffer(wsLinkContent.GetLength()); | |
| } | |
| } | |
| int32_t iTabCount = | |
| m_textParser.CountTabs(bContentNode ? pParentStyle : pStyle); | |
| FX_BOOL bSpaceRun = | |
| m_textParser.IsSpaceRun(bContentNode ? pParentStyle : pStyle); | |
| CFX_WideString wsText; | |
| if (bContentNode && iTabCount == 0) { | |
| ((IFDE_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) | |
| ; | |
| else { | |
| m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE; | |
| } | |
| } | |
| if (wsText.GetLength() > 0) { | |
| if (m_pLoader == NULL || m_pLoader->m_iChar == 0) { | |
| if (pLinkData) { | |
| pLinkData->AddRef(); | |
| } | |
| CXFA_TextUserData* pUserData = FDE_NewWith(m_pAllocator) | |
| CXFA_TextUserData(m_pAllocator, | |
| 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 != NULL) { | |
| pStyle->Release(); | |
| } | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| } | |
| } | |
| } | |
| FX_BOOL ret = TRUE; | |
| for (IFDE_XMLNode* pChildNode = | |
| pXMLNode->GetNodeItem(IFDE_XMLNode::FirstChild); | |
| pChildNode; | |
| pChildNode = pChildNode->GetNodeItem(IFDE_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 != NULL) { | |
| eDisplay = pContext->GetDisplay(); | |
| } | |
| } | |
| if (m_bBlockContinue) { | |
| if (pContext != NULL && !bContentNode) { | |
| FX_DWORD 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(IFDE_XMLNode::NextSibling); | |
| m_pLoader->m_pParentStyle = pParentStyle; | |
| } | |
| return FALSE; | |
| } | |
| } | |
| } | |
| if (pStyle != NULL) { | |
| pStyle->Release(); | |
| } | |
| return TRUE; | |
| } | |
| FX_BOOL CXFA_TextLayout::AppendChar(const CFX_WideString& wsText, | |
| FX_FLOAT& fLinePos, | |
| FX_FLOAT fSpaceAbove, | |
| FX_BOOL bSavePieces) { | |
| FX_DWORD 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 != NULL) { | |
| 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; | |
| } | |
| FX_BOOL CXFA_TextLayout::IsEnd(FX_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(FX_DWORD dwStatus, | |
| FX_FLOAT& fLinePos, | |
| FX_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 == NULL || m_pTabstopContext->m_iTabCount == 0) { | |
| return; | |
| } | |
| if (pStyle == NULL || pPieceLine == NULL) { | |
| return; | |
| } | |
| int32_t iPieces = pPieceLine->m_textPieces.GetSize(); | |
| if (iPieces == 0) { | |
| return; | |
| } | |
| XFA_LPTEXTPIECE 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_LPTEXTPIECE 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); | |
| FX_DWORD dwAlgin = pTabstops->dwAlign; | |
| if (dwAlgin == FX_HashCode_String_GetW(L"center", 6)) { | |
| fLeft = pPiece->rtPiece.width / 2.0f; | |
| } else if (dwAlgin == FX_HashCode_String_GetW(L"right", 5) || | |
| dwAlgin == FX_HashCode_String_GetW(L"before", 6)) { | |
| fLeft = pPiece->rtPiece.width; | |
| } else if (dwAlgin == FX_HashCode_String_GetW(L"decimal", 7)) { | |
| 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(FX_DWORD dwStatus, | |
| FX_FLOAT& fLinePos, | |
| FX_BOOL bSavePieces, | |
| FX_BOOL bEndBreak) { | |
| int32_t iPieces = m_pBreak->CountBreakPieces(); | |
| if (iPieces < 1) { | |
| return; | |
| } | |
| IFDE_CSSComputedStyle* pStyle = NULL; | |
| if (bSavePieces) { | |
| CXFA_PieceLine* pPieceLine = FDE_NewWith(m_pAllocator) 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 != NULL) { | |
| pStyle = pUserData->m_pStyle; | |
| } | |
| FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f; | |
| XFA_LPTEXTPIECE pTP = | |
| (XFA_LPTEXTPIECE)m_pAllocator->Alloc(sizeof(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 != NULL && pUserData->m_pLinkData != NULL) { | |
| pUserData->m_pLinkData->AddRef(); | |
| pTP->pLinkData = pUserData->m_pLinkData; | |
| } else { | |
| pTP->pLinkData = NULL; | |
| } | |
| DoTabstops(pStyle, pPieceLine); | |
| } | |
| for (i = 0; i < iPieces; i++) { | |
| XFA_LPTEXTPIECE 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 != NULL) { | |
| 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->AddRef(); | |
| } | |
| m_pBreak->ClearBreakPieces(); | |
| if (dwStatus == FX_RTFBREAK_ParagraphBreak) { | |
| m_pBreak->Reset(); | |
| if (!pStyle && bEndBreak) { | |
| CXFA_Para para = m_pTextProvider->GetParaNode(); | |
| if (para.IsExistInXML()) { | |
| 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->SetLinePos(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->SetLinePos(fStart); | |
| pStyle->Release(); | |
| } | |
| m_iLines++; | |
| } | |
| void CXFA_TextLayout::RenderString(IFDE_RenderDevice* pDevice, | |
| IFDE_SolidBrush* pBrush, | |
| CXFA_PieceLine* pPieceLine, | |
| int32_t iPiece, | |
| FXTEXT_CHARPOS* pCharPos, | |
| const CFX_Matrix& tmDoc2Device) { | |
| XFA_LPCTEXTPIECE 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(IFDE_RenderDevice* pDevice, | |
| IFDE_Pen* pPen, | |
| CXFA_PieceLine* pPieceLine, | |
| int32_t iPiece, | |
| FXTEXT_CHARPOS* pCharPos, | |
| const CFX_Matrix& tmDoc2Device) { | |
| XFA_TEXTPIECE* pPiece = pPieceLine->m_textPieces.GetAt(iPiece); | |
| FX_BOOL bNoUnderline = pPiece->iUnderline < 1 || pPiece->iUnderline > 2; | |
| FX_BOOL bNoLineThrough = pPiece->iLineThrough < 1 || pPiece->iLineThrough > 2; | |
| if (bNoUnderline && bNoLineThrough) { | |
| return; | |
| } | |
| pPen->SetColor(pPiece->dwColor); | |
| IFDE_Path* pPath = IFDE_Path::Create(); | |
| int32_t iChars = GetDisplayPos(pPiece, pCharPos); | |
| if (iChars > 0) { | |
| CFX_PointF pt1, pt2; | |
| FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f; | |
| int32_t i = 0; | |
| 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 (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)) { | |
| goto XFA_RenderPathRet; | |
| } | |
| 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) { | |
| goto XFA_RenderPathRet; | |
| } | |
| 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) { | |
| goto XFA_RenderPathRet; | |
| } | |
| FX_FLOAT fOrgX = 0.0f, fEndX = 0.0f; | |
| pPiece = pPieceLine->m_textPieces.GetAt(iPiecePrev); | |
| iChars = GetDisplayPos(pPiece, pCharPos); | |
| if (iChars < 1) { | |
| goto XFA_RenderPathRet; | |
| } | |
| 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) { | |
| goto XFA_RenderPathRet; | |
| } | |
| fEndX = pCharPos[0].m_OriginX; | |
| CFX_PointF pt1, pt2; | |
| pt1.x = fOrgX, pt2.x = fEndX; | |
| FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f; | |
| int32_t i = 0; | |
| for (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 (i = 0; i < pPiece->iLineThrough; i++) { | |
| pt1.y = pt2.y = fEndY; | |
| pPath->AddLine(pt1, pt2); | |
| fEndY += 2.0f; | |
| } | |
| } | |
| pDevice->DrawPath(pPen, 1, pPath, &tmDoc2Device); | |
| XFA_RenderPathRet: | |
| pPath->Release(); | |
| } | |
| int32_t CXFA_TextLayout::GetDisplayPos(XFA_LPCTEXTPIECE pPiece, | |
| FXTEXT_CHARPOS* pCharPos, | |
| FX_BOOL bCharCode) { | |
| if (pPiece == NULL) { | |
| return 0; | |
| } | |
| FX_RTFTEXTOBJ tr; | |
| if (!ToRun(pPiece, tr)) { | |
| return 0; | |
| } | |
| return m_pBreak->GetDisplayPos(&tr, pCharPos, bCharCode); | |
| } | |
| FX_BOOL CXFA_TextLayout::ToRun(XFA_LPCTEXTPIECE 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; | |
| } |