Skip to content

Commit

Permalink
view-backend: dispatch pending frame callbacks after a surface is unr…
Browse files Browse the repository at this point in the history
…egistered

This was causing WebKit to stop painting after provisional navigation
fails with PSON enabled. It happened in the following situation:

1. Normal load, view backend registers surface for bridge 1
2. A frame is requested for bridge 1
3. CORS load starts, a new process is launched and view backend
   registers surface for bridge 2
4. Frame for bridge 1 is rendered, but current bridge is 2 so
   ViewBackend::dispatchFrameCallbacks() does nothing.
5. CORS load fails and the provisional load is destroyed so surface for
   bridge 2 is unregistered
6. No more updates because there's still the frame callback pending for
   surface for bridge 1.

This always happens when WebKit starts a CORS navigation that is
converted to a download, because in that case the provisional load fails
with cancelled error. It was never committed and nothing was rendered.
So, while it's ok to stop painting new frames during the provisional
load to avoid flashing, we should check if there's any pending callback
once the current surface is unregistered.
  • Loading branch information
carlosgcampos committed Feb 17, 2023
1 parent cb6b86a commit f2901c6
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 9 deletions.
7 changes: 5 additions & 2 deletions src/view-backend-private.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ void ViewBackend::commitDmabufPoolEntry(struct wpe_dmabuf_pool_entry* entry)
void ViewBackend::dispatchFrameCallbacks()
{
if (G_LIKELY(!m_bridgeIds.empty())) {
WS::Instance::singleton().dispatchFrameCallbacks(m_bridgeIds.back());
wpe_view_backend_dispatch_frame_displayed(m_backend);
if (WS::Instance::singleton().dispatchFrameCallbacks(m_bridgeIds.back()))
wpe_view_backend_dispatch_frame_displayed(m_backend);
}
}

Expand All @@ -130,6 +130,9 @@ void ViewBackend::unregisterSurface(uint32_t bridgeId)

m_bridgeIds.erase(it);
WS::Instance::singleton().unregisterViewBackend(bridgeId);
// Dispatch frame callbacks in case there's any pending callback from previous bridge.
if (!m_bridgeIds.empty())
dispatchFrameCallbacks();
}

void ViewBackend::didReceiveMessage(uint32_t messageId, uint32_t messageBody)
Expand Down
7 changes: 4 additions & 3 deletions src/ws.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,17 +659,18 @@ void Instance::unregisterSurface(Surface* surface)
}
}

void Instance::dispatchFrameCallbacks(uint32_t bridgeId)
bool Instance::dispatchFrameCallbacks(uint32_t bridgeId)
{
auto it = m_viewBackendMap.find(bridgeId);
if (it == m_viewBackendMap.end()) {
g_warning("Instance::dispatchFrameCallbacks(): "
"Cannot find surface with bridgeId %" PRIu32 " in view "
"backend map. Probably the associated surface is gone "
"due to a premature exit in the client side", bridgeId);
} else {
it->second->dispatchFrameCallbacks();
return false;
}

return it->second->dispatchFrameCallbacks();
}

} // namespace WS
11 changes: 7 additions & 4 deletions src/ws.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ struct Surface {
wl_list_insert(m_pendingFrameCallbacks.prev, wl_resource_get_link(resource));
}

void dispatchFrameCallbacks()
bool dispatchFrameCallbacks()
{
struct wl_resource* resource;
struct wl_resource* tmp;
Expand All @@ -107,8 +107,11 @@ struct Surface {
wl_resource_destroy(resource);
}

if (client)
wl_client_flush(client);
if (!client)
return false;

wl_client_flush(client);
return true;
}

private:
Expand Down Expand Up @@ -151,7 +154,7 @@ class Instance {
void unregisterSurface(Surface*);
void registerViewBackend(uint32_t, APIClient&);
void unregisterViewBackend(uint32_t);
void dispatchFrameCallbacks(uint32_t);
bool dispatchFrameCallbacks(uint32_t);

using VideoPlaneDisplayDmaBufCallback = std::function<void(struct wpe_video_plane_display_dmabuf_export*, uint32_t, int, int32_t, int32_t, int32_t, int32_t, uint32_t)>;
using VideoPlaneDisplayDmaBufEndOfStreamCallback = std::function<void(uint32_t)>;
Expand Down

0 comments on commit f2901c6

Please sign in to comment.