1 // Copyright 2018 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "xfa/fxfa/cxfa_imagerenderer.h"
8
9 #include "core/fxge/cfx_renderdevice.h"
10 #include "core/fxge/dib/cfx_dibbase.h"
11 #include "core/fxge/dib/cfx_dibitmap.h"
12 #include "core/fxge/dib/cfx_imagerenderer.h"
13 #include "core/fxge/dib/cfx_imagetransformer.h"
14 #include "third_party/base/ptr_util.h"
15
CXFA_ImageRenderer(CFX_RenderDevice * pDevice,const RetainPtr<CFX_DIBBase> & pDIBBase,const CFX_Matrix * pImage2Device)16 CXFA_ImageRenderer::CXFA_ImageRenderer(CFX_RenderDevice* pDevice,
17 const RetainPtr<CFX_DIBBase>& pDIBBase,
18 const CFX_Matrix* pImage2Device)
19 : m_pDevice(pDevice), m_ImageMatrix(*pImage2Device), m_pDIBBase(pDIBBase) {}
20
21 CXFA_ImageRenderer::~CXFA_ImageRenderer() = default;
22
Start()23 bool CXFA_ImageRenderer::Start() {
24 FXDIB_ResampleOptions options;
25 options.bInterpolateBilinear = true;
26 if (m_pDevice->StartDIBits(m_pDIBBase, 255, 0, m_ImageMatrix, options,
27 &m_DeviceHandle)) {
28 if (m_DeviceHandle) {
29 m_Status = 3;
30 return true;
31 }
32 return false;
33 }
34 CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect();
35 FX_RECT image_rect = image_rect_f.GetOuterRect();
36 int dest_width = image_rect.Width();
37 int dest_height = image_rect.Height();
38 if ((fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) ||
39 (fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0)) {
40 RetainPtr<CFX_DIBBase> pDib = m_pDIBBase;
41 if (m_pDIBBase->HasAlpha() &&
42 !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE) &&
43 !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) {
44 m_pCloneConvert = m_pDIBBase->CloneConvert(FXDIB_Rgb);
45 if (!m_pCloneConvert)
46 return false;
47
48 pDib = m_pCloneConvert;
49 }
50 FX_RECT clip_box = m_pDevice->GetClipBox();
51 clip_box.Intersect(image_rect);
52 m_Status = 2;
53 m_pTransformer = pdfium::MakeUnique<CFX_ImageTransformer>(
54 pDib, m_ImageMatrix, options, &clip_box);
55 return true;
56 }
57 if (m_ImageMatrix.a < 0)
58 dest_width = -dest_width;
59 if (m_ImageMatrix.d > 0)
60 dest_height = -dest_height;
61 int dest_left, dest_top;
62 dest_left = dest_width > 0 ? image_rect.left : image_rect.right;
63 dest_top = dest_height > 0 ? image_rect.top : image_rect.bottom;
64 if (m_pDIBBase->IsOpaqueImage()) {
65 if (m_pDevice->StretchDIBitsWithFlagsAndBlend(
66 m_pDIBBase, dest_left, dest_top, dest_width, dest_height, options,
67 BlendMode::kNormal)) {
68 return false;
69 }
70 }
71 if (m_pDIBBase->IsAlphaMask()) {
72 if (m_pDevice->StretchBitMaskWithFlags(m_pDIBBase, dest_left, dest_top,
73 dest_width, dest_height, 0,
74 options)) {
75 return false;
76 }
77 }
78
79 FX_RECT clip_box = m_pDevice->GetClipBox();
80 FX_RECT dest_rect = clip_box;
81 dest_rect.Intersect(image_rect);
82 FX_RECT dest_clip(
83 dest_rect.left - image_rect.left, dest_rect.top - image_rect.top,
84 dest_rect.right - image_rect.left, dest_rect.bottom - image_rect.top);
85 RetainPtr<CFX_DIBitmap> pStretched =
86 m_pDIBBase->StretchTo(dest_width, dest_height, options, &dest_clip);
87 if (pStretched)
88 CompositeDIBitmap(pStretched, dest_rect.left, dest_rect.top);
89
90 return false;
91 }
92
Continue()93 bool CXFA_ImageRenderer::Continue() {
94 if (m_Status == 2) {
95 if (m_pTransformer->Continue(nullptr))
96 return true;
97
98 RetainPtr<CFX_DIBitmap> pBitmap = m_pTransformer->DetachBitmap();
99 if (!pBitmap)
100 return false;
101
102 if (pBitmap->IsAlphaMask()) {
103 m_pDevice->SetBitMask(pBitmap, m_pTransformer->result().left,
104 m_pTransformer->result().top, 0);
105 } else {
106 m_pDevice->SetDIBitsWithBlend(pBitmap, m_pTransformer->result().left,
107 m_pTransformer->result().top,
108 BlendMode::kNormal);
109 }
110 return false;
111 }
112 if (m_Status == 3)
113 return m_pDevice->ContinueDIBits(m_DeviceHandle.get(), nullptr);
114
115 return false;
116 }
117
CompositeDIBitmap(const RetainPtr<CFX_DIBitmap> & pDIBitmap,int left,int top)118 void CXFA_ImageRenderer::CompositeDIBitmap(
119 const RetainPtr<CFX_DIBitmap>& pDIBitmap,
120 int left,
121 int top) {
122 if (!pDIBitmap)
123 return;
124
125 if (!pDIBitmap->IsAlphaMask()) {
126 if (m_pDevice->SetDIBits(pDIBitmap, left, top))
127 return;
128 } else if (m_pDevice->SetBitMask(pDIBitmap, left, top, 0)) {
129 return;
130 }
131
132 bool bGetBackGround = ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) ||
133 (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) &&
134 (m_pDevice->GetRenderCaps() & FXRC_GET_BITS));
135 if (bGetBackGround) {
136 if (pDIBitmap->IsAlphaMask())
137 return;
138
139 m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, BlendMode::kNormal);
140 return;
141 }
142 if (!pDIBitmap->HasAlpha() ||
143 (m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE)) {
144 return;
145 }
146
147 RetainPtr<CFX_DIBitmap> pCloneConvert = pDIBitmap->CloneConvert(FXDIB_Rgb);
148 if (!pCloneConvert)
149 return;
150
151 CXFA_ImageRenderer imageRender(m_pDevice.Get(), pCloneConvert,
152 &m_ImageMatrix);
153 if (!imageRender.Start())
154 return;
155
156 while (imageRender.Continue())
157 continue;
158 }
159