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_renderstatus.h"
8
9 #include <stdint.h>
10
11 #include <algorithm>
12 #include <memory>
13 #include <numeric>
14 #include <set>
15 #include <utility>
16 #include <vector>
17
18 #include "build/build_config.h"
19 #include "constants/transparency.h"
20 #include "core/fpdfapi/font/cpdf_font.h"
21 #include "core/fpdfapi/font/cpdf_type3char.h"
22 #include "core/fpdfapi/font/cpdf_type3font.h"
23 #include "core/fpdfapi/page/cpdf_docpagedata.h"
24 #include "core/fpdfapi/page/cpdf_form.h"
25 #include "core/fpdfapi/page/cpdf_formobject.h"
26 #include "core/fpdfapi/page/cpdf_function.h"
27 #include "core/fpdfapi/page/cpdf_graphicstates.h"
28 #include "core/fpdfapi/page/cpdf_image.h"
29 #include "core/fpdfapi/page/cpdf_imageobject.h"
30 #include "core/fpdfapi/page/cpdf_occontext.h"
31 #include "core/fpdfapi/page/cpdf_page.h"
32 #include "core/fpdfapi/page/cpdf_pageimagecache.h"
33 #include "core/fpdfapi/page/cpdf_pageobject.h"
34 #include "core/fpdfapi/page/cpdf_pathobject.h"
35 #include "core/fpdfapi/page/cpdf_shadingobject.h"
36 #include "core/fpdfapi/page/cpdf_shadingpattern.h"
37 #include "core/fpdfapi/page/cpdf_textobject.h"
38 #include "core/fpdfapi/page/cpdf_tilingpattern.h"
39 #include "core/fpdfapi/page/cpdf_transferfunc.h"
40 #include "core/fpdfapi/parser/cpdf_array.h"
41 #include "core/fpdfapi/parser/cpdf_document.h"
42 #include "core/fpdfapi/parser/cpdf_stream.h"
43 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
44 #include "core/fpdfapi/render/charposlist.h"
45 #include "core/fpdfapi/render/cpdf_docrenderdata.h"
46 #include "core/fpdfapi/render/cpdf_imagerenderer.h"
47 #include "core/fpdfapi/render/cpdf_rendercontext.h"
48 #include "core/fpdfapi/render/cpdf_renderoptions.h"
49 #include "core/fpdfapi/render/cpdf_rendershading.h"
50 #include "core/fpdfapi/render/cpdf_rendertiling.h"
51 #include "core/fpdfapi/render/cpdf_scaledrenderbuffer.h"
52 #include "core/fpdfapi/render/cpdf_textrenderer.h"
53 #include "core/fpdfapi/render/cpdf_type3cache.h"
54 #include "core/fxcrt/autorestorer.h"
55 #include "core/fxcrt/data_vector.h"
56 #include "core/fxcrt/fx_2d_size.h"
57 #include "core/fxcrt/fx_safe_types.h"
58 #include "core/fxcrt/fx_system.h"
59 #include "core/fxcrt/span_util.h"
60 #include "core/fxcrt/unowned_ptr.h"
61 #include "core/fxge/cfx_defaultrenderdevice.h"
62 #include "core/fxge/cfx_fillrenderoptions.h"
63 #include "core/fxge/cfx_glyphbitmap.h"
64 #include "core/fxge/cfx_path.h"
65 #include "core/fxge/dib/cfx_dibitmap.h"
66 #include "core/fxge/fx_font.h"
67 #include "core/fxge/renderdevicedriver_iface.h"
68 #include "core/fxge/text_char_pos.h"
69 #include "core/fxge/text_glyph_pos.h"
70 #include "third_party/base/check.h"
71 #include "third_party/base/containers/contains.h"
72 #include "third_party/base/containers/span.h"
73 #include "third_party/base/notreached.h"
74
75 namespace {
76
77 constexpr int kRenderMaxRecursionDepth = 64;
78 int g_CurrentRecursionDepth = 0;
79
GetFillOptionsForDrawPathWithBlend(const CPDF_RenderOptions::Options & options,const CPDF_PathObject * path_obj,CFX_FillRenderOptions::FillType fill_type,bool is_stroke,bool is_type3_char)80 CFX_FillRenderOptions GetFillOptionsForDrawPathWithBlend(
81 const CPDF_RenderOptions::Options& options,
82 const CPDF_PathObject* path_obj,
83 CFX_FillRenderOptions::FillType fill_type,
84 bool is_stroke,
85 bool is_type3_char) {
86 CFX_FillRenderOptions fill_options(fill_type);
87 if (fill_type != CFX_FillRenderOptions::FillType::kNoFill && options.bRectAA)
88 fill_options.rect_aa = true;
89 if (options.bNoPathSmooth)
90 fill_options.aliased_path = true;
91 if (path_obj->m_GeneralState.GetStrokeAdjust())
92 fill_options.adjust_stroke = true;
93 if (is_stroke)
94 fill_options.stroke = true;
95 if (is_type3_char)
96 fill_options.text_mode = true;
97
98 return fill_options;
99 }
100
GetFillOptionsForDrawTextPath(const CPDF_RenderOptions::Options & options,const CPDF_TextObject * text_obj,bool is_stroke,bool is_fill)101 CFX_FillRenderOptions GetFillOptionsForDrawTextPath(
102 const CPDF_RenderOptions::Options& options,
103 const CPDF_TextObject* text_obj,
104 bool is_stroke,
105 bool is_fill) {
106 CFX_FillRenderOptions fill_options;
107 if (is_stroke && is_fill) {
108 fill_options.stroke = true;
109 fill_options.stroke_text_mode = true;
110 }
111 if (text_obj->m_GeneralState.GetStrokeAdjust())
112 fill_options.adjust_stroke = true;
113 if (options.bNoTextSmooth)
114 fill_options.aliased_path = true;
115
116 return fill_options;
117 }
118
GetFormatForLuminosity(bool is_luminosity)119 FXDIB_Format GetFormatForLuminosity(bool is_luminosity) {
120 if (!is_luminosity)
121 return FXDIB_Format::k8bppMask;
122 #if BUILDFLAG(IS_APPLE)
123 return FXDIB_Format::kRgb32;
124 #else
125 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
126 return FXDIB_Format::kRgb32;
127 return FXDIB_Format::kRgb;
128 #endif
129 }
130
IsAvailableMatrix(const CFX_Matrix & matrix)131 bool IsAvailableMatrix(const CFX_Matrix& matrix) {
132 if (matrix.a == 0 || matrix.d == 0)
133 return matrix.b != 0 && matrix.c != 0;
134
135 if (matrix.b == 0 || matrix.c == 0)
136 return matrix.a != 0 && matrix.d != 0;
137
138 return true;
139 }
140
MissingFillColor(const CPDF_ColorState * pColorState)141 bool MissingFillColor(const CPDF_ColorState* pColorState) {
142 return !pColorState->HasRef() || pColorState->GetFillColor()->IsNull();
143 }
144
MissingStrokeColor(const CPDF_ColorState * pColorState)145 bool MissingStrokeColor(const CPDF_ColorState* pColorState) {
146 return !pColorState->HasRef() || pColorState->GetStrokeColor()->IsNull();
147 }
148
Type3CharMissingFillColor(const CPDF_Type3Char * pChar,const CPDF_ColorState * pColorState)149 bool Type3CharMissingFillColor(const CPDF_Type3Char* pChar,
150 const CPDF_ColorState* pColorState) {
151 return pChar && (!pChar->colored() || MissingFillColor(pColorState));
152 }
153
Type3CharMissingStrokeColor(const CPDF_Type3Char * pChar,const CPDF_ColorState * pColorState)154 bool Type3CharMissingStrokeColor(const CPDF_Type3Char* pChar,
155 const CPDF_ColorState* pColorState) {
156 return pChar && (!pChar->colored() || MissingStrokeColor(pColorState));
157 }
158
159 } // namespace
160
CPDF_RenderStatus(CPDF_RenderContext * pContext,CFX_RenderDevice * pDevice)161 CPDF_RenderStatus::CPDF_RenderStatus(CPDF_RenderContext* pContext,
162 CFX_RenderDevice* pDevice)
163 : m_pContext(pContext), m_pDevice(pDevice) {}
164
165 CPDF_RenderStatus::~CPDF_RenderStatus() = default;
166
Initialize(const CPDF_RenderStatus * pParentStatus,const CPDF_GraphicStates * pInitialStates)167 void CPDF_RenderStatus::Initialize(const CPDF_RenderStatus* pParentStatus,
168 const CPDF_GraphicStates* pInitialStates) {
169 m_bPrint = m_pDevice->GetDeviceType() != DeviceType::kDisplay;
170 m_pPageResource.Reset(m_pContext->GetPageResources());
171 if (pInitialStates && !m_pType3Char) {
172 m_InitialStates.CopyStates(*pInitialStates);
173 if (pParentStatus) {
174 if (!m_InitialStates.m_ColorState.HasFillColor()) {
175 m_InitialStates.m_ColorState.SetFillColorRef(
176 pParentStatus->m_InitialStates.m_ColorState.GetFillColorRef());
177 *m_InitialStates.m_ColorState.GetMutableFillColor() =
178 *pParentStatus->m_InitialStates.m_ColorState.GetFillColor();
179 }
180 if (!m_InitialStates.m_ColorState.HasStrokeColor()) {
181 m_InitialStates.m_ColorState.SetStrokeColorRef(
182 pParentStatus->m_InitialStates.m_ColorState.GetFillColorRef());
183 *m_InitialStates.m_ColorState.GetMutableStrokeColor() =
184 *pParentStatus->m_InitialStates.m_ColorState.GetStrokeColor();
185 }
186 }
187 } else {
188 m_InitialStates.DefaultStates();
189 }
190 }
191
RenderObjectList(const CPDF_PageObjectHolder * pObjectHolder,const CFX_Matrix & mtObj2Device)192 void CPDF_RenderStatus::RenderObjectList(
193 const CPDF_PageObjectHolder* pObjectHolder,
194 const CFX_Matrix& mtObj2Device) {
195 CFX_FloatRect clip_rect = mtObj2Device.GetInverse().TransformRect(
196 CFX_FloatRect(m_pDevice->GetClipBox()));
197 for (const auto& pCurObj : *pObjectHolder) {
198 if (pCurObj.get() == m_pStopObj) {
199 m_bStopped = true;
200 return;
201 }
202 if (!pCurObj)
203 continue;
204
205 if (pCurObj->GetRect().left > clip_rect.right ||
206 pCurObj->GetRect().right < clip_rect.left ||
207 pCurObj->GetRect().bottom > clip_rect.top ||
208 pCurObj->GetRect().top < clip_rect.bottom) {
209 continue;
210 }
211 RenderSingleObject(pCurObj.get(), mtObj2Device);
212 if (m_bStopped)
213 return;
214 }
215 }
216
RenderSingleObject(CPDF_PageObject * pObj,const CFX_Matrix & mtObj2Device)217 void CPDF_RenderStatus::RenderSingleObject(CPDF_PageObject* pObj,
218 const CFX_Matrix& mtObj2Device) {
219 AutoRestorer<int> restorer(&g_CurrentRecursionDepth);
220 if (++g_CurrentRecursionDepth > kRenderMaxRecursionDepth) {
221 return;
222 }
223 m_pCurObj = pObj;
224 if (!m_Options.CheckPageObjectVisible(pObj)) {
225 return;
226 }
227 ProcessClipPath(pObj->m_ClipPath, mtObj2Device);
228 if (ProcessTransparency(pObj, mtObj2Device)) {
229 return;
230 }
231 ProcessObjectNoClip(pObj, mtObj2Device);
232 }
233
ContinueSingleObject(CPDF_PageObject * pObj,const CFX_Matrix & mtObj2Device,PauseIndicatorIface * pPause)234 bool CPDF_RenderStatus::ContinueSingleObject(CPDF_PageObject* pObj,
235 const CFX_Matrix& mtObj2Device,
236 PauseIndicatorIface* pPause) {
237 if (m_pImageRenderer) {
238 if (m_pImageRenderer->Continue(pPause))
239 return true;
240
241 if (!m_pImageRenderer->GetResult())
242 DrawObjWithBackground(pObj, mtObj2Device);
243 m_pImageRenderer.reset();
244 return false;
245 }
246
247 m_pCurObj = pObj;
248 if (!m_Options.CheckPageObjectVisible(pObj))
249 return false;
250
251 ProcessClipPath(pObj->m_ClipPath, mtObj2Device);
252 if (ProcessTransparency(pObj, mtObj2Device))
253 return false;
254
255 if (!pObj->IsImage()) {
256 ProcessObjectNoClip(pObj, mtObj2Device);
257 return false;
258 }
259
260 m_pImageRenderer = std::make_unique<CPDF_ImageRenderer>(this);
261 if (!m_pImageRenderer->Start(pObj->AsImage(), mtObj2Device, false,
262 BlendMode::kNormal)) {
263 if (!m_pImageRenderer->GetResult())
264 DrawObjWithBackground(pObj, mtObj2Device);
265 m_pImageRenderer.reset();
266 return false;
267 }
268 return ContinueSingleObject(pObj, mtObj2Device, pPause);
269 }
270
GetObjectClippedRect(const CPDF_PageObject * pObj,const CFX_Matrix & mtObj2Device) const271 FX_RECT CPDF_RenderStatus::GetObjectClippedRect(
272 const CPDF_PageObject* pObj,
273 const CFX_Matrix& mtObj2Device) const {
274 FX_RECT rect = pObj->GetTransformedBBox(mtObj2Device);
275 rect.Intersect(m_pDevice->GetClipBox());
276 return rect;
277 }
278
ProcessObjectNoClip(CPDF_PageObject * pObj,const CFX_Matrix & mtObj2Device)279 void CPDF_RenderStatus::ProcessObjectNoClip(CPDF_PageObject* pObj,
280 const CFX_Matrix& mtObj2Device) {
281 bool bRet = false;
282 switch (pObj->GetType()) {
283 case CPDF_PageObject::Type::kText:
284 bRet = ProcessText(pObj->AsText(), mtObj2Device, nullptr);
285 break;
286 case CPDF_PageObject::Type::kPath:
287 bRet = ProcessPath(pObj->AsPath(), mtObj2Device);
288 break;
289 case CPDF_PageObject::Type::kImage:
290 bRet = ProcessImage(pObj->AsImage(), mtObj2Device);
291 break;
292 case CPDF_PageObject::Type::kShading:
293 ProcessShading(pObj->AsShading(), mtObj2Device);
294 return;
295 case CPDF_PageObject::Type::kForm:
296 bRet = ProcessForm(pObj->AsForm(), mtObj2Device);
297 break;
298 }
299 if (!bRet)
300 DrawObjWithBackground(pObj, mtObj2Device);
301 }
302
DrawObjWithBlend(CPDF_PageObject * pObj,const CFX_Matrix & mtObj2Device)303 bool CPDF_RenderStatus::DrawObjWithBlend(CPDF_PageObject* pObj,
304 const CFX_Matrix& mtObj2Device) {
305 switch (pObj->GetType()) {
306 case CPDF_PageObject::Type::kPath:
307 return ProcessPath(pObj->AsPath(), mtObj2Device);
308 case CPDF_PageObject::Type::kImage:
309 return ProcessImage(pObj->AsImage(), mtObj2Device);
310 case CPDF_PageObject::Type::kForm:
311 return ProcessForm(pObj->AsForm(), mtObj2Device);
312 default:
313 return false;
314 }
315 }
316
DrawObjWithBackground(CPDF_PageObject * pObj,const CFX_Matrix & mtObj2Device)317 void CPDF_RenderStatus::DrawObjWithBackground(CPDF_PageObject* pObj,
318 const CFX_Matrix& mtObj2Device) {
319 FX_RECT rect = GetObjectClippedRect(pObj, mtObj2Device);
320 if (rect.IsEmpty())
321 return;
322
323 int res = (pObj->IsImage() && m_bPrint) ? 0 : 300;
324 CPDF_ScaledRenderBuffer buffer;
325 if (!buffer.Initialize(m_pContext, m_pDevice, rect, pObj, &m_Options, res)) {
326 return;
327 }
328 RetainPtr<const CPDF_Dictionary> pFormResource;
329 CFX_Matrix matrix = mtObj2Device * buffer.GetMatrix();
330 const CPDF_FormObject* pFormObj = pObj->AsForm();
331 if (pFormObj)
332 pFormResource = pFormObj->form()->GetDict()->GetDictFor("Resources");
333 CPDF_RenderStatus status(m_pContext, buffer.GetDevice());
334 status.SetOptions(m_Options);
335 status.SetDeviceMatrix(buffer.GetMatrix());
336 status.SetTransparency(m_Transparency);
337 status.SetDropObjects(m_bDropObjects);
338 status.SetFormResource(std::move(pFormResource));
339 status.Initialize(nullptr, nullptr);
340 status.RenderSingleObject(pObj, matrix);
341 buffer.OutputToDevice();
342 }
343
ProcessForm(const CPDF_FormObject * pFormObj,const CFX_Matrix & mtObj2Device)344 bool CPDF_RenderStatus::ProcessForm(const CPDF_FormObject* pFormObj,
345 const CFX_Matrix& mtObj2Device) {
346 RetainPtr<const CPDF_Dictionary> pOC =
347 pFormObj->form()->GetDict()->GetDictFor("OC");
348 if (pOC && !m_Options.CheckOCGDictVisible(pOC.Get()))
349 return true;
350
351 CFX_Matrix matrix = pFormObj->form_matrix() * mtObj2Device;
352 RetainPtr<const CPDF_Dictionary> pResources =
353 pFormObj->form()->GetDict()->GetDictFor("Resources");
354 CPDF_RenderStatus status(m_pContext, m_pDevice);
355 status.SetOptions(m_Options);
356 status.SetStopObject(m_pStopObj);
357 status.SetTransparency(m_Transparency);
358 status.SetDropObjects(m_bDropObjects);
359 status.SetFormResource(std::move(pResources));
360 status.Initialize(this, pFormObj);
361 status.m_curBlend = m_curBlend;
362 {
363 CFX_RenderDevice::StateRestorer restorer(m_pDevice);
364 status.RenderObjectList(pFormObj->form(), matrix);
365 m_bStopped = status.m_bStopped;
366 }
367 return true;
368 }
369
ProcessPath(CPDF_PathObject * path_obj,const CFX_Matrix & mtObj2Device)370 bool CPDF_RenderStatus::ProcessPath(CPDF_PathObject* path_obj,
371 const CFX_Matrix& mtObj2Device) {
372 CFX_FillRenderOptions::FillType fill_type = path_obj->filltype();
373 bool stroke = path_obj->stroke();
374 ProcessPathPattern(path_obj, mtObj2Device, &fill_type, &stroke);
375 if (fill_type == CFX_FillRenderOptions::FillType::kNoFill && !stroke)
376 return true;
377
378 // If the option to convert fill paths to stroke is enabled for forced color,
379 // set |fill_type| to FillType::kNoFill and |stroke| to true.
380 CPDF_RenderOptions::Options& options = m_Options.GetOptions();
381 if (m_Options.ColorModeIs(CPDF_RenderOptions::Type::kForcedColor) &&
382 options.bConvertFillToStroke &&
383 fill_type != CFX_FillRenderOptions::FillType::kNoFill) {
384 stroke = true;
385 fill_type = CFX_FillRenderOptions::FillType::kNoFill;
386 }
387
388 uint32_t fill_argb = fill_type != CFX_FillRenderOptions::FillType::kNoFill
389 ? GetFillArgb(path_obj)
390 : 0;
391 uint32_t stroke_argb = stroke ? GetStrokeArgb(path_obj) : 0;
392 CFX_Matrix path_matrix = path_obj->matrix() * mtObj2Device;
393 if (!IsAvailableMatrix(path_matrix))
394 return true;
395
396 return m_pDevice->DrawPathWithBlend(
397 *path_obj->path().GetObject(), &path_matrix,
398 path_obj->m_GraphState.GetObject(), fill_argb, stroke_argb,
399 GetFillOptionsForDrawPathWithBlend(options, path_obj, fill_type, stroke,
400 m_pType3Char),
401 m_curBlend);
402 }
403
GetTransferFunc(RetainPtr<const CPDF_Object> pObj) const404 RetainPtr<CPDF_TransferFunc> CPDF_RenderStatus::GetTransferFunc(
405 RetainPtr<const CPDF_Object> pObj) const {
406 DCHECK(pObj);
407 auto* pDocCache = CPDF_DocRenderData::FromDocument(m_pContext->GetDocument());
408 return pDocCache ? pDocCache->GetTransferFunc(std::move(pObj)) : nullptr;
409 }
410
GetFillArgb(CPDF_PageObject * pObj) const411 FX_ARGB CPDF_RenderStatus::GetFillArgb(CPDF_PageObject* pObj) const {
412 if (Type3CharMissingFillColor(m_pType3Char, &pObj->m_ColorState))
413 return m_T3FillColor;
414
415 return GetFillArgbForType3(pObj);
416 }
417
GetFillArgbForType3(CPDF_PageObject * pObj) const418 FX_ARGB CPDF_RenderStatus::GetFillArgbForType3(CPDF_PageObject* pObj) const {
419 const CPDF_ColorState* pColorState = &pObj->m_ColorState;
420 if (MissingFillColor(pColorState))
421 pColorState = &m_InitialStates.m_ColorState;
422
423 FX_COLORREF colorref = pColorState->GetFillColorRef();
424 if (colorref == 0xFFFFFFFF)
425 return 0;
426
427 int32_t alpha =
428 static_cast<int32_t>((pObj->m_GeneralState.GetFillAlpha() * 255));
429 RetainPtr<const CPDF_Object> pTR = pObj->m_GeneralState.GetTR();
430 if (pTR) {
431 if (!pObj->m_GeneralState.GetTransferFunc()) {
432 pObj->m_GeneralState.SetTransferFunc(GetTransferFunc(std::move(pTR)));
433 }
434 if (pObj->m_GeneralState.GetTransferFunc()) {
435 colorref =
436 pObj->m_GeneralState.GetTransferFunc()->TranslateColor(colorref);
437 }
438 }
439 return m_Options.TranslateObjectColor(AlphaAndColorRefToArgb(alpha, colorref),
440 pObj->GetType(),
441 CPDF_RenderOptions::RenderType::kFill);
442 }
443
GetStrokeArgb(CPDF_PageObject * pObj) const444 FX_ARGB CPDF_RenderStatus::GetStrokeArgb(CPDF_PageObject* pObj) const {
445 const CPDF_ColorState* pColorState = &pObj->m_ColorState;
446 if (Type3CharMissingStrokeColor(m_pType3Char, pColorState))
447 return m_T3FillColor;
448
449 if (MissingStrokeColor(pColorState))
450 pColorState = &m_InitialStates.m_ColorState;
451
452 FX_COLORREF colorref = pColorState->GetStrokeColorRef();
453 if (colorref == 0xFFFFFFFF)
454 return 0;
455
456 int32_t alpha = static_cast<int32_t>(pObj->m_GeneralState.GetStrokeAlpha() *
457 255); // not rounded.
458 RetainPtr<const CPDF_Object> pTR = pObj->m_GeneralState.GetTR();
459 if (pTR) {
460 if (!pObj->m_GeneralState.GetTransferFunc()) {
461 pObj->m_GeneralState.SetTransferFunc(GetTransferFunc(std::move(pTR)));
462 }
463 if (pObj->m_GeneralState.GetTransferFunc()) {
464 colorref =
465 pObj->m_GeneralState.GetTransferFunc()->TranslateColor(colorref);
466 }
467 }
468 return m_Options.TranslateObjectColor(
469 AlphaAndColorRefToArgb(alpha, colorref), pObj->GetType(),
470 CPDF_RenderOptions::RenderType::kStroke);
471 }
472
ProcessClipPath(const CPDF_ClipPath & ClipPath,const CFX_Matrix & mtObj2Device)473 void CPDF_RenderStatus::ProcessClipPath(const CPDF_ClipPath& ClipPath,
474 const CFX_Matrix& mtObj2Device) {
475 if (!ClipPath.HasRef()) {
476 if (m_LastClipPath.HasRef()) {
477 m_pDevice->RestoreState(true);
478 m_LastClipPath.SetNull();
479 }
480 return;
481 }
482 if (m_LastClipPath == ClipPath)
483 return;
484
485 m_LastClipPath = ClipPath;
486 m_pDevice->RestoreState(true);
487 for (size_t i = 0; i < ClipPath.GetPathCount(); ++i) {
488 const CFX_Path* pPath = ClipPath.GetPath(i).GetObject();
489 if (!pPath)
490 continue;
491
492 if (pPath->GetPoints().empty()) {
493 CFX_Path empty_path;
494 empty_path.AppendRect(-1, -1, 0, 0);
495 m_pDevice->SetClip_PathFill(empty_path, nullptr,
496 CFX_FillRenderOptions::WindingOptions());
497 } else {
498 m_pDevice->SetClip_PathFill(
499 *pPath, &mtObj2Device,
500 CFX_FillRenderOptions(ClipPath.GetClipType(i)));
501 }
502 }
503
504 if (ClipPath.GetTextCount() == 0)
505 return;
506
507 if (!m_bPrint &&
508 !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)) {
509 return;
510 }
511
512 std::unique_ptr<CFX_Path> pTextClippingPath;
513 for (size_t i = 0; i < ClipPath.GetTextCount(); ++i) {
514 CPDF_TextObject* pText = ClipPath.GetText(i);
515 if (pText) {
516 if (!pTextClippingPath)
517 pTextClippingPath = std::make_unique<CFX_Path>();
518 ProcessText(pText, mtObj2Device, pTextClippingPath.get());
519 continue;
520 }
521
522 if (!pTextClippingPath)
523 continue;
524
525 CFX_FillRenderOptions fill_options(CFX_FillRenderOptions::WindingOptions());
526 if (m_Options.GetOptions().bNoTextSmooth)
527 fill_options.aliased_path = true;
528 m_pDevice->SetClip_PathFill(*pTextClippingPath, nullptr, fill_options);
529 pTextClippingPath.reset();
530 }
531 }
532
ClipPattern(const CPDF_PageObject * page_obj,const CFX_Matrix & mtObj2Device,bool stroke)533 bool CPDF_RenderStatus::ClipPattern(const CPDF_PageObject* page_obj,
534 const CFX_Matrix& mtObj2Device,
535 bool stroke) {
536 if (page_obj->IsPath())
537 return SelectClipPath(page_obj->AsPath(), mtObj2Device, stroke);
538 if (page_obj->IsImage()) {
539 m_pDevice->SetClip_Rect(page_obj->GetTransformedBBox(mtObj2Device));
540 return true;
541 }
542 return false;
543 }
544
SelectClipPath(const CPDF_PathObject * path_obj,const CFX_Matrix & mtObj2Device,bool stroke)545 bool CPDF_RenderStatus::SelectClipPath(const CPDF_PathObject* path_obj,
546 const CFX_Matrix& mtObj2Device,
547 bool stroke) {
548 CFX_Matrix path_matrix = path_obj->matrix() * mtObj2Device;
549 if (stroke) {
550 return m_pDevice->SetClip_PathStroke(*path_obj->path().GetObject(),
551 &path_matrix,
552 path_obj->m_GraphState.GetObject());
553 }
554 CFX_FillRenderOptions fill_options(path_obj->filltype());
555 if (m_Options.GetOptions().bNoPathSmooth) {
556 fill_options.aliased_path = true;
557 }
558 return m_pDevice->SetClip_PathFill(*path_obj->path().GetObject(),
559 &path_matrix, fill_options);
560 }
561
ProcessTransparency(CPDF_PageObject * pPageObj,const CFX_Matrix & mtObj2Device)562 bool CPDF_RenderStatus::ProcessTransparency(CPDF_PageObject* pPageObj,
563 const CFX_Matrix& mtObj2Device) {
564 const BlendMode blend_type = pPageObj->m_GeneralState.GetBlendType();
565 RetainPtr<CPDF_Dictionary> pSMaskDict =
566 pPageObj->m_GeneralState.GetMutableSoftMask();
567 if (pSMaskDict) {
568 if (pPageObj->IsImage() &&
569 pPageObj->AsImage()->GetImage()->GetDict()->KeyExist("SMask")) {
570 pSMaskDict = nullptr;
571 }
572 }
573 RetainPtr<const CPDF_Dictionary> pFormResource;
574 float group_alpha = 1.0f;
575 CPDF_Transparency transparency = m_Transparency;
576 bool bGroupTransparent = false;
577 const CPDF_FormObject* pFormObj = pPageObj->AsForm();
578 if (pFormObj) {
579 group_alpha = pFormObj->m_GeneralState.GetFillAlpha();
580 transparency = pFormObj->form()->GetTransparency();
581 bGroupTransparent = transparency.IsIsolated();
582 pFormResource = pFormObj->form()->GetDict()->GetDictFor("Resources");
583 }
584 bool bTextClip =
585 (pPageObj->m_ClipPath.HasRef() &&
586 pPageObj->m_ClipPath.GetTextCount() > 0 && !m_bPrint &&
587 !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP));
588 if (!pSMaskDict && group_alpha == 1.0f && blend_type == BlendMode::kNormal &&
589 !bTextClip && !bGroupTransparent) {
590 return false;
591 }
592 if (m_bPrint) {
593 bool bRet = false;
594 int rendCaps = m_pDevice->GetRenderCaps();
595 if (!(transparency.IsIsolated() || pSMaskDict || bTextClip) &&
596 (rendCaps & FXRC_BLEND_MODE)) {
597 BlendMode oldBlend = m_curBlend;
598 m_curBlend = blend_type;
599 bRet = DrawObjWithBlend(pPageObj, mtObj2Device);
600 m_curBlend = oldBlend;
601 }
602 if (!bRet) {
603 DrawObjWithBackground(pPageObj, mtObj2Device);
604 }
605 return true;
606 }
607 FX_RECT rect = pPageObj->GetTransformedBBox(mtObj2Device);
608 rect.Intersect(m_pDevice->GetClipBox());
609 if (rect.IsEmpty())
610 return true;
611
612 int width = rect.Width();
613 int height = rect.Height();
614 CFX_DefaultRenderDevice bitmap_device;
615 RetainPtr<CFX_DIBitmap> backdrop;
616 if (!transparency.IsIsolated() &&
617 (m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) {
618 backdrop = pdfium::MakeRetain<CFX_DIBitmap>();
619 if (!m_pDevice->CreateCompatibleBitmap(backdrop, width, height))
620 return true;
621 m_pDevice->GetDIBits(backdrop, rect.left, rect.top);
622 }
623 if (!bitmap_device.Create(width, height, FXDIB_Format::kArgb, backdrop))
624 return true;
625
626 CFX_Matrix new_matrix = mtObj2Device;
627 new_matrix.Translate(-rect.left, -rect.top);
628
629 RetainPtr<CFX_DIBitmap> pTextMask;
630 if (bTextClip) {
631 pTextMask = pdfium::MakeRetain<CFX_DIBitmap>();
632 if (!pTextMask->Create(width, height, FXDIB_Format::k8bppMask))
633 return true;
634
635 CFX_DefaultRenderDevice text_device;
636 text_device.Attach(pTextMask);
637 for (size_t i = 0; i < pPageObj->m_ClipPath.GetTextCount(); ++i) {
638 CPDF_TextObject* textobj = pPageObj->m_ClipPath.GetText(i);
639 if (!textobj)
640 break;
641
642 // TODO(thestig): Should we check the return value here?
643 CPDF_TextRenderer::DrawTextPath(
644 &text_device, textobj->GetCharCodes(), textobj->GetCharPositions(),
645 textobj->m_TextState.GetFont().Get(),
646 textobj->m_TextState.GetFontSize(), textobj->GetTextMatrix(),
647 &new_matrix, textobj->m_GraphState.GetObject(), 0xffffffff, 0,
648 nullptr, CFX_FillRenderOptions());
649 }
650 }
651 CPDF_RenderStatus bitmap_render(m_pContext, &bitmap_device);
652 bitmap_render.SetOptions(m_Options);
653 bitmap_render.SetStopObject(m_pStopObj);
654 bitmap_render.SetStdCS(true);
655 bitmap_render.SetDropObjects(m_bDropObjects);
656 bitmap_render.SetFormResource(std::move(pFormResource));
657 bitmap_render.Initialize(nullptr, nullptr);
658 bitmap_render.ProcessObjectNoClip(pPageObj, new_matrix);
659 #if defined(_SKIA_SUPPORT_)
660 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
661 // Safe because `CFX_SkiaDeviceDriver` always uses pre-multiplied alpha.
662 // TODO(crbug.com/pdfium/2011): Remove the need for this.
663 bitmap_device.GetBitmap()->ForcePreMultiply();
664 }
665 #endif // _SKIA_SUPPORT
666 m_bStopped = bitmap_render.m_bStopped;
667 if (pSMaskDict) {
668 CFX_Matrix smask_matrix =
669 *pPageObj->m_GeneralState.GetSMaskMatrix() * mtObj2Device;
670 RetainPtr<CFX_DIBBase> pSMaskSource =
671 LoadSMask(pSMaskDict.Get(), &rect, smask_matrix);
672 if (pSMaskSource)
673 bitmap_device.MultiplyAlpha(pSMaskSource);
674 }
675 if (pTextMask) {
676 bitmap_device.MultiplyAlpha(pTextMask);
677 pTextMask.Reset();
678 }
679 if (group_alpha != 1.0f && transparency.IsGroup()) {
680 bitmap_device.MultiplyAlpha(group_alpha);
681 }
682 transparency = m_Transparency;
683 if (pPageObj->IsForm()) {
684 transparency.SetGroup();
685 }
686 CompositeDIBitmap(bitmap_device.GetBitmap(), rect.left, rect.top, 0, 255,
687 blend_type, transparency);
688 return true;
689 }
690
GetClippedBBox(const FX_RECT & rect) const691 FX_RECT CPDF_RenderStatus::GetClippedBBox(const FX_RECT& rect) const {
692 FX_RECT bbox = rect;
693 bbox.Intersect(m_pDevice->GetClipBox());
694 return bbox;
695 }
696
GetBackdrop(const CPDF_PageObject * pObj,const FX_RECT & bbox,bool bBackAlphaRequired)697 RetainPtr<CFX_DIBitmap> CPDF_RenderStatus::GetBackdrop(
698 const CPDF_PageObject* pObj,
699 const FX_RECT& bbox,
700 bool bBackAlphaRequired) {
701 int width = bbox.Width();
702 int height = bbox.Height();
703 auto pBackdrop = pdfium::MakeRetain<CFX_DIBitmap>();
704 if (bBackAlphaRequired && !m_bDropObjects)
705 pBackdrop->Create(width, height, FXDIB_Format::kArgb);
706 else
707 m_pDevice->CreateCompatibleBitmap(pBackdrop, width, height);
708
709 if (pBackdrop->GetBuffer().empty())
710 return nullptr;
711
712 bool bNeedDraw;
713 if (pBackdrop->IsAlphaFormat())
714 bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT);
715 else
716 bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS);
717
718 if (!bNeedDraw) {
719 m_pDevice->GetDIBits(pBackdrop, bbox.left, bbox.top);
720 return pBackdrop;
721 }
722 CFX_Matrix FinalMatrix = m_DeviceMatrix;
723 FinalMatrix.Translate(-bbox.left, -bbox.top);
724 if (!pBackdrop->IsAlphaFormat()) {
725 pBackdrop->Clear(0xffffffff);
726 }
727
728 CFX_DefaultRenderDevice device;
729 device.Attach(pBackdrop);
730 m_pContext->Render(&device, pObj, &m_Options, &FinalMatrix);
731 return pBackdrop;
732 }
733
CloneObjStates(const CPDF_GraphicStates * pSrcStates,bool stroke)734 std::unique_ptr<CPDF_GraphicStates> CPDF_RenderStatus::CloneObjStates(
735 const CPDF_GraphicStates* pSrcStates,
736 bool stroke) {
737 if (!pSrcStates)
738 return nullptr;
739
740 auto pStates = std::make_unique<CPDF_GraphicStates>();
741 pStates->CopyStates(*pSrcStates);
742 const CPDF_Color* pObjColor = stroke
743 ? pSrcStates->m_ColorState.GetStrokeColor()
744 : pSrcStates->m_ColorState.GetFillColor();
745 if (!pObjColor->IsNull()) {
746 pStates->m_ColorState.SetFillColorRef(
747 stroke ? pSrcStates->m_ColorState.GetStrokeColorRef()
748 : pSrcStates->m_ColorState.GetFillColorRef());
749 pStates->m_ColorState.SetStrokeColorRef(
750 pStates->m_ColorState.GetFillColorRef());
751 }
752 return pStates;
753 }
754
ProcessText(CPDF_TextObject * textobj,const CFX_Matrix & mtObj2Device,CFX_Path * clipping_path)755 bool CPDF_RenderStatus::ProcessText(CPDF_TextObject* textobj,
756 const CFX_Matrix& mtObj2Device,
757 CFX_Path* clipping_path) {
758 if (textobj->GetCharCodes().empty())
759 return true;
760
761 const TextRenderingMode text_render_mode = textobj->m_TextState.GetTextMode();
762 if (text_render_mode == TextRenderingMode::MODE_INVISIBLE)
763 return true;
764
765 RetainPtr<CPDF_Font> pFont = textobj->m_TextState.GetFont();
766 if (pFont->IsType3Font())
767 return ProcessType3Text(textobj, mtObj2Device);
768
769 bool is_fill = false;
770 bool is_stroke = false;
771 bool is_clip = false;
772 if (clipping_path) {
773 is_clip = true;
774 } else {
775 switch (text_render_mode) {
776 case TextRenderingMode::MODE_FILL:
777 case TextRenderingMode::MODE_FILL_CLIP:
778 is_fill = true;
779 break;
780 case TextRenderingMode::MODE_STROKE:
781 case TextRenderingMode::MODE_STROKE_CLIP:
782 if (pFont->HasFace())
783 is_stroke = true;
784 else
785 is_fill = true;
786 break;
787 case TextRenderingMode::MODE_FILL_STROKE:
788 case TextRenderingMode::MODE_FILL_STROKE_CLIP:
789 is_fill = true;
790 if (pFont->HasFace())
791 is_stroke = true;
792 break;
793 case TextRenderingMode::MODE_INVISIBLE:
794 // Already handled above, but the compiler is not smart enough to
795 // realize it.
796 NOTREACHED();
797 return true;
798 case TextRenderingMode::MODE_CLIP:
799 return true;
800 case TextRenderingMode::MODE_UNKNOWN:
801 NOTREACHED();
802 return false;
803 }
804 }
805 FX_ARGB stroke_argb = 0;
806 FX_ARGB fill_argb = 0;
807 bool bPattern = false;
808 if (is_stroke) {
809 if (textobj->m_ColorState.GetStrokeColor()->IsPattern()) {
810 bPattern = true;
811 } else {
812 stroke_argb = GetStrokeArgb(textobj);
813 }
814 }
815 if (is_fill) {
816 if (textobj->m_ColorState.GetFillColor()->IsPattern()) {
817 bPattern = true;
818 } else {
819 fill_argb = GetFillArgb(textobj);
820 }
821 }
822 CFX_Matrix text_matrix = textobj->GetTextMatrix();
823 if (!IsAvailableMatrix(text_matrix))
824 return true;
825
826 float font_size = textobj->m_TextState.GetFontSize();
827 if (bPattern) {
828 DrawTextPathWithPattern(textobj, mtObj2Device, pFont.Get(), font_size,
829 text_matrix, is_fill, is_stroke);
830 return true;
831 }
832 if (is_clip || is_stroke) {
833 const CFX_Matrix* pDeviceMatrix = &mtObj2Device;
834 CFX_Matrix device_matrix;
835 if (is_stroke) {
836 pdfium::span<const float> pCTM = textobj->m_TextState.GetCTM();
837 if (pCTM[0] != 1.0f || pCTM[3] != 1.0f) {
838 CFX_Matrix ctm(pCTM[0], pCTM[1], pCTM[2], pCTM[3], 0, 0);
839 text_matrix *= ctm.GetInverse();
840 device_matrix = ctm * mtObj2Device;
841 pDeviceMatrix = &device_matrix;
842 }
843 }
844 return CPDF_TextRenderer::DrawTextPath(
845 m_pDevice, textobj->GetCharCodes(), textobj->GetCharPositions(),
846 pFont.Get(), font_size, text_matrix, pDeviceMatrix,
847 textobj->m_GraphState.GetObject(), fill_argb, stroke_argb,
848 clipping_path,
849 GetFillOptionsForDrawTextPath(m_Options.GetOptions(), textobj,
850 is_stroke, is_fill));
851 }
852 text_matrix.Concat(mtObj2Device);
853 return CPDF_TextRenderer::DrawNormalText(
854 m_pDevice, textobj->GetCharCodes(), textobj->GetCharPositions(),
855 pFont.Get(), font_size, text_matrix, fill_argb, m_Options);
856 }
857
858 // TODO(npm): Font fallback for type 3 fonts? (Completely separate code!!)
ProcessType3Text(CPDF_TextObject * textobj,const CFX_Matrix & mtObj2Device)859 bool CPDF_RenderStatus::ProcessType3Text(CPDF_TextObject* textobj,
860 const CFX_Matrix& mtObj2Device) {
861 CPDF_Type3Font* pType3Font = textobj->m_TextState.GetFont()->AsType3Font();
862 if (pdfium::Contains(m_Type3FontCache, pType3Font))
863 return true;
864
865 FX_ARGB fill_argb = GetFillArgbForType3(textobj);
866 int fill_alpha = FXARGB_A(fill_argb);
867 if (m_bPrint && fill_alpha < 255)
868 return false;
869
870 CFX_Matrix text_matrix = textobj->GetTextMatrix();
871 CFX_Matrix char_matrix = pType3Font->GetFontMatrix();
872 float font_size = textobj->m_TextState.GetFontSize();
873 char_matrix.Scale(font_size, font_size);
874
875 // Must come before |glyphs|, because |glyphs| points into |refTypeCache|.
876 std::set<RetainPtr<CPDF_Type3Cache>> refTypeCache;
877 std::vector<TextGlyphPos> glyphs;
878 if (!m_bPrint)
879 glyphs.resize(textobj->GetCharCodes().size());
880
881 for (size_t iChar = 0; iChar < textobj->GetCharCodes().size(); ++iChar) {
882 uint32_t charcode = textobj->GetCharCodes()[iChar];
883 if (charcode == static_cast<uint32_t>(-1))
884 continue;
885
886 CPDF_Type3Char* pType3Char = pType3Font->LoadChar(charcode);
887 if (!pType3Char)
888 continue;
889
890 CFX_Matrix matrix = char_matrix;
891 matrix.e += iChar > 0 ? textobj->GetCharPositions()[iChar - 1] : 0;
892 matrix.Concat(text_matrix);
893 matrix.Concat(mtObj2Device);
894 if (!pType3Char->LoadBitmapFromSoleImageOfForm()) {
895 if (!glyphs.empty()) {
896 for (size_t i = 0; i < iChar; ++i) {
897 const TextGlyphPos& glyph = glyphs[i];
898 if (!glyph.m_pGlyph)
899 continue;
900
901 absl::optional<CFX_Point> point = glyph.GetOrigin({0, 0});
902 if (!point.has_value())
903 continue;
904
905 m_pDevice->SetBitMask(glyph.m_pGlyph->GetBitmap(), point->x, point->y,
906 fill_argb);
907 }
908 glyphs.clear();
909 }
910
911 std::unique_ptr<CPDF_GraphicStates> pStates =
912 CloneObjStates(textobj, false);
913 CPDF_RenderOptions options = m_Options;
914 options.GetOptions().bForceHalftone = true;
915 options.GetOptions().bRectAA = true;
916
917 const auto* pForm = static_cast<const CPDF_Form*>(pType3Char->form());
918 RetainPtr<const CPDF_Dictionary> pFormResource =
919 pForm->GetDict()->GetDictFor("Resources");
920
921 if (fill_alpha == 255) {
922 CPDF_RenderStatus status(m_pContext, m_pDevice);
923 status.SetOptions(options);
924 status.SetTransparency(pForm->GetTransparency());
925 status.SetType3Char(pType3Char);
926 status.SetFillColor(fill_argb);
927 status.SetDropObjects(m_bDropObjects);
928 status.SetFormResource(std::move(pFormResource));
929 status.Initialize(this, pStates.get());
930 status.m_Type3FontCache = m_Type3FontCache;
931 status.m_Type3FontCache.emplace_back(pType3Font);
932
933 CFX_RenderDevice::StateRestorer restorer(m_pDevice);
934 status.RenderObjectList(pForm, matrix);
935 } else {
936 FX_RECT rect =
937 matrix.TransformRect(pForm->CalcBoundingBox()).GetOuterRect();
938 if (!rect.Valid())
939 continue;
940
941 CFX_DefaultRenderDevice bitmap_device;
942 if (!bitmap_device.Create(rect.Width(), rect.Height(),
943 FXDIB_Format::kArgb, nullptr)) {
944 return true;
945 }
946 CPDF_RenderStatus status(m_pContext, &bitmap_device);
947 status.SetOptions(options);
948 status.SetTransparency(pForm->GetTransparency());
949 status.SetType3Char(pType3Char);
950 status.SetFillColor(fill_argb);
951 status.SetDropObjects(m_bDropObjects);
952 status.SetFormResource(std::move(pFormResource));
953 status.Initialize(this, pStates.get());
954 status.m_Type3FontCache = m_Type3FontCache;
955 status.m_Type3FontCache.emplace_back(pType3Font);
956 matrix.Translate(-rect.left, -rect.top);
957 status.RenderObjectList(pForm, matrix);
958 m_pDevice->SetDIBits(bitmap_device.GetBitmap(), rect.left, rect.top);
959 }
960 } else if (pType3Char->GetBitmap()) {
961 if (m_bPrint) {
962 CFX_Matrix image_matrix = pType3Char->matrix() * matrix;
963 CPDF_ImageRenderer renderer(this);
964 if (renderer.Start(pType3Char->GetBitmap(), fill_argb, image_matrix,
965 FXDIB_ResampleOptions(), false)) {
966 renderer.Continue(nullptr);
967 }
968 if (!renderer.GetResult())
969 return false;
970 } else {
971 CPDF_Document* pDoc = pType3Font->GetDocument();
972 RetainPtr<CPDF_Type3Cache> pCache =
973 CPDF_DocRenderData::FromDocument(pDoc)->GetCachedType3(pType3Font);
974
975 const CFX_GlyphBitmap* pBitmap = pCache->LoadGlyph(charcode, matrix);
976 if (!pBitmap)
977 continue;
978
979 refTypeCache.insert(std::move(pCache));
980
981 CFX_Point origin(FXSYS_roundf(matrix.e), FXSYS_roundf(matrix.f));
982 if (glyphs.empty()) {
983 FX_SAFE_INT32 left = origin.x;
984 left += pBitmap->left();
985 if (!left.IsValid())
986 continue;
987
988 FX_SAFE_INT32 top = origin.y;
989 top -= pBitmap->top();
990 if (!top.IsValid())
991 continue;
992
993 m_pDevice->SetBitMask(pBitmap->GetBitmap(), left.ValueOrDie(),
994 top.ValueOrDie(), fill_argb);
995 } else {
996 glyphs[iChar].m_pGlyph = pBitmap;
997 glyphs[iChar].m_Origin = origin;
998 }
999 }
1000 }
1001 }
1002
1003 if (glyphs.empty())
1004 return true;
1005
1006 FX_RECT rect = GetGlyphsBBox(glyphs, 0);
1007 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1008 if (!pBitmap->Create(rect.Width(), rect.Height(), FXDIB_Format::k8bppMask))
1009 return true;
1010
1011 for (const TextGlyphPos& glyph : glyphs) {
1012 if (!glyph.m_pGlyph || !glyph.m_pGlyph->GetBitmap()->IsMaskFormat())
1013 continue;
1014
1015 absl::optional<CFX_Point> point = glyph.GetOrigin({rect.left, rect.top});
1016 if (!point.has_value())
1017 continue;
1018
1019 pBitmap->CompositeMask(
1020 point->x, point->y, glyph.m_pGlyph->GetBitmap()->GetWidth(),
1021 glyph.m_pGlyph->GetBitmap()->GetHeight(), glyph.m_pGlyph->GetBitmap(),
1022 fill_argb, 0, 0, BlendMode::kNormal, nullptr, false);
1023 }
1024 m_pDevice->SetBitMask(pBitmap, rect.left, rect.top, fill_argb);
1025 return true;
1026 }
1027
DrawTextPathWithPattern(const CPDF_TextObject * textobj,const CFX_Matrix & mtObj2Device,CPDF_Font * pFont,float font_size,const CFX_Matrix & mtTextMatrix,bool fill,bool stroke)1028 void CPDF_RenderStatus::DrawTextPathWithPattern(const CPDF_TextObject* textobj,
1029 const CFX_Matrix& mtObj2Device,
1030 CPDF_Font* pFont,
1031 float font_size,
1032 const CFX_Matrix& mtTextMatrix,
1033 bool fill,
1034 bool stroke) {
1035 if (!stroke) {
1036 std::vector<std::unique_ptr<CPDF_TextObject>> pCopy;
1037 pCopy.push_back(textobj->Clone());
1038
1039 CPDF_PathObject path;
1040 path.set_filltype(CFX_FillRenderOptions::FillType::kWinding);
1041 path.m_ClipPath.CopyClipPath(m_LastClipPath);
1042 path.m_ClipPath.AppendTexts(&pCopy);
1043 path.m_ColorState = textobj->m_ColorState;
1044 path.m_GeneralState = textobj->m_GeneralState;
1045 path.path().AppendFloatRect(textobj->GetRect());
1046 path.SetRect(textobj->GetRect());
1047
1048 AutoRestorer<UnownedPtr<const CPDF_PageObject>> restorer2(&m_pCurObj);
1049 RenderSingleObject(&path, mtObj2Device);
1050 return;
1051 }
1052
1053 std::vector<TextCharPos> char_pos_list = GetCharPosList(
1054 textobj->GetCharCodes(), textobj->GetCharPositions(), pFont, font_size);
1055 for (const TextCharPos& charpos : char_pos_list) {
1056 auto* font = charpos.m_FallbackFontPosition == -1
1057 ? pFont->GetFont()
1058 : pFont->GetFontFallback(charpos.m_FallbackFontPosition);
1059 const CFX_Path* pPath =
1060 font->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth);
1061 if (!pPath)
1062 continue;
1063
1064 CPDF_PathObject path;
1065 path.m_GraphState = textobj->m_GraphState;
1066 path.m_ColorState = textobj->m_ColorState;
1067
1068 CFX_Matrix matrix = charpos.GetEffectiveMatrix(CFX_Matrix(
1069 font_size, 0, 0, font_size, charpos.m_Origin.x, charpos.m_Origin.y));
1070 matrix.Concat(mtTextMatrix);
1071 path.set_stroke(stroke);
1072 path.set_filltype(fill ? CFX_FillRenderOptions::FillType::kWinding
1073 : CFX_FillRenderOptions::FillType::kNoFill);
1074 path.path().Append(*pPath, &matrix);
1075 path.SetPathMatrix(CFX_Matrix());
1076 ProcessPath(&path, mtObj2Device);
1077 }
1078 }
1079
DrawShadingPattern(CPDF_ShadingPattern * pattern,const CPDF_PageObject * pPageObj,const CFX_Matrix & mtObj2Device,bool stroke)1080 void CPDF_RenderStatus::DrawShadingPattern(CPDF_ShadingPattern* pattern,
1081 const CPDF_PageObject* pPageObj,
1082 const CFX_Matrix& mtObj2Device,
1083 bool stroke) {
1084 if (!pattern->Load())
1085 return;
1086
1087 CFX_RenderDevice::StateRestorer restorer(m_pDevice);
1088 if (!ClipPattern(pPageObj, mtObj2Device, stroke))
1089 return;
1090
1091 FX_RECT rect = GetObjectClippedRect(pPageObj, mtObj2Device);
1092 if (rect.IsEmpty())
1093 return;
1094
1095 CFX_Matrix matrix = pattern->pattern_to_form() * mtObj2Device;
1096 int alpha =
1097 FXSYS_roundf(255 * (stroke ? pPageObj->m_GeneralState.GetStrokeAlpha()
1098 : pPageObj->m_GeneralState.GetFillAlpha()));
1099 CPDF_RenderShading::Draw(m_pDevice, m_pContext, m_pCurObj, pattern, matrix,
1100 rect, alpha, m_Options);
1101 }
1102
ProcessShading(const CPDF_ShadingObject * pShadingObj,const CFX_Matrix & mtObj2Device)1103 void CPDF_RenderStatus::ProcessShading(const CPDF_ShadingObject* pShadingObj,
1104 const CFX_Matrix& mtObj2Device) {
1105 FX_RECT rect = GetObjectClippedRect(pShadingObj, mtObj2Device);
1106 if (rect.IsEmpty())
1107 return;
1108
1109 CFX_Matrix matrix = pShadingObj->matrix() * mtObj2Device;
1110 CPDF_RenderShading::Draw(
1111 m_pDevice, m_pContext, m_pCurObj, pShadingObj->pattern(), matrix, rect,
1112 FXSYS_roundf(255 * pShadingObj->m_GeneralState.GetFillAlpha()),
1113 m_Options);
1114 }
1115
DrawTilingPattern(CPDF_TilingPattern * pattern,CPDF_PageObject * pPageObj,const CFX_Matrix & mtObj2Device,bool stroke)1116 void CPDF_RenderStatus::DrawTilingPattern(CPDF_TilingPattern* pattern,
1117 CPDF_PageObject* pPageObj,
1118 const CFX_Matrix& mtObj2Device,
1119 bool stroke) {
1120 const std::unique_ptr<CPDF_Form> pPatternForm = pattern->Load(pPageObj);
1121 if (!pPatternForm)
1122 return;
1123
1124 CFX_RenderDevice::StateRestorer restorer(m_pDevice);
1125 if (!ClipPattern(pPageObj, mtObj2Device, stroke))
1126 return;
1127
1128 FX_RECT clip_box = m_pDevice->GetClipBox();
1129 if (clip_box.IsEmpty())
1130 return;
1131
1132 RetainPtr<CFX_DIBitmap> pScreen =
1133 CPDF_RenderTiling::Draw(this, pPageObj, pattern, pPatternForm.get(),
1134 mtObj2Device, clip_box, stroke);
1135 if (!pScreen)
1136 return;
1137
1138 CompositeDIBitmap(pScreen, clip_box.left, clip_box.top, 0, 255,
1139 BlendMode::kNormal, CPDF_Transparency());
1140 }
1141
DrawPathWithPattern(CPDF_PathObject * path_obj,const CFX_Matrix & mtObj2Device,const CPDF_Color * pColor,bool stroke)1142 void CPDF_RenderStatus::DrawPathWithPattern(CPDF_PathObject* path_obj,
1143 const CFX_Matrix& mtObj2Device,
1144 const CPDF_Color* pColor,
1145 bool stroke) {
1146 RetainPtr<CPDF_Pattern> pattern = pColor->GetPattern();
1147 if (!pattern)
1148 return;
1149
1150 if (CPDF_TilingPattern* pTilingPattern = pattern->AsTilingPattern())
1151 DrawTilingPattern(pTilingPattern, path_obj, mtObj2Device, stroke);
1152 else if (CPDF_ShadingPattern* pShadingPattern = pattern->AsShadingPattern())
1153 DrawShadingPattern(pShadingPattern, path_obj, mtObj2Device, stroke);
1154 }
1155
ProcessPathPattern(CPDF_PathObject * path_obj,const CFX_Matrix & mtObj2Device,CFX_FillRenderOptions::FillType * fill_type,bool * stroke)1156 void CPDF_RenderStatus::ProcessPathPattern(
1157 CPDF_PathObject* path_obj,
1158 const CFX_Matrix& mtObj2Device,
1159 CFX_FillRenderOptions::FillType* fill_type,
1160 bool* stroke) {
1161 DCHECK(fill_type);
1162 DCHECK(stroke);
1163
1164 if (*fill_type != CFX_FillRenderOptions::FillType::kNoFill) {
1165 const CPDF_Color& FillColor = *path_obj->m_ColorState.GetFillColor();
1166 if (FillColor.IsPattern()) {
1167 DrawPathWithPattern(path_obj, mtObj2Device, &FillColor, false);
1168 *fill_type = CFX_FillRenderOptions::FillType::kNoFill;
1169 }
1170 }
1171 if (*stroke) {
1172 const CPDF_Color& StrokeColor = *path_obj->m_ColorState.GetStrokeColor();
1173 if (StrokeColor.IsPattern()) {
1174 DrawPathWithPattern(path_obj, mtObj2Device, &StrokeColor, true);
1175 *stroke = false;
1176 }
1177 }
1178 }
1179
ProcessImage(CPDF_ImageObject * pImageObj,const CFX_Matrix & mtObj2Device)1180 bool CPDF_RenderStatus::ProcessImage(CPDF_ImageObject* pImageObj,
1181 const CFX_Matrix& mtObj2Device) {
1182 CPDF_ImageRenderer render(this);
1183 if (render.Start(pImageObj, mtObj2Device, m_bStdCS, m_curBlend))
1184 render.Continue(nullptr);
1185 return render.GetResult();
1186 }
1187
CompositeDIBitmap(const RetainPtr<CFX_DIBitmap> & pDIBitmap,int left,int top,FX_ARGB mask_argb,int bitmap_alpha,BlendMode blend_mode,const CPDF_Transparency & transparency)1188 void CPDF_RenderStatus::CompositeDIBitmap(
1189 const RetainPtr<CFX_DIBitmap>& pDIBitmap,
1190 int left,
1191 int top,
1192 FX_ARGB mask_argb,
1193 int bitmap_alpha,
1194 BlendMode blend_mode,
1195 const CPDF_Transparency& transparency) {
1196 if (!pDIBitmap)
1197 return;
1198
1199 if (blend_mode == BlendMode::kNormal) {
1200 if (!pDIBitmap->IsMaskFormat()) {
1201 if (bitmap_alpha < 255) {
1202 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
1203 std::unique_ptr<CFX_ImageRenderer> dummy;
1204 CFX_Matrix m = CFX_RenderDevice::GetFlipMatrix(
1205 pDIBitmap->GetWidth(), pDIBitmap->GetHeight(), left, top);
1206 m_pDevice->StartDIBits(pDIBitmap, bitmap_alpha, 0, m,
1207 FXDIB_ResampleOptions(), &dummy);
1208 return;
1209 }
1210 pDIBitmap->MultiplyAlpha(bitmap_alpha);
1211 }
1212 if (m_pDevice->SetDIBits(pDIBitmap, left, top)) {
1213 return;
1214 }
1215 } else {
1216 uint32_t fill_argb = m_Options.TranslateColor(mask_argb);
1217 if (bitmap_alpha < 255) {
1218 uint8_t* fill_argb8 = reinterpret_cast<uint8_t*>(&fill_argb);
1219 fill_argb8[3] *= bitmap_alpha / 255;
1220 }
1221 if (m_pDevice->SetBitMask(pDIBitmap, left, top, fill_argb)) {
1222 return;
1223 }
1224 }
1225 }
1226 bool bIsolated = transparency.IsIsolated();
1227 bool bBackAlphaRequired =
1228 blend_mode != BlendMode::kNormal && bIsolated && !m_bDropObjects;
1229 bool bGetBackGround =
1230 ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) ||
1231 (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) &&
1232 (m_pDevice->GetRenderCaps() & FXRC_GET_BITS) && !bBackAlphaRequired);
1233 if (bGetBackGround) {
1234 if (bIsolated || !transparency.IsGroup()) {
1235 if (!pDIBitmap->IsMaskFormat())
1236 m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, blend_mode);
1237 return;
1238 }
1239
1240 FX_RECT rect(left, top, left + pDIBitmap->GetWidth(),
1241 top + pDIBitmap->GetHeight());
1242 rect.Intersect(m_pDevice->GetClipBox());
1243 RetainPtr<CFX_DIBitmap> pClone;
1244 if (m_pDevice->GetBackDrop() && m_pDevice->GetBitmap()) {
1245 pClone = m_pDevice->GetBackDrop()->ClipTo(rect);
1246 if (!pClone)
1247 return;
1248
1249 RetainPtr<CFX_DIBitmap> pForeBitmap = m_pDevice->GetBitmap();
1250 pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(),
1251 pForeBitmap, rect.left, rect.top,
1252 BlendMode::kNormal, nullptr, false);
1253 left = std::min(left, 0);
1254 top = std::min(top, 0);
1255 if (pDIBitmap->IsMaskFormat()) {
1256 pClone->CompositeMask(0, 0, pClone->GetWidth(), pClone->GetHeight(),
1257 pDIBitmap, mask_argb, left, top, blend_mode,
1258 nullptr, false);
1259 } else {
1260 pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(),
1261 pDIBitmap, left, top, blend_mode, nullptr,
1262 false);
1263 }
1264 } else {
1265 pClone = pDIBitmap;
1266 }
1267 if (m_pDevice->GetBackDrop()) {
1268 m_pDevice->SetDIBits(pClone, rect.left, rect.top);
1269 } else {
1270 if (!pDIBitmap->IsMaskFormat()) {
1271 m_pDevice->SetDIBitsWithBlend(pDIBitmap, rect.left, rect.top,
1272 blend_mode);
1273 }
1274 }
1275 return;
1276 }
1277 FX_RECT bbox = GetClippedBBox(FX_RECT(left, top, left + pDIBitmap->GetWidth(),
1278 top + pDIBitmap->GetHeight()));
1279 RetainPtr<CFX_DIBitmap> pBackdrop = GetBackdrop(
1280 m_pCurObj, bbox, blend_mode != BlendMode::kNormal && bIsolated);
1281 if (!pBackdrop)
1282 return;
1283
1284 if (pDIBitmap->IsMaskFormat()) {
1285 pBackdrop->CompositeMask(left - bbox.left, top - bbox.top,
1286 pDIBitmap->GetWidth(), pDIBitmap->GetHeight(),
1287 pDIBitmap, mask_argb, 0, 0, blend_mode, nullptr,
1288 false);
1289 } else {
1290 pBackdrop->CompositeBitmap(left - bbox.left, top - bbox.top,
1291 pDIBitmap->GetWidth(), pDIBitmap->GetHeight(),
1292 pDIBitmap, 0, 0, blend_mode, nullptr, false);
1293 }
1294
1295 auto pBackdrop1 = pdfium::MakeRetain<CFX_DIBitmap>();
1296 pBackdrop1->Create(pBackdrop->GetWidth(), pBackdrop->GetHeight(),
1297 FXDIB_Format::kRgb32);
1298 pBackdrop1->Clear((uint32_t)-1);
1299 pBackdrop1->CompositeBitmap(0, 0, pBackdrop->GetWidth(),
1300 pBackdrop->GetHeight(), pBackdrop, 0, 0,
1301 BlendMode::kNormal, nullptr, false);
1302 pBackdrop = std::move(pBackdrop1);
1303 m_pDevice->SetDIBits(pBackdrop, bbox.left, bbox.top);
1304 }
1305
LoadSMask(CPDF_Dictionary * pSMaskDict,FX_RECT * pClipRect,const CFX_Matrix & mtMatrix)1306 RetainPtr<CFX_DIBitmap> CPDF_RenderStatus::LoadSMask(
1307 CPDF_Dictionary* pSMaskDict,
1308 FX_RECT* pClipRect,
1309 const CFX_Matrix& mtMatrix) {
1310 if (!pSMaskDict)
1311 return nullptr;
1312
1313 RetainPtr<CPDF_Stream> pGroup =
1314 pSMaskDict->GetMutableStreamFor(pdfium::transparency::kG);
1315 if (!pGroup)
1316 return nullptr;
1317
1318 std::unique_ptr<CPDF_Function> pFunc;
1319 RetainPtr<const CPDF_Object> pFuncObj =
1320 pSMaskDict->GetDirectObjectFor(pdfium::transparency::kTR);
1321 if (pFuncObj && (pFuncObj->IsDictionary() || pFuncObj->IsStream()))
1322 pFunc = CPDF_Function::Load(std::move(pFuncObj));
1323
1324 CFX_Matrix matrix = mtMatrix;
1325 matrix.Translate(-pClipRect->left, -pClipRect->top);
1326
1327 CPDF_Form form(m_pContext->GetDocument(),
1328 m_pContext->GetMutablePageResources(), pGroup);
1329 form.ParseContent();
1330
1331 CFX_DefaultRenderDevice bitmap_device;
1332 bool bLuminosity =
1333 pSMaskDict->GetByteStringFor(pdfium::transparency::kSoftMaskSubType) !=
1334 pdfium::transparency::kAlpha;
1335 int width = pClipRect->right - pClipRect->left;
1336 int height = pClipRect->bottom - pClipRect->top;
1337 FXDIB_Format format = GetFormatForLuminosity(bLuminosity);
1338 if (!bitmap_device.Create(width, height, format, nullptr))
1339 return nullptr;
1340
1341 RetainPtr<CFX_DIBitmap> bitmap = bitmap_device.GetBitmap();
1342 CPDF_ColorSpace::Family nCSFamily = CPDF_ColorSpace::Family::kUnknown;
1343 if (bLuminosity) {
1344 FX_ARGB back_color =
1345 GetBackColor(pSMaskDict, pGroup->GetDict().Get(), &nCSFamily);
1346 bitmap->Clear(back_color);
1347 } else {
1348 bitmap->Clear(0);
1349 }
1350
1351 RetainPtr<const CPDF_Dictionary> pFormResource =
1352 form.GetDict()->GetDictFor("Resources");
1353 CPDF_RenderOptions options;
1354 options.SetColorMode(bLuminosity ? CPDF_RenderOptions::kNormal
1355 : CPDF_RenderOptions::kAlpha);
1356 CPDF_RenderStatus status(m_pContext, &bitmap_device);
1357 status.SetOptions(options);
1358 status.SetGroupFamily(nCSFamily);
1359 status.SetLoadMask(bLuminosity);
1360 status.SetStdCS(true);
1361 status.SetFormResource(std::move(pFormResource));
1362 status.SetDropObjects(m_bDropObjects);
1363 status.Initialize(nullptr, nullptr);
1364 status.RenderObjectList(&form, matrix);
1365
1366 auto pMask = pdfium::MakeRetain<CFX_DIBitmap>();
1367 if (!pMask->Create(width, height, FXDIB_Format::k8bppMask))
1368 return nullptr;
1369
1370 pdfium::span<uint8_t> dest_buf = pMask->GetWritableBuffer();
1371 pdfium::span<const uint8_t> src_buf = bitmap->GetBuffer();
1372 int dest_pitch = pMask->GetPitch();
1373 int src_pitch = bitmap->GetPitch();
1374 DataVector<uint8_t> transfers(256);
1375 if (pFunc) {
1376 std::vector<float> results(pFunc->CountOutputs());
1377 for (size_t i = 0; i < transfers.size(); ++i) {
1378 float input = i / 255.0f;
1379 pFunc->Call(pdfium::make_span(&input, 1), results);
1380 transfers[i] = FXSYS_roundf(results[0] * 255);
1381 }
1382 } else {
1383 // Fill |transfers| with 0, 1, ... N.
1384 std::iota(transfers.begin(), transfers.end(), 0);
1385 }
1386 if (bLuminosity) {
1387 const int Bpp = bitmap->GetBPP() / 8;
1388 for (int row = 0; row < height; row++) {
1389 const size_t dest_offset = Fx2DSizeOrDie(row, dest_pitch);
1390 const size_t src_offset = Fx2DSizeOrDie(row, src_pitch);
1391 uint8_t* dest_pos = dest_buf.subspan(dest_offset).data();
1392 const uint8_t* src_pos = src_buf.subspan(src_offset).data();
1393 for (int col = 0; col < width; col++) {
1394 *dest_pos++ = transfers[FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos)];
1395 src_pos += Bpp;
1396 }
1397 }
1398 } else if (pFunc) {
1399 int size = dest_pitch * height;
1400 for (int i = 0; i < size; i++) {
1401 dest_buf[i] = transfers[src_buf[i]];
1402 }
1403 } else {
1404 fxcrt::spancpy(dest_buf, src_buf.first(dest_pitch * height));
1405 }
1406 return pMask;
1407 }
1408
GetBackColor(const CPDF_Dictionary * pSMaskDict,const CPDF_Dictionary * pGroupDict,CPDF_ColorSpace::Family * pCSFamily)1409 FX_ARGB CPDF_RenderStatus::GetBackColor(const CPDF_Dictionary* pSMaskDict,
1410 const CPDF_Dictionary* pGroupDict,
1411 CPDF_ColorSpace::Family* pCSFamily) {
1412 static constexpr FX_ARGB kDefaultColor = ArgbEncode(255, 0, 0, 0);
1413 RetainPtr<const CPDF_Array> pBC =
1414 pSMaskDict->GetArrayFor(pdfium::transparency::kBC);
1415 if (!pBC)
1416 return kDefaultColor;
1417
1418 RetainPtr<const CPDF_Object> pCSObj;
1419 RetainPtr<const CPDF_Dictionary> pGroup =
1420 pGroupDict ? pGroupDict->GetDictFor("Group") : nullptr;
1421 if (pGroup)
1422 pCSObj = pGroup->GetDirectObjectFor(pdfium::transparency::kCS);
1423 RetainPtr<CPDF_ColorSpace> pCS =
1424 CPDF_DocPageData::FromDocument(m_pContext->GetDocument())
1425 ->GetColorSpace(pCSObj.Get(), nullptr);
1426 if (!pCS)
1427 return kDefaultColor;
1428
1429 CPDF_ColorSpace::Family family = pCS->GetFamily();
1430 if (family == CPDF_ColorSpace::Family::kLab || pCS->IsSpecial() ||
1431 (family == CPDF_ColorSpace::Family::kICCBased && !pCS->IsNormal())) {
1432 return kDefaultColor;
1433 }
1434
1435 // Store Color Space Family to use in CPDF_RenderStatus::Initialize().
1436 *pCSFamily = family;
1437
1438 uint32_t comps = std::max(8u, pCS->CountComponents());
1439 size_t count = std::min<size_t>(8, pBC->size());
1440 std::vector<float> floats = ReadArrayElementsToVector(pBC.Get(), count);
1441 floats.resize(comps);
1442
1443 float R;
1444 float G;
1445 float B;
1446 pCS->GetRGB(floats, &R, &G, &B);
1447 return ArgbEncode(255, static_cast<int>(R * 255), static_cast<int>(G * 255),
1448 static_cast<int>(B * 255));
1449 }
1450