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