xref: /aosp_15_r20/external/pdfium/core/fpdfapi/render/cpdf_renderstatus.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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