blob: 34534be8085094f483343fdf24eb5cda56fa6327 [file] [log] [blame] [edit]
// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "xfa/fxfa/cxfa_fftext.h"
#include "xfa/fgas/layout/cfx_linkuserdata.h"
#include "xfa/fwl/fwl_widgethit.h"
#include "xfa/fxfa/cxfa_ffapp.h"
#include "xfa/fxfa/cxfa_ffdoc.h"
#include "xfa/fxfa/cxfa_ffpageview.h"
#include "xfa/fxfa/cxfa_ffwidget.h"
#include "xfa/fxfa/cxfa_pieceline.h"
#include "xfa/fxfa/cxfa_textlayout.h"
#include "xfa/fxfa/cxfa_textpiece.h"
#include "xfa/fxfa/parser/cxfa_margin.h"
#include "xfa/fxgraphics/cxfa_graphics.h"
CXFA_FFText::CXFA_FFText(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
CXFA_FFText::~CXFA_FFText() = default;
void CXFA_FFText::RenderWidget(CXFA_Graphics* pGS,
const CFX_Matrix& matrix,
HighlightOption highlight) {
if (!HasVisibleStatus())
return;
CFX_Matrix mtRotate = GetRotateMatrix();
mtRotate.Concat(matrix);
CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
if (!pTextLayout)
return;
CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
CFX_RectF rtText = GetRectWithoutRotate();
CXFA_Margin* margin = m_pNode->GetMarginIfExists();
if (margin) {
CXFA_ContentLayoutItem* pItem = GetLayoutItem();
if (!pItem->GetPrev() && !pItem->GetNext()) {
XFA_RectWithoutMargin(&rtText, margin);
} else {
float fTopInset = 0;
float fBottomInset = 0;
if (!pItem->GetPrev())
fTopInset = margin->GetTopInset();
else if (!pItem->GetNext())
fBottomInset = margin->GetBottomInset();
rtText.Deflate(margin->GetLeftInset(), fTopInset, margin->GetRightInset(),
fBottomInset);
}
}
CFX_Matrix mt(1, 0, 0, 1, rtText.left, rtText.top);
CFX_RectF rtClip = mtRotate.TransformRect(rtText);
mt.Concat(mtRotate);
pTextLayout->DrawString(pRenderDevice, mt, rtClip,
GetLayoutItem()->GetIndex());
}
bool CXFA_FFText::IsLoaded() {
CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
return pTextLayout && !pTextLayout->HasBlock();
}
bool CXFA_FFText::PerformLayout() {
CXFA_FFWidget::PerformLayout();
CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
if (!pTextLayout)
return false;
if (!pTextLayout->HasBlock())
return true;
pTextLayout->ClearBlocks();
CXFA_ContentLayoutItem* pItem = GetLayoutItem();
if (!pItem->GetPrev() && !pItem->GetNext())
return true;
pItem = pItem->GetFirst();
while (pItem) {
CFX_RectF rtText = pItem->GetRect(false);
CXFA_Margin* margin = m_pNode->GetMarginIfExists();
if (margin) {
if (!pItem->GetPrev())
rtText.height -= margin->GetTopInset();
else if (!pItem->GetNext())
rtText.height -= margin->GetBottomInset();
}
pTextLayout->ItemBlocks(rtText, pItem->GetIndex());
pItem = pItem->GetNext();
}
pTextLayout->ResetHasBlock();
return true;
}
bool CXFA_FFText::AcceptsFocusOnButtonDown(uint32_t dwFlags,
const CFX_PointF& point,
FWL_MouseCommand command) {
if (command != FWL_MouseCommand::LeftButtonDown)
return false;
if (!GetRectWithoutRotate().Contains(point))
return false;
const wchar_t* wsURLContent = GetLinkURLAtPoint(point);
if (!wsURLContent)
return false;
return true;
}
bool CXFA_FFText::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
SetButtonDown(true);
return true;
}
bool CXFA_FFText::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) {
return GetRectWithoutRotate().Contains(point) && !!GetLinkURLAtPoint(point);
}
bool CXFA_FFText::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
if (!IsButtonDown())
return false;
SetButtonDown(false);
const wchar_t* wsURLContent = GetLinkURLAtPoint(point);
if (!wsURLContent)
return false;
GetDoc()->GotoURL(wsURLContent);
return true;
}
FWL_WidgetHit CXFA_FFText::HitTest(const CFX_PointF& point) {
if (!GetRectWithoutRotate().Contains(point))
return FWL_WidgetHit::Unknown;
if (!GetLinkURLAtPoint(point))
return FWL_WidgetHit::Unknown;
return FWL_WidgetHit::HyperLink;
}
const wchar_t* CXFA_FFText::GetLinkURLAtPoint(const CFX_PointF& point) {
CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
if (!pTextLayout)
return nullptr;
CFX_RectF rect = GetRectWithoutRotate();
for (const auto& pPieceLine : *pTextLayout->GetPieceLines()) {
for (const auto& pPiece : pPieceLine->m_textPieces) {
if (pPiece->pLinkData &&
pPiece->rtPiece.Contains(point - rect.TopLeft())) {
return pPiece->pLinkData->GetLinkURL();
}
}
}
return nullptr;
}