LibWeb: Use compositor surface IDs for embedded content
Display lists kept canvas and nested navigable content alive through ExternalContentSource objects. That made the resource graph depend on process-local object identity instead of a stable surface handle, which blocks compositor process isolation and made teardown-sensitive embedded content harder to reason about. Allocate CompositorSurfaceId values for canvases and child navigables, publish their backing stores to the owning compositor, and paint them with DrawCompositorSurface. Child navigables now publish to parent compositors by CompositorContextId instead of raw object pointers, so the in-process path uses the same stable addressing model required by a remote compositor. Clear and skip stale child surfaces during teardown, preserve Skia canvas state while drawing compositor surfaces, and add display-list coverage for canvas and iframe compositor surfaces. The nested navigable async-scrolling baseline now expects DrawCompositorSurface.
This commit is contained in:
parent
01cec162c8
commit
93bbdf1f55
30 changed files with 288 additions and 179 deletions
|
|
@ -153,6 +153,13 @@ NonnullRefPtr<Bitmap> PaintingSurface::snapshot_bitmap() const
|
|||
return bitmap;
|
||||
}
|
||||
|
||||
SharedImage PaintingSurface::snapshot_into_shared_image() const
|
||||
{
|
||||
auto shared_image_buffer = SharedImageBuffer::create(size());
|
||||
read_into_bitmap(*shared_image_buffer.bitmap());
|
||||
return shared_image_buffer.export_shared_image();
|
||||
}
|
||||
|
||||
void PaintingSurface::read_into_bitmap(Bitmap& bitmap) const
|
||||
{
|
||||
auto color_type = to_skia_color_type(bitmap.format());
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ class SkSurface;
|
|||
|
||||
namespace Gfx {
|
||||
|
||||
class SharedImage;
|
||||
|
||||
class PaintingSurface : public AtomicRefCounted<PaintingSurface> {
|
||||
public:
|
||||
enum class Origin {
|
||||
|
|
@ -52,6 +54,7 @@ public:
|
|||
#endif
|
||||
|
||||
NonnullRefPtr<Bitmap> snapshot_bitmap() const;
|
||||
SharedImage snapshot_into_shared_image() const;
|
||||
|
||||
void read_into_bitmap(Bitmap&) const;
|
||||
void write_from_bitmap(Bitmap const&);
|
||||
|
|
|
|||
|
|
@ -861,7 +861,6 @@ set(SOURCES
|
|||
Painting/DisplayListRecorder.cpp
|
||||
Painting/DisplayListRecordingContext.cpp
|
||||
Painting/DisplayListResourceStorage.cpp
|
||||
Painting/ExternalContentSource.cpp
|
||||
Painting/FieldSetPaintable.cpp
|
||||
Painting/GradientPainting.cpp
|
||||
Painting/ImagePaintable.cpp
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibCore/Timer.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/PaintingSurface.h>
|
||||
#include <LibGfx/SharedImage.h>
|
||||
#include <LibGfx/SkiaBackendContext.h>
|
||||
|
|
@ -19,7 +18,6 @@
|
|||
#include <LibWeb/HTML/EventLoop/EventLoop.h>
|
||||
#include <LibWeb/Page/InputEvent.h>
|
||||
#include <LibWeb/Painting/DisplayListPlayerSkia.h>
|
||||
#include <LibWeb/Painting/ExternalContentSource.h>
|
||||
|
||||
#include <AK/Debug.h>
|
||||
#include <AK/HashMap.h>
|
||||
|
|
@ -67,6 +65,15 @@ struct UpdateScrollStateCommand {
|
|||
Painting::ScrollStateSnapshot scroll_state_snapshot;
|
||||
};
|
||||
|
||||
struct UpdateCompositorSurfaceCommand {
|
||||
Painting::CompositorSurfaceId surface_id;
|
||||
Gfx::SharedImage shared_image;
|
||||
};
|
||||
|
||||
struct ClearCompositorSurfaceCommand {
|
||||
Painting::CompositorSurfaceId surface_id;
|
||||
};
|
||||
|
||||
struct ViewportSizeUpdatedCommand {
|
||||
Gfx::IntSize viewport_size;
|
||||
bool is_top_level_traversable { false };
|
||||
|
|
@ -79,7 +86,8 @@ struct ScreenshotCommand {
|
|||
};
|
||||
|
||||
using CompositorCommand = Variant<UpdateDisplayListCommand, AsyncScrollByCommand, ViewportScrollbarDragCommand,
|
||||
UpdateScrollStateCommand, ViewportSizeUpdatedCommand, ScreenshotCommand>;
|
||||
UpdateScrollStateCommand, UpdateCompositorSurfaceCommand, ClearCompositorSurfaceCommand, ViewportSizeUpdatedCommand,
|
||||
ScreenshotCommand>;
|
||||
|
||||
static SkRect to_skia_rect(Gfx::IntRect const& rect)
|
||||
{
|
||||
|
|
@ -714,6 +722,12 @@ public:
|
|||
}
|
||||
}
|
||||
},
|
||||
[this](UpdateCompositorSurfaceCommand& cmd) {
|
||||
m_display_list_resource_storage.update_compositor_surface(cmd.surface_id, move(cmd.shared_image));
|
||||
},
|
||||
[this](ClearCompositorSurfaceCommand& cmd) {
|
||||
m_display_list_resource_storage.clear_compositor_surface(cmd.surface_id);
|
||||
},
|
||||
[this](ViewportSizeUpdatedCommand& cmd) {
|
||||
auto allocation = m_backing_store_manager.resize_backing_stores_if_needed(
|
||||
cmd.viewport_size, cmd.is_top_level_traversable, cmd.window_resize_in_progress);
|
||||
|
|
@ -1007,7 +1021,7 @@ private:
|
|||
if (m_cached_display_list && m_backing_store_manager.is_valid()) {
|
||||
auto should_clear_back_store = presentation_mode.visit(
|
||||
[](CompositorThread::PresentToUI) { return false; },
|
||||
[](CompositorThread::PublishToExternalContent const&) { return true; });
|
||||
[](CompositorThread::PublishToCompositorSurface const&) { return true; });
|
||||
auto& back_store = m_backing_store_manager.back_store();
|
||||
if (should_clear_back_store) {
|
||||
// Embedded navigables leave their PaintConfig canvas unfilled, so double-buffered back stores must be
|
||||
|
|
@ -1036,15 +1050,16 @@ private:
|
|||
m_is_rasterizing = false;
|
||||
}
|
||||
},
|
||||
[this](CompositorThread::PublishToExternalContent const& mode) {
|
||||
[this](CompositorThread::PublishToCompositorSurface const& mode) {
|
||||
{
|
||||
Sync::MutexLocker const locker { m_mutex };
|
||||
m_is_rasterizing = false;
|
||||
}
|
||||
if (m_has_async_scrolling_state)
|
||||
dbgln_if(COMPOSITOR_DEBUG, "[Compositor] Publishing present to external content source");
|
||||
auto snapshot = Gfx::DecodedImageFrame { *m_backing_store_manager.front_store().snapshot_bitmap() };
|
||||
mode.source->update(move(snapshot));
|
||||
dbgln_if(COMPOSITOR_DEBUG, "[Compositor] Publishing present to compositor surface");
|
||||
auto& front_store = m_backing_store_manager.front_store();
|
||||
VERIFY(CompositorThread::update_compositor_surface_for_context(
|
||||
mode.target_context_id, mode.surface_id, front_store.snapshot_into_shared_image()));
|
||||
});
|
||||
} else {
|
||||
{
|
||||
|
|
@ -1186,6 +1201,12 @@ static HashMap<u64, NonnullRefPtr<CompositorThread::ThreadData>>& page_composito
|
|||
return *compositors;
|
||||
}
|
||||
|
||||
static HashMap<CompositorContextId, NonnullRefPtr<CompositorThread::ThreadData>>& context_compositors()
|
||||
{
|
||||
static NeverDestroyed<HashMap<CompositorContextId, NonnullRefPtr<CompositorThread::ThreadData>>> compositors;
|
||||
return *compositors;
|
||||
}
|
||||
|
||||
static FramePresentationState& frame_presentation_state()
|
||||
{
|
||||
static NeverDestroyed<FramePresentationState> state;
|
||||
|
|
@ -1199,6 +1220,12 @@ CompositorThread::CompositorThread(u64 page_id, PagePresentationRegistration pag
|
|||
enqueue_viewport_size_updated(m_last_viewport_size, m_last_viewport_size_is_top_level_traversable, WindowResizingInProgress::No);
|
||||
});
|
||||
|
||||
{
|
||||
Sync::MutexLocker const locker { compositor_presentation_state_mutex() };
|
||||
VERIFY(!context_compositors().contains(m_context_id));
|
||||
context_compositors().set(m_context_id, m_thread_data);
|
||||
}
|
||||
|
||||
if (page_presentation_registration == PagePresentationRegistration::Yes)
|
||||
register_page_compositor(page_id, m_thread_data);
|
||||
}
|
||||
|
|
@ -1210,6 +1237,11 @@ CompositorThread::~CompositorThread()
|
|||
m_backing_store_shrink_timer.clear();
|
||||
|
||||
unregister_page_compositor(m_thread_data->page_id(), *m_thread_data);
|
||||
{
|
||||
Sync::MutexLocker const locker { compositor_presentation_state_mutex() };
|
||||
VERIFY(context_compositors().remove(m_context_id));
|
||||
}
|
||||
|
||||
m_thread_data->exit();
|
||||
}
|
||||
|
||||
|
|
@ -1240,6 +1272,23 @@ void CompositorThread::unregister_page_compositor(u64 page_id, ThreadData& threa
|
|||
dbgln_if(COMPOSITOR_DEBUG, "[Compositor] Unregistered page {} from compositor presentation", page_id);
|
||||
}
|
||||
|
||||
bool CompositorThread::update_compositor_surface_for_context(CompositorContextId context_id, Painting::CompositorSurfaceId surface_id, Gfx::SharedImage&& shared_image)
|
||||
{
|
||||
RefPtr<ThreadData> thread_data;
|
||||
{
|
||||
Sync::MutexLocker const locker { compositor_presentation_state_mutex() };
|
||||
auto compositor = context_compositors().find(context_id);
|
||||
if (compositor == context_compositors().end()) {
|
||||
dbgln_if(COMPOSITOR_DEBUG, "[Compositor] Dropping compositor surface {} update for unknown context {}",
|
||||
surface_id, context_id);
|
||||
return false;
|
||||
}
|
||||
thread_data = compositor->value;
|
||||
}
|
||||
thread_data->enqueue_command(UpdateCompositorSurfaceCommand { surface_id, move(shared_image) });
|
||||
return true;
|
||||
}
|
||||
|
||||
void CompositorThread::set_frame_presentation_callbacks(NonnullRefPtr<Core::WeakEventLoopReference> event_loop, BackingStorePresentationCallback backing_store_callback, FramePresentationCallback frame_callback)
|
||||
{
|
||||
Sync::MutexLocker const locker { compositor_presentation_state_mutex() };
|
||||
|
|
@ -1443,6 +1492,16 @@ void CompositorThread::update_display_list(
|
|||
m_thread_data->enqueue_command(UpdateDisplayListCommand { move(display_list), move(resource_transaction), move(scroll_state_snapshot) });
|
||||
}
|
||||
|
||||
void CompositorThread::update_compositor_surface(Painting::CompositorSurfaceId surface_id, Gfx::SharedImage&& shared_image)
|
||||
{
|
||||
m_thread_data->enqueue_command(UpdateCompositorSurfaceCommand { surface_id, move(shared_image) });
|
||||
}
|
||||
|
||||
void CompositorThread::clear_compositor_surface(Painting::CompositorSurfaceId surface_id)
|
||||
{
|
||||
m_thread_data->enqueue_command(ClearCompositorSurfaceCommand { surface_id });
|
||||
}
|
||||
|
||||
void CompositorThread::invalidate_wheel_event_listener_state(u64 generation)
|
||||
{
|
||||
m_thread_data->invalidate_wheel_event_listener_state(generation);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <LibSync/ConditionVariable.h>
|
||||
#include <LibThreading/Forward.h>
|
||||
#include <LibWeb/Compositor/AsyncScrollingState.h>
|
||||
#include <LibWeb/Compositor/Types.h>
|
||||
#include <LibWeb/Export.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/Page/InputEvent.h>
|
||||
|
|
@ -61,10 +62,11 @@ public:
|
|||
};
|
||||
struct PresentToUI {
|
||||
};
|
||||
struct PublishToExternalContent {
|
||||
NonnullRefPtr<Painting::ExternalContentSource> source;
|
||||
struct PublishToCompositorSurface {
|
||||
CompositorContextId target_context_id;
|
||||
Painting::CompositorSurfaceId surface_id;
|
||||
};
|
||||
using PresentationMode = Variant<PresentToUI, PublishToExternalContent>;
|
||||
using PresentationMode = Variant<PresentToUI, PublishToCompositorSurface>;
|
||||
|
||||
CompositorThread(u64 page_id, PagePresentationRegistration);
|
||||
~CompositorThread();
|
||||
|
|
@ -75,11 +77,14 @@ public:
|
|||
static bool async_scroll_by(u64 page_id, Gfx::FloatPoint position, Gfx::FloatPoint delta_in_device_pixels);
|
||||
static bool handle_mouse_event(u64 page_id, MouseEvent const&);
|
||||
|
||||
CompositorContextId context_id() const { return m_context_id; }
|
||||
void start(DisplayListPlayerType);
|
||||
void stop_presenting_to_client();
|
||||
void set_presentation_mode(PresentationMode);
|
||||
|
||||
void update_display_list(NonnullRefPtr<Painting::DisplayList>, Painting::DisplayListResourceTransaction&&, Painting::ScrollStateSnapshot&&);
|
||||
void update_compositor_surface(Painting::CompositorSurfaceId, Gfx::SharedImage&&);
|
||||
void clear_compositor_surface(Painting::CompositorSurfaceId);
|
||||
void update_scroll_state(Painting::ScrollStateSnapshot&&);
|
||||
void invalidate_wheel_event_listener_state(u64 generation);
|
||||
AsyncScrollEnqueueResult async_scroll_by(UniqueNodeID expected_document_id, Gfx::FloatPoint position, Gfx::FloatPoint delta_in_device_pixels,
|
||||
|
|
@ -95,6 +100,7 @@ public:
|
|||
private:
|
||||
void enqueue_viewport_size_updated(Gfx::IntSize, bool is_top_level_traversable, WindowResizingInProgress);
|
||||
|
||||
CompositorContextId m_context_id { allocate_compositor_context_id() };
|
||||
NonnullRefPtr<ThreadData> m_thread_data;
|
||||
RefPtr<Threading::Thread> m_thread;
|
||||
RefPtr<Core::Timer> m_backing_store_shrink_timer;
|
||||
|
|
@ -103,6 +109,7 @@ private:
|
|||
|
||||
static void register_page_compositor(u64 page_id, NonnullRefPtr<ThreadData>);
|
||||
static void unregister_page_compositor(u64 page_id, ThreadData&);
|
||||
static bool update_compositor_surface_for_context(CompositorContextId, Painting::CompositorSurfaceId, Gfx::SharedImage&&);
|
||||
static bool present_backing_stores_to_client(u64 page_id, i32 front_bitmap_id, Gfx::SharedImage&&, i32 back_bitmap_id, Gfx::SharedImage&&);
|
||||
static bool present_frame_to_client(u64 page_id, Gfx::IntRect const&, i32 bitmap_id);
|
||||
};
|
||||
|
|
|
|||
23
Libraries/LibWeb/Compositor/Types.h
Normal file
23
Libraries/LibWeb/Compositor/Types.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Ladybird contributors
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Atomic.h>
|
||||
#include <AK/DistinctNumeric.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
namespace Web::Compositor {
|
||||
|
||||
AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, CompositorContextId);
|
||||
|
||||
inline CompositorContextId allocate_compositor_context_id()
|
||||
{
|
||||
static Atomic<u64> s_next_id { 1 };
|
||||
return CompositorContextId { s_next_id.fetch_add(1, AK::MemoryOrder::memory_order_relaxed) };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -50,7 +50,6 @@ class DisplayList;
|
|||
class DisplayListPlayerSkia;
|
||||
class DisplayListRecorder;
|
||||
class DisplayListResourceStorage;
|
||||
class ExternalContentSource;
|
||||
class VideoFrameSource;
|
||||
struct GradientPaintStyle;
|
||||
struct PatternPaintStyle;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include <AK/Base64.h>
|
||||
#include <AK/Checked.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/SharedImage.h>
|
||||
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
||||
#include <LibWeb/Bindings/HTMLCanvasElement.h>
|
||||
#include <LibWeb/CSS/ComputedProperties.h>
|
||||
|
|
@ -54,6 +54,7 @@ void HTMLCanvasElement::initialize(JS::Realm& realm)
|
|||
|
||||
void HTMLCanvasElement::finalize()
|
||||
{
|
||||
clear_compositor_surface();
|
||||
Base::finalize();
|
||||
document().page().unregister_canvas_element({}, unique_id());
|
||||
}
|
||||
|
|
@ -131,17 +132,16 @@ WebIDL::UnsignedLong HTMLCanvasElement::height() const
|
|||
return 150;
|
||||
}
|
||||
|
||||
Painting::ExternalContentSource& HTMLCanvasElement::ensure_external_content_source()
|
||||
Painting::CompositorSurfaceId HTMLCanvasElement::ensure_compositor_surface_id()
|
||||
{
|
||||
if (!m_external_content_source)
|
||||
m_external_content_source = Painting::ExternalContentSource::create();
|
||||
return *m_external_content_source;
|
||||
if (!m_compositor_surface_id.has_value())
|
||||
m_compositor_surface_id = Painting::allocate_compositor_surface_id();
|
||||
return *m_compositor_surface_id;
|
||||
}
|
||||
|
||||
void HTMLCanvasElement::reset_context_to_default_state()
|
||||
{
|
||||
if (m_external_content_source)
|
||||
m_external_content_source->clear();
|
||||
clear_compositor_surface();
|
||||
m_context.visit(
|
||||
[](GC::Ref<CanvasRenderingContext2D>& context) {
|
||||
context->reset_to_default_state();
|
||||
|
|
@ -453,11 +453,19 @@ void HTMLCanvasElement::present()
|
|||
|
||||
if (auto surface = this->surface()) {
|
||||
surface->flush();
|
||||
auto snapshot = Gfx::DecodedImageFrame { *surface->snapshot_bitmap() };
|
||||
ensure_external_content_source().update(snapshot);
|
||||
if (auto navigable = document().navigable())
|
||||
navigable->rendering_thread().update_compositor_surface(ensure_compositor_surface_id(), surface->snapshot_into_shared_image());
|
||||
}
|
||||
}
|
||||
|
||||
void HTMLCanvasElement::clear_compositor_surface()
|
||||
{
|
||||
if (!m_compositor_surface_id.has_value())
|
||||
return;
|
||||
if (auto navigable = document().navigable())
|
||||
navigable->rendering_thread().clear_compositor_surface(*m_compositor_surface_id);
|
||||
}
|
||||
|
||||
RefPtr<Gfx::PaintingSurface> HTMLCanvasElement::surface() const
|
||||
{
|
||||
return m_context.visit(
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibGfx/PaintingSurface.h>
|
||||
#include <LibWeb/HTML/HTMLElement.h>
|
||||
#include <LibWeb/Painting/ExternalContentSource.h>
|
||||
#include <LibWeb/Painting/DisplayListResourceIds.h>
|
||||
#include <LibWeb/WebIDL/Types.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
|
@ -52,7 +53,7 @@ public:
|
|||
RefPtr<Gfx::PaintingSurface> surface() const;
|
||||
void allocate_painting_surface_if_needed();
|
||||
|
||||
Painting::ExternalContentSource& ensure_external_content_source();
|
||||
Painting::CompositorSurfaceId ensure_compositor_surface_id();
|
||||
|
||||
CSS::ComputationContext canvas_font_computation_context();
|
||||
|
||||
|
|
@ -73,9 +74,10 @@ private:
|
|||
JS::ThrowCompletionOr<HasOrCreatedContext> create_webgl_context(JS::Value options);
|
||||
void reset_context_to_default_state();
|
||||
void notify_context_about_canvas_size_change();
|
||||
void clear_compositor_surface();
|
||||
|
||||
Variant<GC::Ref<HTML::CanvasRenderingContext2D>, GC::Ref<WebGL::WebGLRenderingContext>, GC::Ref<WebGL::WebGL2RenderingContext>, Empty> m_context;
|
||||
RefPtr<Painting::ExternalContentSource> m_external_content_source;
|
||||
Optional<Painting::CompositorSurfaceId> m_compositor_surface_id;
|
||||
bool m_canvas_content_dirty { false };
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@
|
|||
#include <LibWeb/Layout/Viewport.h>
|
||||
#include <LibWeb/Loader/GeneratedPagesLoader.h>
|
||||
#include <LibWeb/Page/Page.h>
|
||||
#include <LibWeb/Painting/ExternalContentSource.h>
|
||||
#include <LibWeb/Painting/Paintable.h>
|
||||
#include <LibWeb/Painting/PaintableBox.h>
|
||||
#include <LibWeb/Painting/ViewportPaintable.h>
|
||||
|
|
@ -297,12 +296,14 @@ Navigable::~Navigable() = default;
|
|||
|
||||
void Navigable::set_has_been_destroyed()
|
||||
{
|
||||
clear_compositor_surface();
|
||||
m_has_been_destroyed = true;
|
||||
resolve_all_pending_async_scroll_operations();
|
||||
}
|
||||
|
||||
void Navigable::remove_from_all_navigables()
|
||||
{
|
||||
clear_compositor_surface();
|
||||
resolve_all_pending_async_scroll_operations();
|
||||
|
||||
if (m_active_document)
|
||||
|
|
@ -312,6 +313,7 @@ void Navigable::remove_from_all_navigables()
|
|||
|
||||
void Navigable::finalize()
|
||||
{
|
||||
clear_compositor_surface();
|
||||
all_navigables().remove(*this);
|
||||
Base::finalize();
|
||||
}
|
||||
|
|
@ -430,8 +432,11 @@ void Navigable::initialize_navigable(NonnullRefPtr<DocumentState> document_state
|
|||
if (parent)
|
||||
m_should_show_line_box_borders = parent->m_should_show_line_box_borders;
|
||||
if (parent && !m_is_svg_page) {
|
||||
m_external_content_source = Painting::ExternalContentSource::create();
|
||||
m_rendering_thread.set_presentation_mode(Compositor::CompositorThread::PublishToExternalContent { external_content_source() });
|
||||
m_compositor_surface_id = Painting::allocate_compositor_surface_id();
|
||||
m_rendering_thread.set_presentation_mode(Compositor::CompositorThread::PublishToCompositorSurface {
|
||||
.target_context_id = parent->rendering_thread().context_id(),
|
||||
.surface_id = *m_compositor_surface_id,
|
||||
});
|
||||
}
|
||||
|
||||
// 6. Set the initial visibility state of documentState's document to navigable's traversable navigable's system visibility state.
|
||||
|
|
@ -3274,10 +3279,19 @@ void Navigable::set_has_session_history_entry_and_ready_for_navigation()
|
|||
}
|
||||
}
|
||||
|
||||
NonnullRefPtr<Painting::ExternalContentSource> Navigable::external_content_source() const
|
||||
Painting::CompositorSurfaceId Navigable::compositor_surface_id() const
|
||||
{
|
||||
VERIFY(m_external_content_source);
|
||||
return *m_external_content_source;
|
||||
VERIFY(m_compositor_surface_id.has_value());
|
||||
return *m_compositor_surface_id;
|
||||
}
|
||||
|
||||
void Navigable::clear_compositor_surface()
|
||||
{
|
||||
if (!m_compositor_surface_id.has_value())
|
||||
return;
|
||||
if (auto parent = this->parent())
|
||||
parent->rendering_thread().clear_compositor_surface(*m_compositor_surface_id);
|
||||
m_compositor_surface_id.clear();
|
||||
}
|
||||
|
||||
void Navigable::set_should_show_line_box_borders(bool value)
|
||||
|
|
@ -3332,14 +3346,18 @@ void Navigable::record_display_list_and_scroll_state(PaintConfig paint_config)
|
|||
|
||||
void Navigable::paint_next_frame()
|
||||
{
|
||||
if (has_been_destroyed())
|
||||
return;
|
||||
|
||||
auto viewport_rect = page().css_to_device_rect(this->viewport_rect()).to_type<int>();
|
||||
PaintConfig paint_config { .paint_overlay = true, .should_show_line_box_borders = m_should_show_line_box_borders };
|
||||
if (is_top_level_traversable()) {
|
||||
paint_config.canvas_fill_rect = Gfx::IntRect { {}, viewport_rect.size() };
|
||||
} else {
|
||||
// Nested navigables publish transparent bitmaps to their preconfigured ExternalContentSource instead of filling
|
||||
// Nested navigables publish transparent bitmaps to their preconfigured compositor surface instead of filling
|
||||
// the canvas for the UI process.
|
||||
VERIFY(m_external_content_source);
|
||||
if (!m_compositor_surface_id.has_value())
|
||||
return;
|
||||
}
|
||||
|
||||
auto should_defer_main_thread_present_for_async_scroll = [&] {
|
||||
|
|
|
|||
|
|
@ -241,7 +241,8 @@ public:
|
|||
|
||||
Compositor::CompositorThread& rendering_thread() { return m_rendering_thread; }
|
||||
|
||||
NonnullRefPtr<Painting::ExternalContentSource> external_content_source() const;
|
||||
Painting::CompositorSurfaceId compositor_surface_id() const;
|
||||
bool has_compositor_surface_id() const { return m_compositor_surface_id.has_value(); }
|
||||
|
||||
void set_pending_set_browser_zoom_request(bool value) { m_pending_set_browser_zoom_request = value; }
|
||||
bool pending_set_browser_zoom_request() const { return m_pending_set_browser_zoom_request; }
|
||||
|
|
@ -277,6 +278,7 @@ private:
|
|||
void reset_cursor_blink_cycle();
|
||||
|
||||
void scroll_offset_did_change();
|
||||
void clear_compositor_surface();
|
||||
|
||||
void inform_the_navigation_api_about_aborting_navigation();
|
||||
void resolve_async_scroll_operation(Compositor::AsyncScrollOperationID);
|
||||
|
|
@ -334,7 +336,7 @@ private:
|
|||
Painting::DisplayListResourceStorage m_display_list_resource_storage;
|
||||
Painting::DisplayListResourceSet m_rendering_thread_display_list_resources;
|
||||
Compositor::CompositorThread m_rendering_thread;
|
||||
RefPtr<Painting::ExternalContentSource> m_external_content_source;
|
||||
Optional<Painting::CompositorSurfaceId> m_compositor_surface_id;
|
||||
|
||||
struct PendingAsyncScrollOperation {
|
||||
Compositor::AsyncScrollOperationID operation_id { 0 };
|
||||
|
|
|
|||
|
|
@ -32,13 +32,13 @@ void CanvasPaintable::paint(DisplayListRecordingContext& context, PaintPhase pha
|
|||
ScopedCornerRadiusClip corner_clip { context, canvas_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) };
|
||||
|
||||
auto& canvas_element = as<HTML::HTMLCanvasElement>(*dom_node());
|
||||
if (canvas_element.surface()) {
|
||||
if (auto surface = canvas_element.surface()) {
|
||||
auto canvas_int_rect = canvas_rect.to_type<int>();
|
||||
auto scaling_mode = to_gfx_scaling_mode(computed_values().image_rendering(),
|
||||
canvas_element.surface()->size(), canvas_int_rect.size());
|
||||
surface->size(), canvas_int_rect.size());
|
||||
auto& mutable_canvas_element = const_cast<HTML::HTMLCanvasElement&>(canvas_element);
|
||||
context.display_list_recorder().draw_external_content(canvas_int_rect,
|
||||
mutable_canvas_element.ensure_external_content_source(), scaling_mode);
|
||||
context.display_list_recorder().draw_compositor_surface(canvas_int_rect,
|
||||
mutable_canvas_element.ensure_compositor_surface_id(), scaling_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#include <LibWeb/Painting/AccumulatedVisualContext.h>
|
||||
#include <LibWeb/Painting/DisplayListCommand.h>
|
||||
#include <LibWeb/Painting/DisplayListResourceStorage.h>
|
||||
#include <LibWeb/Painting/ExternalContentSource.h>
|
||||
#include <LibWeb/Painting/ScrollState.h>
|
||||
#include <LibWeb/Painting/VideoFrameSource.h>
|
||||
|
||||
|
|
@ -97,7 +96,7 @@ private:
|
|||
virtual void fill_rect(FillRect const&) = 0;
|
||||
virtual void draw_scaled_decoded_image_frame(DrawScaledDecodedImageFrame const&) = 0;
|
||||
virtual void draw_repeated_decoded_image_frame(DrawRepeatedDecodedImageFrame const&) = 0;
|
||||
virtual void draw_external_content(DrawExternalContent const&) = 0;
|
||||
virtual void draw_compositor_surface(DrawCompositorSurface const&) = 0;
|
||||
virtual void draw_video_frame_source(DrawVideoFrameSource const&) = 0;
|
||||
virtual void save(Save const&) = 0;
|
||||
virtual void save_layer(SaveLayer const&) = 0;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ void DrawRepeatedDecodedImageFrame::dump(StringBuilder& builder) const
|
|||
builder.appendff(" dst_rect={} clip_rect={}", dst_rect, clip_rect);
|
||||
}
|
||||
|
||||
void DrawExternalContent::dump(StringBuilder& builder) const
|
||||
void DrawCompositorSurface::dump(StringBuilder& builder) const
|
||||
{
|
||||
builder.appendff(" dst_rect={}", dst_rect);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class DisplayList;
|
|||
V(FillRect, fill_rect) \
|
||||
V(DrawScaledDecodedImageFrame, draw_scaled_decoded_image_frame) \
|
||||
V(DrawRepeatedDecodedImageFrame, draw_repeated_decoded_image_frame) \
|
||||
V(DrawExternalContent, draw_external_content) \
|
||||
V(DrawCompositorSurface, draw_compositor_surface) \
|
||||
V(DrawVideoFrameSource, draw_video_frame_source) \
|
||||
V(Save, save) \
|
||||
V(SaveLayer, save_layer) \
|
||||
|
|
@ -165,12 +165,12 @@ struct DrawRepeatedDecodedImageFrame {
|
|||
void dump(StringBuilder&) const;
|
||||
};
|
||||
|
||||
struct DrawExternalContent {
|
||||
static constexpr StringView command_name = "DrawExternalContent"sv;
|
||||
static constexpr DisplayListCommandType command_type = DisplayListCommandType::DrawExternalContent;
|
||||
struct DrawCompositorSurface {
|
||||
static constexpr StringView command_name = "DrawCompositorSurface"sv;
|
||||
static constexpr DisplayListCommandType command_type = DisplayListCommandType::DrawCompositorSurface;
|
||||
|
||||
Gfx::IntRect dst_rect;
|
||||
ExternalContentResourceId source_id;
|
||||
CompositorSurfaceId surface_id;
|
||||
Gfx::ScalingMode scaling_mode;
|
||||
|
||||
[[nodiscard]] Gfx::IntRect bounding_rect() const { return dst_rect; }
|
||||
|
|
|
|||
|
|
@ -165,14 +165,16 @@ void DisplayListPlayerSkia::fill_rect(FillRect const& command)
|
|||
canvas.drawRect(to_skia_rect(rect), paint);
|
||||
}
|
||||
|
||||
void DisplayListPlayerSkia::draw_external_content(DrawExternalContent const& command)
|
||||
void DisplayListPlayerSkia::draw_compositor_surface(DrawCompositorSurface const& command)
|
||||
{
|
||||
auto frame = resource_storage().external_content_source(command.source_id).current_frame();
|
||||
auto frame = resource_storage().compositor_surface(command.surface_id);
|
||||
if (!frame.has_value())
|
||||
return;
|
||||
auto image = m_image_cache.image_for_frame(*frame);
|
||||
|
||||
auto image = m_image_cache.image_for_frame(frame.value());
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
auto dst_rect = to_skia_rect(command.dst_rect);
|
||||
SkRect src_rect = SkRect::MakeIWH(image->width(), image->height());
|
||||
auto& canvas = surface().canvas();
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ private:
|
|||
void fill_rect(FillRect const&) override;
|
||||
void draw_scaled_decoded_image_frame(DrawScaledDecodedImageFrame const&) override;
|
||||
void draw_repeated_decoded_image_frame(DrawRepeatedDecodedImageFrame const&) override;
|
||||
void draw_external_content(DrawExternalContent const&) override;
|
||||
void draw_compositor_surface(DrawCompositorSurface const&) override;
|
||||
void draw_video_frame_source(DrawVideoFrameSource const&) override;
|
||||
void add_clip_rect(AddClipRect const&) override;
|
||||
void save(Save const&) override;
|
||||
|
|
|
|||
|
|
@ -499,13 +499,13 @@ void DisplayListRecorder::draw_rect(Gfx::IntRect const& rect, Color color, bool
|
|||
.rough = rough });
|
||||
}
|
||||
|
||||
void DisplayListRecorder::draw_external_content(Gfx::IntRect const& dst_rect, NonnullRefPtr<ExternalContentSource> source, Gfx::ScalingMode scaling_mode)
|
||||
void DisplayListRecorder::draw_compositor_surface(Gfx::IntRect const& dst_rect, CompositorSurfaceId surface_id, Gfx::ScalingMode scaling_mode)
|
||||
{
|
||||
if (dst_rect.is_empty())
|
||||
return;
|
||||
append_command(DrawExternalContent {
|
||||
append_command(DrawCompositorSurface {
|
||||
.dst_rect = dst_rect,
|
||||
.source_id = resource_storage().add_external_content_source(move(source)),
|
||||
.surface_id = surface_id,
|
||||
.scaling_mode = scaling_mode,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ 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 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_compositor_surface(Gfx::IntRect const& dst_rect, CompositorSurfaceId, 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, Gfx::DecodedImageFrame frame, Gfx::ScalingMode scaling_mode, bool repeat_x, bool repeat_y);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Atomic.h>
|
||||
#include <AK/DistinctNumeric.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
|
|
@ -13,8 +14,14 @@ namespace Web::Painting {
|
|||
|
||||
AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, FontResourceId);
|
||||
AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, ImageFrameResourceId);
|
||||
AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, ExternalContentResourceId);
|
||||
AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, VideoFrameResourceId);
|
||||
AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, DisplayListResourceId);
|
||||
AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, CompositorSurfaceId);
|
||||
|
||||
inline CompositorSurfaceId allocate_compositor_surface_id()
|
||||
{
|
||||
static Atomic<u64> s_next_id { 1 };
|
||||
return CompositorSurfaceId { s_next_id.fetch_add(1, AK::MemoryOrder::memory_order_relaxed) };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <LibGfx/Filter.h>
|
||||
#include <LibGfx/Font/Font.h>
|
||||
#include <LibGfx/SharedImageBuffer.h>
|
||||
#include <LibWeb/Painting/DisplayList.h>
|
||||
#include <LibWeb/Painting/DisplayListResourceStorage.h>
|
||||
|
||||
|
|
@ -27,14 +28,6 @@ ImageFrameResourceId DisplayListResourceStorage::add_image_frame(Gfx::DecodedIma
|
|||
return { id };
|
||||
}
|
||||
|
||||
ExternalContentResourceId DisplayListResourceStorage::add_external_content_source(
|
||||
NonnullRefPtr<ExternalContentSource const> source)
|
||||
{
|
||||
auto id = source->id();
|
||||
m_external_content_sources.ensure(id, [&] { return move(source); });
|
||||
return { id };
|
||||
}
|
||||
|
||||
VideoFrameResourceId DisplayListResourceStorage::add_video_frame_source(NonnullRefPtr<VideoFrameSource const> source)
|
||||
{
|
||||
auto id = source->id();
|
||||
|
|
@ -64,8 +57,6 @@ void DisplayListResourceStorage::append_referenced_resources_from(
|
|||
add_font(source.font(id));
|
||||
for (auto id : referenced_resources.image_frames)
|
||||
add_image_frame(source.image_frame(id));
|
||||
for (auto id : referenced_resources.external_content_sources)
|
||||
add_external_content_source(source.external_content_source(id));
|
||||
for (auto id : referenced_resources.video_frame_sources)
|
||||
add_video_frame_source(source.video_frame_source(id));
|
||||
for (auto id : referenced_resources.display_lists)
|
||||
|
|
@ -89,8 +80,6 @@ void DisplayListResourceStorage::collect_referenced_resources(
|
|||
referenced_resources.fonts.set(command.font_id, AK::HashSetExistingEntryBehavior::Keep);
|
||||
if constexpr (requires { command.frame_id; })
|
||||
referenced_resources.image_frames.set(command.frame_id, AK::HashSetExistingEntryBehavior::Keep);
|
||||
if constexpr (requires { external_content_source(command.source_id); })
|
||||
referenced_resources.external_content_sources.set(command.source_id, AK::HashSetExistingEntryBehavior::Keep);
|
||||
if constexpr (requires { video_frame_source(command.source_id); })
|
||||
referenced_resources.video_frame_sources.set(command.source_id, AK::HashSetExistingEntryBehavior::Keep);
|
||||
if constexpr (requires { command.paint_style; command.paint_kind; }) {
|
||||
|
|
@ -150,10 +139,6 @@ DisplayListResourceTransaction DisplayListResourceStorage::create_transaction(
|
|||
if (!previous.image_frames.contains(id))
|
||||
transaction.image_frames.append(image_frame(id));
|
||||
}
|
||||
for (auto id : current.external_content_sources) {
|
||||
if (!previous.external_content_sources.contains(id))
|
||||
transaction.external_content_sources.append(external_content_source(id));
|
||||
}
|
||||
for (auto id : current.video_frame_sources) {
|
||||
if (!previous.video_frame_sources.contains(id))
|
||||
transaction.video_frame_sources.append(video_frame_source(id));
|
||||
|
|
@ -171,10 +156,6 @@ DisplayListResourceTransaction DisplayListResourceStorage::create_transaction(
|
|||
if (!current.image_frames.contains(id))
|
||||
transaction.image_frame_ids_to_remove.append(id);
|
||||
}
|
||||
for (auto id : previous.external_content_sources) {
|
||||
if (!current.external_content_sources.contains(id))
|
||||
transaction.external_content_source_ids_to_remove.append(id);
|
||||
}
|
||||
for (auto id : previous.video_frame_sources) {
|
||||
if (!current.video_frame_sources.contains(id))
|
||||
transaction.video_frame_source_ids_to_remove.append(id);
|
||||
|
|
@ -183,7 +164,6 @@ DisplayListResourceTransaction DisplayListResourceStorage::create_transaction(
|
|||
if (!current.display_lists.contains(id))
|
||||
transaction.display_list_ids_to_remove.append(id);
|
||||
}
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
|
|
@ -193,8 +173,6 @@ void DisplayListResourceStorage::apply_transaction(DisplayListResourceTransactio
|
|||
add_font(*font);
|
||||
for (auto const& frame : transaction.image_frames)
|
||||
add_image_frame(frame);
|
||||
for (auto& source : transaction.external_content_sources)
|
||||
add_external_content_source(move(source));
|
||||
for (auto& source : transaction.video_frame_sources)
|
||||
add_video_frame_source(move(source));
|
||||
for (auto& display_list : transaction.display_lists)
|
||||
|
|
@ -204,8 +182,6 @@ void DisplayListResourceStorage::apply_transaction(DisplayListResourceTransactio
|
|||
m_fonts.remove(id.value());
|
||||
for (auto id : transaction.image_frame_ids_to_remove)
|
||||
m_image_frames.remove(id.value());
|
||||
for (auto id : transaction.external_content_source_ids_to_remove)
|
||||
m_external_content_sources.remove(id.value());
|
||||
for (auto id : transaction.video_frame_source_ids_to_remove)
|
||||
m_video_frame_sources.remove(id.value());
|
||||
for (auto id : transaction.display_list_ids_to_remove)
|
||||
|
|
@ -216,9 +192,19 @@ void DisplayListResourceStorage::retain_only(DisplayListResourceSet const& resou
|
|||
{
|
||||
m_fonts.remove_all_matching([&](auto id, auto const&) { return !resource_set.fonts.contains(FontResourceId { id }); });
|
||||
m_image_frames.remove_all_matching([&](auto id, auto const&) { return !resource_set.image_frames.contains(ImageFrameResourceId { id }); });
|
||||
m_external_content_sources.remove_all_matching([&](auto id, auto const&) { return !resource_set.external_content_sources.contains(ExternalContentResourceId { id }); });
|
||||
m_video_frame_sources.remove_all_matching([&](auto id, auto const&) { return !resource_set.video_frame_sources.contains(VideoFrameResourceId { id }); });
|
||||
m_display_lists.remove_all_matching([&](auto id, auto const&) { return !resource_set.display_lists.contains(DisplayListResourceId { id }); });
|
||||
}
|
||||
|
||||
void DisplayListResourceStorage::update_compositor_surface(CompositorSurfaceId surface_id, Gfx::SharedImage&& shared_image)
|
||||
{
|
||||
auto shared_image_buffer = Gfx::SharedImageBuffer::import_from_shared_image(move(shared_image));
|
||||
m_compositor_surfaces.set(surface_id.value(), Gfx::DecodedImageFrame { *shared_image_buffer.bitmap() });
|
||||
}
|
||||
|
||||
void DisplayListResourceStorage::clear_compositor_surface(CompositorSurfaceId surface_id)
|
||||
{
|
||||
m_compositor_surfaces.remove(surface_id.value());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@
|
|||
#include <AK/HashTable.h>
|
||||
#include <AK/Noncopyable.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/Span.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/Painting/DisplayListResourceIds.h>
|
||||
#include <LibWeb/Painting/ExternalContentSource.h>
|
||||
#include <LibWeb/Painting/VideoFrameSource.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
|
@ -25,7 +25,6 @@ namespace Web::Painting {
|
|||
struct DisplayListResourceSet {
|
||||
HashTable<FontResourceId> fonts;
|
||||
HashTable<ImageFrameResourceId> image_frames;
|
||||
HashTable<ExternalContentResourceId> external_content_sources;
|
||||
HashTable<VideoFrameResourceId> video_frame_sources;
|
||||
HashTable<DisplayListResourceId> display_lists;
|
||||
};
|
||||
|
|
@ -33,13 +32,11 @@ struct DisplayListResourceSet {
|
|||
struct DisplayListResourceTransaction {
|
||||
Vector<NonnullRefPtr<Gfx::Font const>> fonts;
|
||||
Vector<Gfx::DecodedImageFrame> image_frames;
|
||||
Vector<NonnullRefPtr<ExternalContentSource const>> external_content_sources;
|
||||
Vector<NonnullRefPtr<VideoFrameSource const>> video_frame_sources;
|
||||
Vector<NonnullRefPtr<DisplayList const>> display_lists;
|
||||
|
||||
Vector<FontResourceId> font_ids_to_remove;
|
||||
Vector<ImageFrameResourceId> image_frame_ids_to_remove;
|
||||
Vector<ExternalContentResourceId> external_content_source_ids_to_remove;
|
||||
Vector<VideoFrameResourceId> video_frame_source_ids_to_remove;
|
||||
Vector<DisplayListResourceId> display_list_ids_to_remove;
|
||||
};
|
||||
|
|
@ -54,7 +51,6 @@ public:
|
|||
|
||||
FontResourceId add_font(Gfx::Font const&);
|
||||
ImageFrameResourceId add_image_frame(Gfx::DecodedImageFrame const&);
|
||||
ExternalContentResourceId add_external_content_source(NonnullRefPtr<ExternalContentSource const>);
|
||||
VideoFrameResourceId add_video_frame_source(NonnullRefPtr<VideoFrameSource const>);
|
||||
DisplayListResourceId add_display_list(NonnullRefPtr<DisplayList const>);
|
||||
void append_referenced_resources_from(DisplayListResourceStorage const& source, ReadonlyBytes command_bytes);
|
||||
|
|
@ -63,21 +59,23 @@ public:
|
|||
DisplayListResourceSet collect_referenced_resources(DisplayList const&) const;
|
||||
DisplayListResourceSet collect_referenced_resources(ReadonlyBytes command_bytes) const;
|
||||
void retain_only(DisplayListResourceSet const&);
|
||||
void update_compositor_surface(CompositorSurfaceId, Gfx::SharedImage&&);
|
||||
void clear_compositor_surface(CompositorSurfaceId);
|
||||
|
||||
Gfx::Font const& font(FontResourceId id) const { return *m_fonts.get(id.value()).value(); }
|
||||
Gfx::DecodedImageFrame const& image_frame(ImageFrameResourceId id) const { return m_image_frames.get(id.value()).value(); }
|
||||
ExternalContentSource const& external_content_source(ExternalContentResourceId id) const { return *m_external_content_sources.get(id.value()).value(); }
|
||||
VideoFrameSource const& video_frame_source(VideoFrameResourceId id) const { return *m_video_frame_sources.get(id.value()).value(); }
|
||||
DisplayList const& display_list(DisplayListResourceId id) const { return *m_display_lists.get(id.value()).value(); }
|
||||
Optional<Gfx::DecodedImageFrame const&> compositor_surface(CompositorSurfaceId id) const { return m_compositor_surfaces.get(id.value()); }
|
||||
|
||||
private:
|
||||
void collect_referenced_resources(ReadonlyBytes command_bytes, DisplayListResourceSet&) const;
|
||||
|
||||
HashMap<u64, NonnullRefPtr<Gfx::Font const>> m_fonts;
|
||||
HashMap<u64, Gfx::DecodedImageFrame> m_image_frames;
|
||||
HashMap<u64, NonnullRefPtr<ExternalContentSource const>> m_external_content_sources;
|
||||
HashMap<u64, NonnullRefPtr<VideoFrameSource const>> m_video_frame_sources;
|
||||
HashMap<u64, NonnullRefPtr<DisplayList const>> m_display_lists;
|
||||
HashMap<u64, Gfx::DecodedImageFrame> m_compositor_surfaces;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Atomic.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibWeb/Painting/ExternalContentSource.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
||||
static Atomic<u64> s_next_id { 1 };
|
||||
|
||||
NonnullRefPtr<ExternalContentSource> ExternalContentSource::create()
|
||||
{
|
||||
return adopt_ref(*new ExternalContentSource());
|
||||
}
|
||||
|
||||
ExternalContentSource::ExternalContentSource()
|
||||
: m_id(s_next_id.fetch_add(1, AK::MemoryOrder::memory_order_relaxed))
|
||||
{
|
||||
}
|
||||
|
||||
void ExternalContentSource::update(Optional<Gfx::DecodedImageFrame> frame)
|
||||
{
|
||||
Optional<Gfx::DecodedImageFrame> old;
|
||||
{
|
||||
Sync::MutexLocker const locker { m_mutex };
|
||||
old = move(m_frame);
|
||||
m_frame = move(frame);
|
||||
}
|
||||
}
|
||||
|
||||
void ExternalContentSource::clear()
|
||||
{
|
||||
Optional<Gfx::DecodedImageFrame> old;
|
||||
{
|
||||
Sync::MutexLocker const locker { m_mutex };
|
||||
old = move(m_frame);
|
||||
}
|
||||
}
|
||||
|
||||
Optional<Gfx::DecodedImageFrame> ExternalContentSource::current_frame() const
|
||||
{
|
||||
Sync::MutexLocker const locker { m_mutex };
|
||||
return m_frame;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/AtomicRefCounted.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibSync/Mutex.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
||||
class ExternalContentSource final : public AtomicRefCounted<ExternalContentSource> {
|
||||
public:
|
||||
static NonnullRefPtr<ExternalContentSource> create();
|
||||
|
||||
u64 id() const { return m_id; }
|
||||
|
||||
void update(Optional<Gfx::DecodedImageFrame>);
|
||||
void clear();
|
||||
Optional<Gfx::DecodedImageFrame> current_frame() const;
|
||||
|
||||
private:
|
||||
ExternalContentSource();
|
||||
|
||||
u64 m_id { 0 };
|
||||
mutable Sync::Mutex m_mutex;
|
||||
Optional<Gfx::DecodedImageFrame> m_frame;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@
|
|||
#include <LibWeb/Layout/Viewport.h>
|
||||
#include <LibWeb/Painting/BorderRadiusCornerClipper.h>
|
||||
#include <LibWeb/Painting/DisplayListRecorder.h>
|
||||
#include <LibWeb/Painting/ExternalContentSource.h>
|
||||
#include <LibWeb/Painting/NavigableContainerViewportPaintable.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
|
@ -48,12 +47,14 @@ void NavigableContainerViewportPaintable::paint(DisplayListRecordingContext& con
|
|||
|
||||
auto content_navigable = navigable_container.content_navigable();
|
||||
VERIFY(content_navigable);
|
||||
if (content_navigable->has_been_destroyed() || !content_navigable->has_compositor_surface_id())
|
||||
return;
|
||||
|
||||
context.display_list_recorder().save();
|
||||
context.display_list_recorder().add_clip_rect(clip_rect.to_type<int>());
|
||||
context.display_list_recorder().draw_external_content(
|
||||
context.display_list_recorder().draw_compositor_surface(
|
||||
context.enclosing_device_rect(absolute_rect).to_type<int>(),
|
||||
content_navigable->external_content_source(),
|
||||
content_navigable->compositor_surface_id(),
|
||||
Gfx::ScalingMode::NearestNeighbor);
|
||||
context.display_list_recorder().restore();
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ SaveLayer@0
|
|||
CompositorMainThreadWheelEventRegion@1 rect=[40,40 160x120]
|
||||
Save@1
|
||||
AddClipRect@1 rect=[40,40 160x120]
|
||||
DrawExternalContent@1 dst_rect=[40,40 160x120]
|
||||
DrawCompositorSurface@1 dst_rect=[40,40 160x120]
|
||||
Restore@1
|
||||
Restore@0
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
AccumulatedVisualContext Tree:
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x53]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 784x32]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 784x32]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 32x32]
|
||||
DrawCompositorSurface@1 dst_rect=[8,8 32x32]
|
||||
Restore@0
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
AccumulatedVisualContext Tree:
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x93]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x80]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x80]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 120x80]
|
||||
CompositorMainThreadWheelEventRegion@1 rect=[0,0 120x80]
|
||||
Save@1
|
||||
AddClipRect@1 rect=[0,0 120x80]
|
||||
DrawCompositorSurface@1 dst_rect=[0,0 120x80]
|
||||
Restore@1
|
||||
Restore@0
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
</style>
|
||||
<canvas id="canvas" width="16" height="16"></canvas>
|
||||
<script>
|
||||
test(() => {
|
||||
const canvas = document.getElementById("canvas");
|
||||
const context = canvas.getContext("2d");
|
||||
context.fillStyle = "green";
|
||||
context.fillRect(0, 0, 16, 16);
|
||||
|
||||
println(internals.dumpDisplayList());
|
||||
});
|
||||
</script>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 120px;
|
||||
height: 80px;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
<iframe id="frame" srcdoc="<body style='margin: 0; background: green'></body>"></iframe>
|
||||
<script>
|
||||
promiseTest(async () => {
|
||||
await new Promise(resolve => {
|
||||
if (frame.contentDocument && frame.contentDocument.readyState === "complete") {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
frame.onload = resolve;
|
||||
});
|
||||
await animationFrame();
|
||||
|
||||
println(internals.dumpDisplayList());
|
||||
});
|
||||
</script>
|
||||
Loading…
Reference in a new issue