From 2a0db1dd5e69d1702fa4a6f76a30938063319db8 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Sun, 15 Jan 2023 09:25:26 +1030 Subject: [PATCH 01/26] lua text: Supporting infra Add empty files and various build options for the lua text bindings Adds requirements for Fontconfig, Freetype and Harfbuzz --- .github/workflows/build-and-test-linux.yaml | 1 + AUTHORS | 3 ++ Dockerfile | 8 +++++ appimage/build.sh | 1 + cmake/ConkyBuildOptions.cmake | 1 + cmake/ConkyPlatformChecks.cmake | 11 +++++++ cmake/config.h.in | 2 ++ lua/CMakeLists.txt | 17 ++++++++++ lua/cairo_text_helper.pkg | 7 ++++ lua/libcairo_text_helper.h | 36 +++++++++++++++++++++ lua/text.pkg | 0 src/main.cc | 5 ++- 12 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 lua/cairo_text_helper.pkg create mode 100644 lua/libcairo_text_helper.h create mode 100644 lua/text.pkg diff --git a/.github/workflows/build-and-test-linux.yaml b/.github/workflows/build-and-test-linux.yaml index c126fef3f..9818dea51 100644 --- a/.github/workflows/build-and-test-linux.yaml +++ b/.github/workflows/build-and-test-linux.yaml @@ -137,6 +137,7 @@ jobs: -DBUILD_LUA_CAIRO=ON \ -DBUILD_LUA_IMLIB2=ON \ -DBUILD_LUA_RSVG=${RSVG_ENABLED} \ + -DBUILD_LUA_TEXT=ON \ -DBUILD_MYSQL=ON \ -DBUILD_NVIDIA=ON \ -DBUILD_PULSEAUDIO=ON \ diff --git a/AUTHORS b/AUTHORS index cb4774e32..331f285a7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -313,6 +313,9 @@ Mikko Sysikaski Sceptik --quiet patch +Simon Lees + lua text + Stepan Zastupov WiFi signal level detection support on FreeBSD diff --git a/Dockerfile b/Dockerfile index 5a5eaa9e7..9bbedb499 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,6 +16,9 @@ RUN apt-get update \ libcairo2-dev \ libcurl4-openssl-dev \ libdbus-glib-1-dev \ + libfontconfig-dev \ + libfreetype-dev \ + libharfbuzz-dev \ libical-dev \ libimlib2-dev \ libircclient-dev \ @@ -76,6 +79,7 @@ RUN sh -c 'if [ "$X11" = "yes" ] ; then \ -DBUILD_LUA_CAIRO=ON \ -DBUILD_LUA_IMLIB2=ON \ -DBUILD_LUA_RSVG=ON \ + -DBUILD_LUA_TEXT=ON \ -DBUILD_MYSQL=ON \ -DBUILD_NVIDIA=ON \ -DBUILD_PULSEAUDIO=ON \ @@ -98,6 +102,7 @@ RUN sh -c 'if [ "$X11" = "yes" ] ; then \ -DBUILD_LUA_CAIRO=ON \ -DBUILD_LUA_IMLIB2=ON \ -DBUILD_LUA_RSVG=ON \ + -DBUILD_LUA_TEXT=ON \ -DBUILD_MYSQL=ON \ -DBUILD_PULSEAUDIO=ON \ -DBUILD_RSS=ON \ @@ -121,6 +126,9 @@ RUN apt-get update \ libcairo2 \ libcurl4 \ libdbus-glib-1-2 \ + libfontconfig1 \ + libfreetype6 \ + libharfbuzz-gobject0 \ libical3 \ libimlib2 \ libircclient1 \ diff --git a/appimage/build.sh b/appimage/build.sh index 3c357035f..7fa7199d5 100755 --- a/appimage/build.sh +++ b/appimage/build.sh @@ -44,6 +44,7 @@ cmake -G Ninja \ -DBUILD_LUA_CAIRO=ON \ -DBUILD_LUA_IMLIB2=ON \ -DBUILD_LUA_RSVG=ON \ + -DBUILD_LUA_TEXT=ON \ -DBUILD_MYSQL=ON \ -DBUILD_NVIDIA=ON \ -DBUILD_PULSEAUDIO=ON \ diff --git a/cmake/ConkyBuildOptions.cmake b/cmake/ConkyBuildOptions.cmake index 713430bd6..85515926c 100644 --- a/cmake/ConkyBuildOptions.cmake +++ b/cmake/ConkyBuildOptions.cmake @@ -204,6 +204,7 @@ endif(OWN_WINDOW) option(BUILD_LUA_CAIRO "Build cairo bindings for Lua" false) option(BUILD_LUA_IMLIB2 "Build Imlib2 bindings for Lua" false) option(BUILD_LUA_RSVG "Build rsvg bindings for Lua" false) +option(BUILD_LUA_TEXT "Build Fontconfig Freetype and Harfbuzz bindings for Lua" false) option(BUILD_AUDACIOUS "Build audacious (music player) support" false) diff --git a/cmake/ConkyPlatformChecks.cmake b/cmake/ConkyPlatformChecks.cmake index ac1cfd485..4e8a28216 100644 --- a/cmake/ConkyPlatformChecks.cmake +++ b/cmake/ConkyPlatformChecks.cmake @@ -478,6 +478,17 @@ if(BUILD_X11) set(luarsvg_libs ${RSVG_LIBRARIES} ${LUA_LIBRARIES}) set(luarsvg_includes ${RSVG_INCLUDE_DIRS} ${LUA_INCLUDE_DIR}) endif(BUILD_LUA_RSVG) + if(BUILD_LUA_TEXT) + if(FREETYPE_INCLUDE_DIR_freetype2) + set(FREETYPE_FOUND true) + else(FREETYPE_INCLUDE_DIR_freetype2) + message(FATAL_ERROR "Unable to find freetype library") + endif(FREETYPE_INCLUDE_DIR_freetype2) + PKG_CHECK_MODULES(FONTCONFIG REQUIRED fontconfig) + PKG_CHECK_MODULES(HARFBUZZ REQUIRED harfbuzz) + set(luatext_libs ${FREETYPE_LIBRARIES} ${FONTCONFIG_LIBRARIES} ${HARFBUZZ_LIBRARIES} ${LUA_LIBRARIES}) + set(luatext_includes ${FREETYPE_INCLUDE_DIR_freetype2} ${FONTCONFIG_INCLUDE_DIRS} ${HARFBUZZ_INCLUDE_DIRS} ${LUA_INCLUDE_DIRS}) + endif(BUILD_LUA_TEXT) endif(BUILD_X11) if(BUILD_AUDACIOUS) diff --git a/cmake/config.h.in b/cmake/config.h.in index 54936c3f4..733a913ac 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -127,6 +127,8 @@ #cmakedefine BUILD_LUA_RSVG 1 +#cmakedefine BUILD_LUA_TEXT 1 + #cmakedefine BUILD_IBM 1 #cmakedefine BUILD_RSS 1 diff --git a/lua/CMakeLists.txt b/lua/CMakeLists.txt index b3acd19a0..71697645d 100644 --- a/lua/CMakeLists.txt +++ b/lua/CMakeLists.txt @@ -75,6 +75,7 @@ if(BUILD_X11) print_target_properties(conky-rsvg) endif(BUILD_LUA_RSVG) + if(BUILD_LUA_CAIRO AND BUILD_LUA_IMLIB2) include_directories(${luacairo_includes} ${luaimlib2_includes} ${CMAKE_CURRENT_SOURCE_DIR}) @@ -90,6 +91,22 @@ if(BUILD_X11) toluapp_lib_static) set(lua_libs ${lua_libs} conky-cairo_imlib2_helper) endif(BUILD_LUA_CAIRO AND BUILD_LUA_IMLIB2) + + if(BUILD_LUA_CAIRO AND BUILD_LUA_TEXT) + include_directories(${luacairo_includes} ${luatext_includes} + ${CMAKE_CURRENT_SOURCE_DIR}) + wrap_tolua(luacairo_text_helper_src cairo_text_helper.pkg) + + add_library(conky-cairo_text_helper SHARED ${luacairo_text_helper_src}) + set_target_properties(conky-cairo_text_helper + PROPERTIES OUTPUT_NAME "cairo_text_helper") + + target_link_libraries(conky-cairo_text_helper + ${luacairo_libs} + ${luatext_libs} + toluapp_lib_static) + set(lua_libs ${lua_libs} conky-cairo_text_helper) + endif(BUILD_LUA_CAIRO AND BUILD_LUA_TEXT) endif(BUILD_X11) install(TARGETS ${lua_libs} diff --git a/lua/cairo_text_helper.pkg b/lua/cairo_text_helper.pkg new file mode 100644 index 000000000..8f8ce6512 --- /dev/null +++ b/lua/cairo_text_helper.pkg @@ -0,0 +1,7 @@ +$#include +$#include + +void cairo_draw_text(const char *text, const char *font, int size, + cairo_surface_t *cs, int x, int y, double scale_x, + double scale_y, double *return_scale_w, + double *return_scale_h); diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h new file mode 100644 index 000000000..053703995 --- /dev/null +++ b/lua/libcairo_text_helper.h @@ -0,0 +1,36 @@ +/* + * + * Conky, a system monitor, based on torsmo + * + * Please see COPYING for details + * + * Copyright (c) 2005-2021 Brenden Matthews, Philip Kovacs, et. al. + * (see AUTHORS) + * All rights reserved. + * + * This program 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. + * + * This program 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 this program. If not, see . + * + */ + +#ifndef _LIBCAIRO_TEXT_HELPER_H_ +#define _LIBCAIRO_TEXT_HELPER_H_ + +// string, font, size + +void cairo_draw_image(const char *text, const char *font, int size, + cairo_surface_t *cs, int x, int y, double scale_x, + double scale_y, double *return_scale_w, + double *return_scale_h) { + +} +#endif diff --git a/lua/text.pkg b/lua/text.pkg new file mode 100644 index 000000000..e69de29bb diff --git a/src/main.cc b/src/main.cc index 82458077a..50e27d13e 100644 --- a/src/main.cc +++ b/src/main.cc @@ -143,7 +143,7 @@ static void print_version() { #ifdef DEBUG << _(" * Debugging extensions\n") #endif -#if defined BUILD_LUA_CAIRO || defined BUILD_LUA_IMLIB2 || BUILD_LUA_RSVG +#if defined BUILD_LUA_CAIRO || defined BUILD_LUA_IMLIB2 || BUILD_LUA_RSVG || BUILD_LUA_TEXT << _("\n Lua bindings:\n") #endif #ifdef BUILD_LUA_CAIRO @@ -155,6 +155,9 @@ static void print_version() { #ifdef BUILD_LUA_RSVG << _(" * RSVG\n") #endif /* BUILD_LUA_RSVG */ +#ifdef BUILD_LUA_TEXT + << _(" * TEXT\n") +#endif /* BUILD_LUA_RSVG */ #ifdef BUILD_X11 << _(" X11:\n") #ifdef BUILD_XDAMAGE From 79b81a628076714be5f31cdc295d3a8e818e23fc Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Wed, 15 Feb 2023 09:43:50 +1030 Subject: [PATCH 02/26] lua text: initial implementation. --- lua/cairo_text_helper.pkg | 23 ++++- lua/libcairo_text_helper.h | 167 +++++++++++++++++++++++++++++++++++-- 2 files changed, 181 insertions(+), 9 deletions(-) diff --git a/lua/cairo_text_helper.pkg b/lua/cairo_text_helper.pkg index 8f8ce6512..47cb96928 100644 --- a/lua/cairo_text_helper.pkg +++ b/lua/cairo_text_helper.pkg @@ -1,7 +1,22 @@ $#include $#include -void cairo_draw_text(const char *text, const char *font, int size, - cairo_surface_t *cs, int x, int y, double scale_x, - double scale_y, double *return_scale_w, - double *return_scale_h); +typedef struct _FontData { + cairo_font_face_t *cairo_ft_face; + hb_font_t *hb_ft_font; + hb_face_t *hb_ft_face; + int font_size; + /* Internally the following two are pointers */ + /* Stored here so they can be freed later */ + FT_Library ft_library; + FT_Face ft_face; +}FontData; + +FontData * cairo_text_hp_load_font(const char *font, int font_size); + +void cairo_text_hp_destroy_font(FontData *font); + +void cairo_text_hp_simple_show(cairo_t *cr, int x, int y, const char *text, FontData *font); + +void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontData *font, + const char *direction, const char *script, const char *language); diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h index 053703995..2d22c4b25 100644 --- a/lua/libcairo_text_helper.h +++ b/lua/libcairo_text_helper.h @@ -25,12 +25,169 @@ #ifndef _LIBCAIRO_TEXT_HELPER_H_ #define _LIBCAIRO_TEXT_HELPER_H_ -// string, font, size +#include +#include -void cairo_draw_image(const char *text, const char *font, int size, - cairo_surface_t *cs, int x, int y, double scale_x, - double scale_y, double *return_scale_w, - double *return_scale_h) { +#include +#include +#include FT_FREETYPE_H +#include +#include +#include +#include + +#include +#include +#include + +typedef struct _FontData { + cairo_font_face_t *cairo_ft_face; + hb_font_t *hb_ft_font; + hb_face_t *hb_ft_face; + int font_size; + /* Internally the following two are pointers */ + /* Stored here so they can be freed later */ + FT_Library ft_library; + FT_Face ft_face; +}FontData; + +FontData *cairo_text_hp_load_font(const char *font, int font_size) +{ + /* Fontconfig will take a font name and return the file with */ + /* the best match as Freetype only works directly with font files */ + + FcInit(); + FcConfig* config = FcInitLoadConfigAndFonts(); + + FcPattern* pat = FcNameParse((const FcChar8*)font); + FcConfigSubstitute(config, pat, FcMatchPattern); + FcDefaultSubstitute(pat); + + FcResult result; + FcPattern* font_pat = FcFontMatch(config, pat, &result); + + /* Will be freed with font */ + FcChar8* file = NULL; + FcPatternGetString(font_pat, FC_FILE, 0, &file); + + if (!file) { + /* FIXME: add error handling */ + return NULL; + } + + FontData *font_data = malloc(sizeof(struct _FontData)); + + /* Load the font */ + FT_Init_FreeType(&font_data->ft_library); + FT_Library_SetLcdFilter(font_data->ft_library, FT_LCD_FILTER_DEFAULT); + FT_New_Face(font_data->ft_library, (char *)file, 0, &font_data->ft_face); + FT_Set_Char_Size(font_data->ft_face, font_size*64, font_size*64,0,0); + + /* Store font data for use later */ + font_data->cairo_ft_face = cairo_font_face_reference(cairo_ft_font_face_create_for_ft_face(font_data->ft_face, 0)); + font_data->hb_ft_font = hb_ft_font_create(font_data->ft_face, NULL); + font_data->hb_ft_face = hb_ft_face_create(font_data->ft_face, NULL); + font_data->font_size = font_size; + + /* Cleanup font config */ + FcPatternDestroy(font_pat); + FcPatternDestroy(pat); + FcConfigDestroy(config); + /* FIXME: Crashes */ + /*FcFini(); */ + + return font_data; +} + +void cairo_text_hp_destroy_font(FontData *font) +{ + cairo_font_face_destroy(font->cairo_ft_face); + cairo_font_face_destroy (font->cairo_ft_face); + hb_font_destroy(font->hb_ft_font); + hb_face_destroy(font->hb_ft_face); + + FT_Done_Face (font->ft_face); + FT_Done_FreeType(font->ft_library); + + free(font); +} + +/* + * Direction calls hb_direction_from_string example values are LTR and RTL + * https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-direction-from-string + * Script is an ISO 15924 4 character string, "Zyyy" can be used for "Common" and "Zinh" + * for "Inherited". + * https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-script-from-string + * Language is a BCP 47 language tag. eg "en" or "en-US" + */ +void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontData *font, + const char *direction, const char *script, const char *language) +{ + /* FIXME: Support others */ + hb_direction_t text_direction = hb_direction_from_string(direction, -1); + if (text_direction == HB_DIRECTION_INVALID) { + text_direction = HB_DIRECTION_LTR; + } + hb_script_t text_script = hb_script_from_string(script, -1); + if (text_script == HB_SCRIPT_UNKNOWN) { + text_script = HB_SCRIPT_COMMON; + } + + hb_language_t text_language = hb_language_from_string (language, -1); + + /* Draw text */ + /* Create a buffer for harfbuzz to use */ + hb_buffer_t *buf = hb_buffer_create(); + + //alternatively you can use hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); + hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); + hb_buffer_set_direction(buf, text_direction); /* or LTR */ + hb_buffer_set_script(buf, text_script); /* see hb-unicode.h */ + hb_buffer_set_language(buf, text_language); + + /* Layout the text */ + hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); + hb_shape(font->hb_ft_font, buf, NULL, 0); + + /* Hand the layout to cairo to render */ + unsigned int glyph_count; + hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); + hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); + cairo_glyph_t *cairo_glyphs = malloc(sizeof(cairo_glyph_t) * glyph_count); + + unsigned int string_width_in_pixels = 0; + for (int i=0; i < glyph_count; ++i) { + string_width_in_pixels += glyph_pos[i].x_advance/64; + } + int draw_x = x; + if (HB_DIRECTION_IS_VERTICAL(text_direction)) { + /* FIXME */ + //draw_x = width/2 - string_width_in_pixels/2; + } else if (text_direction == HB_DIRECTION_RTL){ + draw_x = cairo_image_surface_get_width(cairo_get_target(cr)) + x; + } + + for (int i=0; i < glyph_count; ++i) { + cairo_glyphs[i].index = glyph_info[i].codepoint; + cairo_glyphs[i].x = x + (glyph_pos[i].x_offset/64.0); + cairo_glyphs[i].y = y - (glyph_pos[i].y_offset/64.0); + x += glyph_pos[i].x_advance/64.0; + y -= glyph_pos[i].y_advance/64.0; + } + + cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0); + cairo_set_font_face(cr, font->cairo_ft_face); + cairo_set_font_size(cr, font->font_size); + cairo_show_glyphs(cr, cairo_glyphs, glyph_count); + + free(cairo_glyphs); + hb_buffer_destroy(buf); +} + +void cairo_text_hp_simple_show(cairo_t *cr, int x, int y, const char *text, FontData *font) +{ + cairo_text_hp_intl_show(cr, x, y, text, font, "LTR", "Zyyy", "en"); } + #endif From 24706e834c72d8f14991be818cd139385a8c33b2 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Tue, 11 Apr 2023 21:24:34 +0930 Subject: [PATCH 03/26] Add the ability to center and right align text. --- lua/cairo_text_helper.pkg | 17 ++++++- lua/libcairo_text_helper.h | 98 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 6 deletions(-) diff --git a/lua/cairo_text_helper.pkg b/lua/cairo_text_helper.pkg index 47cb96928..170f23e45 100644 --- a/lua/cairo_text_helper.pkg +++ b/lua/cairo_text_helper.pkg @@ -12,11 +12,26 @@ typedef struct _FontData { FT_Face ft_face; }FontData; +typedef enum _cairo_text_alignment { + CAIRO_TEXT_ALIGN_LEFT = 0, + CAIRO_TEXT_ALIGN_RIGHT, + CAIRO_TEXT_ALIGN_CENTER +} cairo_text_alignment_t; + FontData * cairo_text_hp_load_font(const char *font, int font_size); void cairo_text_hp_destroy_font(FontData *font); void cairo_text_hp_simple_show(cairo_t *cr, int x, int y, const char *text, FontData *font); +void cairo_text_hp_simple_show_center(cairo_t *cr, int x, int y, const char *text, FontData *font); +void cairo_text_hp_simple_show_right(cairo_t *cr, int x, int y, const char *text, FontData *font); + +void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t alignment, const char *text, FontData *font, + const char *direction, const char *script, const char *language); -void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontData *font, +int cairo_text_hp_text_width(const char *text, FontData *font, const char *direction, const char *script, const char *language); + +int cairo_text_hp_simple_text_width(const char *text, FontData *font); + +void cairo_text_hp_test(cairo_surface_t *t); \ No newline at end of file diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h index 2d22c4b25..00332920a 100644 --- a/lua/libcairo_text_helper.h +++ b/lua/libcairo_text_helper.h @@ -25,6 +25,8 @@ #ifndef _LIBCAIRO_TEXT_HELPER_H_ #define _LIBCAIRO_TEXT_HELPER_H_ +#include + #include #include @@ -52,6 +54,12 @@ typedef struct _FontData { FT_Face ft_face; }FontData; +typedef enum _cairo_text_alignment { + CAIRO_TEXT_ALIGN_LEFT = 0, + CAIRO_TEXT_ALIGN_RIGHT, + CAIRO_TEXT_ALIGN_CENTER +} cairo_text_alignment_t; + FontData *cairo_text_hp_load_font(const char *font, int font_size) { /* Fontconfig will take a font name and return the file with */ @@ -121,7 +129,7 @@ void cairo_text_hp_destroy_font(FontData *font) * https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-script-from-string * Language is a BCP 47 language tag. eg "en" or "en-US" */ -void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontData *font, +void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t alignment, const char *text, FontData *font, const char *direction, const char *script, const char *language) { /* FIXME: Support others */ @@ -156,18 +164,42 @@ void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontDa hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); cairo_glyph_t *cairo_glyphs = malloc(sizeof(cairo_glyph_t) * glyph_count); + double x1=0, x2=0, y1=0, y2=0; + cairo_clip_extents(cr, &x1, &y1, &x2, &y2); + int width = floor(x2-x1); + int height = floor(y2-y1); + unsigned int string_width_in_pixels = 0; for (int i=0; i < glyph_count; ++i) { string_width_in_pixels += glyph_pos[i].x_advance/64; } int draw_x = x; + if (HB_DIRECTION_IS_VERTICAL(text_direction)) { /* FIXME */ - //draw_x = width/2 - string_width_in_pixels/2; - } else if (text_direction == HB_DIRECTION_RTL){ - draw_x = cairo_image_surface_get_width(cairo_get_target(cr)) + x; + draw_x = width/2 - string_width_in_pixels/2 + x; + } + else { + if (alignment == CAIRO_TEXT_ALIGN_LEFT) { + if (text_direction == HB_DIRECTION_RTL) { + draw_x = width - x - string_width_in_pixels; + } + // LTR handled as default. + } + else if (alignment == CAIRO_TEXT_ALIGN_RIGHT) { + if (text_direction == HB_DIRECTION_RTL) { + draw_x = x; + } + else { + draw_x = width - x - string_width_in_pixels; + } + } + else if (alignment == CAIRO_TEXT_ALIGN_CENTER) { + draw_x = width/2 - string_width_in_pixels/2 + x; + } } + x = draw_x; for (int i=0; i < glyph_count; ++i) { cairo_glyphs[i].index = glyph_info[i].codepoint; cairo_glyphs[i].x = x + (glyph_pos[i].x_offset/64.0); @@ -187,7 +219,63 @@ void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontDa void cairo_text_hp_simple_show(cairo_t *cr, int x, int y, const char *text, FontData *font) { - cairo_text_hp_intl_show(cr, x, y, text, font, "LTR", "Zyyy", "en"); + cairo_text_hp_intl_show(cr, x, y, CAIRO_TEXT_ALIGN_LEFT, text, font, "LTR", "Zyyy", "en"); +} + +void cairo_text_hp_simple_show_center(cairo_t *cr, int x, int y, const char *text, FontData *font) +{ + cairo_text_hp_intl_show(cr, x, y, CAIRO_TEXT_ALIGN_CENTER, text, font, "LTR", "Zyyy", "en"); +} + +void cairo_text_hp_simple_show_right(cairo_t *cr, int x, int y, const char *text, FontData *font) +{ + cairo_text_hp_intl_show(cr, x, y, CAIRO_TEXT_ALIGN_RIGHT, text, font, "LTR", "Zyyy", "en"); +} + +int cairo_text_hp_text_width(const char *text, FontData *font, + const char *direction, const char *script, const char *language) +{ + /* FIXME: Support others */ + hb_direction_t text_direction = hb_direction_from_string(direction, -1); + if (text_direction == HB_DIRECTION_INVALID) { + text_direction = HB_DIRECTION_LTR; + } + hb_script_t text_script = hb_script_from_string(script, -1); + if (text_script == HB_SCRIPT_UNKNOWN) { + text_script = HB_SCRIPT_COMMON; + } + + hb_language_t text_language = hb_language_from_string (language, -1); + + /* Draw text */ + /* Create a buffer for harfbuzz to use */ + hb_buffer_t *buf = hb_buffer_create(); + + //alternatively you can use hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); + hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); + hb_buffer_set_direction(buf, text_direction); /* or LTR */ + hb_buffer_set_script(buf, text_script); /* see hb-unicode.h */ + hb_buffer_set_language(buf, text_language); + + /* Layout the text */ + hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); + hb_shape(font->hb_ft_font, buf, NULL, 0); + + /* Hand the layout to cairo to render */ + unsigned int glyph_count; + hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); + hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); + cairo_glyph_t *cairo_glyphs = malloc(sizeof(cairo_glyph_t) * glyph_count); + + unsigned int string_width_in_pixels = 0; + for (int i=0; i < glyph_count; ++i) { + string_width_in_pixels += glyph_pos[i].x_advance/64; + } + + return string_width_in_pixels; } +int cairo_text_hp_simple_text_width(const char *text, FontData *font) { + return cairo_text_hp_text_width(text, font, "LTR", "Zyyy", "en"); +} #endif From d5d20e8004fab46a8a7789c778be399cbce42808 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Wed, 12 Apr 2023 10:47:25 +0930 Subject: [PATCH 04/26] lua text: Remove test code I thought I already removed this and squashed the commit --- lua/cairo_text_helper.pkg | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lua/cairo_text_helper.pkg b/lua/cairo_text_helper.pkg index 170f23e45..c8401f7db 100644 --- a/lua/cairo_text_helper.pkg +++ b/lua/cairo_text_helper.pkg @@ -32,6 +32,4 @@ void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t a int cairo_text_hp_text_width(const char *text, FontData *font, const char *direction, const char *script, const char *language); -int cairo_text_hp_simple_text_width(const char *text, FontData *font); - -void cairo_text_hp_test(cairo_surface_t *t); \ No newline at end of file +int cairo_text_hp_simple_text_width(const char *text, FontData *font); \ No newline at end of file From b625e935ebd6847216113935b42c702e395aaabc Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Sun, 15 Jan 2023 09:25:26 +1030 Subject: [PATCH 05/26] lua text: Supporting infra Add empty files and various build options for the lua text bindings Adds requirements for Fontconfig, Freetype and Harfbuzz --- .github/workflows/build-and-test-linux.yaml | 1 + AUTHORS | 3 ++ Dockerfile | 8 +++++ appimage/build.sh | 1 + cmake/ConkyBuildOptions.cmake | 1 + cmake/ConkyPlatformChecks.cmake | 12 +++++++ cmake/config.h.in | 2 ++ lua/CMakeLists.txt | 17 ++++++++++ lua/cairo_text_helper.pkg | 7 ++++ lua/libcairo_text_helper.h | 36 +++++++++++++++++++++ lua/text.pkg | 0 src/main.cc | 5 ++- 12 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 lua/cairo_text_helper.pkg create mode 100644 lua/libcairo_text_helper.h create mode 100644 lua/text.pkg diff --git a/.github/workflows/build-and-test-linux.yaml b/.github/workflows/build-and-test-linux.yaml index 92bdc876a..b1829121b 100644 --- a/.github/workflows/build-and-test-linux.yaml +++ b/.github/workflows/build-and-test-linux.yaml @@ -137,6 +137,7 @@ jobs: -DBUILD_LUA_CAIRO=ON \ -DBUILD_LUA_IMLIB2=ON \ -DBUILD_LUA_RSVG=${RSVG_ENABLED} \ + -DBUILD_LUA_TEXT=ON \ -DBUILD_MYSQL=ON \ -DBUILD_NVIDIA=ON \ -DBUILD_PULSEAUDIO=ON \ diff --git a/AUTHORS b/AUTHORS index cb4774e32..331f285a7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -313,6 +313,9 @@ Mikko Sysikaski Sceptik --quiet patch +Simon Lees + lua text + Stepan Zastupov WiFi signal level detection support on FreeBSD diff --git a/Dockerfile b/Dockerfile index 5a5eaa9e7..9bbedb499 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,6 +16,9 @@ RUN apt-get update \ libcairo2-dev \ libcurl4-openssl-dev \ libdbus-glib-1-dev \ + libfontconfig-dev \ + libfreetype-dev \ + libharfbuzz-dev \ libical-dev \ libimlib2-dev \ libircclient-dev \ @@ -76,6 +79,7 @@ RUN sh -c 'if [ "$X11" = "yes" ] ; then \ -DBUILD_LUA_CAIRO=ON \ -DBUILD_LUA_IMLIB2=ON \ -DBUILD_LUA_RSVG=ON \ + -DBUILD_LUA_TEXT=ON \ -DBUILD_MYSQL=ON \ -DBUILD_NVIDIA=ON \ -DBUILD_PULSEAUDIO=ON \ @@ -98,6 +102,7 @@ RUN sh -c 'if [ "$X11" = "yes" ] ; then \ -DBUILD_LUA_CAIRO=ON \ -DBUILD_LUA_IMLIB2=ON \ -DBUILD_LUA_RSVG=ON \ + -DBUILD_LUA_TEXT=ON \ -DBUILD_MYSQL=ON \ -DBUILD_PULSEAUDIO=ON \ -DBUILD_RSS=ON \ @@ -121,6 +126,9 @@ RUN apt-get update \ libcairo2 \ libcurl4 \ libdbus-glib-1-2 \ + libfontconfig1 \ + libfreetype6 \ + libharfbuzz-gobject0 \ libical3 \ libimlib2 \ libircclient1 \ diff --git a/appimage/build.sh b/appimage/build.sh index 3c357035f..7fa7199d5 100755 --- a/appimage/build.sh +++ b/appimage/build.sh @@ -44,6 +44,7 @@ cmake -G Ninja \ -DBUILD_LUA_CAIRO=ON \ -DBUILD_LUA_IMLIB2=ON \ -DBUILD_LUA_RSVG=ON \ + -DBUILD_LUA_TEXT=ON \ -DBUILD_MYSQL=ON \ -DBUILD_NVIDIA=ON \ -DBUILD_PULSEAUDIO=ON \ diff --git a/cmake/ConkyBuildOptions.cmake b/cmake/ConkyBuildOptions.cmake index e38d3f9ba..214f9b9f7 100644 --- a/cmake/ConkyBuildOptions.cmake +++ b/cmake/ConkyBuildOptions.cmake @@ -212,6 +212,7 @@ dependent_option(BUILD_LUA_IMLIB2 "Build Imlib2 bindings for Lua" false "BUILD_X11;BUILD_IMLIB2" false "Imlib2 Lua bindings require X11 and Imlib2") option(BUILD_LUA_RSVG "Build rsvg bindings for Lua" false) +option(BUILD_LUA_TEXT "Build Fontconfig Freetype and Harfbuzz bindings for Lua" false) option(BUILD_AUDACIOUS "Build audacious (music player) support" false) diff --git a/cmake/ConkyPlatformChecks.cmake b/cmake/ConkyPlatformChecks.cmake index f6dab39e3..6c8732a1e 100644 --- a/cmake/ConkyPlatformChecks.cmake +++ b/cmake/ConkyPlatformChecks.cmake @@ -517,6 +517,18 @@ if(BUILD_GUI) set(luarsvg_libs ${RSVG_LIBRARIES} ${LUA_LIBRARIES}) set(luarsvg_includes ${RSVG_INCLUDE_DIRS} ${LUA_INCLUDE_DIR}) endif(BUILD_LUA_RSVG) + + if(BUILD_LUA_TEXT) + if(FREETYPE_INCLUDE_DIR_freetype2) + set(FREETYPE_FOUND true) + else(FREETYPE_INCLUDE_DIR_freetype2) + message(FATAL_ERROR "Unable to find freetype library") + endif(FREETYPE_INCLUDE_DIR_freetype2) + PKG_CHECK_MODULES(FONTCONFIG REQUIRED fontconfig) + PKG_CHECK_MODULES(HARFBUZZ REQUIRED harfbuzz) + set(luatext_libs ${FREETYPE_LIBRARIES} ${FONTCONFIG_LIBRARIES} ${HARFBUZZ_LIBRARIES} ${LUA_LIBRARIES}) + set(luatext_includes ${FREETYPE_INCLUDE_DIR_freetype2} ${FONTCONFIG_INCLUDE_DIRS} ${HARFBUZZ_INCLUDE_DIRS} ${LUA_INCLUDE_DIRS}) + endif(BUILD_LUA_TEXT) endif(BUILD_GUI) if(BUILD_AUDACIOUS) diff --git a/cmake/config.h.in b/cmake/config.h.in index 7efa46418..572ab33e9 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -132,6 +132,8 @@ #cmakedefine BUILD_LUA_RSVG 1 +#cmakedefine BUILD_LUA_TEXT 1 + #cmakedefine BUILD_IBM 1 #cmakedefine BUILD_RSS 1 diff --git a/lua/CMakeLists.txt b/lua/CMakeLists.txt index b3acd19a0..71697645d 100644 --- a/lua/CMakeLists.txt +++ b/lua/CMakeLists.txt @@ -75,6 +75,7 @@ if(BUILD_X11) print_target_properties(conky-rsvg) endif(BUILD_LUA_RSVG) + if(BUILD_LUA_CAIRO AND BUILD_LUA_IMLIB2) include_directories(${luacairo_includes} ${luaimlib2_includes} ${CMAKE_CURRENT_SOURCE_DIR}) @@ -90,6 +91,22 @@ if(BUILD_X11) toluapp_lib_static) set(lua_libs ${lua_libs} conky-cairo_imlib2_helper) endif(BUILD_LUA_CAIRO AND BUILD_LUA_IMLIB2) + + if(BUILD_LUA_CAIRO AND BUILD_LUA_TEXT) + include_directories(${luacairo_includes} ${luatext_includes} + ${CMAKE_CURRENT_SOURCE_DIR}) + wrap_tolua(luacairo_text_helper_src cairo_text_helper.pkg) + + add_library(conky-cairo_text_helper SHARED ${luacairo_text_helper_src}) + set_target_properties(conky-cairo_text_helper + PROPERTIES OUTPUT_NAME "cairo_text_helper") + + target_link_libraries(conky-cairo_text_helper + ${luacairo_libs} + ${luatext_libs} + toluapp_lib_static) + set(lua_libs ${lua_libs} conky-cairo_text_helper) + endif(BUILD_LUA_CAIRO AND BUILD_LUA_TEXT) endif(BUILD_X11) install(TARGETS ${lua_libs} diff --git a/lua/cairo_text_helper.pkg b/lua/cairo_text_helper.pkg new file mode 100644 index 000000000..8f8ce6512 --- /dev/null +++ b/lua/cairo_text_helper.pkg @@ -0,0 +1,7 @@ +$#include +$#include + +void cairo_draw_text(const char *text, const char *font, int size, + cairo_surface_t *cs, int x, int y, double scale_x, + double scale_y, double *return_scale_w, + double *return_scale_h); diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h new file mode 100644 index 000000000..053703995 --- /dev/null +++ b/lua/libcairo_text_helper.h @@ -0,0 +1,36 @@ +/* + * + * Conky, a system monitor, based on torsmo + * + * Please see COPYING for details + * + * Copyright (c) 2005-2021 Brenden Matthews, Philip Kovacs, et. al. + * (see AUTHORS) + * All rights reserved. + * + * This program 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. + * + * This program 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 this program. If not, see . + * + */ + +#ifndef _LIBCAIRO_TEXT_HELPER_H_ +#define _LIBCAIRO_TEXT_HELPER_H_ + +// string, font, size + +void cairo_draw_image(const char *text, const char *font, int size, + cairo_surface_t *cs, int x, int y, double scale_x, + double scale_y, double *return_scale_w, + double *return_scale_h) { + +} +#endif diff --git a/lua/text.pkg b/lua/text.pkg new file mode 100644 index 000000000..e69de29bb diff --git a/src/main.cc b/src/main.cc index ef38fc71d..cea353f0c 100644 --- a/src/main.cc +++ b/src/main.cc @@ -143,7 +143,7 @@ static void print_version() { #ifdef DEBUG << _(" * Debugging extensions\n") #endif -#if defined BUILD_LUA_CAIRO || defined BUILD_LUA_IMLIB2 || BUILD_LUA_RSVG +#if defined BUILD_LUA_CAIRO || defined BUILD_LUA_IMLIB2 || BUILD_LUA_RSVG || BUILD_LUA_TEXT << _("\n Lua bindings:\n") #endif #ifdef BUILD_LUA_CAIRO @@ -155,6 +155,9 @@ static void print_version() { #ifdef BUILD_LUA_RSVG << _(" * RSVG\n") #endif /* BUILD_LUA_RSVG */ +#ifdef BUILD_LUA_TEXT + << _(" * TEXT\n") +#endif /* BUILD_LUA_RSVG */ #ifdef BUILD_X11 << _(" X11:\n") #ifdef BUILD_XDAMAGE From 4077ad5f00086a4d937f6697914c12d3dc91f1bc Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Wed, 15 Feb 2023 09:43:50 +1030 Subject: [PATCH 06/26] lua text: initial implementation. --- lua/cairo_text_helper.pkg | 23 ++++- lua/libcairo_text_helper.h | 167 +++++++++++++++++++++++++++++++++++-- 2 files changed, 181 insertions(+), 9 deletions(-) diff --git a/lua/cairo_text_helper.pkg b/lua/cairo_text_helper.pkg index 8f8ce6512..47cb96928 100644 --- a/lua/cairo_text_helper.pkg +++ b/lua/cairo_text_helper.pkg @@ -1,7 +1,22 @@ $#include $#include -void cairo_draw_text(const char *text, const char *font, int size, - cairo_surface_t *cs, int x, int y, double scale_x, - double scale_y, double *return_scale_w, - double *return_scale_h); +typedef struct _FontData { + cairo_font_face_t *cairo_ft_face; + hb_font_t *hb_ft_font; + hb_face_t *hb_ft_face; + int font_size; + /* Internally the following two are pointers */ + /* Stored here so they can be freed later */ + FT_Library ft_library; + FT_Face ft_face; +}FontData; + +FontData * cairo_text_hp_load_font(const char *font, int font_size); + +void cairo_text_hp_destroy_font(FontData *font); + +void cairo_text_hp_simple_show(cairo_t *cr, int x, int y, const char *text, FontData *font); + +void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontData *font, + const char *direction, const char *script, const char *language); diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h index 053703995..2d22c4b25 100644 --- a/lua/libcairo_text_helper.h +++ b/lua/libcairo_text_helper.h @@ -25,12 +25,169 @@ #ifndef _LIBCAIRO_TEXT_HELPER_H_ #define _LIBCAIRO_TEXT_HELPER_H_ -// string, font, size +#include +#include -void cairo_draw_image(const char *text, const char *font, int size, - cairo_surface_t *cs, int x, int y, double scale_x, - double scale_y, double *return_scale_w, - double *return_scale_h) { +#include +#include +#include FT_FREETYPE_H +#include +#include +#include +#include + +#include +#include +#include + +typedef struct _FontData { + cairo_font_face_t *cairo_ft_face; + hb_font_t *hb_ft_font; + hb_face_t *hb_ft_face; + int font_size; + /* Internally the following two are pointers */ + /* Stored here so they can be freed later */ + FT_Library ft_library; + FT_Face ft_face; +}FontData; + +FontData *cairo_text_hp_load_font(const char *font, int font_size) +{ + /* Fontconfig will take a font name and return the file with */ + /* the best match as Freetype only works directly with font files */ + + FcInit(); + FcConfig* config = FcInitLoadConfigAndFonts(); + + FcPattern* pat = FcNameParse((const FcChar8*)font); + FcConfigSubstitute(config, pat, FcMatchPattern); + FcDefaultSubstitute(pat); + + FcResult result; + FcPattern* font_pat = FcFontMatch(config, pat, &result); + + /* Will be freed with font */ + FcChar8* file = NULL; + FcPatternGetString(font_pat, FC_FILE, 0, &file); + + if (!file) { + /* FIXME: add error handling */ + return NULL; + } + + FontData *font_data = malloc(sizeof(struct _FontData)); + + /* Load the font */ + FT_Init_FreeType(&font_data->ft_library); + FT_Library_SetLcdFilter(font_data->ft_library, FT_LCD_FILTER_DEFAULT); + FT_New_Face(font_data->ft_library, (char *)file, 0, &font_data->ft_face); + FT_Set_Char_Size(font_data->ft_face, font_size*64, font_size*64,0,0); + + /* Store font data for use later */ + font_data->cairo_ft_face = cairo_font_face_reference(cairo_ft_font_face_create_for_ft_face(font_data->ft_face, 0)); + font_data->hb_ft_font = hb_ft_font_create(font_data->ft_face, NULL); + font_data->hb_ft_face = hb_ft_face_create(font_data->ft_face, NULL); + font_data->font_size = font_size; + + /* Cleanup font config */ + FcPatternDestroy(font_pat); + FcPatternDestroy(pat); + FcConfigDestroy(config); + /* FIXME: Crashes */ + /*FcFini(); */ + + return font_data; +} + +void cairo_text_hp_destroy_font(FontData *font) +{ + cairo_font_face_destroy(font->cairo_ft_face); + cairo_font_face_destroy (font->cairo_ft_face); + hb_font_destroy(font->hb_ft_font); + hb_face_destroy(font->hb_ft_face); + + FT_Done_Face (font->ft_face); + FT_Done_FreeType(font->ft_library); + + free(font); +} + +/* + * Direction calls hb_direction_from_string example values are LTR and RTL + * https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-direction-from-string + * Script is an ISO 15924 4 character string, "Zyyy" can be used for "Common" and "Zinh" + * for "Inherited". + * https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-script-from-string + * Language is a BCP 47 language tag. eg "en" or "en-US" + */ +void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontData *font, + const char *direction, const char *script, const char *language) +{ + /* FIXME: Support others */ + hb_direction_t text_direction = hb_direction_from_string(direction, -1); + if (text_direction == HB_DIRECTION_INVALID) { + text_direction = HB_DIRECTION_LTR; + } + hb_script_t text_script = hb_script_from_string(script, -1); + if (text_script == HB_SCRIPT_UNKNOWN) { + text_script = HB_SCRIPT_COMMON; + } + + hb_language_t text_language = hb_language_from_string (language, -1); + + /* Draw text */ + /* Create a buffer for harfbuzz to use */ + hb_buffer_t *buf = hb_buffer_create(); + + //alternatively you can use hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); + hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); + hb_buffer_set_direction(buf, text_direction); /* or LTR */ + hb_buffer_set_script(buf, text_script); /* see hb-unicode.h */ + hb_buffer_set_language(buf, text_language); + + /* Layout the text */ + hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); + hb_shape(font->hb_ft_font, buf, NULL, 0); + + /* Hand the layout to cairo to render */ + unsigned int glyph_count; + hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); + hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); + cairo_glyph_t *cairo_glyphs = malloc(sizeof(cairo_glyph_t) * glyph_count); + + unsigned int string_width_in_pixels = 0; + for (int i=0; i < glyph_count; ++i) { + string_width_in_pixels += glyph_pos[i].x_advance/64; + } + int draw_x = x; + if (HB_DIRECTION_IS_VERTICAL(text_direction)) { + /* FIXME */ + //draw_x = width/2 - string_width_in_pixels/2; + } else if (text_direction == HB_DIRECTION_RTL){ + draw_x = cairo_image_surface_get_width(cairo_get_target(cr)) + x; + } + + for (int i=0; i < glyph_count; ++i) { + cairo_glyphs[i].index = glyph_info[i].codepoint; + cairo_glyphs[i].x = x + (glyph_pos[i].x_offset/64.0); + cairo_glyphs[i].y = y - (glyph_pos[i].y_offset/64.0); + x += glyph_pos[i].x_advance/64.0; + y -= glyph_pos[i].y_advance/64.0; + } + + cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0); + cairo_set_font_face(cr, font->cairo_ft_face); + cairo_set_font_size(cr, font->font_size); + cairo_show_glyphs(cr, cairo_glyphs, glyph_count); + + free(cairo_glyphs); + hb_buffer_destroy(buf); +} + +void cairo_text_hp_simple_show(cairo_t *cr, int x, int y, const char *text, FontData *font) +{ + cairo_text_hp_intl_show(cr, x, y, text, font, "LTR", "Zyyy", "en"); } + #endif From 00b2ec0749e6669a15bb3b41046ba1e315417ff4 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Mon, 12 Feb 2024 20:40:53 +1030 Subject: [PATCH 07/26] Commit the WIP so I can merge it --- lua/cairo_text_helper.pkg | 15 +++- lua/libcairo_text_helper.h | 168 ++++++++++++++++++++++++++++++++++--- 2 files changed, 171 insertions(+), 12 deletions(-) diff --git a/lua/cairo_text_helper.pkg b/lua/cairo_text_helper.pkg index 47cb96928..43f717625 100644 --- a/lua/cairo_text_helper.pkg +++ b/lua/cairo_text_helper.pkg @@ -12,11 +12,24 @@ typedef struct _FontData { FT_Face ft_face; }FontData; +typedef enum _cairo_text_alignment { + CAIRO_TEXT_ALIGN_LEFT = 0, + CAIRO_TEXT_ALIGN_RIGHT, + CAIRO_TEXT_ALIGN_CENTER +} cairo_text_alignment_t; + FontData * cairo_text_hp_load_font(const char *font, int font_size); void cairo_text_hp_destroy_font(FontData *font); void cairo_text_hp_simple_show(cairo_t *cr, int x, int y, const char *text, FontData *font); +void cairo_text_hp_simple_show_center(cairo_t *cr, int x, int y, const char *text, FontData *font); +void cairo_text_hp_simple_show_right(cairo_t *cr, int x, int y, const char *text, FontData *font); -void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontData *font, +void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t alignment, const char *text, FontData *font, const char *direction, const char *script, const char *language); + +/* This function allows you to layout two sets of text next to each other */ +void cairo_text_hp_text_size(const char *text, FontData *font, + const char *direction, const char *script, const char *language, int *width, int *height); +void cairo_text_hp_simple_text_size(const char *text, FontData *font, int *width, int *height); diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h index 2d22c4b25..a04f1c53d 100644 --- a/lua/libcairo_text_helper.h +++ b/lua/libcairo_text_helper.h @@ -52,6 +52,12 @@ typedef struct _FontData { FT_Face ft_face; }FontData; +typedef enum _cairo_text_alignment { + CAIRO_TEXT_ALIGN_LEFT = 0, + CAIRO_TEXT_ALIGN_RIGHT, + CAIRO_TEXT_ALIGN_CENTER +} cairo_text_alignment_t; + FontData *cairo_text_hp_load_font(const char *font, int font_size) { /* Fontconfig will take a font name and return the file with */ @@ -59,7 +65,12 @@ FontData *cairo_text_hp_load_font(const char *font, int font_size) FcInit(); FcConfig* config = FcInitLoadConfigAndFonts(); - + + // crash here + if (!font) { + printf("Error: cairo_text font not set.\n"); + return NULL; + } FcPattern* pat = FcNameParse((const FcChar8*)font); FcConfigSubstitute(config, pat, FcMatchPattern); FcDefaultSubstitute(pat); @@ -73,6 +84,7 @@ FontData *cairo_text_hp_load_font(const char *font, int font_size) if (!file) { /* FIXME: add error handling */ + printf("Error: cairo_text couldn't find font.\n"); return NULL; } @@ -121,17 +133,36 @@ void cairo_text_hp_destroy_font(FontData *font) * https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-script-from-string * Language is a BCP 47 language tag. eg "en" or "en-US" */ -void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontData *font, +void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t alignment, const char *text, FontData *font, const char *direction, const char *script, const char *language) -{ +{ + /* It seems that lua may just pass NULL for an empty string */ + if (text == NULL) { + printf("Error: CairoTextHelper: Null string\n"); + return; + } + if (font == NULL) { + printf("Error: CairoTextHelper: Null FontData"); + return; + } + + double x1,x2,y1,y2; + + cairo_clip_extents(cr, &x1, &y1, &x2, &y2); + + int width = x2-x1; + int height = y2-y1; + /* FIXME: Support others */ hb_direction_t text_direction = hb_direction_from_string(direction, -1); if (text_direction == HB_DIRECTION_INVALID) { text_direction = HB_DIRECTION_LTR; + printf("Error: CairoTextHelper: Text Direction Invalid\n"); } hb_script_t text_script = hb_script_from_string(script, -1); if (text_script == HB_SCRIPT_UNKNOWN) { text_script = HB_SCRIPT_COMMON; + printf("Error: CairoTextHelper: Text Script Invalid\n"); } hb_language_t text_language = hb_language_from_string (language, -1); @@ -150,6 +181,13 @@ void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontDa hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); hb_shape(font->hb_ft_font, buf, NULL, 0); + /* Need to calculate the Baseline for drawing on the y axis */ + hb_font_extents_t font_extents; + hb_font_get_extents_for_direction(font->hb_ft_font, text_direction, &font_extents); + + /* Note Line Gap was always 0 in my testing */ + int baseline_offset = font_extents.ascender/64 + 0.5 * font_extents.line_gap/64 + 1; + /* Hand the layout to cairo to render */ unsigned int glyph_count; hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); @@ -161,22 +199,46 @@ void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontDa string_width_in_pixels += glyph_pos[i].x_advance/64; } int draw_x = x; + int draw_y = y; + if (HB_DIRECTION_IS_VERTICAL(text_direction)) { /* FIXME */ - //draw_x = width/2 - string_width_in_pixels/2; - } else if (text_direction == HB_DIRECTION_RTL){ - draw_x = cairo_image_surface_get_width(cairo_get_target(cr)) + x; + draw_x = width/2 - string_width_in_pixels/2 + x; + } + else { + draw_y = baseline_offset + y; + if (alignment == CAIRO_TEXT_ALIGN_LEFT) { + if (text_direction == HB_DIRECTION_RTL) { + draw_x = width - x - string_width_in_pixels; + } + // LTR handled as default. + } + else if (alignment == CAIRO_TEXT_ALIGN_RIGHT) { + if (text_direction == HB_DIRECTION_RTL) { + draw_x = x; + } + else { + draw_x = width - x - string_width_in_pixels; + } + } + else if (alignment == CAIRO_TEXT_ALIGN_CENTER) { + draw_x = width/2 - string_width_in_pixels/2 + x; + } } + // Reset x/y now that draw_x is set + x = 0; + y = 0; + for (int i=0; i < glyph_count; ++i) { + /* FIXME: Handle Top to Bottom here */ cairo_glyphs[i].index = glyph_info[i].codepoint; - cairo_glyphs[i].x = x + (glyph_pos[i].x_offset/64.0); - cairo_glyphs[i].y = y - (glyph_pos[i].y_offset/64.0); + cairo_glyphs[i].x = x + draw_x + (glyph_pos[i].x_offset/64.0); + cairo_glyphs[i].y = y + draw_y - (glyph_pos[i].y_offset/64.0); x += glyph_pos[i].x_advance/64.0; y -= glyph_pos[i].y_advance/64.0; } - - cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0); + cairo_set_font_face(cr, font->cairo_ft_face); cairo_set_font_size(cr, font->font_size); cairo_show_glyphs(cr, cairo_glyphs, glyph_count); @@ -187,7 +249,91 @@ void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, const char *text, FontDa void cairo_text_hp_simple_show(cairo_t *cr, int x, int y, const char *text, FontData *font) { - cairo_text_hp_intl_show(cr, x, y, text, font, "LTR", "Zyyy", "en"); + cairo_text_hp_intl_show(cr, x, y, CAIRO_TEXT_ALIGN_LEFT, text, font, "LTR", "Zyyy", "en"); +} + +void cairo_text_hp_simple_show_center(cairo_t *cr, int x, int y, const char *text, FontData *font) +{ + cairo_text_hp_intl_show(cr, x, y, CAIRO_TEXT_ALIGN_CENTER, text, font, "LTR", "Zyyy", "en"); } +void cairo_text_hp_simple_show_right(cairo_t *cr, int x, int y, const char *text, FontData *font) +{ + cairo_text_hp_intl_show(cr, x, y, CAIRO_TEXT_ALIGN_RIGHT, text, font, "LTR", "Zyyy", "en"); +} + +int cairo_text_hp_text_size( const char *text, FontData *font, + const char *direction, const char *script, const char *language, int *width, int *height) +{ + /* FIXME: Support others */ + hb_direction_t text_direction = hb_direction_from_string(direction, -1); + if (text_direction == HB_DIRECTION_INVALID) { + text_direction = HB_DIRECTION_LTR; + } + hb_script_t text_script = hb_script_from_string(script, -1); + if (text_script == HB_SCRIPT_UNKNOWN) { + text_script = HB_SCRIPT_COMMON; + } + + hb_language_t text_language = hb_language_from_string (language, -1); + + /* Draw text */ + /* Create a buffer for harfbuzz to use */ + hb_buffer_t *buf = hb_buffer_create(); + + //alternatively you can use hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); + hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); + hb_buffer_set_direction(buf, text_direction); /* or LTR */ + hb_buffer_set_script(buf, text_script); /* see hb-unicode.h */ + hb_buffer_set_language(buf, text_language); + + /* Layout the text */ + hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); + hb_shape(font->hb_ft_font, buf, NULL, 0); + + hb_font_extents_t font_extents; + hb_font_get_extents_for_direction(font->hb_ft_font, text_direction, &font_extents); + + /* Hand the layout to cairo to render */ + unsigned int glyph_count; + hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); + hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); + cairo_glyph_t *cairo_glyphs = malloc(sizeof(cairo_glyph_t) * glyph_count); + + unsigned int string_width_in_pixels = 0; + unsigned int string_height_in_pixels = 0; + + /* Temp variable used for each glyph */ + hb_glyph_extents_t glyph_extents; + if (text_direction == HB_DIRECTION_LTR || + text_direction == HB_DIRECTION_RTL) + { + /* Width */ + for (int i=0; i < glyph_count; ++i) { + string_width_in_pixels += glyph_pos[i].x_advance/64+glyph_pos[i].x_offset/64; + hb_font_get_glyph_extents (font->hb_ft_font, glyph_info[i].codepoint, + &glyph_extents); + int h = ((glyph_extents.height/64)*-1)+(glyph_extents.y_bearing/64); + if (h > string_height_in_pixels) { + string_height_in_pixels = h; + } + } + /* Height */ + //string_height_in_pixels = font_extents.ascender/64 - font_extents.descender/64; + } else { + /* Width */ + string_width_in_pixels = font_extents.ascender/64 - font_extents.descender/64; + /* Height */ + for (int i=0; i < glyph_count; ++i) { + string_height_in_pixels += glyph_pos[i].y_advance/64+glyph_pos[i].y_offset/64; + } + } + + *width = string_width_in_pixels; + *height = string_height_in_pixels; +} + +void cairo_text_hp_simple_text_size(const char *text, FontData *font, int *width, int *height) { + cairo_text_hp_text_size(text, font, "LTR", "Zyyy", "en", width, height); +} #endif From 5036cc4d09b267129351ad0d5485ca139aa98fd7 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Wed, 14 Feb 2024 13:39:39 +1030 Subject: [PATCH 08/26] Fix for #1698 This should go into its own PR but right now I need it for my system to work. --- src/display-x11.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/display-x11.cc b/src/display-x11.cc index 94b3be246..8488133f9 100644 --- a/src/display-x11.cc +++ b/src/display-x11.cc @@ -453,6 +453,8 @@ bool display_output_x11::main_loop_wait(double t) { // modify for propagation ev.xexpose.x += window.x; ev.xexpose.y += window.y; + // Fix for #1698 Remove from this branch before accepting Pull Request + ev.xexpose.window = window.desktop; break; } From 488b4506e448cbbae6b32a50489b06414faefeb4 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Wed, 14 Feb 2024 13:44:27 +1030 Subject: [PATCH 09/26] Fix comment hb-unicode.h should be hb-common.h --- lua/libcairo_text_helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h index a04f1c53d..02d03b1d5 100644 --- a/lua/libcairo_text_helper.h +++ b/lua/libcairo_text_helper.h @@ -284,7 +284,7 @@ int cairo_text_hp_text_size( const char *text, FontData *font, //alternatively you can use hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); hb_buffer_set_direction(buf, text_direction); /* or LTR */ - hb_buffer_set_script(buf, text_script); /* see hb-unicode.h */ + hb_buffer_set_script(buf, text_script); /* see hb-common.h */ hb_buffer_set_language(buf, text_language); /* Layout the text */ From b0063e502f9e3ecd0ceed453469ac53157bf1463 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Wed, 14 Feb 2024 23:03:51 +1030 Subject: [PATCH 10/26] Swap to using optional parameters This replaces the old approach of using a series of function declarations. --- lua/cairo_text_helper.pkg | 11 +---- lua/libcairo_text_helper.h | 98 ++++++++++++++++++++++++-------------- 2 files changed, 64 insertions(+), 45 deletions(-) diff --git a/lua/cairo_text_helper.pkg b/lua/cairo_text_helper.pkg index 43f717625..c59cd1305 100644 --- a/lua/cairo_text_helper.pkg +++ b/lua/cairo_text_helper.pkg @@ -19,17 +19,10 @@ typedef enum _cairo_text_alignment { } cairo_text_alignment_t; FontData * cairo_text_hp_load_font(const char *font, int font_size); - void cairo_text_hp_destroy_font(FontData *font); -void cairo_text_hp_simple_show(cairo_t *cr, int x, int y, const char *text, FontData *font); -void cairo_text_hp_simple_show_center(cairo_t *cr, int x, int y, const char *text, FontData *font); -void cairo_text_hp_simple_show_right(cairo_t *cr, int x, int y, const char *text, FontData *font); - -void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t alignment, const char *text, FontData *font, - const char *direction, const char *script, const char *language); +void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *font, cairo_text_alignment_t alignment = CAIRO_TEXT_ALIGN_LEFT, const char *language = "en", const char *script = NULL, const char *direction = NULL); /* This function allows you to layout two sets of text next to each other */ void cairo_text_hp_text_size(const char *text, FontData *font, - const char *direction, const char *script, const char *language, int *width, int *height); -void cairo_text_hp_simple_text_size(const char *text, FontData *font, int *width, int *height); + const char *language = "en", const char *script = NULL, const char *direction = NULL, int *width, int *height); diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h index 02d03b1d5..ab43deeba 100644 --- a/lua/libcairo_text_helper.h +++ b/lua/libcairo_text_helper.h @@ -133,8 +133,10 @@ void cairo_text_hp_destroy_font(FontData *font) * https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-script-from-string * Language is a BCP 47 language tag. eg "en" or "en-US" */ -void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t alignment, const char *text, FontData *font, - const char *direction, const char *script, const char *language) +//void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t alignment, const char *text, FontData *font, +// const char *direction, const char *script, const char *language) +void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *font, + cairo_text_alignment_t alignment, const char *language, const char *script, const char *direction) { /* It seems that lua may just pass NULL for an empty string */ if (text == NULL) { @@ -153,19 +155,33 @@ void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t a int width = x2-x1; int height = y2-y1; - /* FIXME: Support others */ - hb_direction_t text_direction = hb_direction_from_string(direction, -1); - if (text_direction == HB_DIRECTION_INVALID) { - text_direction = HB_DIRECTION_LTR; - printf("Error: CairoTextHelper: Text Direction Invalid\n"); + hb_language_t text_language; + hb_direction_t text_direction; + if (language != NULL) { + text_language = hb_language_from_string (language, -1); + } + else { + /* Use en as the default as if you are sharing configs with other */ + /* people, you don't want them to break if they use a different lang */ + hb_language_from_string("en", -1); } + hb_script_t text_script = hb_script_from_string(script, -1); if (text_script == HB_SCRIPT_UNKNOWN) { text_script = HB_SCRIPT_COMMON; - printf("Error: CairoTextHelper: Text Script Invalid\n"); } - - hb_language_t text_language = hb_language_from_string (language, -1); + + if (direction != NULL) { + text_direction = hb_direction_from_string(direction, -1); + } + else { + text_direction = hb_script_get_horizontal_direction(text_script); + } + /* Note Direction can be invalid if user passes something invalid */ + /* or if the script can be Vertical or Horizontal */ + if (text_direction == HB_DIRECTION_INVALID) { + text_direction = HB_DIRECTION_LTR; + } /* Draw text */ /* Create a buffer for harfbuzz to use */ @@ -173,9 +189,14 @@ void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t a //alternatively you can use hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); - hb_buffer_set_direction(buf, text_direction); /* or LTR */ - hb_buffer_set_script(buf, text_script); /* see hb-unicode.h */ hb_buffer_set_language(buf, text_language); + if (script != NULL) { + hb_buffer_set_script(buf, text_script); /* see hb-unicode.h */ + } + else { + hb_buffer_guess_segment_properties(buf); + } + hb_buffer_set_direction(buf, text_direction); /* or LTR */ /* Layout the text */ hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); @@ -247,35 +268,36 @@ void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t a hb_buffer_destroy(buf); } -void cairo_text_hp_simple_show(cairo_t *cr, int x, int y, const char *text, FontData *font) -{ - cairo_text_hp_intl_show(cr, x, y, CAIRO_TEXT_ALIGN_LEFT, text, font, "LTR", "Zyyy", "en"); -} - -void cairo_text_hp_simple_show_center(cairo_t *cr, int x, int y, const char *text, FontData *font) -{ - cairo_text_hp_intl_show(cr, x, y, CAIRO_TEXT_ALIGN_CENTER, text, font, "LTR", "Zyyy", "en"); -} - -void cairo_text_hp_simple_show_right(cairo_t *cr, int x, int y, const char *text, FontData *font) -{ - cairo_text_hp_intl_show(cr, x, y, CAIRO_TEXT_ALIGN_RIGHT, text, font, "LTR", "Zyyy", "en"); -} - int cairo_text_hp_text_size( const char *text, FontData *font, - const char *direction, const char *script, const char *language, int *width, int *height) + const char *language, const char *script, const char *direction, int *width, int *height) { - /* FIXME: Support others */ - hb_direction_t text_direction = hb_direction_from_string(direction, -1); - if (text_direction == HB_DIRECTION_INVALID) { - text_direction = HB_DIRECTION_LTR; + hb_language_t text_language; + hb_direction_t text_direction; + if (language != NULL) { + text_language = hb_language_from_string (language, -1); + } + else { + /* Use en as the default as if you are sharing configs with other */ + /* people, you don't want them to break if they use a different lang */ + hb_language_from_string("en", -1); } + hb_script_t text_script = hb_script_from_string(script, -1); if (text_script == HB_SCRIPT_UNKNOWN) { text_script = HB_SCRIPT_COMMON; } - - hb_language_t text_language = hb_language_from_string (language, -1); + + if (direction != NULL) { + text_direction = hb_direction_from_string(direction, -1); + } + else { + text_direction = hb_script_get_horizontal_direction(text_script); + } + /* Note Direction can be invalid if user passes something invalid */ + /* or if the script can be Vertical or Horizontal */ + if (text_direction == HB_DIRECTION_INVALID) { + text_direction = HB_DIRECTION_LTR; + } /* Draw text */ /* Create a buffer for harfbuzz to use */ @@ -284,8 +306,12 @@ int cairo_text_hp_text_size( const char *text, FontData *font, //alternatively you can use hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); hb_buffer_set_unicode_funcs(buf, hb_glib_get_unicode_funcs()); hb_buffer_set_direction(buf, text_direction); /* or LTR */ - hb_buffer_set_script(buf, text_script); /* see hb-common.h */ - hb_buffer_set_language(buf, text_language); + if (script != NULL) { + hb_buffer_set_script(buf, text_script); /* see hb-unicode.h */ + } + else { + hb_buffer_guess_segment_properties(buf); + } hb_buffer_set_language(buf, text_language); /* Layout the text */ hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); From 945ce1fea5bd998fa74b4d825fd2b9c8cd2f9d13 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Thu, 15 Feb 2024 12:04:10 +1030 Subject: [PATCH 11/26] Add Hack for RTL positioning For some reason RTL positioning is wrong, it seems somewhat based on font size 1/10th font size seems to get closer to correct so run with that for now, i'll continue investigating a proper fix. --- lua/libcairo_text_helper.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h index ab43deeba..2a86d539e 100644 --- a/lua/libcairo_text_helper.h +++ b/lua/libcairo_text_helper.h @@ -215,9 +215,20 @@ void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *f hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); cairo_glyph_t *cairo_glyphs = malloc(sizeof(cairo_glyph_t) * glyph_count); + /* RTL positioning seems to be slightly off and characters don't link as they should */ + /* This hack gets it significantly closer to correct but is not 100% for all fonts and sizes */ + int rtl_fix = font->font_size/10; + unsigned int string_width_in_pixels = 0; for (int i=0; i < glyph_count; ++i) { string_width_in_pixels += glyph_pos[i].x_advance/64; + if (text_direction == HB_DIRECTION_RTL) { + string_width_in_pixels -= rtl_fix; + } + } + /* More RTL Hacks */ + if (text_direction == HB_DIRECTION_RTL) { + string_width_in_pixels += 2; } int draw_x = x; int draw_y = y; @@ -257,6 +268,9 @@ void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *f cairo_glyphs[i].x = x + draw_x + (glyph_pos[i].x_offset/64.0); cairo_glyphs[i].y = y + draw_y - (glyph_pos[i].y_offset/64.0); x += glyph_pos[i].x_advance/64.0; + if (text_direction == HB_DIRECTION_RTL) { + x -= rtl_fix; + } y -= glyph_pos[i].y_advance/64.0; } From dc7c0e053c7cee60d6a5bb337a2ba795829d90f4 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Thu, 15 Feb 2024 12:07:06 +1030 Subject: [PATCH 12/26] Remove Top to Bottom Fixme's they are fixed --- lua/libcairo_text_helper.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h index 2a86d539e..28c70111e 100644 --- a/lua/libcairo_text_helper.h +++ b/lua/libcairo_text_helper.h @@ -234,7 +234,6 @@ void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *f int draw_y = y; if (HB_DIRECTION_IS_VERTICAL(text_direction)) { - /* FIXME */ draw_x = width/2 - string_width_in_pixels/2 + x; } else { @@ -263,7 +262,6 @@ void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *f y = 0; for (int i=0; i < glyph_count; ++i) { - /* FIXME: Handle Top to Bottom here */ cairo_glyphs[i].index = glyph_info[i].codepoint; cairo_glyphs[i].x = x + draw_x + (glyph_pos[i].x_offset/64.0); cairo_glyphs[i].y = y + draw_y - (glyph_pos[i].y_offset/64.0); From 47c45af9c84881374446465ba310a5d6c78eb047 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Thu, 15 Feb 2024 12:22:23 +1030 Subject: [PATCH 13/26] Some general cleanup post merge --- lua/cairo_text_helper.pkg | 2 +- lua/libcairo_text_helper.h | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/lua/cairo_text_helper.pkg b/lua/cairo_text_helper.pkg index c59cd1305..86efa646b 100644 --- a/lua/cairo_text_helper.pkg +++ b/lua/cairo_text_helper.pkg @@ -25,4 +25,4 @@ void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *f /* This function allows you to layout two sets of text next to each other */ void cairo_text_hp_text_size(const char *text, FontData *font, - const char *language = "en", const char *script = NULL, const char *direction = NULL, int *width, int *height); + const char *language = "en", const char *script = NULL, const char *direction, int *width, int *height); diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h index 28c70111e..38b4cc41a 100644 --- a/lua/libcairo_text_helper.h +++ b/lua/libcairo_text_helper.h @@ -133,8 +133,6 @@ void cairo_text_hp_destroy_font(FontData *font) * https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-script-from-string * Language is a BCP 47 language tag. eg "en" or "en-US" */ -//void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t alignment, const char *text, FontData *font, -// const char *direction, const char *script, const char *language) void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *font, cairo_text_alignment_t alignment, const char *language, const char *script, const char *direction) { @@ -370,8 +368,4 @@ int cairo_text_hp_text_size( const char *text, FontData *font, *width = string_width_in_pixels; *height = string_height_in_pixels; } - -void cairo_text_hp_simple_text_size(const char *text, FontData *font, int *width, int *height) { - cairo_text_hp_text_size(text, font, "LTR", "Zyyy", "en", width, height); -} #endif From 7553faf5b69b26cbd26049932cdb28ef5480370d Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Thu, 15 Feb 2024 12:37:26 +1030 Subject: [PATCH 14/26] Attempt to fix workflows by adding freetype dep --- .github/workflows/build-and-test-linux.yaml | 1 + .github/workflows/codeql.yml | 1 + .github/workflows/publish-appimage.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/workflows/build-and-test-linux.yaml b/.github/workflows/build-and-test-linux.yaml index b1829121b..8d594c82d 100644 --- a/.github/workflows/build-and-test-linux.yaml +++ b/.github/workflows/build-and-test-linux.yaml @@ -77,6 +77,7 @@ jobs: libcurl4-gnutls-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ + libfreetype-dev \ libglib2.0-dev \ libical-dev \ libimlib2-dev \ diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 37bcdcfb1..5a3cff3ca 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -38,6 +38,7 @@ jobs: libcurl4-gnutls-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ + libfreetype-dev \ libglib2.0-dev \ libical-dev \ libimlib2-dev \ diff --git a/.github/workflows/publish-appimage.yml b/.github/workflows/publish-appimage.yml index dd400fff3..af422ebc0 100644 --- a/.github/workflows/publish-appimage.yml +++ b/.github/workflows/publish-appimage.yml @@ -32,6 +32,7 @@ jobs: libcairo2-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ + libfreetype-dev \ libfuse2 \ libglib2.0-dev \ libical-dev \ From 2c7405865a553ca8dc4ae915fd02b618f3227107 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Thu, 15 Feb 2024 12:41:09 +1030 Subject: [PATCH 15/26] Probably actually need freetype6 --- .github/workflows/build-and-test-linux.yaml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/publish-appimage.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test-linux.yaml b/.github/workflows/build-and-test-linux.yaml index 8d594c82d..2dc95ad96 100644 --- a/.github/workflows/build-and-test-linux.yaml +++ b/.github/workflows/build-and-test-linux.yaml @@ -77,7 +77,7 @@ jobs: libcurl4-gnutls-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ - libfreetype-dev \ + libfreetype6-dev \ libglib2.0-dev \ libical-dev \ libimlib2-dev \ diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5a3cff3ca..af8e92561 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -38,7 +38,7 @@ jobs: libcurl4-gnutls-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ - libfreetype-dev \ + libfreetype6-dev \ libglib2.0-dev \ libical-dev \ libimlib2-dev \ diff --git a/.github/workflows/publish-appimage.yml b/.github/workflows/publish-appimage.yml index af422ebc0..9ed6775c8 100644 --- a/.github/workflows/publish-appimage.yml +++ b/.github/workflows/publish-appimage.yml @@ -32,7 +32,7 @@ jobs: libcairo2-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ - libfreetype-dev \ + libfreetype6-dev \ libfuse2 \ libglib2.0-dev \ libical-dev \ From 7e2a662d5a418f0bdae4021159b7457b555031e2 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Thu, 15 Feb 2024 12:51:46 +1030 Subject: [PATCH 16/26] Try again, I don't understand Ubuntu --- .github/workflows/build-and-test-linux.yaml | 3 ++- .github/workflows/codeql.yml | 3 ++- .github/workflows/publish-appimage.yml | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test-linux.yaml b/.github/workflows/build-and-test-linux.yaml index 2dc95ad96..3ec33312d 100644 --- a/.github/workflows/build-and-test-linux.yaml +++ b/.github/workflows/build-and-test-linux.yaml @@ -77,7 +77,8 @@ jobs: libcurl4-gnutls-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ - libfreetype6-dev \ + libfreetype-dev \ + libfreetype6 \ libglib2.0-dev \ libical-dev \ libimlib2-dev \ diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index af8e92561..73ca3be94 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -38,7 +38,8 @@ jobs: libcurl4-gnutls-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ - libfreetype6-dev \ + libfreetype-dev \ + libfreetype6 \ libglib2.0-dev \ libical-dev \ libimlib2-dev \ diff --git a/.github/workflows/publish-appimage.yml b/.github/workflows/publish-appimage.yml index 9ed6775c8..495153e01 100644 --- a/.github/workflows/publish-appimage.yml +++ b/.github/workflows/publish-appimage.yml @@ -32,7 +32,8 @@ jobs: libcairo2-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ - libfreetype6-dev \ + libfreetype-dev \ + libfreetype6 \ libfuse2 \ libglib2.0-dev \ libical-dev \ From ac50fa7a0707997b988170d967c8af2747daa4e6 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Thu, 15 Feb 2024 12:54:36 +1030 Subject: [PATCH 17/26] Try something from google --- .github/workflows/build-and-test-linux.yaml | 4 ++-- .github/workflows/codeql.yml | 4 ++-- .github/workflows/publish-appimage.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test-linux.yaml b/.github/workflows/build-and-test-linux.yaml index 3ec33312d..b0b7e9cfc 100644 --- a/.github/workflows/build-and-test-linux.yaml +++ b/.github/workflows/build-and-test-linux.yaml @@ -77,8 +77,8 @@ jobs: libcurl4-gnutls-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ - libfreetype-dev \ - libfreetype6 \ + libfreetype6-dev \ + libstdc++6 \ libglib2.0-dev \ libical-dev \ libimlib2-dev \ diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 73ca3be94..7870c0314 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -38,8 +38,8 @@ jobs: libcurl4-gnutls-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ - libfreetype-dev \ - libfreetype6 \ + libfreetype6-dev \ + libstdc++6 \ libglib2.0-dev \ libical-dev \ libimlib2-dev \ diff --git a/.github/workflows/publish-appimage.yml b/.github/workflows/publish-appimage.yml index 495153e01..477e5d10a 100644 --- a/.github/workflows/publish-appimage.yml +++ b/.github/workflows/publish-appimage.yml @@ -32,8 +32,8 @@ jobs: libcairo2-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ - libfreetype-dev \ - libfreetype6 \ + libfreetype6-dev \ + libstdc++6 \ libfuse2 \ libglib2.0-dev \ libical-dev \ From ba71b736a1e0aef9a848d9fb36511ee9dc7aab62 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Thu, 22 Feb 2024 10:14:27 +1030 Subject: [PATCH 18/26] lua-text: Move to caching fonts in C Fonts are now cached in C, given the number of fonts and sizes I expect people will use, this implementation seems simpler then implementing hashmaps or attempting to do bindings in C++ --- lua/cairo_text_helper.pkg | 25 +++------ lua/libcairo_text_helper.h | 102 +++++++++++++++++++++++++++++++------ 2 files changed, 95 insertions(+), 32 deletions(-) diff --git a/lua/cairo_text_helper.pkg b/lua/cairo_text_helper.pkg index 86efa646b..5abfeb7d4 100644 --- a/lua/cairo_text_helper.pkg +++ b/lua/cairo_text_helper.pkg @@ -1,28 +1,19 @@ $#include $#include -typedef struct _FontData { - cairo_font_face_t *cairo_ft_face; - hb_font_t *hb_ft_font; - hb_face_t *hb_ft_face; - int font_size; - /* Internally the following two are pointers */ - /* Stored here so they can be freed later */ - FT_Library ft_library; - FT_Face ft_face; -}FontData; - typedef enum _cairo_text_alignment { CAIRO_TEXT_ALIGN_LEFT = 0, CAIRO_TEXT_ALIGN_RIGHT, CAIRO_TEXT_ALIGN_CENTER } cairo_text_alignment_t; -FontData * cairo_text_hp_load_font(const char *font, int font_size); -void cairo_text_hp_destroy_font(FontData *font); - -void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *font, cairo_text_alignment_t alignment = CAIRO_TEXT_ALIGN_LEFT, const char *language = "en", const char *script = NULL, const char *direction = NULL); +void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, const char *font, int font_size, + cairo_text_alignment_t alignment = CAIRO_TEXT_ALIGN_LEFT, const char *language = "en", + const char *script = NULL, const char *direction = NULL); -/* This function allows you to layout two sets of text next to each other */ -void cairo_text_hp_text_size(const char *text, FontData *font, +/* This function allows you to get sizing so you can layout multiple sets of text next to each other */ +void cairo_text_hp_text_size(const char *text, const char *font, int font_size, const char *language = "en", const char *script = NULL, const char *direction, int *width, int *height); + +/* This will clear all currently loaded / cached fonts */ +void cairo_text_hp_delete_fonts(); diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h index 38b4cc41a..55574d1f4 100644 --- a/lua/libcairo_text_helper.h +++ b/lua/libcairo_text_helper.h @@ -41,7 +41,11 @@ #include #include +#define max_fonts 4096 +#define max_font_name_len 4096 + typedef struct _FontData { + char name[max_font_name_len]; cairo_font_face_t *cairo_ft_face; hb_font_t *hb_ft_font; hb_face_t *hb_ft_face; @@ -52,17 +56,20 @@ typedef struct _FontData { FT_Face ft_face; }FontData; +FontData* font_cache[max_fonts] = {NULL}; + typedef enum _cairo_text_alignment { CAIRO_TEXT_ALIGN_LEFT = 0, CAIRO_TEXT_ALIGN_RIGHT, CAIRO_TEXT_ALIGN_CENTER } cairo_text_alignment_t; -FontData *cairo_text_hp_load_font(const char *font, int font_size) +/* Imports a font from a file */ +FontData *cairo_text_hp_import_font(const char *font, int font_size) { /* Fontconfig will take a font name and return the file with */ /* the best match as Freetype only works directly with font files */ - + FcInit(); FcConfig* config = FcInitLoadConfigAndFonts(); @@ -89,6 +96,8 @@ FontData *cairo_text_hp_load_font(const char *font, int font_size) } FontData *font_data = malloc(sizeof(struct _FontData)); + + strncpy(font_data->name, font, max_font_name_len); /* Load the font */ FT_Init_FreeType(&font_data->ft_library); @@ -112,6 +121,27 @@ FontData *cairo_text_hp_load_font(const char *font, int font_size) return font_data; } +/* Either loads font from cache or imports from a file */ +FontData *cairo_text_hp_load_font(const char *font, int font_size) +{ + FontData *font_data = NULL; + + /* Search for font in cache */ + for (int i = 0; i < max_fonts; i++) { + if (font_cache[i] == NULL) { + /* Haven't used this font yet so load and cache it */ + font_data = cairo_text_hp_import_font(font, font_size); + font_cache[i] = font_data; + return font_data; + } + if ((strncmp(font_cache[i]->name, font, max_font_name_len) == 0) && + (font_size == font_cache[i]->font_size)) { + font_data = font_cache[i]; + return font_data; + } + } +} + void cairo_text_hp_destroy_font(FontData *font) { cairo_font_face_destroy(font->cairo_ft_face); @@ -125,6 +155,13 @@ void cairo_text_hp_destroy_font(FontData *font) free(font); } +void cairo_text_hp_delete_fonts() +{ + for (int i = 0; (i < max_fonts) && (font_cache[i] != NULL); i++) { + cairo_text_hp_destroy_font(font_cache[i]); + } +} + /* * Direction calls hb_direction_from_string example values are LTR and RTL * https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-direction-from-string @@ -133,16 +170,28 @@ void cairo_text_hp_destroy_font(FontData *font) * https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-script-from-string * Language is a BCP 47 language tag. eg "en" or "en-US" */ -void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *font, +void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, const char *font, int font_size, cairo_text_alignment_t alignment, const char *language, const char *script, const char *direction) { /* It seems that lua may just pass NULL for an empty string */ if (text == NULL) { - printf("Error: CairoTextHelper: Null string\n"); + printf("Error: CairoTextHelper: TextShow: Null string\n"); return; } if (font == NULL) { - printf("Error: CairoTextHelper: Null FontData"); + printf("Error: CairoTextHelper: TextShow: Null Font\n"); + return; + } + if (font_size <= 1) { + printf("Error: CairoTextHelper: TextShow: Font Size less then 1\n"); + return; + } + + FontData *font_data = cairo_text_hp_load_font(font, font_size); + + /* If we reach here without font data then we have cached too many fonts */ + if (font_data == NULL) { + printf("Error: CairoTextHelper: TextShow: Used too many fonts\n"); return; } @@ -198,11 +247,11 @@ void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *f /* Layout the text */ hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); - hb_shape(font->hb_ft_font, buf, NULL, 0); + hb_shape(font_data->hb_ft_font, buf, NULL, 0); /* Need to calculate the Baseline for drawing on the y axis */ hb_font_extents_t font_extents; - hb_font_get_extents_for_direction(font->hb_ft_font, text_direction, &font_extents); + hb_font_get_extents_for_direction(font_data->hb_ft_font, text_direction, &font_extents); /* Note Line Gap was always 0 in my testing */ int baseline_offset = font_extents.ascender/64 + 0.5 * font_extents.line_gap/64 + 1; @@ -215,7 +264,7 @@ void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *f /* RTL positioning seems to be slightly off and characters don't link as they should */ /* This hack gets it significantly closer to correct but is not 100% for all fonts and sizes */ - int rtl_fix = font->font_size/10; + int rtl_fix = font_data->font_size/10; unsigned int string_width_in_pixels = 0; for (int i=0; i < glyph_count; ++i) { @@ -270,17 +319,40 @@ void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, FontData *f y -= glyph_pos[i].y_advance/64.0; } - cairo_set_font_face(cr, font->cairo_ft_face); - cairo_set_font_size(cr, font->font_size); + cairo_set_font_face(cr, font_data->cairo_ft_face); + cairo_set_font_size(cr, font_data->font_size); cairo_show_glyphs(cr, cairo_glyphs, glyph_count); free(cairo_glyphs); hb_buffer_destroy(buf); } -int cairo_text_hp_text_size( const char *text, FontData *font, - const char *language, const char *script, const char *direction, int *width, int *height) +int cairo_text_hp_text_size( const char *text, const char *font, int font_size, + const char *language, const char *script, const char *direction, + int *width, int *height) { + /* It seems that lua may just pass NULL for an empty string */ + if (text == NULL) { + printf("Error: CairoTextHelper: TextSize: Null string\n"); + return -1; + } + if (font == NULL) { + printf("Error: CairoTextHelper: TextSize: Null Font\n"); + return -1; + } + if (font_size <= 1) { + printf("Error: CairoTextHelper: TextSize: Font Size less then 1\n"); + return -1; + } + + FontData *font_data = cairo_text_hp_load_font(font, font_size); + + /* If we reach here without font data then we have cached too many fonts */ + if (font_data == NULL) { + printf("Error: CairoTextHelper: TextSize: Used too many fonts\n"); + return -1; + } + hb_language_t text_language; hb_direction_t text_direction; if (language != NULL) { @@ -325,10 +397,10 @@ int cairo_text_hp_text_size( const char *text, FontData *font, /* Layout the text */ hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); - hb_shape(font->hb_ft_font, buf, NULL, 0); + hb_shape(font_data->hb_ft_font, buf, NULL, 0); hb_font_extents_t font_extents; - hb_font_get_extents_for_direction(font->hb_ft_font, text_direction, &font_extents); + hb_font_get_extents_for_direction(font_data->hb_ft_font, text_direction, &font_extents); /* Hand the layout to cairo to render */ unsigned int glyph_count; @@ -347,7 +419,7 @@ int cairo_text_hp_text_size( const char *text, FontData *font, /* Width */ for (int i=0; i < glyph_count; ++i) { string_width_in_pixels += glyph_pos[i].x_advance/64+glyph_pos[i].x_offset/64; - hb_font_get_glyph_extents (font->hb_ft_font, glyph_info[i].codepoint, + hb_font_get_glyph_extents (font_data->hb_ft_font, glyph_info[i].codepoint, &glyph_extents); int h = ((glyph_extents.height/64)*-1)+(glyph_extents.y_bearing/64); if (h > string_height_in_pixels) { From 8f34c9dc8c2573a4156468517ab165ec7a45af72 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Thu, 22 Feb 2024 10:41:07 +1030 Subject: [PATCH 19/26] Revert "Fix for #1698" This reverts commit 5036cc4d09b267129351ad0d5485ca139aa98fd7. Fixed better upstream now --- src/display-x11.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/display-x11.cc b/src/display-x11.cc index 8488133f9..94b3be246 100644 --- a/src/display-x11.cc +++ b/src/display-x11.cc @@ -453,8 +453,6 @@ bool display_output_x11::main_loop_wait(double t) { // modify for propagation ev.xexpose.x += window.x; ev.xexpose.y += window.y; - // Fix for #1698 Remove from this branch before accepting Pull Request - ev.xexpose.window = window.desktop; break; } From 9ba643c7f9413c0000c2e277fc0b254cd2e36ae2 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Thu, 22 Feb 2024 11:10:24 +1030 Subject: [PATCH 20/26] docs: tolua++ now works with more then lua5.1 On my machine i'm using it with lua5.3 and I see packages for 5.4 as well. --- doc/lua.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/lua.yaml b/doc/lua.yaml index 61914964b..295ce7d84 100644 --- a/doc/lua.yaml +++ b/doc/lua.yaml @@ -12,8 +12,7 @@ --- desc: |- Conky features a Lua Programming API, and also ships with Lua bindings - for some useful libraries. Note that the bindings require tolua++, which - currently only compiles against Lua 5.1. + for some useful libraries. Note that the bindings require tolua++. To use Lua Conky, you first need to make sure you have a version of Conky with Lua support enabled (`conky -v` will report this). From f4f74627cf160223c1dead56094450984a78946d Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Thu, 22 Feb 2024 12:06:16 +1030 Subject: [PATCH 21/26] lua-text: Add docs. --- doc/lua.yaml | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/doc/lua.yaml b/doc/lua.yaml index 295ce7d84..3a44ad0f0 100644 --- a/doc/lua.yaml +++ b/doc/lua.yaml @@ -184,3 +184,44 @@ values: - name: RsvgDimensionData:get() desc: |- Gets the values of an existing RsvgDimensionData. + - name: cairo_text_hp_show(cr, x, y, text, font, font_size, alignment, language, script, direction) + desc: |- + Renders text to a cairo_t using harfbuzz and freetype, this provides significantly + better text rendering then using cairo's inbuilt functions. + + | Argument | Description | + |---------------------|--------------------------------------------------------------------------------------| + | cr | The `cairo_t` to render to. | + | x,y | Position to render the text. | + | text | The text to render. | + | font | The name of the font to be used, `Fontconfig` is used to search for the font. | + | font_size | The font size. | + | alignment | One of `CAIRO_TEXT_ALIGN_LEFT`, `CAIRO_TEXT_ALIGN_RIGHT`, `CAIRO_TEXT_ALIGN_CENTER`. | + | | Default value: `CAIRO_TEXT_ALIGN_LEFT` | + | language | A string containing a BCP 47 language tag. | + | | Default value: `en` | + | script | A string containing a ISO 15924 script tag. | + | | Default value: auto-detect from text | + | direction | A string representing text direction eg `LTR`, `RTL` or `TTB` | + | | Default value: auto-detect from text otherwise `LTR` | | + - name: width,height:cairo_text_hp_text_size(text, font, font_size, language, script, direction) + desc: |- + Used to calculate how many pixels will be required to render a string with + `cairo_text_hp_show` returns a pair of int's with `width` and `height`. + + | Argument | Description | + |---------------------|--------------------------------------------------------------------------------------| + | cr | The `cairo_t` to render to. | + | text | The text to render. | + | font | The name of the font to be used, `Fontconfig` is used to search for the font. | + | font_size | The font size. | + | language | A string containing a BCP 47 language tag. | + | | Default value: `en` | + | script | A string containing a ISO 15924 script tag. | + | | Default value: auto-detect from text | + | direction | A string representing text direction eg `LTR`, `RTL` or `TTB` | + | | Default value: auto-detect from text otherwise `LTR` | + - name: cairo_text_hp_delete_fonts() + desc: |- + `cairo_text_hp_show` and `cairo_text_hp_text_size` both cache internal font details, + this function clears those caches. \ No newline at end of file From e5482ca97941677973f2c44eeea1a239e3bdc115 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Tue, 5 Mar 2024 11:30:06 +1030 Subject: [PATCH 22/26] lua-text: Fix build with --- lua/libcairo_text_helper.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h index 55574d1f4..bf471a6f2 100644 --- a/lua/libcairo_text_helper.h +++ b/lua/libcairo_text_helper.h @@ -95,7 +95,7 @@ FontData *cairo_text_hp_import_font(const char *font, int font_size) return NULL; } - FontData *font_data = malloc(sizeof(struct _FontData)); + FontData *font_data = (FontData *)malloc(sizeof(struct _FontData)); strncpy(font_data->name, font, max_font_name_len); @@ -140,6 +140,8 @@ FontData *cairo_text_hp_load_font(const char *font, int font_size) return font_data; } } + + return font_data; } void cairo_text_hp_destroy_font(FontData *font) @@ -260,7 +262,7 @@ void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, const char unsigned int glyph_count; hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); - cairo_glyph_t *cairo_glyphs = malloc(sizeof(cairo_glyph_t) * glyph_count); + cairo_glyph_t *cairo_glyphs = (cairo_glyph_t *)malloc(sizeof(cairo_glyph_t) * glyph_count); /* RTL positioning seems to be slightly off and characters don't link as they should */ /* This hack gets it significantly closer to correct but is not 100% for all fonts and sizes */ @@ -327,22 +329,22 @@ void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, const char hb_buffer_destroy(buf); } -int cairo_text_hp_text_size( const char *text, const char *font, int font_size, +void cairo_text_hp_text_size( const char *text, const char *font, int font_size, const char *language, const char *script, const char *direction, int *width, int *height) { /* It seems that lua may just pass NULL for an empty string */ if (text == NULL) { printf("Error: CairoTextHelper: TextSize: Null string\n"); - return -1; + return; } if (font == NULL) { printf("Error: CairoTextHelper: TextSize: Null Font\n"); - return -1; + return; } if (font_size <= 1) { printf("Error: CairoTextHelper: TextSize: Font Size less then 1\n"); - return -1; + return; } FontData *font_data = cairo_text_hp_load_font(font, font_size); @@ -350,7 +352,7 @@ int cairo_text_hp_text_size( const char *text, const char *font, int font_size, /* If we reach here without font data then we have cached too many fonts */ if (font_data == NULL) { printf("Error: CairoTextHelper: TextSize: Used too many fonts\n"); - return -1; + return; } hb_language_t text_language; @@ -406,7 +408,7 @@ int cairo_text_hp_text_size( const char *text, const char *font, int font_size, unsigned int glyph_count; hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); - cairo_glyph_t *cairo_glyphs = malloc(sizeof(cairo_glyph_t) * glyph_count); + cairo_glyph_t *cairo_glyphs = (cairo_glyph_t *)malloc(sizeof(cairo_glyph_t) * glyph_count); unsigned int string_width_in_pixels = 0; unsigned int string_height_in_pixels = 0; From 78b222f990a78bd58ed57d86d1db112a9e26bd35 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Tue, 29 Oct 2024 19:44:44 +1030 Subject: [PATCH 23/26] lua-text use cairo_fill_preserve This means its possible to add borders from lua after --- lua/libcairo_text_helper.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/libcairo_text_helper.h b/lua/libcairo_text_helper.h index bf471a6f2..d491a9943 100644 --- a/lua/libcairo_text_helper.h +++ b/lua/libcairo_text_helper.h @@ -323,7 +323,9 @@ void cairo_text_hp_show(cairo_t *cr, int x, int y, const char *text, const char cairo_set_font_face(cr, font_data->cairo_ft_face); cairo_set_font_size(cr, font_data->font_size); - cairo_show_glyphs(cr, cairo_glyphs, glyph_count); + // Use glyph path and fill_preserve so its possible to add borders etc from lua after + cairo_glyph_path(cr, cairo_glyphs, glyph_count); + cairo_fill_preserve(cr); free(cairo_glyphs); hb_buffer_destroy(buf); From 9fc5fa98eba7e63fddbcd27a4b8a4b751f1aa80d Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Mon, 18 Nov 2024 12:02:36 +1030 Subject: [PATCH 24/26] Doc: Implement feedback from #1501 for tables --- doc/lua.yaml | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/doc/lua.yaml b/doc/lua.yaml index 1451d868a..2a19a8e62 100644 --- a/doc/lua.yaml +++ b/doc/lua.yaml @@ -204,8 +204,7 @@ values: | cs | The `cairo_surface_t` to render to. | | x,y | Position to render the image. | | scale_x, scale_y | The amount to scale the image, 1.0 provides no scaling, 2.0 for twice the size and | - | | 0.5 for half size etc. | - | | Default value: No Scaling (1.0,1.0) | + | | 0.5 for half size etc.
Default value: No Scaling (1.0,1.0) | require('cairo_imlib2_helper') in your lua file. @@ -221,14 +220,10 @@ values: | text | The text to render. | | font | The name of the font to be used, `Fontconfig` is used to search for the font. | | font_size | The font size. | - | alignment | One of `CAIRO_TEXT_ALIGN_LEFT`, `CAIRO_TEXT_ALIGN_RIGHT`, `CAIRO_TEXT_ALIGN_CENTER`. | - | | Default value: `CAIRO_TEXT_ALIGN_LEFT` | - | language | A string containing a BCP 47 language tag. | - | | Default value: `en` | - | script | A string containing a ISO 15924 script tag. | - | | Default value: auto-detect from text | - | direction | A string representing text direction eg `LTR`, `RTL` or `TTB` | - | | Default value: auto-detect from text otherwise `LTR` | | + | alignment | One of `CAIRO_TEXT_ALIGN_LEFT`, `CAIRO_TEXT_ALIGN_RIGHT`, `CAIRO_TEXT_ALIGN_CENTER`.
Default value: `CAIRO_TEXT_ALIGN_LEFT` | + | language | A string containing a BCP 47 language tag.
Default value: `en` | + | script | A string containing a ISO 15924 script tag.
Default value: auto-detect from text | + | direction | A string representing text direction eg `LTR`, `RTL` or `TTB`
Default value: auto-detect from text otherwise `LTR` | - name: width,height:cairo_text_hp_text_size(text, font, font_size, language, script, direction) desc: |- Used to calculate how many pixels will be required to render a string with @@ -240,12 +235,9 @@ values: | text | The text to render. | | font | The name of the font to be used, `Fontconfig` is used to search for the font. | | font_size | The font size. | - | language | A string containing a BCP 47 language tag. | - | | Default value: `en` | - | script | A string containing a ISO 15924 script tag. | - | | Default value: auto-detect from text | - | direction | A string representing text direction eg `LTR`, `RTL` or `TTB` | - | | Default value: auto-detect from text otherwise `LTR` | + | language | A string containing a BCP 47 language tag.
Default value: `en` | + | script | A string containing a ISO 15924 script tag.
Default value: auto-detect from text | + | direction | A string representing text direction eg `LTR`, `RTL` or `TTB`
Default value: auto-detect from text otherwise `LTR` | - name: cairo_text_hp_delete_fonts() desc: |- `cairo_text_hp_show` and `cairo_text_hp_text_size` both cache internal font details, From 872d87bce2e89d7fda95c88b153ba2f373b08417 Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Mon, 18 Nov 2024 12:38:37 +1030 Subject: [PATCH 25/26] lua-text: Another shot at fixing workflows This time add libfreetype-dev as well. --- .github/workflows/build-and-test-linux.yaml | 1 + .github/workflows/codeql.yml | 1 + .github/workflows/publish-appimage.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/workflows/build-and-test-linux.yaml b/.github/workflows/build-and-test-linux.yaml index bfd6c288d..eb4ed6b6c 100644 --- a/.github/workflows/build-and-test-linux.yaml +++ b/.github/workflows/build-and-test-linux.yaml @@ -46,6 +46,7 @@ jobs: libpango1.0-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ + libfreetype-dev \ libfreetype6-dev \ libstdc++6 \ libglib2.0-dev \ diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3fad655ac..5ba221c69 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,6 +39,7 @@ jobs: libcairo2-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ + libfreetype-dev \ libfreetype6-dev \ libstdc++6 \ libglib2.0-dev \ diff --git a/.github/workflows/publish-appimage.yml b/.github/workflows/publish-appimage.yml index ea549e1ae..01f147b47 100644 --- a/.github/workflows/publish-appimage.yml +++ b/.github/workflows/publish-appimage.yml @@ -45,6 +45,7 @@ jobs: libcairo2-dev \ libcurl4-gnutls-dev \ libdbus-glib-1-dev \ + libfreetype-dev \ libfreetype6-dev \ libstdc++6 \ libfuse2 \ From b1bd60566b21f461d4543d100005266672b7196c Mon Sep 17 00:00:00 2001 From: Simon Lees Date: Mon, 18 Nov 2024 12:56:17 +1030 Subject: [PATCH 26/26] cmake: try and use find_package for freetype The old version worked on openSUSE but not ubuntu's CI, this version also works on openSUSE lets see if it works in the CI --- cmake/ConkyPlatformChecks.cmake | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/cmake/ConkyPlatformChecks.cmake b/cmake/ConkyPlatformChecks.cmake index c7f17ab3e..04cf63cb4 100644 --- a/cmake/ConkyPlatformChecks.cmake +++ b/cmake/ConkyPlatformChecks.cmake @@ -375,12 +375,7 @@ if(BUILD_X11) # check for Xft if(BUILD_XFT) - if(FREETYPE_INCLUDE_DIR_freetype2) - set(FREETYPE_FOUND true) - set(conky_includes ${conky_includes} ${FREETYPE_INCLUDE_DIR_freetype2}) - else(FREETYPE_INCLUDE_DIR_freetype2) - message(FATAL_ERROR "Unable to find freetype library") - endif(FREETYPE_INCLUDE_DIR_freetype2) + find_package(Freetype REQUIRED) if(NOT X11_Xft_FOUND) message(FATAL_ERROR "Unable to find Xft library") @@ -534,11 +529,7 @@ if(BUILD_LUA_RSVG) endif(BUILD_LUA_RSVG) if(BUILD_LUA_TEXT) - if(FREETYPE_INCLUDE_DIR_freetype2) - set(FREETYPE_FOUND true) - else(FREETYPE_INCLUDE_DIR_freetype2) - message(FATAL_ERROR "Unable to find freetype library") - endif(FREETYPE_INCLUDE_DIR_freetype2) + find_package(Freetype REQUIRED) PKG_CHECK_MODULES(FONTCONFIG REQUIRED fontconfig) PKG_CHECK_MODULES(HARFBUZZ REQUIRED harfbuzz) set(luatext_libs ${FREETYPE_LIBRARIES} ${FONTCONFIG_LIBRARIES} ${HARFBUZZ_LIBRARIES} ${LUA_LIBRARIES})