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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_ASH_CLIPBOARD_CLIPBOARD_IMAGE_MODEL_REQUEST_H_
#define CHROME_BROWSER_UI_ASH_CLIPBOARD_CLIPBOARD_IMAGE_MODEL_REQUEST_H_
#include <memory>
#include <optional>
#include <string>
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/base/models/image_model.h"
class AccountId;
namespace ash {
class ScopedClipboardHistoryPause;
} // namespace ash
namespace ui {
class ClipboardData;
} // namespace ui
namespace views {
class WebView;
class Widget;
} // namespace views
// Renders html in an off-screen WebView, copies the rendered surface, and
// passes the copy through |deliver_image_model_callback_|. If the request takes
// takes more than 5s to load, timeout is declared and the callback is not
// called. If the request is Stop()-ed, the callback is not called.
class ClipboardImageModelRequest : public content::WebContentsDelegate,
public content::WebContentsObserver {
public:
using ImageModelCallback = base::OnceCallback<void(ui::ImageModel)>;
struct Params {
Params() = delete;
Params(const base::UnguessableToken& id,
const std::string& html_markup,
const gfx::Size& bounding_box_size,
ImageModelCallback request_finished_callback);
Params(Params&&);
Params& operator=(Params&&);
~Params();
// A unique identifier, used to cancel running requests.
base::UnguessableToken id;
// Markup being rendered.
std::string html_markup;
// The size of the rectangle which encloses the selection region on the
// original page. It is used to calculate the size of the HTML preview image
// shown on the clipboard history menu.
gfx::Size bounding_box_size;
// The callback to return the results of the request. Not called if the
// request is stopped via Stop(), or if timeout occurs.
ImageModelCallback callback;
};
using RequestStopCallback = base::RepeatingCallback<void(bool)>;
struct TestParams {
TestParams() = delete;
explicit TestParams(
RequestStopCallback callback,
const std::optional<bool>& enforce_auto_resize = std::nullopt);
TestParams(const TestParams&) = delete;
TestParams& operator=(const TestParams&) = delete;
~TestParams();
// The callback running when the image model request stops. The boolean
// value indicates whether the image model request renders web contents
// in auto resize mode.
RequestStopCallback callback;
// When set, `enforce_auto_resize` specifies whether the image model request
// should be rendered in auto resize mode. If `enforce_auto_resize` is
// true (or false), auto resize mode is always enabled (or disabled).
std::optional<bool> enforce_auto_resize;
};
// Places `html_markup` on the clipboard and restores the original clipboard
// contents when destructed.
class ScopedClipboardModifier {
public:
explicit ScopedClipboardModifier(const std::string& html_markup);
ScopedClipboardModifier(const ScopedClipboardModifier&) = delete;
ScopedClipboardModifier& operator=(const ScopedClipboardModifier&) = delete;
~ScopedClipboardModifier();
private:
// Pauses ash::ClipboardHistory for its lifetime.
std::unique_ptr<ash::ScopedClipboardHistoryPause>
scoped_clipboard_history_pause_;
std::unique_ptr<ui::ClipboardData> replaced_clipboard_data_;
};
ClipboardImageModelRequest(
const AccountId& account_id,
base::RepeatingClosure on_request_finished_callback);
ClipboardImageModelRequest(const ClipboardImageModelRequest&) = delete;
ClipboardImageModelRequest operator=(const ClipboardImageModelRequest&) =
delete;
~ClipboardImageModelRequest() override;
// Renders the HTML in a WebView and attempts to copy the surface. If this
// fails to load after 5 seconds, OnTimeout is called.
void Start(Params&& params);
// The different reasons a request can `Stop()`. These values are logged to
// UMA. Entries should not be renumbered and numeric values should never be
// reused. Please keep in sync with "RequestStopReason" in
// src/tools/metrics/histograms/enums.xml.
enum class RequestStopReason {
kFulfilled = 0,
kTimeout = 1,
kEmptyResult = 2,
kMultipleCopyCompletion = 3,
kRequestCanceled = 4,
kMaxValue = kRequestCanceled,
};
// Stops the request and resets state. `stop_reason` is the reason the request
// was `Stop()`-ed. |web_view_| is kept alive to enable fast restarting of the
// request.
void Stop(RequestStopReason stop_reason);
// `Stop()`s the request and gets the params of the running request.
Params StopAndGetParams();
// Whether the clipboard is being modified by this request.
bool IsModifyingClipboard() const;
// Returns whether a request with |request_id| is running, or if any request
// is running if no |request_id| is supplied.
bool IsRunningRequest(
std::optional<base::UnguessableToken> request_id = std::nullopt) const;
// content::WebContentsDelegate:
void ResizeDueToAutoResize(content::WebContents* web_contents,
const gfx::Size& new_size) override;
// content::WebContentsObserver:
void DidStopLoading() override;
// Configures test parameter.
static void SetTestParams(TestParams* test_params);
private:
// Called when the results of the paste are painted.
void OnVisualStateChangeFinished(bool done);
// Posts `CopySurface()` to the task sequence.
void PostCopySurfaceTask();
// Copies the rendered HTML.
void CopySurface();
// Callback called when the rendered surface is done being copied.
void OnCopyComplete(float device_scale_factor, const SkBitmap& bitmap);
// Called when the running request takes too long to complete.
void OnTimeout();
// Returns whether the auto-resize mode should be enabled. If auto-resize mode
// is enabled, Blink decides the preview image's size which may be different
// from that of the original selection region.
bool ShouldEnableAutoResizeMode() const;
// A Widget that is not shown, but forces |web_view_| to render.
std::unique_ptr<views::Widget> const widget_;
// Contents view of |widget_|. Owned by |widget_|.
const raw_ptr<views::WebView> web_view_;
// Unique identifier for this request run. Empty when there are no running
// requests.
base::UnguessableToken request_id_;
// The HTML being rendered.
std::string html_markup_;
// The size of the rectangle enclosing the copied HTML on the original page.
gfx::Size bounding_box_size_;
// Whether `DidStopLoading()` was called. Used to prevent the request from
// responding to load events that happen after the initial load.
bool did_stop_loading_ = false;
// Responsible for temporarily replacing contents of the clipboard.
std::optional<ScopedClipboardModifier> scoped_clipboard_modifier_;
// Callback used to deliver the rendered ImageModel.
ImageModelCallback deliver_image_model_callback_;
// Callback called when this request finishes (via timeout or completion).
base::RepeatingClosure on_request_finished_callback_;
// Timer used to abort requests which take longer than 5s to load.
base::RepeatingTimer timeout_timer_;
// Time this object was created. Used to log object lifetime.
const base::TimeTicks request_creation_time_;
// Time this object started its most recent request.
base::TimeTicks request_start_time_;
base::WeakPtrFactory<ClipboardImageModelRequest> weak_ptr_factory_{this};
// Used to debounce calls to `CopySurface()`.
base::WeakPtrFactory<ClipboardImageModelRequest>
copy_surface_weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_UI_ASH_CLIPBOARD_CLIPBOARD_IMAGE_MODEL_REQUEST_H_
|