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