15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/font_cache_dispatcher_win.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map> 87d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <vector> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string16.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/child_process_messages.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)typedef std::vector<base::string16> FontNameVector; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef std::map<FontCacheDispatcher*, FontNameVector> DispatcherToFontNames; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FontCache { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static FontCache* GetInstance() { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Singleton<FontCache>::get(); 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void PreCacheFont(const LOGFONT& font, FontCacheDispatcher* dispatcher) { 26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) typedef std::map<base::string16, FontCache::CacheElement> FontNameToElement; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock lock(mutex_); 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fetch the font into memory. 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No matter the font is cached or not, we load it to avoid GDI swapping out 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that font file. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HDC hdc = GetDC(NULL); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HFONT font_handle = CreateFontIndirect(&font); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(NULL != font_handle); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HGDIOBJ old_font = SelectObject(hdc, font_handle); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(NULL != old_font); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TEXTMETRIC tm; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL ret = GetTextMetrics(hdc, &tm); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(ret); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 font_name = font.lfFaceName; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ref_count_inc = 1; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FontNameVector::iterator it = 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::find(dispatcher_font_map_[dispatcher].begin(), 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dispatcher_font_map_[dispatcher].end(), 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) font_name); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == dispatcher_font_map_[dispatcher].end()) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Requested font is new to cache. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dispatcher_font_map_[dispatcher].push_back(font_name); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ref_count_inc = 0; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cache_[font_name].ref_count_ == 0) { // Requested font is new to cache. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cache_[font_name].ref_count_ = 1; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { // Requested font is already in cache, release old handles. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SelectObject(cache_[font_name].dc_, cache_[font_name].old_font_); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeleteObject(cache_[font_name].font_); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReleaseDC(NULL, cache_[font_name].dc_); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cache_[font_name].font_ = font_handle; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cache_[font_name].dc_ = hdc; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cache_[font_name].old_font_ = old_font; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cache_[font_name].ref_count_ += ref_count_inc; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ReleaseCachedFonts(FontCacheDispatcher* dispatcher) { 71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) typedef std::map<base::string16, FontCache::CacheElement> FontNameToElement; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock lock(mutex_); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DispatcherToFontNames::iterator it; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it = dispatcher_font_map_.find(dispatcher); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == dispatcher_font_map_.end()) { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (FontNameVector::iterator i = it->second.begin(), e = it->second.end(); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != e; ++i) { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FontNameToElement::iterator element; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) element = cache_.find(*i); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (element != cache_.end()) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --((*element).second.ref_count_); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dispatcher_font_map_.erase(it); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (FontNameToElement::iterator i = cache_.begin(); i != cache_.end(); ) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i->second.ref_count_ == 0) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cache_.erase(i++); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++i; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct CacheElement { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CacheElement() 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : font_(NULL), old_font_(NULL), dc_(NULL), ref_count_(0) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~CacheElement() { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (font_) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dc_ && old_font_) { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SelectObject(dc_, old_font_); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeleteObject(font_); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dc_) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReleaseDC(NULL, dc_); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HFONT font_; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HGDIOBJ old_font_; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HDC dc_; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ref_count_; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend struct DefaultSingletonTraits<FontCache>; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FontCache() { 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::map<base::string16, CacheElement> cache_; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DispatcherToFontNames dispatcher_font_map_; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Lock mutex_; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(FontCache); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FontCacheDispatcher::FontCacheDispatcher() 138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : sender_(NULL) { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FontCacheDispatcher::~FontCacheDispatcher() { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FontCacheDispatcher::OnFilterAdded(IPC::Sender* sender) { 145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) sender_ = sender; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FontCacheDispatcher::OnMessageReceived(const IPC::Message& message) { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool handled = true; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_BEGIN_MESSAGE_MAP(FontCacheDispatcher, message) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(ChildProcessHostMsg_PreCacheFont, OnPreCacheFont) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ReleaseCachedFonts, 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnReleaseCachedFonts) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_END_MESSAGE_MAP() 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return handled; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FontCacheDispatcher::OnChannelClosing() { 160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) sender_ = NULL; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FontCacheDispatcher::Send(IPC::Message* message) { 164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (sender_) 165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return sender_->Send(message); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete message; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FontCacheDispatcher::OnPreCacheFont(const LOGFONT& font) { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a child process is running in a sandbox, GetTextMetrics() 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // can sometimes fail. If a font has not been loaded 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // previously, GetTextMetrics() will try to load the font 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // from the font file. However, the sandboxed process does 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not have permissions to access any font files and 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the call fails. So we make the browser pre-load the 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // font for us by using a dummy call to GetTextMetrics of 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the same font. 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This means the browser process just loads the font into memory so that 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // when GDI attempt to query that font info in child process, it does not 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // need to load that file, hence no permission issues there. Therefore, 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // when a font is asked to be cached, we always recreates the font object 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to avoid the case that an in-cache font is swapped out by GDI. 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FontCache::GetInstance()->PreCacheFont(font, this); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FontCacheDispatcher::OnReleaseCachedFonts() { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Release cached fonts that requested from a pid by decrementing the ref 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // count. When ref count is zero, the handles are released. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FontCache::GetInstance()->ReleaseCachedFonts(this); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace content 195