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