1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "xfa/fxfa/app/xfa_fftext.h"
8
9 #include "xfa/fwl/fwl_widgetdef.h"
10 #include "xfa/fwl/fwl_widgethit.h"
11 #include "xfa/fxfa/app/cxfa_linkuserdata.h"
12 #include "xfa/fxfa/app/cxfa_pieceline.h"
13 #include "xfa/fxfa/app/cxfa_textlayout.h"
14 #include "xfa/fxfa/app/xfa_ffdraw.h"
15 #include "xfa/fxfa/app/xfa_textpiece.h"
16 #include "xfa/fxfa/xfa_ffapp.h"
17 #include "xfa/fxfa/xfa_ffdoc.h"
18 #include "xfa/fxfa/xfa_ffpageview.h"
19 #include "xfa/fxfa/xfa_ffwidget.h"
20 #include "xfa/fxgraphics/cfx_graphics.h"
21
CXFA_FFText(CXFA_WidgetAcc * pDataAcc)22 CXFA_FFText::CXFA_FFText(CXFA_WidgetAcc* pDataAcc) : CXFA_FFDraw(pDataAcc) {}
23
~CXFA_FFText()24 CXFA_FFText::~CXFA_FFText() {}
25
RenderWidget(CFX_Graphics * pGS,CFX_Matrix * pMatrix,uint32_t dwStatus)26 void CXFA_FFText::RenderWidget(CFX_Graphics* pGS,
27 CFX_Matrix* pMatrix,
28 uint32_t dwStatus) {
29 if (!IsMatchVisibleStatus(dwStatus))
30 return;
31
32 CFX_Matrix mtRotate = GetRotateMatrix();
33 if (pMatrix)
34 mtRotate.Concat(*pMatrix);
35
36 CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
37
38 CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout();
39 if (!pTextLayout)
40 return;
41
42 CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
43 CFX_RectF rtText = GetRectWithoutRotate();
44 if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin()) {
45 CXFA_LayoutItem* pItem = this;
46 if (!pItem->GetPrev() && !pItem->GetNext()) {
47 XFA_RectWidthoutMargin(rtText, mgWidget);
48 } else {
49 FX_FLOAT fLeftInset;
50 FX_FLOAT fRightInset;
51 FX_FLOAT fTopInset = 0;
52 FX_FLOAT fBottomInset = 0;
53 mgWidget.GetLeftInset(fLeftInset);
54 mgWidget.GetRightInset(fRightInset);
55 if (!pItem->GetPrev())
56 mgWidget.GetTopInset(fTopInset);
57 else if (!pItem->GetNext())
58 mgWidget.GetBottomInset(fBottomInset);
59
60 rtText.Deflate(fLeftInset, fTopInset, fRightInset, fBottomInset);
61 }
62 }
63
64 CFX_Matrix mt(1, 0, 0, 1, rtText.left, rtText.top);
65 CFX_RectF rtClip = rtText;
66 mtRotate.TransformRect(rtClip);
67 mt.Concat(mtRotate);
68 pTextLayout->DrawString(pRenderDevice, mt, rtClip, GetIndex());
69 }
70
IsLoaded()71 bool CXFA_FFText::IsLoaded() {
72 CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout();
73 return pTextLayout && !pTextLayout->m_bHasBlock;
74 }
PerformLayout()75 bool CXFA_FFText::PerformLayout() {
76 CXFA_FFDraw::PerformLayout();
77 CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout();
78 if (!pTextLayout) {
79 return false;
80 }
81 if (!pTextLayout->m_bHasBlock) {
82 return true;
83 }
84 pTextLayout->m_Blocks.RemoveAll();
85 CXFA_LayoutItem* pItem = this;
86 if (!pItem->GetPrev() && !pItem->GetNext()) {
87 return true;
88 }
89 pItem = pItem->GetFirst();
90 while (pItem) {
91 CFX_RectF rtText = pItem->GetRect(false);
92 if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin()) {
93 if (!pItem->GetPrev()) {
94 FX_FLOAT fTopInset;
95 mgWidget.GetTopInset(fTopInset);
96 rtText.height -= fTopInset;
97 } else if (!pItem->GetNext()) {
98 FX_FLOAT fBottomInset;
99 mgWidget.GetBottomInset(fBottomInset);
100 rtText.height -= fBottomInset;
101 }
102 }
103 pTextLayout->ItemBlocks(rtText, pItem->GetIndex());
104 pItem = pItem->GetNext();
105 }
106 pTextLayout->m_bHasBlock = false;
107 return true;
108 }
109
OnLButtonDown(uint32_t dwFlags,const CFX_PointF & point)110 bool CXFA_FFText::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
111 if (!GetRectWithoutRotate().Contains(point))
112 return false;
113
114 const FX_WCHAR* wsURLContent = GetLinkURLAtPoint(point);
115 if (!wsURLContent)
116 return false;
117
118 SetButtonDown(true);
119 return true;
120 }
121
OnMouseMove(uint32_t dwFlags,const CFX_PointF & point)122 bool CXFA_FFText::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) {
123 return GetRectWithoutRotate().Contains(point) && !!GetLinkURLAtPoint(point);
124 }
125
OnLButtonUp(uint32_t dwFlags,const CFX_PointF & point)126 bool CXFA_FFText::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
127 if (!IsButtonDown())
128 return false;
129
130 SetButtonDown(false);
131 const FX_WCHAR* wsURLContent = GetLinkURLAtPoint(point);
132 if (!wsURLContent)
133 return false;
134
135 CXFA_FFDoc* pDoc = GetDoc();
136 pDoc->GetDocEnvironment()->GotoURL(pDoc, wsURLContent);
137 return true;
138 }
139
OnHitTest(const CFX_PointF & point)140 FWL_WidgetHit CXFA_FFText::OnHitTest(const CFX_PointF& point) {
141 if (!GetRectWithoutRotate().Contains(point))
142 return FWL_WidgetHit::Unknown;
143 if (!GetLinkURLAtPoint(point))
144 return FWL_WidgetHit::Unknown;
145 return FWL_WidgetHit::HyperLink;
146 }
147
GetLinkURLAtPoint(const CFX_PointF & point)148 const FX_WCHAR* CXFA_FFText::GetLinkURLAtPoint(const CFX_PointF& point) {
149 CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout();
150 if (!pTextLayout)
151 return nullptr;
152
153 CFX_RectF rect = GetRectWithoutRotate();
154 for (const auto& pPieceLine : *pTextLayout->GetPieceLines()) {
155 for (const auto& pPiece : pPieceLine->m_textPieces) {
156 if (pPiece->pLinkData &&
157 pPiece->rtPiece.Contains(point - rect.TopLeft())) {
158 return pPiece->pLinkData->GetLinkURL();
159 }
160 }
161 }
162 return nullptr;
163 }
164