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

Side by Side Diff: content/browser/browser_plugin/browser_plugin_guest.cc

Issue 291483010: <webview>: Move name attribute to chrome (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@newwindow_refactor
Patch Set: Addressed John's comments Created 6 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/browser_plugin/browser_plugin_guest.h" 5 #include "content/browser/browser_plugin/browser_plugin_guest.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/message_loop/message_loop.h" 9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_util.h" 10 #include "base/strings/string_util.h"
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck) 180 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
181 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_NavigateGuest, OnNavigateGuest) 181 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_NavigateGuest, OnNavigateGuest)
182 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_PluginDestroyed, OnPluginDestroyed) 182 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_PluginDestroyed, OnPluginDestroyed)
183 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources, 183 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
184 OnReclaimCompositorResources) 184 OnReclaimCompositorResources)
185 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest) 185 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest)
186 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetAutoSize, OnSetSize) 186 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetAutoSize, OnSetSize)
187 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent, 187 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
188 OnSetEditCommandsForNextKeyEvent) 188 OnSetEditCommandsForNextKeyEvent)
189 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus) 189 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
190 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetName, OnSetName)
191 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetContentsOpaque, 190 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetContentsOpaque,
192 OnSetContentsOpaque) 191 OnSetContentsOpaque)
193 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility) 192 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
194 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck) 193 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
195 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry) 194 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
196 IPC_MESSAGE_UNHANDLED(handled = false) 195 IPC_MESSAGE_UNHANDLED(handled = false)
197 IPC_END_MESSAGE_MAP() 196 IPC_END_MESSAGE_MAP()
198 return handled; 197 return handled;
199 } 198 }
200 199
201 void BrowserPluginGuest::Initialize( 200 void BrowserPluginGuest::Initialize(
202 const BrowserPluginHostMsg_Attach_Params& params, 201 const BrowserPluginHostMsg_Attach_Params& params,
203 WebContentsImpl* embedder_web_contents) { 202 WebContentsImpl* embedder_web_contents) {
204 focused_ = params.focused; 203 focused_ = params.focused;
205 guest_visible_ = params.visible; 204 guest_visible_ = params.visible;
206 guest_opaque_ = params.opaque; 205 guest_opaque_ = params.opaque;
207 guest_window_rect_ = params.resize_guest_params.view_rect; 206 guest_window_rect_ = params.resize_guest_params.view_rect;
208 207
209 if (!params.name.empty())
210 name_ = params.name;
211 auto_size_enabled_ = params.auto_size_params.enable; 208 auto_size_enabled_ = params.auto_size_params.enable;
212 max_auto_size_ = params.auto_size_params.max_size; 209 max_auto_size_ = params.auto_size_params.max_size;
213 min_auto_size_ = params.auto_size_params.min_size; 210 min_auto_size_ = params.auto_size_params.min_size;
214 211
215 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to 212 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
216 // be attached. 213 // be attached.
217 embedder_web_contents_ = embedder_web_contents; 214 embedder_web_contents_ = embedder_web_contents;
218 215
219 WebContentsViewGuest* new_view = 216 WebContentsViewGuest* new_view =
220 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView()); 217 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 } 271 }
275 272
276 // Inform the embedder of the guest's information. 273 // Inform the embedder of the guest's information.
277 // We pull the partition information from the site's URL, which is of the form 274 // We pull the partition information from the site's URL, which is of the form
278 // guest://site/{persist}?{partition_name}. 275 // guest://site/{persist}?{partition_name}.
279 const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL(); 276 const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL();
280 BrowserPluginMsg_Attach_ACK_Params ack_params; 277 BrowserPluginMsg_Attach_ACK_Params ack_params;
281 ack_params.storage_partition_id = site_url.query(); 278 ack_params.storage_partition_id = site_url.query();
282 ack_params.persist_storage = 279 ack_params.persist_storage =
283 site_url.path().find("persist") != std::string::npos; 280 site_url.path().find("persist") != std::string::npos;
284 ack_params.name = name_;
285 SendMessageToEmbedder( 281 SendMessageToEmbedder(
286 new BrowserPluginMsg_Attach_ACK(instance_id_, ack_params)); 282 new BrowserPluginMsg_Attach_ACK(instance_id_, ack_params));
287 283
288 if (delegate_) 284 if (delegate_)
289 delegate_->DidAttach(); 285 delegate_->DidAttach();
290 } 286 }
291 287
292 BrowserPluginGuest::~BrowserPluginGuest() { 288 BrowserPluginGuest::~BrowserPluginGuest() {
293 while (!pending_messages_.empty()) { 289 while (!pending_messages_.empty()) {
294 delete pending_messages_.front(); 290 delete pending_messages_.front();
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 if (!delegate_) 475 if (!delegate_)
480 return NULL; 476 return NULL;
481 return delegate_->OpenURLFromTab(source, params); 477 return delegate_->OpenURLFromTab(source, params);
482 } 478 }
483 479
484 void BrowserPluginGuest::WebContentsCreated(WebContents* source_contents, 480 void BrowserPluginGuest::WebContentsCreated(WebContents* source_contents,
485 int opener_render_frame_id, 481 int opener_render_frame_id,
486 const base::string16& frame_name, 482 const base::string16& frame_name,
487 const GURL& target_url, 483 const GURL& target_url,
488 WebContents* new_contents) { 484 WebContents* new_contents) {
489 WebContentsImpl* new_contents_impl =
490 static_cast<WebContentsImpl*>(new_contents);
491 BrowserPluginGuest* guest = new_contents_impl->GetBrowserPluginGuest();
492 std::string guest_name = base::UTF16ToUTF8(frame_name);
493 guest->name_ = guest_name;
494
495 if (!delegate_) 485 if (!delegate_)
496 return; 486 return;
497 487
498 delegate_->WebContentsCreated(source_contents, 488 delegate_->WebContentsCreated(source_contents,
499 opener_render_frame_id, 489 opener_render_frame_id,
500 frame_name, 490 frame_name,
501 target_url, 491 target_url,
502 new_contents); 492 new_contents);
503 } 493 }
504 494
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
617 CHECK(rvh->GetProcess()->IsGuest()); 607 CHECK(rvh->GetProcess()->IsGuest());
618 // TODO(fsamuel): Investigate whether it's possible to update state earlier 608 // TODO(fsamuel): Investigate whether it's possible to update state earlier
619 // here (see http://crbug.com/158151). 609 // here (see http://crbug.com/158151).
620 Send(new InputMsg_SetFocus(routing_id(), focused_)); 610 Send(new InputMsg_SetFocus(routing_id(), focused_));
621 UpdateVisibility(); 611 UpdateVisibility();
622 if (auto_size_enabled_) 612 if (auto_size_enabled_)
623 rvh->EnableAutoResize(min_auto_size_, max_auto_size_); 613 rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
624 else 614 else
625 rvh->DisableAutoResize(full_size_); 615 rvh->DisableAutoResize(full_size_);
626 616
627 Send(new ViewMsg_SetName(routing_id(), name_));
628 OnSetContentsOpaque(instance_id_, guest_opaque_); 617 OnSetContentsOpaque(instance_id_, guest_opaque_);
629 618
630 RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay_ms( 619 RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay_ms(
631 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)); 620 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs));
632 } 621 }
633 622
634 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) { 623 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
635 SendMessageToEmbedder(new BrowserPluginMsg_GuestGone(instance_id())); 624 SendMessageToEmbedder(new BrowserPluginMsg_GuestGone(instance_id()));
636 switch (status) { 625 switch (status) {
637 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: 626 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
(...skipping 26 matching lines...) Expand all
664 case BrowserPluginHostMsg_ImeConfirmComposition::ID: 653 case BrowserPluginHostMsg_ImeConfirmComposition::ID:
665 case BrowserPluginHostMsg_ImeSetComposition::ID: 654 case BrowserPluginHostMsg_ImeSetComposition::ID:
666 case BrowserPluginHostMsg_LockMouse_ACK::ID: 655 case BrowserPluginHostMsg_LockMouse_ACK::ID:
667 case BrowserPluginHostMsg_NavigateGuest::ID: 656 case BrowserPluginHostMsg_NavigateGuest::ID:
668 case BrowserPluginHostMsg_PluginDestroyed::ID: 657 case BrowserPluginHostMsg_PluginDestroyed::ID:
669 case BrowserPluginHostMsg_ReclaimCompositorResources::ID: 658 case BrowserPluginHostMsg_ReclaimCompositorResources::ID:
670 case BrowserPluginHostMsg_ResizeGuest::ID: 659 case BrowserPluginHostMsg_ResizeGuest::ID:
671 case BrowserPluginHostMsg_SetAutoSize::ID: 660 case BrowserPluginHostMsg_SetAutoSize::ID:
672 case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID: 661 case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID:
673 case BrowserPluginHostMsg_SetFocus::ID: 662 case BrowserPluginHostMsg_SetFocus::ID:
674 case BrowserPluginHostMsg_SetName::ID:
675 case BrowserPluginHostMsg_SetContentsOpaque::ID: 663 case BrowserPluginHostMsg_SetContentsOpaque::ID:
676 case BrowserPluginHostMsg_SetVisibility::ID: 664 case BrowserPluginHostMsg_SetVisibility::ID:
677 case BrowserPluginHostMsg_UnlockMouse_ACK::ID: 665 case BrowserPluginHostMsg_UnlockMouse_ACK::ID:
678 case BrowserPluginHostMsg_UpdateGeometry::ID: 666 case BrowserPluginHostMsg_UpdateGeometry::ID:
679 return true; 667 return true;
680 default: 668 default:
681 return false; 669 return false;
682 } 670 }
683 } 671 }
684 672
(...skipping 14 matching lines...) Expand all
699 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus) 687 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
700 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged, 688 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged,
701 OnTextInputTypeChanged) 689 OnTextInputTypeChanged)
702 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCancelComposition, 690 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCancelComposition,
703 OnImeCancelComposition) 691 OnImeCancelComposition)
704 #if defined(OS_MACOSX) || defined(USE_AURA) 692 #if defined(OS_MACOSX) || defined(USE_AURA)
705 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCompositionRangeChanged, 693 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCompositionRangeChanged,
706 OnImeCompositionRangeChanged) 694 OnImeCompositionRangeChanged)
707 #endif 695 #endif
708 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse) 696 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
709 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFrameName, OnUpdateFrameName)
710 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect) 697 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect)
711 IPC_MESSAGE_UNHANDLED(handled = false) 698 IPC_MESSAGE_UNHANDLED(handled = false)
712 IPC_END_MESSAGE_MAP() 699 IPC_END_MESSAGE_MAP()
713 return handled; 700 return handled;
714 } 701 }
715 702
716 void BrowserPluginGuest::Attach( 703 void BrowserPluginGuest::Attach(
717 WebContentsImpl* embedder_web_contents, 704 WebContentsImpl* embedder_web_contents,
718 BrowserPluginHostMsg_Attach_Params params, 705 BrowserPluginHostMsg_Attach_Params params,
719 const base::DictionaryValue& extra_params) { 706 const base::DictionaryValue& extra_params) {
720 if (attached()) 707 if (attached())
721 return; 708 return;
722 709
723 // Clear parameters that get inherited from the opener. 710 // Clear parameters that get inherited from the opener.
724 params.storage_partition_id.clear(); 711 params.storage_partition_id.clear();
725 params.persist_storage = false; 712 params.persist_storage = false;
726 params.src.clear(); 713 params.src.clear();
727 714
728 // If a RenderView has already been created for this new window, then we need 715 // If a RenderView has already been created for this new window, then we need
729 // to initialize the browser-side state now so that the RenderFrameHostManager 716 // to initialize the browser-side state now so that the RenderFrameHostManager
730 // does not create a new RenderView on navigation. 717 // does not create a new RenderView on navigation.
731 if (has_render_view_) { 718 if (has_render_view_) {
732 static_cast<RenderViewHostImpl*>( 719 static_cast<RenderViewHostImpl*>(
733 GetWebContents()->GetRenderViewHost())->Init(); 720 GetWebContents()->GetRenderViewHost())->Init();
734 WebContentsViewGuest* new_view = 721 WebContentsViewGuest* new_view =
735 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView()); 722 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
736 new_view->CreateViewForWidget(web_contents()->GetRenderViewHost()); 723 new_view->CreateViewForWidget(web_contents()->GetRenderViewHost());
737 } 724 }
738 725
739 // The guest's frame name takes precedence over the BrowserPlugin's name.
740 // The guest's frame name is assigned in
741 // BrowserPluginGuest::WebContentsCreated.
742 if (!name_.empty())
743 params.name.clear();
744
745 Initialize(params, embedder_web_contents); 726 Initialize(params, embedder_web_contents);
746 727
747 SendQueuedMessages(); 728 SendQueuedMessages();
748 729
749 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached")); 730 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
750 } 731 }
751 732
752 void BrowserPluginGuest::OnCompositorFrameSwappedACK( 733 void BrowserPluginGuest::OnCompositorFrameSwappedACK(
753 int instance_id, 734 int instance_id,
754 const FrameHostMsg_CompositorFrameSwappedACK_Params& params) { 735 const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
968 949
969 // Restore the last seen state of text input to the view. 950 // Restore the last seen state of text input to the view.
970 RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>( 951 RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
971 web_contents()->GetRenderWidgetHostView()); 952 web_contents()->GetRenderWidgetHostView());
972 if (rwhv) { 953 if (rwhv) {
973 rwhv->TextInputTypeChanged(last_text_input_type_, last_input_mode_, 954 rwhv->TextInputTypeChanged(last_text_input_type_, last_input_mode_,
974 last_can_compose_inline_); 955 last_can_compose_inline_);
975 } 956 }
976 } 957 }
977 958
978 void BrowserPluginGuest::OnSetName(int instance_id, const std::string& name) {
979 if (name == name_)
980 return;
981 name_ = name;
982 Send(new ViewMsg_SetName(routing_id(), name));
983 }
984
985 void BrowserPluginGuest::OnSetSize( 959 void BrowserPluginGuest::OnSetSize(
986 int instance_id, 960 int instance_id,
987 const BrowserPluginHostMsg_AutoSize_Params& auto_size_params, 961 const BrowserPluginHostMsg_AutoSize_Params& auto_size_params,
988 const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) { 962 const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) {
989 bool old_auto_size_enabled = auto_size_enabled_; 963 bool old_auto_size_enabled = auto_size_enabled_;
990 gfx::Size old_max_size = max_auto_size_; 964 gfx::Size old_max_size = max_auto_size_;
991 gfx::Size old_min_size = min_auto_size_; 965 gfx::Size old_min_size = min_auto_size_;
992 auto_size_enabled_ = auto_size_params.enable; 966 auto_size_enabled_ = auto_size_params.enable;
993 max_auto_size_ = auto_size_params.max_size; 967 max_auto_size_ = auto_size_params.max_size;
994 min_auto_size_ = auto_size_params.min_size; 968 min_auto_size_ = auto_size_params.min_size;
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
1100 void BrowserPluginGuest::OnShowWidget(int route_id, 1074 void BrowserPluginGuest::OnShowWidget(int route_id,
1101 const gfx::Rect& initial_pos) { 1075 const gfx::Rect& initial_pos) {
1102 GetWebContents()->ShowCreatedWidget(route_id, initial_pos); 1076 GetWebContents()->ShowCreatedWidget(route_id, initial_pos);
1103 } 1077 }
1104 1078
1105 void BrowserPluginGuest::OnTakeFocus(bool reverse) { 1079 void BrowserPluginGuest::OnTakeFocus(bool reverse) {
1106 SendMessageToEmbedder( 1080 SendMessageToEmbedder(
1107 new BrowserPluginMsg_AdvanceFocus(instance_id(), reverse)); 1081 new BrowserPluginMsg_AdvanceFocus(instance_id(), reverse));
1108 } 1082 }
1109 1083
1110 void BrowserPluginGuest::OnUpdateFrameName(int frame_id,
1111 bool is_top_level,
1112 const std::string& name) {
1113 if (!is_top_level)
1114 return;
1115
1116 name_ = name;
1117 SendMessageToEmbedder(new BrowserPluginMsg_UpdatedName(instance_id_, name));
1118 }
1119
1120 void BrowserPluginGuest::RequestMediaAccessPermission( 1084 void BrowserPluginGuest::RequestMediaAccessPermission(
1121 WebContents* web_contents, 1085 WebContents* web_contents,
1122 const MediaStreamRequest& request, 1086 const MediaStreamRequest& request,
1123 const MediaResponseCallback& callback) { 1087 const MediaResponseCallback& callback) {
1124 if (!delegate_) { 1088 if (!delegate_) {
1125 callback.Run(MediaStreamDevices(), 1089 callback.Run(MediaStreamDevices(),
1126 MEDIA_DEVICE_INVALID_STATE, 1090 MEDIA_DEVICE_INVALID_STATE,
1127 scoped_ptr<MediaStreamUI>()); 1091 scoped_ptr<MediaStreamUI>());
1128 return; 1092 return;
1129 } 1093 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1182 void BrowserPluginGuest::OnImeCompositionRangeChanged( 1146 void BrowserPluginGuest::OnImeCompositionRangeChanged(
1183 const gfx::Range& range, 1147 const gfx::Range& range,
1184 const std::vector<gfx::Rect>& character_bounds) { 1148 const std::vector<gfx::Rect>& character_bounds) {
1185 static_cast<RenderWidgetHostViewBase*>( 1149 static_cast<RenderWidgetHostViewBase*>(
1186 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged( 1150 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
1187 range, character_bounds); 1151 range, character_bounds);
1188 } 1152 }
1189 #endif 1153 #endif
1190 1154
1191 } // namespace content 1155 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/browser_plugin/browser_plugin_guest.h ('k') | content/common/browser_plugin/browser_plugin_messages.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698