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/src/foxitlib.h"
8#include "xfa/src/fxfa/src/common/xfa_common.h"
9#include "xfa_ffwidget.h"
10#include "xfa_ffdraw.h"
11#include "xfa_fftext.h"
12#include "xfa_textlayout.h"
13#include "xfa_ffpageview.h"
14#include "xfa_ffdoc.h"
15#include "xfa_ffapp.h"
16CXFA_FFText::CXFA_FFText(CXFA_FFPageView* pPageView, CXFA_WidgetAcc* pDataAcc)
17    : CXFA_FFDraw(pPageView, pDataAcc) {}
18CXFA_FFText::~CXFA_FFText() {}
19void CXFA_FFText::RenderWidget(CFX_Graphics* pGS,
20                               CFX_Matrix* pMatrix,
21                               FX_DWORD dwStatus,
22                               int32_t iRotate) {
23  if (!IsMatchVisibleStatus(dwStatus)) {
24    return;
25  }
26  {
27    CFX_Matrix mtRotate;
28    GetRotateMatrix(mtRotate);
29    if (pMatrix) {
30      mtRotate.Concat(*pMatrix);
31    }
32    CXFA_FFWidget::RenderWidget(pGS, &mtRotate, dwStatus);
33    CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout();
34    if (pTextLayout) {
35      CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
36      CFX_RectF rtText;
37      GetRectWithoutRotate(rtText);
38      if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin()) {
39        CXFA_LayoutItem* pItem = this;
40        if (pItem->GetPrev() == NULL && pItem->GetNext() == NULL) {
41          XFA_RectWidthoutMargin(rtText, mgWidget);
42        } else {
43          FX_FLOAT fLeftInset, fRightInset, fTopInset = 0, fBottomInset = 0;
44          mgWidget.GetLeftInset(fLeftInset);
45          mgWidget.GetRightInset(fRightInset);
46          if (pItem->GetPrev() == NULL) {
47            mgWidget.GetTopInset(fTopInset);
48          } else if (pItem->GetNext() == NULL) {
49            mgWidget.GetBottomInset(fBottomInset);
50          }
51          rtText.Deflate(fLeftInset, fTopInset, fRightInset, fBottomInset);
52        }
53      }
54      CFX_Matrix mt;
55      mt.Set(1, 0, 0, 1, rtText.left, rtText.top);
56      CFX_RectF rtClip = rtText;
57      mtRotate.TransformRect(rtClip);
58      mt.Concat(mtRotate);
59      pTextLayout->DrawString(pRenderDevice, mt, rtClip, GetIndex());
60    }
61  }
62}
63FX_BOOL CXFA_FFText::IsLoaded() {
64  CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout();
65  return pTextLayout != NULL && !pTextLayout->m_bHasBlock;
66}
67FX_BOOL CXFA_FFText::PerformLayout() {
68  CXFA_FFDraw::PerformLayout();
69  CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout();
70  if (!pTextLayout) {
71    return FALSE;
72  }
73  if (!pTextLayout->m_bHasBlock) {
74    return TRUE;
75  }
76  pTextLayout->m_Blocks.RemoveAll();
77  CXFA_LayoutItem* pItem = this;
78  if (pItem->GetPrev() == NULL && pItem->GetNext() == NULL) {
79    return TRUE;
80  }
81  pItem = pItem->GetFirst();
82  while (pItem) {
83    CFX_RectF rtText;
84    pItem->GetRect(rtText);
85    if (CXFA_Margin mgWidget = m_pDataAcc->GetMargin()) {
86      if (pItem->GetPrev() == NULL) {
87        FX_FLOAT fTopInset;
88        mgWidget.GetTopInset(fTopInset);
89        rtText.height -= fTopInset;
90      } else if (pItem->GetNext() == NULL) {
91        FX_FLOAT fBottomInset;
92        mgWidget.GetBottomInset(fBottomInset);
93        rtText.height -= fBottomInset;
94      }
95    }
96    pTextLayout->ItemBlocks(rtText, pItem->GetIndex());
97    pItem = pItem->GetNext();
98  }
99  pTextLayout->m_bHasBlock = FALSE;
100  return TRUE;
101}
102FX_BOOL CXFA_FFText::OnLButtonDown(FX_DWORD dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
103  CFX_RectF rtBox;
104  GetRectWithoutRotate(rtBox);
105  if (!rtBox.Contains(fx, fy)) {
106    return FALSE;
107  }
108  const FX_WCHAR* wsURLContent = GetLinkURLAtPoint(fx, fy);
109  if (NULL == wsURLContent) {
110    return FALSE;
111  }
112  SetButtonDown(TRUE);
113  return TRUE;
114}
115FX_BOOL CXFA_FFText::OnMouseMove(FX_DWORD dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
116  CFX_RectF rtBox;
117  GetRectWithoutRotate(rtBox);
118  if (!rtBox.Contains(fx, fy)) {
119    return FALSE;
120  }
121  const FX_WCHAR* wsURLContent = GetLinkURLAtPoint(fx, fy);
122  if (NULL == wsURLContent) {
123    return FALSE;
124  }
125  return TRUE;
126}
127FX_BOOL CXFA_FFText::OnLButtonUp(FX_DWORD dwFlags, FX_FLOAT fx, FX_FLOAT fy) {
128  if (!IsButtonDown()) {
129    return FALSE;
130  }
131  SetButtonDown(FALSE);
132  const FX_WCHAR* wsURLContent = GetLinkURLAtPoint(fx, fy);
133  if (NULL == wsURLContent) {
134    return FALSE;
135  }
136  CXFA_FFDoc* pDoc = GetDoc();
137  pDoc->GetDocProvider()->GotoURL(pDoc, CFX_WideStringC(wsURLContent), FALSE);
138  return TRUE;
139}
140FX_DWORD CXFA_FFText::OnHitTest(FX_FLOAT fx, FX_FLOAT fy) {
141  CFX_RectF rtBox;
142  GetRectWithoutRotate(rtBox);
143  if (!rtBox.Contains(fx, fy)) {
144    return FWL_WGTHITTEST_Unknown;
145  }
146  if (!GetLinkURLAtPoint(fx, fy)) {
147    return FWL_WGTHITTEST_Unknown;
148  }
149  return FWL_WGTHITTEST_HyperLink;
150}
151const FX_WCHAR* CXFA_FFText::GetLinkURLAtPoint(FX_FLOAT fx, FX_FLOAT fy) {
152  CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout();
153  if (NULL == pTextLayout) {
154    return NULL;
155  }
156  FX_FLOAT x(fx), y(fy);
157  FWLToClient(x, y);
158  const CXFA_PieceLineArray* pPieceLines = pTextLayout->GetPieceLines();
159  int32_t iCount = pPieceLines->GetSize();
160  for (int32_t i = 0; i < iCount; i++) {
161    CXFA_PieceLine* pPieceLine = pPieceLines->GetAt(i);
162    int32_t iPieces = pPieceLine->m_textPieces.GetSize();
163    for (int32_t j = 0; j < iPieces; j++) {
164      XFA_LPTEXTPIECE pPiece = pPieceLine->m_textPieces.GetAt(j);
165      if (pPiece->pLinkData && pPiece->rtPiece.Contains(x, y)) {
166        return pPiece->pLinkData->GetLinkURL();
167      }
168    }
169  }
170  return NULL;
171}
172void CXFA_FFText::FWLToClient(FX_FLOAT& fx, FX_FLOAT& fy) {
173  CFX_RectF rtWidget;
174  GetRectWithoutRotate(rtWidget);
175  fx -= rtWidget.left;
176  fy -= rtWidget.top;
177}
178