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