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

Side by Side Diff: content/browser/renderer_host/render_widget_host_view_aura.cc

Issue 1987903002: Create only a single LegacyRenderWidgetHostHWND per WebContentsViewAura. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix last merge issue Created 4 years, 7 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/browser/renderer_host/render_widget_host_view_aura.h" 5 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
6 6
7 #include <set> 7 #include <set>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/auto_reset.h" 10 #include "base/auto_reset.h"
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 text_input_flags_(0), 375 text_input_flags_(0),
376 can_compose_inline_(true), 376 can_compose_inline_(true),
377 has_composition_text_(false), 377 has_composition_text_(false),
378 accept_return_character_(false), 378 accept_return_character_(false),
379 begin_frame_source_(nullptr), 379 begin_frame_source_(nullptr),
380 needs_begin_frames_(false), 380 needs_begin_frames_(false),
381 synthetic_move_sent_(false), 381 synthetic_move_sent_(false),
382 cursor_visibility_state_in_renderer_(UNKNOWN), 382 cursor_visibility_state_in_renderer_(UNKNOWN),
383 #if defined(OS_WIN) 383 #if defined(OS_WIN)
384 legacy_render_widget_host_HWND_(nullptr), 384 legacy_render_widget_host_HWND_(nullptr),
385 legacy_window_destroyed_(false),
386 #endif 385 #endif
387 has_snapped_to_boundary_(false), 386 has_snapped_to_boundary_(false),
388 is_guest_view_hack_(is_guest_view_hack), 387 is_guest_view_hack_(is_guest_view_hack),
389 set_focus_on_mouse_down_or_key_event_(false), 388 set_focus_on_mouse_down_or_key_event_(false),
390 device_scale_factor_(0.0f), 389 device_scale_factor_(0.0f),
391 disable_input_event_router_for_testing_(false), 390 disable_input_event_router_for_testing_(false),
392 weak_ptr_factory_(this) { 391 weak_ptr_factory_(this) {
393 if (!is_guest_view_hack_) 392 if (!is_guest_view_hack_)
394 host_->SetView(this); 393 host_->SetView(this);
395 394
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
548 547
549 aura::Window* root = window_->GetRootWindow(); 548 aura::Window* root = window_->GetRootWindow();
550 if (root) { 549 if (root) {
551 aura::client::CursorClient* cursor_client = 550 aura::client::CursorClient* cursor_client =
552 aura::client::GetCursorClient(root); 551 aura::client::GetCursorClient(root);
553 if (cursor_client) 552 if (cursor_client)
554 NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible()); 553 NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible());
555 } 554 }
556 555
557 delegated_frame_host_->WasShown(browser_latency_info); 556 delegated_frame_host_->WasShown(browser_latency_info);
558
559 #if defined(OS_WIN)
560 if (legacy_render_widget_host_HWND_) {
561 // Reparent the legacy Chrome_RenderWidgetHostHWND window to the parent
562 // window before reparenting any plugins. This ensures that the plugin
563 // windows stay on top of the child Zorder in the parent and receive
564 // mouse events, etc.
565 legacy_render_widget_host_HWND_->UpdateParent(
566 GetNativeView()->GetHost()->GetAcceleratedWidget());
567 legacy_render_widget_host_HWND_->SetBounds(
568 window_->GetBoundsInRootWindow());
569 legacy_render_widget_host_HWND_->Show();
570 }
571 #endif
572 } 557 }
573 558
574 void RenderWidgetHostViewAura::Hide() { 559 void RenderWidgetHostViewAura::Hide() {
575 window_->Hide(); 560 window_->Hide();
576 561
577 // TODO(wjmaclean): can host_ ever be null? 562 // TODO(wjmaclean): can host_ ever be null?
578 if (host_ && !host_->is_hidden()) { 563 if (host_ && !host_->is_hidden()) {
579 host_->WasHidden(); 564 host_->WasHidden();
580 delegated_frame_host_->WasHidden(); 565 delegated_frame_host_->WasHidden();
581
582 #if defined(OS_WIN)
583 aura::WindowTreeHost* host = window_->GetHost();
584 if (host) {
585 // We reparent the legacy Chrome_RenderWidgetHostHWND window to the global
586 // hidden window on the same lines as Windowed plugin windows.
587 if (legacy_render_widget_host_HWND_)
588 legacy_render_widget_host_HWND_->UpdateParent(ui::GetHiddenWindow());
589 }
590 #endif
591 } 566 }
592 567
593 #if defined(OS_WIN) 568 #if defined(OS_WIN)
594 if (legacy_render_widget_host_HWND_) 569 if (legacy_render_widget_host_HWND_)
595 legacy_render_widget_host_HWND_->Hide(); 570 legacy_render_widget_host_HWND_->Hide();
596 #endif 571 #endif
597 } 572 }
598 573
599 void RenderWidgetHostViewAura::SetSize(const gfx::Size& size) { 574 void RenderWidgetHostViewAura::SetSize(const gfx::Size& size) {
600 // For a SetSize operation, we don't care what coordinate system the origin 575 // For a SetSize operation, we don't care what coordinate system the origin
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after
1042 return (legacy_render_widget_host_HWND_ != NULL); 1017 return (legacy_render_widget_host_HWND_ != NULL);
1043 } 1018 }
1044 1019
1045 void RenderWidgetHostViewAura::UpdateMouseLockRegion() { 1020 void RenderWidgetHostViewAura::UpdateMouseLockRegion() {
1046 RECT window_rect = 1021 RECT window_rect =
1047 display::Screen::GetScreen() 1022 display::Screen::GetScreen()
1048 ->DIPToScreenRectInWindow(window_, window_->GetBoundsInScreen()) 1023 ->DIPToScreenRectInWindow(window_, window_->GetBoundsInScreen())
1049 .ToRECT(); 1024 .ToRECT();
1050 ::ClipCursor(&window_rect); 1025 ::ClipCursor(&window_rect);
1051 } 1026 }
1052 1027 #endif // defined(OS_WIN)
1053 void RenderWidgetHostViewAura::OnLegacyWindowDestroyed() {
1054 legacy_render_widget_host_HWND_ = NULL;
1055 legacy_window_destroyed_ = true;
1056 }
1057 #endif
1058 1028
1059 void RenderWidgetHostViewAura::OnSwapCompositorFrame( 1029 void RenderWidgetHostViewAura::OnSwapCompositorFrame(
1060 uint32_t output_surface_id, 1030 uint32_t output_surface_id,
1061 std::unique_ptr<cc::CompositorFrame> frame) { 1031 std::unique_ptr<cc::CompositorFrame> frame) {
1062 TRACE_EVENT0("content", "RenderWidgetHostViewAura::OnSwapCompositorFrame"); 1032 TRACE_EVENT0("content", "RenderWidgetHostViewAura::OnSwapCompositorFrame");
1063 1033
1064 last_scroll_offset_ = frame->metadata.root_scroll_offset; 1034 last_scroll_offset_ = frame->metadata.root_scroll_offset;
1065 if (!frame->delegated_frame_data) 1035 if (!frame->delegated_frame_data)
1066 return; 1036 return;
1067 1037
(...skipping 14 matching lines...) Expand all
1082 } 1052 }
1083 1053
1084 void RenderWidgetHostViewAura::ClearCompositorFrame() { 1054 void RenderWidgetHostViewAura::ClearCompositorFrame() {
1085 delegated_frame_host_->ClearDelegatedFrame(); 1055 delegated_frame_host_->ClearDelegatedFrame();
1086 } 1056 }
1087 1057
1088 void RenderWidgetHostViewAura::DidStopFlinging() { 1058 void RenderWidgetHostViewAura::DidStopFlinging() {
1089 selection_controller_client_->OnScrollCompleted(); 1059 selection_controller_client_->OnScrollCompleted();
1090 } 1060 }
1091 1061
1062 #if defined(OS_WIN)
1063 void RenderWidgetHostViewAura::SetLegacyRenderWidgetHostHWND(
1064 LegacyRenderWidgetHostHWND* legacy_hwnd) {
1065 legacy_render_widget_host_HWND_ = legacy_hwnd;
1066 }
1067 #endif
1068
1092 bool RenderWidgetHostViewAura::HasAcceleratedSurface( 1069 bool RenderWidgetHostViewAura::HasAcceleratedSurface(
1093 const gfx::Size& desired_size) { 1070 const gfx::Size& desired_size) {
1094 // Aura doesn't use GetBackingStore for accelerated pages, so it doesn't 1071 // Aura doesn't use GetBackingStore for accelerated pages, so it doesn't
1095 // matter what is returned here as GetBackingStore is the only caller of this 1072 // matter what is returned here as GetBackingStore is the only caller of this
1096 // method. TODO(jbates) implement this if other Aura code needs it. 1073 // method. TODO(jbates) implement this if other Aura code needs it.
1097 return false; 1074 return false;
1098 } 1075 }
1099 1076
1100 void RenderWidgetHostViewAura::GetScreenInfo(WebScreenInfo* results) { 1077 void RenderWidgetHostViewAura::GetScreenInfo(WebScreenInfo* results) {
1101 GetScreenInfoForWindow(results, window_->GetRootWindow() ? window_ : NULL); 1078 GetScreenInfoForWindow(results, window_->GetRootWindow() ? window_ : NULL);
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
1263 #else 1240 #else
1264 manager = BrowserAccessibilityManager::Create( 1241 manager = BrowserAccessibilityManager::Create(
1265 BrowserAccessibilityManager::GetEmptyDocument(), delegate); 1242 BrowserAccessibilityManager::GetEmptyDocument(), delegate);
1266 #endif 1243 #endif
1267 return manager; 1244 return manager;
1268 } 1245 }
1269 1246
1270 gfx::AcceleratedWidget 1247 gfx::AcceleratedWidget
1271 RenderWidgetHostViewAura::AccessibilityGetAcceleratedWidget() { 1248 RenderWidgetHostViewAura::AccessibilityGetAcceleratedWidget() {
1272 #if defined(OS_WIN) 1249 #if defined(OS_WIN)
1273 if (legacy_render_widget_host_HWND_) 1250 if (legacy_render_widget_host_HWND_) {
1274 return legacy_render_widget_host_HWND_->hwnd(); 1251 HWND hwnd = legacy_render_widget_host_HWND_->hwnd();
1252 if (::IsWindow(hwnd))
1253 return hwnd;
1254 }
1275 #endif 1255 #endif
1276 return gfx::kNullAcceleratedWidget; 1256 return gfx::kNullAcceleratedWidget;
1277 } 1257 }
1278 1258
1279 gfx::NativeViewAccessible 1259 gfx::NativeViewAccessible
1280 RenderWidgetHostViewAura::AccessibilityGetNativeViewAccessible() { 1260 RenderWidgetHostViewAura::AccessibilityGetNativeViewAccessible() {
1281 #if defined(OS_WIN) 1261 #if defined(OS_WIN)
1282 if (legacy_render_widget_host_HWND_) 1262 if (legacy_render_widget_host_HWND_)
1283 return legacy_render_widget_host_HWND_->window_accessible(); 1263 return legacy_render_widget_host_HWND_->window_accessible();
1284 #endif 1264 #endif
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after
1680 device_scale_factor_ = device_scale_factor; 1660 device_scale_factor_ = device_scale_factor;
1681 const display::Display display = 1661 const display::Display display =
1682 display::Screen::GetScreen()->GetDisplayNearestWindow(window_); 1662 display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
1683 DCHECK_EQ(device_scale_factor, display.device_scale_factor()); 1663 DCHECK_EQ(device_scale_factor, display.device_scale_factor());
1684 current_cursor_.SetDisplayInfo(display); 1664 current_cursor_.SetDisplayInfo(display);
1685 SnapToPhysicalPixelBoundary(); 1665 SnapToPhysicalPixelBoundary();
1686 } 1666 }
1687 1667
1688 void RenderWidgetHostViewAura::OnWindowDestroying(aura::Window* window) { 1668 void RenderWidgetHostViewAura::OnWindowDestroying(aura::Window* window) {
1689 #if defined(OS_WIN) 1669 #if defined(OS_WIN)
1690 // The LegacyRenderWidgetHostHWND instance is destroyed when its window is 1670 HWND parent = NULL;
1691 // destroyed. Normally we control when that happens via the Destroy call 1671 // If the tab was hidden and it's closed, host_->is_hidden would have been
1692 // in the dtor. However there may be cases where the window is destroyed 1672 // reset to false in RenderWidgetHostImpl::RendererExited.
1693 // by Windows, i.e. the parent window is destroyed before the 1673 if (!window_->GetRootWindow() || host_->is_hidden()) {
1694 // RenderWidgetHostViewAura instance goes away etc. To avoid that we 1674 parent = ui::GetHiddenWindow();
1695 // destroy the LegacyRenderWidgetHostHWND instance here. 1675 } else {
1696 if (legacy_render_widget_host_HWND_) { 1676 parent = window_->GetHost()->GetAcceleratedWidget();
1697 legacy_render_widget_host_HWND_->set_host(NULL);
1698 legacy_render_widget_host_HWND_->Destroy();
1699 // The Destroy call above will delete the LegacyRenderWidgetHostHWND
1700 // instance.
1701 legacy_render_widget_host_HWND_ = NULL;
1702 } 1677 }
1678 legacy_render_widget_host_HWND_ = nullptr;
1703 #endif 1679 #endif
1704 1680
1705 // Make sure that the input method no longer references to this object before 1681 // Make sure that the input method no longer references to this object before
1706 // this object is removed from the root window (i.e. this object loses access 1682 // this object is removed from the root window (i.e. this object loses access
1707 // to the input method). 1683 // to the input method).
1708 DetachFromInputMethod(); 1684 DetachFromInputMethod();
1709 1685
1710 if (overscroll_controller_) 1686 if (overscroll_controller_)
1711 overscroll_controller_->Reset(); 1687 overscroll_controller_->Reset();
1712 } 1688 }
(...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after
2273 DCHECK(popup_parent_host_view_->popup_child_host_view_ == NULL || 2249 DCHECK(popup_parent_host_view_->popup_child_host_view_ == NULL ||
2274 popup_parent_host_view_->popup_child_host_view_ == this); 2250 popup_parent_host_view_->popup_child_host_view_ == this);
2275 popup_parent_host_view_->popup_child_host_view_ = NULL; 2251 popup_parent_host_view_->popup_child_host_view_ = NULL;
2276 } 2252 }
2277 if (popup_child_host_view_) { 2253 if (popup_child_host_view_) {
2278 DCHECK(popup_child_host_view_->popup_parent_host_view_ == NULL || 2254 DCHECK(popup_child_host_view_->popup_parent_host_view_ == NULL ||
2279 popup_child_host_view_->popup_parent_host_view_ == this); 2255 popup_child_host_view_->popup_parent_host_view_ == this);
2280 popup_child_host_view_->popup_parent_host_view_ = NULL; 2256 popup_child_host_view_->popup_parent_host_view_ = NULL;
2281 } 2257 }
2282 event_filter_for_popup_exit_.reset(); 2258 event_filter_for_popup_exit_.reset();
2283
2284 #if defined(OS_WIN)
2285 // The LegacyRenderWidgetHostHWND window should have been destroyed in
2286 // RenderWidgetHostViewAura::OnWindowDestroying and the pointer should
2287 // be set to NULL.
2288 DCHECK(!legacy_render_widget_host_HWND_);
2289 #endif
2290 } 2259 }
2291 2260
2292 void RenderWidgetHostViewAura::CreateAuraWindow() { 2261 void RenderWidgetHostViewAura::CreateAuraWindow() {
2293 DCHECK(!window_); 2262 DCHECK(!window_);
2294 window_ = new aura::Window(this); 2263 window_ = new aura::Window(this);
2295 window_observer_.reset(new WindowObserver(this)); 2264 window_observer_.reset(new WindowObserver(this));
2296 2265
2297 aura::client::SetTooltipText(window_, &tooltip_); 2266 aura::client::SetTooltipText(window_, &tooltip_);
2298 aura::client::SetActivationDelegate(window_, this); 2267 aura::client::SetActivationDelegate(window_, this);
2299 aura::client::SetFocusChangeObserver(window_, this); 2268 aura::client::SetFocusChangeObserver(window_, this);
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
2490 } 2459 }
2491 2460
2492 void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) { 2461 void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) {
2493 SnapToPhysicalPixelBoundary(); 2462 SnapToPhysicalPixelBoundary();
2494 // Don't recursively call SetBounds if this bounds update is the result of 2463 // Don't recursively call SetBounds if this bounds update is the result of
2495 // a Window::SetBoundsInternal call. 2464 // a Window::SetBoundsInternal call.
2496 if (!in_bounds_changed_) 2465 if (!in_bounds_changed_)
2497 window_->SetBounds(rect); 2466 window_->SetBounds(rect);
2498 host_->WasResized(); 2467 host_->WasResized();
2499 delegated_frame_host_->WasResized(); 2468 delegated_frame_host_->WasResized();
2469
2500 #if defined(OS_WIN) 2470 #if defined(OS_WIN)
2501 // Create the legacy dummy window which corresponds to the bounds of the
2502 // webcontents. It is needed for accessibility and for scrolling to work in
2503 // legacy drivers for trackpoints/trackpads, etc.
2504 if (!legacy_window_destroyed_ && GetHostWindowHWND()) {
2505 if (!legacy_render_widget_host_HWND_) {
2506 legacy_render_widget_host_HWND_ =
2507 LegacyRenderWidgetHostHWND::Create(GetHostWindowHWND());
2508 }
2509 if (legacy_render_widget_host_HWND_) {
2510 legacy_render_widget_host_HWND_->set_host(this);
2511 legacy_render_widget_host_HWND_->SetBounds(
2512 window_->GetBoundsInRootWindow());
2513 // There are cases where the parent window is created, made visible and
2514 // the associated RenderWidget is also visible before the
2515 // LegacyRenderWidgetHostHWND instace is created. Ensure that it is shown
2516 // here.
2517 if (!host_->is_hidden())
2518 legacy_render_widget_host_HWND_->Show();
2519 }
2520 }
2521
2522 if (mouse_locked_) 2471 if (mouse_locked_)
2523 UpdateMouseLockRegion(); 2472 UpdateMouseLockRegion();
2524 #endif 2473 #endif
2525 } 2474 }
2526 2475
2527 void RenderWidgetHostViewAura::SchedulePaintIfNotInClip( 2476 void RenderWidgetHostViewAura::SchedulePaintIfNotInClip(
2528 const gfx::Rect& rect, 2477 const gfx::Rect& rect,
2529 const gfx::Rect& clip) { 2478 const gfx::Rect& clip) {
2530 if (!clip.IsEmpty()) { 2479 if (!clip.IsEmpty()) {
2531 gfx::Rect to_paint = gfx::SubtractRects(rect, clip); 2480 gfx::Rect to_paint = gfx::SubtractRects(rect, clip);
(...skipping 25 matching lines...) Expand all
2557 if (cursor_client) { 2506 if (cursor_client) {
2558 cursor_client->AddObserver(this); 2507 cursor_client->AddObserver(this);
2559 NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible()); 2508 NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible());
2560 } 2509 }
2561 if (HasFocus()) { 2510 if (HasFocus()) {
2562 ui::InputMethod* input_method = GetInputMethod(); 2511 ui::InputMethod* input_method = GetInputMethod();
2563 if (input_method) 2512 if (input_method)
2564 input_method->SetFocusedTextInputClient(this); 2513 input_method->SetFocusedTextInputClient(this);
2565 } 2514 }
2566 2515
2567 #if defined(OS_WIN)
2568 // The parent may have changed here. Ensure that the legacy window is
2569 // reparented accordingly.
2570 if (legacy_render_widget_host_HWND_)
2571 legacy_render_widget_host_HWND_->UpdateParent(GetHostWindowHWND());
2572 #endif
2573
2574 delegated_frame_host_->SetCompositor(window_->GetHost()->compositor()); 2516 delegated_frame_host_->SetCompositor(window_->GetHost()->compositor());
2575 } 2517 }
2576 2518
2577 void RenderWidgetHostViewAura::RemovingFromRootWindow() { 2519 void RenderWidgetHostViewAura::RemovingFromRootWindow() {
2578 aura::client::CursorClient* cursor_client = 2520 aura::client::CursorClient* cursor_client =
2579 aura::client::GetCursorClient(window_->GetRootWindow()); 2521 aura::client::GetCursorClient(window_->GetRootWindow());
2580 if (cursor_client) 2522 if (cursor_client)
2581 cursor_client->RemoveObserver(this); 2523 cursor_client->RemoveObserver(this);
2582 2524
2583 DetachFromInputMethod(); 2525 DetachFromInputMethod();
2584 2526
2585 window_->GetHost()->RemoveObserver(this); 2527 window_->GetHost()->RemoveObserver(this);
2586 delegated_frame_host_->ResetCompositor(); 2528 delegated_frame_host_->ResetCompositor();
2587
2588 #if defined(OS_WIN)
2589 // Update the legacy window's parent temporarily to the desktop window. It
2590 // will eventually get reparented to the right root.
2591 if (legacy_render_widget_host_HWND_)
2592 legacy_render_widget_host_HWND_->UpdateParent(::GetDesktopWindow());
2593 #endif
2594 } 2529 }
2595 2530
2596 void RenderWidgetHostViewAura::DetachFromInputMethod() { 2531 void RenderWidgetHostViewAura::DetachFromInputMethod() {
2597 ui::InputMethod* input_method = GetInputMethod(); 2532 ui::InputMethod* input_method = GetInputMethod();
2598 if (input_method) 2533 if (input_method)
2599 input_method->DetachTextInputClient(this); 2534 input_method->DetachTextInputClient(this);
2600 } 2535 }
2601 2536
2602 void RenderWidgetHostViewAura::ForwardKeyboardEvent( 2537 void RenderWidgetHostViewAura::ForwardKeyboardEvent(
2603 const NativeWebKeyboardEvent& event) { 2538 const NativeWebKeyboardEvent& event) {
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after
2865 2800
2866 //////////////////////////////////////////////////////////////////////////////// 2801 ////////////////////////////////////////////////////////////////////////////////
2867 // RenderWidgetHostViewBase, public: 2802 // RenderWidgetHostViewBase, public:
2868 2803
2869 // static 2804 // static
2870 void RenderWidgetHostViewBase::GetDefaultScreenInfo(WebScreenInfo* results) { 2805 void RenderWidgetHostViewBase::GetDefaultScreenInfo(WebScreenInfo* results) {
2871 GetScreenInfoForWindow(results, NULL); 2806 GetScreenInfoForWindow(results, NULL);
2872 } 2807 }
2873 2808
2874 } // namespace content 2809 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/renderer_host/render_widget_host_view_aura.h ('k') | content/browser/web_contents/web_contents_view_aura.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698