// Copyright 2014 The PDFium Authors // 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_ffwidget.h" #include #include #include #include "core/fxcodec/fx_codec.h" #include "core/fxcodec/progressive_decoder.h" #include "core/fxcrt/maybe_owned.h" #include "core/fxge/cfx_fillrenderoptions.h" #include "core/fxge/cfx_path.h" #include "core/fxge/cfx_renderdevice.h" #include "core/fxge/dib/cfx_dibitmap.h" #include "third_party/base/check.h" #include "xfa/fgas/graphics/cfgas_gegraphics.h" #include "xfa/fwl/fwl_widgethit.h" #include "xfa/fxfa/cxfa_eventparam.h" #include "xfa/fxfa/cxfa_ffapp.h" #include "xfa/fxfa/cxfa_ffdoc.h" #include "xfa/fxfa/cxfa_ffdocview.h" #include "xfa/fxfa/cxfa_ffpageview.h" #include "xfa/fxfa/cxfa_ffwidgethandler.h" #include "xfa/fxfa/cxfa_imagerenderer.h" #include "xfa/fxfa/layout/cxfa_layoutprocessor.h" #include "xfa/fxfa/parser/cxfa_border.h" #include "xfa/fxfa/parser/cxfa_box.h" #include "xfa/fxfa/parser/cxfa_edge.h" #include "xfa/fxfa/parser/cxfa_image.h" #include "xfa/fxfa/parser/cxfa_margin.h" #include "xfa/fxfa/parser/cxfa_node.h" namespace { FXDIB_Format XFA_GetDIBFormat(FXCODEC_IMAGE_TYPE type, int32_t iComponents, int32_t iBitsPerComponent) { FXDIB_Format dibFormat = FXDIB_Format::kArgb; switch (type) { case FXCODEC_IMAGE_JPG: #ifdef PDF_ENABLE_XFA_BMP case FXCODEC_IMAGE_BMP: #endif // PDF_ENABLE_XFA_BMP #ifdef PDF_ENABLE_XFA_TIFF case FXCODEC_IMAGE_TIFF: #endif // PDF_ENABLE_XFA_TIFF { dibFormat = FXDIB_Format::kRgb32; int32_t bpp = iComponents * iBitsPerComponent; if (bpp <= 24) { dibFormat = FXDIB_Format::kRgb; } } break; #ifdef PDF_ENABLE_XFA_PNG case FXCODEC_IMAGE_PNG: #endif // PDF_ENABLE_XFA_PNG default: break; } return dibFormat; } } // namespace void XFA_DrawImage(CFGAS_GEGraphics* pGS, const CFX_RectF& rtImage, const CFX_Matrix& matrix, RetainPtr pDIBitmap, XFA_AttributeValue iAspect, const CFX_Size& dpi, XFA_AttributeValue iHorzAlign, XFA_AttributeValue iVertAlign) { if (rtImage.IsEmpty()) return; if (!pDIBitmap || pDIBitmap->GetBuffer().empty()) return; CFX_RectF rtFit(rtImage.TopLeft(), XFA_UnitPx2Pt(pDIBitmap->GetWidth(), dpi.width), XFA_UnitPx2Pt(pDIBitmap->GetHeight(), dpi.height)); switch (iAspect) { case XFA_AttributeValue::Fit: { float f1 = rtImage.height / rtFit.height; float f2 = rtImage.width / rtFit.width; f1 = std::min(f1, f2); rtFit.height = rtFit.height * f1; rtFit.width = rtFit.width * f1; break; } case XFA_AttributeValue::Height: { float f1 = rtImage.height / rtFit.height; rtFit.height = rtImage.height; rtFit.width = f1 * rtFit.width; break; } case XFA_AttributeValue::None: rtFit.height = rtImage.height; rtFit.width = rtImage.width; break; case XFA_AttributeValue::Width: { float f1 = rtImage.width / rtFit.width; rtFit.width = rtImage.width; rtFit.height = rtFit.height * f1; break; } case XFA_AttributeValue::Actual: default: break; } if (iHorzAlign == XFA_AttributeValue::Center) rtFit.left += (rtImage.width - rtFit.width) / 2; else if (iHorzAlign == XFA_AttributeValue::Right) rtFit.left = rtImage.right() - rtFit.width; if (iVertAlign == XFA_AttributeValue::Middle) rtFit.top += (rtImage.height - rtFit.height) / 2; else if (iVertAlign == XFA_AttributeValue::Bottom) rtFit.top = rtImage.bottom() - rtImage.height; CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice(); CFX_RenderDevice::StateRestorer restorer(pRenderDevice); CFX_Path path; path.AppendRect(rtImage.left, rtImage.bottom(), rtImage.right(), rtImage.top); pRenderDevice->SetClip_PathFill(path, &matrix, CFX_FillRenderOptions::WindingOptions()); CFX_Matrix mtImage(1, 0, 0, -1, 0, 1); mtImage.Concat( CFX_Matrix(rtFit.width, 0, 0, rtFit.height, rtFit.left, rtFit.top)); mtImage.Concat(matrix); CXFA_ImageRenderer imageRender(pRenderDevice, std::move(pDIBitmap), mtImage); if (!imageRender.Start()) return; while (imageRender.Continue()) continue; } RetainPtr XFA_LoadImageFromBuffer( RetainPtr pImageFileRead, FXCODEC_IMAGE_TYPE type, int32_t& iImageXDpi, int32_t& iImageYDpi) { auto pProgressiveDecoder = std::make_unique(); CFX_DIBAttribute dibAttr; pProgressiveDecoder->LoadImageInfo(std::move(pImageFileRead), type, &dibAttr, false); switch (dibAttr.m_wDPIUnit) { case CFX_DIBAttribute::kResUnitCentimeter: dibAttr.m_nXDPI = static_cast(dibAttr.m_nXDPI * 2.54f); dibAttr.m_nYDPI = static_cast(dibAttr.m_nYDPI * 2.54f); break; case CFX_DIBAttribute::kResUnitMeter: dibAttr.m_nXDPI = static_cast(dibAttr.m_nXDPI / (float)100 * 2.54f); dibAttr.m_nYDPI = static_cast(dibAttr.m_nYDPI / (float)100 * 2.54f); break; default: break; } iImageXDpi = dibAttr.m_nXDPI > 1 ? dibAttr.m_nXDPI : (96); iImageYDpi = dibAttr.m_nYDPI > 1 ? dibAttr.m_nYDPI : (96); if (pProgressiveDecoder->GetWidth() <= 0 || pProgressiveDecoder->GetHeight() <= 0) { return nullptr; } type = pProgressiveDecoder->GetType(); int32_t iComponents = pProgressiveDecoder->GetNumComponents(); int32_t iBpc = pProgressiveDecoder->GetBPC(); FXDIB_Format dibFormat = XFA_GetDIBFormat(type, iComponents, iBpc); RetainPtr pBitmap = pdfium::MakeRetain(); pBitmap->Create(pProgressiveDecoder->GetWidth(), pProgressiveDecoder->GetHeight(), dibFormat); pBitmap->Clear(0xffffffff); size_t nFrames; FXCODEC_STATUS status; std::tie(status, nFrames) = pProgressiveDecoder->GetFrames(); if (status != FXCODEC_STATUS::kDecodeReady || nFrames == 0) return nullptr; status = pProgressiveDecoder->StartDecode(pBitmap, 0, 0, pBitmap->GetWidth(), pBitmap->GetHeight()); if (status == FXCODEC_STATUS::kError) return nullptr; while (status == FXCODEC_STATUS::kDecodeToBeContinued) { status = pProgressiveDecoder->ContinueDecode(); if (status == FXCODEC_STATUS::kError) return nullptr; } return pBitmap; } void XFA_RectWithoutMargin(CFX_RectF* rt, const CXFA_Margin* margin) { if (!margin) return; rt->Deflate(margin->GetLeftInset(), margin->GetTopInset(), margin->GetRightInset(), margin->GetBottomInset()); } // static CXFA_FFWidget* CXFA_FFWidget::FromLayoutItem(CXFA_LayoutItem* pLayoutItem) { if (!pLayoutItem->GetFormNode()->HasCreatedUIWidget()) return nullptr; return GetFFWidget(ToContentLayoutItem(pLayoutItem)); } CXFA_FFWidget::CXFA_FFWidget(CXFA_Node* node) : m_pNode(node) {} CXFA_FFWidget::~CXFA_FFWidget() = default; void CXFA_FFWidget::Trace(cppgc::Visitor* visitor) const { visitor->Trace(m_pLayoutItem); visitor->Trace(m_pDocView); visitor->Trace(m_pPageView); visitor->Trace(m_pNode); } CFWL_App* CXFA_FFWidget::GetFWLApp() const { return GetPageView()->GetDocView()->GetDoc()->GetApp()->GetFWLApp(); } CXFA_FFWidget* CXFA_FFWidget::GetNextFFWidget() const { return GetFFWidget(GetLayoutItem()->GetNext()); } const CFX_RectF& CXFA_FFWidget::GetWidgetRect() const { if (!GetLayoutItem()->TestStatusBits(XFA_WidgetStatus::kRectCached)) RecacheWidgetRect(); return m_WidgetRect; } const CFX_RectF& CXFA_FFWidget::RecacheWidgetRect() const { GetLayoutItem()->SetStatusBits(XFA_WidgetStatus::kRectCached); m_WidgetRect = GetLayoutItem()->GetAbsoluteRect(); return m_WidgetRect; } CFX_RectF CXFA_FFWidget::GetRectWithoutRotate() { CFX_RectF rtWidget = GetWidgetRect(); float fValue = 0; switch (m_pNode->GetRotate()) { case 90: rtWidget.top = rtWidget.bottom(); fValue = rtWidget.width; rtWidget.width = rtWidget.height; rtWidget.height = fValue; break; case 180: rtWidget.left = rtWidget.right(); rtWidget.top = rtWidget.bottom(); break; case 270: rtWidget.left = rtWidget.right(); fValue = rtWidget.width; rtWidget.width = rtWidget.height; rtWidget.height = fValue; break; } return rtWidget; } void CXFA_FFWidget::ModifyStatus(Mask dwAdded, Mask dwRemoved) { GetLayoutItem()->ClearStatusBits(dwRemoved); GetLayoutItem()->SetStatusBits(dwAdded); } CXFA_FFField* CXFA_FFWidget::AsField() { return nullptr; } CFX_RectF CXFA_FFWidget::GetBBox(FocusOption focus) { if (focus == kDrawFocus || !m_pPageView) return CFX_RectF(); return m_pPageView->GetPageViewRect(); } void CXFA_FFWidget::RenderWidget(CFGAS_GEGraphics* pGS, const CFX_Matrix& matrix, HighlightOption highlight) { if (!HasVisibleStatus()) return; CXFA_Border* border = m_pNode->GetBorderIfExists(); if (!border) return; CFX_RectF rtBorder = GetRectWithoutRotate(); CXFA_Margin* margin = border->GetMarginIfExists(); XFA_RectWithoutMargin(&rtBorder, margin); rtBorder.Normalize(); DrawBorder(pGS, border, rtBorder, matrix); } bool CXFA_FFWidget::IsLoaded() { return !!m_pPageView; } bool CXFA_FFWidget::LoadWidget() { PerformLayout(); return true; } bool CXFA_FFWidget::PerformLayout() { RecacheWidgetRect(); return true; } bool CXFA_FFWidget::UpdateFWLData() { return false; } void CXFA_FFWidget::UpdateWidgetProperty() {} bool CXFA_FFWidget::HasEventUnderHandler(XFA_EVENTTYPE eEventType, CXFA_FFWidgetHandler* pHandler) { CXFA_Node* pNode = GetNode(); return pNode->IsWidgetReady() && pHandler->HasEvent(pNode, eEventType); } bool CXFA_FFWidget::ProcessEventUnderHandler(CXFA_EventParam* params, CXFA_FFWidgetHandler* pHandler) { CXFA_Node* pNode = GetNode(); if (!pNode->IsWidgetReady()) return false; return pHandler->ProcessEvent(pNode, params) == XFA_EventError::kSuccess; } void CXFA_FFWidget::DrawBorder(CFGAS_GEGraphics* pGS, CXFA_Box* box, const CFX_RectF& rtBorder, const CFX_Matrix& matrix) { if (box) box->Draw(pGS, rtBorder, matrix, false); } void CXFA_FFWidget::DrawBorderWithFlag(CFGAS_GEGraphics* pGS, CXFA_Box* box, const CFX_RectF& rtBorder, const CFX_Matrix& matrix, bool forceRound) { if (box) box->Draw(pGS, rtBorder, matrix, forceRound); } void CXFA_FFWidget::InvalidateRect() { CFX_RectF rtWidget = GetBBox(kDoNotDrawFocus); rtWidget.Inflate(2, 2); m_pDocView->InvalidateRect(m_pPageView.Get(), rtWidget); } bool CXFA_FFWidget::OnMouseEnter() { return false; } bool CXFA_FFWidget::OnMouseExit() { return false; } bool CXFA_FFWidget::AcceptsFocusOnButtonDown( Mask dwFlags, const CFX_PointF& point, CFWL_MessageMouse::MouseCommand command) { return false; } bool CXFA_FFWidget::OnLButtonDown(Mask dwFlags, const CFX_PointF& point) { return false; } bool CXFA_FFWidget::OnLButtonUp(Mask dwFlags, const CFX_PointF& point) { return false; } bool CXFA_FFWidget::OnLButtonDblClk(Mask dwFlags, const CFX_PointF& point) { return false; } bool CXFA_FFWidget::OnMouseMove(Mask dwFlags, const CFX_PointF& point) { return false; } bool CXFA_FFWidget::OnMouseWheel(Mask dwFlags, const CFX_PointF& point, const CFX_Vector& delta) { return false; } bool CXFA_FFWidget::OnRButtonDown(Mask dwFlags, const CFX_PointF& point) { return false; } bool CXFA_FFWidget::OnRButtonUp(Mask dwFlags, const CFX_PointF& point) { return false; } bool CXFA_FFWidget::OnRButtonDblClk(Mask dwFlags, const CFX_PointF& point) { return false; } bool CXFA_FFWidget::OnSetFocus(CXFA_FFWidget* pOldWidget) { CXFA_FFWidget* pParent = GetFFWidget(ToContentLayoutItem(GetParent())); if (pParent && !pParent->IsAncestorOf(pOldWidget)) { if (!pParent->OnSetFocus(pOldWidget)) return false; } GetLayoutItem()->SetStatusBits(XFA_WidgetStatus::kFocused); CXFA_EventParam eParam; eParam.m_eType = XFA_EVENT_Enter; m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Enter, &eParam); return true; } bool CXFA_FFWidget::OnKillFocus(CXFA_FFWidget* pNewWidget) { GetLayoutItem()->ClearStatusBits(XFA_WidgetStatus::kFocused); EventKillFocus(); if (!pNewWidget) return true; CXFA_FFWidget* pParent = GetFFWidget(ToContentLayoutItem(GetParent())); if (pParent && !pParent->IsAncestorOf(pNewWidget)) { if (!pParent->OnKillFocus(pNewWidget)) return false; } return true; } bool CXFA_FFWidget::OnKeyDown(XFA_FWL_VKEYCODE dwKeyCode, Mask dwFlags) { return false; } bool CXFA_FFWidget::OnChar(uint32_t dwChar, Mask dwFlags) { return false; } FWL_WidgetHit CXFA_FFWidget::HitTest(const CFX_PointF& point) { return FWL_WidgetHit::Unknown; } bool CXFA_FFWidget::CanUndo() { return false; } bool CXFA_FFWidget::CanRedo() { return false; } bool CXFA_FFWidget::CanCopy() { return false; } bool CXFA_FFWidget::CanCut() { return false; } bool CXFA_FFWidget::CanPaste() { return false; } bool CXFA_FFWidget::CanSelectAll() { return false; } bool CXFA_FFWidget::CanDelete() { return CanCut(); } bool CXFA_FFWidget::CanDeSelect() { return CanCopy(); } bool CXFA_FFWidget::Undo() { return false; } bool CXFA_FFWidget::Redo() { return false; } absl::optional CXFA_FFWidget::Copy() { return absl::nullopt; } absl::optional CXFA_FFWidget::Cut() { return absl::nullopt; } bool CXFA_FFWidget::Paste(const WideString& wsPaste) { return false; } void CXFA_FFWidget::SelectAll() {} void CXFA_FFWidget::Delete() {} void CXFA_FFWidget::DeSelect() {} WideString CXFA_FFWidget::GetText() { return WideString(); } FormFieldType CXFA_FFWidget::GetFormFieldType() { return FormFieldType::kXFA; } CFX_PointF CXFA_FFWidget::Rotate2Normal(const CFX_PointF& point) { CFX_Matrix mt = GetRotateMatrix(); if (mt.IsIdentity()) return point; return mt.GetInverse().Transform(point); } CFX_Matrix CXFA_FFWidget::GetRotateMatrix() { int32_t iRotate = m_pNode->GetRotate(); if (!iRotate) return CFX_Matrix(); CFX_RectF rcWidget = GetRectWithoutRotate(); CFX_Matrix mt; switch (iRotate) { case 90: mt.a = 0; mt.b = -1; mt.c = 1; mt.d = 0; mt.e = rcWidget.left - rcWidget.top; mt.f = rcWidget.left + rcWidget.top; break; case 180: mt.a = -1; mt.b = 0; mt.c = 0; mt.d = -1; mt.e = rcWidget.left * 2; mt.f = rcWidget.top * 2; break; case 270: mt.a = 0; mt.b = 1; mt.c = -1; mt.d = 0; mt.e = rcWidget.left + rcWidget.top; mt.f = rcWidget.top - rcWidget.left; break; } return mt; } void CXFA_FFWidget::DisplayCaret(bool bVisible, const CFX_RectF* pRtAnchor) { GetDoc()->DisplayCaret(this, bVisible, pRtAnchor); } void CXFA_FFWidget::GetBorderColorAndThickness(FX_ARGB* cr, float* fWidth) { DCHECK(GetNode()->IsWidgetReady()); CXFA_Border* borderUI = GetNode()->GetUIBorder(); if (!borderUI) return; CXFA_Edge* edge = borderUI->GetEdgeIfExists(0); if (!edge) return; *cr = edge->GetColor(); *fWidth = edge->GetThickness(); } bool CXFA_FFWidget::IsLayoutRectEmpty() { CFX_RectF rtLayout = GetRectWithoutRotate(); return rtLayout.width < 0.1f && rtLayout.height < 0.1f; } CXFA_LayoutItem* CXFA_FFWidget::GetParent() { CXFA_Node* pParentNode = m_pNode->GetParent(); if (!pParentNode) return nullptr; CXFA_LayoutProcessor* layout = GetDocView()->GetLayoutProcessor(); return layout->GetLayoutItem(pParentNode); } bool CXFA_FFWidget::IsAncestorOf(CXFA_FFWidget* pWidget) { if (!pWidget) return false; CXFA_Node* pChildNode = pWidget->GetNode(); while (pChildNode) { if (pChildNode == m_pNode) return true; pChildNode = pChildNode->GetParent(); } return false; } bool CXFA_FFWidget::PtInActiveRect(const CFX_PointF& point) { return GetWidgetRect().Contains(point); } CXFA_FFDoc* CXFA_FFWidget::GetDoc() { return m_pDocView->GetDoc(); } CXFA_FFApp* CXFA_FFWidget::GetApp() { return GetDoc()->GetApp(); } CXFA_FFApp::CallbackIface* CXFA_FFWidget::GetAppProvider() { return GetApp()->GetAppProvider(); } bool CXFA_FFWidget::HasVisibleStatus() const { return GetLayoutItem()->TestStatusBits(XFA_WidgetStatus::kVisible); } void CXFA_FFWidget::EventKillFocus() { CXFA_ContentLayoutItem* pItem = GetLayoutItem(); if (pItem->TestStatusBits(XFA_WidgetStatus::kAccess)) { pItem->ClearStatusBits(XFA_WidgetStatus::kAccess); return; } CXFA_EventParam eParam; eParam.m_eType = XFA_EVENT_Exit; m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Exit, &eParam); } bool CXFA_FFWidget::IsButtonDown() { return GetLayoutItem()->TestStatusBits(XFA_WidgetStatus::kButtonDown); } void CXFA_FFWidget::SetButtonDown(bool bSet) { CXFA_ContentLayoutItem* pItem = GetLayoutItem(); if (bSet) pItem->SetStatusBits(XFA_WidgetStatus::kButtonDown); else pItem->ClearStatusBits(XFA_WidgetStatus::kButtonDown); }