1 /* 2 * Copyright (C) 2006, 2007 Apple Computer, Inc. 3 * Copyright (c) 2006, 2007, 2008, 2009, 2012 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "config.h" 33 #include "core/platform/graphics/FontPlatformData.h" 34 35 #include <windows.h> 36 #include <mlang.h> 37 #include <objidl.h> 38 #include "SkPaint.h" 39 #include "SkTypeface_win.h" 40 #include "core/platform/SharedBuffer.h" 41 #include "core/platform/graphics/FontCache.h" 42 #include "core/platform/graphics/skia/SkiaFontWin.h" 43 #include "core/platform/win/HWndDC.h" 44 #include "public/platform/Platform.h" 45 #include "public/platform/win/WebSandboxSupport.h" 46 #include "wtf/PassOwnPtr.h" 47 #include "wtf/StdLibExtras.h" 48 49 namespace WebCore { 50 51 #if !ENABLE(GDI_FONTS_ON_WINDOWS) 52 void FontPlatformData::setupPaint(SkPaint* paint) const 53 { 54 const float ts = m_size >= 0 ? m_size : 12; 55 paint->setTextSize(SkFloatToScalar(m_size)); 56 paint->setTypeface(m_typeface); 57 } 58 #endif 59 60 // Lookup the current system settings for font smoothing. 61 // We cache these values for performance, but if the browser has a way to be 62 // notified when these change, we could re-query them at that time. 63 static uint32_t getDefaultGDITextFlags() 64 { 65 static bool gInited; 66 static uint32_t gFlags; 67 if (!gInited) { 68 BOOL enabled; 69 gFlags = 0; 70 if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &enabled, 0) && enabled) { 71 gFlags |= SkPaint::kAntiAlias_Flag; 72 73 UINT smoothType; 74 if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothType, 0)) { 75 if (FE_FONTSMOOTHINGCLEARTYPE == smoothType) 76 gFlags |= SkPaint::kLCDRenderText_Flag; 77 } 78 } 79 gInited = true; 80 } 81 return gFlags; 82 } 83 84 static int computePaintTextFlags(const LOGFONT& lf) 85 { 86 int textFlags = 0; 87 switch (lf.lfQuality) { 88 case NONANTIALIASED_QUALITY: 89 textFlags = 0; 90 break; 91 case ANTIALIASED_QUALITY: 92 textFlags = SkPaint::kAntiAlias_Flag; 93 break; 94 case CLEARTYPE_QUALITY: 95 textFlags = (SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag); 96 break; 97 default: 98 textFlags = getDefaultGDITextFlags(); 99 break; 100 } 101 102 // only allow features that SystemParametersInfo allows 103 return textFlags & getDefaultGDITextFlags(); 104 } 105 106 PassRefPtr<SkTypeface> CreateTypefaceFromHFont(HFONT hfont, int* size, int* paintTextFlags) 107 { 108 LOGFONT info; 109 GetObject(hfont, sizeof(info), &info); 110 if (size) { 111 int height = info.lfHeight; 112 if (height < 0) 113 height = -height; 114 *size = height; 115 } 116 if (paintTextFlags) 117 *paintTextFlags = computePaintTextFlags(info); 118 return adoptRef(SkCreateTypefaceFromLOGFONT(info)); 119 } 120 121 FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType) 122 : m_font(0) 123 , m_size(-1) 124 , m_orientation(Horizontal) 125 , m_scriptCache(0) 126 , m_paintTextFlags(0) 127 , m_isHashTableDeletedValue(true) 128 { 129 } 130 131 FontPlatformData::FontPlatformData() 132 : m_font(0) 133 , m_size(0) 134 , m_orientation(Horizontal) 135 , m_scriptCache(0) 136 , m_paintTextFlags(0) 137 , m_isHashTableDeletedValue(false) 138 { 139 } 140 141 FontPlatformData::FontPlatformData(HFONT font, float size, FontOrientation orientation) 142 : m_font(RefCountedHFONT::create(font)) 143 , m_size(size) 144 , m_orientation(orientation) 145 , m_scriptCache(0) 146 , m_typeface(CreateTypefaceFromHFont(font, 0, &m_paintTextFlags)) 147 , m_isHashTableDeletedValue(false) 148 { 149 } 150 151 // FIXME: this constructor is needed for SVG fonts but doesn't seem to do much 152 FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) 153 : m_font(0) 154 , m_size(size) 155 , m_orientation(Horizontal) 156 , m_scriptCache(0) 157 , m_paintTextFlags(0) 158 , m_isHashTableDeletedValue(false) 159 { 160 } 161 162 FontPlatformData::FontPlatformData(const FontPlatformData& data) 163 : m_font(data.m_font) 164 , m_size(data.m_size) 165 , m_orientation(data.m_orientation) 166 , m_scriptCache(0) 167 , m_typeface(data.m_typeface) 168 , m_paintTextFlags(data.m_paintTextFlags) 169 , m_isHashTableDeletedValue(false) 170 { 171 } 172 173 FontPlatformData::FontPlatformData(const FontPlatformData& data, float textSize) 174 : m_font(data.m_font) 175 , m_size(textSize) 176 , m_orientation(data.m_orientation) 177 , m_scriptCache(0) 178 , m_typeface(data.m_typeface) 179 , m_paintTextFlags(data.m_paintTextFlags) 180 , m_isHashTableDeletedValue(false) 181 { 182 } 183 184 FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data) 185 { 186 if (this != &data) { 187 m_font = data.m_font; 188 m_size = data.m_size; 189 m_orientation = data.m_orientation; 190 m_typeface = data.m_typeface; 191 m_paintTextFlags = data.m_paintTextFlags; 192 193 // The following fields will get re-computed if necessary. 194 ScriptFreeCache(&m_scriptCache); 195 m_scriptCache = 0; 196 m_scriptFontProperties.clear(); 197 } 198 return *this; 199 } 200 201 FontPlatformData::~FontPlatformData() 202 { 203 ScriptFreeCache(&m_scriptCache); 204 m_scriptCache = 0; 205 } 206 207 bool FontPlatformData::isFixedPitch() const 208 { 209 #if ENABLE(GDI_FONTS_ON_WINDOWS) 210 // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that. 211 HWndDC dc(0); 212 HGDIOBJ oldFont = SelectObject(dc, hfont()); 213 214 // Yes, this looks backwards, but the fixed pitch bit is actually set if the font 215 // is *not* fixed pitch. Unbelievable but true. 216 TEXTMETRIC textMetric = { 0 }; 217 if (!GetTextMetrics(dc, &textMetric)) { 218 if (ensureFontLoaded(hfont())) { 219 // Retry GetTextMetrics. 220 // FIXME: Handle gracefully the error if this call also fails. 221 // See http://crbug.com/6401. 222 if (!GetTextMetrics(dc, &textMetric)) 223 LOG_ERROR("Unable to get the text metrics after second attempt"); 224 } 225 } 226 227 bool treatAsFixedPitch = !(textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH); 228 229 SelectObject(dc, oldFont); 230 231 return treatAsFixedPitch; 232 #else 233 return typeface()->isFixedPitch(); 234 #endif 235 } 236 237 FontPlatformData::RefCountedHFONT::~RefCountedHFONT() 238 { 239 DeleteObject(m_hfont); 240 } 241 242 SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const 243 { 244 if (!m_scriptFontProperties) { 245 m_scriptFontProperties = adoptPtr(new SCRIPT_FONTPROPERTIES); 246 memset(m_scriptFontProperties.get(), 0, sizeof(SCRIPT_FONTPROPERTIES)); 247 m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES); 248 HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties.get()); 249 if (result == E_PENDING) { 250 HWndDC dc(0); 251 HGDIOBJ oldFont = SelectObject(dc, hfont()); 252 HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get()); 253 if (S_OK != hr) { 254 if (FontPlatformData::ensureFontLoaded(hfont())) { 255 // FIXME: Handle gracefully the error if this call also fails. 256 hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get()); 257 if (S_OK != hr) { 258 LOG_ERROR("Unable to get the font properties after second attempt"); 259 } 260 } 261 } 262 263 SelectObject(dc, oldFont); 264 } 265 } 266 return m_scriptFontProperties.get(); 267 } 268 269 #ifndef NDEBUG 270 String FontPlatformData::description() const 271 { 272 return String(); 273 } 274 #endif 275 276 bool FontPlatformData::ensureFontLoaded(HFONT font) 277 { 278 WebKit::WebSandboxSupport* sandboxSupport = WebKit::Platform::current()->sandboxSupport(); 279 // if there is no sandbox, then we can assume the font 280 // was able to be loaded successfully already 281 return sandboxSupport ? sandboxSupport->ensureFontLoaded(font) : true; 282 } 283 284 } 285