summaryrefslogtreecommitdiffstats
path: root/app/text/gimptextlayout.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:30:19 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:30:19 +0000
commit5c1676dfe6d2f3c837a5e074117b45613fd29a72 (patch)
treecbffb45144febf451e54061db2b21395faf94bfe /app/text/gimptextlayout.c
parentInitial commit. (diff)
downloadgimp-63d1391ab989f6cb1b9abeaca4ec268574f16491.tar.xz
gimp-63d1391ab989f6cb1b9abeaca4ec268574f16491.zip
Adding upstream version 2.10.34.upstream/2.10.34upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'app/text/gimptextlayout.c')
-rw-r--r--app/text/gimptextlayout.c805
1 files changed, 805 insertions, 0 deletions
diff --git a/app/text/gimptextlayout.c b/app/text/gimptextlayout.c
new file mode 100644
index 0000000..3d77c3d
--- /dev/null
+++ b/app/text/gimptextlayout.c
@@ -0,0 +1,805 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * GimpText
+ * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gegl.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <pango/pangocairo.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpcolor/gimpcolor.h"
+#include "libgimpmath/gimpmath.h"
+
+#include "text-types.h"
+
+#include "core/gimperror.h"
+
+#include "gimptext.h"
+#include "gimptextlayout.h"
+
+#include "gimp-intl.h"
+
+struct _GimpTextLayout
+{
+ GObject object;
+
+ GimpText *text;
+ gdouble xres;
+ gdouble yres;
+ PangoLayout *layout;
+ PangoRectangle extents;
+};
+
+
+static void gimp_text_layout_finalize (GObject *object);
+
+static void gimp_text_layout_position (GimpTextLayout *layout);
+static void gimp_text_layout_set_markup (GimpTextLayout *layout,
+ GError **error);
+
+static PangoContext * gimp_text_get_pango_context (GimpText *text,
+ gdouble xres,
+ gdouble yres);
+
+
+G_DEFINE_TYPE (GimpTextLayout, gimp_text_layout, G_TYPE_OBJECT)
+
+#define parent_class gimp_text_layout_parent_class
+
+
+static void
+gimp_text_layout_class_init (GimpTextLayoutClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gimp_text_layout_finalize;
+}
+
+static void
+gimp_text_layout_init (GimpTextLayout *layout)
+{
+ layout->text = NULL;
+ layout->layout = NULL;
+}
+
+static void
+gimp_text_layout_finalize (GObject *object)
+{
+ GimpTextLayout *layout = GIMP_TEXT_LAYOUT (object);
+
+ if (layout->text)
+ {
+ g_object_unref (layout->text);
+ layout->text = NULL;
+ }
+ if (layout->layout)
+ {
+ g_object_unref (layout->layout);
+ layout->layout = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+GimpTextLayout *
+gimp_text_layout_new (GimpText *text,
+ gdouble xres,
+ gdouble yres,
+ GError **error)
+{
+ GimpTextLayout *layout;
+ PangoContext *context;
+ PangoFontDescription *font_desc;
+ PangoAlignment alignment = PANGO_ALIGN_LEFT;
+ gint size;
+
+ g_return_val_if_fail (GIMP_IS_TEXT (text), NULL);
+
+ font_desc = pango_font_description_from_string (text->font);
+ g_return_val_if_fail (font_desc != NULL, NULL);
+
+ size = pango_units_from_double (gimp_units_to_points (text->font_size,
+ text->unit,
+ yres));
+
+ pango_font_description_set_size (font_desc, MAX (1, size));
+
+ context = gimp_text_get_pango_context (text, xres, yres);
+
+ layout = g_object_new (GIMP_TYPE_TEXT_LAYOUT, NULL);
+
+ layout->text = g_object_ref (text);
+ layout->layout = pango_layout_new (context);
+ layout->xres = xres;
+ layout->yres = yres;
+
+ pango_layout_set_wrap (layout->layout, PANGO_WRAP_WORD_CHAR);
+
+ pango_layout_set_font_description (layout->layout, font_desc);
+ pango_font_description_free (font_desc);
+
+ gimp_text_layout_set_markup (layout, error);
+
+ switch (text->justify)
+ {
+ case GIMP_TEXT_JUSTIFY_LEFT:
+ alignment = PANGO_ALIGN_LEFT;
+ break;
+ case GIMP_TEXT_JUSTIFY_RIGHT:
+ alignment = PANGO_ALIGN_RIGHT;
+ break;
+ case GIMP_TEXT_JUSTIFY_CENTER:
+ alignment = PANGO_ALIGN_CENTER;
+ break;
+ case GIMP_TEXT_JUSTIFY_FILL:
+ alignment = PANGO_ALIGN_LEFT;
+ pango_layout_set_justify (layout->layout, TRUE);
+ break;
+ }
+
+ pango_layout_set_alignment (layout->layout, alignment);
+
+ switch (text->box_mode)
+ {
+ case GIMP_TEXT_BOX_DYNAMIC:
+ break;
+ case GIMP_TEXT_BOX_FIXED:
+ if (! PANGO_GRAVITY_IS_VERTICAL (pango_context_get_base_gravity (context)))
+ pango_layout_set_width (layout->layout,
+ pango_units_from_double
+ (gimp_units_to_pixels (text->box_width,
+ text->box_unit,
+ xres)));
+ else
+ pango_layout_set_width (layout->layout,
+ pango_units_from_double
+ (gimp_units_to_pixels (text->box_height,
+ text->box_unit,
+ yres)));
+ break;
+ }
+
+ pango_layout_set_indent (layout->layout,
+ pango_units_from_double
+ (gimp_units_to_pixels (text->indent,
+ text->unit,
+ xres)));
+ pango_layout_set_spacing (layout->layout,
+ pango_units_from_double
+ (gimp_units_to_pixels (text->line_spacing,
+ text->unit,
+ yres)));
+
+ gimp_text_layout_position (layout);
+
+ switch (text->box_mode)
+ {
+ case GIMP_TEXT_BOX_DYNAMIC:
+ break;
+ case GIMP_TEXT_BOX_FIXED:
+ layout->extents.width = ceil (gimp_units_to_pixels (text->box_width,
+ text->box_unit,
+ xres));
+ layout->extents.height = ceil (gimp_units_to_pixels (text->box_height,
+ text->box_unit,
+ yres));
+
+/* #define VERBOSE */
+
+#ifdef VERBOSE
+ g_printerr ("extents set to %d x %d\n",
+ layout->extents.width, layout->extents.height);
+#endif
+ break;
+ }
+
+ g_object_unref (context);
+
+ return layout;
+}
+
+gboolean
+gimp_text_layout_get_size (GimpTextLayout *layout,
+ gint *width,
+ gint *height)
+{
+ g_return_val_if_fail (GIMP_IS_TEXT_LAYOUT (layout), FALSE);
+
+ if (width)
+ *width = layout->extents.width;
+
+ if (height)
+ *height = layout->extents.height;
+
+ return (layout->extents.width > 0 && layout->extents.height > 0);
+}
+
+void
+gimp_text_layout_get_offsets (GimpTextLayout *layout,
+ gint *x,
+ gint *y)
+{
+ g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout));
+
+ if (x)
+ *x = layout->extents.x;
+
+ if (y)
+ *y = layout->extents.y;
+}
+
+void
+gimp_text_layout_get_resolution (GimpTextLayout *layout,
+ gdouble *xres,
+ gdouble *yres)
+{
+ g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout));
+
+ if (xres)
+ *xres = layout->xres;
+
+ if (yres)
+ *yres = layout->yres;
+}
+
+GimpText *
+gimp_text_layout_get_text (GimpTextLayout *layout)
+{
+ g_return_val_if_fail (GIMP_IS_TEXT_LAYOUT (layout), NULL);
+
+ return layout->text;
+}
+
+PangoLayout *
+gimp_text_layout_get_pango_layout (GimpTextLayout *layout)
+{
+ g_return_val_if_fail (GIMP_IS_TEXT_LAYOUT (layout), NULL);
+
+ return layout->layout;
+}
+
+void
+gimp_text_layout_get_transform (GimpTextLayout *layout,
+ cairo_matrix_t *matrix)
+{
+ GimpText *text;
+ gdouble xres;
+ gdouble yres;
+ gdouble norm;
+
+ g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout));
+ g_return_if_fail (matrix != NULL);
+
+ text = gimp_text_layout_get_text (layout);
+
+ gimp_text_layout_get_resolution (layout, &xres, &yres);
+
+ norm = 1.0 / yres * xres;
+
+ matrix->xx = text->transformation.coeff[0][0] * norm;
+ matrix->xy = text->transformation.coeff[0][1] * 1.0;
+ matrix->yx = text->transformation.coeff[1][0] * norm;
+ matrix->yy = text->transformation.coeff[1][1] * 1.0;
+ matrix->x0 = 0;
+ matrix->y0 = 0;
+}
+
+void
+gimp_text_layout_transform_rect (GimpTextLayout *layout,
+ PangoRectangle *rect)
+{
+ cairo_matrix_t matrix;
+ gdouble x, y;
+ gdouble width, height;
+
+ g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout));
+ g_return_if_fail (rect != NULL);
+
+ x = rect->x;
+ y = rect->y;
+ width = rect->width;
+ height = rect->height;
+
+ gimp_text_layout_get_transform (layout, &matrix);
+
+ cairo_matrix_transform_point (&matrix, &x, &y);
+ cairo_matrix_transform_distance (&matrix, &width, &height);
+
+ rect->x = ROUND (x);
+ rect->y = ROUND (y);
+ rect->width = ROUND (width);
+ rect->height = ROUND (height);
+}
+
+void
+gimp_text_layout_transform_point (GimpTextLayout *layout,
+ gdouble *x,
+ gdouble *y)
+{
+ cairo_matrix_t matrix;
+ gdouble _x = 0.0;
+ gdouble _y = 0.0;
+
+ g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout));
+
+ if (x) _x = *x;
+ if (y) _y = *y;
+
+ gimp_text_layout_get_transform (layout, &matrix);
+
+ cairo_matrix_transform_point (&matrix, &_x, &_y);
+
+ if (x) *x = _x;
+ if (y) *y = _y;
+}
+
+void
+gimp_text_layout_transform_distance (GimpTextLayout *layout,
+ gdouble *x,
+ gdouble *y)
+{
+ cairo_matrix_t matrix;
+ gdouble _x = 0.0;
+ gdouble _y = 0.0;
+
+ g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout));
+
+ if (x) _x = *x;
+ if (y) _y = *y;
+
+ gimp_text_layout_get_transform (layout, &matrix);
+
+ cairo_matrix_transform_distance (&matrix, &_x, &_y);
+
+ if (x) *x = _x;
+ if (y) *y = _y;
+}
+
+void
+gimp_text_layout_untransform_rect (GimpTextLayout *layout,
+ PangoRectangle *rect)
+{
+ cairo_matrix_t matrix;
+ gdouble x, y;
+ gdouble width, height;
+
+ g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout));
+ g_return_if_fail (rect != NULL);
+
+ x = rect->x;
+ y = rect->y;
+ width = rect->width;
+ height = rect->height;
+
+ gimp_text_layout_get_transform (layout, &matrix);
+
+ if (cairo_matrix_invert (&matrix) == CAIRO_STATUS_SUCCESS)
+ {
+ cairo_matrix_transform_point (&matrix, &x, &y);
+ cairo_matrix_transform_distance (&matrix, &width, &height);
+
+ rect->x = ROUND (x);
+ rect->y = ROUND (y);
+ rect->width = ROUND (width);
+ rect->height = ROUND (height);
+ }
+}
+
+void
+gimp_text_layout_untransform_point (GimpTextLayout *layout,
+ gdouble *x,
+ gdouble *y)
+{
+ cairo_matrix_t matrix;
+ gdouble _x = 0.0;
+ gdouble _y = 0.0;
+
+ g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout));
+
+ if (x) _x = *x;
+ if (y) _y = *y;
+
+ gimp_text_layout_get_transform (layout, &matrix);
+
+ if (cairo_matrix_invert (&matrix) == CAIRO_STATUS_SUCCESS)
+ {
+ cairo_matrix_transform_point (&matrix, &_x, &_y);
+
+ if (x) *x = _x;
+ if (y) *y = _y;
+ }
+}
+
+void
+gimp_text_layout_untransform_distance (GimpTextLayout *layout,
+ gdouble *x,
+ gdouble *y)
+{
+ cairo_matrix_t matrix;
+ gdouble _x = 0.0;
+ gdouble _y = 0.0;
+
+ g_return_if_fail (GIMP_IS_TEXT_LAYOUT (layout));
+
+ if (x) _x = *x;
+ if (y) _y = *y;
+
+ gimp_text_layout_get_transform (layout, &matrix);
+
+ if (cairo_matrix_invert (&matrix) == CAIRO_STATUS_SUCCESS)
+ {
+ cairo_matrix_transform_distance (&matrix, &_x, &_y);
+
+ if (x) *x = _x;
+ if (y) *y = _y;
+ }
+}
+
+static gboolean
+gimp_text_layout_split_markup (const gchar *markup,
+ gchar **open_tag,
+ gchar **content,
+ gchar **close_tag)
+{
+ gchar *p_open;
+ gchar *p_close;
+
+ p_open = strstr (markup, "<markup>");
+ if (! p_open)
+ return FALSE;
+
+ *open_tag = g_strndup (markup, p_open - markup + strlen ("<markup>"));
+
+ p_close = g_strrstr (markup, "</markup>");
+ if (! p_close)
+ {
+ g_free (*open_tag);
+ return FALSE;
+ }
+
+ *close_tag = g_strdup (p_close);
+
+ if (p_open + strlen ("<markup>") < p_close)
+ {
+ *content = g_strndup (p_open + strlen ("<markup>"),
+ p_close - p_open - strlen ("<markup>"));
+ }
+ else
+ {
+ *content = g_strdup ("");
+ }
+
+ return TRUE;
+}
+
+static gchar *
+gimp_text_layout_apply_tags (GimpTextLayout *layout,
+ const gchar *markup)
+{
+ GimpText *text = layout->text;
+ gchar *result;
+
+ {
+ guchar r, g, b;
+
+ gimp_rgb_get_uchar (&text->color, &r, &g, &b);
+
+ result = g_strdup_printf ("<span color=\"#%02x%02x%02x\">%s</span>",
+ r, g, b, markup);
+ }
+ /* 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
+gimp_text_layout_set_markup (GimpTextLayout *layout,
+ GError **error)
+{
+ GimpText *text = layout->text;
+ gchar *open_tag = NULL;
+ gchar *content = NULL;
+ gchar *close_tag = NULL;
+ gchar *tagged;
+ gchar *markup;
+
+ if (text->markup)
+ {
+ if (! gimp_text_layout_split_markup (text->markup,
+ &open_tag, &content, &close_tag))
+ {
+ open_tag = g_strdup ("<markup>");
+ content = g_strdup ("");
+ close_tag = g_strdup ("</markup>");
+ }
+ }
+ else
+ {
+ open_tag = g_strdup ("<markup>");
+ close_tag = g_strdup ("</markup>");
+
+ if (text->text)
+ content = g_markup_escape_text (text->text, -1);
+ else
+ content = g_strdup ("");
+ }
+
+ tagged = gimp_text_layout_apply_tags (layout, content);
+
+ g_free (content);
+
+ markup = g_strconcat (open_tag, tagged, close_tag, NULL);
+
+ g_free (open_tag);
+ g_free (tagged);
+ g_free (close_tag);
+
+ if (pango_parse_markup (markup, -1, 0, NULL, NULL, NULL, error) == FALSE)
+ {
+ if (error && *error &&
+ (*error)->domain == G_MARKUP_ERROR &&
+ (*error)->code == G_MARKUP_ERROR_INVALID_CONTENT)
+ {
+ /* Errors from pango lib are not accurate enough.
+ * Other possible error codes are: G_MARKUP_ERROR_UNKNOWN_ELEMENT
+ * and G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, which likely indicate a bug
+ * in GIMP code or a pango library version issue.
+ * G_MARKUP_ERROR_INVALID_CONTENT on the other hand likely indicates
+ * size/color/style/weight/variant/etc. value issue. Font size is the
+ * only free text in GIMP GUI so we assume that must be it.
+ * Also we output a custom message because pango's error->message is
+ * too technical (telling of <span> tags, not using user's font size
+ * unit, and such). */
+ g_error_free (*error);
+ *error = NULL;
+ g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
+ _("The new text layout cannot be generated. "
+ "Most likely the font size is too big."));
+ }
+ }
+ else
+ pango_layout_set_markup (layout->layout, markup, -1);
+
+ g_free (markup);
+}
+
+static void
+gimp_text_layout_position (GimpTextLayout *layout)
+{
+ PangoRectangle ink;
+ PangoRectangle logical;
+ PangoContext *context;
+ gint x1, y1;
+ gint x2, y2;
+
+ layout->extents.x = 0;
+ layout->extents.y = 0;
+ layout->extents.width = 0;
+ layout->extents.height = 0;
+
+ pango_layout_get_pixel_extents (layout->layout, &ink, &logical);
+
+ ink.width = ceil ((gdouble) ink.width * layout->xres / layout->yres);
+ logical.width = ceil ((gdouble) logical.width * layout->xres / layout->yres);
+ context = pango_layout_get_context (layout->layout);
+
+#ifdef VERBOSE
+ g_printerr ("ink rect: %d x %d @ %d, %d\n",
+ ink.width, ink.height, ink.x, ink.y);
+ g_printerr ("logical rect: %d x %d @ %d, %d\n",
+ logical.width, logical.height, logical.x, logical.y);
+#endif
+
+ if (ink.width < 1 || ink.height < 1)
+ {
+ layout->extents.width = 1;
+ layout->extents.height = logical.height;
+ return;
+ }
+
+ x1 = MIN (ink.x, logical.x);
+ y1 = MIN (ink.y, logical.y);
+ x2 = MAX (ink.x + ink.width, logical.x + logical.width);
+ y2 = MAX (ink.y + ink.height, logical.y + logical.height);
+
+ layout->extents.x = - x1;
+ layout->extents.y = - y1;
+ layout->extents.width = x2 - x1;
+ layout->extents.height = y2 - y1;
+
+ /* If the width of the layout is > 0, then the text-box is FIXED and
+ * the layout position should be offset if the alignment is centered
+ * or right-aligned, also adjust for RTL text direction.
+ */
+ if (pango_layout_get_width (layout->layout) > 0)
+ {
+ PangoAlignment align = pango_layout_get_alignment (layout->layout);
+ GimpTextDirection base_dir = layout->text->base_dir;
+ gint width;
+
+ pango_layout_get_pixel_size (layout->layout, &width, NULL);
+
+ if ((base_dir == GIMP_TEXT_DIRECTION_LTR && align == PANGO_ALIGN_RIGHT) ||
+ (base_dir == GIMP_TEXT_DIRECTION_RTL && align == PANGO_ALIGN_LEFT) ||
+ (base_dir == GIMP_TEXT_DIRECTION_TTB_RTL && align == PANGO_ALIGN_RIGHT) ||
+ (base_dir == GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT && align == PANGO_ALIGN_RIGHT) ||
+ (base_dir == GIMP_TEXT_DIRECTION_TTB_LTR && align == PANGO_ALIGN_LEFT) ||
+ (base_dir == GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT && align == PANGO_ALIGN_LEFT))
+ {
+ layout->extents.x +=
+ PANGO_PIXELS (pango_layout_get_width (layout->layout)) - width;
+ }
+ else if (align == PANGO_ALIGN_CENTER)
+ {
+ layout->extents.x +=
+ (PANGO_PIXELS (pango_layout_get_width (layout->layout)) - width) / 2;
+ }
+ }
+
+ if (layout->text->border > 0)
+ {
+ gint border = layout->text->border;
+
+ layout->extents.x += border;
+ layout->extents.y += border;
+ layout->extents.width += 2 * border;
+ layout->extents.height += 2 * border;
+ }
+
+ if (PANGO_GRAVITY_IS_VERTICAL (pango_context_get_base_gravity (context)))
+ {
+ gint temp;
+
+ temp = layout->extents.y;
+ layout->extents.y = layout->extents.x;
+ layout->extents.x = temp;
+
+ temp = layout->extents.height;
+ layout->extents.height = layout->extents.width;
+ layout->extents.width = temp;
+ }
+
+#ifdef VERBOSE
+ g_printerr ("layout extents: %d x %d @ %d, %d\n",
+ layout->extents.width, layout->extents.height,
+ layout->extents.x, layout->extents.y);
+#endif
+}
+
+static cairo_font_options_t *
+gimp_text_get_font_options (GimpText *text)
+{
+ cairo_font_options_t *options = cairo_font_options_create ();
+
+ cairo_font_options_set_antialias (options, (text->antialias ?
+ CAIRO_ANTIALIAS_GRAY :
+ CAIRO_ANTIALIAS_NONE));
+
+ switch (text->hint_style)
+ {
+ case GIMP_TEXT_HINT_STYLE_NONE:
+ cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
+ break;
+
+ case GIMP_TEXT_HINT_STYLE_SLIGHT:
+ cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_SLIGHT);
+ break;
+
+ case GIMP_TEXT_HINT_STYLE_MEDIUM:
+ cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_MEDIUM);
+ break;
+
+ case GIMP_TEXT_HINT_STYLE_FULL:
+ cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_FULL);
+ break;
+ }
+
+ return options;
+}
+
+static PangoContext *
+gimp_text_get_pango_context (GimpText *text,
+ gdouble xres,
+ gdouble yres)
+{
+ PangoContext *context;
+ PangoFontMap *fontmap;
+ cairo_font_options_t *options;
+
+ fontmap = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT);
+ if (! fontmap)
+ g_error ("You are using a Pango that has been built against a cairo "
+ "that lacks the Freetype font backend");
+
+ pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (fontmap), yres);
+
+ context = pango_font_map_create_context (fontmap);
+ g_object_unref (fontmap);
+
+ options = gimp_text_get_font_options (text);
+ pango_cairo_context_set_font_options (context, options);
+ cairo_font_options_destroy (options);
+
+ if (text->language)
+ pango_context_set_language (context,
+ pango_language_from_string (text->language));
+
+ switch (text->base_dir)
+ {
+ case GIMP_TEXT_DIRECTION_LTR:
+ pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
+ pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_NATURAL);
+ pango_context_set_base_gravity (context, PANGO_GRAVITY_SOUTH);
+ break;
+
+ case GIMP_TEXT_DIRECTION_RTL:
+ pango_context_set_base_dir (context, PANGO_DIRECTION_RTL);
+ pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_NATURAL);
+ pango_context_set_base_gravity (context, PANGO_GRAVITY_SOUTH);
+ break;
+
+ case GIMP_TEXT_DIRECTION_TTB_RTL:
+ pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
+ pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_LINE);
+ pango_context_set_base_gravity (context, PANGO_GRAVITY_EAST);
+ break;
+
+ case GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT:
+ pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
+ pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_STRONG);
+ pango_context_set_base_gravity (context, PANGO_GRAVITY_EAST);
+ break;
+
+ case GIMP_TEXT_DIRECTION_TTB_LTR:
+ pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
+ pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_LINE);
+ pango_context_set_base_gravity (context, PANGO_GRAVITY_WEST);
+ break;
+
+ case GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT:
+ pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
+ pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_STRONG);
+ pango_context_set_base_gravity (context, PANGO_GRAVITY_WEST);
+ break;
+ }
+
+ return context;
+}