Modern color fonts often contain both an 'SVG' and 'COLR' table. FreeType
always preferred 'SVG' over 'COLR' (this was a design decision), however,
this might not be the right choice for the user. The new flags makes
FreeType ignore the 'SVG' table while loading a glyph.
Fixes#1229.
* include/freetype/freetype.h (FT_LOAD_NO_SVG): New macro.
* src/base/ftobjs.c (FT_Load_Glyph), src/cff/cffgload.c (cff_slot_load),
src/truetype/ttgload.c (TT_Load_Glyph): Use it.
Modern compilers get more insistent on that...
* include/freetype/internal/compiler-macros.h (FALL_THROUGH): Define.
* src/*: Use it instead of `/* fall through */` comments.
Otherwise we get zillions of clang 15 warnings.
* src/autofit/afcjk.c, src/autofit/afhints.c, src/autofit/aflatin.c,
src/base/ftobjs.c, src/base/ftoutln.c, src/cff/cffparse.c,
src/raster/ftraster.c, src/sfnt/pngshim.c, src/truetype/ttgload.c,
src/truetype/ttgxvar.c, src/truetype/ttobjs.c, src/type1/t1gload.c: Use
`double` cast in debugging and tracing macros.
In `open_face_from_buffer` it is possible that a driver is requested but
FreeType was built without the requested module. Return an error in this
case to indicate that the request could not be satisfied, rather than trying
all existing driver modules.
* src/base/ftobjs.c (open_face_from_buffer): Return `FT_Err_Missing_Module`
if a driver is specified but not found.
The documentation for `FT_StreamRec::memory` states that it 'shouldn't be
touched by stream implementations'. This is true even for internal
implementations of the 'close' callback, since it is not guaranteed that
`memory` will even be set when the 'close' callback occurs.
* src/base/ftobjs.c (new_memory_stream): stash current `memory` in
`stream->descriptor`.
(memory_stream_close): Use it.
The `FT_Open_Face` documentation states
> If `FT_OPEN_STREAM` is set in `args->flags`, the stream in `args->stream`
> is automatically closed before this function returns any error (including
> `FT_Err_Invalid_Argument`).
However, if the user provides a stream in `args.stream` with
`FT_OPEN_STREAM` set and a `close` function, but then for some reason passes
NULL for `aface` and a non-negative `face_index`, the error
`Invalid_Argument` is returned but the `close` callback will not be called
on the user-provided stream. This may cause resource leaks if the caller is
depending on the `close` callback to free resources.
The difficulty is that a user may fill out a `FT_StreamRec` and pass its
address as `args.stream`, but the stream isn't really 'live' until
`FT_Stream_New` is called on it (and `memory` is set). In particular, it
cannot really be cleaned up properly in `ft_open_face_internal` until the
stream pointer has been copied into the `stream` local variable.
* src/base/ftobj.c (ft_open_face_internal): Ensure that user-provided
`args.stream.close` is called even with early errors.
`open_face_from_buffer` allocates a new `FT_Stream` to pass to
`ft_open_face_internal`. Because this is an `FT_OPEN_STREAM`,
`ft_open_face_internal` will mark this as an 'external stream', which the
caller must free. However, `open_face_from_buffer` cannot directly free it
because the stream must last as long as the face. There is currently an
attempt at this by clearing the 'external stream' bit after
`open_face_from_buffer` returns successfully. However, this is too late as
the original stream may have already been closed and the stream on the face
may not be the same stream as originally passed.
It is tempting to use `FT_OPEN_MEMORY` and let `ft_open_face_internal`
create the stream internally. However, with this method there is no means
to pass through a 'close' function to the created stream to free the
underlying data, which must be owned by the stream.
A possibility is to check on success if the stream of the face is the same
as the original stream. If it is then unset the external flag. If not,
then free the original stream. Unfortunately, while no current
implementation does so, it is possible that the face still has the original
stream somewhere other than as the `FT_FaceRec::stream`. The stream needs
to remain available for the life of the face or until it is closed,
whichever comes earlier.
The approach taken here is to let the stream own itself. When the stream is
closed it will free itself.
* src/base/ftobjs.c (memory_stream_close): Free `stream`.
(open_face_from_buffer): Simplify error handling, since
`ft_open_face_internal` always closes `args.stream` on any error.
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=54930
In `open_face` the initial stream is set on the face, along with the
information about if FreeType is the owner of the stream object itself. The
loaders may in the course of their work replace this stream with a new
stream (as is the case for 'woff' and 'woff2'), which may have a different
ownership than the initial stream object (likely the original stream object
is owned by the user and is external, while the new stream object is created
internally to FreeType and is internal). When the stream is replaced, the
face's flags are updated with the new ownership status.
However, `open_face` cannot itself free this stream as its caller
`ft_open_face_internal` is responsible for this. In addition, in the case
of an error `open_face` cannot return an actual face with the new stream and
its ownership status to the caller. As a result, it must pass this
information back to the caller as a sort of "failed face" so that the caller
can clean up.
`open_face` was already passing back the new stream but was not passing back
the stream ownership information. As a result the stream may not have been
free'd when needed.
Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=54700
* src/base/ftobjs.c (open_face): Pass back the ownership information as
well.
(ft_open_face_internal): Updated.
The division-by-zero might happen in broken fonts (see #1194).
Instead of returning a huge number from FT_DivFix and failing
to scale later, we now bail immediately.
This follows similar code in `cff_slot_done`.
* src/base/ftobjs.c (ft_glyphslot_done), src/type1/t1objs.c
(T1_GlyphSlot_Done): Check `internal` pointer.
The Type1 problems was reported as
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=50057.
This issue was discovered with an SVG based font with some documents
compressed and other uncompressed. After loading the first compressed
document the ownership flag on the glyph slot was set to true but never
set to false. As a result after loading a compressed document a glyph
from an uncompressed document would load fine, but when this glyph slot
was cleared it would try to free its document resulting in a wild free.
* src/base/ftobjs.c (ft_glyphslot_clear): clear correct flags
Fixes: #1162