diff options
author | Dan Sinclair <dsinclair@chromium.org> | 2018-01-16 21:25:27 +0000 |
---|---|---|
committer | Chromium commit bot <commit-bot@chromium.org> | 2018-01-16 21:25:27 +0000 |
commit | 027190ec8148a2f1edc18c37eae26e896f3a309a (patch) | |
tree | 6f65b1bb530309b8d6656e92e66dad1fcd1e1e44 /xfa | |
parent | 454ab87a354099fb96eee4721328d59f42ca0557 (diff) | |
download | pdfium-027190ec8148a2f1edc18c37eae26e896f3a309a.tar.xz |
Move CXFA_ImageRenderer to own file
This CL Splits CL_ImageRenderer out of CXFA_FFWidget and moves to a
separate file. Methods in CXFA_FFWidget are shuffled around to put the
global methods at the top of the file and static methods in the
anonymous namespace.
Change-Id: I9887a5c9bf9fda63deead7ff785dc4ef3d7e15c8
Reviewed-on: https://pdfium-review.googlesource.com/23031
Reviewed-by: Henrique Nakashima <hnakashima@chromium.org>
Commit-Queue: dsinclair <dsinclair@chromium.org>
Diffstat (limited to 'xfa')
-rw-r--r-- | xfa/fxfa/cxfa_ffwidget.cpp | 1040 | ||||
-rw-r--r-- | xfa/fxfa/cxfa_ffwidget.h | 15 | ||||
-rw-r--r-- | xfa/fxfa/cxfa_imagerenderer.cpp | 238 | ||||
-rw-r--r-- | xfa/fxfa/cxfa_imagerenderer.h | 61 | ||||
-rw-r--r-- | xfa/fxfa/cxfa_widgetacc.cpp | 147 |
5 files changed, 737 insertions, 764 deletions
diff --git a/xfa/fxfa/cxfa_ffwidget.cpp b/xfa/fxfa/cxfa_ffwidget.cpp index 8f7bda6d9e..6aa6fd61b8 100644 --- a/xfa/fxfa/cxfa_ffwidget.cpp +++ b/xfa/fxfa/cxfa_ffwidget.cpp @@ -19,15 +19,14 @@ #include "core/fxcrt/cfx_memorystream.h" #include "core/fxcrt/maybe_owned.h" #include "core/fxge/cfx_pathdata.h" -#include "core/fxge/cfx_renderdevice.h" #include "core/fxge/dib/cfx_imagerenderer.h" -#include "core/fxge/dib/cfx_imagetransformer.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_imagerenderer.h" #include "xfa/fxfa/cxfa_textlayout.h" #include "xfa/fxfa/cxfa_widgetacc.h" #include "xfa/fxfa/parser/cxfa_border.h" @@ -886,6 +885,84 @@ void XFA_DrawBox(CXFA_Box* box, XFA_BOX_Stroke(box, strokes, pGS, rtWidget, matrix, forceRound); } +void XFA_GetMatrix(CFX_Matrix& m, + int32_t iRotate, + XFA_AttributeEnum at, + const CFX_RectF& rt) { + if (!iRotate) { + return; + } + float fAnchorX = 0; + float fAnchorY = 0; + switch (at) { + case XFA_AttributeEnum::TopLeft: + fAnchorX = rt.left, fAnchorY = rt.top; + break; + case XFA_AttributeEnum::TopCenter: + fAnchorX = (rt.left + rt.right()) / 2, fAnchorY = rt.top; + break; + case XFA_AttributeEnum::TopRight: + fAnchorX = rt.right(), fAnchorY = rt.top; + break; + case XFA_AttributeEnum::MiddleLeft: + fAnchorX = rt.left, fAnchorY = (rt.top + rt.bottom()) / 2; + break; + case XFA_AttributeEnum::MiddleCenter: + fAnchorX = (rt.left + rt.right()) / 2, + fAnchorY = (rt.top + rt.bottom()) / 2; + break; + case XFA_AttributeEnum::MiddleRight: + fAnchorX = rt.right(), fAnchorY = (rt.top + rt.bottom()) / 2; + break; + case XFA_AttributeEnum::BottomLeft: + fAnchorX = rt.left, fAnchorY = rt.bottom(); + break; + case XFA_AttributeEnum::BottomCenter: + fAnchorX = (rt.left + rt.right()) / 2, fAnchorY = rt.bottom(); + break; + case XFA_AttributeEnum::BottomRight: + fAnchorX = rt.right(), fAnchorY = rt.bottom(); + break; + default: + break; + } + switch (iRotate) { + case 90: + m.a = 0, m.b = -1, m.c = 1, m.d = 0, m.e = fAnchorX - fAnchorY, + m.f = fAnchorX + fAnchorY; + break; + case 180: + m.a = -1, m.b = 0, m.c = 0, m.d = -1, m.e = fAnchorX * 2, + m.f = fAnchorY * 2; + break; + case 270: + m.a = 0, m.b = 1, m.c = -1, m.d = 0, m.e = fAnchorX + fAnchorY, + m.f = fAnchorY - fAnchorX; + break; + } +} + +FXDIB_Format XFA_GetDIBFormat(FXCODEC_IMAGE_TYPE type, + int32_t iComponents, + int32_t iBitsPerComponent) { + FXDIB_Format dibFormat = FXDIB_Argb; + switch (type) { + case FXCODEC_IMAGE_BMP: + case FXCODEC_IMAGE_JPG: + case FXCODEC_IMAGE_TIF: { + dibFormat = FXDIB_Rgb32; + int32_t bpp = iComponents * iBitsPerComponent; + if (bpp <= 24) { + dibFormat = FXDIB_Rgb; + } + } break; + case FXCODEC_IMAGE_PNG: + default: + break; + } + return dibFormat; +} + bool IsFXCodecErrorStatus(FXCODEC_STATUS status) { return (status == FXCODEC_STATUS_ERROR || #ifdef PDF_ENABLE_XFA @@ -899,6 +976,218 @@ bool IsFXCodecErrorStatus(FXCODEC_STATUS status) { } // namespace +int32_t XFA_StrokeTypeSetLineDash(CXFA_Graphics* pGraphics, + XFA_AttributeEnum iStrokeType, + XFA_AttributeEnum iCapType) { + switch (iStrokeType) { + case XFA_AttributeEnum::DashDot: { + float dashArray[] = {4, 1, 2, 1}; + if (iCapType != XFA_AttributeEnum::Butt) { + dashArray[1] = 2; + dashArray[3] = 2; + } + pGraphics->SetLineDash(0, dashArray, 4); + return FX_DASHSTYLE_DashDot; + } + case XFA_AttributeEnum::DashDotDot: { + float dashArray[] = {4, 1, 2, 1, 2, 1}; + if (iCapType != XFA_AttributeEnum::Butt) { + dashArray[1] = 2; + dashArray[3] = 2; + dashArray[5] = 2; + } + pGraphics->SetLineDash(0, dashArray, 6); + return FX_DASHSTYLE_DashDotDot; + } + case XFA_AttributeEnum::Dashed: { + float dashArray[] = {5, 1}; + if (iCapType != XFA_AttributeEnum::Butt) + dashArray[1] = 2; + + pGraphics->SetLineDash(0, dashArray, 2); + return FX_DASHSTYLE_Dash; + } + case XFA_AttributeEnum::Dotted: { + float dashArray[] = {2, 1}; + if (iCapType != XFA_AttributeEnum::Butt) + dashArray[1] = 2; + + pGraphics->SetLineDash(0, dashArray, 2); + return FX_DASHSTYLE_Dot; + } + default: + break; + } + pGraphics->SetLineDash(FX_DASHSTYLE_Solid); + return FX_DASHSTYLE_Solid; +} + +void XFA_DrawImage(CXFA_Graphics* pGS, + const CFX_RectF& rtImage, + const CFX_Matrix& matrix, + const RetainPtr<CFX_DIBitmap>& pDIBitmap, + XFA_AttributeEnum iAspect, + int32_t iImageXDpi, + int32_t iImageYDpi, + XFA_AttributeEnum iHorzAlign, + XFA_AttributeEnum iVertAlign) { + if (rtImage.IsEmpty()) + return; + if (!pDIBitmap || !pDIBitmap->GetBuffer()) + return; + + CFX_RectF rtFit( + rtImage.TopLeft(), + XFA_UnitPx2Pt((float)pDIBitmap->GetWidth(), (float)iImageXDpi), + XFA_UnitPx2Pt((float)pDIBitmap->GetHeight(), (float)iImageYDpi)); + switch (iAspect) { + case XFA_AttributeEnum::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_AttributeEnum::Height: { + float f1 = rtImage.height / rtFit.height; + rtFit.height = rtImage.height; + rtFit.width = f1 * rtFit.width; + break; + } + case XFA_AttributeEnum::None: + rtFit.height = rtImage.height; + rtFit.width = rtImage.width; + break; + case XFA_AttributeEnum::Width: { + float f1 = rtImage.width / rtFit.width; + rtFit.width = rtImage.width; + rtFit.height = rtFit.height * f1; + break; + } + case XFA_AttributeEnum::Actual: + default: + break; + } + + if (iHorzAlign == XFA_AttributeEnum::Center) + rtFit.left += (rtImage.width - rtFit.width) / 2; + else if (iHorzAlign == XFA_AttributeEnum::Right) + rtFit.left = rtImage.right() - rtFit.width; + + if (iVertAlign == XFA_AttributeEnum::Middle) + rtFit.top += (rtImage.height - rtFit.height) / 2; + else if (iVertAlign == XFA_AttributeEnum::Bottom) + rtFit.top = rtImage.bottom() - rtImage.height; + + CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice(); + CFX_RenderDevice::StateRestorer restorer(pRenderDevice); + CFX_PathData path; + path.AppendRect(rtImage.left, rtImage.bottom(), rtImage.right(), rtImage.top); + pRenderDevice->SetClip_PathFill(&path, &matrix, FXFILL_WINDING); + + 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; + if (!imageRender.Start(pRenderDevice, pDIBitmap, 0, 255, &mtImage, + FXDIB_INTERPOL)) { + return; + } + while (imageRender.Continue()) + continue; +} + +RetainPtr<CFX_DIBitmap> XFA_LoadImageFromBuffer( + const RetainPtr<IFX_SeekableReadStream>& pImageFileRead, + FXCODEC_IMAGE_TYPE type, + int32_t& iImageXDpi, + int32_t& iImageYDpi) { + CCodec_ModuleMgr* pCodecMgr = CPDF_ModuleMgr::Get()->GetCodecModule(); + std::unique_ptr<CCodec_ProgressiveDecoder> pProgressiveDecoder = + pCodecMgr->CreateProgressiveDecoder(); + + CFX_DIBAttribute dibAttr; + pProgressiveDecoder->LoadImageInfo(pImageFileRead, type, &dibAttr, false); + switch (dibAttr.m_wDPIUnit) { + case FXCODEC_RESUNIT_CENTIMETER: + dibAttr.m_nXDPI = (int32_t)(dibAttr.m_nXDPI * 2.54f); + dibAttr.m_nYDPI = (int32_t)(dibAttr.m_nYDPI * 2.54f); + break; + case FXCODEC_RESUNIT_METER: + dibAttr.m_nXDPI = (int32_t)(dibAttr.m_nXDPI / (float)100 * 2.54f); + dibAttr.m_nYDPI = (int32_t)(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<CFX_DIBitmap> pBitmap = pdfium::MakeRetain<CFX_DIBitmap>(); + 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_DECODE_READY || nFrames == 0) { + pBitmap = nullptr; + return pBitmap; + } + + status = pProgressiveDecoder->StartDecode(pBitmap, 0, 0, pBitmap->GetWidth(), + pBitmap->GetHeight()); + if (IsFXCodecErrorStatus(status)) { + pBitmap = nullptr; + return pBitmap; + } + + while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) { + status = pProgressiveDecoder->ContinueDecode(); + if (IsFXCodecErrorStatus(status)) { + pBitmap = nullptr; + return pBitmap; + } + } + + return pBitmap; +} + +void XFA_RectWithoutMargin(CFX_RectF& rt, const CXFA_Margin* margin, bool bUI) { + if (!margin) + return; + + rt.Deflate(margin->GetLeftInset(), margin->GetTopInset(), + margin->GetRightInset(), margin->GetBottomInset()); +} + +CXFA_FFWidget* XFA_GetWidgetFromLayoutItem(CXFA_LayoutItem* pLayoutItem) { + if (XFA_IsCreateWidget(pLayoutItem->GetFormNode()->GetElementType())) + return static_cast<CXFA_FFWidget*>(pLayoutItem); + return nullptr; +} + +bool XFA_IsCreateWidget(XFA_Element eType) { + return eType == XFA_Element::Field || eType == XFA_Element::Draw || + eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup; +} + +CXFA_CalcData::CXFA_CalcData() : m_iRefCount(0) {} + +CXFA_CalcData::~CXFA_CalcData() {} + CXFA_FFWidget::CXFA_FFWidget(CXFA_Node* node) : CXFA_ContentLayoutItem(node), m_pNode(node) {} @@ -1187,63 +1476,6 @@ CFX_PointF CXFA_FFWidget::Rotate2Normal(const CFX_PointF& point) { return mt.GetInverse().Transform(point); } -static void XFA_GetMatrix(CFX_Matrix& m, - int32_t iRotate, - XFA_AttributeEnum at, - const CFX_RectF& rt) { - if (!iRotate) { - return; - } - float fAnchorX = 0; - float fAnchorY = 0; - switch (at) { - case XFA_AttributeEnum::TopLeft: - fAnchorX = rt.left, fAnchorY = rt.top; - break; - case XFA_AttributeEnum::TopCenter: - fAnchorX = (rt.left + rt.right()) / 2, fAnchorY = rt.top; - break; - case XFA_AttributeEnum::TopRight: - fAnchorX = rt.right(), fAnchorY = rt.top; - break; - case XFA_AttributeEnum::MiddleLeft: - fAnchorX = rt.left, fAnchorY = (rt.top + rt.bottom()) / 2; - break; - case XFA_AttributeEnum::MiddleCenter: - fAnchorX = (rt.left + rt.right()) / 2, - fAnchorY = (rt.top + rt.bottom()) / 2; - break; - case XFA_AttributeEnum::MiddleRight: - fAnchorX = rt.right(), fAnchorY = (rt.top + rt.bottom()) / 2; - break; - case XFA_AttributeEnum::BottomLeft: - fAnchorX = rt.left, fAnchorY = rt.bottom(); - break; - case XFA_AttributeEnum::BottomCenter: - fAnchorX = (rt.left + rt.right()) / 2, fAnchorY = rt.bottom(); - break; - case XFA_AttributeEnum::BottomRight: - fAnchorX = rt.right(), fAnchorY = rt.bottom(); - break; - default: - break; - } - switch (iRotate) { - case 90: - m.a = 0, m.b = -1, m.c = 1, m.d = 0, m.e = fAnchorX - fAnchorY, - m.f = fAnchorX + fAnchorY; - break; - case 180: - m.a = -1, m.b = 0, m.c = 0, m.d = -1, m.e = fAnchorX * 2, - m.f = fAnchorY * 2; - break; - case 270: - m.a = 0, m.b = 1, m.c = -1, m.d = 0, m.e = fAnchorX + fAnchorY, - m.f = fAnchorY - fAnchorX; - break; - } -} - CFX_Matrix CXFA_FFWidget::GetRotateMatrix() { CFX_Matrix mt; int32_t iRotate = m_pNode->GetRotate(); @@ -1336,693 +1568,3 @@ void CXFA_FFWidget::SetButtonDown(bool bSet) { bSet ? m_dwStatus |= XFA_WidgetStatus_ButtonDown : m_dwStatus &= ~XFA_WidgetStatus_ButtonDown; } - -int32_t XFA_StrokeTypeSetLineDash(CXFA_Graphics* pGraphics, - XFA_AttributeEnum iStrokeType, - XFA_AttributeEnum iCapType) { - switch (iStrokeType) { - case XFA_AttributeEnum::DashDot: { - float dashArray[] = {4, 1, 2, 1}; - if (iCapType != XFA_AttributeEnum::Butt) { - dashArray[1] = 2; - dashArray[3] = 2; - } - pGraphics->SetLineDash(0, dashArray, 4); - return FX_DASHSTYLE_DashDot; - } - case XFA_AttributeEnum::DashDotDot: { - float dashArray[] = {4, 1, 2, 1, 2, 1}; - if (iCapType != XFA_AttributeEnum::Butt) { - dashArray[1] = 2; - dashArray[3] = 2; - dashArray[5] = 2; - } - pGraphics->SetLineDash(0, dashArray, 6); - return FX_DASHSTYLE_DashDotDot; - } - case XFA_AttributeEnum::Dashed: { - float dashArray[] = {5, 1}; - if (iCapType != XFA_AttributeEnum::Butt) - dashArray[1] = 2; - - pGraphics->SetLineDash(0, dashArray, 2); - return FX_DASHSTYLE_Dash; - } - case XFA_AttributeEnum::Dotted: { - float dashArray[] = {2, 1}; - if (iCapType != XFA_AttributeEnum::Butt) - dashArray[1] = 2; - - pGraphics->SetLineDash(0, dashArray, 2); - return FX_DASHSTYLE_Dot; - } - default: - break; - } - pGraphics->SetLineDash(FX_DASHSTYLE_Solid); - return FX_DASHSTYLE_Solid; -} - -class CXFA_ImageRenderer { - public: - CXFA_ImageRenderer(); - ~CXFA_ImageRenderer(); - - bool Start(CFX_RenderDevice* pDevice, - const RetainPtr<CFX_DIBSource>& pDIBSource, - FX_ARGB bitmap_argb, - int bitmap_alpha, - const CFX_Matrix* pImage2Device, - uint32_t flags, - int blendType = FXDIB_BLEND_NORMAL); - bool Continue(); - - protected: - bool StartDIBSource(); - void CompositeDIBitmap(const RetainPtr<CFX_DIBitmap>& pDIBitmap, - int left, - int top, - FX_ARGB mask_argb, - int bitmap_alpha, - int blend_mode, - int iTransparency); - - CFX_RenderDevice* m_pDevice; - int m_Status; - CFX_Matrix m_ImageMatrix; - RetainPtr<CFX_DIBSource> m_pDIBSource; - RetainPtr<CFX_DIBitmap> m_pCloneConvert; - int m_BitmapAlpha; - FX_ARGB m_FillArgb; - uint32_t m_Flags; - std::unique_ptr<CFX_ImageTransformer> m_pTransformer; - std::unique_ptr<CFX_ImageRenderer> m_DeviceHandle; - int32_t m_BlendType; - bool m_Result; - bool m_bPrint; -}; - -CXFA_ImageRenderer::CXFA_ImageRenderer() - : m_pDevice(nullptr), - m_Status(0), - m_BitmapAlpha(255), - m_FillArgb(0), - m_Flags(0), - m_DeviceHandle(nullptr), - m_BlendType(FXDIB_BLEND_NORMAL), - m_Result(true), - m_bPrint(false) {} - -CXFA_ImageRenderer::~CXFA_ImageRenderer() {} - -bool CXFA_ImageRenderer::Start(CFX_RenderDevice* pDevice, - const RetainPtr<CFX_DIBSource>& pDIBSource, - FX_ARGB bitmap_argb, - int bitmap_alpha, - const CFX_Matrix* pImage2Device, - uint32_t flags, - int blendType) { - m_pDevice = pDevice; - m_pDIBSource = pDIBSource; - m_FillArgb = bitmap_argb; - m_BitmapAlpha = bitmap_alpha; - m_ImageMatrix = *pImage2Device; - m_Flags = flags; - m_BlendType = blendType; - return StartDIBSource(); -} - -bool CXFA_ImageRenderer::StartDIBSource() { - if (m_pDevice->StartDIBitsWithBlend(m_pDIBSource, m_BitmapAlpha, m_FillArgb, - &m_ImageMatrix, m_Flags, &m_DeviceHandle, - m_BlendType)) { - if (m_DeviceHandle) { - m_Status = 3; - return true; - } - return false; - } - CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect(); - FX_RECT image_rect = image_rect_f.GetOuterRect(); - int dest_width = image_rect.Width(); - int dest_height = image_rect.Height(); - if ((fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) || - (fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0)) { - if (m_bPrint && !(m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE)) { - m_Result = false; - return false; - } - RetainPtr<CFX_DIBSource> pDib = m_pDIBSource; - if (m_pDIBSource->HasAlpha() && - !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE) && - !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) { - m_pCloneConvert = m_pDIBSource->CloneConvert(FXDIB_Rgb); - if (!m_pCloneConvert) { - m_Result = false; - return false; - } - pDib = m_pCloneConvert; - } - FX_RECT clip_box = m_pDevice->GetClipBox(); - clip_box.Intersect(image_rect); - m_Status = 2; - m_pTransformer = pdfium::MakeUnique<CFX_ImageTransformer>( - pDib, &m_ImageMatrix, m_Flags, &clip_box); - return true; - } - if (m_ImageMatrix.a < 0) - dest_width = -dest_width; - if (m_ImageMatrix.d > 0) - dest_height = -dest_height; - int dest_left, dest_top; - dest_left = dest_width > 0 ? image_rect.left : image_rect.right; - dest_top = dest_height > 0 ? image_rect.top : image_rect.bottom; - if (m_pDIBSource->IsOpaqueImage() && m_BitmapAlpha == 255) { - if (m_pDevice->StretchDIBitsWithFlagsAndBlend( - m_pDIBSource, dest_left, dest_top, dest_width, dest_height, m_Flags, - m_BlendType)) { - return false; - } - } - if (m_pDIBSource->IsAlphaMask()) { - if (m_BitmapAlpha != 255) { - m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha); - } - if (m_pDevice->StretchBitMaskWithFlags(m_pDIBSource, dest_left, dest_top, - dest_width, dest_height, m_FillArgb, - m_Flags)) { - return false; - } - } - if (m_bPrint && !(m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE)) { - m_Result = false; - return true; - } - FX_RECT clip_box = m_pDevice->GetClipBox(); - FX_RECT dest_rect = clip_box; - dest_rect.Intersect(image_rect); - FX_RECT dest_clip( - dest_rect.left - image_rect.left, dest_rect.top - image_rect.top, - dest_rect.right - image_rect.left, dest_rect.bottom - image_rect.top); - RetainPtr<CFX_DIBitmap> pStretched = - m_pDIBSource->StretchTo(dest_width, dest_height, m_Flags, &dest_clip); - if (pStretched) { - CompositeDIBitmap(pStretched, dest_rect.left, dest_rect.top, m_FillArgb, - m_BitmapAlpha, m_BlendType, false); - } - return false; -} - -bool CXFA_ImageRenderer::Continue() { - if (m_Status == 2) { - if (m_pTransformer->Continue(nullptr)) - return true; - - RetainPtr<CFX_DIBitmap> pBitmap = m_pTransformer->DetachBitmap(); - if (!pBitmap) - return false; - - if (pBitmap->IsAlphaMask()) { - if (m_BitmapAlpha != 255) - m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha); - m_Result = - m_pDevice->SetBitMask(pBitmap, m_pTransformer->result().left, - m_pTransformer->result().top, m_FillArgb); - } else { - if (m_BitmapAlpha != 255) - pBitmap->MultiplyAlpha(m_BitmapAlpha); - m_Result = m_pDevice->SetDIBitsWithBlend( - pBitmap, m_pTransformer->result().left, m_pTransformer->result().top, - m_BlendType); - } - return false; - } - if (m_Status == 3) - return m_pDevice->ContinueDIBits(m_DeviceHandle.get(), nullptr); - - return false; -} - -void CXFA_ImageRenderer::CompositeDIBitmap( - const RetainPtr<CFX_DIBitmap>& pDIBitmap, - int left, - int top, - FX_ARGB mask_argb, - int bitmap_alpha, - int blend_mode, - int iTransparency) { - if (!pDIBitmap) { - return; - } - bool bIsolated = !!(iTransparency & PDFTRANS_ISOLATED); - bool bGroup = !!(iTransparency & PDFTRANS_GROUP); - if (blend_mode == FXDIB_BLEND_NORMAL) { - if (!pDIBitmap->IsAlphaMask()) { - if (bitmap_alpha < 255) { - pDIBitmap->MultiplyAlpha(bitmap_alpha); - } - if (m_pDevice->SetDIBits(pDIBitmap, left, top)) { - return; - } - } else { - uint32_t fill_argb = (mask_argb); - if (bitmap_alpha < 255) { - ((uint8_t*)&fill_argb)[3] = - ((uint8_t*)&fill_argb)[3] * bitmap_alpha / 255; - } - if (m_pDevice->SetBitMask(pDIBitmap, left, top, fill_argb)) { - return; - } - } - } - bool bBackAlphaRequired = blend_mode && bIsolated; - bool bGetBackGround = - ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) || - (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) && - (m_pDevice->GetRenderCaps() & FXRC_GET_BITS) && !bBackAlphaRequired); - if (bGetBackGround) { - if (bIsolated || !bGroup) { - if (pDIBitmap->IsAlphaMask()) { - return; - } - m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, blend_mode); - } else { - FX_RECT rect(left, top, left + pDIBitmap->GetWidth(), - top + pDIBitmap->GetHeight()); - rect.Intersect(m_pDevice->GetClipBox()); - RetainPtr<CFX_DIBitmap> pClone; - if (m_pDevice->GetBackDrop() && m_pDevice->GetBitmap()) { - pClone = m_pDevice->GetBackDrop()->Clone(&rect); - RetainPtr<CFX_DIBitmap> pForeBitmap = m_pDevice->GetBitmap(); - pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(), - pForeBitmap, rect.left, rect.top); - left = left >= 0 ? 0 : left; - top = top >= 0 ? 0 : top; - if (!pDIBitmap->IsAlphaMask()) - pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(), - pDIBitmap, left, top, blend_mode); - else - pClone->CompositeMask(0, 0, pClone->GetWidth(), pClone->GetHeight(), - pDIBitmap, mask_argb, left, top, blend_mode); - } else { - pClone = pDIBitmap; - } - if (m_pDevice->GetBackDrop()) { - m_pDevice->SetDIBits(pClone, rect.left, rect.top); - } else { - if (pDIBitmap->IsAlphaMask()) - return; - m_pDevice->SetDIBitsWithBlend(pDIBitmap, rect.left, rect.top, - blend_mode); - } - } - return; - } - if (!pDIBitmap->HasAlpha() || - (m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE)) { - return; - } - RetainPtr<CFX_DIBitmap> pCloneConvert = pDIBitmap->CloneConvert(FXDIB_Rgb); - if (!pCloneConvert) - return; - - CXFA_ImageRenderer imageRender; - if (!imageRender.Start(m_pDevice, pCloneConvert, m_FillArgb, m_BitmapAlpha, - &m_ImageMatrix, m_Flags)) { - return; - } - while (imageRender.Continue()) - continue; -} - -void XFA_DrawImage(CXFA_Graphics* pGS, - const CFX_RectF& rtImage, - const CFX_Matrix& matrix, - const RetainPtr<CFX_DIBitmap>& pDIBitmap, - XFA_AttributeEnum iAspect, - int32_t iImageXDpi, - int32_t iImageYDpi, - XFA_AttributeEnum iHorzAlign, - XFA_AttributeEnum iVertAlign) { - if (rtImage.IsEmpty()) - return; - if (!pDIBitmap || !pDIBitmap->GetBuffer()) - return; - - CFX_RectF rtFit( - rtImage.TopLeft(), - XFA_UnitPx2Pt((float)pDIBitmap->GetWidth(), (float)iImageXDpi), - XFA_UnitPx2Pt((float)pDIBitmap->GetHeight(), (float)iImageYDpi)); - switch (iAspect) { - case XFA_AttributeEnum::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_AttributeEnum::Height: { - float f1 = rtImage.height / rtFit.height; - rtFit.height = rtImage.height; - rtFit.width = f1 * rtFit.width; - break; - } - case XFA_AttributeEnum::None: - rtFit.height = rtImage.height; - rtFit.width = rtImage.width; - break; - case XFA_AttributeEnum::Width: { - float f1 = rtImage.width / rtFit.width; - rtFit.width = rtImage.width; - rtFit.height = rtFit.height * f1; - break; - } - case XFA_AttributeEnum::Actual: - default: - break; - } - - if (iHorzAlign == XFA_AttributeEnum::Center) - rtFit.left += (rtImage.width - rtFit.width) / 2; - else if (iHorzAlign == XFA_AttributeEnum::Right) - rtFit.left = rtImage.right() - rtFit.width; - - if (iVertAlign == XFA_AttributeEnum::Middle) - rtFit.top += (rtImage.height - rtFit.height) / 2; - else if (iVertAlign == XFA_AttributeEnum::Bottom) - rtFit.top = rtImage.bottom() - rtImage.height; - - CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice(); - CFX_RenderDevice::StateRestorer restorer(pRenderDevice); - CFX_PathData path; - path.AppendRect(rtImage.left, rtImage.bottom(), rtImage.right(), rtImage.top); - pRenderDevice->SetClip_PathFill(&path, &matrix, FXFILL_WINDING); - - 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; - if (!imageRender.Start(pRenderDevice, pDIBitmap, 0, 255, &mtImage, - FXDIB_INTERPOL)) { - return; - } - while (imageRender.Continue()) - continue; -} - -static const uint8_t g_inv_base64[128] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, - 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, - 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 255, 255, 255, 255, 255, -}; - -static uint8_t* XFA_RemoveBase64Whitespace(const uint8_t* pStr, int32_t iLen) { - uint8_t* pCP; - int32_t i = 0, j = 0; - if (iLen == 0) { - iLen = strlen((char*)pStr); - } - pCP = FX_Alloc(uint8_t, iLen + 1); - for (; i < iLen; i++) { - if ((pStr[i] & 128) == 0) { - if (g_inv_base64[pStr[i]] != 0xFF || pStr[i] == '=') { - pCP[j++] = pStr[i]; - } - } - } - pCP[j] = '\0'; - return pCP; -} - -static int32_t XFA_Base64Decode(const char* pStr, uint8_t* pOutBuffer) { - if (!pStr) { - return 0; - } - uint8_t* pBuffer = - XFA_RemoveBase64Whitespace((uint8_t*)pStr, strlen((char*)pStr)); - if (!pBuffer) { - return 0; - } - int32_t iLen = strlen((char*)pBuffer); - int32_t i = 0, j = 0; - uint32_t dwLimb = 0; - for (; i + 3 < iLen; i += 4) { - if (pBuffer[i] == '=' || pBuffer[i + 1] == '=' || pBuffer[i + 2] == '=' || - pBuffer[i + 3] == '=') { - if (pBuffer[i] == '=' || pBuffer[i + 1] == '=') { - break; - } - if (pBuffer[i + 2] == '=') { - dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 6) | - ((uint32_t)g_inv_base64[pBuffer[i + 1]]); - pOutBuffer[j] = (uint8_t)(dwLimb >> 4) & 0xFF; - j++; - } else { - dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 12) | - ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 6) | - ((uint32_t)g_inv_base64[pBuffer[i + 2]]); - pOutBuffer[j] = (uint8_t)(dwLimb >> 10) & 0xFF; - pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 2) & 0xFF; - j += 2; - } - } else { - dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 18) | - ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 12) | - ((uint32_t)g_inv_base64[pBuffer[i + 2]] << 6) | - ((uint32_t)g_inv_base64[pBuffer[i + 3]]); - pOutBuffer[j] = (uint8_t)(dwLimb >> 16) & 0xff; - pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 8) & 0xff; - pOutBuffer[j + 2] = (uint8_t)(dwLimb)&0xff; - j += 3; - } - } - FX_Free(pBuffer); - return j; -} - -static const char g_base64_chars[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -char* XFA_Base64Encode(const uint8_t* buf, int32_t buf_len) { - char* out = nullptr; - int i, j; - uint32_t limb; - out = FX_Alloc(char, ((buf_len * 8 + 5) / 6) + 5); - for (i = 0, j = 0, limb = 0; i + 2 < buf_len; i += 3, j += 4) { - limb = ((uint32_t)buf[i] << 16) | ((uint32_t)buf[i + 1] << 8) | - ((uint32_t)buf[i + 2]); - out[j] = g_base64_chars[(limb >> 18) & 63]; - out[j + 1] = g_base64_chars[(limb >> 12) & 63]; - out[j + 2] = g_base64_chars[(limb >> 6) & 63]; - out[j + 3] = g_base64_chars[(limb)&63]; - } - switch (buf_len - i) { - case 0: - break; - case 1: - limb = ((uint32_t)buf[i]); - out[j++] = g_base64_chars[(limb >> 2) & 63]; - out[j++] = g_base64_chars[(limb << 4) & 63]; - out[j++] = '='; - out[j++] = '='; - break; - case 2: - limb = ((uint32_t)buf[i] << 8) | ((uint32_t)buf[i + 1]); - out[j++] = g_base64_chars[(limb >> 10) & 63]; - out[j++] = g_base64_chars[(limb >> 4) & 63]; - out[j++] = g_base64_chars[(limb << 2) & 63]; - out[j++] = '='; - break; - default: - break; - } - out[j] = '\0'; - return out; -} -FXCODEC_IMAGE_TYPE XFA_GetImageType(const WideString& wsType) { - WideString wsContentType(wsType); - wsContentType.MakeLower(); - if (wsContentType == L"image/jpg") - return FXCODEC_IMAGE_JPG; - if (wsContentType == L"image/png") - return FXCODEC_IMAGE_PNG; - if (wsContentType == L"image/gif") - return FXCODEC_IMAGE_GIF; - if (wsContentType == L"image/bmp") - return FXCODEC_IMAGE_BMP; - if (wsContentType == L"image/tif") - return FXCODEC_IMAGE_TIF; - return FXCODEC_IMAGE_UNKNOWN; -} - -RetainPtr<CFX_DIBitmap> XFA_LoadImageData(CXFA_FFDoc* pDoc, - CXFA_Image* pImage, - bool& bNameImage, - int32_t& iImageXDpi, - int32_t& iImageYDpi) { - WideString wsHref = pImage->GetHref(); - WideString wsImage = pImage->GetContent(); - if (wsHref.IsEmpty() && wsImage.IsEmpty()) - return nullptr; - - FXCODEC_IMAGE_TYPE type = XFA_GetImageType(pImage->GetContentType()); - ByteString bsContent; - uint8_t* pImageBuffer = nullptr; - RetainPtr<IFX_SeekableReadStream> pImageFileRead; - if (wsImage.GetLength() > 0) { - XFA_AttributeEnum iEncoding = pImage->GetTransferEncoding(); - if (iEncoding == XFA_AttributeEnum::Base64) { - ByteString bsData = wsImage.UTF8Encode(); - int32_t iLength = bsData.GetLength(); - pImageBuffer = FX_Alloc(uint8_t, iLength); - int32_t iRead = XFA_Base64Decode(bsData.c_str(), pImageBuffer); - if (iRead > 0) { - pImageFileRead = - pdfium::MakeRetain<CFX_MemoryStream>(pImageBuffer, iRead, false); - } - } else { - bsContent = ByteString::FromUnicode(wsImage); - pImageFileRead = pdfium::MakeRetain<CFX_MemoryStream>( - const_cast<uint8_t*>(bsContent.raw_str()), bsContent.GetLength(), - false); - } - } else { - WideString wsURL = wsHref; - if (wsURL.Left(7) != L"http://" && wsURL.Left(6) != L"ftp://") { - RetainPtr<CFX_DIBitmap> pBitmap = - pDoc->GetPDFNamedImage(wsURL.AsStringView(), iImageXDpi, iImageYDpi); - if (pBitmap) { - bNameImage = true; - return pBitmap; - } - } - pImageFileRead = pDoc->GetDocEnvironment()->OpenLinkedFile(pDoc, wsURL); - } - if (!pImageFileRead) { - FX_Free(pImageBuffer); - return nullptr; - } - bNameImage = false; - RetainPtr<CFX_DIBitmap> pBitmap = - XFA_LoadImageFromBuffer(pImageFileRead, type, iImageXDpi, iImageYDpi); - FX_Free(pImageBuffer); - return pBitmap; -} - -static FXDIB_Format XFA_GetDIBFormat(FXCODEC_IMAGE_TYPE type, - int32_t iComponents, - int32_t iBitsPerComponent) { - FXDIB_Format dibFormat = FXDIB_Argb; - switch (type) { - case FXCODEC_IMAGE_BMP: - case FXCODEC_IMAGE_JPG: - case FXCODEC_IMAGE_TIF: { - dibFormat = FXDIB_Rgb32; - int32_t bpp = iComponents * iBitsPerComponent; - if (bpp <= 24) { - dibFormat = FXDIB_Rgb; - } - } break; - case FXCODEC_IMAGE_PNG: - default: - break; - } - return dibFormat; -} - -RetainPtr<CFX_DIBitmap> XFA_LoadImageFromBuffer( - const RetainPtr<IFX_SeekableReadStream>& pImageFileRead, - FXCODEC_IMAGE_TYPE type, - int32_t& iImageXDpi, - int32_t& iImageYDpi) { - CCodec_ModuleMgr* pCodecMgr = CPDF_ModuleMgr::Get()->GetCodecModule(); - std::unique_ptr<CCodec_ProgressiveDecoder> pProgressiveDecoder = - pCodecMgr->CreateProgressiveDecoder(); - - CFX_DIBAttribute dibAttr; - pProgressiveDecoder->LoadImageInfo(pImageFileRead, type, &dibAttr, false); - switch (dibAttr.m_wDPIUnit) { - case FXCODEC_RESUNIT_CENTIMETER: - dibAttr.m_nXDPI = (int32_t)(dibAttr.m_nXDPI * 2.54f); - dibAttr.m_nYDPI = (int32_t)(dibAttr.m_nYDPI * 2.54f); - break; - case FXCODEC_RESUNIT_METER: - dibAttr.m_nXDPI = (int32_t)(dibAttr.m_nXDPI / (float)100 * 2.54f); - dibAttr.m_nYDPI = (int32_t)(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<CFX_DIBitmap> pBitmap = pdfium::MakeRetain<CFX_DIBitmap>(); - 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_DECODE_READY || nFrames == 0) { - pBitmap = nullptr; - return pBitmap; - } - - status = pProgressiveDecoder->StartDecode(pBitmap, 0, 0, pBitmap->GetWidth(), - pBitmap->GetHeight()); - if (IsFXCodecErrorStatus(status)) { - pBitmap = nullptr; - return pBitmap; - } - - while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) { - status = pProgressiveDecoder->ContinueDecode(); - if (IsFXCodecErrorStatus(status)) { - pBitmap = nullptr; - return pBitmap; - } - } - - return pBitmap; -} - -void XFA_RectWithoutMargin(CFX_RectF& rt, const CXFA_Margin* margin, bool bUI) { - if (!margin) - return; - - rt.Deflate(margin->GetLeftInset(), margin->GetTopInset(), - margin->GetRightInset(), margin->GetBottomInset()); -} - -CXFA_FFWidget* XFA_GetWidgetFromLayoutItem(CXFA_LayoutItem* pLayoutItem) { - if (XFA_IsCreateWidget(pLayoutItem->GetFormNode()->GetElementType())) - return static_cast<CXFA_FFWidget*>(pLayoutItem); - return nullptr; -} - -bool XFA_IsCreateWidget(XFA_Element eType) { - return eType == XFA_Element::Field || eType == XFA_Element::Draw || - eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup; -} - -CXFA_CalcData::CXFA_CalcData() : m_iRefCount(0) {} - -CXFA_CalcData::~CXFA_CalcData() {} diff --git a/xfa/fxfa/cxfa_ffwidget.h b/xfa/fxfa/cxfa_ffwidget.h index 8ec92ef93f..192f559fd4 100644 --- a/xfa/fxfa/cxfa_ffwidget.h +++ b/xfa/fxfa/cxfa_ffwidget.h @@ -31,13 +31,6 @@ inline float XFA_UnitPx2Pt(float fPx, float fDpi) { #define XFA_FLOAT_PERCISION 0.001f -enum XFA_WIDGETITEM { - XFA_WIDGETITEM_Parent, - XFA_WIDGETITEM_FirstChild, - XFA_WIDGETITEM_NextSibling, - XFA_WIDGETITEM_PrevSibling, -}; - int32_t XFA_StrokeTypeSetLineDash(CXFA_Graphics* pGraphics, XFA_AttributeEnum iStrokeType, XFA_AttributeEnum iCapType); @@ -51,20 +44,12 @@ void XFA_DrawImage(CXFA_Graphics* pGS, XFA_AttributeEnum iHorzAlign = XFA_AttributeEnum::Left, XFA_AttributeEnum iVertAlign = XFA_AttributeEnum::Top); -RetainPtr<CFX_DIBitmap> XFA_LoadImageData(CXFA_FFDoc* pDoc, - CXFA_Image* pImage, - bool& bNameImage, - int32_t& iImageXDpi, - int32_t& iImageYDpi); - RetainPtr<CFX_DIBitmap> XFA_LoadImageFromBuffer( const RetainPtr<IFX_SeekableReadStream>& pImageFileRead, FXCODEC_IMAGE_TYPE type, int32_t& iImageXDpi, int32_t& iImageYDpi); -FXCODEC_IMAGE_TYPE XFA_GetImageType(const WideString& wsType); -char* XFA_Base64Encode(const uint8_t* buf, int32_t buf_len); void XFA_RectWithoutMargin(CFX_RectF& rt, const CXFA_Margin* margin, bool bUI = false); diff --git a/xfa/fxfa/cxfa_imagerenderer.cpp b/xfa/fxfa/cxfa_imagerenderer.cpp new file mode 100644 index 0000000000..14f8b25af1 --- /dev/null +++ b/xfa/fxfa/cxfa_imagerenderer.cpp @@ -0,0 +1,238 @@ +// Copyright 2018 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_imagerenderer.h" + +#include "core/fpdfapi/page/cpdf_pageobjectholder.h" +#include "core/fxge/cfx_renderdevice.h" +#include "core/fxge/dib/cfx_dibsource.h" +#include "core/fxge/dib/cfx_imagerenderer.h" +#include "core/fxge/dib/cfx_imagetransformer.h" +#include "third_party/base/ptr_util.h" + +CXFA_ImageRenderer::CXFA_ImageRenderer() : m_pDevice(nullptr) {} + +CXFA_ImageRenderer::~CXFA_ImageRenderer() {} + +bool CXFA_ImageRenderer::Start(CFX_RenderDevice* pDevice, + const RetainPtr<CFX_DIBSource>& pDIBSource, + FX_ARGB bitmap_argb, + int bitmap_alpha, + const CFX_Matrix* pImage2Device, + uint32_t flags, + int blendType) { + m_pDevice = pDevice; + m_pDIBSource = pDIBSource; + m_FillArgb = bitmap_argb; + m_BitmapAlpha = bitmap_alpha; + m_ImageMatrix = *pImage2Device; + m_Flags = flags; + m_BlendType = blendType; + return StartDIBSource(); +} + +bool CXFA_ImageRenderer::StartDIBSource() { + if (m_pDevice->StartDIBitsWithBlend(m_pDIBSource, m_BitmapAlpha, m_FillArgb, + &m_ImageMatrix, m_Flags, &m_DeviceHandle, + m_BlendType)) { + if (m_DeviceHandle) { + m_Status = 3; + return true; + } + return false; + } + CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect(); + FX_RECT image_rect = image_rect_f.GetOuterRect(); + int dest_width = image_rect.Width(); + int dest_height = image_rect.Height(); + if ((fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) || + (fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0)) { + if (m_bPrint && !(m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE)) { + m_Result = false; + return false; + } + RetainPtr<CFX_DIBSource> pDib = m_pDIBSource; + if (m_pDIBSource->HasAlpha() && + !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE) && + !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) { + m_pCloneConvert = m_pDIBSource->CloneConvert(FXDIB_Rgb); + if (!m_pCloneConvert) { + m_Result = false; + return false; + } + pDib = m_pCloneConvert; + } + FX_RECT clip_box = m_pDevice->GetClipBox(); + clip_box.Intersect(image_rect); + m_Status = 2; + m_pTransformer = pdfium::MakeUnique<CFX_ImageTransformer>( + pDib, &m_ImageMatrix, m_Flags, &clip_box); + return true; + } + if (m_ImageMatrix.a < 0) + dest_width = -dest_width; + if (m_ImageMatrix.d > 0) + dest_height = -dest_height; + int dest_left, dest_top; + dest_left = dest_width > 0 ? image_rect.left : image_rect.right; + dest_top = dest_height > 0 ? image_rect.top : image_rect.bottom; + if (m_pDIBSource->IsOpaqueImage() && m_BitmapAlpha == 255) { + if (m_pDevice->StretchDIBitsWithFlagsAndBlend( + m_pDIBSource, dest_left, dest_top, dest_width, dest_height, m_Flags, + m_BlendType)) { + return false; + } + } + if (m_pDIBSource->IsAlphaMask()) { + if (m_BitmapAlpha != 255) { + m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha); + } + if (m_pDevice->StretchBitMaskWithFlags(m_pDIBSource, dest_left, dest_top, + dest_width, dest_height, m_FillArgb, + m_Flags)) { + return false; + } + } + if (m_bPrint && !(m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE)) { + m_Result = false; + return true; + } + FX_RECT clip_box = m_pDevice->GetClipBox(); + FX_RECT dest_rect = clip_box; + dest_rect.Intersect(image_rect); + FX_RECT dest_clip( + dest_rect.left - image_rect.left, dest_rect.top - image_rect.top, + dest_rect.right - image_rect.left, dest_rect.bottom - image_rect.top); + RetainPtr<CFX_DIBitmap> pStretched = + m_pDIBSource->StretchTo(dest_width, dest_height, m_Flags, &dest_clip); + if (pStretched) { + CompositeDIBitmap(pStretched, dest_rect.left, dest_rect.top, m_FillArgb, + m_BitmapAlpha, m_BlendType, false); + } + return false; +} + +bool CXFA_ImageRenderer::Continue() { + if (m_Status == 2) { + if (m_pTransformer->Continue(nullptr)) + return true; + + RetainPtr<CFX_DIBitmap> pBitmap = m_pTransformer->DetachBitmap(); + if (!pBitmap) + return false; + + if (pBitmap->IsAlphaMask()) { + if (m_BitmapAlpha != 255) + m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha); + m_Result = + m_pDevice->SetBitMask(pBitmap, m_pTransformer->result().left, + m_pTransformer->result().top, m_FillArgb); + } else { + if (m_BitmapAlpha != 255) + pBitmap->MultiplyAlpha(m_BitmapAlpha); + m_Result = m_pDevice->SetDIBitsWithBlend( + pBitmap, m_pTransformer->result().left, m_pTransformer->result().top, + m_BlendType); + } + return false; + } + if (m_Status == 3) + return m_pDevice->ContinueDIBits(m_DeviceHandle.get(), nullptr); + + return false; +} + +void CXFA_ImageRenderer::CompositeDIBitmap( + const RetainPtr<CFX_DIBitmap>& pDIBitmap, + int left, + int top, + FX_ARGB mask_argb, + int bitmap_alpha, + int blend_mode, + int iTransparency) { + if (!pDIBitmap) { + return; + } + bool bIsolated = !!(iTransparency & PDFTRANS_ISOLATED); + bool bGroup = !!(iTransparency & PDFTRANS_GROUP); + if (blend_mode == FXDIB_BLEND_NORMAL) { + if (!pDIBitmap->IsAlphaMask()) { + if (bitmap_alpha < 255) { + pDIBitmap->MultiplyAlpha(bitmap_alpha); + } + if (m_pDevice->SetDIBits(pDIBitmap, left, top)) { + return; + } + } else { + uint32_t fill_argb = (mask_argb); + if (bitmap_alpha < 255) { + ((uint8_t*)&fill_argb)[3] = + ((uint8_t*)&fill_argb)[3] * bitmap_alpha / 255; + } + if (m_pDevice->SetBitMask(pDIBitmap, left, top, fill_argb)) { + return; + } + } + } + bool bBackAlphaRequired = blend_mode && bIsolated; + bool bGetBackGround = + ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) || + (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) && + (m_pDevice->GetRenderCaps() & FXRC_GET_BITS) && !bBackAlphaRequired); + if (bGetBackGround) { + if (bIsolated || !bGroup) { + if (pDIBitmap->IsAlphaMask()) { + return; + } + m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, blend_mode); + } else { + FX_RECT rect(left, top, left + pDIBitmap->GetWidth(), + top + pDIBitmap->GetHeight()); + rect.Intersect(m_pDevice->GetClipBox()); + RetainPtr<CFX_DIBitmap> pClone; + if (m_pDevice->GetBackDrop() && m_pDevice->GetBitmap()) { + pClone = m_pDevice->GetBackDrop()->Clone(&rect); + RetainPtr<CFX_DIBitmap> pForeBitmap = m_pDevice->GetBitmap(); + pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(), + pForeBitmap, rect.left, rect.top); + left = left >= 0 ? 0 : left; + top = top >= 0 ? 0 : top; + if (!pDIBitmap->IsAlphaMask()) + pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(), + pDIBitmap, left, top, blend_mode); + else + pClone->CompositeMask(0, 0, pClone->GetWidth(), pClone->GetHeight(), + pDIBitmap, mask_argb, left, top, blend_mode); + } else { + pClone = pDIBitmap; + } + if (m_pDevice->GetBackDrop()) { + m_pDevice->SetDIBits(pClone, rect.left, rect.top); + } else { + if (pDIBitmap->IsAlphaMask()) + return; + m_pDevice->SetDIBitsWithBlend(pDIBitmap, rect.left, rect.top, + blend_mode); + } + } + return; + } + if (!pDIBitmap->HasAlpha() || + (m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE)) { + return; + } + RetainPtr<CFX_DIBitmap> pCloneConvert = pDIBitmap->CloneConvert(FXDIB_Rgb); + if (!pCloneConvert) + return; + + CXFA_ImageRenderer imageRender; + if (!imageRender.Start(m_pDevice, pCloneConvert, m_FillArgb, m_BitmapAlpha, + &m_ImageMatrix, m_Flags)) { + return; + } + while (imageRender.Continue()) + continue; +} diff --git a/xfa/fxfa/cxfa_imagerenderer.h b/xfa/fxfa/cxfa_imagerenderer.h new file mode 100644 index 0000000000..ca53bf639e --- /dev/null +++ b/xfa/fxfa/cxfa_imagerenderer.h @@ -0,0 +1,61 @@ +// Copyright 2018 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 + +#ifndef XFA_FXFA_CXFA_IMAGERENDERER_H_ +#define XFA_FXFA_CXFA_IMAGERENDERER_H_ + +#include <memory> + +#include "core/fxcrt/fx_coordinates.h" +#include "core/fxcrt/retain_ptr.h" +#include "core/fxge/fx_dib.h" + +class CFX_RenderDevice; +class CFX_DIBSource; +class CFX_DIBitmap; +class CFX_ImageTransformer; +class CFX_ImageRenderer; + +class CXFA_ImageRenderer { + public: + CXFA_ImageRenderer(); + ~CXFA_ImageRenderer(); + + bool Start(CFX_RenderDevice* pDevice, + const RetainPtr<CFX_DIBSource>& pDIBSource, + FX_ARGB bitmap_argb, + int bitmap_alpha, + const CFX_Matrix* pImage2Device, + uint32_t flags, + int blendType = FXDIB_BLEND_NORMAL); + bool Continue(); + + protected: + bool StartDIBSource(); + void CompositeDIBitmap(const RetainPtr<CFX_DIBitmap>& pDIBitmap, + int left, + int top, + FX_ARGB mask_argb, + int bitmap_alpha, + int blend_mode, + int iTransparency); + + CFX_RenderDevice* m_pDevice; + int m_Status = 0; + CFX_Matrix m_ImageMatrix; + RetainPtr<CFX_DIBSource> m_pDIBSource; + RetainPtr<CFX_DIBitmap> m_pCloneConvert; + int m_BitmapAlpha = 255; + FX_ARGB m_FillArgb = 0; + uint32_t m_Flags = 0; + std::unique_ptr<CFX_ImageTransformer> m_pTransformer; + std::unique_ptr<CFX_ImageRenderer> m_DeviceHandle; + int32_t m_BlendType = FXDIB_BLEND_NORMAL; + bool m_Result = true; + bool m_bPrint = false; +}; + +#endif // XFA_FXFA_CXFA_IMAGERENDERER_H_ diff --git a/xfa/fxfa/cxfa_widgetacc.cpp b/xfa/fxfa/cxfa_widgetacc.cpp index 407517f564..2ae3381bce 100644 --- a/xfa/fxfa/cxfa_widgetacc.cpp +++ b/xfa/fxfa/cxfa_widgetacc.cpp @@ -11,6 +11,7 @@ #include <vector> #include "core/fxcrt/cfx_decimal.h" +#include "core/fxcrt/cfx_memorystream.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/xml/cfx_xmlelement.h" #include "core/fxcrt/xml/cfx_xmlnode.h" @@ -61,6 +62,152 @@ class CXFA_WidgetLayoutData { namespace { +constexpr uint8_t g_inv_base64[128] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, + 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, + 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255, +}; + +uint8_t* XFA_RemoveBase64Whitespace(const uint8_t* pStr, int32_t iLen) { + uint8_t* pCP; + int32_t i = 0, j = 0; + if (iLen == 0) { + iLen = strlen((char*)pStr); + } + pCP = FX_Alloc(uint8_t, iLen + 1); + for (; i < iLen; i++) { + if ((pStr[i] & 128) == 0) { + if (g_inv_base64[pStr[i]] != 0xFF || pStr[i] == '=') { + pCP[j++] = pStr[i]; + } + } + } + pCP[j] = '\0'; + return pCP; +} + +int32_t XFA_Base64Decode(const char* pStr, uint8_t* pOutBuffer) { + if (!pStr) { + return 0; + } + uint8_t* pBuffer = + XFA_RemoveBase64Whitespace((uint8_t*)pStr, strlen((char*)pStr)); + if (!pBuffer) { + return 0; + } + int32_t iLen = strlen((char*)pBuffer); + int32_t i = 0, j = 0; + uint32_t dwLimb = 0; + for (; i + 3 < iLen; i += 4) { + if (pBuffer[i] == '=' || pBuffer[i + 1] == '=' || pBuffer[i + 2] == '=' || + pBuffer[i + 3] == '=') { + if (pBuffer[i] == '=' || pBuffer[i + 1] == '=') { + break; + } + if (pBuffer[i + 2] == '=') { + dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 6) | + ((uint32_t)g_inv_base64[pBuffer[i + 1]]); + pOutBuffer[j] = (uint8_t)(dwLimb >> 4) & 0xFF; + j++; + } else { + dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 12) | + ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 6) | + ((uint32_t)g_inv_base64[pBuffer[i + 2]]); + pOutBuffer[j] = (uint8_t)(dwLimb >> 10) & 0xFF; + pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 2) & 0xFF; + j += 2; + } + } else { + dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 18) | + ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 12) | + ((uint32_t)g_inv_base64[pBuffer[i + 2]] << 6) | + ((uint32_t)g_inv_base64[pBuffer[i + 3]]); + pOutBuffer[j] = (uint8_t)(dwLimb >> 16) & 0xff; + pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 8) & 0xff; + pOutBuffer[j + 2] = (uint8_t)(dwLimb)&0xff; + j += 3; + } + } + FX_Free(pBuffer); + return j; +} + +FXCODEC_IMAGE_TYPE XFA_GetImageType(const WideString& wsType) { + WideString wsContentType(wsType); + wsContentType.MakeLower(); + if (wsContentType == L"image/jpg") + return FXCODEC_IMAGE_JPG; + if (wsContentType == L"image/png") + return FXCODEC_IMAGE_PNG; + if (wsContentType == L"image/gif") + return FXCODEC_IMAGE_GIF; + if (wsContentType == L"image/bmp") + return FXCODEC_IMAGE_BMP; + if (wsContentType == L"image/tif") + return FXCODEC_IMAGE_TIF; + return FXCODEC_IMAGE_UNKNOWN; +} + +RetainPtr<CFX_DIBitmap> XFA_LoadImageData(CXFA_FFDoc* pDoc, + CXFA_Image* pImage, + bool& bNameImage, + int32_t& iImageXDpi, + int32_t& iImageYDpi) { + WideString wsHref = pImage->GetHref(); + WideString wsImage = pImage->GetContent(); + if (wsHref.IsEmpty() && wsImage.IsEmpty()) + return nullptr; + + FXCODEC_IMAGE_TYPE type = XFA_GetImageType(pImage->GetContentType()); + ByteString bsContent; + uint8_t* pImageBuffer = nullptr; + RetainPtr<IFX_SeekableReadStream> pImageFileRead; + if (wsImage.GetLength() > 0) { + XFA_AttributeEnum iEncoding = pImage->GetTransferEncoding(); + if (iEncoding == XFA_AttributeEnum::Base64) { + ByteString bsData = wsImage.UTF8Encode(); + int32_t iLength = bsData.GetLength(); + pImageBuffer = FX_Alloc(uint8_t, iLength); + int32_t iRead = XFA_Base64Decode(bsData.c_str(), pImageBuffer); + if (iRead > 0) { + pImageFileRead = + pdfium::MakeRetain<CFX_MemoryStream>(pImageBuffer, iRead, false); + } + } else { + bsContent = ByteString::FromUnicode(wsImage); + pImageFileRead = pdfium::MakeRetain<CFX_MemoryStream>( + const_cast<uint8_t*>(bsContent.raw_str()), bsContent.GetLength(), + false); + } + } else { + WideString wsURL = wsHref; + if (wsURL.Left(7) != L"http://" && wsURL.Left(6) != L"ftp://") { + RetainPtr<CFX_DIBitmap> pBitmap = + pDoc->GetPDFNamedImage(wsURL.AsStringView(), iImageXDpi, iImageYDpi); + if (pBitmap) { + bNameImage = true; + return pBitmap; + } + } + pImageFileRead = pDoc->GetDocEnvironment()->OpenLinkedFile(pDoc, wsURL); + } + if (!pImageFileRead) { + FX_Free(pImageBuffer); + return nullptr; + } + bNameImage = false; + RetainPtr<CFX_DIBitmap> pBitmap = + XFA_LoadImageFromBuffer(pImageFileRead, type, iImageXDpi, iImageYDpi); + FX_Free(pImageBuffer); + return pBitmap; +} + class CXFA_TextLayoutData : public CXFA_WidgetLayoutData { public: CXFA_TextLayoutData() {} |