1 // Copyright 2016 The PDFium Authors
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 <math.h>
10
11 #include <algorithm>
12 #include <memory>
13 #include <utility>
14
15 #include "core/fpdfapi/page/cpdf_dib.h"
16 #include "core/fpdfapi/page/cpdf_docpagedata.h"
17 #include "core/fpdfapi/page/cpdf_image.h"
18 #include "core/fpdfapi/page/cpdf_imageloader.h"
19 #include "core/fpdfapi/page/cpdf_imageobject.h"
20 #include "core/fpdfapi/page/cpdf_occontext.h"
21 #include "core/fpdfapi/page/cpdf_page.h"
22 #include "core/fpdfapi/page/cpdf_pageimagecache.h"
23 #include "core/fpdfapi/page/cpdf_pageobject.h"
24 #include "core/fpdfapi/page/cpdf_shadingpattern.h"
25 #include "core/fpdfapi/page/cpdf_tilingpattern.h"
26 #include "core/fpdfapi/page/cpdf_transferfunc.h"
27 #include "core/fpdfapi/parser/cpdf_dictionary.h"
28 #include "core/fpdfapi/parser/cpdf_document.h"
29 #include "core/fpdfapi/parser/cpdf_stream.h"
30 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
31 #include "core/fpdfapi/render/cpdf_rendercontext.h"
32 #include "core/fpdfapi/render/cpdf_renderstatus.h"
33 #include "core/fxcrt/fx_safe_types.h"
34 #include "core/fxcrt/maybe_owned.h"
35 #include "core/fxge/cfx_defaultrenderdevice.h"
36 #include "core/fxge/cfx_fillrenderoptions.h"
37 #include "core/fxge/cfx_path.h"
38 #include "core/fxge/dib/cfx_dibbase.h"
39 #include "core/fxge/dib/cfx_dibitmap.h"
40 #include "core/fxge/dib/cfx_imagestretcher.h"
41 #include "core/fxge/dib/cfx_imagetransformer.h"
42 #include "third_party/base/check.h"
43
44 namespace {
45
IsImageValueTooBig(int val)46 bool IsImageValueTooBig(int val) {
47 // Likely large enough for any real rendering need, but sufficiently small
48 // that operations like val1 + val2 or -val will not overflow.
49 constexpr int kLimit = 256 * 1024 * 1024;
50 FX_SAFE_INT32 safe_val = val;
51 safe_val = safe_val.Abs();
52 return safe_val.ValueOrDefault(kLimit) >= kLimit;
53 }
54
ClearBitmap(CFX_DefaultRenderDevice & bitmap_device,uint32_t color)55 void ClearBitmap(CFX_DefaultRenderDevice& bitmap_device, uint32_t color) {
56 #if defined(_SKIA_SUPPORT_)
57 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
58 bitmap_device.Clear(color);
59 return;
60 }
61 #endif
62 bitmap_device.GetBitmap()->Clear(color);
63 }
64
65 } // namespace
66
CPDF_ImageRenderer(CPDF_RenderStatus * pStatus)67 CPDF_ImageRenderer::CPDF_ImageRenderer(CPDF_RenderStatus* pStatus)
68 : m_pRenderStatus(pStatus),
69 m_pLoader(std::make_unique<CPDF_ImageLoader>()) {}
70
71 CPDF_ImageRenderer::~CPDF_ImageRenderer() = default;
72
StartLoadDIBBase()73 bool CPDF_ImageRenderer::StartLoadDIBBase() {
74 if (!GetUnitRect().has_value())
75 return false;
76
77 if (!m_pLoader->Start(
78 m_pImageObject, m_pRenderStatus->GetContext()->GetPageCache(),
79 m_pRenderStatus->GetFormResource(),
80 m_pRenderStatus->GetPageResource(), m_bStdCS,
81 m_pRenderStatus->GetGroupFamily(), m_pRenderStatus->GetLoadMask(),
82 {m_pRenderStatus->GetRenderDevice()->GetWidth(),
83 m_pRenderStatus->GetRenderDevice()->GetHeight()})) {
84 return false;
85 }
86 m_Mode = Mode::kDefault;
87 return true;
88 }
89
StartRenderDIBBase()90 bool CPDF_ImageRenderer::StartRenderDIBBase() {
91 if (!m_pLoader->GetBitmap())
92 return false;
93
94 CPDF_GeneralState& state = m_pImageObject->m_GeneralState;
95 m_BitmapAlpha = FXSYS_roundf(255 * state.GetFillAlpha());
96 m_pDIBBase = m_pLoader->GetBitmap();
97 if (GetRenderOptions().ColorModeIs(CPDF_RenderOptions::kAlpha) &&
98 !m_pLoader->GetMask()) {
99 return StartBitmapAlpha();
100 }
101 RetainPtr<const CPDF_Object> pTR = state.GetTR();
102 if (pTR) {
103 if (!state.GetTransferFunc())
104 state.SetTransferFunc(m_pRenderStatus->GetTransferFunc(std::move(pTR)));
105
106 if (state.GetTransferFunc() && !state.GetTransferFunc()->GetIdentity())
107 m_pDIBBase = m_pLoader->TranslateImage(state.GetTransferFunc());
108 }
109 m_FillArgb = 0;
110 m_bPatternColor = false;
111 m_pPattern = nullptr;
112 if (m_pDIBBase->IsMaskFormat()) {
113 const CPDF_Color* pColor = m_pImageObject->m_ColorState.GetFillColor();
114 if (pColor && pColor->IsPattern()) {
115 m_pPattern = pColor->GetPattern();
116 if (m_pPattern)
117 m_bPatternColor = true;
118 }
119 m_FillArgb = m_pRenderStatus->GetFillArgb(m_pImageObject);
120 } else if (GetRenderOptions().ColorModeIs(CPDF_RenderOptions::kGray)) {
121 RetainPtr<CFX_DIBitmap> pClone = m_pDIBBase->Realize();
122 if (!pClone)
123 return false;
124
125 pClone->ConvertColorScale(0xffffff, 0);
126 m_pDIBBase = pClone;
127 }
128 m_ResampleOptions = FXDIB_ResampleOptions();
129 if (GetRenderOptions().GetOptions().bForceHalftone)
130 m_ResampleOptions.bHalftone = true;
131
132 if (m_pRenderStatus->GetRenderDevice()->GetDeviceType() !=
133 DeviceType::kDisplay) {
134 HandleFilters();
135 }
136
137 if (GetRenderOptions().GetOptions().bNoImageSmooth)
138 m_ResampleOptions.bNoSmoothing = true;
139 else if (m_pImageObject->GetImage()->IsInterpol())
140 m_ResampleOptions.bInterpolateBilinear = true;
141
142 if (m_pLoader->GetMask())
143 return DrawMaskedImage();
144
145 if (m_bPatternColor)
146 return DrawPatternImage();
147
148 if (m_BitmapAlpha != 255 || !state.HasRef() || !state.GetFillOP() ||
149 state.GetOPMode() != 0 || state.GetBlendType() != BlendMode::kNormal ||
150 state.GetStrokeAlpha() != 1.0f || state.GetFillAlpha() != 1.0f) {
151 return StartDIBBase();
152 }
153 CPDF_Document* pDocument = nullptr;
154 CPDF_Page* pPage = nullptr;
155 if (auto* pPageCache = m_pRenderStatus->GetContext()->GetPageCache()) {
156 pPage = pPageCache->GetPage();
157 pDocument = pPage->GetDocument();
158 } else {
159 pDocument = m_pImageObject->GetImage()->GetDocument();
160 }
161 RetainPtr<const CPDF_Dictionary> pPageResources =
162 pPage ? pPage->GetPageResources() : nullptr;
163 RetainPtr<const CPDF_Dictionary> pStreamDict =
164 m_pImageObject->GetImage()->GetStream()->GetDict();
165 RetainPtr<const CPDF_Object> pCSObj =
166 pStreamDict->GetDirectObjectFor("ColorSpace");
167 auto* pData = CPDF_DocPageData::FromDocument(pDocument);
168 RetainPtr<CPDF_ColorSpace> pColorSpace =
169 pData->GetColorSpace(pCSObj.Get(), pPageResources);
170 if (pColorSpace) {
171 CPDF_ColorSpace::Family format = pColorSpace->GetFamily();
172 if (format == CPDF_ColorSpace::Family::kDeviceCMYK ||
173 format == CPDF_ColorSpace::Family::kSeparation ||
174 format == CPDF_ColorSpace::Family::kDeviceN) {
175 m_BlendType = BlendMode::kDarken;
176 }
177 }
178 return StartDIBBase();
179 }
180
Start(CPDF_ImageObject * pImageObject,const CFX_Matrix & mtObj2Device,bool bStdCS,BlendMode blendType)181 bool CPDF_ImageRenderer::Start(CPDF_ImageObject* pImageObject,
182 const CFX_Matrix& mtObj2Device,
183 bool bStdCS,
184 BlendMode blendType) {
185 DCHECK(pImageObject);
186 m_bStdCS = bStdCS;
187 m_pImageObject = pImageObject;
188 m_BlendType = blendType;
189 m_mtObj2Device = mtObj2Device;
190 RetainPtr<const CPDF_Dictionary> pOC = m_pImageObject->GetImage()->GetOC();
191 if (pOC && !GetRenderOptions().CheckOCGDictVisible(pOC))
192 return false;
193
194 m_ImageMatrix = m_pImageObject->matrix() * mtObj2Device;
195 if (StartLoadDIBBase())
196 return true;
197
198 return StartRenderDIBBase();
199 }
200
Start(RetainPtr<CFX_DIBBase> pDIBBase,FX_ARGB bitmap_argb,const CFX_Matrix & mtImage2Device,const FXDIB_ResampleOptions & options,bool bStdCS)201 bool CPDF_ImageRenderer::Start(RetainPtr<CFX_DIBBase> pDIBBase,
202 FX_ARGB bitmap_argb,
203 const CFX_Matrix& mtImage2Device,
204 const FXDIB_ResampleOptions& options,
205 bool bStdCS) {
206 m_pDIBBase = std::move(pDIBBase);
207 m_FillArgb = bitmap_argb;
208 m_BitmapAlpha = 255;
209 m_ImageMatrix = mtImage2Device;
210 m_ResampleOptions = options;
211 m_bStdCS = bStdCS;
212 m_BlendType = BlendMode::kNormal;
213 return StartDIBBase();
214 }
215
NotDrawing() const216 bool CPDF_ImageRenderer::NotDrawing() const {
217 return m_pRenderStatus->IsPrint() &&
218 !(m_pRenderStatus->GetRenderDevice()->GetRenderCaps() &
219 FXRC_BLEND_MODE);
220 }
221
GetDrawRect() const222 FX_RECT CPDF_ImageRenderer::GetDrawRect() const {
223 FX_RECT rect = m_ImageMatrix.GetUnitRect().GetOuterRect();
224 rect.Intersect(m_pRenderStatus->GetRenderDevice()->GetClipBox());
225 return rect;
226 }
227
GetDrawMatrix(const FX_RECT & rect) const228 CFX_Matrix CPDF_ImageRenderer::GetDrawMatrix(const FX_RECT& rect) const {
229 CFX_Matrix new_matrix = m_ImageMatrix;
230 new_matrix.Translate(-rect.left, -rect.top);
231 return new_matrix;
232 }
233
CalculateDrawImage(CFX_DefaultRenderDevice * pBitmapDevice1,CFX_DefaultRenderDevice * pBitmapDevice2,RetainPtr<CFX_DIBBase> pDIBBase,const CFX_Matrix & mtNewMatrix,const FX_RECT & rect) const234 void CPDF_ImageRenderer::CalculateDrawImage(
235 CFX_DefaultRenderDevice* pBitmapDevice1,
236 CFX_DefaultRenderDevice* pBitmapDevice2,
237 RetainPtr<CFX_DIBBase> pDIBBase,
238 const CFX_Matrix& mtNewMatrix,
239 const FX_RECT& rect) const {
240 CPDF_RenderStatus bitmap_render(m_pRenderStatus->GetContext(),
241 pBitmapDevice2);
242 bitmap_render.SetDropObjects(m_pRenderStatus->GetDropObjects());
243 bitmap_render.SetStdCS(true);
244 bitmap_render.Initialize(nullptr, nullptr);
245
246 CPDF_ImageRenderer image_render(&bitmap_render);
247 if (image_render.Start(std::move(pDIBBase), 0xffffffff, mtNewMatrix,
248 m_ResampleOptions, true)) {
249 image_render.Continue(nullptr);
250 }
251 if (m_pLoader->MatteColor() == 0xffffffff)
252 return;
253 int matte_r = FXARGB_R(m_pLoader->MatteColor());
254 int matte_g = FXARGB_G(m_pLoader->MatteColor());
255 int matte_b = FXARGB_B(m_pLoader->MatteColor());
256 for (int row = 0; row < rect.Height(); row++) {
257 uint8_t* dest_scan =
258 pBitmapDevice1->GetBitmap()->GetWritableScanline(row).data();
259 const uint8_t* mask_scan =
260 pBitmapDevice2->GetBitmap()->GetScanline(row).data();
261 for (int col = 0; col < rect.Width(); col++) {
262 int alpha = *mask_scan++;
263 if (!alpha) {
264 dest_scan += 4;
265 continue;
266 }
267 int orig = (*dest_scan - matte_b) * 255 / alpha + matte_b;
268 *dest_scan++ = std::clamp(orig, 0, 255);
269 orig = (*dest_scan - matte_g) * 255 / alpha + matte_g;
270 *dest_scan++ = std::clamp(orig, 0, 255);
271 orig = (*dest_scan - matte_r) * 255 / alpha + matte_r;
272 *dest_scan++ = std::clamp(orig, 0, 255);
273 dest_scan++;
274 }
275 }
276 }
277
GetRenderOptions() const278 const CPDF_RenderOptions& CPDF_ImageRenderer::GetRenderOptions() const {
279 return m_pRenderStatus->GetRenderOptions();
280 }
281
DrawPatternImage()282 bool CPDF_ImageRenderer::DrawPatternImage() {
283 if (NotDrawing()) {
284 m_Result = false;
285 return false;
286 }
287
288 FX_RECT rect = GetDrawRect();
289 if (rect.IsEmpty())
290 return false;
291
292 CFX_Matrix new_matrix = GetDrawMatrix(rect);
293 CFX_DefaultRenderDevice bitmap_device1;
294 if (!bitmap_device1.Create(rect.Width(), rect.Height(), FXDIB_Format::kArgb,
295 nullptr)) {
296 return true;
297 }
298
299 CPDF_RenderStatus bitmap_render(m_pRenderStatus->GetContext(),
300 &bitmap_device1);
301 bitmap_render.SetOptions(GetRenderOptions());
302 bitmap_render.SetDropObjects(m_pRenderStatus->GetDropObjects());
303 bitmap_render.SetStdCS(true);
304 bitmap_render.Initialize(nullptr, nullptr);
305
306 CFX_Matrix patternDevice = m_mtObj2Device;
307 patternDevice.Translate(static_cast<float>(-rect.left),
308 static_cast<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_DefaultRenderDevice bitmap_device2;
319 if (!bitmap_device2.Create(rect.Width(), rect.Height(),
320 FXDIB_Format::k8bppRgb, nullptr)) {
321 return true;
322 }
323 CalculateDrawImage(&bitmap_device1, &bitmap_device2, m_pDIBBase, new_matrix,
324 rect);
325 bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_Format::k8bppMask);
326 bitmap_device1.GetBitmap()->MultiplyAlpha(bitmap_device2.GetBitmap());
327 bitmap_device1.GetBitmap()->MultiplyAlpha(255);
328 m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
329 bitmap_device1.GetBitmap(), rect.left, rect.top, m_BlendType);
330 return false;
331 }
332
DrawMaskedImage()333 bool CPDF_ImageRenderer::DrawMaskedImage() {
334 if (NotDrawing()) {
335 m_Result = false;
336 return false;
337 }
338
339 FX_RECT rect = GetDrawRect();
340 if (rect.IsEmpty())
341 return false;
342
343 CFX_Matrix new_matrix = GetDrawMatrix(rect);
344 CFX_DefaultRenderDevice bitmap_device1;
345 if (!bitmap_device1.Create(rect.Width(), rect.Height(), FXDIB_Format::kRgb32,
346 nullptr)) {
347 return true;
348 }
349 ClearBitmap(bitmap_device1, 0xffffffff);
350 CPDF_RenderStatus bitmap_render(m_pRenderStatus->GetContext(),
351 &bitmap_device1);
352 bitmap_render.SetDropObjects(m_pRenderStatus->GetDropObjects());
353 bitmap_render.SetStdCS(true);
354 bitmap_render.Initialize(nullptr, nullptr);
355 CPDF_ImageRenderer image_render(&bitmap_render);
356 if (image_render.Start(m_pDIBBase, 0, new_matrix, m_ResampleOptions, true)) {
357 image_render.Continue(nullptr);
358 }
359 CFX_DefaultRenderDevice bitmap_device2;
360 if (!bitmap_device2.Create(rect.Width(), rect.Height(),
361 FXDIB_Format::k8bppRgb, nullptr)) {
362 return true;
363 }
364 CalculateDrawImage(&bitmap_device1, &bitmap_device2, m_pLoader->GetMask(),
365 new_matrix, rect);
366 DCHECK(!bitmap_device2.GetBitmap()->HasPalette());
367 bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_Format::k8bppMask);
368 #if defined(_SKIA_SUPPORT_)
369 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
370 m_pRenderStatus->GetRenderDevice()->SetBitsWithMask(
371 bitmap_device1.GetBitmap(), bitmap_device2.GetBitmap(), rect.left,
372 rect.top, m_BitmapAlpha, m_BlendType);
373 return false;
374 }
375 #endif
376 bitmap_device1.GetBitmap()->MultiplyAlpha(bitmap_device2.GetBitmap());
377 if (m_BitmapAlpha < 255)
378 bitmap_device1.GetBitmap()->MultiplyAlpha(m_BitmapAlpha);
379 m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
380 bitmap_device1.GetBitmap(), rect.left, rect.top, m_BlendType);
381 return false;
382 }
383
StartDIBBase()384 bool CPDF_ImageRenderer::StartDIBBase() {
385 if (m_pDIBBase->GetBPP() > 1) {
386 FX_SAFE_SIZE_T image_size = m_pDIBBase->GetBPP();
387 image_size /= 8;
388 image_size *= m_pDIBBase->GetWidth();
389 image_size *= m_pDIBBase->GetHeight();
390 if (!image_size.IsValid())
391 return false;
392
393 if (image_size.ValueOrDie() > kHugeImageSize &&
394 !m_ResampleOptions.bHalftone) {
395 m_ResampleOptions.bInterpolateBilinear = true;
396 }
397 }
398 if (m_pRenderStatus->GetRenderDevice()->StartDIBitsWithBlend(
399 m_pDIBBase, m_BitmapAlpha, m_FillArgb, m_ImageMatrix,
400 m_ResampleOptions, &m_DeviceHandle, m_BlendType)) {
401 if (m_DeviceHandle) {
402 m_Mode = Mode::kBlend;
403 return true;
404 }
405 return false;
406 }
407
408 if ((fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) ||
409 (fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0)) {
410 if (NotDrawing()) {
411 m_Result = false;
412 return false;
413 }
414
415 absl::optional<FX_RECT> image_rect = GetUnitRect();
416 if (!image_rect.has_value())
417 return false;
418
419 FX_RECT clip_box = m_pRenderStatus->GetRenderDevice()->GetClipBox();
420 clip_box.Intersect(image_rect.value());
421 m_Mode = Mode::kTransform;
422 m_pTransformer = std::make_unique<CFX_ImageTransformer>(
423 m_pDIBBase, m_ImageMatrix, m_ResampleOptions, &clip_box);
424 return true;
425 }
426
427 absl::optional<FX_RECT> image_rect = GetUnitRect();
428 if (!image_rect.has_value())
429 return false;
430
431 int dest_left;
432 int dest_top;
433 int dest_width;
434 int dest_height;
435 if (!GetDimensionsFromUnitRect(image_rect.value(), &dest_left, &dest_top,
436 &dest_width, &dest_height)) {
437 return false;
438 }
439
440 if (m_pDIBBase->IsOpaqueImage() && m_BitmapAlpha == 255) {
441 if (m_pRenderStatus->GetRenderDevice()->StretchDIBitsWithFlagsAndBlend(
442 m_pDIBBase, dest_left, dest_top, dest_width, dest_height,
443 m_ResampleOptions, m_BlendType)) {
444 return false;
445 }
446 }
447 if (m_pDIBBase->IsMaskFormat()) {
448 if (m_BitmapAlpha != 255)
449 m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha);
450 if (m_pRenderStatus->GetRenderDevice()->StretchBitMaskWithFlags(
451 m_pDIBBase, dest_left, dest_top, dest_width, dest_height,
452 m_FillArgb, m_ResampleOptions)) {
453 return false;
454 }
455 }
456 if (NotDrawing()) {
457 m_Result = false;
458 return true;
459 }
460
461 FX_RECT clip_box = m_pRenderStatus->GetRenderDevice()->GetClipBox();
462 FX_RECT dest_rect = clip_box;
463 dest_rect.Intersect(image_rect.value());
464 FX_RECT dest_clip(
465 dest_rect.left - image_rect->left, dest_rect.top - image_rect->top,
466 dest_rect.right - image_rect->left, dest_rect.bottom - image_rect->top);
467 RetainPtr<CFX_DIBitmap> pStretched = m_pDIBBase->StretchTo(
468 dest_width, dest_height, m_ResampleOptions, &dest_clip);
469 if (pStretched) {
470 m_pRenderStatus->CompositeDIBitmap(pStretched, dest_rect.left,
471 dest_rect.top, m_FillArgb, m_BitmapAlpha,
472 m_BlendType, CPDF_Transparency());
473 }
474 return false;
475 }
476
StartBitmapAlpha()477 bool CPDF_ImageRenderer::StartBitmapAlpha() {
478 if (m_pDIBBase->IsOpaqueImage()) {
479 CFX_Path path;
480 path.AppendRect(0, 0, 1, 1);
481 path.Transform(m_ImageMatrix);
482 uint32_t fill_color =
483 ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha);
484 m_pRenderStatus->GetRenderDevice()->DrawPath(
485 path, nullptr, nullptr, fill_color, 0,
486 CFX_FillRenderOptions::WindingOptions());
487 return false;
488 }
489 RetainPtr<CFX_DIBBase> pAlphaMask;
490 if (m_pDIBBase->IsMaskFormat())
491 pAlphaMask = m_pDIBBase;
492 else
493 pAlphaMask = m_pDIBBase->CloneAlphaMask();
494
495 if (fabs(m_ImageMatrix.b) >= 0.5f || fabs(m_ImageMatrix.c) >= 0.5f) {
496 int left;
497 int top;
498 RetainPtr<CFX_DIBitmap> pTransformed =
499 pAlphaMask->TransformTo(m_ImageMatrix, &left, &top);
500 if (!pTransformed)
501 return true;
502
503 m_pRenderStatus->GetRenderDevice()->SetBitMask(
504 pTransformed, left, top,
505 ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha));
506 return false;
507 }
508
509 absl::optional<FX_RECT> image_rect = GetUnitRect();
510 if (!image_rect.has_value())
511 return false;
512
513 int left;
514 int top;
515 int dest_width;
516 int dest_height;
517 if (!GetDimensionsFromUnitRect(image_rect.value(), &left, &top, &dest_width,
518 &dest_height)) {
519 return false;
520 }
521
522 m_pRenderStatus->GetRenderDevice()->StretchBitMask(
523 pAlphaMask, left, top, dest_width, dest_height,
524 ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha));
525 return false;
526 }
527
Continue(PauseIndicatorIface * pPause)528 bool CPDF_ImageRenderer::Continue(PauseIndicatorIface* pPause) {
529 switch (m_Mode) {
530 case Mode::kNone:
531 return false;
532 case Mode::kDefault:
533 return ContinueDefault(pPause);
534 case Mode::kBlend:
535 return ContinueBlend(pPause);
536 case Mode::kTransform:
537 return ContinueTransform(pPause);
538 }
539 }
540
ContinueDefault(PauseIndicatorIface * pPause)541 bool CPDF_ImageRenderer::ContinueDefault(PauseIndicatorIface* pPause) {
542 if (m_pLoader->Continue(pPause))
543 return true;
544
545 if (!StartRenderDIBBase())
546 return false;
547
548 if (m_Mode == Mode::kDefault)
549 return false;
550
551 return Continue(pPause);
552 }
553
ContinueBlend(PauseIndicatorIface * pPause)554 bool CPDF_ImageRenderer::ContinueBlend(PauseIndicatorIface* pPause) {
555 return m_pRenderStatus->GetRenderDevice()->ContinueDIBits(
556 m_DeviceHandle.get(), pPause);
557 }
558
ContinueTransform(PauseIndicatorIface * pPause)559 bool CPDF_ImageRenderer::ContinueTransform(PauseIndicatorIface* pPause) {
560 if (m_pTransformer->Continue(pPause))
561 return true;
562
563 RetainPtr<CFX_DIBitmap> pBitmap = m_pTransformer->DetachBitmap();
564 if (!pBitmap)
565 return false;
566
567 if (pBitmap->IsMaskFormat()) {
568 if (m_BitmapAlpha != 255)
569 m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha);
570 m_Result = m_pRenderStatus->GetRenderDevice()->SetBitMask(
571 pBitmap, m_pTransformer->result().left, m_pTransformer->result().top,
572 m_FillArgb);
573 } else {
574 if (m_BitmapAlpha != 255)
575 pBitmap->MultiplyAlpha(m_BitmapAlpha);
576 m_Result = m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
577 pBitmap, m_pTransformer->result().left, m_pTransformer->result().top,
578 m_BlendType);
579 }
580 return false;
581 }
582
HandleFilters()583 void CPDF_ImageRenderer::HandleFilters() {
584 absl::optional<DecoderArray> decoder_array =
585 GetDecoderArray(m_pImageObject->GetImage()->GetStream()->GetDict());
586 if (!decoder_array.has_value())
587 return;
588
589 for (const auto& decoder : decoder_array.value()) {
590 if (decoder.first == "DCTDecode" || decoder.first == "JPXDecode") {
591 m_ResampleOptions.bLossy = true;
592 return;
593 }
594 }
595 }
596
GetUnitRect() const597 absl::optional<FX_RECT> CPDF_ImageRenderer::GetUnitRect() const {
598 CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect();
599 FX_RECT image_rect = image_rect_f.GetOuterRect();
600 if (!image_rect.Valid())
601 return absl::nullopt;
602 return image_rect;
603 }
604
GetDimensionsFromUnitRect(const FX_RECT & rect,int * left,int * top,int * width,int * height) const605 bool CPDF_ImageRenderer::GetDimensionsFromUnitRect(const FX_RECT& rect,
606 int* left,
607 int* top,
608 int* width,
609 int* height) const {
610 DCHECK(rect.Valid());
611
612 int dest_width = rect.Width();
613 int dest_height = rect.Height();
614 if (IsImageValueTooBig(dest_width) || IsImageValueTooBig(dest_height))
615 return false;
616
617 if (m_ImageMatrix.a < 0)
618 dest_width = -dest_width;
619
620 if (m_ImageMatrix.d > 0)
621 dest_height = -dest_height;
622
623 int dest_left = dest_width > 0 ? rect.left : rect.right;
624 int dest_top = dest_height > 0 ? rect.top : rect.bottom;
625 if (IsImageValueTooBig(dest_left) || IsImageValueTooBig(dest_top))
626 return false;
627
628 *left = dest_left;
629 *top = dest_top;
630 *width = dest_width;
631 *height = dest_height;
632 return true;
633 }
634