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