Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2006, 2007, 2008 Apple Inc.  All rights reserved.
      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  *
      8  * 1.  Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  * 2.  Redistributions in binary form must reproduce the above copyright
     11  *     notice, this list of conditions and the following disclaimer in the
     12  *     documentation and/or other materials provided with the distribution.
     13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     14  *     its contributors may be used to endorse or promote products derived
     15  *     from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 #include "SimpleFontData.h"
     31 
     32 #include "Font.h"
     33 #include "FontCache.h"
     34 #include "FloatRect.h"
     35 #include "FontDescription.h"
     36 #include <mlang.h>
     37 #include <unicode/uchar.h>
     38 #include <unicode/unorm.h>
     39 #include <winsock2.h>
     40 #include <wtf/MathExtras.h>
     41 
     42 #if USE(CG)
     43 #include <ApplicationServices/ApplicationServices.h>
     44 #include <WebKitSystemInterface/WebKitSystemInterface.h>
     45 #endif
     46 
     47 namespace WebCore {
     48 
     49 using std::max;
     50 
     51 const float cSmallCapsFontSizeMultiplier = 0.7f;
     52 
     53 static bool g_shouldApplyMacAscentHack;
     54 
     55 void SimpleFontData::setShouldApplyMacAscentHack(bool b)
     56 {
     57     g_shouldApplyMacAscentHack = b;
     58 }
     59 
     60 bool SimpleFontData::shouldApplyMacAscentHack()
     61 {
     62     return g_shouldApplyMacAscentHack;
     63 }
     64 
     65 void SimpleFontData::initGDIFont()
     66 {
     67     if (!m_platformData.size()) {
     68         m_fontMetrics.reset();
     69         m_avgCharWidth = 0;
     70         m_maxCharWidth = 0;
     71         return;
     72     }
     73 
     74      HDC hdc = GetDC(0);
     75      HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont());
     76      OUTLINETEXTMETRIC metrics;
     77      GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics);
     78      TEXTMETRIC& textMetrics = metrics.otmTextMetrics;
     79      float ascent = textMetrics.tmAscent;
     80      float descent = textMetrics.tmDescent;
     81      float lineGap = textMetrics.tmExternalLeading;
     82      m_fontMetrics.setAscent(ascent);
     83      m_fontMetrics.setDescent(descent);
     84      m_fontMetrics.setLineGap(lineGap);
     85      m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap));
     86      m_avgCharWidth = textMetrics.tmAveCharWidth;
     87      m_maxCharWidth = textMetrics.tmMaxCharWidth;
     88      float xHeight = ascent * 0.56f; // Best guess for xHeight if no x glyph is present.
     89 
     90      GLYPHMETRICS gm;
     91      MAT2 mat = { 1, 0, 0, 1 };
     92      DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
     93      if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
     94          xHeight = gm.gmptGlyphOrigin.y;
     95 
     96      m_fontMetrics.setXHeight(xHeight);
     97      m_fontMetrics.setUnitsPerEm(metrics.otmEMSquare);
     98 
     99      SelectObject(hdc, oldFont);
    100      ReleaseDC(0, hdc);
    101 
    102      return;
    103 }
    104 
    105 void SimpleFontData::platformDestroy()
    106 {
    107     ScriptFreeCache(&m_scriptCache);
    108     delete m_scriptFontProperties;
    109 }
    110 
    111 SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
    112 {
    113         float scaledSize = scaleFactor * m_platformData.size();
    114         if (isCustomFont()) {
    115             FontPlatformData scaledFont(m_platformData);
    116             scaledFont.setSize(scaledSize);
    117             return new SimpleFontData(scaledFont, true, false);
    118         }
    119 
    120         LOGFONT winfont;
    121         GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winfont);
    122         winfont.lfHeight = -lroundf(scaledSize * (m_platformData.useGDI() ? 1 : 32));
    123         HFONT hfont = CreateFontIndirect(&winfont);
    124         return new SimpleFontData(FontPlatformData(hfont, scaledSize, m_platformData.syntheticBold(), m_platformData.syntheticOblique(), m_platformData.useGDI()), isCustomFont(), false);
    125 }
    126 
    127 SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
    128 {
    129     if (!m_derivedFontData)
    130         m_derivedFontData = DerivedFontData::create(isCustomFont());
    131     if (!m_derivedFontData->smallCaps)
    132         m_derivedFontData->smallCaps = scaledFontData(fontDescription, cSmallCapsFontSizeMultiplier);
    133 
    134     return m_derivedFontData->smallCaps.get();
    135 }
    136 
    137 SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
    138 {
    139     if (!m_derivedFontData)
    140         m_derivedFontData = DerivedFontData::create(isCustomFont());
    141     if (!m_derivedFontData->emphasisMark)
    142         m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5);
    143 
    144     return m_derivedFontData->emphasisMark.get();
    145 }
    146 
    147 bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
    148 {
    149     // FIXME: Support custom fonts.
    150     if (isCustomFont())
    151         return false;
    152 
    153     // FIXME: Microsoft documentation seems to imply that characters can be output using a given font and DC
    154     // merely by testing code page intersection.  This seems suspect though.  Can't a font only partially
    155     // cover a given code page?
    156     IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
    157     if (!langFontLink)
    158         return false;
    159 
    160     HDC dc = GetDC(0);
    161 
    162     DWORD acpCodePages;
    163     langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages);
    164 
    165     DWORD fontCodePages;
    166     langFontLink->GetFontCodePages(dc, m_platformData.hfont(), &fontCodePages);
    167 
    168     DWORD actualCodePages;
    169     long numCharactersProcessed;
    170     long offset = 0;
    171     while (offset < length) {
    172         langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &numCharactersProcessed);
    173         if ((actualCodePages & fontCodePages) == 0)
    174             return false;
    175         offset += numCharactersProcessed;
    176     }
    177 
    178     ReleaseDC(0, dc);
    179 
    180     return true;
    181 }
    182 
    183 void SimpleFontData::determinePitch()
    184 {
    185     if (isCustomFont()) {
    186         m_treatAsFixedPitch = false;
    187         return;
    188     }
    189 
    190     // TEXTMETRICS have this.  Set m_treatAsFixedPitch based off that.
    191     HDC dc = GetDC(0);
    192     SaveDC(dc);
    193     SelectObject(dc, m_platformData.hfont());
    194 
    195     // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
    196     // is *not* fixed pitch.  Unbelievable but true.
    197     TEXTMETRIC tm;
    198     GetTextMetrics(dc, &tm);
    199     m_treatAsFixedPitch = ((tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
    200 
    201     RestoreDC(dc, -1);
    202     ReleaseDC(0, dc);
    203 }
    204 
    205 FloatRect SimpleFontData::boundsForGDIGlyph(Glyph glyph) const
    206 {
    207     HDC hdc = GetDC(0);
    208     SetGraphicsMode(hdc, GM_ADVANCED);
    209     HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont());
    210 
    211     GLYPHMETRICS gdiMetrics;
    212     static const MAT2 identity = { 0, 1,  0, 0,  0, 0,  0, 1 };
    213     GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity);
    214 
    215     SelectObject(hdc, oldFont);
    216     ReleaseDC(0, hdc);
    217 
    218     return FloatRect(gdiMetrics.gmptGlyphOrigin.x, -gdiMetrics.gmptGlyphOrigin.y,
    219         gdiMetrics.gmBlackBoxX + m_syntheticBoldOffset, gdiMetrics.gmBlackBoxY);
    220 }
    221 
    222 float SimpleFontData::widthForGDIGlyph(Glyph glyph) const
    223 {
    224     HDC hdc = GetDC(0);
    225     SetGraphicsMode(hdc, GM_ADVANCED);
    226     HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont());
    227 
    228     GLYPHMETRICS gdiMetrics;
    229     static const MAT2 identity = { 0, 1,  0, 0,  0, 0,  0, 1 };
    230     GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity);
    231 
    232     SelectObject(hdc, oldFont);
    233     ReleaseDC(0, hdc);
    234 
    235     return gdiMetrics.gmCellIncX + m_syntheticBoldOffset;
    236 }
    237 
    238 SCRIPT_FONTPROPERTIES* SimpleFontData::scriptFontProperties() const
    239 {
    240     if (!m_scriptFontProperties) {
    241         m_scriptFontProperties = new SCRIPT_FONTPROPERTIES;
    242         memset(m_scriptFontProperties, 0, sizeof(SCRIPT_FONTPROPERTIES));
    243         m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
    244         HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties);
    245         if (result == E_PENDING) {
    246             HDC dc = GetDC(0);
    247             SaveDC(dc);
    248             SelectObject(dc, m_platformData.hfont());
    249             ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties);
    250             RestoreDC(dc, -1);
    251             ReleaseDC(0, dc);
    252         }
    253     }
    254     return m_scriptFontProperties;
    255 }
    256 
    257 }
    258