Commit 8319e7a6 authored by Peter Kasting's avatar Peter Kasting Committed by Commit Bot

Support BI_JPEG and BI_PNG compression formats for BMP.

Bug: 552274
Change-Id: Ieaef52c738965861b31fde06ee9b2d5c9a95f967
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1777120Reviewed-by: default avatarLeon Scroggins <scroggo@chromium.org>
Commit-Queue: Peter Kasting <pkasting@chromium.org>
Auto-Submit: Peter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#692143}
parent d44b8bec
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
#include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.h" #include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.h"
#include "third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h"
#include "third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.h"
namespace { namespace {
// See comments on lookup_table_addresses_ in the header. // See comments on lookup_table_addresses_ in the header.
...@@ -78,6 +81,15 @@ BMPImageReader::BMPImageReader(ImageDecoder* parent, ...@@ -78,6 +81,15 @@ BMPImageReader::BMPImageReader(ImageDecoder* parent,
memset(&info_header_, 0, sizeof(info_header_)); memset(&info_header_, 0, sizeof(info_header_));
} }
BMPImageReader::~BMPImageReader() = default;
void BMPImageReader::SetData(SegmentReader* data) {
data_ = data;
fast_reader_.SetData(data);
if (alternate_decoder_)
alternate_decoder_->SetData(data_.get(), parent_->IsAllDataReceived());
}
bool BMPImageReader::DecodeBMP(bool only_size) { bool BMPImageReader::DecodeBMP(bool only_size) {
// Defensively clear the FastSharedBufferReader's cache, as another caller // Defensively clear the FastSharedBufferReader's cache, as another caller
// may have called SharedBuffer::MergeSegmentsIntoBuffer(). // may have called SharedBuffer::MergeSegmentsIntoBuffer().
...@@ -97,7 +109,10 @@ bool BMPImageReader::DecodeBMP(bool only_size) { ...@@ -97,7 +109,10 @@ bool BMPImageReader::DecodeBMP(bool only_size) {
// space is as well. Unfortunately, since the profile appears after // space is as well. Unfortunately, since the profile appears after
// everything else, this may delay processing until all data is received. // everything else, this may delay processing until all data is received.
// Luckily, few BMPs have an embedded color profile. // Luckily, few BMPs have an embedded color profile.
if (info_header_.profile_data && !ProcessEmbeddedColorProfile()) const bool use_alternate_decoder =
(info_header_.compression == JPEG) || (info_header_.compression == PNG);
if (!use_alternate_decoder && info_header_.profile_data &&
!ProcessEmbeddedColorProfile())
return false; return false;
// Set our size if we haven't already. In ICO files, IsDecodedSizeAvailable() // Set our size if we haven't already. In ICO files, IsDecodedSizeAvailable()
...@@ -111,6 +126,9 @@ bool BMPImageReader::DecodeBMP(bool only_size) { ...@@ -111,6 +126,9 @@ bool BMPImageReader::DecodeBMP(bool only_size) {
if (only_size) if (only_size)
return true; return true;
if (use_alternate_decoder)
return DecodeAlternateFormat();
// Read and process the bitmasks, if needed. // Read and process the bitmasks, if needed.
if (need_to_process_bitmasks_ && !ProcessBitmasks()) if (need_to_process_bitmasks_ && !ProcessBitmasks())
return false; return false;
...@@ -463,8 +481,9 @@ bool BMPImageReader::IsInfoHeaderValid() const { ...@@ -463,8 +481,9 @@ bool BMPImageReader::IsInfoHeaderValid() const {
case JPEG: case JPEG:
case PNG: case PNG:
// Only valid for Windows V3+. // Only valid for Windows V3+. We don't support embedding these inside
if (is_os21x_ || is_os22x_ || info_header_.bit_count) // ICO files.
if (is_os21x_ || is_os22x_ || info_header_.bit_count || !img_data_offset_)
return false; return false;
break; break;
...@@ -491,24 +510,51 @@ bool BMPImageReader::IsInfoHeaderValid() const { ...@@ -491,24 +510,51 @@ bool BMPImageReader::IsInfoHeaderValid() const {
// decoding. Few other people decode these either, they're unlikely to be // decoding. Few other people decode these either, they're unlikely to be
// in much use. // in much use.
// TODO(pkasting): Consider supporting these someday. // TODO(pkasting): Consider supporting these someday.
// * Bitmaps larger than 2^16 pixels in either dimension (Windows // * Bitmaps larger than 2^16 pixels in either dimension.
// probably doesn't draw these well anyway, and the decoded data would
// take a lot of memory).
if ((info_header_.width >= (1 << 16)) || (info_header_.height >= (1 << 16))) if ((info_header_.width >= (1 << 16)) || (info_header_.height >= (1 << 16)))
return false; return false;
// * Windows V3+ JPEG-in-BMP and PNG-in-BMP bitmaps (supposedly not found
// in the wild, only used to send data to printers?).
if ((info_header_.compression == JPEG) || (info_header_.compression == PNG))
return false;
// * OS/2 2.x Huffman-encoded monochrome bitmaps (see // * OS/2 2.x Huffman-encoded monochrome bitmaps (see
// http://www.fileformat.info/mirror/egff/ch09_05.htm , re: "G31D" // http://www.fileformat.info/mirror/egff/ch09_05.htm , re: "G31D"
// algorithm). // algorithm; this seems to be used in TIFF files as well).
if (info_header_.compression == HUFFMAN1D) if (info_header_.compression == HUFFMAN1D)
return false; return false;
return true; return true;
} }
bool BMPImageReader::DecodeAlternateFormat() {
// Create decoder if necessary.
if (!alternate_decoder_) {
if (info_header_.compression == JPEG) {
alternate_decoder_ = std::make_unique<JPEGImageDecoder>(
parent_->GetAlphaOption(), parent_->GetColorBehavior(),
parent_->GetMaxDecodedBytes(), img_data_offset_);
} else {
alternate_decoder_ = std::make_unique<PNGImageDecoder>(
parent_->GetAlphaOption(), ImageDecoder::kDefaultBitDepth,
parent_->GetColorBehavior(), parent_->GetMaxDecodedBytes(),
img_data_offset_);
}
alternate_decoder_->SetData(data_.get(), parent_->IsAllDataReceived());
}
// Decode the image.
if (alternate_decoder_->IsSizeAvailable()) {
if (alternate_decoder_->Size() != parent_->Size())
return parent_->SetFailed();
alternate_decoder_->SetMemoryAllocator(buffer_->GetAllocator());
const auto* frame = alternate_decoder_->DecodeFrameBufferAtIndex(0);
alternate_decoder_->SetMemoryAllocator(nullptr);
if (frame)
*buffer_ = *frame;
}
return alternate_decoder_->Failed()
? parent_->SetFailed()
: (buffer_->GetStatus() == ImageFrame::kFrameComplete);
}
bool BMPImageReader::ProcessEmbeddedColorProfile() { bool BMPImageReader::ProcessEmbeddedColorProfile() {
// Ensure we have received the whole profile. // Ensure we have received the whole profile.
if ((info_header_.profile_data > data_->size()) || if ((info_header_.profile_data > data_->size()) ||
......
...@@ -64,12 +64,10 @@ class PLATFORM_EXPORT BMPImageReader final { ...@@ -64,12 +64,10 @@ class PLATFORM_EXPORT BMPImageReader final {
size_t decoded_and_header_offset, size_t decoded_and_header_offset,
size_t img_data_offset, size_t img_data_offset,
bool is_in_ico); bool is_in_ico);
~BMPImageReader();
void SetBuffer(ImageFrame* buffer) { buffer_ = buffer; } void SetBuffer(ImageFrame* buffer) { buffer_ = buffer; }
void SetData(SegmentReader* data) { void SetData(SegmentReader* data);
data_ = data;
fast_reader_.SetData(data);
}
// Does the actual decoding. If |only_size| is true, decoding only // Does the actual decoding. If |only_size| is true, decoding only
// progresses as far as necessary to get the image size. Returns // progresses as far as necessary to get the image size. Returns
...@@ -182,6 +180,9 @@ class PLATFORM_EXPORT BMPImageReader final { ...@@ -182,6 +180,9 @@ class PLATFORM_EXPORT BMPImageReader final {
// Processes any embedded ICC color profile. // Processes any embedded ICC color profile.
bool ProcessEmbeddedColorProfile(); bool ProcessEmbeddedColorProfile();
// Decodes the image data for compression types JPEG and PNG.
bool DecodeAlternateFormat();
// For BI_[ALPHA]BITFIELDS images, initializes the bit_masks_[] and // For BI_[ALPHA]BITFIELDS images, initializes the bit_masks_[] and
// bit_offsets_[] arrays. ProcessInfoHeader() will initialize these for // bit_offsets_[] arrays. ProcessInfoHeader() will initialize these for
// other compression types where needed. // other compression types where needed.
...@@ -335,6 +336,9 @@ class PLATFORM_EXPORT BMPImageReader final { ...@@ -335,6 +336,9 @@ class PLATFORM_EXPORT BMPImageReader final {
// The BMP info header. // The BMP info header.
BitmapInfoHeader info_header_; BitmapInfoHeader info_header_;
// Used only for bitmaps with compression types JPEG or PNG.
std::unique_ptr<ImageDecoder> alternate_decoder_;
// True if this is an OS/2 1.x (aka Windows 2.x) BMP. The struct // True if this is an OS/2 1.x (aka Windows 2.x) BMP. The struct
// layouts for this type of BMP are slightly different from the later, // layouts for this type of BMP are slightly different from the later,
// more common formats. // more common formats.
......
...@@ -47,11 +47,7 @@ ICOImageDecoder::ICOImageDecoder(AlphaOption alpha_option, ...@@ -47,11 +47,7 @@ ICOImageDecoder::ICOImageDecoder(AlphaOption alpha_option,
: ImageDecoder(alpha_option, : ImageDecoder(alpha_option,
ImageDecoder::kDefaultBitDepth, ImageDecoder::kDefaultBitDepth,
color_behavior, color_behavior,
max_decoded_bytes), max_decoded_bytes) {}
fast_reader_(nullptr),
decoded_offset_(0),
dir_entries_count_(0),
color_behavior_(color_behavior) {}
ICOImageDecoder::~ICOImageDecoder() = default; ICOImageDecoder::~ICOImageDecoder() = default;
......
...@@ -147,12 +147,12 @@ class PLATFORM_EXPORT ICOImageDecoder final : public ImageDecoder { ...@@ -147,12 +147,12 @@ class PLATFORM_EXPORT ICOImageDecoder final : public ImageDecoder {
// if the type could be determined. // if the type could be determined.
ImageType ImageTypeAtIndex(size_t); ImageType ImageTypeAtIndex(size_t);
FastSharedBufferReader fast_reader_; FastSharedBufferReader fast_reader_{nullptr};
// An index into |data_| representing how much we've already decoded. // An index into |data_| representing how much we've already decoded.
// Note that this only tracks data _this_ class decodes; once the // Note that this only tracks data _this_ class decodes; once the
// BMPImageReader takes over this will not be updated further. // BMPImageReader takes over this will not be updated further.
size_t decoded_offset_; size_t decoded_offset_ = 0;
// Which type of file (ICO/CUR) this is. // Which type of file (ICO/CUR) this is.
FileType file_type_; FileType file_type_;
...@@ -164,7 +164,7 @@ class PLATFORM_EXPORT ICOImageDecoder final : public ImageDecoder { ...@@ -164,7 +164,7 @@ class PLATFORM_EXPORT ICOImageDecoder final : public ImageDecoder {
// Count of directory entries is parsed from header before initializing // Count of directory entries is parsed from header before initializing
// dir_entries_. dir_entries_ is populated only when full header // dir_entries_. dir_entries_ is populated only when full header
// information including directory entries is available. // information including directory entries is available.
size_t dir_entries_count_; size_t dir_entries_count_ = 0;
// The image decoders for the various frames. // The image decoders for the various frames.
typedef Vector<std::unique_ptr<BMPImageReader>> BMPReaders; typedef Vector<std::unique_ptr<BMPImageReader>> BMPReaders;
...@@ -176,9 +176,6 @@ class PLATFORM_EXPORT ICOImageDecoder final : public ImageDecoder { ...@@ -176,9 +176,6 @@ class PLATFORM_EXPORT ICOImageDecoder final : public ImageDecoder {
// for the particular entry being decoded. // for the particular entry being decoded.
IntSize frame_size_; IntSize frame_size_;
// Used to pass on to an internally created PNG decoder.
const ColorBehavior color_behavior_;
DISALLOW_COPY_AND_ASSIGN(ICOImageDecoder); DISALLOW_COPY_AND_ASSIGN(ICOImageDecoder);
}; };
......
...@@ -320,6 +320,8 @@ class PLATFORM_EXPORT ImageDecoder { ...@@ -320,6 +320,8 @@ class PLATFORM_EXPORT ImageDecoder {
return premultiply_alpha_ ? kAlphaPremultiplied : kAlphaNotPremultiplied; return premultiply_alpha_ ? kAlphaPremultiplied : kAlphaNotPremultiplied;
} }
size_t GetMaxDecodedBytes() const { return max_decoded_bytes_; }
// Sets the "decode failure" flag. For caller convenience (since so // Sets the "decode failure" flag. For caller convenience (since so
// many callers want to return false after calling this), returns false // many callers want to return false after calling this), returns false
// to enable easy tailcalling. Subclasses may override this to also // to enable easy tailcalling. Subclasses may override this to also
......
...@@ -340,11 +340,11 @@ class JPEGImageReader final { ...@@ -340,11 +340,11 @@ class JPEGImageReader final {
USING_FAST_MALLOC(JPEGImageReader); USING_FAST_MALLOC(JPEGImageReader);
public: public:
JPEGImageReader(JPEGImageDecoder* decoder) JPEGImageReader(JPEGImageDecoder* decoder, size_t initial_offset)
: decoder_(decoder), : decoder_(decoder),
needs_restart_(false), needs_restart_(false),
restart_position_(0), restart_position_(initial_offset),
next_read_position_(0), next_read_position_(initial_offset),
last_set_byte_(nullptr), last_set_byte_(nullptr),
state_(JPEG_HEADER), state_(JPEG_HEADER),
samples_(nullptr) { samples_(nullptr) {
...@@ -854,11 +854,13 @@ void term_source(j_decompress_ptr jd) { ...@@ -854,11 +854,13 @@ void term_source(j_decompress_ptr jd) {
JPEGImageDecoder::JPEGImageDecoder(AlphaOption alpha_option, JPEGImageDecoder::JPEGImageDecoder(AlphaOption alpha_option,
const ColorBehavior& color_behavior, const ColorBehavior& color_behavior,
size_t max_decoded_bytes) size_t max_decoded_bytes,
size_t offset)
: ImageDecoder(alpha_option, : ImageDecoder(alpha_option,
ImageDecoder::kDefaultBitDepth, ImageDecoder::kDefaultBitDepth,
color_behavior, color_behavior,
max_decoded_bytes) {} max_decoded_bytes),
offset_(offset) {}
JPEGImageDecoder::~JPEGImageDecoder() = default; JPEGImageDecoder::~JPEGImageDecoder() = default;
...@@ -1184,7 +1186,7 @@ void JPEGImageDecoder::Decode(bool only_size) { ...@@ -1184,7 +1186,7 @@ void JPEGImageDecoder::Decode(bool only_size) {
return; return;
if (!reader_) { if (!reader_) {
reader_ = std::make_unique<JPEGImageReader>(this); reader_ = std::make_unique<JPEGImageReader>(this, offset_);
reader_->SetData(data_.get()); reader_->SetData(data_.get());
} }
......
...@@ -36,7 +36,10 @@ class JPEGImageReader; ...@@ -36,7 +36,10 @@ class JPEGImageReader;
class PLATFORM_EXPORT JPEGImageDecoder final : public ImageDecoder { class PLATFORM_EXPORT JPEGImageDecoder final : public ImageDecoder {
public: public:
JPEGImageDecoder(AlphaOption, const ColorBehavior&, size_t max_decoded_bytes); JPEGImageDecoder(AlphaOption,
const ColorBehavior&,
size_t max_decoded_bytes,
size_t offset = 0);
~JPEGImageDecoder() override; ~JPEGImageDecoder() override;
// ImageDecoder: // ImageDecoder:
...@@ -79,6 +82,7 @@ class PLATFORM_EXPORT JPEGImageDecoder final : public ImageDecoder { ...@@ -79,6 +82,7 @@ class PLATFORM_EXPORT JPEGImageDecoder final : public ImageDecoder {
void Decode(bool only_size); void Decode(bool only_size);
std::unique_ptr<JPEGImageReader> reader_; std::unique_ptr<JPEGImageReader> reader_;
const size_t offset_;
std::unique_ptr<ImagePlanes> image_planes_; std::unique_ptr<ImagePlanes> image_planes_;
IntSize decoded_size_; IntSize decoded_size_;
Vector<SkISize> supported_decode_sizes_; Vector<SkISize> supported_decode_sizes_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment