blob: 44d10a95bd00c935061c8fb5b7684de27ccc34f4 [file] [log] [blame]
// Copyright 2015 The Cobalt Authors. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include "base/callback.h"
#include "base/containers/hash_tables.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "cobalt/dom/font_face.h"
#include "cobalt/dom/font_list.h"
#include "cobalt/dom/location.h"
#include "cobalt/loader/font/remote_typeface_cache.h"
#include "cobalt/render_tree/font.h"
#include "cobalt/render_tree/glyph.h"
#include "cobalt/render_tree/resource_provider.h"
#include "url/gurl.h"
namespace cobalt {
namespace dom {
// The font cache is typically owned by dom::Document and handles the following:
// - Tracking of font faces, which it uses to determine if a specified
// font family is local or remote, and for url determination in requesting
// remote typefaces.
// - Creation and caching of font lists, which it provides to the used
// style provider as requested. Font lists handle most layout-related font
// cache interactions. Layout objects only interact with the font cache
// through their font lists.
// - Retrieval of typefaces, either locally from the resource provider or
// remotely from the remote typeface cache, and caching of both typefaces
// and fonts to facilitate sharing of them across font lists.
// - Determination of the fallback typeface for a specific character using a
// specific font style, and caching of that information for subsequent
// lookups.
// - Creation of glyph buffers, which is accomplished by passing the request
// to the resource provider.
// NOTE: The font cache is not thread-safe and must only used within a single
// thread.
class FontCache {
class RequestedRemoteTypefaceInfo
: public base::RefCounted<RequestedRemoteTypefaceInfo> {
const scoped_refptr<loader::font::CachedRemoteTypeface>&
const base::Closure& font_load_event_callback);
bool HasActiveRequestTimer() const { return request_timer_ != NULL; }
void ClearRequestTimer() { request_timer_.reset(); }
// The request timer delay, after which the requesting font list's fallback
// font becomes visible.
// NOTE: While using a timer of exactly 3 seconds is not specified by the
// spec, it is the delay used by both Firefox and Webkit, and thus matches
// user expectations.
static const int kRequestTimerDelay = 3000;
// The cached remote typeface reference both provides load event callbacks
// to the remote typeface cache for this remote typeface, and also ensures
// that the remote typeface is retained in the remote typeface cache's
// memory for as long as this reference exists.
// The request timer is started on object creation and triggers a load event
// callback when the timer expires. Before the timer expires, font lists
// that use this font will be rendered transparently to avoid a flash of
// text from briefly displaying a fallback font. However, permanently hiding
// the text while waiting for it to load is considered non-conformant
// behavior by the spec, so after the timer expires, the fallback font
// becomes visible (
std::unique_ptr<base::OneShotTimer> request_timer_;
struct FontListInfo {
scoped_refptr<FontList> font_list;
base::TimeTicks inactive_time;
struct FontKey {
FontKey(render_tree::TypefaceId key_typeface_id, float key_size)
: typeface_id(key_typeface_id), size(key_size) {}
bool operator<(const FontKey& rhs) const {
if (typeface_id != rhs.typeface_id) {
return typeface_id < rhs.typeface_id;
} else {
return size < rhs.size;
render_tree::TypefaceId typeface_id;
float size;
struct FontInfo {
scoped_refptr<render_tree::Font> font;
base::TimeTicks inactive_time;
struct InactiveFontKey {
InactiveFontKey(base::TimeTicks time, FontKey key)
: inactive_time(time), font_key(key) {}
bool operator<(const InactiveFontKey& rhs) const {
if (inactive_time != rhs.inactive_time) {
return inactive_time < rhs.inactive_time;
} else {
return font_key < rhs.font_key;
base::TimeTicks inactive_time;
FontKey font_key;
struct CharacterFallbackKey {
explicit CharacterFallbackKey(const render_tree::FontStyle& key_style)
: style(key_style) {}
bool operator<(const CharacterFallbackKey& rhs) const {
if (style.weight != {
return style.weight <;
} else {
return style.slant <;
render_tree::FontStyle style;
// Font-face related
typedef std::map<std::string, FontFaceStyleSet> FontFaceMap;
typedef std::map<GURL, scoped_refptr<RequestedRemoteTypefaceInfo> >
// Font list related
typedef std::map<FontListKey, FontListInfo> FontListMap;
// Typeface/Font related
typedef base::small_map<
std::map<render_tree::TypefaceId, scoped_refptr<render_tree::Typeface> >,
typedef std::map<FontKey, FontInfo> FontMap;
typedef std::set<InactiveFontKey> InactiveFontSet;
// Character fallback related
typedef base::hash_map<int32, scoped_refptr<render_tree::Typeface> >
typedef std::map<CharacterFallbackKey, CharacterFallbackTypefaceMap>
FontCache(render_tree::ResourceProvider** resource_provider,
loader::font::RemoteTypefaceCache* remote_typeface_cache,
const base::Closure& external_typeface_load_event_callback,
const std::string& language_script,
scoped_refptr<Location> document_location);
// Set a new font face map. If it matches the old font face map then nothing
// is done. Otherwise, it is updated with the new value and the remote
// typeface containers are purged of URLs that are no longer contained within
// the map.
void SetFontFaceMap(std::unique_ptr<FontFaceMap> font_face_map);
// Purge all caches within the font cache.
void PurgeCachedResources();
// Process unused font lists and fonts, potentially purging them from the
// cache if they meet the removal requirements.
void ProcessInactiveFontListsAndFonts();
// Looks up and returns the font list in |font_list_map_|. If the font list
// doesn't already exist, then a new one is created and added to the cache.
const scoped_refptr<FontList>& GetFontList(const FontListKey& font_list_key);
// Looks up and returns the font with the matching typeface and size in
// |font_map_|. If it doesn't already exist in the cache, then a new font is
// created from typeface and added to the cache.
const scoped_refptr<render_tree::Font>& GetFontFromTypefaceAndSize(
const scoped_refptr<render_tree::Typeface>& typeface, float size);
// Attempts to retrieve a font. If the family maps to a font face, then this
// makes a request to |TryGetRemoteFont()|; otherwise, it makes a request
// to |TryGetLocalFont()|. This function may return NULL.
scoped_refptr<render_tree::Font> TryGetFont(const std::string& family,
render_tree::FontStyle style,
float size,
FontListFont::State* state);
// Returns the character fallback typeface map associated with the specified
// style. Each unique style has its own exclusive map. If it doesn't already
// exist in the cache, then it is created during the request.
// NOTE: This map is provided by the font cache so that all font lists with
// the same style can share the same map. However, the cache itself does not
// populate or query the map.
CharacterFallbackTypefaceMap& GetCharacterFallbackTypefaceMap(
const render_tree::FontStyle& style);
// Retrieves the typeface associated with a UTF-32 character and style from
// the resource provider.
// NOTE: |character_fallback_typeface_maps_| is not queried before retrieving
// the typeface from the resource provider. It is expected that the font list
// will query its specific map first.
const scoped_refptr<render_tree::Typeface>& GetCharacterFallbackTypeface(
int32 utf32_character, const render_tree::FontStyle& style);
// Given a string of text, returns the glyph buffer needed to render it.
scoped_refptr<render_tree::GlyphBuffer> CreateGlyphBuffer(
const base::char16* text_buffer, int32 text_length, bool is_rtl,
FontList* font_list);
// Given a string of text, return its width. This is faster than
// CreateGlyphBuffer().
float GetTextWidth(const base::char16* text_buffer, int32 text_length,
bool is_rtl, FontList* font_list,
render_tree::FontVector* maybe_used_fonts);
render_tree::ResourceProvider* resource_provider() const {
return *resource_provider_;
void ProcessInactiveFontLists(const base::TimeTicks& current_time);
void ProcessInactiveFonts(const base::TimeTicks& current_time);
// Looks up and returns the cached typeface in |local_typeface_map_|. If it
// doesn't already exist in the cache, then the passed in typeface is added to
// the cache.
const scoped_refptr<render_tree::Typeface>& GetCachedLocalTypeface(
const scoped_refptr<render_tree::Typeface>& typeface);
// Returns the font if it is in the remote typeface cache and available;
// otherwise returns NULL.
// If the font is in the cache, but is not loaded, this call triggers an
// asynchronous load of it. Both an external load even callback, provided by
// the constructor and an |OnRemoteFontLoadEvent| callback provided by the
// font are registered with the remote typeface cache to be called when the
// load finishes.
scoped_refptr<render_tree::Font> TryGetRemoteFont(const GURL& url, float size,
FontListFont::State* state);
// Returns NULL if the requested family is not empty and is not available in
// the resource provider. Otherwise, returns the best matching local font.
scoped_refptr<render_tree::Font> TryGetLocalFont(const std::string& family,
render_tree::FontStyle style,
float size,
FontListFont::State* state);
// Lookup by a typeface (aka font_face), typeface is defined as font family +
// style (weight, width, and style).
// Returns NULL if the requested font face is not found.
scoped_refptr<render_tree::Font> TryGetLocalFontByFaceName(
const std::string& font_face, float size, FontListFont::State* state);
// Called when a remote typeface either successfully loads or fails to load.
// In either case, the event can impact the fonts contained within the font
// lists. As a result, the font lists need to have their loading fonts reset
// so that they'll be re-requested from the cache.
void OnRemoteTypefaceLoadEvent(const GURL& url);
render_tree::ResourceProvider** resource_provider_;
// TODO: Explore eliminating the remote typeface cache and moving its
// logic into the font cache when the loader interface improves.
loader::font::RemoteTypefaceCache* const remote_typeface_cache_;
const base::Closure external_typeface_load_event_callback_;
const std::string language_script_;
// Font-face related
// The cache contains a map of font faces and handles requesting typefaces by
// url on demand from |remote_typeface_cache_| with a load event callback
// provided by the constructor. Cached remote typeface returned by
// |remote_typeface_cache_| have a reference retained by the cache for as long
// as the cache contains a font face with the corresponding url, to ensure
// that they remain in memory.
std::unique_ptr<FontFaceMap> font_face_map_;
RequestedRemoteTypefaceMap requested_remote_typeface_cache_;
// Font list related
// This maps unique font property combinations that are currently in use
// within the document to the font lists that provides the functionality
// associated with those font property combinations.
FontListMap font_list_map_;
// Typeface/Font related
// Maps of the local typefaces and fonts currently cached. These are used so
// that the same typefaces and fonts can be shared across multiple font lists,
// thereby also sharing the internal caching within typeface and font objects.
// NOTE: Remote typefaces are not cached in |local_typeface_map_|, as the
// RemoteTypefaceCache handles caching of them.
TypefaceMap local_typeface_map_;
FontMap font_map_;
InactiveFontSet inactive_font_set_;
// Fallback font related
// Contains maps of both the unique typeface to use with a specific
// character-style combination and a prototype font for the typeface, which
// can be used to provide copies of the font at any desired size, without
// requiring an additional request of the resource provider for each newly
// encountered size.
CharacterFallbackTypefaceMaps character_fallback_typeface_maps_;
// The last time the cache was checked for inactivity.
base::TimeTicks last_inactive_process_time_;
// Thread checker used to verify safe thread usage of the font cache.
// Font cache's corresponding document's location object. It can provide
// document's origin.
scoped_refptr<Location> document_location_;
} // namespace dom
} // namespace cobalt