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