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/cxfa_fftext.h"
8 
9 #include "xfa/fgas/layout/cfx_linkuserdata.h"
10 #include "xfa/fwl/fwl_widgethit.h"
11 #include "xfa/fxfa/cxfa_ffapp.h"
12 #include "xfa/fxfa/cxfa_ffdoc.h"
13 #include "xfa/fxfa/cxfa_ffpageview.h"
14 #include "xfa/fxfa/cxfa_ffwidget.h"
15 #include "xfa/fxfa/cxfa_pieceline.h"
16 #include "xfa/fxfa/cxfa_textlayout.h"
17 #include "xfa/fxfa/cxfa_textpiece.h"
18 #include "xfa/fxfa/parser/cxfa_margin.h"
19 #include "xfa/fxgraphics/cxfa_graphics.h"
20 
CXFA_FFText(CXFA_Node * pNode)21 CXFA_FFText::CXFA_FFText(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
22 
~CXFA_FFText()23 CXFA_FFText::~CXFA_FFText() {}
24 
RenderWidget(CXFA_Graphics * pGS,const CFX_Matrix & matrix,HighlightOption highlight)25 void CXFA_FFText::RenderWidget(CXFA_Graphics* pGS,
26                                const CFX_Matrix& matrix,
27                                HighlightOption highlight) {
28   if (!HasVisibleStatus())
29     return;
30 
31   CFX_Matrix mtRotate = GetRotateMatrix();
32   mtRotate.Concat(matrix);
33 
34   CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
35 
36   CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
37   if (!pTextLayout)
38     return;
39 
40   CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
41   CFX_RectF rtText = GetRectWithoutRotate();
42   CXFA_Margin* margin = m_pNode->GetMarginIfExists();
43   if (margin) {
44     CXFA_ContentLayoutItem* pItem = GetLayoutItem();
45     if (!pItem->GetPrev() && !pItem->GetNext()) {
46       XFA_RectWithoutMargin(&rtText, margin);
47     } else {
48       float fTopInset = 0;
49       float fBottomInset = 0;
50       if (!pItem->GetPrev())
51         fTopInset = margin->GetTopInset();
52       else if (!pItem->GetNext())
53         fBottomInset = margin->GetBottomInset();
54 
55       rtText.Deflate(margin->GetLeftInset(), fTopInset, margin->GetRightInset(),
56                      fBottomInset);
57     }
58   }
59 
60   CFX_Matrix mt(1, 0, 0, 1, rtText.left, rtText.top);
61   CFX_RectF rtClip = mtRotate.TransformRect(rtText);
62   mt.Concat(mtRotate);
63   pTextLayout->DrawString(pRenderDevice, mt, rtClip,
64                           GetLayoutItem()->GetIndex());
65 }
66 
IsLoaded()67 bool CXFA_FFText::IsLoaded() {
68   CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
69   return pTextLayout && !pTextLayout->HasBlock();
70 }
71 
PerformLayout()72 bool CXFA_FFText::PerformLayout() {
73   CXFA_FFWidget::PerformLayout();
74   CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
75   if (!pTextLayout)
76     return false;
77   if (!pTextLayout->HasBlock())
78     return true;
79 
80   pTextLayout->ClearBlocks();
81   CXFA_ContentLayoutItem* pItem = GetLayoutItem();
82   if (!pItem->GetPrev() && !pItem->GetNext())
83     return true;
84 
85   pItem = pItem->GetFirst();
86   while (pItem) {
87     CFX_RectF rtText = pItem->GetRect(false);
88     CXFA_Margin* margin = m_pNode->GetMarginIfExists();
89     if (margin) {
90       if (!pItem->GetPrev())
91         rtText.height -= margin->GetTopInset();
92       else if (!pItem->GetNext())
93         rtText.height -= margin->GetBottomInset();
94     }
95     pTextLayout->ItemBlocks(rtText, pItem->GetIndex());
96     pItem = pItem->GetNext();
97   }
98   pTextLayout->ResetHasBlock();
99   return true;
100 }
101 
AcceptsFocusOnButtonDown(uint32_t dwFlags,const CFX_PointF & point,FWL_MouseCommand command)102 bool CXFA_FFText::AcceptsFocusOnButtonDown(uint32_t dwFlags,
103                                            const CFX_PointF& point,
104                                            FWL_MouseCommand command) {
105   if (command != FWL_MouseCommand::LeftButtonDown)
106     return false;
107 
108   if (!GetRectWithoutRotate().Contains(point))
109     return false;
110 
111   const wchar_t* wsURLContent = GetLinkURLAtPoint(point);
112   if (!wsURLContent)
113     return false;
114 
115   return true;
116 }
117 
OnLButtonDown(uint32_t dwFlags,const CFX_PointF & point)118 bool CXFA_FFText::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
119   SetButtonDown(true);
120   return true;
121 }
122 
OnMouseMove(uint32_t dwFlags,const CFX_PointF & point)123 bool CXFA_FFText::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) {
124   return GetRectWithoutRotate().Contains(point) && !!GetLinkURLAtPoint(point);
125 }
126 
OnLButtonUp(uint32_t dwFlags,const CFX_PointF & point)127 bool CXFA_FFText::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
128   if (!IsButtonDown())
129     return false;
130 
131   SetButtonDown(false);
132   const wchar_t* wsURLContent = GetLinkURLAtPoint(point);
133   if (!wsURLContent)
134     return false;
135 
136   CXFA_FFDoc* pDoc = GetDoc();
137   pDoc->GetDocEnvironment()->GotoURL(pDoc, wsURLContent);
138   return true;
139 }
140 
HitTest(const CFX_PointF & point)141 FWL_WidgetHit CXFA_FFText::HitTest(const CFX_PointF& point) {
142   if (!GetRectWithoutRotate().Contains(point))
143     return FWL_WidgetHit::Unknown;
144   if (!GetLinkURLAtPoint(point))
145     return FWL_WidgetHit::Unknown;
146   return FWL_WidgetHit::HyperLink;
147 }
148 
GetLinkURLAtPoint(const CFX_PointF & point)149 const wchar_t* CXFA_FFText::GetLinkURLAtPoint(const CFX_PointF& point) {
150   CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
151   if (!pTextLayout)
152     return nullptr;
153 
154   CFX_RectF rect = GetRectWithoutRotate();
155   for (const auto& pPieceLine : *pTextLayout->GetPieceLines()) {
156     for (const auto& pPiece : pPieceLine->m_textPieces) {
157       if (pPiece->pLinkData &&
158           pPiece->rtPiece.Contains(point - rect.TopLeft())) {
159         return pPiece->pLinkData->GetLinkURL();
160       }
161     }
162   }
163   return nullptr;
164 }
165