xref: /aosp_15_r20/external/pdfium/xfa/fxfa/cxfa_fftext.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2014 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker 
5*3ac0a46fSAndroid Build Coastguard Worker // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6*3ac0a46fSAndroid Build Coastguard Worker 
7*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_fftext.h"
8*3ac0a46fSAndroid Build Coastguard Worker 
9*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/graphics/cfgas_gegraphics.h"
10*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/layout/cfgas_linkuserdata.h"
11*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/fwl_widgethit.h"
12*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_ffapp.h"
13*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_ffdoc.h"
14*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_ffpageview.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_ffwidget.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_textlayout.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_margin.h"
18*3ac0a46fSAndroid Build Coastguard Worker 
CXFA_FFText(CXFA_Node * pNode)19*3ac0a46fSAndroid Build Coastguard Worker CXFA_FFText::CXFA_FFText(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
20*3ac0a46fSAndroid Build Coastguard Worker 
21*3ac0a46fSAndroid Build Coastguard Worker CXFA_FFText::~CXFA_FFText() = default;
22*3ac0a46fSAndroid Build Coastguard Worker 
RenderWidget(CFGAS_GEGraphics * pGS,const CFX_Matrix & matrix,HighlightOption highlight)23*3ac0a46fSAndroid Build Coastguard Worker void CXFA_FFText::RenderWidget(CFGAS_GEGraphics* pGS,
24*3ac0a46fSAndroid Build Coastguard Worker                                const CFX_Matrix& matrix,
25*3ac0a46fSAndroid Build Coastguard Worker                                HighlightOption highlight) {
26*3ac0a46fSAndroid Build Coastguard Worker   if (!HasVisibleStatus())
27*3ac0a46fSAndroid Build Coastguard Worker     return;
28*3ac0a46fSAndroid Build Coastguard Worker 
29*3ac0a46fSAndroid Build Coastguard Worker   CFX_Matrix mtRotate = GetRotateMatrix();
30*3ac0a46fSAndroid Build Coastguard Worker   mtRotate.Concat(matrix);
31*3ac0a46fSAndroid Build Coastguard Worker 
32*3ac0a46fSAndroid Build Coastguard Worker   CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
33*3ac0a46fSAndroid Build Coastguard Worker 
34*3ac0a46fSAndroid Build Coastguard Worker   CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
35*3ac0a46fSAndroid Build Coastguard Worker   if (!pTextLayout)
36*3ac0a46fSAndroid Build Coastguard Worker     return;
37*3ac0a46fSAndroid Build Coastguard Worker 
38*3ac0a46fSAndroid Build Coastguard Worker   CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
39*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rtText = GetRectWithoutRotate();
40*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Margin* margin = m_pNode->GetMarginIfExists();
41*3ac0a46fSAndroid Build Coastguard Worker   if (margin) {
42*3ac0a46fSAndroid Build Coastguard Worker     CXFA_ContentLayoutItem* pItem = GetLayoutItem();
43*3ac0a46fSAndroid Build Coastguard Worker     if (!pItem->GetPrev() && !pItem->GetNext()) {
44*3ac0a46fSAndroid Build Coastguard Worker       XFA_RectWithoutMargin(&rtText, margin);
45*3ac0a46fSAndroid Build Coastguard Worker     } else {
46*3ac0a46fSAndroid Build Coastguard Worker       float fTopInset = 0;
47*3ac0a46fSAndroid Build Coastguard Worker       float fBottomInset = 0;
48*3ac0a46fSAndroid Build Coastguard Worker       if (!pItem->GetPrev())
49*3ac0a46fSAndroid Build Coastguard Worker         fTopInset = margin->GetTopInset();
50*3ac0a46fSAndroid Build Coastguard Worker       else if (!pItem->GetNext())
51*3ac0a46fSAndroid Build Coastguard Worker         fBottomInset = margin->GetBottomInset();
52*3ac0a46fSAndroid Build Coastguard Worker 
53*3ac0a46fSAndroid Build Coastguard Worker       rtText.Deflate(margin->GetLeftInset(), fTopInset, margin->GetRightInset(),
54*3ac0a46fSAndroid Build Coastguard Worker                      fBottomInset);
55*3ac0a46fSAndroid Build Coastguard Worker     }
56*3ac0a46fSAndroid Build Coastguard Worker   }
57*3ac0a46fSAndroid Build Coastguard Worker 
58*3ac0a46fSAndroid Build Coastguard Worker   CFX_Matrix mt(1, 0, 0, 1, rtText.left, rtText.top);
59*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rtClip = mtRotate.TransformRect(rtText);
60*3ac0a46fSAndroid Build Coastguard Worker   mt.Concat(mtRotate);
61*3ac0a46fSAndroid Build Coastguard Worker   pTextLayout->DrawString(pRenderDevice, mt, rtClip,
62*3ac0a46fSAndroid Build Coastguard Worker                           GetLayoutItem()->GetIndex());
63*3ac0a46fSAndroid Build Coastguard Worker }
64*3ac0a46fSAndroid Build Coastguard Worker 
IsLoaded()65*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_FFText::IsLoaded() {
66*3ac0a46fSAndroid Build Coastguard Worker   CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
67*3ac0a46fSAndroid Build Coastguard Worker   return pTextLayout && !pTextLayout->HasBlock();
68*3ac0a46fSAndroid Build Coastguard Worker }
69*3ac0a46fSAndroid Build Coastguard Worker 
PerformLayout()70*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_FFText::PerformLayout() {
71*3ac0a46fSAndroid Build Coastguard Worker   CXFA_FFWidget::PerformLayout();
72*3ac0a46fSAndroid Build Coastguard Worker   CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
73*3ac0a46fSAndroid Build Coastguard Worker   if (!pTextLayout)
74*3ac0a46fSAndroid Build Coastguard Worker     return false;
75*3ac0a46fSAndroid Build Coastguard Worker   if (!pTextLayout->HasBlock())
76*3ac0a46fSAndroid Build Coastguard Worker     return true;
77*3ac0a46fSAndroid Build Coastguard Worker 
78*3ac0a46fSAndroid Build Coastguard Worker   pTextLayout->ClearBlocks();
79*3ac0a46fSAndroid Build Coastguard Worker   CXFA_ContentLayoutItem* pItem = GetLayoutItem();
80*3ac0a46fSAndroid Build Coastguard Worker   if (!pItem->GetPrev() && !pItem->GetNext())
81*3ac0a46fSAndroid Build Coastguard Worker     return true;
82*3ac0a46fSAndroid Build Coastguard Worker 
83*3ac0a46fSAndroid Build Coastguard Worker   pItem = pItem->GetFirst();
84*3ac0a46fSAndroid Build Coastguard Worker   while (pItem) {
85*3ac0a46fSAndroid Build Coastguard Worker     CFX_RectF rtText = pItem->GetAbsoluteRect();
86*3ac0a46fSAndroid Build Coastguard Worker     CXFA_Margin* margin = m_pNode->GetMarginIfExists();
87*3ac0a46fSAndroid Build Coastguard Worker     if (margin) {
88*3ac0a46fSAndroid Build Coastguard Worker       if (!pItem->GetPrev())
89*3ac0a46fSAndroid Build Coastguard Worker         rtText.height -= margin->GetTopInset();
90*3ac0a46fSAndroid Build Coastguard Worker       else if (!pItem->GetNext())
91*3ac0a46fSAndroid Build Coastguard Worker         rtText.height -= margin->GetBottomInset();
92*3ac0a46fSAndroid Build Coastguard Worker     }
93*3ac0a46fSAndroid Build Coastguard Worker     pTextLayout->ItemBlocks(rtText, pItem->GetIndex());
94*3ac0a46fSAndroid Build Coastguard Worker     pItem = pItem->GetNext();
95*3ac0a46fSAndroid Build Coastguard Worker   }
96*3ac0a46fSAndroid Build Coastguard Worker   pTextLayout->ResetHasBlock();
97*3ac0a46fSAndroid Build Coastguard Worker   return true;
98*3ac0a46fSAndroid Build Coastguard Worker }
99*3ac0a46fSAndroid Build Coastguard Worker 
AcceptsFocusOnButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,const CFX_PointF & point,CFWL_MessageMouse::MouseCommand command)100*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_FFText::AcceptsFocusOnButtonDown(
101*3ac0a46fSAndroid Build Coastguard Worker     Mask<XFA_FWL_KeyFlag> dwFlags,
102*3ac0a46fSAndroid Build Coastguard Worker     const CFX_PointF& point,
103*3ac0a46fSAndroid Build Coastguard Worker     CFWL_MessageMouse::MouseCommand command) {
104*3ac0a46fSAndroid Build Coastguard Worker   return command == CFWL_MessageMouse::MouseCommand::kLeftButtonDown &&
105*3ac0a46fSAndroid Build Coastguard Worker          GetRectWithoutRotate().Contains(point) &&
106*3ac0a46fSAndroid Build Coastguard Worker          !GetLinkURLAtPoint(point).IsEmpty();
107*3ac0a46fSAndroid Build Coastguard Worker }
108*3ac0a46fSAndroid Build Coastguard Worker 
OnLButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,const CFX_PointF & point)109*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_FFText::OnLButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,
110*3ac0a46fSAndroid Build Coastguard Worker                                 const CFX_PointF& point) {
111*3ac0a46fSAndroid Build Coastguard Worker   SetButtonDown(true);
112*3ac0a46fSAndroid Build Coastguard Worker   return true;
113*3ac0a46fSAndroid Build Coastguard Worker }
114*3ac0a46fSAndroid Build Coastguard Worker 
OnMouseMove(Mask<XFA_FWL_KeyFlag> dwFlags,const CFX_PointF & point)115*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_FFText::OnMouseMove(Mask<XFA_FWL_KeyFlag> dwFlags,
116*3ac0a46fSAndroid Build Coastguard Worker                               const CFX_PointF& point) {
117*3ac0a46fSAndroid Build Coastguard Worker   return GetRectWithoutRotate().Contains(point) &&
118*3ac0a46fSAndroid Build Coastguard Worker          !GetLinkURLAtPoint(point).IsEmpty();
119*3ac0a46fSAndroid Build Coastguard Worker }
120*3ac0a46fSAndroid Build Coastguard Worker 
OnLButtonUp(Mask<XFA_FWL_KeyFlag> dwFlags,const CFX_PointF & point)121*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_FFText::OnLButtonUp(Mask<XFA_FWL_KeyFlag> dwFlags,
122*3ac0a46fSAndroid Build Coastguard Worker                               const CFX_PointF& point) {
123*3ac0a46fSAndroid Build Coastguard Worker   if (!IsButtonDown())
124*3ac0a46fSAndroid Build Coastguard Worker     return false;
125*3ac0a46fSAndroid Build Coastguard Worker 
126*3ac0a46fSAndroid Build Coastguard Worker   SetButtonDown(false);
127*3ac0a46fSAndroid Build Coastguard Worker   WideString wsURLContent = GetLinkURLAtPoint(point);
128*3ac0a46fSAndroid Build Coastguard Worker   if (wsURLContent.IsEmpty())
129*3ac0a46fSAndroid Build Coastguard Worker     return false;
130*3ac0a46fSAndroid Build Coastguard Worker 
131*3ac0a46fSAndroid Build Coastguard Worker   GetDoc()->GotoURL(wsURLContent);
132*3ac0a46fSAndroid Build Coastguard Worker   return true;
133*3ac0a46fSAndroid Build Coastguard Worker }
134*3ac0a46fSAndroid Build Coastguard Worker 
HitTest(const CFX_PointF & point)135*3ac0a46fSAndroid Build Coastguard Worker FWL_WidgetHit CXFA_FFText::HitTest(const CFX_PointF& point) {
136*3ac0a46fSAndroid Build Coastguard Worker   if (GetRectWithoutRotate().Contains(point) &&
137*3ac0a46fSAndroid Build Coastguard Worker       !GetLinkURLAtPoint(point).IsEmpty()) {
138*3ac0a46fSAndroid Build Coastguard Worker     return FWL_WidgetHit::HyperLink;
139*3ac0a46fSAndroid Build Coastguard Worker   }
140*3ac0a46fSAndroid Build Coastguard Worker   return FWL_WidgetHit::Unknown;
141*3ac0a46fSAndroid Build Coastguard Worker }
142*3ac0a46fSAndroid Build Coastguard Worker 
GetLinkURLAtPoint(const CFX_PointF & point)143*3ac0a46fSAndroid Build Coastguard Worker WideString CXFA_FFText::GetLinkURLAtPoint(const CFX_PointF& point) {
144*3ac0a46fSAndroid Build Coastguard Worker   CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
145*3ac0a46fSAndroid Build Coastguard Worker   if (!pTextLayout)
146*3ac0a46fSAndroid Build Coastguard Worker     return WideString();
147*3ac0a46fSAndroid Build Coastguard Worker 
148*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rect = GetRectWithoutRotate();
149*3ac0a46fSAndroid Build Coastguard Worker   return pTextLayout->GetLinkURLAtPoint(point - rect.TopLeft());
150*3ac0a46fSAndroid Build Coastguard Worker }
151