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_dibsource.h"
11 #include "core/fxge/dib/cfx_imagerenderer.h"
12 #include "core/fxge/dib/cfx_imagetransformer.h"
13 #include "third_party/base/ptr_util.h"
14
CXFA_ImageRenderer(CFX_RenderDevice * pDevice,const RetainPtr<CFX_DIBSource> & pDIBSource,const CFX_Matrix * pImage2Device)15 CXFA_ImageRenderer::CXFA_ImageRenderer(
16 CFX_RenderDevice* pDevice,
17 const RetainPtr<CFX_DIBSource>& pDIBSource,
18 const CFX_Matrix* pImage2Device)
19 : m_pDevice(pDevice),
20 m_ImageMatrix(*pImage2Device),
21 m_pDIBSource(pDIBSource) {}
22
~CXFA_ImageRenderer()23 CXFA_ImageRenderer::~CXFA_ImageRenderer() {}
24
Start()25 bool CXFA_ImageRenderer::Start() {
26 if (m_pDevice->StartDIBitsWithBlend(m_pDIBSource, 255, 0, &m_ImageMatrix,
27 FXDIB_INTERPOL, &m_DeviceHandle,
28 FXDIB_BLEND_NORMAL)) {
29 if (m_DeviceHandle) {
30 m_Status = 3;
31 return true;
32 }
33 return false;
34 }
35 CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect();
36 FX_RECT image_rect = image_rect_f.GetOuterRect();
37 int dest_width = image_rect.Width();
38 int dest_height = image_rect.Height();
39 if ((fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) ||
40 (fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0)) {
41 RetainPtr<CFX_DIBSource> pDib = m_pDIBSource;
42 if (m_pDIBSource->HasAlpha() &&
43 !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE) &&
44 !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) {
45 m_pCloneConvert = m_pDIBSource->CloneConvert(FXDIB_Rgb);
46 if (!m_pCloneConvert)
47 return false;
48
49 pDib = m_pCloneConvert;
50 }
51 FX_RECT clip_box = m_pDevice->GetClipBox();
52 clip_box.Intersect(image_rect);
53 m_Status = 2;
54 m_pTransformer = pdfium::MakeUnique<CFX_ImageTransformer>(
55 pDib, &m_ImageMatrix, FXDIB_INTERPOL, &clip_box);
56 return true;
57 }
58 if (m_ImageMatrix.a < 0)
59 dest_width = -dest_width;
60 if (m_ImageMatrix.d > 0)
61 dest_height = -dest_height;
62 int dest_left, dest_top;
63 dest_left = dest_width > 0 ? image_rect.left : image_rect.right;
64 dest_top = dest_height > 0 ? image_rect.top : image_rect.bottom;
65 if (m_pDIBSource->IsOpaqueImage()) {
66 if (m_pDevice->StretchDIBitsWithFlagsAndBlend(
67 m_pDIBSource, dest_left, dest_top, dest_width, dest_height,
68 FXDIB_INTERPOL, FXDIB_BLEND_NORMAL)) {
69 return false;
70 }
71 }
72 if (m_pDIBSource->IsAlphaMask()) {
73 if (m_pDevice->StretchBitMaskWithFlags(m_pDIBSource, dest_left, dest_top,
74 dest_width, dest_height, 0,
75 FXDIB_INTERPOL)) {
76 return false;
77 }
78 }
79
80 FX_RECT clip_box = m_pDevice->GetClipBox();
81 FX_RECT dest_rect = clip_box;
82 dest_rect.Intersect(image_rect);
83 FX_RECT dest_clip(
84 dest_rect.left - image_rect.left, dest_rect.top - image_rect.top,
85 dest_rect.right - image_rect.left, dest_rect.bottom - image_rect.top);
86 RetainPtr<CFX_DIBitmap> pStretched = m_pDIBSource->StretchTo(
87 dest_width, dest_height, FXDIB_INTERPOL, &dest_clip);
88 if (pStretched)
89 CompositeDIBitmap(pStretched, dest_rect.left, dest_rect.top);
90
91 return false;
92 }
93
Continue()94 bool CXFA_ImageRenderer::Continue() {
95 if (m_Status == 2) {
96 if (m_pTransformer->Continue(nullptr))
97 return true;
98
99 RetainPtr<CFX_DIBitmap> pBitmap = m_pTransformer->DetachBitmap();
100 if (!pBitmap)
101 return false;
102
103 if (pBitmap->IsAlphaMask()) {
104 m_pDevice->SetBitMask(pBitmap, m_pTransformer->result().left,
105 m_pTransformer->result().top, 0);
106 } else {
107 m_pDevice->SetDIBitsWithBlend(pBitmap, m_pTransformer->result().left,
108 m_pTransformer->result().top,
109 FXDIB_BLEND_NORMAL);
110 }
111 return false;
112 }
113 if (m_Status == 3)
114 return m_pDevice->ContinueDIBits(m_DeviceHandle.get(), nullptr);
115
116 return false;
117 }
118
CompositeDIBitmap(const RetainPtr<CFX_DIBitmap> & pDIBitmap,int left,int top)119 void CXFA_ImageRenderer::CompositeDIBitmap(
120 const RetainPtr<CFX_DIBitmap>& pDIBitmap,
121 int left,
122 int top) {
123 if (!pDIBitmap)
124 return;
125
126 if (!pDIBitmap->IsAlphaMask()) {
127 if (m_pDevice->SetDIBits(pDIBitmap, left, top))
128 return;
129 } else if (m_pDevice->SetBitMask(pDIBitmap, left, top, 0)) {
130 return;
131 }
132
133 bool bGetBackGround = ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) ||
134 (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) &&
135 (m_pDevice->GetRenderCaps() & FXRC_GET_BITS));
136 if (bGetBackGround) {
137 if (pDIBitmap->IsAlphaMask())
138 return;
139
140 m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, FXDIB_BLEND_NORMAL);
141 return;
142 }
143 if (!pDIBitmap->HasAlpha() ||
144 (m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE)) {
145 return;
146 }
147
148 RetainPtr<CFX_DIBitmap> pCloneConvert = pDIBitmap->CloneConvert(FXDIB_Rgb);
149 if (!pCloneConvert)
150 return;
151
152 CXFA_ImageRenderer imageRender(m_pDevice, pCloneConvert, &m_ImageMatrix);
153 if (!imageRender.Start())
154 return;
155
156 while (imageRender.Continue())
157 continue;
158 }
159