1 // Copyright 2019 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_UI_THUMBNAILS_THUMBNAIL_IMAGE_H_ 6 #define CHROME_BROWSER_UI_THUMBNAILS_THUMBNAIL_IMAGE_H_ 7 8 #include <utility> 9 #include <vector> 10 11 #include "base/callback.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/observer_list.h" 15 #include "base/optional.h" 16 #include "base/sequence_checker.h" 17 #include "ui/gfx/image/image_skia.h" 18 19 namespace base { 20 class TimeTicks; 21 } // namespace base 22 23 // Stores compressed thumbnail data for a tab and can vend that data as an 24 // uncompressed image to observers. 25 class ThumbnailImage : public base::RefCounted<ThumbnailImage> { 26 public: 27 // Smart pointer to reference-counted compressed image data; in this case 28 // JPEG format. 29 using CompressedThumbnailData = 30 scoped_refptr<base::RefCountedData<std::vector<uint8_t>>>; 31 32 // Observes uncompressed and/or compressed versions of the thumbnail image as 33 // they are available. 34 class Observer : public base::CheckedObserver { 35 public: 36 // Receives uncompressed thumbnail image data. Default is no-op. 37 virtual void OnThumbnailImageAvailable(gfx::ImageSkia thumbnail_image); 38 39 // Receives compressed thumbnail image data. Default is no-op. 40 virtual void OnCompressedThumbnailDataAvailable( 41 CompressedThumbnailData thumbnail_data); 42 43 // Provides a desired aspect ratio and minimum size that the observer will 44 // accept. If not specified, or if available thumbnail data is smaller in 45 // either dimension than this value, OnThumbnailImageAvailable will be 46 // called with an uncropped image. If this value is specified, and the 47 // available image is larger, the image passed to OnThumbnailImageAvailable 48 // will be cropped to the same aspect ratio (but otherwise unchanged, 49 // including scale). 50 // 51 // OnCompressedThumbnailDataAvailable is not affected by this value. 52 // 53 // This method is used to ensure that except for very small thumbnails, the 54 // image passed to OnThumbnailImageAvailable fits the needs of the observer 55 // for display purposes, without the observer having to further crop the 56 // image. The default is unspecified. 57 virtual base::Optional<gfx::Size> GetThumbnailSizeHint() const; 58 }; 59 60 // Represents the endpoint 61 class Delegate { 62 public: 63 // Called whenever the thumbnail starts or stops being observed. 64 // Because updating the thumbnail could be an expensive operation, it's 65 // useful to track when there are no observers. Default behavior is no-op. 66 virtual void ThumbnailImageBeingObservedChanged(bool is_being_observed) = 0; 67 68 protected: 69 virtual ~Delegate(); 70 71 private: 72 friend class ThumbnailImage; 73 ThumbnailImage* thumbnail_ = nullptr; 74 }; 75 76 explicit ThumbnailImage(Delegate* delegate); 77 has_data()78 bool has_data() const { return data_.get(); } 79 80 void AddObserver(Observer* observer); 81 void RemoveObserver(Observer* observer); 82 bool HasObserver(const Observer* observer) const; 83 84 // Sets the SkBitmap data and notifies observers with the resulting image. 85 void AssignSkBitmap(SkBitmap bitmap); 86 87 // Requests that a thumbnail image be made available to observers. Does not 88 // guarantee that Observer::OnThumbnailImageAvailable() will be called, or how 89 // long it will take, though in most cases it should happen very quickly. 90 void RequestThumbnailImage(); 91 92 // Similar to RequestThumbnailImage() but requests only the compressed JPEG 93 // data. Users should listen for a call to 94 // Observer::OnCompressedThumbnailDataAvailable(). 95 void RequestCompressedThumbnailData(); 96 97 // Returns the size of the compressed data backing this thumbnail. 98 // This size can be 0. Additionally, since this data is refcounted, 99 // it's possible this returns 0 even if the data is still allocated. A 100 // client can hold a reference to it after |this| drops its reference. 101 size_t GetCompressedDataSizeInBytes() const; 102 set_async_operation_finished_callback_for_testing(base::RepeatingClosure callback)103 void set_async_operation_finished_callback_for_testing( 104 base::RepeatingClosure callback) { 105 async_operation_finished_callback_ = std::move(callback); 106 } 107 108 private: 109 friend class Delegate; 110 friend class ThumbnailImageTest; 111 friend class base::RefCounted<ThumbnailImage>; 112 113 virtual ~ThumbnailImage(); 114 115 void AssignJPEGData(base::TimeTicks assign_sk_bitmap_time, 116 std::vector<uint8_t> data); 117 bool ConvertJPEGDataToImageSkiaAndNotifyObservers(); 118 void NotifyUncompressedDataObservers(gfx::ImageSkia image); 119 void NotifyCompressedDataObservers(CompressedThumbnailData data); 120 121 static std::vector<uint8_t> CompressBitmap(SkBitmap bitmap); 122 static gfx::ImageSkia UncompressImage(CompressedThumbnailData compressed); 123 124 // Crops and returns a preview from a thumbnail of an entire web page. Uses 125 // logic appropriate for fixed-aspect previews (e.g. hover cards). 126 static gfx::ImageSkia CropPreviewImage(const gfx::ImageSkia& source_image, 127 const gfx::Size& minimum_size); 128 129 Delegate* delegate_; 130 131 CompressedThumbnailData data_; 132 133 base::ObserverList<Observer> observers_; 134 135 // Called when an asynchronous operation (such as encoding image data upon 136 // assignment or decoding image data for observers) finishes or fails. 137 // Intended for unit tests that want to wait for internal operations following 138 // AssignSkBitmap() or RequestThumbnailImage() calls. 139 base::RepeatingClosure async_operation_finished_callback_; 140 141 SEQUENCE_CHECKER(sequence_checker_); 142 143 base::WeakPtrFactory<ThumbnailImage> weak_ptr_factory_{this}; 144 145 DISALLOW_COPY_AND_ASSIGN(ThumbnailImage); 146 }; 147 148 #endif // CHROME_BROWSER_UI_THUMBNAILS_THUMBNAIL_IMAGE_H_ 149