1 // Copyright (c) 2012 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_IMAGE_DECODER_IMAGE_DECODER_H_
6 #define CHROME_BROWSER_IMAGE_DECODER_IMAGE_DECODER_H_
7 
8 #include <map>
9 #include <string>
10 #include <vector>
11 
12 #include "base/macros.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/sequence_checker.h"
15 #include "base/sequenced_task_runner.h"
16 #include "base/synchronization/lock.h"
17 
18 namespace data_decoder {
19 class DataDecoder;
20 }  // namespace data_decoder
21 
22 namespace gfx {
23 class Size;
24 }  // namespace gfx
25 
26 class SkBitmap;
27 
28 // This is a helper class for decoding images safely in a sandboxed service. To
29 // use this, call ImageDecoder::Start(...) or
30 // ImageDecoder::StartWithOptions(...) on any thread.
31 //
32 // ImageRequest::OnImageDecoded or ImageRequest::OnDecodeImageFailed is posted
33 // back to the |task_runner_| associated with the ImageRequest.
34 //
35 // The Cancel() method runs on whichever thread called it.
36 //
37 // TODO(rockot): Use of this class should be replaced with direct image_decoder
38 // client library usage.
39 class ImageDecoder {
40  public:
41   // ImageRequest objects needs to be created and destroyed on the same
42   // SequencedTaskRunner.
43   class ImageRequest {
44    public:
45     // Called when image is decoded.
46     virtual void OnImageDecoded(const SkBitmap& decoded_image) = 0;
47 
48     // Called when decoding image failed. ImageRequest can do some cleanup in
49     // this handler.
OnDecodeImageFailed()50     virtual void OnDecodeImageFailed() {}
51 
task_runner()52     base::SequencedTaskRunner* task_runner() const {
53       return task_runner_.get();
54     }
55 
data_decoder()56     data_decoder::DataDecoder* data_decoder() { return data_decoder_; }
57 
58    protected:
59     // Creates an ImageRequest that runs on the thread which created it.
60     ImageRequest();
61     // Explicitly pass in |task_runner| if the current thread is part of a
62     // thread pool.
63     explicit ImageRequest(
64         const scoped_refptr<base::SequencedTaskRunner>& task_runner);
65     // Explicitly pass in |data_decoder| if there's a specific decoder that
66     // should be used; otherwise, an isolated decoder will created and used.
67     explicit ImageRequest(data_decoder::DataDecoder* data_decoder);
68     virtual ~ImageRequest();
69 
70    private:
71     // The thread to post OnImageDecoded() or OnDecodeImageFailed() once the
72     // the image has been decoded.
73     const scoped_refptr<base::SequencedTaskRunner> task_runner_;
74 
75     // If null, will use a new decoder via DecodeImageIsolated() instead.
76     data_decoder::DataDecoder* const data_decoder_ = nullptr;
77 
78     SEQUENCE_CHECKER(sequence_checker_);
79   };
80 
81   enum ImageCodec {
82     DEFAULT_CODEC = 0,  // Uses WebKit image decoding (via WebImage).
83 #if defined(OS_CHROMEOS)
84     ROBUST_PNG_CODEC,   // Restrict decoding to robust PNG codec.
85 #endif                  // defined(OS_CHROMEOS)
86   };
87 
88   static ImageDecoder* GetInstance();
89 
90   // Calls StartWithOptions() with ImageCodec::DEFAULT_CODEC and
91   // shrink_to_fit = false.
92   static void Start(ImageRequest* image_request,
93                     std::vector<uint8_t> image_data);
94   // Deprecated. Use std::vector<uint8_t> version to avoid an extra copy.
95   static void Start(ImageRequest* image_request, const std::string& image_data);
96 
97   // Starts asynchronous image decoding. Once finished, the callback will be
98   // posted back to image_request's |task_runner_|.
99   // For images with multiple frames (e.g. ico files), a frame with a size as
100   // close as possible to |desired_image_frame_size| is chosen (tries to take
101   // one in larger size if there's no precise match). Passing gfx::Size() as
102   // |desired_image_frame_size| is also supported and will result in chosing the
103   // smallest available size.
104   static void StartWithOptions(ImageRequest* image_request,
105                                std::vector<uint8_t> image_data,
106                                ImageCodec image_codec,
107                                bool shrink_to_fit,
108                                const gfx::Size& desired_image_frame_size);
109   // Deprecated. Use std::vector<uint8_t> version to avoid an extra copy.
110   static void StartWithOptions(ImageRequest* image_request,
111                                const std::string& image_data,
112                                ImageCodec image_codec,
113                                bool shrink_to_fit);
114 
115   // Removes all instances of |image_request| from |image_request_id_map_|,
116   // ensuring callbacks are not made to the image_request after it is destroyed.
117   static void Cancel(ImageRequest* image_request);
118 
119  private:
120   using RequestMap = std::map<int, ImageRequest*>;
121 
122   ImageDecoder();
123   ~ImageDecoder() = delete;
124 
125   void StartWithOptionsImpl(ImageRequest* image_request,
126                             std::vector<uint8_t> image_data,
127                             ImageCodec image_codec,
128                             bool shrink_to_fit,
129                             const gfx::Size& desired_image_frame_size);
130 
131   void CancelImpl(ImageRequest* image_request);
132 
133   // IPC message handlers.
134   void OnDecodeImageSucceeded(const SkBitmap& decoded_image, int request_id);
135   void OnDecodeImageFailed(int request_id);
136 
137   // id to use for the next Start() request that comes in.
138   int image_request_id_counter_;
139 
140   // Map of request id's to ImageRequests.
141   RequestMap image_request_id_map_;
142 
143   // Protects |image_request_id_map_| and |image_request_id_counter_|.
144   base::Lock map_lock_;
145 
146   DISALLOW_COPY_AND_ASSIGN(ImageDecoder);
147 };
148 
149 #endif  // CHROME_BROWSER_IMAGE_DECODER_IMAGE_DECODER_H_
150