Serenity Operating System
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}