blob: 842c6ec7313f44f1e6ceaf09d369cc88ab53083b [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 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/include/xfa_ffdoc.h"
#include "xfa/fxfa/parser/xfa_object.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:
CXFA_CSSTagProvider() : m_bTagAvailable(FALSE), m_bContent(FALSE) {}
~CXFA_CSSTagProvider() {}
CFX_WideString GetTagName() { return m_wsTagName; }
using AttributeMap = std::map<CFX_WideString, CFX_WideString>;
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});
}
FX_BOOL m_bTagAvailable;
FX_BOOL m_bContent;
protected:
CFX_WideString m_wsTagName;
AttributeMap 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 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);
FX_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;
FX_BOOL IsSpaceRun(IFDE_CSSComputedStyle* pStyle) const;
FX_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,
FX_BOOL bFirst,
FX_FLOAT fVerScale) const;
FX_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()
: 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;
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)
: m_pAllocator(pAllocator), m_dwRefCount(1), m_wsURLContent(pszText) {}
~CXFA_LinkUserData() override {}
// IFX_Retainable:
uint32_t Retain() override { return ++m_dwRefCount; }
uint32_t Release() override {
uint32_t dwRefCount = --m_dwRefCount;
if (dwRefCount <= 0)
FXTARGET_DeleteWith(CXFA_LinkUserData, m_pAllocator, this);
return dwRefCount;
}
const FX_WCHAR* GetLinkURL() { return m_wsURLContent.c_str(); }
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)
: m_pStyle(pStyle),
m_pLinkData(nullptr),
m_pAllocator(pAllocator),
m_dwRefCount(0) {
ASSERT(m_pAllocator);
if (m_pStyle)
m_pStyle->Retain();
}
CXFA_TextUserData(IFX_MemoryAllocator* pAllocator,
IFDE_CSSComputedStyle* pStyle,
CXFA_LinkUserData* pLinkData)
: m_pStyle(pStyle),
m_pLinkData(pLinkData),
m_pAllocator(pAllocator),
m_dwRefCount(0) {
ASSERT(m_pAllocator);
if (m_pStyle)
m_pStyle->Retain();
}
~CXFA_TextUserData() override {
if (m_pStyle)
m_pStyle->Release();
if (m_pLinkData)
m_pLinkData->Release();
}
// IFX_Retainable:
uint32_t Retain() override { return ++m_dwRefCount; }
uint32_t Release() override {
uint32_t dwRefCount = --m_dwRefCount;
if (dwRefCount == 0)
FXTARGET_DeleteWith(CXFA_TextUserData, m_pAllocator, this);
return dwRefCount;
}
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() : pszText(nullptr), pFont(nullptr), pLinkData(nullptr) {}
~XFA_TextPiece() override {
if (pLinkData)
pLinkData->Release();
}
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_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()
: m_iTabCount(0),
m_iTabIndex(-1),
m_bTabstops(FALSE),
m_fTabWidth(0),
m_fLeft(0) {}
void Append(uint32_t dwAlign, FX_FLOAT fTabstops) {
int32_t i = 0;
for (i = 0; i < m_iTabCount; i++) {
XFA_TABSTOPS* pTabstop = m_tabstops.GetDataPtr(i);
if (fTabstops < pTabstop->fTabstops) {
break;
}
}
m_tabstops.InsertSpaceAt(i, 1);
XFA_TABSTOPS tabstop;
tabstop.dwAlign = dwAlign;
tabstop.fTabstops = fTabstops;
m_tabstops.SetAt(i, tabstop);
m_iTabCount++;
}
void 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:
explicit CXFA_TextLayout(CXFA_TextProvider* pTextProvider);
~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();
CFDE_XMLNode* GetXMLContainerNode();
CFX_RTFBreak* CreateBreak(FX_BOOL bDefault);
void InitBreak(FX_FLOAT fLineWidth);
void InitBreak(IFDE_CSSComputedStyle* pStyle,
FDE_CSSDISPLAY eDisplay,
FX_FLOAT fLineWidth,
CFDE_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(CFDE_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(uint32_t dwStatus,
FX_FLOAT& fLinePos,
FX_BOOL bSavePieces,
FX_BOOL bEndBreak = FALSE);
void EndBreak(uint32_t 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(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,
FX_BOOL bCharCode = FALSE);
FX_BOOL ToRun(const XFA_TextPiece* pPiece, FX_RTFTEXTOBJ& tr);
void DoTabstops(IFDE_CSSComputedStyle* pStyle, CXFA_PieceLine* pPieceLine);
FX_BOOL Layout(int32_t iBlock);
int32_t CountBlocks() const;
CXFA_TextProvider* m_pTextProvider;
CXFA_Node* m_pTextDataNode;
FX_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;
FX_BOOL m_bBlockContinue;
};
#endif // XFA_FXFA_APP_XFA_TEXTLAYOUT_H_