1 // Copyright 2016 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 "core/fpdfapi/render/cpdf_imagerenderer.h"
8
9 #include <algorithm>
10 #include <memory>
11
12 #include "core/fpdfapi/page/cpdf_docpagedata.h"
13 #include "core/fpdfapi/page/cpdf_image.h"
14 #include "core/fpdfapi/page/cpdf_imageobject.h"
15 #include "core/fpdfapi/page/cpdf_page.h"
16 #include "core/fpdfapi/page/cpdf_pageobject.h"
17 #include "core/fpdfapi/page/cpdf_shadingpattern.h"
18 #include "core/fpdfapi/page/cpdf_tilingpattern.h"
19 #include "core/fpdfapi/parser/cpdf_array.h"
20 #include "core/fpdfapi/parser/cpdf_dictionary.h"
21 #include "core/fpdfapi/parser/cpdf_document.h"
22 #include "core/fpdfapi/render/cpdf_dibsource.h"
23 #include "core/fpdfapi/render/cpdf_pagerendercache.h"
24 #include "core/fpdfapi/render/cpdf_rendercontext.h"
25 #include "core/fpdfapi/render/cpdf_renderstatus.h"
26 #include "core/fpdfapi/render/cpdf_transferfunc.h"
27 #include "core/fpdfdoc/cpdf_occontext.h"
28 #include "core/fxcrt/cfx_maybe_owned.h"
29 #include "core/fxcrt/fx_safe_types.h"
30 #include "core/fxge/cfx_fxgedevice.h"
31 #include "core/fxge/cfx_pathdata.h"
32 #include "third_party/base/ptr_util.h"
33
34 #ifdef _SKIA_SUPPORT_
35 #include "core/fxge/skia/fx_skia_device.h"
36 #endif
37
CPDF_ImageRenderer()38 CPDF_ImageRenderer::CPDF_ImageRenderer() {
39 m_pRenderStatus = nullptr;
40 m_pImageObject = nullptr;
41 m_Result = true;
42 m_Status = 0;
43 m_DeviceHandle = nullptr;
44 m_bStdCS = false;
45 m_bPatternColor = false;
46 m_BlendType = FXDIB_BLEND_NORMAL;
47 m_pPattern = nullptr;
48 m_pObj2Device = nullptr;
49 }
50
~CPDF_ImageRenderer()51 CPDF_ImageRenderer::~CPDF_ImageRenderer() {
52 if (m_DeviceHandle)
53 m_pRenderStatus->m_pDevice->CancelDIBits(m_DeviceHandle);
54 }
55
StartLoadDIBSource()56 bool CPDF_ImageRenderer::StartLoadDIBSource() {
57 CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect();
58 FX_RECT image_rect = image_rect_f.GetOuterRect();
59 if (!image_rect.Valid())
60 return false;
61
62 int dest_width =
63 m_ImageMatrix.a >= 0 ? image_rect.Width() : -image_rect.Width();
64 int dest_height =
65 m_ImageMatrix.d <= 0 ? image_rect.Height() : -image_rect.Height();
66 if (m_Loader.Start(
67 m_pImageObject, m_pRenderStatus->m_pContext->GetPageCache(), m_bStdCS,
68 m_pRenderStatus->m_GroupFamily, m_pRenderStatus->m_bLoadMask,
69 m_pRenderStatus, dest_width, dest_height)) {
70 m_Status = 4;
71 return true;
72 }
73 return false;
74 }
75
StartRenderDIBSource()76 bool CPDF_ImageRenderer::StartRenderDIBSource() {
77 if (!m_Loader.m_pBitmap)
78 return false;
79
80 m_BitmapAlpha =
81 FXSYS_round(255 * m_pImageObject->m_GeneralState.GetFillAlpha());
82 m_pDIBSource = m_Loader.m_pBitmap;
83 if (m_pRenderStatus->m_Options.m_ColorMode == RENDER_COLOR_ALPHA &&
84 !m_Loader.m_pMask) {
85 return StartBitmapAlpha();
86 }
87 if (m_pImageObject->m_GeneralState.GetTR()) {
88 if (!m_pImageObject->m_GeneralState.GetTransferFunc()) {
89 m_pImageObject->m_GeneralState.SetTransferFunc(
90 m_pRenderStatus->GetTransferFunc(
91 m_pImageObject->m_GeneralState.GetTR()));
92 }
93 if (m_pImageObject->m_GeneralState.GetTransferFunc() &&
94 !m_pImageObject->m_GeneralState.GetTransferFunc()->m_bIdentity) {
95 m_pDIBSource = m_Loader.m_pBitmap =
96 m_pImageObject->m_GeneralState.GetTransferFunc()->TranslateImage(
97 m_Loader.m_pBitmap, !m_Loader.m_bCached);
98 if (m_Loader.m_bCached && m_Loader.m_pMask)
99 m_Loader.m_pMask = m_Loader.m_pMask->Clone().release();
100 m_Loader.m_bCached = false;
101 }
102 }
103 m_FillArgb = 0;
104 m_bPatternColor = false;
105 m_pPattern = nullptr;
106 if (m_pDIBSource->IsAlphaMask()) {
107 const CPDF_Color* pColor = m_pImageObject->m_ColorState.GetFillColor();
108 if (pColor && pColor->IsPattern()) {
109 m_pPattern = pColor->GetPattern();
110 if (m_pPattern)
111 m_bPatternColor = true;
112 }
113 m_FillArgb = m_pRenderStatus->GetFillArgb(m_pImageObject);
114 } else if (m_pRenderStatus->m_Options.m_ColorMode == RENDER_COLOR_GRAY) {
115 m_pClone = m_pDIBSource->Clone();
116 m_pClone->ConvertColorScale(m_pRenderStatus->m_Options.m_BackColor,
117 m_pRenderStatus->m_Options.m_ForeColor);
118 m_pDIBSource = m_pClone.get();
119 }
120 m_Flags = 0;
121 if (m_pRenderStatus->m_Options.m_Flags & RENDER_FORCE_DOWNSAMPLE)
122 m_Flags |= RENDER_FORCE_DOWNSAMPLE;
123 else if (m_pRenderStatus->m_Options.m_Flags & RENDER_FORCE_HALFTONE)
124 m_Flags |= RENDER_FORCE_HALFTONE;
125 if (m_pRenderStatus->m_pDevice->GetDeviceClass() != FXDC_DISPLAY) {
126 CPDF_Object* pFilters =
127 m_pImageObject->GetImage()->GetStream()->GetDict()->GetDirectObjectFor(
128 "Filter");
129 if (pFilters) {
130 if (pFilters->IsName()) {
131 CFX_ByteString bsDecodeType = pFilters->GetString();
132 if (bsDecodeType == "DCTDecode" || bsDecodeType == "JPXDecode")
133 m_Flags |= FXRENDER_IMAGE_LOSSY;
134 } else if (CPDF_Array* pArray = pFilters->AsArray()) {
135 for (size_t i = 0; i < pArray->GetCount(); i++) {
136 CFX_ByteString bsDecodeType = pArray->GetStringAt(i);
137 if (bsDecodeType == "DCTDecode" || bsDecodeType == "JPXDecode") {
138 m_Flags |= FXRENDER_IMAGE_LOSSY;
139 break;
140 }
141 }
142 }
143 }
144 }
145 if (m_pRenderStatus->m_Options.m_Flags & RENDER_NOIMAGESMOOTH)
146 m_Flags |= FXDIB_NOSMOOTH;
147 else if (m_pImageObject->GetImage()->IsInterpol())
148 m_Flags |= FXDIB_INTERPOL;
149 if (m_Loader.m_pMask)
150 return DrawMaskedImage();
151
152 if (m_bPatternColor)
153 return DrawPatternImage(m_pObj2Device);
154
155 if (m_BitmapAlpha != 255 || !m_pImageObject->m_GeneralState ||
156 !m_pImageObject->m_GeneralState.GetFillOP() ||
157 m_pImageObject->m_GeneralState.GetOPMode() != 0 ||
158 m_pImageObject->m_GeneralState.GetBlendType() != FXDIB_BLEND_NORMAL ||
159 m_pImageObject->m_GeneralState.GetStrokeAlpha() != 1.0f ||
160 m_pImageObject->m_GeneralState.GetFillAlpha() != 1.0f) {
161 return StartDIBSource();
162 }
163 CPDF_Document* pDocument = nullptr;
164 CPDF_Page* pPage = nullptr;
165 if (m_pRenderStatus->m_pContext->GetPageCache()) {
166 pPage = m_pRenderStatus->m_pContext->GetPageCache()->GetPage();
167 pDocument = pPage->m_pDocument;
168 } else {
169 pDocument = m_pImageObject->GetImage()->GetDocument();
170 }
171 CPDF_Dictionary* pPageResources = pPage ? pPage->m_pPageResources : nullptr;
172 CPDF_Object* pCSObj =
173 m_pImageObject->GetImage()->GetStream()->GetDict()->GetDirectObjectFor(
174 "ColorSpace");
175 CPDF_ColorSpace* pColorSpace =
176 pDocument->LoadColorSpace(pCSObj, pPageResources);
177 if (!pColorSpace)
178 return StartDIBSource();
179 int format = pColorSpace->GetFamily();
180 if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION ||
181 format == PDFCS_DEVICEN) {
182 m_BlendType = FXDIB_BLEND_DARKEN;
183 }
184 pDocument->GetPageData()->ReleaseColorSpace(pCSObj);
185 return StartDIBSource();
186 }
187
Start(CPDF_RenderStatus * pStatus,CPDF_PageObject * pObj,const CFX_Matrix * pObj2Device,bool bStdCS,int blendType)188 bool CPDF_ImageRenderer::Start(CPDF_RenderStatus* pStatus,
189 CPDF_PageObject* pObj,
190 const CFX_Matrix* pObj2Device,
191 bool bStdCS,
192 int blendType) {
193 m_pRenderStatus = pStatus;
194 m_bStdCS = bStdCS;
195 m_pImageObject = pObj->AsImage();
196 m_BlendType = blendType;
197 m_pObj2Device = pObj2Device;
198 CPDF_Dictionary* pOC = m_pImageObject->GetImage()->GetOC();
199 if (pOC && m_pRenderStatus->m_Options.m_pOCContext &&
200 !m_pRenderStatus->m_Options.m_pOCContext->CheckOCGVisible(pOC)) {
201 return false;
202 }
203 m_ImageMatrix = m_pImageObject->matrix();
204 m_ImageMatrix.Concat(*pObj2Device);
205 if (StartLoadDIBSource())
206 return true;
207 return StartRenderDIBSource();
208 }
209
Start(CPDF_RenderStatus * pStatus,const CFX_DIBSource * pDIBSource,FX_ARGB bitmap_argb,int bitmap_alpha,const CFX_Matrix * pImage2Device,uint32_t flags,bool bStdCS,int blendType)210 bool CPDF_ImageRenderer::Start(CPDF_RenderStatus* pStatus,
211 const CFX_DIBSource* pDIBSource,
212 FX_ARGB bitmap_argb,
213 int bitmap_alpha,
214 const CFX_Matrix* pImage2Device,
215 uint32_t flags,
216 bool bStdCS,
217 int blendType) {
218 m_pRenderStatus = pStatus;
219 m_pDIBSource = pDIBSource;
220 m_FillArgb = bitmap_argb;
221 m_BitmapAlpha = bitmap_alpha;
222 m_ImageMatrix = *pImage2Device;
223 m_Flags = flags;
224 m_bStdCS = bStdCS;
225 m_BlendType = blendType;
226 return StartDIBSource();
227 }
228
NotDrawing() const229 bool CPDF_ImageRenderer::NotDrawing() const {
230 return m_pRenderStatus->m_bPrint &&
231 !(m_pRenderStatus->m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE);
232 }
233
GetDrawRect() const234 FX_RECT CPDF_ImageRenderer::GetDrawRect() const {
235 FX_RECT rect = m_ImageMatrix.GetUnitRect().GetOuterRect();
236 rect.Intersect(m_pRenderStatus->m_pDevice->GetClipBox());
237 return rect;
238 }
239
GetDrawMatrix(const FX_RECT & rect) const240 CFX_Matrix CPDF_ImageRenderer::GetDrawMatrix(const FX_RECT& rect) const {
241 CFX_Matrix new_matrix = m_ImageMatrix;
242 new_matrix.Translate(-rect.left, -rect.top);
243 return new_matrix;
244 }
245
CalculateDrawImage(CFX_FxgeDevice * pBitmapDevice1,CFX_FxgeDevice * pBitmapDevice2,const CFX_DIBSource * pDIBSource,CFX_Matrix * pNewMatrix,const FX_RECT & rect) const246 void CPDF_ImageRenderer::CalculateDrawImage(CFX_FxgeDevice* pBitmapDevice1,
247 CFX_FxgeDevice* pBitmapDevice2,
248 const CFX_DIBSource* pDIBSource,
249 CFX_Matrix* pNewMatrix,
250 const FX_RECT& rect) const {
251 CPDF_RenderStatus bitmap_render;
252 bitmap_render.Initialize(m_pRenderStatus->m_pContext, pBitmapDevice2, nullptr,
253 nullptr, nullptr, nullptr, nullptr, 0,
254 m_pRenderStatus->m_bDropObjects, nullptr, true);
255 CPDF_ImageRenderer image_render;
256 if (image_render.Start(&bitmap_render, pDIBSource, 0xffffffff, 255,
257 pNewMatrix, m_Flags, true, FXDIB_BLEND_NORMAL)) {
258 image_render.Continue(nullptr);
259 }
260 if (m_Loader.m_MatteColor == 0xffffffff)
261 return;
262 int matte_r = FXARGB_R(m_Loader.m_MatteColor);
263 int matte_g = FXARGB_G(m_Loader.m_MatteColor);
264 int matte_b = FXARGB_B(m_Loader.m_MatteColor);
265 for (int row = 0; row < rect.Height(); row++) {
266 uint8_t* dest_scan =
267 const_cast<uint8_t*>(pBitmapDevice1->GetBitmap()->GetScanline(row));
268 const uint8_t* mask_scan = pBitmapDevice2->GetBitmap()->GetScanline(row);
269 for (int col = 0; col < rect.Width(); col++) {
270 int alpha = *mask_scan++;
271 if (!alpha) {
272 dest_scan += 4;
273 continue;
274 }
275 int orig = (*dest_scan - matte_b) * 255 / alpha + matte_b;
276 *dest_scan++ = std::min(std::max(orig, 0), 255);
277 orig = (*dest_scan - matte_g) * 255 / alpha + matte_g;
278 *dest_scan++ = std::min(std::max(orig, 0), 255);
279 orig = (*dest_scan - matte_r) * 255 / alpha + matte_r;
280 *dest_scan++ = std::min(std::max(orig, 0), 255);
281 dest_scan++;
282 }
283 }
284 }
285
DrawPatternImage(const CFX_Matrix * pObj2Device)286 bool CPDF_ImageRenderer::DrawPatternImage(const CFX_Matrix* pObj2Device) {
287 if (NotDrawing()) {
288 m_Result = false;
289 return false;
290 }
291
292 FX_RECT rect = GetDrawRect();
293 if (rect.IsEmpty())
294 return false;
295
296 CFX_Matrix new_matrix = GetDrawMatrix(rect);
297 CFX_FxgeDevice bitmap_device1;
298 if (!bitmap_device1.Create(rect.Width(), rect.Height(), FXDIB_Rgb32, nullptr))
299 return true;
300
301 bitmap_device1.GetBitmap()->Clear(0xffffff);
302 CPDF_RenderStatus bitmap_render;
303 bitmap_render.Initialize(m_pRenderStatus->m_pContext, &bitmap_device1,
304 nullptr, nullptr, nullptr, nullptr,
305 &m_pRenderStatus->m_Options, 0,
306 m_pRenderStatus->m_bDropObjects, nullptr, true);
307 CFX_Matrix patternDevice = *pObj2Device;
308 patternDevice.Translate((FX_FLOAT)-rect.left, (FX_FLOAT)-rect.top);
309 if (CPDF_TilingPattern* pTilingPattern = m_pPattern->AsTilingPattern()) {
310 bitmap_render.DrawTilingPattern(pTilingPattern, m_pImageObject,
311 &patternDevice, false);
312 } else if (CPDF_ShadingPattern* pShadingPattern =
313 m_pPattern->AsShadingPattern()) {
314 bitmap_render.DrawShadingPattern(pShadingPattern, m_pImageObject,
315 &patternDevice, false);
316 }
317
318 CFX_FxgeDevice bitmap_device2;
319 if (!bitmap_device2.Create(rect.Width(), rect.Height(), FXDIB_8bppRgb,
320 nullptr)) {
321 return true;
322 }
323 bitmap_device2.GetBitmap()->Clear(0);
324 CalculateDrawImage(&bitmap_device1, &bitmap_device2, m_pDIBSource,
325 &new_matrix, rect);
326 bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_8bppMask);
327 bitmap_device1.GetBitmap()->MultiplyAlpha(bitmap_device2.GetBitmap());
328 bitmap_device1.GetBitmap()->MultiplyAlpha(255);
329 m_pRenderStatus->m_pDevice->SetDIBitsWithBlend(
330 bitmap_device1.GetBitmap(), rect.left, rect.top, m_BlendType);
331 return false;
332 }
333
DrawMaskedImage()334 bool CPDF_ImageRenderer::DrawMaskedImage() {
335 if (NotDrawing()) {
336 m_Result = false;
337 return false;
338 }
339
340 FX_RECT rect = GetDrawRect();
341 if (rect.IsEmpty())
342 return false;
343
344 CFX_Matrix new_matrix = GetDrawMatrix(rect);
345 CFX_FxgeDevice bitmap_device1;
346 if (!bitmap_device1.Create(rect.Width(), rect.Height(), FXDIB_Rgb32, nullptr))
347 return true;
348
349 #if defined _SKIA_SUPPORT_
350 bitmap_device1.Clear(0xffffff);
351 #else
352 bitmap_device1.GetBitmap()->Clear(0xffffff);
353 #endif
354 CPDF_RenderStatus bitmap_render;
355 bitmap_render.Initialize(m_pRenderStatus->m_pContext, &bitmap_device1,
356 nullptr, nullptr, nullptr, nullptr, nullptr, 0,
357 m_pRenderStatus->m_bDropObjects, nullptr, true);
358 CPDF_ImageRenderer image_render;
359 if (image_render.Start(&bitmap_render, m_pDIBSource, 0, 255, &new_matrix,
360 m_Flags, true, FXDIB_BLEND_NORMAL)) {
361 image_render.Continue(nullptr);
362 }
363 CFX_FxgeDevice bitmap_device2;
364 if (!bitmap_device2.Create(rect.Width(), rect.Height(), FXDIB_8bppRgb,
365 nullptr))
366 return true;
367
368 #if defined _SKIA_SUPPORT_
369 bitmap_device2.Clear(0);
370 #else
371 bitmap_device2.GetBitmap()->Clear(0);
372 #endif
373 CalculateDrawImage(&bitmap_device1, &bitmap_device2, m_Loader.m_pMask,
374 &new_matrix, rect);
375 #ifdef _SKIA_SUPPORT_
376 m_pRenderStatus->m_pDevice->SetBitsWithMask(
377 bitmap_device1.GetBitmap(), bitmap_device2.GetBitmap(), rect.left,
378 rect.top, m_BitmapAlpha, m_BlendType);
379 #else
380 bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_8bppMask);
381 bitmap_device1.GetBitmap()->MultiplyAlpha(bitmap_device2.GetBitmap());
382 if (m_BitmapAlpha < 255)
383 bitmap_device1.GetBitmap()->MultiplyAlpha(m_BitmapAlpha);
384 m_pRenderStatus->m_pDevice->SetDIBitsWithBlend(
385 bitmap_device1.GetBitmap(), rect.left, rect.top, m_BlendType);
386 #endif // _SKIA_SUPPORT_
387 return false;
388 }
389
StartDIBSource()390 bool CPDF_ImageRenderer::StartDIBSource() {
391 if (!(m_Flags & RENDER_FORCE_DOWNSAMPLE) && m_pDIBSource->GetBPP() > 1) {
392 FX_SAFE_SIZE_T image_size = m_pDIBSource->GetBPP();
393 image_size /= 8;
394 image_size *= m_pDIBSource->GetWidth();
395 image_size *= m_pDIBSource->GetHeight();
396 if (!image_size.IsValid())
397 return false;
398
399 if (image_size.ValueOrDie() > FPDF_HUGE_IMAGE_SIZE &&
400 !(m_Flags & RENDER_FORCE_HALFTONE)) {
401 m_Flags |= RENDER_FORCE_DOWNSAMPLE;
402 }
403 }
404 #ifdef _SKIA_SUPPORT_
405 CFX_DIBitmap* premultiplied = m_pDIBSource->Clone().release();
406 if (m_pDIBSource->HasAlpha())
407 CFX_SkiaDeviceDriver::PreMultiply(premultiplied);
408 if (m_pRenderStatus->m_pDevice->StartDIBitsWithBlend(
409 premultiplied, m_BitmapAlpha, m_FillArgb, &m_ImageMatrix, m_Flags,
410 m_DeviceHandle, m_BlendType)) {
411 if (m_DeviceHandle) {
412 m_Status = 3;
413 return true;
414 }
415 return false;
416 }
417 #else
418 if (m_pRenderStatus->m_pDevice->StartDIBitsWithBlend(
419 m_pDIBSource, m_BitmapAlpha, m_FillArgb, &m_ImageMatrix, m_Flags,
420 m_DeviceHandle, m_BlendType)) {
421 if (m_DeviceHandle) {
422 m_Status = 3;
423 return true;
424 }
425 return false;
426 }
427 #endif
428 CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect();
429 FX_RECT image_rect = image_rect_f.GetOuterRect();
430 int dest_width = image_rect.Width();
431 int dest_height = image_rect.Height();
432 if ((FXSYS_fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) ||
433 (FXSYS_fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0)) {
434 if (NotDrawing()) {
435 m_Result = false;
436 return false;
437 }
438
439 FX_RECT clip_box = m_pRenderStatus->m_pDevice->GetClipBox();
440 clip_box.Intersect(image_rect);
441 m_Status = 2;
442 m_pTransformer = pdfium::MakeUnique<CFX_ImageTransformer>(
443 m_pDIBSource, &m_ImageMatrix, m_Flags, &clip_box);
444 m_pTransformer->Start();
445 return true;
446 }
447 if (m_ImageMatrix.a < 0)
448 dest_width = -dest_width;
449
450 if (m_ImageMatrix.d > 0)
451 dest_height = -dest_height;
452
453 int dest_left = dest_width > 0 ? image_rect.left : image_rect.right;
454 int dest_top = dest_height > 0 ? image_rect.top : image_rect.bottom;
455 if (m_pDIBSource->IsOpaqueImage() && m_BitmapAlpha == 255) {
456 if (m_pRenderStatus->m_pDevice->StretchDIBitsWithFlagsAndBlend(
457 m_pDIBSource, dest_left, dest_top, dest_width, dest_height, m_Flags,
458 m_BlendType)) {
459 return false;
460 }
461 }
462 if (m_pDIBSource->IsAlphaMask()) {
463 if (m_BitmapAlpha != 255)
464 m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha);
465 if (m_pRenderStatus->m_pDevice->StretchBitMaskWithFlags(
466 m_pDIBSource, dest_left, dest_top, dest_width, dest_height,
467 m_FillArgb, m_Flags)) {
468 return false;
469 }
470 }
471 if (NotDrawing()) {
472 m_Result = false;
473 return true;
474 }
475
476 FX_RECT clip_box = m_pRenderStatus->m_pDevice->GetClipBox();
477 FX_RECT dest_rect = clip_box;
478 dest_rect.Intersect(image_rect);
479 FX_RECT dest_clip(
480 dest_rect.left - image_rect.left, dest_rect.top - image_rect.top,
481 dest_rect.right - image_rect.left, dest_rect.bottom - image_rect.top);
482 std::unique_ptr<CFX_DIBitmap> pStretched(
483 m_pDIBSource->StretchTo(dest_width, dest_height, m_Flags, &dest_clip));
484 if (pStretched) {
485 m_pRenderStatus->CompositeDIBitmap(pStretched.get(), dest_rect.left,
486 dest_rect.top, m_FillArgb, m_BitmapAlpha,
487 m_BlendType, false);
488 }
489 return false;
490 }
491
StartBitmapAlpha()492 bool CPDF_ImageRenderer::StartBitmapAlpha() {
493 if (m_pDIBSource->IsOpaqueImage()) {
494 CFX_PathData path;
495 path.AppendRect(0, 0, 1, 1);
496 path.Transform(&m_ImageMatrix);
497 uint32_t fill_color =
498 ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha);
499 m_pRenderStatus->m_pDevice->DrawPath(&path, nullptr, nullptr, fill_color, 0,
500 FXFILL_WINDING);
501 return false;
502 }
503 CFX_MaybeOwned<CFX_DIBSource> pAlphaMask;
504 if (m_pDIBSource->IsAlphaMask())
505 pAlphaMask = const_cast<CFX_DIBSource*>(m_pDIBSource);
506 else
507 pAlphaMask = m_pDIBSource->CloneAlphaMask();
508
509 if (FXSYS_fabs(m_ImageMatrix.b) >= 0.5f ||
510 FXSYS_fabs(m_ImageMatrix.c) >= 0.5f) {
511 int left;
512 int top;
513 std::unique_ptr<CFX_DIBitmap> pTransformed =
514 pAlphaMask->TransformTo(&m_ImageMatrix, left, top);
515 if (!pTransformed)
516 return true;
517
518 m_pRenderStatus->m_pDevice->SetBitMask(
519 pTransformed.get(), left, top,
520 ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha));
521 return false;
522 }
523 CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect();
524 FX_RECT image_rect = image_rect_f.GetOuterRect();
525 int dest_width =
526 m_ImageMatrix.a > 0 ? image_rect.Width() : -image_rect.Width();
527 int dest_height =
528 m_ImageMatrix.d > 0 ? -image_rect.Height() : image_rect.Height();
529 int left = dest_width > 0 ? image_rect.left : image_rect.right;
530 int top = dest_height > 0 ? image_rect.top : image_rect.bottom;
531 m_pRenderStatus->m_pDevice->StretchBitMask(
532 pAlphaMask.Get(), left, top, dest_width, dest_height,
533 ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha));
534 return false;
535 }
536
Continue(IFX_Pause * pPause)537 bool CPDF_ImageRenderer::Continue(IFX_Pause* pPause) {
538 if (m_Status == 2) {
539 if (m_pTransformer->Continue(pPause))
540 return true;
541
542 std::unique_ptr<CFX_DIBitmap> pBitmap(m_pTransformer->DetachBitmap());
543 if (!pBitmap)
544 return false;
545
546 if (pBitmap->IsAlphaMask()) {
547 if (m_BitmapAlpha != 255)
548 m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha);
549 m_Result = m_pRenderStatus->m_pDevice->SetBitMask(
550 pBitmap.get(), m_pTransformer->result().left,
551 m_pTransformer->result().top, m_FillArgb);
552 } else {
553 if (m_BitmapAlpha != 255)
554 pBitmap->MultiplyAlpha(m_BitmapAlpha);
555 m_Result = m_pRenderStatus->m_pDevice->SetDIBitsWithBlend(
556 pBitmap.get(), m_pTransformer->result().left,
557 m_pTransformer->result().top, m_BlendType);
558 }
559 return false;
560 }
561 if (m_Status == 3)
562 return m_pRenderStatus->m_pDevice->ContinueDIBits(m_DeviceHandle, pPause);
563
564 if (m_Status == 4) {
565 if (m_Loader.Continue(pPause))
566 return true;
567
568 if (StartRenderDIBSource())
569 return Continue(pPause);
570 }
571 return false;
572 }
573