OSDN Git Service

itemizing and shaping are done by one character.
[fukui-no-namari/fukui-no-namari-ext.git] / src / thread_view_extend.c
1 /*
2  *  thread_view_extend.c
3  *
4  *  Copyright (C) 2007,2009 by Aiwota Programmer
5  *  aiwotaprog@tetteke.tk
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22
23 #include <Python.h>
24 #include <gtk/gtk.h>
25 #include <pygobject.h>
26 #include <pygtk/pygtk.h>
27
28
29 /* ------------ types from other modules ------------ */
30 static PyTypeObject * _PyPangoAttrList_Type;
31 #define PyPangoAttrList_Type (*_PyPangoAttrList_Type)
32 static PyTypeObject * _PyPangoContext_Type;
33 #define PyPangoContext_Type (*_PyPangoContext_Type)
34
35
36 void get_char_width(PangoContext *context, const char* text,
37     int len, PangoAttrList *attrs, double* widths)
38 {
39     const char* p = text;
40     int idx = 0;
41
42         while (p - text < len) {
43                 const char* const next = g_utf8_next_char(p);
44             GList *list = pango_itemize(context, p, 0, next-p, attrs, NULL);
45             GList *list_s = list;
46
47             while (list_s) {
48                         int i;
49                         PangoItem *item = list_s->data;
50                         PangoAnalysis *analysis = &item->analysis;
51                         PangoGlyphString *glyphs = pango_glyph_string_new();
52                         double width = 0;
53
54                         pango_shape(p + item->offset, item->length, analysis, glyphs);
55
56                         for (i = 0; i < glyphs->num_glyphs; i++)
57                         {
58                                 width +=
59                                         pango_units_to_double(glyphs->glyphs[i].geometry.width);
60                         }
61                         widths[idx++] = width;
62
63                         pango_item_free(item);
64                         pango_glyph_string_free(glyphs);
65                         list_s = list_s->next;
66             }
67
68                 g_list_free(list);
69                 p = next;
70         }
71 }
72
73 static PyObject *
74 _wrap_get_char_width(PyObject *self, PyObject *args, PyObject *kwargs)
75 {
76     static char *kwlist[] = { "context", "text", "attrs", NULL};
77     PyObject *py_context, *py_attrs;
78     PangoContext *context;
79     PangoAttrList *attrs = NULL;
80     const char *text;
81     PyObject* ret;
82     gint length;
83     gdouble *logical_widths;
84     int i, slen;
85
86     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os#O", kwlist,
87             &py_context, &text, &length, &py_attrs))
88         return NULL;
89
90     if (pygobject_check(py_context, &PyPangoContext_Type))
91       context = (PangoContext*) pygobject_get(py_context);
92     else
93     {
94         PyErr_SetString(PyExc_TypeError, "context must be a PangoContext");
95         return NULL;
96     }
97
98     if (pygobject_check(py_attrs, &PyPangoAttrList_Type))
99     /*if (pyg_boxed_check(py_attrs, PANGO_TYPE_ATTR_LIST))*/
100     {
101         attrs = pyg_boxed_get(py_attrs, PangoAttrList);
102     }
103     else if (py_attrs != Py_None)
104     {
105         PyErr_SetString(PyExc_TypeError,
106             "attrlist must be a PangoAttrList or None");
107         return NULL;
108     }
109
110
111     slen = g_utf8_strlen(text, length);
112
113     logical_widths = g_new(double, slen);
114     get_char_width(context, text, length, attrs, logical_widths);
115
116     ret = PyTuple_New(slen);
117     for (i = 0; i < slen; i++)
118     {
119         PyObject *item  = PyFloat_FromDouble(logical_widths[i]);
120         PyTuple_SetItem(ret, i, item);
121     }
122     g_free(logical_widths);
123
124     return ret;
125 }
126
127 static PyMethodDef pythread_view_extend_functions[] = {
128     { "get_char_width", (PyCFunction)_wrap_get_char_width,
129       METH_VARARGS|METH_KEYWORDS, NULL },
130     { NULL, NULL, 0, NULL }
131 };
132
133 /* initialise stuff extension classes */
134 PyMODINIT_FUNC initthread_view_extend()
135 {
136     PyObject *module;
137
138     if ((module = PyImport_ImportModule("pango")) != NULL)
139     {
140         _PyPangoContext_Type = (PyTypeObject *)
141             PyObject_GetAttrString(module, "Context");
142         if (_PyPangoContext_Type == NULL)
143         {
144             PyErr_SetString(PyExc_ImportError,
145                 "cannot import name Context from pango");
146             return ;
147         }
148
149         _PyPangoAttrList_Type = (PyTypeObject *)
150             PyObject_GetAttrString(module, "AttrList");
151         if (_PyPangoAttrList_Type == NULL)
152         {
153             PyErr_SetString(PyExc_ImportError,
154                 "cannot import name AttrList from pango");
155             return ;
156         }
157     } else
158     {
159         PyErr_SetString(PyExc_ImportError, "could not import pango");
160         return ;
161     }
162
163     Py_InitModule("thread_view_extend", pythread_view_extend_functions);
164 }