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