• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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/page/cpdf_dib.h"
8 
9 #include <stdint.h>
10 
11 #include <algorithm>
12 #include <memory>
13 #include <utility>
14 #include <vector>
15 
16 #include "core/fpdfapi/page/cpdf_colorspace.h"
17 #include "core/fpdfapi/page/cpdf_docpagedata.h"
18 #include "core/fpdfapi/page/cpdf_image.h"
19 #include "core/fpdfapi/page/cpdf_imageobject.h"
20 #include "core/fpdfapi/page/cpdf_indexedcs.h"
21 #include "core/fpdfapi/parser/cpdf_array.h"
22 #include "core/fpdfapi/parser/cpdf_dictionary.h"
23 #include "core/fpdfapi/parser/cpdf_document.h"
24 #include "core/fpdfapi/parser/cpdf_name.h"
25 #include "core/fpdfapi/parser/cpdf_number.h"
26 #include "core/fpdfapi/parser/cpdf_stream.h"
27 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
28 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
29 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
30 #include "core/fxcodec/basic/basicmodule.h"
31 #include "core/fxcodec/icc/icc_transform.h"
32 #include "core/fxcodec/jbig2/jbig2_decoder.h"
33 #include "core/fxcodec/jpeg/jpegmodule.h"
34 #include "core/fxcodec/jpx/cjpx_decoder.h"
35 #include "core/fxcodec/scanlinedecoder.h"
36 #include "core/fxcrt/check.h"
37 #include "core/fxcrt/check_op.h"
38 #include "core/fxcrt/compiler_specific.h"
39 #include "core/fxcrt/data_vector.h"
40 #include "core/fxcrt/fx_memcpy_wrappers.h"
41 #include "core/fxcrt/fx_safe_types.h"
42 #include "core/fxcrt/span_util.h"
43 #include "core/fxcrt/stl_util.h"
44 #include "core/fxcrt/zip.h"
45 #include "core/fxge/calculate_pitch.h"
46 #include "core/fxge/dib/cfx_dibitmap.h"
47 
48 namespace {
49 
IsValidDimension(int value)50 bool IsValidDimension(int value) {
51   constexpr int kMaxImageDimension = 0x01FFFF;
52   return value > 0 && value <= kMaxImageDimension;
53 }
54 
GetBits8(pdfium::span<const uint8_t> pData,uint64_t bitpos,size_t nbits)55 unsigned int GetBits8(pdfium::span<const uint8_t> pData,
56                       uint64_t bitpos,
57                       size_t nbits) {
58   DCHECK(nbits == 1 || nbits == 2 || nbits == 4 || nbits == 8 || nbits == 16);
59   DCHECK_EQ((bitpos & (nbits - 1)), 0u);
60   unsigned int byte = pData[bitpos / 8];
61   if (nbits == 8) {
62     return byte;
63   }
64   if (nbits == 16) {
65     return byte * 256 + pData[bitpos / 8 + 1];
66   }
67   return (byte >> (8 - nbits - (bitpos % 8))) & ((1 << nbits) - 1);
68 }
69 
GetBitValue(pdfium::span<const uint8_t> pSrc,uint32_t pos)70 bool GetBitValue(pdfium::span<const uint8_t> pSrc, uint32_t pos) {
71   return pSrc[pos / 8] & (1 << (7 - pos % 8));
72 }
73 
74 // Just to sanity check and filter out obvious bad values.
IsMaybeValidBitsPerComponent(int bpc)75 bool IsMaybeValidBitsPerComponent(int bpc) {
76   return bpc >= 0 && bpc <= 16;
77 }
78 
IsAllowedBitsPerComponent(int bpc)79 bool IsAllowedBitsPerComponent(int bpc) {
80   return bpc == 1 || bpc == 2 || bpc == 4 || bpc == 8 || bpc == 16;
81 }
82 
IsColorIndexOutOfBounds(uint8_t index,const DIB_COMP_DATA & comp_datum)83 bool IsColorIndexOutOfBounds(uint8_t index, const DIB_COMP_DATA& comp_datum) {
84   return index < comp_datum.m_ColorKeyMin || index > comp_datum.m_ColorKeyMax;
85 }
86 
AreColorIndicesOutOfBounds(const uint8_t * indices,const DIB_COMP_DATA * comp_data,size_t count)87 bool AreColorIndicesOutOfBounds(const uint8_t* indices,
88                                 const DIB_COMP_DATA* comp_data,
89                                 size_t count) {
90   UNSAFE_TODO({
91     for (size_t i = 0; i < count; ++i) {
92       if (IsColorIndexOutOfBounds(indices[i], comp_data[i])) {
93         return true;
94       }
95     }
96   });
97   return false;
98 }
99 
ColorSpaceOptionFromColorSpace(CPDF_ColorSpace * pCS)100 CJPX_Decoder::ColorSpaceOption ColorSpaceOptionFromColorSpace(
101     CPDF_ColorSpace* pCS) {
102   if (!pCS) {
103     return CJPX_Decoder::ColorSpaceOption::kNone;
104   }
105   if (pCS->GetFamily() == CPDF_ColorSpace::Family::kIndexed) {
106     return CJPX_Decoder::ColorSpaceOption::kIndexed;
107   }
108   return CJPX_Decoder::ColorSpaceOption::kNormal;
109 }
110 
111 enum class JpxDecodeAction {
112   kFail,
113   kDoNothing,
114   kUseGray,
115   kUseRgb,
116   kUseCmyk,
117   kConvertArgbToRgb,
118 };
119 
120 // ISO 32000-1:2008 section 7.4.9 says the PDF and JPX colorspaces should have
121 // the same number of color channels. This helper function checks the
122 // colorspaces match, but also tolerates unknowns.
IsJPXColorSpaceOrUnspecifiedOrUnknown(COLOR_SPACE actual,COLOR_SPACE expected)123 bool IsJPXColorSpaceOrUnspecifiedOrUnknown(COLOR_SPACE actual,
124                                            COLOR_SPACE expected) {
125   return actual == expected || actual == OPJ_CLRSPC_UNSPECIFIED ||
126          actual == OPJ_CLRSPC_UNKNOWN;
127 }
128 
129 // Decides which JpxDecodeAction to use based on the colorspace information from
130 // the PDF and the JPX image. Called only when the PDF's image object contains a
131 // "/ColorSpace" entry.
GetJpxDecodeActionFromColorSpaces(const CJPX_Decoder::JpxImageInfo & jpx_info,const CPDF_ColorSpace * pdf_colorspace)132 JpxDecodeAction GetJpxDecodeActionFromColorSpaces(
133     const CJPX_Decoder::JpxImageInfo& jpx_info,
134     const CPDF_ColorSpace* pdf_colorspace) {
135   if (pdf_colorspace ==
136       CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray)) {
137     if (!IsJPXColorSpaceOrUnspecifiedOrUnknown(/*actual=*/jpx_info.colorspace,
138                                                /*expected=*/OPJ_CLRSPC_GRAY)) {
139       return JpxDecodeAction::kFail;
140     }
141     return JpxDecodeAction::kUseGray;
142   }
143 
144   if (pdf_colorspace ==
145       CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB)) {
146     if (!IsJPXColorSpaceOrUnspecifiedOrUnknown(/*actual=*/jpx_info.colorspace,
147                                                /*expected=*/OPJ_CLRSPC_SRGB)) {
148       return JpxDecodeAction::kFail;
149     }
150 
151     // The channel count of a JPX image can be different from the PDF color
152     // space's component count.
153     if (jpx_info.channels > 3) {
154       return JpxDecodeAction::kConvertArgbToRgb;
155     }
156     return JpxDecodeAction::kUseRgb;
157   }
158 
159   if (pdf_colorspace ==
160       CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK)) {
161     if (!IsJPXColorSpaceOrUnspecifiedOrUnknown(/*actual=*/jpx_info.colorspace,
162                                                /*expected=*/OPJ_CLRSPC_CMYK)) {
163       return JpxDecodeAction::kFail;
164     }
165     return JpxDecodeAction::kUseCmyk;
166   }
167 
168   // Many PDFs generated by iOS meets this condition. Handle the discrepancy.
169   // See https://crbug.com/345431077 for example.
170   if (pdf_colorspace->ComponentCount() == 3 && jpx_info.channels == 4 &&
171       jpx_info.colorspace == OPJ_CLRSPC_SRGB) {
172     return JpxDecodeAction::kConvertArgbToRgb;
173   }
174 
175   return JpxDecodeAction::kDoNothing;
176 }
177 
GetJpxDecodeActionFromImageColorSpace(const CJPX_Decoder::JpxImageInfo & jpx_info)178 JpxDecodeAction GetJpxDecodeActionFromImageColorSpace(
179     const CJPX_Decoder::JpxImageInfo& jpx_info) {
180   switch (jpx_info.colorspace) {
181     case OPJ_CLRSPC_SYCC:
182     case OPJ_CLRSPC_EYCC:
183     case OPJ_CLRSPC_UNKNOWN:
184     case OPJ_CLRSPC_UNSPECIFIED:
185       return JpxDecodeAction::kDoNothing;
186 
187     case OPJ_CLRSPC_SRGB:
188       if (jpx_info.channels > 3) {
189         return JpxDecodeAction::kConvertArgbToRgb;
190       }
191 
192       return JpxDecodeAction::kUseRgb;
193 
194     case OPJ_CLRSPC_GRAY:
195       return JpxDecodeAction::kUseGray;
196 
197     case OPJ_CLRSPC_CMYK:
198       return JpxDecodeAction::kUseCmyk;
199   }
200 }
201 
GetJpxDecodeAction(const CJPX_Decoder::JpxImageInfo & jpx_info,const CPDF_ColorSpace * pdf_colorspace)202 JpxDecodeAction GetJpxDecodeAction(const CJPX_Decoder::JpxImageInfo& jpx_info,
203                                    const CPDF_ColorSpace* pdf_colorspace) {
204   if (pdf_colorspace) {
205     return GetJpxDecodeActionFromColorSpaces(jpx_info, pdf_colorspace);
206   }
207 
208   // When PDF does not provide a color space, check the image color space.
209   return GetJpxDecodeActionFromImageColorSpace(jpx_info);
210 }
211 
GetComponentCountFromOpjColorSpace(OPJ_COLOR_SPACE colorspace)212 int GetComponentCountFromOpjColorSpace(OPJ_COLOR_SPACE colorspace) {
213   switch (colorspace) {
214     case OPJ_CLRSPC_GRAY:
215       return 1;
216 
217     case OPJ_CLRSPC_SRGB:
218     case OPJ_CLRSPC_SYCC:
219     case OPJ_CLRSPC_EYCC:
220       return 3;
221 
222     case OPJ_CLRSPC_CMYK:
223       return 4;
224 
225     default:
226       return 0;
227   }
228 }
229 
230 }  // namespace
231 
CPDF_DIB(CPDF_Document * pDoc,RetainPtr<const CPDF_Stream> pStream)232 CPDF_DIB::CPDF_DIB(CPDF_Document* pDoc, RetainPtr<const CPDF_Stream> pStream)
233     : m_pDocument(pDoc), m_pStream(std::move(pStream)) {}
234 
235 CPDF_DIB::~CPDF_DIB() = default;
236 
237 CPDF_DIB::JpxSMaskInlineData::JpxSMaskInlineData() = default;
238 
239 CPDF_DIB::JpxSMaskInlineData::~JpxSMaskInlineData() = default;
240 
Load()241 bool CPDF_DIB::Load() {
242   if (!LoadInternal(nullptr, nullptr))
243     return false;
244 
245   if (CreateDecoder(0) == LoadState::kFail)
246     return false;
247 
248   return ContinueInternal();
249 }
250 
ContinueToLoadMask()251 bool CPDF_DIB::ContinueToLoadMask() {
252   if (m_pColorSpace && m_bStdCS)
253     m_pColorSpace->EnableStdConversion(true);
254 
255   return ContinueInternal();
256 }
257 
ContinueInternal()258 bool CPDF_DIB::ContinueInternal() {
259   if (m_bImageMask) {
260     SetMaskProperties();
261   } else {
262     const uint32_t bpp = m_bpc * m_nComponents;
263     if (bpp == 0) {
264       return false;
265     }
266 
267     if (bpp == 1) {
268       SetFormat(FXDIB_Format::k1bppRgb);
269     } else if (bpp <= 8) {
270       SetFormat(FXDIB_Format::k8bppRgb);
271     } else {
272       SetFormat(FXDIB_Format::kBgr);
273     }
274   }
275 
276   std::optional<uint32_t> pitch = fxge::CalculatePitch32(GetBPP(), GetWidth());
277   if (!pitch.has_value())
278     return false;
279 
280   m_LineBuf = DataVector<uint8_t>(pitch.value());
281   LoadPalette();
282   if (m_bColorKey) {
283     // TODO(crbug.com/355676038): Consider adding support for
284     // `FXDIB_Format::kBgraPremul`
285     SetFormat(FXDIB_Format::kBgra);
286     pitch = fxge::CalculatePitch32(GetBPP(), GetWidth());
287     if (!pitch.has_value())
288       return false;
289     m_MaskBuf = DataVector<uint8_t>(pitch.value());
290   }
291   SetPitch(pitch.value());
292   return true;
293 }
294 
StartLoadDIBBase(bool bHasMask,const CPDF_Dictionary * pFormResources,const CPDF_Dictionary * pPageResources,bool bStdCS,CPDF_ColorSpace::Family GroupFamily,bool bLoadMask,const CFX_Size & max_size_required)295 CPDF_DIB::LoadState CPDF_DIB::StartLoadDIBBase(
296     bool bHasMask,
297     const CPDF_Dictionary* pFormResources,
298     const CPDF_Dictionary* pPageResources,
299     bool bStdCS,
300     CPDF_ColorSpace::Family GroupFamily,
301     bool bLoadMask,
302     const CFX_Size& max_size_required) {
303   m_bStdCS = bStdCS;
304   m_bHasMask = bHasMask;
305   m_GroupFamily = GroupFamily;
306   m_bLoadMask = bLoadMask;
307 
308   if (!m_pStream->IsInline())
309     pFormResources = nullptr;
310 
311   if (!LoadInternal(pFormResources, pPageResources))
312     return LoadState::kFail;
313 
314   uint8_t resolution_levels_to_skip = 0;
315   if (max_size_required.width != 0 && max_size_required.height != 0) {
316     resolution_levels_to_skip = static_cast<uint8_t>(std::log2(
317         std::max(1, std::min(GetWidth() / max_size_required.width,
318                              GetHeight() / max_size_required.height))));
319   }
320 
321   LoadState iCreatedDecoder = CreateDecoder(resolution_levels_to_skip);
322   if (iCreatedDecoder == LoadState::kFail)
323     return LoadState::kFail;
324 
325   if (!ContinueToLoadMask())
326     return LoadState::kFail;
327 
328   LoadState iLoadedMask = m_bHasMask ? StartLoadMask() : LoadState::kSuccess;
329   if (iCreatedDecoder == LoadState::kContinue ||
330       iLoadedMask == LoadState::kContinue) {
331     return LoadState::kContinue;
332   }
333 
334   DCHECK_EQ(iCreatedDecoder, LoadState::kSuccess);
335   DCHECK_EQ(iLoadedMask, LoadState::kSuccess);
336   if (m_pColorSpace && m_bStdCS)
337     m_pColorSpace->EnableStdConversion(false);
338   return LoadState::kSuccess;
339 }
340 
ContinueLoadDIBBase(PauseIndicatorIface * pPause)341 CPDF_DIB::LoadState CPDF_DIB::ContinueLoadDIBBase(PauseIndicatorIface* pPause) {
342   if (m_Status == LoadState::kContinue)
343     return ContinueLoadMaskDIB(pPause);
344 
345   ByteString decoder = m_pStreamAcc->GetImageDecoder();
346   if (decoder == "JPXDecode")
347     return LoadState::kFail;
348 
349   if (decoder != "JBIG2Decode")
350     return LoadState::kSuccess;
351 
352   if (m_Status == LoadState::kFail)
353     return LoadState::kFail;
354 
355   FXCODEC_STATUS iDecodeStatus;
356   if (!m_pJbig2Context) {
357     m_pJbig2Context = std::make_unique<Jbig2Context>();
358     if (m_pStreamAcc->GetImageParam()) {
359       RetainPtr<const CPDF_Stream> pGlobals =
360           m_pStreamAcc->GetImageParam()->GetStreamFor("JBIG2Globals");
361       if (pGlobals) {
362         m_pGlobalAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pGlobals));
363         m_pGlobalAcc->LoadAllDataFiltered();
364       }
365     }
366     uint64_t nSrcKey = 0;
367     pdfium::span<const uint8_t> pSrcSpan;
368     if (m_pStreamAcc) {
369       pSrcSpan = m_pStreamAcc->GetSpan();
370       nSrcKey = m_pStreamAcc->KeyForCache();
371     }
372     uint64_t nGlobalKey = 0;
373     pdfium::span<const uint8_t> pGlobalSpan;
374     if (m_pGlobalAcc) {
375       pGlobalSpan = m_pGlobalAcc->GetSpan();
376       nGlobalKey = m_pGlobalAcc->KeyForCache();
377     }
378     iDecodeStatus = Jbig2Decoder::StartDecode(
379         m_pJbig2Context.get(), m_pDocument->GetOrCreateCodecContext(),
380         GetWidth(), GetHeight(), pSrcSpan, nSrcKey, pGlobalSpan, nGlobalKey,
381         m_pCachedBitmap->GetWritableBuffer(), m_pCachedBitmap->GetPitch(),
382         pPause);
383   } else {
384     iDecodeStatus = Jbig2Decoder::ContinueDecode(m_pJbig2Context.get(), pPause);
385   }
386 
387   if (iDecodeStatus == FXCODEC_STATUS::kError) {
388     m_pJbig2Context.reset();
389     m_pCachedBitmap.Reset();
390     m_pGlobalAcc.Reset();
391     return LoadState::kFail;
392   }
393   if (iDecodeStatus == FXCODEC_STATUS::kDecodeToBeContinued)
394     return LoadState::kContinue;
395 
396   LoadState iContinueStatus = LoadState::kSuccess;
397   if (m_bHasMask) {
398     if (ContinueLoadMaskDIB(pPause) == LoadState::kContinue) {
399       iContinueStatus = LoadState::kContinue;
400       m_Status = LoadState::kContinue;
401     }
402   }
403   if (iContinueStatus == LoadState::kContinue)
404     return LoadState::kContinue;
405 
406   if (m_pColorSpace && m_bStdCS)
407     m_pColorSpace->EnableStdConversion(false);
408   return iContinueStatus;
409 }
410 
LoadColorInfo(const CPDF_Dictionary * pFormResources,const CPDF_Dictionary * pPageResources)411 bool CPDF_DIB::LoadColorInfo(const CPDF_Dictionary* pFormResources,
412                              const CPDF_Dictionary* pPageResources) {
413   std::optional<DecoderArray> decoder_array = GetDecoderArray(m_pDict);
414   if (!decoder_array.has_value())
415     return false;
416 
417   m_bpc_orig = m_pDict->GetIntegerFor("BitsPerComponent");
418   if (!IsMaybeValidBitsPerComponent(m_bpc_orig))
419     return false;
420 
421   m_bImageMask = m_pDict->GetBooleanFor("ImageMask", /*bDefault=*/false);
422 
423   if (m_bImageMask || !m_pDict->KeyExist("ColorSpace")) {
424     if (!m_bImageMask && !decoder_array.value().empty()) {
425       const ByteString& filter = decoder_array.value().back().first;
426       if (filter == "JPXDecode") {
427         m_bDoBpcCheck = false;
428         return true;
429       }
430     }
431     m_bImageMask = true;
432     m_bpc = m_nComponents = 1;
433     RetainPtr<const CPDF_Array> pDecode = m_pDict->GetArrayFor("Decode");
434     m_bDefaultDecode = !pDecode || !pDecode->GetIntegerAt(0);
435     return true;
436   }
437 
438   RetainPtr<const CPDF_Object> pCSObj =
439       m_pDict->GetDirectObjectFor("ColorSpace");
440   if (!pCSObj)
441     return false;
442 
443   auto* pDocPageData = CPDF_DocPageData::FromDocument(m_pDocument);
444   if (pFormResources)
445     m_pColorSpace = pDocPageData->GetColorSpace(pCSObj.Get(), pFormResources);
446   if (!m_pColorSpace)
447     m_pColorSpace = pDocPageData->GetColorSpace(pCSObj.Get(), pPageResources);
448   if (!m_pColorSpace)
449     return false;
450 
451   // If the checks above failed to find a colorspace, and the next line to set
452   // |m_nComponents| does not get reached, then a decoder can try to set
453   // |m_nComponents| based on the number of channels in the image being
454   // decoded.
455   m_nComponents = m_pColorSpace->ComponentCount();
456   m_Family = m_pColorSpace->GetFamily();
457   if (m_Family == CPDF_ColorSpace::Family::kICCBased && pCSObj->IsName()) {
458     ByteString cs = pCSObj->GetString();
459     if (cs == "DeviceGray")
460       m_nComponents = 1;
461     else if (cs == "DeviceRGB")
462       m_nComponents = 3;
463     else if (cs == "DeviceCMYK")
464       m_nComponents = 4;
465   }
466 
467   ByteString filter;
468   if (!decoder_array.value().empty())
469     filter = decoder_array.value().back().first;
470 
471   if (!ValidateDictParam(filter))
472     return false;
473 
474   return GetDecodeAndMaskArray();
475 }
476 
GetDecodeAndMaskArray()477 bool CPDF_DIB::GetDecodeAndMaskArray() {
478   if (!m_pColorSpace)
479     return false;
480 
481   m_CompData.resize(m_nComponents);
482   int max_data = (1 << m_bpc) - 1;
483   RetainPtr<const CPDF_Array> pDecode = m_pDict->GetArrayFor("Decode");
484   if (pDecode) {
485     for (uint32_t i = 0; i < m_nComponents; i++) {
486       m_CompData[i].m_DecodeMin = pDecode->GetFloatAt(i * 2);
487       float max = pDecode->GetFloatAt(i * 2 + 1);
488       m_CompData[i].m_DecodeStep = (max - m_CompData[i].m_DecodeMin) / max_data;
489       float def_value;
490       float def_min;
491       float def_max;
492       m_pColorSpace->GetDefaultValue(i, &def_value, &def_min, &def_max);
493       if (m_Family == CPDF_ColorSpace::Family::kIndexed)
494         def_max = max_data;
495       if (def_min != m_CompData[i].m_DecodeMin || def_max != max)
496         m_bDefaultDecode = false;
497     }
498   } else {
499     for (uint32_t i = 0; i < m_nComponents; i++) {
500       float def_value;
501       m_pColorSpace->GetDefaultValue(i, &def_value, &m_CompData[i].m_DecodeMin,
502                                      &m_CompData[i].m_DecodeStep);
503       if (m_Family == CPDF_ColorSpace::Family::kIndexed)
504         m_CompData[i].m_DecodeStep = max_data;
505       m_CompData[i].m_DecodeStep =
506           (m_CompData[i].m_DecodeStep - m_CompData[i].m_DecodeMin) / max_data;
507     }
508   }
509   if (m_pDict->KeyExist("SMask"))
510     return true;
511 
512   RetainPtr<const CPDF_Object> pMask = m_pDict->GetDirectObjectFor("Mask");
513   if (!pMask)
514     return true;
515 
516   if (const CPDF_Array* pArray = pMask->AsArray()) {
517     if (pArray->size() >= m_nComponents * 2) {
518       for (uint32_t i = 0; i < m_nComponents; i++) {
519         int min_num = pArray->GetIntegerAt(i * 2);
520         int max_num = pArray->GetIntegerAt(i * 2 + 1);
521         m_CompData[i].m_ColorKeyMin = std::max(min_num, 0);
522         m_CompData[i].m_ColorKeyMax = std::min(max_num, max_data);
523       }
524     }
525     m_bColorKey = true;
526   }
527   return true;
528 }
529 
CreateDecoder(uint8_t resolution_levels_to_skip)530 CPDF_DIB::LoadState CPDF_DIB::CreateDecoder(uint8_t resolution_levels_to_skip) {
531   ByteString decoder = m_pStreamAcc->GetImageDecoder();
532   if (decoder.IsEmpty())
533     return LoadState::kSuccess;
534 
535   if (m_bDoBpcCheck && m_bpc == 0)
536     return LoadState::kFail;
537 
538   if (decoder == "JPXDecode") {
539     m_pCachedBitmap = LoadJpxBitmap(resolution_levels_to_skip);
540     return m_pCachedBitmap ? LoadState::kSuccess : LoadState::kFail;
541   }
542 
543   if (decoder == "JBIG2Decode") {
544     m_pCachedBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
545     if (!m_pCachedBitmap->Create(
546             GetWidth(), GetHeight(),
547             m_bImageMask ? FXDIB_Format::k1bppMask : FXDIB_Format::k1bppRgb)) {
548       m_pCachedBitmap.Reset();
549       return LoadState::kFail;
550     }
551     m_Status = LoadState::kSuccess;
552     return LoadState::kContinue;
553   }
554 
555   pdfium::span<const uint8_t> src_span = m_pStreamAcc->GetSpan();
556   RetainPtr<const CPDF_Dictionary> pParams = m_pStreamAcc->GetImageParam();
557   if (decoder == "CCITTFaxDecode") {
558     m_pDecoder = CreateFaxDecoder(src_span, GetWidth(), GetHeight(), pParams);
559   } else if (decoder == "FlateDecode") {
560     m_pDecoder = CreateFlateDecoder(src_span, GetWidth(), GetHeight(),
561                                     m_nComponents, m_bpc, pParams);
562   } else if (decoder == "RunLengthDecode") {
563     m_pDecoder = BasicModule::CreateRunLengthDecoder(
564         src_span, GetWidth(), GetHeight(), m_nComponents, m_bpc);
565   } else if (decoder == "DCTDecode") {
566     if (!CreateDCTDecoder(src_span, pParams))
567       return LoadState::kFail;
568   }
569   if (!m_pDecoder)
570     return LoadState::kFail;
571 
572   const std::optional<uint32_t> requested_pitch =
573       fxge::CalculatePitch8(m_bpc, m_nComponents, GetWidth());
574   if (!requested_pitch.has_value())
575     return LoadState::kFail;
576   const std::optional<uint32_t> provided_pitch = fxge::CalculatePitch8(
577       m_pDecoder->GetBPC(), m_pDecoder->CountComps(), m_pDecoder->GetWidth());
578   if (!provided_pitch.has_value())
579     return LoadState::kFail;
580   if (provided_pitch.value() < requested_pitch.value())
581     return LoadState::kFail;
582   return LoadState::kSuccess;
583 }
584 
CreateDCTDecoder(pdfium::span<const uint8_t> src_span,const CPDF_Dictionary * pParams)585 bool CPDF_DIB::CreateDCTDecoder(pdfium::span<const uint8_t> src_span,
586                                 const CPDF_Dictionary* pParams) {
587   m_pDecoder = JpegModule::CreateDecoder(
588       src_span, GetWidth(), GetHeight(), m_nComponents,
589       !pParams || pParams->GetIntegerFor("ColorTransform", 1));
590   if (m_pDecoder)
591     return true;
592 
593   std::optional<JpegModule::ImageInfo> info_opt =
594       JpegModule::LoadInfo(src_span);
595   if (!info_opt.has_value())
596     return false;
597 
598   const JpegModule::ImageInfo& info = info_opt.value();
599   SetWidth(info.width);
600   SetHeight(info.height);
601 
602   if (!CPDF_Image::IsValidJpegComponent(info.num_components) ||
603       !CPDF_Image::IsValidJpegBitsPerComponent(info.bits_per_components)) {
604     return false;
605   }
606 
607   if (m_nComponents == static_cast<uint32_t>(info.num_components)) {
608     m_bpc = info.bits_per_components;
609     m_pDecoder = JpegModule::CreateDecoder(src_span, GetWidth(), GetHeight(),
610                                            m_nComponents, info.color_transform);
611     return true;
612   }
613 
614   m_nComponents = static_cast<uint32_t>(info.num_components);
615   m_CompData.clear();
616   if (m_pColorSpace) {
617     uint32_t colorspace_comps = m_pColorSpace->ComponentCount();
618     switch (m_Family) {
619       case CPDF_ColorSpace::Family::kDeviceGray:
620       case CPDF_ColorSpace::Family::kDeviceRGB:
621       case CPDF_ColorSpace::Family::kDeviceCMYK: {
622         uint32_t dwMinComps = CPDF_ColorSpace::ComponentsForFamily(m_Family);
623         if (colorspace_comps < dwMinComps || m_nComponents < dwMinComps)
624           return false;
625         break;
626       }
627       case CPDF_ColorSpace::Family::kLab: {
628         if (m_nComponents != 3 || colorspace_comps < 3)
629           return false;
630         break;
631       }
632       case CPDF_ColorSpace::Family::kICCBased: {
633         if (!fxcodec::IccTransform::IsValidIccComponents(colorspace_comps) ||
634             !fxcodec::IccTransform::IsValidIccComponents(m_nComponents) ||
635             colorspace_comps < m_nComponents) {
636           return false;
637         }
638         break;
639       }
640       default: {
641         if (colorspace_comps != m_nComponents)
642           return false;
643         break;
644       }
645     }
646   } else {
647     if (m_Family == CPDF_ColorSpace::Family::kLab && m_nComponents != 3)
648       return false;
649   }
650   if (!GetDecodeAndMaskArray())
651     return false;
652 
653   m_bpc = info.bits_per_components;
654   m_pDecoder = JpegModule::CreateDecoder(src_span, GetWidth(), GetHeight(),
655                                          m_nComponents, info.color_transform);
656   return true;
657 }
658 
LoadJpxBitmap(uint8_t resolution_levels_to_skip)659 RetainPtr<CFX_DIBitmap> CPDF_DIB::LoadJpxBitmap(
660     uint8_t resolution_levels_to_skip) {
661   std::unique_ptr<CJPX_Decoder> decoder =
662       CJPX_Decoder::Create(m_pStreamAcc->GetSpan(),
663                            ColorSpaceOptionFromColorSpace(m_pColorSpace.Get()),
664                            resolution_levels_to_skip, /*strict_mode=*/true);
665   if (!decoder)
666     return nullptr;
667 
668   SetWidth(GetWidth() >> resolution_levels_to_skip);
669   SetHeight(GetHeight() >> resolution_levels_to_skip);
670 
671   if (!decoder->StartDecode())
672     return nullptr;
673 
674   CJPX_Decoder::JpxImageInfo image_info = decoder->GetInfo();
675   if (static_cast<int>(image_info.width) < GetWidth() ||
676       static_cast<int>(image_info.height) < GetHeight()) {
677     return nullptr;
678   }
679 
680   RetainPtr<CPDF_ColorSpace> original_colorspace = m_pColorSpace;
681   bool swap_rgb = false;
682   bool convert_argb_to_rgb = false;
683   auto action = GetJpxDecodeAction(image_info, m_pColorSpace.Get());
684   switch (action) {
685     case JpxDecodeAction::kFail:
686       return nullptr;
687 
688     case JpxDecodeAction::kDoNothing:
689       break;
690 
691     case JpxDecodeAction::kUseGray:
692       m_pColorSpace =
693           CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray);
694       break;
695 
696     case JpxDecodeAction::kUseRgb:
697       DCHECK(image_info.channels >= 3);
698       swap_rgb = true;
699       m_pColorSpace = nullptr;
700       break;
701 
702     case JpxDecodeAction::kUseCmyk:
703       m_pColorSpace =
704           CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK);
705       break;
706 
707     case JpxDecodeAction::kConvertArgbToRgb:
708       swap_rgb = true;
709       convert_argb_to_rgb = true;
710       m_pColorSpace.Reset();
711   }
712 
713   // If |original_colorspace| exists, then LoadColorInfo() already set
714   // |m_nComponents|.
715   if (original_colorspace) {
716     DCHECK_NE(0u, m_nComponents);
717   } else {
718     DCHECK_EQ(0u, m_nComponents);
719     m_nComponents = GetComponentCountFromOpjColorSpace(image_info.colorspace);
720     if (m_nComponents == 0) {
721       return nullptr;
722     }
723   }
724 
725   FXDIB_Format format;
726   if (action == JpxDecodeAction::kUseGray) {
727     format = FXDIB_Format::k8bppRgb;
728   } else if (action == JpxDecodeAction::kUseRgb && image_info.channels == 3) {
729     format = FXDIB_Format::kBgr;
730   } else if (action == JpxDecodeAction::kUseRgb && image_info.channels == 4) {
731     format = FXDIB_Format::kBgrx;
732   } else if (action == JpxDecodeAction::kConvertArgbToRgb) {
733     CHECK_GE(image_info.channels, 4);
734     format = FXDIB_Format::kBgrx;
735   } else {
736     image_info.width = (image_info.width * image_info.channels + 2) / 3;
737     format = FXDIB_Format::kBgr;
738   }
739 
740   auto result_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
741   if (!result_bitmap->Create(image_info.width, image_info.height, format))
742     return nullptr;
743 
744   result_bitmap->Clear(0xFFFFFFFF);
745   if (!decoder->Decode(result_bitmap->GetWritableBuffer(),
746                        result_bitmap->GetPitch(), swap_rgb, m_nComponents)) {
747     return nullptr;
748   }
749 
750   if (convert_argb_to_rgb) {
751     DCHECK_EQ(3u, m_nComponents);
752     auto rgb_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
753     if (!rgb_bitmap->Create(image_info.width, image_info.height,
754                             FXDIB_Format::kBgr)) {
755       return nullptr;
756     }
757     if (m_pDict->GetIntegerFor("SMaskInData") == 1) {
758       // TODO(thestig): Acrobat does not support "/SMaskInData 1" combined with
759       // filters. Check for that and fail early.
760       DCHECK(m_JpxInlineData.data.empty());
761       m_JpxInlineData.width = image_info.width;
762       m_JpxInlineData.height = image_info.height;
763       m_JpxInlineData.data.reserve(image_info.width * image_info.height);
764       for (uint32_t row = 0; row < image_info.height; ++row) {
765         auto src =
766             result_bitmap->GetScanlineAs<FX_BGRA_STRUCT<uint8_t>>(row).first(
767                 image_info.width);
768         auto dest =
769             rgb_bitmap->GetWritableScanlineAs<FX_BGR_STRUCT<uint8_t>>(row);
770         for (auto [input, output] : fxcrt::Zip(src, dest)) {
771           m_JpxInlineData.data.push_back(input.alpha);
772           const uint8_t na = 255 - input.alpha;
773           output.blue = (input.blue * input.alpha + 255 * na) / 255;
774           output.green = (input.green * input.alpha + 255 * na) / 255;
775           output.red = (input.red * input.alpha + 255 * na) / 255;
776         }
777       }
778     } else {
779       // TODO(thestig): Is there existing code that does this already?
780       for (uint32_t row = 0; row < image_info.height; ++row) {
781         auto src =
782             result_bitmap->GetScanlineAs<FX_BGRA_STRUCT<uint8_t>>(row).first(
783                 image_info.width);
784         auto dest =
785             rgb_bitmap->GetWritableScanlineAs<FX_BGR_STRUCT<uint8_t>>(row);
786         for (auto [input, output] : fxcrt::Zip(src, dest)) {
787           output.green = input.green;
788           output.red = input.red;
789           output.blue = input.blue;
790         }
791       }
792     }
793     result_bitmap = std::move(rgb_bitmap);
794   } else if (m_pColorSpace &&
795              m_pColorSpace->GetFamily() == CPDF_ColorSpace::Family::kIndexed &&
796              m_bpc < 8) {
797     int scale = 8 - m_bpc;
798     for (uint32_t row = 0; row < image_info.height; ++row) {
799       pdfium::span<uint8_t> scanline =
800           result_bitmap->GetWritableScanline(row).first(image_info.width);
801       for (auto& pixel : scanline) {
802         pixel >>= scale;
803       }
804     }
805   }
806 
807   // TODO(crbug.com/pdfium/1747): Handle SMaskInData entries for different
808   // color space types.
809 
810   m_bpc = 8;
811   return result_bitmap;
812 }
813 
LoadInternal(const CPDF_Dictionary * pFormResources,const CPDF_Dictionary * pPageResources)814 bool CPDF_DIB::LoadInternal(const CPDF_Dictionary* pFormResources,
815                             const CPDF_Dictionary* pPageResources) {
816   if (!m_pStream)
817     return false;
818 
819   m_pDict = m_pStream->GetDict();
820   SetWidth(m_pDict->GetIntegerFor("Width"));
821   SetHeight(m_pDict->GetIntegerFor("Height"));
822   if (!IsValidDimension(GetWidth()) || !IsValidDimension(GetHeight())) {
823     return false;
824   }
825 
826   if (!LoadColorInfo(pFormResources, pPageResources))
827     return false;
828 
829   if (m_bDoBpcCheck && (m_bpc == 0 || m_nComponents == 0))
830     return false;
831 
832   const std::optional<uint32_t> maybe_size =
833       fxge::CalculatePitch8(m_bpc, m_nComponents, GetWidth());
834   if (!maybe_size.has_value())
835     return false;
836 
837   FX_SAFE_UINT32 src_size = maybe_size.value();
838   src_size *= GetHeight();
839   if (!src_size.IsValid())
840     return false;
841 
842   m_pStreamAcc = pdfium::MakeRetain<CPDF_StreamAcc>(m_pStream);
843   m_pStreamAcc->LoadAllDataImageAcc(src_size.ValueOrDie());
844   return !m_pStreamAcc->GetSpan().empty();
845 }
846 
StartLoadMask()847 CPDF_DIB::LoadState CPDF_DIB::StartLoadMask() {
848   m_MatteColor = 0XFFFFFFFF;
849 
850   if (!m_JpxInlineData.data.empty()) {
851     auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
852     dict->SetNewFor<CPDF_Name>("Type", "XObject");
853     dict->SetNewFor<CPDF_Name>("Subtype", "Image");
854     dict->SetNewFor<CPDF_Name>("ColorSpace", "DeviceGray");
855     dict->SetNewFor<CPDF_Number>("Width", m_JpxInlineData.width);
856     dict->SetNewFor<CPDF_Number>("Height", m_JpxInlineData.height);
857     dict->SetNewFor<CPDF_Number>("BitsPerComponent", 8);
858 
859     return StartLoadMaskDIB(
860         pdfium::MakeRetain<CPDF_Stream>(m_JpxInlineData.data, std::move(dict)));
861   }
862 
863   RetainPtr<const CPDF_Stream> mask(m_pDict->GetStreamFor("SMask"));
864   if (!mask) {
865     mask = ToStream(m_pDict->GetDirectObjectFor("Mask"));
866     return mask ? StartLoadMaskDIB(std::move(mask)) : LoadState::kSuccess;
867   }
868 
869   RetainPtr<const CPDF_Array> pMatte = mask->GetDict()->GetArrayFor("Matte");
870   if (pMatte && m_pColorSpace &&
871       m_Family != CPDF_ColorSpace::Family::kPattern &&
872       pMatte->size() == m_nComponents &&
873       m_pColorSpace->ComponentCount() <= m_nComponents) {
874     std::vector<float> colors =
875         ReadArrayElementsToVector(pMatte.Get(), m_nComponents);
876 
877     auto rgb = m_pColorSpace->GetRGBOrZerosOnError(colors);
878     m_MatteColor =
879         ArgbEncode(0, FXSYS_roundf(rgb.red * 255),
880                    FXSYS_roundf(rgb.green * 255), FXSYS_roundf(rgb.blue * 255));
881   }
882   return StartLoadMaskDIB(std::move(mask));
883 }
884 
ContinueLoadMaskDIB(PauseIndicatorIface * pPause)885 CPDF_DIB::LoadState CPDF_DIB::ContinueLoadMaskDIB(PauseIndicatorIface* pPause) {
886   if (!m_pMask)
887     return LoadState::kSuccess;
888 
889   LoadState ret = m_pMask->ContinueLoadDIBBase(pPause);
890   if (ret == LoadState::kContinue)
891     return LoadState::kContinue;
892 
893   if (m_pColorSpace && m_bStdCS)
894     m_pColorSpace->EnableStdConversion(false);
895 
896   if (ret == LoadState::kFail) {
897     m_pMask.Reset();
898     return LoadState::kFail;
899   }
900   return LoadState::kSuccess;
901 }
902 
DetachMask()903 RetainPtr<CPDF_DIB> CPDF_DIB::DetachMask() {
904   return std::move(m_pMask);
905 }
906 
IsJBigImage() const907 bool CPDF_DIB::IsJBigImage() const {
908   return m_pStreamAcc->GetImageDecoder() == "JBIG2Decode";
909 }
910 
StartLoadMaskDIB(RetainPtr<const CPDF_Stream> mask_stream)911 CPDF_DIB::LoadState CPDF_DIB::StartLoadMaskDIB(
912     RetainPtr<const CPDF_Stream> mask_stream) {
913   m_pMask = pdfium::MakeRetain<CPDF_DIB>(m_pDocument, std::move(mask_stream));
914   LoadState ret = m_pMask->StartLoadDIBBase(false, nullptr, nullptr, true,
915                                             CPDF_ColorSpace::Family::kUnknown,
916                                             false, {0, 0});
917   if (ret == LoadState::kContinue) {
918     if (m_Status == LoadState::kFail)
919       m_Status = LoadState::kContinue;
920     return LoadState::kContinue;
921   }
922   if (ret == LoadState::kFail)
923     m_pMask.Reset();
924   return LoadState::kSuccess;
925 }
926 
LoadPalette()927 void CPDF_DIB::LoadPalette() {
928   if (!m_pColorSpace || m_Family == CPDF_ColorSpace::Family::kPattern)
929     return;
930 
931   if (m_bpc == 0)
932     return;
933 
934   // Use FX_SAFE_UINT32 just to be on the safe side, in case |m_bpc| or
935   // |m_nComponents| somehow gets a bad value.
936   FX_SAFE_UINT32 safe_bits = m_bpc;
937   safe_bits *= m_nComponents;
938   uint32_t bits = safe_bits.ValueOrDefault(255);
939   if (bits > 8)
940     return;
941 
942   if (bits == 1) {
943     if (m_bDefaultDecode && (m_Family == CPDF_ColorSpace::Family::kDeviceGray ||
944                              m_Family == CPDF_ColorSpace::Family::kDeviceRGB)) {
945       return;
946     }
947     if (m_pColorSpace->ComponentCount() > 3) {
948       return;
949     }
950     float color_values[3];
951     std::fill(std::begin(color_values), std::end(color_values),
952               m_CompData[0].m_DecodeMin);
953 
954     auto rgb = m_pColorSpace->GetRGBOrZerosOnError(color_values);
955     FX_ARGB argb0 =
956         ArgbEncode(255, FXSYS_roundf(rgb.red * 255),
957                    FXSYS_roundf(rgb.green * 255), FXSYS_roundf(rgb.blue * 255));
958     FX_ARGB argb1;
959     const CPDF_IndexedCS* indexed_cs = m_pColorSpace->AsIndexedCS();
960     if (indexed_cs && indexed_cs->GetMaxIndex() == 0) {
961       // If an indexed color space's hival value is 0, only 1 color is specified
962       // in the lookup table. Another color should be set to 0xFF000000 by
963       // default to set the range of the color space.
964       argb1 = 0xFF000000;
965     } else {
966       color_values[0] += m_CompData[0].m_DecodeStep;
967       color_values[1] += m_CompData[0].m_DecodeStep;
968       color_values[2] += m_CompData[0].m_DecodeStep;
969       auto result = m_pColorSpace->GetRGBOrZerosOnError(color_values);
970       argb1 = ArgbEncode(255, FXSYS_roundf(result.red * 255),
971                          FXSYS_roundf(result.green * 255),
972                          FXSYS_roundf(result.blue * 255));
973     }
974 
975     if (argb0 != 0xFF000000 || argb1 != 0xFFFFFFFF) {
976       SetPaletteArgb(0, argb0);
977       SetPaletteArgb(1, argb1);
978     }
979     return;
980   }
981   if (m_bpc == 8 && m_bDefaultDecode &&
982       m_pColorSpace ==
983           CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray)) {
984     return;
985   }
986 
987   int palette_count = 1 << bits;
988   // Using at least 16 elements due to the call m_pColorSpace->GetRGB().
989   std::vector<float> color_values(std::max(m_nComponents, 16u));
990   for (int i = 0; i < palette_count; i++) {
991     int color_data = i;
992     for (uint32_t j = 0; j < m_nComponents; j++) {
993       int encoded_component = color_data % (1 << m_bpc);
994       color_data /= 1 << m_bpc;
995       color_values[j] = m_CompData[j].m_DecodeMin +
996                         m_CompData[j].m_DecodeStep * encoded_component;
997     }
998     FX_RGB_STRUCT<float> rgb;
999     if (m_nComponents == 1 && m_Family == CPDF_ColorSpace::Family::kICCBased &&
1000         m_pColorSpace->ComponentCount() > 1) {
1001       const size_t nComponents = m_pColorSpace->ComponentCount();
1002       std::vector<float> temp_buf(nComponents, color_values[0]);
1003       rgb = m_pColorSpace->GetRGBOrZerosOnError(temp_buf);
1004     } else {
1005       rgb = m_pColorSpace->GetRGBOrZerosOnError(color_values);
1006     }
1007     SetPaletteArgb(i, ArgbEncode(255, FXSYS_roundf(rgb.red * 255),
1008                                  FXSYS_roundf(rgb.green * 255),
1009                                  FXSYS_roundf(rgb.blue * 255)));
1010   }
1011 }
1012 
ValidateDictParam(const ByteString & filter)1013 bool CPDF_DIB::ValidateDictParam(const ByteString& filter) {
1014   m_bpc = m_bpc_orig;
1015 
1016   // Per spec, |m_bpc| should always be 8 for RunLengthDecode, but too many
1017   // documents do not conform to it. So skip this check.
1018 
1019   if (filter == "JPXDecode") {
1020     m_bDoBpcCheck = false;
1021     return true;
1022   }
1023 
1024   if (filter == "CCITTFaxDecode" || filter == "JBIG2Decode") {
1025     m_bpc = 1;
1026     m_nComponents = 1;
1027   } else if (filter == "DCTDecode") {
1028     m_bpc = 8;
1029   }
1030 
1031   if (!IsAllowedBitsPerComponent(m_bpc)) {
1032     m_bpc = 0;
1033     return false;
1034   }
1035   return true;
1036 }
1037 
TranslateScanline24bpp(pdfium::span<uint8_t> dest_scan,pdfium::span<const uint8_t> src_scan) const1038 void CPDF_DIB::TranslateScanline24bpp(
1039     pdfium::span<uint8_t> dest_scan,
1040     pdfium::span<const uint8_t> src_scan) const {
1041   if (m_bpc == 0)
1042     return;
1043 
1044   if (TranslateScanline24bppDefaultDecode(dest_scan, src_scan))
1045     return;
1046 
1047   // Using at least 16 elements due to the call m_pColorSpace->GetRGB().
1048   std::vector<float> color_values(std::max(m_nComponents, 16u));
1049   FX_RGB_STRUCT<float> rgb = {};
1050   uint64_t src_bit_pos = 0;
1051   uint64_t src_byte_pos = 0;
1052   size_t dest_byte_pos = 0;
1053   const bool bpp8 = m_bpc == 8;
1054   for (int column = 0; column < GetWidth(); column++) {
1055     for (uint32_t color = 0; color < m_nComponents; color++) {
1056       if (bpp8) {
1057         uint8_t data = src_scan[src_byte_pos++];
1058         color_values[color] = m_CompData[color].m_DecodeMin +
1059                               m_CompData[color].m_DecodeStep * data;
1060       } else {
1061         unsigned int data = GetBits8(src_scan, src_bit_pos, m_bpc);
1062         color_values[color] = m_CompData[color].m_DecodeMin +
1063                               m_CompData[color].m_DecodeStep * data;
1064         src_bit_pos += m_bpc;
1065       }
1066     }
1067     if (TransMask()) {
1068       float k = 1.0f - color_values[3];
1069       rgb.red = (1.0f - color_values[0]) * k;
1070       rgb.green = (1.0f - color_values[1]) * k;
1071       rgb.blue = (1.0f - color_values[2]) * k;
1072     } else if (m_Family != CPDF_ColorSpace::Family::kPattern) {
1073       rgb = m_pColorSpace->GetRGBOrZerosOnError(color_values);
1074     }
1075     const float R = std::clamp(rgb.red, 0.0f, 1.0f);
1076     const float G = std::clamp(rgb.green, 0.0f, 1.0f);
1077     const float B = std::clamp(rgb.blue, 0.0f, 1.0f);
1078     dest_scan[dest_byte_pos] = static_cast<uint8_t>(B * 255);
1079     dest_scan[dest_byte_pos + 1] = static_cast<uint8_t>(G * 255);
1080     dest_scan[dest_byte_pos + 2] = static_cast<uint8_t>(R * 255);
1081     dest_byte_pos += 3;
1082   }
1083 }
1084 
TranslateScanline24bppDefaultDecode(pdfium::span<uint8_t> dest_scan,pdfium::span<const uint8_t> src_scan) const1085 bool CPDF_DIB::TranslateScanline24bppDefaultDecode(
1086     pdfium::span<uint8_t> dest_scan,
1087     pdfium::span<const uint8_t> src_scan) const {
1088   if (!m_bDefaultDecode)
1089     return false;
1090 
1091   if (m_Family != CPDF_ColorSpace::Family::kDeviceRGB &&
1092       m_Family != CPDF_ColorSpace::Family::kCalRGB) {
1093     if (m_bpc != 8)
1094       return false;
1095 
1096     if (m_nComponents == m_pColorSpace->ComponentCount()) {
1097       m_pColorSpace->TranslateImageLine(dest_scan, src_scan, GetWidth(),
1098                                         GetWidth(), GetHeight(), TransMask());
1099     }
1100     return true;
1101   }
1102 
1103   if (m_nComponents != 3)
1104     return true;
1105 
1106   uint8_t* dest_pos = dest_scan.data();
1107   const uint8_t* src_pos = src_scan.data();
1108   switch (m_bpc) {
1109     case 8:
1110       UNSAFE_TODO({
1111         for (int column = 0; column < GetWidth(); column++) {
1112           *dest_pos++ = src_pos[2];
1113           *dest_pos++ = src_pos[1];
1114           *dest_pos++ = *src_pos;
1115           src_pos += 3;
1116         }
1117       });
1118       break;
1119     case 16:
1120       UNSAFE_TODO({
1121         for (int col = 0; col < GetWidth(); col++) {
1122           *dest_pos++ = src_pos[4];
1123           *dest_pos++ = src_pos[2];
1124           *dest_pos++ = *src_pos;
1125           src_pos += 6;
1126         }
1127       });
1128       break;
1129     default:
1130       const unsigned int max_data = (1 << m_bpc) - 1;
1131       uint64_t src_bit_pos = 0;
1132       size_t dest_byte_pos = 0;
1133       for (int column = 0; column < GetWidth(); column++) {
1134         unsigned int R = GetBits8(src_scan, src_bit_pos, m_bpc);
1135         src_bit_pos += m_bpc;
1136         unsigned int G = GetBits8(src_scan, src_bit_pos, m_bpc);
1137         src_bit_pos += m_bpc;
1138         unsigned int B = GetBits8(src_scan, src_bit_pos, m_bpc);
1139         src_bit_pos += m_bpc;
1140         R = std::min(R, max_data);
1141         G = std::min(G, max_data);
1142         B = std::min(B, max_data);
1143         UNSAFE_TODO({
1144           dest_pos[dest_byte_pos] = B * 255 / max_data;
1145           dest_pos[dest_byte_pos + 1] = G * 255 / max_data;
1146           dest_pos[dest_byte_pos + 2] = R * 255 / max_data;
1147           dest_byte_pos += 3;
1148         });
1149       }
1150       break;
1151   }
1152   return true;
1153 }
1154 
GetScanline(int line) const1155 pdfium::span<const uint8_t> CPDF_DIB::GetScanline(int line) const {
1156   if (m_bpc == 0)
1157     return pdfium::span<const uint8_t>();
1158 
1159   const std::optional<uint32_t> src_pitch =
1160       fxge::CalculatePitch8(m_bpc, m_nComponents, GetWidth());
1161   if (!src_pitch.has_value())
1162     return pdfium::span<const uint8_t>();
1163 
1164   uint32_t src_pitch_value = src_pitch.value();
1165   // This is used as the buffer of `pSrcLine` when the stream is truncated,
1166   // and the remaining bytes count is less than `src_pitch_value`
1167   DataVector<uint8_t> temp_buffer;
1168   pdfium::span<const uint8_t> pSrcLine;
1169 
1170   if (m_pCachedBitmap && src_pitch_value <= m_pCachedBitmap->GetPitch()) {
1171     if (line >= m_pCachedBitmap->GetHeight())
1172       line = m_pCachedBitmap->GetHeight() - 1;
1173     pSrcLine = m_pCachedBitmap->GetScanline(line);
1174   } else if (m_pDecoder) {
1175     pSrcLine = m_pDecoder->GetScanline(line);
1176   } else if (m_pStreamAcc->GetSize() > line * src_pitch_value) {
1177     pdfium::span<const uint8_t> remaining_bytes =
1178         m_pStreamAcc->GetSpan().subspan(line * src_pitch_value);
1179     if (remaining_bytes.size() >= src_pitch_value) {
1180       pSrcLine = remaining_bytes.first(src_pitch_value);
1181     } else {
1182       temp_buffer = DataVector<uint8_t>(src_pitch_value);
1183       fxcrt::Copy(remaining_bytes, temp_buffer);
1184       pSrcLine = temp_buffer;
1185     }
1186   }
1187 
1188   if (pSrcLine.empty()) {
1189     pdfium::span<uint8_t> result = !m_MaskBuf.empty() ? m_MaskBuf : m_LineBuf;
1190     fxcrt::Fill(result, 0);
1191     return result;
1192   }
1193   if (m_bpc * m_nComponents == 1) {
1194     if (m_bImageMask && m_bDefaultDecode) {
1195       for (uint32_t i = 0; i < src_pitch_value; i++) {
1196         // TODO(tsepez): Bounds check if cost is acceptable.
1197         UNSAFE_TODO(m_LineBuf[i] = ~pSrcLine.data()[i]);
1198       }
1199       return pdfium::make_span(m_LineBuf).first(src_pitch_value);
1200     }
1201     if (!m_bColorKey) {
1202       fxcrt::Copy(pSrcLine.first(src_pitch_value), m_LineBuf);
1203       return pdfium::make_span(m_LineBuf).first(src_pitch_value);
1204     }
1205     uint32_t reset_argb = Get1BitResetValue();
1206     uint32_t set_argb = Get1BitSetValue();
1207     auto mask32_span =
1208         fxcrt::reinterpret_span<uint32_t>(pdfium::make_span(m_MaskBuf));
1209     for (int col = 0; col < GetWidth(); col++) {
1210       mask32_span[col] = GetBitValue(pSrcLine, col) ? set_argb : reset_argb;
1211     }
1212     return fxcrt::reinterpret_span<uint8_t>(mask32_span.first(GetWidth()));
1213   }
1214   if (m_bpc * m_nComponents <= 8) {
1215     pdfium::span<uint8_t> result = m_LineBuf;
1216     if (m_bpc == 8) {
1217       fxcrt::Copy(pSrcLine.first(src_pitch_value), result);
1218       result = result.first(src_pitch_value);
1219     } else {
1220       uint64_t src_bit_pos = 0;
1221       for (int col = 0; col < GetWidth(); col++) {
1222         unsigned int color_index = 0;
1223         for (uint32_t color = 0; color < m_nComponents; color++) {
1224           unsigned int data = GetBits8(pSrcLine, src_bit_pos, m_bpc);
1225           color_index |= data << (color * m_bpc);
1226           src_bit_pos += m_bpc;
1227         }
1228         m_LineBuf[col] = color_index;
1229       }
1230       result = result.first(GetWidth());
1231     }
1232     if (!m_bColorKey)
1233       return result;
1234 
1235     uint8_t* pDestPixel = m_MaskBuf.data();
1236     const uint8_t* pSrcPixel = m_LineBuf.data();
1237     pdfium::span<const uint32_t> palette = GetPaletteSpan();
1238     UNSAFE_TODO({
1239       if (HasPalette()) {
1240         for (int col = 0; col < GetWidth(); col++) {
1241           uint8_t index = *pSrcPixel++;
1242           *pDestPixel++ = FXARGB_B(palette[index]);
1243           *pDestPixel++ = FXARGB_G(palette[index]);
1244           *pDestPixel++ = FXARGB_R(palette[index]);
1245           *pDestPixel++ =
1246               IsColorIndexOutOfBounds(index, m_CompData[0]) ? 0xFF : 0;
1247         }
1248       } else {
1249         for (int col = 0; col < GetWidth(); col++) {
1250           uint8_t index = *pSrcPixel++;
1251           *pDestPixel++ = index;
1252           *pDestPixel++ = index;
1253           *pDestPixel++ = index;
1254           *pDestPixel++ =
1255               IsColorIndexOutOfBounds(index, m_CompData[0]) ? 0xFF : 0;
1256         }
1257       }
1258     });
1259     return pdfium::make_span(m_MaskBuf).first(4 * GetWidth());
1260   }
1261   if (m_bColorKey) {
1262     if (m_nComponents == 3 && m_bpc == 8) {
1263       UNSAFE_TODO({
1264         uint8_t* alpha_channel = m_MaskBuf.data() + 3;
1265         for (int col = 0; col < GetWidth(); col++) {
1266           const uint8_t* pPixel = pSrcLine.data() + col * 3;
1267           alpha_channel[col * 4] =
1268               AreColorIndicesOutOfBounds(pPixel, m_CompData.data(), 3) ? 0xFF
1269                                                                        : 0;
1270         }
1271       });
1272     } else {
1273       fxcrt::Fill(m_MaskBuf, 0xFF);
1274     }
1275   }
1276   if (m_pColorSpace) {
1277     TranslateScanline24bpp(m_LineBuf, pSrcLine);
1278     src_pitch_value = 3 * GetWidth();
1279     pSrcLine = pdfium::make_span(m_LineBuf).first(src_pitch_value);
1280   }
1281   if (!m_bColorKey)
1282     return pSrcLine;
1283 
1284   // TODO(tsepez): Bounds check if cost is acceptable.
1285   const uint8_t* pSrcPixel = pSrcLine.data();
1286   uint8_t* pDestPixel = m_MaskBuf.data();
1287   UNSAFE_TODO({
1288     for (int col = 0; col < GetWidth(); col++) {
1289       *pDestPixel++ = *pSrcPixel++;
1290       *pDestPixel++ = *pSrcPixel++;
1291       *pDestPixel++ = *pSrcPixel++;
1292       pDestPixel++;
1293     }
1294   });
1295   return pdfium::make_span(m_MaskBuf).first(4 * GetWidth());
1296 }
1297 
SkipToScanline(int line,PauseIndicatorIface * pPause) const1298 bool CPDF_DIB::SkipToScanline(int line, PauseIndicatorIface* pPause) const {
1299   return m_pDecoder && m_pDecoder->SkipToScanline(line, pPause);
1300 }
1301 
GetEstimatedImageMemoryBurden() const1302 size_t CPDF_DIB::GetEstimatedImageMemoryBurden() const {
1303   return m_pCachedBitmap ? m_pCachedBitmap->GetEstimatedImageMemoryBurden() : 0;
1304 }
1305 
TransMask() const1306 bool CPDF_DIB::TransMask() const {
1307   return m_bLoadMask && m_GroupFamily == CPDF_ColorSpace::Family::kDeviceCMYK &&
1308          m_Family == CPDF_ColorSpace::Family::kDeviceCMYK;
1309 }
1310 
SetMaskProperties()1311 void CPDF_DIB::SetMaskProperties() {
1312   m_bpc = 1;
1313   m_nComponents = 1;
1314   SetFormat(FXDIB_Format::k1bppMask);
1315 }
1316 
Get1BitSetValue() const1317 uint32_t CPDF_DIB::Get1BitSetValue() const {
1318   if (m_CompData[0].m_ColorKeyMax == 1)
1319     return 0x00000000;
1320   return HasPalette() ? GetPaletteSpan()[1] : 0xFFFFFFFF;
1321 }
1322 
Get1BitResetValue() const1323 uint32_t CPDF_DIB::Get1BitResetValue() const {
1324   if (m_CompData[0].m_ColorKeyMin == 0)
1325     return 0x00000000;
1326   return HasPalette() ? GetPaletteSpan()[0] : 0xFF000000;
1327 }
1328