]> git.saurik.com Git - wxWidgets.git/blame - src/common/textmeasurecmn.cpp
Disable wxUSE_ENH_METAFILE for wxGTK builds.
[wxWidgets.git] / src / common / textmeasurecmn.cpp
CommitLineData
8cd79b7a
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/common/textmeasurecmn.cpp
3// Purpose: wxTextMeasureBase implementation
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/dc.h"
24 #include "wx/window.h"
25#endif //WX_PRECOMP
26
27#include "wx/private/textmeasure.h"
28
29// ============================================================================
30// wxTextMeasureBase implementation
31// ============================================================================
32
33wxTextMeasureBase::wxTextMeasureBase(const wxDC *dc, const wxFont *theFont)
34 : m_dc(dc),
35 m_win(NULL),
36 m_font(theFont)
37{
38 wxASSERT_MSG( dc, wxS("wxTextMeasure needs a valid wxDC") );
1bce253a
VZ
39
40 // By default, use wxDC version, we'll explicitly reset this to false in
41 // the derived classes if the DC is of native variety.
42 m_useDCImpl = true;
8cd79b7a
VZ
43}
44
45wxTextMeasureBase::wxTextMeasureBase(const wxWindow *win, const wxFont *theFont)
46 : m_dc(NULL),
47 m_win(win),
48 m_font(theFont)
49{
50 wxASSERT_MSG( win, wxS("wxTextMeasure needs a valid wxWindow") );
1bce253a
VZ
51
52 // We don't have any wxDC so we can't forward to it.
53 m_useDCImpl = false;
54}
55
e0da9e87
VZ
56wxFont wxTextMeasureBase::GetFont() const
57{
58 return m_font ? *m_font
59 : m_win ? m_win->GetFont()
60 : m_dc->GetFont();
61}
62
1bce253a
VZ
63void wxTextMeasureBase::CallGetTextExtent(const wxString& string,
64 wxCoord *width,
65 wxCoord *height,
66 wxCoord *descent,
67 wxCoord *externalLeading)
68{
69 if ( m_useDCImpl )
70 m_dc->GetTextExtent(string, width, height, descent, externalLeading);
71 else
72 DoGetTextExtent(string, width, height, descent, externalLeading);
8cd79b7a
VZ
73}
74
75void wxTextMeasureBase::GetTextExtent(const wxString& string,
76 wxCoord *width,
77 wxCoord *height,
78 wxCoord *descent,
79 wxCoord *externalLeading)
80{
81 // To make the code simpler, make sure that the width and height pointers
82 // are always valid, even if they point to dummy variables.
83 int unusedWidth, unusedHeight;
84 if ( !width )
85 width = &unusedWidth;
86 if ( !height )
87 height = &unusedHeight;
88
0646084e
VZ
89 // Avoid even setting up the DC for measuring if we don't actually need to
90 // measure anything.
91 if ( string.empty() && !descent && !externalLeading )
8cd79b7a
VZ
92 {
93 *width =
94 *height = 0;
95
96 return;
97 }
98
99 MeasuringGuard guard(*this);
100
1bce253a 101 CallGetTextExtent(string, width, height, descent, externalLeading);
8cd79b7a
VZ
102}
103
104void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
105 wxCoord *width,
106 wxCoord *height,
107 wxCoord *heightOneLine)
108{
109 MeasuringGuard guard(*this);
110
111 wxCoord widthTextMax = 0, widthLine,
112 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
113
114 wxString curLine;
115 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
116 {
117 if ( pc == text.end() || *pc == wxS('\n') )
118 {
119 if ( curLine.empty() )
120 {
121 // we can't use GetTextExtent - it will return 0 for both width
122 // and height and an empty line should count in height
123 // calculation
124
125 // assume that this line has the same height as the previous
126 // one
127 if ( !heightLineDefault )
128 heightLineDefault = heightLine;
129
130 if ( !heightLineDefault )
131 {
132 // but we don't know it yet - choose something reasonable
bb996f28 133 int dummy;
1bce253a 134 CallGetTextExtent(wxS("W"), &dummy, &heightLineDefault);
8cd79b7a
VZ
135 }
136
137 heightTextTotal += heightLineDefault;
138 }
139 else
140 {
1bce253a 141 CallGetTextExtent(curLine, &widthLine, &heightLine);
8cd79b7a
VZ
142 if ( widthLine > widthTextMax )
143 widthTextMax = widthLine;
144 heightTextTotal += heightLine;
145 }
146
147 if ( pc == text.end() )
148 {
149 break;
150 }
151 else // '\n'
152 {
153 curLine.clear();
154 }
155 }
156 else
157 {
158 curLine += *pc;
159 }
160 }
161
162 if ( width )
163 *width = widthTextMax;
164 if ( height )
165 *height = heightTextTotal;
166 if ( heightOneLine )
167 *heightOneLine = heightLine;
168}
169
a9f1207c
VZ
170wxSize wxTextMeasureBase::GetLargestStringExtent(size_t n,
171 const wxString* strings)
8cd79b7a
VZ
172{
173 MeasuringGuard guard(*this);
174
175 wxCoord w, h, widthMax = 0, heightMax = 0;
a9f1207c 176 for ( size_t i = 0; i < n; ++i )
8cd79b7a 177 {
a9f1207c 178 CallGetTextExtent(strings[i], &w, &h);
8cd79b7a
VZ
179
180 if ( w > widthMax )
181 widthMax = w;
182 if ( h > heightMax )
183 heightMax = h;
184 }
185
a9f1207c 186 return wxSize(widthMax, heightMax);
8cd79b7a
VZ
187}
188
189bool wxTextMeasureBase::GetPartialTextExtents(const wxString& text,
190 wxArrayInt& widths,
191 double scaleX)
192{
193 widths.Empty();
194 if ( text.empty() )
195 return true;
196
197 MeasuringGuard guard(*this);
198
199 widths.Add(0, text.length());
200
201 return DoGetPartialTextExtents(text, widths, scaleX);
202}
1cd86ff6
VZ
203
204// ----------------------------------------------------------------------------
205// Generic and inefficient DoGetPartialTextExtents() implementation.
206// ----------------------------------------------------------------------------
207
208// Each element of the widths array will be the width of the string up to and
209// including the corresponding character in text. This is the generic
210// implementation, the port-specific classes should do this with native APIs
211// if available and if faster. Note: pango_layout_index_to_pos is much slower
212// than calling GetTextExtent!!
213
214#define FWC_SIZE 256
215
216class FontWidthCache
217{
218public:
219 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
220 ~FontWidthCache() { delete []m_widths; }
221
222 void Reset()
223 {
224 if ( !m_widths )
225 m_widths = new int[FWC_SIZE];
226
227 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
228 }
229
230 wxFont m_font;
231 double m_scaleX;
232 int *m_widths;
233};
234
235static FontWidthCache s_fontWidthCache;
236
237bool wxTextMeasureBase::DoGetPartialTextExtents(const wxString& text,
238 wxArrayInt& widths,
239 double scaleX)
240{
241 int totalWidth = 0;
242
243 // reset the cache if font or horizontal scale have changed
244 if ( !s_fontWidthCache.m_widths ||
245 !wxIsSameDouble(s_fontWidthCache.m_scaleX, scaleX) ||
246 (s_fontWidthCache.m_font != *m_font) )
247 {
248 s_fontWidthCache.Reset();
249 s_fontWidthCache.m_font = *m_font;
250 s_fontWidthCache.m_scaleX = scaleX;
251 }
252
253 // Calculate the position of each character based on the widths of
254 // the previous characters. This is inexact for not fixed fonts.
255 int n = 0;
256 for ( wxString::const_iterator it = text.begin();
257 it != text.end();
258 ++it )
259 {
260 const wxChar c = *it;
261 unsigned int c_int = (unsigned int)c;
262
263 int w;
264 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
265 {
266 w = s_fontWidthCache.m_widths[c_int];
267 }
268 else
269 {
270 DoGetTextExtent(c, &w, NULL);
271 if (c_int < FWC_SIZE)
272 s_fontWidthCache.m_widths[c_int] = w;
273 }
274
275 totalWidth += w;
276 widths[n++] = totalWidth;
277 }
278
279 return true;
280}
281