Index: chrome/browser/android/thumbnail_cache.h |
diff --git a/chrome/browser/android/thumbnail_cache.h b/chrome/browser/android/thumbnail_cache.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a1b45b134bdb1e776596108a8194035d88d2c968 |
--- /dev/null |
+++ b/chrome/browser/android/thumbnail_cache.h |
@@ -0,0 +1,371 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef CHROME_BROWSER_ANDROID_THUMBNAIL_CACHE_H_ |
+#define CHROME_BROWSER_ANDROID_THUMBNAIL_CACHE_H_ |
+ |
+#include <list> |
+#include <set> |
+#include <string> |
+ |
+#include "base/bind.h" |
+#include "base/containers/hash_tables.h" |
+#include "base/files/file_path.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/threading/thread.h" |
+#include "base/time/time.h" |
+#include "content/public/browser/android/ui_resource_listener.h" |
+#include "content/public/browser/android/ui_resource_provider.h" |
+#include "net/base/linked_hash_map.h" |
+#include "skia/ext/refptr.h" |
+#include "third_party/skia/include/core/SkBitmap.h" |
+#include "ui/gfx/geometry/point.h" |
+#include "ui/gfx/geometry/size.h" |
+#include "ui/gfx/geometry/size_f.h" |
+#include "url/gurl.h" |
+ |
+class SkBitmap; |
+class TabThumbnailProvider; |
+ |
+namespace base { |
+class File; |
+class Time; |
+} |
+ |
+namespace content { |
+class ContentViewCore; |
+class UIResourceProvider; |
+} |
+ |
+typedef int TabId; |
+typedef std::list<TabId> TabIdList; |
+ |
+class ThumbnailChangeListener { |
+ public: |
+ virtual void OnThumbnailChanged(TabId tab_id, bool upgrade) = 0; |
+ virtual void OnUIResourceUpdated(TabId tab_id, |
+ cc::UIResourceId ui_resource_id, |
+ gfx::Size content_size, |
+ gfx::SizeF scaled_thumbnail_size) = 0; |
+}; |
+ |
+class ThumbnailCache : public content::UIResourceListener { |
+ private: |
+ class Thumbnail : public base::RefCountedThreadSafe<Thumbnail> { |
+ public: |
+ enum ThumbnailFormat { DECOMPRESSED, COMPRESSED }; |
+ |
+ // This constructs a placeholder for the thumbnail. The content is filled |
+ // by calling ReadThumbnailFromFile. |
+ Thumbnail(TabId tab_id, content::UIResourceProvider* ui_resource_provider); |
+ |
+ Thumbnail(TabId tab_id, |
+ SkBitmap bitmap, |
+ float scale, |
+ content::UIResourceProvider* ui_resource_provider); |
+ Thumbnail(const Thumbnail& thumbnail); |
+ void CleanupThumbnail(); |
+ bool AttemptToScheduleRebuildFromData(); |
+ void CleanupCPUData(bool force); |
+ bool RebuildThumbnail(); |
+ bool CompressionRequired() const; |
+ bool DataWriteRequired() const; |
+ bool HasCompressedRawData() const; |
+ bool IsValid() const; |
+ |
+ // Returns the size of the content represented by this thumbnail. |
+ gfx::Size GetContentSize() const; |
+ |
+ TabId tab_id() const { return tab_id_; } |
+ cc::UIResourceId ui_resource_id() const { return ui_resource_id_; } |
+ |
+ // The ratio of the size of the thumbnail to the content size. |
+ float scale() const { return scale_; } |
+ |
+ // Returns the size of the data (pixels) held by this thumbnail. Can be the |
+ // size of the uncompressed or compressed data. |
+ gfx::Size data_size() const { return data_size_; } |
+ |
+ virtual bool is_approximation() const { return false; } |
+ |
+ // Called on the compression thread. |
+ void Compress(); |
+ // Called on the disk thread. Returns true if writing was successful. |
+ bool WriteThumbnailToFile(base::File& file); |
+ // Called on the disk thread. Returns true if reading was successful. |
+ bool ReadThumbnailFromFile(base::File& file); |
+ |
+ // We invalidate the thumbnail content if a read/write/compress has failed. |
+ void Invalidate(); |
+ |
+ SkBitmap raw_data() { return raw_data_; } |
+ |
+ protected: |
+ friend class base::RefCountedThreadSafe<Thumbnail>; |
+ ~Thumbnail(); |
+ |
+ private: |
+ void SetRawThumbnailData(SkBitmap bitmap); |
+ void SetCompressedThumbnailData(skia::RefPtr<SkPixelRef> compressed_data, |
+ gfx::Size scaled_content_size); |
+ bool CleanupRequired(); |
+ |
+ TabId tab_id_; |
+ SkBitmap raw_data_; |
+ float scale_; |
+ content::UIResourceProvider* ui_resource_provider_; |
+ cc::UIResourceId ui_resource_id_; |
+ skia::RefPtr<SkPixelRef> compressed_data_; |
+ gfx::Size data_size_; |
+ gfx::Size scaled_content_size_; |
+ ThumbnailFormat format_; |
+ bool rebuild_pending_; |
+ bool data_write_pending_; |
+ bool from_stream_; |
+ }; |
+ |
+ class ApproxThumbnail : public Thumbnail { |
+ public: |
+ ApproxThumbnail(TabId tab_id, |
+ SkBitmap bitmap, |
+ float scale, |
+ content::UIResourceProvider* ui_resource_provider); |
+ |
+ virtual bool is_approximation() const OVERRIDE { return true; } |
+ }; |
+ |
+ class ThumbnailBitmap { |
+ public: |
+ ThumbnailBitmap(); |
+ ThumbnailBitmap(SkBitmap bitmap, float scale); |
+ bool IsValid() const; |
+ SkBitmap bitmap() const { return bitmap_; } |
+ float scale() const { return scale_; } |
+ ThumbnailBitmap CreateApproximation() const; |
+ |
+ private: |
+ SkBitmap bitmap_; |
+ float scale_; |
+ }; |
+ |
+ class ThumbnailMetaData { |
+ public: |
+ ThumbnailMetaData(); |
+ ThumbnailMetaData(const base::Time& current_time, const GURL& url); |
+ const GURL& url() const { return url_; } |
+ base::Time capture_time() const { return capture_time_; } |
+ |
+ private: |
+ base::Time capture_time_; |
+ GURL url_; |
+ }; |
+ |
+ class TabReadbackRequest : public base::RefCounted<TabReadbackRequest> { |
+ public: |
+ TabReadbackRequest( |
+ TabId tab_id, |
+ content::ContentViewCore* content_view_core, |
+ float thumbnail_scale, |
+ base::Callback<void(int, const ThumbnailBitmap&)> end_callback); |
+ |
+ bool drop_after_readback() const { return drop_after_readback_; } |
+ |
+ void Run(); |
+ void OnFinishGetTabThumbnailBitmap(bool success, const SkBitmap& bitmap); |
+ void SetDropAfterReadback(bool flag) { drop_after_readback_ = flag; } |
+ |
+ private: |
+ TabId tab_id_; |
+ content::ContentViewCore* content_view_core_; |
+ const float thumbnail_scale_; |
+ base::Callback<void(int, const ThumbnailBitmap&)> end_callback_; |
+ bool drop_after_readback_; |
+ |
+ base::WeakPtrFactory<TabReadbackRequest> weak_factory_; |
+ }; |
+ |
+ template <class Key, class Value> |
+ class LRUExpiringCache { |
+ private: |
+ typedef linked_hash_map<Key, Value> LinkedHashMap; |
+ |
+ public: |
+ typedef typename LinkedHashMap::iterator iterator; |
+ typedef typename LinkedHashMap::const_iterator const_iterator; |
+ |
+ explicit LRUExpiringCache(size_t max_cache_size) |
+ : max_cache_size_(max_cache_size) {} |
+ |
+ void Put(const Key& key, const Value& value) { |
+ map_[key] = value; |
+ EvictIfFull(); |
+ } |
+ |
+ Value Get(const Key& key) { |
+ iterator iter = map_.find(key); |
+ if (iter != map_.end()) |
+ return iter->second; |
+ return Value(); |
+ } |
+ |
+ bool Contains(const Key& key) const { |
+ const_iterator iter = map_.find(key); |
+ return iter != map_.end(); |
+ } |
+ |
+ Value Remove(const Key& key) { |
+ Value val = Get(key); |
+ map_.erase(key); |
+ return val; |
+ } |
+ |
+ iterator begin() { return map_.begin(); } |
+ iterator end() { return map_.end(); } |
+ size_t MaximumCacheSize() const { return max_cache_size_; } |
+ size_t size() const { return map_.size(); } |
+ |
+ private: |
+ void EvictIfFull() { |
+ while (map_.size() > max_cache_size_) { |
+ iterator it = map_.begin(); |
+ map_.erase(it); |
+ } |
+ } |
+ |
+ size_t max_cache_size_; |
+ LinkedHashMap map_; |
+ }; |
+ |
+ typedef LRUExpiringCache<TabId, scoped_refptr<Thumbnail> > |
+ ExpiringThumbnailCache; |
+ typedef std::set<ThumbnailChangeListener*> ThumbnailChangeListenerSet; |
+ typedef base::hash_map<TabId, scoped_refptr<TabReadbackRequest> > |
+ TabReadbackRequestMap; |
+ typedef base::hash_map<TabId, ThumbnailMetaData> ThumbnailMetaDataMap; |
+ typedef std::list<scoped_refptr<Thumbnail> > ThumbnailQueue; |
+ |
+ public: |
+ ThumbnailCache(const std::string& disk_cache_path_str, |
+ size_t default_cache_size, |
+ size_t approximation_cache_size, |
+ size_t compression_queue_max_size, |
+ size_t write_queue_max_size, |
+ bool use_approximation_thumbnails, |
+ float thumbnail_scale); |
+ |
+ ~ThumbnailCache(); |
+ |
+ void AddThumbnailChangeListener(ThumbnailChangeListener* listener); |
+ void RemoveThumbnailChangeListener(ThumbnailChangeListener* listener); |
+ void CacheTabThumbnail(const TabThumbnailProvider* tab); |
+ void CacheTabThumbnailWithBitmap(const TabThumbnailProvider* tab, |
+ const SkBitmap& bitmap, |
+ float thumbnail_scale); |
+ void HandleLowMemory(bool consider_gpu_memory); |
+ void InvalidateIfChanged(const TabThumbnailProvider* tab); |
+ void RemoveThumbnailsAndScheduleReload(); |
+ void CacheInTab(TabId tab_id); |
+ void Remove(TabId tab_id); |
+ void RemoveFromDiskAtAndAboveId(TabId min_id); |
+ void RemoveFromDisk(TabId tab_id); |
+ void UpdateVisibleIds(const TabIdList& last_visible_ids); |
+ void ThumbnailRequested(TabId tab_id); |
+ void SetUIResourceProvider(content::UIResourceProvider* ui_resource_provider); |
+ |
+ // Implements content::UIResourceListener. |
+ virtual void OnUIResourcesAreInvalid() OVERRIDE; |
+ virtual void OnRecreateUIResources() OVERRIDE; |
+ |
+ private: |
+ // The task to run |
+ static void CompressionTask(scoped_refptr<Thumbnail> thumbnail); |
+ |
+ void PostCompressionTask(scoped_refptr<Thumbnail> thumbnail); |
+ |
+ static void WriteTask(const base::FilePath& file_path, |
+ scoped_refptr<Thumbnail> thumbnail); |
+ |
+ void PostWriteTask(scoped_refptr<Thumbnail> thumbnail); |
+ |
+ static void ReadTask(const base::FilePath& file_path, |
+ scoped_refptr<Thumbnail> thumbnail); |
+ |
+ void PostReadTask(scoped_refptr<Thumbnail> thumbnail); |
+ |
+ static void RemoveFromDiskTask(const base::FilePath& file_path); |
+ static void RemoveFromDiskAtAndAboveIdTask(const base::FilePath& dir_path, |
+ TabId min_id); |
+ scoped_refptr<Thumbnail> GetThumbnail(TabId tab_id); |
+ scoped_refptr<Thumbnail> GetThumbnail(TabId tab_id, bool cache_in_if_missing); |
+ void EndCacheTabThumbnail(TabId tab_id, const ThumbnailBitmap& bitmap); |
+ bool CanReadTabContent(const TabThumbnailProvider* tab); |
+ void PutThumbnail(TabId tab_id, const ThumbnailBitmap& thumbnail_bitmap); |
+ void PutThumbnail(TabId tab_id, |
+ const ThumbnailBitmap& thumbnail_bitmap, |
+ scoped_refptr<Thumbnail> thumbnail); |
+ bool CheckAndUpdateThumbnailMetaData(const TabThumbnailProvider* tab, |
+ bool is_native_page); |
+ void RemoveFromCache(ExpiringThumbnailCache& cache, |
+ const std::list<TabId>& tab_ids); |
+ size_t HandleLowMemoryOnQueue(ThumbnailQueue& queue, |
+ bool consider_gpu_memory); |
+ void RemoveFromQueues(TabId tab_id); |
+ bool WriteThumbnailIfNecessary(scoped_refptr<Thumbnail> thumbnail); |
+ bool CompressThumbnailIfNecessary(scoped_refptr<Thumbnail> thumbnail); |
+ void WriteNextThumbnail(); |
+ bool RemoveDuplicateIdsFromQueueHelper(ThumbnailQueue& queue, |
+ scoped_refptr<Thumbnail> thumbnail); |
+ void ReadNextThumbnail(TabId id); |
+ void ReadNextThumbnail(); |
+ void CompressNextThumbnail(); |
+ void RebuildThumbnail(scoped_refptr<Thumbnail> thumbnail, |
+ bool force_cleanup_cpu_data); |
+ bool ShouldCleanupThumbnail(scoped_refptr<Thumbnail> thumbnail, |
+ const ExpiringThumbnailCache* forced_source); |
+ void CleanupThumbnail(scoped_refptr<Thumbnail> thumbnail); |
+ void CleanupThumbnail(scoped_refptr<Thumbnail> thumbnail, |
+ const ExpiringThumbnailCache* forced_source); |
+ void NotifyListenersOfThumbnailChange(TabId tab_id, bool upgrade); |
+ void NotifyListenersOfUIResourceUpdate(TabId tab_id); |
+ base::FilePath GetFilePath(TabId tab_id) const; |
+ bool ThumbnailInputFileExists(TabId tab_id) const; |
+ void RemoveCorruptThumbnailSource(TabId tab_id); |
+ void MakeSpaceForNewItemIfNecessary(TabId tab_id); |
+ void RemoveThumbnailFromCache(); |
+ void AddIdToVisibleIds(TabId tab_id); |
+ void CleanupPersistentData(); |
+ |
+ base::Time CurrentTime(); |
+ |
+ content::UIResourceProvider* ui_resource_provider_; |
+ const base::FilePath disk_cache_path_; |
+ const size_t compression_queue_max_size_; |
+ const size_t write_queue_max_size_; |
+ |
+ ExpiringThumbnailCache cache_; |
+ ExpiringThumbnailCache approximation_cache_; |
+ const bool use_approximation_thumbnails_; |
+ |
+ // All thumbnails are scaled by this value. This accounts for device's DPI |
+ // (dots per inch). |
+ const float thumbnail_scale_; |
+ |
+ ThumbnailChangeListenerSet thumbnail_change_listeners_; |
+ |
+ TabReadbackRequestMap pending_thumbnail_readbacks_; |
+ ThumbnailMetaDataMap thumbnail_meta_data_; |
+ |
+ ThumbnailQueue compression_queue_; |
+ ThumbnailQueue write_queue_; |
+ TabIdList read_queue_; |
+ |
+ TabIdList last_visible_ids_; |
+ TabIdList visible_ids_; |
+ |
+ base::Thread compression_thread_; |
+ |
+ base::WeakPtrFactory<ThumbnailCache> weak_factory_; |
+}; |
+ |
+#endif // CHROME_BROWSER_ANDROID_THUMBNAIL_CACHE_H_ |