Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 60 additions & 32 deletions Libraries/LibCore/Promise.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,27 @@ class Promise : public PromiseBase {
virtual ~Promise() = default;
static NonnullRefPtr<Promise> construct() { return adopt_ref(*new Promise()); }

Function<ErrorOr<void, TError>(Result&)> on_resolution;
template<typename R = Result>
static NonnullRefPtr<Promise> resolved(R&& result)
{
auto promise = construct();
promise->resolve(forward<R>(result));
return promise;
}

template<typename E = ErrorType>
static NonnullRefPtr<Promise> rejected(E&& error)
{
auto promise = construct();
promise->reject(forward<E>(error));
return promise;
}

Function<ErrorOr<void, ErrorType>(Result&)> on_resolution;
Function<void(ErrorType&)> on_rejection;

template<typename U>
static NonnullRefPtr<Promise> after(Vector<NonnullRefPtr<Promise<U>>> promises)
template<typename U, typename E>
static NonnullRefPtr<Promise> after(Vector<NonnullRefPtr<Promise<U, E>>> promises)
{
auto promise = Promise::construct();
struct Resolved : RefCounted<Resolved> {
Expand All @@ -46,35 +62,42 @@ class Promise : public PromiseBase {

size_t count { 0 };
size_t needed { 0 };
Optional<Error> error;
Optional<E> error;
};

auto resolved = make_ref_counted<Resolved>(promises.size());
auto weak_promise = promise->template make_weak_ptr<Promise>();
for (auto p : promises) {
p->when_resolved([weak_promise, resolved](auto&&) -> ErrorOr<void> {
if (!weak_promise || weak_promise->is_rejected())
if (!promises.is_empty()) {
auto resolved = make_ref_counted<Resolved>(promises.size());
auto weak_promise = promise->template make_weak_ptr<Promise>();
for (auto p : promises) {
p->when_resolved([weak_promise, resolved](auto&&) -> ErrorOr<void, E> {
if (!weak_promise || weak_promise->is_rejected())
return {};

if (++resolved->count == resolved->needed) {
if (resolved->error.has_value())
weak_promise->reject(ErrorType(resolved->error.release_value()));
else
weak_promise->resolve({});
}
return {};
});

p->when_rejected([weak_promise, resolved](auto&& error) {
++resolved->count;
if (!resolved->error.has_value())
resolved->error = move(error);

if (!weak_promise)
return;

if (++resolved->count == resolved->needed) {
if (resolved->error.has_value())
weak_promise->reject(resolved->error.release_value());
else
weak_promise->resolve({});
}
return {};
});

p->when_rejected([weak_promise, resolved](auto&& error) {
resolved->error = move(error);
if (!weak_promise)
return;

if (++resolved->count == resolved->needed)
weak_promise->reject(resolved->error.release_value());
});

promise->add_child(*p);
if (resolved->count == resolved->needed)
weak_promise->reject(ErrorType(resolved->error.release_value()));
});

promise->add_child(*p);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
} else {
promise->resolve({});
}

return promise;
Expand All @@ -83,19 +106,24 @@ class Promise : public PromiseBase {
template<typename R = Result>
void resolve(R&& result)
{
auto protector = NonnullRefPtr { *this };
m_result_or_rejection = forward<R>(result);

if (on_resolution) {
auto handler_result = on_resolution(m_result_or_rejection->value());
possibly_handle_rejection(handler_result);
}

m_children.clear();
}

template<typename E = ErrorType>
void reject(E&& error)
{
auto protector = NonnullRefPtr { *this };
m_result_or_rejection = forward<E>(error);
possibly_handle_rejection(*m_result_or_rejection);
m_children.clear();
}

bool is_rejected()
Expand Down Expand Up @@ -127,7 +155,7 @@ class Promise : public PromiseBase {
if (is_rejected())
new_promise->reject(m_result_or_rejection->release_error());

on_resolution = [new_promise, func = move(func)](Result& result) -> ErrorOr<void> {
on_resolution = [new_promise, func = move(func)](Result& result) -> ErrorOr<void, ErrorType> {
new_promise->resolve(func(result));
return {};
};
Expand All @@ -140,13 +168,13 @@ class Promise : public PromiseBase {
template<CallableAs<void, Result&> F>
Promise& when_resolved(F handler)
{
return when_resolved([handler = move(handler)](Result& result) mutable -> ErrorOr<void> {
return when_resolved([handler = move(handler)](Result& result) mutable -> ErrorOr<void, ErrorType> {
handler(result);
return {};
});
}

template<CallableAs<ErrorOr<void>, Result&> F>
template<CallableAs<ErrorOr<void, ErrorType>, Result&> F>
Promise& when_resolved(F handler)
{
on_resolution = move(handler);
Expand All @@ -172,7 +200,7 @@ class Promise : public PromiseBase {

private:
template<typename T>
void possibly_handle_rejection(ErrorOr<T, TError>& result)
void possibly_handle_rejection(ErrorOr<T, ErrorType>& result)
{
if (result.is_error() && on_rejection)
on_rejection(result.error());
Expand Down
35 changes: 24 additions & 11 deletions Libraries/LibWeb/HTML/LocalTraversableNavigable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1708,7 +1708,7 @@ void LocalTraversableNavigable::finalize_same_document_navigation(GC::Ref<LocalN
}

// https://html.spec.whatwg.org/multipage/document-sequences.html#close-a-top-level-traversable
void LocalTraversableNavigable::close_top_level_traversable()
void LocalTraversableNavigable::close_top_level_traversable(PromptToUnload prompt_to_unload)
{
// 1. If traversable's is closing is true, then return.
if (is_closing())
Expand All @@ -1718,22 +1718,15 @@ void LocalTraversableNavigable::close_top_level_traversable()
set_closing(true);

// 2. Definitely close traversable.
definitely_close_top_level_traversable();
definitely_close_top_level_traversable(prompt_to_unload);
}

// https://html.spec.whatwg.org/multipage/document-sequences.html#definitely-close-a-top-level-traversable
void LocalTraversableNavigable::definitely_close_top_level_traversable()
void LocalTraversableNavigable::definitely_close_top_level_traversable(PromptToUnload prompt_to_unload)
{
VERIFY(is_top_level_traversable());

// 1. Let toUnload be traversable's active document's inclusive descendant navigables.
auto to_unload = active_document()->inclusive_descendant_navigables();

// 2. If the result of checking if unloading is canceled for toUnload is not "continue", then return.
check_if_unloading_is_canceled(move(to_unload), GC::create_function(heap(), [this](CheckIfUnloadingIsCanceledResult result) {
if (result != CheckIfUnloadingIsCanceledResult::Continue)
return;

auto append_close_steps = [this] {
// 3. Append the following session history traversal steps to traversable:
request_history_operation(
CloseTopLevelTraversableHistoryOperationParameters { .traversable_id = id() },
Expand All @@ -1749,6 +1742,26 @@ void LocalTraversableNavigable::definitely_close_top_level_traversable()
ready->function()(HistoryStepResult::Applied);
}),
});
};

if (prompt_to_unload == PromptToUnload::No) {
append_close_steps();
return;
}

// 1. Let toUnload be traversable's active document's inclusive descendant navigables.
auto to_unload = active_document()->inclusive_descendant_navigables();

// 2. If the result of checking if unloading is canceled for toUnload is not "continue", then return.
check_if_unloading_is_canceled(move(to_unload), GC::create_function(heap(), [this, append_close_steps = move(append_close_steps)](CheckIfUnloadingIsCanceledResult result) {
if (result != CheckIfUnloadingIsCanceledResult::Continue) {
// AD-HOC: Allow a later close attempt if this one was canceled.
set_closing(false);
return;
}

// 3. Append the following session history traversal steps to traversable:
append_close_steps();
}));
}

Expand Down
8 changes: 6 additions & 2 deletions Libraries/LibWeb/HTML/LocalTraversableNavigable.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,12 @@ class WEB_API LocalTraversableNavigable final : public LocalNavigable {
bool route_child_created_during_history_reconstruction(LocalNavigable& parent, LocalNavigable& child, SessionHistoryEntry& initial_entry, SessionHistoryEntryDescriptor target_entry);
void reset_session_history_for_testing(GC::Ref<GC::Function<void()>> on_complete);

void close_top_level_traversable();
void definitely_close_top_level_traversable();
enum class PromptToUnload : bool {
No,
Yes,
};
void close_top_level_traversable(PromptToUnload = PromptToUnload::Yes);
void definitely_close_top_level_traversable(PromptToUnload = PromptToUnload::Yes);
void destroy_top_level_traversable();

Utf16String const& window_handle() const { return m_window_handle; }
Expand Down
4 changes: 2 additions & 2 deletions Libraries/LibWeb/Page/Page.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,10 +484,10 @@ GC::Ref<HTML::LocalTraversableNavigable> Page::top_level_traversable() const
return *m_top_level_traversable;
}

void Page::did_update_window_rect()
void Page::did_complete_window_rect_request(u64 completion_id)
{
if (m_window_rect_observer)
m_window_rect_observer->function()({ window_position(), window_size() });
m_window_rect_observer->function()({ window_position(), window_size() }, completion_id);
}

template<typename ResponseType>
Expand Down
12 changes: 6 additions & 6 deletions Libraries/LibWeb/Page/Page.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ class WEB_API Page final : public JS::Cell {
DevicePixelSize window_size() const { return m_window_size; }
void set_window_size(DevicePixelSize size) { m_window_size = size; }

void did_update_window_rect();
void set_window_rect_observer(GC::Ptr<GC::Function<void(DevicePixelRect)>> window_rect_observer) { m_window_rect_observer = window_rect_observer; }
void did_complete_window_rect_request(u64 completion_id);
void set_window_rect_observer(GC::Ptr<GC::Function<void(DevicePixelRect, u64)>> window_rect_observer) { m_window_rect_observer = window_rect_observer; }

void did_request_alert(Utf16String const& message);
void alert_closed();
Expand Down Expand Up @@ -384,7 +384,7 @@ class WEB_API Page final : public JS::Cell {

DevicePixelPoint m_window_position {};
DevicePixelSize m_window_size {};
GC::Ptr<GC::Function<void(DevicePixelRect)>> m_window_rect_observer;
GC::Ptr<GC::Function<void(DevicePixelRect, u64)>> m_window_rect_observer;

PendingDialog m_pending_dialog { PendingDialog::None };
Optional<Utf16String> m_pending_dialog_text;
Expand Down Expand Up @@ -521,10 +521,10 @@ class PageClient : public JS::Cell {
virtual void page_did_change_title(Utf16String const&) { }
virtual void page_did_update_editing_history_state(bool, bool) { }
virtual void page_did_request_refresh() { }
virtual void page_did_request_resize_window(Gfx::IntSize) { }
virtual void page_did_request_reposition_window(Gfx::IntPoint) { }
virtual void page_did_request_resize_window(Gfx::IntSize, u64) { }
virtual void page_did_request_reposition_window(Gfx::IntPoint, u64) { }
virtual void page_did_request_restore_window() { }
virtual void page_did_request_maximize_window() { }
virtual void page_did_request_maximize_window(u64) { }
virtual void page_did_request_minimize_window() { }
virtual void page_did_request_fullscreen_window() { }
virtual void page_did_request_exit_fullscreen() { }
Expand Down
Loading
Loading