Mercurial > octave-nkf
diff libinterp/corefcn/txt-eng-ft.cc @ 16892:68fc671a9339
maint: Collapse interpfcn and interpfcn-core directories into corefcn directory.
* libgui/src/module.mk: Remove -I references to interp-core, interpfcn, add
reference to corefcn.
* libinterp/Makefile.am: Remove -I references to interp-core, interpfcn, add
reference to corefcn.
* libinterp/corefcn/module.mk: Add files from interp-core, interpfcn to
build system. Copy over special rules from module.mk files in interp-core
andd interpfcn.
* src/Makefile.am: Replace references to interp-core, interpfcn with those
to corefcn.
* libinterp/corefcn/Cell.cc, libinterp/corefcn/Cell.h,
libinterp/corefcn/action-container.h, libinterp/corefcn/c-file-ptr-stream.cc,
libinterp/corefcn/c-file-ptr-stream.h, libinterp/corefcn/comment-list.cc,
libinterp/corefcn/comment-list.h, libinterp/corefcn/cutils.c,
libinterp/corefcn/cutils.h, libinterp/corefcn/data.cc,
libinterp/corefcn/data.h, libinterp/corefcn/debug.cc,
libinterp/corefcn/debug.h, libinterp/corefcn/defaults.cc,
libinterp/corefcn/defaults.in.h, libinterp/corefcn/defun-dld.h,
libinterp/corefcn/defun-int.h, libinterp/corefcn/defun.cc,
libinterp/corefcn/defun.h, libinterp/corefcn/dirfns.cc,
libinterp/corefcn/dirfns.h, libinterp/corefcn/display.cc,
libinterp/corefcn/display.h, libinterp/corefcn/dynamic-ld.cc,
libinterp/corefcn/dynamic-ld.h, libinterp/corefcn/error.cc,
libinterp/corefcn/error.h, libinterp/corefcn/event-queue.h,
libinterp/corefcn/file-io.cc, libinterp/corefcn/file-io.h,
libinterp/corefcn/gl-render.cc, libinterp/corefcn/gl-render.h,
libinterp/corefcn/gl2ps-renderer.cc, libinterp/corefcn/gl2ps-renderer.h,
libinterp/corefcn/gl2ps.c, libinterp/corefcn/gl2ps.h,
libinterp/corefcn/graphics.cc, libinterp/corefcn/graphics.in.h,
libinterp/corefcn/gripes.cc, libinterp/corefcn/gripes.h,
libinterp/corefcn/help.cc, libinterp/corefcn/help.h,
libinterp/corefcn/hook-fcn.cc, libinterp/corefcn/hook-fcn.h,
libinterp/corefcn/input.cc, libinterp/corefcn/input.h,
libinterp/corefcn/jit-ir.cc, libinterp/corefcn/jit-ir.h,
libinterp/corefcn/jit-typeinfo.cc, libinterp/corefcn/jit-typeinfo.h,
libinterp/corefcn/jit-util.cc, libinterp/corefcn/jit-util.h,
libinterp/corefcn/load-path.cc, libinterp/corefcn/load-path.h,
libinterp/corefcn/load-save.cc, libinterp/corefcn/load-save.h,
libinterp/corefcn/ls-ascii-helper.cc, libinterp/corefcn/ls-ascii-helper.h,
libinterp/corefcn/ls-hdf5.cc, libinterp/corefcn/ls-hdf5.h,
libinterp/corefcn/ls-mat-ascii.cc, libinterp/corefcn/ls-mat-ascii.h,
libinterp/corefcn/ls-mat4.cc, libinterp/corefcn/ls-mat4.h,
libinterp/corefcn/ls-mat5.cc, libinterp/corefcn/ls-mat5.h,
libinterp/corefcn/ls-oct-ascii.cc, libinterp/corefcn/ls-oct-ascii.h,
libinterp/corefcn/ls-oct-binary.cc, libinterp/corefcn/ls-oct-binary.h,
libinterp/corefcn/ls-utils.cc, libinterp/corefcn/ls-utils.h,
libinterp/corefcn/matherr.c, libinterp/corefcn/mex.cc, libinterp/corefcn/mex.h,
libinterp/corefcn/mexproto.h, libinterp/corefcn/mxarray.in.h,
libinterp/corefcn/oct-errno.h, libinterp/corefcn/oct-errno.in.cc,
libinterp/corefcn/oct-fstrm.cc, libinterp/corefcn/oct-fstrm.h,
libinterp/corefcn/oct-hdf5.h, libinterp/corefcn/oct-hist.cc,
libinterp/corefcn/oct-hist.h, libinterp/corefcn/oct-iostrm.cc,
libinterp/corefcn/oct-iostrm.h, libinterp/corefcn/oct-lvalue.cc,
libinterp/corefcn/oct-lvalue.h, libinterp/corefcn/oct-map.cc,
libinterp/corefcn/oct-map.h, libinterp/corefcn/oct-obj.cc,
libinterp/corefcn/oct-obj.h, libinterp/corefcn/oct-prcstrm.cc,
libinterp/corefcn/oct-prcstrm.h, libinterp/corefcn/oct-procbuf.cc,
libinterp/corefcn/oct-procbuf.h, libinterp/corefcn/oct-stdstrm.h,
libinterp/corefcn/oct-stream.cc, libinterp/corefcn/oct-stream.h,
libinterp/corefcn/oct-strstrm.cc, libinterp/corefcn/oct-strstrm.h,
libinterp/corefcn/oct.h, libinterp/corefcn/octave-link.cc,
libinterp/corefcn/octave-link.h, libinterp/corefcn/pager.cc,
libinterp/corefcn/pager.h, libinterp/corefcn/pr-output.cc,
libinterp/corefcn/pr-output.h, libinterp/corefcn/procstream.cc,
libinterp/corefcn/procstream.h, libinterp/corefcn/profiler.cc,
libinterp/corefcn/profiler.h, libinterp/corefcn/pt-jit.cc,
libinterp/corefcn/pt-jit.h, libinterp/corefcn/sighandlers.cc,
libinterp/corefcn/sighandlers.h, libinterp/corefcn/siglist.c,
libinterp/corefcn/siglist.h, libinterp/corefcn/sparse-xdiv.cc,
libinterp/corefcn/sparse-xdiv.h, libinterp/corefcn/sparse-xpow.cc,
libinterp/corefcn/sparse-xpow.h, libinterp/corefcn/symtab.cc,
libinterp/corefcn/symtab.h, libinterp/corefcn/sysdep.cc,
libinterp/corefcn/sysdep.h, libinterp/corefcn/toplev.cc,
libinterp/corefcn/toplev.h, libinterp/corefcn/txt-eng-ft.cc,
libinterp/corefcn/txt-eng-ft.h, libinterp/corefcn/txt-eng.h,
libinterp/corefcn/unwind-prot.cc, libinterp/corefcn/unwind-prot.h,
libinterp/corefcn/utils.cc, libinterp/corefcn/utils.h,
libinterp/corefcn/variables.cc, libinterp/corefcn/variables.h,
libinterp/corefcn/workspace-element.h, libinterp/corefcn/xdiv.cc,
libinterp/corefcn/xdiv.h, libinterp/corefcn/xgl2ps.c,
libinterp/corefcn/xnorm.cc, libinterp/corefcn/xnorm.h,
libinterp/corefcn/xpow.cc, libinterp/corefcn/xpow.h,
libinterp/corefcn/zfstream.cc, libinterp/corefcn/zfstream.h:
Files moved from interp-core and interpfcn directories.
* libinterp/interp-core/Cell.cc, libinterp/interp-core/Cell.h,
libinterp/interp-core/action-container.h,
libinterp/interp-core/c-file-ptr-stream.cc,
libinterp/interp-core/c-file-ptr-stream.h,
libinterp/interp-core/comment-list.cc, libinterp/interp-core/comment-list.h,
libinterp/interp-core/cutils.c, libinterp/interp-core/cutils.h,
libinterp/interp-core/defun-dld.h, libinterp/interp-core/defun-int.h,
libinterp/interp-core/display.cc, libinterp/interp-core/display.h,
libinterp/interp-core/dynamic-ld.cc, libinterp/interp-core/dynamic-ld.h,
libinterp/interp-core/event-queue.h, libinterp/interp-core/gl-render.cc,
libinterp/interp-core/gl-render.h, libinterp/interp-core/gl2ps-renderer.cc,
libinterp/interp-core/gl2ps-renderer.h, libinterp/interp-core/gl2ps.c,
libinterp/interp-core/gl2ps.h, libinterp/interp-core/gripes.cc,
libinterp/interp-core/gripes.h, libinterp/interp-core/jit-ir.cc,
libinterp/interp-core/jit-ir.h, libinterp/interp-core/jit-typeinfo.cc,
libinterp/interp-core/jit-typeinfo.h, libinterp/interp-core/jit-util.cc,
libinterp/interp-core/jit-util.h, libinterp/interp-core/ls-ascii-helper.cc,
libinterp/interp-core/ls-ascii-helper.h, libinterp/interp-core/ls-hdf5.cc,
libinterp/interp-core/ls-hdf5.h, libinterp/interp-core/ls-mat-ascii.cc,
libinterp/interp-core/ls-mat-ascii.h, libinterp/interp-core/ls-mat4.cc,
libinterp/interp-core/ls-mat4.h, libinterp/interp-core/ls-mat5.cc,
libinterp/interp-core/ls-mat5.h, libinterp/interp-core/ls-oct-binary.cc,
libinterp/interp-core/ls-oct-binary.h, libinterp/interp-core/ls-utils.cc,
libinterp/interp-core/ls-utils.h, libinterp/interp-core/matherr.c,
libinterp/interp-core/mex.cc, libinterp/interp-core/mex.h,
libinterp/interp-core/mexproto.h, libinterp/interp-core/module.mk,
libinterp/interp-core/mxarray.in.h, libinterp/interp-core/oct-errno.h,
libinterp/interp-core/oct-errno.in.cc, libinterp/interp-core/oct-fstrm.cc,
libinterp/interp-core/oct-fstrm.h, libinterp/interp-core/oct-hdf5.h,
libinterp/interp-core/oct-iostrm.cc, libinterp/interp-core/oct-iostrm.h,
libinterp/interp-core/oct-lvalue.cc, libinterp/interp-core/oct-lvalue.h,
libinterp/interp-core/oct-map.cc, libinterp/interp-core/oct-map.h,
libinterp/interp-core/oct-obj.cc, libinterp/interp-core/oct-obj.h,
libinterp/interp-core/oct-prcstrm.cc, libinterp/interp-core/oct-prcstrm.h,
libinterp/interp-core/oct-procbuf.cc, libinterp/interp-core/oct-procbuf.h,
libinterp/interp-core/oct-stdstrm.h, libinterp/interp-core/oct-stream.cc,
libinterp/interp-core/oct-stream.h, libinterp/interp-core/oct-strstrm.cc,
libinterp/interp-core/oct-strstrm.h, libinterp/interp-core/oct.h,
libinterp/interp-core/procstream.cc, libinterp/interp-core/procstream.h,
libinterp/interp-core/pt-jit.cc, libinterp/interp-core/pt-jit.h,
libinterp/interp-core/siglist.c, libinterp/interp-core/siglist.h,
libinterp/interp-core/sparse-xdiv.cc, libinterp/interp-core/sparse-xdiv.h,
libinterp/interp-core/sparse-xpow.cc, libinterp/interp-core/sparse-xpow.h,
libinterp/interp-core/txt-eng-ft.cc, libinterp/interp-core/txt-eng-ft.h,
libinterp/interp-core/txt-eng.h, libinterp/interp-core/unwind-prot.cc,
libinterp/interp-core/unwind-prot.h, libinterp/interp-core/xdiv.cc,
libinterp/interp-core/xdiv.h, libinterp/interp-core/xgl2ps.c,
libinterp/interp-core/xnorm.cc, libinterp/interp-core/xnorm.h,
libinterp/interp-core/xpow.cc, libinterp/interp-core/xpow.h,
libinterp/interp-core/zfstream.cc, libinterp/interp-core/zfstream.h,
libinterp/interpfcn/data.cc, libinterp/interpfcn/data.h,
libinterp/interpfcn/debug.cc, libinterp/interpfcn/debug.h,
libinterp/interpfcn/defaults.cc, libinterp/interpfcn/defaults.in.h,
libinterp/interpfcn/defun.cc, libinterp/interpfcn/defun.h,
libinterp/interpfcn/dirfns.cc, libinterp/interpfcn/dirfns.h,
libinterp/interpfcn/error.cc, libinterp/interpfcn/error.h,
libinterp/interpfcn/file-io.cc, libinterp/interpfcn/file-io.h,
libinterp/interpfcn/graphics.cc, libinterp/interpfcn/graphics.in.h,
libinterp/interpfcn/help.cc, libinterp/interpfcn/help.h,
libinterp/interpfcn/hook-fcn.cc, libinterp/interpfcn/hook-fcn.h,
libinterp/interpfcn/input.cc, libinterp/interpfcn/input.h,
libinterp/interpfcn/load-path.cc, libinterp/interpfcn/load-path.h,
libinterp/interpfcn/load-save.cc, libinterp/interpfcn/load-save.h,
libinterp/interpfcn/ls-oct-ascii.cc, libinterp/interpfcn/ls-oct-ascii.h,
libinterp/interpfcn/module.mk, libinterp/interpfcn/oct-hist.cc,
libinterp/interpfcn/oct-hist.h, libinterp/interpfcn/octave-link.cc,
libinterp/interpfcn/octave-link.h, libinterp/interpfcn/pager.cc,
libinterp/interpfcn/pager.h, libinterp/interpfcn/pr-output.cc,
libinterp/interpfcn/pr-output.h, libinterp/interpfcn/profiler.cc,
libinterp/interpfcn/profiler.h, libinterp/interpfcn/sighandlers.cc,
libinterp/interpfcn/sighandlers.h, libinterp/interpfcn/symtab.cc,
libinterp/interpfcn/symtab.h, libinterp/interpfcn/sysdep.cc,
libinterp/interpfcn/sysdep.h, libinterp/interpfcn/toplev.cc,
libinterp/interpfcn/toplev.h, libinterp/interpfcn/utils.cc,
libinterp/interpfcn/utils.h, libinterp/interpfcn/variables.cc,
libinterp/interpfcn/variables.h, libinterp/interpfcn/workspace-element.h:
deleted files.
author | Rik <rik@octave.org> |
---|---|
date | Wed, 03 Jul 2013 17:43:48 -0700 |
parents | libinterp/interp-core/txt-eng-ft.cc@9ba5c5ed3aeb |
children | 5b088598df1d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/corefcn/txt-eng-ft.cc Wed Jul 03 17:43:48 2013 -0700 @@ -0,0 +1,675 @@ +/* + +Copyright (C) 2009-2012 Michael Goffioul + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if defined (HAVE_FREETYPE) + +#if defined (HAVE_FONTCONFIG) +#include <fontconfig/fontconfig.h> +#endif + +#include <iostream> + +#include "singleton-cleanup.h" + +#include "error.h" +#include "pr-output.h" +#include "txt-eng-ft.h" + +// FIXME -- maybe issue at most one warning per glyph/font/size/weight +// combination. + +static void +gripe_missing_glyph (char c) +{ + warning_with_id ("Octave:missing-glyph", + "ft_render: skipping missing glyph for character '%c'", + c); +} + +static void +gripe_glyph_render (char c) +{ + warning_with_id ("Octave:glyph-render", + "ft_render: unable to render glyph for character '%c'", + c); +} + +#ifdef _MSC_VER +// This is just a trick to avoid multiply symbols definition. +// PermMatrix.h contains a dllexport'ed Array<octave_idx_type> +// that will make MSVC not to generate new instantiation and +// use the imported one. +#include "PermMatrix.h" +#endif + +class +ft_manager +{ +public: + static bool instance_ok (void) + { + bool retval = true; + + if (! instance) + { + instance = new ft_manager (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create ft_manager!"); + + retval = false; + } + + return retval; + } + + static void cleanup_instance (void) { delete instance; instance = 0; } + + static FT_Face get_font (const std::string& name, const std::string& weight, + const std::string& angle, double size) + { return (instance_ok () + ? instance->do_get_font (name, weight, angle, size) + : 0); } + +private: + + static ft_manager *instance; + +private: + + // No copying! + + ft_manager (const ft_manager&); + + ft_manager& operator = (const ft_manager&); + + ft_manager (void) + : library (), freetype_initialized (false), fontconfig_initialized (false) + { + if (FT_Init_FreeType (&library)) + ::error ("unable to initialize freetype library"); + else + freetype_initialized = true; + +#if defined (HAVE_FONTCONFIG) + if (! FcInit ()) + ::error ("unable to initialize fontconfig library"); + else + fontconfig_initialized = true; +#endif + } + + ~ft_manager (void) + { + if (freetype_initialized) + FT_Done_FreeType (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 (fontconfig_initialized) + // FcFini (); +#endif + } + + + FT_Face do_get_font (const std::string& name, const std::string& weight, + const std::string& angle, double size) + { + FT_Face retval = 0; + + std::string file; + +#if defined (HAVE_FONTCONFIG) + if (fontconfig_initialized) + { + int fc_weight, fc_angle; + + if (weight == "bold") + fc_weight = FC_WEIGHT_BOLD; + else if (weight == "light") + fc_weight = FC_WEIGHT_LIGHT; + else if (weight == "demi") + fc_weight = FC_WEIGHT_DEMIBOLD; + else + fc_weight = FC_WEIGHT_NORMAL; + + 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 == "*" ? "sans" : name.c_str ()))); + + FcPatternAddInteger (pat, FC_WEIGHT, fc_weight); + FcPatternAddInteger (pat, FC_SLANT, fc_angle); + FcPatternAddDouble (pat, FC_PIXEL_SIZE, size); + + if (FcConfigSubstitute (0, pat, FcMatchPattern)) + { + FcResult res; + FcPattern *match; + + FcDefaultSubstitute (pat); + match = FcFontMatch (0, 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", + name.c_str (), weight.c_str (), angle.c_str (), + size); + + if (match) + FcPatternDestroy (match); + } + + FcPatternDestroy (pat); + } +#endif + + if (file.empty ()) + { +#ifdef __WIN32__ + file = "C:/WINDOWS/Fonts/verdana.ttf"; +#else + // FIXME: find a "standard" font for UNIX platforms +#endif + } + + if (! file.empty () && FT_New_Face (library, file.c_str (), 0, &retval)) + ::warning ("ft_manager: unable to load font: %s", file.c_str ()); + + return retval; + } + +private: + FT_Library library; + bool freetype_initialized; + bool fontconfig_initialized; +}; + +ft_manager* ft_manager::instance = 0; + +// --------------------------------------------------------------------------- + +ft_render::ft_render (void) + : text_processor (), face (0), bbox (1, 4, 0.0), + xoffset (0), yoffset (0), multiline_halign (0), + multiline_align_xoffsets (), mode (MODE_BBOX), + red (0), green (0), blue (0) +{ +} + +ft_render::~ft_render (void) +{ + if (face) + FT_Done_Face (face); +} + +void +ft_render::set_font (const std::string& name, const std::string& weight, + const std::string& angle, double size) +{ + if (face) + FT_Done_Face (face); + + // FIXME: take "fontunits" into account + face = ft_manager::get_font (name, weight, angle, size); + + if (face) + { + if (FT_Set_Char_Size (face, 0, size*64, 0, 0)) + ::warning ("ft_render: unable to set font size to %d", size); + } + else + ::warning ("ft_render: unable to load appropriate font"); +} + +void +ft_render::set_mode (int m) +{ + mode = m; + + switch (mode) + { + case MODE_BBOX: + xoffset = yoffset = 0; + bbox = Matrix (1, 4, 0.0); + break; + case MODE_RENDER: + if (bbox.numel () != 4) + { + ::warning ("ft_render: invalid bounding box, cannot render"); + + xoffset = yoffset = 0; + pixels = uint8NDArray (); + } + else + { + pixels = uint8NDArray (dim_vector (4, bbox(2), bbox(3)), + static_cast<uint8_t> (0)); + xoffset = 0; + yoffset = -bbox(1)-1; + } + break; + default: + ::error ("ft_render: invalid mode '%d'", mode); + break; + } +} + +void +ft_render::visit (text_element_string& e) +{ + if (face) + { + int line_index = 0; + FT_UInt box_line_width = 0; + std::string str = e.string_value (); + FT_UInt glyph_index, previous = 0; + + if (mode == MODE_BBOX) + multiline_align_xoffsets.clear (); + else if (mode == MODE_RENDER) + xoffset += multiline_align_xoffsets[line_index]; + + for (size_t i = 0; i < str.length (); i++) + { + glyph_index = FT_Get_Char_Index (face, str[i]); + + if (str[i] != '\n' + && (! glyph_index + || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))) + gripe_missing_glyph (str[i]); + else + { + switch (mode) + { + case MODE_RENDER: + if (str[i] == '\n') + { + glyph_index = FT_Get_Char_Index (face, ' '); + if (!glyph_index || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) + { + gripe_missing_glyph (' '); + } + else + { + line_index++; + xoffset = multiline_align_xoffsets[line_index]; + yoffset -= (face->size->metrics.height >> 6); + } + } + else if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL)) + { + gripe_glyph_render (str[i]); + } + else + { + FT_Bitmap& bitmap = face->glyph->bitmap; + int x0, y0; + + if (previous) + { + FT_Vector delta; + + FT_Get_Kerning (face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); + xoffset += (delta.x >> 6); + } + + x0 = xoffset+face->glyph->bitmap_left; + y0 = yoffset+face->glyph->bitmap_top; + + // 'w' seems to have a negative -1 + // face->glyph->bitmap_left, this is so we don't + // index out of bound, and assumes we we allocated + // the right amount of horizontal space in the bbox. + if (x0 < 0) + x0 = 0; + + for (int r = 0; r < bitmap.rows; r++) + for (int c = 0; c < bitmap.width; c++) + { + unsigned char pix = bitmap.buffer[r*bitmap.width+c]; + if (x0+c < 0 || x0+c >= pixels.dim2 () + || y0-r < 0 || y0-r >= pixels.dim3 ()) + { + //::error ("out-of-bound indexing!!"); + } + else if (pixels(3, x0+c, y0-r).value () == 0) + { + pixels(0, x0+c, y0-r) = red; + pixels(1, x0+c, y0-r) = green; + pixels(2, x0+c, y0-r) = blue; + pixels(3, x0+c, y0-r) = pix; + } + } + + xoffset += (face->glyph->advance.x >> 6); + } + break; + + case MODE_BBOX: + if (str[i] == '\n') + { + glyph_index = FT_Get_Char_Index (face, ' '); + if (! glyph_index + || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) + { + gripe_missing_glyph (' '); + } + else + { + multiline_align_xoffsets.push_back (box_line_width); + // Reset the pixel width for this newline, so we don't + // allocate a bounding box larger than the horizontal + // width of the multi-line + box_line_width = 0; + bbox(1) -= (face->size->metrics.height >> 6); + } + } + else + { + // width + if (previous) + { + FT_Vector delta; + + FT_Get_Kerning (face, previous, glyph_index, + FT_KERNING_DEFAULT, &delta); + + box_line_width += (delta.x >> 6); + } + + box_line_width += (face->glyph->advance.x >> 6); + + int asc, desc; + + if (false /*tight*/) + { + desc = face->glyph->metrics.horiBearingY - face->glyph->metrics.height; + asc = face->glyph->metrics.horiBearingY; + } + else + { + asc = face->size->metrics.ascender; + desc = face->size->metrics.descender; + } + + asc = yoffset + (asc >> 6); + desc = yoffset + (desc >> 6); + + if (desc < bbox(1)) + { + bbox(3) += (bbox(1) - desc); + bbox(1) = desc; + } + if (asc > (bbox(3)+bbox(1))) + bbox(3) = asc-bbox(1); + if (bbox(2) < box_line_width) + bbox(2) = box_line_width; + } + break; + } + if (str[i] == '\n') + previous = 0; + else + previous = glyph_index; + } + } + if (mode == MODE_BBOX) + { + /* Push last the width associated with the last line */ + multiline_align_xoffsets.push_back (box_line_width); + + for (unsigned int i = 0; i < multiline_align_xoffsets.size (); i++) + { + /* Center align */ + if (multiline_halign == 1) + multiline_align_xoffsets[i] = (bbox(2) - multiline_align_xoffsets[i])/2; + /* Right align */ + else if (multiline_halign == 2) + multiline_align_xoffsets[i] = (bbox(2) - multiline_align_xoffsets[i]); + /* Left align */ + else + multiline_align_xoffsets[i] = 0; + } + } + } +} + +void +ft_render::reset (void) +{ + set_mode (MODE_BBOX); + set_color (Matrix (1, 3, 0.0)); +} + +void +ft_render::set_color (Matrix c) +{ + if (c.numel () == 3) + { + red = static_cast<uint8_t> (c(0)*255); + green = static_cast<uint8_t> (c(1)*255); + blue = static_cast<uint8_t> (c(2)*255); + } + else + ::warning ("ft_render::set_color: invalid color"); +} + +uint8NDArray +ft_render::render (text_element* elt, Matrix& box, int rotation) +{ + set_mode (MODE_BBOX); + elt->accept (*this); + box = bbox; + + set_mode (MODE_RENDER); + if (pixels.numel () > 0) + { + elt->accept (*this); + + switch (rotation) + { + case ROTATION_0: + break; + case ROTATION_90: + { + Array<octave_idx_type> perm (dim_vector (3, 1)); + perm(0) = 0; + perm(1) = 2; + perm(2) = 1; + pixels = pixels.permute (perm); + + Array<idx_vector> idx (dim_vector (3, 1)); + idx(0) = idx_vector (':'); + idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1); + idx(2) = idx_vector (':'); + pixels = uint8NDArray (pixels.index (idx)); + } + break; + case ROTATION_180: + { + Array<idx_vector> idx (dim_vector (3, 1)); + idx(0) = idx_vector (':'); + idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1); + idx(2)= idx_vector (pixels.dim3 ()-1, -1, -1); + pixels = uint8NDArray (pixels.index (idx)); + } + break; + case ROTATION_270: + { + Array<octave_idx_type> perm (dim_vector (3, 1)); + perm(0) = 0; + perm(1) = 2; + perm(2) = 1; + pixels = pixels.permute (perm); + + Array<idx_vector> idx (dim_vector (3, 1)); + idx(0) = idx_vector (':'); + idx(1) = idx_vector (':'); + idx(2) = idx_vector (pixels.dim3 ()-1, -1, -1); + pixels = uint8NDArray (pixels.index (idx)); + } + break; + } + } + + return 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. + +Matrix +ft_render::get_extent (text_element *elt, double rotation) +{ + set_mode (MODE_BBOX); + elt->accept (*this); + + Matrix extent (1, 2, 0.0); + + switch (rotation_to_mode (rotation)) + { + case ROTATION_0: + case ROTATION_180: + extent(0) = bbox(2); + extent(1) = bbox(3); + break; + case ROTATION_90: + case ROTATION_270: + extent(0) = bbox(3); + extent(1) = bbox(2); + } + + return extent; +} + +Matrix +ft_render::get_extent (const std::string& txt, double rotation) +{ + text_element *elt = text_parser_none ().parse (txt); + Matrix extent = get_extent (elt, rotation); + delete elt; + + return extent; +} + +int +ft_render::rotation_to_mode (double rotation) const +{ + if (rotation == 0.0) + return ROTATION_0; + else if (rotation == 90.0) + return ROTATION_90; + else if (rotation == 180.0) + return ROTATION_180; + else if (rotation == 270.0) + return ROTATION_270; + else + return ROTATION_0; +} + +void +ft_render::text_to_pixels (const std::string& txt, + uint8NDArray& pixels_, Matrix& box, + int halign, int valign, double rotation) +{ + // FIXME: clip "rotation" between 0 and 360 + int rot_mode = rotation_to_mode (rotation); + + multiline_halign = halign; + + text_element *elt = text_parser_none ().parse (txt); + pixels_ = render (elt, box, rot_mode); + delete elt; + + if (pixels_.numel () == 0) + { + // nothing to render + return; + } + + switch (halign) + { + default: box(0) = 0; break; + case 1: box(0) = -box(2)/2; break; + case 2: box(0) = -box(2); break; + } + switch (valign) + { + default: box(1) = 0; break; + case 1: box(1) = -box(3)/2; break; + case 2: box(1) = -box(3); break; + case 3: break; + case 4: box(1) = -box(3)-box(1); break; + } + + switch (rot_mode) + { + case ROTATION_90: + std::swap (box(0), box(1)); + std::swap (box(2), box(3)); + box(0) = -box(0)-box(2); + break; + case ROTATION_180: + box(0) = -box(0)-box(2); + box(1) = -box(1)-box(3); + break; + case ROTATION_270: + std::swap (box(0), box(1)); + std::swap (box(2), box(3)); + box(1) = -box(1)-box(3); + break; + } +} + +#endif // HAVE_FREETYPE