// 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/fxge/cfx_renderdevice.h" #include "core/fxge/dib/cfx_dibbase.h" #include "core/fxge/dib/cfx_dibitmap.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(CFX_RenderDevice* pDevice, const RetainPtr& pDIBBase, const CFX_Matrix* pImage2Device) : m_pDevice(pDevice), m_ImageMatrix(*pImage2Device), m_pDIBBase(pDIBBase) {} CXFA_ImageRenderer::~CXFA_ImageRenderer() = default; bool CXFA_ImageRenderer::Start() { FXDIB_ResampleOptions options; options.bInterpolateBilinear = true; if (m_pDevice->StartDIBits(m_pDIBBase, 255, 0, m_ImageMatrix, options, &m_DeviceHandle)) { 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)) { RetainPtr pDib = m_pDIBBase; if (m_pDIBBase->HasAlpha() && !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE) && !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) { m_pCloneConvert = m_pDIBBase->CloneConvert(FXDIB_Rgb); if (!m_pCloneConvert) return false; pDib = m_pCloneConvert; } FX_RECT clip_box = m_pDevice->GetClipBox(); clip_box.Intersect(image_rect); m_Status = 2; m_pTransformer = pdfium::MakeUnique( pDib, m_ImageMatrix, options, &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_pDIBBase->IsOpaqueImage()) { if (m_pDevice->StretchDIBitsWithFlagsAndBlend( m_pDIBBase, dest_left, dest_top, dest_width, dest_height, options, BlendMode::kNormal)) { return false; } } if (m_pDIBBase->IsAlphaMask()) { if (m_pDevice->StretchBitMaskWithFlags(m_pDIBBase, dest_left, dest_top, dest_width, dest_height, 0, options)) { return false; } } 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 pStretched = m_pDIBBase->StretchTo(dest_width, dest_height, options, &dest_clip); if (pStretched) CompositeDIBitmap(pStretched, dest_rect.left, dest_rect.top); return false; } bool CXFA_ImageRenderer::Continue() { if (m_Status == 2) { if (m_pTransformer->Continue(nullptr)) return true; RetainPtr pBitmap = m_pTransformer->DetachBitmap(); if (!pBitmap) return false; if (pBitmap->IsAlphaMask()) { m_pDevice->SetBitMask(pBitmap, m_pTransformer->result().left, m_pTransformer->result().top, 0); } else { m_pDevice->SetDIBitsWithBlend(pBitmap, m_pTransformer->result().left, m_pTransformer->result().top, BlendMode::kNormal); } return false; } if (m_Status == 3) return m_pDevice->ContinueDIBits(m_DeviceHandle.get(), nullptr); return false; } void CXFA_ImageRenderer::CompositeDIBitmap( const RetainPtr& pDIBitmap, int left, int top) { if (!pDIBitmap) return; if (!pDIBitmap->IsAlphaMask()) { if (m_pDevice->SetDIBits(pDIBitmap, left, top)) return; } else if (m_pDevice->SetBitMask(pDIBitmap, left, top, 0)) { return; } bool bGetBackGround = ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) || (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) && (m_pDevice->GetRenderCaps() & FXRC_GET_BITS)); if (bGetBackGround) { if (pDIBitmap->IsAlphaMask()) return; m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, BlendMode::kNormal); return; } if (!pDIBitmap->HasAlpha() || (m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE)) { return; } RetainPtr pCloneConvert = pDIBitmap->CloneConvert(FXDIB_Rgb); if (!pCloneConvert) return; CXFA_ImageRenderer imageRender(m_pDevice.Get(), pCloneConvert, &m_ImageMatrix); if (!imageRender.Start()) return; while (imageRender.Continue()) continue; }