Allow wxTextMeasure to work with non-native wxDC objects too.
[wxWidgets.git] / src / msw / textmeasure.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/textmeasure.cpp
3 // Purpose: wxTextMeasure implementation for wxMSW
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 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #include "wx/msw/private.h"
27
28 #ifndef WX_PRECOMP
29 #include "wx/window.h"
30 #include "wx/font.h"
31 #endif //WX_PRECOMP
32
33 #include "wx/private/textmeasure.h"
34
35 #include "wx/msw/dc.h"
36
37 // ============================================================================
38 // wxTextMeasure implementation
39 // ============================================================================
40
41 void wxTextMeasure::Init()
42 {
43 m_hdc = NULL;
44 m_hfontOld = NULL;
45
46 if ( m_dc )
47 {
48 wxClassInfo* const ci = m_dc->GetImpl()->GetClassInfo();
49
50 if ( ci->IsKindOf(wxCLASSINFO(wxMSWDCImpl)))
51 {
52 m_useDCImpl = false;
53 }
54 }
55 }
56
57 void wxTextMeasure::BeginMeasuring()
58 {
59 if ( m_dc )
60 {
61 m_hdc = m_dc->GetHDC();
62
63 // Non-native wxDC subclasses should override their DoGetTextExtent()
64 // and other methods.
65 wxASSERT_MSG( m_hdc, wxS("Must not be used with non-native wxDCs") );
66 }
67 else if ( m_win )
68 {
69 m_hdc = ::GetDC(GetHwndOf(m_win));
70 }
71
72 if ( m_font )
73 m_hfontOld = (HFONT)::SelectObject(m_hdc, GetHfontOf(*m_font));
74 }
75
76 void wxTextMeasure::EndMeasuring()
77 {
78 if ( m_hfontOld )
79 {
80 ::SelectObject(m_hdc, m_hfontOld);
81 m_hfontOld = NULL;
82 }
83
84 if ( m_win )
85 ::ReleaseDC(GetHwndOf(m_win), m_hdc);
86 //else: our HDC belongs to m_dc, don't touch it
87
88 m_hdc = NULL;
89 }
90
91 // Notice we don't check here the font. It is supposed to be OK before the call.
92 void wxTextMeasure::DoGetTextExtent(const wxString& string,
93 wxCoord *width,
94 wxCoord *height,
95 wxCoord *descent,
96 wxCoord *externalLeading)
97 {
98 SIZE sizeRect;
99 const size_t len = string.length();
100 if ( !::GetTextExtentPoint32(m_hdc, string.t_str(), len, &sizeRect) )
101 {
102 wxLogLastError(wxT("GetTextExtentPoint32()"));
103 }
104
105 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
106 // the result computed by GetTextExtentPoint32() may be too small as it
107 // accounts for under/overhang of the first/last character while we want
108 // just the bounding rect for this string so adjust the width as needed
109 // (using API not available in 2002 SDKs of WinCE)
110 if ( len > 0 )
111 {
112 ABC widthABC;
113 const wxChar chFirst = *string.begin();
114 if ( ::GetCharABCWidths(m_hdc, chFirst, chFirst, &widthABC) )
115 {
116 if ( widthABC.abcA < 0 )
117 sizeRect.cx -= widthABC.abcA;
118
119 if ( len > 1 )
120 {
121 const wxChar chLast = *string.rbegin();
122 ::GetCharABCWidths(m_hdc, chLast, chLast, &widthABC);
123 }
124 //else: we already have the width of the last character
125
126 if ( widthABC.abcC < 0 )
127 sizeRect.cx -= widthABC.abcC;
128 }
129 //else: GetCharABCWidths() failed, not a TrueType font?
130 }
131 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
132
133 *width = sizeRect.cx;
134 *height = sizeRect.cy;
135
136 if ( descent || externalLeading )
137 {
138 TEXTMETRIC tm;
139 ::GetTextMetrics(m_hdc, &tm);
140 if ( descent )
141 *descent = tm.tmDescent;
142 if ( externalLeading )
143 *externalLeading = tm.tmExternalLeading;
144 }
145 }
146
147 bool wxTextMeasure::DoGetPartialTextExtents(const wxString& text,
148 wxArrayInt& widths,
149 double WXUNUSED(scaleX))
150 {
151 static int maxLenText = -1;
152 static int maxWidth = -1;
153
154 if (maxLenText == -1)
155 {
156 // Win9x and WinNT+ have different limits
157 int version = wxGetOsVersion();
158 maxLenText = version == wxOS_WINDOWS_NT ? 65535 : 8192;
159 maxWidth = version == wxOS_WINDOWS_NT ? INT_MAX : 32767;
160 }
161
162 int len = text.length();
163 if ( len > maxLenText )
164 len = maxLenText;
165
166 int fit = 0;
167 SIZE sz = {0,0};
168 if ( !::GetTextExtentExPoint(m_hdc,
169 text.t_str(), // string to check
170 len,
171 maxWidth,
172 &fit, // [out] count of chars
173 // that will fit
174 &widths[0], // array to fill
175 &sz) )
176 {
177 wxLogLastError(wxT("GetTextExtentExPoint"));
178
179 return false;
180 }
181
182 return true;
183 }