• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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/fxcodec/progressive_decoder.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 
13 #include "build/build_config.h"
14 #include "core/fxcodec/cfx_codec_memory.h"
15 #include "core/fxcodec/jpeg/jpeg_progressive_decoder.h"
16 #include "core/fxcrt/check.h"
17 #include "core/fxcrt/check_op.h"
18 #include "core/fxcrt/compiler_specific.h"
19 #include "core/fxcrt/fx_2d_size.h"
20 #include "core/fxcrt/fx_memcpy_wrappers.h"
21 #include "core/fxcrt/fx_safe_types.h"
22 #include "core/fxcrt/fx_stream.h"
23 #include "core/fxcrt/fx_system.h"
24 #include "core/fxcrt/notreached.h"
25 #include "core/fxcrt/numerics/safe_conversions.h"
26 #include "core/fxcrt/span_util.h"
27 #include "core/fxcrt/stl_util.h"
28 #include "core/fxge/dib/cfx_cmyk_to_srgb.h"
29 #include "core/fxge/dib/cfx_dibitmap.h"
30 #include "core/fxge/dib/fx_dib.h"
31 
32 #ifdef PDF_ENABLE_XFA_BMP
33 #include "core/fxcodec/bmp/bmp_progressive_decoder.h"
34 #endif  // PDF_ENABLE_XFA_BMP
35 
36 #ifdef PDF_ENABLE_XFA_GIF
37 #include "core/fxcodec/gif/gif_progressive_decoder.h"
38 #endif  // PDF_ENABLE_XFA_GIF
39 
40 #ifdef PDF_ENABLE_XFA_TIFF
41 #include "core/fxcodec/tiff/tiff_decoder.h"
42 #endif  // PDF_ENABLE_XFA_TIFF
43 
44 namespace fxcodec {
45 
46 namespace {
47 
48 constexpr size_t kBlockSize = 4096;
49 
50 #ifdef PDF_ENABLE_XFA_PNG
51 #if BUILDFLAG(IS_APPLE)
52 const double kPngGamma = 1.7;
53 #else
54 const double kPngGamma = 2.2;
55 #endif  // BUILDFLAG(IS_APPLE)
56 #endif  // PDF_ENABLE_XFA_PNG
57 
RGB2BGR(uint8_t * buffer,int width=1)58 void RGB2BGR(uint8_t* buffer, int width = 1) {
59   if (buffer && width > 0) {
60     uint8_t temp;
61     int i = 0;
62     int j = 0;
63     UNSAFE_TODO({
64       for (; i < width; i++, j += 3) {
65         temp = buffer[j];
66         buffer[j] = buffer[j + 2];
67         buffer[j + 2] = temp;
68       }
69     });
70   }
71 }
72 
73 }  // namespace
74 
75 ProgressiveDecoder::ProgressiveDecoder() = default;
76 
77 ProgressiveDecoder::~ProgressiveDecoder() = default;
78 
79 #ifdef PDF_ENABLE_XFA_PNG
PngReadHeader(int width,int height,int bpc,int pass,int * color_type,double * gamma)80 bool ProgressiveDecoder::PngReadHeader(int width,
81                                        int height,
82                                        int bpc,
83                                        int pass,
84                                        int* color_type,
85                                        double* gamma) {
86   if (!m_pDeviceBitmap) {
87     m_SrcWidth = width;
88     m_SrcHeight = height;
89     m_SrcBPC = bpc;
90     m_SrcPassNumber = pass;
91     switch (*color_type) {
92       case 0:
93         m_SrcComponents = 1;
94         break;
95       case 4:
96         m_SrcComponents = 2;
97         break;
98       case 2:
99         m_SrcComponents = 3;
100         break;
101       case 3:
102       case 6:
103         m_SrcComponents = 4;
104         break;
105       default:
106         m_SrcComponents = 0;
107         break;
108     }
109     return false;
110   }
111   switch (m_pDeviceBitmap->GetFormat()) {
112     case FXDIB_Format::kInvalid:
113     case FXDIB_Format::k1bppMask:
114     case FXDIB_Format::k1bppRgb:
115     case FXDIB_Format::k8bppMask:
116     case FXDIB_Format::k8bppRgb:
117       NOTREACHED_NORETURN();
118     case FXDIB_Format::kBgr:
119       *color_type = 2;
120       break;
121     case FXDIB_Format::kBgrx:
122     case FXDIB_Format::kBgra:
123       *color_type = 6;
124       break;
125 #if defined(PDF_USE_SKIA)
126     case FXDIB_Format::kBgraPremul:
127       // TODO(crbug.com/355630556): Consider adding support for
128       // `FXDIB_Format::kBgraPremul`
129       NOTREACHED_NORETURN();
130 #endif
131   }
132   *gamma = kPngGamma;
133   return true;
134 }
135 
PngAskScanlineBuf(int line)136 uint8_t* ProgressiveDecoder::PngAskScanlineBuf(int line) {
137   CHECK_GE(line, 0);
138   CHECK_LT(line, m_SrcHeight);
139   CHECK_EQ(m_pDeviceBitmap->GetFormat(), FXDIB_Format::kBgra);
140   CHECK_EQ(m_SrcFormat, FXCodec_Argb);
141   pdfium::span<const uint8_t> src_span = m_pDeviceBitmap->GetScanline(line);
142   pdfium::span<uint8_t> dest_span = pdfium::make_span(m_DecodeBuf);
143   const size_t byte_size = Fx2DSizeOrDie(
144       m_SrcWidth, GetCompsFromFormat(m_pDeviceBitmap->GetFormat()));
145   fxcrt::Copy(src_span.first(byte_size), dest_span);
146   return m_DecodeBuf.data();
147 }
148 
PngFillScanlineBufCompleted(int pass,int line)149 void ProgressiveDecoder::PngFillScanlineBufCompleted(int pass, int line) {
150   if (line < 0 || line >= m_SrcHeight) {
151     return;
152   }
153 
154   CHECK_EQ(m_pDeviceBitmap->GetFormat(), FXDIB_Format::kBgra);
155   pdfium::span<const uint8_t> src_span = pdfium::make_span(m_DecodeBuf);
156   pdfium::span<uint8_t> dest_span = m_pDeviceBitmap->GetWritableScanline(line);
157   const size_t byte_size = Fx2DSizeOrDie(
158       m_SrcWidth, GetCompsFromFormat(m_pDeviceBitmap->GetFormat()));
159   fxcrt::Copy(src_span.first(byte_size), dest_span);
160 }
161 #endif  // PDF_ENABLE_XFA_PNG
162 
163 #ifdef PDF_ENABLE_XFA_GIF
GifCurrentPosition() const164 uint32_t ProgressiveDecoder::GifCurrentPosition() const {
165   uint32_t remain_size = pdfium::checked_cast<uint32_t>(
166       GifDecoder::GetAvailInput(m_pGifContext.get()));
167   return m_offSet - remain_size;
168 }
169 
GifInputRecordPositionBuf(uint32_t rcd_pos,const FX_RECT & img_rc,pdfium::span<CFX_GifPalette> pal_span,int32_t trans_index,bool interlace)170 bool ProgressiveDecoder::GifInputRecordPositionBuf(
171     uint32_t rcd_pos,
172     const FX_RECT& img_rc,
173     pdfium::span<CFX_GifPalette> pal_span,
174     int32_t trans_index,
175     bool interlace) {
176   m_offSet = rcd_pos;
177 
178   FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
179   m_pCodecMemory->Seek(m_pCodecMemory->GetSize());
180   if (!GifReadMoreData(&error_status))
181     return false;
182 
183   if (pal_span.empty()) {
184     pal_span = m_GifPalette;
185   }
186   if (pal_span.empty()) {
187     return false;
188   }
189   m_SrcPalette.resize(pal_span.size());
190   for (size_t i = 0; i < pal_span.size(); i++) {
191     m_SrcPalette[i] =
192         ArgbEncode(0xff, pal_span[i].r, pal_span[i].g, pal_span[i].b);
193   }
194   m_GifTransIndex = trans_index;
195   m_GifFrameRect = img_rc;
196   m_SrcPassNumber = interlace ? 4 : 1;
197   int32_t pal_index = m_GifBgIndex;
198   RetainPtr<CFX_DIBitmap> pDevice = m_pDeviceBitmap;
199   if (trans_index >= static_cast<int>(pal_span.size())) {
200     trans_index = -1;
201   }
202   if (trans_index != -1) {
203     m_SrcPalette[trans_index] &= 0x00ffffff;
204     if (pDevice->IsAlphaFormat()) {
205       pal_index = trans_index;
206     }
207   }
208   if (pal_index >= static_cast<int>(pal_span.size())) {
209     return false;
210   }
211   int startX = 0;
212   int startY = 0;
213   int sizeX = m_SrcWidth;
214   int sizeY = m_SrcHeight;
215   const int bytes_per_pixel = pDevice->GetBPP() / 8;
216   FX_ARGB argb = m_SrcPalette[pal_index];
217   for (int row = 0; row < sizeY; row++) {
218     pdfium::span<uint8_t> scan_span = pDevice->GetWritableScanline(row + startY)
219                                           .subspan(startX * bytes_per_pixel);
220     switch (m_TransMethod) {
221       case TransformMethod::k8BppRgbToRgbNoAlpha: {
222         uint8_t* pScanline = scan_span.data();
223         UNSAFE_TODO({
224           for (int col = 0; col < sizeX; col++) {
225             *pScanline++ = FXARGB_B(argb);
226             *pScanline++ = FXARGB_G(argb);
227             *pScanline++ = FXARGB_R(argb);
228             pScanline += bytes_per_pixel - 3;
229           }
230         });
231         break;
232       }
233       case TransformMethod::k8BppRgbToArgb: {
234         uint8_t* pScanline = scan_span.data();
235         UNSAFE_TODO({
236           for (int col = 0; col < sizeX; col++) {
237             FXARGB_SetDIB(pScanline, argb);
238             pScanline += 4;
239           }
240         });
241         break;
242       }
243       default:
244         break;
245     }
246   }
247   return true;
248 }
249 
GifReadScanline(int32_t row_num,pdfium::span<uint8_t> row_buf)250 void ProgressiveDecoder::GifReadScanline(int32_t row_num,
251                                          pdfium::span<uint8_t> row_buf) {
252   RetainPtr<CFX_DIBitmap> pDIBitmap = m_pDeviceBitmap;
253   DCHECK(pDIBitmap);
254   int32_t img_width = m_GifFrameRect.Width();
255   if (!pDIBitmap->IsAlphaFormat()) {
256     pdfium::span<uint8_t> byte_span = row_buf;
257     for (int i = 0; i < img_width; i++) {
258       if (byte_span.front() == m_GifTransIndex) {
259         byte_span.front() = m_GifBgIndex;
260       }
261       byte_span = byte_span.subspan(1);
262     }
263   }
264   int32_t pal_index = m_GifBgIndex;
265   if (m_GifTransIndex != -1 && m_pDeviceBitmap->IsAlphaFormat()) {
266     pal_index = m_GifTransIndex;
267   }
268   const int32_t left = m_GifFrameRect.left;
269   const pdfium::span<uint8_t> decode_span = m_DecodeBuf;
270   fxcrt::Fill(decode_span.first(m_SrcWidth), pal_index);
271   fxcrt::Copy(row_buf.first(img_width), decode_span.subspan(left));
272 
273   int32_t line = row_num + m_GifFrameRect.top;
274   if (line < 0 || line >= m_SrcHeight) {
275     return;
276   }
277 
278   ResampleScanline(pDIBitmap, line, decode_span, m_SrcFormat);
279 }
280 #endif  // PDF_ENABLE_XFA_GIF
281 
282 #ifdef PDF_ENABLE_XFA_BMP
BmpInputImagePositionBuf(uint32_t rcd_pos)283 bool ProgressiveDecoder::BmpInputImagePositionBuf(uint32_t rcd_pos) {
284   m_offSet = rcd_pos;
285   FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
286   return BmpReadMoreData(m_pBmpContext.get(), &error_status);
287 }
288 
BmpReadScanline(uint32_t row_num,pdfium::span<const uint8_t> row_buf)289 void ProgressiveDecoder::BmpReadScanline(uint32_t row_num,
290                                          pdfium::span<const uint8_t> row_buf) {
291   RetainPtr<CFX_DIBitmap> pDIBitmap = m_pDeviceBitmap;
292   DCHECK(pDIBitmap);
293 
294   fxcrt::Copy(row_buf.first(m_ScanlineSize), m_DecodeBuf);
295 
296   if (row_num >= static_cast<uint32_t>(m_SrcHeight)) {
297     return;
298   }
299 
300   ResampleScanline(pDIBitmap, row_num, m_DecodeBuf, m_SrcFormat);
301 }
302 
BmpDetectImageTypeInBuffer(CFX_DIBAttribute * pAttribute)303 bool ProgressiveDecoder::BmpDetectImageTypeInBuffer(
304     CFX_DIBAttribute* pAttribute) {
305   std::unique_ptr<ProgressiveDecoderIface::Context> pBmpContext =
306       BmpDecoder::StartDecode(this);
307   BmpDecoder::Input(pBmpContext.get(), m_pCodecMemory);
308 
309   pdfium::span<const FX_ARGB> palette;
310   BmpDecoder::Status read_result = BmpDecoder::ReadHeader(
311       pBmpContext.get(), &m_SrcWidth, &m_SrcHeight, &m_BmpIsTopBottom,
312       &m_SrcComponents, &palette, pAttribute);
313   while (read_result == BmpDecoder::Status::kContinue) {
314     FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
315     if (!BmpReadMoreData(pBmpContext.get(), &error_status)) {
316       m_status = error_status;
317       return false;
318     }
319     read_result = BmpDecoder::ReadHeader(
320         pBmpContext.get(), &m_SrcWidth, &m_SrcHeight, &m_BmpIsTopBottom,
321         &m_SrcComponents, &palette, pAttribute);
322   }
323 
324   if (read_result != BmpDecoder::Status::kSuccess) {
325     m_status = FXCODEC_STATUS::kError;
326     return false;
327   }
328 
329   FXDIB_Format format = FXDIB_Format::kInvalid;
330   switch (m_SrcComponents) {
331     case 1:
332       m_SrcFormat = FXCodec_8bppRgb;
333       format = FXDIB_Format::k8bppRgb;
334       break;
335     case 3:
336       m_SrcFormat = FXCodec_Rgb;
337       format = FXDIB_Format::kBgr;
338       break;
339     case 4:
340       m_SrcFormat = FXCodec_Rgb32;
341       format = FXDIB_Format::kBgrx;
342       break;
343     default:
344       m_status = FXCODEC_STATUS::kError;
345       return false;
346   }
347 
348   // Set to 0 to make CalculatePitchAndSize() calculate it.
349   constexpr uint32_t kNoPitch = 0;
350   std::optional<CFX_DIBitmap::PitchAndSize> needed_data =
351       CFX_DIBitmap::CalculatePitchAndSize(m_SrcWidth, m_SrcHeight, format,
352                                           kNoPitch);
353   if (!needed_data.has_value()) {
354     m_status = FXCODEC_STATUS::kError;
355     return false;
356   }
357 
358   uint32_t available_data = pdfium::checked_cast<uint32_t>(
359       m_pFile->GetSize() - m_offSet +
360       BmpDecoder::GetAvailInput(pBmpContext.get()));
361   if (needed_data.value().size > available_data) {
362     m_status = FXCODEC_STATUS::kError;
363     return false;
364   }
365 
366   m_SrcBPC = 8;
367   m_pBmpContext = std::move(pBmpContext);
368   if (!palette.empty()) {
369     m_SrcPalette.resize(palette.size());
370     fxcrt::Copy(palette, m_SrcPalette);
371   } else {
372     m_SrcPalette.clear();
373   }
374   return true;
375 }
376 
BmpReadMoreData(ProgressiveDecoderIface::Context * pContext,FXCODEC_STATUS * err_status)377 bool ProgressiveDecoder::BmpReadMoreData(
378     ProgressiveDecoderIface::Context* pContext,
379     FXCODEC_STATUS* err_status) {
380   return ReadMoreData(BmpProgressiveDecoder::GetInstance(), pContext,
381                       err_status);
382 }
383 
BmpStartDecode()384 FXCODEC_STATUS ProgressiveDecoder::BmpStartDecode() {
385   SetTransMethod();
386   m_ScanlineSize = FxAlignToBoundary<4>(m_SrcWidth * m_SrcComponents);
387   m_DecodeBuf.resize(m_ScanlineSize);
388   FXDIB_ResampleOptions options;
389   options.bInterpolateBilinear = true;
390   m_WeightHorz.CalculateWeights(m_SrcWidth, 0, m_SrcWidth, m_SrcWidth, 0,
391                                 m_SrcWidth, options);
392   m_status = FXCODEC_STATUS::kDecodeToBeContinued;
393   return m_status;
394 }
395 
BmpContinueDecode()396 FXCODEC_STATUS ProgressiveDecoder::BmpContinueDecode() {
397   BmpDecoder::Status read_res = BmpDecoder::LoadImage(m_pBmpContext.get());
398   while (read_res == BmpDecoder::Status::kContinue) {
399     FXCODEC_STATUS error_status = FXCODEC_STATUS::kDecodeFinished;
400     if (!BmpReadMoreData(m_pBmpContext.get(), &error_status)) {
401       m_pDeviceBitmap = nullptr;
402       m_pFile = nullptr;
403       m_status = error_status;
404       return m_status;
405     }
406     read_res = BmpDecoder::LoadImage(m_pBmpContext.get());
407   }
408 
409   m_pDeviceBitmap = nullptr;
410   m_pFile = nullptr;
411   m_status = read_res == BmpDecoder::Status::kSuccess
412                  ? FXCODEC_STATUS::kDecodeFinished
413                  : FXCODEC_STATUS::kError;
414   return m_status;
415 }
416 #endif  // PDF_ENABLE_XFA_BMP
417 
418 #ifdef PDF_ENABLE_XFA_GIF
GifReadMoreData(FXCODEC_STATUS * err_status)419 bool ProgressiveDecoder::GifReadMoreData(FXCODEC_STATUS* err_status) {
420   return ReadMoreData(GifProgressiveDecoder::GetInstance(), m_pGifContext.get(),
421                       err_status);
422 }
423 
GifDetectImageTypeInBuffer()424 bool ProgressiveDecoder::GifDetectImageTypeInBuffer() {
425   m_pGifContext = GifDecoder::StartDecode(this);
426   GifDecoder::Input(m_pGifContext.get(), m_pCodecMemory);
427   m_SrcComponents = 1;
428   GifDecoder::Status readResult =
429       GifDecoder::ReadHeader(m_pGifContext.get(), &m_SrcWidth, &m_SrcHeight,
430                              &m_GifPalette, &m_GifBgIndex);
431   while (readResult == GifDecoder::Status::kUnfinished) {
432     FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
433     if (!GifReadMoreData(&error_status)) {
434       m_pGifContext = nullptr;
435       m_status = error_status;
436       return false;
437     }
438     readResult =
439         GifDecoder::ReadHeader(m_pGifContext.get(), &m_SrcWidth, &m_SrcHeight,
440                                &m_GifPalette, &m_GifBgIndex);
441   }
442   if (readResult == GifDecoder::Status::kSuccess) {
443     m_SrcBPC = 8;
444     return true;
445   }
446   m_pGifContext = nullptr;
447   m_status = FXCODEC_STATUS::kError;
448   return false;
449 }
450 
GifStartDecode()451 FXCODEC_STATUS ProgressiveDecoder::GifStartDecode() {
452   m_SrcFormat = FXCodec_8bppRgb;
453   SetTransMethod();
454   int scanline_size = FxAlignToBoundary<4>(m_SrcWidth);
455   m_DecodeBuf.resize(scanline_size);
456   FXDIB_ResampleOptions options;
457   options.bInterpolateBilinear = true;
458   m_WeightHorz.CalculateWeights(m_SrcWidth, 0, m_SrcWidth, m_SrcWidth, 0,
459                                 m_SrcWidth, options);
460   m_FrameCur = 0;
461   m_status = FXCODEC_STATUS::kDecodeToBeContinued;
462   return m_status;
463 }
464 
GifContinueDecode()465 FXCODEC_STATUS ProgressiveDecoder::GifContinueDecode() {
466   GifDecoder::Status readRes =
467       GifDecoder::LoadFrame(m_pGifContext.get(), m_FrameCur);
468   while (readRes == GifDecoder::Status::kUnfinished) {
469     FXCODEC_STATUS error_status = FXCODEC_STATUS::kDecodeFinished;
470     if (!GifReadMoreData(&error_status)) {
471       m_pDeviceBitmap = nullptr;
472       m_pFile = nullptr;
473       m_status = error_status;
474       return m_status;
475     }
476     readRes = GifDecoder::LoadFrame(m_pGifContext.get(), m_FrameCur);
477   }
478 
479   if (readRes == GifDecoder::Status::kSuccess) {
480     m_pDeviceBitmap = nullptr;
481     m_pFile = nullptr;
482     m_status = FXCODEC_STATUS::kDecodeFinished;
483     return m_status;
484   }
485 
486   m_pDeviceBitmap = nullptr;
487   m_pFile = nullptr;
488   m_status = FXCODEC_STATUS::kError;
489   return m_status;
490 }
491 #endif  // PDF_ENABLE_XFA_GIF
492 
JpegReadMoreData(FXCODEC_STATUS * err_status)493 bool ProgressiveDecoder::JpegReadMoreData(FXCODEC_STATUS* err_status) {
494   return ReadMoreData(JpegProgressiveDecoder::GetInstance(),
495                       m_pJpegContext.get(), err_status);
496 }
497 
JpegDetectImageTypeInBuffer(CFX_DIBAttribute * pAttribute)498 bool ProgressiveDecoder::JpegDetectImageTypeInBuffer(
499     CFX_DIBAttribute* pAttribute) {
500   m_pJpegContext = JpegProgressiveDecoder::Start();
501   if (!m_pJpegContext) {
502     m_status = FXCODEC_STATUS::kError;
503     return false;
504   }
505   JpegProgressiveDecoder::GetInstance()->Input(m_pJpegContext.get(),
506                                                m_pCodecMemory);
507 
508   // Setting jump marker before calling ReadHeader, since a longjmp to
509   // the marker indicates a fatal error.
510   if (setjmp(JpegProgressiveDecoder::GetJumpMark(m_pJpegContext.get())) == -1) {
511     m_pJpegContext.reset();
512     m_status = FXCODEC_STATUS::kError;
513     return false;
514   }
515 
516   int32_t readResult = JpegProgressiveDecoder::ReadHeader(
517       m_pJpegContext.get(), &m_SrcWidth, &m_SrcHeight, &m_SrcComponents,
518       pAttribute);
519   while (readResult == 2) {
520     FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
521     if (!JpegReadMoreData(&error_status)) {
522       m_status = error_status;
523       return false;
524     }
525     readResult = JpegProgressiveDecoder::ReadHeader(
526         m_pJpegContext.get(), &m_SrcWidth, &m_SrcHeight, &m_SrcComponents,
527         pAttribute);
528   }
529   if (!readResult) {
530     m_SrcBPC = 8;
531     return true;
532   }
533   m_pJpegContext.reset();
534   m_status = FXCODEC_STATUS::kError;
535   return false;
536 }
537 
JpegStartDecode()538 FXCODEC_STATUS ProgressiveDecoder::JpegStartDecode() {
539   // Setting jump marker before calling StartScanLine, since a longjmp to
540   // the marker indicates a fatal error.
541   if (setjmp(JpegProgressiveDecoder::GetJumpMark(m_pJpegContext.get())) == -1) {
542     m_pJpegContext.reset();
543     m_status = FXCODEC_STATUS::kError;
544     return FXCODEC_STATUS::kError;
545   }
546 
547   bool start_status =
548       JpegProgressiveDecoder::StartScanline(m_pJpegContext.get());
549   while (!start_status) {
550     FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
551     if (!JpegReadMoreData(&error_status)) {
552       m_pDeviceBitmap = nullptr;
553       m_pFile = nullptr;
554       m_status = error_status;
555       return m_status;
556     }
557 
558     start_status = JpegProgressiveDecoder::StartScanline(m_pJpegContext.get());
559   }
560   m_DecodeBuf.resize(FxAlignToBoundary<4>(m_SrcWidth * m_SrcComponents));
561   FXDIB_ResampleOptions options;
562   options.bInterpolateBilinear = true;
563   m_WeightHorz.CalculateWeights(m_SrcWidth, 0, m_SrcWidth, m_SrcWidth, 0,
564                                 m_SrcWidth, options);
565   switch (m_SrcComponents) {
566     case 1:
567       m_SrcFormat = FXCodec_8bppGray;
568       break;
569     case 3:
570       m_SrcFormat = FXCodec_Rgb;
571       break;
572     case 4:
573       m_SrcFormat = FXCodec_Cmyk;
574       break;
575   }
576   SetTransMethod();
577   m_status = FXCODEC_STATUS::kDecodeToBeContinued;
578   return m_status;
579 }
580 
JpegContinueDecode()581 FXCODEC_STATUS ProgressiveDecoder::JpegContinueDecode() {
582   // JpegModule* pJpegModule = m_pCodecMgr->GetJpegModule();
583   // Setting jump marker before calling ReadScanLine, since a longjmp to
584   // the marker indicates a fatal error.
585   if (setjmp(JpegProgressiveDecoder::GetJumpMark(m_pJpegContext.get())) == -1) {
586     m_pJpegContext.reset();
587     m_status = FXCODEC_STATUS::kError;
588     return FXCODEC_STATUS::kError;
589   }
590 
591   while (true) {
592     bool readRes = JpegProgressiveDecoder::ReadScanline(m_pJpegContext.get(),
593                                                         m_DecodeBuf.data());
594     while (!readRes) {
595       FXCODEC_STATUS error_status = FXCODEC_STATUS::kDecodeFinished;
596       if (!JpegReadMoreData(&error_status)) {
597         m_pDeviceBitmap = nullptr;
598         m_pFile = nullptr;
599         m_status = error_status;
600         return m_status;
601       }
602       readRes = JpegProgressiveDecoder::ReadScanline(m_pJpegContext.get(),
603                                                      m_DecodeBuf.data());
604     }
605     if (m_SrcFormat == FXCodec_Rgb) {
606       RGB2BGR(UNSAFE_TODO(m_DecodeBuf.data()), m_SrcWidth);
607     }
608     if (m_SrcRow >= m_SrcHeight) {
609       m_pDeviceBitmap = nullptr;
610       m_pFile = nullptr;
611       m_status = FXCODEC_STATUS::kDecodeFinished;
612       return m_status;
613     }
614     Resample(m_pDeviceBitmap, m_SrcRow, m_DecodeBuf.data(), m_SrcFormat);
615     m_SrcRow++;
616   }
617 }
618 
619 #ifdef PDF_ENABLE_XFA_PNG
PngDetectImageTypeInBuffer(CFX_DIBAttribute * pAttribute)620 bool ProgressiveDecoder::PngDetectImageTypeInBuffer(
621     CFX_DIBAttribute* pAttribute) {
622   m_pPngContext = PngDecoder::StartDecode(this);
623   if (!m_pPngContext) {
624     m_status = FXCODEC_STATUS::kError;
625     return false;
626   }
627   while (PngDecoder::ContinueDecode(m_pPngContext.get(), m_pCodecMemory,
628                                     pAttribute)) {
629     uint32_t remain_size = static_cast<uint32_t>(m_pFile->GetSize()) - m_offSet;
630     uint32_t input_size = std::min<uint32_t>(remain_size, kBlockSize);
631     if (input_size == 0) {
632       m_pPngContext.reset();
633       m_status = FXCODEC_STATUS::kError;
634       return false;
635     }
636     if (m_pCodecMemory && input_size > m_pCodecMemory->GetSize())
637       m_pCodecMemory = pdfium::MakeRetain<CFX_CodecMemory>(input_size);
638 
639     if (!m_pFile->ReadBlockAtOffset(
640             m_pCodecMemory->GetBufferSpan().first(input_size), m_offSet)) {
641       m_status = FXCODEC_STATUS::kError;
642       return false;
643     }
644     m_offSet += input_size;
645   }
646   m_pPngContext.reset();
647   if (m_SrcPassNumber == 0) {
648     m_status = FXCODEC_STATUS::kError;
649     return false;
650   }
651   return true;
652 }
653 
PngStartDecode()654 FXCODEC_STATUS ProgressiveDecoder::PngStartDecode() {
655   m_pPngContext = PngDecoder::StartDecode(this);
656   if (!m_pPngContext) {
657     m_pDeviceBitmap = nullptr;
658     m_pFile = nullptr;
659     m_status = FXCODEC_STATUS::kError;
660     return m_status;
661   }
662   m_offSet = 0;
663   CHECK_EQ(m_pDeviceBitmap->GetFormat(), FXDIB_Format::kBgra);
664   m_SrcComponents = 4;
665   m_SrcFormat = FXCodec_Argb;
666   SetTransMethod();
667   int scanline_size = FxAlignToBoundary<4>(m_SrcWidth * m_SrcComponents);
668   m_DecodeBuf.resize(scanline_size);
669   m_status = FXCODEC_STATUS::kDecodeToBeContinued;
670   return m_status;
671 }
672 
PngContinueDecode()673 FXCODEC_STATUS ProgressiveDecoder::PngContinueDecode() {
674   while (true) {
675     uint32_t remain_size = (uint32_t)m_pFile->GetSize() - m_offSet;
676     uint32_t input_size = std::min<uint32_t>(remain_size, kBlockSize);
677     if (input_size == 0) {
678       m_pPngContext.reset();
679       m_pDeviceBitmap = nullptr;
680       m_pFile = nullptr;
681       m_status = FXCODEC_STATUS::kDecodeFinished;
682       return m_status;
683     }
684     if (m_pCodecMemory && input_size > m_pCodecMemory->GetSize())
685       m_pCodecMemory = pdfium::MakeRetain<CFX_CodecMemory>(input_size);
686 
687     bool bResult = m_pFile->ReadBlockAtOffset(
688         m_pCodecMemory->GetBufferSpan().first(input_size), m_offSet);
689     if (!bResult) {
690       m_pDeviceBitmap = nullptr;
691       m_pFile = nullptr;
692       m_status = FXCODEC_STATUS::kError;
693       return m_status;
694     }
695     m_offSet += input_size;
696     bResult = PngDecoder::ContinueDecode(m_pPngContext.get(), m_pCodecMemory,
697                                          nullptr);
698     if (!bResult) {
699       m_pDeviceBitmap = nullptr;
700       m_pFile = nullptr;
701       m_status = FXCODEC_STATUS::kError;
702       return m_status;
703     }
704   }
705 }
706 #endif  // PDF_ENABLE_XFA_PNG
707 
708 #ifdef PDF_ENABLE_XFA_TIFF
TiffDetectImageTypeFromFile(CFX_DIBAttribute * pAttribute)709 bool ProgressiveDecoder::TiffDetectImageTypeFromFile(
710     CFX_DIBAttribute* pAttribute) {
711   m_pTiffContext = TiffDecoder::CreateDecoder(m_pFile);
712   if (!m_pTiffContext) {
713     m_status = FXCODEC_STATUS::kError;
714     return false;
715   }
716   int32_t dummy_bpc;
717   bool ret = TiffDecoder::LoadFrameInfo(m_pTiffContext.get(), 0, &m_SrcWidth,
718                                         &m_SrcHeight, &m_SrcComponents,
719                                         &dummy_bpc, pAttribute);
720   m_SrcComponents = 4;
721   if (!ret) {
722     m_pTiffContext.reset();
723     m_status = FXCODEC_STATUS::kError;
724     return false;
725   }
726   return true;
727 }
728 
TiffContinueDecode()729 FXCODEC_STATUS ProgressiveDecoder::TiffContinueDecode() {
730   // TODO(crbug.com/355630556): Consider adding support for
731   // `FXDIB_Format::kBgraPremul`
732   CHECK_EQ(m_pDeviceBitmap->GetFormat(), FXDIB_Format::kBgra);
733   m_status =
734       TiffDecoder::Decode(m_pTiffContext.get(), std::move(m_pDeviceBitmap))
735           ? FXCODEC_STATUS::kDecodeFinished
736           : FXCODEC_STATUS::kError;
737   m_pFile = nullptr;
738   return m_status;
739 }
740 #endif  // PDF_ENABLE_XFA_TIFF
741 
DetectImageType(FXCODEC_IMAGE_TYPE imageType,CFX_DIBAttribute * pAttribute)742 bool ProgressiveDecoder::DetectImageType(FXCODEC_IMAGE_TYPE imageType,
743                                          CFX_DIBAttribute* pAttribute) {
744 #ifdef PDF_ENABLE_XFA_TIFF
745   if (imageType == FXCODEC_IMAGE_TIFF)
746     return TiffDetectImageTypeFromFile(pAttribute);
747 #endif  // PDF_ENABLE_XFA_TIFF
748 
749   size_t size = pdfium::checked_cast<size_t>(
750       std::min<FX_FILESIZE>(m_pFile->GetSize(), kBlockSize));
751   m_pCodecMemory = pdfium::MakeRetain<CFX_CodecMemory>(size);
752   m_offSet = 0;
753   if (!m_pFile->ReadBlockAtOffset(m_pCodecMemory->GetBufferSpan().first(size),
754                                   m_offSet)) {
755     m_status = FXCODEC_STATUS::kError;
756     return false;
757   }
758   m_offSet += size;
759 
760   if (imageType == FXCODEC_IMAGE_JPG)
761     return JpegDetectImageTypeInBuffer(pAttribute);
762 
763 #ifdef PDF_ENABLE_XFA_BMP
764   if (imageType == FXCODEC_IMAGE_BMP)
765     return BmpDetectImageTypeInBuffer(pAttribute);
766 #endif  // PDF_ENABLE_XFA_BMP
767 
768 #ifdef PDF_ENABLE_XFA_GIF
769   if (imageType == FXCODEC_IMAGE_GIF)
770     return GifDetectImageTypeInBuffer();
771 #endif  // PDF_ENABLE_XFA_GIF
772 
773 #ifdef PDF_ENABLE_XFA_PNG
774   if (imageType == FXCODEC_IMAGE_PNG)
775     return PngDetectImageTypeInBuffer(pAttribute);
776 #endif  // PDF_ENABLE_XFA_PNG
777 
778   m_status = FXCODEC_STATUS::kError;
779   return false;
780 }
781 
ReadMoreData(ProgressiveDecoderIface * pModule,ProgressiveDecoderIface::Context * pContext,FXCODEC_STATUS * err_status)782 bool ProgressiveDecoder::ReadMoreData(
783     ProgressiveDecoderIface* pModule,
784     ProgressiveDecoderIface::Context* pContext,
785     FXCODEC_STATUS* err_status) {
786   // Check for EOF.
787   if (m_offSet >= static_cast<uint32_t>(m_pFile->GetSize()))
788     return false;
789 
790   // Try to get whatever remains.
791   uint32_t dwBytesToFetchFromFile =
792       pdfium::checked_cast<uint32_t>(m_pFile->GetSize() - m_offSet);
793 
794   // Figure out if the codec stopped processing midway through the buffer.
795   size_t dwUnconsumed;
796   FX_SAFE_SIZE_T avail_input = pModule->GetAvailInput(pContext);
797   if (!avail_input.AssignIfValid(&dwUnconsumed))
798     return false;
799 
800   if (dwUnconsumed == m_pCodecMemory->GetSize()) {
801     // Codec couldn't make any progress against the bytes in the buffer.
802     // Increase the buffer size so that there might be enough contiguous
803     // bytes to allow whatever operation is having difficulty to succeed.
804     dwBytesToFetchFromFile =
805         std::min<uint32_t>(dwBytesToFetchFromFile, kBlockSize);
806     size_t dwNewSize = m_pCodecMemory->GetSize() + dwBytesToFetchFromFile;
807     if (!m_pCodecMemory->TryResize(dwNewSize)) {
808       *err_status = FXCODEC_STATUS::kError;
809       return false;
810     }
811   } else {
812     // TODO(crbug.com/pdfium/1904): Simplify the `CFX_CodecMemory` API so we
813     // don't need to do this awkward dance to free up exactly enough buffer
814     // space for the next read.
815     size_t dwConsumable = m_pCodecMemory->GetSize() - dwUnconsumed;
816     dwBytesToFetchFromFile = pdfium::checked_cast<uint32_t>(
817         std::min<size_t>(dwBytesToFetchFromFile, dwConsumable));
818     m_pCodecMemory->Consume(dwBytesToFetchFromFile);
819     m_pCodecMemory->Seek(dwConsumable - dwBytesToFetchFromFile);
820     dwUnconsumed += m_pCodecMemory->GetPosition();
821   }
822 
823   // Append new data past the bytes not yet processed by the codec.
824   if (!m_pFile->ReadBlockAtOffset(m_pCodecMemory->GetBufferSpan().subspan(
825                                       dwUnconsumed, dwBytesToFetchFromFile),
826                                   m_offSet)) {
827     *err_status = FXCODEC_STATUS::kError;
828     return false;
829   }
830   m_offSet += dwBytesToFetchFromFile;
831   return pModule->Input(pContext, m_pCodecMemory);
832 }
833 
LoadImageInfo(RetainPtr<IFX_SeekableReadStream> pFile,FXCODEC_IMAGE_TYPE imageType,CFX_DIBAttribute * pAttribute,bool bSkipImageTypeCheck)834 FXCODEC_STATUS ProgressiveDecoder::LoadImageInfo(
835     RetainPtr<IFX_SeekableReadStream> pFile,
836     FXCODEC_IMAGE_TYPE imageType,
837     CFX_DIBAttribute* pAttribute,
838     bool bSkipImageTypeCheck) {
839   DCHECK(pAttribute);
840 
841   switch (m_status) {
842     case FXCODEC_STATUS::kFrameReady:
843     case FXCODEC_STATUS::kFrameToBeContinued:
844     case FXCODEC_STATUS::kDecodeReady:
845     case FXCODEC_STATUS::kDecodeToBeContinued:
846       return FXCODEC_STATUS::kError;
847     case FXCODEC_STATUS::kError:
848     case FXCODEC_STATUS::kDecodeFinished:
849       break;
850   }
851   m_pFile = std::move(pFile);
852   if (!m_pFile) {
853     m_status = FXCODEC_STATUS::kError;
854     return m_status;
855   }
856   m_offSet = 0;
857   m_SrcWidth = 0;
858   m_SrcHeight = 0;
859   m_SrcComponents = 0;
860   m_SrcBPC = 0;
861   m_SrcPassNumber = 0;
862   if (imageType != FXCODEC_IMAGE_UNKNOWN &&
863       DetectImageType(imageType, pAttribute)) {
864     m_imageType = imageType;
865     m_status = FXCODEC_STATUS::kFrameReady;
866     return m_status;
867   }
868   // If we got here then the image data does not match the requested decoder.
869   // If we're skipping the type check then bail out at this point and return
870   // the failed status.
871   if (bSkipImageTypeCheck)
872     return m_status;
873 
874   for (int type = FXCODEC_IMAGE_UNKNOWN + 1; type < FXCODEC_IMAGE_MAX; type++) {
875     if (DetectImageType(static_cast<FXCODEC_IMAGE_TYPE>(type), pAttribute)) {
876       m_imageType = static_cast<FXCODEC_IMAGE_TYPE>(type);
877       m_status = FXCODEC_STATUS::kFrameReady;
878       return m_status;
879     }
880   }
881   m_status = FXCODEC_STATUS::kError;
882   m_pFile = nullptr;
883   return m_status;
884 }
885 
SetTransMethod()886 void ProgressiveDecoder::SetTransMethod() {
887   switch (m_pDeviceBitmap->GetFormat()) {
888     case FXDIB_Format::kInvalid:
889     case FXDIB_Format::k1bppMask:
890     case FXDIB_Format::k1bppRgb:
891     case FXDIB_Format::k8bppMask:
892     case FXDIB_Format::k8bppRgb:
893       NOTREACHED_NORETURN();
894     case FXDIB_Format::kBgr: {
895       switch (m_SrcFormat) {
896         case FXCodec_Invalid:
897           m_TransMethod = TransformMethod::kInvalid;
898           break;
899         case FXCodec_8bppGray:
900           m_TransMethod = TransformMethod::k8BppGrayToRgbMaybeAlpha;
901           break;
902         case FXCodec_8bppRgb:
903           m_TransMethod = TransformMethod::k8BppRgbToRgbNoAlpha;
904           break;
905         case FXCodec_Rgb:
906         case FXCodec_Rgb32:
907         case FXCodec_Argb:
908           m_TransMethod = TransformMethod::kRgbMaybeAlphaToRgbMaybeAlpha;
909           break;
910         case FXCodec_Cmyk:
911           m_TransMethod = TransformMethod::kCmykToRgbMaybeAlpha;
912           break;
913       }
914       break;
915     }
916     case FXDIB_Format::kBgrx:
917     case FXDIB_Format::kBgra: {
918       switch (m_SrcFormat) {
919         case FXCodec_Invalid:
920           m_TransMethod = TransformMethod::kInvalid;
921           break;
922         case FXCodec_8bppGray:
923           m_TransMethod = TransformMethod::k8BppGrayToRgbMaybeAlpha;
924           break;
925         case FXCodec_8bppRgb:
926           if (m_pDeviceBitmap->GetFormat() == FXDIB_Format::kBgra) {
927             m_TransMethod = TransformMethod::k8BppRgbToArgb;
928           } else {
929             m_TransMethod = TransformMethod::k8BppRgbToRgbNoAlpha;
930           }
931           break;
932         case FXCodec_Rgb:
933         case FXCodec_Rgb32:
934           m_TransMethod = TransformMethod::kRgbMaybeAlphaToRgbMaybeAlpha;
935           break;
936         case FXCodec_Cmyk:
937           m_TransMethod = TransformMethod::kCmykToRgbMaybeAlpha;
938           break;
939         case FXCodec_Argb:
940           m_TransMethod = TransformMethod::kArgbToArgb;
941           break;
942       }
943       break;
944     }
945 #if defined(PDF_USE_SKIA)
946     case FXDIB_Format::kBgraPremul:
947       // TODO(crbug.com/355630556): Consider adding support for
948       // `FXDIB_Format::kBgraPremul`
949       NOTREACHED_NORETURN();
950 #endif
951   }
952 }
953 
ResampleScanline(const RetainPtr<CFX_DIBitmap> & pDeviceBitmap,int dest_line,pdfium::span<uint8_t> src_span,FXCodec_Format src_format)954 void ProgressiveDecoder::ResampleScanline(
955     const RetainPtr<CFX_DIBitmap>& pDeviceBitmap,
956     int dest_line,
957     pdfium::span<uint8_t> src_span,
958     FXCodec_Format src_format) {
959   uint8_t* src_scan = src_span.data();
960   uint8_t* dest_scan = pDeviceBitmap->GetWritableScanline(dest_line).data();
961   const int src_bytes_per_pixel = (src_format & 0xff) / 8;
962   const int dest_bytes_per_pixel = pDeviceBitmap->GetBPP() / 8;
963   for (int dest_col = 0; dest_col < m_SrcWidth; dest_col++) {
964     CStretchEngine::PixelWeight* pPixelWeights =
965         m_WeightHorz.GetPixelWeight(dest_col);
966     switch (m_TransMethod) {
967       case TransformMethod::kInvalid:
968         return;
969       case TransformMethod::k8BppGrayToRgbMaybeAlpha: {
970         UNSAFE_TODO({
971           uint32_t dest_g = 0;
972           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
973                j++) {
974             uint32_t pixel_weight =
975                 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
976             dest_g += pixel_weight * src_scan[j];
977           }
978           FXSYS_memset(dest_scan, CStretchEngine::PixelFromFixed(dest_g), 3);
979           dest_scan += dest_bytes_per_pixel;
980           break;
981         });
982       }
983       case TransformMethod::k8BppRgbToRgbNoAlpha: {
984         UNSAFE_TODO({
985           uint32_t dest_r = 0;
986           uint32_t dest_g = 0;
987           uint32_t dest_b = 0;
988           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
989                j++) {
990             uint32_t pixel_weight =
991                 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
992             uint32_t argb = m_SrcPalette[src_scan[j]];
993             dest_r += pixel_weight * FXARGB_R(argb);
994             dest_g += pixel_weight * FXARGB_G(argb);
995             dest_b += pixel_weight * FXARGB_B(argb);
996           }
997           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
998           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
999           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
1000           dest_scan += dest_bytes_per_pixel - 3;
1001           break;
1002         });
1003       }
1004       case TransformMethod::k8BppRgbToArgb: {
1005 #ifdef PDF_ENABLE_XFA_BMP
1006         if (m_pBmpContext) {
1007           UNSAFE_TODO({
1008             uint32_t dest_r = 0;
1009             uint32_t dest_g = 0;
1010             uint32_t dest_b = 0;
1011             for (int j = pPixelWeights->m_SrcStart;
1012                  j <= pPixelWeights->m_SrcEnd; j++) {
1013               uint32_t pixel_weight =
1014                   pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
1015               uint32_t argb = m_SrcPalette[src_scan[j]];
1016               dest_r += pixel_weight * FXARGB_R(argb);
1017               dest_g += pixel_weight * FXARGB_G(argb);
1018               dest_b += pixel_weight * FXARGB_B(argb);
1019             }
1020             *dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
1021             *dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
1022             *dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
1023             *dest_scan++ = 0xFF;
1024             break;
1025           });
1026         }
1027 #endif  // PDF_ENABLE_XFA_BMP
1028         UNSAFE_TODO({
1029           uint32_t dest_a = 0;
1030           uint32_t dest_r = 0;
1031           uint32_t dest_g = 0;
1032           uint32_t dest_b = 0;
1033           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
1034                j++) {
1035             uint32_t pixel_weight =
1036                 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
1037             FX_ARGB argb = m_SrcPalette[src_scan[j]];
1038             dest_a += pixel_weight * FXARGB_A(argb);
1039             dest_r += pixel_weight * FXARGB_R(argb);
1040             dest_g += pixel_weight * FXARGB_G(argb);
1041             dest_b += pixel_weight * FXARGB_B(argb);
1042           }
1043           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
1044           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
1045           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
1046           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_a);
1047           break;
1048         });
1049       }
1050       case TransformMethod::kRgbMaybeAlphaToRgbMaybeAlpha: {
1051         UNSAFE_TODO({
1052           uint32_t dest_b = 0;
1053           uint32_t dest_g = 0;
1054           uint32_t dest_r = 0;
1055           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
1056                j++) {
1057             uint32_t pixel_weight =
1058                 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
1059             const uint8_t* src_pixel = src_scan + j * src_bytes_per_pixel;
1060             dest_b += pixel_weight * (*src_pixel++);
1061             dest_g += pixel_weight * (*src_pixel++);
1062             dest_r += pixel_weight * (*src_pixel);
1063           }
1064           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
1065           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
1066           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
1067           dest_scan += dest_bytes_per_pixel - 3;
1068           break;
1069         });
1070       }
1071       case TransformMethod::kCmykToRgbMaybeAlpha: {
1072         UNSAFE_TODO({
1073           uint32_t dest_b = 0;
1074           uint32_t dest_g = 0;
1075           uint32_t dest_r = 0;
1076           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
1077                j++) {
1078             uint32_t pixel_weight =
1079                 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
1080             const uint8_t* src_pixel = src_scan + j * src_bytes_per_pixel;
1081             FX_RGB_STRUCT<uint8_t> src_rgb =
1082                 AdobeCMYK_to_sRGB1(255 - src_pixel[0], 255 - src_pixel[1],
1083                                    255 - src_pixel[2], 255 - src_pixel[3]);
1084             dest_b += pixel_weight * src_rgb.blue;
1085             dest_g += pixel_weight * src_rgb.green;
1086             dest_r += pixel_weight * src_rgb.red;
1087           }
1088           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
1089           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
1090           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
1091           dest_scan += dest_bytes_per_pixel - 3;
1092           break;
1093         });
1094       }
1095       case TransformMethod::kArgbToArgb: {
1096         UNSAFE_TODO({
1097           uint32_t dest_alpha = 0;
1098           uint32_t dest_r = 0;
1099           uint32_t dest_g = 0;
1100           uint32_t dest_b = 0;
1101           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
1102                j++) {
1103             uint32_t pixel_weight =
1104                 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
1105             const uint8_t* src_pixel = src_scan + j * src_bytes_per_pixel;
1106             pixel_weight = pixel_weight * src_pixel[3] / 255;
1107             dest_b += pixel_weight * (*src_pixel++);
1108             dest_g += pixel_weight * (*src_pixel++);
1109             dest_r += pixel_weight * (*src_pixel);
1110             dest_alpha += pixel_weight;
1111           }
1112           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
1113           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
1114           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
1115           *dest_scan++ = CStretchEngine::PixelFromFixed(dest_alpha * 255);
1116           break;
1117         });
1118       }
1119     }
1120   }
1121 }
1122 
Resample(const RetainPtr<CFX_DIBitmap> & pDeviceBitmap,int32_t src_line,uint8_t * src_scan,FXCodec_Format src_format)1123 void ProgressiveDecoder::Resample(const RetainPtr<CFX_DIBitmap>& pDeviceBitmap,
1124                                   int32_t src_line,
1125                                   uint8_t* src_scan,
1126                                   FXCodec_Format src_format) {
1127   if (src_line < 0 || src_line >= m_SrcHeight) {
1128     return;
1129   }
1130 
1131   ResampleScanline(pDeviceBitmap, src_line, m_DecodeBuf, src_format);
1132 }
1133 
GetBitmapFormat() const1134 FXDIB_Format ProgressiveDecoder::GetBitmapFormat() const {
1135   switch (m_imageType) {
1136     case FXCODEC_IMAGE_JPG:
1137 #ifdef PDF_ENABLE_XFA_BMP
1138     case FXCODEC_IMAGE_BMP:
1139 #endif  // PDF_ENABLE_XFA_BMP
1140       return GetBitsPerPixel() <= 24 ? FXDIB_Format::kBgr : FXDIB_Format::kBgrx;
1141 #ifdef PDF_ENABLE_XFA_PNG
1142     case FXCODEC_IMAGE_PNG:
1143 #endif  // PDF_ENABLE_XFA_PNG
1144 #ifdef PDF_ENABLE_XFA_TIFF
1145     case FXCODEC_IMAGE_TIFF:
1146 #endif  // PDF_ENABLE_XFA_TIFF
1147     default:
1148       // TODO(crbug.com/355630556): Consider adding support for
1149       // `FXDIB_Format::kBgraPremul`
1150       return FXDIB_Format::kBgra;
1151   }
1152 }
1153 
GetFrames()1154 std::pair<FXCODEC_STATUS, size_t> ProgressiveDecoder::GetFrames() {
1155   if (!(m_status == FXCODEC_STATUS::kFrameReady ||
1156         m_status == FXCODEC_STATUS::kFrameToBeContinued)) {
1157     return {FXCODEC_STATUS::kError, 0};
1158   }
1159 
1160   switch (m_imageType) {
1161 #ifdef PDF_ENABLE_XFA_BMP
1162     case FXCODEC_IMAGE_BMP:
1163 #endif  // PDF_ENABLE_XFA_BMP
1164     case FXCODEC_IMAGE_JPG:
1165 #ifdef PDF_ENABLE_XFA_PNG
1166     case FXCODEC_IMAGE_PNG:
1167 #endif  // PDF_ENABLE_XFA_PNG
1168 #ifdef PDF_ENABLE_XFA_TIFF
1169     case FXCODEC_IMAGE_TIFF:
1170 #endif  // PDF_ENABLE_XFA_TIFF
1171       m_FrameNumber = 1;
1172       m_status = FXCODEC_STATUS::kDecodeReady;
1173       return {m_status, 1};
1174 #ifdef PDF_ENABLE_XFA_GIF
1175     case FXCODEC_IMAGE_GIF: {
1176       while (true) {
1177         GifDecoder::Status readResult;
1178         std::tie(readResult, m_FrameNumber) =
1179             GifDecoder::LoadFrameInfo(m_pGifContext.get());
1180         while (readResult == GifDecoder::Status::kUnfinished) {
1181           FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
1182           if (!GifReadMoreData(&error_status))
1183             return {error_status, 0};
1184 
1185           std::tie(readResult, m_FrameNumber) =
1186               GifDecoder::LoadFrameInfo(m_pGifContext.get());
1187         }
1188         if (readResult == GifDecoder::Status::kSuccess) {
1189           m_status = FXCODEC_STATUS::kDecodeReady;
1190           return {m_status, m_FrameNumber};
1191         }
1192         m_pGifContext = nullptr;
1193         m_status = FXCODEC_STATUS::kError;
1194         return {m_status, 0};
1195       }
1196     }
1197 #endif  // PDF_ENABLE_XFA_GIF
1198     default:
1199       return {FXCODEC_STATUS::kError, 0};
1200   }
1201 }
1202 
StartDecode(RetainPtr<CFX_DIBitmap> bitmap)1203 FXCODEC_STATUS ProgressiveDecoder::StartDecode(RetainPtr<CFX_DIBitmap> bitmap) {
1204   CHECK(bitmap);
1205   CHECK_EQ(bitmap->GetWidth(), m_SrcWidth);
1206   CHECK_EQ(bitmap->GetHeight(), m_SrcHeight);
1207   CHECK_GT(m_SrcWidth, 0);
1208   CHECK_GT(m_SrcHeight, 0);
1209 
1210   const FXDIB_Format format = bitmap->GetFormat();
1211   CHECK(format == FXDIB_Format::kBgra || format == FXDIB_Format::kBgr ||
1212         format == FXDIB_Format::kBgrx);
1213 
1214   if (m_status != FXCODEC_STATUS::kDecodeReady) {
1215     return FXCODEC_STATUS::kError;
1216   }
1217 
1218   if (m_FrameNumber == 0) {
1219     return FXCODEC_STATUS::kError;
1220   }
1221 
1222   if (bitmap->GetWidth() > 65535 || bitmap->GetHeight() > 65535) {
1223     return FXCODEC_STATUS::kError;
1224   }
1225 
1226   m_FrameCur = 0;
1227   m_pDeviceBitmap = std::move(bitmap);
1228   switch (m_imageType) {
1229 #ifdef PDF_ENABLE_XFA_BMP
1230     case FXCODEC_IMAGE_BMP:
1231       return BmpStartDecode();
1232 #endif  // PDF_ENABLE_XFA_BMP
1233 #ifdef PDF_ENABLE_XFA_GIF
1234     case FXCODEC_IMAGE_GIF:
1235       return GifStartDecode();
1236 #endif  // PDF_ENABLE_XFA_GIF
1237     case FXCODEC_IMAGE_JPG:
1238       return JpegStartDecode();
1239 #ifdef PDF_ENABLE_XFA_PNG
1240     case FXCODEC_IMAGE_PNG:
1241       return PngStartDecode();
1242 #endif  // PDF_ENABLE_XFA_PNG
1243 #ifdef PDF_ENABLE_XFA_TIFF
1244     case FXCODEC_IMAGE_TIFF:
1245       m_status = FXCODEC_STATUS::kDecodeToBeContinued;
1246       return m_status;
1247 #endif  // PDF_ENABLE_XFA_TIFF
1248     default:
1249       return FXCODEC_STATUS::kError;
1250   }
1251 }
1252 
ContinueDecode()1253 FXCODEC_STATUS ProgressiveDecoder::ContinueDecode() {
1254   if (m_status != FXCODEC_STATUS::kDecodeToBeContinued)
1255     return FXCODEC_STATUS::kError;
1256 
1257   switch (m_imageType) {
1258     case FXCODEC_IMAGE_JPG:
1259       return JpegContinueDecode();
1260 #ifdef PDF_ENABLE_XFA_BMP
1261     case FXCODEC_IMAGE_BMP:
1262       return BmpContinueDecode();
1263 #endif  // PDF_ENABLE_XFA_BMP
1264 #ifdef PDF_ENABLE_XFA_GIF
1265     case FXCODEC_IMAGE_GIF:
1266       return GifContinueDecode();
1267 #endif  // PDF_ENABLE_XFA_GIF
1268 #ifdef PDF_ENABLE_XFA_PNG
1269     case FXCODEC_IMAGE_PNG:
1270       return PngContinueDecode();
1271 #endif  // PDF_ENABLE_XFA_PNG
1272 #ifdef PDF_ENABLE_XFA_TIFF
1273     case FXCODEC_IMAGE_TIFF:
1274       return TiffContinueDecode();
1275 #endif  // PDF_ENABLE_XFA_TIFF
1276     default:
1277       return FXCODEC_STATUS::kError;
1278   }
1279 }
1280 
1281 }  // namespace fxcodec
1282