1 // 2 // PangoUtils.cs 3 // 4 // Author: 5 // Michael Hutchinson <mhutchinson@novell.com> 6 // 7 // Copyright (c) 2010 Novell, Inc. (http://www.novell.com) 8 // 9 // Permission is hereby granted, free of charge, to any person obtaining a copy 10 // of this software and associated documentation files (the "Software"), to deal 11 // in the Software without restriction, including without limitation the rights 12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 // copies of the Software, and to permit persons to whom the Software is 14 // furnished to do so, subject to the following conditions: 15 // 16 // The above copyright notice and this permission notice shall be included in 17 // all copies or substantial portions of the Software. 18 // 19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 // THE SOFTWARE. 26 27 using System; 28 using Gtk; 29 using System.Runtime.InteropServices; 30 31 namespace Pinta.Docking 32 { 33 static class PangoUtil 34 { 35 internal const string LIBGTK = "libgtk-win32-2.0-0.dll"; 36 internal const string LIBATK = "libatk-1.0-0.dll"; 37 internal const string LIBGLIB = "libglib-2.0-0.dll"; 38 internal const string LIBGDK = "libgdk-win32-2.0-0.dll"; 39 internal const string LIBGOBJECT = "libgobject-2.0-0.dll"; 40 internal const string LIBPANGO = "libpango-1.0-0.dll"; 41 internal const string LIBPANGOCAIRO = "libpangocairo-1.0-0.dll"; 42 internal const string LIBQUARTZ = "libgtk-quartz-2.0.dylib"; 43 internal const string LIBGTKGLUE = "gtksharpglue-2"; 44 45 /// <summary> 46 /// This doesn't leak Pango layouts, unlike some other ways to create them in GTK# <= 2.12.11 47 /// </summary> CreateLayout(Widget widget)48 public static Pango.Layout CreateLayout (Widget widget) 49 { 50 var ptr = gtk_widget_create_pango_layout (widget.Handle, IntPtr.Zero); 51 return ptr == IntPtr.Zero? null : new Pango.Layout (ptr); 52 } 53 CreateLayout(Widget widget, string text)54 public static Pango.Layout CreateLayout (Widget widget, string text) 55 { 56 IntPtr textPtr = text == null? IntPtr.Zero : GLib.Marshaller.StringToPtrGStrdup (text); 57 58 var ptr = gtk_widget_create_pango_layout (widget.Handle, textPtr); 59 60 if (textPtr != IntPtr.Zero) 61 GLib.Marshaller.Free (textPtr); 62 63 return ptr == IntPtr.Zero? null : new Pango.Layout (ptr); 64 } 65 CreateLayout(PrintContext context)66 public static Pango.Layout CreateLayout (PrintContext context) 67 { 68 var ptr = gtk_print_context_create_pango_layout (context.Handle); 69 return ptr == IntPtr.Zero? null : new Pango.Layout (ptr); 70 } 71 72 [DllImport (LIBGTK, CallingConvention=CallingConvention.Cdecl)] gtk_widget_create_pango_layout(IntPtr widget, IntPtr text)73 static extern IntPtr gtk_widget_create_pango_layout (IntPtr widget, IntPtr text); 74 75 [DllImport (LIBGTK, CallingConvention=CallingConvention.Cdecl)] gtk_print_context_create_pango_layout(IntPtr context)76 static extern IntPtr gtk_print_context_create_pango_layout (IntPtr context); 77 } 78 79 /// <summary> 80 /// This creates a Pango list and applies attributes to it with *much* less overhead than the GTK# version. 81 /// </summary> 82 class FastPangoAttrList : IDisposable 83 { 84 IntPtr list; 85 FastPangoAttrList()86 public FastPangoAttrList () 87 { 88 list = pango_attr_list_new (); 89 } 90 AddStyleAttribute(Pango.Style style, uint start, uint end)91 public void AddStyleAttribute (Pango.Style style, uint start, uint end) 92 { 93 Add (pango_attr_style_new (style), start, end); 94 } 95 AddWeightAttribute(Pango.Weight weight, uint start, uint end)96 public void AddWeightAttribute (Pango.Weight weight, uint start, uint end) 97 { 98 Add (pango_attr_weight_new (weight), start, end); 99 } 100 AddForegroundAttribute(Gdk.Color color, uint start, uint end)101 public void AddForegroundAttribute (Gdk.Color color, uint start, uint end) 102 { 103 Add (pango_attr_foreground_new (color.Red, color.Green, color.Blue), start, end); 104 } 105 AddBackgroundAttribute(Gdk.Color color, uint start, uint end)106 public void AddBackgroundAttribute (Gdk.Color color, uint start, uint end) 107 { 108 Add (pango_attr_background_new (color.Red, color.Green, color.Blue), start, end); 109 } 110 AddUnderlineAttribute(Pango.Underline underline, uint start, uint end)111 public void AddUnderlineAttribute (Pango.Underline underline, uint start, uint end) 112 { 113 Add (pango_attr_underline_new (underline), start, end); 114 } 115 Add(IntPtr attribute, uint start, uint end)116 void Add (IntPtr attribute, uint start, uint end) 117 { 118 unsafe { 119 PangoAttribute *attPtr = (PangoAttribute *) attribute; 120 attPtr->start_index = start; 121 attPtr->end_index = end; 122 } 123 pango_attr_list_insert (list, attribute); 124 } 125 126 /// <summary> 127 /// Like Splice, except it only offsets/clamps the inserted items, doesn't affect items already in the list. 128 /// </summary> InsertOffsetList(Pango.AttrList atts, uint startOffset, uint endOffset)129 public void InsertOffsetList (Pango.AttrList atts, uint startOffset, uint endOffset) 130 { 131 //HACK: atts.Iterator.Attrs broken (throws NRE), so manually P/Invoke 132 var iter = pango_attr_list_get_iterator (atts.Handle); 133 try { 134 do { 135 IntPtr list = pango_attr_iterator_get_attrs (iter); 136 try { 137 int len = g_slist_length (list); 138 for (uint i = 0; i < len; i++) { 139 IntPtr val = g_slist_nth_data (list, i); 140 AddOffsetCopy (val, startOffset, endOffset); 141 } 142 } finally { 143 g_slist_free (list); 144 } 145 } while (pango_attr_iterator_next (iter)); 146 } finally { 147 pango_attr_iterator_destroy (iter); 148 } 149 } 150 AddOffsetCopy(IntPtr attr, uint startOffset, uint endOffset)151 void AddOffsetCopy (IntPtr attr, uint startOffset, uint endOffset) 152 { 153 var copy = pango_attribute_copy (attr); 154 unsafe { 155 PangoAttribute *attPtr = (PangoAttribute *) copy; 156 attPtr->start_index = startOffset + attPtr->start_index; 157 attPtr->end_index = System.Math.Min (endOffset, startOffset + attPtr->end_index); 158 } 159 pango_attr_list_insert (list, copy); 160 } 161 162 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_style_new(Pango.Style style)163 static extern IntPtr pango_attr_style_new (Pango.Style style); 164 165 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_stretch_new(Pango.Stretch stretch)166 static extern IntPtr pango_attr_stretch_new (Pango.Stretch stretch); 167 168 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_weight_new(Pango.Weight weight)169 static extern IntPtr pango_attr_weight_new (Pango.Weight weight); 170 171 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_foreground_new(ushort red, ushort green, ushort blue)172 static extern IntPtr pango_attr_foreground_new (ushort red, ushort green, ushort blue); 173 174 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_background_new(ushort red, ushort green, ushort blue)175 static extern IntPtr pango_attr_background_new (ushort red, ushort green, ushort blue); 176 177 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_underline_new(Pango.Underline underline)178 static extern IntPtr pango_attr_underline_new (Pango.Underline underline); 179 180 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_list_new()181 static extern IntPtr pango_attr_list_new (); 182 183 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_list_unref(IntPtr list)184 static extern void pango_attr_list_unref (IntPtr list); 185 186 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_list_insert(IntPtr list, IntPtr attr)187 static extern void pango_attr_list_insert (IntPtr list, IntPtr attr); 188 189 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_layout_set_attributes(IntPtr layout, IntPtr attrList)190 static extern void pango_layout_set_attributes (IntPtr layout, IntPtr attrList); 191 192 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_list_splice(IntPtr attr_list, IntPtr other, Int32 pos, Int32 len)193 static extern void pango_attr_list_splice (IntPtr attr_list, IntPtr other, Int32 pos, Int32 len); 194 195 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attribute_copy(IntPtr attr)196 static extern IntPtr pango_attribute_copy (IntPtr attr); 197 198 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_list_get_iterator(IntPtr list)199 static extern IntPtr pango_attr_list_get_iterator (IntPtr list); 200 201 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_iterator_next(IntPtr iterator)202 static extern bool pango_attr_iterator_next (IntPtr iterator); 203 204 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_iterator_destroy(IntPtr iterator)205 static extern void pango_attr_iterator_destroy (IntPtr iterator); 206 207 [DllImport (PangoUtil.LIBPANGO, CallingConvention=CallingConvention.Cdecl)] pango_attr_iterator_get_attrs(IntPtr iterator)208 static extern IntPtr pango_attr_iterator_get_attrs (IntPtr iterator); 209 210 [DllImport (PangoUtil.LIBGLIB, CallingConvention = CallingConvention.Cdecl)] g_slist_length(IntPtr l)211 private static extern int g_slist_length (IntPtr l); 212 213 [DllImport (PangoUtil.LIBGLIB, CallingConvention = CallingConvention.Cdecl)] g_slist_nth_data(IntPtr l, uint n)214 private static extern IntPtr g_slist_nth_data (IntPtr l, uint n); 215 216 [DllImport (PangoUtil.LIBGLIB, CallingConvention = CallingConvention.Cdecl)] g_slist_free(IntPtr l)217 private static extern void g_slist_free (IntPtr l); 218 Splice(Pango.AttrList attrs, int pos, int len)219 public void Splice (Pango.AttrList attrs, int pos, int len) 220 { 221 pango_attr_list_splice (list, attrs.Handle, pos, len); 222 } 223 AssignTo(Pango.Layout layout)224 public void AssignTo (Pango.Layout layout) 225 { 226 pango_layout_set_attributes (layout.Handle, list); 227 } 228 229 [StructLayout (LayoutKind.Sequential)] 230 struct PangoAttribute 231 { 232 public IntPtr klass; 233 public uint start_index; 234 public uint end_index; 235 } 236 Dispose()237 public void Dispose () 238 { 239 if (list != IntPtr.Zero) { 240 GC.SuppressFinalize (this); 241 Destroy (); 242 } 243 } 244 245 //NOTE: the list destroys all its attributes when the ref count reaches zero Destroy()246 void Destroy () 247 { 248 pango_attr_list_unref (list); 249 list = IntPtr.Zero; 250 } 251 ~FastPangoAttrList()252 ~FastPangoAttrList () 253 { 254 GLib.Idle.Add (delegate { 255 Destroy (); 256 return false; 257 }); 258 } 259 } 260 }