instead of just a boolean "convert_profile". This takes the logic to figure the right target profile out of gimp_layer_convert_type(), it can't possibly know everything about how to convert anyway, and having the logic in the callers conveniently splits it up and distributes its parts to the places they belong. This commit should cause no behavor change and is just preparation for fixing bug 765176.
768 lines
24 KiB
C
768 lines
24 KiB
C
/* GIMP - The GNU Image Manipulation Program
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* GimpTextLayer
|
|
* Copyright (C) 2002-2004 Sven Neumann <sven@gimp.org>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include <cairo.h>
|
|
#include <gegl.h>
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
|
#include <pango/pangocairo.h>
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
|
#include "libgimpcolor/gimpcolor.h"
|
|
#include "libgimpconfig/gimpconfig.h"
|
|
|
|
#include "text-types.h"
|
|
|
|
#include "gegl/gimp-babl.h"
|
|
#include "gegl/gimp-gegl-utils.h"
|
|
|
|
#include "core/gimp.h"
|
|
#include "core/gimp-utils.h"
|
|
#include "core/gimpcontext.h"
|
|
#include "core/gimpcontainer.h"
|
|
#include "core/gimpimage.h"
|
|
#include "core/gimpimage-undo.h"
|
|
#include "core/gimpimage-undo-push.h"
|
|
#include "core/gimpitemtree.h"
|
|
#include "core/gimpparasitelist.h"
|
|
|
|
#include "gimptext.h"
|
|
#include "gimptextlayer.h"
|
|
#include "gimptextlayer-transform.h"
|
|
#include "gimptextlayout.h"
|
|
#include "gimptextlayout-render.h"
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_TEXT,
|
|
PROP_AUTO_RENAME,
|
|
PROP_MODIFIED
|
|
};
|
|
|
|
|
|
static void gimp_text_layer_finalize (GObject *object);
|
|
static void gimp_text_layer_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gimp_text_layer_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
|
|
static gint64 gimp_text_layer_get_memsize (GimpObject *object,
|
|
gint64 *gui_size);
|
|
|
|
static GimpItem * gimp_text_layer_duplicate (GimpItem *item,
|
|
GType new_type);
|
|
static gboolean gimp_text_layer_rename (GimpItem *item,
|
|
const gchar *new_name,
|
|
const gchar *undo_desc,
|
|
GError **error);
|
|
|
|
static void gimp_text_layer_convert_type (GimpDrawable *drawable,
|
|
GimpImage *dest_image,
|
|
const Babl *new_format,
|
|
GimpImageBaseType new_base_type,
|
|
GimpPrecision new_precision,
|
|
GimpColorProfile *dest_profile,
|
|
gint layer_dither_type,
|
|
gint mask_dither_type,
|
|
gboolean push_undo,
|
|
GimpProgress *progress);
|
|
static void gimp_text_layer_set_buffer (GimpDrawable *drawable,
|
|
gboolean push_undo,
|
|
const gchar *undo_desc,
|
|
GeglBuffer *buffer,
|
|
gint offset_x,
|
|
gint offset_y);
|
|
static void gimp_text_layer_push_undo (GimpDrawable *drawable,
|
|
const gchar *undo_desc,
|
|
GeglBuffer *buffer,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height);
|
|
|
|
static void gimp_text_layer_text_changed (GimpTextLayer *layer);
|
|
static gboolean gimp_text_layer_render (GimpTextLayer *layer);
|
|
static void gimp_text_layer_render_layout (GimpTextLayer *layer,
|
|
GimpTextLayout *layout);
|
|
|
|
|
|
G_DEFINE_TYPE (GimpTextLayer, gimp_text_layer, GIMP_TYPE_LAYER)
|
|
|
|
#define parent_class gimp_text_layer_parent_class
|
|
|
|
|
|
static void
|
|
gimp_text_layer_class_init (GimpTextLayerClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
|
|
GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
|
|
GimpItemClass *item_class = GIMP_ITEM_CLASS (klass);
|
|
GimpDrawableClass *drawable_class = GIMP_DRAWABLE_CLASS (klass);
|
|
|
|
object_class->finalize = gimp_text_layer_finalize;
|
|
object_class->get_property = gimp_text_layer_get_property;
|
|
object_class->set_property = gimp_text_layer_set_property;
|
|
|
|
gimp_object_class->get_memsize = gimp_text_layer_get_memsize;
|
|
|
|
viewable_class->default_icon_name = "gimp-text-layer";
|
|
|
|
item_class->duplicate = gimp_text_layer_duplicate;
|
|
item_class->rename = gimp_text_layer_rename;
|
|
|
|
#if 0
|
|
item_class->scale = gimp_text_layer_scale;
|
|
item_class->flip = gimp_text_layer_flip;
|
|
item_class->rotate = gimp_text_layer_rotate;
|
|
item_class->transform = gimp_text_layer_transform;
|
|
#endif
|
|
|
|
item_class->default_name = _("Text Layer");
|
|
item_class->rename_desc = _("Rename Text Layer");
|
|
item_class->translate_desc = _("Move Text Layer");
|
|
item_class->scale_desc = _("Scale Text Layer");
|
|
item_class->resize_desc = _("Resize Text Layer");
|
|
item_class->flip_desc = _("Flip Text Layer");
|
|
item_class->rotate_desc = _("Rotate Text Layer");
|
|
item_class->transform_desc = _("Transform Text Layer");
|
|
|
|
drawable_class->convert_type = gimp_text_layer_convert_type;
|
|
drawable_class->set_buffer = gimp_text_layer_set_buffer;
|
|
drawable_class->push_undo = gimp_text_layer_push_undo;
|
|
|
|
GIMP_CONFIG_PROP_OBJECT (object_class, PROP_TEXT,
|
|
"text",
|
|
NULL, NULL,
|
|
GIMP_TYPE_TEXT,
|
|
GIMP_PARAM_STATIC_STRINGS);
|
|
|
|
GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_AUTO_RENAME,
|
|
"auto-rename",
|
|
NULL, NULL,
|
|
TRUE,
|
|
GIMP_PARAM_STATIC_STRINGS);
|
|
|
|
GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_MODIFIED,
|
|
"modified",
|
|
NULL, NULL,
|
|
FALSE,
|
|
GIMP_PARAM_STATIC_STRINGS);
|
|
}
|
|
|
|
static void
|
|
gimp_text_layer_init (GimpTextLayer *layer)
|
|
{
|
|
layer->text = NULL;
|
|
layer->text_parasite = NULL;
|
|
}
|
|
|
|
static void
|
|
gimp_text_layer_finalize (GObject *object)
|
|
{
|
|
GimpTextLayer *layer = GIMP_TEXT_LAYER (object);
|
|
|
|
if (layer->text)
|
|
{
|
|
g_object_unref (layer->text);
|
|
layer->text = NULL;
|
|
}
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gimp_text_layer_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpTextLayer *text_layer = GIMP_TEXT_LAYER (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_TEXT:
|
|
g_value_set_object (value, text_layer->text);
|
|
break;
|
|
case PROP_AUTO_RENAME:
|
|
g_value_set_boolean (value, text_layer->auto_rename);
|
|
break;
|
|
case PROP_MODIFIED:
|
|
g_value_set_boolean (value, text_layer->modified);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_text_layer_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpTextLayer *text_layer = GIMP_TEXT_LAYER (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_TEXT:
|
|
gimp_text_layer_set_text (text_layer, g_value_get_object (value));
|
|
break;
|
|
case PROP_AUTO_RENAME:
|
|
text_layer->auto_rename = g_value_get_boolean (value);
|
|
break;
|
|
case PROP_MODIFIED:
|
|
text_layer->modified = g_value_get_boolean (value);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static gint64
|
|
gimp_text_layer_get_memsize (GimpObject *object,
|
|
gint64 *gui_size)
|
|
{
|
|
GimpTextLayer *text_layer = GIMP_TEXT_LAYER (object);
|
|
gint64 memsize = 0;
|
|
|
|
memsize += gimp_object_get_memsize (GIMP_OBJECT (text_layer->text),
|
|
gui_size);
|
|
|
|
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
|
|
gui_size);
|
|
}
|
|
|
|
static GimpItem *
|
|
gimp_text_layer_duplicate (GimpItem *item,
|
|
GType new_type)
|
|
{
|
|
GimpItem *new_item;
|
|
|
|
g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_DRAWABLE), NULL);
|
|
|
|
new_item = GIMP_ITEM_CLASS (parent_class)->duplicate (item, new_type);
|
|
|
|
if (GIMP_IS_TEXT_LAYER (new_item))
|
|
{
|
|
GimpTextLayer *layer = GIMP_TEXT_LAYER (item);
|
|
GimpTextLayer *new_layer = GIMP_TEXT_LAYER (new_item);
|
|
|
|
gimp_config_sync (G_OBJECT (layer), G_OBJECT (new_layer), 0);
|
|
|
|
if (layer->text)
|
|
{
|
|
GimpText *text = gimp_config_duplicate (GIMP_CONFIG (layer->text));
|
|
|
|
gimp_text_layer_set_text (new_layer, text);
|
|
|
|
g_object_unref (text);
|
|
}
|
|
|
|
/* this is just the parasite name, not a pointer to the parasite */
|
|
if (layer->text_parasite)
|
|
new_layer->text_parasite = layer->text_parasite;
|
|
}
|
|
|
|
return new_item;
|
|
}
|
|
|
|
static gboolean
|
|
gimp_text_layer_rename (GimpItem *item,
|
|
const gchar *new_name,
|
|
const gchar *undo_desc,
|
|
GError **error)
|
|
{
|
|
if (GIMP_ITEM_CLASS (parent_class)->rename (item, new_name, undo_desc, error))
|
|
{
|
|
g_object_set (item, "auto-rename", FALSE, NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gimp_text_layer_convert_type (GimpDrawable *drawable,
|
|
GimpImage *dest_image,
|
|
const Babl *new_format,
|
|
GimpImageBaseType new_base_type,
|
|
GimpPrecision new_precision,
|
|
GimpColorProfile *dest_profile,
|
|
gint layer_dither_type,
|
|
gint mask_dither_type,
|
|
gboolean push_undo,
|
|
GimpProgress *progress)
|
|
{
|
|
GimpTextLayer *layer = GIMP_TEXT_LAYER (drawable);
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
|
|
|
if (! layer->text || layer->modified || layer_dither_type != 0)
|
|
{
|
|
GIMP_DRAWABLE_CLASS (parent_class)->convert_type (drawable, dest_image,
|
|
new_format,
|
|
new_base_type,
|
|
new_precision,
|
|
dest_profile,
|
|
layer_dither_type,
|
|
mask_dither_type,
|
|
push_undo,
|
|
progress);
|
|
}
|
|
else
|
|
{
|
|
if (push_undo)
|
|
gimp_image_undo_push_text_layer_convert (image, NULL, layer);
|
|
|
|
layer->convert_format = new_format;
|
|
|
|
gimp_text_layer_render (layer);
|
|
|
|
layer->convert_format = NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_text_layer_set_buffer (GimpDrawable *drawable,
|
|
gboolean push_undo,
|
|
const gchar *undo_desc,
|
|
GeglBuffer *buffer,
|
|
gint offset_x,
|
|
gint offset_y)
|
|
{
|
|
GimpTextLayer *layer = GIMP_TEXT_LAYER (drawable);
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
|
|
|
if (push_undo && ! layer->modified)
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_DRAWABLE_MOD,
|
|
undo_desc);
|
|
|
|
GIMP_DRAWABLE_CLASS (parent_class)->set_buffer (drawable,
|
|
push_undo, undo_desc,
|
|
buffer,
|
|
offset_x, offset_y);
|
|
|
|
if (push_undo && ! layer->modified)
|
|
{
|
|
gimp_image_undo_push_text_layer_modified (image, NULL, layer);
|
|
|
|
g_object_set (drawable, "modified", TRUE, NULL);
|
|
|
|
gimp_image_undo_group_end (image);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_text_layer_push_undo (GimpDrawable *drawable,
|
|
const gchar *undo_desc,
|
|
GeglBuffer *buffer,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
GimpTextLayer *layer = GIMP_TEXT_LAYER (drawable);
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
|
|
|
if (! layer->modified)
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_DRAWABLE, undo_desc);
|
|
|
|
GIMP_DRAWABLE_CLASS (parent_class)->push_undo (drawable, undo_desc,
|
|
buffer,
|
|
x, y, width, height);
|
|
|
|
if (! layer->modified)
|
|
{
|
|
gimp_image_undo_push_text_layer_modified (image, NULL, layer);
|
|
|
|
g_object_set (drawable, "modified", TRUE, NULL);
|
|
|
|
gimp_image_undo_group_end (image);
|
|
}
|
|
}
|
|
|
|
|
|
/* public functions */
|
|
|
|
/**
|
|
* gimp_text_layer_new:
|
|
* @image: the #GimpImage the layer should belong to
|
|
* @text: a #GimpText object
|
|
*
|
|
* Creates a new text layer.
|
|
*
|
|
* Return value: a new #GimpTextLayer or %NULL in case of a problem
|
|
**/
|
|
GimpLayer *
|
|
gimp_text_layer_new (GimpImage *image,
|
|
GimpText *text)
|
|
{
|
|
GimpTextLayer *layer;
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
|
g_return_val_if_fail (GIMP_IS_TEXT (text), NULL);
|
|
|
|
if (! text->text && ! text->markup)
|
|
return NULL;
|
|
|
|
layer =
|
|
GIMP_TEXT_LAYER (gimp_drawable_new (GIMP_TYPE_TEXT_LAYER,
|
|
image, NULL,
|
|
0, 0, 1, 1,
|
|
gimp_image_get_layer_format (image,
|
|
TRUE)));
|
|
|
|
gimp_text_layer_set_text (layer, text);
|
|
|
|
if (! gimp_text_layer_render (layer))
|
|
{
|
|
g_object_unref (layer);
|
|
return NULL;
|
|
}
|
|
|
|
return GIMP_LAYER (layer);
|
|
}
|
|
|
|
void
|
|
gimp_text_layer_set_text (GimpTextLayer *layer,
|
|
GimpText *text)
|
|
{
|
|
g_return_if_fail (GIMP_IS_TEXT_LAYER (layer));
|
|
g_return_if_fail (text == NULL || GIMP_IS_TEXT (text));
|
|
|
|
if (layer->text == text)
|
|
return;
|
|
|
|
if (layer->text)
|
|
{
|
|
g_signal_handlers_disconnect_by_func (layer->text,
|
|
G_CALLBACK (gimp_text_layer_text_changed),
|
|
layer);
|
|
|
|
g_object_unref (layer->text);
|
|
layer->text = NULL;
|
|
}
|
|
|
|
if (text)
|
|
{
|
|
layer->text = g_object_ref (text);
|
|
|
|
g_signal_connect_object (text, "changed",
|
|
G_CALLBACK (gimp_text_layer_text_changed),
|
|
layer, G_CONNECT_SWAPPED);
|
|
}
|
|
|
|
g_object_notify (G_OBJECT (layer), "text");
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer));
|
|
}
|
|
|
|
GimpText *
|
|
gimp_text_layer_get_text (GimpTextLayer *layer)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_TEXT_LAYER (layer), NULL);
|
|
|
|
return layer->text;
|
|
}
|
|
|
|
void
|
|
gimp_text_layer_set (GimpTextLayer *layer,
|
|
const gchar *undo_desc,
|
|
const gchar *first_property_name,
|
|
...)
|
|
{
|
|
GimpImage *image;
|
|
GimpText *text;
|
|
va_list var_args;
|
|
|
|
g_return_if_fail (gimp_item_is_text_layer (GIMP_ITEM (layer)));
|
|
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer)));
|
|
|
|
text = gimp_text_layer_get_text (layer);
|
|
if (! text)
|
|
return;
|
|
|
|
image = gimp_item_get_image (GIMP_ITEM (layer));
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT, undo_desc);
|
|
|
|
g_object_freeze_notify (G_OBJECT (layer));
|
|
|
|
if (layer->modified)
|
|
{
|
|
gimp_image_undo_push_text_layer_modified (image, NULL, layer);
|
|
|
|
/* pass copy_tiles = TRUE so we not only ref the tiles; after
|
|
* being a text layer again, undo doesn't care about the
|
|
* layer's pixels any longer because they are generated, so
|
|
* changing the text would happily overwrite the layer's
|
|
* pixels, changing the pixels on the undo stack too without
|
|
* any chance to ever undo again.
|
|
*/
|
|
gimp_image_undo_push_drawable_mod (image, NULL,
|
|
GIMP_DRAWABLE (layer), TRUE);
|
|
}
|
|
|
|
gimp_image_undo_push_text_layer (image, undo_desc, layer, NULL);
|
|
|
|
va_start (var_args, first_property_name);
|
|
|
|
g_object_set_valist (G_OBJECT (text), first_property_name, var_args);
|
|
|
|
va_end (var_args);
|
|
|
|
g_object_set (layer, "modified", FALSE, NULL);
|
|
|
|
g_object_thaw_notify (G_OBJECT (layer));
|
|
|
|
gimp_image_undo_group_end (image);
|
|
}
|
|
|
|
/**
|
|
* gimp_text_layer_discard:
|
|
* @layer: a #GimpTextLayer
|
|
*
|
|
* Discards the text information. This makes @layer behave like a
|
|
* normal layer.
|
|
*/
|
|
void
|
|
gimp_text_layer_discard (GimpTextLayer *layer)
|
|
{
|
|
g_return_if_fail (GIMP_IS_TEXT_LAYER (layer));
|
|
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer)));
|
|
|
|
if (! layer->text)
|
|
return;
|
|
|
|
gimp_image_undo_push_text_layer (gimp_item_get_image (GIMP_ITEM (layer)),
|
|
_("Discard Text Information"),
|
|
layer, NULL);
|
|
|
|
gimp_text_layer_set_text (layer, NULL);
|
|
}
|
|
|
|
gboolean
|
|
gimp_item_is_text_layer (GimpItem *item)
|
|
{
|
|
return (GIMP_IS_TEXT_LAYER (item) &&
|
|
GIMP_TEXT_LAYER (item)->text &&
|
|
GIMP_TEXT_LAYER (item)->modified == FALSE);
|
|
}
|
|
|
|
|
|
/* private functions */
|
|
|
|
static const Babl *
|
|
gimp_text_layer_get_format (GimpTextLayer *layer)
|
|
{
|
|
if (layer->convert_format)
|
|
return layer->convert_format;
|
|
|
|
return gimp_drawable_get_format (GIMP_DRAWABLE (layer));
|
|
}
|
|
|
|
static void
|
|
gimp_text_layer_text_changed (GimpTextLayer *layer)
|
|
{
|
|
/* If the text layer was created from a parasite, it's time to
|
|
* remove that parasite now.
|
|
*/
|
|
if (layer->text_parasite)
|
|
{
|
|
/* Don't push an undo because the parasite only exists temporarily
|
|
* while the text layer is loaded from XCF.
|
|
*/
|
|
gimp_item_parasite_detach (GIMP_ITEM (layer), layer->text_parasite,
|
|
FALSE);
|
|
layer->text_parasite = NULL;
|
|
}
|
|
|
|
gimp_text_layer_render (layer);
|
|
}
|
|
|
|
static gboolean
|
|
gimp_text_layer_render (GimpTextLayer *layer)
|
|
{
|
|
GimpDrawable *drawable;
|
|
GimpItem *item;
|
|
GimpImage *image;
|
|
GimpTextLayout *layout;
|
|
gdouble xres;
|
|
gdouble yres;
|
|
gint width;
|
|
gint height;
|
|
GError *error = NULL;
|
|
|
|
if (! layer->text)
|
|
return FALSE;
|
|
|
|
drawable = GIMP_DRAWABLE (layer);
|
|
item = GIMP_ITEM (layer);
|
|
image = gimp_item_get_image (item);
|
|
|
|
if (gimp_container_is_empty (image->gimp->fonts))
|
|
{
|
|
gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR,
|
|
_("Due to lack of any fonts, "
|
|
"text functionality is not available."));
|
|
return FALSE;
|
|
}
|
|
|
|
gimp_image_get_resolution (image, &xres, &yres);
|
|
|
|
layout = gimp_text_layout_new (layer->text, xres, yres, &error);
|
|
if (error)
|
|
{
|
|
gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR, error->message);
|
|
g_error_free (error);
|
|
}
|
|
|
|
g_object_freeze_notify (G_OBJECT (drawable));
|
|
|
|
if (gimp_text_layout_get_size (layout, &width, &height) &&
|
|
(width != gimp_item_get_width (item) ||
|
|
height != gimp_item_get_height (item) ||
|
|
gimp_text_layer_get_format (layer) !=
|
|
gimp_drawable_get_format (drawable)))
|
|
{
|
|
GeglBuffer *new_buffer;
|
|
|
|
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
|
|
gimp_text_layer_get_format (layer));
|
|
gimp_drawable_set_buffer (drawable, FALSE, NULL, new_buffer);
|
|
g_object_unref (new_buffer);
|
|
|
|
if (gimp_layer_get_mask (GIMP_LAYER (layer)))
|
|
{
|
|
GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (layer));
|
|
|
|
static GimpContext *unused_eek = NULL;
|
|
|
|
if (! unused_eek)
|
|
unused_eek = gimp_context_new (image->gimp, "eek", NULL);
|
|
|
|
gimp_item_resize (GIMP_ITEM (mask), unused_eek, width, height, 0, 0);
|
|
}
|
|
}
|
|
|
|
if (layer->auto_rename)
|
|
{
|
|
GimpItem *item = GIMP_ITEM (layer);
|
|
gchar *name = NULL;
|
|
|
|
if (layer->text->text)
|
|
{
|
|
name = gimp_utf8_strtrim (layer->text->text, 30);
|
|
}
|
|
else if (layer->text->markup)
|
|
{
|
|
gchar *tmp = gimp_markup_extract_text (layer->text->markup);
|
|
name = gimp_utf8_strtrim (tmp, 30);
|
|
g_free (tmp);
|
|
}
|
|
|
|
if (! name)
|
|
name = g_strdup (_("Empty Text Layer"));
|
|
|
|
if (gimp_item_is_attached (item))
|
|
{
|
|
gimp_item_tree_rename_item (gimp_item_get_tree (item), item,
|
|
name, FALSE, NULL);
|
|
g_free (name);
|
|
}
|
|
else
|
|
{
|
|
gimp_object_take_name (GIMP_OBJECT (layer), name);
|
|
}
|
|
}
|
|
|
|
if (width > 0 && height > 0)
|
|
gimp_text_layer_render_layout (layer, layout);
|
|
|
|
g_object_unref (layout);
|
|
|
|
g_object_thaw_notify (G_OBJECT (drawable));
|
|
|
|
return (width > 0 && height > 0);
|
|
}
|
|
|
|
static void
|
|
gimp_text_layer_render_layout (GimpTextLayer *layer,
|
|
GimpTextLayout *layout)
|
|
{
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (layer);
|
|
GimpItem *item = GIMP_ITEM (layer);
|
|
GeglBuffer *buffer;
|
|
cairo_t *cr;
|
|
cairo_surface_t *surface;
|
|
gint width;
|
|
gint height;
|
|
cairo_status_t status;
|
|
|
|
g_return_if_fail (gimp_drawable_has_alpha (drawable));
|
|
|
|
width = gimp_item_get_width (item);
|
|
height = gimp_item_get_height (item);
|
|
|
|
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
|
status = cairo_surface_status (surface);
|
|
|
|
if (status != CAIRO_STATUS_SUCCESS)
|
|
{
|
|
GimpImage *image = gimp_item_get_image (item);
|
|
|
|
gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR,
|
|
_("Your text cannot be rendered. It is likely too big. "
|
|
"Please make it shorter or use a smaller font."));
|
|
cairo_surface_destroy (surface);
|
|
return;
|
|
}
|
|
|
|
cr = cairo_create (surface);
|
|
gimp_text_layout_render (layout, cr, layer->text->base_dir, FALSE);
|
|
cairo_destroy (cr);
|
|
|
|
cairo_surface_flush (surface);
|
|
|
|
buffer = gimp_cairo_surface_create_buffer (surface);
|
|
|
|
gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE,
|
|
gimp_drawable_get_buffer (drawable), NULL);
|
|
|
|
g_object_unref (buffer);
|
|
cairo_surface_destroy (surface);
|
|
|
|
gimp_drawable_update (drawable, 0, 0, width, height);
|
|
}
|