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