1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fpdfapi/render/cpdf_imagerenderer.h"
8 
9 #include <algorithm>
10 #include <memory>
11 
12 #include "core/fpdfapi/page/cpdf_dib.h"
13 #include "core/fpdfapi/page/cpdf_docpagedata.h"
14 #include "core/fpdfapi/page/cpdf_image.h"
15 #include "core/fpdfapi/page/cpdf_imageobject.h"
16 #include "core/fpdfapi/page/cpdf_occontext.h"
17 #include "core/fpdfapi/page/cpdf_page.h"
18 #include "core/fpdfapi/page/cpdf_pageobject.h"
19 #include "core/fpdfapi/page/cpdf_shadingpattern.h"
20 #include "core/fpdfapi/page/cpdf_tilingpattern.h"
21 #include "core/fpdfapi/page/cpdf_transferfunc.h"
22 #include "core/fpdfapi/parser/cpdf_array.h"
23 #include "core/fpdfapi/parser/cpdf_dictionary.h"
24 #include "core/fpdfapi/parser/cpdf_document.h"
25 #include "core/fpdfapi/parser/cpdf_stream.h"
26 #include "core/fpdfapi/render/cpdf_pagerendercache.h"
27 #include "core/fpdfapi/render/cpdf_rendercontext.h"
28 #include "core/fpdfapi/render/cpdf_renderstatus.h"
29 #include "core/fxcrt/fx_safe_types.h"
30 #include "core/fxcrt/maybe_owned.h"
31 #include "core/fxge/cfx_defaultrenderdevice.h"
32 #include "core/fxge/cfx_pathdata.h"
33 #include "core/fxge/dib/cfx_dibbase.h"
34 #include "core/fxge/dib/cfx_dibitmap.h"
35 #include "core/fxge/dib/cfx_imagestretcher.h"
36 #include "core/fxge/dib/cfx_imagetransformer.h"
37 #include "third_party/base/ptr_util.h"
38 #include "third_party/base/stl_util.h"
39 
40 #ifdef _SKIA_SUPPORT_
41 #include "core/fxge/skia/fx_skia_device.h"
42 #endif
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 
55 }  // namespace
56 
57 CPDF_ImageRenderer::CPDF_ImageRenderer() = default;
58 
59 CPDF_ImageRenderer::~CPDF_ImageRenderer() = default;
60 
StartLoadDIBBase()61 bool CPDF_ImageRenderer::StartLoadDIBBase() {
62   if (!GetUnitRect().has_value())
63     return false;
64 
65   if (!m_Loader.Start(m_pImageObject.Get(), m_pRenderStatus.Get(), m_bStdCS))
66     return false;
67 
68   m_Mode = Mode::kDefault;
69   return true;
70 }
71 
StartRenderDIBBase()72 bool CPDF_ImageRenderer::StartRenderDIBBase() {
73   if (!m_Loader.GetBitmap())
74     return false;
75 
76   CPDF_GeneralState& state = m_pImageObject->m_GeneralState;
77   m_BitmapAlpha = FXSYS_roundf(255 * state.GetFillAlpha());
78   m_pDIBBase = m_Loader.GetBitmap();
79   if (GetRenderOptions().ColorModeIs(CPDF_RenderOptions::kAlpha) &&
80       !m_Loader.GetMask()) {
81     return StartBitmapAlpha();
82   }
83   if (state.GetTR()) {
84     if (!state.GetTransferFunc())
85       state.SetTransferFunc(m_pRenderStatus->GetTransferFunc(state.GetTR()));
86 
87     if (state.GetTransferFunc() && !state.GetTransferFunc()->GetIdentity())
88       m_pDIBBase = m_Loader.TranslateImage(state.GetTransferFunc());
89   }
90   m_FillArgb = 0;
91   m_bPatternColor = false;
92   m_pPattern = nullptr;
93   if (m_pDIBBase->IsAlphaMask()) {
94     const CPDF_Color* pColor = m_pImageObject->m_ColorState.GetFillColor();
95     if (pColor && pColor->IsPattern()) {
96       m_pPattern.Reset(pColor->GetPattern());
97       if (m_pPattern)
98         m_bPatternColor = true;
99     }
100     m_FillArgb = m_pRenderStatus->GetFillArgb(m_pImageObject.Get());
101   } else if (GetRenderOptions().ColorModeIs(CPDF_RenderOptions::kGray)) {
102     RetainPtr<CFX_DIBitmap> pClone = m_pDIBBase->Clone(nullptr);
103     if (!pClone)
104       return false;
105 
106     pClone->ConvertColorScale(0xffffff, 0);
107     m_pDIBBase = pClone;
108   }
109   m_ResampleOptions = FXDIB_ResampleOptions();
110   if (GetRenderOptions().GetOptions().bForceHalftone)
111     m_ResampleOptions.bHalftone = true;
112 
113   if (m_pRenderStatus->GetRenderDevice()->GetDeviceType() !=
114       DeviceType::kDisplay) {
115     HandleFilters();
116   }
117 
118   if (GetRenderOptions().GetOptions().bNoImageSmooth)
119     m_ResampleOptions.bNoSmoothing = true;
120   else if (m_pImageObject->GetImage()->IsInterpol())
121     m_ResampleOptions.bInterpolateBilinear = true;
122 
123   if (m_Loader.GetMask())
124     return DrawMaskedImage();
125 
126   if (m_bPatternColor)
127     return DrawPatternImage();
128 
129   if (m_BitmapAlpha != 255 || !state.HasRef() || !state.GetFillOP() ||
130       state.GetOPMode() != 0 || state.GetBlendType() != BlendMode::kNormal ||
131       state.GetStrokeAlpha() != 1.0f || state.GetFillAlpha() != 1.0f) {
132     return StartDIBBase();
133   }
134   CPDF_Document* pDocument = nullptr;
135   CPDF_Page* pPage = nullptr;
136   if (auto* pPageCache = m_pRenderStatus->GetContext()->GetPageCache()) {
137     pPage = pPageCache->GetPage();
138     pDocument = pPage->GetDocument();
139   } else {
140     pDocument = m_pImageObject->GetImage()->GetDocument();
141   }
142   CPDF_Dictionary* pPageResources =
143       pPage ? pPage->m_pPageResources.Get() : nullptr;
144   CPDF_Object* pCSObj =
145       m_pImageObject->GetImage()->GetStream()->GetDict()->GetDirectObjectFor(
146           "ColorSpace");
147   auto* pData = CPDF_DocPageData::FromDocument(pDocument);
148   RetainPtr<CPDF_ColorSpace> pColorSpace =
149       pData->GetColorSpace(pCSObj, pPageResources);
150   if (pColorSpace) {
151     int format = pColorSpace->GetFamily();
152     if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION ||
153         format == PDFCS_DEVICEN) {
154       m_BlendType = BlendMode::kDarken;
155     }
156   }
157   return StartDIBBase();
158 }
159 
Start(CPDF_RenderStatus * pStatus,CPDF_ImageObject * pImageObject,const CFX_Matrix & mtObj2Device,bool bStdCS,BlendMode blendType)160 bool CPDF_ImageRenderer::Start(CPDF_RenderStatus* pStatus,
161                                CPDF_ImageObject* pImageObject,
162                                const CFX_Matrix& mtObj2Device,
163                                bool bStdCS,
164                                BlendMode blendType) {
165   ASSERT(pImageObject);
166   m_pRenderStatus = pStatus;
167   m_bStdCS = bStdCS;
168   m_pImageObject = pImageObject;
169   m_BlendType = blendType;
170   m_mtObj2Device = mtObj2Device;
171   const CPDF_Dictionary* pOC = m_pImageObject->GetImage()->GetOC();
172   if (pOC && GetRenderOptions().GetOCContext() &&
173       !GetRenderOptions().GetOCContext()->CheckOCGVisible(pOC)) {
174     return false;
175   }
176   m_ImageMatrix = m_pImageObject->matrix() * mtObj2Device;
177   if (StartLoadDIBBase())
178     return true;
179   return StartRenderDIBBase();
180 }
181 
Start(CPDF_RenderStatus * pStatus,const RetainPtr<CFX_DIBBase> & pDIBBase,FX_ARGB bitmap_argb,int bitmap_alpha,const CFX_Matrix & mtImage2Device,const FXDIB_ResampleOptions & options,bool bStdCS,BlendMode blendType)182 bool CPDF_ImageRenderer::Start(CPDF_RenderStatus* pStatus,
183                                const RetainPtr<CFX_DIBBase>& pDIBBase,
184                                FX_ARGB bitmap_argb,
185                                int bitmap_alpha,
186                                const CFX_Matrix& mtImage2Device,
187                                const FXDIB_ResampleOptions& options,
188                                bool bStdCS,
189                                BlendMode blendType) {
190   m_pRenderStatus = pStatus;
191   m_pDIBBase = pDIBBase;
192   m_FillArgb = bitmap_argb;
193   m_BitmapAlpha = bitmap_alpha;
194   m_ImageMatrix = mtImage2Device;
195   m_ResampleOptions = options;
196   m_bStdCS = bStdCS;
197   m_BlendType = blendType;
198   return StartDIBBase();
199 }
200 
NotDrawing() const201 bool CPDF_ImageRenderer::NotDrawing() const {
202   return m_pRenderStatus->IsPrint() &&
203          !(m_pRenderStatus->GetRenderDevice()->GetRenderCaps() &
204            FXRC_BLEND_MODE);
205 }
206 
GetDrawRect() const207 FX_RECT CPDF_ImageRenderer::GetDrawRect() const {
208   FX_RECT rect = m_ImageMatrix.GetUnitRect().GetOuterRect();
209   rect.Intersect(m_pRenderStatus->GetRenderDevice()->GetClipBox());
210   return rect;
211 }
212 
GetDrawMatrix(const FX_RECT & rect) const213 CFX_Matrix CPDF_ImageRenderer::GetDrawMatrix(const FX_RECT& rect) const {
214   CFX_Matrix new_matrix = m_ImageMatrix;
215   new_matrix.Translate(-rect.left, -rect.top);
216   return new_matrix;
217 }
218 
CalculateDrawImage(CFX_DefaultRenderDevice * pBitmapDevice1,CFX_DefaultRenderDevice * pBitmapDevice2,const RetainPtr<CFX_DIBBase> & pDIBBase,const CFX_Matrix & mtNewMatrix,const FX_RECT & rect) const219 void CPDF_ImageRenderer::CalculateDrawImage(
220     CFX_DefaultRenderDevice* pBitmapDevice1,
221     CFX_DefaultRenderDevice* pBitmapDevice2,
222     const RetainPtr<CFX_DIBBase>& pDIBBase,
223     const CFX_Matrix& mtNewMatrix,
224     const FX_RECT& rect) const {
225   CPDF_RenderStatus bitmap_render(m_pRenderStatus->GetContext(),
226                                   pBitmapDevice2);
227   bitmap_render.SetDropObjects(m_pRenderStatus->GetDropObjects());
228   bitmap_render.SetStdCS(true);
229   bitmap_render.Initialize(nullptr, nullptr);
230 
231   CPDF_ImageRenderer image_render;
232   if (image_render.Start(&bitmap_render, pDIBBase, 0xffffffff, 255, mtNewMatrix,
233                          m_ResampleOptions, true, BlendMode::kNormal)) {
234     image_render.Continue(nullptr);
235   }
236   if (m_Loader.MatteColor() == 0xffffffff)
237     return;
238   int matte_r = FXARGB_R(m_Loader.MatteColor());
239   int matte_g = FXARGB_G(m_Loader.MatteColor());
240   int matte_b = FXARGB_B(m_Loader.MatteColor());
241   for (int row = 0; row < rect.Height(); row++) {
242     uint8_t* dest_scan = pBitmapDevice1->GetBitmap()->GetWritableScanline(row);
243     const uint8_t* mask_scan = pBitmapDevice2->GetBitmap()->GetScanline(row);
244     for (int col = 0; col < rect.Width(); col++) {
245       int alpha = *mask_scan++;
246       if (!alpha) {
247         dest_scan += 4;
248         continue;
249       }
250       int orig = (*dest_scan - matte_b) * 255 / alpha + matte_b;
251       *dest_scan++ = pdfium::clamp(orig, 0, 255);
252       orig = (*dest_scan - matte_g) * 255 / alpha + matte_g;
253       *dest_scan++ = pdfium::clamp(orig, 0, 255);
254       orig = (*dest_scan - matte_r) * 255 / alpha + matte_r;
255       *dest_scan++ = pdfium::clamp(orig, 0, 255);
256       dest_scan++;
257     }
258   }
259 }
260 
GetRenderOptions() const261 const CPDF_RenderOptions& CPDF_ImageRenderer::GetRenderOptions() const {
262   return m_pRenderStatus->GetRenderOptions();
263 }
264 
DrawPatternImage()265 bool CPDF_ImageRenderer::DrawPatternImage() {
266   if (NotDrawing()) {
267     m_Result = false;
268     return false;
269   }
270 
271   FX_RECT rect = GetDrawRect();
272   if (rect.IsEmpty())
273     return false;
274 
275   CFX_Matrix new_matrix = GetDrawMatrix(rect);
276   CFX_DefaultRenderDevice bitmap_device1;
277   if (!bitmap_device1.Create(rect.Width(), rect.Height(), FXDIB_Rgb32, nullptr))
278     return true;
279 
280   bitmap_device1.GetBitmap()->Clear(0xffffff);
281 
282   CPDF_RenderStatus bitmap_render(m_pRenderStatus->GetContext(),
283                                   &bitmap_device1);
284   bitmap_render.SetOptions(GetRenderOptions());
285   bitmap_render.SetDropObjects(m_pRenderStatus->GetDropObjects());
286   bitmap_render.SetStdCS(true);
287   bitmap_render.Initialize(nullptr, nullptr);
288 
289   CFX_Matrix patternDevice = m_mtObj2Device;
290   patternDevice.Translate(static_cast<float>(-rect.left),
291                           static_cast<float>(-rect.top));
292   if (CPDF_TilingPattern* pTilingPattern = m_pPattern->AsTilingPattern()) {
293     bitmap_render.DrawTilingPattern(pTilingPattern, m_pImageObject.Get(),
294                                     patternDevice, false);
295   } else if (CPDF_ShadingPattern* pShadingPattern =
296                  m_pPattern->AsShadingPattern()) {
297     bitmap_render.DrawShadingPattern(pShadingPattern, m_pImageObject.Get(),
298                                      patternDevice, false);
299   }
300 
301   CFX_DefaultRenderDevice bitmap_device2;
302   if (!bitmap_device2.Create(rect.Width(), rect.Height(), FXDIB_8bppRgb,
303                              nullptr)) {
304     return true;
305   }
306   bitmap_device2.GetBitmap()->Clear(0);
307   CalculateDrawImage(&bitmap_device1, &bitmap_device2, m_pDIBBase, new_matrix,
308                      rect);
309   bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_8bppMask);
310   bitmap_device1.GetBitmap()->MultiplyAlpha(bitmap_device2.GetBitmap());
311   bitmap_device1.GetBitmap()->MultiplyAlpha(255);
312   m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
313       bitmap_device1.GetBitmap(), rect.left, rect.top, m_BlendType);
314   return false;
315 }
316 
DrawMaskedImage()317 bool CPDF_ImageRenderer::DrawMaskedImage() {
318   if (NotDrawing()) {
319     m_Result = false;
320     return false;
321   }
322 
323   FX_RECT rect = GetDrawRect();
324   if (rect.IsEmpty())
325     return false;
326 
327   CFX_Matrix new_matrix = GetDrawMatrix(rect);
328   CFX_DefaultRenderDevice bitmap_device1;
329   if (!bitmap_device1.Create(rect.Width(), rect.Height(), FXDIB_Rgb32, nullptr))
330     return true;
331 
332 #if defined _SKIA_SUPPORT_
333   bitmap_device1.Clear(0xffffff);
334 #else
335   bitmap_device1.GetBitmap()->Clear(0xffffff);
336 #endif
337   CPDF_RenderStatus bitmap_render(m_pRenderStatus->GetContext(),
338                                   &bitmap_device1);
339   bitmap_render.SetDropObjects(m_pRenderStatus->GetDropObjects());
340   bitmap_render.SetStdCS(true);
341   bitmap_render.Initialize(nullptr, nullptr);
342   CPDF_ImageRenderer image_render;
343   if (image_render.Start(&bitmap_render, m_pDIBBase, 0, 255, new_matrix,
344                          m_ResampleOptions, true, BlendMode::kNormal)) {
345     image_render.Continue(nullptr);
346   }
347   CFX_DefaultRenderDevice bitmap_device2;
348   if (!bitmap_device2.Create(rect.Width(), rect.Height(), FXDIB_8bppRgb,
349                              nullptr))
350     return true;
351 
352 #if defined _SKIA_SUPPORT_
353   bitmap_device2.Clear(0);
354 #else
355   bitmap_device2.GetBitmap()->Clear(0);
356 #endif
357   CalculateDrawImage(&bitmap_device1, &bitmap_device2, m_Loader.GetMask(),
358                      new_matrix, rect);
359 #ifdef _SKIA_SUPPORT_
360   m_pRenderStatus->GetRenderDevice()->SetBitsWithMask(
361       bitmap_device1.GetBitmap(), bitmap_device2.GetBitmap(), rect.left,
362       rect.top, m_BitmapAlpha, m_BlendType);
363 #else
364   bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_8bppMask);
365   bitmap_device1.GetBitmap()->MultiplyAlpha(bitmap_device2.GetBitmap());
366   if (m_BitmapAlpha < 255)
367     bitmap_device1.GetBitmap()->MultiplyAlpha(m_BitmapAlpha);
368   m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
369       bitmap_device1.GetBitmap(), rect.left, rect.top, m_BlendType);
370 #endif  //  _SKIA_SUPPORT_
371   return false;
372 }
373 
StartDIBBase()374 bool CPDF_ImageRenderer::StartDIBBase() {
375   if (m_pDIBBase->GetBPP() > 1) {
376     FX_SAFE_SIZE_T image_size = m_pDIBBase->GetBPP();
377     image_size /= 8;
378     image_size *= m_pDIBBase->GetWidth();
379     image_size *= m_pDIBBase->GetHeight();
380     if (!image_size.IsValid())
381       return false;
382 
383     if (image_size.ValueOrDie() > kHugeImageSize &&
384         !m_ResampleOptions.bHalftone) {
385       m_ResampleOptions.bInterpolateBilinear = true;
386     }
387   }
388 #ifdef _SKIA_SUPPORT_
389   RetainPtr<CFX_DIBitmap> premultiplied = m_pDIBBase->Clone(nullptr);
390   if (m_pDIBBase->HasAlpha())
391     CFX_SkiaDeviceDriver::PreMultiply(premultiplied);
392   if (m_pRenderStatus->GetRenderDevice()->StartDIBitsWithBlend(
393           premultiplied, m_BitmapAlpha, m_FillArgb, m_ImageMatrix,
394           m_ResampleOptions, &m_DeviceHandle, m_BlendType)) {
395     if (m_DeviceHandle) {
396       m_Mode = Mode::kBlend;
397       return true;
398     }
399     return false;
400   }
401 #else
402   if (m_pRenderStatus->GetRenderDevice()->StartDIBitsWithBlend(
403           m_pDIBBase, m_BitmapAlpha, m_FillArgb, m_ImageMatrix,
404           m_ResampleOptions, &m_DeviceHandle, m_BlendType)) {
405     if (m_DeviceHandle) {
406       m_Mode = Mode::kBlend;
407       return true;
408     }
409     return false;
410   }
411 #endif
412 
413   if ((fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) ||
414       (fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0)) {
415     if (NotDrawing()) {
416       m_Result = false;
417       return false;
418     }
419 
420     Optional<FX_RECT> image_rect = GetUnitRect();
421     if (!image_rect.has_value())
422       return false;
423 
424     FX_RECT clip_box = m_pRenderStatus->GetRenderDevice()->GetClipBox();
425     clip_box.Intersect(image_rect.value());
426     m_Mode = Mode::kTransform;
427     m_pTransformer = pdfium::MakeUnique<CFX_ImageTransformer>(
428         m_pDIBBase, m_ImageMatrix, m_ResampleOptions, &clip_box);
429     return true;
430   }
431 
432   Optional<FX_RECT> image_rect = GetUnitRect();
433   if (!image_rect.has_value())
434     return false;
435 
436   int dest_left;
437   int dest_top;
438   int dest_width;
439   int dest_height;
440   if (!GetDimensionsFromUnitRect(image_rect.value(), &dest_left, &dest_top,
441                                  &dest_width, &dest_height)) {
442     return false;
443   }
444 
445   if (m_pDIBBase->IsOpaqueImage() && m_BitmapAlpha == 255) {
446     if (m_pRenderStatus->GetRenderDevice()->StretchDIBitsWithFlagsAndBlend(
447             m_pDIBBase, dest_left, dest_top, dest_width, dest_height,
448             m_ResampleOptions, m_BlendType)) {
449       return false;
450     }
451   }
452   if (m_pDIBBase->IsAlphaMask()) {
453     if (m_BitmapAlpha != 255)
454       m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha);
455     if (m_pRenderStatus->GetRenderDevice()->StretchBitMaskWithFlags(
456             m_pDIBBase, dest_left, dest_top, dest_width, dest_height,
457             m_FillArgb, m_ResampleOptions)) {
458       return false;
459     }
460   }
461   if (NotDrawing()) {
462     m_Result = false;
463     return true;
464   }
465 
466   FX_RECT clip_box = m_pRenderStatus->GetRenderDevice()->GetClipBox();
467   FX_RECT dest_rect = clip_box;
468   dest_rect.Intersect(image_rect.value());
469   FX_RECT dest_clip(
470       dest_rect.left - image_rect->left, dest_rect.top - image_rect->top,
471       dest_rect.right - image_rect->left, dest_rect.bottom - image_rect->top);
472   RetainPtr<CFX_DIBitmap> pStretched = m_pDIBBase->StretchTo(
473       dest_width, dest_height, m_ResampleOptions, &dest_clip);
474   if (pStretched) {
475     m_pRenderStatus->CompositeDIBitmap(pStretched, dest_rect.left,
476                                        dest_rect.top, m_FillArgb, m_BitmapAlpha,
477                                        m_BlendType, CPDF_Transparency());
478   }
479   return false;
480 }
481 
StartBitmapAlpha()482 bool CPDF_ImageRenderer::StartBitmapAlpha() {
483   if (m_pDIBBase->IsOpaqueImage()) {
484     CFX_PathData path;
485     path.AppendRect(0, 0, 1, 1);
486     path.Transform(m_ImageMatrix);
487     uint32_t fill_color =
488         ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha);
489     m_pRenderStatus->GetRenderDevice()->DrawPath(&path, nullptr, nullptr,
490                                                  fill_color, 0, FXFILL_WINDING);
491     return false;
492   }
493   RetainPtr<CFX_DIBBase> pAlphaMask;
494   if (m_pDIBBase->IsAlphaMask())
495     pAlphaMask = m_pDIBBase;
496   else
497     pAlphaMask = m_pDIBBase->CloneAlphaMask();
498 
499   if (fabs(m_ImageMatrix.b) >= 0.5f || fabs(m_ImageMatrix.c) >= 0.5f) {
500     int left;
501     int top;
502     RetainPtr<CFX_DIBitmap> pTransformed =
503         pAlphaMask->TransformTo(m_ImageMatrix, &left, &top);
504     if (!pTransformed)
505       return true;
506 
507     m_pRenderStatus->GetRenderDevice()->SetBitMask(
508         pTransformed, left, top,
509         ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha));
510     return false;
511   }
512 
513   Optional<FX_RECT> image_rect = GetUnitRect();
514   if (!image_rect.has_value())
515     return false;
516 
517   int left;
518   int top;
519   int dest_width;
520   int dest_height;
521   if (!GetDimensionsFromUnitRect(image_rect.value(), &left, &top, &dest_width,
522                                  &dest_height)) {
523     return false;
524   }
525 
526   m_pRenderStatus->GetRenderDevice()->StretchBitMask(
527       pAlphaMask, left, top, dest_width, dest_height,
528       ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha));
529   return false;
530 }
531 
Continue(PauseIndicatorIface * pPause)532 bool CPDF_ImageRenderer::Continue(PauseIndicatorIface* pPause) {
533   switch (m_Mode) {
534     case Mode::kNone:
535       return false;
536     case Mode::kDefault:
537       return ContinueDefault(pPause);
538     case Mode::kBlend:
539       return ContinueBlend(pPause);
540     case Mode::kTransform:
541       return ContinueTransform(pPause);
542   }
543   NOTREACHED();
544   return false;
545 }
546 
ContinueDefault(PauseIndicatorIface * pPause)547 bool CPDF_ImageRenderer::ContinueDefault(PauseIndicatorIface* pPause) {
548   if (m_Loader.Continue(pPause, m_pRenderStatus.Get()))
549     return true;
550 
551   if (!StartRenderDIBBase())
552     return false;
553 
554   if (m_Mode == Mode::kDefault)
555     return false;
556 
557   return Continue(pPause);
558 }
559 
ContinueBlend(PauseIndicatorIface * pPause)560 bool CPDF_ImageRenderer::ContinueBlend(PauseIndicatorIface* pPause) {
561   return m_pRenderStatus->GetRenderDevice()->ContinueDIBits(
562       m_DeviceHandle.get(), pPause);
563 }
564 
ContinueTransform(PauseIndicatorIface * pPause)565 bool CPDF_ImageRenderer::ContinueTransform(PauseIndicatorIface* pPause) {
566   if (m_pTransformer->Continue(pPause))
567     return true;
568 
569   RetainPtr<CFX_DIBitmap> pBitmap = m_pTransformer->DetachBitmap();
570   if (!pBitmap)
571     return false;
572 
573   if (pBitmap->IsAlphaMask()) {
574     if (m_BitmapAlpha != 255)
575       m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha);
576     m_Result = m_pRenderStatus->GetRenderDevice()->SetBitMask(
577         pBitmap, m_pTransformer->result().left, m_pTransformer->result().top,
578         m_FillArgb);
579   } else {
580     if (m_BitmapAlpha != 255)
581       pBitmap->MultiplyAlpha(m_BitmapAlpha);
582     m_Result = m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
583         pBitmap, m_pTransformer->result().left, m_pTransformer->result().top,
584         m_BlendType);
585   }
586   return false;
587 }
588 
HandleFilters()589 void CPDF_ImageRenderer::HandleFilters() {
590   CPDF_Object* pFilters =
591       m_pImageObject->GetImage()->GetStream()->GetDict()->GetDirectObjectFor(
592           "Filter");
593   if (!pFilters)
594     return;
595 
596   if (pFilters->IsName()) {
597     ByteString bsDecodeType = pFilters->GetString();
598     if (bsDecodeType == "DCTDecode" || bsDecodeType == "JPXDecode")
599       m_ResampleOptions.bLossy = true;
600     return;
601   }
602 
603   CPDF_Array* pArray = pFilters->AsArray();
604   if (!pArray)
605     return;
606 
607   for (size_t i = 0; i < pArray->size(); i++) {
608     ByteString bsDecodeType = pArray->GetStringAt(i);
609     if (bsDecodeType == "DCTDecode" || bsDecodeType == "JPXDecode") {
610       m_ResampleOptions.bLossy = true;
611       break;
612     }
613   }
614 }
615 
GetUnitRect() const616 Optional<FX_RECT> CPDF_ImageRenderer::GetUnitRect() const {
617   CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect();
618   FX_RECT image_rect = image_rect_f.GetOuterRect();
619   if (!image_rect.Valid())
620     return {};
621   return image_rect;
622 }
623 
GetDimensionsFromUnitRect(const FX_RECT & rect,int * left,int * top,int * width,int * height) const624 bool CPDF_ImageRenderer::GetDimensionsFromUnitRect(const FX_RECT& rect,
625                                                    int* left,
626                                                    int* top,
627                                                    int* width,
628                                                    int* height) const {
629   ASSERT(rect.Valid());
630 
631   int dest_width = rect.Width();
632   int dest_height = rect.Height();
633   if (IsImageValueTooBig(dest_width) || IsImageValueTooBig(dest_height))
634     return false;
635 
636   if (m_ImageMatrix.a < 0)
637     dest_width = -dest_width;
638 
639   if (m_ImageMatrix.d > 0)
640     dest_height = -dest_height;
641 
642   int dest_left = dest_width > 0 ? rect.left : rect.right;
643   int dest_top = dest_height > 0 ? rect.top : rect.bottom;
644   if (IsImageValueTooBig(dest_left) || IsImageValueTooBig(dest_top))
645     return false;
646 
647   *left = dest_left;
648   *top = dest_top;
649   *width = dest_width;
650   *height = dest_height;
651   return true;
652 }
653