This commit restructures the entire text shaping stack to enable lines of shaped text to
have non-homogeneous properties like which font face they belong to and which direction
a segment of text is going.
The text package now provides a concrete type text.Shaper which can be used to convert
strings into sequences of renderable text.Glyphs. At a high level, the API is used
like this:
// Prepare some fonts.
var collection []text.FontFace
// Make a shaper with those fonts loaded.
shaper := text.NewShaper(collection)
// Shape a string.
shaper.LayoutString(text.Parameters{
PxPerEm: fixed.I(12),
}, 0, 100, system.Locale{}, "Hello")
// Iterate the glyphs from that string.
for glyph, ok := shaper.NextGlyph(); ok; glyph, ok = shaper.NextGlyph() {
// Convert the glyph data into a path. In real uses, convert batches of glyphs
// rather than single glyphs to reduce the number of individual paths and offsets
// required to display your text.
shape := shaper.Shape([]text.Glyph{glyph})
// Offset the glyph to the position it declares within its fields. This will
// automatically handle correct bidirectional text glyph positioning.
offset := op.Offset(image.Pt(glyph.X.Floor(), int(glyph.Y))).Push(gtx.Ops)
// Create a clip area from the shape of the glyph.
area := clip.Outline{Path: shape}.Push(gtx.Ops)
// Paint whatever the current color is within the glyph's shape.
paint.PaintOp{}.Add(gtx.Ops)
area.Pop()
offset.Pop()
}
This API will transparently handle both font fallback (choosing appropriate fonts
from those loaded when the primary font doesn't contain a required glyph) and
bidirectional text (mixed left-to-right and right-to-left text). Glyphs are
iterated in order of the input runes, not their visual order, but proper use
of the provided offsets will ensure that text always displays correctly.
Thanks to Elias Naur for suggesting this glyph iterator strategy. It let us cut
through a lot of accumulated complexity from trying to match our old text APIs,
meaning that this change actually is a net negative change in lines of code.
This commit consumes the upstream github.com/go-text/typesetting/shaping API
now that my prior work is merged there, removing the need for the font/opentype/internal
package entirely.
As part of my efforts, I fuzzed both the low-level text shaping stack and the
editor widget extensively. I've committed regression tests found that way into
the appropriate testdata files to ensure the fuzzer re-checks them.
Fixes: https://todo.sr.ht/~eliasnaur/gio/425
Fixes: https://todo.sr.ht/~eliasnaur/gio/211
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
The windowWillClose callback is too soon to destroy our Window:
at least draw callbacks may be called after windowWillClose but
before the window is gone. This change moves cleanup to the
viewDidMoveToWindow callback where we're sure the NSView is no longer
active.
Fixes: https://todo.sr.ht/~eliasnaur/gio/466
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Allow app ID to be set by linger flag -X gioui.org/app.ID=%s so that wayland
can group windows, search for ${gioui.org/app.ID}.desktop file and display
application name. e.g. /usr/share/applications/${gioui.org/app.ID}.desktop
~/.local/share/applications/${appID}.desktop.
ID is set by the gogio tool or manually with the -X linker flag.
Signed-off-by: Marko Kungla <marko.kungla@gmail.com>
When applying window config on runtime, it is nessesary
to do full redraw in order to changed config option to
apply correctly. This fixes a bug where e.g window size
change renders next frame in updated dimensions while
native window is not scaled yet since it was waiting
for stage event to apply resize.
Signed-off-by: Marko Kungla <marko.kungla@gmail.com>
Some IME editors don't send explicit GCS_CURSORPOS messages, in
which case we should assume the cursor moves to the end of the
composition string.
Fixes: https://todo.sr.ht/~eliasnaur/gio/458
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit replaces invalid UTF8 codepoints with the replacement character
when they are inserted into the editor. This ensures that the editor never
moves the editing gap to an invalid location and reads its contents.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit adds a series of benchmarks for text rendering. They are intended
to capture the performance of static and continuously changing text within
labels and editors, and will serve as a baseline to compare the post-bidi
text stack against.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit fixes the expectations of our ligature iteration tests to
match the new behavior of the text position iterator. Now the cursor
can reach the position after the final glyph on a line, if that glyph
is not a newline.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit redefines incrementing a combinedPos to either move a single
rune forward, *or* transition from EOL->BOL, *or* both. This allows traversal
of lines without a trailing newline character to reach the position after the
final glyph of content.
Additionally, this commit updates positionGreaterOrEqual to explicitly handle
hard newlines via special-case logic, allowing lines without a hard newline to
avoid the newline-based short-circuit logic that would prevent them from iteratively
reaching the combinedPos following the final glyph on the line.
Fixes: https://todo.sr.ht/~eliasnaur/gio/400
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit adds a test for the seekPosition helper, a function which can
be used to move a combinedPos forward through a body of text until it approaches
a position.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit adds an exhaustive test case for the positionGreaterOrEqual
helper function that our text widgets use to compare locations within
shaped text.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit adds documentation and tests for the clusterIndexFor helper,
making it easier to understand what it does and how to use it safely.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit restructures seekPosition from a complex state-manipulating
loop into a simple loop of iteratively applying an increment operation
to the combinedPos. The increment operation itself is now tested, and
much easier to understand.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit switches the way in which the editor and helper functions check
for RTL text from a heuristic to using the actual text direction.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
All GPU APIs except OpenGL ES 2 can generate mipmaps for textures.
This trades 33% more GPU memory use for improved rendering quality
and speed for downscaled images.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Now, Gio will send one system.StageEvent with system.StageInactive when
the window is not active. It is implemented on macOS and Windows.
This change is not fully backward compatible, if your code compares
the Stage (`stage < system.StageRunning`), you need to consider
the new system.StageInactive.
Signed-off-by: inkeliz <inkeliz@inkeliz.com>
Before that change, Gio could crash when the WebGL context was lost
unexpectedly. Now, Gio will properly handle such situation and
recreate the buffers/resources when context is restored and will
wait until context is recovered.
Signed-off-by: Inkeliz <inkeliz@inkeliz.com>
Before this change, inverse transformations of pointer positions would
stack up, leading to incorrect positions when an enter or leave event
was delivered to multiple areas.
Signed-off-by: Dominik Honnef <dominik@honnef.co>
This commit switches the priority of EGL and Vulkan so that EGL is always
tried first. This is because our EGL backend performs significantly better
than the Vulkan one, and we want the most performant experience to be the
default.
Our hypothesis is that the EGL backend is benefitting from lots of optimization
within the OpenGL driver that Vulkan drivers expect applications to perform
themselves. Rather than invest a bunch of time optimizing the Vulkan backend
right now, this change lets us focus on other priorities.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
Bump golang/x/exp/shiny to use the specific module,
instead of using a single all-encompassing module.
This significantly reduces the number of packages in go.sum.
Unfortunately, this requires us to bump the go.mod language
version to 1.18, otherwise using `go mod tidy` and similar
tools will complain about incompatibility with module lookup
in Go 1.16. The code should still compile with 1.17.
Bump github.com/gioui/uax, which gets rid one additional unneeded
dependency and should also reduce the binary size.
Signed-off-by: Egon Elbre <egonelbre@gmail.com>
This commit adds methods to widget.Scrollbar that enable consuming
code to check if the scroll indicator is processing a drag gesture
or if the scroll track is currently being hovered. These accessors
enable scrollbar style types to have enough information to hide the
scroll indicator when it isn't needed, whereas currently they cannot
differentiate between a scrollbar indicator that is being dragged
but hasn't moved since the last frame and a scrollbar indicator that
is not being dragged.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
Window.decorations.height is supposed to be a constant during the
lifetime of the window, unlike w.decorations.Config.decoHeight that
varies depending on the decorations state (fallback or custom).
This change makes that so, fixing a problem where the fallback
decorations would fail to offset client content after a maximize
or minimize.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Before this change, the middle alignment would align according to
the widest child. This change aligns according to the widest child
or minimum constraint, whichever is largest.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Before this change, an IME text edit would always have its newlines
replaced with spaces. However, for Editors where Submit is enabled
we want newlines to result in SubmitEvents.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This reverts commit cd0c9dab9f. It turns out
that Enter/Leave is important for cancelling press-then-release-outside
for clickables.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Before that change, on Android, was impossible to overlay GioView with
a custom view. This change adds FrameLayout and renders GioView into
that, allowing to use addView from Android API.
Fixes: https://todo.sr.ht/~eliasnaur/gio/427
Signed-off-by: Inkeliz <inkeliz@inkeliz.com>
The Nix version of the macOS toolchain has difficulties compiling
Objective-C modules; disable modules instead of figuring out why.
It also doesn't include any frameworks automatically; add them explicitly.
While here, move suppression of OpenGL deprecation to a GL-specific
file.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
We used to track the pressed pointer buttons through the global function
[NSEvent pressedMouseButtons]. However, it's possible that at the time a pointer
press event is delivered, the pointer button is up again. To ensure a consistent
view of the pointer press state, track it through the buttonNumber property on
delivered events.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Previously, Gio doesn't reclaim the focus when they lose that to a
parent window. In such a case, the child window can steal
keyboard focus, and Gio will never recover it.
Now, Gio will recover the focus when clicked.
Signed-off-by: Inkeliz <inkeliz@inkeliz.com>