Initial checkin of Pika from heckimp
This commit is contained in:
47
app/text/meson.build
Normal file
47
app/text/meson.build
Normal file
@ -0,0 +1,47 @@
|
||||
stamp_text_enums = custom_target('stamp-text-enums.h',
|
||||
input : [
|
||||
files(
|
||||
'text-enums.h'
|
||||
),
|
||||
],
|
||||
output: [ 'stamp-text-enums.h', ],
|
||||
command: [
|
||||
mkenums_wrap, perl,
|
||||
meson.project_source_root(), meson.current_source_dir(),
|
||||
meson.current_build_dir(),
|
||||
'text-',
|
||||
'#include <gio/gio.h>\n' +
|
||||
'#include "libpikabase/pikabase.h"\n',
|
||||
'#include "pika-intl.h"'
|
||||
],
|
||||
build_by_default: true
|
||||
)
|
||||
|
||||
libapptext_sources = [
|
||||
'pikafont.c',
|
||||
'pikafontfactory.c',
|
||||
'pikatext-compat.c',
|
||||
'pikatext-parasite.c',
|
||||
'pikatext-vectors.c',
|
||||
'pikatext-xlfd.c',
|
||||
'pikatext.c',
|
||||
'pikatextlayer-transform.c',
|
||||
'pikatextlayer-xcf.c',
|
||||
'pikatextlayer.c',
|
||||
'pikatextlayout-render.c',
|
||||
'pikatextlayout.c',
|
||||
'pikatextundo.c',
|
||||
|
||||
'text-enums.c',
|
||||
stamp_text_enums
|
||||
]
|
||||
|
||||
|
||||
libapptext = static_library('apptext',
|
||||
libapptext_sources,
|
||||
include_directories: [ rootInclude, rootAppInclude, ],
|
||||
c_args: '-DG_LOG_DOMAIN="Pika-Text"',
|
||||
dependencies: [
|
||||
gegl, gdk_pixbuf, harfbuzz, pangocairo, pangoft2,
|
||||
],
|
||||
)
|
1298
app/text/pikafont.c
Normal file
1298
app/text/pikafont.c
Normal file
File diff suppressed because it is too large
Load Diff
75
app/text/pikafont.h
Normal file
75
app/text/pikafont.h
Normal file
@ -0,0 +1,75 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikafont.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 __PIKA_FONT_H__
|
||||
#define __PIKA_FONT_H__
|
||||
|
||||
|
||||
#include "core/pikadata.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_FONT (pika_font_get_type ())
|
||||
#define PIKA_FONT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FONT, PikaFont))
|
||||
#define PIKA_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FONT, PikaFontClass))
|
||||
#define PIKA_IS_FONT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_FONT))
|
||||
#define PIKA_IS_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FONT))
|
||||
#define PIKA_FONT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FONT, PikaFontClass))
|
||||
|
||||
|
||||
typedef struct _PikaFontClass PikaFontClass;
|
||||
|
||||
GType pika_font_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaData * pika_font_get_standard (void);
|
||||
const gchar * pika_font_get_lookup_name (PikaFont *font);
|
||||
void pika_font_set_lookup_name (PikaFont *font,
|
||||
gchar *name);
|
||||
gboolean pika_font_match_by_lookup_name (PikaFont *font,
|
||||
const gchar *name);
|
||||
void pika_font_set_font_info (PikaFont *font,
|
||||
gpointer font_info[]);
|
||||
void pika_font_class_set_font_factory (PikaContainer *factory);
|
||||
|
||||
enum
|
||||
{
|
||||
/* properties for serialization*/
|
||||
PROP_HASH,
|
||||
PROP_FULLNAME,
|
||||
PROP_FAMILY,
|
||||
PROP_STYLE,
|
||||
PROP_PSNAME,
|
||||
PROP_WEIGHT,
|
||||
PROP_WIDTH,
|
||||
PROP_INDEX,
|
||||
PROP_SLANT,
|
||||
PROP_FONTVERSION,
|
||||
|
||||
/*for backward compatibility*/
|
||||
PROP_DESC,
|
||||
|
||||
PROPERTIES_COUNT
|
||||
};
|
||||
|
||||
#endif /* __PIKA_FONT_H__ */
|
899
app/text/pikafontfactory.c
Normal file
899
app/text/pikafontfactory.c
Normal file
@ -0,0 +1,899 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikafontfactory.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 "libpikabase/pikabase.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "text-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pika-parallel.h"
|
||||
#include "core/pikaasync.h"
|
||||
#include "core/pikaasyncset.h"
|
||||
#include "core/pikacancelable.h"
|
||||
#include "core/pikacontainer.h"
|
||||
|
||||
#include "pikafont.h"
|
||||
#include "pikafontfactory.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
#define CONF_FNAME "fonts.conf"
|
||||
|
||||
|
||||
struct _PikaFontFactoryPrivate
|
||||
{
|
||||
gpointer foo; /* can't have an empty struct */
|
||||
};
|
||||
|
||||
#define GET_PRIVATE(obj) (((PikaFontFactory *) (obj))->priv)
|
||||
|
||||
|
||||
static void pika_font_factory_data_init (PikaDataFactory *factory,
|
||||
PikaContext *context);
|
||||
static void pika_font_factory_data_refresh (PikaDataFactory *factory,
|
||||
PikaContext *context);
|
||||
static void pika_font_factory_data_save (PikaDataFactory *factory);
|
||||
static void pika_font_factory_data_cancel (PikaDataFactory *factory);
|
||||
static PikaData * pika_font_factory_data_duplicate (PikaDataFactory *factory,
|
||||
PikaData *data);
|
||||
static gboolean pika_font_factory_data_delete (PikaDataFactory *factory,
|
||||
PikaData *data,
|
||||
gboolean delete_from_disk,
|
||||
GError **error);
|
||||
|
||||
static void pika_font_factory_load (PikaFontFactory *factory,
|
||||
GError **error);
|
||||
static gboolean pika_font_factory_load_fonts_conf (FcConfig *config,
|
||||
GFile *fonts_conf);
|
||||
static void pika_font_factory_add_directories (FcConfig *config,
|
||||
GList *path,
|
||||
GError **error);
|
||||
static void pika_font_factory_recursive_add_fontdir
|
||||
(FcConfig *config,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
static void pika_font_factory_load_names (PikaContainer *container,
|
||||
PangoFontMap *fontmap,
|
||||
PangoContext *context);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaFontFactory, pika_font_factory,
|
||||
PIKA_TYPE_DATA_FACTORY)
|
||||
|
||||
#define parent_class pika_font_factory_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_font_factory_class_init (PikaFontFactoryClass *klass)
|
||||
{
|
||||
PikaDataFactoryClass *factory_class = PIKA_DATA_FACTORY_CLASS (klass);
|
||||
|
||||
factory_class->data_init = pika_font_factory_data_init;
|
||||
factory_class->data_refresh = pika_font_factory_data_refresh;
|
||||
factory_class->data_save = pika_font_factory_data_save;
|
||||
factory_class->data_cancel = pika_font_factory_data_cancel;
|
||||
factory_class->data_duplicate = pika_font_factory_data_duplicate;
|
||||
factory_class->data_delete = pika_font_factory_data_delete;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_font_factory_init (PikaFontFactory *factory)
|
||||
{
|
||||
factory->priv = pika_font_factory_get_instance_private (factory);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_font_factory_data_init (PikaDataFactory *factory,
|
||||
PikaContext *context)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
pika_font_factory_load (PIKA_FONT_FACTORY (factory), &error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
pika_message_literal (pika_data_factory_get_pika (factory), NULL,
|
||||
PIKA_MESSAGE_INFO,
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_font_factory_data_refresh (PikaDataFactory *factory,
|
||||
PikaContext *context)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
pika_font_factory_load (PIKA_FONT_FACTORY (factory), &error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
pika_message_literal (pika_data_factory_get_pika (factory), NULL,
|
||||
PIKA_MESSAGE_INFO,
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_font_factory_data_save (PikaDataFactory *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 (! pika_async_set_is_empty (pika_data_factory_get_async_set (factory)))
|
||||
return;
|
||||
|
||||
/* Reinit the library with defaults. */
|
||||
FcInitReinitialize ();
|
||||
}
|
||||
|
||||
static void
|
||||
pika_font_factory_data_cancel (PikaDataFactory *factory)
|
||||
{
|
||||
PikaAsyncSet *async_set = pika_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
|
||||
* pika_font_factory_load_async_callback() that loading was canceled and the
|
||||
* factory might be dead, and that it should just do nothing.
|
||||
*/
|
||||
pika_cancelable_cancel (PIKA_CANCELABLE (async_set));
|
||||
pika_async_set_clear (async_set);
|
||||
}
|
||||
|
||||
static PikaData *
|
||||
pika_font_factory_data_duplicate (PikaDataFactory *factory,
|
||||
PikaData *data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_font_factory_data_delete (PikaDataFactory *factory,
|
||||
PikaData *data,
|
||||
gboolean delete_from_disk,
|
||||
GError **error)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
PikaDataFactory *
|
||||
pika_font_factory_new (Pika *pika,
|
||||
const gchar *path_property_name)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (path_property_name != NULL, NULL);
|
||||
|
||||
return g_object_new (PIKA_TYPE_FONT_FACTORY,
|
||||
"pika", pika,
|
||||
"data-type", PIKA_TYPE_FONT,
|
||||
"path-property-name", path_property_name,
|
||||
"get-standard-func", pika_font_get_standard,
|
||||
"unique-names", FALSE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_font_factory_load_async (PikaAsync *async,
|
||||
FcConfig *config)
|
||||
{
|
||||
if (FcConfigBuildFonts (config))
|
||||
{
|
||||
pika_async_finish (async, config);
|
||||
}
|
||||
else
|
||||
{
|
||||
FcConfigDestroy (config);
|
||||
|
||||
pika_async_abort (async);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_font_factory_load_async_callback (PikaAsync *async,
|
||||
PikaFontFactory *factory)
|
||||
{
|
||||
PikaContainer *container;
|
||||
|
||||
/* the operation was canceled and the factory might be dead (see
|
||||
* pika_font_factory_data_cancel()). bail.
|
||||
*/
|
||||
if (pika_async_is_canceled (async))
|
||||
return;
|
||||
|
||||
container = pika_data_factory_get_container (PIKA_DATA_FACTORY (factory));
|
||||
|
||||
if (pika_async_is_finished (async))
|
||||
{
|
||||
FcConfig *config = pika_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);
|
||||
|
||||
pika_font_factory_load_names (container, PANGO_FONT_MAP (fontmap), context);
|
||||
g_object_unref (context);
|
||||
FcConfigDestroy (config);
|
||||
}
|
||||
|
||||
pika_container_thaw (container);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_font_factory_load (PikaFontFactory *factory,
|
||||
GError **error)
|
||||
{
|
||||
PikaContainer *container;
|
||||
Pika *pika;
|
||||
PikaAsyncSet *async_set;
|
||||
FcConfig *config;
|
||||
GFile *fonts_conf;
|
||||
GList *path;
|
||||
PikaAsync *async;
|
||||
|
||||
async_set = pika_data_factory_get_async_set (PIKA_DATA_FACTORY (factory));
|
||||
|
||||
if (! pika_async_set_is_empty (async_set))
|
||||
{
|
||||
/* font loading is already in progress */
|
||||
return;
|
||||
}
|
||||
|
||||
container = pika_data_factory_get_container (PIKA_DATA_FACTORY (factory));
|
||||
|
||||
pika = pika_data_factory_get_pika (PIKA_DATA_FACTORY (factory));
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Loading fonts\n");
|
||||
|
||||
config = FcInitLoadConfig ();
|
||||
|
||||
if (! config)
|
||||
return;
|
||||
|
||||
fonts_conf = pika_directory_file (CONF_FNAME, NULL);
|
||||
if (! pika_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 = pika_sysconf_directory_file (CONF_FNAME, NULL);
|
||||
if (! pika_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 = pika_data_factory_get_data_path (PIKA_DATA_FACTORY (factory));
|
||||
if (! path)
|
||||
return;
|
||||
|
||||
pika_container_freeze (container);
|
||||
pika_container_clear (container);
|
||||
|
||||
pika_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 = pika_parallel_run_async_independent_full (
|
||||
+10,
|
||||
(PikaRunAsyncFunc) pika_font_factory_load_async,
|
||||
config);
|
||||
|
||||
pika_async_add_callback_for_object (
|
||||
async,
|
||||
(PikaAsyncCallback) pika_font_factory_load_async_callback,
|
||||
factory,
|
||||
factory);
|
||||
|
||||
pika_async_set_add (async_set, async);
|
||||
|
||||
g_object_unref (async);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_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
|
||||
pika_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.
|
||||
*/
|
||||
pika_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
|
||||
pika_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)
|
||||
{
|
||||
pika_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
|
||||
pika_font_factory_add_font (PikaContainer *container,
|
||||
PangoContext *context,
|
||||
PangoFontDescription *desc,
|
||||
const gchar *full_name,
|
||||
const gchar *path,
|
||||
gpointer font_info[])
|
||||
{
|
||||
gchar *name = (gchar *) full_name;
|
||||
|
||||
if (! desc && ! full_name)
|
||||
return;
|
||||
|
||||
if (! full_name)
|
||||
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))
|
||||
{
|
||||
PikaFont *font;
|
||||
|
||||
font = g_object_new (PIKA_TYPE_FONT,
|
||||
"name", name,
|
||||
"pango-context", context,
|
||||
NULL);
|
||||
pika_font_set_lookup_name (font, pango_font_description_to_string (desc));
|
||||
|
||||
if (font_info != NULL)
|
||||
pika_font_set_font_info (font, font_info);
|
||||
|
||||
if (path != NULL)
|
||||
{
|
||||
GFile *file;
|
||||
|
||||
file = g_file_new_for_path (path);
|
||||
pika_data_set_file (PIKA_DATA (font), file, FALSE, FALSE);
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_data_make_internal (PIKA_DATA (font), "pika-font-standard-alias");
|
||||
}
|
||||
|
||||
pika_container_add (container, PIKA_OBJECT (font));
|
||||
g_object_unref (font);
|
||||
}
|
||||
|
||||
if (!full_name)
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
/* We're really chummy here with the implementation. Oh well. */
|
||||
|
||||
/* This is copied straight from make_alias_description in pango, plus
|
||||
* the pika_font_list_add_font bits.
|
||||
*/
|
||||
static void
|
||||
pika_font_factory_make_alias (PikaContainer *container,
|
||||
PangoContext *context,
|
||||
const gchar *family,
|
||||
gboolean bold,
|
||||
gboolean italic)
|
||||
{
|
||||
FcPattern *fcpattern;
|
||||
PangoFontDescription *desc = pango_font_description_new ();
|
||||
gchar *desc_str = NULL;
|
||||
gchar *style = NULL;
|
||||
gchar *psname = NULL;
|
||||
gchar *fullname = NULL;
|
||||
gint index = -1;
|
||||
gint weight = -1;
|
||||
gint width = -1;
|
||||
gint slant = -1;
|
||||
gint fontversion = -1;
|
||||
gpointer font_info[PROPERTIES_COUNT];
|
||||
|
||||
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);
|
||||
|
||||
fcpattern = pango_fc_font_get_pattern (PANGO_FC_FONT (pango_context_load_font (context, desc)));
|
||||
|
||||
/* this is for backward compatibility*/
|
||||
desc_str = pango_font_description_to_string (desc);
|
||||
|
||||
FcPatternGetString (fcpattern, FC_FULLNAME, 0, (FcChar8 **) &fullname);
|
||||
FcPatternGetString (fcpattern, FC_POSTSCRIPT_NAME, 0, (FcChar8 **) &psname);
|
||||
FcPatternGetString (fcpattern, FC_STYLE, 0, (FcChar8 **) &style);
|
||||
FcPatternGetInteger (fcpattern, FC_WEIGHT, 0, &weight);
|
||||
FcPatternGetInteger (fcpattern, FC_WIDTH, 0, &width);
|
||||
FcPatternGetInteger (fcpattern, FC_INDEX, 0, &index);
|
||||
FcPatternGetInteger (fcpattern, FC_SLANT, 0, &slant);
|
||||
FcPatternGetInteger (fcpattern, FC_FONTVERSION, 0, &fontversion);
|
||||
|
||||
font_info[PROP_DESC] = (gpointer) desc_str;
|
||||
font_info[PROP_FULLNAME] = (gpointer) fullname;
|
||||
font_info[PROP_FAMILY] = (gpointer) family;
|
||||
font_info[PROP_STYLE] = (gpointer) style;
|
||||
font_info[PROP_PSNAME] = (gpointer) psname;
|
||||
font_info[PROP_WEIGHT] = (gpointer) &weight;
|
||||
font_info[PROP_WIDTH] = (gpointer) &width;
|
||||
font_info[PROP_INDEX] = (gpointer) &index;
|
||||
font_info[PROP_SLANT] = (gpointer) &slant;
|
||||
font_info[PROP_FONTVERSION] = (gpointer) &fontversion;
|
||||
|
||||
/* This might be the only valid time where a NULL path is valid. Though I do
|
||||
* wonder if really these aliases are the right thing to do. Generic aliases
|
||||
* are the best way to have differing text renders over time (and that's not
|
||||
* something to be wished for). XXX
|
||||
*/
|
||||
pika_font_factory_add_font (container, context, desc, NULL, NULL, font_info);
|
||||
|
||||
g_free (desc_str);
|
||||
pango_font_description_free (desc);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_font_factory_load_aliases (PikaContainer *container,
|
||||
PangoContext *context)
|
||||
{
|
||||
const gchar *families[] = { "Sans-serif", "Serif", "Monospace" };
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
pika_font_factory_make_alias (container, context, families[i],
|
||||
FALSE, FALSE);
|
||||
pika_font_factory_make_alias (container, context, families[i],
|
||||
TRUE, FALSE);
|
||||
pika_font_factory_make_alias (container, context, families[i],
|
||||
FALSE, TRUE);
|
||||
pika_font_factory_make_alias (container, context, families[i],
|
||||
TRUE, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_font_factory_load_names (PikaContainer *container,
|
||||
PangoFontMap *fontmap,
|
||||
PangoContext *context)
|
||||
{
|
||||
FcObjectSet *os;
|
||||
FcPattern *pat;
|
||||
FcFontSet *fontset;
|
||||
GString *ignored_fonts;
|
||||
gint n_ignored = 0;
|
||||
gint i;
|
||||
|
||||
os = FcObjectSetBuild (FC_FAMILY,
|
||||
FC_STYLE,
|
||||
FC_POSTSCRIPT_NAME,
|
||||
FC_FULLNAME,
|
||||
FC_FILE,
|
||||
FC_WEIGHT,
|
||||
FC_SLANT,
|
||||
FC_WIDTH,
|
||||
FC_INDEX,
|
||||
FC_FONTVERSION,
|
||||
FC_FONTFORMAT,
|
||||
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);
|
||||
ignored_fonts = g_string_new (NULL);
|
||||
|
||||
FcPatternDestroy (pat);
|
||||
FcObjectSetDestroy (os);
|
||||
|
||||
g_return_if_fail (fontset);
|
||||
|
||||
for (i = 0; i < fontset->nfont; i++)
|
||||
{
|
||||
PangoFontDescription *pfd;
|
||||
GString *xml;
|
||||
gchar *fontformat;
|
||||
gchar *family = NULL;
|
||||
gchar *style = NULL;
|
||||
gchar *psname = NULL;
|
||||
gchar *newname = NULL;
|
||||
gchar *escaped_fullname = NULL;
|
||||
gchar *fullname = NULL;
|
||||
gchar *fullname2 = NULL;
|
||||
gchar *escaped_file = NULL;
|
||||
gchar *file = NULL;
|
||||
gint index = -1;
|
||||
gint weight = -1;
|
||||
gint width = -1;
|
||||
gint slant = -1;
|
||||
gint fontversion = -1;
|
||||
gpointer font_info[PROPERTIES_COUNT];
|
||||
PangoFontDescription *pattern_pfd;
|
||||
gchar *pattern_pfd_desc;
|
||||
|
||||
FcPatternGetString (fontset->fonts[i], FC_FILE, 0, (FcChar8 **) &file);
|
||||
|
||||
/*
|
||||
* woff and woff2 cause problems with pango (probably with harfbuzz).
|
||||
* pcf,pcf.gz are bitmap font formats, not supported by pango (because of harfbuzz).
|
||||
* afm, pfm, pfb are type1 font formats, not supported by pango (because of harfbuzz).
|
||||
*/
|
||||
if (g_str_has_suffix (file, ".woff") ||
|
||||
g_str_has_suffix (file, ".woff2") ||
|
||||
g_str_has_suffix (file, ".pcf") ||
|
||||
g_str_has_suffix (file, ".pcf.gz") ||
|
||||
g_str_has_suffix (file, ".afm") ||
|
||||
g_str_has_suffix (file, ".pfm") ||
|
||||
g_str_has_suffix (file, ".pfb"))
|
||||
{
|
||||
g_string_append_printf (ignored_fonts, "- %s (not supported by pango)\n", file);
|
||||
n_ignored++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Pango doesn't support non SFNT fonts because harfbuzz doesn't support them. */
|
||||
if (FcPatternGetString (fontset->fonts[i], FC_FONTFORMAT, 0, (FcChar8 **) &fontformat) != FcResultMatch ||
|
||||
(g_ascii_strcasecmp (fontformat, "TrueType") != 0 &&
|
||||
g_ascii_strcasecmp (fontformat, "CFF") != 0))
|
||||
{
|
||||
g_string_append_printf (ignored_fonts, "- %s (non-SFNT font)\n", file);
|
||||
n_ignored++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Some variable fonts have only a family name and a font version. */
|
||||
if (FcPatternGetString (fontset->fonts[i], FC_FULLNAME, 0, (FcChar8 **) &fullname) != FcResultMatch)
|
||||
{
|
||||
g_string_append_printf (ignored_fonts, "- %s (no full name)\n", file);
|
||||
n_ignored++;
|
||||
continue;
|
||||
}
|
||||
|
||||
FcPatternGetString (fontset->fonts[i], FC_FAMILY, 0, (FcChar8 **) &family);
|
||||
FcPatternGetString (fontset->fonts[i], FC_POSTSCRIPT_NAME, 0, (FcChar8 **) &psname);
|
||||
FcPatternGetString (fontset->fonts[i], FC_STYLE, 0, (FcChar8 **) &style);
|
||||
FcPatternGetInteger (fontset->fonts[i], FC_WEIGHT, 0, &weight);
|
||||
FcPatternGetInteger (fontset->fonts[i], FC_WIDTH, 0, &width);
|
||||
FcPatternGetInteger (fontset->fonts[i], FC_INDEX, 0, &index);
|
||||
FcPatternGetInteger (fontset->fonts[i], FC_SLANT, 0, &slant);
|
||||
FcPatternGetInteger (fontset->fonts[i], FC_FONTVERSION, 0, &fontversion);
|
||||
|
||||
/* this is for backward compatibility*/
|
||||
pattern_pfd = pango_fc_font_description_from_pattern (fontset->fonts[i], FALSE);
|
||||
pattern_pfd_desc = pango_font_description_to_string (pattern_pfd);
|
||||
|
||||
font_info[PROP_DESC] = (gpointer) pattern_pfd_desc;
|
||||
font_info[PROP_FULLNAME] = (gpointer) fullname;
|
||||
font_info[PROP_FAMILY] = (gpointer) family;
|
||||
font_info[PROP_STYLE] = (gpointer) style;
|
||||
font_info[PROP_PSNAME] = (gpointer) psname;
|
||||
font_info[PROP_WEIGHT] = (gpointer) &weight;
|
||||
font_info[PROP_WIDTH] = (gpointer) &width;
|
||||
font_info[PROP_INDEX] = (gpointer) &index;
|
||||
font_info[PROP_SLANT] = (gpointer) &slant;
|
||||
font_info[PROP_FONTVERSION] = (gpointer) &fontversion;
|
||||
|
||||
/* Sometimes a font has more than one fullname,
|
||||
* sometimes the second is more appropriate for display,
|
||||
* in such cases we use it instead of the first.
|
||||
*/
|
||||
if (FcPatternGetString (fontset->fonts[i], FC_FULLNAME, 1, (FcChar8 **) &fullname2) != FcResultMatch)
|
||||
fullname2 = NULL;
|
||||
|
||||
newname = g_strdup_printf ("pikafont%i", i);
|
||||
|
||||
xml = g_string_new ("<?xml version=\"1.0\"?>\n<match>");
|
||||
|
||||
g_string_append_printf (xml,
|
||||
"<test name=\"family\"><string>%s</string></test>",
|
||||
newname);
|
||||
|
||||
escaped_fullname = g_markup_escape_text (fullname, -1);
|
||||
g_string_append_printf (xml,
|
||||
"<edit name=\"fullname\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
|
||||
escaped_fullname);
|
||||
g_free (escaped_fullname);
|
||||
|
||||
family = g_markup_escape_text (family, -1);
|
||||
g_string_append_printf (xml,
|
||||
"<edit name=\"family\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
|
||||
family);
|
||||
g_free (family);
|
||||
|
||||
escaped_file = g_markup_escape_text (file, -1);
|
||||
g_string_append_printf (xml,
|
||||
"<edit name=\"file\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
|
||||
escaped_file);
|
||||
g_free (escaped_file);
|
||||
|
||||
if (psname != NULL)
|
||||
{
|
||||
psname = g_markup_escape_text (psname, -1);
|
||||
g_string_append_printf (xml,
|
||||
"<edit name=\"postscriptname\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
|
||||
psname);
|
||||
g_free (psname);
|
||||
}
|
||||
|
||||
if (style != NULL)
|
||||
{
|
||||
style = g_markup_escape_text (style, -1);
|
||||
g_string_append_printf (xml,
|
||||
"<edit name=\"style\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
|
||||
style);
|
||||
g_free (style);
|
||||
}
|
||||
|
||||
if (weight != -1)
|
||||
g_string_append_printf (xml,
|
||||
"<edit name=\"weight\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
|
||||
weight);
|
||||
|
||||
if (width != -1)
|
||||
g_string_append_printf (xml,
|
||||
"<edit name=\"width\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
|
||||
width);
|
||||
|
||||
if (slant != -1)
|
||||
g_string_append_printf (xml,
|
||||
"<edit name=\"slant\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
|
||||
slant);
|
||||
|
||||
if (fontversion != -1)
|
||||
g_string_append_printf (xml,
|
||||
"<edit name=\"fontversion\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
|
||||
fontversion);
|
||||
|
||||
if (index != -1)
|
||||
g_string_append_printf (xml,
|
||||
"<edit name=\"index\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
|
||||
index);
|
||||
|
||||
g_string_append (xml, "</match>\n");
|
||||
|
||||
FcConfigParseAndLoadFromMemory (FcConfigGetCurrent (), (const FcChar8 *) xml->str, FcTrue);
|
||||
|
||||
pfd = pango_font_description_from_string (newname);
|
||||
|
||||
if (fullname2 != NULL && g_str_is_ascii (fullname2))
|
||||
fullname = fullname2;
|
||||
|
||||
pika_font_factory_add_font (container, context, pfd, fullname, (const gchar *) file, font_info);
|
||||
|
||||
pango_font_description_free (pattern_pfd);
|
||||
g_free (pattern_pfd_desc);
|
||||
pango_font_description_free (pfd);
|
||||
g_free (newname);
|
||||
g_string_free (xml, TRUE);
|
||||
}
|
||||
|
||||
if (n_ignored > 0)
|
||||
{
|
||||
if (g_getenv ("PIKA_DEBUG_FONTS") == NULL)
|
||||
g_printerr ("%s: %d unsupported fonts were ignored. Set the PIKA_DEBUG_FONTS environment variable for a listing.\n", G_STRFUNC, n_ignored);
|
||||
else
|
||||
g_printerr ("%s: %d unsupported fonts were ignored: %s", G_STRFUNC, n_ignored, ignored_fonts->str);
|
||||
}
|
||||
|
||||
g_string_free (ignored_fonts, TRUE);
|
||||
|
||||
/* only create aliases if there is at least one font available */
|
||||
if (fontset->nfont > 0)
|
||||
pika_font_factory_load_aliases (container, context);
|
||||
|
||||
FcFontSetDestroy (fontset);
|
||||
|
||||
pika_font_class_set_font_factory (container);
|
||||
}
|
62
app/text/pikafontfactory.h
Normal file
62
app/text/pikafontfactory.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikafontfactory.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 __PIKA_FONT_FACTORY_H__
|
||||
#define __PIKA_FONT_FACTORY_H__
|
||||
|
||||
|
||||
#include "core/pikadatafactory.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_FONT_FACTORY (pika_font_factory_get_type ())
|
||||
#define PIKA_FONT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FONT_FACTORY, PikaFontFactory))
|
||||
#define PIKA_FONT_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FONT_FACTORY, PikaFontFactoryClass))
|
||||
#define PIKA_IS_FONT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_FONT_FACTORY))
|
||||
#define PIKA_IS_FONT_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FONT_FACTORY))
|
||||
#define PIKA_FONT_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FONT_FACTORY, PikaFontFactoryClass))
|
||||
|
||||
|
||||
typedef struct _PikaFontFactoryPrivate PikaFontFactoryPrivate;
|
||||
typedef struct _PikaFontFactoryClass PikaFontFactoryClass;
|
||||
|
||||
struct _PikaFontFactory
|
||||
{
|
||||
PikaDataFactory parent_instance;
|
||||
|
||||
PikaFontFactoryPrivate *priv;
|
||||
};
|
||||
|
||||
struct _PikaFontFactoryClass
|
||||
{
|
||||
PikaDataFactoryClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_font_factory_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaDataFactory * pika_font_factory_new (Pika *pika,
|
||||
const gchar *path_property_name);
|
||||
|
||||
|
||||
#endif /* __PIKA_FONT_FACTORY_H__ */
|
211
app/text/pikatext-compat.c
Normal file
211
app/text/pikatext-compat.c
Normal file
@ -0,0 +1,211 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 "libpikacolor/pikacolor.h"
|
||||
|
||||
#include "text-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikachannel.h"
|
||||
#include "core/pikacontext.h"
|
||||
#include "core/pikadatafactory.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikadrawable.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikaimage-undo.h"
|
||||
#include "core/pikalayer-floating-selection.h"
|
||||
|
||||
#include "pikatext.h"
|
||||
#include "pikatext-compat.h"
|
||||
#include "pikatextlayer.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
PikaLayer *
|
||||
text_render (PikaImage *image,
|
||||
PikaDrawable *drawable,
|
||||
PikaContext *context,
|
||||
gint text_x,
|
||||
gint text_y,
|
||||
const gchar *fontname,
|
||||
const gchar *text,
|
||||
gint border,
|
||||
gboolean antialias)
|
||||
{
|
||||
PangoFontDescription *desc;
|
||||
PikaText *gtext;
|
||||
PikaLayer *layer;
|
||||
PikaRGB color;
|
||||
gchar *font;
|
||||
gdouble size;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
|
||||
g_return_val_if_fail (drawable == NULL || PIKA_IS_DRAWABLE (drawable), NULL);
|
||||
g_return_val_if_fail (drawable == NULL ||
|
||||
pika_item_is_attached (PIKA_ITEM (drawable)), NULL);
|
||||
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
|
||||
g_return_val_if_fail (fontname != NULL, NULL);
|
||||
g_return_val_if_fail (text != NULL, NULL);
|
||||
|
||||
if (! pika_data_factory_data_wait (image->pika->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);
|
||||
|
||||
pika_context_get_foreground (context, &color);
|
||||
|
||||
gtext = g_object_new (PIKA_TYPE_TEXT,
|
||||
"text", text,
|
||||
"font", font,
|
||||
"font-size", size,
|
||||
"antialias", antialias,
|
||||
"border", border,
|
||||
"color", &color,
|
||||
NULL);
|
||||
|
||||
g_free (font);
|
||||
|
||||
layer = pika_text_layer_new (image, gtext);
|
||||
|
||||
g_object_unref (gtext);
|
||||
|
||||
if (!layer)
|
||||
return NULL;
|
||||
|
||||
/* Start a group undo */
|
||||
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_TEXT,
|
||||
_("Add Text Layer"));
|
||||
|
||||
/* Set the layer offsets */
|
||||
pika_item_set_offset (PIKA_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 (! pika_channel_is_empty (pika_image_get_mask (image)))
|
||||
pika_channel_clear (pika_image_get_mask (image), NULL, TRUE);
|
||||
|
||||
if (drawable == NULL)
|
||||
{
|
||||
/* If the drawable is NULL, create a new layer */
|
||||
pika_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 */
|
||||
pika_image_undo_group_end (image);
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
gboolean
|
||||
text_get_extents (Pika *pika,
|
||||
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 (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (fontname != NULL, FALSE);
|
||||
g_return_val_if_fail (text != NULL, FALSE);
|
||||
|
||||
if (! pika_data_factory_data_wait (pika->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;
|
||||
}
|
49
app/text/pikatext-compat.h
Normal file
49
app/text/pikatext-compat.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 __PIKA_TEXT_COMPAT_H__
|
||||
#define __PIKA_TEXT_COMPAT_H__
|
||||
|
||||
|
||||
/* convenience functions that provide the 1.2 API, only used by the PDB */
|
||||
|
||||
PikaLayer * text_render (PikaImage *image,
|
||||
PikaDrawable *drawable,
|
||||
PikaContext *context,
|
||||
gint text_x,
|
||||
gint text_y,
|
||||
const gchar *fontname,
|
||||
const gchar *text,
|
||||
gint border,
|
||||
gboolean antialias);
|
||||
gboolean text_get_extents (Pika *pika,
|
||||
const gchar *fontname,
|
||||
const gchar *text,
|
||||
gint *width,
|
||||
gint *height,
|
||||
gint *ascent,
|
||||
gint *descent);
|
||||
|
||||
|
||||
#endif /* __PIKA_TEXT_COMPAT_H__ */
|
302
app/text/pikatext-parasite.c
Normal file
302
app/text/pikatext-parasite.c
Normal file
@ -0,0 +1,302 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 <pango/pango.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "text-types.h"
|
||||
|
||||
#include "core/pikaerror.h"
|
||||
|
||||
#include "pikafont.h"
|
||||
#include "pikatext.h"
|
||||
#include "pikatext-parasite.h"
|
||||
#include "pikatext-xlfd.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
/****************************************/
|
||||
/* The native PikaTextLayer parasite. */
|
||||
/****************************************/
|
||||
|
||||
const gchar *
|
||||
pika_text_parasite_name (void)
|
||||
{
|
||||
return "pika-text-layer";
|
||||
}
|
||||
|
||||
PikaParasite *
|
||||
pika_text_to_parasite (PikaText *text)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_TEXT (text), NULL);
|
||||
|
||||
return pika_config_serialize_to_parasite (PIKA_CONFIG (text),
|
||||
pika_text_parasite_name (),
|
||||
PIKA_PARASITE_PERSISTENT,
|
||||
NULL);
|
||||
}
|
||||
|
||||
PikaText *
|
||||
pika_text_from_parasite (const PikaParasite *parasite,
|
||||
Pika *pika,
|
||||
gboolean *before_xcf_v19,
|
||||
GError **error)
|
||||
{
|
||||
PikaText *text;
|
||||
gchar *parasite_data;
|
||||
guint32 parasite_data_size;
|
||||
|
||||
g_return_val_if_fail (parasite != NULL, NULL);
|
||||
g_return_val_if_fail (strcmp (pika_parasite_get_name (parasite),
|
||||
pika_text_parasite_name ()) == 0, NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
text = g_object_new (PIKA_TYPE_TEXT, "pika", pika, NULL);
|
||||
g_object_set (text, "font", pika_font_get_standard(), NULL);
|
||||
|
||||
parasite_data = (gchar *) pika_parasite_get_data (parasite, ¶site_data_size);
|
||||
if (parasite_data)
|
||||
{
|
||||
gboolean has_markup = g_str_has_prefix (parasite_data, "(markup ");
|
||||
PikaParasite *new_parasite = NULL;
|
||||
GString *new_data;
|
||||
|
||||
*before_xcf_v19 = (strstr (parasite_data, "(font \"PikaFont\"") == NULL);
|
||||
/* This is for backward compatibility with older xcf files.
|
||||
* font used to be serialized as a string, but now it is serialized/deserialized as
|
||||
* PikaFont, so the object Type name is inserted for the PikaFont deserialization function to be called.
|
||||
* And more importantly, fonts in the markup are extracted into their own fields for deserialization.
|
||||
*/
|
||||
if (*before_xcf_v19)
|
||||
{
|
||||
new_data = g_string_new (parasite_data);
|
||||
g_string_replace (new_data, "\")\n(font", "\")\n(font \"PikaFont\"", 1);
|
||||
|
||||
if (has_markup)
|
||||
{
|
||||
char *markup_start = strstr (parasite_data, "\"<");
|
||||
char *markup_end = strstr (parasite_data, ">\")");
|
||||
|
||||
if (markup_start != NULL && markup_end != NULL)
|
||||
{
|
||||
PangoAttrList *attr_list;
|
||||
gchar *desc;
|
||||
guint length;
|
||||
GSList *list = NULL;
|
||||
GSList *fonts = NULL;
|
||||
GString *markup_fonts = g_string_new (NULL);
|
||||
glong markup_start_pos;
|
||||
glong markup_end_pos;
|
||||
gchar *markup_str;
|
||||
GString *markup;
|
||||
|
||||
markup_start_pos = (glong) (markup_start - parasite_data) + 1;
|
||||
markup_end_pos = (glong) (markup_end - parasite_data) + 1;
|
||||
markup_str = g_utf8_substring (parasite_data, markup_start_pos, markup_end_pos);
|
||||
markup = g_string_new (markup_str);
|
||||
g_string_replace (markup, "\\\"", "\"", 0);
|
||||
pango_parse_markup (markup->str, -1, 0, &attr_list, NULL, NULL, NULL);
|
||||
|
||||
list = pango_attr_list_get_attributes (attr_list);
|
||||
length = g_slist_length (list);
|
||||
|
||||
for (guint i = 0; i < length; ++i)
|
||||
{
|
||||
PangoAttrFontDesc *attr_font_desc = pango_attribute_as_font_desc ((PangoAttribute*)g_slist_nth_data (list, i));
|
||||
|
||||
if (attr_font_desc != NULL)
|
||||
{
|
||||
desc = pango_font_description_to_string (attr_font_desc->desc);
|
||||
|
||||
if (g_slist_find_custom (fonts, (gconstpointer) desc, (GCompareFunc) g_strcmp0) == NULL)
|
||||
{
|
||||
fonts = g_slist_prepend (fonts, (gpointer) desc);
|
||||
/*duplicate font name to making parsing easier when deserializing*/
|
||||
g_string_append_printf (markup_fonts,
|
||||
"\n\"%s\" \"%s\"",
|
||||
desc, desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_free (desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
g_slist_free_full (fonts, (GDestroyNotify) g_free);
|
||||
g_slist_free_full (list, (GDestroyNotify) pango_attribute_destroy);
|
||||
pango_attr_list_unref (attr_list);
|
||||
|
||||
g_string_insert (new_data, markup_end_pos + 1, markup_fonts->str);
|
||||
|
||||
g_free (markup_str);
|
||||
g_string_free (markup_fonts, TRUE);
|
||||
g_string_free (markup, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We could not find the markup delimiters. */
|
||||
g_set_error_literal (error, PIKA_ERROR, PIKA_FAILED,
|
||||
_("Invalid markup format in text parasite"));
|
||||
}
|
||||
}
|
||||
|
||||
new_parasite = pika_parasite_new (pika_parasite_get_name (parasite),
|
||||
pika_parasite_get_flags (parasite),
|
||||
new_data->len+1,
|
||||
new_data->str);
|
||||
parasite = new_parasite;
|
||||
|
||||
g_string_free (new_data, TRUE);
|
||||
}
|
||||
|
||||
if (error == NULL || *error == NULL)
|
||||
pika_config_deserialize_parasite (PIKA_CONFIG (text),
|
||||
parasite,
|
||||
NULL,
|
||||
error);
|
||||
|
||||
pika_parasite_free (new_parasite);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error_literal (error, PIKA_ERROR, PIKA_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 *
|
||||
pika_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
|
||||
};
|
||||
|
||||
PikaText *
|
||||
pika_text_from_gdyntext_parasite (const PikaParasite *parasite)
|
||||
{
|
||||
PikaText *retval = NULL;
|
||||
PikaTextJustification justify;
|
||||
gchar *str;
|
||||
gchar *text = NULL;
|
||||
gchar **params;
|
||||
guint32 parasite_data_size;
|
||||
gboolean antialias;
|
||||
gdouble spacing;
|
||||
PikaRGB rgb;
|
||||
glong color;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (parasite != NULL, NULL);
|
||||
g_return_val_if_fail (strcmp (pika_parasite_get_name (parasite),
|
||||
pika_text_gdyntext_parasite_name ()) == 0,
|
||||
NULL);
|
||||
|
||||
str = (gchar *) pika_parasite_get_data (parasite, ¶site_data_size);
|
||||
str = g_strndup (str, parasite_data_size);
|
||||
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 = pika_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 = PIKA_TEXT_JUSTIFY_LEFT; break;
|
||||
case 1: justify = PIKA_TEXT_JUSTIFY_CENTER; break;
|
||||
case 2: justify = PIKA_TEXT_JUSTIFY_RIGHT; break;
|
||||
}
|
||||
|
||||
spacing = g_strtod (params[LINE_SPACING], NULL);
|
||||
|
||||
color = strtol (params[COLOR], NULL, 16);
|
||||
pika_rgba_set_uchar (&rgb, color >> 16, color >> 8, color, 255);
|
||||
|
||||
retval = g_object_new (PIKA_TYPE_TEXT,
|
||||
"text", text,
|
||||
"antialias", antialias,
|
||||
"justify", justify,
|
||||
"line-spacing", spacing,
|
||||
"color", &rgb,
|
||||
NULL);
|
||||
|
||||
pika_text_set_font_from_xlfd (PIKA_TEXT (retval), params[XLFD]);
|
||||
|
||||
cleanup:
|
||||
g_free (str);
|
||||
g_free (text);
|
||||
g_strfreev (params);
|
||||
|
||||
return retval;
|
||||
}
|
40
app/text/pikatext-parasite.h
Normal file
40
app/text/pikatext-parasite.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 __PIKA_TEXT_PARASITE_H__
|
||||
#define __PIKA_TEXT_PARASITE_H__
|
||||
|
||||
|
||||
const gchar * pika_text_parasite_name (void) G_GNUC_CONST;
|
||||
PikaParasite * pika_text_to_parasite (PikaText *text);
|
||||
PikaText * pika_text_from_parasite (const PikaParasite *parasite,
|
||||
Pika *pika,
|
||||
gboolean *before_xcf_v19,
|
||||
GError **error);
|
||||
|
||||
const gchar * pika_text_gdyntext_parasite_name (void) G_GNUC_CONST;
|
||||
PikaText * pika_text_from_gdyntext_parasite (const PikaParasite *parasite);
|
||||
|
||||
|
||||
#endif /* __PIKA_TEXT_PARASITE_H__ */
|
259
app/text/pikatext-vectors.c
Normal file
259
app/text/pikatext-vectors.c
Normal file
@ -0,0 +1,259 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText-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/pika.h"
|
||||
#include "core/pikaimage.h"
|
||||
|
||||
#include "vectors/pikabezierstroke.h"
|
||||
#include "vectors/pikavectors.h"
|
||||
#include "vectors/pikaanchor.h"
|
||||
|
||||
#include "pikatext.h"
|
||||
#include "pikatext-vectors.h"
|
||||
#include "pikatextlayout.h"
|
||||
#include "pikatextlayout-render.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PikaVectors *vectors;
|
||||
PikaStroke *stroke;
|
||||
PikaAnchor *anchor;
|
||||
} RenderContext;
|
||||
|
||||
|
||||
static void pika_text_render_vectors (cairo_t *cr,
|
||||
RenderContext *context);
|
||||
|
||||
|
||||
PikaVectors *
|
||||
pika_text_vectors_new (PikaImage *image,
|
||||
PikaText *text)
|
||||
{
|
||||
PikaVectors *vectors;
|
||||
RenderContext context = { NULL, };
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
|
||||
g_return_val_if_fail (PIKA_IS_TEXT (text), NULL);
|
||||
|
||||
vectors = pika_vectors_new (image, NULL);
|
||||
|
||||
if (text->text || text->markup)
|
||||
{
|
||||
PikaTextLayout *layout;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
gdouble xres;
|
||||
gdouble yres;
|
||||
GError *error = NULL;
|
||||
|
||||
if (text->text)
|
||||
pika_object_set_name_safe (PIKA_OBJECT (vectors), text->text);
|
||||
|
||||
context.vectors = vectors;
|
||||
|
||||
surface = cairo_recording_surface_create (CAIRO_CONTENT_ALPHA, NULL);
|
||||
cr = cairo_create (surface);
|
||||
|
||||
pika_image_get_resolution (image, &xres, &yres);
|
||||
|
||||
layout = pika_text_layout_new (text, xres, yres, &error);
|
||||
if (error)
|
||||
{
|
||||
pika_message_literal (image->pika, NULL, PIKA_MESSAGE_ERROR, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
pika_text_layout_render (layout, cr, text->base_dir, TRUE);
|
||||
g_object_unref (layout);
|
||||
|
||||
pika_text_render_vectors (cr, &context);
|
||||
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
if (context.stroke)
|
||||
pika_stroke_close (context.stroke);
|
||||
}
|
||||
|
||||
return vectors;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
pika_text_vector_coords (const double x,
|
||||
const double y,
|
||||
PikaCoords *coords)
|
||||
{
|
||||
const PikaCoords default_values = PIKA_COORDS_DEFAULT_VALUES;
|
||||
|
||||
*coords = default_values;
|
||||
|
||||
coords->x = x;
|
||||
coords->y = y;
|
||||
}
|
||||
|
||||
static gint
|
||||
moveto (RenderContext *context,
|
||||
const double x,
|
||||
const double y)
|
||||
{
|
||||
PikaCoords start;
|
||||
|
||||
#if PIKA_TEXT_DEBUG
|
||||
g_printerr ("moveto %f, %f\n", x, y);
|
||||
#endif
|
||||
|
||||
pika_text_vector_coords (x, y, &start);
|
||||
|
||||
if (context->stroke)
|
||||
pika_stroke_close (context->stroke);
|
||||
|
||||
context->stroke = pika_bezier_stroke_new_moveto (&start);
|
||||
|
||||
pika_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)
|
||||
{
|
||||
PikaCoords end;
|
||||
|
||||
#if PIKA_TEXT_DEBUG
|
||||
g_printerr ("lineto %f, %f\n", x, y);
|
||||
#endif
|
||||
|
||||
if (! context->stroke)
|
||||
return 0;
|
||||
|
||||
pika_text_vector_coords (x, y, &end);
|
||||
|
||||
pika_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)
|
||||
{
|
||||
PikaCoords control1;
|
||||
PikaCoords control2;
|
||||
PikaCoords end;
|
||||
|
||||
#if PIKA_TEXT_DEBUG
|
||||
g_printerr ("cubicto %f, %f\n", x3, y3);
|
||||
#endif
|
||||
|
||||
if (! context->stroke)
|
||||
return 0;
|
||||
|
||||
pika_text_vector_coords (x1, y1, &control1);
|
||||
pika_text_vector_coords (x2, y2, &control2);
|
||||
pika_text_vector_coords (x3, y3, &end);
|
||||
|
||||
pika_bezier_stroke_cubicto (context->stroke, &control1, &control2, &end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gint
|
||||
closepath (RenderContext *context)
|
||||
{
|
||||
#if PIKA_TEXT_DEBUG
|
||||
g_printerr ("moveto\n");
|
||||
#endif
|
||||
|
||||
if (! context->stroke)
|
||||
return 0;
|
||||
|
||||
pika_stroke_close (context->stroke);
|
||||
|
||||
context->stroke = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_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);
|
||||
}
|
33
app/text/pikatext-vectors.h
Normal file
33
app/text/pikatext-vectors.h
Normal file
@ -0,0 +1,33 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText-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 __PIKA_TEXT_VECTORS_H__
|
||||
#define __PIKA_TEXT_VECTORS_H__
|
||||
|
||||
|
||||
PikaVectors * pika_text_vectors_new (PikaImage *image,
|
||||
PikaText *text);
|
||||
|
||||
|
||||
#endif /* __PIKA_TEXT_VECTORS_H__ */
|
304
app/text/pikatext-xlfd.c
Normal file
304
app/text/pikatext-xlfd.c
Normal file
@ -0,0 +1,304 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 "libpikabase/pikabase.h"
|
||||
|
||||
#include "text-types.h"
|
||||
|
||||
#include "pikatext.h"
|
||||
#include "pikatext-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 * pika_text_get_xlfd_field (const gchar *fontname,
|
||||
gint field_num,
|
||||
gchar *buffer);
|
||||
static gchar * launder_font_name (gchar *name);
|
||||
|
||||
|
||||
/**
|
||||
* pika_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.
|
||||
*
|
||||
* Returns: a newly allocated string.
|
||||
**/
|
||||
gchar *
|
||||
pika_text_font_name_from_xlfd (const gchar *xlfd)
|
||||
{
|
||||
gchar *fields[4];
|
||||
gchar buffers[4][XLFD_MAX_FIELD_LEN];
|
||||
gint i = 0;
|
||||
|
||||
/* family */
|
||||
fields[i] = pika_text_get_xlfd_field (xlfd, XLFD_FAMILY, buffers[i]);
|
||||
if (fields[i])
|
||||
i++;
|
||||
|
||||
/* weight */
|
||||
fields[i] = pika_text_get_xlfd_field (xlfd, XLFD_WEIGHT, buffers[i]);
|
||||
if (fields[i] && strcmp (fields[i], "medium"))
|
||||
i++;
|
||||
|
||||
/* slant */
|
||||
fields[i] = pika_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] = pika_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));
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_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.
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE otherwise.
|
||||
**/
|
||||
gboolean
|
||||
pika_text_font_size_from_xlfd (const gchar *xlfd,
|
||||
gdouble *size,
|
||||
PikaUnit *size_unit)
|
||||
{
|
||||
gchar buffer[XLFD_MAX_FIELD_LEN];
|
||||
gchar *field;
|
||||
|
||||
if (!xlfd)
|
||||
return FALSE;
|
||||
|
||||
field = pika_text_get_xlfd_field (xlfd, XLFD_PIXELS, buffer);
|
||||
if (field)
|
||||
{
|
||||
*size = atoi (field);
|
||||
*size_unit = PIKA_UNIT_PIXEL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
field = pika_text_get_xlfd_field (xlfd, XLFD_POINTS, buffer);
|
||||
if (field)
|
||||
{
|
||||
*size = atoi (field) / 10.0;
|
||||
*size_unit = PIKA_UNIT_POINT;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_text_set_font_from_xlfd:
|
||||
* @text: a #PikaText object
|
||||
* @xlfd: X Logical Font Description
|
||||
*
|
||||
* Attempts to extract font name and font size from @xlfd and sets
|
||||
* them on the #PikaText object.
|
||||
**/
|
||||
void
|
||||
pika_text_set_font_from_xlfd (PikaText *text,
|
||||
const gchar *xlfd)
|
||||
{
|
||||
gchar *font;
|
||||
gdouble size;
|
||||
PikaUnit size_unit;
|
||||
|
||||
g_return_if_fail (PIKA_IS_TEXT (text));
|
||||
|
||||
if (!xlfd)
|
||||
return;
|
||||
|
||||
font = pika_text_font_name_from_xlfd (xlfd);
|
||||
|
||||
#if PIKA_TEXT_DEBUG
|
||||
g_printerr ("XLFD: %s font: %s\n", xlfd, font ? font : "(null)");
|
||||
#endif
|
||||
|
||||
if (pika_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_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 *
|
||||
pika_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;
|
||||
|
||||
g_strlcpy (buffer, t1, len);
|
||||
|
||||
/* 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;
|
||||
}
|
40
app/text/pikatext-xlfd.h
Normal file
40
app/text/pikatext-xlfd.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 __PIKA_TEXT_XLFD_H__
|
||||
#define __PIKA_TEXT_XLFD_H__
|
||||
|
||||
|
||||
/* handle X Logical Font Descriptions for compat */
|
||||
|
||||
gchar * pika_text_font_name_from_xlfd (const gchar *xlfd);
|
||||
gboolean pika_text_font_size_from_xlfd (const gchar *xlfd,
|
||||
gdouble *size,
|
||||
PikaUnit *size_unit);
|
||||
|
||||
void pika_text_set_font_from_xlfd (PikaText *text,
|
||||
const gchar *xlfd);
|
||||
|
||||
|
||||
#endif /* __PIKA_TEXT_COMPAT_H__ */
|
1015
app/text/pikatext.c
Normal file
1015
app/text/pikatext.c
Normal file
File diff suppressed because it is too large
Load Diff
98
app/text/pikatext.h
Normal file
98
app/text/pikatext.h
Normal file
@ -0,0 +1,98 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 __PIKA_TEXT_H__
|
||||
#define __PIKA_TEXT_H__
|
||||
|
||||
|
||||
#include "core/pikaobject.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_TEXT (pika_text_get_type ())
|
||||
#define PIKA_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_TEXT, PikaText))
|
||||
#define PIKA_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_TEXT, PikaTextClass))
|
||||
#define PIKA_IS_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_TEXT))
|
||||
#define PIKA_IS_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_TEXT))
|
||||
#define PIKA_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_TEXT, PikaTextClass))
|
||||
|
||||
|
||||
typedef struct _PikaTextClass PikaTextClass;
|
||||
|
||||
struct _PikaText
|
||||
{
|
||||
PikaObject parent_instance;
|
||||
|
||||
gchar *text;
|
||||
gchar *markup;
|
||||
PikaFont *font;
|
||||
PikaUnit unit;
|
||||
gdouble font_size;
|
||||
gboolean antialias;
|
||||
PikaTextHintStyle hint_style;
|
||||
gboolean kerning;
|
||||
gchar *language;
|
||||
PikaTextDirection base_dir;
|
||||
PikaRGB color;
|
||||
PikaCustomStyle outline_style;
|
||||
PikaPattern *outline_pattern;
|
||||
PikaRGB outline_foreground;
|
||||
gdouble outline_width;
|
||||
PikaCapStyle outline_cap_style;
|
||||
PikaJoinStyle outline_join_style;
|
||||
gdouble outline_miter_limit;
|
||||
gboolean outline_antialias;
|
||||
gdouble outline_dash_offset;
|
||||
GArray *outline_dash_info;
|
||||
PikaTextOutline outline;
|
||||
PikaTextJustification justify;
|
||||
gdouble indent;
|
||||
gdouble line_spacing;
|
||||
gdouble letter_spacing;
|
||||
PikaTextBoxMode box_mode;
|
||||
gdouble box_width;
|
||||
gdouble box_height;
|
||||
PikaUnit box_unit;
|
||||
PikaMatrix2 transformation;
|
||||
gdouble offset_x;
|
||||
gdouble offset_y;
|
||||
|
||||
gdouble border;
|
||||
Pika *pika;
|
||||
};
|
||||
|
||||
struct _PikaTextClass
|
||||
{
|
||||
PikaObjectClass parent_class;
|
||||
|
||||
void (* changed) (PikaText *text);
|
||||
};
|
||||
|
||||
|
||||
GType pika_text_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void pika_text_get_transformation (PikaText *text,
|
||||
PikaMatrix3 *matrix);
|
||||
|
||||
|
||||
#endif /* __PIKA_TEXT_H__ */
|
205
app/text/pikatextlayer-transform.c
Normal file
205
app/text/pikatextlayer-transform.c
Normal file
@ -0,0 +1,205 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaTextLayer
|
||||
* 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 "libpikamath/pikamath.h"
|
||||
|
||||
#include "text-types.h"
|
||||
|
||||
#include "core/pika-transform-utils.h"
|
||||
#include "core/pikaimage-undo.h"
|
||||
|
||||
#include "pikatext.h"
|
||||
#include "pikatextlayer.h"
|
||||
#include "pikatextlayer-transform.h"
|
||||
|
||||
|
||||
static PikaItemClass * pika_text_layer_parent_class (void) G_GNUC_CONST;
|
||||
|
||||
static gboolean pika_text_layer_get_transformation (PikaTextLayer *layer,
|
||||
PikaMatrix3 *matrix);
|
||||
static gboolean pika_text_layer_set_transformation (PikaTextLayer *layer,
|
||||
PikaMatrix3 *matrix);
|
||||
|
||||
|
||||
void
|
||||
pika_text_layer_scale (PikaItem *item,
|
||||
gint new_width,
|
||||
gint new_height,
|
||||
gint new_offset_x,
|
||||
gint new_offset_y,
|
||||
PikaInterpolationType interpolation_type,
|
||||
PikaProgress *progress)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_text_layer_transform_flip (PikaTextLayer *layer,
|
||||
PikaOrientationType flip_type,
|
||||
gdouble axis)
|
||||
{
|
||||
PikaMatrix3 matrix;
|
||||
|
||||
if (! pika_text_layer_get_transformation (layer, &matrix))
|
||||
return FALSE;
|
||||
|
||||
pika_transform_matrix_flip (&matrix, flip_type, axis);
|
||||
|
||||
return pika_text_layer_set_transformation (layer, &matrix);
|
||||
}
|
||||
|
||||
void
|
||||
pika_text_layer_flip (PikaItem *item,
|
||||
PikaContext *context,
|
||||
PikaOrientationType flip_type,
|
||||
gdouble axis,
|
||||
gboolean clip_result)
|
||||
{
|
||||
PikaTextLayer *layer = PIKA_TEXT_LAYER (item);
|
||||
|
||||
if (pika_text_layer_transform_flip (layer, flip_type, axis))
|
||||
{
|
||||
PikaLayerMask *mask = pika_layer_get_mask (PIKA_LAYER (layer));
|
||||
|
||||
if (mask)
|
||||
pika_item_flip (PIKA_ITEM (mask), context,
|
||||
flip_type, axis, clip_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_text_layer_parent_class ()->flip (item, context,
|
||||
flip_type, axis, clip_result);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_text_layer_transform_rotate (PikaTextLayer *layer,
|
||||
PikaRotationType rotate_type,
|
||||
gdouble center_x,
|
||||
gdouble center_y)
|
||||
{
|
||||
PikaMatrix3 matrix;
|
||||
|
||||
if (! pika_text_layer_get_transformation (layer, &matrix))
|
||||
return FALSE;
|
||||
|
||||
pika_transform_matrix_rotate (&matrix, rotate_type, center_x, center_y);
|
||||
|
||||
return pika_text_layer_set_transformation (layer, &matrix);
|
||||
}
|
||||
|
||||
void
|
||||
pika_text_layer_rotate (PikaItem *item,
|
||||
PikaContext *context,
|
||||
PikaRotationType rotate_type,
|
||||
gdouble center_x,
|
||||
gdouble center_y,
|
||||
gboolean clip_result)
|
||||
{
|
||||
PikaTextLayer *layer = PIKA_TEXT_LAYER (item);
|
||||
|
||||
if (! pika_text_layer_transform_rotate (layer,
|
||||
rotate_type, center_x, center_y))
|
||||
{
|
||||
PikaLayerMask *mask = pika_layer_get_mask (PIKA_LAYER (layer));
|
||||
|
||||
if (mask)
|
||||
pika_item_rotate (PIKA_ITEM (mask), context,
|
||||
rotate_type, center_x, center_y, clip_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_text_layer_parent_class ()->rotate (item, context,
|
||||
rotate_type, center_x, center_y,
|
||||
clip_result);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_text_layer_transform (PikaItem *item,
|
||||
PikaContext *context,
|
||||
const PikaMatrix3 *matrix,
|
||||
PikaTransformDirection direction,
|
||||
PikaInterpolationType interpolation_type,
|
||||
gboolean supersample,
|
||||
PikaTransformResize clip_result,
|
||||
PikaProgress *progress)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
static PikaItemClass *
|
||||
pika_text_layer_parent_class (void)
|
||||
{
|
||||
static PikaItemClass *parent_class = NULL;
|
||||
|
||||
if (! parent_class)
|
||||
{
|
||||
gpointer klass = g_type_class_peek (PIKA_TYPE_TEXT_LAYER);
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
}
|
||||
|
||||
return parent_class;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_text_layer_get_transformation (PikaTextLayer *layer,
|
||||
PikaMatrix3 *matrix)
|
||||
{
|
||||
if (! layer->text || layer->modified)
|
||||
return FALSE;
|
||||
|
||||
pika_text_get_transformation (layer->text, matrix);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_text_layer_set_transformation (PikaTextLayer *layer,
|
||||
PikaMatrix3 *matrix)
|
||||
{
|
||||
PikaMatrix2 trafo;
|
||||
|
||||
if (! pika_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];
|
||||
|
||||
pika_text_layer_set (PIKA_TEXT_LAYER (layer), NULL,
|
||||
"transformation", &trafo,
|
||||
"offset-x", matrix->coeff[0][2],
|
||||
"offset-y", matrix->coeff[1][2],
|
||||
NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
57
app/text/pikatextlayer-transform.h
Normal file
57
app/text/pikatextlayer-transform.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaTextLayer
|
||||
* 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 __PIKA_TEXT_LAYER_TRANSFORM_H__
|
||||
#define __PIKA_TEXT_LAYER_TRANSFORM_H__
|
||||
|
||||
|
||||
void pika_text_layer_scale (PikaItem *item,
|
||||
gint new_width,
|
||||
gint new_height,
|
||||
gint new_offset_x,
|
||||
gint new_offset_y,
|
||||
PikaInterpolationType interpolation_type,
|
||||
PikaProgress *progress);
|
||||
void pika_text_layer_flip (PikaItem *item,
|
||||
PikaContext *context,
|
||||
PikaOrientationType flip_type,
|
||||
gdouble axis,
|
||||
gboolean clip_result);
|
||||
void pika_text_layer_rotate (PikaItem *item,
|
||||
PikaContext *context,
|
||||
PikaRotationType rotate_type,
|
||||
gdouble center_x,
|
||||
gdouble center_y,
|
||||
gboolean clip_result);
|
||||
void pika_text_layer_transform (PikaItem *item,
|
||||
PikaContext *context,
|
||||
const PikaMatrix3 *matrix,
|
||||
PikaTransformDirection direction,
|
||||
PikaInterpolationType interpolation_type,
|
||||
gboolean supersample,
|
||||
PikaTransformResize clip_result,
|
||||
PikaProgress *progress);
|
||||
|
||||
|
||||
#endif /* __PIKA_TEXT_LAYER_TRANSFORM_H__ */
|
232
app/text/pikatextlayer-xcf.c
Normal file
232
app/text/pikatextlayer-xcf.c
Normal file
@ -0,0 +1,232 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 "libpikabase/pikabase.h"
|
||||
#include "text-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikadrawable-private.h" /* eek */
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikaparasitelist.h"
|
||||
|
||||
#include "pikatext.h"
|
||||
#include "pikatext-parasite.h"
|
||||
#include "pikatextlayer.h"
|
||||
#include "pikatextlayer-xcf.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
TEXT_LAYER_XCF_NONE = 0,
|
||||
TEXT_LAYER_XCF_DONT_AUTO_RENAME = 1 << 0,
|
||||
TEXT_LAYER_XCF_MODIFIED = 1 << 1
|
||||
};
|
||||
|
||||
|
||||
static PikaLayer * pika_text_layer_from_layer (PikaLayer *layer,
|
||||
PikaText *text);
|
||||
|
||||
|
||||
gboolean
|
||||
pika_text_layer_xcf_load_hack (PikaLayer **layer)
|
||||
{
|
||||
const gchar *name;
|
||||
PikaText *text = NULL;
|
||||
const PikaParasite *parasite;
|
||||
gboolean before_xcf_v19 = FALSE;
|
||||
|
||||
g_return_val_if_fail (layer != NULL, FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_LAYER (*layer), FALSE);
|
||||
|
||||
name = pika_text_parasite_name ();
|
||||
parasite = pika_item_parasite_find (PIKA_ITEM (*layer), name);
|
||||
|
||||
if (parasite)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
text = pika_text_from_parasite (parasite,
|
||||
pika_item_get_image (PIKA_ITEM (*layer))->pika,
|
||||
&before_xcf_v19,
|
||||
&error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
pika_message (pika_item_get_image (PIKA_ITEM (*layer))->pika, NULL,
|
||||
PIKA_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."),
|
||||
pika_object_get_name (*layer),
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name = pika_text_gdyntext_parasite_name ();
|
||||
|
||||
parasite = pika_item_parasite_find (PIKA_ITEM (*layer), name);
|
||||
|
||||
if (parasite)
|
||||
{
|
||||
text = pika_text_from_gdyntext_parasite (parasite);
|
||||
before_xcf_v19 = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (text)
|
||||
{
|
||||
*layer = pika_text_layer_from_layer (*layer, text);
|
||||
|
||||
/* let the text layer knows what parasite was used to create it */
|
||||
PIKA_TEXT_LAYER (*layer)->text_parasite = name;
|
||||
PIKA_TEXT_LAYER (*layer)->text_parasite_is_old = before_xcf_v19;
|
||||
}
|
||||
|
||||
return (text != NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_text_layer_xcf_save_prepare (PikaTextLayer *layer)
|
||||
{
|
||||
PikaText *text;
|
||||
|
||||
g_return_if_fail (PIKA_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 = pika_text_layer_get_text (layer);
|
||||
if (text)
|
||||
{
|
||||
PikaParasite *parasite = pika_text_to_parasite (text);
|
||||
|
||||
/* Don't push an undo because the parasite only exists temporarily
|
||||
* while the text layer is saved to XCF.
|
||||
*/
|
||||
pika_item_parasite_attach (PIKA_ITEM (layer), parasite, FALSE);
|
||||
|
||||
pika_parasite_free (parasite);
|
||||
}
|
||||
}
|
||||
|
||||
guint32
|
||||
pika_text_layer_get_xcf_flags (PikaTextLayer *text_layer)
|
||||
{
|
||||
guint flags = 0;
|
||||
|
||||
g_return_val_if_fail (PIKA_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
|
||||
pika_text_layer_set_xcf_flags (PikaTextLayer *text_layer,
|
||||
guint32 flags)
|
||||
{
|
||||
g_return_if_fail (PIKA_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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pika_text_layer_from_layer:
|
||||
* @layer: a #PikaLayer object
|
||||
* @text: a #PikaText object
|
||||
*
|
||||
* Converts a standard #PikaLayer and a #PikaText object into a
|
||||
* #PikaTextLayer. 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!
|
||||
*
|
||||
* Returns: a newly allocated #PikaTextLayer object
|
||||
**/
|
||||
static PikaLayer *
|
||||
pika_text_layer_from_layer (PikaLayer *layer,
|
||||
PikaText *text)
|
||||
{
|
||||
PikaTextLayer *text_layer;
|
||||
PikaDrawable *drawable;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_LAYER (layer), NULL);
|
||||
g_return_val_if_fail (PIKA_IS_TEXT (text), NULL);
|
||||
|
||||
text_layer = g_object_new (PIKA_TYPE_TEXT_LAYER,
|
||||
"image", pika_item_get_image (PIKA_ITEM (layer)),
|
||||
NULL);
|
||||
|
||||
pika_item_replace_item (PIKA_ITEM (text_layer), PIKA_ITEM (layer));
|
||||
|
||||
drawable = PIKA_DRAWABLE (text_layer);
|
||||
|
||||
pika_drawable_steal_buffer (drawable, PIKA_DRAWABLE (layer));
|
||||
|
||||
pika_layer_set_opacity (PIKA_LAYER (text_layer),
|
||||
pika_layer_get_opacity (layer), FALSE);
|
||||
pika_layer_set_mode (PIKA_LAYER (text_layer),
|
||||
pika_layer_get_mode (layer), FALSE);
|
||||
pika_layer_set_blend_space (PIKA_LAYER (text_layer),
|
||||
pika_layer_get_blend_space (layer), FALSE);
|
||||
pika_layer_set_composite_space (PIKA_LAYER (text_layer),
|
||||
pika_layer_get_composite_space (layer), FALSE);
|
||||
pika_layer_set_composite_mode (PIKA_LAYER (text_layer),
|
||||
pika_layer_get_composite_mode (layer), FALSE);
|
||||
pika_layer_set_lock_alpha (PIKA_LAYER (text_layer),
|
||||
pika_layer_get_lock_alpha (layer), FALSE);
|
||||
|
||||
pika_text_layer_set_text (text_layer, text);
|
||||
|
||||
g_object_unref (text);
|
||||
g_object_unref (layer);
|
||||
|
||||
return PIKA_LAYER (text_layer);
|
||||
}
|
38
app/text/pikatextlayer-xcf.h
Normal file
38
app/text/pikatextlayer-xcf.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 __PIKA_TEXT_LAYER_XCF_H__
|
||||
#define __PIKA_TEXT_LAYER_XCF_H__
|
||||
|
||||
|
||||
gboolean pika_text_layer_xcf_load_hack (PikaLayer **layer);
|
||||
|
||||
void pika_text_layer_xcf_save_prepare (PikaTextLayer *text_layer);
|
||||
|
||||
guint32 pika_text_layer_get_xcf_flags (PikaTextLayer *text_layer);
|
||||
void pika_text_layer_set_xcf_flags (PikaTextLayer *text_layer,
|
||||
guint32 flags);
|
||||
|
||||
|
||||
#endif /* __PIKA_TEXT_LAYER_XCF_H__ */
|
1043
app/text/pikatextlayer.c
Normal file
1043
app/text/pikatextlayer.c
Normal file
File diff suppressed because it is too large
Load Diff
83
app/text/pikatextlayer.h
Normal file
83
app/text/pikatextlayer.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaTextLayer
|
||||
* 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 __PIKA_TEXT_LAYER_H__
|
||||
#define __PIKA_TEXT_LAYER_H__
|
||||
|
||||
|
||||
#include "core/pikalayer.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_TEXT_LAYER (pika_text_layer_get_type ())
|
||||
#define PIKA_TEXT_LAYER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_TEXT_LAYER, PikaTextLayer))
|
||||
#define PIKA_TEXT_LAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_TEXT_LAYER, PikaTextLayerClass))
|
||||
#define PIKA_IS_TEXT_LAYER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_TEXT_LAYER))
|
||||
#define PIKA_IS_TEXT_LAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_TEXT_LAYER))
|
||||
#define PIKA_TEXT_LAYER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_TEXT_LAYER, PikaTextLayerClass))
|
||||
|
||||
|
||||
typedef struct _PikaTextLayerClass PikaTextLayerClass;
|
||||
typedef struct _PikaTextLayerPrivate PikaTextLayerPrivate;
|
||||
|
||||
struct _PikaTextLayer
|
||||
{
|
||||
PikaLayer layer;
|
||||
|
||||
PikaText *text;
|
||||
const gchar *text_parasite; /* parasite name that this text was set from,
|
||||
* and that should be removed when the text
|
||||
* is changed.
|
||||
*/
|
||||
gboolean text_parasite_is_old; /* Format before XCF 19. */
|
||||
gboolean auto_rename;
|
||||
gboolean modified;
|
||||
|
||||
const Babl *convert_format;
|
||||
|
||||
PikaTextLayerPrivate *private;
|
||||
};
|
||||
|
||||
struct _PikaTextLayerClass
|
||||
{
|
||||
PikaLayerClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_text_layer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaLayer * pika_text_layer_new (PikaImage *image,
|
||||
PikaText *text);
|
||||
PikaText * pika_text_layer_get_text (PikaTextLayer *layer);
|
||||
void pika_text_layer_set_text (PikaTextLayer *layer,
|
||||
PikaText *text);
|
||||
void pika_text_layer_discard (PikaTextLayer *layer);
|
||||
void pika_text_layer_set (PikaTextLayer *layer,
|
||||
const gchar *undo_desc,
|
||||
const gchar *first_property_name,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
gboolean pika_item_is_text_layer (PikaItem *item);
|
||||
|
||||
|
||||
#endif /* __PIKA_TEXT_LAYER_H__ */
|
81
app/text/pikatextlayout-render.c
Normal file
81
app/text/pikatextlayout-render.c
Normal file
@ -0,0 +1,81 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 "pikatextlayout.h"
|
||||
#include "pikatextlayout-render.h"
|
||||
|
||||
|
||||
void
|
||||
pika_text_layout_render (PikaTextLayout *layout,
|
||||
cairo_t *cr,
|
||||
PikaTextDirection base_dir,
|
||||
gboolean path)
|
||||
{
|
||||
PangoLayout *pango_layout;
|
||||
cairo_matrix_t trafo;
|
||||
gint x, y;
|
||||
gint width, height;
|
||||
|
||||
g_return_if_fail (PIKA_IS_TEXT_LAYOUT (layout));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
pika_text_layout_get_offsets (layout, &x, &y);
|
||||
cairo_translate (cr, x, y);
|
||||
|
||||
pika_text_layout_get_transform (layout, &trafo);
|
||||
cairo_transform (cr, &trafo);
|
||||
|
||||
if (base_dir == PIKA_TEXT_DIRECTION_TTB_RTL ||
|
||||
base_dir == PIKA_TEXT_DIRECTION_TTB_RTL_UPRIGHT)
|
||||
{
|
||||
pika_text_layout_get_size (layout, &width, &height);
|
||||
cairo_translate (cr, width, 0);
|
||||
cairo_rotate (cr, G_PI_2);
|
||||
}
|
||||
|
||||
if (base_dir == PIKA_TEXT_DIRECTION_TTB_LTR ||
|
||||
base_dir == PIKA_TEXT_DIRECTION_TTB_LTR_UPRIGHT)
|
||||
{
|
||||
pika_text_layout_get_size (layout, &width, &height);
|
||||
cairo_translate (cr, 0, height);
|
||||
cairo_rotate (cr, -G_PI_2);
|
||||
}
|
||||
|
||||
pango_layout = pika_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);
|
||||
}
|
35
app/text/pikatextlayout-render.h
Normal file
35
app/text/pikatextlayout-render.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 __PIKA_TEXT_LAYOUT_RENDER_H__
|
||||
#define __PIKA_TEXT_LAYOUT_RENDER_H__
|
||||
|
||||
|
||||
void pika_text_layout_render (PikaTextLayout *layout,
|
||||
cairo_t *cr,
|
||||
PikaTextDirection base_dir,
|
||||
gboolean path);
|
||||
|
||||
|
||||
#endif /* __PIKA_TEXT_LAYOUT_RENDER_H__ */
|
811
app/text/pikatextlayout.c
Normal file
811
app/text/pikatextlayout.c
Normal file
@ -0,0 +1,811 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 "libpikabase/pikabase.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "text-types.h"
|
||||
|
||||
#include "core/pikaerror.h"
|
||||
|
||||
#include "pikafont.h"
|
||||
|
||||
#include "pikatext.h"
|
||||
#include "pikatextlayout.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
struct _PikaTextLayout
|
||||
{
|
||||
GObject object;
|
||||
|
||||
PikaText *text;
|
||||
gdouble xres;
|
||||
gdouble yres;
|
||||
PangoLayout *layout;
|
||||
PangoRectangle extents;
|
||||
};
|
||||
|
||||
|
||||
static void pika_text_layout_finalize (GObject *object);
|
||||
|
||||
static void pika_text_layout_position (PikaTextLayout *layout);
|
||||
static void pika_text_layout_set_markup (PikaTextLayout *layout,
|
||||
GError **error);
|
||||
|
||||
static PangoContext * pika_text_get_pango_context (PikaText *text,
|
||||
gdouble xres,
|
||||
gdouble yres);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaTextLayout, pika_text_layout, G_TYPE_OBJECT)
|
||||
|
||||
#define parent_class pika_text_layout_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_text_layout_class_init (PikaTextLayoutClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_text_layout_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_text_layout_init (PikaTextLayout *layout)
|
||||
{
|
||||
layout->text = NULL;
|
||||
layout->layout = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_text_layout_finalize (GObject *object)
|
||||
{
|
||||
PikaTextLayout *layout = PIKA_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);
|
||||
}
|
||||
|
||||
|
||||
PikaTextLayout *
|
||||
pika_text_layout_new (PikaText *text,
|
||||
gdouble xres,
|
||||
gdouble yres,
|
||||
GError **error)
|
||||
{
|
||||
PikaTextLayout *layout;
|
||||
PangoContext *context;
|
||||
PangoFontDescription *font_desc;
|
||||
PangoAlignment alignment = PANGO_ALIGN_LEFT;
|
||||
gint size;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_TEXT (text), NULL);
|
||||
|
||||
font_desc = pango_font_description_from_string (pika_font_get_lookup_name (text->font));
|
||||
g_return_val_if_fail (font_desc != NULL, NULL);
|
||||
|
||||
size = pango_units_from_double (pika_units_to_points (text->font_size,
|
||||
text->unit,
|
||||
yres));
|
||||
|
||||
pango_font_description_set_size (font_desc, MAX (1, size));
|
||||
|
||||
context = pika_text_get_pango_context (text, xres, yres);
|
||||
|
||||
layout = g_object_new (PIKA_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);
|
||||
|
||||
pika_text_layout_set_markup (layout, error);
|
||||
|
||||
switch (text->justify)
|
||||
{
|
||||
case PIKA_TEXT_JUSTIFY_LEFT:
|
||||
alignment = PANGO_ALIGN_LEFT;
|
||||
break;
|
||||
case PIKA_TEXT_JUSTIFY_RIGHT:
|
||||
alignment = PANGO_ALIGN_RIGHT;
|
||||
break;
|
||||
case PIKA_TEXT_JUSTIFY_CENTER:
|
||||
alignment = PANGO_ALIGN_CENTER;
|
||||
break;
|
||||
case PIKA_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 PIKA_TEXT_BOX_DYNAMIC:
|
||||
break;
|
||||
case PIKA_TEXT_BOX_FIXED:
|
||||
if (! PANGO_GRAVITY_IS_VERTICAL (pango_context_get_base_gravity (context)))
|
||||
pango_layout_set_width (layout->layout,
|
||||
pango_units_from_double
|
||||
(pika_units_to_pixels (text->box_width,
|
||||
text->box_unit,
|
||||
xres)));
|
||||
else
|
||||
pango_layout_set_width (layout->layout,
|
||||
pango_units_from_double
|
||||
(pika_units_to_pixels (text->box_height,
|
||||
text->box_unit,
|
||||
yres)));
|
||||
break;
|
||||
}
|
||||
|
||||
pango_layout_set_indent (layout->layout,
|
||||
pango_units_from_double
|
||||
(pika_units_to_pixels (text->indent,
|
||||
text->unit,
|
||||
xres)));
|
||||
pango_layout_set_spacing (layout->layout,
|
||||
pango_units_from_double
|
||||
(pika_units_to_pixels (text->line_spacing,
|
||||
text->unit,
|
||||
yres)));
|
||||
|
||||
pika_text_layout_position (layout);
|
||||
|
||||
switch (text->box_mode)
|
||||
{
|
||||
case PIKA_TEXT_BOX_DYNAMIC:
|
||||
break;
|
||||
case PIKA_TEXT_BOX_FIXED:
|
||||
layout->extents.width = ceil (pika_units_to_pixels (text->box_width,
|
||||
text->box_unit,
|
||||
xres));
|
||||
layout->extents.height = ceil (pika_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
|
||||
pika_text_layout_get_size (PikaTextLayout *layout,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_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
|
||||
pika_text_layout_get_offsets (PikaTextLayout *layout,
|
||||
gint *x,
|
||||
gint *y)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_TEXT_LAYOUT (layout));
|
||||
|
||||
if (x)
|
||||
*x = layout->extents.x;
|
||||
|
||||
if (y)
|
||||
*y = layout->extents.y;
|
||||
}
|
||||
|
||||
void
|
||||
pika_text_layout_get_resolution (PikaTextLayout *layout,
|
||||
gdouble *xres,
|
||||
gdouble *yres)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_TEXT_LAYOUT (layout));
|
||||
|
||||
if (xres)
|
||||
*xres = layout->xres;
|
||||
|
||||
if (yres)
|
||||
*yres = layout->yres;
|
||||
}
|
||||
|
||||
PikaText *
|
||||
pika_text_layout_get_text (PikaTextLayout *layout)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_TEXT_LAYOUT (layout), NULL);
|
||||
|
||||
return layout->text;
|
||||
}
|
||||
|
||||
PangoLayout *
|
||||
pika_text_layout_get_pango_layout (PikaTextLayout *layout)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_TEXT_LAYOUT (layout), NULL);
|
||||
|
||||
return layout->layout;
|
||||
}
|
||||
|
||||
void
|
||||
pika_text_layout_get_transform (PikaTextLayout *layout,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
PikaText *text;
|
||||
gdouble xres;
|
||||
gdouble yres;
|
||||
gdouble norm;
|
||||
|
||||
g_return_if_fail (PIKA_IS_TEXT_LAYOUT (layout));
|
||||
g_return_if_fail (matrix != NULL);
|
||||
|
||||
text = pika_text_layout_get_text (layout);
|
||||
|
||||
pika_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
|
||||
pika_text_layout_transform_rect (PikaTextLayout *layout,
|
||||
PangoRectangle *rect)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
gdouble x, y;
|
||||
gdouble width, height;
|
||||
|
||||
g_return_if_fail (PIKA_IS_TEXT_LAYOUT (layout));
|
||||
g_return_if_fail (rect != NULL);
|
||||
|
||||
x = rect->x;
|
||||
y = rect->y;
|
||||
width = rect->width;
|
||||
height = rect->height;
|
||||
|
||||
pika_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
|
||||
pika_text_layout_transform_point (PikaTextLayout *layout,
|
||||
gdouble *x,
|
||||
gdouble *y)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
gdouble _x = 0.0;
|
||||
gdouble _y = 0.0;
|
||||
|
||||
g_return_if_fail (PIKA_IS_TEXT_LAYOUT (layout));
|
||||
|
||||
if (x) _x = *x;
|
||||
if (y) _y = *y;
|
||||
|
||||
pika_text_layout_get_transform (layout, &matrix);
|
||||
|
||||
cairo_matrix_transform_point (&matrix, &_x, &_y);
|
||||
|
||||
if (x) *x = _x;
|
||||
if (y) *y = _y;
|
||||
}
|
||||
|
||||
void
|
||||
pika_text_layout_transform_distance (PikaTextLayout *layout,
|
||||
gdouble *x,
|
||||
gdouble *y)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
gdouble _x = 0.0;
|
||||
gdouble _y = 0.0;
|
||||
|
||||
g_return_if_fail (PIKA_IS_TEXT_LAYOUT (layout));
|
||||
|
||||
if (x) _x = *x;
|
||||
if (y) _y = *y;
|
||||
|
||||
pika_text_layout_get_transform (layout, &matrix);
|
||||
|
||||
cairo_matrix_transform_distance (&matrix, &_x, &_y);
|
||||
|
||||
if (x) *x = _x;
|
||||
if (y) *y = _y;
|
||||
}
|
||||
|
||||
void
|
||||
pika_text_layout_untransform_rect (PikaTextLayout *layout,
|
||||
PangoRectangle *rect)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
gdouble x, y;
|
||||
gdouble width, height;
|
||||
|
||||
g_return_if_fail (PIKA_IS_TEXT_LAYOUT (layout));
|
||||
g_return_if_fail (rect != NULL);
|
||||
|
||||
x = rect->x;
|
||||
y = rect->y;
|
||||
width = rect->width;
|
||||
height = rect->height;
|
||||
|
||||
pika_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
|
||||
pika_text_layout_untransform_point (PikaTextLayout *layout,
|
||||
gdouble *x,
|
||||
gdouble *y)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
gdouble _x = 0.0;
|
||||
gdouble _y = 0.0;
|
||||
|
||||
g_return_if_fail (PIKA_IS_TEXT_LAYOUT (layout));
|
||||
|
||||
if (x) _x = *x;
|
||||
if (y) _y = *y;
|
||||
|
||||
pika_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
|
||||
pika_text_layout_untransform_distance (PikaTextLayout *layout,
|
||||
gdouble *x,
|
||||
gdouble *y)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
gdouble _x = 0.0;
|
||||
gdouble _y = 0.0;
|
||||
|
||||
g_return_if_fail (PIKA_IS_TEXT_LAYOUT (layout));
|
||||
|
||||
if (x) _x = *x;
|
||||
if (y) _y = *y;
|
||||
|
||||
pika_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
|
||||
pika_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 *
|
||||
pika_text_layout_apply_tags (PikaTextLayout *layout,
|
||||
const gchar *markup)
|
||||
{
|
||||
PikaText *text = layout->text;
|
||||
gchar *result;
|
||||
|
||||
{
|
||||
guchar r, g, b;
|
||||
|
||||
pika_rgb_get_uchar (&text->color, &r, &g, &b);
|
||||
|
||||
result = g_strdup_printf ("<span color=\"#%02x%02x%02x\">%s</span>",
|
||||
r, g, b, markup);
|
||||
}
|
||||
/* Updating font 'locl' (if supported) with 'lang' feature tag */
|
||||
if (text->language)
|
||||
{
|
||||
gchar *tmp = g_strdup_printf ("<span lang=\"%s\">%s</span>",
|
||||
text->language,
|
||||
result);
|
||||
g_free (result);
|
||||
result = tmp;
|
||||
}
|
||||
|
||||
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
|
||||
pika_text_layout_set_markup (PikaTextLayout *layout,
|
||||
GError **error)
|
||||
{
|
||||
PikaText *text = layout->text;
|
||||
gchar *open_tag = NULL;
|
||||
gchar *content = NULL;
|
||||
gchar *close_tag = NULL;
|
||||
gchar *tagged;
|
||||
gchar *markup;
|
||||
|
||||
if (text->markup)
|
||||
{
|
||||
if (! pika_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 = pika_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 PIKA 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 PIKA 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, PIKA_ERROR, PIKA_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
|
||||
pika_text_layout_position (PikaTextLayout *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);
|
||||
PikaTextDirection base_dir = layout->text->base_dir;
|
||||
gint width;
|
||||
|
||||
pango_layout_get_pixel_size (layout->layout, &width, NULL);
|
||||
|
||||
if ((base_dir == PIKA_TEXT_DIRECTION_LTR && align == PANGO_ALIGN_RIGHT) ||
|
||||
(base_dir == PIKA_TEXT_DIRECTION_RTL && align == PANGO_ALIGN_RIGHT) ||
|
||||
(base_dir == PIKA_TEXT_DIRECTION_TTB_RTL && align == PANGO_ALIGN_RIGHT) ||
|
||||
(base_dir == PIKA_TEXT_DIRECTION_TTB_RTL_UPRIGHT && align == PANGO_ALIGN_RIGHT) ||
|
||||
(base_dir == PIKA_TEXT_DIRECTION_TTB_LTR && align == PANGO_ALIGN_LEFT) ||
|
||||
(base_dir == PIKA_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 *
|
||||
pika_text_get_font_options (PikaText *text)
|
||||
{
|
||||
cairo_font_options_t *options = cairo_font_options_create ();
|
||||
|
||||
cairo_font_options_set_antialias (options, (text->antialias ?
|
||||
CAIRO_ANTIALIAS_GRAY :
|
||||
CAIRO_ANTIALIAS_NONE));
|
||||
|
||||
switch (text->hint_style)
|
||||
{
|
||||
case PIKA_TEXT_HINT_STYLE_NONE:
|
||||
cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
|
||||
break;
|
||||
|
||||
case PIKA_TEXT_HINT_STYLE_SLIGHT:
|
||||
cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_SLIGHT);
|
||||
break;
|
||||
|
||||
case PIKA_TEXT_HINT_STYLE_MEDIUM:
|
||||
cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_MEDIUM);
|
||||
break;
|
||||
|
||||
case PIKA_TEXT_HINT_STYLE_FULL:
|
||||
cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_FULL);
|
||||
break;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
static PangoContext *
|
||||
pika_text_get_pango_context (PikaText *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 = pika_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 PIKA_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 PIKA_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 PIKA_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 PIKA_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 PIKA_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 PIKA_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;
|
||||
}
|
83
app/text/pikatextlayout.h
Normal file
83
app/text/pikatextlayout.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 __PIKA_TEXT_LAYOUT_H__
|
||||
#define __PIKA_TEXT_LAYOUT_H__
|
||||
|
||||
|
||||
#define PIKA_TYPE_TEXT_LAYOUT (pika_text_layout_get_type ())
|
||||
#define PIKA_TEXT_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_TEXT_LAYOUT, PikaTextLayout))
|
||||
#define PIKA_IS_TEXT_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_TEXT_LAYOUT))
|
||||
|
||||
|
||||
typedef struct _PikaTextLayoutClass PikaTextLayoutClass;
|
||||
|
||||
struct _PikaTextLayoutClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_text_layout_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaTextLayout * pika_text_layout_new (PikaText *text,
|
||||
gdouble xres,
|
||||
gdouble yres,
|
||||
GError **error);
|
||||
gboolean pika_text_layout_get_size (PikaTextLayout *layout,
|
||||
gint *width,
|
||||
gint *height);
|
||||
void pika_text_layout_get_offsets (PikaTextLayout *layout,
|
||||
gint *x,
|
||||
gint *y);
|
||||
void pika_text_layout_get_resolution (PikaTextLayout *layout,
|
||||
gdouble *xres,
|
||||
gdouble *yres);
|
||||
|
||||
PikaText * pika_text_layout_get_text (PikaTextLayout *layout);
|
||||
PangoLayout * pika_text_layout_get_pango_layout (PikaTextLayout *layout);
|
||||
|
||||
void pika_text_layout_get_transform (PikaTextLayout *layout,
|
||||
cairo_matrix_t *matrix);
|
||||
|
||||
void pika_text_layout_transform_rect (PikaTextLayout *layout,
|
||||
PangoRectangle *rect);
|
||||
void pika_text_layout_transform_point (PikaTextLayout *layout,
|
||||
gdouble *x,
|
||||
gdouble *y);
|
||||
void pika_text_layout_transform_distance (PikaTextLayout *layout,
|
||||
gdouble *x,
|
||||
gdouble *y);
|
||||
|
||||
void pika_text_layout_untransform_rect (PikaTextLayout *layout,
|
||||
PangoRectangle *rect);
|
||||
void pika_text_layout_untransform_point (PikaTextLayout *layout,
|
||||
gdouble *x,
|
||||
gdouble *y);
|
||||
void pika_text_layout_untransform_distance (PikaTextLayout *layout,
|
||||
gdouble *x,
|
||||
gdouble *y);
|
||||
|
||||
|
||||
#endif /* __PIKA_TEXT_LAYOUT_H__ */
|
312
app/text/pikatextundo.c
Normal file
312
app/text/pikatextundo.c
Normal file
@ -0,0 +1,312 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* 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 "libpikabase/pikabase.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "text-types.h"
|
||||
|
||||
#include "gegl/pika-babl.h"
|
||||
|
||||
#include "core/pika-memsize.h"
|
||||
#include "core/pikaitem.h"
|
||||
#include "core/pikaitemundo.h"
|
||||
|
||||
#include "pikatext.h"
|
||||
#include "pikatextlayer.h"
|
||||
#include "pikatextundo.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_PARAM
|
||||
};
|
||||
|
||||
|
||||
static void pika_text_undo_constructed (GObject *object);
|
||||
static void pika_text_undo_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_text_undo_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static gint64 pika_text_undo_get_memsize (PikaObject *object,
|
||||
gint64 *gui_size);
|
||||
|
||||
static void pika_text_undo_pop (PikaUndo *undo,
|
||||
PikaUndoMode undo_mode,
|
||||
PikaUndoAccumulator *accum);
|
||||
static void pika_text_undo_free (PikaUndo *undo,
|
||||
PikaUndoMode undo_mode);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaTextUndo, pika_text_undo, PIKA_TYPE_ITEM_UNDO)
|
||||
|
||||
#define parent_class pika_text_undo_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_text_undo_class_init (PikaTextUndoClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaObjectClass *pika_object_class = PIKA_OBJECT_CLASS (klass);
|
||||
PikaUndoClass *undo_class = PIKA_UNDO_CLASS (klass);
|
||||
|
||||
object_class->constructed = pika_text_undo_constructed;
|
||||
object_class->set_property = pika_text_undo_set_property;
|
||||
object_class->get_property = pika_text_undo_get_property;
|
||||
|
||||
pika_object_class->get_memsize = pika_text_undo_get_memsize;
|
||||
|
||||
undo_class->pop = pika_text_undo_pop;
|
||||
undo_class->free = pika_text_undo_free;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PARAM,
|
||||
g_param_spec_param ("param", NULL, NULL,
|
||||
G_TYPE_PARAM,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_text_undo_init (PikaTextUndo *undo)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_text_undo_constructed (GObject *object)
|
||||
{
|
||||
PikaTextUndo *text_undo = PIKA_TEXT_UNDO (object);
|
||||
PikaTextLayer *layer;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||
|
||||
pika_assert (PIKA_IS_TEXT_LAYER (PIKA_ITEM_UNDO (text_undo)->item));
|
||||
|
||||
layer = PIKA_TEXT_LAYER (PIKA_ITEM_UNDO (text_undo)->item);
|
||||
|
||||
switch (PIKA_UNDO (object)->undo_type)
|
||||
{
|
||||
case PIKA_UNDO_TEXT_LAYER:
|
||||
if (text_undo->pspec)
|
||||
{
|
||||
pika_assert (text_undo->pspec->owner_type == PIKA_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 = pika_config_duplicate (PIKA_CONFIG (layer->text));
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_UNDO_TEXT_LAYER_MODIFIED:
|
||||
text_undo->modified = layer->modified;
|
||||
break;
|
||||
|
||||
case PIKA_UNDO_TEXT_LAYER_CONVERT:
|
||||
text_undo->format = pika_drawable_get_format (PIKA_DRAWABLE (layer));
|
||||
break;
|
||||
|
||||
default:
|
||||
pika_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_text_undo_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaTextUndo *text_undo = PIKA_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
|
||||
pika_text_undo_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaTextUndo *text_undo = PIKA_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
|
||||
pika_text_undo_get_memsize (PikaObject *object,
|
||||
gint64 *gui_size)
|
||||
{
|
||||
PikaTextUndo *undo = PIKA_TEXT_UNDO (object);
|
||||
gint64 memsize = 0;
|
||||
|
||||
memsize += pika_g_value_get_memsize (undo->value);
|
||||
memsize += pika_object_get_memsize (PIKA_OBJECT (undo->text), NULL);
|
||||
|
||||
return memsize + PIKA_OBJECT_CLASS (parent_class)->get_memsize (object,
|
||||
gui_size);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_text_undo_pop (PikaUndo *undo,
|
||||
PikaUndoMode undo_mode,
|
||||
PikaUndoAccumulator *accum)
|
||||
{
|
||||
PikaTextUndo *text_undo = PIKA_TEXT_UNDO (undo);
|
||||
PikaTextLayer *layer = PIKA_TEXT_LAYER (PIKA_ITEM_UNDO (undo)->item);
|
||||
|
||||
PIKA_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum);
|
||||
|
||||
switch (undo->undo_type)
|
||||
{
|
||||
case PIKA_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
|
||||
{
|
||||
PikaText *text;
|
||||
|
||||
text = (layer->text ?
|
||||
pika_config_duplicate (PIKA_CONFIG (layer->text)) : NULL);
|
||||
|
||||
if (layer->text && text_undo->text)
|
||||
pika_config_sync (G_OBJECT (text_undo->text),
|
||||
G_OBJECT (layer->text), 0);
|
||||
else
|
||||
pika_text_layer_set_text (layer, text_undo->text);
|
||||
|
||||
if (text_undo->text)
|
||||
g_object_unref (text_undo->text);
|
||||
|
||||
text_undo->text = text;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_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;
|
||||
|
||||
pika_viewable_invalidate_preview (PIKA_VIEWABLE (layer));
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_UNDO_TEXT_LAYER_CONVERT:
|
||||
{
|
||||
const Babl *format;
|
||||
|
||||
format = pika_drawable_get_format (PIKA_DRAWABLE (layer));
|
||||
pika_drawable_convert_type (PIKA_DRAWABLE (layer),
|
||||
pika_item_get_image (PIKA_ITEM (layer)),
|
||||
pika_babl_format_get_base_type (text_undo->format),
|
||||
pika_babl_format_get_precision (text_undo->format),
|
||||
babl_format_has_alpha (text_undo->format),
|
||||
NULL, NULL,
|
||||
GEGL_DITHER_NONE, GEGL_DITHER_NONE,
|
||||
FALSE, NULL);
|
||||
text_undo->format = format;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
pika_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_text_undo_free (PikaUndo *undo,
|
||||
PikaUndoMode undo_mode)
|
||||
{
|
||||
PikaTextUndo *text_undo = PIKA_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;
|
||||
}
|
||||
|
||||
PIKA_UNDO_CLASS (parent_class)->free (undo, undo_mode);
|
||||
}
|
59
app/text/pikatextundo.h
Normal file
59
app/text/pikatextundo.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* 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 __PIKA_TEXT_UNDO_H__
|
||||
#define __PIKA_TEXT_UNDO_H__
|
||||
|
||||
|
||||
#include "core/pikaitemundo.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_TEXT_UNDO (pika_text_undo_get_type ())
|
||||
#define PIKA_TEXT_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_TEXT_UNDO, PikaTextUndo))
|
||||
#define PIKA_TEXT_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_TEXT_UNDO, PikaTextUndoClass))
|
||||
#define PIKA_IS_TEXT_UNDO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_TEXT_UNDO))
|
||||
#define PIKA_IS_TEXT_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_TEXT_UNDO))
|
||||
#define PIKA_TEXT_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_TEXT_UNDO, PikaTextUndoClass))
|
||||
|
||||
|
||||
typedef struct _PikaTextUndoClass PikaTextUndoClass;
|
||||
|
||||
struct _PikaTextUndo
|
||||
{
|
||||
PikaItemUndo parent_instance;
|
||||
|
||||
PikaText *text;
|
||||
const GParamSpec *pspec;
|
||||
GValue *value;
|
||||
gboolean modified;
|
||||
const Babl *format;
|
||||
};
|
||||
|
||||
struct _PikaTextUndoClass
|
||||
{
|
||||
PikaItemClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_text_undo_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_TEXT_UNDO_H__ */
|
74
app/text/text-enums.c
Normal file
74
app/text/text-enums.c
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
/* Generated data (by pika-mkenums) */
|
||||
|
||||
#include "stamp-text-enums.h"
|
||||
#include "config.h"
|
||||
#include <gio/gio.h>
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "text-enums.h"
|
||||
#include "pika-intl.h"
|
||||
|
||||
/* enumerations from "text-enums.h" */
|
||||
GType
|
||||
pika_text_box_mode_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_TEXT_BOX_DYNAMIC, "PIKA_TEXT_BOX_DYNAMIC", "dynamic" },
|
||||
{ PIKA_TEXT_BOX_FIXED, "PIKA_TEXT_BOX_FIXED", "fixed" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_TEXT_BOX_DYNAMIC, NC_("text-box-mode", "Dynamic"), NULL },
|
||||
{ PIKA_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 ("PikaTextBoxMode", values);
|
||||
pika_type_set_translation_context (type, "text-box-mode");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
GType
|
||||
pika_text_outline_get_type (void)
|
||||
{
|
||||
static const GEnumValue values[] =
|
||||
{
|
||||
{ PIKA_TEXT_OUTLINE_NONE, "PIKA_TEXT_OUTLINE_NONE", "none" },
|
||||
{ PIKA_TEXT_OUTLINE_STROKE_ONLY, "PIKA_TEXT_OUTLINE_STROKE_ONLY", "stroke-only" },
|
||||
{ PIKA_TEXT_OUTLINE_STROKE_FILL, "PIKA_TEXT_OUTLINE_STROKE_FILL", "stroke-fill" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const PikaEnumDesc descs[] =
|
||||
{
|
||||
{ PIKA_TEXT_OUTLINE_NONE, NC_("text-outline", "Filled"), NULL },
|
||||
{ PIKA_TEXT_OUTLINE_STROKE_ONLY, NC_("text-outline", "Outlined"), NULL },
|
||||
{ PIKA_TEXT_OUTLINE_STROKE_FILL, NC_("text-outline", "Outlined and filled"), NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (! type))
|
||||
{
|
||||
type = g_enum_register_static ("PikaTextOutline", values);
|
||||
pika_type_set_translation_context (type, "text-outline");
|
||||
pika_enum_set_value_descriptions (type, descs);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/* Generated data ends here */
|
||||
|
49
app/text/text-enums.h
Normal file
49
app/text/text-enums.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* 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 PIKA_TYPE_TEXT_BOX_MODE (pika_text_box_mode_get_type ())
|
||||
|
||||
GType pika_text_box_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_TEXT_BOX_DYNAMIC, /*< desc="Dynamic" >*/
|
||||
PIKA_TEXT_BOX_FIXED /*< desc="Fixed" >*/
|
||||
} PikaTextBoxMode;
|
||||
|
||||
|
||||
#define PIKA_TYPE_TEXT_OUTLINE (pika_text_outline_get_type ())
|
||||
|
||||
GType pika_text_outline_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_TEXT_OUTLINE_NONE, /*< desc="Filled" >*/
|
||||
PIKA_TEXT_OUTLINE_STROKE_ONLY, /*< desc="Outlined" >*/
|
||||
PIKA_TEXT_OUTLINE_STROKE_FILL /*< desc="Outlined and filled" >*/
|
||||
} PikaTextOutline;
|
||||
|
||||
|
||||
#endif /* __TEXT_ENUMS_H__ */
|
42
app/text/text-types.h
Normal file
42
app/text/text-types.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* PikaText
|
||||
* 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 _PikaFont PikaFont;
|
||||
typedef struct _PikaFontFactory PikaFontFactory;
|
||||
typedef struct _PikaFontList PikaFontList;
|
||||
typedef struct _PikaText PikaText;
|
||||
typedef struct _PikaTextLayer PikaTextLayer;
|
||||
typedef struct _PikaTextLayout PikaTextLayout;
|
||||
typedef struct _PikaTextUndo PikaTextUndo;
|
||||
|
||||
|
||||
#endif /* __TEXT_TYPES_H__ */
|
Reference in New Issue
Block a user