• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fpdfapi/render/cpdf_renderstatus.h"
8 
9 #include <algorithm>
10 #include <cmath>
11 #include <limits>
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_pageobject.h"
33 #include "core/fpdfapi/page/cpdf_pathobject.h"
34 #include "core/fpdfapi/page/cpdf_shadingobject.h"
35 #include "core/fpdfapi/page/cpdf_shadingpattern.h"
36 #include "core/fpdfapi/page/cpdf_textobject.h"
37 #include "core/fpdfapi/page/cpdf_tilingpattern.h"
38 #include "core/fpdfapi/page/cpdf_transferfunc.h"
39 #include "core/fpdfapi/parser/cpdf_array.h"
40 #include "core/fpdfapi/parser/cpdf_document.h"
41 #include "core/fpdfapi/parser/cpdf_stream.h"
42 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
43 #include "core/fpdfapi/render/cpdf_charposlist.h"
44 #include "core/fpdfapi/render/cpdf_docrenderdata.h"
45 #include "core/fpdfapi/render/cpdf_imagerenderer.h"
46 #include "core/fpdfapi/render/cpdf_pagerendercache.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_scaledrenderbuffer.h"
51 #include "core/fpdfapi/render/cpdf_textrenderer.h"
52 #include "core/fpdfapi/render/cpdf_type3cache.h"
53 #include "core/fxcrt/autorestorer.h"
54 #include "core/fxcrt/fx_safe_types.h"
55 #include "core/fxcrt/fx_system.h"
56 #include "core/fxge/cfx_defaultrenderdevice.h"
57 #include "core/fxge/cfx_glyphbitmap.h"
58 #include "core/fxge/cfx_pathdata.h"
59 #include "core/fxge/dib/cfx_dibitmap.h"
60 #include "core/fxge/fx_font.h"
61 #include "core/fxge/renderdevicedriver_iface.h"
62 #include "core/fxge/text_char_pos.h"
63 #include "core/fxge/text_glyph_pos.h"
64 #include "third_party/base/compiler_specific.h"
65 #include "third_party/base/logging.h"
66 #include "third_party/base/numerics/safe_math.h"
67 #include "third_party/base/ptr_util.h"
68 #include "third_party/base/stl_util.h"
69 
70 #ifdef _SKIA_SUPPORT_
71 #include "core/fxge/skia/fx_skia_device.h"
72 #endif
73 
74 namespace {
75 
76 constexpr int kRenderMaxRecursionDepth = 64;
77 int g_CurrentRecursionDepth = 0;
78 
DrawPatternBitmap(CPDF_Document * pDoc,CPDF_PageRenderCache * pCache,CPDF_TilingPattern * pPattern,CPDF_Form * pPatternForm,const CFX_Matrix & mtObject2Device,int width,int height,const CPDF_RenderOptions::Options & draw_options)79 RetainPtr<CFX_DIBitmap> DrawPatternBitmap(
80     CPDF_Document* pDoc,
81     CPDF_PageRenderCache* pCache,
82     CPDF_TilingPattern* pPattern,
83     CPDF_Form* pPatternForm,
84     const CFX_Matrix& mtObject2Device,
85     int width,
86     int height,
87     const CPDF_RenderOptions::Options& draw_options) {
88   auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
89   if (!pBitmap->Create(width, height,
90                        pPattern->colored() ? FXDIB_Argb : FXDIB_8bppMask)) {
91     return nullptr;
92   }
93   CFX_DefaultRenderDevice bitmap_device;
94   bitmap_device.Attach(pBitmap, false, nullptr, false);
95   pBitmap->Clear(0);
96   CFX_FloatRect cell_bbox =
97       pPattern->pattern_to_form().TransformRect(pPattern->bbox());
98   cell_bbox = mtObject2Device.TransformRect(cell_bbox);
99   CFX_FloatRect bitmap_rect(0.0f, 0.0f, width, height);
100   CFX_Matrix mtAdjust;
101   mtAdjust.MatchRect(bitmap_rect, cell_bbox);
102 
103   CFX_Matrix mtPattern2Bitmap = mtObject2Device * mtAdjust;
104   CPDF_RenderOptions options;
105   if (!pPattern->colored())
106     options.SetColorMode(CPDF_RenderOptions::kAlpha);
107 
108   options.GetOptions() = draw_options;
109   options.GetOptions().bForceHalftone = true;
110 
111   CPDF_RenderContext context(pDoc, nullptr, pCache);
112   context.AppendLayer(pPatternForm, &mtPattern2Bitmap);
113   context.Render(&bitmap_device, &options, nullptr);
114 #if defined _SKIA_SUPPORT_PATHS_
115   bitmap_device.Flush(true);
116   pBitmap->UnPreMultiply();
117 #endif
118   return pBitmap;
119 }
120 
IsAvailableMatrix(const CFX_Matrix & matrix)121 bool IsAvailableMatrix(const CFX_Matrix& matrix) {
122   if (matrix.a == 0 || matrix.d == 0)
123     return matrix.b != 0 && matrix.c != 0;
124 
125   if (matrix.b == 0 || matrix.c == 0)
126     return matrix.a != 0 && matrix.d != 0;
127 
128   return true;
129 }
130 
MissingFillColor(const CPDF_ColorState * pColorState)131 bool MissingFillColor(const CPDF_ColorState* pColorState) {
132   return !pColorState->HasRef() || pColorState->GetFillColor()->IsNull();
133 }
134 
MissingStrokeColor(const CPDF_ColorState * pColorState)135 bool MissingStrokeColor(const CPDF_ColorState* pColorState) {
136   return !pColorState->HasRef() || pColorState->GetStrokeColor()->IsNull();
137 }
138 
Type3CharMissingFillColor(const CPDF_Type3Char * pChar,const CPDF_ColorState * pColorState)139 bool Type3CharMissingFillColor(const CPDF_Type3Char* pChar,
140                                const CPDF_ColorState* pColorState) {
141   return pChar && (!pChar->colored() || MissingFillColor(pColorState));
142 }
143 
Type3CharMissingStrokeColor(const CPDF_Type3Char * pChar,const CPDF_ColorState * pColorState)144 bool Type3CharMissingStrokeColor(const CPDF_Type3Char* pChar,
145                                  const CPDF_ColorState* pColorState) {
146   return pChar && (!pChar->colored() || MissingStrokeColor(pColorState));
147 }
148 
149 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
150 class ScopedSkiaDeviceFlush {
151  public:
ScopedSkiaDeviceFlush(CFX_RenderDevice * pDevice)152   explicit ScopedSkiaDeviceFlush(CFX_RenderDevice* pDevice)
153       : m_pDevice(pDevice) {}
154 
155   ScopedSkiaDeviceFlush(const ScopedSkiaDeviceFlush&) = delete;
156   ScopedSkiaDeviceFlush& operator=(const ScopedSkiaDeviceFlush&) = delete;
157 
~ScopedSkiaDeviceFlush()158   ~ScopedSkiaDeviceFlush() { m_pDevice->Flush(/*release=*/false); }
159 
160  private:
161   CFX_RenderDevice* const m_pDevice;
162 };
163 #endif
164 
165 }  // namespace
166 
CPDF_RenderStatus(CPDF_RenderContext * pContext,CFX_RenderDevice * pDevice)167 CPDF_RenderStatus::CPDF_RenderStatus(CPDF_RenderContext* pContext,
168                                      CFX_RenderDevice* pDevice)
169     : m_pContext(pContext), m_pDevice(pDevice) {}
170 
~CPDF_RenderStatus()171 CPDF_RenderStatus::~CPDF_RenderStatus() {}
172 
Initialize(const CPDF_RenderStatus * pParentStatus,const CPDF_GraphicStates * pInitialStates)173 void CPDF_RenderStatus::Initialize(const CPDF_RenderStatus* pParentStatus,
174                                    const CPDF_GraphicStates* pInitialStates) {
175   m_bPrint = m_pDevice->GetDeviceType() != DeviceType::kDisplay;
176   m_pPageResource.Reset(m_pContext->GetPageResources());
177   if (pInitialStates && !m_pType3Char) {
178     m_InitialStates.CopyStates(*pInitialStates);
179     if (pParentStatus) {
180       if (!m_InitialStates.m_ColorState.HasFillColor()) {
181         m_InitialStates.m_ColorState.SetFillColorRef(
182             pParentStatus->m_InitialStates.m_ColorState.GetFillColorRef());
183         *m_InitialStates.m_ColorState.GetMutableFillColor() =
184             *pParentStatus->m_InitialStates.m_ColorState.GetFillColor();
185       }
186       if (!m_InitialStates.m_ColorState.HasStrokeColor()) {
187         m_InitialStates.m_ColorState.SetStrokeColorRef(
188             pParentStatus->m_InitialStates.m_ColorState.GetFillColorRef());
189         *m_InitialStates.m_ColorState.GetMutableStrokeColor() =
190             *pParentStatus->m_InitialStates.m_ColorState.GetStrokeColor();
191       }
192     }
193   } else {
194     m_InitialStates.DefaultStates();
195   }
196 }
197 
RenderObjectList(const CPDF_PageObjectHolder * pObjectHolder,const CFX_Matrix & mtObj2Device)198 void CPDF_RenderStatus::RenderObjectList(
199     const CPDF_PageObjectHolder* pObjectHolder,
200     const CFX_Matrix& mtObj2Device) {
201 #if defined _SKIA_SUPPORT_
202   DebugVerifyDeviceIsPreMultiplied();
203 #endif
204   CFX_FloatRect clip_rect = mtObj2Device.GetInverse().TransformRect(
205       CFX_FloatRect(m_pDevice->GetClipBox()));
206   for (const auto& pCurObj : *pObjectHolder) {
207     if (pCurObj.get() == m_pStopObj) {
208       m_bStopped = true;
209       return;
210     }
211     if (!pCurObj)
212       continue;
213 
214     if (pCurObj->GetRect().left > clip_rect.right ||
215         pCurObj->GetRect().right < clip_rect.left ||
216         pCurObj->GetRect().bottom > clip_rect.top ||
217         pCurObj->GetRect().top < clip_rect.bottom) {
218       continue;
219     }
220     RenderSingleObject(pCurObj.get(), mtObj2Device);
221     if (m_bStopped)
222       return;
223   }
224 #if defined _SKIA_SUPPORT_
225   DebugVerifyDeviceIsPreMultiplied();
226 #endif
227 }
228 
RenderSingleObject(CPDF_PageObject * pObj,const CFX_Matrix & mtObj2Device)229 void CPDF_RenderStatus::RenderSingleObject(CPDF_PageObject* pObj,
230                                            const CFX_Matrix& mtObj2Device) {
231 #if defined _SKIA_SUPPORT_
232   DebugVerifyDeviceIsPreMultiplied();
233 #endif
234   AutoRestorer<int> restorer(&g_CurrentRecursionDepth);
235   if (++g_CurrentRecursionDepth > kRenderMaxRecursionDepth) {
236     return;
237   }
238   m_pCurObj = pObj;
239   if (m_Options.GetOCContext() &&
240       !m_Options.GetOCContext()->CheckObjectVisible(pObj)) {
241     return;
242   }
243   ProcessClipPath(pObj->m_ClipPath, mtObj2Device);
244   if (ProcessTransparency(pObj, mtObj2Device)) {
245     return;
246   }
247   ProcessObjectNoClip(pObj, mtObj2Device);
248 #if defined _SKIA_SUPPORT_
249   DebugVerifyDeviceIsPreMultiplied();
250 #endif
251 }
252 
ContinueSingleObject(CPDF_PageObject * pObj,const CFX_Matrix & mtObj2Device,PauseIndicatorIface * pPause)253 bool CPDF_RenderStatus::ContinueSingleObject(CPDF_PageObject* pObj,
254                                              const CFX_Matrix& mtObj2Device,
255                                              PauseIndicatorIface* pPause) {
256   if (m_pImageRenderer) {
257     if (m_pImageRenderer->Continue(pPause))
258       return true;
259 
260     if (!m_pImageRenderer->GetResult())
261       DrawObjWithBackground(pObj, mtObj2Device);
262     m_pImageRenderer.reset();
263     return false;
264   }
265 
266   m_pCurObj = pObj;
267   if (m_Options.GetOCContext() &&
268       !m_Options.GetOCContext()->CheckObjectVisible(pObj)) {
269     return false;
270   }
271 
272   ProcessClipPath(pObj->m_ClipPath, mtObj2Device);
273   if (ProcessTransparency(pObj, mtObj2Device))
274     return false;
275 
276   if (!pObj->IsImage()) {
277     ProcessObjectNoClip(pObj, mtObj2Device);
278     return false;
279   }
280 
281   m_pImageRenderer = pdfium::MakeUnique<CPDF_ImageRenderer>();
282   if (!m_pImageRenderer->Start(this, pObj->AsImage(), mtObj2Device, false,
283                                BlendMode::kNormal)) {
284     if (!m_pImageRenderer->GetResult())
285       DrawObjWithBackground(pObj, mtObj2Device);
286     m_pImageRenderer.reset();
287     return false;
288   }
289   return ContinueSingleObject(pObj, mtObj2Device, pPause);
290 }
291 
GetObjectClippedRect(const CPDF_PageObject * pObj,const CFX_Matrix & mtObj2Device) const292 FX_RECT CPDF_RenderStatus::GetObjectClippedRect(
293     const CPDF_PageObject* pObj,
294     const CFX_Matrix& mtObj2Device) const {
295   FX_RECT rect = pObj->GetTransformedBBox(mtObj2Device);
296   rect.Intersect(m_pDevice->GetClipBox());
297   return rect;
298 }
299 
ProcessObjectNoClip(CPDF_PageObject * pObj,const CFX_Matrix & mtObj2Device)300 void CPDF_RenderStatus::ProcessObjectNoClip(CPDF_PageObject* pObj,
301                                             const CFX_Matrix& mtObj2Device) {
302 #if defined _SKIA_SUPPORT_
303   DebugVerifyDeviceIsPreMultiplied();
304 #endif
305   bool bRet = false;
306   switch (pObj->GetType()) {
307     case CPDF_PageObject::TEXT:
308       bRet = ProcessText(pObj->AsText(), mtObj2Device, nullptr);
309       break;
310     case CPDF_PageObject::PATH:
311       bRet = ProcessPath(pObj->AsPath(), mtObj2Device);
312       break;
313     case CPDF_PageObject::IMAGE:
314       bRet = ProcessImage(pObj->AsImage(), mtObj2Device);
315       break;
316     case CPDF_PageObject::SHADING:
317       ProcessShading(pObj->AsShading(), mtObj2Device);
318       return;
319     case CPDF_PageObject::FORM:
320       bRet = ProcessForm(pObj->AsForm(), mtObj2Device);
321       break;
322   }
323   if (!bRet)
324     DrawObjWithBackground(pObj, mtObj2Device);
325 #if defined _SKIA_SUPPORT_
326   DebugVerifyDeviceIsPreMultiplied();
327 #endif
328 }
329 
DrawObjWithBlend(CPDF_PageObject * pObj,const CFX_Matrix & mtObj2Device)330 bool CPDF_RenderStatus::DrawObjWithBlend(CPDF_PageObject* pObj,
331                                          const CFX_Matrix& mtObj2Device) {
332   switch (pObj->GetType()) {
333     case CPDF_PageObject::PATH:
334       return ProcessPath(pObj->AsPath(), mtObj2Device);
335     case CPDF_PageObject::IMAGE:
336       return ProcessImage(pObj->AsImage(), mtObj2Device);
337     case CPDF_PageObject::FORM:
338       return ProcessForm(pObj->AsForm(), mtObj2Device);
339     default:
340       return false;
341   }
342 }
343 
DrawObjWithBackground(CPDF_PageObject * pObj,const CFX_Matrix & mtObj2Device)344 void CPDF_RenderStatus::DrawObjWithBackground(CPDF_PageObject* pObj,
345                                               const CFX_Matrix& mtObj2Device) {
346   FX_RECT rect = GetObjectClippedRect(pObj, mtObj2Device);
347   if (rect.IsEmpty())
348     return;
349 
350   int res = 300;
351   if (pObj->IsImage() && m_pDevice->GetDeviceType() == DeviceType::kPrinter)
352     res = 0;
353 
354   CPDF_ScaledRenderBuffer buffer;
355   if (!buffer.Initialize(m_pContext.Get(), m_pDevice, rect, pObj, &m_Options,
356                          res)) {
357     return;
358   }
359   CFX_Matrix matrix = mtObj2Device * buffer.GetMatrix();
360   const CPDF_Dictionary* pFormResource = nullptr;
361   const CPDF_FormObject* pFormObj = pObj->AsForm();
362   if (pFormObj)
363     pFormResource = pFormObj->form()->GetDict()->GetDictFor("Resources");
364   CPDF_RenderStatus status(m_pContext.Get(), buffer.GetDevice());
365   status.SetOptions(m_Options);
366   status.SetDeviceMatrix(buffer.GetMatrix());
367   status.SetTransparency(m_Transparency);
368   status.SetDropObjects(m_bDropObjects);
369   status.SetFormResource(pFormResource);
370   status.Initialize(nullptr, nullptr);
371   status.RenderSingleObject(pObj, matrix);
372   buffer.OutputToDevice();
373 }
374 
ProcessForm(const CPDF_FormObject * pFormObj,const CFX_Matrix & mtObj2Device)375 bool CPDF_RenderStatus::ProcessForm(const CPDF_FormObject* pFormObj,
376                                     const CFX_Matrix& mtObj2Device) {
377 #if defined _SKIA_SUPPORT_
378   DebugVerifyDeviceIsPreMultiplied();
379 #endif
380   const CPDF_Dictionary* pOC = pFormObj->form()->GetDict()->GetDictFor("OC");
381   if (pOC && m_Options.GetOCContext() &&
382       !m_Options.GetOCContext()->CheckOCGVisible(pOC)) {
383     return true;
384   }
385   CFX_Matrix matrix = pFormObj->form_matrix() * mtObj2Device;
386   const CPDF_Dictionary* pResources =
387       pFormObj->form()->GetDict()->GetDictFor("Resources");
388   CPDF_RenderStatus status(m_pContext.Get(), m_pDevice);
389   status.SetOptions(m_Options);
390   status.SetStopObject(m_pStopObj.Get());
391   status.SetTransparency(m_Transparency);
392   status.SetDropObjects(m_bDropObjects);
393   status.SetFormResource(pResources);
394   status.Initialize(this, pFormObj);
395   status.m_curBlend = m_curBlend;
396   {
397     CFX_RenderDevice::StateRestorer restorer(m_pDevice);
398     status.RenderObjectList(pFormObj->form(), matrix);
399     m_bStopped = status.m_bStopped;
400   }
401 #if defined _SKIA_SUPPORT_
402   DebugVerifyDeviceIsPreMultiplied();
403 #endif
404   return true;
405 }
406 
ProcessPath(CPDF_PathObject * pPathObj,const CFX_Matrix & mtObj2Device)407 bool CPDF_RenderStatus::ProcessPath(CPDF_PathObject* pPathObj,
408                                     const CFX_Matrix& mtObj2Device) {
409   int FillType = pPathObj->filltype();
410   bool bStroke = pPathObj->stroke();
411   ProcessPathPattern(pPathObj, mtObj2Device, &FillType, &bStroke);
412   if (FillType == 0 && !bStroke)
413     return true;
414 
415   uint32_t fill_argb = FillType ? GetFillArgb(pPathObj) : 0;
416   uint32_t stroke_argb = bStroke ? GetStrokeArgb(pPathObj) : 0;
417   CFX_Matrix path_matrix = pPathObj->matrix() * mtObj2Device;
418   if (!IsAvailableMatrix(path_matrix))
419     return true;
420 
421   if (FillType && m_Options.GetOptions().bRectAA)
422     FillType |= FXFILL_RECT_AA;
423   if (m_Options.GetOptions().bFillFullcover)
424     FillType |= FXFILL_FULLCOVER;
425   if (m_Options.GetOptions().bNoPathSmooth)
426     FillType |= FXFILL_NOPATHSMOOTH;
427   if (bStroke)
428     FillType |= FX_FILL_STROKE;
429 
430   const CPDF_PageObject* pPageObj =
431       static_cast<const CPDF_PageObject*>(pPathObj);
432   if (pPageObj->m_GeneralState.GetStrokeAdjust())
433     FillType |= FX_STROKE_ADJUST;
434   if (m_pType3Char)
435     FillType |= FX_FILL_TEXT_MODE;
436 
437   CFX_GraphState graphState = pPathObj->m_GraphState;
438   if (m_Options.GetOptions().bThinLine)
439     graphState.SetLineWidth(0);
440   return m_pDevice->DrawPathWithBlend(
441       pPathObj->path().GetObject(), &path_matrix, graphState.GetObject(),
442       fill_argb, stroke_argb, FillType, m_curBlend);
443 }
444 
GetTransferFunc(const CPDF_Object * pObj) const445 RetainPtr<CPDF_TransferFunc> CPDF_RenderStatus::GetTransferFunc(
446     const CPDF_Object* pObj) const {
447   ASSERT(pObj);
448   auto* pDocCache = CPDF_DocRenderData::FromDocument(m_pContext->GetDocument());
449   return pDocCache ? pDocCache->GetTransferFunc(pObj) : nullptr;
450 }
451 
GetFillArgbInternal(CPDF_PageObject * pObj,bool bType3) const452 FX_ARGB CPDF_RenderStatus::GetFillArgbInternal(CPDF_PageObject* pObj,
453                                                bool bType3) const {
454   const CPDF_ColorState* pColorState = &pObj->m_ColorState;
455   if (!bType3 && Type3CharMissingFillColor(m_pType3Char.Get(), pColorState))
456     return m_T3FillColor;
457 
458   if (MissingFillColor(pColorState))
459     pColorState = &m_InitialStates.m_ColorState;
460 
461   FX_COLORREF colorref = pColorState->GetFillColorRef();
462   if (colorref == 0xFFFFFFFF)
463     return 0;
464 
465   int32_t alpha =
466       static_cast<int32_t>((pObj->m_GeneralState.GetFillAlpha() * 255));
467   if (pObj->m_GeneralState.GetTR()) {
468     if (!pObj->m_GeneralState.GetTransferFunc()) {
469       pObj->m_GeneralState.SetTransferFunc(
470           GetTransferFunc(pObj->m_GeneralState.GetTR()));
471     }
472     if (pObj->m_GeneralState.GetTransferFunc()) {
473       colorref =
474           pObj->m_GeneralState.GetTransferFunc()->TranslateColor(colorref);
475     }
476   }
477   return m_Options.TranslateColor(AlphaAndColorRefToArgb(alpha, colorref));
478 }
479 
GetStrokeArgb(CPDF_PageObject * pObj) const480 FX_ARGB CPDF_RenderStatus::GetStrokeArgb(CPDF_PageObject* pObj) const {
481   const CPDF_ColorState* pColorState = &pObj->m_ColorState;
482   if (Type3CharMissingStrokeColor(m_pType3Char.Get(), pColorState))
483     return m_T3FillColor;
484 
485   if (MissingStrokeColor(pColorState))
486     pColorState = &m_InitialStates.m_ColorState;
487 
488   FX_COLORREF colorref = pColorState->GetStrokeColorRef();
489   if (colorref == 0xFFFFFFFF)
490     return 0;
491 
492   int32_t alpha = static_cast<int32_t>(pObj->m_GeneralState.GetStrokeAlpha() *
493                                        255);  // not rounded.
494   if (pObj->m_GeneralState.GetTR()) {
495     if (!pObj->m_GeneralState.GetTransferFunc()) {
496       pObj->m_GeneralState.SetTransferFunc(
497           GetTransferFunc(pObj->m_GeneralState.GetTR()));
498     }
499     if (pObj->m_GeneralState.GetTransferFunc()) {
500       colorref =
501           pObj->m_GeneralState.GetTransferFunc()->TranslateColor(colorref);
502     }
503   }
504   return m_Options.TranslateColor(AlphaAndColorRefToArgb(alpha, colorref));
505 }
506 
ProcessClipPath(const CPDF_ClipPath & ClipPath,const CFX_Matrix & mtObj2Device)507 void CPDF_RenderStatus::ProcessClipPath(const CPDF_ClipPath& ClipPath,
508                                         const CFX_Matrix& mtObj2Device) {
509   if (!ClipPath.HasRef()) {
510     if (m_LastClipPath.HasRef()) {
511       m_pDevice->RestoreState(true);
512       m_LastClipPath.SetNull();
513     }
514     return;
515   }
516   if (m_LastClipPath == ClipPath)
517     return;
518 
519   m_LastClipPath = ClipPath;
520   m_pDevice->RestoreState(true);
521   for (size_t i = 0; i < ClipPath.GetPathCount(); ++i) {
522     const CFX_PathData* pPathData = ClipPath.GetPath(i).GetObject();
523     if (!pPathData)
524       continue;
525 
526     if (pPathData->GetPoints().empty()) {
527       CFX_PathData EmptyPath;
528       EmptyPath.AppendRect(-1, -1, 0, 0);
529       m_pDevice->SetClip_PathFill(&EmptyPath, nullptr, FXFILL_WINDING);
530     } else {
531       m_pDevice->SetClip_PathFill(pPathData, &mtObj2Device,
532                                   ClipPath.GetClipType(i));
533     }
534   }
535 
536   if (ClipPath.GetTextCount() == 0)
537     return;
538 
539   if (m_pDevice->GetDeviceType() == DeviceType::kDisplay &&
540       !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)) {
541     return;
542   }
543 
544   std::unique_ptr<CFX_PathData> pTextClippingPath;
545   for (size_t i = 0; i < ClipPath.GetTextCount(); ++i) {
546     CPDF_TextObject* pText = ClipPath.GetText(i);
547     if (pText) {
548       if (!pTextClippingPath)
549         pTextClippingPath = pdfium::MakeUnique<CFX_PathData>();
550       ProcessText(pText, mtObj2Device, pTextClippingPath.get());
551       continue;
552     }
553 
554     if (!pTextClippingPath)
555       continue;
556 
557     int fill_mode = FXFILL_WINDING;
558     if (m_Options.GetOptions().bNoTextSmooth)
559       fill_mode |= FXFILL_NOPATHSMOOTH;
560     m_pDevice->SetClip_PathFill(pTextClippingPath.get(), nullptr, fill_mode);
561     pTextClippingPath.reset();
562   }
563 }
564 
ClipPattern(const CPDF_PageObject * pPageObj,const CFX_Matrix & mtObj2Device,bool bStroke)565 bool CPDF_RenderStatus::ClipPattern(const CPDF_PageObject* pPageObj,
566                                     const CFX_Matrix& mtObj2Device,
567                                     bool bStroke) {
568   if (pPageObj->IsPath())
569     return SelectClipPath(pPageObj->AsPath(), mtObj2Device, bStroke);
570   if (pPageObj->IsImage()) {
571     m_pDevice->SetClip_Rect(pPageObj->GetTransformedBBox(mtObj2Device));
572     return true;
573   }
574   return false;
575 }
576 
SelectClipPath(const CPDF_PathObject * pPathObj,const CFX_Matrix & mtObj2Device,bool bStroke)577 bool CPDF_RenderStatus::SelectClipPath(const CPDF_PathObject* pPathObj,
578                                        const CFX_Matrix& mtObj2Device,
579                                        bool bStroke) {
580   CFX_Matrix path_matrix = pPathObj->matrix() * mtObj2Device;
581   if (bStroke) {
582     CFX_GraphState graphState = pPathObj->m_GraphState;
583     if (m_Options.GetOptions().bThinLine)
584       graphState.SetLineWidth(0);
585     return m_pDevice->SetClip_PathStroke(pPathObj->path().GetObject(),
586                                          &path_matrix, graphState.GetObject());
587   }
588   int fill_mode = pPathObj->filltype();
589   if (m_Options.GetOptions().bNoPathSmooth) {
590     fill_mode |= FXFILL_NOPATHSMOOTH;
591   }
592   return m_pDevice->SetClip_PathFill(pPathObj->path().GetObject(), &path_matrix,
593                                      fill_mode);
594 }
595 
ProcessTransparency(CPDF_PageObject * pPageObj,const CFX_Matrix & mtObj2Device)596 bool CPDF_RenderStatus::ProcessTransparency(CPDF_PageObject* pPageObj,
597                                             const CFX_Matrix& mtObj2Device) {
598 #if defined _SKIA_SUPPORT_
599   DebugVerifyDeviceIsPreMultiplied();
600 #endif
601   BlendMode blend_type = pPageObj->m_GeneralState.GetBlendType();
602   CPDF_Dictionary* pSMaskDict =
603       ToDictionary(pPageObj->m_GeneralState.GetSoftMask());
604   if (pSMaskDict) {
605     if (pPageObj->IsImage() &&
606         pPageObj->AsImage()->GetImage()->GetDict()->KeyExist("SMask")) {
607       pSMaskDict = nullptr;
608     }
609   }
610   const CPDF_Dictionary* pFormResource = nullptr;
611   float group_alpha = 1.0f;
612   CPDF_Transparency transparency = m_Transparency;
613   bool bGroupTransparent = false;
614   const CPDF_FormObject* pFormObj = pPageObj->AsForm();
615   if (pFormObj) {
616     group_alpha = pFormObj->m_GeneralState.GetFillAlpha();
617     transparency = pFormObj->form()->GetTransparency();
618     bGroupTransparent = transparency.IsIsolated();
619     pFormResource = pFormObj->form()->GetDict()->GetDictFor("Resources");
620   }
621   bool bTextClip =
622       (pPageObj->m_ClipPath.HasRef() &&
623        pPageObj->m_ClipPath.GetTextCount() > 0 &&
624        m_pDevice->GetDeviceType() == DeviceType::kDisplay &&
625        !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP));
626   if (m_Options.GetOptions().bOverprint && pPageObj->IsImage() &&
627       pPageObj->m_GeneralState.GetFillOP() &&
628       pPageObj->m_GeneralState.GetStrokeOP()) {
629     CPDF_Document* pDocument = nullptr;
630     CPDF_Page* pPage = nullptr;
631     if (m_pContext->GetPageCache()) {
632       pPage = m_pContext->GetPageCache()->GetPage();
633       pDocument = pPage->GetDocument();
634     } else {
635       pDocument = pPageObj->AsImage()->GetImage()->GetDocument();
636     }
637     const CPDF_Dictionary* pPageResources =
638         pPage ? pPage->m_pPageResources.Get() : nullptr;
639     auto* pImageStream = pPageObj->AsImage()->GetImage()->GetStream();
640     const CPDF_Object* pCSObj =
641         pImageStream->GetDict()->GetDirectObjectFor("ColorSpace");
642     RetainPtr<CPDF_ColorSpace> pColorSpace =
643         CPDF_DocPageData::FromDocument(pDocument)->GetColorSpace(
644             pCSObj, pPageResources);
645     if (pColorSpace) {
646       int format = pColorSpace->GetFamily();
647       if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION ||
648           format == PDFCS_DEVICEN) {
649         blend_type = BlendMode::kDarken;
650       }
651     }
652   }
653   if (!pSMaskDict && group_alpha == 1.0f && blend_type == BlendMode::kNormal &&
654       !bTextClip && !bGroupTransparent) {
655     return false;
656   }
657   if (m_bPrint) {
658     bool bRet = false;
659     int rendCaps = m_pDevice->GetRenderCaps();
660     if (!(transparency.IsIsolated() || pSMaskDict || bTextClip) &&
661         (rendCaps & FXRC_BLEND_MODE)) {
662       BlendMode oldBlend = m_curBlend;
663       m_curBlend = blend_type;
664       bRet = DrawObjWithBlend(pPageObj, mtObj2Device);
665       m_curBlend = oldBlend;
666     }
667     if (!bRet) {
668       DrawObjWithBackground(pPageObj, mtObj2Device);
669     }
670     return true;
671   }
672   FX_RECT rect = pPageObj->GetTransformedBBox(mtObj2Device);
673   rect.Intersect(m_pDevice->GetClipBox());
674   if (rect.IsEmpty())
675     return true;
676 
677   int width = rect.Width();
678   int height = rect.Height();
679   CFX_DefaultRenderDevice bitmap_device;
680   RetainPtr<CFX_DIBitmap> backdrop;
681   if (!transparency.IsIsolated() &&
682       (m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) {
683     backdrop = pdfium::MakeRetain<CFX_DIBitmap>();
684     if (!m_pDevice->CreateCompatibleBitmap(backdrop, width, height))
685       return true;
686     m_pDevice->GetDIBits(backdrop, rect.left, rect.top);
687   }
688   if (!bitmap_device.Create(width, height, FXDIB_Argb, backdrop))
689     return true;
690 
691   RetainPtr<CFX_DIBitmap> bitmap = bitmap_device.GetBitmap();
692   bitmap->Clear(0);
693 
694   CFX_Matrix new_matrix = mtObj2Device;
695   new_matrix.Translate(-rect.left, -rect.top);
696 
697   RetainPtr<CFX_DIBitmap> pTextMask;
698   if (bTextClip) {
699     pTextMask = pdfium::MakeRetain<CFX_DIBitmap>();
700     if (!pTextMask->Create(width, height, FXDIB_8bppMask))
701       return true;
702 
703     pTextMask->Clear(0);
704     CFX_DefaultRenderDevice text_device;
705     text_device.Attach(pTextMask, false, nullptr, false);
706     for (size_t i = 0; i < pPageObj->m_ClipPath.GetTextCount(); ++i) {
707       CPDF_TextObject* textobj = pPageObj->m_ClipPath.GetText(i);
708       if (!textobj)
709         break;
710 
711       // TODO(thestig): Should we check the return value here?
712       CPDF_TextRenderer::DrawTextPath(
713           &text_device, textobj->GetCharCodes(), textobj->GetCharPositions(),
714           textobj->m_TextState.GetFont().Get(),
715           textobj->m_TextState.GetFontSize(), textobj->GetTextMatrix(),
716           &new_matrix, textobj->m_GraphState.GetObject(), 0xffffffff, 0,
717           nullptr, 0);
718     }
719   }
720   CPDF_RenderStatus bitmap_render(m_pContext.Get(), &bitmap_device);
721   bitmap_render.SetOptions(m_Options);
722   bitmap_render.SetStopObject(m_pStopObj.Get());
723   bitmap_render.SetStdCS(true);
724   bitmap_render.SetDropObjects(m_bDropObjects);
725   bitmap_render.SetFormResource(pFormResource);
726   bitmap_render.Initialize(nullptr, nullptr);
727   bitmap_render.ProcessObjectNoClip(pPageObj, new_matrix);
728 #if defined _SKIA_SUPPORT_PATHS_
729   bitmap_device.Flush(true);
730   bitmap->UnPreMultiply();
731 #endif
732   m_bStopped = bitmap_render.m_bStopped;
733   if (pSMaskDict) {
734     CFX_Matrix smask_matrix =
735         *pPageObj->m_GeneralState.GetSMaskMatrix() * mtObj2Device;
736     RetainPtr<CFX_DIBBase> pSMaskSource =
737         LoadSMask(pSMaskDict, &rect, &smask_matrix);
738     if (pSMaskSource)
739       bitmap->MultiplyAlpha(pSMaskSource);
740   }
741   if (pTextMask) {
742     bitmap->MultiplyAlpha(pTextMask);
743     pTextMask.Reset();
744   }
745   int32_t blitAlpha = 255;
746   if (group_alpha != 1.0f && transparency.IsGroup()) {
747     blitAlpha = (int32_t)(group_alpha * 255);
748 #ifndef _SKIA_SUPPORT_
749     bitmap->MultiplyAlpha(blitAlpha);
750     blitAlpha = 255;
751 #endif
752   }
753   transparency = m_Transparency;
754   if (pPageObj->IsForm()) {
755     transparency.SetGroup();
756   }
757   CompositeDIBitmap(bitmap, rect.left, rect.top, 0, blitAlpha, blend_type,
758                     transparency);
759 #if defined _SKIA_SUPPORT_
760   DebugVerifyDeviceIsPreMultiplied();
761 #endif
762   return true;
763 }
764 
GetBackdrop(const CPDF_PageObject * pObj,const FX_RECT & rect,bool bBackAlphaRequired,int * left,int * top)765 RetainPtr<CFX_DIBitmap> CPDF_RenderStatus::GetBackdrop(
766     const CPDF_PageObject* pObj,
767     const FX_RECT& rect,
768     bool bBackAlphaRequired,
769     int* left,
770     int* top) {
771   FX_RECT bbox = rect;
772   bbox.Intersect(m_pDevice->GetClipBox());
773   *left = bbox.left;
774   *top = bbox.top;
775   int width = bbox.Width();
776   int height = bbox.Height();
777   auto pBackdrop = pdfium::MakeRetain<CFX_DIBitmap>();
778   if (bBackAlphaRequired && !m_bDropObjects)
779     pBackdrop->Create(width, height, FXDIB_Argb);
780   else
781     m_pDevice->CreateCompatibleBitmap(pBackdrop, width, height);
782 
783   if (!pBackdrop->GetBuffer())
784     return nullptr;
785 
786   bool bNeedDraw;
787   if (pBackdrop->HasAlpha())
788     bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT);
789   else
790     bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS);
791 
792   if (!bNeedDraw) {
793     m_pDevice->GetDIBits(pBackdrop, *left, *top);
794     return pBackdrop;
795   }
796   CFX_Matrix FinalMatrix = m_DeviceMatrix;
797   FinalMatrix.Translate(-*left, -*top);
798   pBackdrop->Clear(pBackdrop->HasAlpha() ? 0 : 0xffffffff);
799 
800   CFX_DefaultRenderDevice device;
801   device.Attach(pBackdrop, false, nullptr, false);
802   m_pContext->Render(&device, pObj, &m_Options, &FinalMatrix);
803   return pBackdrop;
804 }
805 
CloneObjStates(const CPDF_GraphicStates * pSrcStates,bool bStroke)806 std::unique_ptr<CPDF_GraphicStates> CPDF_RenderStatus::CloneObjStates(
807     const CPDF_GraphicStates* pSrcStates,
808     bool bStroke) {
809   if (!pSrcStates)
810     return nullptr;
811 
812   auto pStates = pdfium::MakeUnique<CPDF_GraphicStates>();
813   pStates->CopyStates(*pSrcStates);
814   const CPDF_Color* pObjColor = bStroke
815                                     ? pSrcStates->m_ColorState.GetStrokeColor()
816                                     : pSrcStates->m_ColorState.GetFillColor();
817   if (!pObjColor->IsNull()) {
818     pStates->m_ColorState.SetFillColorRef(
819         bStroke ? pSrcStates->m_ColorState.GetStrokeColorRef()
820                 : pSrcStates->m_ColorState.GetFillColorRef());
821     pStates->m_ColorState.SetStrokeColorRef(
822         pStates->m_ColorState.GetFillColorRef());
823   }
824   return pStates;
825 }
826 
827 #if defined _SKIA_SUPPORT_
DebugVerifyDeviceIsPreMultiplied() const828 void CPDF_RenderStatus::DebugVerifyDeviceIsPreMultiplied() const {
829   m_pDevice->DebugVerifyBitmapIsPreMultiplied();
830 }
831 #endif
832 
ProcessText(CPDF_TextObject * textobj,const CFX_Matrix & mtObj2Device,CFX_PathData * pClippingPath)833 bool CPDF_RenderStatus::ProcessText(CPDF_TextObject* textobj,
834                                     const CFX_Matrix& mtObj2Device,
835                                     CFX_PathData* pClippingPath) {
836   if (textobj->GetCharCodes().empty())
837     return true;
838 
839   const TextRenderingMode text_render_mode = textobj->m_TextState.GetTextMode();
840   if (text_render_mode == TextRenderingMode::MODE_INVISIBLE)
841     return true;
842 
843   RetainPtr<CPDF_Font> pFont = textobj->m_TextState.GetFont();
844   if (pFont->IsType3Font())
845     return ProcessType3Text(textobj, mtObj2Device);
846 
847   bool bFill = false;
848   bool bStroke = false;
849   bool bClip = false;
850   if (pClippingPath) {
851     bClip = true;
852   } else {
853     switch (text_render_mode) {
854       case TextRenderingMode::MODE_FILL:
855       case TextRenderingMode::MODE_FILL_CLIP:
856         bFill = true;
857         break;
858       case TextRenderingMode::MODE_STROKE:
859       case TextRenderingMode::MODE_STROKE_CLIP:
860         if (pFont->HasFace())
861           bStroke = true;
862         else
863           bFill = true;
864         break;
865       case TextRenderingMode::MODE_FILL_STROKE:
866       case TextRenderingMode::MODE_FILL_STROKE_CLIP:
867         bFill = true;
868         if (pFont->HasFace())
869           bStroke = true;
870         break;
871       case TextRenderingMode::MODE_INVISIBLE:
872         // Already handled above, but the compiler is not smart enough to
873         // realize it.
874         NOTREACHED();
875         return true;
876       case TextRenderingMode::MODE_CLIP:
877         return true;
878       case TextRenderingMode::MODE_UNKNOWN:
879         NOTREACHED();
880         return false;
881     }
882   }
883   FX_ARGB stroke_argb = 0;
884   FX_ARGB fill_argb = 0;
885   bool bPattern = false;
886   if (bStroke) {
887     if (textobj->m_ColorState.GetStrokeColor()->IsPattern()) {
888       bPattern = true;
889     } else {
890       stroke_argb = GetStrokeArgb(textobj);
891     }
892   }
893   if (bFill) {
894     if (textobj->m_ColorState.GetFillColor()->IsPattern()) {
895       bPattern = true;
896     } else {
897       fill_argb = GetFillArgb(textobj);
898     }
899   }
900   CFX_Matrix text_matrix = textobj->GetTextMatrix();
901   if (!IsAvailableMatrix(text_matrix))
902     return true;
903 
904   float font_size = textobj->m_TextState.GetFontSize();
905   if (bPattern) {
906     DrawTextPathWithPattern(textobj, mtObj2Device, pFont.Get(), font_size,
907                             &text_matrix, bFill, bStroke);
908     return true;
909   }
910   if (bClip || bStroke) {
911     const CFX_Matrix* pDeviceMatrix = &mtObj2Device;
912     CFX_Matrix device_matrix;
913     if (bStroke) {
914       const float* pCTM = textobj->m_TextState.GetCTM();
915       if (pCTM[0] != 1.0f || pCTM[3] != 1.0f) {
916         CFX_Matrix ctm(pCTM[0], pCTM[1], pCTM[2], pCTM[3], 0, 0);
917         text_matrix *= ctm.GetInverse();
918         device_matrix = ctm * mtObj2Device;
919         pDeviceMatrix = &device_matrix;
920       }
921     }
922     int flag = 0;
923     if (bStroke && bFill) {
924       flag |= FX_FILL_STROKE;
925       flag |= FX_STROKE_TEXT_MODE;
926     }
927     if (textobj->m_GeneralState.GetStrokeAdjust())
928       flag |= FX_STROKE_ADJUST;
929     if (m_Options.GetOptions().bNoTextSmooth)
930       flag |= FXFILL_NOPATHSMOOTH;
931     return CPDF_TextRenderer::DrawTextPath(
932         m_pDevice, textobj->GetCharCodes(), textobj->GetCharPositions(),
933         pFont.Get(), font_size, text_matrix, pDeviceMatrix,
934         textobj->m_GraphState.GetObject(), fill_argb, stroke_argb,
935         pClippingPath, flag);
936   }
937   text_matrix.Concat(mtObj2Device);
938   return CPDF_TextRenderer::DrawNormalText(
939       m_pDevice, textobj->GetCharCodes(), textobj->GetCharPositions(),
940       pFont.Get(), font_size, text_matrix, fill_argb, m_Options);
941 }
942 
943 // TODO(npm): Font fallback for type 3 fonts? (Completely separate code!!)
ProcessType3Text(CPDF_TextObject * textobj,const CFX_Matrix & mtObj2Device)944 bool CPDF_RenderStatus::ProcessType3Text(CPDF_TextObject* textobj,
945                                          const CFX_Matrix& mtObj2Device) {
946   CPDF_Type3Font* pType3Font = textobj->m_TextState.GetFont()->AsType3Font();
947   if (pdfium::ContainsValue(m_Type3FontCache, pType3Font))
948     return true;
949 
950   DeviceType device_type = m_pDevice->GetDeviceType();
951   FX_ARGB fill_argb = GetFillArgbForType3(textobj);
952   int fill_alpha = FXARGB_A(fill_argb);
953   if (device_type != DeviceType::kDisplay && fill_alpha < 255)
954     return false;
955 
956   CFX_Matrix text_matrix = textobj->GetTextMatrix();
957   CFX_Matrix char_matrix = pType3Font->GetFontMatrix();
958   float font_size = textobj->m_TextState.GetFontSize();
959   char_matrix.Scale(font_size, font_size);
960 
961   // Must come before |glyphs|, because |glyphs| points into |refTypeCache|.
962   std::set<RetainPtr<CPDF_Type3Cache>> refTypeCache;
963   std::vector<TextGlyphPos> glyphs;
964   if (device_type == DeviceType::kDisplay)
965     glyphs.resize(textobj->GetCharCodes().size());
966 
967   for (size_t iChar = 0; iChar < textobj->GetCharCodes().size(); ++iChar) {
968     uint32_t charcode = textobj->GetCharCodes()[iChar];
969     if (charcode == static_cast<uint32_t>(-1))
970       continue;
971 
972     CPDF_Type3Char* pType3Char = pType3Font->LoadChar(charcode);
973     if (!pType3Char)
974       continue;
975 
976     CFX_Matrix matrix = char_matrix;
977     matrix.e += iChar > 0 ? textobj->GetCharPositions()[iChar - 1] : 0;
978     matrix.Concat(text_matrix);
979     matrix.Concat(mtObj2Device);
980     if (!pType3Char->LoadBitmapFromSoleImageOfForm()) {
981       if (!glyphs.empty()) {
982         for (size_t i = 0; i < iChar; ++i) {
983           const TextGlyphPos& glyph = glyphs[i];
984           if (!glyph.m_pGlyph)
985             continue;
986 
987           Optional<CFX_Point> point = glyph.GetOrigin({0, 0});
988           if (!point.has_value())
989             continue;
990 
991           m_pDevice->SetBitMask(glyph.m_pGlyph->GetBitmap(), point->x, point->y,
992                                 fill_argb);
993         }
994         glyphs.clear();
995       }
996 
997       std::unique_ptr<CPDF_GraphicStates> pStates =
998           CloneObjStates(textobj, false);
999       CPDF_RenderOptions options = m_Options;
1000       options.GetOptions().bForceHalftone = true;
1001       options.GetOptions().bRectAA = true;
1002 
1003       const auto* pForm = static_cast<const CPDF_Form*>(pType3Char->form());
1004       const CPDF_Dictionary* pFormResource =
1005           pForm->GetDict()->GetDictFor("Resources");
1006 
1007       if (fill_alpha == 255) {
1008         CPDF_RenderStatus status(m_pContext.Get(), m_pDevice);
1009         status.SetOptions(options);
1010         status.SetTransparency(pForm->GetTransparency());
1011         status.SetType3Char(pType3Char);
1012         status.SetFillColor(fill_argb);
1013         status.SetDropObjects(m_bDropObjects);
1014         status.SetFormResource(pFormResource);
1015         status.Initialize(this, pStates.get());
1016         status.m_Type3FontCache = m_Type3FontCache;
1017         status.m_Type3FontCache.push_back(pType3Font);
1018 
1019         CFX_RenderDevice::StateRestorer restorer(m_pDevice);
1020         status.RenderObjectList(pForm, matrix);
1021       } else {
1022         FX_RECT rect =
1023             matrix.TransformRect(pForm->CalcBoundingBox()).GetOuterRect();
1024         if (!rect.Valid())
1025           continue;
1026 
1027         CFX_DefaultRenderDevice bitmap_device;
1028         if (!bitmap_device.Create(rect.Width(), rect.Height(), FXDIB_Argb,
1029                                   nullptr)) {
1030           return true;
1031         }
1032         bitmap_device.GetBitmap()->Clear(0);
1033         CPDF_RenderStatus status(m_pContext.Get(), &bitmap_device);
1034         status.SetOptions(options);
1035         status.SetTransparency(pForm->GetTransparency());
1036         status.SetType3Char(pType3Char);
1037         status.SetFillColor(fill_argb);
1038         status.SetDropObjects(m_bDropObjects);
1039         status.SetFormResource(pFormResource);
1040         status.Initialize(this, pStates.get());
1041         status.m_Type3FontCache = m_Type3FontCache;
1042         status.m_Type3FontCache.push_back(pType3Font);
1043         matrix.Translate(-rect.left, -rect.top);
1044         status.RenderObjectList(pForm, matrix);
1045         m_pDevice->SetDIBits(bitmap_device.GetBitmap(), rect.left, rect.top);
1046       }
1047     } else if (pType3Char->GetBitmap()) {
1048       if (device_type == DeviceType::kDisplay) {
1049         CPDF_Document* pDoc = pType3Font->GetDocument();
1050         RetainPtr<CPDF_Type3Cache> pCache =
1051             CPDF_DocRenderData::FromDocument(pDoc)->GetCachedType3(pType3Font);
1052 
1053         const CFX_GlyphBitmap* pBitmap = pCache->LoadGlyph(charcode, &matrix);
1054         if (!pBitmap)
1055           continue;
1056 
1057         refTypeCache.insert(std::move(pCache));
1058 
1059         CFX_Point origin(FXSYS_roundf(matrix.e), FXSYS_roundf(matrix.f));
1060         if (glyphs.empty()) {
1061           FX_SAFE_INT32 left = origin.x;
1062           left += pBitmap->left();
1063           if (!left.IsValid())
1064             continue;
1065 
1066           FX_SAFE_INT32 top = origin.y;
1067           top -= pBitmap->top();
1068           if (!top.IsValid())
1069             continue;
1070 
1071           m_pDevice->SetBitMask(pBitmap->GetBitmap(), left.ValueOrDie(),
1072                                 top.ValueOrDie(), fill_argb);
1073         } else {
1074           glyphs[iChar].m_pGlyph = pBitmap;
1075           glyphs[iChar].m_Origin = origin;
1076         }
1077       } else {
1078         CFX_Matrix image_matrix = pType3Char->matrix() * matrix;
1079         CPDF_ImageRenderer renderer;
1080         if (renderer.Start(this, pType3Char->GetBitmap(), fill_argb, 255,
1081                            image_matrix, FXDIB_ResampleOptions(), false,
1082                            BlendMode::kNormal)) {
1083           renderer.Continue(nullptr);
1084         }
1085         if (!renderer.GetResult())
1086           return false;
1087       }
1088     }
1089   }
1090 
1091   if (glyphs.empty())
1092     return true;
1093 
1094   FX_RECT rect = GetGlyphsBBox(glyphs, 0);
1095   auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1096   if (!pBitmap->Create(rect.Width(), rect.Height(), FXDIB_8bppMask))
1097     return true;
1098 
1099   pBitmap->Clear(0);
1100   for (const TextGlyphPos& glyph : glyphs) {
1101     if (!glyph.m_pGlyph)
1102       continue;
1103 
1104     Optional<CFX_Point> point = glyph.GetOrigin({rect.left, rect.top});
1105     if (!point.has_value())
1106       continue;
1107 
1108     pBitmap->CompositeMask(
1109         point->x, point->y, glyph.m_pGlyph->GetBitmap()->GetWidth(),
1110         glyph.m_pGlyph->GetBitmap()->GetHeight(), glyph.m_pGlyph->GetBitmap(),
1111         fill_argb, 0, 0, BlendMode::kNormal, nullptr, false);
1112   }
1113   m_pDevice->SetBitMask(pBitmap, rect.left, rect.top, fill_argb);
1114   return true;
1115 }
1116 
DrawTextPathWithPattern(const CPDF_TextObject * textobj,const CFX_Matrix & mtObj2Device,CPDF_Font * pFont,float font_size,const CFX_Matrix * pTextMatrix,bool bFill,bool bStroke)1117 void CPDF_RenderStatus::DrawTextPathWithPattern(const CPDF_TextObject* textobj,
1118                                                 const CFX_Matrix& mtObj2Device,
1119                                                 CPDF_Font* pFont,
1120                                                 float font_size,
1121                                                 const CFX_Matrix* pTextMatrix,
1122                                                 bool bFill,
1123                                                 bool bStroke) {
1124   if (!bStroke) {
1125     std::vector<std::unique_ptr<CPDF_TextObject>> pCopy;
1126     pCopy.push_back(std::unique_ptr<CPDF_TextObject>(textobj->Clone()));
1127 
1128     CPDF_PathObject path;
1129     path.set_filltype(FXFILL_WINDING);
1130     path.m_ClipPath.CopyClipPath(m_LastClipPath);
1131     path.m_ClipPath.AppendTexts(&pCopy);
1132     path.m_ColorState = textobj->m_ColorState;
1133     path.m_GeneralState = textobj->m_GeneralState;
1134     path.path().AppendFloatRect(textobj->GetRect());
1135     path.SetRect(textobj->GetRect());
1136 
1137     AutoRestorer<UnownedPtr<const CPDF_PageObject>> restorer2(&m_pCurObj);
1138     RenderSingleObject(&path, mtObj2Device);
1139     return;
1140   }
1141   const CPDF_CharPosList CharPosList(
1142       textobj->GetCharCodes(), textobj->GetCharPositions(), pFont, font_size);
1143   for (const TextCharPos& charpos : CharPosList.Get()) {
1144     auto* font = charpos.m_FallbackFontPosition == -1
1145                      ? pFont->GetFont()
1146                      : pFont->GetFontFallback(charpos.m_FallbackFontPosition);
1147     const CFX_PathData* pPath =
1148         font->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth);
1149     if (!pPath)
1150       continue;
1151 
1152     CPDF_PathObject path;
1153     path.m_GraphState = textobj->m_GraphState;
1154     path.m_ColorState = textobj->m_ColorState;
1155 
1156     CFX_Matrix matrix;
1157     if (charpos.m_bGlyphAdjust) {
1158       matrix = CFX_Matrix(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
1159                           charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3],
1160                           0, 0);
1161     }
1162     matrix.Concat(CFX_Matrix(font_size, 0, 0, font_size, charpos.m_Origin.x,
1163                              charpos.m_Origin.y));
1164     path.set_stroke(bStroke);
1165     path.set_filltype(bFill ? FXFILL_WINDING : 0);
1166     path.path().Append(pPath, &matrix);
1167     path.set_matrix(*pTextMatrix);
1168     path.CalcBoundingBox();
1169     ProcessPath(&path, mtObj2Device);
1170   }
1171 }
1172 
DrawShadingPattern(CPDF_ShadingPattern * pattern,const CPDF_PageObject * pPageObj,const CFX_Matrix & mtObj2Device,bool bStroke)1173 void CPDF_RenderStatus::DrawShadingPattern(CPDF_ShadingPattern* pattern,
1174                                            const CPDF_PageObject* pPageObj,
1175                                            const CFX_Matrix& mtObj2Device,
1176                                            bool bStroke) {
1177   if (!pattern->Load())
1178     return;
1179 
1180   CFX_RenderDevice::StateRestorer restorer(m_pDevice);
1181   if (!ClipPattern(pPageObj, mtObj2Device, bStroke))
1182     return;
1183 
1184   FX_RECT rect = GetObjectClippedRect(pPageObj, mtObj2Device);
1185   if (rect.IsEmpty())
1186     return;
1187 
1188   CFX_Matrix matrix = pattern->pattern_to_form() * mtObj2Device;
1189   int alpha =
1190       FXSYS_roundf(255 * (bStroke ? pPageObj->m_GeneralState.GetStrokeAlpha()
1191                                   : pPageObj->m_GeneralState.GetFillAlpha()));
1192   CPDF_RenderShading::Draw(m_pDevice, m_pContext.Get(), m_pCurObj.Get(),
1193                            pattern, matrix, rect, alpha, m_Options);
1194 }
1195 
ProcessShading(const CPDF_ShadingObject * pShadingObj,const CFX_Matrix & mtObj2Device)1196 void CPDF_RenderStatus::ProcessShading(const CPDF_ShadingObject* pShadingObj,
1197                                        const CFX_Matrix& mtObj2Device) {
1198   FX_RECT rect = pShadingObj->GetTransformedBBox(mtObj2Device);
1199   FX_RECT clip_box = m_pDevice->GetClipBox();
1200   rect.Intersect(clip_box);
1201   if (rect.IsEmpty())
1202     return;
1203 
1204   CFX_Matrix matrix = pShadingObj->matrix() * mtObj2Device;
1205   CPDF_RenderShading::Draw(
1206       m_pDevice, m_pContext.Get(), m_pCurObj.Get(), pShadingObj->pattern(),
1207       matrix, rect,
1208       FXSYS_roundf(255 * pShadingObj->m_GeneralState.GetFillAlpha()),
1209       m_Options);
1210 }
1211 
DrawTilingPattern(CPDF_TilingPattern * pPattern,CPDF_PageObject * pPageObj,const CFX_Matrix & mtObj2Device,bool bStroke)1212 void CPDF_RenderStatus::DrawTilingPattern(CPDF_TilingPattern* pPattern,
1213                                           CPDF_PageObject* pPageObj,
1214                                           const CFX_Matrix& mtObj2Device,
1215                                           bool bStroke) {
1216   const std::unique_ptr<CPDF_Form> pPatternForm = pPattern->Load(pPageObj);
1217   if (!pPatternForm)
1218     return;
1219 
1220   CFX_RenderDevice::StateRestorer restorer(m_pDevice);
1221 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1222   ScopedSkiaDeviceFlush scoped_skia_device_flush(m_pDevice);
1223 #endif
1224   if (!ClipPattern(pPageObj, mtObj2Device, bStroke))
1225     return;
1226 
1227   FX_RECT clip_box = m_pDevice->GetClipBox();
1228   if (clip_box.IsEmpty())
1229     return;
1230 
1231   const CFX_Matrix mtPattern2Device =
1232       pPattern->pattern_to_form() * mtObj2Device;
1233 
1234   CFX_FloatRect cell_bbox = mtPattern2Device.TransformRect(pPattern->bbox());
1235 
1236   float ceil_height = std::ceil(cell_bbox.Height());
1237   float ceil_width = std::ceil(cell_bbox.Width());
1238 
1239   // Validate the float will fit into the int when the conversion is done.
1240   if (!pdfium::base::IsValueInRangeForNumericType<int>(ceil_height) ||
1241       !pdfium::base::IsValueInRangeForNumericType<int>(ceil_width)) {
1242     return;
1243   }
1244 
1245   int width = static_cast<int>(ceil_width);
1246   int height = static_cast<int>(ceil_height);
1247   if (width <= 0)
1248     width = 1;
1249   if (height <= 0)
1250     height = 1;
1251 
1252   CFX_FloatRect clip_box_p =
1253       mtPattern2Device.GetInverse().TransformRect(CFX_FloatRect(clip_box));
1254   int min_col = static_cast<int>(
1255       ceil((clip_box_p.left - pPattern->bbox().right) / pPattern->x_step()));
1256   int max_col = static_cast<int>(
1257       floor((clip_box_p.right - pPattern->bbox().left) / pPattern->x_step()));
1258   int min_row = static_cast<int>(
1259       ceil((clip_box_p.bottom - pPattern->bbox().top) / pPattern->y_step()));
1260   int max_row = static_cast<int>(
1261       floor((clip_box_p.top - pPattern->bbox().bottom) / pPattern->y_step()));
1262 
1263   // Make sure we can fit the needed width * height into an int.
1264   if (height > std::numeric_limits<int>::max() / width)
1265     return;
1266 
1267   if (width > clip_box.Width() || height > clip_box.Height() ||
1268       width * height > clip_box.Width() * clip_box.Height()) {
1269     std::unique_ptr<CPDF_GraphicStates> pStates;
1270     if (!pPattern->colored())
1271       pStates = CloneObjStates(pPageObj, bStroke);
1272 
1273     const CPDF_Dictionary* pFormDict = pPatternForm->GetDict();
1274     const CPDF_Dictionary* pFormResource =
1275         pFormDict ? pFormDict->GetDictFor("Resources") : nullptr;
1276     for (int col = min_col; col <= max_col; col++) {
1277       for (int row = min_row; row <= max_row; row++) {
1278         CFX_PointF original = mtPattern2Device.Transform(
1279             CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step()));
1280         CFX_Matrix matrix = mtObj2Device;
1281         matrix.Translate(original.x - mtPattern2Device.e,
1282                          original.y - mtPattern2Device.f);
1283         CFX_RenderDevice::StateRestorer restorer2(m_pDevice);
1284         CPDF_RenderStatus status(m_pContext.Get(), m_pDevice);
1285         status.SetOptions(m_Options);
1286         status.SetTransparency(pPatternForm->GetTransparency());
1287         status.SetFormResource(pFormResource);
1288         status.SetDropObjects(m_bDropObjects);
1289         status.Initialize(this, pStates.get());
1290         status.RenderObjectList(pPatternForm.get(), matrix);
1291       }
1292     }
1293     return;
1294   }
1295 
1296   bool bAligned =
1297       pPattern->bbox().left == 0 && pPattern->bbox().bottom == 0 &&
1298       pPattern->bbox().right == pPattern->x_step() &&
1299       pPattern->bbox().top == pPattern->y_step() &&
1300       (mtPattern2Device.IsScaled() || mtPattern2Device.Is90Rotated());
1301   if (bAligned) {
1302     int orig_x = FXSYS_roundf(mtPattern2Device.e);
1303     int orig_y = FXSYS_roundf(mtPattern2Device.f);
1304     min_col = (clip_box.left - orig_x) / width;
1305     if (clip_box.left < orig_x)
1306       min_col--;
1307 
1308     max_col = (clip_box.right - orig_x) / width;
1309     if (clip_box.right <= orig_x)
1310       max_col--;
1311 
1312     min_row = (clip_box.top - orig_y) / height;
1313     if (clip_box.top < orig_y)
1314       min_row--;
1315 
1316     max_row = (clip_box.bottom - orig_y) / height;
1317     if (clip_box.bottom <= orig_y)
1318       max_row--;
1319   }
1320   float left_offset = cell_bbox.left - mtPattern2Device.e;
1321   float top_offset = cell_bbox.bottom - mtPattern2Device.f;
1322   RetainPtr<CFX_DIBitmap> pPatternBitmap;
1323   if (width * height < 16) {
1324     RetainPtr<CFX_DIBitmap> pEnlargedBitmap = DrawPatternBitmap(
1325         m_pContext->GetDocument(), m_pContext->GetPageCache(), pPattern,
1326         pPatternForm.get(), mtObj2Device, 8, 8, m_Options.GetOptions());
1327     pPatternBitmap = pEnlargedBitmap->StretchTo(
1328         width, height, FXDIB_ResampleOptions(), nullptr);
1329   } else {
1330     pPatternBitmap =
1331         DrawPatternBitmap(m_pContext->GetDocument(), m_pContext->GetPageCache(),
1332                           pPattern, pPatternForm.get(), mtObj2Device, width,
1333                           height, m_Options.GetOptions());
1334   }
1335   if (!pPatternBitmap)
1336     return;
1337 
1338   if (m_Options.ColorModeIs(CPDF_RenderOptions::kGray))
1339     pPatternBitmap->ConvertColorScale(0, 0xffffff);
1340 
1341   FX_ARGB fill_argb = GetFillArgb(pPageObj);
1342   int clip_width = clip_box.right - clip_box.left;
1343   int clip_height = clip_box.bottom - clip_box.top;
1344   auto pScreen = pdfium::MakeRetain<CFX_DIBitmap>();
1345   if (!pScreen->Create(clip_width, clip_height, FXDIB_Argb))
1346     return;
1347 
1348   pScreen->Clear(0);
1349   const uint8_t* const src_buf = pPatternBitmap->GetBuffer();
1350   for (int col = min_col; col <= max_col; col++) {
1351     for (int row = min_row; row <= max_row; row++) {
1352       int start_x;
1353       int start_y;
1354       if (bAligned) {
1355         start_x =
1356             FXSYS_roundf(mtPattern2Device.e) + col * width - clip_box.left;
1357         start_y =
1358             FXSYS_roundf(mtPattern2Device.f) + row * height - clip_box.top;
1359       } else {
1360         CFX_PointF original = mtPattern2Device.Transform(
1361             CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step()));
1362 
1363         pdfium::base::CheckedNumeric<int> safeStartX =
1364             FXSYS_roundf(original.x + left_offset);
1365         pdfium::base::CheckedNumeric<int> safeStartY =
1366             FXSYS_roundf(original.y + top_offset);
1367 
1368         safeStartX -= clip_box.left;
1369         safeStartY -= clip_box.top;
1370         if (!safeStartX.IsValid() || !safeStartY.IsValid())
1371           return;
1372 
1373         start_x = safeStartX.ValueOrDie();
1374         start_y = safeStartY.ValueOrDie();
1375       }
1376       if (width == 1 && height == 1) {
1377         if (start_x < 0 || start_x >= clip_box.Width() || start_y < 0 ||
1378             start_y >= clip_box.Height()) {
1379           continue;
1380         }
1381         uint32_t* dest_buf = reinterpret_cast<uint32_t*>(
1382             pScreen->GetBuffer() + pScreen->GetPitch() * start_y + start_x * 4);
1383         if (pPattern->colored()) {
1384           const auto* src_buf32 = reinterpret_cast<const uint32_t*>(src_buf);
1385           *dest_buf = *src_buf32;
1386         } else {
1387           *dest_buf = (*src_buf << 24) | (fill_argb & 0xffffff);
1388         }
1389       } else {
1390         if (pPattern->colored()) {
1391           pScreen->CompositeBitmap(start_x, start_y, width, height,
1392                                    pPatternBitmap, 0, 0, BlendMode::kNormal,
1393                                    nullptr, false);
1394         } else {
1395           pScreen->CompositeMask(start_x, start_y, width, height,
1396                                  pPatternBitmap, fill_argb, 0, 0,
1397                                  BlendMode::kNormal, nullptr, false);
1398         }
1399       }
1400     }
1401   }
1402   CompositeDIBitmap(pScreen, clip_box.left, clip_box.top, 0, 255,
1403                     BlendMode::kNormal, CPDF_Transparency());
1404 }
1405 
DrawPathWithPattern(CPDF_PathObject * pPathObj,const CFX_Matrix & mtObj2Device,const CPDF_Color * pColor,bool bStroke)1406 void CPDF_RenderStatus::DrawPathWithPattern(CPDF_PathObject* pPathObj,
1407                                             const CFX_Matrix& mtObj2Device,
1408                                             const CPDF_Color* pColor,
1409                                             bool bStroke) {
1410   CPDF_Pattern* pattern = pColor->GetPattern();
1411   if (!pattern)
1412     return;
1413 
1414   if (CPDF_TilingPattern* pTilingPattern = pattern->AsTilingPattern())
1415     DrawTilingPattern(pTilingPattern, pPathObj, mtObj2Device, bStroke);
1416   else if (CPDF_ShadingPattern* pShadingPattern = pattern->AsShadingPattern())
1417     DrawShadingPattern(pShadingPattern, pPathObj, mtObj2Device, bStroke);
1418 }
1419 
ProcessPathPattern(CPDF_PathObject * pPathObj,const CFX_Matrix & mtObj2Device,int * filltype,bool * bStroke)1420 void CPDF_RenderStatus::ProcessPathPattern(CPDF_PathObject* pPathObj,
1421                                            const CFX_Matrix& mtObj2Device,
1422                                            int* filltype,
1423                                            bool* bStroke) {
1424   ASSERT(filltype);
1425   ASSERT(bStroke);
1426 
1427   if (*filltype) {
1428     const CPDF_Color& FillColor = *pPathObj->m_ColorState.GetFillColor();
1429     if (FillColor.IsPattern()) {
1430       DrawPathWithPattern(pPathObj, mtObj2Device, &FillColor, false);
1431       *filltype = 0;
1432     }
1433   }
1434   if (*bStroke) {
1435     const CPDF_Color& StrokeColor = *pPathObj->m_ColorState.GetStrokeColor();
1436     if (StrokeColor.IsPattern()) {
1437       DrawPathWithPattern(pPathObj, mtObj2Device, &StrokeColor, true);
1438       *bStroke = false;
1439     }
1440   }
1441 }
1442 
ProcessImage(CPDF_ImageObject * pImageObj,const CFX_Matrix & mtObj2Device)1443 bool CPDF_RenderStatus::ProcessImage(CPDF_ImageObject* pImageObj,
1444                                      const CFX_Matrix& mtObj2Device) {
1445   CPDF_ImageRenderer render;
1446   if (render.Start(this, pImageObj, mtObj2Device, m_bStdCS, m_curBlend))
1447     render.Continue(nullptr);
1448   return render.GetResult();
1449 }
1450 
CompositeDIBitmap(const RetainPtr<CFX_DIBitmap> & pDIBitmap,int left,int top,FX_ARGB mask_argb,int bitmap_alpha,BlendMode blend_mode,const CPDF_Transparency & transparency)1451 void CPDF_RenderStatus::CompositeDIBitmap(
1452     const RetainPtr<CFX_DIBitmap>& pDIBitmap,
1453     int left,
1454     int top,
1455     FX_ARGB mask_argb,
1456     int bitmap_alpha,
1457     BlendMode blend_mode,
1458     const CPDF_Transparency& transparency) {
1459   if (!pDIBitmap)
1460     return;
1461 
1462   if (blend_mode == BlendMode::kNormal) {
1463     if (!pDIBitmap->IsAlphaMask()) {
1464       if (bitmap_alpha < 255) {
1465 #ifdef _SKIA_SUPPORT_
1466         std::unique_ptr<CFX_ImageRenderer> dummy;
1467         CFX_Matrix m = CFX_RenderDevice::GetFlipMatrix(
1468             pDIBitmap->GetWidth(), pDIBitmap->GetHeight(), left, top);
1469         m_pDevice->StartDIBits(pDIBitmap, bitmap_alpha, 0, m,
1470                                FXDIB_ResampleOptions(), &dummy);
1471         return;
1472 #else
1473         pDIBitmap->MultiplyAlpha(bitmap_alpha);
1474 #endif
1475       }
1476 #ifdef _SKIA_SUPPORT_
1477       CFX_SkiaDeviceDriver::PreMultiply(pDIBitmap);
1478 #endif
1479       if (m_pDevice->SetDIBits(pDIBitmap, left, top)) {
1480         return;
1481       }
1482     } else {
1483       uint32_t fill_argb = m_Options.TranslateColor(mask_argb);
1484       if (bitmap_alpha < 255) {
1485         uint8_t* fill_argb8 = reinterpret_cast<uint8_t*>(&fill_argb);
1486         fill_argb8[3] *= bitmap_alpha / 255;
1487       }
1488       if (m_pDevice->SetBitMask(pDIBitmap, left, top, fill_argb)) {
1489         return;
1490       }
1491     }
1492   }
1493   bool bIsolated = transparency.IsIsolated();
1494   bool bBackAlphaRequired =
1495       blend_mode != BlendMode::kNormal && bIsolated && !m_bDropObjects;
1496   bool bGetBackGround =
1497       ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) ||
1498       (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) &&
1499        (m_pDevice->GetRenderCaps() & FXRC_GET_BITS) && !bBackAlphaRequired);
1500   if (bGetBackGround) {
1501     if (bIsolated || !transparency.IsGroup()) {
1502       if (!pDIBitmap->IsAlphaMask())
1503         m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, blend_mode);
1504       return;
1505     }
1506 
1507     FX_RECT rect(left, top, left + pDIBitmap->GetWidth(),
1508                  top + pDIBitmap->GetHeight());
1509     rect.Intersect(m_pDevice->GetClipBox());
1510     RetainPtr<CFX_DIBitmap> pClone;
1511     if (m_pDevice->GetBackDrop() && m_pDevice->GetBitmap()) {
1512       pClone = m_pDevice->GetBackDrop()->Clone(&rect);
1513       if (!pClone)
1514         return;
1515 
1516       RetainPtr<CFX_DIBitmap> pForeBitmap = m_pDevice->GetBitmap();
1517       pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(),
1518                               pForeBitmap, rect.left, rect.top,
1519                               BlendMode::kNormal, nullptr, false);
1520       left = std::min(left, 0);
1521       top = std::min(top, 0);
1522       if (pDIBitmap->IsAlphaMask()) {
1523         pClone->CompositeMask(0, 0, pClone->GetWidth(), pClone->GetHeight(),
1524                               pDIBitmap, mask_argb, left, top, blend_mode,
1525                               nullptr, false);
1526       } else {
1527         pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(),
1528                                 pDIBitmap, left, top, blend_mode, nullptr,
1529                                 false);
1530       }
1531     } else {
1532       pClone = pDIBitmap;
1533     }
1534     if (m_pDevice->GetBackDrop()) {
1535       m_pDevice->SetDIBits(pClone, rect.left, rect.top);
1536     } else {
1537       if (!pDIBitmap->IsAlphaMask()) {
1538         m_pDevice->SetDIBitsWithBlend(pDIBitmap, rect.left, rect.top,
1539                                       blend_mode);
1540       }
1541     }
1542     return;
1543   }
1544   int back_left;
1545   int back_top;
1546   FX_RECT rect(left, top, left + pDIBitmap->GetWidth(),
1547                top + pDIBitmap->GetHeight());
1548   RetainPtr<CFX_DIBitmap> pBackdrop = GetBackdrop(
1549       m_pCurObj.Get(), rect, blend_mode != BlendMode::kNormal && bIsolated,
1550       &back_left, &back_top);
1551   if (!pBackdrop)
1552     return;
1553 
1554   if (pDIBitmap->IsAlphaMask()) {
1555     pBackdrop->CompositeMask(left - back_left, top - back_top,
1556                              pDIBitmap->GetWidth(), pDIBitmap->GetHeight(),
1557                              pDIBitmap, mask_argb, 0, 0, blend_mode, nullptr,
1558                              false);
1559   } else {
1560     pBackdrop->CompositeBitmap(left - back_left, top - back_top,
1561                                pDIBitmap->GetWidth(), pDIBitmap->GetHeight(),
1562                                pDIBitmap, 0, 0, blend_mode, nullptr, false);
1563   }
1564 
1565   auto pBackdrop1 = pdfium::MakeRetain<CFX_DIBitmap>();
1566   pBackdrop1->Create(pBackdrop->GetWidth(), pBackdrop->GetHeight(),
1567                      FXDIB_Rgb32);
1568   pBackdrop1->Clear((uint32_t)-1);
1569   pBackdrop1->CompositeBitmap(0, 0, pBackdrop->GetWidth(),
1570                               pBackdrop->GetHeight(), pBackdrop, 0, 0,
1571                               BlendMode::kNormal, nullptr, false);
1572   pBackdrop = std::move(pBackdrop1);
1573   m_pDevice->SetDIBits(pBackdrop, back_left, back_top);
1574 }
1575 
LoadSMask(CPDF_Dictionary * pSMaskDict,FX_RECT * pClipRect,const CFX_Matrix * pMatrix)1576 RetainPtr<CFX_DIBitmap> CPDF_RenderStatus::LoadSMask(
1577     CPDF_Dictionary* pSMaskDict,
1578     FX_RECT* pClipRect,
1579     const CFX_Matrix* pMatrix) {
1580   if (!pSMaskDict)
1581     return nullptr;
1582 
1583   CPDF_Stream* pGroup = pSMaskDict->GetStreamFor(pdfium::transparency::kG);
1584   if (!pGroup)
1585     return nullptr;
1586 
1587   std::unique_ptr<CPDF_Function> pFunc;
1588   const CPDF_Object* pFuncObj =
1589       pSMaskDict->GetDirectObjectFor(pdfium::transparency::kTR);
1590   if (pFuncObj && (pFuncObj->IsDictionary() || pFuncObj->IsStream()))
1591     pFunc = CPDF_Function::Load(pFuncObj);
1592 
1593   CFX_Matrix matrix = *pMatrix;
1594   matrix.Translate(-pClipRect->left, -pClipRect->top);
1595 
1596   CPDF_Form form(m_pContext->GetDocument(), m_pContext->GetPageResources(),
1597                  pGroup);
1598   form.ParseContent();
1599 
1600   CFX_DefaultRenderDevice bitmap_device;
1601   bool bLuminosity =
1602       pSMaskDict->GetStringFor(pdfium::transparency::kSoftMaskSubType) !=
1603       pdfium::transparency::kAlpha;
1604   int width = pClipRect->right - pClipRect->left;
1605   int height = pClipRect->bottom - pClipRect->top;
1606   FXDIB_Format format;
1607 #if defined(OS_MACOSX) || defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_
1608   format = bLuminosity ? FXDIB_Rgb32 : FXDIB_8bppMask;
1609 #else
1610   format = bLuminosity ? FXDIB_Rgb : FXDIB_8bppMask;
1611 #endif
1612   if (!bitmap_device.Create(width, height, format, nullptr))
1613     return nullptr;
1614 
1615   RetainPtr<CFX_DIBitmap> bitmap = bitmap_device.GetBitmap();
1616   int nCSFamily = 0;
1617   if (bLuminosity) {
1618     FX_ARGB back_color =
1619         GetBackColor(pSMaskDict, pGroup->GetDict(), &nCSFamily);
1620     bitmap->Clear(back_color);
1621   } else {
1622     bitmap->Clear(0);
1623   }
1624 
1625   const CPDF_Dictionary* pFormResource =
1626       form.GetDict()->GetDictFor("Resources");
1627   CPDF_RenderOptions options;
1628   options.SetColorMode(bLuminosity ? CPDF_RenderOptions::kNormal
1629                                    : CPDF_RenderOptions::kAlpha);
1630   CPDF_RenderStatus status(m_pContext.Get(), &bitmap_device);
1631   status.SetOptions(options);
1632   status.SetGroupFamily(nCSFamily);
1633   status.SetLoadMask(bLuminosity);
1634   status.SetStdCS(true);
1635   status.SetFormResource(pFormResource);
1636   status.SetDropObjects(m_bDropObjects);
1637   status.Initialize(nullptr, nullptr);
1638   status.RenderObjectList(&form, matrix);
1639 
1640   auto pMask = pdfium::MakeRetain<CFX_DIBitmap>();
1641   if (!pMask->Create(width, height, FXDIB_8bppMask))
1642     return nullptr;
1643 
1644   uint8_t* dest_buf = pMask->GetBuffer();
1645   int dest_pitch = pMask->GetPitch();
1646   uint8_t* src_buf = bitmap->GetBuffer();
1647   int src_pitch = bitmap->GetPitch();
1648   std::vector<uint8_t> transfers(256);
1649   if (pFunc) {
1650     std::vector<float> results(pFunc->CountOutputs());
1651     for (size_t i = 0; i < transfers.size(); ++i) {
1652       float input = i / 255.0f;
1653       int nresult;
1654       pFunc->Call(&input, 1, results.data(), &nresult);
1655       transfers[i] = FXSYS_roundf(results[0] * 255);
1656     }
1657   } else {
1658     // Fill |transfers| with 0, 1, ... N.
1659     std::iota(transfers.begin(), transfers.end(), 0);
1660   }
1661   if (bLuminosity) {
1662     int Bpp = bitmap->GetBPP() / 8;
1663     for (int row = 0; row < height; row++) {
1664       uint8_t* dest_pos = dest_buf + row * dest_pitch;
1665       uint8_t* src_pos = src_buf + row * src_pitch;
1666       for (int col = 0; col < width; col++) {
1667         *dest_pos++ = transfers[FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos)];
1668         src_pos += Bpp;
1669       }
1670     }
1671   } else if (pFunc) {
1672     int size = dest_pitch * height;
1673     for (int i = 0; i < size; i++) {
1674       dest_buf[i] = transfers[src_buf[i]];
1675     }
1676   } else {
1677     memcpy(dest_buf, src_buf, dest_pitch * height);
1678   }
1679   return pMask;
1680 }
1681 
GetBackColor(const CPDF_Dictionary * pSMaskDict,const CPDF_Dictionary * pGroupDict,int * pCSFamily)1682 FX_ARGB CPDF_RenderStatus::GetBackColor(const CPDF_Dictionary* pSMaskDict,
1683                                         const CPDF_Dictionary* pGroupDict,
1684                                         int* pCSFamily) {
1685   static constexpr FX_ARGB kDefaultColor = ArgbEncode(255, 0, 0, 0);
1686   const CPDF_Array* pBC = pSMaskDict->GetArrayFor(pdfium::transparency::kBC);
1687   if (!pBC)
1688     return kDefaultColor;
1689 
1690   const CPDF_Object* pCSObj = nullptr;
1691   const CPDF_Dictionary* pGroup =
1692       pGroupDict ? pGroupDict->GetDictFor("Group") : nullptr;
1693   if (pGroup)
1694     pCSObj = pGroup->GetDirectObjectFor(pdfium::transparency::kCS);
1695   RetainPtr<CPDF_ColorSpace> pCS =
1696       CPDF_DocPageData::FromDocument(m_pContext->GetDocument())
1697           ->GetColorSpace(pCSObj, nullptr);
1698   if (!pCS)
1699     return kDefaultColor;
1700 
1701   int family = pCS->GetFamily();
1702   if (family == PDFCS_LAB || pCS->IsSpecial() ||
1703       (family == PDFCS_ICCBASED && !pCS->IsNormal())) {
1704     return kDefaultColor;
1705   }
1706 
1707   // Store Color Space Family to use in CPDF_RenderStatus::Initialize().
1708   *pCSFamily = family;
1709 
1710   uint32_t comps = std::max(8u, pCS->CountComponents());
1711   size_t count = std::min<size_t>(8, pBC->size());
1712   std::vector<float> floats = ReadArrayElementsToVector(pBC, count);
1713   floats.resize(comps);
1714 
1715   float R;
1716   float G;
1717   float B;
1718   pCS->GetRGB(floats.data(), &R, &G, &B);
1719   return ArgbEncode(255, static_cast<int>(R * 255), static_cast<int>(G * 255),
1720                     static_cast<int>(B * 255));
1721 }
1722