summaryrefslogtreecommitdiffstats
path: root/chrome/browser/image_decoder.h
blob: 9e0b3edeaff92cff17a04aac93b0cbc236e06c9e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Copyright (c) 2012 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_IMAGE_DECODER_H_
#define CHROME_BROWSER_IMAGE_DECODER_H_

#include <map>
#include <string>
#include <vector>

#include "base/lazy_instance.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/timer/timer.h"
#include "content/public/browser/utility_process_host.h"
#include "content/public/browser/utility_process_host_client.h"

class SkBitmap;

// This is a helper class for decoding images safely in a utility process. To
// use this, call ImageDecoder::Start(...) or
// ImageDecoder::StartWithOptions(...) on any thread.
//
// Internally, most of the work happens on the IO thread, and then
// the callback (ImageRequest::OnImageDecoded or
// ImageRequest::OnDecodeImageFailed) is posted back to the |task_runner_|
// associated with the ImageRequest.
// The Cancel() method runs on whichever thread called it. |map_lock_| is used
// to protect the data that is accessed from multiple threads.
class ImageDecoder : public content::UtilityProcessHostClient {
 public:
  // ImageRequest objects needs to be created and destroyed on the same
  // SequencedTaskRunner.
  class ImageRequest {
   public:
    // Called when image is decoded.
    virtual void OnImageDecoded(const SkBitmap& decoded_image) = 0;

    // Called when decoding image failed. ImageRequest can do some cleanup in
    // this handler.
    virtual void OnDecodeImageFailed() {}

    base::SequencedTaskRunner* task_runner() const {
      return task_runner_.get();
    }

   protected:
    // Creates an ImageRequest that runs on the thread creating it.
    ImageRequest();
    // Explicitly pass in |task_runner| if the current thread is part of a
    // thread pool.
    explicit ImageRequest(
        const scoped_refptr<base::SequencedTaskRunner>& task_runner);
    virtual ~ImageRequest();

   private:
    // The thread to post OnImageDecoded() or OnDecodeImageFailed() once the
    // the image has been decoded.
    const scoped_refptr<base::SequencedTaskRunner> task_runner_;

    base::SequenceChecker sequence_checker_;
  };

  enum ImageCodec {
    DEFAULT_CODEC = 0,  // Uses WebKit image decoding (via WebImage).
#if defined(OS_CHROMEOS)
    ROBUST_JPEG_CODEC,  // Restrict decoding to robust jpeg codec.
#endif  // defined(OS_CHROMEOS)
  };

  // Calls StartWithOptions() with ImageCodec::DEFAULT_CODEC and
  // shrink_to_fit = false.
  static void Start(ImageRequest* image_request,
                    const std::string& image_data);

  // Starts asynchronous image decoding. Once finished, the callback will be
  // posted back to image_request's |task_runner_|.
  static void StartWithOptions(ImageRequest* image_request,
                               const std::string& image_data,
                               ImageCodec image_codec,
                               bool shrink_to_fit);

  // Removes all instances of |image_request| from |image_request_id_map_|,
  // ensuring callbacks are not made to the image_request after it is destroyed.
  static void Cancel(ImageRequest* image_request);

 private:
  friend struct base::DefaultLazyInstanceTraits<ImageDecoder>;

  using RequestMap = std::map<int, ImageRequest*>;

  ImageDecoder();
  // It's a reference counted object, so destructor is private.
  ~ImageDecoder() override;

  // Sends a request to the sandboxed process to decode the image. Starts
  // batch mode if necessary. If the utility process fails to start,
  // an OnDecodeImageFailed task is posted to image_request's |task_runner_|.
  void DecodeImageInSandbox(int request_id,
                            const std::vector<unsigned char>& image_data,
                            ImageCodec image_codec,
                            bool shrink_to_fit);

  void StartWithOptionsImpl(ImageRequest* image_request,
                            const std::string& image_data,
                            ImageCodec image_codec,
                            bool shrink_to_fit);
  void CancelImpl(ImageRequest* image_request);

  // Starts UtilityProcessHost in batch mode and starts |batch_mode_timer_|.
  // If the utility process fails to start, the method resets
  // |utility_process_host_| and returns.
  void StartBatchMode();

  // Stops batch mode if no requests have come in since
  // |kBatchModeTimeoutSeconds|.
  void StopBatchMode();

  // Fails all outstanding requests.
  void FailAllRequests();

  // Overidden from UtilityProcessHostClient.
  void OnProcessCrashed(int exit_code) override;
  void OnProcessLaunchFailed() override;
  bool OnMessageReceived(const IPC::Message& message) override;

  // IPC message handlers.
  void OnDecodeImageSucceeded(const SkBitmap& decoded_image, int request_id);
  void OnDecodeImageFailed(int request_id);

  // For the ImageRequest identified by |request_id|, call its OnImageDecoded()
  // or OnDecodeImageFailed() method on its task runner thread.
  void RunOnImageDecoded(const SkBitmap& decoded_image, int request_id);
  void RunOnDecodeImageFailed(int request_id);

  // id to use for the next Start() request that comes in.
  int image_request_id_counter_;

  // Map of request id's to ImageRequests.
  RequestMap image_request_id_map_;

  // Protects |image_request_id_map_| and |image_request_id_counter_|.
  base::Lock map_lock_;

  // The UtilityProcessHost requests are sent to.
  base::WeakPtr<content::UtilityProcessHost> utility_process_host_;

  // Calls StopBatchMode() after |kBatchModeTimeoutSeconds| have elapsed,
  // unless a new decoding request resets the timer.
  scoped_ptr<base::DelayTimer<ImageDecoder>> batch_mode_timer_;

  DISALLOW_COPY_AND_ASSIGN(ImageDecoder);
};

#endif  // CHROME_BROWSER_IMAGE_DECODER_H_