Allow wxTextMeasure to work with non-native wxDC objects too.
[wxWidgets.git] / src / gtk / textmeasure.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/textmeasure.cpp
3 // Purpose: wxTextMeasure implementation for wxGTK
4 // Author: Manuel Martin
5 // Created: 2012-10-05
6 // RCS-ID: $Id:
7 // Copyright: (c) 1997-2012 wxWidgets team
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/window.h"
24 #include "wx/log.h"
25 #endif //WX_PRECOMP
26
27 #include "wx/private/textmeasure.h"
28
29 #include "wx/fontutil.h"
30 #include "wx/gtk/private.h"
31 #include "wx/gtk/dc.h"
32
33 #ifndef __WXGTK3__
34 #include "wx/gtk/dcclient.h"
35 #endif
36
37 // ============================================================================
38 // wxTextMeasure implementation
39 // ============================================================================
40
41 void wxTextMeasure::Init()
42 {
43 wxASSERT_MSG( m_font, wxT("wxTextMeasure needs a valid wxFont") );
44
45 m_context = NULL;
46 m_layout = NULL;
47
48 #ifndef __WXGTK3__
49 m_wdc = NULL;
50
51 if ( m_dc )
52 {
53 wxClassInfo* const ci = m_dc->GetImpl()->GetClassInfo();
54
55 // Currently the code here only works with wxWindowDCImpl and only in
56 // wxGTK2 as wxGTK3 uses Cairo and not Pango for all its DCs.
57 if ( ci->IsKindOf(wxCLASSINFO(wxWindowDCImpl)))
58 {
59 m_useDCImpl = false;
60 }
61 }
62 #endif // GTK+ < 3
63 }
64
65 // Get Gtk needed elements, if we have not them yet.
66 void wxTextMeasure::BeginMeasuring()
67 {
68 if ( m_dc )
69 {
70 #ifndef __WXGTK3__
71 m_wdc = wxDynamicCast(m_dc->GetImpl(), wxWindowDCImpl);
72 if ( m_wdc )
73 {
74 m_context = m_wdc->m_context;
75 m_layout = m_wdc->m_layout;
76 }
77 #endif // GTK+ < 3
78 }
79 else if ( m_win )
80 {
81 m_context = gtk_widget_get_pango_context( m_win->GetHandle() );
82 if ( m_context )
83 m_layout = pango_layout_new(m_context);
84 }
85
86 // set the font to use
87 if ( m_layout )
88 {
89 pango_layout_set_font_description(m_layout,
90 m_font->GetNativeFontInfo()->description);
91 }
92 }
93
94 void wxTextMeasure::EndMeasuring()
95 {
96 if ( !m_layout )
97 return;
98
99 #ifndef __WXGTK3__
100 if ( m_wdc )
101 {
102 // Reset dc own font description
103 pango_layout_set_font_description( m_wdc->m_layout, m_wdc->m_fontdesc );
104 }
105 else
106 #endif // GTK+ < 3
107 {
108 g_object_unref (m_layout);
109 }
110 }
111
112 // Notice we don't check here the font. It is supposed to be OK before the call.
113 void wxTextMeasure::DoGetTextExtent(const wxString& string,
114 wxCoord *width,
115 wxCoord *height,
116 wxCoord *descent,
117 wxCoord *externalLeading)
118 {
119 if ( !m_context )
120 {
121 *width =
122 *height = 0;
123 return;
124 }
125
126 // Set layout's text
127 const wxCharBuffer dataUTF8 = wxGTK_CONV_FONT(string, *m_font);
128 if ( !dataUTF8 )
129 {
130 // hardly ideal, but what else can we do if conversion failed?
131 wxLogLastError(wxT("GetTextExtent"));
132 return;
133 }
134 pango_layout_set_text(m_layout, dataUTF8, -1);
135
136 if ( m_dc )
137 {
138 // in device units
139 pango_layout_get_pixel_size(m_layout, width, height);
140 }
141 else // win
142 {
143 // the logical rect bounds the ink rect
144 PangoRectangle rect;
145 pango_layout_get_extents(m_layout, NULL, &rect);
146 *width = PANGO_PIXELS(rect.width);
147 *height = PANGO_PIXELS(rect.height);
148 }
149
150 if (descent)
151 {
152 PangoLayoutIter *iter = pango_layout_get_iter(m_layout);
153 int baseline = pango_layout_iter_get_baseline(iter);
154 pango_layout_iter_free(iter);
155 *descent = *height - PANGO_PIXELS(baseline);
156 }
157
158 if (externalLeading)
159 {
160 // No support for MSW-like "external leading" in Pango.
161 *externalLeading = 0;
162 }
163 }
164
165 bool wxTextMeasure::DoGetPartialTextExtents(const wxString& text,
166 wxArrayInt& widths,
167 double WXUNUSED(scaleX))
168 {
169 // Set layout's text
170 const wxCharBuffer dataUTF8 = wxGTK_CONV_FONT(text, *m_font);
171 if ( !dataUTF8 )
172 {
173 // hardly ideal, but what else can we do if conversion failed?
174 wxLogLastError(wxT("GetPartialTextExtents"));
175 return false;
176 }
177
178 pango_layout_set_text(m_layout, dataUTF8, -1);
179
180 // Calculate the position of each character based on the widths of
181 // the previous characters
182
183 // Code borrowed from Scintilla's PlatGTK
184 PangoLayoutIter *iter = pango_layout_get_iter(m_layout);
185 PangoRectangle pos;
186 pango_layout_iter_get_cluster_extents(iter, NULL, &pos);
187 size_t i = 0;
188 while (pango_layout_iter_next_cluster(iter))
189 {
190 pango_layout_iter_get_cluster_extents(iter, NULL, &pos);
191 int position = PANGO_PIXELS(pos.x);
192 widths[i++] = position;
193 }
194
195 const size_t len = text.length();
196 while (i < len)
197 widths[i++] = PANGO_PIXELS(pos.x + pos.width);
198 pango_layout_iter_free(iter);
199
200 return true;
201 }