blob: 0078ec74bbfbff3f8dcdecdd1291f1bb5b59dca6 [file] [log] [blame]
// 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 _FXFA_TEXTLAYOUT_H
#define _FXFA_TEXTLAYOUT_H
#define XFA_LOADERCNTXTFLG_FILTERSPACE 0x001
class CXFA_TextTabstopsContext;
class IXFA_TextProvider {
public:
virtual ~IXFA_TextProvider() {}
virtual CXFA_Node* GetTextNode(FX_BOOL& bRichText) = 0;
virtual CXFA_Para GetParaNode() = 0;
virtual CXFA_Font GetFontNode() = 0;
virtual FX_BOOL IsCheckButtonAndAutoWidth() = 0;
virtual CXFA_FFDoc* GetDocNode() = 0;
virtual FX_BOOL GetEmbbedObj(FX_BOOL bURI,
FX_BOOL bRaw,
const CFX_WideString& wsAttr,
CFX_WideString& wsValue) = 0;
};
class CXFA_CSSTagProvider : public IFDE_CSSTagProvider {
public:
CXFA_CSSTagProvider() : m_bTagAviliable(FALSE), m_bContent(FALSE) {}
virtual ~CXFA_CSSTagProvider();
virtual CFX_WideStringC GetTagName() { return m_wsTagName; }
virtual FX_POSITION GetFirstAttribute() {
return m_Attributes.GetStartPosition();
}
virtual void GetNextAttribute(FX_POSITION& pos,
CFX_WideStringC& wsAttr,
CFX_WideStringC& wsValue);
void SetTagNameObj(const CFX_WideString& wsName) { m_wsTagName = wsName; }
void SetAttribute(const CFX_WideString& wsAttr,
const CFX_WideString& wsValue);
FX_BOOL m_bTagAviliable;
FX_BOOL m_bContent;
protected:
CFX_WideString m_wsTagName;
CFX_MapPtrToPtr m_Attributes;
};
class CXFA_TextParseContext : public CFX_Target {
public:
CXFA_TextParseContext()
: m_pParentStyle(nullptr),
m_ppMatchedDecls(nullptr),
m_dwMatchedDecls(0),
m_eDisplay(FDE_CSSDISPLAY_None) {}
~CXFA_TextParseContext() {
if (m_pParentStyle)
m_pParentStyle->Release();
FX_Free(m_ppMatchedDecls);
}
void SetDisplay(FDE_CSSDISPLAY eDisplay) { m_eDisplay = eDisplay; }
FDE_CSSDISPLAY GetDisplay() const { return m_eDisplay; }
void SetDecls(const IFDE_CSSDeclaration** ppDeclArray, int32_t iDeclCount);
const IFDE_CSSDeclaration** GetDecls() {
return (const IFDE_CSSDeclaration**)m_ppMatchedDecls;
}
FX_DWORD CountDecls() const { return m_dwMatchedDecls; }
IFDE_CSSComputedStyle* m_pParentStyle;
protected:
IFDE_CSSDeclaration** m_ppMatchedDecls;
FX_DWORD m_dwMatchedDecls : 28;
FDE_CSSDISPLAY m_eDisplay : 4;
};
class CXFA_TextParser {
public:
CXFA_TextParser() : m_pAllocator(NULL), m_pSelector(NULL), m_pUASheet(NULL) {}
virtual ~CXFA_TextParser();
void Reset();
void DoParse(IFDE_XMLNode* pXMLContainer, IXFA_TextProvider* pTextProvider);
IFDE_CSSComputedStyle* CreateRootStyle(IXFA_TextProvider* pTextProvider);
IFDE_CSSComputedStyle* ComputeStyle(IFDE_XMLNode* pXMLNode,
IFDE_CSSComputedStyle* pParentStyle);
FX_BOOL IsParsed() const { return m_pAllocator != NULL; }
int32_t GetVAlgin(IXFA_TextProvider* pTextProvider) const;
FX_FLOAT GetTabInterval(IFDE_CSSComputedStyle* pStyle) const;
int32_t CountTabs(IFDE_CSSComputedStyle* pStyle) const;
FX_BOOL IsSpaceRun(IFDE_CSSComputedStyle* pStyle) const;
FX_BOOL GetTabstops(IFDE_CSSComputedStyle* pStyle,
CXFA_TextTabstopsContext* pTabstopContext);
IFX_Font* GetFont(IXFA_TextProvider* pTextProvider,
IFDE_CSSComputedStyle* pStyle) const;
FX_FLOAT GetFontSize(IXFA_TextProvider* pTextProvider,
IFDE_CSSComputedStyle* pStyle) const;
int32_t GetHorScale(IXFA_TextProvider* pTextProvider,
IFDE_CSSComputedStyle* pStyle,
IFDE_XMLNode* pXMLNode) const;
int32_t GetVerScale(IXFA_TextProvider* pTextProvider,
IFDE_CSSComputedStyle* pStyle) const;
void GetUnderline(IXFA_TextProvider* pTextProvider,
IFDE_CSSComputedStyle* pStyle,
int32_t& iUnderline,
int32_t& iPeriod) const;
void GetLinethrough(IXFA_TextProvider* pTextProvider,
IFDE_CSSComputedStyle* pStyle,
int32_t& iLinethrough) const;
FX_ARGB GetColor(IXFA_TextProvider* pTextProvider,
IFDE_CSSComputedStyle* pStyle) const;
FX_FLOAT GetBaseline(IXFA_TextProvider* pTextProvider,
IFDE_CSSComputedStyle* pStyle) const;
FX_FLOAT GetLineHeight(IXFA_TextProvider* pTextProvider,
IFDE_CSSComputedStyle* pStyle,
FX_BOOL bFirst,
FX_FLOAT fVerScale) const;
FX_BOOL GetEmbbedObj(IXFA_TextProvider* pTextProvider,
IFDE_XMLNode* pXMLNode,
CFX_WideString& wsValue);
CXFA_TextParseContext* GetParseContextFromMap(IFDE_XMLNode* pXMLNode);
private:
void InitCSSData(IXFA_TextProvider* pTextProvider);
void ParseRichText(IFDE_XMLNode* pXMLNode,
IFDE_CSSComputedStyle* pParentStyle);
void ParseTagInfo(IFDE_XMLNode* pXMLNode, CXFA_CSSTagProvider& tagProvider);
IFDE_CSSStyleSheet* LoadDefaultSheetStyle();
IFDE_CSSComputedStyle* CreateStyle(IFDE_CSSComputedStyle* pParentStyle);
IFX_MEMAllocator* m_pAllocator;
IFDE_CSSStyleSelector* m_pSelector;
IFDE_CSSStyleSheet* m_pUASheet;
CFX_MapPtrTemplate<IFDE_XMLNode*, CXFA_TextParseContext*>
m_mapXMLNodeToParseContext;
};
class CXFA_LoaderContext {
public:
CXFA_LoaderContext()
: m_bSaveLineHeight(FALSE),
m_fWidth(0),
m_fHeight(0),
m_fLastPos(0),
m_fStartLineOffset(0),
m_iChar(0),
m_iTotalLines(-1),
m_pXMLNode(NULL),
m_pNode(NULL),
m_pParentStyle(NULL),
m_dwFlags(0) {}
FX_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;
IFDE_XMLNode* m_pXMLNode;
CXFA_Node* m_pNode;
IFDE_CSSComputedStyle* m_pParentStyle;
CFX_ArrayTemplate<FX_FLOAT> m_lineHeights;
FX_DWORD m_dwFlags;
CFX_FloatArray m_BlocksHeight;
};
class CXFA_LinkUserData : public IFX_Unknown, public CFX_Target {
public:
CXFA_LinkUserData(IFX_MEMAllocator* pAllocator, FX_WCHAR* pszText)
: m_pAllocator(pAllocator), m_dwRefCount(1) {
m_pszURLContent = pszText;
}
~CXFA_LinkUserData() {}
virtual FX_DWORD Release() {
FX_DWORD dwRefCount = --m_dwRefCount;
if (dwRefCount <= 0) {
FDE_DeleteWith(CXFA_LinkUserData, m_pAllocator, this);
}
return dwRefCount;
}
virtual FX_DWORD AddRef() { return ++m_dwRefCount; }
public:
const FX_WCHAR* GetLinkURL() { return m_pszURLContent; };
protected:
IFX_MEMAllocator* m_pAllocator;
FX_DWORD m_dwRefCount;
CFX_WideString m_pszURLContent;
};
class CXFA_TextUserData : public IFX_Unknown, public CFX_Target {
public:
CXFA_TextUserData(IFX_MEMAllocator* pAllocator, IFDE_CSSComputedStyle* pStyle)
: m_pStyle(pStyle),
m_pLinkData(nullptr),
m_pAllocator(pAllocator),
m_dwRefCount(0) {
FXSYS_assert(m_pAllocator);
if (m_pStyle)
m_pStyle->AddRef();
}
CXFA_TextUserData(IFX_MEMAllocator* pAllocator,
IFDE_CSSComputedStyle* pStyle,
CXFA_LinkUserData* pLinkData)
: m_pStyle(pStyle),
m_pLinkData(pLinkData),
m_pAllocator(pAllocator),
m_dwRefCount(0) {
FXSYS_assert(m_pAllocator);
if (m_pStyle)
m_pStyle->AddRef();
}
~CXFA_TextUserData() {
if (m_pStyle)
m_pStyle->Release();
if (m_pLinkData)
m_pLinkData->Release();
}
virtual FX_DWORD Release() {
FX_DWORD dwRefCount = --m_dwRefCount;
if (dwRefCount == 0) {
FDE_DeleteWith(CXFA_TextUserData, m_pAllocator, this);
}
return dwRefCount;
}
virtual FX_DWORD AddRef() { return ++m_dwRefCount; }
IFDE_CSSComputedStyle* m_pStyle;
CXFA_LinkUserData* m_pLinkData;
protected:
IFX_MEMAllocator* m_pAllocator;
FX_DWORD m_dwRefCount;
};
typedef struct _XFA_TEXTPIECE : public CFX_Target {
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;
IFX_Font* pFont;
FX_ARGB dwColor;
FX_FLOAT fFontSize;
CFX_RectF rtPiece;
CXFA_LinkUserData* pLinkData;
_XFA_TEXTPIECE() : pszText(NULL), pFont(NULL), pLinkData(NULL) {
pszText = NULL;
}
~_XFA_TEXTPIECE() {
pszText = NULL;
if (NULL != pLinkData) {
pLinkData->Release();
pLinkData = NULL;
}
}
} XFA_TEXTPIECE, *XFA_LPTEXTPIECE;
typedef XFA_TEXTPIECE const* XFA_LPCTEXTPIECE;
typedef CFX_ArrayTemplate<XFA_LPTEXTPIECE> CXFA_PieceArray;
class CXFA_PieceLine : public CFX_Target {
public:
CXFA_PieceLine() {}
CXFA_PieceArray m_textPieces;
CFX_Int32Array m_charCounts;
};
typedef CFX_ArrayTemplate<CXFA_PieceLine*> CXFA_PieceLineArray;
struct XFA_TABSTOPS {
FX_DWORD dwAlign;
FX_FLOAT fTabstops;
};
class CXFA_TextTabstopsContext {
public:
CXFA_TextTabstopsContext()
: m_iTabCount(0),
m_iTabIndex(-1),
m_bTabstops(FALSE),
m_fTabWidth(0),
m_fLeft(0) {}
void Append(FX_DWORD dwAlign, FX_FLOAT fTabstops) {
int32_t i = 0;
for (i = 0; i < m_iTabCount; i++) {
XFA_TABSTOPS* pTabstop = m_tabstops.GetDataPtr(i);
if (fTabstops < pTabstop->fTabstops) {
break;
}
}
m_tabstops.InsertSpaceAt(i, 1);
XFA_TABSTOPS tabstop;
tabstop.dwAlign = dwAlign;
tabstop.fTabstops = fTabstops;
m_tabstops.SetAt(i, tabstop);
m_iTabCount++;
}
void RemoveAll() {
m_tabstops.RemoveAll();
m_iTabCount = 0;
}
void Reset() {
m_iTabIndex = -1;
m_bTabstops = FALSE;
m_fTabWidth = 0;
m_fLeft = 0;
}
CFX_ArrayTemplate<XFA_TABSTOPS> m_tabstops;
int32_t m_iTabCount;
int32_t m_iTabIndex;
FX_BOOL m_bTabstops;
FX_FLOAT m_fTabWidth;
FX_FLOAT m_fLeft;
};
class CXFA_TextLayout {
public:
CXFA_TextLayout(IXFA_TextProvider* pTextProvider);
virtual ~CXFA_TextLayout();
int32_t GetText(CFX_WideString& wsText);
FX_FLOAT GetLayoutHeight();
FX_FLOAT StartLayout(FX_FLOAT fWidth = -1);
FX_BOOL DoLayout(int32_t iBlockIndex,
FX_FLOAT& fCalcHeight,
FX_FLOAT fContentAreaHeight = -1,
FX_FLOAT fTextHeight = -1);
FX_BOOL CalcSize(const CFX_SizeF& minSize,
const CFX_SizeF& maxSize,
CFX_SizeF& defaultSize);
FX_BOOL Layout(const CFX_SizeF& size, FX_FLOAT* fHeight = NULL);
void ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex);
FX_BOOL DrawString(CFX_RenderDevice* pFxDevice,
const CFX_Matrix& tmDoc2Device,
const CFX_RectF& rtClip,
int32_t iBlock = 0);
FX_BOOL IsLoaded() const { return m_pieceLines.GetSize() > 0; }
void Unload();
const CXFA_PieceLineArray* GetPieceLines();
FX_BOOL m_bHasBlock;
CFX_Int32Array m_Blocks;
private:
void GetTextDataNode();
IFDE_XMLNode* GetXMLContainerNode();
IFX_RTFBreak* CreateBreak(FX_BOOL bDefault);
void InitBreak(FX_FLOAT fLineWidth);
void InitBreak(IFDE_CSSComputedStyle* pStyle,
FDE_CSSDISPLAY eDisplay,
FX_FLOAT fLineWidth,
IFDE_XMLNode* pXMLNode,
IFDE_CSSComputedStyle* pParentStyle = NULL);
FX_BOOL Loader(const CFX_SizeF& szText,
FX_FLOAT& fLinePos,
FX_BOOL bSavePieces = TRUE);
void LoadText(CXFA_Node* pNode,
const CFX_SizeF& szText,
FX_FLOAT& fLinePos,
FX_BOOL bSavePieces);
FX_BOOL LoadRichText(IFDE_XMLNode* pXMLNode,
const CFX_SizeF& szText,
FX_FLOAT& fLinePos,
IFDE_CSSComputedStyle* pParentStyle,
FX_BOOL bSavePieces,
CXFA_LinkUserData* pLinkData = NULL,
FX_BOOL bEndBreak = TRUE,
FX_BOOL bIsOl = FALSE,
int32_t iLiCount = 0);
FX_BOOL AppendChar(const CFX_WideString& wsText,
FX_FLOAT& fLinePos,
FX_FLOAT fSpaceAbove,
FX_BOOL bSavePieces);
void AppendTextLine(FX_DWORD dwStatus,
FX_FLOAT& fLinePos,
FX_BOOL bSavePieces,
FX_BOOL bEndBreak = FALSE);
void EndBreak(FX_DWORD dwStatus, FX_FLOAT& fLinePos, FX_BOOL bDefault);
FX_BOOL IsEnd(FX_BOOL bSavePieces);
void ProcessText(CFX_WideString& wsText);
void UpdateAlign(FX_FLOAT fHeight, FX_FLOAT fBottom);
void RenderString(IFDE_RenderDevice* pDevice,
IFDE_SolidBrush* pBrush,
CXFA_PieceLine* pPieceLine,
int32_t iPiece,
FXTEXT_CHARPOS* pCharPos,
const CFX_Matrix& tmDoc2Device);
void RenderPath(IFDE_RenderDevice* pDevice,
IFDE_Pen* pPen,
CXFA_PieceLine* pPieceLine,
int32_t iPiece,
FXTEXT_CHARPOS* pCharPos,
const CFX_Matrix& tmDoc2Device);
int32_t GetDisplayPos(XFA_LPCTEXTPIECE pPiece,
FXTEXT_CHARPOS* pCharPos,
FX_BOOL bCharCode = FALSE);
FX_BOOL ToRun(XFA_LPCTEXTPIECE pPiece, FX_RTFTEXTOBJ& tr);
void DoTabstops(IFDE_CSSComputedStyle* pStyle, CXFA_PieceLine* pPieceLine);
FX_BOOL Layout(int32_t iBlock);
int32_t CountBlocks() const;
IXFA_TextProvider* m_pTextProvider;
CXFA_Node* m_pTextDataNode;
FX_BOOL m_bRichText;
IFX_MEMAllocator* m_pAllocator;
IFX_RTFBreak* m_pBreak;
CXFA_LoaderContext* m_pLoader;
int32_t m_iLines;
FX_FLOAT m_fMaxWidth;
CXFA_TextParser m_textParser;
CXFA_PieceLineArray m_pieceLines;
CXFA_TextTabstopsContext* m_pTabstopContext;
FX_BOOL m_bBlockContinue;
};
#endif