File: annotator_controller.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (219 lines) | stat: -rw-r--r-- 7,091 bytes parent folder | download | duplicates (6)
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
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/annotator/annotator_controller.h"

#include "ash/annotator/annotation_source_watcher.h"
#include "ash/annotator/annotation_tray.h"
#include "ash/annotator/annotations_overlay_controller.h"
#include "ash/annotator/annotator_metrics.h"
#include "ash/capture_mode/capture_mode_controller.h"
#include "ash/projector/projector_metrics.h"
#include "ash/public/cpp/annotator/annotations_overlay_view.h"
#include "ash/public/cpp/annotator/annotator_tool.h"
#include "ash/root_window_controller.h"
#include "ash/system/status_area_widget.h"
#include "ash/webui/annotator/public/cpp/annotator_client.h"
#include "base/check.h"
#include "ui/aura/window.h"
#include "ui/gfx/geometry/rect_f.h"

namespace ash {
namespace {
AnnotatorMarkerColor GetMarkerColorForMetrics(SkColor color) {
  switch (color) {
    case kAnnotatorMagentaPenColor:
      return AnnotatorMarkerColor::kMagenta;
    case kAnnotatorBluePenColor:
      return AnnotatorMarkerColor::kBlue;
    case kAnnotatorRedPenColor:
      return AnnotatorMarkerColor::kRed;
    case kAnnotatorYellowPenColor:
      return AnnotatorMarkerColor::kYellow;
  }
  return AnnotatorMarkerColor::kMaxValue;
}

AnnotationTray* GetAnnotationTrayForRoot(aura::Window* root) {
  // It may happen that root is nullptr. This may happen in the event that
  // the annotation tray is hidden before the canvas finishes its
  // initialization.
  if (!root) {
    return nullptr;
  }

  DCHECK(root->IsRootWindow());

  // Annotating can end when a display being fullscreen-captured gets removed,
  // in this case, we don't need to hide the button.
  if (root->is_destroying()) {
    return nullptr;
  }

  // Can be null while shutting down.
  auto* root_window_controller = RootWindowController::ForWindow(root);
  if (!root_window_controller) {
    return nullptr;
  }

  auto* annotation_tray =
      root_window_controller->GetStatusAreaWidget()->annotation_tray();
  DCHECK(annotation_tray);
  return annotation_tray;
}

void SetAnnotationTrayVisibility(aura::Window* root, bool visible) {
  if (auto* annotation_tray = GetAnnotationTrayForRoot(root)) {
    annotation_tray->SetVisiblePreferred(visible);
  }
}
}  // namespace

AnnotatorController::AnnotatorController() {
  annotation_source_watcher_ = std::make_unique<AnnotationSourceWatcher>(this);
  UpdateAnnotationTrayAccessibleName(/*is_annotator_enabled=*/true);
}

AnnotatorController::~AnnotatorController() {
  annotation_source_watcher_.reset();
  annotations_overlay_controller_.reset();
  client_ = nullptr;
  current_root_ = nullptr;
  UpdateAnnotationTrayAccessibleName(/*is_annotator_enabled=*/false);
}

void AnnotatorController::SetAnnotatorTool(const AnnotatorTool& tool) {
  DCHECK(client_);
  client_->SetTool(tool);
  RecordMarkerColorMetrics(GetMarkerColorForMetrics(tool.color));
}

void AnnotatorController::ResetTools() {
  if (annotator_enabled_) {
    DCHECK(client_);
    ToggleAnnotatorCanvas();
    annotator_enabled_ = false;
    client_->Clear();
    UpdateAnnotationTrayAccessibleName(/*is_annotator_enabled=*/false);
  }
}

void AnnotatorController::RegisterView(aura::Window* new_root) {
  // Make sure the annotator tray is only visible on one root window.
  // TODO(b/342104047): Remove this check when annotator starts being used
  // outside of the capture mode.
  if (current_root_) {
    UnregisterView(current_root_);
  }
  current_root_ = new_root;
  // Show the tray icon.
  SetAnnotationTrayVisibility(current_root_, /*visible=*/true);
}

void AnnotatorController::UnregisterView(aura::Window* window) {
  DCHECK_EQ(current_root_, window);
  if (auto* annotation_tray = GetAnnotationTrayForRoot(current_root_)) {
    annotation_tray->HideAnnotationTray();
  }
  current_root_ = nullptr;
}

void AnnotatorController::UpdateRootView(aura::Window* new_root) {
  // Do nothing if the root window is the same.
  if (new_root == current_root_) {
    return;
  }
  UnregisterView(current_root_);
  RegisterView(new_root);
  current_root_ = new_root;
  if (GetAnnotatorAvailability()) {
    UpdateTrayEnabledState();
  }
}

void AnnotatorController::EnableAnnotatorTool() {
  if (!annotator_enabled_ && annotations_overlay_controller_) {
    ToggleAnnotatorCanvas();
    annotator_enabled_ = !annotator_enabled_;
    UpdateAnnotationTrayAccessibleName(annotator_enabled_);
    // TODO(b/342104047): Decouple from projector metrics.
    RecordToolbarMetrics(ProjectorToolbar::kMarkerTool);
  }
}

void AnnotatorController::DisableAnnotator() {
  ResetTools();
  if (current_root_) {
    UnregisterView(current_root_);
  }
  annotations_overlay_controller_.reset();
  canvas_initialized_state_.reset();
}

void AnnotatorController::CreateAnnotationOverlayForWindow(
    aura::Window* window,
    std::optional<gfx::Rect> partial_region_bounds) {
  annotations_overlay_controller_ =
      std::make_unique<AnnotationsOverlayController>(window,
                                                     partial_region_bounds);
}

void AnnotatorController::UpdateAnnotationTrayAccessibleName(
    bool is_annotator_enabled) {
  if (auto* annotation_tray = GetAnnotationTrayForRoot(current_root_)) {
    annotation_tray->UpdateAccessibleName(is_annotator_enabled);
  }
}

void AnnotatorController::SetToolClient(AnnotatorClient* client) {
  client_ = client;
}

bool AnnotatorController::GetAnnotatorAvailability() const {
  return canvas_initialized_state_.value_or(false);
}

void AnnotatorController::OnCanvasInitialized(bool success) {
  canvas_initialized_state_ = success;
  UpdateTrayEnabledState();
  if (on_canvas_initialized_callback_for_test_) {
    std::move(on_canvas_initialized_callback_for_test_).Run();
  }
}

void AnnotatorController::ToggleAnnotationTray() {
  if (auto* annotation_tray = GetAnnotationTrayForRoot(current_root_)) {
    annotation_tray->ToggleAnnotator();
  }
}

// Callback indicating availability of undo and redo functionalities.
void AnnotatorController::OnUndoRedoAvailabilityChanged(bool undo_available,
                                                        bool redo_available) {
  // TODO(b/198184362): Reflect undo and redo buttons availability
  // on the annotator tray.
}

std::unique_ptr<AnnotationsOverlayView>
AnnotatorController::CreateAnnotationsOverlayView() const {
  return client_->CreateAnnotationsOverlayView();
}

void AnnotatorController::UpdateTrayEnabledState() {
  if (auto* annotation_tray = GetAnnotationTrayForRoot(current_root_)) {
    annotation_tray->SetTrayEnabled(GetAnnotatorAvailability());
  }
}

void AnnotatorController::ToggleAnnotatorCanvas() {
  auto* capture_mode_controller = CaptureModeController::Get();
  // TODO(b/342104047): This check is necessary as long as we only toggle
  // annotator from Projector. Once we start using the annotator outside of
  // Projector, we should remove the check.
  if (capture_mode_controller->is_recording_in_progress()) {
    annotations_overlay_controller_->Toggle();
  }
}

}  // namespace ash