| // Copyright 2014 PDFium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| |
| #ifndef XFA_FXFA_APP_XFA_TEXTLAYOUT_H_ |
| #define XFA_FXFA_APP_XFA_TEXTLAYOUT_H_ |
| |
| #include <map> |
| #include <memory> |
| |
| #include "xfa/fde/css/fde_css.h" |
| #include "xfa/fde/fde_gedevice.h" |
| #include "xfa/fgas/layout/fgas_rtfbreak.h" |
| #include "xfa/fxfa/parser/xfa_object.h" |
| #include "xfa/fxfa/xfa_ffdoc.h" |
| |
| #define XFA_LOADERCNTXTFLG_FILTERSPACE 0x001 |
| |
| class CFDE_CSSStyleSelector; |
| class CXFA_Para; |
| class CXFA_Font; |
| class CXFA_TextProvider; |
| class CXFA_TextTabstopsContext; |
| |
| class CXFA_CSSTagProvider { |
| public: |
| using AttributeMap = std::map<CFX_WideString, CFX_WideString>; |
| |
| CXFA_CSSTagProvider(); |
| ~CXFA_CSSTagProvider(); |
| |
| CFX_WideString GetTagName() { return m_wsTagName; } |
| |
| AttributeMap::iterator begin() { return m_Attributes.begin(); } |
| AttributeMap::iterator end() { return m_Attributes.end(); } |
| |
| bool empty() const { return m_Attributes.empty(); } |
| |
| void SetTagNameObj(const CFX_WideString& wsName) { m_wsTagName = wsName; } |
| void SetAttribute(const CFX_WideString& wsAttr, |
| const CFX_WideString& wsValue) { |
| m_Attributes.insert({wsAttr, wsValue}); |
| } |
| |
| bool m_bTagAvailable; |
| bool m_bContent; |
| |
| protected: |
| CFX_WideString m_wsTagName; |
| AttributeMap m_Attributes; |
| }; |
| |
| class CXFA_TextParseContext : public CFX_Target { |
| public: |
| CXFA_TextParseContext(); |
| ~CXFA_TextParseContext() override; |
| |
| void SetDisplay(FDE_CSSDISPLAY eDisplay) { m_eDisplay = eDisplay; } |
| FDE_CSSDISPLAY GetDisplay() const { return m_eDisplay; } |
| void SetDecls(const CFDE_CSSDeclaration** ppDeclArray, int32_t iDeclCount); |
| const CFDE_CSSDeclaration** GetDecls() { |
| return const_cast<const CFDE_CSSDeclaration**>(m_ppMatchedDecls); |
| } |
| uint32_t CountDecls() const { return m_dwMatchedDecls; } |
| |
| IFDE_CSSComputedStyle* m_pParentStyle; |
| |
| protected: |
| CFDE_CSSDeclaration** m_ppMatchedDecls; |
| uint32_t m_dwMatchedDecls; |
| FDE_CSSDISPLAY m_eDisplay; |
| }; |
| |
| class CXFA_TextParser { |
| public: |
| CXFA_TextParser(); |
| virtual ~CXFA_TextParser(); |
| |
| void Reset(); |
| void DoParse(CFDE_XMLNode* pXMLContainer, CXFA_TextProvider* pTextProvider); |
| IFDE_CSSComputedStyle* CreateRootStyle(CXFA_TextProvider* pTextProvider); |
| IFDE_CSSComputedStyle* ComputeStyle(CFDE_XMLNode* pXMLNode, |
| IFDE_CSSComputedStyle* pParentStyle); |
| bool IsParsed() const { return !!m_pAllocator; } |
| |
| int32_t GetVAlign(CXFA_TextProvider* pTextProvider) const; |
| FX_FLOAT GetTabInterval(IFDE_CSSComputedStyle* pStyle) const; |
| int32_t CountTabs(IFDE_CSSComputedStyle* pStyle) const; |
| bool IsSpaceRun(IFDE_CSSComputedStyle* pStyle) const; |
| bool GetTabstops(IFDE_CSSComputedStyle* pStyle, |
| CXFA_TextTabstopsContext* pTabstopContext); |
| CFGAS_GEFont* GetFont(CXFA_TextProvider* pTextProvider, |
| IFDE_CSSComputedStyle* pStyle) const; |
| FX_FLOAT GetFontSize(CXFA_TextProvider* pTextProvider, |
| IFDE_CSSComputedStyle* pStyle) const; |
| int32_t GetHorScale(CXFA_TextProvider* pTextProvider, |
| IFDE_CSSComputedStyle* pStyle, |
| CFDE_XMLNode* pXMLNode) const; |
| int32_t GetVerScale(CXFA_TextProvider* pTextProvider, |
| IFDE_CSSComputedStyle* pStyle) const; |
| void GetUnderline(CXFA_TextProvider* pTextProvider, |
| IFDE_CSSComputedStyle* pStyle, |
| int32_t& iUnderline, |
| int32_t& iPeriod) const; |
| void GetLinethrough(CXFA_TextProvider* pTextProvider, |
| IFDE_CSSComputedStyle* pStyle, |
| int32_t& iLinethrough) const; |
| FX_ARGB GetColor(CXFA_TextProvider* pTextProvider, |
| IFDE_CSSComputedStyle* pStyle) const; |
| FX_FLOAT GetBaseline(CXFA_TextProvider* pTextProvider, |
| IFDE_CSSComputedStyle* pStyle) const; |
| FX_FLOAT GetLineHeight(CXFA_TextProvider* pTextProvider, |
| IFDE_CSSComputedStyle* pStyle, |
| bool bFirst, |
| FX_FLOAT fVerScale) const; |
| bool GetEmbbedObj(CXFA_TextProvider* pTextProvider, |
| CFDE_XMLNode* pXMLNode, |
| CFX_WideString& wsValue); |
| CXFA_TextParseContext* GetParseContextFromMap(CFDE_XMLNode* pXMLNode); |
| |
| protected: |
| bool TagValidate(const CFX_WideString& str) const; |
| |
| private: |
| void InitCSSData(CXFA_TextProvider* pTextProvider); |
| void ParseRichText(CFDE_XMLNode* pXMLNode, |
| IFDE_CSSComputedStyle* pParentStyle); |
| void ParseTagInfo(CFDE_XMLNode* pXMLNode, CXFA_CSSTagProvider& tagProvider); |
| IFDE_CSSStyleSheet* LoadDefaultSheetStyle(); |
| IFDE_CSSComputedStyle* CreateStyle(IFDE_CSSComputedStyle* pParentStyle); |
| std::unique_ptr<IFX_MemoryAllocator> m_pAllocator; |
| std::unique_ptr<CFDE_CSSStyleSelector> m_pSelector; |
| IFDE_CSSStyleSheet* m_pUASheet; |
| CFX_MapPtrTemplate<CFDE_XMLNode*, CXFA_TextParseContext*> |
| m_mapXMLNodeToParseContext; |
| }; |
| |
| class CXFA_LoaderContext { |
| public: |
| CXFA_LoaderContext(); |
| ~CXFA_LoaderContext(); |
| |
| bool m_bSaveLineHeight; |
| FX_FLOAT m_fWidth; |
| FX_FLOAT m_fHeight; |
| FX_FLOAT m_fLastPos; |
| FX_FLOAT m_fStartLineOffset; |
| int32_t m_iChar; |
| int32_t m_iLines; |
| int32_t m_iTotalLines; |
| CFDE_XMLNode* m_pXMLNode; |
| CXFA_Node* m_pNode; |
| IFDE_CSSComputedStyle* m_pParentStyle; |
| CFX_ArrayTemplate<FX_FLOAT> m_lineHeights; |
| uint32_t m_dwFlags; |
| CFX_FloatArray m_BlocksHeight; |
| }; |
| |
| class CXFA_LinkUserData : public IFX_Retainable, public CFX_Target { |
| public: |
| CXFA_LinkUserData(IFX_MemoryAllocator* pAllocator, FX_WCHAR* pszText); |
| ~CXFA_LinkUserData() override; |
| |
| // IFX_Retainable: |
| uint32_t Retain() override; |
| uint32_t Release() override; |
| |
| const FX_WCHAR* GetLinkURL(); |
| |
| protected: |
| IFX_MemoryAllocator* m_pAllocator; |
| uint32_t m_dwRefCount; |
| CFX_WideString m_wsURLContent; |
| }; |
| |
| class CXFA_TextUserData : public IFX_Retainable, public CFX_Target { |
| public: |
| CXFA_TextUserData(IFX_MemoryAllocator* pAllocator, |
| IFDE_CSSComputedStyle* pStyle); |
| CXFA_TextUserData(IFX_MemoryAllocator* pAllocator, |
| IFDE_CSSComputedStyle* pStyle, |
| CXFA_LinkUserData* pLinkData); |
| ~CXFA_TextUserData() override; |
| |
| // IFX_Retainable: |
| uint32_t Retain() override; |
| uint32_t Release() override; |
| |
| IFDE_CSSComputedStyle* m_pStyle; |
| CXFA_LinkUserData* m_pLinkData; |
| |
| protected: |
| IFX_MemoryAllocator* m_pAllocator; |
| uint32_t m_dwRefCount; |
| }; |
| |
| class XFA_TextPiece : public CFX_Target { |
| public: |
| XFA_TextPiece(); |
| ~XFA_TextPiece() override; |
| |
| FX_WCHAR* pszText; |
| int32_t iChars; |
| int32_t* pWidths; |
| int32_t iHorScale; |
| int32_t iVerScale; |
| int32_t iBidiLevel; |
| int32_t iUnderline; |
| int32_t iPeriod; |
| int32_t iLineThrough; |
| CFGAS_GEFont* pFont; |
| FX_ARGB dwColor; |
| FX_FLOAT fFontSize; |
| CFX_RectF rtPiece; |
| CXFA_LinkUserData* pLinkData; |
| }; |
| typedef CFX_ArrayTemplate<XFA_TextPiece*> CXFA_PieceArray; |
| |
| class CXFA_PieceLine : public CFX_Target { |
| public: |
| CXFA_PieceLine(); |
| ~CXFA_PieceLine() override; |
| |
| CXFA_PieceArray m_textPieces; |
| CFX_Int32Array m_charCounts; |
| }; |
| typedef CFX_ArrayTemplate<CXFA_PieceLine*> CXFA_PieceLineArray; |
| |
| struct XFA_TABSTOPS { |
| uint32_t dwAlign; |
| FX_FLOAT fTabstops; |
| }; |
| |
| class CXFA_TextTabstopsContext { |
| public: |
| CXFA_TextTabstopsContext(); |
| ~CXFA_TextTabstopsContext(); |
| |
| void Append(uint32_t dwAlign, FX_FLOAT fTabstops); |
| void RemoveAll(); |
| void Reset(); |
| |
| CFX_ArrayTemplate<XFA_TABSTOPS> m_tabstops; |
| int32_t m_iTabCount; |
| int32_t m_iTabIndex; |
| bool m_bTabstops; |
| FX_FLOAT m_fTabWidth; |
| FX_FLOAT m_fLeft; |
| }; |
| |
| class CXFA_TextLayout { |
| public: |
| explicit CXFA_TextLayout(CXFA_TextProvider* pTextProvider); |
| ~CXFA_TextLayout(); |
| |
| int32_t GetText(CFX_WideString& wsText); |
| FX_FLOAT GetLayoutHeight(); |
| FX_FLOAT StartLayout(FX_FLOAT fWidth = -1); |
| bool DoLayout(int32_t iBlockIndex, |
| FX_FLOAT& fCalcHeight, |
| FX_FLOAT fContentAreaHeight = -1, |
| FX_FLOAT fTextHeight = -1); |
| |
| bool CalcSize(const CFX_SizeF& minSize, |
| const CFX_SizeF& maxSize, |
| CFX_SizeF& defaultSize); |
| bool Layout(const CFX_SizeF& size, FX_FLOAT* fHeight = nullptr); |
| void ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex); |
| bool DrawString(CFX_RenderDevice* pFxDevice, |
| const CFX_Matrix& tmDoc2Device, |
| const CFX_RectF& rtClip, |
| int32_t iBlock = 0); |
| bool IsLoaded() const { return m_pieceLines.GetSize() > 0; } |
| void Unload(); |
| const CXFA_PieceLineArray* GetPieceLines(); |
| |
| bool m_bHasBlock; |
| CFX_Int32Array m_Blocks; |
| |
| private: |
| void GetTextDataNode(); |
| CFDE_XMLNode* GetXMLContainerNode(); |
| CFX_RTFBreak* CreateBreak(bool bDefault); |
| void InitBreak(FX_FLOAT fLineWidth); |
| void InitBreak(IFDE_CSSComputedStyle* pStyle, |
| FDE_CSSDISPLAY eDisplay, |
| FX_FLOAT fLineWidth, |
| CFDE_XMLNode* pXMLNode, |
| IFDE_CSSComputedStyle* pParentStyle = nullptr); |
| bool Loader(const CFX_SizeF& szText, |
| FX_FLOAT& fLinePos, |
| bool bSavePieces = true); |
| void LoadText(CXFA_Node* pNode, |
| const CFX_SizeF& szText, |
| FX_FLOAT& fLinePos, |
| bool bSavePieces); |
| bool LoadRichText(CFDE_XMLNode* pXMLNode, |
| const CFX_SizeF& szText, |
| FX_FLOAT& fLinePos, |
| IFDE_CSSComputedStyle* pParentStyle, |
| bool bSavePieces, |
| CXFA_LinkUserData* pLinkData = nullptr, |
| bool bEndBreak = true, |
| bool bIsOl = false, |
| int32_t iLiCount = 0); |
| bool AppendChar(const CFX_WideString& wsText, |
| FX_FLOAT& fLinePos, |
| FX_FLOAT fSpaceAbove, |
| bool bSavePieces); |
| void AppendTextLine(uint32_t dwStatus, |
| FX_FLOAT& fLinePos, |
| bool bSavePieces, |
| bool bEndBreak = false); |
| void EndBreak(uint32_t dwStatus, FX_FLOAT& fLinePos, bool bDefault); |
| bool IsEnd(bool bSavePieces); |
| void ProcessText(CFX_WideString& wsText); |
| void UpdateAlign(FX_FLOAT fHeight, FX_FLOAT fBottom); |
| void RenderString(CFDE_RenderDevice* pDevice, |
| CFDE_Brush* pBrush, |
| CXFA_PieceLine* pPieceLine, |
| int32_t iPiece, |
| FXTEXT_CHARPOS* pCharPos, |
| const CFX_Matrix& tmDoc2Device); |
| void RenderPath(CFDE_RenderDevice* pDevice, |
| CFDE_Pen* pPen, |
| CXFA_PieceLine* pPieceLine, |
| int32_t iPiece, |
| FXTEXT_CHARPOS* pCharPos, |
| const CFX_Matrix& tmDoc2Device); |
| int32_t GetDisplayPos(const XFA_TextPiece* pPiece, |
| FXTEXT_CHARPOS* pCharPos, |
| bool bCharCode = false); |
| bool ToRun(const XFA_TextPiece* pPiece, FX_RTFTEXTOBJ& tr); |
| void DoTabstops(IFDE_CSSComputedStyle* pStyle, CXFA_PieceLine* pPieceLine); |
| bool Layout(int32_t iBlock); |
| int32_t CountBlocks() const; |
| |
| CXFA_TextProvider* m_pTextProvider; |
| CXFA_Node* m_pTextDataNode; |
| bool m_bRichText; |
| std::unique_ptr<IFX_MemoryAllocator> m_pAllocator; |
| std::unique_ptr<CFX_RTFBreak> m_pBreak; |
| std::unique_ptr<CXFA_LoaderContext> m_pLoader; |
| int32_t m_iLines; |
| FX_FLOAT m_fMaxWidth; |
| CXFA_TextParser m_textParser; |
| CXFA_PieceLineArray m_pieceLines; |
| std::unique_ptr<CXFA_TextTabstopsContext> m_pTabstopContext; |
| bool m_bBlockContinue; |
| }; |
| |
| #endif // XFA_FXFA_APP_XFA_TEXTLAYOUT_H_ |