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