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