This is intended to address an assertion that sometimes fired during
shaping text on Android, for example when using the font "Noto Sans
Symbols" and shaping ASCII text including a line break in a multiline
text editor.
The cause of the issue seems to be that the shaper would search for
substitute fonts using the original string content, but would then
replace some characters in the string during shaping. Shaping could then
fail if the font did not contain glyphs for the replaced characters.
We now create a UTF32 string with replaced characters at the beginning
of the shaping process, and use that new string for all queries other
than unicode analysis.
Android 15+ removed the 'legacy' png-based emoji font. Modern Android
versions may include only a COLR-v1-based font, which JUCE cannot
render itself.
As a workaround, on Android, we use a Canvas object to render each emoji
glyph into a bitmap, and then render that bitmap in the same way as a
legacy png-based glyph. This won't look as crisp as rendering COLRv1
glyphs directly, especially at larger sizes, but this is a sufficient
stop-gap for the time being.
The OpenGL renderer listens for imageDataChanged() to invalidated cached
textures.
Before this change, the SimpleFFTDemo would display a static (outdated)
image on Windows when using the OpenGLRenderer.
When syncing from CPU->GPU storage, we currently copy the entire image
contents. The contents of the CPU backup completely replace the old GPU
image. Therefore, if any pixels need to retain their existing values, we
need to read those pixels before overwriting them. This in turn implies
that, when a BitmapData refers to a subsection of the image, we should
always flush GPU->CPU storage first, so that the subsequent CPU->GPU
sync doesn't clobber pixels outside of the BitmapData region with
outdated values.
It's clear that copying the entire image back and forth could be
suboptimal when writing to image subsections, but to optimise this
process we'd have to keep track of dirty image regions or similar, which
may in turn pessimise more common cases.
Previously, this code assumed that a single channel image would always
have a pixel stride of 1. For image types where this assumption did not
hold, such as OpenGL, this function would produce incorrect results.
Prior to this commit the returned values were always normalised to the
value returned by getHeightInPoints().
I.e. getAscentInPoints() + getDescentInPoints() would always equal
getHeightInPoints(), even if ascent or descent overrides were in place.
With this change in place getAscentInPoints() + getDescentInPoints()
will always equal
getHeightInPoints() * (getAscentOverride() + getDescentOverride())
JUCE classes don't use this value for layout logic, so this commit
causes no visible changes in how JUCE draws text.
This commit removes the possibility to construct BidiParagraph and
BidiLine objects with non-zero offsets. We don't use these features,
and the assumption that these offsets are always zero simplifies our
visual ordering algorithm.
Prior to this commit we overallocated the s32 buffer. The buffer was
unnecessarily padded by zeros, and the line stating this, wasn't
actually dropping the null terminator.
After reviewing the NSAttributedString API it seems justified to have
two different functions for additive and multiplicative line spacing
settings. For NSAttributedString they are setLineSpacing and
setLineHeightMultiple.
Using this function, when appropriate, exercises it lessening the
likelihood of code rot.
This makes Direct2DMetrics and current frameId accessible to implementation subclasses.
It also replaces JUCE_WRITE_TRACE_LOG with JUCE_WRITE_TRACE_LOG_VA as intended in original implementation.
Co-authored-by: Matt Gonzalez <matt@echoaudio.com>