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