| /* |
| * Copyright 2015 Google Inc. 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 |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef COBALT_DOM_FONT_CACHE_H_ |
| #define COBALT_DOM_FONT_CACHE_H_ |
| |
| #include <map> |
| #include <set> |
| #include <string> |
| #include <utility> |
| |
| #include "base/callback.h" |
| #include "base/hash_tables.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/threading/thread_checker.h" |
| #include "base/timer.h" |
| #include "cobalt/dom/font_face.h" |
| #include "cobalt/dom/font_list.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 "googleurl/src/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 { |
| public: |
| class RequestedRemoteTypefaceInfo |
| : public base::RefCounted<RequestedRemoteTypefaceInfo> { |
| public: |
| RequestedRemoteTypefaceInfo( |
| const scoped_refptr<loader::font::CachedRemoteTypeface>& |
| cached_remote_typeface, |
| const base::Closure& font_load_event_callback); |
| |
| bool HasActiveRequestTimer() const { return request_timer_ != NULL; } |
| void ClearRequestTimer() { request_timer_.reset(); } |
| |
| private: |
| // 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. |
| scoped_ptr<loader::font::CachedRemoteTypefaceReferenceWithCallbacks> |
| cached_remote_typeface_reference_; |
| |
| // 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 (https://www.w3.org/TR/css3-fonts/#font-face-loading). |
| scoped_ptr<base::Timer> 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 != rhs.style.weight) { |
| return style.weight < rhs.style.weight; |
| } else { |
| return style.slant < rhs.style.slant; |
| } |
| } |
| |
| render_tree::FontStyle style; |
| }; |
| |
| // Font-face related |
| typedef std::map<std::string, FontFaceStyleSet> FontFaceMap; |
| typedef std::map<GURL, scoped_refptr<RequestedRemoteTypefaceInfo> > |
| RequestedRemoteTypefaceMap; |
| |
| // Font list related |
| typedef std::map<FontListKey, FontListInfo> FontListMap; |
| |
| // Typeface/Font related |
| typedef base::SmallMap< |
| std::map<render_tree::TypefaceId, scoped_refptr<render_tree::Typeface> >, |
| 7> TypefaceMap; |
| typedef std::map<FontKey, FontInfo> FontMap; |
| typedef std::set<InactiveFontKey> InactiveFontSet; |
| |
| // Character fallback related |
| typedef base::hash_map<int32, scoped_refptr<render_tree::Typeface> > |
| CharacterFallbackTypefaceMap; |
| typedef std::map<CharacterFallbackKey, CharacterFallbackTypefaceMap> |
| CharacterFallbackTypefaceMaps; |
| |
| FontCache(render_tree::ResourceProvider* resource_provider, |
| loader::font::RemoteTypefaceCache* remote_typeface_cache, |
| const base::Closure& external_typeface_load_event_callback, |
| const std::string& language); |
| |
| // 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(scoped_ptr<FontFaceMap> font_face_map); |
| |
| // 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 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 char16* text_buffer, int32 text_length, bool is_rtl, |
| FontList* font_list, |
| render_tree::FontVector* maybe_used_fonts); |
| |
| private: |
| 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. |
| // If the font is loading but not currently available, |maybe_is_font_loading| |
| // will be set to true. |
| 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. |
| // |maybe_is_font_loading| is always set to false. |
| scoped_refptr<render_tree::Font> TryGetLocalFont(const std::string& family, |
| render_tree::FontStyle style, |
| 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* const 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_; |
| |
| // 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. |
| scoped_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. |
| base::ThreadChecker thread_checker_; |
| }; |
| |
| } // namespace dom |
| } // namespace cobalt |
| |
| #endif // COBALT_DOM_FONT_CACHE_H_ |