player_compositor_delegate.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  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. #include "components/paint_preview/player/player_compositor_delegate.h"
  5. #include <string>
  6. #include <utility>
  7. #include <vector>
  8. #include "base/containers/flat_map.h"
  9. #include "base/files/file_path.h"
  10. #include "base/memory/memory_pressure_monitor.h"
  11. #include "base/memory/read_only_shared_memory_region.h"
  12. #include "base/memory/weak_ptr.h"
  13. #include "base/notreached.h"
  14. #include "base/strings/string_piece.h"
  15. #include "base/strings/utf_string_conversions.h"
  16. #include "base/task/thread_pool.h"
  17. #include "base/trace_event/common/trace_event_common.h"
  18. #include "base/trace_event/trace_event.h"
  19. #include "base/unguessable_token.h"
  20. #include "components/paint_preview/browser/paint_preview_base_service.h"
  21. #include "components/paint_preview/browser/warm_compositor.h"
  22. #include "components/paint_preview/common/proto/paint_preview.pb.h"
  23. #include "components/paint_preview/common/recording_map.h"
  24. #include "components/paint_preview/common/serialized_recording.h"
  25. #include "components/paint_preview/common/version.h"
  26. #include "components/paint_preview/public/paint_preview_compositor_client.h"
  27. #include "components/paint_preview/public/paint_preview_compositor_service.h"
  28. #include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
  29. #include "mojo/public/cpp/bindings/remote.h"
  30. #include "third_party/abseil-cpp/absl/types/optional.h"
  31. #include "third_party/skia/include/core/SkBitmap.h"
  32. #include "ui/gfx/geometry/rect.h"
  33. namespace paint_preview {
  34. namespace {
  35. std::pair<base::UnguessableToken, std::unique_ptr<HitTester>> BuildHitTester(
  36. const PaintPreviewFrameProto& proto) {
  37. std::pair<base::UnguessableToken, std::unique_ptr<HitTester>> out(
  38. base::UnguessableToken::Deserialize(proto.embedding_token_high(),
  39. proto.embedding_token_low()),
  40. std::make_unique<HitTester>());
  41. out.second->Build(proto);
  42. return out;
  43. }
  44. std::unique_ptr<
  45. base::flat_map<base::UnguessableToken, std::unique_ptr<HitTester>>>
  46. BuildHitTesters(std::unique_ptr<PaintPreviewProto> proto) {
  47. TRACE_EVENT0("paint_preview", "PaintPreview BuildHitTesters");
  48. std::vector<std::pair<base::UnguessableToken, std::unique_ptr<HitTester>>>
  49. hit_testers;
  50. hit_testers.reserve(proto->subframes_size() + 1);
  51. hit_testers.push_back(BuildHitTester(proto->root_frame()));
  52. for (const auto& frame_proto : proto->subframes())
  53. hit_testers.push_back(BuildHitTester(frame_proto));
  54. return std::make_unique<
  55. base::flat_map<base::UnguessableToken, std::unique_ptr<HitTester>>>(
  56. std::move(hit_testers));
  57. }
  58. absl::optional<base::ReadOnlySharedMemoryRegion> ToReadOnlySharedMemory(
  59. paint_preview::PaintPreviewProto&& proto) {
  60. TRACE_EVENT0("paint_preview", "PaintPreviewProto ToReadOnlySharedMemory");
  61. auto region = base::WritableSharedMemoryRegion::Create(proto.ByteSizeLong());
  62. if (!region.IsValid())
  63. return absl::nullopt;
  64. auto mapping = region.Map();
  65. if (!mapping.IsValid())
  66. return absl::nullopt;
  67. proto.SerializeToArray(mapping.memory(), mapping.size());
  68. return base::WritableSharedMemoryRegion::ConvertToReadOnly(std::move(region));
  69. }
  70. paint_preview::mojom::PaintPreviewBeginCompositeRequestPtr
  71. PrepareCompositeRequest(std::unique_ptr<CaptureResult> capture_result) {
  72. TRACE_EVENT0("paint_preview", "PaintPreview PrepareCompositeRequest");
  73. paint_preview::mojom::PaintPreviewBeginCompositeRequestPtr
  74. begin_composite_request =
  75. paint_preview::mojom::PaintPreviewBeginCompositeRequest::New();
  76. std::pair<RecordingMap, PaintPreviewProto> map_and_proto =
  77. RecordingMapFromCaptureResult(std::move(*capture_result));
  78. begin_composite_request->recording_map = std::move(map_and_proto.first);
  79. if (begin_composite_request->recording_map.empty())
  80. return nullptr;
  81. auto read_only_proto =
  82. ToReadOnlySharedMemory(std::move(map_and_proto.second));
  83. if (!read_only_proto) {
  84. DVLOG(1) << "Failed to read proto to read-only shared memory.";
  85. return nullptr;
  86. }
  87. begin_composite_request->proto = std::move(read_only_proto.value());
  88. return begin_composite_request;
  89. }
  90. } // namespace
  91. PlayerCompositorDelegate::PlayerCompositorDelegate()
  92. : paint_preview_compositor_service_(nullptr,
  93. base::OnTaskRunnerDeleter(nullptr)),
  94. paint_preview_compositor_client_(nullptr,
  95. base::OnTaskRunnerDeleter(nullptr)) {}
  96. PlayerCompositorDelegate::~PlayerCompositorDelegate() {
  97. if (compress_on_close_ && paint_preview_service_) {
  98. paint_preview_service_->GetFileMixin()->GetTaskRunner()->PostTask(
  99. FROM_HERE,
  100. base::BindOnce(base::IgnoreResult(&FileManager::CompressDirectory),
  101. paint_preview_service_->GetFileMixin()->GetFileManager(),
  102. key_));
  103. }
  104. }
  105. void PlayerCompositorDelegate::Initialize(
  106. PaintPreviewBaseService* paint_preview_service,
  107. const GURL& expected_url,
  108. const DirectoryKey& key,
  109. bool main_frame_mode,
  110. CompositorErrorCallback compositor_error,
  111. base::TimeDelta timeout_duration,
  112. std::array<size_t, PressureLevelCount::kLevels> max_requests_map) {
  113. TRACE_EVENT0("paint_preview", "PlayerCompositorDelegate::Initialize");
  114. TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("paint_preview",
  115. "PlayerCompositorDelegate CreateCompositor",
  116. TRACE_ID_LOCAL(this));
  117. auto* memory_monitor = memory_pressure_monitor();
  118. // If the device is already under moderate memory pressure abort right away.
  119. if (memory_monitor &&
  120. memory_monitor->GetCurrentPressureLevel() >=
  121. base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE) {
  122. base::SequencedTaskRunnerHandle::Get()->PostTask(
  123. FROM_HERE,
  124. base::BindOnce(std::move(compositor_error),
  125. static_cast<int>(
  126. CompositorStatus::SKIPPED_DUE_TO_MEMORY_PRESSURE)));
  127. return;
  128. }
  129. paint_preview_compositor_service_ =
  130. WarmCompositor::GetInstance()->GetOrStartCompositorService(base::BindOnce(
  131. &PlayerCompositorDelegate::OnCompositorServiceDisconnected,
  132. weak_factory_.GetWeakPtr()));
  133. InitializeInternal(paint_preview_service, expected_url, key, main_frame_mode,
  134. std::move(compositor_error), timeout_duration,
  135. std::move(max_requests_map));
  136. }
  137. void PlayerCompositorDelegate::SetCaptureResult(
  138. std::unique_ptr<CaptureResult> capture_result) {
  139. capture_result_ = std::move(capture_result);
  140. }
  141. void PlayerCompositorDelegate::InitializeWithFakeServiceForTest(
  142. PaintPreviewBaseService* paint_preview_service,
  143. const GURL& expected_url,
  144. const DirectoryKey& key,
  145. bool main_frame_mode,
  146. CompositorErrorCallback compositor_error,
  147. base::TimeDelta timeout_duration,
  148. std::array<size_t, PressureLevelCount::kLevels> max_requests_map,
  149. std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter>
  150. fake_compositor_service) {
  151. paint_preview_compositor_service_ = std::move(fake_compositor_service);
  152. paint_preview_compositor_service_->SetDisconnectHandler(
  153. base::BindOnce(&PlayerCompositorDelegate::OnCompositorServiceDisconnected,
  154. weak_factory_.GetWeakPtr()));
  155. InitializeInternal(paint_preview_service, expected_url, key, main_frame_mode,
  156. std::move(compositor_error), timeout_duration,
  157. std::move(max_requests_map));
  158. }
  159. void PlayerCompositorDelegate::InitializeInternal(
  160. PaintPreviewBaseService* paint_preview_service,
  161. const GURL& expected_url,
  162. const DirectoryKey& key,
  163. bool main_frame_mode,
  164. CompositorErrorCallback compositor_error,
  165. base::TimeDelta timeout_duration,
  166. std::array<size_t, PressureLevelCount::kLevels> max_requests_map) {
  167. max_requests_map_ = max_requests_map;
  168. max_requests_ = max_requests_map_
  169. [base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE];
  170. main_frame_mode_ = main_frame_mode;
  171. compositor_error_ = std::move(compositor_error);
  172. paint_preview_service_ = paint_preview_service;
  173. key_ = key;
  174. paint_preview_compositor_client_ =
  175. paint_preview_compositor_service_->CreateCompositor(
  176. base::BindOnce(&PlayerCompositorDelegate::OnCompositorClientCreated,
  177. weak_factory_.GetWeakPtr(), expected_url, key));
  178. paint_preview_compositor_client_->SetDisconnectHandler(
  179. base::BindOnce(&PlayerCompositorDelegate::OnCompositorClientDisconnected,
  180. weak_factory_.GetWeakPtr()));
  181. memory_pressure_ = std::make_unique<base::MemoryPressureListener>(
  182. FROM_HERE, base::DoNothing(),
  183. base::BindRepeating(&PlayerCompositorDelegate::OnMemoryPressure,
  184. weak_factory_.GetWeakPtr()));
  185. if (!timeout_duration.is_inf() && !timeout_duration.is_zero()) {
  186. timeout_.Reset(
  187. base::BindOnce(&PlayerCompositorDelegate::OnCompositorTimeout,
  188. weak_factory_.GetWeakPtr()));
  189. base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
  190. FROM_HERE, timeout_.callback(), timeout_duration);
  191. }
  192. }
  193. int32_t PlayerCompositorDelegate::RequestBitmap(
  194. const absl::optional<base::UnguessableToken>& frame_guid,
  195. const gfx::Rect& clip_rect,
  196. float scale_factor,
  197. base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
  198. const SkBitmap&)> callback,
  199. bool run_callback_on_default_task_runner) {
  200. TRACE_EVENT0("paint_preview", "PlayerCompositorDelegate::RequestBitmap");
  201. DCHECK(IsInitialized());
  202. DCHECK((main_frame_mode_ && !frame_guid.has_value()) ||
  203. (!main_frame_mode_ && frame_guid.has_value()));
  204. const int32_t request_id = next_request_id_;
  205. next_request_id_++;
  206. if (!paint_preview_compositor_client_) {
  207. std::move(callback).Run(
  208. mojom::PaintPreviewCompositor::BitmapStatus::kMissingFrame, SkBitmap());
  209. return request_id;
  210. }
  211. bitmap_request_queue_.push(request_id);
  212. pending_bitmap_requests_.emplace(
  213. request_id,
  214. BitmapRequest(frame_guid, clip_rect, scale_factor,
  215. std::move(callback).Then(base::BindOnce(
  216. &PlayerCompositorDelegate::AfterBitmapRequestCallback,
  217. weak_factory_.GetWeakPtr())),
  218. run_callback_on_default_task_runner));
  219. ProcessBitmapRequestsFromQueue();
  220. return request_id;
  221. }
  222. bool PlayerCompositorDelegate::CancelBitmapRequest(int32_t request_id) {
  223. auto it = pending_bitmap_requests_.find(request_id);
  224. if (it == pending_bitmap_requests_.end())
  225. return false;
  226. pending_bitmap_requests_.erase(it);
  227. return true;
  228. }
  229. void PlayerCompositorDelegate::CancelAllBitmapRequests() {
  230. while (bitmap_request_queue_.size())
  231. bitmap_request_queue_.pop();
  232. pending_bitmap_requests_.clear();
  233. }
  234. std::vector<const GURL*> PlayerCompositorDelegate::OnClick(
  235. const base::UnguessableToken& frame_guid,
  236. const gfx::Rect& rect) {
  237. DCHECK(IsInitialized());
  238. std::vector<const GURL*> urls;
  239. if (!hit_testers_) {
  240. return urls;
  241. }
  242. auto it = hit_testers_->find(frame_guid);
  243. if (it != hit_testers_->end())
  244. it->second->HitTest(rect, &urls);
  245. return urls;
  246. }
  247. void PlayerCompositorDelegate::OnMemoryPressure(
  248. base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
  249. TRACE_EVENT1("paint_preview", "PlayerCompositorDelegate::OnMemoryPressure",
  250. "memory_pressure_level",
  251. static_cast<int>(memory_pressure_level));
  252. if (paint_preview_compositor_service_) {
  253. paint_preview_compositor_service_->OnMemoryPressure(memory_pressure_level);
  254. }
  255. DCHECK(memory_pressure_level >= 0 &&
  256. static_cast<size_t>(memory_pressure_level) <
  257. PressureLevelCount::kLevels);
  258. max_requests_ = max_requests_map_[memory_pressure_level];
  259. if (max_requests_ == 0 ||
  260. memory_pressure_level ==
  261. base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
  262. if (paint_preview_compositor_client_)
  263. paint_preview_compositor_client_.reset();
  264. if (paint_preview_compositor_service_)
  265. paint_preview_compositor_service_.reset();
  266. if (compositor_error_) {
  267. base::SequencedTaskRunnerHandle::Get()->PostTask(
  268. FROM_HERE,
  269. base::BindOnce(
  270. std::move(compositor_error_),
  271. static_cast<int>(
  272. CompositorStatus::STOPPED_DUE_TO_MEMORY_PRESSURE)));
  273. }
  274. }
  275. }
  276. base::MemoryPressureMonitor*
  277. PlayerCompositorDelegate::memory_pressure_monitor() {
  278. return base::MemoryPressureMonitor::Get();
  279. }
  280. void PlayerCompositorDelegate::OnCompositorReadyStatusAdapter(
  281. mojom::PaintPreviewCompositor::BeginCompositeStatus status,
  282. mojom::PaintPreviewBeginCompositeResponsePtr composite_response) {
  283. timeout_.Cancel();
  284. CompositorStatus new_status;
  285. float page_scale_factor = 0.0;
  286. switch (status) {
  287. // fallthrough
  288. case mojom::PaintPreviewCompositor::BeginCompositeStatus::kSuccess:
  289. case mojom::PaintPreviewCompositor::BeginCompositeStatus::kPartialSuccess:
  290. new_status = CompositorStatus::OK;
  291. page_scale_factor = page_scale_factor_;
  292. break;
  293. case mojom::PaintPreviewCompositor::BeginCompositeStatus::
  294. kDeserializingFailure:
  295. new_status = CompositorStatus::COMPOSITOR_DESERIALIZATION_ERROR;
  296. break;
  297. case mojom::PaintPreviewCompositor::BeginCompositeStatus::
  298. kCompositingFailure:
  299. new_status = CompositorStatus::INVALID_ROOT_FRAME_SKP;
  300. break;
  301. default:
  302. NOTREACHED();
  303. }
  304. OnCompositorReady(new_status, std::move(composite_response),
  305. page_scale_factor, std::move(ax_tree_update_));
  306. }
  307. void PlayerCompositorDelegate::OnCompositorServiceDisconnected() {
  308. DLOG(ERROR) << "Compositor service disconnected.";
  309. if (compositor_error_) {
  310. std::move(compositor_error_)
  311. .Run(static_cast<int>(CompositorStatus::COMPOSITOR_SERVICE_DISCONNECT));
  312. }
  313. }
  314. void PlayerCompositorDelegate::OnCompositorClientCreated(
  315. const GURL& expected_url,
  316. const DirectoryKey& key) {
  317. TRACE_EVENT_NESTABLE_ASYNC_END0("paint_preview",
  318. "PlayerCompositorDelegate CreateCompositor",
  319. TRACE_ID_LOCAL(this));
  320. if (!capture_result_) {
  321. paint_preview_service_->GetFileMixin()->GetCapturedPaintPreviewProto(
  322. key, absl::nullopt,
  323. base::BindOnce(&PlayerCompositorDelegate::OnProtoAvailable,
  324. weak_factory_.GetWeakPtr(), expected_url));
  325. } else {
  326. ValidateProtoAndLoadAXTree(expected_url);
  327. }
  328. }
  329. // Chrometto data suggests this function might be slow as the callback passed to
  330. // GetCapturedPaintPreviewProto appears to block the UI thread. Nothing here
  331. // looks to be particularly slow or blocking though...
  332. void PlayerCompositorDelegate::OnProtoAvailable(
  333. const GURL& expected_url,
  334. PaintPreviewFileMixin::ProtoReadStatus proto_status,
  335. std::unique_ptr<PaintPreviewProto> proto) {
  336. TRACE_EVENT0("paint_preview", "PlayerCompositorDelegate::OnProtoAvailable");
  337. if (proto_status == PaintPreviewFileMixin::ProtoReadStatus::kExpired) {
  338. OnCompositorReady(CompositorStatus::CAPTURE_EXPIRED, nullptr, 0.0, nullptr);
  339. return;
  340. }
  341. if (proto_status == PaintPreviewFileMixin::ProtoReadStatus::kNoProto) {
  342. OnCompositorReady(CompositorStatus::NO_CAPTURE, nullptr, 0.0, nullptr);
  343. return;
  344. }
  345. if (proto_status ==
  346. PaintPreviewFileMixin::ProtoReadStatus::kDeserializationError ||
  347. !proto || !proto->IsInitialized()) {
  348. OnCompositorReady(CompositorStatus::PROTOBUF_DESERIALIZATION_ERROR, nullptr,
  349. 0.0, nullptr);
  350. return;
  351. }
  352. capture_result_ =
  353. std::make_unique<CaptureResult>(RecordingPersistence::kFileSystem);
  354. capture_result_->proto = std::move(*proto);
  355. ValidateProtoAndLoadAXTree(expected_url);
  356. }
  357. void PlayerCompositorDelegate::ValidateProtoAndLoadAXTree(
  358. const GURL& expected_url) {
  359. TRACE_EVENT0("paint_preview",
  360. "PlayerCompositorDelegate::ValidateProtoAndLoadAXTree");
  361. const uint32_t version = capture_result_->proto.metadata().version();
  362. if (version < kPaintPreviewVersion) {
  363. // If the version is old there was a breaking change to either;
  364. // - The SkPicture encoding format
  365. // - The storage structure
  366. // In either case, the new code is likely unable to deserialize the result
  367. // so we should early abort.
  368. OnCompositorReady(CompositorStatus::OLD_VERSION, nullptr, 0.0, nullptr);
  369. return;
  370. } else if (version > kPaintPreviewVersion) {
  371. // This shouldn't happen hence NOTREACHED(). However, in release we should
  372. // treat this as a new failure type to catch any possible regressions.
  373. OnCompositorReady(CompositorStatus::UNEXPECTED_VERSION, nullptr, 0.0,
  374. nullptr);
  375. NOTREACHED();
  376. return;
  377. }
  378. auto proto_url = GURL(capture_result_->proto.metadata().url());
  379. if (expected_url != proto_url) {
  380. OnCompositorReady(CompositorStatus::URL_MISMATCH, nullptr, 0.0, nullptr);
  381. return;
  382. }
  383. if (!paint_preview_compositor_client_) {
  384. OnCompositorReady(CompositorStatus::COMPOSITOR_CLIENT_DISCONNECT, nullptr,
  385. 0.0, nullptr);
  386. return;
  387. }
  388. paint_preview_compositor_client_->SetRootFrameUrl(proto_url);
  389. root_frame_offsets_ =
  390. gfx::Point(capture_result_->proto.root_frame().frame_offset_x(),
  391. capture_result_->proto.root_frame().frame_offset_y());
  392. // If the current Chrome version doesn't match the one in proto, we can't
  393. // use the AXTreeUpdate.
  394. auto chrome_version = capture_result_->proto.metadata().chrome_version();
  395. if (capture_result_->proto.metadata().has_chrome_version() &&
  396. chrome_version.major() == CHROME_VERSION_MAJOR &&
  397. chrome_version.minor() == CHROME_VERSION_MINOR &&
  398. chrome_version.build() == CHROME_VERSION_BUILD &&
  399. chrome_version.patch() == CHROME_VERSION_PATCH) {
  400. paint_preview_service_->GetFileMixin()->GetAXTreeUpdate(
  401. key_, base::BindOnce(&PlayerCompositorDelegate::OnAXTreeUpdateAvailable,
  402. weak_factory_.GetWeakPtr()));
  403. } else {
  404. PlayerCompositorDelegate::OnAXTreeUpdateAvailable(nullptr);
  405. }
  406. }
  407. void PlayerCompositorDelegate::OnAXTreeUpdateAvailable(
  408. std::unique_ptr<ui::AXTreeUpdate> update) {
  409. TRACE_EVENT0("paint_preview",
  410. "PlayerCompositorDelegate::OnAXTreeUpdateAvailable");
  411. ax_tree_update_ = std::move(update);
  412. proto_copy_ = std::make_unique<PaintPreviewProto>(capture_result_->proto);
  413. page_scale_factor_ = proto_copy_->metadata().page_scale_factor();
  414. if (capture_result_->persistence == RecordingPersistence::kFileSystem) {
  415. base::ThreadPool::PostTaskAndReplyWithResult(
  416. FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
  417. base::BindOnce(&PrepareCompositeRequest, std::move(capture_result_)),
  418. base::BindOnce(&PlayerCompositorDelegate::SendCompositeRequest,
  419. weak_factory_.GetWeakPtr()));
  420. return;
  421. }
  422. SendCompositeRequest(PrepareCompositeRequest(std::move(capture_result_)));
  423. }
  424. void PlayerCompositorDelegate::SendCompositeRequest(
  425. mojom::PaintPreviewBeginCompositeRequestPtr begin_composite_request) {
  426. TRACE_EVENT0("paint_preview",
  427. "PlayerCompositorDelegate::SendCompositeRequest");
  428. // TODO(crbug.com/1021590): Handle initialization errors.
  429. if (!begin_composite_request) {
  430. OnCompositorReady(CompositorStatus::INVALID_REQUEST, nullptr, 0.0, nullptr);
  431. return;
  432. }
  433. // It is possible the client was disconnected while loading the proto.
  434. if (!paint_preview_compositor_client_) {
  435. OnCompositorReady(CompositorStatus::COMPOSITOR_CLIENT_DISCONNECT, nullptr,
  436. 0.0, nullptr);
  437. return;
  438. }
  439. if (main_frame_mode_) {
  440. paint_preview_compositor_client_->BeginMainFrameComposite(
  441. std::move(begin_composite_request),
  442. base::BindOnce(
  443. &PlayerCompositorDelegate::OnCompositorReadyStatusAdapter,
  444. weak_factory_.GetWeakPtr()));
  445. } else {
  446. paint_preview_compositor_client_->BeginSeparatedFrameComposite(
  447. std::move(begin_composite_request),
  448. base::BindOnce(
  449. &PlayerCompositorDelegate::OnCompositorReadyStatusAdapter,
  450. weak_factory_.GetWeakPtr()));
  451. }
  452. // Defer building hit testers so it happens in parallel with preparing the
  453. // compositor.
  454. if (proto_copy_) {
  455. base::ThreadPool::PostTaskAndReplyWithResult(
  456. FROM_HERE, base::BindOnce(&BuildHitTesters, std::move(proto_copy_)),
  457. base::BindOnce(&PlayerCompositorDelegate::OnHitTestersBuilt,
  458. weak_factory_.GetWeakPtr()));
  459. }
  460. proto_copy_.reset();
  461. }
  462. void PlayerCompositorDelegate::OnHitTestersBuilt(
  463. std::unique_ptr<base::flat_map<base::UnguessableToken,
  464. std::unique_ptr<HitTester>>> hit_testers) {
  465. hit_testers_ = std::move(hit_testers);
  466. }
  467. void PlayerCompositorDelegate::OnCompositorClientDisconnected() {
  468. DLOG(ERROR) << "Compositor client disconnected.";
  469. if (compositor_error_) {
  470. std::move(compositor_error_)
  471. .Run(static_cast<int>(CompositorStatus::COMPOSITOR_CLIENT_DISCONNECT));
  472. }
  473. }
  474. void PlayerCompositorDelegate::OnCompositorTimeout() {
  475. DLOG(ERROR) << "Compositor process startup timed out.";
  476. if (compositor_error_) {
  477. std::move(compositor_error_)
  478. .Run(static_cast<int>(CompositorStatus::TIMED_OUT));
  479. }
  480. }
  481. void PlayerCompositorDelegate::ProcessBitmapRequestsFromQueue() {
  482. TRACE_EVENT0("paint_preview",
  483. "PlayerCompositorDelegate::ProcessBitmapRequestsFromQueue");
  484. while (active_requests_ < max_requests_ && bitmap_request_queue_.size()) {
  485. int request_id = bitmap_request_queue_.front();
  486. bitmap_request_queue_.pop();
  487. auto it = pending_bitmap_requests_.find(request_id);
  488. if (it == pending_bitmap_requests_.end())
  489. continue;
  490. BitmapRequest& request = it->second;
  491. active_requests_++;
  492. // If the client disconnects mid request, just give up as we should be
  493. // exiting.
  494. if (!paint_preview_compositor_client_)
  495. return;
  496. if (request.frame_guid.has_value()) {
  497. paint_preview_compositor_client_->BitmapForSeparatedFrame(
  498. request.frame_guid.value(), request.clip_rect, request.scale_factor,
  499. std::move(request.callback));
  500. } else {
  501. paint_preview_compositor_client_->BitmapForMainFrame(
  502. request.clip_rect, request.scale_factor, std::move(request.callback));
  503. }
  504. pending_bitmap_requests_.erase(it);
  505. }
  506. }
  507. void PlayerCompositorDelegate::AfterBitmapRequestCallback() {
  508. active_requests_--;
  509. ProcessBitmapRequestsFromQueue();
  510. }
  511. } // namespace paint_preview