1/*
2 * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27// this needs to be included before fontprops.h for UChar* to be defined.
28#include <wtf/unicode/Unicode.h>
29
30#include "fontprops.h"
31#include "math.h"
32#include "MathExtras.h"
33
34#include <wx/defs.h>
35#include <wx/gdicmn.h>
36#include <wx/wx.h>
37#include "wx/msw/private.h"
38
39#include <mlang.h>
40#include <usp10.h>
41
42inline long  my_round(double x)
43{
44    return (long)(x < 0 ? x - 0.5 : x + 0.5);
45}
46
47wxFontProperties::wxFontProperties(wxFont* font):
48m_ascent(0), m_descent(0), m_lineGap(0), m_lineSpacing(0), m_xHeight(0)
49{
50    HDC dc = GetDC(0);
51    WXHFONT hFont = font->GetHFONT();
52    ::SelectObject(dc, hFont);
53    if (font){
54
55        int height = font->GetPointSize();
56
57        TEXTMETRIC tm;
58        GetTextMetrics(dc, &tm);
59        m_ascent = lroundf(tm.tmAscent);
60        m_descent = lroundf(tm.tmDescent);
61        m_xHeight = m_ascent * 0.56f;  // Best guess for xHeight for non-Truetype fonts.
62        m_lineGap = lroundf(tm.tmExternalLeading);
63        m_lineSpacing = m_lineGap + m_ascent + m_descent;
64    }
65    RestoreDC(dc, -1);
66    ReleaseDC(0, dc);
67}
68
69bool wxFontContainsCharacters(void* font, const UChar* characters, int length)
70{
71    // FIXME: Microsoft documentation seems to imply that characters can be output using a given font and DC
72    // merely by testing code page intersection.  This seems suspect though.  Can't a font only partially
73    // cover a given code page?
74    static IMultiLanguage *multiLanguage;
75    if (!multiLanguage) {
76        if (CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_ALL, IID_IMultiLanguage, (void**)&multiLanguage) != S_OK)
77            return true;
78    }
79
80    static IMLangFontLink2* langFontLink;
81    if (!langFontLink) {
82        if (multiLanguage->QueryInterface(&langFontLink) != S_OK)
83            return true;
84    }
85
86    HDC dc = GetDC(0);
87
88    DWORD acpCodePages;
89    langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages);
90
91    DWORD fontCodePages;
92    langFontLink->GetFontCodePages(dc, (HFONT)font, &fontCodePages);
93
94    DWORD actualCodePages;
95    long numCharactersProcessed;
96    long offset = 0;
97    while (offset < length) {
98        langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &numCharactersProcessed);
99        if ((actualCodePages & fontCodePages))
100            return false;
101        offset += numCharactersProcessed;
102    }
103
104    ReleaseDC(0, dc);
105
106    return true;
107}
108
109void GetTextExtent( const wxFont& font, const wxString& str, wxCoord *width, wxCoord *height,
110                            wxCoord *descent, wxCoord *externalLeading )
111{
112    HDC dc = GetDC(0);
113    WXHFONT hFont = font.GetHFONT();
114    ::SelectObject(dc, hFont);
115
116    HFONT hfontOld;
117    if ( font != wxNullFont )
118    {
119        wxASSERT_MSG( font.Ok(), _T("invalid font in wxDC::GetTextExtent") );
120
121        hfontOld = (HFONT)::SelectObject(dc, hFont);
122    }
123    else // don't change the font
124    {
125        hfontOld = 0;
126    }
127
128    SIZE sizeRect;
129    const size_t len = str.length();
130    if ( !::GetTextExtentPoint32(dc, str, len, &sizeRect) )
131    {
132        wxLogLastError(_T("GetTextExtentPoint32()"));
133    }
134
135#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
136    // the result computed by GetTextExtentPoint32() may be too small as it
137    // accounts for under/overhang of the first/last character while we want
138    // just the bounding rect for this string so adjust the width as needed
139    // (using API not available in 2002 SDKs of WinCE)
140    if ( len > 1 )
141    {
142        ABC width;
143        const wxChar chFirst = *str.begin();
144        if ( ::GetCharABCWidths(dc, chFirst, chFirst, &width) )
145        {
146            if ( width.abcA < 0 )
147                sizeRect.cx -= width.abcA;
148
149            if ( len > 1 )
150            {
151                const wxChar chLast = *str.rbegin();
152                ::GetCharABCWidths(dc, chLast, chLast, &width);
153            }
154            //else: we already have the width of the last character
155
156            if ( width.abcC < 0 )
157                sizeRect.cx -= width.abcC;
158        }
159        //else: GetCharABCWidths() failed, not a TrueType font?
160    }
161#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
162
163    TEXTMETRIC tm;
164    ::GetTextMetrics(dc, &tm);
165
166    if (width)
167        *width = sizeRect.cx;
168    if (height)
169        *height = sizeRect.cy;
170    if (descent)
171        *descent = tm.tmDescent;
172    if (externalLeading)
173        *externalLeading = tm.tmExternalLeading;
174
175    if ( hfontOld )
176    {
177        ::SelectObject(dc, hfontOld);
178    }
179
180    ReleaseDC(0, dc);
181}
182