Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cfx_gifcontext.cpp
Go to the documentation of this file.
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/fxcodec/gif/cfx_gifcontext.h"
8
9#include <stdint.h>
10#include <string.h>
11
12#include <algorithm>
13#include <array>
14#include <iterator>
15#include <utility>
16
17#include "core/fxcodec/cfx_codec_memory.h"
18#include "core/fxcrt/byteorder.h"
19#include "core/fxcrt/compiler_specific.h"
20#include "core/fxcrt/data_vector.h"
21#include "core/fxcrt/stl_util.h"
22
23namespace fxcodec {
24
25namespace {
26
27constexpr std::array<const int32_t, 4> kGifInterlaceStep = {{8, 8, 4, 2}};
28
29} // namespace
30
33
34CFX_GifContext::~CFX_GifContext() = default;
35
36void CFX_GifContext::ReadScanline(int32_t row_num,
37 pdfium::span<uint8_t> row_buf) {
38 delegate_->GifReadScanline(row_num, row_buf);
39}
40
41bool CFX_GifContext::GetRecordPosition(uint32_t cur_pos,
42 int32_t left,
43 int32_t top,
44 int32_t width,
45 int32_t height,
46 pdfium::span<CFX_GifPalette> pal,
47 int32_t trans_index,
48 bool interlace) {
49 return delegate_->GifInputRecordPositionBuf(
50 cur_pos, FX_RECT(left, top, left + width, top + height), pal, trans_index,
51 interlace);
52}
53
60
63 while (true) {
64 switch (decode_status_) {
67 case GIF_D_STATUS_SIG: {
68 uint8_t signature;
69 if (!ReadAllOrNone(pdfium::byte_span_from_ref(signature))) {
71 }
72 switch (signature) {
74 SaveDecodingStatus(GIF_D_STATUS_EXT);
75 continue;
76 case GIF_SIG_IMAGE:
77 SaveDecodingStatus(GIF_D_STATUS_IMG_INFO);
78 continue;
79 case GIF_SIG_TRAILER:
80 SaveDecodingStatus(GIF_D_STATUS_TAIL);
82 default:
83 if (!input_buffer_->IsEOF()) {
84 // The Gif File has non_standard Tag!
85 SaveDecodingStatus(GIF_D_STATUS_SIG);
86 continue;
87 }
88 // The Gif File Doesn't have Trailer Tag!
90 }
91 }
92 case GIF_D_STATUS_EXT: {
93 uint8_t extension;
94 if (!ReadAllOrNone(pdfium::byte_span_from_ref(extension))) {
96 }
97 switch (extension) {
98 case GIF_BLOCK_CE:
99 SaveDecodingStatus(GIF_D_STATUS_EXT_CE);
100 continue;
101 case GIF_BLOCK_GCE:
102 SaveDecodingStatus(GIF_D_STATUS_EXT_GCE);
103 continue;
104 case GIF_BLOCK_PTE:
105 SaveDecodingStatus(GIF_D_STATUS_EXT_PTE);
106 continue;
107 default: {
108 int32_t status = GIF_D_STATUS_EXT_UNE;
109 if (extension == GIF_BLOCK_PTE) {
110 status = GIF_D_STATUS_EXT_PTE;
111 }
112 SaveDecodingStatus(status);
113 continue;
114 }
115 }
116 }
118 ret = DecodeImageInfo();
120 return ret;
121
122 continue;
123 }
125 uint8_t img_data_size;
126 size_t read_marker = input_buffer_->GetPosition();
127 if (!ReadAllOrNone(pdfium::byte_span_from_ref(img_data_size))) {
129 }
130 while (img_data_size != GIF_BLOCK_TERMINAL) {
131 if (!input_buffer_->Seek(input_buffer_->GetPosition() +
132 img_data_size)) {
133 input_buffer_->Seek(read_marker);
135 }
136
137 // This saving of the scan state on partial reads is why
138 // ScanForTerminalMarker() cannot be used here.
139 SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
140 read_marker = input_buffer_->GetPosition();
141 if (!ReadAllOrNone(pdfium::byte_span_from_ref(img_data_size))) {
143 }
144 }
145 SaveDecodingStatus(GIF_D_STATUS_SIG);
146 continue;
147 }
148 default: {
149 ret = DecodeExtension();
151 return ret;
152 break;
153 }
154 }
155 }
156}
157
159 if (frame_num >= images_.size())
161
162 CFX_GifImage* gif_image = images_[frame_num].get();
163 if (gif_image->image_info.height == 0)
165
166 uint32_t gif_img_row_bytes = gif_image->image_info.width;
167 if (gif_img_row_bytes == 0)
169
171 gif_image->row_buffer.resize(gif_img_row_bytes);
172 CFX_GifGraphicControlExtension* gif_img_gce = gif_image->image_GCE.get();
173 pdfium::span<CFX_GifPalette> pLocalPalette = gif_image->local_palettes;
174 if (!gif_img_gce) {
175 bool bRes = GetRecordPosition(
176 gif_image->data_pos, gif_image->image_info.left,
177 gif_image->image_info.top, gif_image->image_info.width,
178 gif_image->image_info.height, pLocalPalette, -1,
179 gif_image->image_info.local_flags.interlace);
180 if (!bRes) {
181 gif_image->row_buffer.clear();
183 }
184 } else {
185 bool bRes = GetRecordPosition(
186 gif_image->data_pos, gif_image->image_info.left,
187 gif_image->image_info.top, gif_image->image_info.width,
188 gif_image->image_info.height, pLocalPalette,
189 gif_image->image_GCE->gce_flags.transparency
190 ? static_cast<int32_t>(gif_image->image_GCE->trans_index)
191 : -1,
192 gif_image->image_info.local_flags.interlace);
193 if (!bRes) {
194 gif_image->row_buffer.clear();
196 }
197 }
198
199 if (gif_image->code_exp > GIF_MAX_LZW_EXP) {
200 gif_image->row_buffer.clear();
202 }
203
204 img_row_offset_ = 0;
206 img_pass_num_ = 0;
207 gif_image->row_num = 0;
208 SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
209 }
210
211 uint8_t img_data_size;
212 DataVector<uint8_t> img_data;
213 size_t read_marker = input_buffer_->GetPosition();
214
215 // TODO(crbug.com/pdfium/1793): This logic can be simplified a lot, but it
216 // probably makes more sense to switch to a different GIF decoder altogether.
218 if (!ReadAllOrNone(pdfium::byte_span_from_ref(img_data_size))) {
220 }
221 if (img_data_size != GIF_BLOCK_TERMINAL) {
222 img_data.resize(img_data_size);
223 if (!ReadAllOrNone(img_data)) {
224 input_buffer_->Seek(read_marker);
226 }
227 if (!lzw_decompressor_) {
228 lzw_decompressor_ = LZWDecompressor::Create(GetPaletteExp(gif_image),
229 gif_image->code_exp);
230 if (!lzw_decompressor_) {
231 DecodingFailureAtTailCleanup(gif_image);
233 }
234 }
235 lzw_decompressor_->SetSource(img_data);
236
237 SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
239 img_row_avail_size_ = gif_img_row_bytes - img_row_offset_;
240 auto img_row_span = pdfium::make_span(gif_image->row_buffer)
243 lzw_decompressor_->Decode(img_row_span.data(), &img_row_avail_size_));
245 DecodingFailureAtTailCleanup(gif_image);
247 }
248
249 while (ret != LZWDecompressor::Status::kError) {
251 ReadScanline(gif_image->row_num, gif_image->row_buffer);
252 gif_image->row_buffer.clear();
253 SaveDecodingStatus(GIF_D_STATUS_TAIL);
255 }
256
258 read_marker = input_buffer_->GetPosition();
259 if (!ReadAllOrNone(pdfium::byte_span_from_ref(img_data_size))) {
261 }
262 if (img_data_size != GIF_BLOCK_TERMINAL) {
263 img_data.resize(img_data_size);
264 if (!ReadAllOrNone(img_data)) {
265 input_buffer_->Seek(read_marker);
267 }
268 lzw_decompressor_->SetSource(img_data);
269
270 SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
272 img_row_avail_size_ = gif_img_row_bytes - img_row_offset_;
273 img_row_span = pdfium::make_span(gif_image->row_buffer)
275 ret = UNSAFE_TODO(lzw_decompressor_->Decode(img_row_span.data(),
276 &img_row_avail_size_));
277 }
278 }
279
282 ReadScanline(gif_image->row_num, gif_image->row_buffer);
283 gif_image->row_num += kGifInterlaceStep[img_pass_num_];
284 if (gif_image->row_num >=
285 static_cast<int32_t>(gif_image->image_info.height)) {
287 if (img_pass_num_ == std::size(kGifInterlaceStep)) {
288 DecodingFailureAtTailCleanup(gif_image);
290 }
291 gif_image->row_num = kGifInterlaceStep[img_pass_num_] / 2;
292 }
293 } else {
294 ReadScanline(gif_image->row_num++, gif_image->row_buffer);
295 }
296
297 img_row_offset_ = 0;
298 img_row_avail_size_ = gif_img_row_bytes;
299 img_row_span = pdfium::make_span(gif_image->row_buffer)
301 ret = UNSAFE_TODO(lzw_decompressor_->Decode(img_row_span.data(),
302 &img_row_avail_size_));
303 }
304
306 DecodingFailureAtTailCleanup(gif_image);
308 }
309 }
310 }
311 SaveDecodingStatus(GIF_D_STATUS_TAIL);
312 }
314}
315
316void CFX_GifContext::SetInputBuffer(RetainPtr<CFX_CodecMemory> codec_memory) {
317 input_buffer_ = std::move(codec_memory);
318}
319
320uint32_t CFX_GifContext::GetAvailInput() const {
321 if (!input_buffer_)
322 return 0;
323
324 return pdfium::checked_cast<uint32_t>(input_buffer_->GetSize() -
325 input_buffer_->GetPosition());
326}
327
328bool CFX_GifContext::ReadAllOrNone(pdfium::span<uint8_t> dest) {
329 if (!input_buffer_ || dest.empty()) {
330 return false;
331 }
332 size_t read_marker = input_buffer_->GetPosition();
333 size_t read = input_buffer_->ReadBlock(dest);
334 if (read < dest.size()) {
335 input_buffer_->Seek(read_marker);
336 return false;
337 }
338 return true;
339}
340
342 CFX_GifHeader header;
343 if (!ReadAllOrNone(pdfium::byte_span_from_ref(header))) {
345 }
346 if (strncmp(header.signature, kGifSignature87, 6) != 0 &&
347 strncmp(header.signature, kGifSignature89, 6) != 0) {
349 }
350
352}
353
356 size_t read_marker = input_buffer_->GetPosition();
357 if (!ReadAllOrNone(pdfium::byte_span_from_ref(lsd))) {
359 }
361 uint32_t palette_count = unsigned(2 << lsd.global_flags.pal_bits);
362 if (lsd.bc_index >= palette_count)
364 bc_index_ = lsd.bc_index;
365
366 std::vector<CFX_GifPalette> palette(palette_count);
367 if (!ReadAllOrNone(pdfium::as_writable_byte_span(palette))) {
368 // Roll back the read for the LSD
369 input_buffer_->Seek(read_marker);
371 }
372
376 std::swap(global_palette_, palette);
377 }
378
381
383}
384
385void CFX_GifContext::SaveDecodingStatus(int32_t status) {
386 decode_status_ = status;
387}
388
389GifDecoder::Status CFX_GifContext::DecodeExtension() {
390 size_t read_marker = input_buffer_->GetPosition();
391
392 switch (decode_status_) {
393 case GIF_D_STATUS_EXT_CE: {
394 if (!ScanForTerminalMarker()) {
395 input_buffer_->Seek(read_marker);
397 }
398 break;
399 }
402 if (!ReadAllOrNone(pdfium::byte_span_from_ref(gif_pte))) {
404 }
405 graphic_control_extension_ = nullptr;
406 if (!ScanForTerminalMarker()) {
407 input_buffer_->Seek(read_marker);
409 }
410 break;
411 }
414 if (!ReadAllOrNone(pdfium::byte_span_from_ref(gif_gce))) {
416 }
417 if (!graphic_control_extension_.get()) {
418 graphic_control_extension_ =
419 std::make_unique<CFX_GifGraphicControlExtension>();
420 }
421 graphic_control_extension_->block_size = gif_gce.block_size;
422 graphic_control_extension_->gce_flags = gif_gce.gce_flags;
423 graphic_control_extension_->delay_time =
424 fxcrt::FromLE16(gif_gce.delay_time);
425 graphic_control_extension_->trans_index = gif_gce.trans_index;
426 break;
427 }
428 default: {
429 if (decode_status_ == GIF_D_STATUS_EXT_PTE)
430 graphic_control_extension_ = nullptr;
431 if (!ScanForTerminalMarker()) {
432 input_buffer_->Seek(read_marker);
434 }
435 }
436 }
437
438 SaveDecodingStatus(GIF_D_STATUS_SIG);
440}
441
442GifDecoder::Status CFX_GifContext::DecodeImageInfo() {
443 if (width_ <= 0 || height_ <= 0)
445
446 size_t read_marker = input_buffer_->GetPosition();
447 CFX_GifImageInfo img_info;
448 if (!ReadAllOrNone(pdfium::byte_span_from_ref(img_info))) {
450 }
451 auto gif_image = std::make_unique<CFX_GifImage>();
452 gif_image->image_info.left = fxcrt::FromLE16(img_info.left);
453 gif_image->image_info.top = fxcrt::FromLE16(img_info.top);
454 gif_image->image_info.width = fxcrt::FromLE16(img_info.width);
455 gif_image->image_info.height = fxcrt::FromLE16(img_info.height);
456 gif_image->image_info.local_flags = img_info.local_flags;
457 if (gif_image->image_info.left + gif_image->image_info.width > width_ ||
458 gif_image->image_info.top + gif_image->image_info.height > height_)
460
461 CFX_GifLocalFlags* gif_img_info_lf = &img_info.local_flags;
462 if (gif_img_info_lf->local_pal) {
463 gif_image->local_palette_exp = gif_img_info_lf->pal_bits;
464 uint32_t loc_pal_count = unsigned(2 << gif_img_info_lf->pal_bits);
465 std::vector<CFX_GifPalette> loc_pal(loc_pal_count);
466 if (!ReadAllOrNone(pdfium::as_writable_byte_span(loc_pal))) {
467 input_buffer_->Seek(read_marker);
469 }
470 gif_image->local_palettes = std::move(loc_pal);
471 }
472
473 uint8_t code_size;
474 if (!ReadAllOrNone(pdfium::span_from_ref(code_size))) {
475 input_buffer_->Seek(read_marker);
477 }
478
479 gif_image->code_exp = code_size;
480 gif_image->data_pos = delegate_->GifCurrentPosition();
481 gif_image->image_GCE = nullptr;
482 if (graphic_control_extension_.get()) {
483 if (graphic_control_extension_->gce_flags.transparency) {
484 // Need to test that the color that is going to be transparent is actually
485 // in the palette being used.
486 if (graphic_control_extension_->trans_index >=
487 (2 << GetPaletteExp(gif_image.get()))) {
489 }
490 }
491 gif_image->image_GCE = std::move(graphic_control_extension_);
492 graphic_control_extension_ = nullptr;
493 }
494
495 images_.push_back(std::move(gif_image));
496 SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
498}
499
500void CFX_GifContext::DecodingFailureAtTailCleanup(CFX_GifImage* gif_image) {
501 gif_image->row_buffer.clear();
502 SaveDecodingStatus(GIF_D_STATUS_TAIL);
503}
504
505bool CFX_GifContext::ScanForTerminalMarker() {
506 uint8_t data_size;
507 if (!ReadAllOrNone(pdfium::span_from_ref(data_size))) {
508 return false;
509 }
510 while (data_size != GIF_BLOCK_TERMINAL) {
511 if (!input_buffer_->Seek(input_buffer_->GetPosition() + data_size) ||
512 !ReadAllOrNone(pdfium::span_from_ref(data_size))) {
513 return false;
514 }
515 }
516 return true;
517}
518
519uint8_t CFX_GifContext::GetPaletteExp(CFX_GifImage* gif_image) const {
520 return !gif_image->local_palettes.empty() ? gif_image->local_palette_exp
522}
523
524} // namespace fxcodec
#define GIF_SIG_EXTENSION
Definition cfx_gif.h:20
#define GIF_BLOCK_GCE
Definition cfx_gif.h:23
#define GIF_D_STATUS_TAIL
Definition cfx_gif.h:30
#define GIF_D_STATUS_EXT
Definition cfx_gif.h:31
#define GIF_D_STATUS_EXT_UNE
Definition cfx_gif.h:35
#define GIF_SIG_TRAILER
Definition cfx_gif.h:22
#define GIF_D_STATUS_EXT_GCE
Definition cfx_gif.h:33
#define GIF_SIG_IMAGE
Definition cfx_gif.h:21
#define GIF_D_STATUS_EXT_CE
Definition cfx_gif.h:32
#define GIF_D_STATUS_SIG
Definition cfx_gif.h:29
#define GIF_D_STATUS_IMG_INFO
Definition cfx_gif.h:36
#define GIF_BLOCK_PTE
Definition cfx_gif.h:24
#define GIF_MAX_LZW_EXP
Definition cfx_gif.h:27
#define GIF_BLOCK_TERMINAL
Definition cfx_gif.h:26
#define GIF_BLOCK_CE
Definition cfx_gif.h:25
#define GIF_D_STATUS_IMG_DATA
Definition cfx_gif.h:37
#define GIF_D_STATUS_EXT_PTE
Definition cfx_gif.h:34
CFX_GifContext(GifDecoder::Delegate *delegate)
GifDecoder::Status GetFrame()
void SetInputBuffer(RetainPtr< CFX_CodecMemory > codec_memory)
GifDecoder::Status LoadFrame(size_t frame_num)
bool GetRecordPosition(uint32_t cur_pos, int32_t left, int32_t top, int32_t width, int32_t height, pdfium::span< CFX_GifPalette > pal, int32_t trans_index, bool interlace)
uint32_t GetAvailInput() const
void ReadScanline(int32_t row_num, pdfium::span< uint8_t > row_buf)
bool ReadAllOrNone(pdfium::span< uint8_t > dest)
GifDecoder::Status ReadHeader()
GifDecoder::Status ReadLogicalScreenDescriptor()
GifDecoder::Status ReadGifSignature()
#define UNSAFE_TODO(...)
uint16_t FromLE16(uint16_t x)
Definition byteorder.h:56
uint8_t global_pal
Definition cfx_gif.h:44
uint8_t color_resolution
Definition cfx_gif.h:43
uint8_t sort_flag
Definition cfx_gif.h:42
uint8_t pal_bits
Definition cfx_gif.h:41
uint16_t height
Definition cfx_gif.h:71
uint16_t top
Definition cfx_gif.h:69
uint16_t left
Definition cfx_gif.h:68
uint16_t width
Definition cfx_gif.h:70
CFX_GifLocalFlags local_flags
Definition cfx_gif.h:72
uint8_t code_exp
Definition cfx_gif.h:123
CFX_GifImageInfo image_info
Definition cfx_gif.h:121
uint8_t local_palette_exp
Definition cfx_gif.h:122
int32_t row_num
Definition cfx_gif.h:125
uint8_t local_pal
Definition cfx_gif.h:52
uint8_t interlace
Definition cfx_gif.h:51
uint8_t pal_bits
Definition cfx_gif.h:48
CFX_GifGlobalFlags global_flags
Definition cfx_gif.h:62