diff options
Diffstat (limited to '')
31 files changed, 7448 insertions, 0 deletions
diff --git a/app/text/Makefile.am b/app/text/Makefile.am new file mode 100644 index 0000000..de7616e --- /dev/null +++ b/app/text/Makefile.am @@ -0,0 +1,80 @@ +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gimp-Text\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir)/app \ + -I$(top_srcdir)/app \ + $(GEGL_CFLAGS) \ + $(PANGOCAIRO_CFLAGS) \ + $(HARFBUZZ_CFLAGS) \ + $(GDK_PIXBUF_CFLAGS) \ + -I$(includedir) + +noinst_LIBRARIES = libapptext.a + +libapptext_a_sources = \ + text-types.h \ + text-enums.h \ + gimpfont.c \ + gimpfont.h \ + gimpfontfactory.c \ + gimpfontfactory.h \ + gimptext.c \ + gimptext.h \ + gimptext-compat.c \ + gimptext-compat.h \ + gimptext-parasite.c \ + gimptext-parasite.h \ + gimptext-vectors.c \ + gimptext-vectors.h \ + gimptext-xlfd.c \ + gimptext-xlfd.h \ + gimptextlayer.c \ + gimptextlayer.h \ + gimptextlayer-transform.c \ + gimptextlayer-transform.h \ + gimptextlayer-xcf.c \ + gimptextlayer-xcf.h \ + gimptextlayout.c \ + gimptextlayout.h \ + gimptextlayout-render.c \ + gimptextlayout-render.h \ + gimptextundo.c \ + gimptextundo.h + +libapptext_a_built_sources = text-enums.c + +libapptext_a_SOURCES = $(libapptext_a_built_sources) $(libapptext_a_sources) + +# +# rules to generate built sources +# +# setup autogeneration dependencies +gen_sources = xgen-tec +CLEANFILES = $(gen_sources) + +xgen-tec: $(srcdir)/text-enums.h $(GIMP_MKENUMS) Makefile.am + $(AM_V_GEN) $(GIMP_MKENUMS) \ + --fhead "#include \"config.h\"\n#include <gio/gio.h>\n#include \"libgimpbase/gimpbase.h\"\n#include \"text-enums.h\"\n#include \"gimp-intl.h\"" \ + --fprod "\n/* enumerations from \"@basename@\" */" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n static const G@Type@Value values[] =\n {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n };\n" \ + --dhead " static const Gimp@Type@Desc descs[] =\n {" \ + --dprod " { @VALUENAME@, @valuedesc@, @valuehelp@ },@if ('@valueabbrev@' ne 'NULL')@\n /* Translators: this is an abbreviated version of @valueudesc@.\n Keep it short. */\n { @VALUENAME@, @valueabbrev@, NULL },@endif@" \ + --dtail " { 0, NULL, NULL }\n };\n\n static GType type = 0;\n\n if (G_UNLIKELY (! type))\n {\n type = g_@type@_register_static (\"@EnumName@\", values);\n gimp_type_set_translation_context (type, \"@enumnick@\");\n gimp_@type@_set_value_descriptions (type, descs);\n }\n\n return type;\n}\n" \ + $< > $@ + +# copy the generated enum file back to the source directory only if it's +# changed; otherwise, only update its timestamp, so that the recipe isn't +# executed again on the next build, however, allow this to (harmlessly) fail, +# to support building from a read-only source tree. +$(srcdir)/text-enums.c: xgen-tec + $(AM_V_GEN) if ! cmp -s $< $@; then \ + cp $< $@; \ + else \ + touch $@ 2> /dev/null \ + || true; \ + fi diff --git a/app/text/Makefile.in b/app/text/Makefile.in new file mode 100644 index 0000000..699ff00 --- /dev/null +++ b/app/text/Makefile.in @@ -0,0 +1,1030 @@ +# Makefile.in generated by automake 1.16.2 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = app/text +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4macros/gtk-doc.m4 \ + $(top_srcdir)/m4macros/intltool.m4 \ + $(top_srcdir)/m4macros/libtool.m4 \ + $(top_srcdir)/m4macros/ltoptions.m4 \ + $(top_srcdir)/m4macros/ltsugar.m4 \ + $(top_srcdir)/m4macros/ltversion.m4 \ + $(top_srcdir)/m4macros/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/m4macros/alsa.m4 \ + $(top_srcdir)/m4macros/ax_compare_version.m4 \ + $(top_srcdir)/m4macros/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/m4macros/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/m4macros/ax_prog_cc_for_build.m4 \ + $(top_srcdir)/m4macros/ax_prog_perl_version.m4 \ + $(top_srcdir)/m4macros/detectcflags.m4 \ + $(top_srcdir)/m4macros/pythondev.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libapptext_a_AR = $(AR) $(ARFLAGS) +libapptext_a_LIBADD = +am__objects_1 = text-enums.$(OBJEXT) +am__objects_2 = gimpfont.$(OBJEXT) gimpfontfactory.$(OBJEXT) \ + gimptext.$(OBJEXT) gimptext-compat.$(OBJEXT) \ + gimptext-parasite.$(OBJEXT) gimptext-vectors.$(OBJEXT) \ + gimptext-xlfd.$(OBJEXT) gimptextlayer.$(OBJEXT) \ + gimptextlayer-transform.$(OBJEXT) gimptextlayer-xcf.$(OBJEXT) \ + gimptextlayout.$(OBJEXT) gimptextlayout-render.$(OBJEXT) \ + gimptextundo.$(OBJEXT) +am_libapptext_a_OBJECTS = $(am__objects_1) $(am__objects_2) +libapptext_a_OBJECTS = $(am_libapptext_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/gimpfont.Po \ + ./$(DEPDIR)/gimpfontfactory.Po ./$(DEPDIR)/gimptext-compat.Po \ + ./$(DEPDIR)/gimptext-parasite.Po \ + ./$(DEPDIR)/gimptext-vectors.Po ./$(DEPDIR)/gimptext-xlfd.Po \ + ./$(DEPDIR)/gimptext.Po ./$(DEPDIR)/gimptextlayer-transform.Po \ + ./$(DEPDIR)/gimptextlayer-xcf.Po ./$(DEPDIR)/gimptextlayer.Po \ + ./$(DEPDIR)/gimptextlayout-render.Po \ + ./$(DEPDIR)/gimptextlayout.Po ./$(DEPDIR)/gimptextundo.Po \ + ./$(DEPDIR)/text-enums.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libapptext_a_SOURCES) +DIST_SOURCES = $(libapptext_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +AA_LIBS = @AA_LIBS@ +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +ALL_LINGUAS = @ALL_LINGUAS@ +ALSA_CFLAGS = @ALSA_CFLAGS@ +ALSA_LIBS = @ALSA_LIBS@ +ALTIVEC_EXTRA_CFLAGS = @ALTIVEC_EXTRA_CFLAGS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APPSTREAM_UTIL = @APPSTREAM_UTIL@ +AR = @AR@ +AS = @AS@ +ATK_CFLAGS = @ATK_CFLAGS@ +ATK_LIBS = @ATK_LIBS@ +ATK_REQUIRED_VERSION = @ATK_REQUIRED_VERSION@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BABL_CFLAGS = @BABL_CFLAGS@ +BABL_LIBS = @BABL_LIBS@ +BABL_REQUIRED_VERSION = @BABL_REQUIRED_VERSION@ +BUG_REPORT_URL = @BUG_REPORT_URL@ +BUILD_EXEEXT = @BUILD_EXEEXT@ +BUILD_OBJEXT = @BUILD_OBJEXT@ +BZIP2_LIBS = @BZIP2_LIBS@ +CAIRO_CFLAGS = @CAIRO_CFLAGS@ +CAIRO_LIBS = @CAIRO_LIBS@ +CAIRO_PDF_CFLAGS = @CAIRO_PDF_CFLAGS@ +CAIRO_PDF_LIBS = @CAIRO_PDF_LIBS@ +CAIRO_PDF_REQUIRED_VERSION = @CAIRO_PDF_REQUIRED_VERSION@ +CAIRO_REQUIRED_VERSION = @CAIRO_REQUIRED_VERSION@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CC_VERSION = @CC_VERSION@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CPP_FOR_BUILD = @CPP_FOR_BUILD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DESKTOP_DATADIR = @DESKTOP_DATADIR@ +DESKTOP_FILE_VALIDATE = @DESKTOP_FILE_VALIDATE@ +DLLTOOL = @DLLTOOL@ +DOC_SHOOTER = @DOC_SHOOTER@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILE_AA = @FILE_AA@ +FILE_EXR = @FILE_EXR@ +FILE_HEIF = @FILE_HEIF@ +FILE_JP2_LOAD = @FILE_JP2_LOAD@ +FILE_MNG = @FILE_MNG@ +FILE_PDF_SAVE = @FILE_PDF_SAVE@ +FILE_PS = @FILE_PS@ +FILE_WMF = @FILE_WMF@ +FILE_XMC = @FILE_XMC@ +FILE_XPM = @FILE_XPM@ +FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ +FONTCONFIG_LIBS = @FONTCONFIG_LIBS@ +FONTCONFIG_REQUIRED_VERSION = @FONTCONFIG_REQUIRED_VERSION@ +FREETYPE2_REQUIRED_VERSION = @FREETYPE2_REQUIRED_VERSION@ +FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ +FREETYPE_LIBS = @FREETYPE_LIBS@ +GDBUS_CODEGEN = @GDBUS_CODEGEN@ +GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@ +GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@ +GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@ +GDK_PIXBUF_REQUIRED_VERSION = @GDK_PIXBUF_REQUIRED_VERSION@ +GEGL = @GEGL@ +GEGL_CFLAGS = @GEGL_CFLAGS@ +GEGL_LIBS = @GEGL_LIBS@ +GEGL_MAJOR_MINOR_VERSION = @GEGL_MAJOR_MINOR_VERSION@ +GEGL_REQUIRED_VERSION = @GEGL_REQUIRED_VERSION@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GEXIV2_CFLAGS = @GEXIV2_CFLAGS@ +GEXIV2_LIBS = @GEXIV2_LIBS@ +GEXIV2_REQUIRED_VERSION = @GEXIV2_REQUIRED_VERSION@ +GIMP_API_VERSION = @GIMP_API_VERSION@ +GIMP_APP_VERSION = @GIMP_APP_VERSION@ +GIMP_BINARY_AGE = @GIMP_BINARY_AGE@ +GIMP_COMMAND = @GIMP_COMMAND@ +GIMP_DATA_VERSION = @GIMP_DATA_VERSION@ +GIMP_FULL_NAME = @GIMP_FULL_NAME@ +GIMP_INTERFACE_AGE = @GIMP_INTERFACE_AGE@ +GIMP_MAJOR_VERSION = @GIMP_MAJOR_VERSION@ +GIMP_MICRO_VERSION = @GIMP_MICRO_VERSION@ +GIMP_MINOR_VERSION = @GIMP_MINOR_VERSION@ +GIMP_MKENUMS = @GIMP_MKENUMS@ +GIMP_MODULES = @GIMP_MODULES@ +GIMP_PACKAGE_REVISION = @GIMP_PACKAGE_REVISION@ +GIMP_PKGCONFIG_VERSION = @GIMP_PKGCONFIG_VERSION@ +GIMP_PLUGINS = @GIMP_PLUGINS@ +GIMP_PLUGIN_VERSION = @GIMP_PLUGIN_VERSION@ +GIMP_REAL_VERSION = @GIMP_REAL_VERSION@ +GIMP_SYSCONF_VERSION = @GIMP_SYSCONF_VERSION@ +GIMP_TOOL_VERSION = @GIMP_TOOL_VERSION@ +GIMP_UNSTABLE = @GIMP_UNSTABLE@ +GIMP_USER_VERSION = @GIMP_USER_VERSION@ +GIMP_VERSION = @GIMP_VERSION@ +GIO_CFLAGS = @GIO_CFLAGS@ +GIO_LIBS = @GIO_LIBS@ +GIO_UNIX_CFLAGS = @GIO_UNIX_CFLAGS@ +GIO_UNIX_LIBS = @GIO_UNIX_LIBS@ +GIO_WINDOWS_CFLAGS = @GIO_WINDOWS_CFLAGS@ +GIO_WINDOWS_LIBS = @GIO_WINDOWS_LIBS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GLIB_REQUIRED_VERSION = @GLIB_REQUIRED_VERSION@ +GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@ +GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GOBJECT_QUERY = @GOBJECT_QUERY@ +GREP = @GREP@ +GS_LIBS = @GS_LIBS@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_LIBS = @GTK_LIBS@ +GTK_MAC_INTEGRATION_CFLAGS = @GTK_MAC_INTEGRATION_CFLAGS@ +GTK_MAC_INTEGRATION_LIBS = @GTK_MAC_INTEGRATION_LIBS@ +GTK_REQUIRED_VERSION = @GTK_REQUIRED_VERSION@ +GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@ +GUDEV_CFLAGS = @GUDEV_CFLAGS@ +GUDEV_LIBS = @GUDEV_LIBS@ +HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@ +HARFBUZZ_LIBS = @HARFBUZZ_LIBS@ +HARFBUZZ_REQUIRED_VERSION = @HARFBUZZ_REQUIRED_VERSION@ +HAVE_CXX14 = @HAVE_CXX14@ +HAVE_FINITE = @HAVE_FINITE@ +HAVE_ISFINITE = @HAVE_ISFINITE@ +HAVE_VFORK = @HAVE_VFORK@ +HOST_GLIB_COMPILE_RESOURCES = @HOST_GLIB_COMPILE_RESOURCES@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLLIBS = @INTLLIBS@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +INTLTOOL_MERGE = @INTLTOOL_MERGE@ +INTLTOOL_PERL = @INTLTOOL_PERL@ +INTLTOOL_REQUIRED_VERSION = @INTLTOOL_REQUIRED_VERSION@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@ +INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@ +INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@ +INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +ISO_CODES_LOCALEDIR = @ISO_CODES_LOCALEDIR@ +ISO_CODES_LOCATION = @ISO_CODES_LOCATION@ +JPEG_LIBS = @JPEG_LIBS@ +JSON_GLIB_CFLAGS = @JSON_GLIB_CFLAGS@ +JSON_GLIB_LIBS = @JSON_GLIB_LIBS@ +LCMS_CFLAGS = @LCMS_CFLAGS@ +LCMS_LIBS = @LCMS_LIBS@ +LCMS_REQUIRED_VERSION = @LCMS_REQUIRED_VERSION@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBACKTRACE_LIBS = @LIBBACKTRACE_LIBS@ +LIBHEIF_CFLAGS = @LIBHEIF_CFLAGS@ +LIBHEIF_LIBS = @LIBHEIF_LIBS@ +LIBHEIF_REQUIRED_VERSION = @LIBHEIF_REQUIRED_VERSION@ +LIBLZMA_REQUIRED_VERSION = @LIBLZMA_REQUIRED_VERSION@ +LIBMYPAINT_CFLAGS = @LIBMYPAINT_CFLAGS@ +LIBMYPAINT_LIBS = @LIBMYPAINT_LIBS@ +LIBMYPAINT_REQUIRED_VERSION = @LIBMYPAINT_REQUIRED_VERSION@ +LIBOBJS = @LIBOBJS@ +LIBPNG_REQUIRED_VERSION = @LIBPNG_REQUIRED_VERSION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@ +LIBUNWIND_LIBS = @LIBUNWIND_LIBS@ +LIBUNWIND_REQUIRED_VERSION = @LIBUNWIND_REQUIRED_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LT_VERSION_INFO = @LT_VERSION_INFO@ +LZMA_CFLAGS = @LZMA_CFLAGS@ +LZMA_LIBS = @LZMA_LIBS@ +MAIL = @MAIL@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MIME_INFO_CFLAGS = @MIME_INFO_CFLAGS@ +MIME_INFO_LIBS = @MIME_INFO_LIBS@ +MIME_TYPES = @MIME_TYPES@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MMX_EXTRA_CFLAGS = @MMX_EXTRA_CFLAGS@ +MNG_CFLAGS = @MNG_CFLAGS@ +MNG_LIBS = @MNG_LIBS@ +MSGFMT = @MSGFMT@ +MSGFMT_OPTS = @MSGFMT_OPTS@ +MSGMERGE = @MSGMERGE@ +MYPAINT_BRUSHES_CFLAGS = @MYPAINT_BRUSHES_CFLAGS@ +MYPAINT_BRUSHES_LIBS = @MYPAINT_BRUSHES_LIBS@ +NATIVE_GLIB_CFLAGS = @NATIVE_GLIB_CFLAGS@ +NATIVE_GLIB_LIBS = @NATIVE_GLIB_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENEXR_CFLAGS = @OPENEXR_CFLAGS@ +OPENEXR_LIBS = @OPENEXR_LIBS@ +OPENEXR_REQUIRED_VERSION = @OPENEXR_REQUIRED_VERSION@ +OPENJPEG_CFLAGS = @OPENJPEG_CFLAGS@ +OPENJPEG_LIBS = @OPENJPEG_LIBS@ +OPENJPEG_REQUIRED_VERSION = @OPENJPEG_REQUIRED_VERSION@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PANGOCAIRO_CFLAGS = @PANGOCAIRO_CFLAGS@ +PANGOCAIRO_LIBS = @PANGOCAIRO_LIBS@ +PANGOCAIRO_REQUIRED_VERSION = @PANGOCAIRO_REQUIRED_VERSION@ +PATHSEP = @PATHSEP@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_REQUIRED_VERSION = @PERL_REQUIRED_VERSION@ +PERL_VERSION = @PERL_VERSION@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PNG_CFLAGS = @PNG_CFLAGS@ +PNG_LIBS = @PNG_LIBS@ +POFILES = @POFILES@ +POPPLER_CFLAGS = @POPPLER_CFLAGS@ +POPPLER_DATA_CFLAGS = @POPPLER_DATA_CFLAGS@ +POPPLER_DATA_LIBS = @POPPLER_DATA_LIBS@ +POPPLER_DATA_REQUIRED_VERSION = @POPPLER_DATA_REQUIRED_VERSION@ +POPPLER_LIBS = @POPPLER_LIBS@ +POPPLER_REQUIRED_VERSION = @POPPLER_REQUIRED_VERSION@ +POSUB = @POSUB@ +PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ +PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ +PYBIN_PATH = @PYBIN_PATH@ +PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@ +PYCAIRO_LIBS = @PYCAIRO_LIBS@ +PYGIMP_EXTRA_CFLAGS = @PYGIMP_EXTRA_CFLAGS@ +PYGTK_CFLAGS = @PYGTK_CFLAGS@ +PYGTK_CODEGEN = @PYGTK_CODEGEN@ +PYGTK_DEFSDIR = @PYGTK_DEFSDIR@ +PYGTK_LIBS = @PYGTK_LIBS@ +PYLINK_LIBS = @PYLINK_LIBS@ +PYTHON = @PYTHON@ +PYTHON2_REQUIRED_VERSION = @PYTHON2_REQUIRED_VERSION@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +RSVG_REQUIRED_VERSION = @RSVG_REQUIRED_VERSION@ +RT_LIBS = @RT_LIBS@ +SCREENSHOT_LIBS = @SCREENSHOT_LIBS@ +SED = @SED@ +SENDMAIL = @SENDMAIL@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKET_LIBS = @SOCKET_LIBS@ +SSE2_EXTRA_CFLAGS = @SSE2_EXTRA_CFLAGS@ +SSE4_1_EXTRA_CFLAGS = @SSE4_1_EXTRA_CFLAGS@ +SSE_EXTRA_CFLAGS = @SSE_EXTRA_CFLAGS@ +STRIP = @STRIP@ +SVG_CFLAGS = @SVG_CFLAGS@ +SVG_LIBS = @SVG_LIBS@ +SYMPREFIX = @SYMPREFIX@ +TIFF_LIBS = @TIFF_LIBS@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WEBKIT_CFLAGS = @WEBKIT_CFLAGS@ +WEBKIT_LIBS = @WEBKIT_LIBS@ +WEBKIT_REQUIRED_VERSION = @WEBKIT_REQUIRED_VERSION@ +WEBPDEMUX_CFLAGS = @WEBPDEMUX_CFLAGS@ +WEBPDEMUX_LIBS = @WEBPDEMUX_LIBS@ +WEBPMUX_CFLAGS = @WEBPMUX_CFLAGS@ +WEBPMUX_LIBS = @WEBPMUX_LIBS@ +WEBP_CFLAGS = @WEBP_CFLAGS@ +WEBP_LIBS = @WEBP_LIBS@ +WEBP_REQUIRED_VERSION = @WEBP_REQUIRED_VERSION@ +WEB_PAGE = @WEB_PAGE@ +WIN32_LARGE_ADDRESS_AWARE = @WIN32_LARGE_ADDRESS_AWARE@ +WINDRES = @WINDRES@ +WMF_CFLAGS = @WMF_CFLAGS@ +WMF_CONFIG = @WMF_CONFIG@ +WMF_LIBS = @WMF_LIBS@ +WMF_REQUIRED_VERSION = @WMF_REQUIRED_VERSION@ +XDG_EMAIL = @XDG_EMAIL@ +XFIXES_CFLAGS = @XFIXES_CFLAGS@ +XFIXES_LIBS = @XFIXES_LIBS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_REQUIRED_VERSION = @XGETTEXT_REQUIRED_VERSION@ +XMC_CFLAGS = @XMC_CFLAGS@ +XMC_LIBS = @XMC_LIBS@ +XMKMF = @XMKMF@ +XMLLINT = @XMLLINT@ +XMU_LIBS = @XMU_LIBS@ +XPM_LIBS = @XPM_LIBS@ +XSLTPROC = @XSLTPROC@ +XVFB_RUN = @XVFB_RUN@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +Z_LIBS = @Z_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gimpdatadir = @gimpdatadir@ +gimpdir = @gimpdir@ +gimplocaledir = @gimplocaledir@ +gimpplugindir = @gimpplugindir@ +gimpsysconfdir = @gimpsysconfdir@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +intltool__v_merge_options_ = @intltool__v_merge_options_@ +intltool__v_merge_options_0 = @intltool__v_merge_options_0@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +manpage_gimpdir = @manpage_gimpdir@ +mkdir_p = @mkdir_p@ +ms_librarian = @ms_librarian@ +mypaint_brushes_dir = @mypaint_brushes_dir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gimp-Text\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir)/app \ + -I$(top_srcdir)/app \ + $(GEGL_CFLAGS) \ + $(PANGOCAIRO_CFLAGS) \ + $(HARFBUZZ_CFLAGS) \ + $(GDK_PIXBUF_CFLAGS) \ + -I$(includedir) + +noinst_LIBRARIES = libapptext.a +libapptext_a_sources = \ + text-types.h \ + text-enums.h \ + gimpfont.c \ + gimpfont.h \ + gimpfontfactory.c \ + gimpfontfactory.h \ + gimptext.c \ + gimptext.h \ + gimptext-compat.c \ + gimptext-compat.h \ + gimptext-parasite.c \ + gimptext-parasite.h \ + gimptext-vectors.c \ + gimptext-vectors.h \ + gimptext-xlfd.c \ + gimptext-xlfd.h \ + gimptextlayer.c \ + gimptextlayer.h \ + gimptextlayer-transform.c \ + gimptextlayer-transform.h \ + gimptextlayer-xcf.c \ + gimptextlayer-xcf.h \ + gimptextlayout.c \ + gimptextlayout.h \ + gimptextlayout-render.c \ + gimptextlayout-render.h \ + gimptextundo.c \ + gimptextundo.h + +libapptext_a_built_sources = text-enums.c +libapptext_a_SOURCES = $(libapptext_a_built_sources) $(libapptext_a_sources) + +# +# rules to generate built sources +# +# setup autogeneration dependencies +gen_sources = xgen-tec +CLEANFILES = $(gen_sources) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu app/text/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu app/text/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libapptext.a: $(libapptext_a_OBJECTS) $(libapptext_a_DEPENDENCIES) $(EXTRA_libapptext_a_DEPENDENCIES) + $(AM_V_at)-rm -f libapptext.a + $(AM_V_AR)$(libapptext_a_AR) libapptext.a $(libapptext_a_OBJECTS) $(libapptext_a_LIBADD) + $(AM_V_at)$(RANLIB) libapptext.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpfont.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpfontfactory.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptext-compat.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptext-parasite.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptext-vectors.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptext-xlfd.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptext.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptextlayer-transform.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptextlayer-xcf.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptextlayer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptextlayout-render.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptextlayout.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptextundo.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/text-enums.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/gimpfont.Po + -rm -f ./$(DEPDIR)/gimpfontfactory.Po + -rm -f ./$(DEPDIR)/gimptext-compat.Po + -rm -f ./$(DEPDIR)/gimptext-parasite.Po + -rm -f ./$(DEPDIR)/gimptext-vectors.Po + -rm -f ./$(DEPDIR)/gimptext-xlfd.Po + -rm -f ./$(DEPDIR)/gimptext.Po + -rm -f ./$(DEPDIR)/gimptextlayer-transform.Po + -rm -f ./$(DEPDIR)/gimptextlayer-xcf.Po + -rm -f ./$(DEPDIR)/gimptextlayer.Po + -rm -f ./$(DEPDIR)/gimptextlayout-render.Po + -rm -f ./$(DEPDIR)/gimptextlayout.Po + -rm -f ./$(DEPDIR)/gimptextundo.Po + -rm -f ./$(DEPDIR)/text-enums.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/gimpfont.Po + -rm -f ./$(DEPDIR)/gimpfontfactory.Po + -rm -f ./$(DEPDIR)/gimptext-compat.Po + -rm -f ./$(DEPDIR)/gimptext-parasite.Po + -rm -f ./$(DEPDIR)/gimptext-vectors.Po + -rm -f ./$(DEPDIR)/gimptext-xlfd.Po + -rm -f ./$(DEPDIR)/gimptext.Po + -rm -f ./$(DEPDIR)/gimptextlayer-transform.Po + -rm -f ./$(DEPDIR)/gimptextlayer-xcf.Po + -rm -f ./$(DEPDIR)/gimptextlayer.Po + -rm -f ./$(DEPDIR)/gimptextlayout-render.Po + -rm -f ./$(DEPDIR)/gimptextlayout.Po + -rm -f ./$(DEPDIR)/gimptextundo.Po + -rm -f ./$(DEPDIR)/text-enums.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +xgen-tec: $(srcdir)/text-enums.h $(GIMP_MKENUMS) Makefile.am + $(AM_V_GEN) $(GIMP_MKENUMS) \ + --fhead "#include \"config.h\"\n#include <gio/gio.h>\n#include \"libgimpbase/gimpbase.h\"\n#include \"text-enums.h\"\n#include \"gimp-intl.h\"" \ + --fprod "\n/* enumerations from \"@basename@\" */" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n static const G@Type@Value values[] =\n {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n };\n" \ + --dhead " static const Gimp@Type@Desc descs[] =\n {" \ + --dprod " { @VALUENAME@, @valuedesc@, @valuehelp@ },@if ('@valueabbrev@' ne 'NULL')@\n /* Translators: this is an abbreviated version of @valueudesc@.\n Keep it short. */\n { @VALUENAME@, @valueabbrev@, NULL },@endif@" \ + --dtail " { 0, NULL, NULL }\n };\n\n static GType type = 0;\n\n if (G_UNLIKELY (! type))\n {\n type = g_@type@_register_static (\"@EnumName@\", values);\n gimp_type_set_translation_context (type, \"@enumnick@\");\n gimp_@type@_set_value_descriptions (type, descs);\n }\n\n return type;\n}\n" \ + $< > $@ + +# copy the generated enum file back to the source directory only if it's +# changed; otherwise, only update its timestamp, so that the recipe isn't +# executed again on the next build, however, allow this to (harmlessly) fail, +# to support building from a read-only source tree. +$(srcdir)/text-enums.c: xgen-tec + $(AM_V_GEN) if ! cmp -s $< $@; then \ + cp $< $@; \ + else \ + touch $@ 2> /dev/null \ + || true; \ + fi + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/app/text/gimpfont.c b/app/text/gimpfont.c new file mode 100644 index 0000000..23d3a60 --- /dev/null +++ b/app/text/gimpfont.c @@ -0,0 +1,820 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpfont.c + * Copyright (C) 2003 Michael Natterer <mitch@gimp.org> + * Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include <pango/pangocairo.h> + +#include <hb.h> +#include <hb-ot.h> +#include <hb-ft.h> + +#define PANGO_ENABLE_ENGINE 1 /* Argh */ +#include <pango/pango-ot.h> + +#include <ft2build.h> +#include FT_TRUETYPE_TABLES_H + +#include "text-types.h" + +#include "core/gimptempbuf.h" + +#include "gimpfont.h" + +#include "gimp-intl.h" + + +/* This is a so-called pangram; it's supposed to + contain all characters found in the alphabet. */ +#define GIMP_TEXT_PANGRAM N_("Pack my box with\nfive dozen liquor jugs.") + +#define GIMP_FONT_POPUP_SIZE (PANGO_SCALE * 30) + +#define DEBUGPRINT(x) /* g_print x */ + +enum +{ + PROP_0, + PROP_PANGO_CONTEXT +}; + + +struct _GimpFont +{ + GimpData parent_instance; + + PangoContext *pango_context; + + PangoLayout *popup_layout; + gint popup_width; + gint popup_height; +}; + +struct _GimpFontClass +{ + GimpDataClass parent_class; +}; + + +static void gimp_font_constructed (GObject *object); +static void gimp_font_finalize (GObject *object); +static void gimp_font_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_font_get_preview_size (GimpViewable *viewable, + gint size, + gboolean popup, + gboolean dot_for_dot, + gint *width, + gint *height); +static gboolean gimp_font_get_popup_size (GimpViewable *viewable, + gint width, + gint height, + gboolean dot_for_dot, + gint *popup_width, + gint *popup_height); +static GimpTempBuf * gimp_font_get_new_preview (GimpViewable *viewable, + GimpContext *context, + gint width, + gint height); + +static const gchar * gimp_font_get_sample_string (PangoContext *context, + PangoFontDescription *font_desc); + + +G_DEFINE_TYPE (GimpFont, gimp_font, GIMP_TYPE_DATA) + +#define parent_class gimp_font_parent_class + + +static void +gimp_font_class_init (GimpFontClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass); + + object_class->constructed = gimp_font_constructed; + object_class->finalize = gimp_font_finalize; + object_class->set_property = gimp_font_set_property; + + viewable_class->get_preview_size = gimp_font_get_preview_size; + viewable_class->get_popup_size = gimp_font_get_popup_size; + viewable_class->get_new_preview = gimp_font_get_new_preview; + + viewable_class->default_icon_name = "gtk-select-font"; + + g_object_class_install_property (object_class, PROP_PANGO_CONTEXT, + g_param_spec_object ("pango-context", + NULL, NULL, + PANGO_TYPE_CONTEXT, + GIMP_PARAM_WRITABLE)); +} + +static void +gimp_font_init (GimpFont *font) +{ +} + +static void +gimp_font_constructed (GObject *object) +{ + G_OBJECT_CLASS (parent_class)->constructed (object); + + gimp_data_make_internal (GIMP_DATA (object), + gimp_object_get_name (object)); +} + +static void +gimp_font_finalize (GObject *object) +{ + GimpFont *font = GIMP_FONT (object); + + g_clear_object (&font->pango_context); + g_clear_object (&font->popup_layout); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_font_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpFont *font = GIMP_FONT (object); + + switch (property_id) + { + case PROP_PANGO_CONTEXT: + if (font->pango_context) + g_object_unref (font->pango_context); + font->pango_context = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_font_get_preview_size (GimpViewable *viewable, + gint size, + gboolean popup, + gboolean dot_for_dot, + gint *width, + gint *height) +{ + *width = size; + *height = size; +} + +static gboolean +gimp_font_get_popup_size (GimpViewable *viewable, + gint width, + gint height, + gboolean dot_for_dot, + gint *popup_width, + gint *popup_height) +{ + GimpFont *font = GIMP_FONT (viewable); + PangoFontDescription *font_desc; + PangoRectangle ink; + PangoRectangle logical; + const gchar *name; + + if (! font->pango_context) + return FALSE; + + name = gimp_object_get_name (font); + + font_desc = pango_font_description_from_string (name); + g_return_val_if_fail (font_desc != NULL, FALSE); + + pango_font_description_set_size (font_desc, GIMP_FONT_POPUP_SIZE); + + if (font->popup_layout) + g_object_unref (font->popup_layout); + + font->popup_layout = pango_layout_new (font->pango_context); + pango_layout_set_font_description (font->popup_layout, font_desc); + pango_font_description_free (font_desc); + + pango_layout_set_text (font->popup_layout, gettext (GIMP_TEXT_PANGRAM), -1); + pango_layout_get_pixel_extents (font->popup_layout, &ink, &logical); + + *popup_width = MAX (ink.width, logical.width) + 6; + *popup_height = MAX (ink.height, logical.height) + 6; + + *popup_width = cairo_format_stride_for_width (CAIRO_FORMAT_A8, *popup_width); + + font->popup_width = *popup_width; + font->popup_height = *popup_height; + + return TRUE; +} + +static GimpTempBuf * +gimp_font_get_new_preview (GimpViewable *viewable, + GimpContext *context, + gint width, + gint height) +{ + GimpFont *font = GIMP_FONT (viewable); + PangoLayout *layout; + PangoRectangle ink; + PangoRectangle logical; + gint layout_width; + gint layout_height; + gint layout_x; + gint layout_y; + GimpTempBuf *temp_buf; + cairo_t *cr; + cairo_surface_t *surface; + + if (! font->pango_context) + return NULL; + + if (! font->popup_layout || + font->popup_width != width || font->popup_height != height) + { + PangoFontDescription *font_desc; + const gchar *name; + + name = gimp_object_get_name (font); + + DEBUGPRINT (("%s: ", name)); + + font_desc = pango_font_description_from_string (name); + g_return_val_if_fail (font_desc != NULL, NULL); + + pango_font_description_set_size (font_desc, + PANGO_SCALE * height * 2.0 / 3.0); + + layout = pango_layout_new (font->pango_context); + + pango_layout_set_font_description (layout, font_desc); + pango_layout_set_text (layout, + gimp_font_get_sample_string (font->pango_context, + font_desc), + -1); + + pango_font_description_free (font_desc); + } + else + { + layout = g_object_ref (font->popup_layout); + } + + width = cairo_format_stride_for_width (CAIRO_FORMAT_A8, width); + + temp_buf = gimp_temp_buf_new (width, height, babl_format ("Y' u8")); + memset (gimp_temp_buf_get_data (temp_buf), 255, width * height); + + surface = cairo_image_surface_create_for_data (gimp_temp_buf_get_data (temp_buf), + CAIRO_FORMAT_A8, + width, height, width); + + pango_layout_get_pixel_extents (layout, &ink, &logical); + + layout_width = MAX (ink.width, logical.width); + layout_height = MAX (ink.height, logical.height); + + layout_x = (width - layout_width) / 2; + layout_y = (height - layout_height) / 2; + + if (ink.x < logical.x) + layout_x += logical.x - ink.x; + + if (ink.y < logical.y) + layout_y += logical.y - ink.y; + + cr = cairo_create (surface); + + cairo_translate (cr, layout_x, layout_y); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + pango_cairo_show_layout (cr, layout); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + g_object_unref (layout); + + return temp_buf; +} + +GimpData * +gimp_font_get_standard (void) +{ + static GimpData *standard_font = NULL; + + if (! standard_font) + { + standard_font = g_object_new (GIMP_TYPE_FONT, + "name", "Standard", + NULL); + + gimp_data_clean (standard_font); + gimp_data_make_internal (standard_font, "gimp-font-standard"); + + g_object_add_weak_pointer (G_OBJECT (standard_font), + (gpointer *) &standard_font); + } + + return standard_font; +} + + +static inline gboolean +gimp_font_covers_string (PangoFcFont *font, + const gchar *sample) +{ + const gchar *p; + + for (p = sample; *p; p = g_utf8_next_char (p)) + { + if (! pango_fc_font_has_char (font, g_utf8_get_char (p))) + return FALSE; + } + + return TRUE; +} + +/* This function was picked up from Pango's pango-ot-info.c. Until there + * is a better way to get the tag, we use this. + */ +static hb_tag_t +get_hb_table_type (PangoOTTableType table_type) +{ + switch (table_type) + { + case PANGO_OT_TABLE_GSUB: + return HB_OT_TAG_GSUB; + case PANGO_OT_TABLE_GPOS: + return HB_OT_TAG_GPOS; + default: + return HB_TAG_NONE; + } +} + +/* Guess a suitable short sample string for the font. */ +static const gchar * +gimp_font_get_sample_string (PangoContext *context, + PangoFontDescription *font_desc) +{ + PangoFont *font; + hb_face_t *hb_face; + FT_Face face; + TT_OS2 *os2; + PangoOTTableType tt; + gint i; + + /* This is a table of scripts and corresponding short sample strings + * to be used instead of the Latin sample string Aa. The script + * codes are as in ISO15924 (see + * https://www.unicode.org/iso15924/iso15924-codes.html), but in + * lower case. The Unicode subrange bit numbers, as used in TrueType + * so-called OS/2 tables, are from + * https://www.microsoft.com/typography/otspec/os2.htm#ur . + * + * The table is mostly ordered by Unicode order. But as there are + * fonts that support several of these scripts, the ordering is + * be modified so that the script which such a font is more likely + * to be actually designed for comes first and matches. + * + * These sample strings are mostly just guesswork as for their + * usefulness. Usually they contain what I assume is the first + * letter in the corresponding alphabet, or two first letters if the + * first one happens to look too "trivial" to be recognizable by + * itself. + * + * This table is used to determine the primary script a font has + * been designed for. + * + * Very useful link: https://www.wazu.jp/index.html + */ + static const struct + { + const gchar script[4]; + gint bit; + const gchar *sample; + } scripts[] = { + /* Han is first because fonts that support it presumably are primarily + * designed for it. + */ + { + "hani", /* Han Ideographic */ + 59, + "\346\260\270" /* U+6C38 "forever". Ed Trager says + * this is a "pan-stroke" often used + * in teaching Chinese calligraphy. It + * contains the eight basic Chinese + * stroke forms. + */ + }, + { + "copt", /* Coptic */ + 7, + "\316\221\316\261" /* U+0410 GREEK CAPITAL LETTER ALPHA + U+0430 GREEK SMALL LETTER ALPHA + */ + }, + { + "grek", /* Greek */ + 7, + "\316\221\316\261" /* U+0410 GREEK CAPITAL LETTER ALPHA + U+0430 GREEK SMALL LETTER ALPHA + */ + }, + { + "cyrl", /* Cyrillic */ + 9, + "\320\220\325\260" /* U+0410 CYRILLIC CAPITAL LETTER A + U+0430 CYRILLIC SMALL LETTER A + */ + }, + { + "armn", /* Armenian */ + 10, + "\324\261\325\241" /* U+0531 ARMENIAN CAPITAL LETTER AYB + U+0561 ARMENIAN SMALL LETTER AYB + */ + }, + { + "hebr", /* Hebrew */ + 11, + "\327\220" /* U+05D0 HEBREW LETTER ALEF */ + }, + { + "arab", /* Arabic */ + 13, + "\330\247\330\250" /* U+0627 ARABIC LETTER ALEF + * U+0628 ARABIC LETTER BEH + */ + }, + { + "syrc", /* Syriac */ + 71, + "\334\220\334\222" /* U+0710 SYRIAC LETTER ALAPH + * U+0712 SYRIAC LETTER BETH + */ + }, + { + "thaa", /* Thaana */ + 72, + "\336\200\336\201" /* U+0780 THAANA LETTER HAA + * U+0781 THAANA LETTER SHAVIYANI + */ + }, + /* Should really use some better sample strings for the complex + * scripts. Something that shows how well the font handles the + * complex processing for each script. + */ + { + "deva", /* Devanagari */ + 15, + "\340\244\205" /* U+0905 DEVANAGARI LETTER A*/ + }, + { + "beng", /* Bengali */ + 16, + "\340\246\205" /* U+0985 BENGALI LETTER A */ + }, + { + "guru", /* Gurmukhi */ + 17, + "\340\250\205" /* U+0A05 GURMUKHI LETTER A */ + }, + { + "gujr", /* Gujarati */ + 18, + "\340\252\205" /* U+0A85 GUJARATI LETTER A */ + }, + { + "orya", /* Oriya */ + 19, + "\340\254\205" /* U+0B05 ORIYA LETTER A */ + }, + { + "taml", /* Tamil */ + 20, + "\340\256\205" /* U+0B85 TAMIL LETTER A */ + }, + { + "telu", /* Telugu */ + 21, + "\340\260\205" /* U+0C05 TELUGU LETTER A */ + }, + { + "knda", /* Kannada */ + 22, + "\340\262\205" /* U+0C85 KANNADA LETTER A */ + }, + { + "mylm", /* Malayalam */ + 23, + "\340\264\205" /* U+0D05 MALAYALAM LETTER A */ + }, + { + "sinh", /* Sinhala */ + 73, + "\340\266\205" /* U+0D85 SINHALA LETTER AYANNA */ + }, + { + "thai", /* Thai */ + 24, + "\340\270\201\340\270\264"/* U+0E01 THAI CHARACTER KO KAI + * U+0E34 THAI CHARACTER SARA I + */ + }, + { + "laoo", /* Lao */ + 25, + "\340\272\201\340\272\264"/* U+0E81 LAO LETTER KO + * U+0EB4 LAO VOWEL SIGN I + */ + }, + { + "tibt", /* Tibetan */ + 70, + "\340\274\200" /* U+0F00 TIBETAN SYLLABLE OM */ + }, + { + "mymr", /* Myanmar */ + 74, + "\341\200\200" /* U+1000 MYANMAR LETTER KA */ + }, + { + "geor", /* Georgian */ + 26, + "\341\202\240\341\203\200" /* U+10A0 GEORGIAN CAPITAL LETTER AN + * U+10D0 GEORGIAN LETTER AN + */ + }, + { + "hang", /* Hangul */ + 28, + "\341\204\200\341\204\201"/* U+1100 HANGUL CHOSEONG KIYEOK + * U+1101 HANGUL CHOSEONG SSANGKIYEOK + */ + }, + { + "ethi", /* Ethiopic */ + 75, + "\341\210\200" /* U+1200 ETHIOPIC SYLLABLE HA */ + }, + { + "cher", /* Cherokee */ + 76, + "\341\216\243" /* U+13A3 CHEROKEE LETTER O */ + }, + { + "cans", /* Unified Canadian Aboriginal Syllabics */ + 77, + "\341\220\201" /* U+1401 CANADIAN SYLLABICS E */ + }, + { + "ogam", /* Ogham */ + 78, + "\341\232\201" /* U+1681 OGHAM LETTER BEITH */ + }, + { + "runr", /* Runic */ + 79, + "\341\232\240" /* U+16A0 RUNIC LETTER FEHU FEOH FE F */ + }, + { + "tglg", /* Tagalog */ + 84, + "\341\234\200" /* U+1700 TAGALOG LETTER A */ + }, + { + "hano", /* Hanunoo */ + -1, + "\341\234\240" /* U+1720 HANUNOO LETTER A */ + }, + { + "buhd", /* Buhid */ + -1, + "\341\235\200" /* U+1740 BUHID LETTER A */ + }, + { + "tagb", /* Tagbanwa */ + -1, + "\341\235\240" /* U+1760 TAGBANWA LETTER A */ + }, + { + "khmr", /* Khmer */ + 80, + "\341\236\201\341\237\222\341\236\211\341\236\273\341\237\206" + /* U+1781 KHMER LETTER KHA + * U+17D2 KHMER LETTER SIGN COENG + * U+1789 KHMER LETTER NYO + * U+17BB KHMER VOWEL SIGN U + * U+17C6 KHMER SIGN NIKAHIT + * A common word meaning "I" that contains + * lots of complex processing. + */ + }, + { + "mong", /* Mongolian */ + 81, + "\341\240\240" /* U+1820 MONGOLIAN LETTER A */ + }, + { + "limb", /* Limbu */ + -1, + "\341\244\201" /* U+1901 LIMBU LETTER KA */ + }, + { + "tale", /* Tai Le */ + -1, + "\341\245\220" /* U+1950 TAI LE LETTER KA */ + }, + { + "latn", /* Latin */ + 0, + "Aa" + } + }; + + gint ot_alts[4]; + gint n_ot_alts = 0; + gint sr_alts[20]; + gint n_sr_alts = 0; + + font = pango_context_load_font (context, font_desc); + + g_return_val_if_fail (PANGO_IS_FC_FONT (font), "Aa"); + + face = pango_fc_font_lock_face (PANGO_FC_FONT (font)); + g_return_val_if_fail (face != NULL, "Aa"); + hb_face = hb_ft_face_create (face, NULL); + + /* First check what script(s), if any, the font has GSUB or GPOS + * OpenType layout tables for. + */ + for (tt = PANGO_OT_TABLE_GSUB; + n_ot_alts < G_N_ELEMENTS (ot_alts) && tt <= PANGO_OT_TABLE_GPOS; + tt++) + { + hb_tag_t tag; + unsigned int count; + PangoOTTag *slist; + + tag = get_hb_table_type (tt); + count = hb_ot_layout_table_get_script_tags (hb_face, tag, 0, NULL, NULL); + slist = g_new (PangoOTTag, count + 1); + hb_ot_layout_table_get_script_tags (hb_face, tag, 0, &count, slist); + slist[count] = 0; + + for (i = 0; + n_ot_alts < G_N_ELEMENTS (ot_alts) && i < G_N_ELEMENTS (scripts); + i++) + { + gint j, k; + + for (k = 0; k < n_ot_alts; k++) + if (ot_alts[k] == i) + break; + + if (k == n_ot_alts) + { + for (j = 0; + n_ot_alts < G_N_ELEMENTS (ot_alts) && slist[j]; + j++) + { +#define TAG(s) FT_MAKE_TAG (s[0], s[1], s[2], s[3]) + + if (slist[j] == TAG (scripts[i].script) && + gimp_font_covers_string (PANGO_FC_FONT (font), + scripts[i].sample)) + { + ot_alts[n_ot_alts++] = i; + DEBUGPRINT (("%.4s ", scripts[i].script)); + } +#undef TAG + } + } + } + + g_free (slist); + } + + hb_face_destroy (hb_face); + + DEBUGPRINT (("; OS/2: ")); + + /* Next check the OS/2 table for Unicode ranges the font claims + * to cover. + */ + + os2 = FT_Get_Sfnt_Table (face, ft_sfnt_os2); + + if (os2) + { + for (i = 0; + n_sr_alts < G_N_ELEMENTS (sr_alts) && i < G_N_ELEMENTS (scripts); + i++) + { + if (scripts[i].bit >= 0 && + (&os2->ulUnicodeRange1)[scripts[i].bit/32] & (1 << (scripts[i].bit % 32)) && + gimp_font_covers_string (PANGO_FC_FONT (font), + scripts[i].sample)) + { + sr_alts[n_sr_alts++] = i; + DEBUGPRINT (("%.4s ", scripts[i].script)); + } + } + } + + pango_fc_font_unlock_face (PANGO_FC_FONT (font)); + + g_object_unref (font); + + if (n_ot_alts > 2) + { + /* The font has OpenType tables for several scripts. If it + * support Basic Latin as well, use Aa. + */ + gint i; + + for (i = 0; i < n_sr_alts; i++) + if (scripts[sr_alts[i]].bit == 0) + { + DEBUGPRINT (("=> several OT, also latin, use Aa\n")); + return "Aa"; + } + } + + if (n_ot_alts > 0 && n_sr_alts >= n_ot_alts + 3) + { + /* At least one script with an OpenType table, but many more + * subranges than such scripts. If it supports Basic Latin, + * use Aa, else the highest priority subrange. + */ + gint i; + + for (i = 0; i < n_sr_alts; i++) + if (scripts[sr_alts[i]].bit == 0) + { + DEBUGPRINT (("=> several SR, also latin, use Aa\n")); + return "Aa"; + } + + DEBUGPRINT (("=> several SR, use %.4s\n", scripts[sr_alts[0]].script)); + return scripts[sr_alts[0]].sample; + } + + if (n_ot_alts > 0) + { + /* OpenType tables for at least one script, use the + * highest priority one + */ + DEBUGPRINT (("=> at least one OT, use %.4s\n", + scripts[sr_alts[0]].script)); + return scripts[ot_alts[0]].sample; + } + + if (n_sr_alts > 0) + { + /* Use the highest priority subrange. This means that a + * font that supports Greek, Cyrillic and Latin (quite + * common), will get the Greek sample string. That is + * capital and lowercase alpha, which looks like capital A + * and lowercase alpha, so it's actually quite nice, and + * doesn't give a too strong impression that the font would + * be for Greek only. + */ + DEBUGPRINT (("=> at least one SR, use %.4s\n", + scripts[sr_alts[0]].script)); + return scripts[sr_alts[0]].sample; + } + + /* Final fallback */ + DEBUGPRINT (("=> fallback, use Aa\n")); + return "Aa"; +} diff --git a/app/text/gimpfont.h b/app/text/gimpfont.h new file mode 100644 index 0000000..1b6a632 --- /dev/null +++ b/app/text/gimpfont.h @@ -0,0 +1,45 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpfont.h + * Copyright (C) 2003 Michael Natterer <mitch@gimp.org> + * Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_FONT_H__ +#define __GIMP_FONT_H__ + + +#include "core/gimpdata.h" + + +#define GIMP_TYPE_FONT (gimp_font_get_type ()) +#define GIMP_FONT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_FONT, GimpFont)) +#define GIMP_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_FONT, GimpFontClass)) +#define GIMP_IS_FONT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_FONT)) +#define GIMP_IS_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_FONT)) +#define GIMP_FONT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_FONT, GimpFontClass)) + + +typedef struct _GimpFontClass GimpFontClass; + + +GType gimp_font_get_type (void) G_GNUC_CONST; + +GimpData * gimp_font_get_standard (void); + + +#endif /* __GIMP_FONT_H__ */ diff --git a/app/text/gimpfontfactory.c b/app/text/gimpfontfactory.c new file mode 100644 index 0000000..ead75d5 --- /dev/null +++ b/app/text/gimpfontfactory.c @@ -0,0 +1,677 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpfontfactory.c + * Copyright (C) 2003-2018 Michael Natterer <mitch@gimp.org> + * + * Partly based on code Copyright (C) Sven Neumann <sven@gimp.org> + * Manish Singh <yosh@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <pango/pangocairo.h> +#include <pango/pangofc-fontmap.h> +#include <gegl.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpconfig/gimpconfig.h" + +#include "text-types.h" + +#include "core/gimp.h" +#include "core/gimp-parallel.h" +#include "core/gimpasync.h" +#include "core/gimpasyncset.h" +#include "core/gimpcancelable.h" +#include "core/gimpcontainer.h" + +#include "gimpfont.h" +#include "gimpfontfactory.h" + +#include "gimp-intl.h" + + +/* Use fontconfig directly for speed. We can use the pango stuff when/if + * fontconfig/pango get more efficient. + */ +#define USE_FONTCONFIG_DIRECTLY + +#ifdef USE_FONTCONFIG_DIRECTLY +#include <fontconfig/fontconfig.h> +#endif + +#define CONF_FNAME "fonts.conf" + + +struct _GimpFontFactoryPrivate +{ + gpointer foo; /* can't have an empty struct */ +}; + +#define GET_PRIVATE(obj) (((GimpFontFactory *) (obj))->priv) + + +static void gimp_font_factory_data_init (GimpDataFactory *factory, + GimpContext *context); +static void gimp_font_factory_data_refresh (GimpDataFactory *factory, + GimpContext *context); +static void gimp_font_factory_data_save (GimpDataFactory *factory); +static void gimp_font_factory_data_cancel (GimpDataFactory *factory); +static GimpData * gimp_font_factory_data_duplicate (GimpDataFactory *factory, + GimpData *data); +static gboolean gimp_font_factory_data_delete (GimpDataFactory *factory, + GimpData *data, + gboolean delete_from_disk, + GError **error); + +static void gimp_font_factory_load (GimpFontFactory *factory, + GError **error); +static gboolean gimp_font_factory_load_fonts_conf (FcConfig *config, + GFile *fonts_conf); +static void gimp_font_factory_add_directories (FcConfig *config, + GList *path, + GError **error); +static void gimp_font_factory_recursive_add_fontdir + (FcConfig *config, + GFile *file, + GError **error); +static void gimp_font_factory_load_names (GimpContainer *container, + PangoFontMap *fontmap, + PangoContext *context); + + +G_DEFINE_TYPE_WITH_PRIVATE (GimpFontFactory, gimp_font_factory, + GIMP_TYPE_DATA_FACTORY) + +#define parent_class gimp_font_factory_parent_class + + +static void +gimp_font_factory_class_init (GimpFontFactoryClass *klass) +{ + GimpDataFactoryClass *factory_class = GIMP_DATA_FACTORY_CLASS (klass); + + factory_class->data_init = gimp_font_factory_data_init; + factory_class->data_refresh = gimp_font_factory_data_refresh; + factory_class->data_save = gimp_font_factory_data_save; + factory_class->data_cancel = gimp_font_factory_data_cancel; + factory_class->data_duplicate = gimp_font_factory_data_duplicate; + factory_class->data_delete = gimp_font_factory_data_delete; +} + +static void +gimp_font_factory_init (GimpFontFactory *factory) +{ + factory->priv = gimp_font_factory_get_instance_private (factory); +} + +static void +gimp_font_factory_data_init (GimpDataFactory *factory, + GimpContext *context) +{ + GError *error = NULL; + + gimp_font_factory_load (GIMP_FONT_FACTORY (factory), &error); + + if (error) + { + gimp_message_literal (gimp_data_factory_get_gimp (factory), NULL, + GIMP_MESSAGE_INFO, + error->message); + g_error_free (error); + } +} + +static void +gimp_font_factory_data_refresh (GimpDataFactory *factory, + GimpContext *context) +{ + GError *error = NULL; + + gimp_font_factory_load (GIMP_FONT_FACTORY (factory), &error); + + if (error) + { + gimp_message_literal (gimp_data_factory_get_gimp (factory), NULL, + GIMP_MESSAGE_INFO, + error->message); + g_error_free (error); + } +} + +static void +gimp_font_factory_data_save (GimpDataFactory *factory) +{ + /* this is not "saving" but this functions is called at the right + * time at exit to reset the config + */ + + /* if font loading is in progress in another thread, do nothing. calling + * FcInitReinitialize() while loading takes place is unsafe. + */ + if (! gimp_async_set_is_empty (gimp_data_factory_get_async_set (factory))) + return; + + /* Reinit the library with defaults. */ + FcInitReinitialize (); +} + +static void +gimp_font_factory_data_cancel (GimpDataFactory *factory) +{ + GimpAsyncSet *async_set = gimp_data_factory_get_async_set (factory); + + /* we can't really cancel font loading, so we just clear the async set and + * return without waiting for loading to finish. we also cancel the async + * set beforehand, as a way to signal to + * gimp_font_factory_load_async_callback() that loading was canceled and the + * factory might be dead, and that it should just do nothing. + */ + gimp_cancelable_cancel (GIMP_CANCELABLE (async_set)); + gimp_async_set_clear (async_set); +} + +static GimpData * +gimp_font_factory_data_duplicate (GimpDataFactory *factory, + GimpData *data) +{ + return NULL; +} + +static gboolean +gimp_font_factory_data_delete (GimpDataFactory *factory, + GimpData *data, + gboolean delete_from_disk, + GError **error) +{ + return TRUE; +} + + +/* public functions */ + +GimpDataFactory * +gimp_font_factory_new (Gimp *gimp, + const gchar *path_property_name) +{ + g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); + g_return_val_if_fail (path_property_name != NULL, NULL); + + return g_object_new (GIMP_TYPE_FONT_FACTORY, + "gimp", gimp, + "data-type", GIMP_TYPE_FONT, + "path-property-name", path_property_name, + "get-standard-func", gimp_font_get_standard, + NULL); +} + + +/* private functions */ + +static void +gimp_font_factory_load_async (GimpAsync *async, + FcConfig *config) +{ + if (FcConfigBuildFonts (config)) + { + gimp_async_finish (async, config); + } + else + { + FcConfigDestroy (config); + + gimp_async_abort (async); + } +} + +static void +gimp_font_factory_load_async_callback (GimpAsync *async, + GimpFontFactory *factory) +{ + GimpContainer *container; + + /* the operation was canceled and the factory might be dead (see + * gimp_font_factory_data_cancel()). bail. + */ + if (gimp_async_is_canceled (async)) + return; + + container = gimp_data_factory_get_container (GIMP_DATA_FACTORY (factory)); + + if (gimp_async_is_finished (async)) + { + FcConfig *config = gimp_async_get_result (async); + PangoFontMap *fontmap; + PangoContext *context; + + FcConfigSetCurrent (config); + + fontmap = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT); + if (! fontmap) + g_error ("You are using a Pango that has been built against a cairo " + "that lacks the Freetype font backend"); + + pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (fontmap), + 72.0 /* FIXME */); + context = pango_font_map_create_context (fontmap); + g_object_unref (fontmap); + + gimp_font_factory_load_names (container, PANGO_FONT_MAP (fontmap), context); + g_object_unref (context); + FcConfigDestroy (config); + } + + gimp_container_thaw (container); +} + +static void +gimp_font_factory_load (GimpFontFactory *factory, + GError **error) +{ + GimpContainer *container; + Gimp *gimp; + GimpAsyncSet *async_set; + FcConfig *config; + GFile *fonts_conf; + GList *path; + GimpAsync *async; + + async_set = gimp_data_factory_get_async_set (GIMP_DATA_FACTORY (factory)); + + if (! gimp_async_set_is_empty (async_set)) + { + /* font loading is already in progress */ + return; + } + + container = gimp_data_factory_get_container (GIMP_DATA_FACTORY (factory)); + + gimp = gimp_data_factory_get_gimp (GIMP_DATA_FACTORY (factory)); + + if (gimp->be_verbose) + g_print ("Loading fonts\n"); + + config = FcInitLoadConfig (); + + if (! config) + return; + + fonts_conf = gimp_directory_file (CONF_FNAME, NULL); + if (! gimp_font_factory_load_fonts_conf (config, fonts_conf)) + g_printerr ("%s: failed to read '%s'.\n", + G_STRFUNC, g_file_peek_path (fonts_conf)); + g_object_unref (fonts_conf); + + fonts_conf = gimp_sysconf_directory_file (CONF_FNAME, NULL); + if (! gimp_font_factory_load_fonts_conf (config, fonts_conf)) + g_printerr ("%s: failed to read '%s'.\n", + G_STRFUNC, g_file_peek_path (fonts_conf)); + g_object_unref (fonts_conf); + + path = gimp_data_factory_get_data_path (GIMP_DATA_FACTORY (factory)); + if (! path) + return; + + gimp_container_freeze (container); + gimp_container_clear (container); + + gimp_font_factory_add_directories (config, path, error); + g_list_free_full (path, (GDestroyNotify) g_object_unref); + + /* We perform font cache initialization in a separate thread, so + * in the case a cache rebuild is to be done it will not block + * the UI. + */ + async = gimp_parallel_run_async_independent_full ( + +10, + (GimpRunAsyncFunc) gimp_font_factory_load_async, + config); + + gimp_async_add_callback_for_object ( + async, + (GimpAsyncCallback) gimp_font_factory_load_async_callback, + factory, + factory); + + gimp_async_set_add (async_set, async); + + g_object_unref (async); +} + +static gboolean +gimp_font_factory_load_fonts_conf (FcConfig *config, + GFile *fonts_conf) +{ + gchar *path = g_file_get_path (fonts_conf); + gboolean ret = TRUE; + + if (! FcConfigParseAndLoad (config, (const guchar *) path, FcFalse)) + ret = FALSE; + + g_free (path); + + return ret; +} + +static void +gimp_font_factory_add_directories (FcConfig *config, + GList *path, + GError **error) +{ + GList *list; + + for (list = path; list; list = list->next) + { + /* The configured directories must exist or be created. */ + g_file_make_directory_with_parents (list->data, NULL, NULL); + + /* Do not use FcConfigAppFontAddDir(). Instead use + * FcConfigAppFontAddFile() with our own recursive loop. + * Otherwise, when some fonts fail to load (e.g. permission + * issues), we end up in weird situations where the fonts are in + * the list, but are unusable and output many errors. + * See bug 748553. + */ + gimp_font_factory_recursive_add_fontdir (config, list->data, error); + } + + if (error && *error) + { + gchar *font_list = g_strdup ((*error)->message); + + g_clear_error (error); + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Some fonts failed to load:\n%s"), font_list); + g_free (font_list); + } +} + +static void +gimp_font_factory_recursive_add_fontdir (FcConfig *config, + GFile *file, + GError **error) +{ + GFileEnumerator *enumerator; + + g_return_if_fail (config != NULL); + + enumerator = g_file_enumerate_children (file, + G_FILE_ATTRIBUTE_STANDARD_NAME "," + G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," + G_FILE_ATTRIBUTE_STANDARD_TYPE "," + G_FILE_ATTRIBUTE_TIME_MODIFIED, + G_FILE_QUERY_INFO_NONE, + NULL, NULL); + if (enumerator) + { + GFileInfo *info; + + while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL))) + { + GFileType file_type; + GFile *child; + + if (g_file_info_get_is_hidden (info)) + { + g_object_unref (info); + continue; + } + + file_type = g_file_info_get_file_type (info); + child = g_file_enumerator_get_child (enumerator, info); + + if (file_type == G_FILE_TYPE_DIRECTORY) + { + gimp_font_factory_recursive_add_fontdir (config, child, error); + } + else if (file_type == G_FILE_TYPE_REGULAR) + { + gchar *path = g_file_get_path (child); +#ifdef G_OS_WIN32 + gchar *tmp = g_win32_locale_filename_from_utf8 (path); + + g_free (path); + /* XXX: g_win32_locale_filename_from_utf8() may return + * NULL. So we need to check that path is not NULL before + * trying to load with fontconfig. + */ + path = tmp; +#endif + + if (! path || + FcFalse == FcConfigAppFontAddFile (config, (const FcChar8 *) path)) + { + g_printerr ("%s: adding font file '%s' failed.\n", + G_STRFUNC, path); + if (error) + { + if (*error) + { + gchar *current_message = g_strdup ((*error)->message); + + g_clear_error (error); + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + "%s\n- %s", current_message, path); + g_free (current_message); + } + else + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + "- %s", path); + } + } + } + + g_free (path); + } + + g_object_unref (child); + g_object_unref (info); + } + + g_object_unref (enumerator); + } + else + { + if (error) + { + gchar *path = g_file_get_path (file); + + if (*error) + { + gchar *current_message = g_strdup ((*error)->message); + + g_clear_error (error); + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + "%s\n- %s%s", current_message, path, + G_DIR_SEPARATOR_S); + g_free (current_message); + } + else + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + "- %s%s", path, G_DIR_SEPARATOR_S); + } + + g_free (path); + } + } +} + +static void +gimp_font_factory_add_font (GimpContainer *container, + PangoContext *context, + PangoFontDescription *desc) +{ + gchar *name; + + if (! desc) + return; + + name = pango_font_description_to_string (desc); + + /* It doesn't look like pango_font_description_to_string() could ever + * return NULL. But just to be double sure and avoid a segfault, I + * check before validating the string. + */ + if (name && strlen (name) > 0 && + g_utf8_validate (name, -1, NULL)) + { + GimpFont *font; + + font = g_object_new (GIMP_TYPE_FONT, + "name", name, + "pango-context", context, + NULL); + + gimp_container_add (container, GIMP_OBJECT (font)); + g_object_unref (font); + } + + g_free (name); +} + +#ifdef USE_FONTCONFIG_DIRECTLY +/* We're really chummy here with the implementation. Oh well. */ + +/* This is copied straight from make_alias_description in pango, plus + * the gimp_font_list_add_font bits. + */ +static void +gimp_font_factory_make_alias (GimpContainer *container, + PangoContext *context, + const gchar *family, + gboolean bold, + gboolean italic) +{ + PangoFontDescription *desc = pango_font_description_new (); + + pango_font_description_set_family (desc, family); + pango_font_description_set_style (desc, + italic ? + PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); + pango_font_description_set_variant (desc, PANGO_VARIANT_NORMAL); + pango_font_description_set_weight (desc, + bold ? + PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL); + pango_font_description_set_stretch (desc, PANGO_STRETCH_NORMAL); + + gimp_font_factory_add_font (container, context, desc); + + pango_font_description_free (desc); +} + +static void +gimp_font_factory_load_aliases (GimpContainer *container, + PangoContext *context) +{ + const gchar *families[] = { "Sans-serif", "Serif", "Monospace" }; + gint i; + + for (i = 0; i < 3; i++) + { + gimp_font_factory_make_alias (container, context, families[i], + FALSE, FALSE); + gimp_font_factory_make_alias (container, context, families[i], + TRUE, FALSE); + gimp_font_factory_make_alias (container, context, families[i], + FALSE, TRUE); + gimp_font_factory_make_alias (container, context, families[i], + TRUE, TRUE); + } +} + +static void +gimp_font_factory_load_names (GimpContainer *container, + PangoFontMap *fontmap, + PangoContext *context) +{ + FcObjectSet *os; + FcPattern *pat; + FcFontSet *fontset; + gint i; + + os = FcObjectSetBuild (FC_FAMILY, FC_STYLE, + FC_SLANT, FC_WEIGHT, FC_WIDTH, + NULL); + g_return_if_fail (os); + + pat = FcPatternCreate (); + if (! pat) + { + FcObjectSetDestroy (os); + g_critical ("%s: FcPatternCreate() returned NULL.", G_STRFUNC); + return; + } + + fontset = FcFontList (NULL, pat, os); + + FcPatternDestroy (pat); + FcObjectSetDestroy (os); + + g_return_if_fail (fontset); + + for (i = 0; i < fontset->nfont; i++) + { + PangoFontDescription *desc; + + desc = pango_fc_font_description_from_pattern (fontset->fonts[i], FALSE); + gimp_font_factory_add_font (container, context, desc); + pango_font_description_free (desc); + } + + /* only create aliases if there is at least one font available */ + if (fontset->nfont > 0) + gimp_font_factory_load_aliases (container, context); + + FcFontSetDestroy (fontset); +} + +#else /* ! USE_FONTCONFIG_DIRECTLY */ + +static void +gimp_font_factory_load_names (GimpContainer *container, + PangoFontMap *fontmap, + PangoContext *context) +{ + PangoFontFamily **families; + PangoFontFace **faces; + gint n_families; + gint n_faces; + gint i, j; + + pango_font_map_list_families (fontmap, &families, &n_families); + + for (i = 0; i < n_families; i++) + { + pango_font_family_list_faces (families[i], &faces, &n_faces); + + for (j = 0; j < n_faces; j++) + { + PangoFontDescription *desc; + + desc = pango_font_face_describe (faces[j]); + gimp_font_factory_add_font (container, context, desc); + pango_font_description_free (desc); + } + } + + g_free (families); +} + +#endif /* USE_FONTCONFIG_DIRECTLY */ diff --git a/app/text/gimpfontfactory.h b/app/text/gimpfontfactory.h new file mode 100644 index 0000000..4c52041 --- /dev/null +++ b/app/text/gimpfontfactory.h @@ -0,0 +1,58 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpfontfactory.h + * Copyright (C) 2018 Michael Natterer <mitch@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_FONT_FACTORY_H__ +#define __GIMP_FONT_FACTORY_H__ + + +#include "core/gimpdatafactory.h" + + +#define GIMP_TYPE_FONT_FACTORY (gimp_font_factory_get_type ()) +#define GIMP_FONT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_FONT_FACTORY, GimpFontFactory)) +#define GIMP_FONT_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_FONT_FACTORY, GimpFontFactoryClass)) +#define GIMP_IS_FONT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_FONT_FACTORY)) +#define GIMP_IS_FONT_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_FONT_FACTORY)) +#define GIMP_FONT_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_FONT_FACTORY, GimpFontFactoryClass)) + + +typedef struct _GimpFontFactoryPrivate GimpFontFactoryPrivate; +typedef struct _GimpFontFactoryClass GimpFontFactoryClass; + +struct _GimpFontFactory +{ + GimpDataFactory parent_instance; + + GimpFontFactoryPrivate *priv; +}; + +struct _GimpFontFactoryClass +{ + GimpDataFactoryClass parent_class; +}; + + +GType gimp_font_factory_get_type (void) G_GNUC_CONST; + +GimpDataFactory * gimp_font_factory_new (Gimp *gimp, + const gchar *path_property_name); + + +#endif /* __GIMP_FONT_FACTORY_H__ */ diff --git a/app/text/gimptext-compat.c b/app/text/gimptext-compat.c new file mode 100644 index 0000000..cb71f3e --- /dev/null +++ b/app/text/gimptext-compat.c @@ -0,0 +1,207 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <pango/pangocairo.h> + +#include "libgimpcolor/gimpcolor.h" + +#include "text-types.h" + +#include "core/gimp.h" +#include "core/gimpchannel.h" +#include "core/gimpcontext.h" +#include "core/gimpdatafactory.h" +#include "core/gimpimage.h" +#include "core/gimpdrawable.h" +#include "core/gimpimage.h" +#include "core/gimpimage-undo.h" +#include "core/gimplayer-floating-selection.h" + +#include "gimptext.h" +#include "gimptext-compat.h" +#include "gimptextlayer.h" + +#include "gimp-intl.h" + + +GimpLayer * +text_render (GimpImage *image, + GimpDrawable *drawable, + GimpContext *context, + gint text_x, + gint text_y, + const gchar *fontname, + const gchar *text, + gint border, + gboolean antialias) +{ + PangoFontDescription *desc; + GimpText *gtext; + GimpLayer *layer; + GimpRGB color; + gchar *font; + gdouble size; + + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); + g_return_val_if_fail (drawable == NULL || GIMP_IS_DRAWABLE (drawable), NULL); + g_return_val_if_fail (drawable == NULL || + gimp_item_is_attached (GIMP_ITEM (drawable)), NULL); + g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); + g_return_val_if_fail (fontname != NULL, NULL); + g_return_val_if_fail (text != NULL, NULL); + + if (! gimp_data_factory_data_wait (image->gimp->font_factory)) + return NULL; + + if (border < 0) + border = 0; + + desc = pango_font_description_from_string (fontname); + size = PANGO_PIXELS (pango_font_description_get_size (desc)); + + pango_font_description_unset_fields (desc, PANGO_FONT_MASK_SIZE); + font = pango_font_description_to_string (desc); + + pango_font_description_free (desc); + + gimp_context_get_foreground (context, &color); + + gtext = g_object_new (GIMP_TYPE_TEXT, + "text", text, + "font", font, + "font-size", size, + "antialias", antialias, + "border", border, + "color", &color, + NULL); + + g_free (font); + + layer = gimp_text_layer_new (image, gtext); + + g_object_unref (gtext); + + if (!layer) + return NULL; + + /* Start a group undo */ + gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT, + _("Add Text Layer")); + + /* Set the layer offsets */ + gimp_item_set_offset (GIMP_ITEM (layer), text_x, text_y); + + /* If there is a selection mask clear it-- + * this might not always be desired, but in general, + * it seems like the correct behavior. + */ + if (! gimp_channel_is_empty (gimp_image_get_mask (image))) + gimp_channel_clear (gimp_image_get_mask (image), NULL, TRUE); + + if (drawable == NULL) + { + /* If the drawable is NULL, create a new layer */ + gimp_image_add_layer (image, layer, NULL, -1, TRUE); + } + else + { + /* Otherwise, instantiate the text as the new floating selection */ + floating_sel_attach (layer, drawable); + } + + /* end the group undo */ + gimp_image_undo_group_end (image); + + return layer; +} + +gboolean +text_get_extents (Gimp *gimp, + const gchar *fontname, + const gchar *text, + gint *width, + gint *height, + gint *ascent, + gint *descent) +{ + PangoFontDescription *font_desc; + PangoContext *context; + PangoLayout *layout; + PangoFontMap *fontmap; + PangoRectangle rect; + + g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE); + g_return_val_if_fail (fontname != NULL, FALSE); + g_return_val_if_fail (text != NULL, FALSE); + + if (! gimp_data_factory_data_wait (gimp->font_factory)) + return FALSE; + + fontmap = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT); + if (! fontmap) + g_error ("You are using a Pango that has been built against a cairo " + "that lacks the Freetype font backend"); + + pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (fontmap), + 72.0); /* FIXME: resolution */ + context = pango_font_map_create_context (fontmap); + g_object_unref (fontmap); + + layout = pango_layout_new (context); + g_object_unref (context); + + font_desc = pango_font_description_from_string (fontname); + pango_layout_set_font_description (layout, font_desc); + pango_font_description_free (font_desc); + + pango_layout_set_text (layout, text, -1); + + pango_layout_get_pixel_extents (layout, NULL, &rect); + + if (width) + *width = rect.width; + if (height) + *height = rect.height; + + if (ascent || descent) + { + PangoLayoutIter *iter; + PangoLayoutLine *line; + + iter = pango_layout_get_iter (layout); + line = pango_layout_iter_get_line_readonly (iter); + pango_layout_iter_free (iter); + + pango_layout_line_get_pixel_extents (line, NULL, &rect); + + if (ascent) + *ascent = PANGO_ASCENT (rect); + if (descent) + *descent = - PANGO_DESCENT (rect); + } + + g_object_unref (layout); + + return TRUE; +} diff --git a/app/text/gimptext-compat.h b/app/text/gimptext-compat.h new file mode 100644 index 0000000..2e178f0 --- /dev/null +++ b/app/text/gimptext-compat.h @@ -0,0 +1,45 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_TEXT_COMPAT_H__ +#define __GIMP_TEXT_COMPAT_H__ + + +/* convenience functions that provide the 1.2 API, only used by the PDB */ + +GimpLayer * text_render (GimpImage *image, + GimpDrawable *drawable, + GimpContext *context, + gint text_x, + gint text_y, + const gchar *fontname, + const gchar *text, + gint border, + gboolean antialias); +gboolean text_get_extents (Gimp *gimp, + const gchar *fontname, + const gchar *text, + gint *width, + gint *height, + gint *ascent, + gint *descent); + + +#endif /* __GIMP_TEXT_COMPAT_H__ */ diff --git a/app/text/gimptext-parasite.c b/app/text/gimptext-parasite.c new file mode 100644 index 0000000..790a5b1 --- /dev/null +++ b/app/text/gimptext-parasite.c @@ -0,0 +1,204 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> +#include <stdlib.h> + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpcolor/gimpcolor.h" +#include "libgimpconfig/gimpconfig.h" + +#include "text-types.h" + +#include "core/gimperror.h" + +#include "gimptext.h" +#include "gimptext-parasite.h" +#include "gimptext-xlfd.h" + +#include "gimp-intl.h" + + +/****************************************/ +/* The native GimpTextLayer parasite. */ +/****************************************/ + +const gchar * +gimp_text_parasite_name (void) +{ + return "gimp-text-layer"; +} + +GimpParasite * +gimp_text_to_parasite (const GimpText *text) +{ + GimpParasite *parasite; + gchar *str; + + g_return_val_if_fail (GIMP_IS_TEXT (text), NULL); + + str = gimp_config_serialize_to_string (GIMP_CONFIG (text), NULL); + g_return_val_if_fail (str != NULL, NULL); + + parasite = gimp_parasite_new (gimp_text_parasite_name (), + GIMP_PARASITE_PERSISTENT, + strlen (str) + 1, str); + g_free (str); + + return parasite; +} + +GimpText * +gimp_text_from_parasite (const GimpParasite *parasite, + GError **error) +{ + GimpText *text; + const gchar *str; + + g_return_val_if_fail (parasite != NULL, NULL); + g_return_val_if_fail (strcmp (gimp_parasite_name (parasite), + gimp_text_parasite_name ()) == 0, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + str = gimp_parasite_data (parasite); + + text = g_object_new (GIMP_TYPE_TEXT, NULL); + + if (str != NULL) + { + gimp_config_deserialize_string (GIMP_CONFIG (text), + str, + gimp_parasite_data_size (parasite), + NULL, + error); + } + else + { + g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, + _("Empty text parasite")); + } + + return text; +} + + +/****************************************************************/ +/* Compatibility to plug-in GDynText 1.4.4 and later versions */ +/* GDynText was written by Marco Lamberto <lm@geocities.com> */ +/****************************************************************/ + +const gchar * +gimp_text_gdyntext_parasite_name (void) +{ + return "plug_in_gdyntext/data"; +} + +enum +{ + TEXT = 0, + ANTIALIAS = 1, + ALIGNMENT = 2, + ROTATION = 3, + LINE_SPACING = 4, + COLOR = 5, + LAYER_ALIGNMENT = 6, + XLFD = 7, + NUM_PARAMS +}; + +GimpText * +gimp_text_from_gdyntext_parasite (const GimpParasite *parasite) +{ + GimpText *retval = NULL; + GimpTextJustification justify; + const gchar *str; + gchar *text = NULL; + gchar **params; + gboolean antialias; + gdouble spacing; + GimpRGB rgb; + glong color; + gint i; + + g_return_val_if_fail (parasite != NULL, NULL); + g_return_val_if_fail (strcmp (gimp_parasite_name (parasite), + gimp_text_gdyntext_parasite_name ()) == 0, + NULL); + + str = gimp_parasite_data (parasite); + g_return_val_if_fail (str != NULL, NULL); + + if (! g_str_has_prefix (str, "GDT10{")) /* magic value */ + return NULL; + + params = g_strsplit (str + strlen ("GDT10{"), "}{", -1); + + /* first check that we have the required number of parameters */ + for (i = 0; i < NUM_PARAMS; i++) + if (!params[i]) + goto cleanup; + + text = g_strcompress (params[TEXT]); + + if (! g_utf8_validate (text, -1, NULL)) + { + gchar *tmp = gimp_any_to_utf8 (text, -1, NULL); + + g_free (text); + text = tmp; + } + + antialias = atoi (params[ANTIALIAS]) ? TRUE : FALSE; + + switch (atoi (params[ALIGNMENT])) + { + default: + case 0: justify = GIMP_TEXT_JUSTIFY_LEFT; break; + case 1: justify = GIMP_TEXT_JUSTIFY_CENTER; break; + case 2: justify = GIMP_TEXT_JUSTIFY_RIGHT; break; + } + + spacing = g_strtod (params[LINE_SPACING], NULL); + + color = strtol (params[COLOR], NULL, 16); + gimp_rgba_set_uchar (&rgb, color >> 16, color >> 8, color, 255); + + retval = g_object_new (GIMP_TYPE_TEXT, + "text", text, + "antialias", antialias, + "justify", justify, + "line-spacing", spacing, + "color", &rgb, + NULL); + + gimp_text_set_font_from_xlfd (GIMP_TEXT (retval), params[XLFD]); + + cleanup: + g_free (text); + g_strfreev (params); + + return retval; +} diff --git a/app/text/gimptext-parasite.h b/app/text/gimptext-parasite.h new file mode 100644 index 0000000..d834309 --- /dev/null +++ b/app/text/gimptext-parasite.h @@ -0,0 +1,34 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_TEXT_PARASITE_H__ +#define __GIMP_TEXT_PARASITE_H__ + + +const gchar * gimp_text_parasite_name (void) G_GNUC_CONST; +GimpParasite * gimp_text_to_parasite (const GimpText *text); +GimpText * gimp_text_from_parasite (const GimpParasite *parasite, + GError **error); + +const gchar * gimp_text_gdyntext_parasite_name (void) G_GNUC_CONST; +GimpText * gimp_text_from_gdyntext_parasite (const GimpParasite *parasite); + + +#endif /* __GIMP_TEXT_PARASITE_H__ */ diff --git a/app/text/gimptext-vectors.c b/app/text/gimptext-vectors.c new file mode 100644 index 0000000..3a6901e --- /dev/null +++ b/app/text/gimptext-vectors.c @@ -0,0 +1,255 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText-vectors + * Copyright (C) 2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <pango/pangocairo.h> +#include <gegl.h> + +#include "text-types.h" + +#include "core/gimp.h" +#include "core/gimpimage.h" + +#include "vectors/gimpbezierstroke.h" +#include "vectors/gimpvectors.h" +#include "vectors/gimpanchor.h" + +#include "gimptext.h" +#include "gimptext-vectors.h" +#include "gimptextlayout.h" +#include "gimptextlayout-render.h" + + +typedef struct +{ + GimpVectors *vectors; + GimpStroke *stroke; + GimpAnchor *anchor; +} RenderContext; + + +static void gimp_text_render_vectors (cairo_t *cr, + RenderContext *context); + + +GimpVectors * +gimp_text_vectors_new (GimpImage *image, + GimpText *text) +{ + GimpVectors *vectors; + RenderContext context = { NULL, }; + + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); + g_return_val_if_fail (GIMP_IS_TEXT (text), NULL); + + vectors = gimp_vectors_new (image, NULL); + + if (text->text || text->markup) + { + GimpTextLayout *layout; + cairo_surface_t *surface; + cairo_t *cr; + gdouble xres; + gdouble yres; + GError *error = NULL; + + if (text->text) + gimp_object_set_name_safe (GIMP_OBJECT (vectors), text->text); + + context.vectors = vectors; + + surface = cairo_recording_surface_create (CAIRO_CONTENT_ALPHA, NULL); + cr = cairo_create (surface); + + gimp_image_get_resolution (image, &xres, &yres); + + layout = gimp_text_layout_new (text, xres, yres, &error); + if (error) + { + gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR, error->message); + g_error_free (error); + } + gimp_text_layout_render (layout, cr, text->base_dir, TRUE); + g_object_unref (layout); + + gimp_text_render_vectors (cr, &context); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + if (context.stroke) + gimp_stroke_close (context.stroke); + } + + return vectors; +} + + +static inline void +gimp_text_vector_coords (const double x, + const double y, + GimpCoords *coords) +{ + const GimpCoords default_values = GIMP_COORDS_DEFAULT_VALUES; + + *coords = default_values; + + coords->x = x; + coords->y = y; +} + +static gint +moveto (RenderContext *context, + const double x, + const double y) +{ + GimpCoords start; + +#if GIMP_TEXT_DEBUG + g_printerr ("moveto %f, %f\n", x, y); +#endif + + gimp_text_vector_coords (x, y, &start); + + if (context->stroke) + gimp_stroke_close (context->stroke); + + context->stroke = gimp_bezier_stroke_new_moveto (&start); + + gimp_vectors_stroke_add (context->vectors, context->stroke); + g_object_unref (context->stroke); + + return 0; +} + +static gint +lineto (RenderContext *context, + const double x, + const double y) +{ + GimpCoords end; + +#if GIMP_TEXT_DEBUG + g_printerr ("lineto %f, %f\n", x, y); +#endif + + if (! context->stroke) + return 0; + + gimp_text_vector_coords (x, y, &end); + + gimp_bezier_stroke_lineto (context->stroke, &end); + + return 0; +} + +static gint +cubicto (RenderContext *context, + const double x1, + const double y1, + const double x2, + const double y2, + const double x3, + const double y3) +{ + GimpCoords control1; + GimpCoords control2; + GimpCoords end; + +#if GIMP_TEXT_DEBUG + g_printerr ("cubicto %f, %f\n", x3, y3); +#endif + + if (! context->stroke) + return 0; + + gimp_text_vector_coords (x1, y1, &control1); + gimp_text_vector_coords (x2, y2, &control2); + gimp_text_vector_coords (x3, y3, &end); + + gimp_bezier_stroke_cubicto (context->stroke, &control1, &control2, &end); + + return 0; +} + +static gint +closepath (RenderContext *context) +{ +#if GIMP_TEXT_DEBUG + g_printerr ("moveto\n"); +#endif + + if (! context->stroke) + return 0; + + gimp_stroke_close (context->stroke); + + context->stroke = NULL; + + return 0; +} + +static void +gimp_text_render_vectors (cairo_t *cr, + RenderContext *context) +{ + cairo_path_t *path; + gint i; + + path = cairo_copy_path (cr); + + for (i = 0; i < path->num_data; i += path->data[i].header.length) + { + cairo_path_data_t *data = &path->data[i]; + + /* if the drawing operation is the final moveto of the glyph, + * break to avoid creating an empty point. This is because cairo + * always adds a moveto after each closepath. + */ + if (i + data->header.length >= path->num_data) + break; + + switch (data->header.type) + { + case CAIRO_PATH_MOVE_TO: + moveto (context, data[1].point.x, data[1].point.y); + break; + + case CAIRO_PATH_LINE_TO: + lineto (context, data[1].point.x, data[1].point.y); + break; + + case CAIRO_PATH_CURVE_TO: + cubicto (context, + data[1].point.x, data[1].point.y, + data[2].point.x, data[2].point.y, + data[3].point.x, data[3].point.y); + break; + + case CAIRO_PATH_CLOSE_PATH: + closepath (context); + break; + } + } + + cairo_path_destroy (path); +} diff --git a/app/text/gimptext-vectors.h b/app/text/gimptext-vectors.h new file mode 100644 index 0000000..df01aae --- /dev/null +++ b/app/text/gimptext-vectors.h @@ -0,0 +1,29 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText-vectors + * Copyright (C) 2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_TEXT_VECTORS_H__ +#define __GIMP_TEXT_VECTORS_H__ + + +GimpVectors * gimp_text_vectors_new (GimpImage *image, + GimpText *text); + + +#endif /* __GIMP_TEXT_VECTORS_H__ */ diff --git a/app/text/gimptext-xlfd.c b/app/text/gimptext-xlfd.c new file mode 100644 index 0000000..16245b5 --- /dev/null +++ b/app/text/gimptext-xlfd.c @@ -0,0 +1,301 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2002-2004 Sven Neumann <sven@gimp.org> + * + * Some of this code was copied from Pango (pangox-fontmap.c) + * and was originally written by Owen Taylor <otaylor@redhat.com>. + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> + +#include <gio/gio.h> + +#include "libgimpbase/gimpbase.h" + +#include "text-types.h" + +#include "gimptext.h" +#include "gimptext-xlfd.h" + + +#define XLFD_MAX_FIELD_LEN 64 + +/* These are the field numbers in the X Logical Font Description fontnames, + e.g. -adobe-courier-bold-o-normal--25-180-100-100-m-150-iso8859-1 */ +enum +{ + XLFD_FOUNDRY = 0, + XLFD_FAMILY = 1, + XLFD_WEIGHT = 2, + XLFD_SLANT = 3, + XLFD_SET_WIDTH = 4, + XLFD_ADD_STYLE = 5, + XLFD_PIXELS = 6, + XLFD_POINTS = 7, + XLFD_RESOLUTION_X = 8, + XLFD_RESOLUTION_Y = 9, + XLFD_SPACING = 10, + XLFD_AVERAGE_WIDTH = 11, + XLFD_CHARSET = 12, + XLFD_NUM_FIELDS +}; + +static gchar * gimp_text_get_xlfd_field (const gchar *fontname, + gint field_num, + gchar *buffer); +static gchar * launder_font_name (gchar *name); + + +/** + * gimp_text_font_name_from_xlfd: + * @xlfd: X Logical Font Description + * + * Attempts to extract a meaningful font name from the "family", + * "weight", "slant" and "stretch" fields of an X Logical Font + * Description. + * + * Return value: a newly allocated string. + **/ +gchar * +gimp_text_font_name_from_xlfd (const gchar *xlfd) +{ + gchar *fields[4]; + gchar buffers[4][XLFD_MAX_FIELD_LEN]; + gint i = 0; + + /* family */ + fields[i] = gimp_text_get_xlfd_field (xlfd, XLFD_FAMILY, buffers[i]); + if (fields[i]) + i++; + + /* weight */ + fields[i] = gimp_text_get_xlfd_field (xlfd, XLFD_WEIGHT, buffers[i]); + if (fields[i] && strcmp (fields[i], "medium")) + i++; + + /* slant */ + fields[i] = gimp_text_get_xlfd_field (xlfd, XLFD_SLANT, buffers[i]); + if (fields[i]) + { + switch (*fields[i]) + { + case 'i': + strcpy (buffers[i], "italic"); + i++; + break; + case 'o': + strcpy (buffers[i], "oblique"); + i++; + break; + case 'r': + break; + } + } + + /* stretch */ + fields[i] = gimp_text_get_xlfd_field (xlfd, XLFD_SET_WIDTH, buffers[i]); + if (fields[i] && strcmp (fields[i], "normal")) + i++; + + if (i < 4) + fields[i] = NULL; + + return launder_font_name (g_strconcat (fields[0], " ", + fields[1], " ", + fields[2], " ", + fields[3], NULL)); +} + +/** + * gimp_text_font_size_from_xlfd: + * @xlfd: X Logical Font Description + * @size: return location for the font size + * @size_unit: return location for the font size unit + * + * Attempts to extract the font size from an X Logical Font + * Description. + * + * Return value: %TRUE on success, %FALSE otherwise. + **/ +gboolean +gimp_text_font_size_from_xlfd (const gchar *xlfd, + gdouble *size, + GimpUnit *size_unit) +{ + gchar buffer[XLFD_MAX_FIELD_LEN]; + gchar *field; + + if (!xlfd) + return FALSE; + + field = gimp_text_get_xlfd_field (xlfd, XLFD_PIXELS, buffer); + if (field) + { + *size = atoi (field); + *size_unit = GIMP_UNIT_PIXEL; + return TRUE; + } + + field = gimp_text_get_xlfd_field (xlfd, XLFD_POINTS, buffer); + if (field) + { + *size = atoi (field) / 10.0; + *size_unit = GIMP_UNIT_POINT; + return TRUE; + } + + return FALSE; +} + +/** + * gimp_text_set_font_from_xlfd: + * @text: a #GimpText object + * @xlfd: X Logical Font Description + * + * Attempts to extract font name and font size from @xlfd and sets + * them on the #GimpText object. + **/ +void +gimp_text_set_font_from_xlfd (GimpText *text, + const gchar *xlfd) +{ + gchar *font; + gdouble size; + GimpUnit size_unit; + + g_return_if_fail (GIMP_IS_TEXT (text)); + + if (!xlfd) + return; + + font = gimp_text_font_name_from_xlfd (xlfd); + +#if GIMP_TEXT_DEBUG + g_printerr ("XLFD: %s font: %s\n", xlfd, font ? font : "(null)"); +#endif + + if (gimp_text_font_size_from_xlfd (xlfd, &size, &size_unit)) + { + g_object_set (text, + "font-size", size, + "font-size-unit", size_unit, + font ? "font" : NULL, font, + NULL); + } + else if (font) + { + g_object_set (text, + "font", font, + NULL); + } + + g_free (font); +} + +/** + * gimp_text_get_xlfd_field: + * @fontname: an XLFD fontname + * @field_num: field index + * @buffer: buffer of at least XLFD_MAX_FIELD_LEN chars + * + * Fills the buffer with the specified field from the X Logical Font + * Description name, and returns it. Note: For the charset field, we + * also return the encoding, e.g. 'iso8859-1'. + * + * This function is basically copied from pangox-fontmap.c. + * + * Returns: a pointer to the filled buffer or %NULL if fontname is + * %NULL, the field is longer than XFLD_MAX_FIELD_LEN or it contains + * just an asterisk. + **/ +static gchar * +gimp_text_get_xlfd_field (const gchar *fontname, + gint field_num, + gchar *buffer) +{ + const gchar *t1, *t2; + gchar *p; + gint countdown, num_dashes; + gsize len; + + if (!fontname) + return NULL; + + /* we assume this is a valid fontname...that is, it has 14 fields */ + + for (t1 = fontname, countdown = field_num; *t1 && (countdown >= 0); t1++) + if (*t1 == '-') + countdown--; + + num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1; + + for (t2 = t1; *t2; t2++) + { + if (*t2 == '-' && --num_dashes == 0) + break; + } + + if (t2 > t1) + { + /* Check we don't overflow the buffer */ + len = (gsize) t2 - (gsize) t1; + if (len > XLFD_MAX_FIELD_LEN - 1) + return NULL; + + if (*t1 == '*') + return NULL; + + strncpy (buffer, t1, len); + buffer[len] = 0; + + /* Convert to lower case. */ + for (p = buffer; *p; p++) + *p = g_ascii_tolower (*p); + } + else + { + return NULL; + } + + return buffer; +} + +/* Guard against font names that end in numbers being interpreted as a + * font size in pango font descriptions + */ +static gchar * +launder_font_name (gchar *name) +{ + gchar *laundered_name; + gchar last_char; + + last_char = name[strlen (name) - 1]; + + if (g_ascii_isdigit (last_char) || last_char == '.') + { + laundered_name = g_strconcat (name, ",", NULL); + g_free (name); + + return laundered_name; + } + else + return name; +} diff --git a/app/text/gimptext-xlfd.h b/app/text/gimptext-xlfd.h new file mode 100644 index 0000000..3a9c509 --- /dev/null +++ b/app/text/gimptext-xlfd.h @@ -0,0 +1,36 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_TEXT_XLFD_H__ +#define __GIMP_TEXT_XLFD_H__ + + +/* handle X Logical Font Descriptions for compat */ + +gchar * gimp_text_font_name_from_xlfd (const gchar *xlfd); +gboolean gimp_text_font_size_from_xlfd (const gchar *xlfd, + gdouble *size, + GimpUnit *size_unit); + +void gimp_text_set_font_from_xlfd (GimpText *text, + const gchar *xlfd); + + +#endif /* __GIMP_TEXT_COMPAT_H__ */ diff --git a/app/text/gimptext.c b/app/text/gimptext.c new file mode 100644 index 0000000..fe671a4 --- /dev/null +++ b/app/text/gimptext.c @@ -0,0 +1,596 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <pango/pango.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpmath/gimpmath.h" +#include "libgimpcolor/gimpcolor.h" +#include "libgimpconfig/gimpconfig.h" + +#include "text-types.h" + +#include "core/gimp-memsize.h" +#include "core/gimp-utils.h" +#include "core/gimpmarshal.h" +#include "core/gimpstrokeoptions.h" + +#include "gimptext.h" + + +enum +{ + PROP_0, + PROP_TEXT, + PROP_MARKUP, + PROP_FONT, + PROP_FONT_SIZE, + PROP_UNIT, + PROP_ANTIALIAS, + PROP_HINT_STYLE, + PROP_KERNING, + PROP_LANGUAGE, + PROP_BASE_DIR, + PROP_COLOR, + PROP_OUTLINE, + PROP_JUSTIFICATION, + PROP_INDENTATION, + PROP_LINE_SPACING, + PROP_LETTER_SPACING, + PROP_BOX_MODE, + PROP_BOX_WIDTH, + PROP_BOX_HEIGHT, + PROP_BOX_UNIT, + PROP_TRANSFORMATION, + PROP_OFFSET_X, + PROP_OFFSET_Y, + PROP_BORDER, + /* for backward compatibility */ + PROP_HINTING +}; + +enum +{ + CHANGED, + LAST_SIGNAL +}; + + +static void gimp_text_finalize (GObject *object); +static void gimp_text_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_text_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_text_dispatch_properties_changed (GObject *object, + guint n_pspecs, + GParamSpec **pspecs); +static gint64 gimp_text_get_memsize (GimpObject *object, + gint64 *gui_size); + + +G_DEFINE_TYPE_WITH_CODE (GimpText, gimp_text, GIMP_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, NULL)) + +#define parent_class gimp_text_parent_class + +static guint text_signals[LAST_SIGNAL] = { 0 }; + + +static void +gimp_text_class_init (GimpTextClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); + GimpRGB black; + GimpMatrix2 identity; + gchar *language; + + text_signals[CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GimpTextClass, changed), + NULL, NULL, + gimp_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + object_class->finalize = gimp_text_finalize; + object_class->get_property = gimp_text_get_property; + object_class->set_property = gimp_text_set_property; + object_class->dispatch_properties_changed = gimp_text_dispatch_properties_changed; + + gimp_object_class->get_memsize = gimp_text_get_memsize; + + gimp_rgba_set (&black, 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE); + gimp_matrix2_identity (&identity); + + GIMP_CONFIG_PROP_STRING (object_class, PROP_TEXT, + "text", + NULL, NULL, + NULL, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_STRING (object_class, PROP_MARKUP, + "markup", + NULL, NULL, + NULL, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_STRING (object_class, PROP_FONT, + "font", + NULL, NULL, + "Sans-serif", + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_FONT_SIZE, + "font-size", + NULL, NULL, + 0.0, 8192.0, 24.0, + GIMP_PARAM_STATIC_STRINGS); + + /* We use the name "font-size-unit" for backward compatibility. + * The unit is also used for other sizes in the text object. + */ + GIMP_CONFIG_PROP_UNIT (object_class, PROP_UNIT, + "font-size-unit", + NULL, NULL, + TRUE, FALSE, GIMP_UNIT_PIXEL, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_ANTIALIAS, + "antialias", + NULL, NULL, + TRUE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_HINT_STYLE, + "hint-style", + NULL, NULL, + GIMP_TYPE_TEXT_HINT_STYLE, + GIMP_TEXT_HINT_STYLE_MEDIUM, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_KERNING, + "kerning", + NULL, NULL, + FALSE, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + language = gimp_get_default_language (NULL); + + GIMP_CONFIG_PROP_STRING (object_class, PROP_LANGUAGE, + "language", + NULL, NULL, + language, + GIMP_PARAM_STATIC_STRINGS); + + g_free (language); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_BASE_DIR, + "base-direction", + NULL, NULL, + GIMP_TYPE_TEXT_DIRECTION, + GIMP_TEXT_DIRECTION_LTR, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_RGB (object_class, PROP_COLOR, + "color", + NULL, NULL, + FALSE, &black, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_OUTLINE, + "outline", + NULL, NULL, + GIMP_TYPE_TEXT_OUTLINE, + GIMP_TEXT_OUTLINE_NONE, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_JUSTIFICATION, + "justify", + NULL, NULL, + GIMP_TYPE_TEXT_JUSTIFICATION, + GIMP_TEXT_JUSTIFY_LEFT, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_INDENTATION, + "indent", + NULL, NULL, + -8192.0, 8192.0, 0.0, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_LINE_SPACING, + "line-spacing", + NULL, NULL, + -8192.0, 8192.0, 0.0, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_LETTER_SPACING, + "letter-spacing", + NULL, NULL, + -8192.0, 8192.0, 0.0, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_BOX_MODE, + "box-mode", + NULL, NULL, + GIMP_TYPE_TEXT_BOX_MODE, + GIMP_TEXT_BOX_DYNAMIC, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_BOX_WIDTH, + "box-width", + NULL, NULL, + 0.0, GIMP_MAX_IMAGE_SIZE, 0.0, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_BOX_HEIGHT, + "box-height", + NULL, NULL, + 0.0, GIMP_MAX_IMAGE_SIZE, 0.0, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_UNIT (object_class, PROP_BOX_UNIT, + "box-unit", + NULL, NULL, + TRUE, FALSE, GIMP_UNIT_PIXEL, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_MATRIX2 (object_class, PROP_TRANSFORMATION, + "transformation", + NULL, NULL, + &identity, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_OFFSET_X, + "offset-x", + NULL, NULL, + -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_OFFSET_Y, + "offset-y", + NULL, NULL, + -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + /* border does only exist to implement the old text API */ + g_object_class_install_property (object_class, PROP_BORDER, + g_param_spec_int ("border", NULL, NULL, + 0, GIMP_MAX_IMAGE_SIZE, 0, + G_PARAM_CONSTRUCT | + GIMP_PARAM_WRITABLE)); + + /* the old hinting options have been replaced by 'hint-style' */ + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_HINTING, + "hinting", + NULL, NULL, + TRUE, + GIMP_PARAM_STATIC_STRINGS); +} + +static void +gimp_text_init (GimpText *text) +{ +} + +static void +gimp_text_finalize (GObject *object) +{ + GimpText *text = GIMP_TEXT (object); + + g_clear_pointer (&text->text, g_free); + g_clear_pointer (&text->markup, g_free); + g_clear_pointer (&text->font, g_free); + g_clear_pointer (&text->language, g_free); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_text_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpText *text = GIMP_TEXT (object); + + switch (property_id) + { + case PROP_TEXT: + g_value_set_string (value, text->text); + break; + case PROP_MARKUP: + g_value_set_string (value, text->markup); + break; + case PROP_FONT: + g_value_set_string (value, text->font); + break; + case PROP_FONT_SIZE: + g_value_set_double (value, text->font_size); + break; + case PROP_UNIT: + g_value_set_int (value, text->unit); + break; + case PROP_ANTIALIAS: + g_value_set_boolean (value, text->antialias); + break; + case PROP_HINT_STYLE: + g_value_set_enum (value, text->hint_style); + break; + case PROP_KERNING: + g_value_set_boolean (value, text->kerning); + break; + case PROP_BASE_DIR: + g_value_set_enum (value, text->base_dir); + break; + case PROP_LANGUAGE: + g_value_set_string (value, text->language); + break; + case PROP_COLOR: + g_value_set_boxed (value, &text->color); + break; + case PROP_OUTLINE: + g_value_set_enum (value, text->outline); + break; + case PROP_JUSTIFICATION: + g_value_set_enum (value, text->justify); + break; + case PROP_INDENTATION: + g_value_set_double (value, text->indent); + break; + case PROP_LINE_SPACING: + g_value_set_double (value, text->line_spacing); + break; + case PROP_LETTER_SPACING: + g_value_set_double (value, text->letter_spacing); + break; + case PROP_BOX_MODE: + g_value_set_enum (value, text->box_mode); + break; + case PROP_BOX_WIDTH: + g_value_set_double (value, text->box_width); + break; + case PROP_BOX_HEIGHT: + g_value_set_double (value, text->box_height); + break; + case PROP_BOX_UNIT: + g_value_set_int (value, text->box_unit); + break; + case PROP_TRANSFORMATION: + g_value_set_boxed (value, &text->transformation); + break; + case PROP_OFFSET_X: + g_value_set_double (value, text->offset_x); + break; + case PROP_OFFSET_Y: + g_value_set_double (value, text->offset_y); + break; + case PROP_HINTING: + g_value_set_boolean (value, + text->hint_style != GIMP_TEXT_HINT_STYLE_NONE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_text_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpText *text = GIMP_TEXT (object); + GimpRGB *color; + GimpMatrix2 *matrix; + + switch (property_id) + { + case PROP_TEXT: + g_free (text->text); + text->text = g_value_dup_string (value); + if (text->text && text->markup) + { + g_clear_pointer (&text->markup, g_free); + g_object_notify (object, "markup"); + } + break; + case PROP_MARKUP: + g_free (text->markup); + text->markup = g_value_dup_string (value); + if (text->markup && text->text) + { + g_clear_pointer (&text->text, g_free); + g_object_notify (object, "text"); + } + break; + case PROP_FONT: + { + const gchar *font = g_value_get_string (value); + + g_free (text->font); + + if (font) + { + gsize len = strlen (font); + + if (g_str_has_suffix (font, " Not-Rotated")) + len -= strlen ( " Not-Rotated"); + + text->font = g_strndup (font, len); + } + else + { + text->font = NULL; + } + } + break; + case PROP_FONT_SIZE: + text->font_size = g_value_get_double (value); + break; + case PROP_UNIT: + text->unit = g_value_get_int (value); + break; + case PROP_ANTIALIAS: + text->antialias = g_value_get_boolean (value); + break; + case PROP_HINT_STYLE: + text->hint_style = g_value_get_enum (value); + break; + case PROP_KERNING: + text->kerning = g_value_get_boolean (value); + break; + case PROP_LANGUAGE: + g_free (text->language); + text->language = g_value_dup_string (value); + break; + case PROP_BASE_DIR: + text->base_dir = g_value_get_enum (value); + break; + case PROP_COLOR: + color = g_value_get_boxed (value); + text->color = *color; + break; + case PROP_OUTLINE: + text->outline = g_value_get_enum (value); + break; + case PROP_JUSTIFICATION: + text->justify = g_value_get_enum (value); + break; + case PROP_INDENTATION: + text->indent = g_value_get_double (value); + break; + case PROP_LINE_SPACING: + text->line_spacing = g_value_get_double (value); + break; + case PROP_LETTER_SPACING: + text->letter_spacing = g_value_get_double (value); + break; + case PROP_BOX_MODE: + text->box_mode = g_value_get_enum (value); + break; + case PROP_BOX_WIDTH: + text->box_width = g_value_get_double (value); + break; + case PROP_BOX_HEIGHT: + text->box_height = g_value_get_double (value); + break; + case PROP_BOX_UNIT: + text->box_unit = g_value_get_int (value); + break; + case PROP_TRANSFORMATION: + matrix = g_value_get_boxed (value); + text->transformation = *matrix; + break; + case PROP_OFFSET_X: + text->offset_x = g_value_get_double (value); + break; + case PROP_OFFSET_Y: + text->offset_y = g_value_get_double (value); + break; + case PROP_BORDER: + text->border = g_value_get_int (value); + break; + case PROP_HINTING: + /* interpret "hinting" only if "hint-style" has its default + * value, so we don't overwrite a serialized new hint-style with + * a compat "hinting" that is only there for old GIMP versions + */ + if (text->hint_style == GIMP_TEXT_HINT_STYLE_MEDIUM) + text->hint_style = (g_value_get_boolean (value) ? + GIMP_TEXT_HINT_STYLE_MEDIUM : + GIMP_TEXT_HINT_STYLE_NONE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_text_dispatch_properties_changed (GObject *object, + guint n_pspecs, + GParamSpec **pspecs) +{ + G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object, + n_pspecs, pspecs); + + g_signal_emit (object, text_signals[CHANGED], 0); +} + +static gint64 +gimp_text_get_memsize (GimpObject *object, + gint64 *gui_size) +{ + GimpText *text = GIMP_TEXT (object); + gint64 memsize = 0; + + memsize += gimp_string_get_memsize (text->text); + memsize += gimp_string_get_memsize (text->markup); + memsize += gimp_string_get_memsize (text->font); + memsize += gimp_string_get_memsize (text->language); + + return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, + gui_size); +} + +void +gimp_text_get_transformation (GimpText *text, + GimpMatrix3 *matrix) +{ + g_return_if_fail (GIMP_IS_TEXT (text)); + g_return_if_fail (matrix != NULL); + + matrix->coeff[0][0] = text->transformation.coeff[0][0]; + matrix->coeff[0][1] = text->transformation.coeff[0][1]; + matrix->coeff[0][2] = text->offset_x; + + matrix->coeff[1][0] = text->transformation.coeff[1][0]; + matrix->coeff[1][1] = text->transformation.coeff[1][1]; + matrix->coeff[1][2] = text->offset_y; + + matrix->coeff[2][0] = 0.0; + matrix->coeff[2][1] = 0.0; + matrix->coeff[2][2] = 1.0; +} diff --git a/app/text/gimptext.h b/app/text/gimptext.h new file mode 100644 index 0000000..8a292be --- /dev/null +++ b/app/text/gimptext.h @@ -0,0 +1,83 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_TEXT_H__ +#define __GIMP_TEXT_H__ + + +#include "core/gimpobject.h" + + +#define GIMP_TYPE_TEXT (gimp_text_get_type ()) +#define GIMP_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TEXT, GimpText)) +#define GIMP_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TEXT, GimpTextClass)) +#define GIMP_IS_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TEXT)) +#define GIMP_IS_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TEXT)) +#define GIMP_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TEXT, GimpTextClass)) + + +typedef struct _GimpTextClass GimpTextClass; + +struct _GimpText +{ + GimpObject parent_instance; + + gchar *text; + gchar *markup; + gchar *font; + GimpUnit unit; + gdouble font_size; + gboolean antialias; + GimpTextHintStyle hint_style; + gboolean kerning; + gchar *language; + GimpTextDirection base_dir; + GimpRGB color; + GimpTextOutline outline; + GimpTextJustification justify; + gdouble indent; + gdouble line_spacing; + gdouble letter_spacing; + GimpTextBoxMode box_mode; + gdouble box_width; + gdouble box_height; + GimpUnit box_unit; + GimpMatrix2 transformation; + gdouble offset_x; + gdouble offset_y; + + gdouble border; +}; + +struct _GimpTextClass +{ + GimpObjectClass parent_class; + + void (* changed) (GimpText *text); +}; + + +GType gimp_text_get_type (void) G_GNUC_CONST; + +void gimp_text_get_transformation (GimpText *text, + GimpMatrix3 *matrix); + + +#endif /* __GIMP_TEXT_H__ */ diff --git a/app/text/gimptextlayer-transform.c b/app/text/gimptextlayer-transform.c new file mode 100644 index 0000000..20e6720 --- /dev/null +++ b/app/text/gimptextlayer-transform.c @@ -0,0 +1,201 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpTextLayer + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpmath/gimpmath.h" + +#include "text-types.h" + +#include "core/gimp-transform-utils.h" +#include "core/gimpimage-undo.h" + +#include "gimptext.h" +#include "gimptextlayer.h" +#include "gimptextlayer-transform.h" + + +static GimpItemClass * gimp_text_layer_parent_class (void) G_GNUC_CONST; + +static gboolean gimp_text_layer_get_transformation (GimpTextLayer *layer, + GimpMatrix3 *matrix); +static gboolean gimp_text_layer_set_transformation (GimpTextLayer *layer, + GimpMatrix3 *matrix); + + +void +gimp_text_layer_scale (GimpItem *item, + gint new_width, + gint new_height, + gint new_offset_x, + gint new_offset_y, + GimpInterpolationType interpolation_type, + GimpProgress *progress) +{ + /* TODO */ +} + +static gboolean +gimp_text_layer_transform_flip (GimpTextLayer *layer, + GimpOrientationType flip_type, + gdouble axis) +{ + GimpMatrix3 matrix; + + if (! gimp_text_layer_get_transformation (layer, &matrix)) + return FALSE; + + gimp_transform_matrix_flip (&matrix, flip_type, axis); + + return gimp_text_layer_set_transformation (layer, &matrix); +} + +void +gimp_text_layer_flip (GimpItem *item, + GimpContext *context, + GimpOrientationType flip_type, + gdouble axis, + gboolean clip_result) +{ + GimpTextLayer *layer = GIMP_TEXT_LAYER (item); + + if (gimp_text_layer_transform_flip (layer, flip_type, axis)) + { + GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (layer)); + + if (mask) + gimp_item_flip (GIMP_ITEM (mask), context, + flip_type, axis, clip_result); + } + else + { + gimp_text_layer_parent_class ()->flip (item, context, + flip_type, axis, clip_result); + } +} + +static gboolean +gimp_text_layer_transform_rotate (GimpTextLayer *layer, + GimpRotationType rotate_type, + gdouble center_x, + gdouble center_y) +{ + GimpMatrix3 matrix; + + if (! gimp_text_layer_get_transformation (layer, &matrix)) + return FALSE; + + gimp_transform_matrix_rotate (&matrix, rotate_type, center_x, center_y); + + return gimp_text_layer_set_transformation (layer, &matrix); +} + +void +gimp_text_layer_rotate (GimpItem *item, + GimpContext *context, + GimpRotationType rotate_type, + gdouble center_x, + gdouble center_y, + gboolean clip_result) +{ + GimpTextLayer *layer = GIMP_TEXT_LAYER (item); + + if (! gimp_text_layer_transform_rotate (layer, + rotate_type, center_x, center_y)) + { + GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (layer)); + + if (mask) + gimp_item_rotate (GIMP_ITEM (mask), context, + rotate_type, center_x, center_y, clip_result); + } + else + { + gimp_text_layer_parent_class ()->rotate (item, context, + rotate_type, center_x, center_y, + clip_result); + } +} + +void +gimp_text_layer_transform (GimpItem *item, + GimpContext *context, + const GimpMatrix3 *matrix, + GimpTransformDirection direction, + GimpInterpolationType interpolation_type, + gboolean supersample, + GimpTransformResize clip_result, + GimpProgress *progress) +{ + /* TODO */ +} + +static GimpItemClass * +gimp_text_layer_parent_class (void) +{ + static GimpItemClass *parent_class = NULL; + + if (! parent_class) + { + gpointer klass = g_type_class_peek (GIMP_TYPE_TEXT_LAYER); + + parent_class = g_type_class_peek_parent (klass); + } + + return parent_class; +} + +static gboolean +gimp_text_layer_get_transformation (GimpTextLayer *layer, + GimpMatrix3 *matrix) +{ + if (! layer->text || layer->modified) + return FALSE; + + gimp_text_get_transformation (layer->text, matrix); + + return TRUE; +} + +static gboolean +gimp_text_layer_set_transformation (GimpTextLayer *layer, + GimpMatrix3 *matrix) +{ + GimpMatrix2 trafo; + + if (! gimp_matrix3_is_affine (matrix)) + return FALSE; + + trafo.coeff[0][0] = matrix->coeff[0][0]; + trafo.coeff[0][1] = matrix->coeff[0][1]; + trafo.coeff[1][0] = matrix->coeff[1][0]; + trafo.coeff[1][1] = matrix->coeff[1][1]; + + gimp_text_layer_set (GIMP_TEXT_LAYER (layer), NULL, + "transformation", &trafo, + "offset-x", matrix->coeff[0][2], + "offset-y", matrix->coeff[1][2], + NULL); + + return TRUE; +} diff --git a/app/text/gimptextlayer-transform.h b/app/text/gimptextlayer-transform.h new file mode 100644 index 0000000..bf17a86 --- /dev/null +++ b/app/text/gimptextlayer-transform.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpTextLayer + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_TEXT_LAYER_TRANSFORM_H__ +#define __GIMP_TEXT_LAYER_TRANSFORM_H__ + + +void gimp_text_layer_scale (GimpItem *item, + gint new_width, + gint new_height, + gint new_offset_x, + gint new_offset_y, + GimpInterpolationType interpolation_type, + GimpProgress *progress); +void gimp_text_layer_flip (GimpItem *item, + GimpContext *context, + GimpOrientationType flip_type, + gdouble axis, + gboolean clip_result); +void gimp_text_layer_rotate (GimpItem *item, + GimpContext *context, + GimpRotationType rotate_type, + gdouble center_x, + gdouble center_y, + gboolean clip_result); +void gimp_text_layer_transform (GimpItem *item, + GimpContext *context, + const GimpMatrix3 *matrix, + GimpTransformDirection direction, + GimpInterpolationType interpolation_type, + gboolean supersample, + GimpTransformResize clip_result, + GimpProgress *progress); + + +#endif /* __GIMP_TEXT_LAYER_TRANSFORM_H__ */ diff --git a/app/text/gimptextlayer-xcf.c b/app/text/gimptextlayer-xcf.c new file mode 100644 index 0000000..33452a1 --- /dev/null +++ b/app/text/gimptextlayer-xcf.c @@ -0,0 +1,220 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> +#include <cairo.h> + +#include "libgimpbase/gimpbase.h" +#include "text-types.h" + +#include "core/gimp.h" +#include "core/gimpdrawable-private.h" /* eek */ +#include "core/gimpimage.h" +#include "core/gimpparasitelist.h" + +#include "gimptext.h" +#include "gimptext-parasite.h" +#include "gimptextlayer.h" +#include "gimptextlayer-xcf.h" + +#include "gimp-intl.h" + + +enum +{ + TEXT_LAYER_XCF_NONE = 0, + TEXT_LAYER_XCF_DONT_AUTO_RENAME = 1 << 0, + TEXT_LAYER_XCF_MODIFIED = 1 << 1 +}; + + +static GimpLayer * gimp_text_layer_from_layer (GimpLayer *layer, + GimpText *text); + + +gboolean +gimp_text_layer_xcf_load_hack (GimpLayer **layer) +{ + const gchar *name; + GimpText *text = NULL; + const GimpParasite *parasite; + + g_return_val_if_fail (layer != NULL, FALSE); + g_return_val_if_fail (GIMP_IS_LAYER (*layer), FALSE); + + name = gimp_text_parasite_name (); + parasite = gimp_item_parasite_find (GIMP_ITEM (*layer), name); + + if (parasite) + { + GError *error = NULL; + + text = gimp_text_from_parasite (parasite, &error); + + if (error) + { + gimp_message (gimp_item_get_image (GIMP_ITEM (*layer))->gimp, NULL, + GIMP_MESSAGE_ERROR, + _("Problems parsing the text parasite for layer '%s':\n" + "%s\n\n" + "Some text properties may be wrong. " + "Unless you want to edit the text layer, " + "you don't need to worry about this."), + gimp_object_get_name (*layer), + error->message); + g_clear_error (&error); + } + } + else + { + name = gimp_text_gdyntext_parasite_name (); + + parasite = gimp_item_parasite_find (GIMP_ITEM (*layer), name); + + if (parasite) + text = gimp_text_from_gdyntext_parasite (parasite); + } + + if (text) + { + *layer = gimp_text_layer_from_layer (*layer, text); + + /* let the text layer knows what parasite was used to create it */ + GIMP_TEXT_LAYER (*layer)->text_parasite = name; + } + + return (text != NULL); +} + +void +gimp_text_layer_xcf_save_prepare (GimpTextLayer *layer) +{ + GimpText *text; + + g_return_if_fail (GIMP_IS_TEXT_LAYER (layer)); + + /* If the layer has a text parasite already, it wasn't changed and we + * can simply save the original parasite back which is still attached. + */ + if (layer->text_parasite) + return; + + text = gimp_text_layer_get_text (layer); + if (text) + { + GimpParasite *parasite = gimp_text_to_parasite (text); + + /* Don't push an undo because the parasite only exists temporarily + * while the text layer is saved to XCF. + */ + gimp_item_parasite_attach (GIMP_ITEM (layer), parasite, FALSE); + + gimp_parasite_free (parasite); + } +} + +guint32 +gimp_text_layer_get_xcf_flags (GimpTextLayer *text_layer) +{ + guint flags = 0; + + g_return_val_if_fail (GIMP_IS_TEXT_LAYER (text_layer), 0); + + if (! text_layer->auto_rename) + flags |= TEXT_LAYER_XCF_DONT_AUTO_RENAME; + + if (text_layer->modified) + flags |= TEXT_LAYER_XCF_MODIFIED; + + return flags; +} + +void +gimp_text_layer_set_xcf_flags (GimpTextLayer *text_layer, + guint32 flags) +{ + g_return_if_fail (GIMP_IS_TEXT_LAYER (text_layer)); + + g_object_set (text_layer, + "auto-rename", (flags & TEXT_LAYER_XCF_DONT_AUTO_RENAME) == 0, + "modified", (flags & TEXT_LAYER_XCF_MODIFIED) != 0, + NULL); +} + + +/** + * gimp_text_layer_from_layer: + * @layer: a #GimpLayer object + * @text: a #GimpText object + * + * Converts a standard #GimpLayer and a #GimpText object into a + * #GimpTextLayer. The new text layer takes ownership of the @text and + * @layer objects. The @layer object is rendered unusable by this + * function. Don't even try to use if afterwards! + * + * This is a gross hack that is needed in order to load text layers + * from XCF files in a backwards-compatible way. Please don't use it + * for anything else! + * + * Return value: a newly allocated #GimpTextLayer object + **/ +static GimpLayer * +gimp_text_layer_from_layer (GimpLayer *layer, + GimpText *text) +{ + GimpTextLayer *text_layer; + GimpDrawable *drawable; + + g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); + g_return_val_if_fail (GIMP_IS_TEXT (text), NULL); + + text_layer = g_object_new (GIMP_TYPE_TEXT_LAYER, + "image", gimp_item_get_image (GIMP_ITEM (layer)), + NULL); + + gimp_item_replace_item (GIMP_ITEM (text_layer), GIMP_ITEM (layer)); + + drawable = GIMP_DRAWABLE (text_layer); + + gimp_drawable_steal_buffer (drawable, GIMP_DRAWABLE (layer)); + + gimp_layer_set_opacity (GIMP_LAYER (text_layer), + gimp_layer_get_opacity (layer), FALSE); + gimp_layer_set_mode (GIMP_LAYER (text_layer), + gimp_layer_get_mode (layer), FALSE); + gimp_layer_set_blend_space (GIMP_LAYER (text_layer), + gimp_layer_get_blend_space (layer), FALSE); + gimp_layer_set_composite_space (GIMP_LAYER (text_layer), + gimp_layer_get_composite_space (layer), FALSE); + gimp_layer_set_composite_mode (GIMP_LAYER (text_layer), + gimp_layer_get_composite_mode (layer), FALSE); + gimp_layer_set_lock_alpha (GIMP_LAYER (text_layer), + gimp_layer_get_lock_alpha (layer), FALSE); + + gimp_text_layer_set_text (text_layer, text); + + g_object_unref (text); + g_object_unref (layer); + + return GIMP_LAYER (text_layer); +} diff --git a/app/text/gimptextlayer-xcf.h b/app/text/gimptextlayer-xcf.h new file mode 100644 index 0000000..3d08dfa --- /dev/null +++ b/app/text/gimptextlayer-xcf.h @@ -0,0 +1,34 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_TEXT_LAYER_XCF_H__ +#define __GIMP_TEXT_LAYER_XCF_H__ + + +gboolean gimp_text_layer_xcf_load_hack (GimpLayer **layer); + +void gimp_text_layer_xcf_save_prepare (GimpTextLayer *text_layer); + +guint32 gimp_text_layer_get_xcf_flags (GimpTextLayer *text_layer); +void gimp_text_layer_set_xcf_flags (GimpTextLayer *text_layer, + guint32 flags); + + +#endif /* __GIMP_TEXT_LAYER_XCF_H__ */ diff --git a/app/text/gimptextlayer.c b/app/text/gimptextlayer.c new file mode 100644 index 0000000..fb4146a --- /dev/null +++ b/app/text/gimptextlayer.c @@ -0,0 +1,861 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpTextLayer + * Copyright (C) 2002-2004 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <pango/pangocairo.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpcolor/gimpcolor.h" +#include "libgimpconfig/gimpconfig.h" + +#include "text-types.h" + +#include "gegl/gimp-babl.h" +#include "gegl/gimp-gegl-loops.h" +#include "gegl/gimp-gegl-utils.h" + +#include "core/gimp.h" +#include "core/gimp-utils.h" +#include "core/gimpcontext.h" +#include "core/gimpcontainer.h" +#include "core/gimpdatafactory.h" +#include "core/gimpimage.h" +#include "core/gimpimage-color-profile.h" +#include "core/gimpimage-undo.h" +#include "core/gimpimage-undo-push.h" +#include "core/gimpitemtree.h" +#include "core/gimpparasitelist.h" + +#include "gimptext.h" +#include "gimptextlayer.h" +#include "gimptextlayer-transform.h" +#include "gimptextlayout.h" +#include "gimptextlayout-render.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_TEXT, + PROP_AUTO_RENAME, + PROP_MODIFIED +}; + +struct _GimpTextLayerPrivate +{ + GimpTextDirection base_dir; +}; + +static void gimp_text_layer_finalize (GObject *object); +static void gimp_text_layer_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_text_layer_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static gint64 gimp_text_layer_get_memsize (GimpObject *object, + gint64 *gui_size); + +static GimpItem * gimp_text_layer_duplicate (GimpItem *item, + GType new_type); +static gboolean gimp_text_layer_rename (GimpItem *item, + const gchar *new_name, + const gchar *undo_desc, + GError **error); + +static void gimp_text_layer_set_buffer (GimpDrawable *drawable, + gboolean push_undo, + const gchar *undo_desc, + GeglBuffer *buffer, + const GeglRectangle *bounds); +static void gimp_text_layer_push_undo (GimpDrawable *drawable, + const gchar *undo_desc, + GeglBuffer *buffer, + gint x, + gint y, + gint width, + gint height); + +static void gimp_text_layer_convert_type (GimpLayer *layer, + GimpImage *dest_image, + const Babl *new_format, + GimpColorProfile *dest_profile, + GeglDitherMethod layer_dither_type, + GeglDitherMethod mask_dither_type, + gboolean push_undo, + GimpProgress *progress); + +static void gimp_text_layer_text_changed (GimpTextLayer *layer); +static gboolean gimp_text_layer_render (GimpTextLayer *layer); +static void gimp_text_layer_render_layout (GimpTextLayer *layer, + GimpTextLayout *layout); + + +G_DEFINE_TYPE_WITH_PRIVATE (GimpTextLayer, gimp_text_layer, GIMP_TYPE_LAYER) + +#define parent_class gimp_text_layer_parent_class + + +static void +gimp_text_layer_class_init (GimpTextLayerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); + GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass); + GimpItemClass *item_class = GIMP_ITEM_CLASS (klass); + GimpDrawableClass *drawable_class = GIMP_DRAWABLE_CLASS (klass); + GimpLayerClass *layer_class = GIMP_LAYER_CLASS (klass); + + object_class->finalize = gimp_text_layer_finalize; + object_class->get_property = gimp_text_layer_get_property; + object_class->set_property = gimp_text_layer_set_property; + + gimp_object_class->get_memsize = gimp_text_layer_get_memsize; + + viewable_class->default_icon_name = "gimp-text-layer"; + + item_class->duplicate = gimp_text_layer_duplicate; + item_class->rename = gimp_text_layer_rename; + +#if 0 + item_class->scale = gimp_text_layer_scale; + item_class->flip = gimp_text_layer_flip; + item_class->rotate = gimp_text_layer_rotate; + item_class->transform = gimp_text_layer_transform; +#endif + + item_class->default_name = _("Text Layer"); + item_class->rename_desc = _("Rename Text Layer"); + item_class->translate_desc = _("Move Text Layer"); + item_class->scale_desc = _("Scale Text Layer"); + item_class->resize_desc = _("Resize Text Layer"); + item_class->flip_desc = _("Flip Text Layer"); + item_class->rotate_desc = _("Rotate Text Layer"); + item_class->transform_desc = _("Transform Text Layer"); + + drawable_class->set_buffer = gimp_text_layer_set_buffer; + drawable_class->push_undo = gimp_text_layer_push_undo; + + layer_class->convert_type = gimp_text_layer_convert_type; + + GIMP_CONFIG_PROP_OBJECT (object_class, PROP_TEXT, + "text", + NULL, NULL, + GIMP_TYPE_TEXT, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_AUTO_RENAME, + "auto-rename", + NULL, NULL, + TRUE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_MODIFIED, + "modified", + NULL, NULL, + FALSE, + GIMP_PARAM_STATIC_STRINGS); +} + +static void +gimp_text_layer_init (GimpTextLayer *layer) +{ + layer->text = NULL; + layer->text_parasite = NULL; + layer->private = gimp_text_layer_get_instance_private (layer); +} + +static void +gimp_text_layer_finalize (GObject *object) +{ + GimpTextLayer *layer = GIMP_TEXT_LAYER (object); + + g_clear_object (&layer->text); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_text_layer_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpTextLayer *text_layer = GIMP_TEXT_LAYER (object); + + switch (property_id) + { + case PROP_TEXT: + g_value_set_object (value, text_layer->text); + break; + case PROP_AUTO_RENAME: + g_value_set_boolean (value, text_layer->auto_rename); + break; + case PROP_MODIFIED: + g_value_set_boolean (value, text_layer->modified); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_text_layer_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpTextLayer *text_layer = GIMP_TEXT_LAYER (object); + + switch (property_id) + { + case PROP_TEXT: + gimp_text_layer_set_text (text_layer, g_value_get_object (value)); + break; + case PROP_AUTO_RENAME: + text_layer->auto_rename = g_value_get_boolean (value); + break; + case PROP_MODIFIED: + text_layer->modified = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gint64 +gimp_text_layer_get_memsize (GimpObject *object, + gint64 *gui_size) +{ + GimpTextLayer *text_layer = GIMP_TEXT_LAYER (object); + gint64 memsize = 0; + + memsize += gimp_object_get_memsize (GIMP_OBJECT (text_layer->text), + gui_size); + + return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, + gui_size); +} + +static GimpItem * +gimp_text_layer_duplicate (GimpItem *item, + GType new_type) +{ + GimpItem *new_item; + + g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_DRAWABLE), NULL); + + new_item = GIMP_ITEM_CLASS (parent_class)->duplicate (item, new_type); + + if (GIMP_IS_TEXT_LAYER (new_item)) + { + GimpTextLayer *layer = GIMP_TEXT_LAYER (item); + GimpTextLayer *new_layer = GIMP_TEXT_LAYER (new_item); + + gimp_config_sync (G_OBJECT (layer), G_OBJECT (new_layer), 0); + + if (layer->text) + { + GimpText *text = gimp_config_duplicate (GIMP_CONFIG (layer->text)); + + gimp_text_layer_set_text (new_layer, text); + + g_object_unref (text); + } + + /* this is just the parasite name, not a pointer to the parasite */ + if (layer->text_parasite) + new_layer->text_parasite = layer->text_parasite; + + new_layer->private->base_dir = layer->private->base_dir; + } + + return new_item; +} + +static gboolean +gimp_text_layer_rename (GimpItem *item, + const gchar *new_name, + const gchar *undo_desc, + GError **error) +{ + if (GIMP_ITEM_CLASS (parent_class)->rename (item, new_name, undo_desc, error)) + { + g_object_set (item, "auto-rename", FALSE, NULL); + + return TRUE; + } + + return FALSE; +} + +static void +gimp_text_layer_set_buffer (GimpDrawable *drawable, + gboolean push_undo, + const gchar *undo_desc, + GeglBuffer *buffer, + const GeglRectangle *bounds) +{ + GimpTextLayer *layer = GIMP_TEXT_LAYER (drawable); + GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer)); + + if (push_undo && ! layer->modified) + gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_DRAWABLE_MOD, + undo_desc); + + GIMP_DRAWABLE_CLASS (parent_class)->set_buffer (drawable, + push_undo, undo_desc, + buffer, bounds); + + if (push_undo && ! layer->modified) + { + gimp_image_undo_push_text_layer_modified (image, NULL, layer); + + g_object_set (drawable, "modified", TRUE, NULL); + + gimp_image_undo_group_end (image); + } +} + +static void +gimp_text_layer_push_undo (GimpDrawable *drawable, + const gchar *undo_desc, + GeglBuffer *buffer, + gint x, + gint y, + gint width, + gint height) +{ + GimpTextLayer *layer = GIMP_TEXT_LAYER (drawable); + GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer)); + + if (! layer->modified) + gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_DRAWABLE, undo_desc); + + GIMP_DRAWABLE_CLASS (parent_class)->push_undo (drawable, undo_desc, + buffer, + x, y, width, height); + + if (! layer->modified) + { + gimp_image_undo_push_text_layer_modified (image, NULL, layer); + + g_object_set (drawable, "modified", TRUE, NULL); + + gimp_image_undo_group_end (image); + } +} + +static void +gimp_text_layer_convert_type (GimpLayer *layer, + GimpImage *dest_image, + const Babl *new_format, + GimpColorProfile *dest_profile, + GeglDitherMethod layer_dither_type, + GeglDitherMethod mask_dither_type, + gboolean push_undo, + GimpProgress *progress) +{ + GimpTextLayer *text_layer = GIMP_TEXT_LAYER (layer); + GimpImage *image = gimp_item_get_image (GIMP_ITEM (text_layer)); + + if (! text_layer->text || + text_layer->modified || + layer_dither_type != GEGL_DITHER_NONE) + { + GIMP_LAYER_CLASS (parent_class)->convert_type (layer, dest_image, + new_format, + dest_profile, + layer_dither_type, + mask_dither_type, + push_undo, + progress); + } + else + { + if (push_undo) + gimp_image_undo_push_text_layer_convert (image, NULL, text_layer); + + text_layer->convert_format = new_format; + + gimp_text_layer_render (text_layer); + + text_layer->convert_format = NULL; + } +} + + +/* public functions */ + +/** + * gimp_text_layer_new: + * @image: the #GimpImage the layer should belong to + * @text: a #GimpText object + * + * Creates a new text layer. + * + * Return value: a new #GimpTextLayer or %NULL in case of a problem + **/ +GimpLayer * +gimp_text_layer_new (GimpImage *image, + GimpText *text) +{ + GimpTextLayer *layer; + + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); + g_return_val_if_fail (GIMP_IS_TEXT (text), NULL); + + if (! text->text && ! text->markup) + return NULL; + + layer = + GIMP_TEXT_LAYER (gimp_drawable_new (GIMP_TYPE_TEXT_LAYER, + image, NULL, + 0, 0, 1, 1, + gimp_image_get_layer_format (image, + TRUE))); + + gimp_layer_set_mode (GIMP_LAYER (layer), + gimp_image_get_default_new_layer_mode (image), + FALSE); + + gimp_text_layer_set_text (layer, text); + + if (! gimp_text_layer_render (layer)) + { + g_object_unref (layer); + return NULL; + } + + return GIMP_LAYER (layer); +} + +void +gimp_text_layer_set_text (GimpTextLayer *layer, + GimpText *text) +{ + g_return_if_fail (GIMP_IS_TEXT_LAYER (layer)); + g_return_if_fail (text == NULL || GIMP_IS_TEXT (text)); + + if (layer->text == text) + return; + + if (layer->text) + { + g_signal_handlers_disconnect_by_func (layer->text, + G_CALLBACK (gimp_text_layer_text_changed), + layer); + + g_clear_object (&layer->text); + } + + if (text) + { + layer->text = g_object_ref (text); + layer->private->base_dir = layer->text->base_dir; + + g_signal_connect_object (text, "changed", + G_CALLBACK (gimp_text_layer_text_changed), + layer, G_CONNECT_SWAPPED); + } + + g_object_notify (G_OBJECT (layer), "text"); + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer)); +} + +GimpText * +gimp_text_layer_get_text (GimpTextLayer *layer) +{ + g_return_val_if_fail (GIMP_IS_TEXT_LAYER (layer), NULL); + + return layer->text; +} + +void +gimp_text_layer_set (GimpTextLayer *layer, + const gchar *undo_desc, + const gchar *first_property_name, + ...) +{ + GimpImage *image; + GimpText *text; + va_list var_args; + + g_return_if_fail (gimp_item_is_text_layer (GIMP_ITEM (layer))); + g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer))); + + text = gimp_text_layer_get_text (layer); + if (! text) + return; + + image = gimp_item_get_image (GIMP_ITEM (layer)); + + gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT, undo_desc); + + g_object_freeze_notify (G_OBJECT (layer)); + + if (layer->modified) + { + gimp_image_undo_push_text_layer_modified (image, NULL, layer); + + /* pass copy_tiles = TRUE so we not only ref the tiles; after + * being a text layer again, undo doesn't care about the + * layer's pixels any longer because they are generated, so + * changing the text would happily overwrite the layer's + * pixels, changing the pixels on the undo stack too without + * any chance to ever undo again. + */ + gimp_image_undo_push_drawable_mod (image, NULL, + GIMP_DRAWABLE (layer), TRUE); + } + + gimp_image_undo_push_text_layer (image, undo_desc, layer, NULL); + + va_start (var_args, first_property_name); + + g_object_set_valist (G_OBJECT (text), first_property_name, var_args); + + va_end (var_args); + + g_object_set (layer, "modified", FALSE, NULL); + + g_object_thaw_notify (G_OBJECT (layer)); + + gimp_image_undo_group_end (image); +} + +/** + * gimp_text_layer_discard: + * @layer: a #GimpTextLayer + * + * Discards the text information. This makes @layer behave like a + * normal layer. + */ +void +gimp_text_layer_discard (GimpTextLayer *layer) +{ + g_return_if_fail (GIMP_IS_TEXT_LAYER (layer)); + g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer))); + + if (! layer->text) + return; + + gimp_image_undo_push_text_layer (gimp_item_get_image (GIMP_ITEM (layer)), + _("Discard Text Information"), + layer, NULL); + + gimp_text_layer_set_text (layer, NULL); +} + +gboolean +gimp_item_is_text_layer (GimpItem *item) +{ + return (GIMP_IS_TEXT_LAYER (item) && + GIMP_TEXT_LAYER (item)->text && + GIMP_TEXT_LAYER (item)->modified == FALSE); +} + + +/* private functions */ + +static const Babl * +gimp_text_layer_get_format (GimpTextLayer *layer) +{ + if (layer->convert_format) + return layer->convert_format; + + return gimp_drawable_get_format (GIMP_DRAWABLE (layer)); +} + +static void +gimp_text_layer_text_changed (GimpTextLayer *layer) +{ + /* If the text layer was created from a parasite, it's time to + * remove that parasite now. + */ + if (layer->text_parasite) + { + /* Don't push an undo because the parasite only exists temporarily + * while the text layer is loaded from XCF. + */ + gimp_item_parasite_detach (GIMP_ITEM (layer), layer->text_parasite, + FALSE); + layer->text_parasite = NULL; + } + + if (layer->text->box_mode == GIMP_TEXT_BOX_DYNAMIC) + { + gint old_width; + gint new_width; + GimpItem *item = GIMP_ITEM (layer); + GimpTextDirection old_base_dir = layer->private->base_dir; + GimpTextDirection new_base_dir = layer->text->base_dir; + + old_width = gimp_item_get_width (item); + gimp_text_layer_render (layer); + new_width = gimp_item_get_width (item); + + if (old_base_dir != new_base_dir) + { + switch (old_base_dir) + { + case GIMP_TEXT_DIRECTION_LTR: + case GIMP_TEXT_DIRECTION_RTL: + case GIMP_TEXT_DIRECTION_TTB_LTR: + case GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT: + switch (new_base_dir) + { + case GIMP_TEXT_DIRECTION_TTB_RTL: + case GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT: + gimp_item_translate (item, -new_width, 0, FALSE); + break; + + case GIMP_TEXT_DIRECTION_LTR: + case GIMP_TEXT_DIRECTION_RTL: + case GIMP_TEXT_DIRECTION_TTB_LTR: + case GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT: + break; + } + break; + + case GIMP_TEXT_DIRECTION_TTB_RTL: + case GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT: + switch (new_base_dir) + { + case GIMP_TEXT_DIRECTION_LTR: + case GIMP_TEXT_DIRECTION_RTL: + case GIMP_TEXT_DIRECTION_TTB_LTR: + case GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT: + gimp_item_translate (item, old_width, 0, FALSE); + break; + + case GIMP_TEXT_DIRECTION_TTB_RTL: + case GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT: + break; + } + break; + } + } + else if ((new_base_dir == GIMP_TEXT_DIRECTION_TTB_RTL || + new_base_dir == GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT)) + { + if (old_width != new_width) + gimp_item_translate (item, old_width - new_width, 0, FALSE); + } + } + else + gimp_text_layer_render (layer); + + layer->private->base_dir = layer->text->base_dir; +} + +static gboolean +gimp_text_layer_render (GimpTextLayer *layer) +{ + GimpDrawable *drawable; + GimpItem *item; + GimpImage *image; + GimpContainer *container; + GimpTextLayout *layout; + gdouble xres; + gdouble yres; + gint width; + gint height; + GError *error = NULL; + + if (! layer->text) + return FALSE; + + drawable = GIMP_DRAWABLE (layer); + item = GIMP_ITEM (layer); + image = gimp_item_get_image (item); + container = gimp_data_factory_get_container (image->gimp->font_factory); + + gimp_data_factory_data_wait (image->gimp->font_factory); + + if (gimp_container_is_empty (container)) + { + gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR, + _("Due to lack of any fonts, " + "text functionality is not available.")); + return FALSE; + } + + gimp_image_get_resolution (image, &xres, &yres); + + layout = gimp_text_layout_new (layer->text, xres, yres, &error); + if (error) + { + gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR, error->message); + g_error_free (error); + } + + g_object_freeze_notify (G_OBJECT (drawable)); + + if (gimp_text_layout_get_size (layout, &width, &height) && + (width != gimp_item_get_width (item) || + height != gimp_item_get_height (item) || + gimp_text_layer_get_format (layer) != + gimp_drawable_get_format (drawable))) + { + GeglBuffer *new_buffer; + + new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height), + gimp_text_layer_get_format (layer)); + gimp_drawable_set_buffer (drawable, FALSE, NULL, new_buffer); + g_object_unref (new_buffer); + + if (gimp_layer_get_mask (GIMP_LAYER (layer))) + { + GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (layer)); + + static GimpContext *unused_eek = NULL; + + if (! unused_eek) + unused_eek = gimp_context_new (image->gimp, "eek", NULL); + + gimp_item_resize (GIMP_ITEM (mask), + unused_eek, GIMP_FILL_TRANSPARENT, + width, height, 0, 0); + } + } + + if (layer->auto_rename) + { + GimpItem *item = GIMP_ITEM (layer); + gchar *name = NULL; + + if (layer->text->text) + { + name = gimp_utf8_strtrim (layer->text->text, 30); + } + else if (layer->text->markup) + { + gchar *tmp = gimp_markup_extract_text (layer->text->markup); + name = gimp_utf8_strtrim (tmp, 30); + g_free (tmp); + } + + if (! name || ! name[0]) + { + g_free (name); + name = g_strdup (_("Empty Text Layer")); + } + + if (gimp_item_is_attached (item)) + { + gimp_item_tree_rename_item (gimp_item_get_tree (item), item, + name, FALSE, NULL); + g_free (name); + } + else + { + gimp_object_take_name (GIMP_OBJECT (layer), name); + } + } + + if (width > 0 && height > 0) + gimp_text_layer_render_layout (layer, layout); + + g_object_unref (layout); + + g_object_thaw_notify (G_OBJECT (drawable)); + + return (width > 0 && height > 0); +} + +static void +gimp_text_layer_render_layout (GimpTextLayer *layer, + GimpTextLayout *layout) +{ + GimpDrawable *drawable = GIMP_DRAWABLE (layer); + GimpItem *item = GIMP_ITEM (layer); + GimpImage *image = gimp_item_get_image (item); + GeglBuffer *buffer; + GimpColorTransform *transform; + cairo_t *cr; + cairo_surface_t *surface; + gint width; + gint height; + cairo_status_t status; + + g_return_if_fail (gimp_drawable_has_alpha (drawable)); + + width = gimp_item_get_width (item); + height = gimp_item_get_height (item); + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + status = cairo_surface_status (surface); + + if (status != CAIRO_STATUS_SUCCESS) + { + GimpImage *image = gimp_item_get_image (item); + + gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR, + _("Your text cannot be rendered. It is likely too big. " + "Please make it shorter or use a smaller font.")); + cairo_surface_destroy (surface); + return; + } + + cr = cairo_create (surface); + gimp_text_layout_render (layout, cr, layer->text->base_dir, FALSE); + cairo_destroy (cr); + + cairo_surface_flush (surface); + + buffer = gimp_cairo_surface_create_buffer (surface); + + transform = gimp_image_get_color_transform_from_srgb_u8 (image); + + if (transform) + { + gimp_color_transform_process_buffer (transform, + buffer, + NULL, + gimp_drawable_get_buffer (drawable), + NULL); + } + else + { + gimp_gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, + gimp_drawable_get_buffer (drawable), NULL); + } + + g_object_unref (buffer); + cairo_surface_destroy (surface); + + gimp_drawable_update (drawable, 0, 0, width, height); +} diff --git a/app/text/gimptextlayer.h b/app/text/gimptextlayer.h new file mode 100644 index 0000000..87c61a7 --- /dev/null +++ b/app/text/gimptextlayer.h @@ -0,0 +1,78 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpTextLayer + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_TEXT_LAYER_H__ +#define __GIMP_TEXT_LAYER_H__ + + +#include "core/gimplayer.h" + + +#define GIMP_TYPE_TEXT_LAYER (gimp_text_layer_get_type ()) +#define GIMP_TEXT_LAYER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TEXT_LAYER, GimpTextLayer)) +#define GIMP_TEXT_LAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TEXT_LAYER, GimpTextLayerClass)) +#define GIMP_IS_TEXT_LAYER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TEXT_LAYER)) +#define GIMP_IS_TEXT_LAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TEXT_LAYER)) +#define GIMP_TEXT_LAYER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TEXT_LAYER, GimpTextLayerClass)) + + +typedef struct _GimpTextLayerClass GimpTextLayerClass; +typedef struct _GimpTextLayerPrivate GimpTextLayerPrivate; + +struct _GimpTextLayer +{ + GimpLayer layer; + + GimpText *text; + const gchar *text_parasite; /* parasite name that this text was set from, + * and that should be removed when the text + * is changed. + */ + gboolean auto_rename; + gboolean modified; + + const Babl *convert_format; + + GimpTextLayerPrivate *private; +}; + +struct _GimpTextLayerClass +{ + GimpLayerClass parent_class; +}; + + +GType gimp_text_layer_get_type (void) G_GNUC_CONST; + +GimpLayer * gimp_text_layer_new (GimpImage *image, + GimpText *text); +GimpText * gimp_text_layer_get_text (GimpTextLayer *layer); +void gimp_text_layer_set_text (GimpTextLayer *layer, + GimpText *text); +void gimp_text_layer_discard (GimpTextLayer *layer); +void gimp_text_layer_set (GimpTextLayer *layer, + const gchar *undo_desc, + const gchar *first_property_name, + ...) G_GNUC_NULL_TERMINATED; + +gboolean gimp_item_is_text_layer (GimpItem *item); + + +#endif /* __GIMP_TEXT_LAYER_H__ */ diff --git a/app/text/gimptextlayout-render.c b/app/text/gimptextlayout-render.c new file mode 100644 index 0000000..f3605e3 --- /dev/null +++ b/app/text/gimptextlayout-render.c @@ -0,0 +1,77 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <pango/pangocairo.h> + +#include "text-types.h" + +#include "gimptextlayout.h" +#include "gimptextlayout-render.h" + + +void +gimp_text_layout_render (GimpTextLayout *layout, + cairo_t *cr, + GimpTextDirection base_dir, + gboolean path) +{ + PangoLayout *pango_layout; + cairo_matrix_t trafo; + gint x, y; + gint width, height; + + g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout)); + g_return_if_fail (cr != NULL); + + cairo_save (cr); + + gimp_text_layout_get_offsets (layout, &x, &y); + cairo_translate (cr, x, y); + + gimp_text_layout_get_transform (layout, &trafo); + cairo_transform (cr, &trafo); + + if (base_dir == GIMP_TEXT_DIRECTION_TTB_RTL || + base_dir == GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT) + { + gimp_text_layout_get_size (layout, &width, &height); + cairo_translate (cr, width, 0); + cairo_rotate (cr, G_PI_2); + } + + if (base_dir == GIMP_TEXT_DIRECTION_TTB_LTR || + base_dir == GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT) + { + gimp_text_layout_get_size (layout, &width, &height); + cairo_translate (cr, 0, height); + cairo_rotate (cr, -G_PI_2); + } + + pango_layout = gimp_text_layout_get_pango_layout (layout); + + if (path) + pango_cairo_layout_path (cr, pango_layout); + else + pango_cairo_show_layout (cr, pango_layout); + + cairo_restore (cr); +} diff --git a/app/text/gimptextlayout-render.h b/app/text/gimptextlayout-render.h new file mode 100644 index 0000000..456480a --- /dev/null +++ b/app/text/gimptextlayout-render.h @@ -0,0 +1,31 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_TEXT_LAYOUT_RENDER_H__ +#define __GIMP_TEXT_LAYOUT_RENDER_H__ + + +void gimp_text_layout_render (GimpTextLayout *layout, + cairo_t *cr, + GimpTextDirection base_dir, + gboolean path); + + +#endif /* __GIMP_TEXT_LAYOUT_RENDER_H__ */ diff --git a/app/text/gimptextlayout.c b/app/text/gimptextlayout.c new file mode 100644 index 0000000..47beed7 --- /dev/null +++ b/app/text/gimptextlayout.c @@ -0,0 +1,796 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> + +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <pango/pangocairo.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" + +#include "text-types.h" + +#include "core/gimperror.h" + +#include "gimptext.h" +#include "gimptextlayout.h" + +#include "gimp-intl.h" + +struct _GimpTextLayout +{ + GObject object; + + GimpText *text; + gdouble xres; + gdouble yres; + PangoLayout *layout; + PangoRectangle extents; +}; + + +static void gimp_text_layout_finalize (GObject *object); + +static void gimp_text_layout_position (GimpTextLayout *layout); +static void gimp_text_layout_set_markup (GimpTextLayout *layout, + GError **error); + +static PangoContext * gimp_text_get_pango_context (GimpText *text, + gdouble xres, + gdouble yres); + + +G_DEFINE_TYPE (GimpTextLayout, gimp_text_layout, G_TYPE_OBJECT) + +#define parent_class gimp_text_layout_parent_class + + +static void +gimp_text_layout_class_init (GimpTextLayoutClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gimp_text_layout_finalize; +} + +static void +gimp_text_layout_init (GimpTextLayout *layout) +{ + layout->text = NULL; + layout->layout = NULL; +} + +static void +gimp_text_layout_finalize (GObject *object) +{ + GimpTextLayout *layout = GIMP_TEXT_LAYOUT (object); + + if (layout->text) + { + g_object_unref (layout->text); + layout->text = NULL; + } + if (layout->layout) + { + g_object_unref (layout->layout); + layout->layout = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +GimpTextLayout * +gimp_text_layout_new (GimpText *text, + gdouble xres, + gdouble yres, + GError **error) +{ + GimpTextLayout *layout; + PangoContext *context; + PangoFontDescription *font_desc; + PangoAlignment alignment = PANGO_ALIGN_LEFT; + gint size; + + g_return_val_if_fail (GIMP_IS_TEXT (text), NULL); + + font_desc = pango_font_description_from_string (text->font); + g_return_val_if_fail (font_desc != NULL, NULL); + + size = pango_units_from_double (gimp_units_to_points (text->font_size, + text->unit, + yres)); + + pango_font_description_set_size (font_desc, MAX (1, size)); + + context = gimp_text_get_pango_context (text, xres, yres); + + layout = g_object_new (GIMP_TYPE_TEXT_LAYOUT, NULL); + + layout->text = g_object_ref (text); + layout->layout = pango_layout_new (context); + layout->xres = xres; + layout->yres = yres; + + pango_layout_set_wrap (layout->layout, PANGO_WRAP_WORD_CHAR); + + pango_layout_set_font_description (layout->layout, font_desc); + pango_font_description_free (font_desc); + + gimp_text_layout_set_markup (layout, error); + + switch (text->justify) + { + case GIMP_TEXT_JUSTIFY_LEFT: + alignment = PANGO_ALIGN_LEFT; + break; + case GIMP_TEXT_JUSTIFY_RIGHT: + alignment = PANGO_ALIGN_RIGHT; + break; + case GIMP_TEXT_JUSTIFY_CENTER: + alignment = PANGO_ALIGN_CENTER; + break; + case GIMP_TEXT_JUSTIFY_FILL: + alignment = PANGO_ALIGN_LEFT; + pango_layout_set_justify (layout->layout, TRUE); + break; + } + + pango_layout_set_alignment (layout->layout, alignment); + + switch (text->box_mode) + { + case GIMP_TEXT_BOX_DYNAMIC: + break; + case GIMP_TEXT_BOX_FIXED: + if (! PANGO_GRAVITY_IS_VERTICAL (pango_context_get_base_gravity (context))) + pango_layout_set_width (layout->layout, + pango_units_from_double + (gimp_units_to_pixels (text->box_width, + text->box_unit, + xres))); + else + pango_layout_set_width (layout->layout, + pango_units_from_double + (gimp_units_to_pixels (text->box_height, + text->box_unit, + yres))); + break; + } + + pango_layout_set_indent (layout->layout, + pango_units_from_double + (gimp_units_to_pixels (text->indent, + text->unit, + xres))); + pango_layout_set_spacing (layout->layout, + pango_units_from_double + (gimp_units_to_pixels (text->line_spacing, + text->unit, + yres))); + + gimp_text_layout_position (layout); + + switch (text->box_mode) + { + case GIMP_TEXT_BOX_DYNAMIC: + break; + case GIMP_TEXT_BOX_FIXED: + layout->extents.width = ceil (gimp_units_to_pixels (text->box_width, + text->box_unit, + xres)); + layout->extents.height = ceil (gimp_units_to_pixels (text->box_height, + text->box_unit, + yres)); + +/* #define VERBOSE */ + +#ifdef VERBOSE + g_printerr ("extents set to %d x %d\n", + layout->extents.width, layout->extents.height); +#endif + break; + } + + g_object_unref (context); + + return layout; +} + +gboolean +gimp_text_layout_get_size (GimpTextLayout *layout, + gint *width, + gint *height) +{ + g_return_val_if_fail (GIMP_IS_TEXT_LAYOUT (layout), FALSE); + + if (width) + *width = layout->extents.width; + + if (height) + *height = layout->extents.height; + + return (layout->extents.width > 0 && layout->extents.height > 0); +} + +void +gimp_text_layout_get_offsets (GimpTextLayout *layout, + gint *x, + gint *y) +{ + g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout)); + + if (x) + *x = layout->extents.x; + + if (y) + *y = layout->extents.y; +} + +void +gimp_text_layout_get_resolution (GimpTextLayout *layout, + gdouble *xres, + gdouble *yres) +{ + g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout)); + + if (xres) + *xres = layout->xres; + + if (yres) + *yres = layout->yres; +} + +GimpText * +gimp_text_layout_get_text (GimpTextLayout *layout) +{ + g_return_val_if_fail (GIMP_IS_TEXT_LAYOUT (layout), NULL); + + return layout->text; +} + +PangoLayout * +gimp_text_layout_get_pango_layout (GimpTextLayout *layout) +{ + g_return_val_if_fail (GIMP_IS_TEXT_LAYOUT (layout), NULL); + + return layout->layout; +} + +void +gimp_text_layout_get_transform (GimpTextLayout *layout, + cairo_matrix_t *matrix) +{ + GimpText *text; + gdouble xres; + gdouble yres; + gdouble norm; + + g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout)); + g_return_if_fail (matrix != NULL); + + text = gimp_text_layout_get_text (layout); + + gimp_text_layout_get_resolution (layout, &xres, &yres); + + norm = 1.0 / yres * xres; + + matrix->xx = text->transformation.coeff[0][0] * norm; + matrix->xy = text->transformation.coeff[0][1] * 1.0; + matrix->yx = text->transformation.coeff[1][0] * norm; + matrix->yy = text->transformation.coeff[1][1] * 1.0; + matrix->x0 = 0; + matrix->y0 = 0; +} + +void +gimp_text_layout_transform_rect (GimpTextLayout *layout, + PangoRectangle *rect) +{ + cairo_matrix_t matrix; + gdouble x, y; + gdouble width, height; + + g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout)); + g_return_if_fail (rect != NULL); + + x = rect->x; + y = rect->y; + width = rect->width; + height = rect->height; + + gimp_text_layout_get_transform (layout, &matrix); + + cairo_matrix_transform_point (&matrix, &x, &y); + cairo_matrix_transform_distance (&matrix, &width, &height); + + rect->x = ROUND (x); + rect->y = ROUND (y); + rect->width = ROUND (width); + rect->height = ROUND (height); +} + +void +gimp_text_layout_transform_point (GimpTextLayout *layout, + gdouble *x, + gdouble *y) +{ + cairo_matrix_t matrix; + gdouble _x = 0.0; + gdouble _y = 0.0; + + g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout)); + + if (x) _x = *x; + if (y) _y = *y; + + gimp_text_layout_get_transform (layout, &matrix); + + cairo_matrix_transform_point (&matrix, &_x, &_y); + + if (x) *x = _x; + if (y) *y = _y; +} + +void +gimp_text_layout_transform_distance (GimpTextLayout *layout, + gdouble *x, + gdouble *y) +{ + cairo_matrix_t matrix; + gdouble _x = 0.0; + gdouble _y = 0.0; + + g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout)); + + if (x) _x = *x; + if (y) _y = *y; + + gimp_text_layout_get_transform (layout, &matrix); + + cairo_matrix_transform_distance (&matrix, &_x, &_y); + + if (x) *x = _x; + if (y) *y = _y; +} + +void +gimp_text_layout_untransform_rect (GimpTextLayout *layout, + PangoRectangle *rect) +{ + cairo_matrix_t matrix; + gdouble x, y; + gdouble width, height; + + g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout)); + g_return_if_fail (rect != NULL); + + x = rect->x; + y = rect->y; + width = rect->width; + height = rect->height; + + gimp_text_layout_get_transform (layout, &matrix); + + if (cairo_matrix_invert (&matrix) == CAIRO_STATUS_SUCCESS) + { + cairo_matrix_transform_point (&matrix, &x, &y); + cairo_matrix_transform_distance (&matrix, &width, &height); + + rect->x = ROUND (x); + rect->y = ROUND (y); + rect->width = ROUND (width); + rect->height = ROUND (height); + } +} + +void +gimp_text_layout_untransform_point (GimpTextLayout *layout, + gdouble *x, + gdouble *y) +{ + cairo_matrix_t matrix; + gdouble _x = 0.0; + gdouble _y = 0.0; + + g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout)); + + if (x) _x = *x; + if (y) _y = *y; + + gimp_text_layout_get_transform (layout, &matrix); + + if (cairo_matrix_invert (&matrix) == CAIRO_STATUS_SUCCESS) + { + cairo_matrix_transform_point (&matrix, &_x, &_y); + + if (x) *x = _x; + if (y) *y = _y; + } +} + +void +gimp_text_layout_untransform_distance (GimpTextLayout *layout, + gdouble *x, + gdouble *y) +{ + cairo_matrix_t matrix; + gdouble _x = 0.0; + gdouble _y = 0.0; + + g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout)); + + if (x) _x = *x; + if (y) _y = *y; + + gimp_text_layout_get_transform (layout, &matrix); + + if (cairo_matrix_invert (&matrix) == CAIRO_STATUS_SUCCESS) + { + cairo_matrix_transform_distance (&matrix, &_x, &_y); + + if (x) *x = _x; + if (y) *y = _y; + } +} + +static gboolean +gimp_text_layout_split_markup (const gchar *markup, + gchar **open_tag, + gchar **content, + gchar **close_tag) +{ + gchar *p_open; + gchar *p_close; + + p_open = strstr (markup, "<markup>"); + if (! p_open) + return FALSE; + + *open_tag = g_strndup (markup, p_open - markup + strlen ("<markup>")); + + p_close = g_strrstr (markup, "</markup>"); + if (! p_close) + { + g_free (*open_tag); + return FALSE; + } + + *close_tag = g_strdup (p_close); + + if (p_open + strlen ("<markup>") < p_close) + { + *content = g_strndup (p_open + strlen ("<markup>"), + p_close - p_open - strlen ("<markup>")); + } + else + { + *content = g_strdup (""); + } + + return TRUE; +} + +static gchar * +gimp_text_layout_apply_tags (GimpTextLayout *layout, + const gchar *markup) +{ + GimpText *text = layout->text; + gchar *result; + + { + guchar r, g, b; + + gimp_rgb_get_uchar (&text->color, &r, &g, &b); + + result = g_strdup_printf ("<span color=\"#%02x%02x%02x\">%s</span>", + r, g, b, markup); + } + + if (fabs (text->letter_spacing) > 0.1) + { + gchar *tmp = g_strdup_printf ("<span letter_spacing=\"%d\">%s</span>", + (gint) (text->letter_spacing * PANGO_SCALE), + result); + g_free (result); + result = tmp; + } + + return result; +} + +static void +gimp_text_layout_set_markup (GimpTextLayout *layout, + GError **error) +{ + GimpText *text = layout->text; + gchar *open_tag = NULL; + gchar *content = NULL; + gchar *close_tag = NULL; + gchar *tagged; + gchar *markup; + + if (text->markup) + { + if (! gimp_text_layout_split_markup (text->markup, + &open_tag, &content, &close_tag)) + { + open_tag = g_strdup ("<markup>"); + content = g_strdup (""); + close_tag = g_strdup ("</markup>"); + } + } + else + { + open_tag = g_strdup ("<markup>"); + close_tag = g_strdup ("</markup>"); + + if (text->text) + content = g_markup_escape_text (text->text, -1); + else + content = g_strdup (""); + } + + tagged = gimp_text_layout_apply_tags (layout, content); + + g_free (content); + + markup = g_strconcat (open_tag, tagged, close_tag, NULL); + + g_free (open_tag); + g_free (tagged); + g_free (close_tag); + + if (pango_parse_markup (markup, -1, 0, NULL, NULL, NULL, error) == FALSE) + { + if (error && *error && + (*error)->domain == G_MARKUP_ERROR && + (*error)->code == G_MARKUP_ERROR_INVALID_CONTENT) + { + /* Errors from pango lib are not accurate enough. + * Other possible error codes are: G_MARKUP_ERROR_UNKNOWN_ELEMENT + * and G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, which likely indicate a bug + * in GIMP code or a pango library version issue. + * G_MARKUP_ERROR_INVALID_CONTENT on the other hand likely indicates + * size/color/style/weight/variant/etc. value issue. Font size is the + * only free text in GIMP GUI so we assume that must be it. + * Also we output a custom message because pango's error->message is + * too technical (telling of <span> tags, not using user's font size + * unit, and such). */ + g_error_free (*error); + *error = NULL; + g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED, + _("The new text layout cannot be generated. " + "Most likely the font size is too big.")); + } + } + else + pango_layout_set_markup (layout->layout, markup, -1); + + g_free (markup); +} + +static void +gimp_text_layout_position (GimpTextLayout *layout) +{ + PangoRectangle ink; + PangoRectangle logical; + PangoContext *context; + gint x1, y1; + gint x2, y2; + + layout->extents.x = 0; + layout->extents.y = 0; + layout->extents.width = 0; + layout->extents.height = 0; + + pango_layout_get_pixel_extents (layout->layout, &ink, &logical); + + ink.width = ceil ((gdouble) ink.width * layout->xres / layout->yres); + logical.width = ceil ((gdouble) logical.width * layout->xres / layout->yres); + context = pango_layout_get_context (layout->layout); + +#ifdef VERBOSE + g_printerr ("ink rect: %d x %d @ %d, %d\n", + ink.width, ink.height, ink.x, ink.y); + g_printerr ("logical rect: %d x %d @ %d, %d\n", + logical.width, logical.height, logical.x, logical.y); +#endif + + if (ink.width < 1 || ink.height < 1) + { + layout->extents.width = 1; + layout->extents.height = logical.height; + return; + } + + x1 = MIN (ink.x, logical.x); + y1 = MIN (ink.y, logical.y); + x2 = MAX (ink.x + ink.width, logical.x + logical.width); + y2 = MAX (ink.y + ink.height, logical.y + logical.height); + + layout->extents.x = - x1; + layout->extents.y = - y1; + layout->extents.width = x2 - x1; + layout->extents.height = y2 - y1; + + /* If the width of the layout is > 0, then the text-box is FIXED and + * the layout position should be offset if the alignment is centered + * or right-aligned, also adjust for RTL text direction. + */ + if (pango_layout_get_width (layout->layout) > 0) + { + PangoAlignment align = pango_layout_get_alignment (layout->layout); + GimpTextDirection base_dir = layout->text->base_dir; + gint width; + + pango_layout_get_pixel_size (layout->layout, &width, NULL); + + if ((base_dir == GIMP_TEXT_DIRECTION_LTR && align == PANGO_ALIGN_RIGHT) || + (base_dir == GIMP_TEXT_DIRECTION_RTL && align == PANGO_ALIGN_LEFT) || + (base_dir == GIMP_TEXT_DIRECTION_TTB_RTL && align == PANGO_ALIGN_RIGHT) || + (base_dir == GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT && align == PANGO_ALIGN_RIGHT) || + (base_dir == GIMP_TEXT_DIRECTION_TTB_LTR && align == PANGO_ALIGN_LEFT) || + (base_dir == GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT && align == PANGO_ALIGN_LEFT)) + { + layout->extents.x += + PANGO_PIXELS (pango_layout_get_width (layout->layout)) - width; + } + else if (align == PANGO_ALIGN_CENTER) + { + layout->extents.x += + (PANGO_PIXELS (pango_layout_get_width (layout->layout)) - width) / 2; + } + } + + if (layout->text->border > 0) + { + gint border = layout->text->border; + + layout->extents.x += border; + layout->extents.y += border; + layout->extents.width += 2 * border; + layout->extents.height += 2 * border; + } + + if (PANGO_GRAVITY_IS_VERTICAL (pango_context_get_base_gravity (context))) + { + gint temp; + + temp = layout->extents.y; + layout->extents.y = layout->extents.x; + layout->extents.x = temp; + + temp = layout->extents.height; + layout->extents.height = layout->extents.width; + layout->extents.width = temp; + } + +#ifdef VERBOSE + g_printerr ("layout extents: %d x %d @ %d, %d\n", + layout->extents.width, layout->extents.height, + layout->extents.x, layout->extents.y); +#endif +} + +static cairo_font_options_t * +gimp_text_get_font_options (GimpText *text) +{ + cairo_font_options_t *options = cairo_font_options_create (); + + cairo_font_options_set_antialias (options, (text->antialias ? + CAIRO_ANTIALIAS_DEFAULT : + CAIRO_ANTIALIAS_NONE)); + + switch (text->hint_style) + { + case GIMP_TEXT_HINT_STYLE_NONE: + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); + break; + + case GIMP_TEXT_HINT_STYLE_SLIGHT: + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_SLIGHT); + break; + + case GIMP_TEXT_HINT_STYLE_MEDIUM: + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_MEDIUM); + break; + + case GIMP_TEXT_HINT_STYLE_FULL: + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_FULL); + break; + } + + return options; +} + +static PangoContext * +gimp_text_get_pango_context (GimpText *text, + gdouble xres, + gdouble yres) +{ + PangoContext *context; + PangoFontMap *fontmap; + cairo_font_options_t *options; + + fontmap = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT); + if (! fontmap) + g_error ("You are using a Pango that has been built against a cairo " + "that lacks the Freetype font backend"); + + pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (fontmap), yres); + + context = pango_font_map_create_context (fontmap); + g_object_unref (fontmap); + + options = gimp_text_get_font_options (text); + pango_cairo_context_set_font_options (context, options); + cairo_font_options_destroy (options); + + if (text->language) + pango_context_set_language (context, + pango_language_from_string (text->language)); + + switch (text->base_dir) + { + case GIMP_TEXT_DIRECTION_LTR: + pango_context_set_base_dir (context, PANGO_DIRECTION_LTR); + pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_NATURAL); + pango_context_set_base_gravity (context, PANGO_GRAVITY_SOUTH); + break; + + case GIMP_TEXT_DIRECTION_RTL: + pango_context_set_base_dir (context, PANGO_DIRECTION_RTL); + pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_NATURAL); + pango_context_set_base_gravity (context, PANGO_GRAVITY_SOUTH); + break; + + case GIMP_TEXT_DIRECTION_TTB_RTL: + pango_context_set_base_dir (context, PANGO_DIRECTION_LTR); + pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_LINE); + pango_context_set_base_gravity (context, PANGO_GRAVITY_EAST); + break; + + case GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT: + pango_context_set_base_dir (context, PANGO_DIRECTION_LTR); + pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_STRONG); + pango_context_set_base_gravity (context, PANGO_GRAVITY_EAST); + break; + + case GIMP_TEXT_DIRECTION_TTB_LTR: + pango_context_set_base_dir (context, PANGO_DIRECTION_LTR); + pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_LINE); + pango_context_set_base_gravity (context, PANGO_GRAVITY_WEST); + break; + + case GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT: + pango_context_set_base_dir (context, PANGO_DIRECTION_LTR); + pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_STRONG); + pango_context_set_base_gravity (context, PANGO_GRAVITY_WEST); + break; + } + + return context; +} diff --git a/app/text/gimptextlayout.h b/app/text/gimptextlayout.h new file mode 100644 index 0000000..042751b --- /dev/null +++ b/app/text/gimptextlayout.h @@ -0,0 +1,79 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_TEXT_LAYOUT_H__ +#define __GIMP_TEXT_LAYOUT_H__ + + +#define GIMP_TYPE_TEXT_LAYOUT (gimp_text_layout_get_type ()) +#define GIMP_TEXT_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TEXT_LAYOUT, GimpTextLayout)) +#define GIMP_IS_TEXT_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TEXT_LAYOUT)) + + +typedef struct _GimpTextLayoutClass GimpTextLayoutClass; + +struct _GimpTextLayoutClass +{ + GObjectClass parent_class; +}; + + +GType gimp_text_layout_get_type (void) G_GNUC_CONST; + +GimpTextLayout * gimp_text_layout_new (GimpText *text, + gdouble xres, + gdouble yres, + GError **error); +gboolean gimp_text_layout_get_size (GimpTextLayout *layout, + gint *width, + gint *height); +void gimp_text_layout_get_offsets (GimpTextLayout *layout, + gint *x, + gint *y); +void gimp_text_layout_get_resolution (GimpTextLayout *layout, + gdouble *xres, + gdouble *yres); + +GimpText * gimp_text_layout_get_text (GimpTextLayout *layout); +PangoLayout * gimp_text_layout_get_pango_layout (GimpTextLayout *layout); + +void gimp_text_layout_get_transform (GimpTextLayout *layout, + cairo_matrix_t *matrix); + +void gimp_text_layout_transform_rect (GimpTextLayout *layout, + PangoRectangle *rect); +void gimp_text_layout_transform_point (GimpTextLayout *layout, + gdouble *x, + gdouble *y); +void gimp_text_layout_transform_distance (GimpTextLayout *layout, + gdouble *x, + gdouble *y); + +void gimp_text_layout_untransform_rect (GimpTextLayout *layout, + PangoRectangle *rect); +void gimp_text_layout_untransform_point (GimpTextLayout *layout, + gdouble *x, + gdouble *y); +void gimp_text_layout_untransform_distance (GimpTextLayout *layout, + gdouble *x, + gdouble *y); + + +#endif /* __GIMP_TEXT_LAYOUT_H__ */ diff --git a/app/text/gimptextundo.c b/app/text/gimptextundo.c new file mode 100644 index 0000000..8d1a74b --- /dev/null +++ b/app/text/gimptextundo.c @@ -0,0 +1,307 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpconfig/gimpconfig.h" + +#include "text-types.h" + +#include "gegl/gimp-babl.h" + +#include "core/gimp-memsize.h" +#include "core/gimpitem.h" +#include "core/gimpitemundo.h" + +#include "gimptext.h" +#include "gimptextlayer.h" +#include "gimptextundo.h" + + +enum +{ + PROP_0, + PROP_PARAM +}; + + +static void gimp_text_undo_constructed (GObject *object); +static void gimp_text_undo_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_text_undo_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static gint64 gimp_text_undo_get_memsize (GimpObject *object, + gint64 *gui_size); + +static void gimp_text_undo_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum); +static void gimp_text_undo_free (GimpUndo *undo, + GimpUndoMode undo_mode); + + +G_DEFINE_TYPE (GimpTextUndo, gimp_text_undo, GIMP_TYPE_ITEM_UNDO) + +#define parent_class gimp_text_undo_parent_class + + +static void +gimp_text_undo_class_init (GimpTextUndoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); + GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass); + + object_class->constructed = gimp_text_undo_constructed; + object_class->set_property = gimp_text_undo_set_property; + object_class->get_property = gimp_text_undo_get_property; + + gimp_object_class->get_memsize = gimp_text_undo_get_memsize; + + undo_class->pop = gimp_text_undo_pop; + undo_class->free = gimp_text_undo_free; + + g_object_class_install_property (object_class, PROP_PARAM, + g_param_spec_param ("param", NULL, NULL, + G_TYPE_PARAM, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gimp_text_undo_init (GimpTextUndo *undo) +{ +} + +static void +gimp_text_undo_constructed (GObject *object) +{ + GimpTextUndo *text_undo = GIMP_TEXT_UNDO (object); + GimpTextLayer *layer; + + G_OBJECT_CLASS (parent_class)->constructed (object); + + gimp_assert (GIMP_IS_TEXT_LAYER (GIMP_ITEM_UNDO (text_undo)->item)); + + layer = GIMP_TEXT_LAYER (GIMP_ITEM_UNDO (text_undo)->item); + + switch (GIMP_UNDO (object)->undo_type) + { + case GIMP_UNDO_TEXT_LAYER: + if (text_undo->pspec) + { + gimp_assert (text_undo->pspec->owner_type == GIMP_TYPE_TEXT); + + text_undo->value = g_slice_new0 (GValue); + + g_value_init (text_undo->value, text_undo->pspec->value_type); + g_object_get_property (G_OBJECT (layer->text), + text_undo->pspec->name, text_undo->value); + } + else if (layer->text) + { + text_undo->text = gimp_config_duplicate (GIMP_CONFIG (layer->text)); + } + break; + + case GIMP_UNDO_TEXT_LAYER_MODIFIED: + text_undo->modified = layer->modified; + break; + + case GIMP_UNDO_TEXT_LAYER_CONVERT: + text_undo->format = gimp_drawable_get_format (GIMP_DRAWABLE (layer)); + break; + + default: + gimp_assert_not_reached (); + } +} + +static void +gimp_text_undo_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpTextUndo *text_undo = GIMP_TEXT_UNDO (object); + + switch (property_id) + { + case PROP_PARAM: + text_undo->pspec = g_value_get_param (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_text_undo_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpTextUndo *text_undo = GIMP_TEXT_UNDO (object); + + switch (property_id) + { + case PROP_PARAM: + g_value_set_param (value, (GParamSpec *) text_undo->pspec); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gint64 +gimp_text_undo_get_memsize (GimpObject *object, + gint64 *gui_size) +{ + GimpTextUndo *undo = GIMP_TEXT_UNDO (object); + gint64 memsize = 0; + + memsize += gimp_g_value_get_memsize (undo->value); + memsize += gimp_object_get_memsize (GIMP_OBJECT (undo->text), NULL); + + return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, + gui_size); +} + +static void +gimp_text_undo_pop (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum) +{ + GimpTextUndo *text_undo = GIMP_TEXT_UNDO (undo); + GimpTextLayer *layer = GIMP_TEXT_LAYER (GIMP_ITEM_UNDO (undo)->item); + + GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum); + + switch (undo->undo_type) + { + case GIMP_UNDO_TEXT_LAYER: + if (text_undo->pspec) + { + GValue *value; + + g_return_if_fail (layer->text != NULL); + + value = g_slice_new0 (GValue); + g_value_init (value, text_undo->pspec->value_type); + + g_object_get_property (G_OBJECT (layer->text), + text_undo->pspec->name, value); + + g_object_set_property (G_OBJECT (layer->text), + text_undo->pspec->name, text_undo->value); + + g_value_unset (text_undo->value); + g_slice_free (GValue, text_undo->value); + + text_undo->value = value; + } + else + { + GimpText *text; + + text = (layer->text ? + gimp_config_duplicate (GIMP_CONFIG (layer->text)) : NULL); + + if (layer->text && text_undo->text) + gimp_config_sync (G_OBJECT (text_undo->text), + G_OBJECT (layer->text), 0); + else + gimp_text_layer_set_text (layer, text_undo->text); + + if (text_undo->text) + g_object_unref (text_undo->text); + + text_undo->text = text; + } + break; + + case GIMP_UNDO_TEXT_LAYER_MODIFIED: + { + gboolean modified; + +#if 0 + g_print ("setting layer->modified from %s to %s\n", + layer->modified ? "TRUE" : "FALSE", + text_undo->modified ? "TRUE" : "FALSE"); +#endif + + modified = layer->modified; + g_object_set (layer, "modified", text_undo->modified, NULL); + text_undo->modified = modified; + + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer)); + } + break; + + case GIMP_UNDO_TEXT_LAYER_CONVERT: + { + const Babl *format; + + format = gimp_drawable_get_format (GIMP_DRAWABLE (layer)); + gimp_drawable_convert_type (GIMP_DRAWABLE (layer), + gimp_item_get_image (GIMP_ITEM (layer)), + gimp_babl_format_get_base_type (text_undo->format), + gimp_babl_format_get_precision (text_undo->format), + babl_format_has_alpha (text_undo->format), + NULL, + GEGL_DITHER_NONE, GEGL_DITHER_NONE, + FALSE, NULL); + text_undo->format = format; + } + break; + + default: + gimp_assert_not_reached (); + } +} + +static void +gimp_text_undo_free (GimpUndo *undo, + GimpUndoMode undo_mode) +{ + GimpTextUndo *text_undo = GIMP_TEXT_UNDO (undo); + + g_clear_object (&text_undo->text); + + if (text_undo->pspec) + { + g_value_unset (text_undo->value); + g_slice_free (GValue, text_undo->value); + + text_undo->value = NULL; + text_undo->pspec = NULL; + } + + GIMP_UNDO_CLASS (parent_class)->free (undo, undo_mode); +} diff --git a/app/text/gimptextundo.h b/app/text/gimptextundo.h new file mode 100644 index 0000000..913aeb9 --- /dev/null +++ b/app/text/gimptextundo.h @@ -0,0 +1,55 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_TEXT_UNDO_H__ +#define __GIMP_TEXT_UNDO_H__ + + +#include "core/gimpitemundo.h" + + +#define GIMP_TYPE_TEXT_UNDO (gimp_text_undo_get_type ()) +#define GIMP_TEXT_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TEXT_UNDO, GimpTextUndo)) +#define GIMP_TEXT_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TEXT_UNDO, GimpTextUndoClass)) +#define GIMP_IS_TEXT_UNDO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TEXT_UNDO)) +#define GIMP_IS_TEXT_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TEXT_UNDO)) +#define GIMP_TEXT_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TEXT_UNDO, GimpTextUndoClass)) + + +typedef struct _GimpTextUndoClass GimpTextUndoClass; + +struct _GimpTextUndo +{ + GimpItemUndo parent_instance; + + GimpText *text; + const GParamSpec *pspec; + GValue *value; + gboolean modified; + const Babl *format; +}; + +struct _GimpTextUndoClass +{ + GimpItemClass parent_class; +}; + + +GType gimp_text_undo_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_TEXT_UNDO_H__ */ diff --git a/app/text/text-enums.c b/app/text/text-enums.c new file mode 100644 index 0000000..cc18ec9 --- /dev/null +++ b/app/text/text-enums.c @@ -0,0 +1,73 @@ + +/* Generated data (by gimp-mkenums) */ + +#include "config.h" +#include <gio/gio.h> +#include "libgimpbase/gimpbase.h" +#include "text-enums.h" +#include "gimp-intl.h" + +/* enumerations from "text-enums.h" */ +GType +gimp_text_box_mode_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_TEXT_BOX_DYNAMIC, "GIMP_TEXT_BOX_DYNAMIC", "dynamic" }, + { GIMP_TEXT_BOX_FIXED, "GIMP_TEXT_BOX_FIXED", "fixed" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_TEXT_BOX_DYNAMIC, NC_("text-box-mode", "Dynamic"), NULL }, + { GIMP_TEXT_BOX_FIXED, NC_("text-box-mode", "Fixed"), NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_enum_register_static ("GimpTextBoxMode", values); + gimp_type_set_translation_context (type, "text-box-mode"); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} + +GType +gimp_text_outline_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_TEXT_OUTLINE_NONE, "GIMP_TEXT_OUTLINE_NONE", "none" }, + { GIMP_TEXT_OUTLINE_STROKE_ONLY, "GIMP_TEXT_OUTLINE_STROKE_ONLY", "stroke-only" }, + { GIMP_TEXT_OUTLINE_STROKE_FILL, "GIMP_TEXT_OUTLINE_STROKE_FILL", "stroke-fill" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_TEXT_OUTLINE_NONE, "GIMP_TEXT_OUTLINE_NONE", NULL }, + { GIMP_TEXT_OUTLINE_STROKE_ONLY, "GIMP_TEXT_OUTLINE_STROKE_ONLY", NULL }, + { GIMP_TEXT_OUTLINE_STROKE_FILL, "GIMP_TEXT_OUTLINE_STROKE_FILL", NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_enum_register_static ("GimpTextOutline", values); + gimp_type_set_translation_context (type, "text-outline"); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} + + +/* Generated data ends here */ + diff --git a/app/text/text-enums.h b/app/text/text-enums.h new file mode 100644 index 0000000..20bd327 --- /dev/null +++ b/app/text/text-enums.h @@ -0,0 +1,45 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __TEXT_ENUMS_H__ +#define __TEXT_ENUMS_H__ + + +#define GIMP_TYPE_TEXT_BOX_MODE (gimp_text_box_mode_get_type ()) + +GType gimp_text_box_mode_get_type (void) G_GNUC_CONST; + +typedef enum +{ + GIMP_TEXT_BOX_DYNAMIC, /*< desc="Dynamic" >*/ + GIMP_TEXT_BOX_FIXED /*< desc="Fixed" >*/ +} GimpTextBoxMode; + + +#define GIMP_TYPE_TEXT_OUTLINE (gimp_text_outline_get_type ()) + +GType gimp_text_outline_get_type (void) G_GNUC_CONST; + +typedef enum +{ + GIMP_TEXT_OUTLINE_NONE, + GIMP_TEXT_OUTLINE_STROKE_ONLY, + GIMP_TEXT_OUTLINE_STROKE_FILL +} GimpTextOutline; + + +#endif /* __TEXT_ENUMS_H__ */ diff --git a/app/text/text-types.h b/app/text/text-types.h new file mode 100644 index 0000000..83b6190 --- /dev/null +++ b/app/text/text-types.h @@ -0,0 +1,38 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * GimpText + * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#ifndef __TEXT_TYPES_H__ +#define __TEXT_TYPES_H__ + +#include "core/core-types.h" + +#include "text/text-enums.h" + + +typedef struct _GimpFont GimpFont; +typedef struct _GimpFontFactory GimpFontFactory; +typedef struct _GimpFontList GimpFontList; +typedef struct _GimpText GimpText; +typedef struct _GimpTextLayer GimpTextLayer; +typedef struct _GimpTextLayout GimpTextLayout; +typedef struct _GimpTextUndo GimpTextUndo; + + +#endif /* __TEXT_TYPES_H__ */ |