C++程序  |  159行  |  5.1 KB

// 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_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(
    CFX_RenderDevice* pDevice,
    const RetainPtr<CFX_DIBSource>& pDIBSource,
    const CFX_Matrix* pImage2Device)
    : m_pDevice(pDevice),
      m_ImageMatrix(*pImage2Device),
      m_pDIBSource(pDIBSource) {}

CXFA_ImageRenderer::~CXFA_ImageRenderer() {}

bool CXFA_ImageRenderer::Start() {
  if (m_pDevice->StartDIBitsWithBlend(m_pDIBSource, 255, 0, &m_ImageMatrix,
                                      FXDIB_INTERPOL, &m_DeviceHandle,
                                      FXDIB_BLEND_NORMAL)) {
    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<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)
        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, FXDIB_INTERPOL, &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()) {
    if (m_pDevice->StretchDIBitsWithFlagsAndBlend(
            m_pDIBSource, dest_left, dest_top, dest_width, dest_height,
            FXDIB_INTERPOL, FXDIB_BLEND_NORMAL)) {
      return false;
    }
  }
  if (m_pDIBSource->IsAlphaMask()) {
    if (m_pDevice->StretchBitMaskWithFlags(m_pDIBSource, dest_left, dest_top,
                                           dest_width, dest_height, 0,
                                           FXDIB_INTERPOL)) {
      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<CFX_DIBitmap> pStretched = m_pDIBSource->StretchTo(
      dest_width, dest_height, FXDIB_INTERPOL, &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<CFX_DIBitmap> 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,
                                    FXDIB_BLEND_NORMAL);
    }
    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) {
  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, FXDIB_BLEND_NORMAL);
    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(m_pDevice, pCloneConvert, &m_ImageMatrix);
  if (!imageRender.Start())
    return;

  while (imageRender.Continue())
    continue;
}