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 22 CXFA_FFText::CXFA_FFText(CXFA_WidgetAcc* pDataAcc) : CXFA_FFDraw(pDataAcc) {} 23 24 CXFA_FFText::~CXFA_FFText() {} 25 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 71 bool CXFA_FFText::IsLoaded() { 72 CXFA_TextLayout* pTextLayout = m_pDataAcc->GetTextLayout(); 73 return pTextLayout && !pTextLayout->m_bHasBlock; 74 } 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 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 122 bool CXFA_FFText::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) { 123 return GetRectWithoutRotate().Contains(point) && !!GetLinkURLAtPoint(point); 124 } 125 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 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 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