diff -Nura plymouth-0.9.5+git20191101+d18086e/configure.ac plymouth-0.9.5+git20191101+d18086e_new/configure.ac --- plymouth-0.9.5+git20191101+d18086e/configure.ac 2019-11-06 10:19:50.000000000 +0800 +++ plymouth-0.9.5+git20191101+d18086e_new/configure.ac 2019-12-14 17:27:03.730000000 +0800 @@ -76,6 +76,15 @@ AC_SUBST(PANGO_LIBS) fi +AC_ARG_ENABLE(freetype, AS_HELP_STRING([--enable-freetype],[enable building the FreeType-based label plugin]),enable_freetype=$enableval,enable_freetype=yes) +AM_CONDITIONAL(ENABLE_FREETYPE, [test "$enable_freetype" = yes]) + +if test x$enable_freetype = xyes; then + PKG_CHECK_MODULES(FREETYPE, [freetype2]) + AC_SUBST(FREETYPE_CFLAGS) + AC_SUBST(FREETYPE_LIBS) +fi + AC_ARG_ENABLE(gtk, AS_HELP_STRING([--enable-gtk],[enable building with gtk, disabled there is no x11 renderer]),enable_gtk=$enableval,enable_gtk=yes) AM_CONDITIONAL(ENABLE_GTK, [test "$enable_gtk" = yes]) @@ -318,6 +327,7 @@ src/plugins/splash/script/Makefile src/plugins/controls/Makefile src/plugins/controls/label/Makefile + src/plugins/controls/label-ft/Makefile src/Makefile src/client/ply-boot-client.pc src/client/Makefile diff -Nura plymouth-0.9.5+git20191101+d18086e/src/libply-splash-graphics/ply-label.c plymouth-0.9.5+git20191101+d18086e_new/src/libply-splash-graphics/ply-label.c --- plymouth-0.9.5+git20191101+d18086e/src/libply-splash-graphics/ply-label.c 2019-10-22 15:31:17.000000000 +0800 +++ plymouth-0.9.5+git20191101+d18086e_new/src/libply-splash-graphics/ply-label.c 2019-12-14 17:23:10.796000000 +0800 @@ -98,6 +98,10 @@ label->module_handle = ply_open_module (PLYMOUTH_PLUGIN_PATH "label.so"); + /* ...and the FreeType based one after that, it is not a complete substitute (yet). */ + if (label->module_handle == NULL) + label->module_handle = ply_open_module (PLYMOUTH_PLUGIN_PATH "label-ft.so"); + if (label->module_handle == NULL) return false; diff -Nura plymouth-0.9.5+git20191101+d18086e/src/plugins/controls/label-ft/Makefile.am plymouth-0.9.5+git20191101+d18086e_new/src/plugins/controls/label-ft/Makefile.am --- plymouth-0.9.5+git20191101+d18086e/src/plugins/controls/label-ft/Makefile.am 1970-01-01 08:00:00.000000000 +0800 +++ plymouth-0.9.5+git20191101+d18086e_new/src/plugins/controls/label-ft/Makefile.am 2019-12-14 17:17:26.473000000 +0800 @@ -0,0 +1,22 @@ +AM_CPPFLAGS = -I$(top_srcdir) \ + -I$(srcdir)/../../../libply \ + -I$(srcdir)/../../../libply-splash-core \ + -I$(srcdir)/../../../libply-splash-graphics \ + -I$(srcdir)/../../.. \ + -I$(srcdir)/../.. \ + -I$(srcdir)/.. \ + -I$(srcdir) + +plugindir = $(libdir)/plymouth +plugin_LTLIBRARIES = label-ft.la + +label_ft_la_CFLAGS = $(PLYMOUTH_CFLAGS) $(FREETYPE_CFLAGS) + +label_ft_la_LDFLAGS = -module -avoid-version -export-dynamic +label_ft_la_LIBADD = $(PLYMOUTH_LIBS) $(FREETYPE_LIBS) \ + ../../../libply/libply.la \ + ../../../libply-splash-core/libply-splash-core.la \ + ../../../libply-splash-graphics/libply-splash-graphics.la +label_ft_la_SOURCES = $(srcdir)/plugin.c + +MAINTAINERCLEANFILES = Makefile.in diff -Nura plymouth-0.9.5+git20191101+d18086e/src/plugins/controls/label-ft/plugin.c plymouth-0.9.5+git20191101+d18086e_new/src/plugins/controls/label-ft/plugin.c --- plymouth-0.9.5+git20191101+d18086e/src/plugins/controls/label-ft/plugin.c 1970-01-01 08:00:00.000000000 +0800 +++ plymouth-0.9.5+git20191101+d18086e_new/src/plugins/controls/label-ft/plugin.c 2019-12-14 17:17:26.475000000 +0800 @@ -0,0 +1,507 @@ +/* ply-label.c - label control + * + * Copyright (C) 2008 Red Hat, Inc. + * Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. + * + * 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 2, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Ray Strode + * Written by: Fabian Vogt + */ +#include "config.h" + +#include +#include +#include +#include + +#include +#include FT_FREETYPE_H + +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" +#include "ply-utils.h" + +#include "ply-label-plugin.h" + +/* This is used if fontconfig (fc-match) is not available, like in the initrd. */ +#define FONT_FALLBACK "/usr/share/fonts/Plymouth.ttf" + +struct _ply_label_plugin_control +{ + ply_pixel_display_t *display; + ply_rectangle_t area; + + ply_label_alignment_t alignment; + long width; /* For alignment */ + + FT_Library library; + FT_Face face; + + char *text; + float red; + float green; + float blue; + float alpha; + + bool is_hidden; +}; + +ply_label_plugin_interface_t *ply_label_plugin_get_interface (void); + +/* Query fontconfig, if available, for the default font. */ +static const char * +query_fc_match() +{ + FILE *fp; + static char fc_match_out[PATH_MAX]; + + fp = popen("/usr/bin/fc-match -f %{file}", "r"); + if (!fp) + return NULL; + + fgets(fc_match_out, sizeof(fc_match_out), fp); + + pclose(fp); + + return fc_match_out; +} + +static ply_label_plugin_control_t * +create_control (void) +{ + FT_Error error; + ply_label_plugin_control_t *label; + const char *font_path; + + label = calloc (1, sizeof(ply_label_plugin_control_t)); + if(!label) + return NULL; + + label->is_hidden = true; + label->width = -1; + label->text = NULL; + + error = FT_Init_FreeType (&label->library); + if(error) + { + free(label); + return NULL; + } + + font_path = query_fc_match(); + + if(font_path) + error = FT_New_Face (label->library, font_path, 0, &label->face); + + if(!font_path || error) + { + font_path = FONT_FALLBACK; + error = FT_New_Face (label->library, font_path, 0, &label->face); + + if(error) + { + FT_Done_FreeType (label->library); + free(label); + return NULL; + } + } + + /* 12pt/100dpi as default */ + error = FT_Set_Char_Size (label->face, 12 << 6, 0, 100, 0); + if(error) + { + FT_Done_Face (label->face); + FT_Done_FreeType (label->library); + free(label); + return NULL; + } + + return label; +} + +static void +destroy_control (ply_label_plugin_control_t *label) +{ + if (label == NULL) + return; + + free (label->text); + FT_Done_Face (label->face); + FT_Done_FreeType (label->library); + + free (label); +} + +static long +get_width_of_control (ply_label_plugin_control_t *label) +{ + return label->area.width; +} + +static long +get_height_of_control (ply_label_plugin_control_t *label) +{ + return label->area.height; +} + +static FT_Int width_of_line(ply_label_plugin_control_t *label, + const char *text) +{ + FT_Int width = 0; + FT_Int last_left = 0; + + while(*text != '\0' && *text != '\n') + { + if(FT_Load_Char (label->face, *text, FT_LOAD_RENDER)) + continue; + + width += label->face->glyph->advance.x >> 6; + last_left = label->face->glyph->bitmap_left; + + ++text; + } + + return width + last_left; +} + +static void +size_control (ply_label_plugin_control_t *label) +{ + FT_Int width; + const char *text = label->text; + + if(label->is_hidden) + return; + + label->area.width = 0; + label->area.height = 0; + + /* Go through each line */ + while(text && *text) + { + width = width_of_line (label, text); + if((uint32_t) width > label->area.width) + label->area.width = width; + + label->area.height += (label->face->size->metrics.ascender - label->face->size->metrics.descender) >> 6; + + text = strchr (text, '\n'); + /* skip newline character */ + if (text) + ++text; + } + + /* If centered, area.x is not the origin anymore */ + if((long) label->area.width < label->width) + label->area.width = label->width; +} + +static void trigger_redraw (ply_label_plugin_control_t *label, + bool adjust_size) +{ + ply_rectangle_t dirty_area = label->area; + + if (label->is_hidden || label->display == NULL) + return; + + if(adjust_size) + size_control(label); + + ply_pixel_display_draw_area (label->display, + dirty_area.x, dirty_area.y, + dirty_area.width, dirty_area.height); +} + +static FT_Int +min (FT_Int a, + FT_Int b) +{ + return a < b ? a : b; +} + +static void +draw_bitmap (ply_label_plugin_control_t *label, + uint32_t *target, + ply_rectangle_t target_size, + FT_Bitmap *source, + FT_Int x_start, + FT_Int y_start) +{ + FT_Int x, y, xs, ys; + FT_Int x_end = min (x_start + source->width, target_size.width); + FT_Int y_end = min (y_start + source->rows, target_size.height); + + if((uint32_t) x_start >= target_size.width || (uint32_t) y_start >= target_size.height) + return; + + uint8_t rs, gs, bs, rd, gd, bd, ad; + rs = 255 * label->red; + gs = 255 * label->green; + bs = 255 * label->blue; + + for(y = y_start, ys = 0; y < y_end; ++y, ++ys) + for(x = x_start, xs = 0; x < x_end; ++x, ++xs) + { + float alpha = label->alpha * (source->buffer[xs + source->pitch * ys] / 255.0f); + float invalpha = 1.0f - alpha; + uint32_t dest = target[x + target_size.width * y]; + + /* Separate colors */ + rd = dest >> 16; + gd = dest >> 8; + bd = dest; + + /* Alpha blending */ + rd = invalpha * rd + alpha * rs; + gd = invalpha * gd + alpha * gs; + bd = invalpha * bd + alpha * bs; + /* Semi-correct: Disregard the target alpha */ + ad = alpha * 255; + + target[x + target_size.width * y] = (ad << 24) | (rd << 16) | (gd << 8) | bd; + } +} + +static void +draw_control (ply_label_plugin_control_t *label, + ply_pixel_buffer_t *pixel_buffer, + long x, + long y, + unsigned long width, + unsigned long height) +{ + FT_Error error; + FT_Vector pen; + FT_GlyphSlot slot; + const char *cur_c; + uint32_t *target; + ply_rectangle_t target_size; + + if (label->is_hidden) + return; + + /* Check for overlap. + TODO: Don't redraw everything if only a part should be drawn! */ + if(label->area.x > x + (long) width || label->area.y > y + (long) height + || label->area.x + (long) label->area.width < x + || label->area.y + (long) label->area.height < y) + return; + + slot = label->face->glyph; + + cur_c = label->text; + + target = ply_pixel_buffer_get_argb32_data (pixel_buffer); + ply_pixel_buffer_get_size (pixel_buffer, &target_size); + + if(target_size.height == 0) + return; /* This happens sometimes. */ + + /* 64ths of a pixel */ + pen.y = label->area.y << 6; + + /* Make sure that the first row fits */ + pen.y += label->face->size->metrics.ascender; + + /* Go through each line */ + while(*cur_c) + { + pen.x = label->area.x << 6; + + /* Start at start position (alignment) */ + if(label->alignment == PLY_LABEL_ALIGN_CENTER) + pen.x += (label->width - width_of_line(label, cur_c)) << 5; + else if(label->alignment == PLY_LABEL_ALIGN_RIGHT) + pen.x += (label->width - width_of_line(label, cur_c)) << 6; + + while(*cur_c && *cur_c != '\n') + { + /* TODO: Unicode support. */ + error = FT_Load_Char (label->face, *cur_c, FT_LOAD_RENDER | FT_LOAD_TARGET_LIGHT); + if(error) + continue; + + draw_bitmap (label, target, target_size, &slot->bitmap, + (pen.x >> 6) + slot->bitmap_left, + (pen.y >> 6) - slot->bitmap_top); + + pen.x += slot->advance.x; + pen.y += slot->advance.y; + + ++cur_c; + } + /* skip newline character */ + if (*cur_c) + ++cur_c; + + /* Next line */ + pen.y += label->face->size->metrics.height; + } +} + +static void +set_alignment_for_control (ply_label_plugin_control_t *label, + ply_label_alignment_t alignment) +{ + if (label->alignment != alignment) { + label->alignment = alignment; + trigger_redraw(label, true); + } +} + +static void +set_width_for_control (ply_label_plugin_control_t *label, + long width) +{ + if (label->width != width) { + label->width = width; + trigger_redraw(label, true); + } +} + +static void +set_text_for_control (ply_label_plugin_control_t *label, + const char *text) +{ + if (label->text != text) { + free (label->text); + label->text = strdup (text); + trigger_redraw(label, true); + } +} + +static void +set_font_for_control (ply_label_plugin_control_t *label, + const char *fontdesc) +{ + /* Only able to set size */ + + char *size_str_after; + const char *size_str; + unsigned long size; + bool size_in_pixels; + + size = 25; /* Default, if not set. */ + size_in_pixels = false; + + /* Format is "Family 1[,Family 2[,..]] [25[px]]" . + [] means optional. */ + size_str = strrchr(fontdesc, ' '); + + if(size_str) + { + size = strtoul(size_str, &size_str_after, 10); + if(size_str_after == size_str) + size = 25; /* Not a number */ + else if(strcmp(size_str_after, "px") == 0) + size_in_pixels = true; + } + + if(size_in_pixels) + FT_Set_Pixel_Sizes (label->face, 0, size); + else + FT_Set_Char_Size (label->face, size << 6, 0, 100, 0); + + /* Ignore errors, to keep the current size. */ + + trigger_redraw(label, true); +} + +static void +set_color_for_control (ply_label_plugin_control_t *label, + float red, + float green, + float blue, + float alpha) +{ + label->red = red; + label->green = green; + label->blue = blue; + label->alpha = alpha; + + trigger_redraw(label, false); +} + +static bool +show_control (ply_label_plugin_control_t *label, + ply_pixel_display_t *display, + long x, + long y) +{ + ply_rectangle_t dirty_area; + + dirty_area = label->area; + label->display = display; + label->area.x = x; + label->area.y = y; + + label->is_hidden = false; + + size_control (label); + + if (!label->is_hidden && label->display != NULL) + ply_pixel_display_draw_area (label->display, + dirty_area.x, dirty_area.y, + dirty_area.width, dirty_area.height); + + label->is_hidden = false; + + return true; +} + +static void +hide_control (ply_label_plugin_control_t *label) +{ + label->is_hidden = true; + if (label->display != NULL) + ply_pixel_display_draw_area (label->display, + label->area.x, label->area.y, + label->area.width, label->area.height); + + label->display = NULL; +} + +static bool +is_control_hidden (ply_label_plugin_control_t *label) +{ + return label->is_hidden; +} + +ply_label_plugin_interface_t * +ply_label_plugin_get_interface (void) +{ + static ply_label_plugin_interface_t plugin_interface = + { + .create_control = create_control, + .destroy_control = destroy_control, + .show_control = show_control, + .hide_control = hide_control, + .draw_control = draw_control, + .is_control_hidden = is_control_hidden, + .set_text_for_control = set_text_for_control, + .set_alignment_for_control = set_alignment_for_control, + .set_width_for_control = set_width_for_control, + .set_font_for_control = set_font_for_control, + .set_color_for_control = set_color_for_control, + .get_width_of_control = get_width_of_control, + .get_height_of_control = get_height_of_control + }; + + return &plugin_interface; +} + +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff -Nura plymouth-0.9.5+git20191101+d18086e/src/plugins/controls/Makefile.am plymouth-0.9.5+git20191101+d18086e_new/src/plugins/controls/Makefile.am --- plymouth-0.9.5+git20191101+d18086e/src/plugins/controls/Makefile.am 2019-10-22 15:31:17.000000000 +0800 +++ plymouth-0.9.5+git20191101+d18086e_new/src/plugins/controls/Makefile.am 2019-12-14 17:20:38.575000000 +0800 @@ -1,4 +1,8 @@ +SUBDIRS = if ENABLE_PANGO -SUBDIRS = label +SUBDIRS += label +endif +if ENABLE_FREETYPE +SUBDIRS += label-ft endif MAINTAINERCLEANFILES = Makefile.in