Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cpdf_imagerenderer.cpp
Go to the documentation of this file.
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
50namespace {
51
52bool 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
66
68
69bool 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
86bool 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();
173 m_BlendType = BlendMode::kDarken;
174 }
175 }
176 return StartDIBBase();
177}
178
179bool 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
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)
214bool 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
225void 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
241FX_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
247CFX_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
253RetainPtr<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(),
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
308const CPDF_RenderOptions& CPDF_ImageRenderer::GetRenderOptions() const {
309 return m_pRenderStatus->GetRenderOptions();
310}
311
312bool 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
360bool 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
409bool 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 }
424 m_pRenderStatus->GetRenderDevice()->StartDIBitsWithBlend(
425 m_pDIBBase, m_Alpha, m_FillArgb, m_ImageMatrix, m_ResampleOptions,
426 m_BlendType);
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
443 m_Result = false;
444 return false;
445}
446
447#if BUILDFLAG(IS_WIN)
448bool 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
521bool 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
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
587bool 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
600bool CPDF_ImageRenderer::ContinueBlend(PauseIndicatorIface* pPause) {
601 return m_pRenderStatus->GetRenderDevice()->ContinueDIBits(
602 m_DeviceHandle.get(), pPause);
603}
604
605#if BUILDFLAG(IS_WIN)
606bool 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
632std::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
640bool 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}
#define DCHECK
Definition check.h:33
#define CHECK_EQ(x, y)
Definition check_op.h:10
bool Attach(RetainPtr< CFX_DIBitmap > pBitmap)
bool Create(int width, int height, FXDIB_Format format)
FX_RECT GetOuterRect() const
CFX_Matrix & operator=(const CFX_Matrix &other)=default
void Translate(int32_t x, int32_t y)
CFX_FloatRect GetUnitRect() const
void Transform(const CFX_Matrix &matrix)
Definition cfx_path.cpp:393
void AppendRect(float left, float bottom, float right, float top)
Definition cfx_path.cpp:310
bool IsPattern() const
std::map< ByteString, RetainPtr< CPDF_Object >, std::less<> > DictMap
static CPDF_DocPageData * FromDocument(const CPDF_Document *pDoc)
float GetStrokeAlpha() const
BlendMode GetBlendType() const
CPDF_ImageRenderer(CPDF_RenderStatus *pStatus)
bool Start(RetainPtr< CFX_DIBBase > pDIBBase, FX_ARGB bitmap_argb, const CFX_Matrix &mtImage2Device, const FXDIB_ResampleOptions &options, bool bStdCS)
bool Start(CPDF_ImageObject *pImageObject, const CFX_Matrix &mtObj2Device, bool bStdCS)
bool Continue(PauseIndicatorIface *pPause)
CPDF_Document * GetDocument() const override
Definition cpdf_page.cpp:51
const Options & GetOptions() const
bool CheckOCGDictVisible(const CPDF_Dictionary *pOC) const
bool ColorModeIs(Type mode) const
void SetOptions(const CPDF_RenderOptions &options)
void SetStdCS(bool bStdCS)
void Initialize(const CPDF_RenderStatus *pParentStatus, const CPDF_GraphicStates *pInitialStates)
uint32_t FX_ARGB
Definition fx_dib.h:36
BlendMode
Definition fx_dib.h:119
@ kNormal
Definition fx_dib.h:120
@ kDarken
Definition fx_dib.h:124
#define FXARGB_B(argb)
Definition fx_dib.h:199
#define FXARGB_G(argb)
Definition fx_dib.h:198
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
Definition fx_dib.h:188
#define FXARGB_R(argb)
Definition fx_dib.h:197
FXDIB_Format
Definition fx_dib.h:21
pdfium::CheckedNumeric< int32_t > FX_SAFE_INT32
int FXSYS_roundf(float f)
#define CHECK(cvref)
int Height() const
int32_t bottom
bool Valid() const
int32_t right
int Width() const
int32_t top
int32_t left
bool IsEmpty() const