26 #if defined (HAVE_CONFIG_H)
33 #if defined (HAVE_FREETYPE)
35 #if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
36 # pragma GCC diagnostic push
37 # pragma GCC diagnostic ignored "-Wold-style-cast"
41 #include FT_FREETYPE_H
44 #if defined (HAVE_FONTCONFIG)
45 # include <fontconfig/fontconfig.h>
48 #if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
49 # pragma GCC diagnostic pop
76 "text_renderer: skipping missing glyph for character '%lx'", c);
83 "text_renderer: unable to render glyph for character '%lx'", c);
86 #if defined (_MSC_VER)
105 : library (), freetype_initialized (false), fontconfig_initialized (false)
107 if (FT_Init_FreeType (&library))
108 error (
"unable to initialize FreeType library");
110 freetype_initialized =
true;
112 #if defined (HAVE_FONTCONFIG)
114 error (
"unable to initialize fontconfig library");
116 fontconfig_initialized =
true;
132 if (freetype_initialized)
133 FT_Done_FreeType (library);
135 #if defined (HAVE_FONTCONFIG)
162 static FT_Face
get_font (
const std::string&
name,
const std::string& weight,
163 const std::string& angle,
double size)
165 return (instance_ok ()
166 ? instance->do_get_font (
name, weight, angle, size)
172 return (instance_ok ()
173 ? instance->do_get_system_fonts ()
180 instance->do_font_destroyed (face);
187 typedef std::pair<std::string, double>
ft_key;
201 #if defined (HAVE_FONTCONFIG)
202 FcConfig *config = FcConfigGetCurrent();
203 FcPattern *pat = FcPatternCreate ();
204 FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, FC_SLANT, FC_WEIGHT,
205 FC_CHARSET,
nullptr);
206 FcFontSet *fs = FcFontList (config, pat, os);
211 FcCharSet *minimal_charset = FcCharSetCreate ();
212 for (
int i = 32; i < 127; i++)
213 FcCharSetAddChar (minimal_charset,
static_cast<FcChar32
> (i));
216 fields(0) =
"family";
218 fields(2) =
"weight";
219 fields(3) =
"suitable";
227 unsigned char *family;
229 for (
int i = 0; fs && i < fs->nfont; i++)
231 FcPattern *font = fs->fonts[i];
232 if (FcPatternGetString (font, FC_FAMILY, 0, &family)
234 families(i) = std::string (
reinterpret_cast<char*
> (family));
236 families(i) =
"unknown";
238 if (FcPatternGetInteger (font, FC_SLANT, 0, &val)
240 angles(i) = (val == FC_SLANT_ITALIC
241 || val == FC_SLANT_OBLIQUE)
242 ?
"italic" :
"normal";
244 angles(i) =
"unknown";
246 if (FcPatternGetInteger (font, FC_WEIGHT, 0, &val)
248 weights(i) = (val == FC_WEIGHT_BOLD
249 || val == FC_WEIGHT_DEMIBOLD)
252 weights(i) =
"unknown";
255 if (FcPatternGetCharSet (font, FC_CHARSET, 0, &cset)
257 suitable(i) = (FcCharSetIsSubset (minimal_charset, cset)
265 font_map.
assign (
"family", families);
266 font_map.
assign (
"angle", angles);
267 font_map.
assign (
"weight", weights);
268 font_map.
assign (
"suitable", suitable);
271 FcFontSetDestroy (fs);
280 const std::string& angle,
double size)
284 #if defined (HAVE_FT_REFERENCE_FACE)
288 ft_key key (
name +
':' + weight +
':' + angle, size);
289 ft_cache::const_iterator it = cache.find (key);
291 if (it != cache.end ())
293 FT_Reference_Face (it->second);
298 static std::string fonts_dir;
300 if (fonts_dir.empty ())
304 if (fonts_dir.empty ())
305 #if defined (SYSTEM_FREEFONT_DIR)
306 fonts_dir = SYSTEM_FREEFONT_DIR;
316 if (! fonts_dir.empty ())
320 if (weight ==
"bold")
323 if (angle ==
"italic" || angle ==
"oblique")
329 #if defined (HAVE_FONTCONFIG)
330 if (
name !=
"*" && fontconfig_initialized)
332 int fc_weight, fc_angle;
334 if (weight ==
"bold")
335 fc_weight = FC_WEIGHT_BOLD;
337 fc_weight = FC_WEIGHT_NORMAL;
339 if (angle ==
"italic")
340 fc_angle = FC_SLANT_ITALIC;
341 else if (angle ==
"oblique")
342 fc_angle = FC_SLANT_OBLIQUE;
344 fc_angle = FC_SLANT_ROMAN;
346 FcPattern *pat = FcPatternCreate ();
348 FcPatternAddString (pat, FC_FAMILY,
349 (
reinterpret_cast<const FcChar8 *
>
352 FcPatternAddInteger (pat, FC_WEIGHT, fc_weight);
353 FcPatternAddInteger (pat, FC_SLANT, fc_angle);
354 FcPatternAddDouble (pat, FC_PIXEL_SIZE, size);
356 if (FcConfigSubstitute (
nullptr, pat, FcMatchPattern))
361 FcDefaultSubstitute (pat);
362 match = FcFontMatch (
nullptr, pat, &res);
370 FcPatternGetString (match, FC_FILE, 0, &tmp);
371 file =
reinterpret_cast<char *
> (tmp);
374 ::warning (
"could not match any font: %s-%s-%s-%g, using default font",
375 name.c_str (), weight.c_str (), angle.c_str (),
379 FcPatternDestroy (match);
382 FcPatternDestroy (pat);
387 ::warning (
"unable to find default font files");
390 if (FT_New_Face (library, file.c_str (), 0, &
retval))
391 ::warning (
"ft_manager: unable to load font: %s", file.c_str ());
392 #if defined (HAVE_FT_REFERENCE_FACE)
403 if (FT_Reference_Face (
retval) == 0)
414 if (face->generic.data)
416 ft_key *pkey =
reinterpret_cast<ft_key *
> (face->generic.data);
420 face->generic.data =
nullptr;
463 xoffset (0), line_yoffset (0), yoffset (0), mode (MODE_BBOX),
464 color (
dim_vector (1, 3), 0), m_do_strlist (false), m_strlist (),
465 line_xoffset (0), m_ymin (0), m_ymax (0), m_deltax (0),
466 m_max_fontsize (0), m_antialias (true)
504 int rotation = ROTATION_0);
507 Matrix get_extent (
const std::string& txt,
double rotation,
512 void set_font (
const std::string&
name,
const std::string& weight,
513 const std::string& angle,
double size);
517 void set_color (
const Matrix& c);
519 void set_mode (
int m);
521 void text_to_pixels (
const std::string& txt,
523 int halign,
int valign,
double rotation,
525 bool handle_rotation);
529 int rotation_to_mode (
double rotation)
const;
541 ft_font (
const std::string& nm,
const std::string& wt,
542 const std::string& ang,
double sz, FT_Face
f =
nullptr)
558 FT_Face get_face (
void)
const;
565 void push_new_line (
void);
567 void update_line_bbox (
void);
569 void compute_bbox (
void);
571 int compute_line_xoffset (
const Matrix& lb)
const;
573 FT_UInt process_character (FT_ULong code, FT_UInt previous = 0);
577 void text_to_strlist (
const std::string& txt,
578 std::list<text_renderer::string>& lst,
Matrix& bbox,
579 int halign,
int valign,
double rotation,
646 const std::string& weight,
647 const std::string& angle,
double size)
693 + (new_bbox(3) + new_bbox(1)));
711 return (
bbox(2) - lb(2)) / 2;
713 return (
bbox(2) - lb(2));
792 ::error (
"ft_text_renderer: invalid bounding box, cannot render");
809 error (
"ft_text_renderer: invalid mode '%d'",
mode);
813 bool is_opaque (
const FT_GlyphSlot &glyph,
const int x,
const int y)
817 int pitch =
std::abs (glyph->bitmap.pitch);
818 unsigned char *row = &glyph->bitmap.buffer[pitch * y];
819 char cvalue = row[
x >> 3];
821 return ((cvalue & (128 >> (
x & 7))) != 0);
828 FT_UInt glyph_index = 0;
832 glyph_index = FT_Get_Char_Index (face, code);
834 if (code !=
'\n' && code !=
'\t'
836 || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)))
841 else if ((code ==
'\n') || (code ==
'\t'))
843 glyph_index = FT_Get_Char_Index (face,
' ');
845 || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
850 else if (code ==
'\n')
856 int x_tab = 4 * (face->glyph->advance.x >> 6);
866 ? FT_RENDER_MODE_NORMAL
867 : FT_RENDER_MODE_MONO)))
874 FT_Bitmap& bitmap = face->glyph->bitmap;
881 FT_Get_Kerning (face, previous, glyph_index,
882 FT_KERNING_DEFAULT, &delta);
886 x0 =
xoffset + face->glyph->bitmap_left;
896 for (
int r = 0;
static_cast<unsigned int> (
r) < bitmap.rows;
r++)
897 for (
int c = 0;
static_cast<unsigned int> (c) < bitmap.width; c++)
901 ? bitmap.buffer[
r*bitmap.width+c]
910 else if (
pixels(3, x0+c, y0-
r).value () == 0)
919 xoffset += (face->glyph->advance.x >> 6);
933 FT_Get_Kerning (face, previous, glyph_index,
934 FT_KERNING_DEFAULT, &delta);
942 xoffset += (face->glyph->advance.x >> 6);
947 if (FT_Get_Glyph (face->glyph, &glyph))
952 FT_Glyph_Get_CBox (glyph, FT_GLYPH_BBOX_UNSCALED,
954 m_deltax = (glyph_bbox.xMax - face->glyph->advance.x) >> 6;
959 FT_Done_Glyph (glyph);
972 std::list<text_renderer::string>& lst,
974 int ha,
int va,
double rot,
981 m_strlist = std::list<text_renderer::string> ();
999 FT_UInt glyph_index, previous = 0;
1002 const uint8_t *c =
reinterpret_cast<const uint8_t *
> (str.c_str ());
1005 size_t n = str.size ();
1012 std::vector<double> xdata;
1037 std::string s = str.substr (ibegin, icurr - ibegin);
1067 previous = glyph_index;
1094 color = saved_color;
1221 std::vector<double> xdata (1,
xoffset);
1251 for (
auto *txt_elt : e)
1254 txt_elt->accept (*
this);
1266 m_strlist = std::list<text_renderer::string> ();
1272 if (c.
numel () == 3)
1274 color(0) =
static_cast<uint8_t
> (c(0)*255);
1275 color(1) =
static_cast<uint8_t
> (c(1)*255);
1276 color(2) =
static_cast<uint8_t
> (c(2)*255);
1279 ::warning (
"ft_text_renderer::set_color: invalid color");
1360 Matrix extent (1, 2, 0.0);
1366 extent(0) =
bbox(2);
1367 extent(1) =
bbox(3);
1372 extent(0) =
bbox(3);
1373 extent(1) =
bbox(2);
1394 while (rotation < 0)
1396 while (rotation > 360.0)
1399 if (rotation == 0.0)
1401 else if (rotation == 90.0)
1403 else if (rotation == 180.0)
1405 else if (rotation == 270.0)
1414 int _halign,
int valign,
double rotation,
1416 bool handle_rotation)
1466 if (handle_rotation)
1471 std::swap (
box(0),
box(1));
1472 std::swap (
box(2),
box(3));
1482 std::swap (
box(0),
box(1));
1483 std::swap (
box(2),
box(3));
1493 #if defined (HAVE_FT_REFERENCE_FACE)
1496 if (ft_face && FT_Reference_Face (ft_face) == 0)
1510 FT_Done_Face (face);
1514 #if defined (HAVE_FT_REFERENCE_FACE)
1517 if (ft_face && FT_Reference_Face (ft_face) == 0)
1528 if (! face && !
name.empty ())
1534 if (FT_Set_Char_Size (face, 0, size*64, 0, 0))
1535 ::warning (
"ft_text_renderer: unable to set font size to %g", size);
1538 ::warning (
"ft_text_renderer: unable to load appropriate font");
1552 #if defined (HAVE_FREETYPE)
charNDArray max(char d, const charNDArray &m)
octave_idx_type dim3(void) const
Size of the specified dimension.
octave_idx_type numel(void) const
Number of elements in the array.
const T * data(void) const
Size of the specified dimension.
Array< T > index(const idx_vector &i) const
Indexing without resizing.
octave_idx_type dim2(void) const
bool isempty(void) const
Size of the specified dimension.
MArray< T > permute(const Array< octave_idx_type > &vec, bool inv=false) const
Matrix extract(octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) const
Vector representing the dimensions (size) of an Array.
bool fontconfig_initialized
void do_font_destroyed(FT_Face face)
bool freetype_initialized
static FT_Face get_font(const std::string &name, const std::string &weight, const std::string &angle, double size)
std::pair< std::string, double > ft_key
static ft_manager * instance
static octave_map get_system_fonts(void)
static bool instance_ok(void)
FT_Face do_get_font(const std::string &name, const std::string &weight, const std::string &angle, double size)
static void cleanup_instance(void)
static octave_map do_get_system_fonts(void)
static void font_destroyed(FT_Face face)
std::map< ft_key, FT_Face > ft_cache
ft_manager(const ft_manager &)=delete
ft_font & operator=(const ft_font &ft)
ft_font(const std::string &nm, const std::string &wt, const std::string &ang, double sz, FT_Face f=nullptr)
bool is_valid(void) const
FT_Face get_face(void) const
std::list< text_renderer::string > m_strlist
ft_text_renderer(const ft_text_renderer &)=delete
std::list< Matrix > line_bbox
void visit(text_element_string &e)
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)
Matrix get_extent(text_element *elt, double rotation=0.0)
int compute_line_xoffset(const Matrix &lb) const
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)
void update_line_bbox(void)
Matrix get_boundingbox(void) const
void set_font(const std::string &name, const std::string &weight, const std::string &angle, double size)
uint8NDArray get_pixels(void) const
void set_anti_aliasing(bool val)
octave_map get_system_fonts(void)
uint8NDArray render(text_element *elt, Matrix &box, int rotation=ROTATION_0)
void set_color(const Matrix &c)
int rotation_to_mode(double rotation) const
FT_UInt process_character(FT_ULong code, FT_UInt previous=0)
~ft_text_renderer(void)=default
static std::string getenv(const std::string &name)
const std::string & get_fontname(void) const
double get_fontsize(void) const
fontstyle get_fontstyle(void) const
std::string string_value(void) const
uint32_t get_symbol_code(void) const
int get_symbol(void) const
virtual void accept(text_processor &p)=0
virtual text_element * parse(const std::string &s)=0
virtual void visit(text_element_string &e)=0
std::string get_angle(void) const
double get_size(void) const
std::string get_weight(void) const
font & operator=(const font &ft)
std::string get_name(void) const
void set_family(const std::string &nm)
void set_string(const std::string &s)
void set_code(const uint32_t c)
void set_xdata(const std::vector< double > &x0)
void set_y(const double y0)
std::string get_string(void) const
uint32_t get_code(void) const
void set_color(const uint8NDArray &c)
void assign(const std::string &k, const Cell &val)
void warning(const char *fmt,...)
void warning_with_id(const char *id, const char *fmt,...)
void error(const char *fmt,...)
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x
std::string oct_fonts_dir(void)
std::complex< T > ceil(const std::complex< T > &x)
std::complex< T > floor(const std::complex< T > &x)
std::string dir_sep_str(void)
static double f(double k, double l_nu, double c_pm)
static void ft_face_destroyed(void *object)
static void warn_glyph_render(FT_ULong c)
static void warn_missing_glyph(FT_ULong c)
base_text_renderer * make_ft_text_renderer(void)
bool is_opaque(const FT_GlyphSlot &glyph, const int x, const int y)
static octave_value box(JNIEnv *jni_env, void *jobj, void *jcls_arg=nullptr)
octave_value::octave_value(const Array< char > &chm, char type) return retval
intNDArray< octave_uint8 > uint8NDArray
int octave_u8_strmbtouc_wrapper(uint32_t *puc, const uint8_t *src)