summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2004-06-23 19:00:36 +0000
committerOwen Taylor <otaylor@src.gnome.org>2004-06-23 19:00:36 +0000
commit3aabb8d5ce0720c9a22cdcf975380d1d0213c4c8 (patch)
treeb6a641821de5c6e8643fb869c3950cd9d167ed61
parent1939a027b1d4e6c7d83af9e42e191f1bfb0cf8a0 (diff)
downloadpango-3aabb8d5ce0720c9a22cdcf975380d1d0213c4c8.tar.gz
Add new letter_spacing attribute.
Wed Jun 23 11:17:51 2004 Owen Taylor <otaylor@redhat.com> * pango/pango-attributes.[ch]: Add new letter_spacing attribute. * pango/pango-attributes.c (pango_attr_rise_new): Correct description; rise is in Pango units, not em-relative. * pango/pango-glyph-item.c: Break out iteration-over-clusters from ApplyAttrsState into a separate GlyphItemIter. * pango/pango-glyph-item.[ch]: New function pango_glyph_item_letter_space() to add add letter spacing to a single glyph item. * pango/pango-markup.c: Add a letter_spacing attribute. * pango/pango-layout.c: Use G_DEFINE_TYPE(). * pango/pango-layout.c (pango_layout_get_item_properties): Switch to use a structure rather than a pile of out parameters. * pango/pango-layout.c (pango_run_get_extents): Remove the unused shape_set out parameter. * pango/pangofc-decoder.[ch] pango/pangofc-fontmap.[ch]: Doc fixes. * pango/pango-types.h: Deprecate pango_get_mirror_char() * pango/pango-utils.c (pango_get_mirror_char): Add docs. * docs/pango-sections.txt docs/pango-docs.sgml: Add PangoFcDecoder and letter spacing.
-rw-r--r--ChangeLog36
-rw-r--r--ChangeLog.pre-1-1036
-rw-r--r--ChangeLog.pre-1-636
-rw-r--r--ChangeLog.pre-1-836
-rw-r--r--docs/pango-docs.sgml2
-rw-r--r--docs/pango-sections.txt21
-rw-r--r--docs/pango.types1
-rw-r--r--docs/tmpl/glyphs.sgml11
-rw-r--r--docs/tmpl/pangofc-fontmap.sgml21
-rw-r--r--docs/tmpl/text-attributes.sgml10
-rw-r--r--pango/pango-attributes.c27
-rw-r--r--pango/pango-attributes.h4
-rw-r--r--pango/pango-glyph-item.c246
-rw-r--r--pango/pango-glyph-item.h17
-rw-r--r--pango/pango-layout.c380
-rw-r--r--pango/pango-markup.c28
-rw-r--r--pango/pango-types.h4
-rw-r--r--pango/pango-utils.c15
-rw-r--r--pango/pangofc-decoder.c45
-rw-r--r--pango/pangofc-decoder.h20
-rw-r--r--pango/pangofc-fontmap.c25
-rw-r--r--pango/pangofc-fontmap.h10
22 files changed, 762 insertions, 269 deletions
diff --git a/ChangeLog b/ChangeLog
index 5e806cfe..77b8baba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+Wed Jun 23 11:17:51 2004 Owen Taylor <otaylor@redhat.com>
+
+ * pango/pango-attributes.[ch]: Add new letter_spacing
+ attribute.
+
+ * pango/pango-attributes.c (pango_attr_rise_new): Correct
+ description; rise is in Pango units, not em-relative.
+
+ * pango/pango-glyph-item.c: Break out iteration-over-clusters
+ from ApplyAttrsState into a separate GlyphItemIter.
+
+ * pango/pango-glyph-item.[ch]: New function
+ pango_glyph_item_letter_space() to add add letter spacing
+ to a single glyph item.
+
+ * pango/pango-markup.c: Add a letter_spacing attribute.
+
+ * pango/pango-layout.c: Use G_DEFINE_TYPE().
+
+ * pango/pango-layout.c (pango_layout_get_item_properties):
+ Switch to use a structure rather than a pile of out
+ parameters.
+
+ * pango/pango-layout.c (pango_run_get_extents): Remove
+ the unused shape_set out parameter.
+
+ * pango/pangofc-decoder.[ch] pango/pangofc-fontmap.[ch]:
+ Doc fixes.
+
+ * pango/pango-types.h: Deprecate pango_get_mirror_char()
+
+ * pango/pango-utils.c (pango_get_mirror_char): Add docs.
+
+ * docs/pango-sections.txt docs/pango-docs.sgml: Add
+ PangoFcDecoder and letter spacing.
+
Tue Jun 22 14:10:41 2004 Owen Taylor <otaylor@redhat.com>
* pango/break.c: Handle new Unicode-4.0 WORD_JOINER
diff --git a/ChangeLog.pre-1-10 b/ChangeLog.pre-1-10
index 5e806cfe..77b8baba 100644
--- a/ChangeLog.pre-1-10
+++ b/ChangeLog.pre-1-10
@@ -1,3 +1,39 @@
+Wed Jun 23 11:17:51 2004 Owen Taylor <otaylor@redhat.com>
+
+ * pango/pango-attributes.[ch]: Add new letter_spacing
+ attribute.
+
+ * pango/pango-attributes.c (pango_attr_rise_new): Correct
+ description; rise is in Pango units, not em-relative.
+
+ * pango/pango-glyph-item.c: Break out iteration-over-clusters
+ from ApplyAttrsState into a separate GlyphItemIter.
+
+ * pango/pango-glyph-item.[ch]: New function
+ pango_glyph_item_letter_space() to add add letter spacing
+ to a single glyph item.
+
+ * pango/pango-markup.c: Add a letter_spacing attribute.
+
+ * pango/pango-layout.c: Use G_DEFINE_TYPE().
+
+ * pango/pango-layout.c (pango_layout_get_item_properties):
+ Switch to use a structure rather than a pile of out
+ parameters.
+
+ * pango/pango-layout.c (pango_run_get_extents): Remove
+ the unused shape_set out parameter.
+
+ * pango/pangofc-decoder.[ch] pango/pangofc-fontmap.[ch]:
+ Doc fixes.
+
+ * pango/pango-types.h: Deprecate pango_get_mirror_char()
+
+ * pango/pango-utils.c (pango_get_mirror_char): Add docs.
+
+ * docs/pango-sections.txt docs/pango-docs.sgml: Add
+ PangoFcDecoder and letter spacing.
+
Tue Jun 22 14:10:41 2004 Owen Taylor <otaylor@redhat.com>
* pango/break.c: Handle new Unicode-4.0 WORD_JOINER
diff --git a/ChangeLog.pre-1-6 b/ChangeLog.pre-1-6
index 5e806cfe..77b8baba 100644
--- a/ChangeLog.pre-1-6
+++ b/ChangeLog.pre-1-6
@@ -1,3 +1,39 @@
+Wed Jun 23 11:17:51 2004 Owen Taylor <otaylor@redhat.com>
+
+ * pango/pango-attributes.[ch]: Add new letter_spacing
+ attribute.
+
+ * pango/pango-attributes.c (pango_attr_rise_new): Correct
+ description; rise is in Pango units, not em-relative.
+
+ * pango/pango-glyph-item.c: Break out iteration-over-clusters
+ from ApplyAttrsState into a separate GlyphItemIter.
+
+ * pango/pango-glyph-item.[ch]: New function
+ pango_glyph_item_letter_space() to add add letter spacing
+ to a single glyph item.
+
+ * pango/pango-markup.c: Add a letter_spacing attribute.
+
+ * pango/pango-layout.c: Use G_DEFINE_TYPE().
+
+ * pango/pango-layout.c (pango_layout_get_item_properties):
+ Switch to use a structure rather than a pile of out
+ parameters.
+
+ * pango/pango-layout.c (pango_run_get_extents): Remove
+ the unused shape_set out parameter.
+
+ * pango/pangofc-decoder.[ch] pango/pangofc-fontmap.[ch]:
+ Doc fixes.
+
+ * pango/pango-types.h: Deprecate pango_get_mirror_char()
+
+ * pango/pango-utils.c (pango_get_mirror_char): Add docs.
+
+ * docs/pango-sections.txt docs/pango-docs.sgml: Add
+ PangoFcDecoder and letter spacing.
+
Tue Jun 22 14:10:41 2004 Owen Taylor <otaylor@redhat.com>
* pango/break.c: Handle new Unicode-4.0 WORD_JOINER
diff --git a/ChangeLog.pre-1-8 b/ChangeLog.pre-1-8
index 5e806cfe..77b8baba 100644
--- a/ChangeLog.pre-1-8
+++ b/ChangeLog.pre-1-8
@@ -1,3 +1,39 @@
+Wed Jun 23 11:17:51 2004 Owen Taylor <otaylor@redhat.com>
+
+ * pango/pango-attributes.[ch]: Add new letter_spacing
+ attribute.
+
+ * pango/pango-attributes.c (pango_attr_rise_new): Correct
+ description; rise is in Pango units, not em-relative.
+
+ * pango/pango-glyph-item.c: Break out iteration-over-clusters
+ from ApplyAttrsState into a separate GlyphItemIter.
+
+ * pango/pango-glyph-item.[ch]: New function
+ pango_glyph_item_letter_space() to add add letter spacing
+ to a single glyph item.
+
+ * pango/pango-markup.c: Add a letter_spacing attribute.
+
+ * pango/pango-layout.c: Use G_DEFINE_TYPE().
+
+ * pango/pango-layout.c (pango_layout_get_item_properties):
+ Switch to use a structure rather than a pile of out
+ parameters.
+
+ * pango/pango-layout.c (pango_run_get_extents): Remove
+ the unused shape_set out parameter.
+
+ * pango/pangofc-decoder.[ch] pango/pangofc-fontmap.[ch]:
+ Doc fixes.
+
+ * pango/pango-types.h: Deprecate pango_get_mirror_char()
+
+ * pango/pango-utils.c (pango_get_mirror_char): Add docs.
+
+ * docs/pango-sections.txt docs/pango-docs.sgml: Add
+ PangoFcDecoder and letter spacing.
+
Tue Jun 22 14:10:41 2004 Owen Taylor <otaylor@redhat.com>
* pango/break.c: Handle new Unicode-4.0 WORD_JOINER
diff --git a/docs/pango-docs.sgml b/docs/pango-docs.sgml
index a923b96c..ea014a5e 100644
--- a/docs/pango-docs.sgml
+++ b/docs/pango-docs.sgml
@@ -19,6 +19,7 @@
<!ENTITY pango-Xft-Fonts-and-Rendering SYSTEM "xml/xft-fonts.xml">
<!ENTITY PangoFcFontMap SYSTEM "xml/pangofc-fontmap.xml">
<!ENTITY PangoFcFont SYSTEM "xml/pangofc-font.xml">
+<!ENTITY PangoFcDecoder SYSTEM "xml/pangofc-decoder.xml">
<!ENTITY pango-OpenType-Font-Handling SYSTEM "xml/opentype.xml">
<!ENTITY markup-format SYSTEM "pango_markup.sgml">
<!ENTITY pango-querymodules SYSTEM "pango-querymodules.xml">
@@ -54,6 +55,7 @@
<title>Low Level Functionality</title>
&PangoFcFontMap;
&PangoFcFont;
+ &PangoFcDecoder;
&pango-OpenType-Font-Handling;
&pango-Coverage-Maps;
&pango-Engines;
diff --git a/docs/pango-sections.txt b/docs/pango-sections.txt
index c3b73f90..d6eafa31 100644
--- a/docs/pango-sections.txt
+++ b/docs/pango-sections.txt
@@ -93,6 +93,7 @@ pango_glyph_string_x_to_index
pango_glyph_string_get_logical_widths
pango_glyph_item_split
pango_glyph_item_apply_attrs
+pango_glyph_item_letter_space
<SUBSECTION Private>
pango_glyph_string_get_type
@@ -312,6 +313,7 @@ PANGO_SCALE_LARGE
PANGO_SCALE_X_LARGE
PANGO_SCALE_XX_LARGE
pango_attr_rise_new
+pango_attr_letter_spacing_new
PangoColor
PANGO_TYPE_COLOR
pango_color_free
@@ -697,6 +699,8 @@ pango_fc_font_description_from_pattern
pango_fc_font_map_cache_clear
pango_fc_font_map_create_context
pango_fc_font_map_shutdown
+pango_fc_font_map_add_decoder_find_func
+PangoFcDecoderFindFunc
<SUBSECTION Standard>
PANGO_FC_FONT_MAP
PANGO_IS_FC_FONT_MAP
@@ -734,6 +738,23 @@ pango_fc_font_get_type
</SECTION>
<SECTION>
+<FILE>pangofc-decoder</FILE>
+<TITLE>PangoFcDecoder</TITLE>
+PangoFcDecoder
+PangoFcDecoderClass
+pango_fc_decoder_get_charset
+pango_fc_decoder_get_glyph
+<SUBSECTION Standard>
+PANGO_FC_DECODER
+PANGO_IS_FC_DECODER
+PANGO_TYPE_FC_DECODER
+pango_fc_decoder_get_type
+PANGO_FC_DECODER_CLASS
+PANGO_IS_FC_DECODER_CLASS
+PANGO_FC_DECODER_GET_CLASS
+</SECTION>
+
+<SECTION>
<TITLE>OpenType Font Handling</TITLE>
<FILE>opentype</FILE>
PangoOTTag
diff --git a/docs/pango.types b/docs/pango.types
index 4e54d55f..5cda42a7 100644
--- a/docs/pango.types
+++ b/docs/pango.types
@@ -16,6 +16,7 @@ pango_fontset_get_type
pango_fontset_simple_get_type
pango_fc_font_get_type
pango_fc_font_map_get_type
+pango_fc_decoder_get_type
pango_ft2_font_map_get_type
pango_xft_font_get_type
diff --git a/docs/tmpl/glyphs.sgml b/docs/tmpl/glyphs.sgml
index 952435a3..435d939d 100644
--- a/docs/tmpl/glyphs.sgml
+++ b/docs/tmpl/glyphs.sgml
@@ -393,3 +393,14 @@ The GObject type for #PangoGlyphString.
@Returns:
+<!-- ##### FUNCTION pango_glyph_item_letter_space ##### -->
+<para>
+
+</para>
+
+@glyph_item:
+@text:
+@log_attrs:
+@letter_spacing:
+
+
diff --git a/docs/tmpl/pangofc-fontmap.sgml b/docs/tmpl/pangofc-fontmap.sgml
index 7c505247..db72b732 100644
--- a/docs/tmpl/pangofc-fontmap.sgml
+++ b/docs/tmpl/pangofc-fontmap.sgml
@@ -84,3 +84,24 @@ Fontconfig-based backend involves deriving from both
@fontmap:
+<!-- ##### FUNCTION pango_fc_font_map_add_decoder_find_func ##### -->
+<para>
+
+</para>
+
+@fcfontmap:
+@findfunc:
+@user_data:
+@dnotify:
+
+
+<!-- ##### USER_FUNCTION PangoFcDecoderFindFunc ##### -->
+<para>
+
+</para>
+
+@pattern:
+@user_data:
+@Returns:
+
+
diff --git a/docs/tmpl/text-attributes.sgml b/docs/tmpl/text-attributes.sgml
index 907b2f0a..9690711f 100644
--- a/docs/tmpl/text-attributes.sgml
+++ b/docs/tmpl/text-attributes.sgml
@@ -44,6 +44,7 @@ attribute is listed in parentheses after the description.
@PANGO_ATTR_SHAPE: shape (#PangoAttrShape)
@PANGO_ATTR_SCALE: font size scale factor (#PangoAttrScale)
@PANGO_ATTR_FALLBACK: whether fallback is enabled (#PangoAttrInt)
+@PANGO_ATTR_LETTER_SPACING:
<!-- ##### MACRO PANGO_TYPE_ATTR_TYPE ##### -->
<para>
@@ -421,6 +422,15 @@ The scale factor for three magnification steps (1.2 * 1.2 * 1.2).
@Returns:
+<!-- ##### FUNCTION pango_attr_letter_spacing_new ##### -->
+<para>
+
+</para>
+
+@letter_spacing:
+@Returns:
+
+
<!-- ##### STRUCT PangoColor ##### -->
<para>
The <structname>PangoColor</structname> structure is used to
diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c
index cd0af8bd..fd5be6fb 100644
--- a/pango/pango-attributes.c
+++ b/pango/pango-attributes.c
@@ -601,8 +601,7 @@ pango_attr_strikethrough_new (gboolean strikethrough)
/**
* pango_attr_rise_new:
* @rise: the amount that the text should be displaced vertically,
- * in 10'000ths of an em. Positive values displace the
- * text upwards.
+ * in Pango units. Positive values displace the text upwards.
*
* Create a new baseline displacement attribute.
*
@@ -670,6 +669,30 @@ pango_attr_fallback_new (gboolean enable_fallback)
return pango_attr_int_new (&klass, (int)enable_fallback);
}
+/**
+ * pango_attr_letter_spacing_new:
+ * @letter_spacing: amount of extra space to add between graphemes
+ * of the text, in Pango units.
+ *
+ * Create a new letter-spacing attribute.
+ *
+ * Return value: the new #PangoAttribute.
+ *
+ * Since: 1.6
+ **/
+PangoAttribute *
+pango_attr_letter_spacing_new (int letter_spacing)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_LETTER_SPACING,
+ pango_attr_int_copy,
+ pango_attr_int_destroy,
+ pango_attr_int_equal
+ };
+
+ return pango_attr_int_new (&klass, letter_spacing);
+}
+
static PangoAttribute *
pango_attr_shape_copy (const PangoAttribute *attr)
{
diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h
index a9971fcb..04086c4e 100644
--- a/pango/pango-attributes.h
+++ b/pango/pango-attributes.h
@@ -81,7 +81,8 @@ typedef enum
PANGO_ATTR_RISE, /* PangoAttrInt */
PANGO_ATTR_SHAPE, /* PangoAttrShape */
PANGO_ATTR_SCALE, /* PangoAttrFloat */
- PANGO_ATTR_FALLBACK /* PangoAttrInt */
+ PANGO_ATTR_FALLBACK, /* PangoAttrInt */
+ PANGO_ATTR_LETTER_SPACING /* PangoAttrInt */
} PangoAttrType;
typedef enum {
@@ -182,6 +183,7 @@ PangoAttribute *pango_attr_shape_new (const PangoRectangle *ink_re
const PangoRectangle *logical_rect);
PangoAttribute *pango_attr_scale_new (double scale_factor);
PangoAttribute *pango_attr_fallback_new (gboolean enable_fallback);
+PangoAttribute *pango_attr_letter_spacing_new (int letter_spacing);
GType pango_attr_list_get_type (void) G_GNUC_CONST;
PangoAttrList * pango_attr_list_new (void);
diff --git a/pango/pango-glyph-item.c b/pango/pango-glyph-item.c
index 087f0fa6..b62bf840 100644
--- a/pango/pango-glyph-item.c
+++ b/pango/pango-glyph-item.c
@@ -44,6 +44,8 @@
* it internally)
*
* Return value: new item representing text before @split_index
+ *
+ * Since: 1.2
**/
PangoGlyphItem *
pango_glyph_item_split (PangoGlyphItem *orig,
@@ -124,62 +126,41 @@ pango_glyph_item_split (PangoGlyphItem *orig,
return new;
}
-/* Structure holding state when we're iterating over a GlyphItem for
- * pango_glyph_item_apply_attrs(). cluster_start/cluster_end (and
- * range_start/range_end in apply_attrs()) are offsets into the
- * text, so note the difference of glyph_item->item->offset between
- * them and clusters in the log_clusters[] array.
+/* Structure holding state when we're iterating over a GlyphItem.
+ start_index/cluster_end (and range_start/range_end in
+ apply_attrs()) are offsets into the text, so note the difference
+ of glyph_item->item->offset between them and clusters in the
+ log_clusters[] array.
*/
-typedef struct
+typedef struct
{
PangoGlyphItem *glyph_item;
const gchar *text;
- int glyph_index;
- int cluster_start;
- int cluster_end;
-
- GSList *segment_attrs;
-} ApplyAttrsState;
-
-/* Tack @attrs onto the attributes of glyph_item
- */
-static void
-append_attrs (PangoGlyphItem *glyph_item,
- GSList *attrs)
-{
- glyph_item->item->analysis.extra_attrs =
- g_slist_concat (glyph_item->item->analysis.extra_attrs, attrs);
-}
-
-/* Make a deep copy of a GSlist of PangoAttribute
- */
-static GSList *
-attr_slist_copy (GSList *attrs)
-{
- GSList *tmp_list;
- GSList *new_attrs;
-
- new_attrs = g_slist_copy (attrs);
-
- for (tmp_list = new_attrs; tmp_list; tmp_list = tmp_list->next)
- tmp_list->data = pango_attribute_copy (tmp_list->data);
+ int start_glyph;
+ int start_index;
+ int start_char;
- return new_attrs;
-}
+ int end_glyph;
+ int end_index;
+ int end_char;
+} GlyphItemIter;
-/* Advance to the next logical cluster
+/* Advance to the next cluster, returns FALSE if
+ * we were already on the last cluster
*/
static gboolean
-next_cluster (ApplyAttrsState *state)
+glyph_item_iter_next_cluster (GlyphItemIter *iter)
{
- int glyph_index = state->glyph_index;
- PangoGlyphString *glyphs = state->glyph_item->glyphs;
- PangoItem *item = state->glyph_item->item;
+ int glyph_index = iter->end_glyph;
+ PangoGlyphString *glyphs = iter->glyph_item->glyphs;
+ PangoItem *item = iter->glyph_item->item;
- state->cluster_start = state->cluster_end;
+ iter->start_glyph = iter->end_glyph;
+ iter->start_index = iter->end_index;
+ iter->start_char = iter->end_char;
- if (LTR (state->glyph_item))
+ if (LTR (iter->glyph_item))
{
if (glyph_index == glyphs->num_glyphs)
return FALSE;
@@ -190,13 +171,16 @@ next_cluster (ApplyAttrsState *state)
if (glyph_index == glyphs->num_glyphs)
{
- state->cluster_end = item->offset + item->length;
+ iter->end_index = item->offset + item->length;
+ iter->end_char = item->num_chars;
break;
}
- if (item->offset + glyphs->log_clusters[glyph_index] >= state->cluster_start)
+ if (item->offset + glyphs->log_clusters[glyph_index] >= iter->start_index)
{
- state->cluster_end = item->offset + glyphs->log_clusters[glyph_index];
+ iter->end_index = item->offset + glyphs->log_clusters[glyph_index];
+ iter->end_char += g_utf8_strlen (iter->text + iter->start_index,
+ iter->end_index - iter->start_index);
break;
}
}
@@ -212,37 +196,100 @@ next_cluster (ApplyAttrsState *state)
if (glyph_index < 0)
{
- state->cluster_end = item->offset + item->length;
+ iter->end_index = item->offset + item->length;
+ iter->end_char = item->num_chars;
break;
}
- if (item->offset + glyphs->log_clusters[glyph_index] >= state->cluster_start)
+ if (item->offset + glyphs->log_clusters[glyph_index] >= iter->start_index)
{
- state->cluster_end = item->offset + glyphs->log_clusters[glyph_index];
+ iter->end_index = item->offset + glyphs->log_clusters[glyph_index];
+ iter->end_char += g_utf8_strlen (iter->text + iter->start_index,
+ iter->end_index - iter->start_index);
break;
}
}
}
- state->glyph_index = glyph_index;
+ iter->end_glyph = glyph_index;
return TRUE;
}
+/* Returns FALSE if there are no clusters in the glyph item */
+static gboolean
+glyph_item_iter_init (GlyphItemIter *iter,
+ PangoGlyphItem *glyph_item,
+ const char *text)
+{
+ iter->glyph_item = glyph_item;
+ iter->text = text;
+
+ if (LTR (glyph_item))
+ iter->end_glyph = 0;
+ else
+ iter->end_glyph = glyph_item->glyphs->num_glyphs - 1;
+
+ iter->end_index = glyph_item->item->offset;
+ iter->end_char = 0;
+
+ /* Advance onto the first cluster of the glyph item */
+ return glyph_item_iter_next_cluster (iter);
+}
+
+typedef struct
+{
+ GlyphItemIter iter;
+
+ GSList *segment_attrs;
+} ApplyAttrsState;
+
+/* Tack @attrs onto the attributes of glyph_item
+ */
+static void
+append_attrs (PangoGlyphItem *glyph_item,
+ GSList *attrs)
+{
+ glyph_item->item->analysis.extra_attrs =
+ g_slist_concat (glyph_item->item->analysis.extra_attrs, attrs);
+}
+
+/* Make a deep copy of a GSlist of PangoAttribute
+ */
+static GSList *
+attr_slist_copy (GSList *attrs)
+{
+ GSList *tmp_list;
+ GSList *new_attrs;
+
+ new_attrs = g_slist_copy (attrs);
+
+ for (tmp_list = new_attrs; tmp_list; tmp_list = tmp_list->next)
+ tmp_list->data = pango_attribute_copy (tmp_list->data);
+
+ return new_attrs;
+}
+
/* Split the glyph item at the start of the current cluster
*/
static PangoGlyphItem *
split_before_cluster_start (ApplyAttrsState *state)
{
PangoGlyphItem *split_item;
- int split_len = state->cluster_start - state->glyph_item->item->offset;
+ int split_len = state->iter.start_index - state->iter.glyph_item->item->offset;
- split_item = pango_glyph_item_split (state->glyph_item, state->text, split_len);
+ split_item = pango_glyph_item_split (state->iter.glyph_item, state->iter.text, split_len);
append_attrs (split_item, state->segment_attrs);
/* Adjust iteration to account for the split
*/
- if (LTR (state->glyph_item))
- state->glyph_index -= split_item->glyphs->num_glyphs;
+ if (LTR (state->iter.glyph_item))
+ {
+ state->iter.start_glyph -= split_item->glyphs->num_glyphs;
+ state->iter.end_glyph -= split_item->glyphs->num_glyphs;
+ }
+
+ state->iter.start_char -= split_item->item->num_chars;
+ state->iter.end_char -= split_item->item->num_chars;
return split_item;
}
@@ -273,6 +320,8 @@ split_before_cluster_start (ApplyAttrsState *state)
* Return value: a list of glyph items resulting from splitting
* @glyph_item. Free the elements using pango_glyph_item_free(),
* the list using g_slist_free().
+ *
+ * Since: 1.2
**/
GSList *
pango_glyph_item_apply_attrs (PangoGlyphItem *glyph_item,
@@ -283,6 +332,7 @@ pango_glyph_item_apply_attrs (PangoGlyphItem *glyph_item,
GSList *result = NULL;
ApplyAttrsState state;
gboolean start_new_segment = FALSE;
+ gboolean have_cluster;
int range_start, range_end;
/* This routine works by iterating through the item cluster by
@@ -290,30 +340,20 @@ pango_glyph_item_apply_attrs (PangoGlyphItem *glyph_item,
* add to the next output item, and decide when to split
* off an output item based on two criteria:
*
- * A) If cluster_start < attribute_start < cluster_end
+ * A) If start_index < attribute_start < end_index
* (attribute starts within cluster) then we need
* to split between the last cluster and this cluster.
- * B) If cluster_start < attribute_end <= cluster_end,
+ * B) If start_index < attribute_end <= end_index,
* (attribute ends within cluster) then we need to
* split between this cluster and the next one.
*/
- state.glyph_item = glyph_item;
- state.text = text;
-
- if (LTR (glyph_item))
- state.glyph_index = 0;
- else
- state.glyph_index = glyph_item->glyphs->num_glyphs - 1;
-
- state.cluster_end = glyph_item->item->offset;
-
/* Advance the attr iterator to the start of the item
*/
while (TRUE)
{
pango_attr_iterator_range (iter, &range_start, &range_end);
- if (range_end > state.cluster_end)
+ if (range_end > glyph_item->item->offset)
break;
pango_attr_iterator_next (iter);
@@ -327,14 +367,15 @@ pango_glyph_item_apply_attrs (PangoGlyphItem *glyph_item,
if (range_start <= glyph_item->item->offset &&
range_end >= glyph_item->item->offset + glyph_item->item->length)
goto out;
-
- while (TRUE)
+
+ for (have_cluster = glyph_item_iter_init (&state.iter, glyph_item, text);
+ have_cluster;
+ have_cluster = glyph_item_iter_next_cluster (&state.iter))
{
- /* Find the next logical cluster; [range_start,range_end]
- * is the first range that intersects the new cluster.
+
+ /* [range_start,range_end] is the first range that intersects
+ * the current cluster.
*/
- if (!next_cluster (&state))
- break;
/* Split item into two, if this cluster isn't a continuation
* of the last cluster
@@ -357,29 +398,29 @@ pango_glyph_item_apply_attrs (PangoGlyphItem *glyph_item,
/* If any ranges end in this cluster, then the next cluster
* goes into a separate segment
*/
- if (range_end <= state.cluster_end)
+ if (range_end <= state.iter.end_index)
start_new_segment = TRUE;
- if (range_end > state.cluster_end) /* Range intersects next cluster */
+ if (range_end > state.iter.end_index) /* Range intersects next cluster */
break;
pango_attr_iterator_next (iter);
pango_attr_iterator_range (iter, &range_start, &range_end);
- if (range_start >= state.cluster_end) /* New range doesn't intersect this cluster */
+ if (range_start >= state.iter.end_index) /* New range doesn't intersect this cluster */
{
/* No gap between ranges, so previous range must of ended
* at cluster boundary.
*/
- g_assert (range_start == state.cluster_end && start_new_segment);
+ g_assert (range_start == state.iter.end_index && start_new_segment);
break;
}
/* If any ranges start *inside* this cluster, then we need
* to split the previous cluster into a separate segment
*/
- if (range_start > state.cluster_start &&
- state.cluster_start != glyph_item->item->offset)
+ if (range_start > state.iter.start_index &&
+ state.iter.start_index != glyph_item->item->offset)
{
GSList *new_attrs = attr_slist_copy (state.segment_attrs);
result = g_slist_prepend (result,
@@ -390,6 +431,9 @@ pango_glyph_item_apply_attrs (PangoGlyphItem *glyph_item,
state.segment_attrs = g_slist_concat (state.segment_attrs,
pango_attr_iterator_get_attrs (iter));
}
+
+ if (!glyph_item_iter_next_cluster (&state.iter))
+ break;
}
out:
@@ -405,3 +449,45 @@ pango_glyph_item_apply_attrs (PangoGlyphItem *glyph_item,
return result;
}
+
+/**
+ * pango_glyph_item_letter_space:
+ * @glyph_item: a #PangoGlyphItem
+ * @text: text that @glyph_item corresponds to
+ * (glyph_item->item->offset is an offset from the
+ * start of @text)
+ * @log_attrs: logical attributes for the item (the
+ * first logical attribute refers to the position
+ * before the first character in the item)
+ * @letter_spacing: amount of letter spacing to add
+ * in Pango units. May be negative, though too large
+ * negative values will give ugly results.
+ *
+ * Adds spacing between the graphemes of @glyph_item to
+ * give the effect of typographic letter spacing.b
+ *
+ * Since: 1.6
+ **/
+void
+pango_glyph_item_letter_space (PangoGlyphItem *glyph_item,
+ const char *text,
+ PangoLogAttr *log_attrs,
+ int letter_spacing)
+{
+ GlyphItemIter iter;
+ gboolean have_cluster;
+
+ for (have_cluster = glyph_item_iter_init (&iter, glyph_item, text);
+ have_cluster;
+ have_cluster = glyph_item_iter_next_cluster (&iter))
+ {
+ if (iter.start_char > 0 &&
+ log_attrs[iter.start_char].is_cursor_position)
+ {
+ if (iter.start_glyph < iter.end_glyph) /* LTR */
+ glyph_item->glyphs->glyphs[iter.start_glyph - 1].geometry.width += letter_spacing;
+ else /* RTL */
+ glyph_item->glyphs->glyphs[iter.start_glyph].geometry.width += letter_spacing;
+ }
+ }
+}
diff --git a/pango/pango-glyph-item.h b/pango/pango-glyph-item.h
index c9849f47..01a57489 100644
--- a/pango/pango-glyph-item.h
+++ b/pango/pango-glyph-item.h
@@ -24,6 +24,7 @@
#define __PANGO_GLYPH_ITEM_H__
#include <pango/pango-attributes.h>
+#include <pango/pango-break.h>
#include <pango/pango-item.h>
#include <pango/pango-glyph.h>
@@ -37,12 +38,16 @@ struct _PangoGlyphItem
PangoGlyphString *glyphs;
};
-PangoGlyphItem *pango_glyph_item_split (PangoGlyphItem *orig,
- const char *text,
- int split_index);
-GSList * pango_glyph_item_apply_attrs (PangoGlyphItem *glyph_item,
- const char *text,
- PangoAttrList *list);
+PangoGlyphItem *pango_glyph_item_split (PangoGlyphItem *orig,
+ const char *text,
+ int split_index);
+GSList * pango_glyph_item_apply_attrs (PangoGlyphItem *glyph_item,
+ const char *text,
+ PangoAttrList *list);
+void pango_glyph_item_letter_space (PangoGlyphItem *glyph_item,
+ const char *text,
+ PangoLogAttr *log_attrs,
+ int letter_spacing);
G_END_DECLS
diff --git a/pango/pango-layout.c b/pango/pango-layout.c
index 278c6766..108a8aaa 100644
--- a/pango/pango-layout.c
+++ b/pango/pango-layout.c
@@ -29,6 +29,7 @@
#define LINE_IS_VALID(line) ((line)->layout != NULL)
typedef struct _Extents Extents;
+typedef struct _ItemProperties ItemProperties;
struct _Extents
{
@@ -40,6 +41,16 @@ struct _Extents
PangoRectangle logical_rect;
};
+struct _ItemProperties
+{
+ PangoUnderline uline;
+ gint rise;
+ gint letter_spacing;
+ gboolean shape_set;
+ PangoRectangle *shape_ink_rect;
+ PangoRectangle *shape_logical_rect;
+};
+
struct _PangoLayoutIter
{
PangoLayout *layout;
@@ -63,9 +74,6 @@ struct _PangoLayoutIter
/* X position of the current run */
int run_x;
- /* Does the run have a shape attribute */
- gboolean run_is_shaped;
-
/* Extents of the current run */
PangoRectangle run_logical_rect;
@@ -152,45 +160,13 @@ static int *pango_layout_line_get_vis2log_map (PangoLayoutLine *line,
gboolean strong);
static void pango_layout_get_item_properties (PangoItem *item,
- PangoUnderline *uline,
- gint *rise,
- PangoRectangle *ink_rect,
- PangoRectangle *logical_rect,
- gboolean *shape_set);
+ ItemProperties *properties);
static void pango_layout_init (PangoLayout *layout);
static void pango_layout_class_init (PangoLayoutClass *klass);
static void pango_layout_finalize (GObject *object);
-static gpointer parent_class;
-
-GType
-pango_layout_get_type (void)
-{
- static GType object_type = 0;
-
- if (!object_type)
- {
- static const GTypeInfo object_info =
- {
- sizeof (PangoLayoutClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) pango_layout_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (PangoLayout),
- 0, /* n_preallocs */
- (GInstanceInitFunc) pango_layout_init,
- };
-
- object_type = g_type_register_static (G_TYPE_OBJECT,
- "PangoLayout",
- &object_info, 0);
- }
-
- return object_type;
-}
+G_DEFINE_TYPE (PangoLayout, pango_layout, G_TYPE_OBJECT)
static void
pango_layout_init (PangoLayout *layout)
@@ -219,8 +195,6 @@ pango_layout_class_init (PangoLayoutClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- parent_class = g_type_class_peek_parent (klass);
-
object_class->finalize = pango_layout_finalize;
}
@@ -247,7 +221,7 @@ pango_layout_finalize (GObject *object)
if (layout->tabs)
pango_tab_array_free (layout->tabs);
- G_OBJECT_CLASS (parent_class)->finalize (object);
+ G_OBJECT_CLASS (pango_layout_parent_class)->finalize (object);
}
@@ -1038,19 +1012,17 @@ pango_layout_line_index_to_x (PangoLayoutLine *line,
while (run_list)
{
- PangoRectangle logical_rect;
PangoLayoutRun *run = run_list->data;
- gboolean shape_set;
+ ItemProperties properties;
- pango_layout_get_item_properties (run->item, NULL, NULL, NULL,
- &logical_rect, &shape_set);
+ pango_layout_get_item_properties (run->item, &properties);
if (run->item->offset <= index && run->item->offset + run->item->length > index)
{
- if (shape_set)
+ if (properties.shape_set)
{
if (x_pos)
- *x_pos = width + (trailing > 0 ? logical_rect.width : 0);
+ *x_pos = width + (trailing > 0 ? properties.shape_logical_rect->width : 0);
}
else
{
@@ -1088,11 +1060,18 @@ pango_layout_line_index_to_x (PangoLayoutLine *line,
return;
}
- if (!shape_set)
- pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
- NULL, &logical_rect);
-
- width += logical_rect.width;
+ if (!properties.shape_set)
+ {
+ PangoRectangle logical_rect;
+
+ pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
+ NULL, &logical_rect);
+ width += logical_rect.width;
+ }
+ else
+ {
+ width += properties.shape_logical_rect->width;
+ }
run_list = run_list->next;
}
@@ -2603,15 +2582,57 @@ struct _ParaBreakState
int start_offset; /* Character offset of first item in state->items in layout->text */
PangoGlyphString *glyphs; /* Glyphs for the first item in state->items */
+ ItemProperties properties; /* Properties for the first item in state->items */
PangoGlyphUnit *log_widths; /* Logical widths for first item in state->items.. */
int log_widths_offset; /* Offset into log_widths to the point corresponding
* to the remaining portion of the first item */
};
+static PangoGlyphString *
+shape_run (PangoLayoutLine *line,
+ ParaBreakState *state,
+ PangoItem *item)
+{
+ PangoLayout *layout = line->layout;
+ PangoGlyphString *glyphs = pango_glyph_string_new ();
+
+ if (layout->text[item->offset] == '\t')
+ shape_tab (line, glyphs);
+ else
+ {
+ if (state->properties.shape_set)
+ imposed_shape (layout->text + item->offset, item->num_chars,
+ state->properties.shape_ink_rect, state->properties.shape_logical_rect,
+ glyphs);
+ else
+ pango_shape (layout->text + item->offset, item->length, &item->analysis, glyphs);
+
+ if (state->properties.letter_spacing)
+ {
+ PangoGlyphItem glyph_item;
+
+ glyph_item.item = item;
+ glyph_item.glyphs = glyphs;
+
+ pango_glyph_item_letter_space (&glyph_item,
+ layout->text,
+ layout->log_attrs + state->start_offset,
+ state->properties.letter_spacing);
+
+ /* We put all the letter spacing after the last glyph, then
+ * will go back and redistribute it at the beginning and the
+ * end in a post-processing step over the whole line.
+ */
+ glyphs->glyphs[glyphs->num_glyphs - 1].geometry.width += state->properties.letter_spacing;
+ }
+ }
+
+ return glyphs;
+}
+
static void
insert_run (PangoLayoutLine *line,
ParaBreakState *state,
- const char *text,
PangoItem *run_item,
gboolean last_run)
{
@@ -2622,14 +2643,7 @@ insert_run (PangoLayoutLine *line,
if (last_run && state->log_widths_offset == 0)
run->glyphs = state->glyphs;
else
- {
- run->glyphs = pango_glyph_string_new ();
-
- if (text[run_item->offset] == '\t')
- shape_tab (line, run->glyphs);
- else
- pango_shape (text + run_item->offset, run_item->length, &run_item->analysis, run->glyphs);
- }
+ run->glyphs = shape_run (line, state, run_item);
if (last_run)
{
@@ -2668,8 +2682,6 @@ process_item (PangoLayout *layout,
gboolean force_fit,
gboolean no_break_at_end)
{
- PangoRectangle shape_ink;
- PangoRectangle shape_logical;
PangoItem *item = state->items->data;
gboolean shape_set = FALSE;
int width;
@@ -2683,20 +2695,9 @@ process_item (PangoLayout *layout,
if (!state->glyphs)
{
- state->glyphs = pango_glyph_string_new ();
+ pango_layout_get_item_properties (item, &state->properties);
+ state->glyphs = shape_run (line, state, item);
- pango_layout_get_item_properties (item, NULL, NULL,
- &shape_ink,
- &shape_logical,
- &shape_set);
-
- if (shape_set)
- imposed_shape (layout->text + item->offset, item->num_chars, &shape_ink, &shape_logical, state->glyphs);
- else if (layout->text[item->offset] == '\t')
- shape_tab (line, state->glyphs);
- else
- pango_shape (layout->text + item->offset, item->length, &item->analysis, state->glyphs);
-
state->log_widths = NULL;
state->log_widths_offset = 0;
@@ -2705,14 +2706,14 @@ process_item (PangoLayout *layout,
if (g_utf8_get_char (layout->text + item->offset) == LINE_SEPARATOR)
{
- insert_run (line, state, layout->text, item, TRUE);
+ insert_run (line, state, item, TRUE);
state->log_widths_offset += item->num_chars;
return BREAK_LINE_SEPARATOR;
}
if (state->remaining_width < 0 && !no_break_at_end) /* Wrapping off */
{
- insert_run (line, state, layout->text, item, TRUE);
+ insert_run (line, state, item, TRUE);
return BREAK_ALL_FIT;
}
@@ -2722,11 +2723,17 @@ process_item (PangoLayout *layout,
{
for (i = 0; i < state->glyphs->num_glyphs; i++)
width += state->glyphs->glyphs[i].geometry.width;
+
+ /* We'll add half the letter spacing to each side of the item */
+ width += state->properties.letter_spacing;
}
else
{
for (i = 0; i < item->num_chars; i++)
width += state->log_widths[state->log_widths_offset + i];
+
+ /* In this case, the letter spacing width has already been
+ * added to the last element in log_widths */
}
if ((width <= state->remaining_width || (item->num_chars == 1 && !line->runs)) &&
@@ -2734,7 +2741,7 @@ process_item (PangoLayout *layout,
{
state->remaining_width -= width;
state->remaining_width = MAX (state->remaining_width, 0);
- insert_run (line, state, layout->text, item, TRUE);
+ insert_run (line, state, item, TRUE);
return BREAK_ALL_FIT;
}
@@ -2752,6 +2759,13 @@ process_item (PangoLayout *layout,
pango_glyph_string_get_logical_widths (state->glyphs,
layout->text + item->offset, item->length, item->analysis.level,
state->log_widths);
+
+ /* The extra run letter spacing is actually divided after
+ * the last and and before the first, but it works to
+ * account it all on the last
+ */
+ if (item->num_chars > 0)
+ state->log_widths[item->num_chars] += state->properties.letter_spacing;
}
retry_break:
@@ -2794,7 +2808,7 @@ process_item (PangoLayout *layout,
if (break_num_chars == item->num_chars)
{
- insert_run (line, state, layout->text, item, TRUE);
+ insert_run (line, state, item, TRUE);
return BREAK_ALL_FIT;
}
@@ -2810,7 +2824,7 @@ process_item (PangoLayout *layout,
new_item = pango_item_split (item, length, break_num_chars);
- insert_run (line, state, layout->text, new_item, FALSE);
+ insert_run (line, state, new_item, FALSE);
state->log_widths_offset += break_num_chars;
@@ -3366,14 +3380,15 @@ pango_layout_line_x_to_index (PangoLayoutLine *line,
tmp_list = line->runs;
while (tmp_list)
{
- PangoRectangle logical_rect;
PangoLayoutRun *run = tmp_list->data;
- gboolean shape_set;
+ PangoRectangle logical_rect;
+ ItemProperties properties;
- pango_layout_get_item_properties (run->item, NULL, NULL,
- NULL, &logical_rect, &shape_set);
+ pango_layout_get_item_properties (run->item, &properties);
- if (!shape_set)
+ if (properties.shape_set)
+ logical_rect = *properties.shape_logical_rect;
+ else
pango_glyph_string_extents (run->glyphs, run->item->analysis.font, NULL, &logical_rect);
if (x_pos >= start_pos && x_pos < start_pos + logical_rect.width)
@@ -3388,7 +3403,7 @@ pango_layout_line_x_to_index (PangoLayoutLine *line,
char_index = run->item->offset;
- if (shape_set)
+ if (properties.shape_set)
{
*trailing = 0;
}
@@ -3697,28 +3712,22 @@ pango_layout_line_get_empty_extents (PangoLayoutLine *line,
static void
pango_layout_run_get_extents (PangoLayoutRun *run,
- gboolean *shape_setp,
PangoRectangle *run_ink,
PangoRectangle *run_logical)
{
PangoUnderline uline = PANGO_UNDERLINE_NONE;
- int rise = 0;
- PangoRectangle shape_ink;
- PangoRectangle shape_logical;
+ ItemProperties properties;
PangoRectangle tmp_ink;
- gboolean shape_set;
gboolean need_ink;
- pango_layout_get_item_properties (run->item, &uline, &rise,
- &shape_ink, &shape_logical, &shape_set);
-
- if (shape_setp)
- *shape_setp = shape_set;
+ pango_layout_get_item_properties (run->item, &properties);
need_ink = run_ink || uline == PANGO_UNDERLINE_LOW;
- if (shape_set)
- imposed_extents (run->item->num_chars, &shape_ink, &shape_logical,
+ if (properties.shape_set)
+ imposed_extents (run->item->num_chars,
+ properties.shape_ink_rect,
+ properties.shape_logical_rect,
need_ink ? &tmp_ink : NULL, run_logical);
else
pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
@@ -3728,7 +3737,7 @@ pango_layout_run_get_extents (PangoLayoutRun *run,
if (run_ink)
*run_ink = tmp_ink;
- switch (uline)
+ switch (properties.uline)
{
case PANGO_UNDERLINE_NONE:
break;
@@ -3761,13 +3770,13 @@ pango_layout_run_get_extents (PangoLayoutRun *run,
break;
}
- if (rise != 0)
+ if (properties.rise != 0)
{
if (run_ink)
- run_ink->y -= rise;
+ run_ink->y -= properties.rise;
if (run_logical)
- run_logical->y -= rise;
+ run_logical->y -= properties.rise;
}
}
@@ -3820,7 +3829,7 @@ pango_layout_line_get_extents (PangoLayoutLine *line,
PangoRectangle run_ink;
PangoRectangle run_logical;
- pango_layout_run_get_extents (run, NULL,
+ pango_layout_run_get_extents (run,
ink_rect ? &run_ink : NULL,
&run_logical);
@@ -3997,6 +4006,118 @@ pango_layout_line_reorder (PangoLayoutLine *line)
g_slist_free (logical_runs);
}
+static int
+get_item_letter_spacing (PangoItem *item)
+{
+ ItemProperties properties;
+
+ pango_layout_get_item_properties (item, &properties);
+
+ return properties.letter_spacing;
+}
+
+static void
+adjust_final_space (PangoGlyphString *glyphs,
+ int adjustment)
+{
+ glyphs->glyphs[glyphs->num_glyphs - 1].geometry.width += adjustment;
+}
+
+static gboolean
+is_tab_run (PangoLayout *layout,
+ PangoLayoutRun *run)
+{
+ return (layout->text[run->item->offset] == '\t');
+}
+
+/* When doing shaping, we add the letter spacing value for a
+ * run after every grapheme in the run. This produces ugly
+ * asymetrical results, so what this routine is redistributes
+ * that space to the beginning and the end of the run.
+ *
+ * We also trim the letter spacing from runs adjacent to
+ * tabs and from the outside runs of the lines so that things
+ * line up properly. The line breaking and tab positioning
+ * were computed without this trimming so they are no longer
+ * exactly correct, but this won't be very noticable in most
+ * cases.
+ */
+static void
+adjust_line_letter_spacing (PangoLayoutLine *line)
+{
+ PangoLayout *layout = line->layout;
+ gboolean reversed;
+ PangoLayoutRun *last_run;
+ int tab_adjustment;
+ GSList *l;
+
+ /* If we have tab stops and the resolved direction of the
+ * line is RTL, then we need to walk through the line
+ * in reverse direction to figure out the corrections for
+ * tab stops.
+ */
+ reversed = FALSE;
+ if (line->resolved_dir == PANGO_DIRECTION_RTL)
+ {
+ for (l = line->runs; l; l = l->next)
+ if (is_tab_run (layout, l->data))
+ {
+ line->runs = g_slist_reverse (line->runs);
+ reversed = TRUE;
+ break;
+ }
+ }
+
+ /* Walk over the runs in the line, redistributing letter
+ * spacing from the end of the run to the start of the
+ * run and trimming letter spacing from the ends of the
+ * runs adjacent to the ends of the line or tab stops.
+ *
+ * We accumulate a correction factor from this trimming
+ * which we add onto the next tab stop space to keep the
+ * things properly aligned.
+ */
+
+ last_run = NULL;
+ tab_adjustment = 0;
+ for (l = line->runs; l; l = l->next)
+ {
+ PangoLayoutRun *run = l->data;
+ PangoLayoutRun *next_run = l->next ? l->next->data : NULL;
+
+ if (is_tab_run (layout, run))
+ {
+ adjust_final_space (run->glyphs, tab_adjustment);
+ tab_adjustment = 0;
+ }
+ else
+ {
+ PangoLayoutRun *visual_next_run = reversed ? last_run : next_run;
+ PangoLayoutRun *visual_last_run = reversed ? next_run : last_run;
+ int run_spacing = get_item_letter_spacing (run->item);
+ int adjustment = run_spacing / 2;
+
+ if (visual_last_run && !is_tab_run (layout, visual_last_run))
+ adjust_final_space (visual_last_run->glyphs, adjustment);
+ else
+ tab_adjustment += adjustment;
+
+ if (visual_next_run && !is_tab_run (layout, visual_next_run))
+ adjust_final_space (run->glyphs, - adjustment);
+ else
+ {
+ adjust_final_space (run->glyphs, - run_spacing);
+ tab_adjustment += run_spacing - adjustment;
+ }
+ }
+
+ last_run = run;
+ }
+
+ if (reversed)
+ line->runs = g_slist_reverse (line->runs);
+}
+
static void
pango_layout_line_postprocess (PangoLayoutLine *line)
{
@@ -4010,30 +4131,25 @@ pango_layout_line_postprocess (PangoLayoutLine *line)
/* Now convert logical to visual order
*/
pango_layout_line_reorder (line);
+
+ /* Fixup letter spacing between runs
+ */
+ adjust_line_letter_spacing (line);
}
-/* This utility function is duplicated here and in pangox.c; should it be
- * public? Trouble is - what is the appropriate set of properties?
- */
static void
pango_layout_get_item_properties (PangoItem *item,
- PangoUnderline *uline,
- gint *rise,
- PangoRectangle *ink_rect,
- PangoRectangle *logical_rect,
- gboolean *shape_set)
+ ItemProperties *properties)
{
GSList *tmp_list = item->analysis.extra_attrs;
- if (shape_set)
- *shape_set = FALSE;
-
- if (rise)
- *rise = 0;
+ properties->uline = PANGO_UNDERLINE_NONE;
+ properties->letter_spacing = 0;
+ properties->rise = 0;
+ properties->shape_set = FALSE;
+ properties->shape_ink_rect = NULL;
+ properties->shape_logical_rect = NULL;
- if (uline)
- *uline = PANGO_UNDERLINE_NONE;
-
while (tmp_list)
{
PangoAttribute *attr = tmp_list->data;
@@ -4041,24 +4157,23 @@ pango_layout_get_item_properties (PangoItem *item,
switch (attr->klass->type)
{
case PANGO_ATTR_UNDERLINE:
- if (uline)
- *uline = ((PangoAttrInt *)attr)->value;
+ properties->uline = ((PangoAttrInt *)attr)->value;
break;
case PANGO_ATTR_RISE:
- if (rise)
- *rise = ((PangoAttrInt *)attr)->value;
+ properties->rise = ((PangoAttrInt *)attr)->value;
break;
+ case PANGO_ATTR_LETTER_SPACING:
+ properties->letter_spacing = ((PangoAttrInt *)attr)->value;
+ break;
+
case PANGO_ATTR_SHAPE:
- if (shape_set)
- *shape_set = TRUE;
- if (logical_rect)
- *logical_rect = ((PangoAttrShape *)attr)->logical_rect;
- if (ink_rect)
- *ink_rect = ((PangoAttrShape *)attr)->ink_rect;
+ properties->shape_set = TRUE;
+ properties->shape_logical_rect = &((PangoAttrShape *)attr)->logical_rect;
+ properties->shape_ink_rect = &((PangoAttrShape *)attr)->ink_rect;
break;
-
+
default:
break;
}
@@ -4157,7 +4272,6 @@ update_run (PangoLayoutIter *iter,
if (iter->run)
{
pango_layout_run_get_extents (iter->run,
- &iter->run_is_shaped,
NULL,
&iter->run_logical_rect);
@@ -4168,8 +4282,6 @@ update_run (PangoLayoutIter *iter,
}
else
{
- iter->run_is_shaped = FALSE;
-
iter->run_logical_rect.x = iter->run_x;
iter->run_logical_rect.y = line_ext->logical_rect.y;
iter->run_logical_rect.width = 0;
@@ -4694,7 +4806,7 @@ pango_layout_iter_get_run_extents (PangoLayoutIter *iter,
{
if (iter->run)
{
- pango_layout_run_get_extents (iter->run, NULL, ink_rect, NULL);
+ pango_layout_run_get_extents (iter->run, ink_rect, NULL);
offset_y (iter, &ink_rect->y);
ink_rect->x += iter->run_x;
}
diff --git a/pango/pango-markup.c b/pango/pango-markup.c
index a4bd108c..3b45cc73 100644
--- a/pango/pango-markup.c
+++ b/pango/pango-markup.c
@@ -857,6 +857,7 @@ span_parse_func (MarkupData *md,
const char *underline = NULL;
const char *strikethrough = NULL;
const char *rise = NULL;
+ const char *letter_spacing = NULL;
const char *lang = NULL;
const char *fallback = NULL;
@@ -928,6 +929,11 @@ span_parse_func (MarkupData *md,
CHECK_DUPLICATE (rise);
rise = values[i];
}
+ else if (strcmp (names[i], "letter_spacing") == 0)
+ {
+ CHECK_DUPLICATE (letter_spacing);
+ letter_spacing = values[i];
+ }
else if (strcmp (names[i], "lang") == 0)
{
CHECK_DUPLICATE (lang);
@@ -1231,6 +1237,28 @@ span_parse_func (MarkupData *md,
add_attribute (tag, pango_attr_rise_new (n));
}
+ if (letter_spacing)
+ {
+ char *end = NULL;
+ glong n;
+
+ n = strtol (letter_spacing, &end, 10);
+
+ if (*end != '\0')
+ {
+ g_set_error (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_INVALID_CONTENT,
+ _("Value of 'letter_spacing' attribute on <span> tag "
+ "on line %d could not be parsed; "
+ "should be an integer, not '%s'"),
+ line_number, letter_spacing);
+ goto error;
+ }
+
+ add_attribute (tag, pango_attr_letter_spacing_new (n));
+ }
+
if (lang)
{
add_attribute (tag,
diff --git a/pango/pango-types.h b/pango/pango-types.h
index 7e1259ab..e2168866 100644
--- a/pango/pango-types.h
+++ b/pango/pango-types.h
@@ -172,8 +172,12 @@ PangoLanguage *pango_language_from_string (const char *language);
gboolean pango_language_matches (PangoLanguage *language,
const char *range_list);
+#ifndef PANGO_DISABLE_DEPRECATED
gboolean pango_get_mirror_char (gunichar ch,
gunichar *mirrored_ch);
+#endif
+
+
PangoDirection pango_unichar_direction (gunichar ch);
PangoDirection pango_find_base_dir (const gchar *text,
gint length);
diff --git a/pango/pango-utils.c b/pango/pango-utils.c
index 96378168..768ac8e6 100644
--- a/pango/pango-utils.c
+++ b/pango/pango-utils.c
@@ -1391,6 +1391,21 @@ pango_log2vis_get_embedding_levels (gunichar *str,
#endif /* HAVE_FRIBIDI */
+/**
+ * pango_get_mirror_char:
+ * @ch: a unicode character
+ * @mirrored_ch: location to store the mirrored character
+ *
+ * If @ch has the Unicode mirrored property and there is another unicode
+ * character that typically has a glyph that is the mirror image of @ch's
+ * glyph, puts that character in the address pointed to by @mirrored_ch.
+ *
+ * Use g_unichar_get_mirror_char() instead; the docs for that function
+ * provide full details.
+ *
+ * Return value: %TRUE if @ch has a mirrored character and @mirrored_ch is
+ * filled in, %FALSE otherwise
+ **/
gboolean
pango_get_mirror_char (gunichar ch,
gunichar *mirrored_ch)
diff --git a/pango/pangofc-decoder.c b/pango/pangofc-decoder.c
index ff177b1e..118c17e8 100644
--- a/pango/pangofc-decoder.c
+++ b/pango/pangofc-decoder.c
@@ -41,19 +41,19 @@ pango_fc_decoder_class_init (PangoFcDecoderClass *klass)
/**
* pango_fc_decoder_get_charset:
- * @decoder: A #PangoFcDecoder to use when querying the font for a
- * supported #FcCharSet.
- * @fcfont: The #PangoFcFont to query.
+ * @decoder: a #PangoFcDecoder
+ * @fcfont: the #PangoFcFont to query.
*
* Generates an #FcCharSet of supported characters for the fcfont
- * given. The returned #FcCharSet should be a reference to an
- * internal value stored by the #PangoFcDecoder and will not be freed
- * by Pango.
+ * given. The returned #FcCharSet will be a reference to an
+ * internal value stored by the #PangoFcDecoder and must not
+ * be modified or freed.
*
- * Since: 1.6
+ * Return value: the #FcCharset for @fcfont; must not be modified
+ * or freed.
*
- */
-
+ * Since: 1.6
+ **/
FcCharSet *
pango_fc_decoder_get_charset (PangoFcDecoder *decoder,
PangoFcFont *fcfont)
@@ -65,22 +65,25 @@ pango_fc_decoder_get_charset (PangoFcDecoder *decoder,
/**
* pango_fc_decoder_get_glyph:
- * @decoder: A #PangoFcDecoder to use when querying the font.
- * @fcfont: The #PangoFcFont to query.
- * @wc: The unicode code point that you would like to see converted to
- * a single #PangoGlyph.
+ * @decoder: a #PangoFcDecoder
+ * @fcfont: a #PangoFcFont to query.
+ * @wc: the unicode code point to convert to a single #PangoGlyph.
*
- * Generates a #PangoGlyph for the given unicode point with the custom
- * decoder.
+ * Generates a #PangoGlyph for the given unicode point using the
+ * custom decoder. For complex scripts where there can be multiple
+ * glyphs for a single character, the decoder will return whatever
+ * glyph is most convenient for it. (Usually whatever glyph is directly
+ * in the fonts character map table.)
*
- * Since: 1.6
+ * Return value: the glyph index, or 0 if the glyph isn't covered
+ * by the font.
*
- */
-
+ * Since: 1.6
+ **/
PangoGlyph
-pango_fc_decoder_get_glyph (PangoFcDecoder *decoder,
- PangoFcFont *fcfont,
- guint32 wc)
+pango_fc_decoder_get_glyph (PangoFcDecoder *decoder,
+ PangoFcFont *fcfont,
+ guint32 wc)
{
g_return_val_if_fail (PANGO_IS_FC_DECODER (decoder), 0);
diff --git a/pango/pangofc-decoder.h b/pango/pangofc-decoder.h
index 0178ab1b..d5bb6818 100644
--- a/pango/pangofc-decoder.h
+++ b/pango/pangofc-decoder.h
@@ -46,37 +46,33 @@ typedef struct _PangoFcDecoderClass PangoFcDecoderClass;
* function callback that was originally registered with
* pango_fc_font_map_add_decoder_find_func(). Pango requires
* information about the supported charset for a font as well as the
- * indivdual character to glyph conversions. Pango gets that
+ * individual character to glyph conversions. Pango gets that
* information via the #get_charset and #get_glyph callbacks into your
* object implementation.
*
* Since: 1.6
- *
**/
-
struct _PangoFcDecoder
{
+ /*< private >*/
GObject parent_instance;
};
/**
* PangoFcDecoderClass:
- *
* @get_charset: This returns an #FcCharset given a #PangoFcFont that
- * includes a list of supported characters in the font. The
- * #FcCharSet that is returned should be an internal reference to your
- * code. Pango will not free this structure. It is also important
- * that you make this callback very fast because this callback is also
- * used to determine unicode coverage on a per-character basis.
+ * includes a list of supported characters in the font. The
+ * #FcCharSet that is returned should be an internal reference to your
+ * code. Pango will not free this structure. It is important that
+ * you make this callback fast because this callback is called
+ * separately for each character to determine unicode coverage.
* @get_glyph: This returns a single #PangoGlyph for a given unicode
- * code point.
+ * code point.
*
* Class structure for #PangoFcDecoder.
*
* Since: 1.6
- *
**/
-
struct _PangoFcDecoderClass
{
/*< private >*/
diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c
index 63c628a6..2fc88d50 100644
--- a/pango/pangofc-fontmap.c
+++ b/pango/pangofc-fontmap.c
@@ -343,28 +343,27 @@ pango_fc_clear_pattern_hashes (PangoFcFontMap *fcfontmap)
}
/**
- * pango_fc_font_map_add_find_func:
+ * pango_fc_font_map_add_decoder_find_func:
* @fcfontmap: The #PangoFcFontMap to add this method to.
- * @factory: The #PangoFcDecoderFindFunc callback function
+ * @findfunc: The #PangoFcDecoderFindFunc callback function
* @user_data: User data.
* @dnotify: A #GDestroyNotify callback that will be called when the
- * fontmap is finalized and the decoder is released.
+ * fontmap is finalized and the decoder is released.
*
* This function saves a callback method in the #PangoFcFontMap that
- * will be called whenever new fonts are created. If the function
- * returns a #PangoFcDecoder, that decoder will be used to determine
- * both coverage via a #FcCharSet and a one-to-one mapping of
+ * will be called whenever new fonts are created. If the
+ * function returns a #PangoFcDecoder, that decoder will be used to
+ * determine both coverage via a #FcCharSet and a one-to-one mapping of
* characters to glyphs. This will allow applications to have
* application-specific encodings for various fonts.
*
* Since: 1.6.
- *
- */
-
-void pango_fc_font_map_add_decoder_find_func (PangoFcFontMap *fcfontmap,
- PangoFcDecoderFindFunc findfunc,
- gpointer user_data,
- GDestroyNotify dnotify)
+ **/
+void
+pango_fc_font_map_add_decoder_find_func (PangoFcFontMap *fcfontmap,
+ PangoFcDecoderFindFunc findfunc,
+ gpointer user_data,
+ GDestroyNotify dnotify)
{
PangoFcFontMapPrivate *priv = fcfontmap->priv;
PangoFcFindFuncInfo *info;
diff --git a/pango/pangofc-fontmap.h b/pango/pangofc-fontmap.h
index 3ad3430a..f5d193be 100644
--- a/pango/pangofc-fontmap.h
+++ b/pango/pangofc-fontmap.h
@@ -99,6 +99,16 @@ void pango_fc_font_map_shutdown (PangoFcFontMap *fcfontmap);
GType pango_fc_font_map_get_type (void);
+/**
+ * PangoFcDecoderFindFunc:
+ * @pattern: a fully resolved #FcPattern specifying the font on the system
+ * @user_data: user data passed to pango_fc_font_map_add_decoder_find_func()
+ *
+ * Callback function passed to pango_fc_font_map_add_decoder_find_func().
+ *
+ * Return value: a new reference to a custom decoder for this pattern,
+ * or %NULL if the default decoder handling should be used.
+ **/
typedef PangoFcDecoder * (*PangoFcDecoderFindFunc) (FcPattern *pattern,
gpointer user_data);