Mercurial > octave
diff libinterp/corefcn/ft-text-renderer.cc @ 31607:aac27ad79be6 stable
maint: Re-indent code after switch to using namespace macros.
* build-env.h, build-env.in.cc, Cell.h, __betainc__.cc, __eigs__.cc,
__ftp__.cc, __ichol__.cc, __ilu__.cc, __isprimelarge__.cc, __magick_read__.cc,
__pchip_deriv__.cc, amd.cc, base-text-renderer.cc, base-text-renderer.h,
besselj.cc, bitfcns.cc, bsxfun.cc, c-file-ptr-stream.h, call-stack.cc,
call-stack.h, ccolamd.cc, cellfun.cc, chol.cc, colamd.cc, dasrt.cc, data.cc,
debug.cc, defaults.cc, defaults.h, det.cc, display.cc, display.h, dlmread.cc,
dynamic-ld.cc, dynamic-ld.h, ellipj.cc, environment.cc, environment.h,
error.cc, error.h, errwarn.h, event-manager.cc, event-manager.h,
event-queue.cc, event-queue.h, fcn-info.cc, fcn-info.h, fft.cc, fft2.cc,
file-io.cc, filter.cc, find.cc, ft-text-renderer.cc, ft-text-renderer.h,
gcd.cc, gl-render.cc, gl-render.h, gl2ps-print.cc, gl2ps-print.h,
graphics-toolkit.cc, graphics-toolkit.h, graphics.cc, gsvd.cc, gtk-manager.cc,
gtk-manager.h, help.cc, help.h, hook-fcn.cc, hook-fcn.h, input.cc, input.h,
interpreter-private.cc, interpreter-private.h, interpreter.cc, interpreter.h,
inv.cc, jsondecode.cc, jsonencode.cc, latex-text-renderer.cc,
latex-text-renderer.h, load-path.cc, load-path.h, load-save.cc, load-save.h,
lookup.cc, ls-hdf5.cc, ls-mat4.cc, ls-mat5.cc, lsode.cc, lu.cc, mappers.cc,
matrix_type.cc, max.cc, mex.cc, mexproto.h, mxarray.h, mxtypes.in.h,
oct-errno.in.cc, oct-hdf5-types.cc, oct-hist.cc, oct-hist.h, oct-map.cc,
oct-map.h, oct-opengl.h, oct-prcstrm.h, oct-process.cc, oct-process.h,
oct-stdstrm.h, oct-stream.cc, oct-stream.h, oct-strstrm.h,
octave-default-image.h, ordqz.cc, ordschur.cc, pager.cc, pager.h, pinv.cc,
pow2.cc, pr-output.cc, psi.cc, qr.cc, quadcc.cc, rand.cc, regexp.cc,
settings.cc, settings.h, sighandlers.cc, sighandlers.h, sparse-xpow.cc,
sqrtm.cc, stack-frame.cc, stack-frame.h, stream-euler.cc, strfns.cc, svd.cc,
syminfo.cc, syminfo.h, symrcm.cc, symrec.cc, symrec.h, symscope.cc, symscope.h,
symtab.cc, symtab.h, sysdep.cc, sysdep.h, text-engine.cc, text-engine.h,
text-renderer.cc, text-renderer.h, time.cc, toplev.cc, typecast.cc,
url-handle-manager.cc, url-handle-manager.h, urlwrite.cc, utils.cc, utils.h,
variables.cc, variables.h, xdiv.cc, __delaunayn__.cc, __init_fltk__.cc,
__init_gnuplot__.cc, __ode15__.cc, __voronoi__.cc, audioread.cc, convhulln.cc,
gzip.cc, cdef-class.cc, cdef-class.h, cdef-fwd.h, cdef-manager.cc,
cdef-manager.h, cdef-method.cc, cdef-method.h, cdef-object.cc, cdef-object.h,
cdef-package.cc, cdef-package.h, cdef-property.cc, cdef-property.h,
cdef-utils.cc, cdef-utils.h, ov-base-diag.cc, ov-base-int.cc, ov-base-mat.cc,
ov-base-mat.h, ov-base-scalar.cc, ov-base.cc, ov-base.h, ov-bool-mat.cc,
ov-bool-mat.h, ov-bool-sparse.cc, ov-bool.cc, ov-builtin.h, ov-cell.cc,
ov-ch-mat.cc, ov-class.cc, ov-class.h, ov-classdef.cc, ov-classdef.h,
ov-complex.cc, ov-cx-diag.cc, ov-cx-mat.cc, ov-cx-sparse.cc, ov-dld-fcn.cc,
ov-dld-fcn.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-fcn.h, ov-float.cc,
ov-flt-complex.cc, ov-flt-cx-diag.cc, ov-flt-cx-mat.cc, ov-flt-re-diag.cc,
ov-flt-re-mat.cc, ov-flt-re-mat.h, ov-intx.h, ov-java.cc, ov-lazy-idx.cc,
ov-legacy-range.cc, ov-magic-int.cc, ov-mex-fcn.cc, ov-mex-fcn.h,
ov-null-mat.cc, ov-perm.cc, ov-range.cc, ov-re-diag.cc, ov-re-mat.cc,
ov-re-mat.h, ov-re-sparse.cc, ov-scalar.cc, ov-str-mat.cc, ov-struct.cc,
ov-typeinfo.cc, ov-typeinfo.h, ov-usr-fcn.cc, ov-usr-fcn.h, ov.cc, ov.h, ovl.h,
octave.cc, octave.h, op-b-sbm.cc, op-bm-sbm.cc, op-cs-scm.cc, op-fm-fcm.cc,
op-fs-fcm.cc, op-s-scm.cc, op-scm-cs.cc, op-scm-s.cc, op-sm-cs.cc, ops.h,
anon-fcn-validator.cc, anon-fcn-validator.h, bp-table.cc, bp-table.h,
comment-list.cc, comment-list.h, filepos.h, lex.h, oct-lvalue.cc, oct-lvalue.h,
parse.h, profiler.cc, profiler.h, pt-anon-scopes.cc, pt-anon-scopes.h,
pt-arg-list.cc, pt-arg-list.h, pt-args-block.cc, pt-args-block.h,
pt-array-list.cc, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc,
pt-binop.h, pt-bp.cc, pt-bp.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc,
pt-cell.h, pt-check.cc, pt-check.h, pt-classdef.cc, pt-classdef.h, pt-cmd.h,
pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h,
pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h,
pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h,
pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h,
pt-pr-code.cc, pt-pr-code.h, pt-select.cc, pt-select.h, pt-spmd.cc, pt-spmd.h,
pt-stmt.cc, pt-stmt.h, pt-tm-const.cc, pt-tm-const.h, pt-unop.cc, pt-unop.h,
pt-walk.cc, pt-walk.h, pt.cc, pt.h, token.cc, token.h, Range.cc, Range.h,
idx-vector.cc, idx-vector.h, range-fwd.h, CollocWt.cc, CollocWt.h,
aepbalance.cc, aepbalance.h, chol.cc, chol.h, gepbalance.cc, gepbalance.h,
gsvd.cc, gsvd.h, hess.cc, hess.h, lo-mappers.cc, lo-mappers.h, lo-specfun.cc,
lo-specfun.h, lu.cc, lu.h, oct-convn.cc, oct-convn.h, oct-fftw.cc, oct-fftw.h,
oct-norm.cc, oct-norm.h, oct-rand.cc, oct-rand.h, oct-spparms.cc,
oct-spparms.h, qr.cc, qr.h, qrp.cc, qrp.h, randgamma.cc, randgamma.h,
randmtzig.cc, randmtzig.h, randpoisson.cc, randpoisson.h, schur.cc, schur.h,
sparse-chol.cc, sparse-chol.h, sparse-lu.cc, sparse-lu.h, sparse-qr.cc,
sparse-qr.h, svd.cc, svd.h, child-list.cc, child-list.h, dir-ops.cc, dir-ops.h,
file-ops.cc, file-ops.h, file-stat.cc, file-stat.h, lo-sysdep.cc, lo-sysdep.h,
lo-sysinfo.cc, lo-sysinfo.h, mach-info.cc, mach-info.h, oct-env.cc, oct-env.h,
oct-group.cc, oct-group.h, oct-password.cc, oct-password.h, oct-syscalls.cc,
oct-syscalls.h, oct-time.cc, oct-time.h, oct-uname.cc, oct-uname.h,
action-container.cc, action-container.h, base-list.h, cmd-edit.cc, cmd-edit.h,
cmd-hist.cc, cmd-hist.h, f77-fcn.h, file-info.cc, file-info.h,
lo-array-errwarn.cc, lo-array-errwarn.h, lo-hash.cc, lo-hash.h, lo-ieee.h,
lo-regexp.cc, lo-regexp.h, lo-utils.cc, lo-utils.h, oct-base64.cc,
oct-base64.h, oct-glob.cc, oct-glob.h, oct-inttypes.h, oct-mutex.cc,
oct-mutex.h, oct-refcount.h, oct-shlib.cc, oct-shlib.h, oct-sparse.cc,
oct-sparse.h, oct-string.h, octave-preserve-stream-state.h, pathsearch.cc,
pathsearch.h, quit.cc, quit.h, unwind-prot.cc, unwind-prot.h, url-transfer.cc,
url-transfer.h:
Re-indent code after switch to using namespace macros.
author | Rik <rik@octave.org> |
---|---|
date | Thu, 01 Dec 2022 18:02:15 -0800 |
parents | e88a07dec498 |
children | 597f3ee61a48 |
line wrap: on
line diff
--- a/libinterp/corefcn/ft-text-renderer.cc Thu Dec 01 14:23:45 2022 -0800 +++ b/libinterp/corefcn/ft-text-renderer.cc Thu Dec 01 18:02:15 2022 -0800 @@ -67,1465 +67,1465 @@ OCTAVE_BEGIN_NAMESPACE(octave) - // FIXME: maybe issue at most one warning per glyph/font/size/weight - // combination. +// FIXME: maybe issue at most one warning per glyph/font/size/weight +// combination. - static void - warn_missing_glyph (FT_ULong c) - { - warning_with_id ("Octave:missing-glyph", - "text_renderer: skipping missing glyph for character '%lx'", c); - } +static void +warn_missing_glyph (FT_ULong c) +{ + warning_with_id ("Octave:missing-glyph", + "text_renderer: skipping missing glyph for character '%lx'", c); +} - static void - warn_glyph_render (FT_ULong c) - { - warning_with_id ("Octave:glyph-render", - "text_renderer: unable to render glyph for character '%lx'", c); - } +static void +warn_glyph_render (FT_ULong c) +{ + warning_with_id ("Octave:glyph-render", + "text_renderer: unable to render glyph for character '%lx'", c); +} #if defined (_MSC_VER) - // FIXME: is this really needed? - // - // This is just a trick to avoid multiple symbol definitions. - // PermMatrix.h contains a dllexport'ed Array<octave_idx_type> - // that will cause MSVC not to generate a new instantiation and - // use the imported one instead. +// FIXME: is this really needed? +// +// This is just a trick to avoid multiple symbol definitions. +// PermMatrix.h contains a dllexport'ed Array<octave_idx_type> +// that will cause MSVC not to generate a new instantiation and +// use the imported one instead. # include "PermMatrix.h" #endif - // Forward declaration - static void ft_face_destroyed (void *object); +// Forward declaration +static void ft_face_destroyed (void *object); - class - ft_manager - { - private: +class +ft_manager +{ +private: - ft_manager (void) - : m_library (), m_freetype_initialized (false), - m_fontconfig_initialized (false) - { - if (FT_Init_FreeType (&m_library)) - error ("unable to initialize FreeType library"); - else - m_freetype_initialized = true; + ft_manager (void) + : m_library (), m_freetype_initialized (false), + m_fontconfig_initialized (false) + { + if (FT_Init_FreeType (&m_library)) + error ("unable to initialize FreeType library"); + else + m_freetype_initialized = true; #if defined (HAVE_FONTCONFIG) - if (! FcInit ()) - error ("unable to initialize fontconfig library"); - else - m_fontconfig_initialized = true; + if (! FcInit ()) + error ("unable to initialize fontconfig library"); + else + m_fontconfig_initialized = true; #endif - } + } - public: +public: - // No copying! + // No copying! - ft_manager (const ft_manager&) = delete; + ft_manager (const ft_manager&) = delete; - ft_manager& operator = (const ft_manager&) = delete; + ft_manager& operator = (const ft_manager&) = delete; - private: +private: - ~ft_manager (void) - { - if (m_freetype_initialized) - FT_Done_FreeType (m_library); + ~ft_manager (void) + { + if (m_freetype_initialized) + FT_Done_FreeType (m_library); #if defined (HAVE_FONTCONFIG) - // FIXME: Skip the call to FcFini because it can trigger the assertion - // - // octave: fccache.c:507: FcCacheFini: Assertion 'fcCacheChains[i] == ((void *)0)' failed. - // - // if (m_fontconfig_initialized) - // FcFini (); + // FIXME: Skip the call to FcFini because it can trigger the assertion + // + // octave: fccache.c:507: FcCacheFini: Assertion 'fcCacheChains[i] == ((void *)0)' failed. + // + // if (m_fontconfig_initialized) + // FcFini (); #endif - } + } - public: +public: - static bool instance_ok (void) - { - bool retval = true; + static bool instance_ok (void) + { + bool retval = true; - if (! m_instance) - { - m_instance = new ft_manager (); - singleton_cleanup_list::add (cleanup_instance); - } + if (! m_instance) + { + m_instance = new ft_manager (); + singleton_cleanup_list::add (cleanup_instance); + } - return retval; - } + return retval; + } - static void cleanup_instance (void) - { delete m_instance; m_instance = nullptr; } + static void cleanup_instance (void) + { delete m_instance; m_instance = nullptr; } - static FT_Face get_font (const std::string& name, const std::string& weight, - const std::string& angle, double size, - FT_ULong c = 0) - { - return (instance_ok () - ? m_instance->do_get_font (name, weight, angle, size, c) - : nullptr); - } + static FT_Face get_font (const std::string& name, const std::string& weight, + const std::string& angle, double size, + FT_ULong c = 0) + { + return (instance_ok () + ? m_instance->do_get_font (name, weight, angle, size, c) + : nullptr); + } - static octave_map get_system_fonts (void) - { - return (instance_ok () - ? m_instance->do_get_system_fonts () - : octave_map ()); - } + static octave_map get_system_fonts (void) + { + return (instance_ok () + ? m_instance->do_get_system_fonts () + : octave_map ()); + } - static void font_destroyed (FT_Face face) - { - if (instance_ok ()) - m_instance->do_font_destroyed (face); - } + static void font_destroyed (FT_Face face) + { + if (instance_ok ()) + m_instance->do_font_destroyed (face); + } - private: +private: - typedef std::pair<std::string, double> ft_key; - typedef std::map<ft_key, FT_Face> ft_cache; + typedef std::pair<std::string, double> ft_key; + typedef std::map<ft_key, FT_Face> ft_cache; - static octave_map do_get_system_fonts (void) - { - static octave_map font_map; + static octave_map do_get_system_fonts (void) + { + static octave_map font_map; - if (font_map.isempty ()) - { + if (font_map.isempty ()) + { #if defined (HAVE_FONTCONFIG) - FcConfig *config = FcConfigGetCurrent(); - FcPattern *pat = FcPatternCreate (); - FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, FC_SLANT, FC_WEIGHT, - FC_CHARSET, nullptr); - FcFontSet *fs = FcFontList (config, pat, os); + FcConfig *config = FcConfigGetCurrent(); + FcPattern *pat = FcPatternCreate (); + FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, FC_SLANT, FC_WEIGHT, + FC_CHARSET, nullptr); + FcFontSet *fs = FcFontList (config, pat, os); - if (fs->nfont > 0) - { - // Mark fonts that have at least all printable ASCII chars - FcCharSet *minimal_charset = FcCharSetCreate (); - for (int i = 32; i < 127; i++) - FcCharSetAddChar (minimal_charset, static_cast<FcChar32> (i)); + if (fs->nfont > 0) + { + // Mark fonts that have at least all printable ASCII chars + FcCharSet *minimal_charset = FcCharSetCreate (); + for (int i = 32; i < 127; i++) + FcCharSetAddChar (minimal_charset, static_cast<FcChar32> (i)); - string_vector fields (4); - fields(0) = "family"; - fields(1) = "angle"; - fields(2) = "weight"; - fields(3) = "suitable"; + string_vector fields (4); + fields(0) = "family"; + fields(1) = "angle"; + fields(2) = "weight"; + fields(3) = "suitable"; - dim_vector dv (1, fs->nfont); - Cell families (dv); - Cell angles (dv); - Cell weights (dv); - Cell suitable (dv); + dim_vector dv (1, fs->nfont); + Cell families (dv); + Cell angles (dv); + Cell weights (dv); + Cell suitable (dv); - unsigned char *family; - int val; - for (int i = 0; fs && i < fs->nfont; i++) - { - FcPattern *font = fs->fonts[i]; - if (FcPatternGetString (font, FC_FAMILY, 0, &family) - == FcResultMatch) - families(i) = std::string (reinterpret_cast<char *> (family)); - else - families(i) = "unknown"; + unsigned char *family; + int val; + for (int i = 0; fs && i < fs->nfont; i++) + { + FcPattern *font = fs->fonts[i]; + if (FcPatternGetString (font, FC_FAMILY, 0, &family) + == FcResultMatch) + families(i) = std::string (reinterpret_cast<char *> (family)); + else + families(i) = "unknown"; - if (FcPatternGetInteger (font, FC_SLANT, 0, &val) - == FcResultMatch) - angles(i) = (val == FC_SLANT_ITALIC - || val == FC_SLANT_OBLIQUE) - ? "italic" : "normal"; - else - angles(i) = "unknown"; + if (FcPatternGetInteger (font, FC_SLANT, 0, &val) + == FcResultMatch) + angles(i) = (val == FC_SLANT_ITALIC + || val == FC_SLANT_OBLIQUE) + ? "italic" : "normal"; + else + angles(i) = "unknown"; - if (FcPatternGetInteger (font, FC_WEIGHT, 0, &val) - == FcResultMatch) - weights(i) = (val == FC_WEIGHT_BOLD - || val == FC_WEIGHT_DEMIBOLD) - ? "bold" : "normal"; - else - weights(i) = "unknown"; + if (FcPatternGetInteger (font, FC_WEIGHT, 0, &val) + == FcResultMatch) + weights(i) = (val == FC_WEIGHT_BOLD + || val == FC_WEIGHT_DEMIBOLD) + ? "bold" : "normal"; + else + weights(i) = "unknown"; - FcCharSet *cset; - if (FcPatternGetCharSet (font, FC_CHARSET, 0, &cset) - == FcResultMatch) - suitable(i) = (FcCharSetIsSubset (minimal_charset, cset) - ? true : false); - else - suitable(i) = false; - } + FcCharSet *cset; + if (FcPatternGetCharSet (font, FC_CHARSET, 0, &cset) + == FcResultMatch) + suitable(i) = (FcCharSetIsSubset (minimal_charset, cset) + ? true : false); + else + suitable(i) = false; + } - font_map = octave_map (dv, fields); + font_map = octave_map (dv, fields); - font_map.assign ("family", families); - font_map.assign ("angle", angles); - font_map.assign ("weight", weights); - font_map.assign ("suitable", suitable); + font_map.assign ("family", families); + font_map.assign ("angle", angles); + font_map.assign ("weight", weights); + font_map.assign ("suitable", suitable); - if (fs) - FcFontSetDestroy (fs); - } + if (fs) + FcFontSetDestroy (fs); + } #endif - } + } - return font_map; - } + return font_map; + } - FT_Face do_get_font (const std::string& name, const std::string& weight, - const std::string& angle, double size, - FT_ULong search_code_point) - { - FT_Face retval = nullptr; + FT_Face do_get_font (const std::string& name, const std::string& weight, + const std::string& angle, double size, + FT_ULong search_code_point) + { + FT_Face retval = nullptr; #if defined (HAVE_FT_REFERENCE_FACE) - // Look first into the font cache, then use fontconfig. If the font - // is present in the cache, simply add a reference and return it. - - ft_key key (name + ':' + weight + ':' + angle + ':' - + std::to_string (search_code_point), size); - ft_cache::const_iterator it = m_cache.find (key); - - if (it != m_cache.end ()) - { - FT_Reference_Face (it->second); - return it->second; - } -#endif - - static std::string fonts_dir; - - if (fonts_dir.empty ()) - { - fonts_dir = sys::env::getenv ("OCTAVE_FONTS_DIR"); - - if (fonts_dir.empty ()) -#if defined (SYSTEM_FREEFONT_DIR) - fonts_dir = SYSTEM_FREEFONT_DIR; -#else - fonts_dir = config::oct_fonts_dir (); -#endif - } - - - // Default font file - std::string file; - - if (! fonts_dir.empty ()) - { - file = fonts_dir + sys::file_ops::dir_sep_str () + "FreeSans"; - - if (weight == "bold") - file += "Bold"; - - if (angle == "italic" || angle == "oblique") - file += "Oblique"; - - file += ".otf"; - } - -#if defined (HAVE_FONTCONFIG) - if ((search_code_point != 0 || name != "*") && m_fontconfig_initialized) - { - int fc_weight, fc_angle; - - if (weight == "bold") - fc_weight = FC_WEIGHT_BOLD; - else - fc_weight = FC_WEIGHT_NORMAL; + // Look first into the font cache, then use fontconfig. If the font + // is present in the cache, simply add a reference and return it. - if (angle == "italic") - fc_angle = FC_SLANT_ITALIC; - else if (angle == "oblique") - fc_angle = FC_SLANT_OBLIQUE; - else - fc_angle = FC_SLANT_ROMAN; - - FcPattern *pat = FcPatternCreate (); - - FcPatternAddString (pat, FC_FAMILY, - (reinterpret_cast<const FcChar8 *> - (name.c_str ()))); - - FcPatternAddInteger (pat, FC_WEIGHT, fc_weight); - FcPatternAddInteger (pat, FC_SLANT, fc_angle); - FcPatternAddDouble (pat, FC_PIXEL_SIZE, size); - - if (search_code_point > 0) - { - FcCharSet *minimal_charset = FcCharSetCreate (); - FcCharSetAddChar (minimal_charset, - static_cast<FcChar32> (search_code_point)); - FcPatternAddCharSet (pat, FC_CHARSET, minimal_charset); - } + ft_key key (name + ':' + weight + ':' + angle + ':' + + std::to_string (search_code_point), size); + ft_cache::const_iterator it = m_cache.find (key); - if (FcConfigSubstitute (nullptr, pat, FcMatchPattern)) - { - FcResult res; - FcPattern *match; - - FcDefaultSubstitute (pat); - - match = FcFontMatch (nullptr, pat, &res); - - // FIXME: originally, this test also required that - // res != FcResultNoMatch. Is that really needed? - if (match) - { - unsigned char *tmp; - - FcPatternGetString (match, FC_FILE, 0, &tmp); - file = reinterpret_cast<char *> (tmp); - } - else - ::warning ("could not match any font: %s-%s-%s-%g, using default font", - name.c_str (), weight.c_str (), angle.c_str (), - size); - - if (match) - FcPatternDestroy (match); - } - - FcPatternDestroy (pat); - } + if (it != m_cache.end ()) + { + FT_Reference_Face (it->second); + return it->second; + } #endif - if (file.empty ()) - ::warning ("unable to find default font files"); - else - { - std::string ascii_file = sys::get_ASCII_filename (file); - - if (FT_New_Face (m_library, ascii_file.c_str (), 0, &retval)) - ::warning ("ft_manager: unable to load font: %s", file.c_str ()); -#if defined (HAVE_FT_REFERENCE_FACE) - else - { - // Install a finalizer to notify ft_manager that the font is - // being destroyed. The class ft_manager only keeps weak - // references to font objects. + static std::string fonts_dir; - retval->generic.data = new ft_key (key); - retval->generic.finalizer = ft_face_destroyed; - - // Insert loaded font into the cache. - if (FT_Reference_Face (retval) == 0) - m_cache[key] = retval; - } -#endif - } - - return retval; - } - - void do_font_destroyed (FT_Face face) - { - if (face->generic.data) - { - ft_key *pkey = reinterpret_cast<ft_key *> (face->generic.data); + if (fonts_dir.empty ()) + { + fonts_dir = sys::env::getenv ("OCTAVE_FONTS_DIR"); - m_cache.erase (*pkey); - delete pkey; - face->generic.data = nullptr; - FT_Done_Face (face); - } - } - - //-------- - - static ft_manager *m_instance; - - // Cache the fonts loaded by FreeType. This cache only contains - // weak references to the fonts, strong references are only present - // in class text_renderer. - ft_cache m_cache; - - FT_Library m_library; - bool m_freetype_initialized; - bool m_fontconfig_initialized; - }; + if (fonts_dir.empty ()) +#if defined (SYSTEM_FREEFONT_DIR) + fonts_dir = SYSTEM_FREEFONT_DIR; +#else + fonts_dir = config::oct_fonts_dir (); +#endif + } - ft_manager *ft_manager::m_instance = nullptr; - - static void - ft_face_destroyed (void *object) - { - ft_manager::font_destroyed (reinterpret_cast<FT_Face> (object)); - } - - class - OCTINTERP_API - ft_text_renderer : public base_text_renderer - { - public: - - enum - { - MODE_BBOX = 0, - MODE_RENDER = 1 - }; - - public: - ft_text_renderer (void) - : base_text_renderer (), m_font (), m_bbox (1, 4, 0.0), m_halign (0), - m_xoffset (0), m_line_yoffset (0), m_yoffset (0), m_mode (MODE_BBOX), - m_color (dim_vector (1, 3), 0), m_do_strlist (false), m_strlist (), - m_line_xoffset (0), m_ymin (0), m_ymax (0), m_deltax (0), - m_max_fontsize (0), m_antialias (true) - { } - - // No copying! - - ft_text_renderer (const ft_text_renderer&) = delete; - - ft_text_renderer& operator = (const ft_text_renderer&) = delete; - - ~ft_text_renderer (void) = default; - - void visit (text_element_string& e); - - void visit (text_element_list& e); - - void visit (text_element_subscript& e); + // Default font file + std::string file; - void visit (text_element_superscript& e); - - void visit (text_element_color& e); - - void visit (text_element_fontsize& e); - - void visit (text_element_fontname& e); - - void visit (text_element_fontstyle& e); - - void visit (text_element_symbol& e); - - void visit (text_element_combined& e); - - void reset (void); - - uint8NDArray get_pixels (void) const { return m_pixels; } - - Matrix get_boundingbox (void) const { return m_bbox; } - - uint8NDArray render (text_element *elt, Matrix& box, - int rotation = ROTATION_0); + if (! fonts_dir.empty ()) + { + file = fonts_dir + sys::file_ops::dir_sep_str () + "FreeSans"; - Matrix get_extent (text_element *elt, double rotation = 0.0); - Matrix get_extent (const std::string& txt, double rotation, - const caseless_str& interpreter); - - void set_anti_aliasing (bool val) { m_antialias = val; }; - - void set_font (const std::string& name, const std::string& weight, - const std::string& angle, double size); - - octave_map get_system_fonts (void); - - void set_color (const Matrix& c); - - void set_mode (int m); - - void text_to_pixels (const std::string& txt, - uint8NDArray& pxls, Matrix& bbox, - int halign, int valign, double rotation, - const caseless_str& interpreter, - bool handle_rotation); + if (weight == "bold") + file += "Bold"; - private: - - // Class to hold information about fonts and a strong - // reference to the font objects loaded by FreeType. - - class ft_font : public text_renderer::font - { - public: - - ft_font (void) - : text_renderer::font (), m_face (nullptr) { } + if (angle == "italic" || angle == "oblique") + file += "Oblique"; - ft_font (const std::string& nm, const std::string& wt, - const std::string& ang, double sz, FT_Face f = nullptr) - : text_renderer::font (nm, wt, ang, sz), m_face (f) - { } - - ft_font (const ft_font& ft); - - ~ft_font (void) - { - if (m_face) - FT_Done_Face (m_face); + file += ".otf"; } - ft_font& operator = (const ft_font& ft); - - bool is_valid (void) const { return get_face (); } - - FT_Face get_face (void) const; - - private: - - mutable FT_Face m_face; - }; +#if defined (HAVE_FONTCONFIG) + if ((search_code_point != 0 || name != "*") && m_fontconfig_initialized) + { + int fc_weight, fc_angle; - void push_new_line (void); - - void update_line_bbox (void); - - void compute_bbox (void); + if (weight == "bold") + fc_weight = FC_WEIGHT_BOLD; + else + fc_weight = FC_WEIGHT_NORMAL; - int compute_line_xoffset (const Matrix& lb) const; + if (angle == "italic") + fc_angle = FC_SLANT_ITALIC; + else if (angle == "oblique") + fc_angle = FC_SLANT_OBLIQUE; + else + fc_angle = FC_SLANT_ROMAN; - FT_UInt process_character (FT_ULong code, FT_UInt previous, - std::string& sub_font); - - public: + FcPattern *pat = FcPatternCreate (); - void text_to_strlist (const std::string& txt, - std::list<text_renderer::string>& lst, Matrix& bbox, - int halign, int valign, double rotation, - const caseless_str& interp); + FcPatternAddString (pat, FC_FAMILY, + (reinterpret_cast<const FcChar8 *> + (name.c_str ()))); - private: - - // The current font used by the renderer. - ft_font m_font; + FcPatternAddInteger (pat, FC_WEIGHT, fc_weight); + FcPatternAddInteger (pat, FC_SLANT, fc_angle); + FcPatternAddDouble (pat, FC_PIXEL_SIZE, size); - // Used to stored the bounding box corresponding to the rendered text. - // The bounding box has the form [x, y, w, h] where x and y represent the - // coordinates of the bottom left corner relative to the anchor point of - // the text (== start of text on the baseline). Due to font descent or - // multiple lines, the value y is usually negative. - Matrix m_bbox; + if (search_code_point > 0) + { + FcCharSet *minimal_charset = FcCharSetCreate (); + FcCharSetAddChar (minimal_charset, + static_cast<FcChar32> (search_code_point)); + FcPatternAddCharSet (pat, FC_CHARSET, minimal_charset); + } - // Used to stored the rendered text. It's a 3D matrix with size MxNx4 - // where M and N are the width and height of the bounding box. - uint8NDArray m_pixels; + if (FcConfigSubstitute (nullptr, pat, FcMatchPattern)) + { + FcResult res; + FcPattern *match; - // Used to store the bounding box of each line. This is used to layout - // multiline text properly. - std::list<Matrix> m_line_bbox; + FcDefaultSubstitute (pat); - // The current horizontal alignment. This is used to align multi-line text. - int m_halign; + match = FcFontMatch (nullptr, pat, &res); - // The X offset for the next glyph. - int m_xoffset; - - // The Y offset of the baseline for the current line. - int m_line_yoffset; - - // The Y offset of the baseline for the next glyph. The offset is relative - // to line_yoffset. The total Y offset is computed with: - // line_yoffset + yoffset. - int m_yoffset; + // FIXME: originally, this test also required that + // res != FcResultNoMatch. Is that really needed? + if (match) + { + unsigned char *tmp; - // The current mode of the rendering process (box computing or rendering). - int m_mode; - - // The base color of the rendered text. - uint8NDArray m_color; + FcPatternGetString (match, FC_FILE, 0, &tmp); + file = reinterpret_cast<char *> (tmp); + } + else + ::warning ("could not match any font: %s-%s-%s-%g, using default font", + name.c_str (), weight.c_str (), angle.c_str (), + size); - // A list of parsed strings to be used for printing. - bool m_do_strlist; - std::list<text_renderer::string> m_strlist; + if (match) + FcPatternDestroy (match); + } - // The X offset of the baseline for the current line. - int m_line_xoffset; + FcPatternDestroy (pat); + } +#endif - // Min and max y coordinates of all glyphs in a line. - FT_Pos m_ymin; - FT_Pos m_ymax; - - // Difference between the advance and the actual extent of the latest glyph - FT_Pos m_deltax; - - // Used for computing the distance between lines. - double m_max_fontsize; - - // Anti-aliasing. - bool m_antialias; + if (file.empty ()) + ::warning ("unable to find default font files"); + else + { + std::string ascii_file = sys::get_ASCII_filename (file); - }; + if (FT_New_Face (m_library, ascii_file.c_str (), 0, &retval)) + ::warning ("ft_manager: unable to load font: %s", file.c_str ()); +#if defined (HAVE_FT_REFERENCE_FACE) + else + { + // Install a finalizer to notify ft_manager that the font is + // being destroyed. The class ft_manager only keeps weak + // references to font objects. - void - ft_text_renderer::set_font (const std::string& name, - const std::string& weight, - const std::string& angle, double size) - { - // FIXME: take "fontunits" into account - m_font = ft_font (name, weight, angle, size, nullptr); - } + retval->generic.data = new ft_key (key); + retval->generic.finalizer = ft_face_destroyed; - octave_map - ft_text_renderer::get_system_fonts (void) - { - return ft_manager::get_system_fonts (); + // Insert loaded font into the cache. + if (FT_Reference_Face (retval) == 0) + m_cache[key] = retval; + } +#endif + } + + return retval; } - void - ft_text_renderer::push_new_line (void) + void do_font_destroyed (FT_Face face) { - switch (m_mode) - { - case MODE_BBOX: - { - // Create a new bbox entry based on the current font. - - FT_Face face = m_font.get_face (); - - if (face) - { - Matrix bb (1, 5, 0.0); - - m_line_bbox.push_back (bb); - - m_xoffset = m_yoffset = 0; - m_ymin = m_ymax = m_deltax = 0; - } - } - break; - - case MODE_RENDER: - { - // Move to the next line bbox, adjust xoffset based on alignment - // and yoffset based on the old and new line bbox. - - Matrix old_bbox = m_line_bbox.front (); - m_line_bbox.pop_front (); - Matrix new_bbox = m_line_bbox.front (); - - m_xoffset = m_line_xoffset = compute_line_xoffset (new_bbox); - m_line_yoffset -= (-old_bbox(1) + math::round (0.4 * m_max_fontsize) - + (new_bbox(3) + new_bbox(1))); - m_yoffset = 0; - m_ymin = m_ymax = m_deltax = 0; - } - break; - } - } - - int - ft_text_renderer::compute_line_xoffset (const Matrix& lb) const - { - if (! m_bbox.isempty ()) + if (face->generic.data) { - switch (m_halign) - { - case 0: - return 0; - case 1: - return (m_bbox(2) - lb(2)) / 2; - case 2: - return (m_bbox(2) - lb(2)); - } - } - - return 0; - } - - void - ft_text_renderer::compute_bbox (void) - { - // Stack the various line bbox together and compute the final - // bounding box for the entire text string. - - m_bbox = Matrix (); - - switch (m_line_bbox.size ()) - { - case 0: - break; - - case 1: - m_bbox = m_line_bbox.front ().extract (0, 0, 0, 3); - break; + ft_key *pkey = reinterpret_cast<ft_key *> (face->generic.data); - default: - for (const auto& lbox : m_line_bbox) - { - if (m_bbox.isempty ()) - m_bbox = lbox.extract (0, 0, 0, 3); - else - { - double delta = math::round (0.4 * m_max_fontsize) + lbox(3); - m_bbox(1) -= delta; - m_bbox(3) += delta; - m_bbox(2) = math::max (m_bbox(2), lbox(2)); - } - } - break; - } - } - - void - ft_text_renderer::update_line_bbox (void) - { - // Called after a font change, when in MODE_BBOX mode, to update the - // current line bbox with the new font metrics. This also includes the - // current yoffset, that is the offset of the current glyph's baseline - // the line's baseline. - - if (m_mode == MODE_BBOX) - { - Matrix& bb = m_line_bbox.back (); - bb(1) = m_ymin; - // Add one pixel to the bbox height to avoid occasional text clipping. - // See bug #55328. - bb(3) = (m_ymax + 1) - m_ymin; - if (m_deltax > 0) - bb(2) += m_deltax; + m_cache.erase (*pkey); + delete pkey; + face->generic.data = nullptr; + FT_Done_Face (face); } } - void - ft_text_renderer::set_mode (int m) + //-------- + + static ft_manager *m_instance; + + // Cache the fonts loaded by FreeType. This cache only contains + // weak references to the fonts, strong references are only present + // in class text_renderer. + ft_cache m_cache; + + FT_Library m_library; + bool m_freetype_initialized; + bool m_fontconfig_initialized; +}; + +ft_manager *ft_manager::m_instance = nullptr; + +static void +ft_face_destroyed (void *object) +{ + ft_manager::font_destroyed (reinterpret_cast<FT_Face> (object)); +} + +class +OCTINTERP_API +ft_text_renderer : public base_text_renderer +{ +public: + + enum + { + MODE_BBOX = 0, + MODE_RENDER = 1 + }; + +public: + + ft_text_renderer (void) + : base_text_renderer (), m_font (), m_bbox (1, 4, 0.0), m_halign (0), + m_xoffset (0), m_line_yoffset (0), m_yoffset (0), m_mode (MODE_BBOX), + m_color (dim_vector (1, 3), 0), m_do_strlist (false), m_strlist (), + m_line_xoffset (0), m_ymin (0), m_ymax (0), m_deltax (0), + m_max_fontsize (0), m_antialias (true) + { } + + // No copying! + + ft_text_renderer (const ft_text_renderer&) = delete; + + ft_text_renderer& operator = (const ft_text_renderer&) = delete; + + ~ft_text_renderer (void) = default; + + void visit (text_element_string& e); + + void visit (text_element_list& e); + + void visit (text_element_subscript& e); + + void visit (text_element_superscript& e); + + void visit (text_element_color& e); + + void visit (text_element_fontsize& e); + + void visit (text_element_fontname& e); + + void visit (text_element_fontstyle& e); + + void visit (text_element_symbol& e); + + void visit (text_element_combined& e); + + void reset (void); + + uint8NDArray get_pixels (void) const { return m_pixels; } + + Matrix get_boundingbox (void) const { return m_bbox; } + + uint8NDArray render (text_element *elt, Matrix& box, + int rotation = ROTATION_0); + + Matrix get_extent (text_element *elt, double rotation = 0.0); + Matrix get_extent (const std::string& txt, double rotation, + const caseless_str& interpreter); + + void set_anti_aliasing (bool val) { m_antialias = val; }; + + void set_font (const std::string& name, const std::string& weight, + const std::string& angle, double size); + + octave_map get_system_fonts (void); + + void set_color (const Matrix& c); + + void set_mode (int m); + + void text_to_pixels (const std::string& txt, + uint8NDArray& pxls, Matrix& bbox, + int halign, int valign, double rotation, + const caseless_str& interpreter, + bool handle_rotation); + +private: + + // Class to hold information about fonts and a strong + // reference to the font objects loaded by FreeType. + + class ft_font : public text_renderer::font { - m_mode = m; + public: + + ft_font (void) + : text_renderer::font (), m_face (nullptr) { } + + ft_font (const std::string& nm, const std::string& wt, + const std::string& ang, double sz, FT_Face f = nullptr) + : text_renderer::font (nm, wt, ang, sz), m_face (f) + { } + + ft_font (const ft_font& ft); + + ~ft_font (void) + { + if (m_face) + FT_Done_Face (m_face); + } + + ft_font& operator = (const ft_font& ft); + + bool is_valid (void) const { return get_face (); } + + FT_Face get_face (void) const; + + private: + + mutable FT_Face m_face; + }; + + void push_new_line (void); + + void update_line_bbox (void); + + void compute_bbox (void); + + int compute_line_xoffset (const Matrix& lb) const; + + FT_UInt process_character (FT_ULong code, FT_UInt previous, + std::string& sub_font); + +public: + + void text_to_strlist (const std::string& txt, + std::list<text_renderer::string>& lst, Matrix& bbox, + int halign, int valign, double rotation, + const caseless_str& interp); + +private: + + // The current font used by the renderer. + ft_font m_font; + + // Used to stored the bounding box corresponding to the rendered text. + // The bounding box has the form [x, y, w, h] where x and y represent the + // coordinates of the bottom left corner relative to the anchor point of + // the text (== start of text on the baseline). Due to font descent or + // multiple lines, the value y is usually negative. + Matrix m_bbox; + + // Used to stored the rendered text. It's a 3D matrix with size MxNx4 + // where M and N are the width and height of the bounding box. + uint8NDArray m_pixels; - switch (m_mode) + // Used to store the bounding box of each line. This is used to layout + // multiline text properly. + std::list<Matrix> m_line_bbox; + + // The current horizontal alignment. This is used to align multi-line text. + int m_halign; + + // The X offset for the next glyph. + int m_xoffset; + + // The Y offset of the baseline for the current line. + int m_line_yoffset; + + // The Y offset of the baseline for the next glyph. The offset is relative + // to line_yoffset. The total Y offset is computed with: + // line_yoffset + yoffset. + int m_yoffset; + + // The current mode of the rendering process (box computing or rendering). + int m_mode; + + // The base color of the rendered text. + uint8NDArray m_color; + + // A list of parsed strings to be used for printing. + bool m_do_strlist; + std::list<text_renderer::string> m_strlist; + + // The X offset of the baseline for the current line. + int m_line_xoffset; + + // Min and max y coordinates of all glyphs in a line. + FT_Pos m_ymin; + FT_Pos m_ymax; + + // Difference between the advance and the actual extent of the latest glyph + FT_Pos m_deltax; + + // Used for computing the distance between lines. + double m_max_fontsize; + + // Anti-aliasing. + bool m_antialias; + +}; + +void +ft_text_renderer::set_font (const std::string& name, + const std::string& weight, + const std::string& angle, double size) +{ + // FIXME: take "fontunits" into account + m_font = ft_font (name, weight, angle, size, nullptr); +} + +octave_map +ft_text_renderer::get_system_fonts (void) +{ + return ft_manager::get_system_fonts (); +} + +void +ft_text_renderer::push_new_line (void) +{ + switch (m_mode) + { + case MODE_BBOX: { - case MODE_BBOX: - m_xoffset = m_line_yoffset = m_yoffset = 0; - m_max_fontsize = 0.0; - m_bbox = Matrix (1, 4, 0.0); - m_line_bbox.clear (); - push_new_line (); - break; + // Create a new bbox entry based on the current font. + + FT_Face face = m_font.get_face (); - case MODE_RENDER: - if (m_bbox.numel () != 4) + if (face) { - ::error ("ft_text_renderer: invalid bounding box, cannot render"); + Matrix bb (1, 5, 0.0); - m_xoffset = m_line_yoffset = m_yoffset = 0; - m_pixels = uint8NDArray (); + m_line_bbox.push_back (bb); + + m_xoffset = m_yoffset = 0; + m_ymin = m_ymax = m_deltax = 0; } - else - { - dim_vector d (4, octave_idx_type (m_bbox(2)), - octave_idx_type (m_bbox(3))); - m_pixels = uint8NDArray (d, static_cast<uint8_t> (0)); - m_xoffset = compute_line_xoffset (m_line_bbox.front ()); - m_line_yoffset = -m_bbox(1); - m_yoffset = 0; - } - break; + } + break; + + case MODE_RENDER: + { + // Move to the next line bbox, adjust xoffset based on alignment + // and yoffset based on the old and new line bbox. - default: - error ("ft_text_renderer: invalid mode '%d'", m_mode); - break; - } - } + Matrix old_bbox = m_line_bbox.front (); + m_line_bbox.pop_front (); + Matrix new_bbox = m_line_bbox.front (); - bool is_opaque (const FT_GlyphSlot& glyph, const int x, const int y) - { - // Borrowed from https://stackoverflow.com/questions/14800827/ - // indexing-pixels-in-a-monochrome-freetype-glyph-buffer - int pitch = std::abs (glyph->bitmap.pitch); - unsigned char *row = &glyph->bitmap.buffer[pitch * y]; - char cvalue = row[x >> 3]; + m_xoffset = m_line_xoffset = compute_line_xoffset (new_bbox); + m_line_yoffset -= (-old_bbox(1) + math::round (0.4 * m_max_fontsize) + + (new_bbox(3) + new_bbox(1))); + m_yoffset = 0; + m_ymin = m_ymax = m_deltax = 0; + } + break; + } +} - return ((cvalue & (128 >> (x & 7))) != 0); - } +int +ft_text_renderer::compute_line_xoffset (const Matrix& lb) const +{ + if (! m_bbox.isempty ()) + { + switch (m_halign) + { + case 0: + return 0; + case 1: + return (m_bbox(2) - lb(2)) / 2; + case 2: + return (m_bbox(2) - lb(2)); + } + } + + return 0; +} + +void +ft_text_renderer::compute_bbox (void) +{ + // Stack the various line bbox together and compute the final + // bounding box for the entire text string. + + m_bbox = Matrix (); - FT_UInt - ft_text_renderer::process_character (FT_ULong code, FT_UInt previous, - std::string& sub_name) - { - FT_Face face = m_font.get_face (); + switch (m_line_bbox.size ()) + { + case 0: + break; + + case 1: + m_bbox = m_line_bbox.front ().extract (0, 0, 0, 3); + break; - sub_name = face->family_name; + default: + for (const auto& lbox : m_line_bbox) + { + if (m_bbox.isempty ()) + m_bbox = lbox.extract (0, 0, 0, 3); + else + { + double delta = math::round (0.4 * m_max_fontsize) + lbox(3); + m_bbox(1) -= delta; + m_bbox(3) += delta; + m_bbox(2) = math::max (m_bbox(2), lbox(2)); + } + } + break; + } +} + +void +ft_text_renderer::update_line_bbox (void) +{ + // Called after a font change, when in MODE_BBOX mode, to update the + // current line bbox with the new font metrics. This also includes the + // current yoffset, that is the offset of the current glyph's baseline + // the line's baseline. - FT_UInt glyph_index = 0; + if (m_mode == MODE_BBOX) + { + Matrix& bb = m_line_bbox.back (); + bb(1) = m_ymin; + // Add one pixel to the bbox height to avoid occasional text clipping. + // See bug #55328. + bb(3) = (m_ymax + 1) - m_ymin; + if (m_deltax > 0) + bb(2) += m_deltax; + } +} + +void +ft_text_renderer::set_mode (int m) +{ + m_mode = m; + + switch (m_mode) + { + case MODE_BBOX: + m_xoffset = m_line_yoffset = m_yoffset = 0; + m_max_fontsize = 0.0; + m_bbox = Matrix (1, 4, 0.0); + m_line_bbox.clear (); + push_new_line (); + break; + + case MODE_RENDER: + if (m_bbox.numel () != 4) + { + ::error ("ft_text_renderer: invalid bounding box, cannot render"); - if (face) - { - glyph_index = FT_Get_Char_Index (face, code); + m_xoffset = m_line_yoffset = m_yoffset = 0; + m_pixels = uint8NDArray (); + } + else + { + dim_vector d (4, octave_idx_type (m_bbox(2)), + octave_idx_type (m_bbox(3))); + m_pixels = uint8NDArray (d, static_cast<uint8_t> (0)); + m_xoffset = compute_line_xoffset (m_line_bbox.front ()); + m_line_yoffset = -m_bbox(1); + m_yoffset = 0; + } + break; + + default: + error ("ft_text_renderer: invalid mode '%d'", m_mode); + break; + } +} - if (code != '\n' && code != '\t' - && (! glyph_index - || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))) - { +bool is_opaque (const FT_GlyphSlot& glyph, const int x, const int y) +{ + // Borrowed from https://stackoverflow.com/questions/14800827/ + // indexing-pixels-in-a-monochrome-freetype-glyph-buffer + int pitch = std::abs (glyph->bitmap.pitch); + unsigned char *row = &glyph->bitmap.buffer[pitch * y]; + char cvalue = row[x >> 3]; + + return ((cvalue & (128 >> (x & 7))) != 0); +} + +FT_UInt +ft_text_renderer::process_character (FT_ULong code, FT_UInt previous, + std::string& sub_name) +{ + FT_Face face = m_font.get_face (); + + sub_name = face->family_name; + + FT_UInt glyph_index = 0; + + if (face) + { + glyph_index = FT_Get_Char_Index (face, code); + + if (code != '\n' && code != '\t' + && (! glyph_index + || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))) + { #if defined (HAVE_FONTCONFIG) - // Try to substitue font - FT_Face sub_face = ft_manager::get_font (m_font.get_name (), - m_font.get_weight (), - m_font.get_angle (), - m_font.get_size (), - code); + // Try to substitue font + FT_Face sub_face = ft_manager::get_font (m_font.get_name (), + m_font.get_weight (), + m_font.get_angle (), + m_font.get_size (), + code); + + if (sub_face) + { + FT_Set_Char_Size (sub_face, 0, m_font.get_size ()*64, 0, 0); + + glyph_index = FT_Get_Char_Index (sub_face, code); - if (sub_face) - { - FT_Set_Char_Size (sub_face, 0, m_font.get_size ()*64, 0, 0); + if (glyph_index + && (FT_Load_Glyph (sub_face, glyph_index, FT_LOAD_DEFAULT) + == 0)) + { + static std::string prev_sub_name; - glyph_index = FT_Get_Char_Index (sub_face, code); + if (prev_sub_name.empty () + || prev_sub_name != std::string (sub_face->family_name)) + { + prev_sub_name = sub_face->family_name; + warning_with_id ("Octave:substituted-glyph", + "text_renderer: substituting font to '%s' for some characters", + sub_face->family_name); + } + + ft_font saved_font = m_font; + + m_font = ft_font (m_font.get_name (), m_font.get_weight (), + m_font.get_angle (), m_font.get_size (), + sub_face); + + process_character (code, previous, sub_name); - if (glyph_index - && (FT_Load_Glyph (sub_face, glyph_index, FT_LOAD_DEFAULT) - == 0)) - { - static std::string prev_sub_name; + m_font = saved_font; + } + else + { + glyph_index = 0; + warn_missing_glyph (code); + } + } + else + { + glyph_index = 0; + warn_missing_glyph (code); + } +#else + glyph_index = 0; + warn_missing_glyph (code); +#endif + } + else if ((code == '\n') || (code == '\t')) + { + glyph_index = FT_Get_Char_Index (face, ' '); + if (! glyph_index + || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) + { + glyph_index = 0; + warn_missing_glyph (' '); + } + else if (code == '\n') + push_new_line (); + else + { + // Advance to next multiple of 4 times the width of the "space" + // character. + int x_tab = 4 * (face->glyph->advance.x >> 6); + m_xoffset = (1 + std::floor (1. * m_xoffset / x_tab)) * x_tab; + } + } + else + { + switch (m_mode) + { + case MODE_RENDER: + if (FT_Render_Glyph (face->glyph, (m_antialias + ? FT_RENDER_MODE_NORMAL + : FT_RENDER_MODE_MONO))) + { + glyph_index = 0; + warn_glyph_render (code); + } + else + { + FT_Bitmap& bitmap = face->glyph->bitmap; + int x0, y0; - if (prev_sub_name.empty () - || prev_sub_name != std::string (sub_face->family_name)) + if (previous) + { + FT_Vector delta; + + FT_Get_Kerning (face, previous, glyph_index, + FT_KERNING_DEFAULT, &delta); + + m_xoffset += (delta.x >> 6); + } + + x0 = m_xoffset + face->glyph->bitmap_left; + y0 = m_line_yoffset + m_yoffset + + (face->glyph->bitmap_top - 1); + + // 'w' seems to have a negative -1 + // face->glyph->bitmap_left, this is so we don't index out + // of bound, and assumes we've allocated the right amount of + // horizontal space in the bbox. + if (x0 < 0) + x0 = 0; + + for (int r = 0; static_cast<unsigned int> (r) < bitmap.rows; r++) + for (int c = 0; static_cast<unsigned int> (c) < bitmap.width; c++) { - prev_sub_name = sub_face->family_name; - warning_with_id ("Octave:substituted-glyph", - "text_renderer: substituting font to '%s' for some characters", - sub_face->family_name); + unsigned char pix + = (m_antialias + ? bitmap.buffer[r*bitmap.width+c] + : (is_opaque (face->glyph, c, r) ? 255 : 0)); + + if (x0+c < 0 || x0+c >= m_pixels.dim2 () + || y0-r < 0 || y0-r >= m_pixels.dim3 ()) + { + // ::warning ("ft_text_renderer: x %d, y %d", + // x0+c, y0-r); + } + else if (m_pixels(3, x0+c, y0-r).value () == 0) + { + m_pixels(0, x0+c, y0-r) = m_color(0); + m_pixels(1, x0+c, y0-r) = m_color(1); + m_pixels(2, x0+c, y0-r) = m_color(2); + m_pixels(3, x0+c, y0-r) = pix; + } } - ft_font saved_font = m_font; + m_xoffset += (face->glyph->advance.x >> 6); + } + break; - m_font = ft_font (m_font.get_name (), m_font.get_weight (), - m_font.get_angle (), m_font.get_size (), - sub_face); - - process_character (code, previous, sub_name); + case MODE_BBOX: + Matrix& bb = m_line_bbox.back (); - m_font = saved_font; - } - else - { - glyph_index = 0; - warn_missing_glyph (code); - } - } - else - { - glyph_index = 0; - warn_missing_glyph (code); - } -#else - glyph_index = 0; - warn_missing_glyph (code); -#endif - } - else if ((code == '\n') || (code == '\t')) - { - glyph_index = FT_Get_Char_Index (face, ' '); - if (! glyph_index - || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) - { - glyph_index = 0; - warn_missing_glyph (' '); - } - else if (code == '\n') - push_new_line (); - else - { - // Advance to next multiple of 4 times the width of the "space" - // character. - int x_tab = 4 * (face->glyph->advance.x >> 6); - m_xoffset = (1 + std::floor (1. * m_xoffset / x_tab)) * x_tab; - } - } - else - { - switch (m_mode) - { - case MODE_RENDER: - if (FT_Render_Glyph (face->glyph, (m_antialias - ? FT_RENDER_MODE_NORMAL - : FT_RENDER_MODE_MONO))) - { - glyph_index = 0; - warn_glyph_render (code); - } - else - { - FT_Bitmap& bitmap = face->glyph->bitmap; - int x0, y0; + // If we have a previous glyph, use kerning information. This + // usually means moving a bit backward before adding the next + // glyph. That is, "delta.x" is usually < 0. + if (previous) + { + FT_Vector delta; - if (previous) - { - FT_Vector delta; + FT_Get_Kerning (face, previous, glyph_index, + FT_KERNING_DEFAULT, &delta); - FT_Get_Kerning (face, previous, glyph_index, - FT_KERNING_DEFAULT, &delta); - - m_xoffset += (delta.x >> 6); - } + m_xoffset += (delta.x >> 6); + } - x0 = m_xoffset + face->glyph->bitmap_left; - y0 = m_line_yoffset + m_yoffset - + (face->glyph->bitmap_top - 1); + // Extend current X offset box by the width of the current + // glyph. Then extend the line bounding box if necessary. - // 'w' seems to have a negative -1 - // face->glyph->bitmap_left, this is so we don't index out - // of bound, and assumes we've allocated the right amount of - // horizontal space in the bbox. - if (x0 < 0) - x0 = 0; + m_xoffset += (face->glyph->advance.x >> 6); + bb(2) = math::max (bb(2), m_xoffset); - for (int r = 0; static_cast<unsigned int> (r) < bitmap.rows; r++) - for (int c = 0; static_cast<unsigned int> (c) < bitmap.width; c++) - { - unsigned char pix - = (m_antialias - ? bitmap.buffer[r*bitmap.width+c] - : (is_opaque (face->glyph, c, r) ? 255 : 0)); - - if (x0+c < 0 || x0+c >= m_pixels.dim2 () - || y0-r < 0 || y0-r >= m_pixels.dim3 ()) - { - // ::warning ("ft_text_renderer: x %d, y %d", - // x0+c, y0-r); - } - else if (m_pixels(3, x0+c, y0-r).value () == 0) - { - m_pixels(0, x0+c, y0-r) = m_color(0); - m_pixels(1, x0+c, y0-r) = m_color(1); - m_pixels(2, x0+c, y0-r) = m_color(2); - m_pixels(3, x0+c, y0-r) = pix; - } - } - - m_xoffset += (face->glyph->advance.x >> 6); - } - break; - - case MODE_BBOX: - Matrix& bb = m_line_bbox.back (); - - // If we have a previous glyph, use kerning information. This - // usually means moving a bit backward before adding the next - // glyph. That is, "delta.x" is usually < 0. - if (previous) - { - FT_Vector delta; - - FT_Get_Kerning (face, previous, glyph_index, - FT_KERNING_DEFAULT, &delta); - - m_xoffset += (delta.x >> 6); - } + // Store the actual bbox vertical coordinates of this character + FT_Glyph glyph; + if (FT_Get_Glyph (face->glyph, &glyph)) + warn_glyph_render (code); + else + { + FT_BBox glyph_bbox; + FT_Glyph_Get_CBox (glyph, FT_GLYPH_BBOX_UNSCALED, + &glyph_bbox); + m_deltax = (glyph_bbox.xMax - face->glyph->advance.x) >> 6; + m_ymin = math::min ((glyph_bbox.yMin >> 6) + m_yoffset, + m_ymin); + m_ymax = math::max ((glyph_bbox.yMax >> 6) + m_yoffset, + m_ymax); + FT_Done_Glyph (glyph); + update_line_bbox (); + } + break; + } + } + } - // Extend current X offset box by the width of the current - // glyph. Then extend the line bounding box if necessary. - - m_xoffset += (face->glyph->advance.x >> 6); - bb(2) = math::max (bb(2), m_xoffset); + return glyph_index; +} - // Store the actual bbox vertical coordinates of this character - FT_Glyph glyph; - if (FT_Get_Glyph (face->glyph, &glyph)) - warn_glyph_render (code); - else - { - FT_BBox glyph_bbox; - FT_Glyph_Get_CBox (glyph, FT_GLYPH_BBOX_UNSCALED, - &glyph_bbox); - m_deltax = (glyph_bbox.xMax - face->glyph->advance.x) >> 6; - m_ymin = math::min ((glyph_bbox.yMin >> 6) + m_yoffset, - m_ymin); - m_ymax = math::max ((glyph_bbox.yMax >> 6) + m_yoffset, - m_ymax); - FT_Done_Glyph (glyph); - update_line_bbox (); - } - break; - } - } - } +void +ft_text_renderer::text_to_strlist (const std::string& txt, + std::list<text_renderer::string>& lst, + Matrix& box, + int ha, int va, double rot, + const caseless_str& interp) +{ + uint8NDArray pxls; - return glyph_index; - } + // First run text_to_pixels which will also build the string list - void - ft_text_renderer::text_to_strlist (const std::string& txt, - std::list<text_renderer::string>& lst, - Matrix& box, - int ha, int va, double rot, - const caseless_str& interp) - { - uint8NDArray pxls; + m_strlist = std::list<text_renderer::string> (); - // First run text_to_pixels which will also build the string list - - m_strlist = std::list<text_renderer::string> (); - - unwind_protect_var<bool> restore_var1 (m_do_strlist); - unwind_protect_var<std::list<text_renderer::string>> + unwind_protect_var<bool> restore_var1 (m_do_strlist); + unwind_protect_var<std::list<text_renderer::string>> restore_var2 (m_strlist); - m_do_strlist = true; + m_do_strlist = true; - text_to_pixels (txt, pxls, box, ha, va, rot, interp, false); + text_to_pixels (txt, pxls, box, ha, va, rot, interp, false); - lst = m_strlist; - } + lst = m_strlist; +} - void - ft_text_renderer::visit (text_element_string& e) - { - if (m_font.is_valid ()) - { - m_max_fontsize = std::max (m_max_fontsize, m_font.get_size ()); - FT_UInt glyph_index, previous = 0; +void +ft_text_renderer::visit (text_element_string& e) +{ + if (m_font.is_valid ()) + { + m_max_fontsize = std::max (m_max_fontsize, m_font.get_size ()); + FT_UInt glyph_index, previous = 0; - std::string str = e.string_value (); - const uint8_t *c = reinterpret_cast<const uint8_t *> (str.c_str ()); - uint32_t u32_c; + std::string str = e.string_value (); + const uint8_t *c = reinterpret_cast<const uint8_t *> (str.c_str ()); + uint32_t u32_c; - std::size_t n = str.size (); - std::size_t icurr = 0; - std::size_t ibegin = 0; + std::size_t n = str.size (); + std::size_t icurr = 0; + std::size_t ibegin = 0; - // Initialize a new string - text_renderer::string fs (str, m_font, m_xoffset, m_yoffset); + // Initialize a new string + text_renderer::string fs (str, m_font, m_xoffset, m_yoffset); - std::string fname = m_font.get_face ()->family_name; + std::string fname = m_font.get_face ()->family_name; - if (fname.find (" ") != std::string::npos) - fname = "'" + fname + "'"; + if (fname.find (" ") != std::string::npos) + fname = "'" + fname + "'"; - fs.set_family (fname); + fs.set_family (fname); - std::vector<double> xdata; - std::string sub_name; + std::vector<double> xdata; + std::string sub_name; - while (n > 0) - { - // Retrieve the length and the u32 representation of the current - // character - int mblen = octave_u8_strmbtouc_wrapper (&u32_c, c + icurr); - if (mblen < 1) - { - // This is not an UTF-8 character, use a replacement character - mblen = 1; - u32_c = 0xFFFD; - } + while (n > 0) + { + // Retrieve the length and the u32 representation of the current + // character + int mblen = octave_u8_strmbtouc_wrapper (&u32_c, c + icurr); + if (mblen < 1) + { + // This is not an UTF-8 character, use a replacement character + mblen = 1; + u32_c = 0xFFFD; + } - n -= mblen; + n -= mblen; - if (m_do_strlist && m_mode == MODE_RENDER) - { - if (u32_c == 10) - { - // Finish previous string in m_strlist before processing - // the newline character - fs.set_y (m_line_yoffset + m_yoffset); - fs.set_color (m_color); + if (m_do_strlist && m_mode == MODE_RENDER) + { + if (u32_c == 10) + { + // Finish previous string in m_strlist before processing + // the newline character + fs.set_y (m_line_yoffset + m_yoffset); + fs.set_color (m_color); - std::string s = str.substr (ibegin, icurr - ibegin); - if (! s.empty ()) - { - fs.set_string (s); - fs.set_y (m_line_yoffset + m_yoffset); - fs.set_xdata (xdata); - fs.set_family (fname); - m_strlist.push_back (fs); - } - } - else - xdata.push_back (m_xoffset); - } + std::string s = str.substr (ibegin, icurr - ibegin); + if (! s.empty ()) + { + fs.set_string (s); + fs.set_y (m_line_yoffset + m_yoffset); + fs.set_xdata (xdata); + fs.set_family (fname); + m_strlist.push_back (fs); + } + } + else + xdata.push_back (m_xoffset); + } - glyph_index = process_character (u32_c, previous, sub_name); + glyph_index = process_character (u32_c, previous, sub_name); - if (m_do_strlist && m_mode == MODE_RENDER && ! sub_name.empty ()) - { - // Add substitution font to the family name stack - std::string tmp_family = fs.get_family (); + if (m_do_strlist && m_mode == MODE_RENDER && ! sub_name.empty ()) + { + // Add substitution font to the family name stack + std::string tmp_family = fs.get_family (); - if (tmp_family.find (sub_name) == std::string::npos) - { - if (sub_name.find (" ") != std::string::npos) - sub_name = "'" + sub_name + "'"; + if (tmp_family.find (sub_name) == std::string::npos) + { + if (sub_name.find (" ") != std::string::npos) + sub_name = "'" + sub_name + "'"; - fs.set_family (tmp_family + ", " + sub_name); - } - } + fs.set_family (tmp_family + ", " + sub_name); + } + } - if (u32_c == 10) - { - previous = 0; + if (u32_c == 10) + { + previous = 0; - if (m_do_strlist && m_mode == MODE_RENDER) - { - // Start a new string in m_strlist - ibegin = icurr+1; - xdata.clear (); - fs = text_renderer::string (str.substr (ibegin), m_font, - m_line_xoffset, m_yoffset); - } - } - else - previous = glyph_index; + if (m_do_strlist && m_mode == MODE_RENDER) + { + // Start a new string in m_strlist + ibegin = icurr+1; + xdata.clear (); + fs = text_renderer::string (str.substr (ibegin), m_font, + m_line_xoffset, m_yoffset); + } + } + else + previous = glyph_index; - icurr += mblen; - } + icurr += mblen; + } - if (m_do_strlist && m_mode == MODE_RENDER - && ! fs.get_string ().empty ()) - { - fs.set_y (m_line_yoffset + m_yoffset); - fs.set_color (m_color); - fs.set_xdata (xdata); - m_strlist.push_back (fs); - } - } - } + if (m_do_strlist && m_mode == MODE_RENDER + && ! fs.get_string ().empty ()) + { + fs.set_y (m_line_yoffset + m_yoffset); + fs.set_color (m_color); + fs.set_xdata (xdata); + m_strlist.push_back (fs); + } + } +} - void - ft_text_renderer::visit (text_element_list& e) - { - // Save and restore (after processing the list) the current font and color. +void +ft_text_renderer::visit (text_element_list& e) +{ + // Save and restore (after processing the list) the current font and color. - ft_font saved_font (m_font); - uint8NDArray saved_color (m_color); + ft_font saved_font (m_font); + uint8NDArray saved_color (m_color); - text_processor::visit (e); + text_processor::visit (e); - m_font = saved_font; - m_color = saved_color; - } + m_font = saved_font; + m_color = saved_color; +} - void - ft_text_renderer::visit (text_element_subscript& e) - { - ft_font saved_font (m_font); - int saved_line_yoffset = m_line_yoffset; - int saved_yoffset = m_yoffset; +void +ft_text_renderer::visit (text_element_subscript& e) +{ + ft_font saved_font (m_font); + int saved_line_yoffset = m_line_yoffset; + int saved_yoffset = m_yoffset; - double sz = m_font.get_size (); + double sz = m_font.get_size (); - // Reducing font size by 70% produces decent results. - set_font (m_font.get_name (), m_font.get_weight (), m_font.get_angle (), - std::max (5.0, sz * 0.7)); + // Reducing font size by 70% produces decent results. + set_font (m_font.get_name (), m_font.get_weight (), m_font.get_angle (), + std::max (5.0, sz * 0.7)); - if (m_font.is_valid ()) - { - // Shifting the baseline by 15% of the font size gives decent results. - m_yoffset -= std::ceil (sz * 0.15); + if (m_font.is_valid ()) + { + // Shifting the baseline by 15% of the font size gives decent results. + m_yoffset -= std::ceil (sz * 0.15); - if (m_mode == MODE_BBOX) - update_line_bbox (); - } + if (m_mode == MODE_BBOX) + update_line_bbox (); + } - text_processor::visit (e); + text_processor::visit (e); - m_font = saved_font; - // If line_yoffset changed, this means we moved to a new line; hence yoffset - // cannot be restored, because the saved value is not relevant anymore. - if (m_line_yoffset == saved_line_yoffset) - m_yoffset = saved_yoffset; - } + m_font = saved_font; + // If line_yoffset changed, this means we moved to a new line; hence yoffset + // cannot be restored, because the saved value is not relevant anymore. + if (m_line_yoffset == saved_line_yoffset) + m_yoffset = saved_yoffset; +} - void - ft_text_renderer::visit (text_element_superscript& e) - { - ft_font saved_font (m_font); - int saved_line_yoffset = m_line_yoffset; - int saved_yoffset = m_yoffset; +void +ft_text_renderer::visit (text_element_superscript& e) +{ + ft_font saved_font (m_font); + int saved_line_yoffset = m_line_yoffset; + int saved_yoffset = m_yoffset; - double sz = m_font.get_size (); + double sz = m_font.get_size (); - // Reducing font size by 70% produces decent results. - set_font (m_font.get_name (), m_font.get_weight (), m_font.get_angle (), - std::max (5.0, sz * 0.7)); + // Reducing font size by 70% produces decent results. + set_font (m_font.get_name (), m_font.get_weight (), m_font.get_angle (), + std::max (5.0, sz * 0.7)); - if (saved_font.is_valid ()) - { - // Shifting the baseline by 40% of the font size gives decent results. - m_yoffset += std::ceil (sz * 0.4); + if (saved_font.is_valid ()) + { + // Shifting the baseline by 40% of the font size gives decent results. + m_yoffset += std::ceil (sz * 0.4); - if (m_mode == MODE_BBOX) - update_line_bbox (); - } + if (m_mode == MODE_BBOX) + update_line_bbox (); + } - text_processor::visit (e); + text_processor::visit (e); - m_font = saved_font; - // If line_yoffset changed, this means we moved to a new line; hence yoffset - // cannot be restored, because the saved value is not relevant anymore. - if (m_line_yoffset == saved_line_yoffset) - m_yoffset = saved_yoffset; - } + m_font = saved_font; + // If line_yoffset changed, this means we moved to a new line; hence yoffset + // cannot be restored, because the saved value is not relevant anymore. + if (m_line_yoffset == saved_line_yoffset) + m_yoffset = saved_yoffset; +} - void - ft_text_renderer::visit (text_element_color& e) - { - if (m_mode == MODE_RENDER) - set_color (e.get_color ()); - } +void +ft_text_renderer::visit (text_element_color& e) +{ + if (m_mode == MODE_RENDER) + set_color (e.get_color ()); +} - void - ft_text_renderer::visit (text_element_fontsize& e) - { - double sz = e.get_fontsize (); +void +ft_text_renderer::visit (text_element_fontsize& e) +{ + double sz = e.get_fontsize (); - // FIXME: Matlab documentation says that the font size is expressed - // in the text object FontUnit. + // FIXME: Matlab documentation says that the font size is expressed + // in the text object FontUnit. - set_font (m_font.get_name (), m_font.get_weight (), - m_font.get_angle (), sz); + set_font (m_font.get_name (), m_font.get_weight (), + m_font.get_angle (), sz); - if (m_mode == MODE_BBOX) - update_line_bbox (); - } + if (m_mode == MODE_BBOX) + update_line_bbox (); +} - void - ft_text_renderer::visit (text_element_fontname& e) - { - set_font (e.get_fontname (), m_font.get_weight (), m_font.get_angle (), - m_font.get_size ()); +void +ft_text_renderer::visit (text_element_fontname& e) +{ + set_font (e.get_fontname (), m_font.get_weight (), m_font.get_angle (), + m_font.get_size ()); - if (m_mode == MODE_BBOX) - update_line_bbox (); - } + if (m_mode == MODE_BBOX) + update_line_bbox (); +} - void - ft_text_renderer::visit (text_element_fontstyle& e) - { - switch (e.get_fontstyle ()) - { - case text_element_fontstyle::normal: - set_font (m_font.get_name (), "normal", "normal", m_font.get_size ()); - break; +void +ft_text_renderer::visit (text_element_fontstyle& e) +{ + switch (e.get_fontstyle ()) + { + case text_element_fontstyle::normal: + set_font (m_font.get_name (), "normal", "normal", m_font.get_size ()); + break; - case text_element_fontstyle::bold: - set_font (m_font.get_name (), "bold", "normal", m_font.get_size ()); - break; + case text_element_fontstyle::bold: + set_font (m_font.get_name (), "bold", "normal", m_font.get_size ()); + break; - case text_element_fontstyle::italic: - set_font (m_font.get_name (), "normal", "italic", m_font.get_size ()); - break; + case text_element_fontstyle::italic: + set_font (m_font.get_name (), "normal", "italic", m_font.get_size ()); + break; - case text_element_fontstyle::oblique: - set_font (m_font.get_name (), "normal", "oblique", m_font.get_size ()); - break; - } + case text_element_fontstyle::oblique: + set_font (m_font.get_name (), "normal", "oblique", m_font.get_size ()); + break; + } - if (m_mode == MODE_BBOX) - update_line_bbox (); - } + if (m_mode == MODE_BBOX) + update_line_bbox (); +} - void - ft_text_renderer::visit (text_element_symbol& e) - { - uint32_t code = e.get_symbol_code (); +void +ft_text_renderer::visit (text_element_symbol& e) +{ + uint32_t code = e.get_symbol_code (); - std::vector<double> xdata (1, m_xoffset); - text_renderer::string fs ("-", m_font, m_xoffset, m_yoffset); + std::vector<double> xdata (1, m_xoffset); + text_renderer::string fs ("-", m_font, m_xoffset, m_yoffset); - if (code != text_element_symbol::invalid_code && m_font.is_valid ()) - { - std::string sub_name; + if (code != text_element_symbol::invalid_code && m_font.is_valid ()) + { + std::string sub_name; - process_character (code, 0, sub_name); + process_character (code, 0, sub_name); - if (m_do_strlist && m_mode == MODE_RENDER) - { - if (! sub_name.empty ()) - { - // Add substitution font to the family name - std::string tmp_family = fs.get_family (); + if (m_do_strlist && m_mode == MODE_RENDER) + { + if (! sub_name.empty ()) + { + // Add substitution font to the family name + std::string tmp_family = fs.get_family (); - if (tmp_family.find (sub_name) == std::string::npos) - { - if (sub_name.find (" ") != std::string::npos) - sub_name = "'" + sub_name + "'"; + if (tmp_family.find (sub_name) == std::string::npos) + { + if (sub_name.find (" ") != std::string::npos) + sub_name = "'" + sub_name + "'"; - fs.set_family (tmp_family + ", " + sub_name); - } - } + fs.set_family (tmp_family + ", " + sub_name); + } + } - fs.set_code (code); - fs.set_xdata (xdata); - } - } - else if (m_font.is_valid ()) - ::warning ("ignoring unknown symbol: %d", e.get_symbol ()); + fs.set_code (code); + fs.set_xdata (xdata); + } + } + else if (m_font.is_valid ()) + ::warning ("ignoring unknown symbol: %d", e.get_symbol ()); - if (m_do_strlist && m_mode == MODE_RENDER && fs.get_code ()) - { - fs.set_y (m_line_yoffset + m_yoffset); - fs.set_color (m_color); - fs.set_family (m_font.get_face ()->family_name); - m_strlist.push_back (fs); - } - } + if (m_do_strlist && m_mode == MODE_RENDER && fs.get_code ()) + { + fs.set_y (m_line_yoffset + m_yoffset); + fs.set_color (m_color); + fs.set_family (m_font.get_face ()->family_name); + m_strlist.push_back (fs); + } +} - void - ft_text_renderer::visit (text_element_combined& e) - { - int saved_xoffset = m_xoffset; - int max_xoffset = m_xoffset; +void +ft_text_renderer::visit (text_element_combined& e) +{ + int saved_xoffset = m_xoffset; + int max_xoffset = m_xoffset; - for (auto *txt_elt : e) - { - m_xoffset = saved_xoffset; - txt_elt->accept (*this); - max_xoffset = math::max (m_xoffset, max_xoffset); - } + for (auto *txt_elt : e) + { + m_xoffset = saved_xoffset; + txt_elt->accept (*this); + max_xoffset = math::max (m_xoffset, max_xoffset); + } - m_xoffset = max_xoffset; - } + m_xoffset = max_xoffset; +} - void - ft_text_renderer::reset (void) - { - set_mode (MODE_BBOX); - set_color (Matrix (1, 3, 0.0)); - m_strlist = std::list<text_renderer::string> (); - } +void +ft_text_renderer::reset (void) +{ + set_mode (MODE_BBOX); + set_color (Matrix (1, 3, 0.0)); + m_strlist = std::list<text_renderer::string> (); +} - void - ft_text_renderer::set_color (const Matrix& c) - { - if (c.numel () == 3) - { - m_color(0) = static_cast<uint8_t> (c(0)*255); - m_color(1) = static_cast<uint8_t> (c(1)*255); - m_color(2) = static_cast<uint8_t> (c(2)*255); - } - else - ::warning ("ft_text_renderer::set_color: invalid color"); - } +void +ft_text_renderer::set_color (const Matrix& c) +{ + if (c.numel () == 3) + { + m_color(0) = static_cast<uint8_t> (c(0)*255); + m_color(1) = static_cast<uint8_t> (c(1)*255); + m_color(2) = static_cast<uint8_t> (c(2)*255); + } + else + ::warning ("ft_text_renderer::set_color: invalid color"); +} - uint8NDArray - ft_text_renderer::render (text_element *elt, Matrix& box, int rotation) - { - set_mode (MODE_BBOX); - elt->accept (*this); - compute_bbox (); - box = m_bbox; +uint8NDArray +ft_text_renderer::render (text_element *elt, Matrix& box, int rotation) +{ + set_mode (MODE_BBOX); + elt->accept (*this); + compute_bbox (); + box = m_bbox; - set_mode (MODE_RENDER); + set_mode (MODE_RENDER); - if (m_pixels.numel () > 0) - { - elt->accept (*this); + if (m_pixels.numel () > 0) + { + elt->accept (*this); - rotate_pixels (m_pixels, rotation); - } + rotate_pixels (m_pixels, rotation); + } - return m_pixels; - } + return m_pixels; +} - // Note: - // x-extent accurately measures width of glyphs. - // y-extent is overly large because it is measured from baseline-to-baseline. - // Calling routines, such as ylabel, may need to account for this mismatch. +// Note: +// x-extent accurately measures width of glyphs. +// y-extent is overly large because it is measured from baseline-to-baseline. +// Calling routines, such as ylabel, may need to account for this mismatch. - Matrix - ft_text_renderer::get_extent (text_element *elt, double rotation) - { - set_mode (MODE_BBOX); - elt->accept (*this); - compute_bbox (); +Matrix +ft_text_renderer::get_extent (text_element *elt, double rotation) +{ + set_mode (MODE_BBOX); + elt->accept (*this); + compute_bbox (); - Matrix extent (1, 2, 0.0); + Matrix extent (1, 2, 0.0); - switch (rotation_to_mode (rotation)) - { - case ROTATION_0: - case ROTATION_180: - extent(0) = m_bbox(2); - extent(1) = m_bbox(3); - break; + switch (rotation_to_mode (rotation)) + { + case ROTATION_0: + case ROTATION_180: + extent(0) = m_bbox(2); + extent(1) = m_bbox(3); + break; - case ROTATION_90: - case ROTATION_270: - extent(0) = m_bbox(3); - extent(1) = m_bbox(2); - } + case ROTATION_90: + case ROTATION_270: + extent(0) = m_bbox(3); + extent(1) = m_bbox(2); + } - return extent; - } + return extent; +} - Matrix - ft_text_renderer::get_extent (const std::string& txt, double rotation, - const caseless_str& interpreter) - { - text_element *elt = text_parser::parse (txt, interpreter); - Matrix extent = get_extent (elt, rotation); - delete elt; +Matrix +ft_text_renderer::get_extent (const std::string& txt, double rotation, + const caseless_str& interpreter) +{ + text_element *elt = text_parser::parse (txt, interpreter); + Matrix extent = get_extent (elt, rotation); + delete elt; - return extent; - } + return extent; +} - void - ft_text_renderer::text_to_pixels (const std::string& txt, - uint8NDArray& pxls, Matrix& box, - int _halign, int valign, double rotation, - const caseless_str& interpreter, - bool handle_rotation) - { - int rot_mode = rotation_to_mode (rotation); +void +ft_text_renderer::text_to_pixels (const std::string& txt, + uint8NDArray& pxls, Matrix& box, + int _halign, int valign, double rotation, + const caseless_str& interpreter, + bool handle_rotation) +{ + int rot_mode = rotation_to_mode (rotation); - m_halign = _halign; + m_halign = _halign; - text_element *elt = text_parser::parse (txt, interpreter); - pxls = render (elt, box, rot_mode); - delete elt; + text_element *elt = text_parser::parse (txt, interpreter); + pxls = render (elt, box, rot_mode); + delete elt; - if (pxls.isempty ()) - return; // nothing to render + if (pxls.isempty ()) + return; // nothing to render - // Move X0 and Y0 depending on alignments and eventually swap all values - // for text rotated 90° 180° or 270° - fix_bbox_anchor (box, m_halign, valign, rot_mode, handle_rotation); - } + // Move X0 and Y0 depending on alignments and eventually swap all values + // for text rotated 90° 180° or 270° + fix_bbox_anchor (box, m_halign, valign, rot_mode, handle_rotation); +} - ft_text_renderer::ft_font::ft_font (const ft_font& ft) - : text_renderer::font (ft), m_face (nullptr) - { +ft_text_renderer::ft_font::ft_font (const ft_font& ft) + : text_renderer::font (ft), m_face (nullptr) +{ #if defined (HAVE_FT_REFERENCE_FACE) - FT_Face ft_face = ft.get_face (); + FT_Face ft_face = ft.get_face (); - if (ft_face && FT_Reference_Face (ft_face) == 0) - m_face = ft_face; + if (ft_face && FT_Reference_Face (ft_face) == 0) + m_face = ft_face; #endif - } +} - ft_text_renderer::ft_font& - ft_text_renderer::ft_font::operator = (const ft_font& ft) - { - if (&ft != this) - { - text_renderer::font::operator = (ft); +ft_text_renderer::ft_font& +ft_text_renderer::ft_font::operator = (const ft_font& ft) +{ + if (&ft != this) + { + text_renderer::font::operator = (ft); - if (m_face) - { - FT_Done_Face (m_face); - m_face = nullptr; - } + if (m_face) + { + FT_Done_Face (m_face); + m_face = nullptr; + } #if defined (HAVE_FT_REFERENCE_FACE) - FT_Face ft_face = ft.get_face (); + FT_Face ft_face = ft.get_face (); - if (ft_face && FT_Reference_Face (ft_face) == 0) - m_face = ft_face; + if (ft_face && FT_Reference_Face (ft_face) == 0) + m_face = ft_face; #endif - } + } - return *this; - } + return *this; +} - FT_Face - ft_text_renderer::ft_font::get_face (void) const - { - if (! m_face && ! m_name.empty ()) - { - m_face = ft_manager::get_font (m_name, m_weight, m_angle, m_size); +FT_Face +ft_text_renderer::ft_font::get_face (void) const +{ + if (! m_face && ! m_name.empty ()) + { + m_face = ft_manager::get_font (m_name, m_weight, m_angle, m_size); - if (m_face) - { - if (FT_Set_Char_Size (m_face, 0, m_size*64, 0, 0)) - ::warning ("ft_text_renderer: unable to set font size to %g", m_size); - } - else - ::warning ("ft_text_renderer: unable to load appropriate font"); - } + if (m_face) + { + if (FT_Set_Char_Size (m_face, 0, m_size*64, 0, 0)) + ::warning ("ft_text_renderer: unable to set font size to %g", m_size); + } + else + ::warning ("ft_text_renderer: unable to load appropriate font"); + } - return m_face; - } + return m_face; +} OCTAVE_END_NAMESPACE(octave) @@ -1533,14 +1533,14 @@ OCTAVE_BEGIN_NAMESPACE(octave) - base_text_renderer * - make_ft_text_renderer (void) - { +base_text_renderer * +make_ft_text_renderer (void) +{ #if defined (HAVE_FREETYPE) - return new ft_text_renderer (); + return new ft_text_renderer (); #else - return 0; + return 0; #endif - } +} OCTAVE_END_NAMESPACE(octave)