| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2020, Paul Roukema <roukemap@gmail.com> | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <AK/ByteBuffer.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-24 15:28:26 +01:00
										 |  |  | #include <AK/Debug.h>
 | 
					
						
							| 
									
										
										
										
											2020-09-20 12:19:01 +02:00
										 |  |  | #include <AK/MemoryStream.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | #include <AK/NonnullOwnPtrVector.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-18 21:18:35 -04:00
										 |  |  | #include <AK/Types.h>
 | 
					
						
							| 
									
										
										
										
											2022-12-18 18:13:19 +00:00
										 |  |  | #include <LibGfx/BMPLoader.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | #include <LibGfx/ICOLoader.h>
 | 
					
						
							|  |  |  | #include <LibGfx/PNGLoader.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Gfx { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // FIXME: This is in little-endian order. Maybe need a NetworkOrdered<T> equivalent eventually.
 | 
					
						
							|  |  |  | struct ICONDIR { | 
					
						
							| 
									
										
										
										
											2020-09-20 12:19:01 +02:00
										 |  |  |     u16 must_be_0 = 0; | 
					
						
							|  |  |  |     u16 must_be_1 = 0; | 
					
						
							|  |  |  |     u16 image_count = 0; | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2021-09-05 01:00:46 -07:00
										 |  |  | static_assert(AssertSize<ICONDIR, 6>()); | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct ICONDIRENTRY { | 
					
						
							|  |  |  |     u8 width; | 
					
						
							|  |  |  |     u8 height; | 
					
						
							|  |  |  |     u8 color_count; | 
					
						
							|  |  |  |     u8 reserved_0; | 
					
						
							|  |  |  |     u16 planes; | 
					
						
							|  |  |  |     u16 bits_per_pixel; | 
					
						
							|  |  |  |     u32 size; | 
					
						
							|  |  |  |     u32 offset; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2021-09-05 01:00:46 -07:00
										 |  |  | static_assert(AssertSize<ICONDIRENTRY, 16>()); | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-28 07:01:52 +02:00
										 |  |  | struct ICOImageDescriptor { | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |     u16 width; | 
					
						
							|  |  |  |     u16 height; | 
					
						
							| 
									
										
										
										
											2023-01-06 16:04:02 +01:00
										 |  |  |     u16 bits_per_pixel; | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |     size_t offset; | 
					
						
							|  |  |  |     size_t size; | 
					
						
							|  |  |  |     RefPtr<Gfx::Bitmap> bitmap; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct ICOLoadingContext { | 
					
						
							|  |  |  |     enum State { | 
					
						
							|  |  |  |         NotDecoded = 0, | 
					
						
							|  |  |  |         Error, | 
					
						
							|  |  |  |         DirectoryDecoded, | 
					
						
							|  |  |  |         BitmapDecoded | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     State state { NotDecoded }; | 
					
						
							| 
									
										
										
										
											2022-04-01 20:58:27 +03:00
										 |  |  |     u8 const* data { nullptr }; | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |     size_t data_size { 0 }; | 
					
						
							| 
									
										
										
										
											2021-05-28 07:01:52 +02:00
										 |  |  |     Vector<ICOImageDescriptor> images; | 
					
						
							| 
									
										
										
										
											2020-06-16 23:24:01 -04:00
										 |  |  |     size_t largest_index; | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-20 12:19:01 +02:00
										 |  |  | static Optional<size_t> decode_ico_header(InputMemoryStream& stream) | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | { | 
					
						
							|  |  |  |     ICONDIR header; | 
					
						
							| 
									
										
										
										
											2020-09-20 12:19:01 +02:00
										 |  |  |     stream >> Bytes { &header, sizeof(header) }; | 
					
						
							|  |  |  |     if (stream.handle_any_error()) | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (header.must_be_0 != 0 || header.must_be_1 != 1) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  |     return { header.image_count }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-28 07:01:52 +02:00
										 |  |  | static Optional<ICOImageDescriptor> decode_ico_direntry(InputMemoryStream& stream) | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | { | 
					
						
							|  |  |  |     ICONDIRENTRY entry; | 
					
						
							| 
									
										
										
										
											2020-09-20 12:19:01 +02:00
										 |  |  |     stream >> Bytes { &entry, sizeof(entry) }; | 
					
						
							|  |  |  |     if (stream.handle_any_error()) | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-06 16:04:02 +01:00
										 |  |  |     ICOImageDescriptor desc = { entry.width, entry.height, entry.bits_per_pixel, entry.offset, entry.size, nullptr }; | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |     if (desc.width == 0) | 
					
						
							|  |  |  |         desc.width = 256; | 
					
						
							|  |  |  |     if (desc.height == 0) | 
					
						
							|  |  |  |         desc.height = 256; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return { desc }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-01 20:58:27 +03:00
										 |  |  | static size_t find_largest_image(ICOLoadingContext const& context) | 
					
						
							| 
									
										
										
										
											2020-06-16 23:24:01 -04:00
										 |  |  | { | 
					
						
							|  |  |  |     size_t max_area = 0; | 
					
						
							|  |  |  |     size_t index = 0; | 
					
						
							|  |  |  |     size_t largest_index = 0; | 
					
						
							| 
									
										
										
										
											2023-01-06 16:04:02 +01:00
										 |  |  |     u16 max_bits_per_pixel = 0; | 
					
						
							| 
									
										
										
										
											2022-04-01 20:58:27 +03:00
										 |  |  |     for (auto const& desc : context.images) { | 
					
						
							| 
									
										
										
										
											2023-01-06 16:04:02 +01:00
										 |  |  |         if (static_cast<size_t>(desc.width) * static_cast<size_t>(desc.height) >= max_area) { | 
					
						
							|  |  |  |             if (desc.bits_per_pixel > max_bits_per_pixel) { | 
					
						
							|  |  |  |                 max_area = desc.width * desc.height; | 
					
						
							|  |  |  |                 largest_index = index; | 
					
						
							|  |  |  |                 max_bits_per_pixel = desc.bits_per_pixel; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-16 23:24:01 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |         ++index; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return largest_index; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | static bool load_ico_directory(ICOLoadingContext& context) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-20 12:19:01 +02:00
										 |  |  |     InputMemoryStream stream { { context.data, context.data_size } }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |     auto image_count = decode_ico_header(stream); | 
					
						
							|  |  |  |     if (!image_count.has_value() || image_count.value() == 0) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (size_t i = 0; i < image_count.value(); ++i) { | 
					
						
							|  |  |  |         auto maybe_desc = decode_ico_direntry(stream); | 
					
						
							|  |  |  |         if (!maybe_desc.has_value()) { | 
					
						
							| 
									
										
										
										
											2021-05-29 17:54:33 +03:00
										 |  |  |             dbgln_if(ICO_DEBUG, "load_ico_directory: error loading entry: {}", i); | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         auto& desc = maybe_desc.value(); | 
					
						
							|  |  |  |         if (desc.offset + desc.size < desc.offset // detect integer overflow
 | 
					
						
							|  |  |  |             || (desc.offset + desc.size) > context.data_size) { | 
					
						
							| 
									
										
										
										
											2021-05-29 17:54:33 +03:00
										 |  |  |             dbgln_if(ICO_DEBUG, "load_ico_directory: offset: {} size: {} doesn't fit in ICO size: {}", desc.offset, desc.size, context.data_size); | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-05-29 17:54:33 +03:00
										 |  |  |         dbgln_if(ICO_DEBUG, "load_ico_directory: index {} width: {} height: {} offset: {} size: {}", i, desc.width, desc.height, desc.offset, desc.size); | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |         context.images.append(desc); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-16 23:24:01 -04:00
										 |  |  |     context.largest_index = find_largest_image(context); | 
					
						
							| 
									
										
										
										
											2020-06-18 21:18:35 -04:00
										 |  |  |     context.state = ICOLoadingContext::State::DirectoryDecoded; | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  | bool ICOImageDecoderPlugin::load_ico_bitmap(ICOLoadingContext& context, Optional<size_t> index) | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | { | 
					
						
							|  |  |  |     if (context.state < ICOLoadingContext::State::DirectoryDecoded) { | 
					
						
							|  |  |  |         if (!load_ico_directory(context)) { | 
					
						
							|  |  |  |             context.state = ICOLoadingContext::State::Error; | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         context.state = ICOLoadingContext::State::DirectoryDecoded; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-16 23:24:01 -04:00
										 |  |  |     size_t real_index = context.largest_index; | 
					
						
							|  |  |  |     if (index.has_value()) | 
					
						
							|  |  |  |         real_index = index.value(); | 
					
						
							|  |  |  |     if (real_index >= context.images.size()) { | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-28 07:01:52 +02:00
										 |  |  |     ICOImageDescriptor& desc = context.images[real_index]; | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  |     if (PNGImageDecoderPlugin::sniff({ context.data + desc.offset, desc.size }).release_value_but_fixme_should_propagate_errors()) { | 
					
						
							|  |  |  |         auto png_decoder = PNGImageDecoderPlugin::create({ context.data + desc.offset, desc.size }).release_value_but_fixme_should_propagate_errors(); | 
					
						
							|  |  |  |         if (png_decoder->initialize()) { | 
					
						
							|  |  |  |             auto decoded_png_frame = png_decoder->frame(0); | 
					
						
							|  |  |  |             if (decoded_png_frame.is_error() || !decoded_png_frame.value().image) { | 
					
						
							|  |  |  |                 dbgln_if(ICO_DEBUG, "load_ico_bitmap: failed to load PNG encoded image index: {}", real_index); | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             desc.bitmap = decoded_png_frame.value().image; | 
					
						
							|  |  |  |             return true; | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  |         auto bmp_decoder = BMPImageDecoderPlugin::create_as_included_in_ico({}, { context.data + desc.offset, desc.size }).release_value_but_fixme_should_propagate_errors(); | 
					
						
							|  |  |  |         // NOTE: We don't initialize a BMP decoder in the usual way, but rather
 | 
					
						
							|  |  |  |         // we just create an object and try to sniff for a frame when it's included
 | 
					
						
							|  |  |  |         // inside an ICO image.
 | 
					
						
							|  |  |  |         if (bmp_decoder->sniff_dib()) { | 
					
						
							|  |  |  |             auto decoded_bmp_frame = bmp_decoder->frame(0); | 
					
						
							| 
									
										
										
										
											2022-12-18 18:13:19 +00:00
										 |  |  |             if (decoded_bmp_frame.is_error() || !decoded_bmp_frame.value().image) { | 
					
						
							|  |  |  |                 dbgln_if(ICO_DEBUG, "load_ico_bitmap: failed to load BMP encoded image index: {}", real_index); | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             desc.bitmap = decoded_bmp_frame.value().image; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             dbgln_if(ICO_DEBUG, "load_ico_bitmap: encoded image not supported at index: {}", real_index); | 
					
						
							| 
									
										
										
										
											2020-06-18 21:18:35 -04:00
										 |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  | ErrorOr<bool> ICOImageDecoderPlugin::sniff(ReadonlyBytes data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InputMemoryStream stream { { data.data(), data.size() } }; | 
					
						
							|  |  |  |     return decode_ico_header(stream).has_value(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> ICOImageDecoderPlugin::create(ReadonlyBytes data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return adopt_nonnull_own_or_enomem(new (nothrow) ICOImageDecoderPlugin(data.data(), data.size())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-01 20:58:27 +03:00
										 |  |  | ICOImageDecoderPlugin::ICOImageDecoderPlugin(u8 const* data, size_t size) | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | { | 
					
						
							|  |  |  |     m_context = make<ICOLoadingContext>(); | 
					
						
							|  |  |  |     m_context->data = data; | 
					
						
							|  |  |  |     m_context->data_size = size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-14 13:26:37 -06:00
										 |  |  | ICOImageDecoderPlugin::~ICOImageDecoderPlugin() = default; | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | IntSize ICOImageDecoderPlugin::size() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_context->state == ICOLoadingContext::State::Error) { | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (m_context->state < ICOLoadingContext::State::DirectoryDecoded) { | 
					
						
							|  |  |  |         if (!load_ico_directory(*m_context)) { | 
					
						
							|  |  |  |             m_context->state = ICOLoadingContext::State::Error; | 
					
						
							|  |  |  |             return {}; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         m_context->state = ICOLoadingContext::State::DirectoryDecoded; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-16 23:24:01 -04:00
										 |  |  |     return { m_context->images[m_context->largest_index].width, m_context->images[m_context->largest_index].height }; | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ICOImageDecoderPlugin::set_volatile() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_context->images[0].bitmap) | 
					
						
							|  |  |  |         m_context->images[0].bitmap->set_volatile(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 22:49:48 +02:00
										 |  |  | bool ICOImageDecoderPlugin::set_nonvolatile(bool& was_purged) | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!m_context->images[0].bitmap) | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2021-07-24 22:49:48 +02:00
										 |  |  |     return m_context->images[0].bitmap->set_nonvolatile(was_purged); | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  | bool ICOImageDecoderPlugin::initialize() | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-20 12:19:01 +02:00
										 |  |  |     InputMemoryStream stream { { m_context->data, m_context->data_size } }; | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  |     return decode_ico_header(stream).has_value(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ICOImageDecoderPlugin::is_animated() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | size_t ICOImageDecoderPlugin::loop_count() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | size_t ICOImageDecoderPlugin::frame_count() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 14:29:33 +01:00
										 |  |  | ErrorOr<ImageFrameDescriptor> ICOImageDecoderPlugin::frame(size_t index) | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-11-20 14:29:33 +01:00
										 |  |  |     if (index > 0) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:57:32 +00:00
										 |  |  |         return Error::from_string_literal("ICOImageDecoderPlugin: Invalid frame index"); | 
					
						
							| 
									
										
										
										
											2021-11-18 13:47:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (m_context->state == ICOLoadingContext::State::Error) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:57:32 +00:00
										 |  |  |         return Error::from_string_literal("ICOImageDecoderPlugin: Decoding failed"); | 
					
						
							| 
									
										
										
										
											2021-11-18 13:47:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (m_context->state < ICOLoadingContext::State::BitmapDecoded) { | 
					
						
							|  |  |  |         // NOTE: This forces the chunk decoding to happen.
 | 
					
						
							|  |  |  |         bool success = load_ico_bitmap(*m_context, {}); | 
					
						
							|  |  |  |         if (!success) { | 
					
						
							|  |  |  |             m_context->state = ICOLoadingContext::State::Error; | 
					
						
							| 
									
										
										
										
											2022-07-11 17:57:32 +00:00
										 |  |  |             return Error::from_string_literal("ICOImageDecoderPlugin: Decoding failed"); | 
					
						
							| 
									
										
										
										
											2021-11-18 13:47:29 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         m_context->state = ICOLoadingContext::State::BitmapDecoded; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VERIFY(m_context->images[m_context->largest_index].bitmap); | 
					
						
							| 
									
										
										
										
											2021-11-20 14:29:33 +01:00
										 |  |  |     return ImageFrameDescriptor { m_context->images[m_context->largest_index].bitmap, 0 }; | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-26 07:23:59 -05:00
										 |  |  | ErrorOr<Optional<ReadonlyBytes>> ICOImageDecoderPlugin::icc_data() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return OptionalNone {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-15 21:36:05 -04:00
										 |  |  | } |