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

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

Issue 23648014: cc: Move TextureMailbox::ReleaseCallback to SingleReleaseCallback. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: releasecallback: SingleReleaseCallback Created 7 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 | Annotate | Revision Log
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 "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/callback_helpers.h" 9 #include "base/callback_helpers.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 94
95 class MemoryHolder : public base::RefCounted<MemoryHolder> { 95 class MemoryHolder : public base::RefCounted<MemoryHolder> {
96 public: 96 public:
97 MemoryHolder(scoped_ptr<base::SharedMemory> shared_memory, 97 MemoryHolder(scoped_ptr<base::SharedMemory> shared_memory,
98 gfx::Size frame_size, 98 gfx::Size frame_size,
99 base::Callback<void()> callback) 99 base::Callback<void()> callback)
100 : shared_memory_(shared_memory.Pass()), 100 : shared_memory_(shared_memory.Pass()),
101 frame_size_(frame_size), 101 frame_size_(frame_size),
102 callback_(callback) {} 102 callback_(callback) {}
103 103
104 cc::TextureMailbox GetMailbox() { 104 void GetMailbox(cc::TextureMailbox* mailbox,
105 return cc::TextureMailbox( 105 scoped_ptr<cc::SingleReleaseCallback>* release_callback) {
106 shared_memory_.get(), 106 *mailbox = cc::TextureMailbox(shared_memory_.get(), frame_size_);
107 frame_size_, 107 *release_callback = cc::SingleReleaseCallback::Create(
108 base::Bind(ReleaseMailbox, make_scoped_refptr(this))); 108 base::Bind(ReleaseMailbox, make_scoped_refptr(this)));
109 } 109 }
110 110
111 private: 111 private:
112 friend class base::RefCounted<MemoryHolder>; 112 friend class base::RefCounted<MemoryHolder>;
113 ~MemoryHolder() { callback_.Run(); } 113 ~MemoryHolder() { callback_.Run(); }
114 114
115 scoped_ptr<base::SharedMemory> shared_memory_; 115 scoped_ptr<base::SharedMemory> shared_memory_;
116 gfx::Size frame_size_; 116 gfx::Size frame_size_;
117 base::Callback<void()> callback_; 117 base::Callback<void()> callback_;
(...skipping 1183 matching lines...) Expand 10 before | Expand all | Expand 10 after
1301 accelerated_compositing_state_changed_ = false; 1301 accelerated_compositing_state_changed_ = false;
1302 1302
1303 bool is_compositing_active = host_->is_accelerated_compositing_active(); 1303 bool is_compositing_active = host_->is_accelerated_compositing_active();
1304 if (is_compositing_active && current_surface_.get()) { 1304 if (is_compositing_active && current_surface_.get()) {
1305 window_->layer()->SetExternalTexture(current_surface_.get()); 1305 window_->layer()->SetExternalTexture(current_surface_.get());
1306 current_frame_size_ = ConvertSizeToDIP( 1306 current_frame_size_ = ConvertSizeToDIP(
1307 current_surface_->device_scale_factor(), current_surface_->size()); 1307 current_surface_->device_scale_factor(), current_surface_->size());
1308 CheckResizeLock(); 1308 CheckResizeLock();
1309 framebuffer_holder_ = NULL; 1309 framebuffer_holder_ = NULL;
1310 } else if (is_compositing_active && framebuffer_holder_) { 1310 } else if (is_compositing_active && framebuffer_holder_) {
1311 cc::TextureMailbox mailbox = framebuffer_holder_->GetMailbox(); 1311 cc::TextureMailbox mailbox;
1312 scoped_ptr<cc::SingleReleaseCallback> callback;
1313 framebuffer_holder_->GetMailbox(&mailbox, &callback);
1312 window_->layer()->SetTextureMailbox(mailbox, 1314 window_->layer()->SetTextureMailbox(mailbox,
1315 callback.Pass(),
1313 last_swapped_surface_scale_factor_); 1316 last_swapped_surface_scale_factor_);
1314 current_frame_size_ = ConvertSizeToDIP(last_swapped_surface_scale_factor_, 1317 current_frame_size_ = ConvertSizeToDIP(last_swapped_surface_scale_factor_,
1315 mailbox.shared_memory_size()); 1318 mailbox.shared_memory_size());
1316 CheckResizeLock(); 1319 CheckResizeLock();
1317 } else { 1320 } else {
1318 window_->layer()->SetExternalTexture(NULL); 1321 window_->layer()->SetExternalTexture(NULL);
1319 resize_lock_.reset(); 1322 resize_lock_.reset();
1320 host_->WasResized(); 1323 host_->WasResized();
1321 framebuffer_holder_ = NULL; 1324 framebuffer_holder_ = NULL;
1322 } 1325 }
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
1539 1542
1540 scoped_refptr<MemoryHolder> holder(new MemoryHolder( 1543 scoped_refptr<MemoryHolder> holder(new MemoryHolder(
1541 shared_memory.Pass(), 1544 shared_memory.Pass(),
1542 frame_size, 1545 frame_size,
1543 base::Bind(&RenderWidgetHostViewAura::SendSoftwareFrameAck, 1546 base::Bind(&RenderWidgetHostViewAura::SendSoftwareFrameAck,
1544 AsWeakPtr(), 1547 AsWeakPtr(),
1545 output_surface_id, 1548 output_surface_id,
1546 frame_data->id))); 1549 frame_data->id)));
1547 bool first_frame = !framebuffer_holder_; 1550 bool first_frame = !framebuffer_holder_;
1548 framebuffer_holder_.swap(holder); 1551 framebuffer_holder_.swap(holder);
1549 cc::TextureMailbox mailbox = framebuffer_holder_->GetMailbox(); 1552 cc::TextureMailbox mailbox;
1553 scoped_ptr<cc::SingleReleaseCallback> callback;
1554 framebuffer_holder_->GetMailbox(&mailbox, &callback);
1550 DCHECK(mailbox.IsSharedMemory()); 1555 DCHECK(mailbox.IsSharedMemory());
1551 current_frame_size_ = frame_size_in_dip; 1556 current_frame_size_ = frame_size_in_dip;
1552 1557
1553 released_front_lock_ = NULL; 1558 released_front_lock_ = NULL;
1554 CheckResizeLock(); 1559 CheckResizeLock();
1555 window_->layer()->SetTextureMailbox(mailbox, frame_device_scale_factor); 1560 window_->layer()->SetTextureMailbox(mailbox,
1561 callback.Pass(),
1562 frame_device_scale_factor);
1556 window_->SchedulePaintInRect( 1563 window_->SchedulePaintInRect(
1557 ConvertRectToDIP(frame_device_scale_factor, damage_rect)); 1564 ConvertRectToDIP(frame_device_scale_factor, damage_rect));
1558 1565
1559 ui::Compositor* compositor = GetCompositor(); 1566 ui::Compositor* compositor = GetCompositor();
1560 if (compositor) { 1567 if (compositor) {
1561 compositor->SetLatencyInfo(latency_info); 1568 compositor->SetLatencyInfo(latency_info);
1562 if (first_frame) { 1569 if (first_frame) {
1563 // Send swap for first frame, because no frame will be released due to 1570 // Send swap for first frame, because no frame will be released due to
1564 // that. 1571 // that.
1565 AddOnCommitCallbackAndDisableLocks( 1572 AddOnCommitCallbackAndDisableLocks(
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
1780 PrepareTextureCopyOutputResult(dst_size_in_pixel, callback, result.Pass()); 1787 PrepareTextureCopyOutputResult(dst_size_in_pixel, callback, result.Pass());
1781 return; 1788 return;
1782 } 1789 }
1783 1790
1784 DCHECK(result->HasBitmap()); 1791 DCHECK(result->HasBitmap());
1785 PrepareBitmapCopyOutputResult(dst_size_in_pixel, callback, result.Pass()); 1792 PrepareBitmapCopyOutputResult(dst_size_in_pixel, callback, result.Pass());
1786 } 1793 }
1787 1794
1788 static void CopyFromCompositingSurfaceFinished( 1795 static void CopyFromCompositingSurfaceFinished(
1789 const base::Callback<void(bool, const SkBitmap&)>& callback, 1796 const base::Callback<void(bool, const SkBitmap&)>& callback,
1790 const cc::TextureMailbox::ReleaseCallback& release_callback, 1797 scoped_ptr<cc::SingleReleaseCallback> release_callback,
1791 scoped_ptr<SkBitmap> bitmap, 1798 scoped_ptr<SkBitmap> bitmap,
1792 scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock, 1799 scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
1793 bool result) { 1800 bool result) {
1794 bitmap_pixels_lock.reset(); 1801 bitmap_pixels_lock.reset();
1795 release_callback.Run(0, false); 1802 release_callback->Run(0, false);
1796 callback.Run(result, *bitmap); 1803 callback.Run(result, *bitmap);
1797 } 1804 }
1798 1805
1799 // static 1806 // static
1800 void RenderWidgetHostViewAura::PrepareTextureCopyOutputResult( 1807 void RenderWidgetHostViewAura::PrepareTextureCopyOutputResult(
1801 const gfx::Size& dst_size_in_pixel, 1808 const gfx::Size& dst_size_in_pixel,
1802 const base::Callback<void(bool, const SkBitmap&)>& callback, 1809 const base::Callback<void(bool, const SkBitmap&)>& callback,
1803 scoped_ptr<cc::CopyOutputResult> result) { 1810 scoped_ptr<cc::CopyOutputResult> result) {
1804 base::ScopedClosureRunner scoped_callback_runner( 1811 base::ScopedClosureRunner scoped_callback_runner(
1805 base::Bind(callback, false, SkBitmap())); 1812 base::Bind(callback, false, SkBitmap()));
(...skipping 11 matching lines...) Expand all
1817 1824
1818 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); 1825 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
1819 GLHelper* gl_helper = factory->GetGLHelper(); 1826 GLHelper* gl_helper = factory->GetGLHelper();
1820 if (!gl_helper) 1827 if (!gl_helper)
1821 return; 1828 return;
1822 1829
1823 scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock( 1830 scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock(
1824 new SkAutoLockPixels(*bitmap)); 1831 new SkAutoLockPixels(*bitmap));
1825 uint8* pixels = static_cast<uint8*>(bitmap->getPixels()); 1832 uint8* pixels = static_cast<uint8*>(bitmap->getPixels());
1826 1833
1827 scoped_ptr<cc::TextureMailbox> texture_mailbox = result->TakeTexture(); 1834 cc::TextureMailbox texture_mailbox;
1828 DCHECK(texture_mailbox->IsTexture()); 1835 scoped_ptr<cc::SingleReleaseCallback> release_callback;
1829 if (!texture_mailbox->IsTexture()) 1836 result->TakeTexture(&texture_mailbox, &release_callback);
1837 DCHECK(texture_mailbox.IsTexture());
1838 if (!texture_mailbox.IsTexture())
1830 return; 1839 return;
1831 1840
1832 ignore_result(scoped_callback_runner.Release()); 1841 ignore_result(scoped_callback_runner.Release());
1833 1842
1834 gl_helper->CropScaleReadbackAndCleanMailbox( 1843 gl_helper->CropScaleReadbackAndCleanMailbox(
1835 texture_mailbox->name(), 1844 texture_mailbox.name(),
1836 texture_mailbox->sync_point(), 1845 texture_mailbox.sync_point(),
1837 result->size(), 1846 result->size(),
1838 gfx::Rect(result->size()), 1847 gfx::Rect(result->size()),
1839 dst_size_in_pixel, 1848 dst_size_in_pixel,
1840 pixels, 1849 pixels,
1841 base::Bind(&CopyFromCompositingSurfaceFinished, 1850 base::Bind(&CopyFromCompositingSurfaceFinished,
1842 callback, 1851 callback,
1843 texture_mailbox->callback(), 1852 base::Passed(&release_callback),
1844 base::Passed(&bitmap), 1853 base::Passed(&bitmap),
1845 base::Passed(&bitmap_pixels_lock))); 1854 base::Passed(&bitmap_pixels_lock)));
1846 } 1855 }
1847 1856
1848 // static 1857 // static
1849 void RenderWidgetHostViewAura::PrepareBitmapCopyOutputResult( 1858 void RenderWidgetHostViewAura::PrepareBitmapCopyOutputResult(
1850 const gfx::Size& dst_size_in_pixel, 1859 const gfx::Size& dst_size_in_pixel,
1851 const base::Callback<void(bool, const SkBitmap&)>& callback, 1860 const base::Callback<void(bool, const SkBitmap&)>& callback,
1852 scoped_ptr<cc::CopyOutputResult> result) { 1861 scoped_ptr<cc::CopyOutputResult> result) {
1853 DCHECK(result->HasBitmap()); 1862 DCHECK(result->HasBitmap());
(...skipping 13 matching lines...) Expand all
1867 SkBitmap bitmap = skia::ImageOperations::Resize( 1876 SkBitmap bitmap = skia::ImageOperations::Resize(
1868 *source, 1877 *source,
1869 skia::ImageOperations::RESIZE_BEST, 1878 skia::ImageOperations::RESIZE_BEST,
1870 dst_size_in_pixel.width(), 1879 dst_size_in_pixel.width(),
1871 dst_size_in_pixel.height()); 1880 dst_size_in_pixel.height());
1872 callback.Run(true, bitmap); 1881 callback.Run(true, bitmap);
1873 } 1882 }
1874 1883
1875 static void CopyFromCompositingSurfaceFinishedForVideo( 1884 static void CopyFromCompositingSurfaceFinishedForVideo(
1876 const base::Callback<void(bool)>& callback, 1885 const base::Callback<void(bool)>& callback,
1877 const cc::TextureMailbox::ReleaseCallback& release_callback, 1886 scoped_ptr<cc::SingleReleaseCallback> release_callback,
1878 bool result) { 1887 bool result) {
1879 release_callback.Run(0, false); 1888 release_callback->Run(0, false);
1880 callback.Run(result); 1889 callback.Run(result);
1881 } 1890 }
1882 1891
1883 // static 1892 // static
1884 void RenderWidgetHostViewAura::CopyFromCompositingSurfaceHasResultForVideo( 1893 void RenderWidgetHostViewAura::CopyFromCompositingSurfaceHasResultForVideo(
1885 base::WeakPtr<RenderWidgetHostViewAura> rwhva, 1894 base::WeakPtr<RenderWidgetHostViewAura> rwhva,
1886 scoped_refptr<media::VideoFrame> video_frame, 1895 scoped_refptr<media::VideoFrame> video_frame,
1887 const base::Callback<void(bool)>& callback, 1896 const base::Callback<void(bool)>& callback,
1888 scoped_ptr<cc::CopyOutputResult> result) { 1897 scoped_ptr<cc::CopyOutputResult> result) {
1889 base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false)); 1898 base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false));
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1942 ignore_result(scoped_callback_runner.Release()); 1951 ignore_result(scoped_callback_runner.Release());
1943 callback.Run(true); 1952 callback.Run(true);
1944 return; 1953 return;
1945 } 1954 }
1946 1955
1947 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); 1956 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
1948 GLHelper* gl_helper = factory->GetGLHelper(); 1957 GLHelper* gl_helper = factory->GetGLHelper();
1949 if (!gl_helper) 1958 if (!gl_helper)
1950 return; 1959 return;
1951 1960
1952 scoped_ptr<cc::TextureMailbox> texture_mailbox = result->TakeTexture(); 1961 cc::TextureMailbox texture_mailbox;
1953 DCHECK(texture_mailbox->IsTexture()); 1962 scoped_ptr<cc::SingleReleaseCallback> release_callback;
1954 if (!texture_mailbox->IsTexture()) 1963 result->TakeTexture(&texture_mailbox, &release_callback);
1964 DCHECK(texture_mailbox.IsTexture());
1965 if (!texture_mailbox.IsTexture())
1955 return; 1966 return;
1956 1967
1957 gfx::Rect result_rect(result->size()); 1968 gfx::Rect result_rect(result->size());
1958 1969
1959 content::ReadbackYUVInterface* yuv_readback_pipeline = 1970 content::ReadbackYUVInterface* yuv_readback_pipeline =
1960 rwhva->yuv_readback_pipeline_.get(); 1971 rwhva->yuv_readback_pipeline_.get();
1961 if (yuv_readback_pipeline == NULL || 1972 if (yuv_readback_pipeline == NULL ||
1962 yuv_readback_pipeline->scaler()->SrcSize() != result_rect.size() || 1973 yuv_readback_pipeline->scaler()->SrcSize() != result_rect.size() ||
1963 yuv_readback_pipeline->scaler()->SrcSubrect() != result_rect || 1974 yuv_readback_pipeline->scaler()->SrcSubrect() != result_rect ||
1964 yuv_readback_pipeline->scaler()->DstSize() != region_in_frame.size()) { 1975 yuv_readback_pipeline->scaler()->DstSize() != region_in_frame.size()) {
(...skipping 21 matching lines...) Expand all
1986 region_in_frame, 1997 region_in_frame,
1987 true, 1998 true,
1988 false)); 1999 false));
1989 yuv_readback_pipeline = rwhva->yuv_readback_pipeline_.get(); 2000 yuv_readback_pipeline = rwhva->yuv_readback_pipeline_.get();
1990 } 2001 }
1991 2002
1992 ignore_result(scoped_callback_runner.Release()); 2003 ignore_result(scoped_callback_runner.Release());
1993 base::Callback<void(bool result)> finished_callback = base::Bind( 2004 base::Callback<void(bool result)> finished_callback = base::Bind(
1994 &CopyFromCompositingSurfaceFinishedForVideo, 2005 &CopyFromCompositingSurfaceFinishedForVideo,
1995 callback, 2006 callback,
1996 texture_mailbox->callback()); 2007 base::Passed(&release_callback));
1997 yuv_readback_pipeline->ReadbackYUV( 2008 yuv_readback_pipeline->ReadbackYUV(
1998 texture_mailbox->name(), 2009 texture_mailbox.name(),
1999 texture_mailbox->sync_point(), 2010 texture_mailbox.sync_point(),
2000 video_frame.get(), 2011 video_frame.get(),
2001 finished_callback); 2012 finished_callback);
2002 } 2013 }
2003 2014
2004 void RenderWidgetHostViewAura::GetScreenInfo(WebScreenInfo* results) { 2015 void RenderWidgetHostViewAura::GetScreenInfo(WebScreenInfo* results) {
2005 GetScreenInfoForWindow(results, window_->GetRootWindow() ? window_ : NULL); 2016 GetScreenInfoForWindow(results, window_->GetRootWindow() ? window_ : NULL);
2006 } 2017 }
2007 2018
2008 gfx::Rect RenderWidgetHostViewAura::GetBoundsInRootWindow() { 2019 gfx::Rect RenderWidgetHostViewAura::GetBoundsInRootWindow() {
2009 return window_->GetToplevelWindow()->GetBoundsInScreen(); 2020 return window_->GetToplevelWindow()->GetBoundsInScreen();
(...skipping 520 matching lines...) Expand 10 before | Expand all | Expand 10 after
2530 } else if (old_mailbox.IsSharedMemory()) { 2541 } else if (old_mailbox.IsSharedMemory()) {
2531 base::SharedMemory* old_buffer = old_mailbox.shared_memory(); 2542 base::SharedMemory* old_buffer = old_mailbox.shared_memory();
2532 const size_t size = old_mailbox.shared_memory_size_in_bytes(); 2543 const size_t size = old_mailbox.shared_memory_size_in_bytes();
2533 2544
2534 scoped_ptr<base::SharedMemory> new_buffer(new base::SharedMemory); 2545 scoped_ptr<base::SharedMemory> new_buffer(new base::SharedMemory);
2535 new_buffer->CreateAndMapAnonymous(size); 2546 new_buffer->CreateAndMapAnonymous(size);
2536 2547
2537 if (old_buffer->memory() && new_buffer->memory()) { 2548 if (old_buffer->memory() && new_buffer->memory()) {
2538 memcpy(new_buffer->memory(), old_buffer->memory(), size); 2549 memcpy(new_buffer->memory(), old_buffer->memory(), size);
2539 base::SharedMemory* new_buffer_raw_ptr = new_buffer.get(); 2550 base::SharedMemory* new_buffer_raw_ptr = new_buffer.get();
2540 cc::TextureMailbox::ReleaseCallback callback = 2551 scoped_ptr<cc::SingleReleaseCallback> callback =
2541 base::Bind(MailboxReleaseCallback, Passed(&new_buffer)); 2552 cc::SingleReleaseCallback::Create(base::Bind(MailboxReleaseCallback,
2553 Passed(&new_buffer)));
2542 cc::TextureMailbox new_mailbox(new_buffer_raw_ptr, 2554 cc::TextureMailbox new_mailbox(new_buffer_raw_ptr,
2543 old_mailbox.shared_memory_size(), 2555 old_mailbox.shared_memory_size());
2544 callback); 2556 new_layer->SetTextureMailbox(new_mailbox,
2545 new_layer->SetTextureMailbox(new_mailbox, mailbox_scale_factor); 2557 callback.Pass(),
2558 mailbox_scale_factor);
2546 } 2559 }
2547 } 2560 }
2548 // TODO(piman): handle delegated frames. 2561 // TODO(piman): handle delegated frames.
2549 } 2562 }
2550 2563
2551 //////////////////////////////////////////////////////////////////////////////// 2564 ////////////////////////////////////////////////////////////////////////////////
2552 // RenderWidgetHostViewAura, ui::EventHandler implementation: 2565 // RenderWidgetHostViewAura, ui::EventHandler implementation:
2553 2566
2554 void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) { 2567 void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) {
2555 TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnKeyEvent"); 2568 TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnKeyEvent");
(...skipping 746 matching lines...) Expand 10 before | Expand all | Expand 10 after
3302 RenderWidgetHost* widget) { 3315 RenderWidgetHost* widget) {
3303 return new RenderWidgetHostViewAura(widget); 3316 return new RenderWidgetHostViewAura(widget);
3304 } 3317 }
3305 3318
3306 // static 3319 // static
3307 void RenderWidgetHostViewPort::GetDefaultScreenInfo(WebScreenInfo* results) { 3320 void RenderWidgetHostViewPort::GetDefaultScreenInfo(WebScreenInfo* results) {
3308 GetScreenInfoForWindow(results, NULL); 3321 GetScreenInfoForWindow(results, NULL);
3309 } 3322 }
3310 3323
3311 } // namespace content 3324 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698