Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2007 Kevin Ollivier <kevino (at) 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 
     42 inline long  my_round(double x)
     43 {
     44     return (long)(x < 0 ? x - 0.5 : x + 0.5);
     45 }
     46 
     47 wxFontProperties::wxFontProperties(wxFont* font):
     48 m_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 
     69 bool 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 
    109 void 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