• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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