1 /*
2  * Distributed under the Boost Software License, Version 1.0.
3  *    (See accompanying file LICENSE_1_0.txt or copy at
4  *          http://www.boost.org/LICENSE_1_0.txt)
5  */
6 module pango.glyph_item;
7 
8 import pango.utils;
9 import pango.attributes;
10 import pango.item;
11 import pango.glyph;
12 import pango.break_;
13 import pango.c.glyph_item;
14 
15 import glib;
16 import gobject;
17 
18 import std..string;
19 
20 
21 /**
22  * PangoGlyphItem:
23  *
24  * A #PangoGlyphItem is a pair of a #PangoItem and the glyphs
25  * resulting from shaping the text corresponding to an item.
26  * As an example of the usage of #PangoGlyphItem, the results
27  * of shaping text with #PangoLayout is a list of #PangoLayoutLine,
28  * each of which contains a list of #PangoGlyphItem.
29  */
30 
31 class GlyphItem
32 {
33     mixin NativePtrHolder!(PangoGlyphItem, pango_glyph_item_free);
34     bool owned_ = true;
35 
36     package this(PangoGlyphItem *ptr, Transfer transfer) {
37         initialize(ptr, transfer);
38     }
39 
40     //PangoGlyphItem *pango_glyph_item_copy         (PangoGlyphItem *orig);
41 
42     @property Item item() {
43         return getDObject!Item(nativePtr.item, Transfer.None);
44     }
45 
46     @property GlyphString glyphs() {
47         return getDObject!GlyphString(nativePtr.glyphs, Transfer.None);
48     }
49 
50     GlyphItem split(string text, int splitIndex) {
51         return getDObject!GlyphItem(pango_glyph_item_split(nativePtr, toStringz(text), splitIndex), Transfer.Full);
52     }
53 
54     GlyphItem[] applyAttrs(string text, AttrList attrs)
55     {
56         GSList *list = pango_glyph_item_apply_attrs(nativePtr, toStringz(text), attrs.nativePtr);
57         if (!list) return [];
58         scope(exit) g_slist_free(list); // not free_full as we transfer ownership to GlyphItem objects
59 
60         GlyphItem[] res;
61         while (list) {
62             res ~= getDObject!GlyphItem(cast(PangoGlyphItem*)list.data, Transfer.Full);
63             list = list.next;
64         }
65         return res;
66     }
67 
68 
69     void letterSpace(string text, LogAttr[] logAttrs, int letterSpacing)
70     {
71         pango_glyph_item_letter_space(nativePtr, text.ptr, logAttrs.ptr, letterSpacing);
72     }
73 
74 
75     int[] logicalWidths(string text) {
76         if (!nativePtr || !nativePtr.item) return [];
77         assert(text.length >= nativePtr.item.offset);
78         int[] res = new int[nativePtr.item.num_chars];
79         pango_glyph_item_get_logical_widths(nativePtr, toStringz(text), res.ptr);
80         return res;
81     }
82 }
83 
84 
85 
86 /**
87  * PangoGlyphItemIter:
88  *
89  * A #PangoGlyphItemIter is an iterator over the clusters in a
90  * #PangoGlyphItem.  The <firstterm>forward direction</firstterm> of the
91  * iterator is the logical direction of text.  That is, with increasing
92  * @start_index and @start_char values.  If @glyph_item is right-to-left
93  * (that is, if <literal>@glyph_item->item->analysis.level</literal> is odd),
94  * then @start_glyph decreases as the iterator moves forward.  Moreover,
95  * in right-to-left cases, @start_glyph is greater than @end_glyph.
96  *
97  * An iterator should be initialized using either of
98  * pango_glyph_item_iter_init_start() and
99  * pango_glyph_item_iter_init_end(), for forward and backward iteration
100  * respectively, and walked over using any desired mixture of
101  * pango_glyph_item_iter_next_cluster() and
102  * pango_glyph_item_iter_prev_cluster().  A common idiom for doing a
103  * forward iteration over the clusters is:
104  * <programlisting>
105  * PangoGlyphItemIter cluster_iter;
106  * gboolean have_cluster;
107  *
108  * for (have_cluster = pango_glyph_item_iter_init_start (&amp;cluster_iter,
109  *                                                       glyph_item, text);
110  *      have_cluster;
111  *      have_cluster = pango_glyph_item_iter_next_cluster (&amp;cluster_iter))
112  * {
113  *   ...
114  * }
115  * </programlisting>
116  *
117  * Note that @text is the start of the text for layout, which is then
118  * indexed by <literal>@glyph_item->item->offset</literal> to get to the
119  * text of @glyph_item.  The @start_index and @end_index values can directly
120  * index into @text.  The @start_glyph, @end_glyph, @start_char, and @end_char
121  * values however are zero-based for the @glyph_item.  For each cluster, the
122  * item pointed at by the start variables is included in the cluster while
123  * the one pointed at by end variables is not.
124  *
125  * None of the members of a #PangoGlyphItemIter should be modified manually.
126  *
127  * Since: 1.22
128  */
129 struct GlyphItemIter
130 {
131     PangoGlyphItemIter pangoStruct;
132 
133     @property string text() { return fromStringz(pangoStruct.text).idup; }
134     @property void text(string text) { pangoStruct.text = toStringz(text); }
135 
136     alias startGlyph = pangoStruct.start_glyph;
137     alias startIndex = pangoStruct.start_index;
138     alias startChar = pangoStruct.start_char;
139 
140     alias endGlyph = pangoStruct.end_glyph;
141     alias endIndex = pangoStruct.end_index;
142     alias endChar = pangoStruct.end_char;
143 
144 
145     bool initStart(GlyphItem item, string text) {
146         return cast(bool)pango_glyph_item_iter_init_start(&pangoStruct, item.nativePtr, toStringz(text));
147     }
148 
149     bool initEnd(GlyphItem item, string text) {
150         return cast(bool)pango_glyph_item_iter_init_end(&pangoStruct, item.nativePtr, toStringz(text));
151     }
152 
153     bool nextCluster() {
154         return cast(bool)pango_glyph_item_iter_next_cluster(&pangoStruct);
155     }
156 
157     bool prevCluster() {
158         return cast(bool)pango_glyph_item_iter_prev_cluster(&pangoStruct);
159     }
160 }
161