Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(434)

Side by Side Diff: components/mus/public/cpp/lib/view.cc

Issue 1340983002: Mandoline UI Process: Update namespaces and file names (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updated all the namespaces in mus Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/mus/public/cpp/view.h" 5 #include "components/mus/public/cpp/view.h"
6 6
7 #include <set> 7 #include <set>
8 #include <string> 8 #include <string>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "components/mus/public/cpp/lib/view_private.h" 11 #include "components/mus/public/cpp/lib/view_private.h"
12 #include "components/mus/public/cpp/lib/view_tree_client_impl.h" 12 #include "components/mus/public/cpp/lib/view_tree_client_impl.h"
13 #include "components/mus/public/cpp/view_observer.h" 13 #include "components/mus/public/cpp/view_observer.h"
14 #include "components/mus/public/cpp/view_surface.h" 14 #include "components/mus/public/cpp/view_surface.h"
15 #include "components/mus/public/cpp/view_tracker.h" 15 #include "components/mus/public/cpp/view_tracker.h"
16 #include "mojo/application/public/cpp/service_provider_impl.h" 16 #include "mojo/application/public/cpp/service_provider_impl.h"
17 17
18 namespace mojo { 18 namespace mus {
19 19
20 namespace { 20 namespace {
21 21
22 void NotifyViewTreeChangeAtReceiver( 22 void NotifyViewTreeChangeAtReceiver(
23 View* receiver, 23 View* receiver,
24 const ViewObserver::TreeChangeParams& params, 24 const ViewObserver::TreeChangeParams& params,
25 bool change_applied) { 25 bool change_applied) {
26 ViewObserver::TreeChangeParams local_params = params; 26 ViewObserver::TreeChangeParams local_params = params;
27 local_params.receiver = receiver; 27 local_params.receiver = receiver;
28 if (change_applied) { 28 if (change_applied) {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 if (it != children->end()) { 81 if (it != children->end()) {
82 children->erase(it); 82 children->erase(it);
83 ViewPrivate(child).ClearParent(); 83 ViewPrivate(child).ClearParent();
84 } 84 }
85 } 85 }
86 86
87 class ScopedOrderChangedNotifier { 87 class ScopedOrderChangedNotifier {
88 public: 88 public:
89 ScopedOrderChangedNotifier(View* view, 89 ScopedOrderChangedNotifier(View* view,
90 View* relative_view, 90 View* relative_view,
91 OrderDirection direction) 91 mojo::OrderDirection direction)
92 : view_(view), relative_view_(relative_view), direction_(direction) { 92 : view_(view), relative_view_(relative_view), direction_(direction) {
93 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(), 93 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(),
94 OnViewReordering(view_, relative_view_, direction_)); 94 OnViewReordering(view_, relative_view_, direction_));
95 } 95 }
96 ~ScopedOrderChangedNotifier() { 96 ~ScopedOrderChangedNotifier() {
97 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(), 97 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(),
98 OnViewReordered(view_, relative_view_, direction_)); 98 OnViewReordered(view_, relative_view_, direction_));
99 } 99 }
100 100
101 private: 101 private:
102 View* view_; 102 View* view_;
103 View* relative_view_; 103 View* relative_view_;
104 OrderDirection direction_; 104 mojo::OrderDirection direction_;
105 105
106 MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedOrderChangedNotifier); 106 MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedOrderChangedNotifier);
107 }; 107 };
108 108
109 // Returns true if the order actually changed. 109 // Returns true if the order actually changed.
110 bool ReorderImpl(View::Children* children, 110 bool ReorderImpl(View::Children* children,
111 View* view, 111 View* view,
112 View* relative, 112 View* relative,
113 OrderDirection direction) { 113 mojo::OrderDirection direction) {
114 DCHECK(relative); 114 DCHECK(relative);
115 DCHECK_NE(view, relative); 115 DCHECK_NE(view, relative);
116 DCHECK_EQ(view->parent(), relative->parent()); 116 DCHECK_EQ(view->parent(), relative->parent());
117 117
118 const size_t child_i = 118 const size_t child_i =
119 std::find(children->begin(), children->end(), view) - children->begin(); 119 std::find(children->begin(), children->end(), view) - children->begin();
120 const size_t target_i = 120 const size_t target_i =
121 std::find(children->begin(), children->end(), relative) - 121 std::find(children->begin(), children->end(), relative) -
122 children->begin(); 122 children->begin();
123 if ((direction == ORDER_DIRECTION_ABOVE && child_i == target_i + 1) || 123 if ((direction == mojo::ORDER_DIRECTION_ABOVE && child_i == target_i + 1) ||
124 (direction == ORDER_DIRECTION_BELOW && child_i + 1 == target_i)) { 124 (direction == mojo::ORDER_DIRECTION_BELOW && child_i + 1 == target_i)) {
125 return false; 125 return false;
126 } 126 }
127 127
128 ScopedOrderChangedNotifier notifier(view, relative, direction); 128 ScopedOrderChangedNotifier notifier(view, relative, direction);
129 129
130 const size_t dest_i = direction == ORDER_DIRECTION_ABOVE 130 const size_t dest_i = direction == mojo::ORDER_DIRECTION_ABOVE
131 ? (child_i < target_i ? target_i : target_i + 1) 131 ? (child_i < target_i ? target_i : target_i + 1)
132 : (child_i < target_i ? target_i - 1 : target_i); 132 : (child_i < target_i ? target_i - 1 : target_i);
133 children->erase(children->begin() + child_i); 133 children->erase(children->begin() + child_i);
134 children->insert(children->begin() + dest_i, view); 134 children->insert(children->begin() + dest_i, view);
135 135
136 return true; 136 return true;
137 } 137 }
138 138
139 class ScopedSetBoundsNotifier { 139 class ScopedSetBoundsNotifier {
140 public: 140 public:
141 ScopedSetBoundsNotifier(View* view, 141 ScopedSetBoundsNotifier(View* view,
142 const Rect& old_bounds, 142 const mojo::Rect& old_bounds,
143 const Rect& new_bounds) 143 const mojo::Rect& new_bounds)
144 : view_(view), old_bounds_(old_bounds), new_bounds_(new_bounds) { 144 : view_(view), old_bounds_(old_bounds), new_bounds_(new_bounds) {
145 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(), 145 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(),
146 OnViewBoundsChanging(view_, old_bounds_, new_bounds_)); 146 OnViewBoundsChanging(view_, old_bounds_, new_bounds_));
147 } 147 }
148 ~ScopedSetBoundsNotifier() { 148 ~ScopedSetBoundsNotifier() {
149 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(), 149 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(),
150 OnViewBoundsChanged(view_, old_bounds_, new_bounds_)); 150 OnViewBoundsChanged(view_, old_bounds_, new_bounds_));
151 } 151 }
152 152
153 private: 153 private:
154 View* view_; 154 View* view_;
155 const Rect old_bounds_; 155 const mojo::Rect old_bounds_;
156 const Rect new_bounds_; 156 const mojo::Rect new_bounds_;
157 157
158 MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier); 158 MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier);
159 }; 159 };
160 160
161 // Some operations are only permitted in the connection that created the view. 161 // Some operations are only permitted in the connection that created the view.
162 bool OwnsView(ViewTreeConnection* connection, View* view) { 162 bool OwnsView(ViewTreeConnection* connection, View* view) {
163 return !connection || 163 return !connection ||
164 static_cast<ViewTreeClientImpl*>(connection)->OwnsView(view->id()); 164 static_cast<ViewTreeClientImpl*>(connection)->OwnsView(view->id());
165 } 165 }
166 166
(...skipping 17 matching lines...) Expand all
184 children_.erase(children_.begin()); 184 children_.erase(children_.begin());
185 } else { 185 } else {
186 child->Destroy(); 186 child->Destroy();
187 DCHECK(std::find(children_.begin(), children_.end(), child) == 187 DCHECK(std::find(children_.begin(), children_.end(), child) ==
188 children_.end()); 188 children_.end());
189 } 189 }
190 } 190 }
191 LocalDestroy(); 191 LocalDestroy();
192 } 192 }
193 193
194 void View::SetBounds(const Rect& bounds) { 194 void View::SetBounds(const mojo::Rect& bounds) {
195 if (!OwnsView(connection_, this)) 195 if (!OwnsView(connection_, this))
196 return; 196 return;
197 197
198 if (bounds_.Equals(bounds)) 198 if (bounds_.Equals(bounds))
199 return; 199 return;
200 200
201 if (connection_) 201 if (connection_)
202 static_cast<ViewTreeClientImpl*>(connection_)->SetBounds(id_, bounds); 202 static_cast<ViewTreeClientImpl*>(connection_)->SetBounds(id_, bounds);
203 LocalSetBounds(bounds_, bounds); 203 LocalSetBounds(bounds_, bounds);
204 } 204 }
205 205
206 void View::SetVisible(bool value) { 206 void View::SetVisible(bool value) {
207 if (visible_ == value) 207 if (visible_ == value)
208 return; 208 return;
209 209
210 if (connection_) 210 if (connection_)
211 static_cast<ViewTreeClientImpl*>(connection_)->SetVisible(id_, value); 211 static_cast<ViewTreeClientImpl*>(connection_)->SetVisible(id_, value);
212 LocalSetVisible(value); 212 LocalSetVisible(value);
213 } 213 }
214 214
215 scoped_ptr<mojo::ViewSurface> View::RequestSurface() { 215 scoped_ptr<ViewSurface> View::RequestSurface() {
216 mojo::SurfacePtr surface; 216 mojo::SurfacePtr surface;
217 mojo::SurfaceClientPtr client; 217 mojo::SurfaceClientPtr client;
218 mojo::InterfaceRequest<SurfaceClient> client_request = GetProxy(&client); 218 mojo::InterfaceRequest<mojo::SurfaceClient> client_request =
219 GetProxy(&client);
219 static_cast<ViewTreeClientImpl*>(connection_) 220 static_cast<ViewTreeClientImpl*>(connection_)
220 ->RequestSurface(id_, GetProxy(&surface), client.Pass()); 221 ->RequestSurface(id_, GetProxy(&surface), client.Pass());
221 return make_scoped_ptr( 222 return make_scoped_ptr(
222 new mojo::ViewSurface(surface.PassInterface(), client_request.Pass())); 223 new ViewSurface(surface.PassInterface(), client_request.Pass()));
223 } 224 }
224 225
225 void View::SetSharedProperty(const std::string& name, 226 void View::SetSharedProperty(const std::string& name,
226 const std::vector<uint8_t>* value) { 227 const std::vector<uint8_t>* value) {
227 std::vector<uint8_t> old_value; 228 std::vector<uint8_t> old_value;
228 std::vector<uint8_t>* old_value_ptr = nullptr; 229 std::vector<uint8_t>* old_value_ptr = nullptr;
229 auto it = properties_.find(name); 230 auto it = properties_.find(name);
230 if (it != properties_.end()) { 231 if (it != properties_.end()) {
231 old_value = it->second; 232 old_value = it->second;
232 old_value_ptr = &old_value; 233 old_value_ptr = &old_value;
233 234
234 if (value && old_value == *value) 235 if (value && old_value == *value)
235 return; 236 return;
236 } else if (!value) { 237 } else if (!value) {
237 // This property isn't set in |properties_| and |value| is NULL, so there's 238 // This property isn't set in |properties_| and |value| is NULL, so there's
238 // no change. 239 // no change.
239 return; 240 return;
240 } 241 }
241 242
242 if (value) { 243 if (value) {
243 properties_[name] = *value; 244 properties_[name] = *value;
244 } else if (it != properties_.end()) { 245 } else if (it != properties_.end()) {
245 properties_.erase(it); 246 properties_.erase(it);
246 } 247 }
247 248
248 // TODO: add test coverage of this (450303). 249 // TODO: add test coverage of this (450303).
249 if (connection_) { 250 if (connection_) {
250 Array<uint8_t> transport_value; 251 mojo::Array<uint8_t> transport_value;
251 if (value) { 252 if (value) {
252 transport_value.resize(value->size()); 253 transport_value.resize(value->size());
253 if (value->size()) 254 if (value->size())
254 memcpy(&transport_value.front(), &(value->front()), value->size()); 255 memcpy(&transport_value.front(), &(value->front()), value->size());
255 } 256 }
256 static_cast<ViewTreeClientImpl*>(connection_) 257 static_cast<ViewTreeClientImpl*>(connection_)
257 ->SetProperty(id_, name, transport_value.Pass()); 258 ->SetProperty(id_, name, transport_value.Pass());
258 } 259 }
259 260
260 FOR_EACH_OBSERVER( 261 FOR_EACH_OBSERVER(
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 LocalRemoveChild(child); 309 LocalRemoveChild(child);
309 if (connection_) { 310 if (connection_) {
310 static_cast<ViewTreeClientImpl*>(connection_) 311 static_cast<ViewTreeClientImpl*>(connection_)
311 ->RemoveChild(child->id(), id_); 312 ->RemoveChild(child->id(), id_);
312 } 313 }
313 } 314 }
314 315
315 void View::MoveToFront() { 316 void View::MoveToFront() {
316 if (!parent_ || parent_->children_.back() == this) 317 if (!parent_ || parent_->children_.back() == this)
317 return; 318 return;
318 Reorder(parent_->children_.back(), ORDER_DIRECTION_ABOVE); 319 Reorder(parent_->children_.back(), mojo::ORDER_DIRECTION_ABOVE);
319 } 320 }
320 321
321 void View::MoveToBack() { 322 void View::MoveToBack() {
322 if (!parent_ || parent_->children_.front() == this) 323 if (!parent_ || parent_->children_.front() == this)
323 return; 324 return;
324 Reorder(parent_->children_.front(), ORDER_DIRECTION_BELOW); 325 Reorder(parent_->children_.front(), mojo::ORDER_DIRECTION_BELOW);
325 } 326 }
326 327
327 void View::Reorder(View* relative, OrderDirection direction) { 328 void View::Reorder(View* relative, mojo::OrderDirection direction) {
328 if (!LocalReorder(relative, direction)) 329 if (!LocalReorder(relative, direction))
329 return; 330 return;
330 if (connection_) { 331 if (connection_) {
331 static_cast<ViewTreeClientImpl*>(connection_) 332 static_cast<ViewTreeClientImpl*>(connection_)
332 ->Reorder(id_, relative->id(), direction); 333 ->Reorder(id_, relative->id(), direction);
333 } 334 }
334 } 335 }
335 336
336 bool View::Contains(View* child) const { 337 bool View::Contains(View* child) const {
337 if (!child) 338 if (!child)
(...skipping 15 matching lines...) Expand all
353 // TODO(beng): this could be improved depending on how we decide to own views. 354 // TODO(beng): this could be improved depending on how we decide to own views.
354 Children::const_iterator it = children_.begin(); 355 Children::const_iterator it = children_.begin();
355 for (; it != children_.end(); ++it) { 356 for (; it != children_.end(); ++it) {
356 View* view = (*it)->GetChildById(id); 357 View* view = (*it)->GetChildById(id);
357 if (view) 358 if (view)
358 return view; 359 return view;
359 } 360 }
360 return NULL; 361 return NULL;
361 } 362 }
362 363
363 void View::SetTextInputState(TextInputStatePtr state) { 364 void View::SetTextInputState(mojo::TextInputStatePtr state) {
364 if (connection_) { 365 if (connection_) {
365 static_cast<ViewTreeClientImpl*>(connection_) 366 static_cast<ViewTreeClientImpl*>(connection_)
366 ->SetViewTextInputState(id_, state.Pass()); 367 ->SetViewTextInputState(id_, state.Pass());
367 } 368 }
368 } 369 }
369 370
370 void View::SetImeVisibility(bool visible, TextInputStatePtr state) { 371 void View::SetImeVisibility(bool visible, mojo::TextInputStatePtr state) {
371 // SetImeVisibility() shouldn't be used if the view is not editable. 372 // SetImeVisibility() shouldn't be used if the view is not editable.
372 DCHECK(state.is_null() || state->type != TEXT_INPUT_TYPE_NONE); 373 DCHECK(state.is_null() || state->type != mojo::TEXT_INPUT_TYPE_NONE);
373 if (connection_) { 374 if (connection_) {
374 static_cast<ViewTreeClientImpl*>(connection_) 375 static_cast<ViewTreeClientImpl*>(connection_)
375 ->SetImeVisibility(id_, visible, state.Pass()); 376 ->SetImeVisibility(id_, visible, state.Pass());
376 } 377 }
377 } 378 }
378 379
379 void View::SetFocus() { 380 void View::SetFocus() {
380 if (connection_) 381 if (connection_)
381 static_cast<ViewTreeClientImpl*>(connection_)->SetFocus(id_); 382 static_cast<ViewTreeClientImpl*>(connection_)->SetFocus(id_);
382 } 383 }
383 384
384 bool View::HasFocus() const { 385 bool View::HasFocus() const {
385 return connection_ && connection_->GetFocusedView() == this; 386 return connection_ && connection_->GetFocusedView() == this;
386 } 387 }
387 388
388 void View::Embed(ViewTreeClientPtr client) { 389 void View::Embed(mojo::ViewTreeClientPtr client) {
389 Embed(client.Pass(), base::Bind(&EmptyEmbedCallback)); 390 Embed(client.Pass(), base::Bind(&EmptyEmbedCallback));
390 } 391 }
391 392
392 void View::Embed(ViewTreeClientPtr client, const EmbedCallback& callback) { 393 void View::Embed(mojo::ViewTreeClientPtr client,
394 const EmbedCallback& callback) {
393 if (PrepareForEmbed()) { 395 if (PrepareForEmbed()) {
394 static_cast<ViewTreeClientImpl*>(connection_) 396 static_cast<ViewTreeClientImpl*>(connection_)
395 ->Embed(id_, client.Pass(), callback); 397 ->Embed(id_, client.Pass(), callback);
396 } else { 398 } else {
397 callback.Run(false, 0); 399 callback.Run(false, 0);
398 } 400 }
399 } 401 }
400 402
401 //////////////////////////////////////////////////////////////////////////////// 403 ////////////////////////////////////////////////////////////////////////////////
402 // View, protected: 404 // View, protected:
403 405
404 namespace { 406 namespace {
405 407
406 ViewportMetricsPtr CreateEmptyViewportMetrics() { 408 mojo::ViewportMetricsPtr CreateEmptyViewportMetrics() {
407 ViewportMetricsPtr metrics = ViewportMetrics::New(); 409 mojo::ViewportMetricsPtr metrics = mojo::ViewportMetrics::New();
408 metrics->size_in_pixels = Size::New(); 410 metrics->size_in_pixels = mojo::Size::New();
409 // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it 411 // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it
410 // once that's fixed. 412 // once that's fixed.
411 return metrics.Pass(); 413 return metrics.Pass();
412 } 414 }
413 415
414 } // namespace 416 } // namespace
415 417
416 View::View() 418 View::View()
417 : connection_(NULL), 419 : connection_(NULL),
418 id_(static_cast<Id>(-1)), 420 id_(static_cast<Id>(-1)),
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
502 children_.push_back(child); 504 children_.push_back(child);
503 child->parent_ = this; 505 child->parent_ = this;
504 } 506 }
505 507
506 void View::LocalRemoveChild(View* child) { 508 void View::LocalRemoveChild(View* child) {
507 DCHECK_EQ(this, child->parent()); 509 DCHECK_EQ(this, child->parent());
508 ScopedTreeNotifier notifier(child, this, NULL); 510 ScopedTreeNotifier notifier(child, this, NULL);
509 RemoveChildImpl(child, &children_); 511 RemoveChildImpl(child, &children_);
510 } 512 }
511 513
512 bool View::LocalReorder(View* relative, OrderDirection direction) { 514 bool View::LocalReorder(View* relative, mojo::OrderDirection direction) {
513 return ReorderImpl(&parent_->children_, this, relative, direction); 515 return ReorderImpl(&parent_->children_, this, relative, direction);
514 } 516 }
515 517
516 void View::LocalSetBounds(const Rect& old_bounds, const Rect& new_bounds) { 518 void View::LocalSetBounds(const mojo::Rect& old_bounds,
519 const mojo::Rect& new_bounds) {
517 DCHECK(old_bounds.x == bounds_.x); 520 DCHECK(old_bounds.x == bounds_.x);
518 DCHECK(old_bounds.y == bounds_.y); 521 DCHECK(old_bounds.y == bounds_.y);
519 DCHECK(old_bounds.width == bounds_.width); 522 DCHECK(old_bounds.width == bounds_.width);
520 DCHECK(old_bounds.height == bounds_.height); 523 DCHECK(old_bounds.height == bounds_.height);
521 ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds); 524 ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds);
522 bounds_ = new_bounds; 525 bounds_ = new_bounds;
523 } 526 }
524 527
525 void View::LocalSetViewportMetrics(const ViewportMetrics& old_metrics, 528 void View::LocalSetViewportMetrics(const mojo::ViewportMetrics& old_metrics,
526 const ViewportMetrics& new_metrics) { 529 const mojo::ViewportMetrics& new_metrics) {
527 // TODO(eseidel): We could check old_metrics against viewport_metrics_. 530 // TODO(eseidel): We could check old_metrics against viewport_metrics_.
528 viewport_metrics_ = new_metrics.Clone(); 531 viewport_metrics_ = new_metrics.Clone();
529 FOR_EACH_OBSERVER( 532 FOR_EACH_OBSERVER(
530 ViewObserver, observers_, 533 ViewObserver, observers_,
531 OnViewViewportMetricsChanged(this, old_metrics, new_metrics)); 534 OnViewViewportMetricsChanged(this, old_metrics, new_metrics));
532 } 535 }
533 536
534 void View::LocalSetDrawn(bool value) { 537 void View::LocalSetDrawn(bool value) {
535 if (drawn_ == value) 538 if (drawn_ == value)
536 return; 539 return;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
607 if (!OwnsView(connection_, this) && 610 if (!OwnsView(connection_, this) &&
608 !static_cast<ViewTreeClientImpl*>(connection_)->is_embed_root()) { 611 !static_cast<ViewTreeClientImpl*>(connection_)->is_embed_root()) {
609 return false; 612 return false;
610 } 613 }
611 614
612 while (!children_.empty()) 615 while (!children_.empty())
613 RemoveChild(children_[0]); 616 RemoveChild(children_[0]);
614 return true; 617 return true;
615 } 618 }
616 619
617 } // namespace mojo 620 } // namespace mus
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698