LibGfx+LibWeb: Make DecodedImageFrame a value type
DecodedImageFrame only wraps a ref-counted Bitmap and color-space metadata. The frame object itself does not provide shared mutable state or lifetime ownership beyond those members, so ref-counting it adds an unnecessary layer of indirection.
This commit is contained in:
parent
b221d7fe8b
commit
f8640d813a
56 changed files with 225 additions and 188 deletions
|
|
@ -7,7 +7,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/AtomicRefCounted.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/ColorSpace.h>
|
||||
|
|
@ -16,29 +15,22 @@
|
|||
|
||||
namespace Gfx {
|
||||
|
||||
class DecodedImageFrame final : public AtomicRefCounted<DecodedImageFrame> {
|
||||
class DecodedImageFrame final {
|
||||
public:
|
||||
static NonnullRefPtr<DecodedImageFrame> create(NonnullRefPtr<Bitmap const> bitmap, ColorSpace color_space = {})
|
||||
DecodedImageFrame(NonnullRefPtr<Bitmap const> bitmap, ColorSpace color_space = {})
|
||||
: m_bitmap(move(bitmap))
|
||||
, m_color_space(move(color_space))
|
||||
{
|
||||
return adopt_ref(*new DecodedImageFrame(move(bitmap), move(color_space)));
|
||||
}
|
||||
|
||||
static NonnullRefPtr<DecodedImageFrame> create(Bitmap const& bitmap, ColorSpace color_space = {})
|
||||
DecodedImageFrame(Bitmap const& bitmap, ColorSpace color_space = {})
|
||||
: DecodedImageFrame(NonnullRefPtr<Bitmap const> { bitmap }, move(color_space))
|
||||
{
|
||||
return create(NonnullRefPtr<Bitmap const> { bitmap }, move(color_space));
|
||||
}
|
||||
|
||||
static NonnullRefPtr<DecodedImageFrame> create(Bitmap const& bitmap, AlphaType alpha_type, ColorSpace color_space = {})
|
||||
DecodedImageFrame(Bitmap const& bitmap, AlphaType alpha_type, ColorSpace color_space = {})
|
||||
: DecodedImageFrame(bitmap_with_alpha_type(bitmap, alpha_type), move(color_space))
|
||||
{
|
||||
auto converted_bitmap = [&] -> NonnullRefPtr<Bitmap const> {
|
||||
if (bitmap.alpha_type() == alpha_type)
|
||||
return NonnullRefPtr<Bitmap const> { bitmap };
|
||||
auto new_bitmap = MUST(bitmap.clone());
|
||||
new_bitmap->set_alpha_type_destructive(alpha_type);
|
||||
return new_bitmap;
|
||||
}();
|
||||
|
||||
return create(move(converted_bitmap), move(color_space));
|
||||
}
|
||||
|
||||
Bitmap const& bitmap() const { return *m_bitmap; }
|
||||
|
|
@ -51,10 +43,13 @@ public:
|
|||
IntSize size() const { return m_bitmap->size(); }
|
||||
|
||||
private:
|
||||
DecodedImageFrame(NonnullRefPtr<Bitmap const> bitmap, ColorSpace color_space)
|
||||
: m_bitmap(move(bitmap))
|
||||
, m_color_space(move(color_space))
|
||||
static NonnullRefPtr<Bitmap const> bitmap_with_alpha_type(Bitmap const& bitmap, AlphaType alpha_type)
|
||||
{
|
||||
if (bitmap.alpha_type() == alpha_type)
|
||||
return NonnullRefPtr<Bitmap const> { bitmap };
|
||||
auto new_bitmap = MUST(bitmap.clone());
|
||||
new_bitmap->set_alpha_type_destructive(alpha_type);
|
||||
return new_bitmap;
|
||||
}
|
||||
|
||||
NonnullRefPtr<Bitmap const> m_bitmap;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <LibGfx/SkiaBackendContext.h>
|
||||
#include <LibGfx/SkiaUtils.h>
|
||||
|
||||
#include <core/SkColorSpace.h>
|
||||
#include <core/SkImage.h>
|
||||
#include <gpu/ganesh/GrDirectContext.h>
|
||||
#include <gpu/ganesh/SkImageGanesh.h>
|
||||
|
|
@ -28,12 +29,13 @@ DecodedImageFrameSkiaImageCache::~DecodedImageFrameSkiaImageCache() = default;
|
|||
|
||||
sk_sp<SkImage> DecodedImageFrameSkiaImageCache::image_for_frame(DecodedImageFrame const& frame)
|
||||
{
|
||||
if (auto it = m_images.find(&frame); it != m_images.end()) {
|
||||
auto const& bitmap = frame.bitmap();
|
||||
if (auto it = m_images.find(frame); it != m_images.end()) {
|
||||
it->value.last_used_generation = m_generation;
|
||||
return it->value.image;
|
||||
}
|
||||
|
||||
auto raster_image = sk_image_from_bitmap(frame.bitmap(), frame.color_space());
|
||||
auto raster_image = sk_image_from_bitmap(bitmap, frame.color_space());
|
||||
sk_sp<SkImage> image;
|
||||
auto* gr_context = m_skia_backend_context ? m_skia_backend_context->sk_context() : nullptr;
|
||||
if (gr_context) {
|
||||
|
|
@ -48,11 +50,10 @@ sk_sp<SkImage> DecodedImageFrameSkiaImageCache::image_for_frame(DecodedImageFram
|
|||
return nullptr;
|
||||
|
||||
CachedImage cached_image {
|
||||
.frame = &frame,
|
||||
.image = image,
|
||||
.last_used_generation = m_generation,
|
||||
};
|
||||
m_images.set(&frame, move(cached_image));
|
||||
m_images.set(frame, move(cached_image));
|
||||
return image;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/HashFunctions.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/Types.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <core/SkRefCnt.h>
|
||||
|
||||
class SkColorSpace;
|
||||
class SkImage;
|
||||
|
||||
namespace Gfx {
|
||||
|
|
@ -26,14 +29,36 @@ public:
|
|||
void prune();
|
||||
|
||||
private:
|
||||
struct DecodedImageFrameKeyTraits : public Traits<DecodedImageFrame> {
|
||||
static unsigned hash(DecodedImageFrame const& frame)
|
||||
{
|
||||
return pair_int_hash(
|
||||
ptr_hash(&frame.bitmap()),
|
||||
ptr_hash(color_space_pointer(frame)));
|
||||
}
|
||||
|
||||
static bool equals(DecodedImageFrame const& a, DecodedImageFrame const& b)
|
||||
{
|
||||
return &a.bitmap() == &b.bitmap()
|
||||
&& color_space_pointer(a) == color_space_pointer(b);
|
||||
}
|
||||
|
||||
static constexpr bool may_have_slow_equality_check() { return false; }
|
||||
|
||||
private:
|
||||
static SkColorSpace const* color_space_pointer(DecodedImageFrame const& frame)
|
||||
{
|
||||
return frame.color_space().color_space<sk_sp<SkColorSpace>>().get();
|
||||
}
|
||||
};
|
||||
|
||||
struct CachedImage {
|
||||
RefPtr<DecodedImageFrame const> frame;
|
||||
sk_sp<SkImage> image;
|
||||
u64 last_used_generation { 0 };
|
||||
};
|
||||
|
||||
RefPtr<SkiaBackendContext> m_skia_backend_context;
|
||||
HashMap<DecodedImageFrame const*, CachedImage> m_images;
|
||||
HashMap<DecodedImageFrame, CachedImage, DecodedImageFrameKeyTraits> m_images;
|
||||
u64 m_generation { 0 };
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -318,11 +318,11 @@ ErrorOr<size_t> PNGLoadingContext::read_frames(png_structp png_ptr, png_infop in
|
|||
switch (blend_op) {
|
||||
case PNG_BLEND_OP_SOURCE:
|
||||
// All color components of the frame, including alpha, overwrite the current contents of the frame's output buffer region.
|
||||
painter->draw_bitmap(frame_rect, *Gfx::DecodedImageFrame::create(*decoded_frame_bitmap), decoded_frame_bitmap->rect(), Gfx::ScalingMode::NearestNeighbor, {}, 1.0f, Gfx::CompositingAndBlendingOperator::Copy);
|
||||
painter->draw_bitmap(frame_rect, Gfx::DecodedImageFrame { *decoded_frame_bitmap }, decoded_frame_bitmap->rect(), Gfx::ScalingMode::NearestNeighbor, {}, 1.0f, Gfx::CompositingAndBlendingOperator::Copy);
|
||||
break;
|
||||
case PNG_BLEND_OP_OVER:
|
||||
// The frame should be composited onto the output buffer based on its alpha, using a simple OVER operation as described in the "Alpha Channel Processing" section of the PNG specification.
|
||||
painter->draw_bitmap(frame_rect, *Gfx::DecodedImageFrame::create(*decoded_frame_bitmap), decoded_frame_bitmap->rect(), ScalingMode::NearestNeighbor, {}, 1.0f, Gfx::CompositingAndBlendingOperator::SourceOver);
|
||||
painter->draw_bitmap(frame_rect, Gfx::DecodedImageFrame { *decoded_frame_bitmap }, decoded_frame_bitmap->rect(), ScalingMode::NearestNeighbor, {}, 1.0f, Gfx::CompositingAndBlendingOperator::SourceOver);
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
|
|
@ -341,7 +341,7 @@ ErrorOr<size_t> PNGLoadingContext::read_frames(png_structp png_ptr, png_infop in
|
|||
break;
|
||||
case PNG_DISPOSE_OP_PREVIOUS:
|
||||
// The frame's region of the output buffer is to be reverted to the previous contents before rendering the next frame.
|
||||
painter->draw_bitmap(frame_rect, *Gfx::DecodedImageFrame::create(*prev_output_buffer), IntRect { x, y, width, height }, Gfx::ScalingMode::NearestNeighbor, {}, 1.0f, Gfx::CompositingAndBlendingOperator::Copy);
|
||||
painter->draw_bitmap(frame_rect, Gfx::DecodedImageFrame { *prev_output_buffer }, IntRect { x, y, width, height }, Gfx::ScalingMode::NearestNeighbor, {}, 1.0f, Gfx::CompositingAndBlendingOperator::Copy);
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
|
|
|
|||
|
|
@ -10,18 +10,18 @@
|
|||
|
||||
namespace Gfx {
|
||||
|
||||
CanvasPatternPaintStyle::CanvasPatternPaintStyle(RefPtr<DecodedImageFrame> image, Repetition repetition)
|
||||
CanvasPatternPaintStyle::CanvasPatternPaintStyle(Optional<DecodedImageFrame> image, Repetition repetition)
|
||||
: m_image(move(image))
|
||||
, m_repetition(repetition)
|
||||
{
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<CanvasPatternPaintStyle>> CanvasPatternPaintStyle::create(RefPtr<DecodedImageFrame> image, Repetition repetition)
|
||||
ErrorOr<NonnullRefPtr<CanvasPatternPaintStyle>> CanvasPatternPaintStyle::create(Optional<DecodedImageFrame> image, Repetition repetition)
|
||||
{
|
||||
return adopt_nonnull_ref_or_enomem(new (nothrow) CanvasPatternPaintStyle(move(image), repetition));
|
||||
}
|
||||
|
||||
RefPtr<DecodedImageFrame> CanvasPatternPaintStyle::image() const
|
||||
Optional<DecodedImageFrame> CanvasPatternPaintStyle::image() const
|
||||
{
|
||||
return m_image;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGfx/AffineTransform.h>
|
||||
#include <LibGfx/Color.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibGfx/Gradients.h>
|
||||
#include <LibGfx/Rect.h>
|
||||
|
|
@ -90,17 +91,17 @@ public:
|
|||
NoRepeat
|
||||
};
|
||||
|
||||
static ErrorOr<NonnullRefPtr<CanvasPatternPaintStyle>> create(RefPtr<DecodedImageFrame> image, Repetition repetition);
|
||||
static ErrorOr<NonnullRefPtr<CanvasPatternPaintStyle>> create(Optional<DecodedImageFrame> image, Repetition repetition);
|
||||
|
||||
RefPtr<DecodedImageFrame> image() const;
|
||||
Optional<DecodedImageFrame> image() const;
|
||||
Repetition repetition() const { return m_repetition; }
|
||||
Optional<AffineTransform> const& transform() const { return m_transform; }
|
||||
void set_transform(AffineTransform const& transform) { m_transform = transform; }
|
||||
|
||||
private:
|
||||
CanvasPatternPaintStyle(RefPtr<DecodedImageFrame> image, Repetition repetition);
|
||||
CanvasPatternPaintStyle(Optional<DecodedImageFrame> image, Repetition repetition);
|
||||
|
||||
RefPtr<DecodedImageFrame> m_image;
|
||||
Optional<DecodedImageFrame> m_image;
|
||||
Repetition m_repetition { Repetition::Repeat };
|
||||
Optional<AffineTransform> m_transform;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ static void apply_paint_style(SkPaint& paint, PaintStyle const& style, DecodedIm
|
|||
paint.setShader(shader);
|
||||
} else if (auto const* canvas_pattern = as_if<CanvasPatternPaintStyle>(style)) {
|
||||
auto frame = canvas_pattern->image();
|
||||
if (!frame)
|
||||
if (!frame.has_value())
|
||||
return;
|
||||
auto sk_image = image_cache.image_for_frame(*frame);
|
||||
if (!sk_image)
|
||||
|
|
|
|||
|
|
@ -2058,7 +2058,7 @@ NonnullRefPtr<StyleValue const> Parser::parse_as_sizes_attribute(DOM::Element co
|
|||
// 3. If size is auto, and img is not null, and img is being rendered, and img allows auto-sizes,
|
||||
// then set size to the concrete object size width of img, in CSS pixels.
|
||||
// FIXME: "img is being rendered" - we just see if it has a bitmap for now
|
||||
if (size->has_auto() && img && img->current_image_frame() && img->allows_auto_sizes()) {
|
||||
if (size->has_auto() && img && img->current_image_frame().has_value() && img->allows_auto_sizes()) {
|
||||
// FIXME: The spec doesn't seem to tell us how to determine the concrete size of an <img>, so use the default sizing algorithm.
|
||||
// Should this use some of the methods from FormattingContext?
|
||||
auto concrete_size = run_default_sizing_algorithm(
|
||||
|
|
|
|||
|
|
@ -118,11 +118,11 @@ bool ImageStyleValue::is_paintable() const
|
|||
return image_data();
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> ImageStyleValue::frame(size_t frame_index, Gfx::IntSize size) const
|
||||
Optional<Gfx::DecodedImageFrame> ImageStyleValue::frame(size_t frame_index, Gfx::IntSize size) const
|
||||
{
|
||||
if (auto image_data = this->image_data())
|
||||
return image_data->frame(frame_index, size);
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
void ImageStyleValue::serialize(StringBuilder& builder, SerializationMode) const
|
||||
|
|
@ -170,7 +170,7 @@ void ImageStyleValue::paint(DisplayListRecordingContext& context, DevicePixelRec
|
|||
image_data->paint(context, m_current_frame_index, dest_int_rect, dest_int_rect, scaling_mode);
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> ImageStyleValue::current_frame(DevicePixelRect const& dest_rect) const
|
||||
Optional<Gfx::DecodedImageFrame> ImageStyleValue::current_frame(DevicePixelRect const& dest_rect) const
|
||||
{
|
||||
return frame(m_current_frame_index, dest_rect.size().to_type<int>());
|
||||
}
|
||||
|
|
@ -184,7 +184,7 @@ GC::Ptr<HTML::DecodedImageData> ImageStyleValue::image_data() const
|
|||
|
||||
Optional<Gfx::Color> ImageStyleValue::color_if_single_pixel_bitmap() const
|
||||
{
|
||||
if (auto decoded_frame = frame(m_current_frame_index)) {
|
||||
if (auto decoded_frame = frame(m_current_frame_index); decoded_frame.has_value()) {
|
||||
auto const& bitmap = decoded_frame->bitmap();
|
||||
if (bitmap.width() == 1 && bitmap.height() == 1)
|
||||
return bitmap.get_pixel(0, 0);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <LibGC/Weak.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibWeb/CSS/StyleValues/AbstractImageStyleValue.h>
|
||||
|
|
@ -58,7 +60,7 @@ public:
|
|||
void paint(DisplayListRecordingContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering) const override;
|
||||
|
||||
virtual Optional<Gfx::Color> color_if_single_pixel_bitmap() const override;
|
||||
RefPtr<Gfx::DecodedImageFrame> current_frame(DevicePixelRect const& dest_rect) const;
|
||||
Optional<Gfx::DecodedImageFrame> current_frame(DevicePixelRect const& dest_rect) const;
|
||||
|
||||
mutable Function<void()> on_animate;
|
||||
|
||||
|
|
@ -76,7 +78,7 @@ private:
|
|||
|
||||
virtual ValueComparingNonnullRefPtr<StyleValue const> absolutized(ComputationContext const&) const override;
|
||||
void animate();
|
||||
RefPtr<Gfx::DecodedImageFrame> frame(size_t frame_index, Gfx::IntSize = {}) const;
|
||||
Optional<Gfx::DecodedImageFrame> frame(size_t frame_index, Gfx::IntSize = {}) const;
|
||||
|
||||
GC::Ptr<HTML::SharedResourceRequest> m_resource_request;
|
||||
GC::Ptr<CSSStyleSheet> m_style_sheet;
|
||||
|
|
|
|||
|
|
@ -4583,11 +4583,11 @@ Optional<FlyString> Element::document_scoped_view_transition_name()
|
|||
|
||||
// https://drafts.csswg.org/css-view-transitions-1/#capture-the-image
|
||||
// To capture the image given an element element, perform the following steps. They return an image.
|
||||
RefPtr<Gfx::DecodedImageFrame> Element::capture_the_image()
|
||||
Optional<Gfx::DecodedImageFrame> Element::capture_the_image()
|
||||
{
|
||||
// FIXME: Actually implement this.
|
||||
auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied, Gfx::IntSize(1, 1)));
|
||||
return Gfx::DecodedImageFrame::create(*bitmap);
|
||||
return Gfx::DecodedImageFrame { *bitmap };
|
||||
}
|
||||
|
||||
void Element::set_pointer_capture(WebIDL::Long pointer_id)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibWeb/ARIA/ARIAMixin.h>
|
||||
#include <LibWeb/Animations/Animatable.h>
|
||||
#include <LibWeb/Bindings/Element.h>
|
||||
|
|
@ -586,7 +587,7 @@ public:
|
|||
Optional<FlyString> document_scoped_view_transition_name();
|
||||
|
||||
// https://drafts.csswg.org/css-view-transitions-1/#capture-the-image
|
||||
RefPtr<Gfx::DecodedImageFrame> capture_the_image();
|
||||
Optional<Gfx::DecodedImageFrame> capture_the_image();
|
||||
|
||||
void set_pointer_capture(WebIDL::Long pointer_id);
|
||||
void release_pointer_capture(WebIDL::Long pointer_id);
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ GC::Ref<AnimatedDecodedImageData> AnimatedDecodedImageData::create(
|
|||
for (u32 i = 0; i < initial_bitmaps.size(); ++i) {
|
||||
auto& slot = data->m_buffer_slots[i % BUFFER_POOL_SIZE];
|
||||
slot.frame_index = i;
|
||||
slot.frame = Gfx::DecodedImageFrame::create(*initial_bitmaps[i], data->m_color_space);
|
||||
slot.frame = Gfx::DecodedImageFrame { *initial_bitmaps[i], data->m_color_space };
|
||||
slot.generation = ++data->m_write_generation;
|
||||
}
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ size_t AnimatedDecodedImageData::external_memory_size() const
|
|||
{
|
||||
size_t size = JS::vector_external_memory_size(m_durations);
|
||||
for (auto const& slot : m_buffer_slots) {
|
||||
if (slot.frame)
|
||||
if (slot.frame.has_value())
|
||||
size = JS::saturating_add_external_memory_size(size, slot.frame->bitmap().data_size());
|
||||
}
|
||||
return size;
|
||||
|
|
@ -121,7 +121,7 @@ void AnimatedDecodedImageData::finalize()
|
|||
AnimatedDecodedImageData::BufferSlot const* AnimatedDecodedImageData::find_slot(u32 frame_index) const
|
||||
{
|
||||
for (auto const& slot : m_buffer_slots) {
|
||||
if (slot.frame_index == frame_index && slot.frame)
|
||||
if (slot.frame_index == frame_index && slot.frame.has_value())
|
||||
return &slot;
|
||||
}
|
||||
return nullptr;
|
||||
|
|
@ -137,7 +137,7 @@ AnimatedDecodedImageData::BufferSlot& AnimatedDecodedImageData::evict_oldest_slo
|
|||
return *oldest;
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> AnimatedDecodedImageData::frame(size_t frame_index, Gfx::IntSize) const
|
||||
Optional<Gfx::DecodedImageFrame> AnimatedDecodedImageData::frame(size_t frame_index, Gfx::IntSize) const
|
||||
{
|
||||
if (frame_index >= m_frame_count)
|
||||
return m_last_displayed_frame;
|
||||
|
|
@ -181,7 +181,7 @@ Optional<Gfx::IntRect> AnimatedDecodedImageData::frame_rect(size_t) const
|
|||
void AnimatedDecodedImageData::paint(DisplayListRecordingContext& context, size_t frame_index, Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, Gfx::ScalingMode scaling_mode) const
|
||||
{
|
||||
auto decoded_frame = frame(frame_index);
|
||||
if (!decoded_frame)
|
||||
if (!decoded_frame.has_value())
|
||||
return;
|
||||
context.display_list_recorder().draw_scaled_decoded_image_frame(dst_rect, clip_rect, *decoded_frame, scaling_mode);
|
||||
}
|
||||
|
|
@ -201,7 +201,7 @@ void AnimatedDecodedImageData::receive_frames(Vector<NonnullRefPtr<Gfx::Bitmap>>
|
|||
|
||||
auto& slot = evict_oldest_slot();
|
||||
slot.frame_index = frame_index;
|
||||
slot.frame = Gfx::DecodedImageFrame::create(*bitmaps[i], m_color_space);
|
||||
slot.frame = Gfx::DecodedImageFrame { *bitmaps[i], m_color_space };
|
||||
slot.generation = ++m_write_generation;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ public:
|
|||
virtual ~AnimatedDecodedImageData() override;
|
||||
virtual void finalize() override;
|
||||
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> frame(size_t frame_index, Gfx::IntSize = {}) const override;
|
||||
virtual Optional<Gfx::DecodedImageFrame> frame(size_t frame_index, Gfx::IntSize = {}) const override;
|
||||
virtual int frame_duration(size_t frame_index) const override;
|
||||
|
||||
virtual size_t frame_count() const override { return m_frame_count; }
|
||||
|
|
@ -67,7 +67,7 @@ private:
|
|||
|
||||
struct BufferSlot {
|
||||
Optional<u32> frame_index;
|
||||
RefPtr<Gfx::DecodedImageFrame> frame;
|
||||
Optional<Gfx::DecodedImageFrame> frame;
|
||||
u64 generation { 0 };
|
||||
};
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ private:
|
|||
Vector<u32> m_durations;
|
||||
|
||||
Array<BufferSlot, BUFFER_POOL_SIZE> m_buffer_slots;
|
||||
mutable RefPtr<Gfx::DecodedImageFrame> m_last_displayed_frame;
|
||||
mutable Optional<Gfx::DecodedImageFrame> m_last_displayed_frame;
|
||||
u64 m_write_generation { 0 };
|
||||
bool m_request_in_flight { false };
|
||||
u32 m_current_frame_index { 0 };
|
||||
|
|
|
|||
|
|
@ -33,17 +33,15 @@ BitmapDecodedImageData::~BitmapDecodedImageData() = default;
|
|||
size_t BitmapDecodedImageData::external_memory_size() const
|
||||
{
|
||||
size_t size = JS::vector_external_memory_size(m_frames);
|
||||
for (auto const& frame : m_frames) {
|
||||
if (frame.frame)
|
||||
size = JS::saturating_add_external_memory_size(size, frame.frame->bitmap().data_size());
|
||||
}
|
||||
for (auto const& frame : m_frames)
|
||||
size = JS::saturating_add_external_memory_size(size, frame.frame.bitmap().data_size());
|
||||
return size;
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> BitmapDecodedImageData::frame(size_t frame_index, Gfx::IntSize) const
|
||||
Optional<Gfx::DecodedImageFrame> BitmapDecodedImageData::frame(size_t frame_index, Gfx::IntSize) const
|
||||
{
|
||||
if (frame_index >= m_frames.size())
|
||||
return nullptr;
|
||||
return {};
|
||||
return m_frames[frame_index].frame;
|
||||
}
|
||||
|
||||
|
|
@ -56,27 +54,27 @@ int BitmapDecodedImageData::frame_duration(size_t frame_index) const
|
|||
|
||||
Optional<CSSPixels> BitmapDecodedImageData::intrinsic_width() const
|
||||
{
|
||||
return m_frames.first().frame->width();
|
||||
return m_frames.first().frame.width();
|
||||
}
|
||||
|
||||
Optional<CSSPixels> BitmapDecodedImageData::intrinsic_height() const
|
||||
{
|
||||
return m_frames.first().frame->height();
|
||||
return m_frames.first().frame.height();
|
||||
}
|
||||
|
||||
Optional<CSSPixelFraction> BitmapDecodedImageData::intrinsic_aspect_ratio() const
|
||||
{
|
||||
return CSSPixels(m_frames.first().frame->width()) / CSSPixels(m_frames.first().frame->height());
|
||||
return CSSPixels(m_frames.first().frame.width()) / CSSPixels(m_frames.first().frame.height());
|
||||
}
|
||||
|
||||
Optional<Gfx::IntRect> BitmapDecodedImageData::frame_rect(size_t frame_index) const
|
||||
{
|
||||
return m_frames[frame_index].frame->rect();
|
||||
return m_frames[frame_index].frame.rect();
|
||||
}
|
||||
|
||||
void BitmapDecodedImageData::paint(DisplayListRecordingContext& context, size_t frame_index, Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, Gfx::ScalingMode scaling_mode) const
|
||||
{
|
||||
context.display_list_recorder().draw_scaled_decoded_image_frame(dst_rect, clip_rect, *m_frames[frame_index].frame, scaling_mode);
|
||||
context.display_list_recorder().draw_scaled_decoded_image_frame(dst_rect, clip_rect, m_frames[frame_index].frame, scaling_mode);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ class BitmapDecodedImageData final : public DecodedImageData {
|
|||
|
||||
public:
|
||||
struct Frame {
|
||||
RefPtr<Gfx::DecodedImageFrame> frame;
|
||||
Gfx::DecodedImageFrame frame;
|
||||
int duration { 0 };
|
||||
};
|
||||
|
||||
static ErrorOr<GC::Ref<BitmapDecodedImageData>> create(JS::Realm&, Vector<Frame>&&, size_t loop_count, bool animated);
|
||||
virtual ~BitmapDecodedImageData() override;
|
||||
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> frame(size_t frame_index, Gfx::IntSize = {}) const override;
|
||||
virtual Optional<Gfx::DecodedImageFrame> frame(size_t frame_index, Gfx::IntSize = {}) const override;
|
||||
virtual int frame_duration(size_t frame_index) const override;
|
||||
|
||||
virtual size_t frame_count() const override { return m_frames.size(); }
|
||||
|
|
|
|||
|
|
@ -17,14 +17,14 @@ Gfx::IntSize canvas_image_source_dimensions(CanvasImageSource const& image)
|
|||
{
|
||||
return image.visit(
|
||||
[](GC::Root<HTMLImageElement> const& source) -> Gfx::IntSize {
|
||||
if (auto frame = source->current_image_frame())
|
||||
if (auto frame = source->current_image_frame(); frame.has_value())
|
||||
return frame->size();
|
||||
|
||||
// FIXME: This is very janky and not correct.
|
||||
return { source->width(), source->height() };
|
||||
},
|
||||
[](GC::Root<SVG::SVGImageElement> const& source) -> Gfx::IntSize {
|
||||
if (auto decoded_image_frame = source->current_image_frame())
|
||||
if (auto decoded_image_frame = source->current_image_frame(); decoded_image_frame.has_value())
|
||||
return decoded_image_frame->size();
|
||||
|
||||
// FIXME: This is very janky and not correct.
|
||||
|
|
@ -50,10 +50,10 @@ Gfx::IntSize canvas_image_source_dimensions(CanvasImageSource const& image)
|
|||
});
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> canvas_image_source_frame(CanvasImageSource const& image)
|
||||
Optional<Gfx::DecodedImageFrame> canvas_image_source_frame(CanvasImageSource const& image)
|
||||
{
|
||||
return image.visit(
|
||||
[](OneOf<GC::Root<HTMLImageElement>, GC::Root<SVG::SVGImageElement>> auto const& element) -> RefPtr<Gfx::DecodedImageFrame> {
|
||||
[](OneOf<GC::Root<HTMLImageElement>, GC::Root<SVG::SVGImageElement>> auto const& element) -> Optional<Gfx::DecodedImageFrame> {
|
||||
auto image_data = element->decoded_image_data();
|
||||
if (!image_data)
|
||||
return {};
|
||||
|
|
@ -66,20 +66,20 @@ RefPtr<Gfx::DecodedImageFrame> canvas_image_source_frame(CanvasImageSource const
|
|||
|
||||
return image_data->frame(0, size);
|
||||
},
|
||||
[](GC::Root<HTMLCanvasElement> const& canvas) -> RefPtr<Gfx::DecodedImageFrame> {
|
||||
[](GC::Root<HTMLCanvasElement> const& canvas) -> Optional<Gfx::DecodedImageFrame> {
|
||||
canvas->present();
|
||||
auto surface = canvas->surface();
|
||||
if (!surface)
|
||||
return Gfx::DecodedImageFrame::create(*canvas->get_bitmap_from_surface());
|
||||
return Gfx::DecodedImageFrame::create(*surface->snapshot_bitmap());
|
||||
return Gfx::DecodedImageFrame { *canvas->get_bitmap_from_surface() };
|
||||
return Gfx::DecodedImageFrame { *surface->snapshot_bitmap() };
|
||||
},
|
||||
[](OneOf<GC::Root<ImageBitmap>, GC::Root<OffscreenCanvas>> auto const& source) -> RefPtr<Gfx::DecodedImageFrame> {
|
||||
[](OneOf<GC::Root<ImageBitmap>, GC::Root<OffscreenCanvas>> auto const& source) -> Optional<Gfx::DecodedImageFrame> {
|
||||
auto bitmap = source->bitmap();
|
||||
if (!bitmap)
|
||||
return {};
|
||||
return Gfx::DecodedImageFrame::create(*bitmap);
|
||||
return Gfx::DecodedImageFrame { *bitmap };
|
||||
},
|
||||
[](GC::Root<HTMLVideoElement> const& source) -> RefPtr<Gfx::DecodedImageFrame> {
|
||||
[](GC::Root<HTMLVideoElement> const& source) -> Optional<Gfx::DecodedImageFrame> {
|
||||
return source->current_decoded_image_frame();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/Size.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/HTML/HTMLCanvasElement.h>
|
||||
|
|
@ -23,7 +25,7 @@ namespace Web::HTML {
|
|||
using CanvasImageSource = Variant<GC::Root<HTMLImageElement>, GC::Root<SVG::SVGImageElement>, GC::Root<HTMLCanvasElement>, GC::Root<ImageBitmap>, GC::Root<OffscreenCanvas>, GC::Root<HTMLVideoElement>>;
|
||||
|
||||
Gfx::IntSize canvas_image_source_dimensions(CanvasImageSource const&);
|
||||
RefPtr<Gfx::DecodedImageFrame> canvas_image_source_frame(CanvasImageSource const&);
|
||||
Optional<Gfx::DecodedImageFrame> canvas_image_source_frame(CanvasImageSource const&);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/canvas.html#canvasdrawimage
|
||||
class CanvasDrawImage {
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ WebIDL::ExceptionOr<void> CanvasRenderingContext2D::draw_image_internal(CanvasIm
|
|||
return {};
|
||||
|
||||
auto frame = canvas_image_source_frame(image);
|
||||
if (!frame)
|
||||
if (!frame.has_value())
|
||||
return {};
|
||||
auto const& bitmap = frame->bitmap();
|
||||
|
||||
|
|
@ -576,7 +576,7 @@ WebIDL::ExceptionOr<GC::Ptr<ImageData>> CanvasRenderingContext2D::get_image_data
|
|||
auto surface = canvas_element().surface();
|
||||
if (!surface)
|
||||
return image_data;
|
||||
auto const snapshot = Gfx::DecodedImageFrame::create(*surface->snapshot_bitmap());
|
||||
auto const snapshot = Gfx::DecodedImageFrame { *surface->snapshot_bitmap() };
|
||||
|
||||
// 5. Let the source rectangle be the rectangle whose corners are the four points (sx, sy), (sx+sw, sy), (sx+sw, sy+sh), (sx, sy+sh).
|
||||
auto source_rect = Gfx::Rect { x, y, abs_width, abs_height };
|
||||
|
|
@ -587,17 +587,17 @@ WebIDL::ExceptionOr<GC::Ptr<ImageData>> CanvasRenderingContext2D::get_image_data
|
|||
if (width < 0 || height < 0) {
|
||||
source_rect = source_rect.translated(min(width, 0), min(height, 0));
|
||||
}
|
||||
auto source_rect_intersected = source_rect.intersected(snapshot->rect());
|
||||
auto source_rect_intersected = source_rect.intersected(snapshot.rect());
|
||||
|
||||
// 6. Set the pixel values of imageData to be the pixels of this's output bitmap in the area specified by the source rectangle in the bitmap's coordinate space units, converted from this's color space to imageData's colorSpace using 'relative-colorimetric' rendering intent.
|
||||
// NOTE: Internally we must use premultiplied alpha, but ImageData should hold unpremultiplied alpha. This conversion
|
||||
// might result in a loss of precision, but is according to spec.
|
||||
// See: https://html.spec.whatwg.org/multipage/canvas.html#premultiplied-alpha-and-the-2d-rendering-context
|
||||
VERIFY(snapshot->bitmap().alpha_type() == Gfx::AlphaType::Premultiplied);
|
||||
VERIFY(snapshot.bitmap().alpha_type() == Gfx::AlphaType::Premultiplied);
|
||||
VERIFY(image_data->bitmap().alpha_type() == Gfx::AlphaType::Unpremultiplied);
|
||||
|
||||
auto painter = Gfx::Painter::create(image_data->bitmap());
|
||||
painter->draw_bitmap(image_data->bitmap().rect().to_type<float>(), *snapshot, source_rect_intersected, Gfx::ScalingMode::NearestNeighbor, {}, 1, Gfx::CompositingAndBlendingOperator::SourceOver);
|
||||
painter->draw_bitmap(image_data->bitmap().rect().to_type<float>(), snapshot, source_rect_intersected, Gfx::ScalingMode::NearestNeighbor, {}, 1, Gfx::CompositingAndBlendingOperator::SourceOver);
|
||||
|
||||
// 7. Set the pixels values of imageData for areas of the source rectangle that are outside of the output bitmap to transparent black.
|
||||
// NOTE: No-op, already done during creation.
|
||||
|
|
@ -689,7 +689,7 @@ WebIDL::ExceptionOr<void> CanvasRenderingContext2D::put_pixels_from_an_image_dat
|
|||
painter.set_transform({});
|
||||
painter.draw_bitmap(
|
||||
dst_rect,
|
||||
*Gfx::DecodedImageFrame::create(image_data.bitmap(), Gfx::AlphaType::Unpremultiplied),
|
||||
Gfx::DecodedImageFrame { image_data.bitmap(), Gfx::AlphaType::Unpremultiplied },
|
||||
Gfx::IntRect { dirty_x, dirty_y, dirty_width, dirty_height },
|
||||
Gfx::ScalingMode::NearestNeighbor,
|
||||
{},
|
||||
|
|
@ -916,11 +916,12 @@ WebIDL::ExceptionOr<CanvasImageSourceUsability> check_usability_of_image(CanvasI
|
|||
return WebIDL::InvalidStateError::create(image_element->realm(), "Image element state is broken"_utf16);
|
||||
|
||||
// If image is not fully decodable, then return bad.
|
||||
if (!image_element->current_image_frame())
|
||||
auto current_image_frame = image_element->current_image_frame();
|
||||
if (!current_image_frame.has_value())
|
||||
return { CanvasImageSourceUsability::Bad };
|
||||
|
||||
// If image has an intrinsic width or intrinsic height (or both) equal to zero, then return bad.
|
||||
if (image_element->current_image_frame()->width() == 0 || image_element->current_image_frame()->height() == 0)
|
||||
if (current_image_frame->width() == 0 || current_image_frame->height() == 0)
|
||||
return { CanvasImageSourceUsability::Bad };
|
||||
return Optional<CanvasImageSourceUsability> {};
|
||||
},
|
||||
|
|
@ -929,11 +930,12 @@ WebIDL::ExceptionOr<CanvasImageSourceUsability> check_usability_of_image(CanvasI
|
|||
// FIXME: If image's current request's state is broken, then throw an "InvalidStateError" DOMException.
|
||||
|
||||
// If image is not fully decodable, then return bad.
|
||||
if (!image_element->current_image_frame())
|
||||
auto current_image_frame = image_element->current_image_frame();
|
||||
if (!current_image_frame.has_value())
|
||||
return { CanvasImageSourceUsability::Bad };
|
||||
|
||||
// If image has an intrinsic width or intrinsic height (or both) equal to zero, then return bad.
|
||||
if (image_element->current_image_frame()->width() == 0 || image_element->current_image_frame()->height() == 0)
|
||||
if (current_image_frame->width() == 0 || current_image_frame->height() == 0)
|
||||
return { CanvasImageSourceUsability::Bad };
|
||||
return Optional<CanvasImageSourceUsability> {};
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/ScalingMode.h>
|
||||
#include <LibGfx/Size.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
|
|
@ -25,7 +27,7 @@ public:
|
|||
virtual Optional<Gfx::IntRect> frame_rect([[maybe_unused]] size_t frame_index) const = 0;
|
||||
virtual void paint([[maybe_unused]] DisplayListRecordingContext&, [[maybe_unused]] size_t frame_index, [[maybe_unused]] Gfx::IntRect dst_rect, [[maybe_unused]] Gfx::IntRect clip_rect, [[maybe_unused]] Gfx::ScalingMode scaling_mode) const = 0;
|
||||
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> frame(size_t frame_index, Gfx::IntSize = {}) const = 0;
|
||||
virtual Optional<Gfx::DecodedImageFrame> frame(size_t frame_index, Gfx::IntSize = {}) const = 0;
|
||||
virtual int frame_duration(size_t frame_index) const = 0;
|
||||
|
||||
virtual size_t frame_count() const = 0;
|
||||
|
|
|
|||
|
|
@ -464,7 +464,7 @@ void HTMLCanvasElement::present()
|
|||
|
||||
if (auto surface = this->surface()) {
|
||||
surface->flush();
|
||||
auto snapshot = Gfx::DecodedImageFrame::create(*surface->snapshot_bitmap());
|
||||
auto snapshot = Gfx::DecodedImageFrame { *surface->snapshot_bitmap() };
|
||||
ensure_external_content_source().update(snapshot);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,11 +241,11 @@ void HTMLImageElement::adjust_computed_style(CSS::ComputedProperties& style)
|
|||
style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> HTMLImageElement::default_image_frame_sized(Gfx::IntSize size) const
|
||||
Optional<Gfx::DecodedImageFrame> HTMLImageElement::default_image_frame_sized(Gfx::IntSize size) const
|
||||
{
|
||||
if (auto data = m_current_request->image_data())
|
||||
return data->frame(0, size);
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
bool HTMLImageElement::is_image_available() const
|
||||
|
|
@ -274,11 +274,11 @@ Optional<CSSPixelFraction> HTMLImageElement::intrinsic_aspect_ratio() const
|
|||
return {};
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> HTMLImageElement::current_image_frame_sized(Gfx::IntSize size) const
|
||||
Optional<Gfx::DecodedImageFrame> HTMLImageElement::current_image_frame_sized(Gfx::IntSize size) const
|
||||
{
|
||||
if (auto data = m_current_request->image_data())
|
||||
return data->frame(m_current_frame_index, size);
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
void HTMLImageElement::set_visible_in_viewport(bool)
|
||||
|
|
@ -303,7 +303,7 @@ WebIDL::UnsignedLong HTMLImageElement::width() const
|
|||
|
||||
// ...or else the density-corrected intrinsic width and height of the image, in CSS pixels,
|
||||
// if the image has intrinsic dimensions and is available but not being rendered.
|
||||
if (auto bitmap = current_image_frame())
|
||||
if (auto bitmap = current_image_frame(); bitmap.has_value())
|
||||
return bitmap->width();
|
||||
|
||||
// ...or else 0, if the image is not available or does not have intrinsic dimensions.
|
||||
|
|
@ -334,7 +334,7 @@ WebIDL::UnsignedLong HTMLImageElement::height() const
|
|||
|
||||
// ...or else the density-corrected intrinsic height and height of the image, in CSS pixels,
|
||||
// if the image has intrinsic dimensions and is available but not being rendered.
|
||||
if (auto bitmap = current_image_frame())
|
||||
if (auto bitmap = current_image_frame(); bitmap.has_value())
|
||||
return bitmap->height();
|
||||
|
||||
// ...or else 0, if the image is not available or does not have intrinsic dimensions.
|
||||
|
|
@ -353,7 +353,7 @@ unsigned HTMLImageElement::natural_width() const
|
|||
{
|
||||
// Return the density-corrected intrinsic width of the image, in CSS pixels,
|
||||
// if the image has intrinsic dimensions and is available.
|
||||
if (auto bitmap = current_image_frame())
|
||||
if (auto bitmap = current_image_frame(); bitmap.has_value())
|
||||
return bitmap->width();
|
||||
|
||||
// ...or else 0.
|
||||
|
|
@ -365,7 +365,7 @@ unsigned HTMLImageElement::natural_height() const
|
|||
{
|
||||
// Return the density-corrected intrinsic height of the image, in CSS pixels,
|
||||
// if the image has intrinsic dimensions and is available.
|
||||
if (auto bitmap = current_image_frame())
|
||||
if (auto bitmap = current_image_frame(); bitmap.has_value())
|
||||
return bitmap->height();
|
||||
|
||||
// ...or else 0.
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public:
|
|||
|
||||
String alt() const { return get_attribute_value(HTML::AttributeNames::alt); }
|
||||
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> default_image_frame_sized(Gfx::IntSize) const override;
|
||||
virtual Optional<Gfx::DecodedImageFrame> default_image_frame_sized(Gfx::IntSize) const override;
|
||||
|
||||
WebIDL::UnsignedLong width() const;
|
||||
void set_width(WebIDL::UnsignedLong);
|
||||
|
|
@ -111,7 +111,7 @@ public:
|
|||
virtual Optional<CSSPixels> intrinsic_width() const override;
|
||||
virtual Optional<CSSPixels> intrinsic_height() const override;
|
||||
virtual Optional<CSSPixelFraction> intrinsic_aspect_ratio() const override;
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> current_image_frame_sized(Gfx::IntSize) const override;
|
||||
virtual Optional<Gfx::DecodedImageFrame> current_image_frame_sized(Gfx::IntSize) const override;
|
||||
virtual void set_visible_in_viewport(bool) override;
|
||||
virtual GC::Ptr<DOM::Element const> to_html_element() const override { return *this; }
|
||||
virtual GC::Ptr<DecodedImageData> decoded_image_data() const override;
|
||||
|
|
|
|||
|
|
@ -2289,11 +2289,11 @@ Optional<CSSPixelFraction> HTMLInputElement::intrinsic_aspect_ratio() const
|
|||
return {};
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> HTMLInputElement::current_image_frame_sized(Gfx::IntSize size) const
|
||||
Optional<Gfx::DecodedImageFrame> HTMLInputElement::current_image_frame_sized(Gfx::IntSize size) const
|
||||
{
|
||||
if (auto image_data = this->image_data())
|
||||
return image_data->frame(0, size);
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
void HTMLInputElement::set_visible_in_viewport(bool)
|
||||
|
|
@ -2386,7 +2386,7 @@ WebIDL::UnsignedLong HTMLInputElement::height() const
|
|||
}
|
||||
|
||||
// ...or else the natural height and height of the image, in CSS pixels, if an image is available but not being rendered
|
||||
if (auto bitmap = current_image_frame())
|
||||
if (auto bitmap = current_image_frame(); bitmap.has_value())
|
||||
return bitmap->height();
|
||||
|
||||
// ...or else 0, if the image is not available or does not have intrinsic dimensions.
|
||||
|
|
@ -2421,7 +2421,7 @@ WebIDL::UnsignedLong HTMLInputElement::width() const
|
|||
}
|
||||
|
||||
// ...or else the natural width and height of the image, in CSS pixels, if an image is available but not being rendered
|
||||
if (auto bitmap = current_image_frame())
|
||||
if (auto bitmap = current_image_frame(); bitmap.has_value())
|
||||
return bitmap->width();
|
||||
|
||||
// ...or else 0, if the image is not available or does not have intrinsic dimensions.
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ private:
|
|||
virtual Optional<CSSPixels> intrinsic_width() const override;
|
||||
virtual Optional<CSSPixels> intrinsic_height() const override;
|
||||
virtual Optional<CSSPixelFraction> intrinsic_aspect_ratio() const override;
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> current_image_frame_sized(Gfx::IntSize) const override;
|
||||
virtual Optional<Gfx::DecodedImageFrame> current_image_frame_sized(Gfx::IntSize) const override;
|
||||
virtual void set_visible_in_viewport(bool) override;
|
||||
virtual GC::Ptr<DOM::Element const> to_html_element() const override { return *this; }
|
||||
virtual size_t current_frame_index() const override { return 0; }
|
||||
|
|
|
|||
|
|
@ -906,7 +906,7 @@ static NonnullRefPtr<Core::Promise<bool>> decode_favicon(ReadonlyBytes favicon_d
|
|||
// FIXME: Calculate size based on device pixel ratio
|
||||
Gfx::IntSize size { 32, 32 };
|
||||
auto decoded_frame = result.release_value()->frame(0, size);
|
||||
if (!decoded_frame) {
|
||||
if (!decoded_frame.has_value()) {
|
||||
promise->reject(Error::from_string_view("Failed to get bitmap from SVG favicon"sv));
|
||||
return promise;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -606,11 +606,11 @@ Optional<CSSPixelFraction> HTMLObjectElement::intrinsic_aspect_ratio() const
|
|||
return {};
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> HTMLObjectElement::current_image_frame_sized(Gfx::IntSize size) const
|
||||
Optional<Gfx::DecodedImageFrame> HTMLObjectElement::current_image_frame_sized(Gfx::IntSize size) const
|
||||
{
|
||||
if (auto image_data = this->image_data())
|
||||
return image_data->frame(0, size);
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
void HTMLObjectElement::set_visible_in_viewport(bool)
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ private:
|
|||
virtual Optional<CSSPixels> intrinsic_width() const override;
|
||||
virtual Optional<CSSPixels> intrinsic_height() const override;
|
||||
virtual Optional<CSSPixelFraction> intrinsic_aspect_ratio() const override;
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> current_image_frame_sized(Gfx::IntSize) const override;
|
||||
virtual Optional<Gfx::DecodedImageFrame> current_image_frame_sized(Gfx::IntSize) const override;
|
||||
virtual void set_visible_in_viewport(bool) override;
|
||||
virtual GC::Ptr<DOM::Element const> to_html_element() const override { return *this; }
|
||||
virtual size_t current_frame_index() const override { return 0; }
|
||||
|
|
|
|||
|
|
@ -339,21 +339,21 @@ HTMLVideoElement::Representation HTMLVideoElement::current_representation() cons
|
|||
return Representation::VideoFrame;
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> HTMLVideoElement::current_decoded_image_frame() const
|
||||
Optional<Gfx::DecodedImageFrame> HTMLVideoElement::current_decoded_image_frame() const
|
||||
{
|
||||
auto const& sink = selected_video_track_sink();
|
||||
if (sink == nullptr)
|
||||
return nullptr;
|
||||
return {};
|
||||
auto current_frame = sink->current_frame();
|
||||
if (!current_frame)
|
||||
return nullptr;
|
||||
return {};
|
||||
auto bitmap_or_error = current_frame->yuv_data().to_bitmap();
|
||||
if (bitmap_or_error.is_error()) {
|
||||
dbgln("Could not convert video frame to bitmap: {}", bitmap_or_error.release_error());
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
auto bitmap = bitmap_or_error.release_value();
|
||||
return Gfx::DecodedImageFrame::create(NonnullRefPtr<Gfx::Bitmap const> { *bitmap }, current_frame->color_space());
|
||||
return Gfx::DecodedImageFrame { NonnullRefPtr<Gfx::Bitmap const> { *bitmap }, current_frame->color_space() };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibWeb/DOM/DocumentLoadEventDelayer.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
|
@ -59,7 +60,7 @@ public:
|
|||
};
|
||||
Representation current_representation() const;
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> current_decoded_image_frame() const;
|
||||
Optional<Gfx::DecodedImageFrame> current_decoded_image_frame() const;
|
||||
|
||||
private:
|
||||
HTMLVideoElement(DOM::Document&, DOM::QualifiedName);
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ public:
|
|||
});
|
||||
},
|
||||
[this](RenderingThread::PublishToExternalContent const& mode) {
|
||||
auto snapshot = Gfx::DecodedImageFrame::create(*m_backing_stores.front_store->snapshot_bitmap());
|
||||
auto snapshot = Gfx::DecodedImageFrame { *m_backing_stores.front_store->snapshot_bitmap() };
|
||||
mode.source->update(move(snapshot));
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ void SharedResourceRequest::handle_successful_fetch(URL::URL const& url_string,
|
|||
Vector<BitmapDecodedImageData::Frame> frames;
|
||||
for (auto& frame : result.frames) {
|
||||
frames.append(BitmapDecodedImageData::Frame {
|
||||
.frame = Gfx::DecodedImageFrame::create(*frame.bitmap, result.color_space),
|
||||
.frame = Gfx::DecodedImageFrame { *frame.bitmap, result.color_space },
|
||||
.duration = static_cast<int>(frame.duration),
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ GC::Ref<WebIDL::Promise> WindowOrWorkerGlobalScopeMixin::create_image_bitmap_imp
|
|||
|
||||
// 2. If image's media data has no natural dimensions (e.g., it's a vector graphic with no specified content size), it should be rendered to a bitmap of the size specified by the resizeWidth and the resizeHeight options.
|
||||
// 3. Set imageBitmap's bitmap data to a copy of image's media data, cropped to the source rectangle with formatting. If this is an animated image, imageBitmap's bitmap data must only be taken from the default image of the animation (the one that the format defines is to be used when animation is not supported or is disabled), or, if there is no such image, the first frame of the animation.
|
||||
RefPtr<Gfx::DecodedImageFrame> decoded_frame;
|
||||
Optional<Gfx::DecodedImageFrame> decoded_frame;
|
||||
if (has_natural_dimensions) {
|
||||
decoded_frame = image_element->default_image_frame_sized(Gfx::IntSize { *image_element->intrinsic_width(), *image_element->intrinsic_height() });
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -25,17 +25,17 @@ Optional<CSSPixelSize> ImageProvider::intrinsic_size() const
|
|||
return CSSPixelSize { *width, *height };
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> ImageProvider::current_image_frame() const
|
||||
Optional<Gfx::DecodedImageFrame> ImageProvider::current_image_frame() const
|
||||
{
|
||||
return current_image_frame_sized(intrinsic_size().value_or({}).to_type<int>());
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> ImageProvider::default_image_frame() const
|
||||
Optional<Gfx::DecodedImageFrame> ImageProvider::default_image_frame() const
|
||||
{
|
||||
return default_image_frame_sized(intrinsic_size().value_or({}).to_type<int>());
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> ImageProvider::default_image_frame_sized(Gfx::IntSize size) const
|
||||
Optional<Gfx::DecodedImageFrame> ImageProvider::default_image_frame_sized(Gfx::IntSize size) const
|
||||
{
|
||||
// Defer to the current image by default.
|
||||
return current_image_frame_sized(size);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <LibGC/Cell.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/Size.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/PixelUnits.h>
|
||||
|
|
@ -28,11 +30,11 @@ public:
|
|||
Optional<CSSPixelSize> intrinsic_size() const;
|
||||
virtual Optional<CSSPixelFraction> intrinsic_aspect_ratio() const = 0;
|
||||
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> current_image_frame() const;
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> current_image_frame_sized(Gfx::IntSize) const = 0;
|
||||
virtual Optional<Gfx::DecodedImageFrame> current_image_frame() const;
|
||||
virtual Optional<Gfx::DecodedImageFrame> current_image_frame_sized(Gfx::IntSize) const = 0;
|
||||
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> default_image_frame() const;
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> default_image_frame_sized(Gfx::IntSize) const;
|
||||
virtual Optional<Gfx::DecodedImageFrame> default_image_frame() const;
|
||||
virtual Optional<Gfx::DecodedImageFrame> default_image_frame_sized(Gfx::IntSize) const;
|
||||
|
||||
virtual void set_visible_in_viewport(bool) = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ public:
|
|||
virtual Optional<CSSPixels> intrinsic_height() const override { return m_image->natural_height(); }
|
||||
virtual Optional<CSSPixelFraction> intrinsic_aspect_ratio() const override { return m_image->natural_aspect_ratio(); }
|
||||
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> current_image_frame_sized(Gfx::IntSize size) const override
|
||||
virtual Optional<Gfx::DecodedImageFrame> current_image_frame_sized(Gfx::IntSize size) const override
|
||||
{
|
||||
auto rect = DevicePixelRect { DevicePixelPoint {}, size.to_type<DevicePixels>() };
|
||||
return m_image->current_frame(rect);
|
||||
|
|
|
|||
|
|
@ -951,7 +951,7 @@ void EventHandler::maybe_show_context_menu(GC::Ref<DOM::Node> node, MouseEventCo
|
|||
auto image_url = image_element.document().encoding_parse_url(image_element.current_src());
|
||||
if (image_url.has_value()) {
|
||||
Optional<Gfx::Bitmap const*> bitmap;
|
||||
if (auto frame = image_element.current_image_frame())
|
||||
if (auto frame = image_element.current_image_frame(); frame.has_value())
|
||||
bitmap = &frame->bitmap();
|
||||
|
||||
m_navigable->page().client().page_did_request_image_context_menu(top_level_viewport_position, *image_url, "", modifiers, bitmap);
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ void paint_background(DisplayListRecordingContext& context, PaintableBox const&
|
|||
dest_rect.set_height(1);
|
||||
|
||||
auto frame = static_cast<CSS::ImageStyleValue const&>(image).current_frame(dest_rect);
|
||||
if (!frame)
|
||||
if (!frame.has_value())
|
||||
return;
|
||||
auto scaling_mode = to_gfx_scaling_mode(image_rendering, frame->size(), dest_rect.size().to_type<int>());
|
||||
context.display_list_recorder().draw_repeated_decoded_image_frame(dest_rect.to_type<int>(), clip_rect.to_type<int>(), *frame, scaling_mode, repeat_x, repeat_y);
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ struct DrawScaledDecodedImageFrame {
|
|||
|
||||
Gfx::IntRect dst_rect;
|
||||
Gfx::IntRect clip_rect;
|
||||
NonnullRefPtr<Gfx::DecodedImageFrame const> frame;
|
||||
Gfx::DecodedImageFrame frame;
|
||||
Gfx::ScalingMode scaling_mode;
|
||||
|
||||
[[nodiscard]] Gfx::IntRect bounding_rect() const { return clip_rect; }
|
||||
|
|
@ -81,7 +81,7 @@ struct DrawRepeatedDecodedImageFrame {
|
|||
|
||||
Gfx::IntRect dst_rect;
|
||||
Gfx::IntRect clip_rect;
|
||||
NonnullRefPtr<Gfx::DecodedImageFrame const> frame;
|
||||
Gfx::DecodedImageFrame frame;
|
||||
Gfx::ScalingMode scaling_mode;
|
||||
Repeat repeat;
|
||||
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ void DisplayListPlayerSkia::fill_rect(FillRect const& command)
|
|||
void DisplayListPlayerSkia::draw_external_content(DrawExternalContent const& command)
|
||||
{
|
||||
auto frame = command.source->current_frame();
|
||||
if (!frame)
|
||||
if (!frame.has_value())
|
||||
return;
|
||||
auto image = m_image_cache.image_for_frame(*frame);
|
||||
if (!image)
|
||||
|
|
@ -212,7 +212,7 @@ void DisplayListPlayerSkia::draw_video_frame_source(DrawVideoFrameSource const&
|
|||
|
||||
void DisplayListPlayerSkia::draw_scaled_decoded_image_frame(DrawScaledDecodedImageFrame const& command)
|
||||
{
|
||||
auto image = m_image_cache.image_for_frame(*command.frame);
|
||||
auto image = m_image_cache.image_for_frame(command.frame);
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
|
|
@ -229,13 +229,13 @@ void DisplayListPlayerSkia::draw_scaled_decoded_image_frame(DrawScaledDecodedIma
|
|||
|
||||
void DisplayListPlayerSkia::draw_repeated_decoded_image_frame(DrawRepeatedDecodedImageFrame const& command)
|
||||
{
|
||||
auto image = m_image_cache.image_for_frame(*command.frame);
|
||||
auto image = m_image_cache.image_for_frame(command.frame);
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
SkMatrix matrix;
|
||||
auto dst_rect = command.dst_rect.to_type<float>();
|
||||
auto src_size = command.frame->size().to_type<float>();
|
||||
auto src_size = command.frame.size().to_type<float>();
|
||||
matrix.setScale(dst_rect.width() / src_size.width(), dst_rect.height() / src_size.height());
|
||||
matrix.postTranslate(dst_rect.x(), dst_rect.y());
|
||||
auto sampling_options = to_skia_sampling_options(command.scaling_mode);
|
||||
|
|
|
|||
|
|
@ -246,19 +246,19 @@ void DisplayListRecorder::draw_video_frame_source(Gfx::IntRect const& dst_rect,
|
|||
APPEND(DrawVideoFrameSource { .dst_rect = dst_rect, .source = move(source), .scaling_mode = scaling_mode });
|
||||
}
|
||||
|
||||
void DisplayListRecorder::draw_scaled_decoded_image_frame(Gfx::IntRect const& dst_rect, Gfx::IntRect const& clip_rect, Gfx::DecodedImageFrame const& frame, Gfx::ScalingMode scaling_mode)
|
||||
void DisplayListRecorder::draw_scaled_decoded_image_frame(Gfx::IntRect const& dst_rect, Gfx::IntRect const& clip_rect, Gfx::DecodedImageFrame frame, Gfx::ScalingMode scaling_mode)
|
||||
{
|
||||
if (dst_rect.is_empty())
|
||||
return;
|
||||
APPEND(DrawScaledDecodedImageFrame {
|
||||
.dst_rect = dst_rect,
|
||||
.clip_rect = clip_rect,
|
||||
.frame = frame,
|
||||
.frame = move(frame),
|
||||
.scaling_mode = scaling_mode,
|
||||
});
|
||||
}
|
||||
|
||||
void DisplayListRecorder::draw_repeated_decoded_image_frame(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, NonnullRefPtr<Gfx::DecodedImageFrame const> frame, Gfx::ScalingMode scaling_mode, bool repeat_x, bool repeat_y)
|
||||
void DisplayListRecorder::draw_repeated_decoded_image_frame(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, Gfx::DecodedImageFrame frame, Gfx::ScalingMode scaling_mode, bool repeat_x, bool repeat_y)
|
||||
{
|
||||
APPEND(DrawRepeatedDecodedImageFrame {
|
||||
.dst_rect = dst_rect,
|
||||
|
|
|
|||
|
|
@ -71,11 +71,11 @@ public:
|
|||
|
||||
void draw_rect(Gfx::IntRect const& rect, Color color, bool rough = false);
|
||||
|
||||
void draw_scaled_decoded_image_frame(Gfx::IntRect const& dst_rect, Gfx::IntRect const& clip_rect, Gfx::DecodedImageFrame const& frame, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor);
|
||||
void draw_scaled_decoded_image_frame(Gfx::IntRect const& dst_rect, Gfx::IntRect const& clip_rect, Gfx::DecodedImageFrame frame, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor);
|
||||
void draw_external_content(Gfx::IntRect const& dst_rect, NonnullRefPtr<ExternalContentSource>, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor);
|
||||
void draw_video_frame_source(Gfx::IntRect const& dst_rect, NonnullRefPtr<VideoFrameSource>, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor);
|
||||
|
||||
void draw_repeated_decoded_image_frame(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, NonnullRefPtr<Gfx::DecodedImageFrame const> frame, Gfx::ScalingMode scaling_mode, bool repeat_x, bool repeat_y);
|
||||
void draw_repeated_decoded_image_frame(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, Gfx::DecodedImageFrame frame, Gfx::ScalingMode scaling_mode, bool repeat_x, bool repeat_y);
|
||||
|
||||
void draw_line(Gfx::IntPoint from, Gfx::IntPoint to, Color color, int thickness = 1, Gfx::LineStyle style = Gfx::LineStyle::Solid, Color alternate_color = Color::Transparent);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ NonnullRefPtr<ExternalContentSource> ExternalContentSource::create()
|
|||
return adopt_ref(*new ExternalContentSource());
|
||||
}
|
||||
|
||||
void ExternalContentSource::update(RefPtr<Gfx::DecodedImageFrame> frame)
|
||||
void ExternalContentSource::update(Optional<Gfx::DecodedImageFrame> frame)
|
||||
{
|
||||
RefPtr<Gfx::DecodedImageFrame> old;
|
||||
Optional<Gfx::DecodedImageFrame> old;
|
||||
{
|
||||
Threading::MutexLocker const locker { m_mutex };
|
||||
old = move(m_frame);
|
||||
|
|
@ -26,14 +26,14 @@ void ExternalContentSource::update(RefPtr<Gfx::DecodedImageFrame> frame)
|
|||
|
||||
void ExternalContentSource::clear()
|
||||
{
|
||||
RefPtr<Gfx::DecodedImageFrame> old;
|
||||
Optional<Gfx::DecodedImageFrame> old;
|
||||
{
|
||||
Threading::MutexLocker const locker { m_mutex };
|
||||
old = move(m_frame);
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> ExternalContentSource::current_frame() const
|
||||
Optional<Gfx::DecodedImageFrame> ExternalContentSource::current_frame() const
|
||||
{
|
||||
Threading::MutexLocker const locker { m_mutex };
|
||||
return m_frame;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/AtomicRefCounted.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibThreading/Mutex.h>
|
||||
|
|
@ -18,15 +19,15 @@ class ExternalContentSource final : public AtomicRefCounted<ExternalContentSourc
|
|||
public:
|
||||
static NonnullRefPtr<ExternalContentSource> create();
|
||||
|
||||
void update(RefPtr<Gfx::DecodedImageFrame>);
|
||||
void update(Optional<Gfx::DecodedImageFrame>);
|
||||
void clear();
|
||||
RefPtr<Gfx::DecodedImageFrame> current_frame() const;
|
||||
Optional<Gfx::DecodedImageFrame> current_frame() const;
|
||||
|
||||
private:
|
||||
ExternalContentSource() = default;
|
||||
|
||||
mutable Threading::Mutex m_mutex;
|
||||
RefPtr<Gfx::DecodedImageFrame> m_frame;
|
||||
Optional<Gfx::DecodedImageFrame> m_frame;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,12 +52,12 @@ void VideoPaintable::paint(DisplayListRecordingContext& context, PaintPhase phas
|
|||
auto const& poster_frame = video_element.poster_frame();
|
||||
|
||||
auto paint_bitmap = [&](auto const& bitmap) {
|
||||
auto frame = Gfx::DecodedImageFrame::create(bitmap);
|
||||
auto frame = Gfx::DecodedImageFrame { bitmap };
|
||||
auto dst_rect = get_replaced_box_painting_area(*this, context, computed_values().object_fit(), bitmap.size());
|
||||
if (dst_rect.is_empty())
|
||||
return;
|
||||
auto scaling_mode = to_gfx_scaling_mode(computed_values().image_rendering(), frame->size(), dst_rect.size());
|
||||
context.display_list_recorder().draw_scaled_decoded_image_frame(dst_rect, dst_rect, *frame, scaling_mode);
|
||||
auto scaling_mode = to_gfx_scaling_mode(computed_values().image_rendering(), frame.size(), dst_rect.size());
|
||||
context.display_list_recorder().draw_scaled_decoded_image_frame(dst_rect, dst_rect, move(frame), scaling_mode);
|
||||
};
|
||||
|
||||
auto paint_video_frame = [&]() {
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ size_t SVGDecodedImageData::external_memory_size() const
|
|||
size_t size = Base::external_memory_size();
|
||||
size = JS::saturating_add_external_memory_size(size, JS::hash_map_external_memory_size(m_cached_rendered_frames));
|
||||
for (auto const& cached_frame : m_cached_rendered_frames)
|
||||
size = JS::saturating_add_external_memory_size(size, cached_frame.value->bitmap().data_size());
|
||||
size = JS::saturating_add_external_memory_size(size, cached_frame.value.bitmap().data_size());
|
||||
|
||||
size = JS::saturating_add_external_memory_size(size, JS::hash_map_external_memory_size(m_cached_rendered_surfaces));
|
||||
for (auto const& cached_surface : m_cached_rendered_surfaces)
|
||||
|
|
@ -146,7 +146,7 @@ RefPtr<Gfx::PaintingSurface> SVGDecodedImageData::render_to_surface(Gfx::IntSize
|
|||
VERIFY(m_document->navigable());
|
||||
|
||||
if (size.is_empty())
|
||||
return nullptr;
|
||||
return {};
|
||||
|
||||
if (auto it = m_cached_rendered_surfaces.find(size); it != m_cached_rendered_surfaces.end())
|
||||
return it->value;
|
||||
|
|
@ -176,10 +176,10 @@ RefPtr<Gfx::PaintingSurface> SVGDecodedImageData::render_to_surface(Gfx::IntSize
|
|||
return surface;
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> SVGDecodedImageData::frame(size_t, Gfx::IntSize size) const
|
||||
Optional<Gfx::DecodedImageFrame> SVGDecodedImageData::frame(size_t, Gfx::IntSize size) const
|
||||
{
|
||||
if (size.is_empty())
|
||||
return nullptr;
|
||||
return {};
|
||||
|
||||
if (auto it = m_cached_rendered_frames.find(size); it != m_cached_rendered_frames.end())
|
||||
return it->value;
|
||||
|
|
@ -189,7 +189,7 @@ RefPtr<Gfx::DecodedImageFrame> SVGDecodedImageData::frame(size_t, Gfx::IntSize s
|
|||
if (m_cached_rendered_frames.size() > 10)
|
||||
m_cached_rendered_frames.remove(m_cached_rendered_frames.begin());
|
||||
|
||||
auto decoded_frame = Gfx::DecodedImageFrame::create(*render_to_surface(size)->snapshot_bitmap());
|
||||
auto decoded_frame = Gfx::DecodedImageFrame { *render_to_surface(size)->snapshot_bitmap() };
|
||||
m_cached_rendered_frames.set(size, decoded_frame);
|
||||
return decoded_frame;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public:
|
|||
static ErrorOr<GC::Ref<SVGDecodedImageData>> create(JS::Realm&, GC::Ref<Page>, URL::URL const&, ReadonlyBytes encoded_svg);
|
||||
virtual ~SVGDecodedImageData() override;
|
||||
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> frame(size_t frame_index, Gfx::IntSize) const override;
|
||||
virtual Optional<Gfx::DecodedImageFrame> frame(size_t frame_index, Gfx::IntSize) const override;
|
||||
|
||||
virtual Optional<CSSPixels> intrinsic_width() const override;
|
||||
virtual Optional<CSSPixels> intrinsic_height() const override;
|
||||
|
|
@ -49,7 +49,7 @@ private:
|
|||
RefPtr<Painting::DisplayList> record_display_list(Gfx::IntSize) const;
|
||||
|
||||
// FIXME: Remove this once everything is using surfaces instead.
|
||||
mutable HashMap<Gfx::IntSize, NonnullRefPtr<Gfx::DecodedImageFrame>> m_cached_rendered_frames;
|
||||
mutable HashMap<Gfx::IntSize, Gfx::DecodedImageFrame> m_cached_rendered_frames;
|
||||
|
||||
mutable HashMap<Gfx::IntSize, NonnullRefPtr<Gfx::PaintingSurface>> m_cached_rendered_surfaces;
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ GC::Ptr<HTML::DecodedImageData> SVGFEImageElement::image_data() const
|
|||
return m_resource_request->image_data();
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> SVGFEImageElement::current_image_frame(Gfx::IntSize size) const
|
||||
Optional<Gfx::DecodedImageFrame> SVGFEImageElement::current_image_frame(Gfx::IntSize size) const
|
||||
{
|
||||
if (auto data = image_data())
|
||||
return data->frame(0, size);
|
||||
|
|
@ -97,7 +97,7 @@ RefPtr<Gfx::DecodedImageFrame> SVGFEImageElement::current_image_frame(Gfx::IntSi
|
|||
Optional<Gfx::IntRect> SVGFEImageElement::content_rect() const
|
||||
{
|
||||
auto bitmap = current_image_frame();
|
||||
if (!bitmap)
|
||||
if (!bitmap.has_value())
|
||||
return {};
|
||||
// NB: Called during painting.
|
||||
auto layout_node = this->unsafe_layout_node();
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/SVG/SVGElement.h>
|
||||
#include <LibWeb/SVG/SVGFilterPrimitiveStandardAttributes.h>
|
||||
|
|
@ -24,7 +26,7 @@ public:
|
|||
virtual ~SVGFEImageElement() override = default;
|
||||
|
||||
GC::Ptr<HTML::DecodedImageData> image_data() const;
|
||||
RefPtr<Gfx::DecodedImageFrame> current_image_frame(Gfx::IntSize = {}) const;
|
||||
Optional<Gfx::DecodedImageFrame> current_image_frame(Gfx::IntSize = {}) const;
|
||||
Optional<Gfx::IntRect> content_rect() const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ Optional<Gfx::Filter> SVGFilterElement::gfx_filter(Layout::NodeWithStyle const&
|
|||
return IterationDecision::Continue;
|
||||
|
||||
auto frame = image_data->frame(0, {});
|
||||
if (!frame)
|
||||
if (!frame.has_value())
|
||||
return IterationDecision::Continue;
|
||||
|
||||
auto src_rect = image_primitive->content_rect();
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ Optional<CSSPixelFraction> SVGImageElement::intrinsic_aspect_ratio() const
|
|||
return {};
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> SVGImageElement::default_image_frame_sized(Gfx::IntSize size) const
|
||||
Optional<Gfx::DecodedImageFrame> SVGImageElement::default_image_frame_sized(Gfx::IntSize size) const
|
||||
{
|
||||
if (!m_resource_request)
|
||||
return {};
|
||||
|
|
@ -252,7 +252,7 @@ RefPtr<Gfx::DecodedImageFrame> SVGImageElement::default_image_frame_sized(Gfx::I
|
|||
return {};
|
||||
}
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> SVGImageElement::current_image_frame_sized(Gfx::IntSize size) const
|
||||
Optional<Gfx::DecodedImageFrame> SVGImageElement::current_image_frame_sized(Gfx::IntSize size) const
|
||||
{
|
||||
if (!m_resource_request)
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -33,14 +33,14 @@ public:
|
|||
|
||||
Gfx::FloatRect bounding_box() const;
|
||||
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> default_image_frame_sized(Gfx::IntSize) const override;
|
||||
virtual Optional<Gfx::DecodedImageFrame> default_image_frame_sized(Gfx::IntSize) const override;
|
||||
|
||||
// ^Layout::ImageProvider
|
||||
virtual bool is_image_available() const override;
|
||||
virtual Optional<CSSPixels> intrinsic_width() const override;
|
||||
virtual Optional<CSSPixels> intrinsic_height() const override;
|
||||
virtual Optional<CSSPixelFraction> intrinsic_aspect_ratio() const override;
|
||||
virtual RefPtr<Gfx::DecodedImageFrame> current_image_frame_sized(Gfx::IntSize) const override;
|
||||
virtual Optional<Gfx::DecodedImageFrame> current_image_frame_sized(Gfx::IntSize) const override;
|
||||
virtual void set_visible_in_viewport(bool) override { }
|
||||
virtual GC::Ptr<DOM::Element const> to_html_element() const override { return *this; }
|
||||
virtual size_t current_frame_index() const override { return m_current_frame_index; }
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ NamedViewTransitionPseudoElement::NamedViewTransitionPseudoElement(CSS::PseudoEl
|
|||
{
|
||||
}
|
||||
|
||||
ReplacedNamedViewTransitionPseudoElement::ReplacedNamedViewTransitionPseudoElement(CSS::PseudoElement type, FlyString view_transition_name, RefPtr<Gfx::DecodedImageFrame> content = {})
|
||||
ReplacedNamedViewTransitionPseudoElement::ReplacedNamedViewTransitionPseudoElement(CSS::PseudoElement type, FlyString view_transition_name, Optional<Gfx::DecodedImageFrame> content = {})
|
||||
: NamedViewTransitionPseudoElement(type, view_transition_name)
|
||||
{
|
||||
m_content = content;
|
||||
|
|
@ -437,7 +437,7 @@ void ViewTransition::setup_transition_pseudo_elements()
|
|||
group->append_child(image_pair);
|
||||
|
||||
// 5. If capturedElement’s old image is not null, then:
|
||||
if (captured_element->old_image) {
|
||||
if (captured_element->old_image.has_value()) {
|
||||
// 1. Let old be a new '::view-transition-old()', with its view transition name set to transitionName,
|
||||
// displaying capturedElement’s old image as its replaced content.
|
||||
auto old = heap().allocate<ReplacedNamedViewTransitionPseudoElement>(CSS::PseudoElement::ViewTransitionOld, transition_name, captured_element->old_image);
|
||||
|
|
@ -457,7 +457,7 @@ void ViewTransition::setup_transition_pseudo_elements()
|
|||
}
|
||||
|
||||
// 7. If capturedElement’s old image is null, then:
|
||||
if (!captured_element->old_image) {
|
||||
if (!captured_element->old_image.has_value()) {
|
||||
// 1. Assert: capturedElement’s new element is not null.
|
||||
VERIFY(captured_element->new_element);
|
||||
|
||||
|
|
@ -480,7 +480,7 @@ void ViewTransition::setup_transition_pseudo_elements()
|
|||
// 8. If capturedElement’s new element is null, then:
|
||||
if (!captured_element->new_element) {
|
||||
// 1. Assert: capturedElement’s old image is not null.
|
||||
VERIFY(captured_element->old_image);
|
||||
VERIFY(captured_element->old_image.has_value());
|
||||
|
||||
// 2. Set capturedElement’s image animation name rule to a new CSSStyleRule representing the
|
||||
// following CSS, and append it to document’s dynamic view transition style sheet:
|
||||
|
|
@ -499,7 +499,7 @@ void ViewTransition::setup_transition_pseudo_elements()
|
|||
}
|
||||
|
||||
// 9. If both of capturedElement’s old image and new element are not null, then:
|
||||
if (captured_element->old_image && captured_element->new_element) {
|
||||
if (captured_element->old_image.has_value() && captured_element->new_element) {
|
||||
// 1. Let transform be capturedElement’s old transform.
|
||||
auto& transform = captured_element->old_transform;
|
||||
// FIXME: Remove this once tranform gets used in step 5 below.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
#include <LibWeb/Bindings/ViewTransition.h>
|
||||
|
|
@ -41,9 +43,9 @@ class ReplacedNamedViewTransitionPseudoElement
|
|||
GC_CELL(ReplacedNamedViewTransitionPseudoElement, NamedViewTransitionPseudoElement);
|
||||
GC_DECLARE_ALLOCATOR(ReplacedNamedViewTransitionPseudoElement);
|
||||
|
||||
ReplacedNamedViewTransitionPseudoElement(CSS::PseudoElement, FlyString, RefPtr<Gfx::DecodedImageFrame>);
|
||||
ReplacedNamedViewTransitionPseudoElement(CSS::PseudoElement, FlyString, Optional<Gfx::DecodedImageFrame>);
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> m_content;
|
||||
Optional<Gfx::DecodedImageFrame> m_content;
|
||||
};
|
||||
|
||||
// https://drafts.csswg.org/css-view-transitions-1/#captured-element
|
||||
|
|
@ -51,7 +53,7 @@ struct CapturedElement : public JS::Cell {
|
|||
GC_CELL(CapturedElement, JS::Cell)
|
||||
GC_DECLARE_ALLOCATOR(CapturedElement);
|
||||
|
||||
RefPtr<Gfx::DecodedImageFrame> old_image {};
|
||||
Optional<Gfx::DecodedImageFrame> old_image {};
|
||||
CSSPixels old_width = 0;
|
||||
CSSPixels old_height = 0;
|
||||
// FIXME: Make this an identity transform function by default.
|
||||
|
|
|
|||
|
|
@ -266,28 +266,28 @@ Optional<Gfx::BitmapExportResult> WebGLRenderingContextBase::read_and_pixel_conv
|
|||
// a SECURITY_ERR exception must be thrown. See Origin Restrictions.
|
||||
// FIXME: If source is null then an INVALID_VALUE error is generated.
|
||||
auto frame = source.visit(
|
||||
[](GC::Root<HTML::HTMLImageElement> const& source) -> RefPtr<Gfx::DecodedImageFrame> {
|
||||
[](GC::Root<HTML::HTMLImageElement> const& source) -> Optional<Gfx::DecodedImageFrame> {
|
||||
return source->current_image_frame();
|
||||
},
|
||||
[](GC::Root<HTML::HTMLCanvasElement> const& source) -> RefPtr<Gfx::DecodedImageFrame> {
|
||||
[](GC::Root<HTML::HTMLCanvasElement> const& source) -> Optional<Gfx::DecodedImageFrame> {
|
||||
auto surface = source->surface();
|
||||
if (!surface)
|
||||
return Gfx::DecodedImageFrame::create(*source->get_bitmap_from_surface());
|
||||
return Gfx::DecodedImageFrame::create(*surface->snapshot_bitmap());
|
||||
return Gfx::DecodedImageFrame { *source->get_bitmap_from_surface() };
|
||||
return Gfx::DecodedImageFrame { *surface->snapshot_bitmap() };
|
||||
},
|
||||
[](GC::Root<HTML::OffscreenCanvas> const& source) -> RefPtr<Gfx::DecodedImageFrame> {
|
||||
return Gfx::DecodedImageFrame::create(*source->bitmap());
|
||||
[](GC::Root<HTML::OffscreenCanvas> const& source) -> Optional<Gfx::DecodedImageFrame> {
|
||||
return Gfx::DecodedImageFrame { *source->bitmap() };
|
||||
},
|
||||
[](GC::Root<HTML::HTMLVideoElement> const& source) -> RefPtr<Gfx::DecodedImageFrame> {
|
||||
[](GC::Root<HTML::HTMLVideoElement> const& source) -> Optional<Gfx::DecodedImageFrame> {
|
||||
return source->current_decoded_image_frame();
|
||||
},
|
||||
[](GC::Root<HTML::ImageBitmap> const& source) -> RefPtr<Gfx::DecodedImageFrame> {
|
||||
return Gfx::DecodedImageFrame::create(*source->bitmap());
|
||||
[](GC::Root<HTML::ImageBitmap> const& source) -> Optional<Gfx::DecodedImageFrame> {
|
||||
return Gfx::DecodedImageFrame { *source->bitmap() };
|
||||
},
|
||||
[](GC::Root<HTML::ImageData> const& source) -> RefPtr<Gfx::DecodedImageFrame> {
|
||||
return Gfx::DecodedImageFrame::create(source->bitmap());
|
||||
[](GC::Root<HTML::ImageData> const& source) -> Optional<Gfx::DecodedImageFrame> {
|
||||
return Gfx::DecodedImageFrame { source->bitmap() };
|
||||
});
|
||||
if (!frame)
|
||||
if (!frame.has_value())
|
||||
return OptionalNone {};
|
||||
|
||||
auto export_format = determine_export_format(format, type);
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ void WebViewImplementationNative::paint_into_bitmap(void* android_bitmap_raw, An
|
|||
auto android_bitmap = MUST(Gfx::Bitmap::create_wrapper(to_gfx_bitmap_format(info.format), Gfx::AlphaType::Premultiplied, { info.width, info.height }, info.stride, android_bitmap_raw));
|
||||
auto painter = Gfx::Painter::create(android_bitmap);
|
||||
if (auto* bitmap = m_client_state.has_usable_bitmap ? m_client_state.front_bitmap.bitmap.ptr() : m_backup_bitmap.ptr())
|
||||
painter->draw_bitmap(android_bitmap->rect().to_type<float>(), *Gfx::DecodedImageFrame::create(*MUST(bitmap->clone())), bitmap->rect(), Gfx::ScalingMode::NearestNeighbor, {}, 1.0f, Gfx::CompositingAndBlendingOperator::Copy);
|
||||
painter->draw_bitmap(android_bitmap->rect().to_type<float>(), Gfx::DecodedImageFrame { *MUST(bitmap->clone()) }, bitmap->rect(), Gfx::ScalingMode::NearestNeighbor, {}, 1.0f, Gfx::CompositingAndBlendingOperator::Copy);
|
||||
else
|
||||
painter->fill_rect(android_bitmap->rect().to_type<float>(), Gfx::Color::Magenta);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue