Properly release GL resource when unmapping a window and detect stale
cache indices using a generation count. This fixes the disappearing
images (GL textures would be invalid and need to be re-created) as well
as the panics when an item's cache index ended up being re-used because
some other item was drawn first and allocated that indices. The latter
is fixed by using a generational counter on the cache that's bumped when
clearing, instead of a single "cache_ok" bool.
Move the item graphics cache into the GraphicsWindow and then, together
with the new femtovg::TextContext, we can provide the metrics and can
stop using the window_map_pending notifier for this query.
When we calculate the initial layout without a mapped window early on,
we end up with zero text metrics with the GL backend due to an API
limitation of femtovg.
While working on that, this patch introduces a workaround to mark the callers of
image_size() and font_metrics() as dirty when the window is mapped.
We don't need a property reference anymore, a plain image reference is fine AFAICS.
Dirtyness of the source is tracked on the caller side of layouting_info()
or in the draw_image_impl anyway.
Pass everything needed for delayed evaluation for
`PlatformWindow::font_metrics()` to permit caching the font matching
result in the Text/TextInput's rendering cache.
We query text metrics frequently for text items, for example when in
layouts. This requires font resolution, which is about to become more
much more expensive due to analysis of the underlying text. To speed
this up, the objective is to use the item rendering cache. Making that
work in turn requires querying all related properties inside a property
tracker. That means we need to delay querying anything related to that,
including the font request needed for the `font_metrics()` function on
the PlatformWindow trait.
Cache the default font properties in a Property<FontRequest>, so that we
can query it in the future when determining the GLFont for text
rendering. When that will happen through a property tracker, the dirty
propagation should mark the item cache dirty when default font
properties change.
The component layout needs to be re-calculated. For some reason it is with
the Qt backend but not with GL.
Either way we can force it to re-calculate when the component changes.
It possibly doesn't get dirty when the dependencies are deleted.
Remove the intermediate properties for width and height and - just like
qt backend - apply the width and height in apply_window_properties
and when receiving a window resize event.
This also elimiates the get_geometry() getter as that would otherwise just
have been a FIXME'ed default().
* Provide an internal behavior parameter to run_event_loop() that we can use
from the preview to not quit when the last window was closed.
* Fix Drop for the winit event loop GraphicsWindow to drop the backend window correctly
when unmapping, not when the graphics window dies. Otherwise QuitOnLastWindowClosed doesn't work.
Similar to the window properties, use a property tracker with a change
handler in window to issue redraw requests. This allows eliminating the
forced repaints in the event loop after event processing and ensures
that the UI is repainted when programmatically setting a property, for
example.
Synchronize title/background/etc. once when the window is mapped and
afterwards lazily when the corresponding property tracker notifies us.
Since that callback can happen at any point in time and to also capture
potentially multiple changes, this first triggers a wakeup of the event
loop, when the actual application of properties happens.
By default PropertyTracker::evaluate() registers the currently
evaluating binding/tracker as a dependency. This should help with
repeaters and other scenarios where in the run-time we use property
trackers but want to track the overall "dirtyness" in the window with
regards to whether a redraw is needed or not.
The new evaluate_as_dependency_root() function allows skipping this
mechanism and is used for the two trackers in the window.
Don't use the item's rendering cache to determine the image size, as
that's soley for rendering. The Qt backend doesn't use the item cache
and the GL backend neither after this change. Instead both backends have
a cache for decoded images.
This allows creating multiple windows for example, and it will allow for
showing windows in those tests that require a mapped window.
As a bonus, the run() function on generated components is not consuming
anymore.
Reduce the dependency of the GLRenderer to a new trait that exposes the
EventLoopTarget and EventLoopProxy. Those are provided by either an
winit::event_loop::EventLoop or, once the loop is started using the
self-consuming run(), by the event loop target provided to the run_fn.
This way renderers can be created from either within run or before.
The initial event loop instance is kept in TLS. When starting the loop,
it's taken out and instead the event loop target is placed into a scoped
tls variable.
During rendering the GLRenderer's Option<WindowedContext<NotCurrent>>
is None. That however leads to any font_metrics() calls such as due to
implicit sizing to panic, because the call requires access to the
window's scale factor.
This is fixed by keeping a shared reference to the PossiblyCurrent
WindowedContext also in the GLRenderer.
The GL backend uses the item graphics cache for the image size function,
which uses a PropertyTracker. That tracker must have the Image's source
included in its dependencies, to avoid that when loading a HTML image
for example, the cache isn't invalidated when the source is changed
before the HTML image was loaded async. That's why the get() call on the
source property must happen from within the PropertyTracker's callback.
For all other items the default is the empty size.
This also required three fixes for the HTML image loading:
* The upload_pending property value was inverted, it needs to start
out as true (pending yes) and be set to false when it finished
loading (not pending anymore)
* Mark the upload_pending property as dirty before scheduling the
redraw, in case it's sync
* Pass the item rendering cache to the image_size function to ensure
that the Rc<CachedImage> is not only weak inside the image_cache
of the GLRendererData but also strong on the item.
Allow images to be just decoded and uploaded to the GPU in a separate
step. This is in preparation to implicit size support, where the actual
dimension of the image can be determined by decoding it immediately when
needed and uploaded to the GPU later (when we can be sure to have a
current GL context).
For images loaded through HTMLImageElement this is trickier, in the
sense that - unlike when loading off disk - it is inherently async.
Therefore we use a Property<bool> that we toggle when loading is
complete, in order to mark any dependent bindings as dirty, after
reporting an initial (1, 1) size.
Move data structures shared between the GLRenderer and the
GLItemRenderer into a *ka-ching* shared data structure. This reduces the
amount of separate Rc instances.
Also moving the image loading functions from GLItemRenderer to
GLRendererData will allow for re-use from the GLRenderer in the future.