Serenity Operating System
at master 112 lines 2.9 kB view raw
1/* 2 * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Function.h> 8#include <LibGfx/Bitmap.h> 9#include <LibWeb/Loader/ImageResource.h> 10#include <LibWeb/Platform/ImageCodecPlugin.h> 11 12namespace Web { 13 14NonnullRefPtr<ImageResource> ImageResource::convert_from_resource(Resource& resource) 15{ 16 return adopt_ref(*new ImageResource(resource)); 17} 18 19ImageResource::ImageResource(LoadRequest const& request) 20 : Resource(Type::Image, request) 21{ 22} 23 24ImageResource::ImageResource(Resource& resource) 25 : Resource(Type::Image, resource) 26{ 27} 28 29ImageResource::~ImageResource() = default; 30 31int ImageResource::frame_duration(size_t frame_index) const 32{ 33 decode_if_needed(); 34 if (frame_index >= m_decoded_frames.size()) 35 return 0; 36 return m_decoded_frames[frame_index].duration; 37} 38 39void ImageResource::decode_if_needed() const 40{ 41 if (!has_encoded_data()) 42 return; 43 44 if (m_has_attempted_decode) 45 return; 46 47 if (!m_decoded_frames.is_empty()) 48 return; 49 50 auto image = Platform::ImageCodecPlugin::the().decode_image(encoded_data()); 51 m_has_attempted_decode = true; 52 53 if (!image.has_value()) { 54 dbgln("Could not decode image resource {}", url()); 55 return; 56 } 57 58 m_loop_count = image.value().loop_count; 59 m_animated = image.value().is_animated; 60 m_decoded_frames.resize(image.value().frames.size()); 61 for (size_t i = 0; i < m_decoded_frames.size(); ++i) { 62 auto& frame = m_decoded_frames[i]; 63 frame.bitmap = image.value().frames[i].bitmap; 64 frame.duration = image.value().frames[i].duration; 65 } 66} 67 68Gfx::Bitmap const* ImageResource::bitmap(size_t frame_index) const 69{ 70 decode_if_needed(); 71 if (frame_index >= m_decoded_frames.size()) 72 return nullptr; 73 return m_decoded_frames[frame_index].bitmap; 74} 75 76void ImageResource::update_volatility() 77{ 78 bool visible_in_viewport = false; 79 for_each_client([&](auto& client) { 80 if (static_cast<const ImageResourceClient&>(client).is_visible_in_viewport()) 81 visible_in_viewport = true; 82 }); 83 84 if (!visible_in_viewport) { 85 for (auto& frame : m_decoded_frames) { 86 if (frame.bitmap) 87 frame.bitmap->set_volatile(); 88 } 89 return; 90 } 91 92 bool still_has_decoded_image = true; 93 for (auto& frame : m_decoded_frames) { 94 if (!frame.bitmap) { 95 still_has_decoded_image = false; 96 } else { 97 bool was_purged = false; 98 bool bitmap_has_memory = frame.bitmap->set_nonvolatile(was_purged); 99 if (!bitmap_has_memory || was_purged) 100 still_has_decoded_image = false; 101 } 102 } 103 if (still_has_decoded_image) 104 return; 105 106 m_decoded_frames.clear(); 107 m_has_attempted_decode = false; 108} 109 110ImageResourceClient::~ImageResourceClient() = default; 111 112}