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