Previously, it wasn't safe to access Font instances from multiple
threads because there was a chance that they might reference the same
shared internal state. In this case, calling getTypeface() or getAscent from
two threads simultaneously would cause a race on the typeface and ascent
data members, even though the Font instances appeared to be disjoint.
With this change in place, it is now safe to use Font instances from
multiple threads simultaneously.
It is still an error to modify the same Font instance from multiple
threads without synchronization!
// Fine:
Font a;
Font b = a;
auto futureA = std::async (std::launch::async, [&a] { /* do something with a */ });
auto futureB = std::async (std::launch::async, [&b] { /* do something with b */ });
// Bad idea:
Font f;
auto futureA = std::async (std::launch::async, [&f] { /* do something with f */ });
auto futureB = std::async (std::launch::async, [&f] { /* do something with f */ });
On Windows, calls to `createSystemTypefaceFor` with a data buffer always
create a WindowsTypeface instance. However, calls with an existing
`Font` instance may try to create a WindowsDirectWriteTypeface, and will
only fall back to using a WindowsTypeface on failure.
Previously, a missing typeface wasn't treated as a failure, which meant
that `WindowsDirectWriteTypeface` would fall back to the first usable
typeface it could find.
With this change applied, we check whether the
WindowsDirectWriteTypeface actually managed to find the font we
requested, and will fall back to using a plain WindowsTypeface in that
case.