]> git.saurik.com Git - wxWidgets.git/blame - src/common/textmeasurecmn.cpp
make methods available to all ports
[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
89 if ( string.empty() )
90 {
91 *width =
92 *height = 0;
93
94 return;
95 }
96
97 MeasuringGuard guard(*this);
98
1bce253a 99 CallGetTextExtent(string, width, height, descent, externalLeading);
8cd79b7a
VZ
100}
101
102void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
103 wxCoord *width,
104 wxCoord *height,
105 wxCoord *heightOneLine)
106{
107 MeasuringGuard guard(*this);
108
109 wxCoord widthTextMax = 0, widthLine,
110 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
111
112 wxString curLine;
113 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
114 {
115 if ( pc == text.end() || *pc == wxS('\n') )
116 {
117 if ( curLine.empty() )
118 {
119 // we can't use GetTextExtent - it will return 0 for both width
120 // and height and an empty line should count in height
121 // calculation
122
123 // assume that this line has the same height as the previous
124 // one
125 if ( !heightLineDefault )
126 heightLineDefault = heightLine;
127
128 if ( !heightLineDefault )
129 {
130 // but we don't know it yet - choose something reasonable
bb996f28 131 int dummy;
1bce253a 132 CallGetTextExtent(wxS("W"), &dummy, &heightLineDefault);
8cd79b7a
VZ
133 }
134
135 heightTextTotal += heightLineDefault;
136 }
137 else
138 {
1bce253a 139 CallGetTextExtent(curLine, &widthLine, &heightLine);
8cd79b7a
VZ
140 if ( widthLine > widthTextMax )
141 widthTextMax = widthLine;
142 heightTextTotal += heightLine;
143 }
144
145 if ( pc == text.end() )
146 {
147 break;
148 }
149 else // '\n'
150 {
151 curLine.clear();
152 }
153 }
154 else
155 {
156 curLine += *pc;
157 }
158 }
159
160 if ( width )
161 *width = widthTextMax;
162 if ( height )
163 *height = heightTextTotal;
164 if ( heightOneLine )
165 *heightOneLine = heightLine;
166}
167
a9f1207c
VZ
168wxSize wxTextMeasureBase::GetLargestStringExtent(size_t n,
169 const wxString* strings)
8cd79b7a
VZ
170{
171 MeasuringGuard guard(*this);
172
173 wxCoord w, h, widthMax = 0, heightMax = 0;
a9f1207c 174 for ( size_t i = 0; i < n; ++i )
8cd79b7a 175 {
a9f1207c 176 CallGetTextExtent(strings[i], &w, &h);
8cd79b7a
VZ
177
178 if ( w > widthMax )
179 widthMax = w;
180 if ( h > heightMax )
181 heightMax = h;
182 }
183
a9f1207c 184 return wxSize(widthMax, heightMax);
8cd79b7a
VZ
185}
186
187bool wxTextMeasureBase::GetPartialTextExtents(const wxString& text,
188 wxArrayInt& widths,
189 double scaleX)
190{
191 widths.Empty();
192 if ( text.empty() )
193 return true;
194
195 MeasuringGuard guard(*this);
196
197 widths.Add(0, text.length());
198
199 return DoGetPartialTextExtents(text, widths, scaleX);
200}
1cd86ff6
VZ
201
202// ----------------------------------------------------------------------------
203// Generic and inefficient DoGetPartialTextExtents() implementation.
204// ----------------------------------------------------------------------------
205
206// Each element of the widths array will be the width of the string up to and
207// including the corresponding character in text. This is the generic
208// implementation, the port-specific classes should do this with native APIs
209// if available and if faster. Note: pango_layout_index_to_pos is much slower
210// than calling GetTextExtent!!
211
212#define FWC_SIZE 256
213
214class FontWidthCache
215{
216public:
217 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
218 ~FontWidthCache() { delete []m_widths; }
219
220 void Reset()
221 {
222 if ( !m_widths )
223 m_widths = new int[FWC_SIZE];
224
225 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
226 }
227
228 wxFont m_font;
229 double m_scaleX;
230 int *m_widths;
231};
232
233static FontWidthCache s_fontWidthCache;
234
235bool wxTextMeasureBase::DoGetPartialTextExtents(const wxString& text,
236 wxArrayInt& widths,
237 double scaleX)
238{
239 int totalWidth = 0;
240
241 // reset the cache if font or horizontal scale have changed
242 if ( !s_fontWidthCache.m_widths ||
243 !wxIsSameDouble(s_fontWidthCache.m_scaleX, scaleX) ||
244 (s_fontWidthCache.m_font != *m_font) )
245 {
246 s_fontWidthCache.Reset();
247 s_fontWidthCache.m_font = *m_font;
248 s_fontWidthCache.m_scaleX = scaleX;
249 }
250
251 // Calculate the position of each character based on the widths of
252 // the previous characters. This is inexact for not fixed fonts.
253 int n = 0;
254 for ( wxString::const_iterator it = text.begin();
255 it != text.end();
256 ++it )
257 {
258 const wxChar c = *it;
259 unsigned int c_int = (unsigned int)c;
260
261 int w;
262 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
263 {
264 w = s_fontWidthCache.m_widths[c_int];
265 }
266 else
267 {
268 DoGetTextExtent(c, &w, NULL);
269 if (c_int < FWC_SIZE)
270 s_fontWidthCache.m_widths[c_int] = w;
271 }
272
273 totalWidth += w;
274 widths[n++] = totalWidth;
275 }
276
277 return true;
278}
279