diff options
author | jamesr <jamesr@chromium.org> | 2014-09-11 22:49:13 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-12 05:51:10 +0000 |
commit | 2abb46fdc18d2110b443a9e570ea393e3b0a42c5 (patch) | |
tree | e53147118cc91471f189c516751b23a08507f099 | |
parent | 8176b73b02e137a3c06afb7382a0a277338cc5ea (diff) | |
download | chromium_src-2abb46fdc18d2110b443a9e570ea393e3b0a42c5.zip chromium_src-2abb46fdc18d2110b443a9e570ea393e3b0a42c5.tar.gz chromium_src-2abb46fdc18d2110b443a9e570ea393e3b0a42c5.tar.bz2 |
Compositor bindings for mojo html_viewer
This binds mojo's html_viewer to a compositor implementation that uses surfaces
to present. It reuses the bindings for the WebLayer* types in cc/blink and adds
a new implementation of blink::WebLayerTreeView that shares some things with
content/renderer/gpu/render_widget_compositor.cc but is distinct enough to be
its own class. Whenever the compositor resizes (and thus needs a new surface id)
it passes the surface id to the view manager client lib.
This also adds mojo bindings for a few new quad types that are used on the web.
We don't yet have support for video quad types, but we don't have the media
system hooked up to html_viewer yet either so these will not be generated.
Review URL: https://codereview.chromium.org/558343004
Cr-Commit-Position: refs/heads/master@{#294546}
17 files changed, 638 insertions, 73 deletions
diff --git a/mojo/cc/output_surface_mojo.cc b/mojo/cc/output_surface_mojo.cc index 05c6a84..37a4eb0 100644 --- a/mojo/cc/output_surface_mojo.cc +++ b/mojo/cc/output_surface_mojo.cc @@ -12,13 +12,17 @@ namespace mojo { OutputSurfaceMojo::OutputSurfaceMojo( + OutputSurfaceMojoClient* client, const scoped_refptr<cc::ContextProvider>& context_provider, SurfacePtr surface, uint32_t id_namespace) : cc::OutputSurface(context_provider), + output_surface_mojo_client_(client), surface_(surface.Pass()), id_allocator_(id_namespace) { surface_.set_client(this); + capabilities_.delegated_rendering = true; + capabilities_.max_frames_pending = 1; } OutputSurfaceMojo::~OutputSurfaceMojo() { @@ -37,6 +41,7 @@ void OutputSurfaceMojo::SwapBuffers(cc::CompositorFrame* frame) { surface_id_ = id_allocator_.GenerateId(); surface_->CreateSurface(SurfaceId::From(surface_id_), Size::From(frame_size)); + output_surface_mojo_client_->DidCreateSurface(surface_id_); surface_size_ = frame_size; } diff --git a/mojo/cc/output_surface_mojo.h b/mojo/cc/output_surface_mojo.h index fbde931..f5b98ae 100644 --- a/mojo/cc/output_surface_mojo.h +++ b/mojo/cc/output_surface_mojo.h @@ -12,12 +12,19 @@ namespace mojo { +class OutputSurfaceMojoClient { + public: + virtual ~OutputSurfaceMojoClient() {} + + virtual void DidCreateSurface(cc::SurfaceId id) = 0; +}; + class OutputSurfaceMojo : public cc::OutputSurface, public SurfaceClient { public: - OutputSurfaceMojo(const scoped_refptr<cc::ContextProvider>& context_provider, + OutputSurfaceMojo(OutputSurfaceMojoClient* client, + const scoped_refptr<cc::ContextProvider>& context_provider, SurfacePtr surface, uint32_t id_namespace); - virtual ~OutputSurfaceMojo(); // SurfaceClient implementation. virtual void ReturnResources(Array<ReturnedResourcePtr> resources) OVERRIDE; @@ -25,7 +32,11 @@ class OutputSurfaceMojo : public cc::OutputSurface, public SurfaceClient { // cc::OutputSurface implementation. virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE; + protected: + virtual ~OutputSurfaceMojo(); + private: + OutputSurfaceMojoClient* output_surface_mojo_client_; SurfacePtr surface_; cc::SurfaceIdAllocator id_allocator_; cc::SurfaceId surface_id_; diff --git a/mojo/mojo_services.gypi b/mojo/mojo_services.gypi index b9768b6..5bd1f82 100644 --- a/mojo/mojo_services.gypi +++ b/mojo/mojo_services.gypi @@ -8,6 +8,9 @@ 'target_name': 'mojo_html_viewer', 'type': 'loadable_module', 'dependencies': [ + '../cc/blink/cc_blink.gyp:cc_blink', + '../cc/cc.gyp:cc', + '../cc/cc.gyp:cc_surfaces', '../net/net.gyp:net', '../skia/skia.gyp:skia', '../third_party/WebKit/public/blink.gyp:blink', @@ -17,9 +20,12 @@ 'mojo_base.gyp:mojo_common_lib', 'mojo_base.gyp:mojo_cpp_bindings', 'mojo_base.gyp:mojo_utility', + 'mojo_cc_support', 'mojo_content_handler_bindings', + 'mojo_gpu_bindings', 'mojo_navigation_bindings', 'mojo_network_bindings', + 'mojo_surfaces_bindings', 'mojo_view_manager_lib', '<(mojo_system_for_loadable_module)', ], @@ -52,6 +58,8 @@ 'services/html_viewer/webthread_impl.h', 'services/html_viewer/weburlloader_impl.cc', 'services/html_viewer/weburlloader_impl.h', + 'services/html_viewer/weblayertreeview_impl.cc', + 'services/html_viewer/weblayertreeview_impl.h', ], }, { diff --git a/mojo/services/html_viewer/DEPS b/mojo/services/html_viewer/DEPS index d33f90d..c6be1b0 100644 --- a/mojo/services/html_viewer/DEPS +++ b/mojo/services/html_viewer/DEPS @@ -1,4 +1,6 @@ include_rules = [ + "+cc", + "+mojo/cc", "+mojo/services", "+net/base", "+skia", diff --git a/mojo/services/html_viewer/blink_platform_impl.cc b/mojo/services/html_viewer/blink_platform_impl.cc index 3db0faf..1d19b83 100644 --- a/mojo/services/html_viewer/blink_platform_impl.cc +++ b/mojo/services/html_viewer/blink_platform_impl.cc @@ -137,6 +137,14 @@ void BlinkPlatformImpl::callOnMainThread( main_loop_->PostTask(FROM_HERE, base::Bind(func, context)); } +bool BlinkPlatformImpl::isThreadedCompositingEnabled() { + return true; +} + +blink::WebCompositorSupport* BlinkPlatformImpl::compositorSupport() { + return &compositor_support_; +} + blink::WebScrollbarBehavior* BlinkPlatformImpl::scrollbarBehavior() { return &scrollbar_behavior_; } diff --git a/mojo/services/html_viewer/blink_platform_impl.h b/mojo/services/html_viewer/blink_platform_impl.h index 5aaf358..aeae757 100644 --- a/mojo/services/html_viewer/blink_platform_impl.h +++ b/mojo/services/html_viewer/blink_platform_impl.h @@ -9,6 +9,7 @@ #include "base/message_loop/message_loop.h" #include "base/threading/thread_local_storage.h" #include "base/timer/timer.h" +#include "cc/blink/web_compositor_support_impl.h" #include "mojo/services/html_viewer/webmimeregistry_impl.h" #include "mojo/services/html_viewer/webthemeengine_impl.h" #include "mojo/services/public/interfaces/network/network_service.mojom.h" @@ -37,6 +38,8 @@ class BlinkPlatformImpl : public blink::Platform { virtual void setSharedTimerFireInterval(double interval_seconds); virtual void stopSharedTimer(); virtual void callOnMainThread(void (*func)(void*), void* context); + virtual bool isThreadedCompositingEnabled(); + virtual blink::WebCompositorSupport* compositorSupport(); virtual blink::WebURLLoader* createURLLoader(); virtual blink::WebSocketHandle* createWebSocketHandle(); virtual blink::WebString userAgent(); @@ -72,6 +75,7 @@ class BlinkPlatformImpl : public blink::Platform { bool shared_timer_fire_time_was_set_while_suspended_; int shared_timer_suspended_; // counter base::ThreadLocalStorage::Slot current_thread_slot_; + cc_blink::WebCompositorSupportImpl compositor_support_; WebThemeEngineImpl theme_engine_; scoped_ptr<WebCookieJarImpl> cookie_jar_; WebMimeRegistryImpl mime_registry_; diff --git a/mojo/services/html_viewer/html_document_view.cc b/mojo/services/html_viewer/html_document_view.cc index d0c48f8..8bdd501 100644 --- a/mojo/services/html_viewer/html_document_view.cc +++ b/mojo/services/html_viewer/html_document_view.cc @@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/location.h" +#include "base/message_loop/message_loop_proxy.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_util.h" #include "base/thread_task_runner_handle.h" @@ -15,9 +16,11 @@ #include "mojo/public/interfaces/application/shell.mojom.h" #include "mojo/services/html_viewer/blink_input_events_type_converters.h" #include "mojo/services/html_viewer/blink_url_request_type_converters.h" +#include "mojo/services/html_viewer/weblayertreeview_impl.h" #include "mojo/services/html_viewer/webstoragenamespace_impl.h" #include "mojo/services/html_viewer/weburlloader_impl.h" #include "mojo/services/public/cpp/view_manager/view.h" +#include "mojo/services/public/interfaces/surfaces/surfaces_service.mojom.h" #include "skia/ext/refptr.h" #include "third_party/WebKit/public/platform/Platform.h" #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h" @@ -37,7 +40,6 @@ namespace mojo { namespace { void ConfigureSettings(blink::WebSettings* settings) { - settings->setAcceleratedCompositingEnabled(false); settings->setCookieEnabled(true); settings->setDefaultFixedFontSize(13); settings->setDefaultFontSize(16); @@ -84,12 +86,13 @@ bool CanNavigateLocally(blink::WebFrame* frame, HTMLDocumentView::HTMLDocumentView( URLResponsePtr response, InterfaceRequest<ServiceProvider> service_provider_request, - Shell* shell) + Shell* shell, + scoped_refptr<base::MessageLoopProxy> compositor_thread) : shell_(shell), web_view_(NULL), root_(NULL), view_manager_client_factory_(shell, this), - repaint_pending_(false), + compositor_thread_(compositor_thread), weak_factory_(this) { ServiceProviderImpl* exported_services = new ServiceProviderImpl(); exported_services->AddService(&view_manager_client_factory_); @@ -113,8 +116,9 @@ void HTMLDocumentView::OnEmbed( embedder_service_provider_ = embedder_service_provider.Pass(); navigator_host_.set_service_provider(embedder_service_provider_.get()); - root_->SetColor(SK_ColorCYAN); // Dummy background color. web_view_->resize(root_->bounds().size()); + web_layer_tree_view_impl_->setViewportSize(root_->bounds().size()); + web_layer_tree_view_impl_->set_view(root_); root_->AddObserver(this); } @@ -124,6 +128,7 @@ void HTMLDocumentView::OnViewManagerDisconnected(ViewManager* view_manager) { void HTMLDocumentView::Load(URLResponsePtr response) { web_view_ = blink::WebView::create(this); + web_layer_tree_view_impl_->set_widget(web_view_); ConfigureSettings(web_view_->settings()); web_view_->setMainFrame(blink::WebLocalFrame::create(this)); @@ -144,22 +149,25 @@ blink::WebStorageNamespace* HTMLDocumentView::createSessionStorageNamespace() { return new WebStorageNamespaceImpl(); } -void HTMLDocumentView::didInvalidateRect(const blink::WebRect& rect) { - if (!repaint_pending_) { - repaint_pending_ = true; - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&HTMLDocumentView::Repaint, weak_factory_.GetWeakPtr())); - } +void HTMLDocumentView::initializeLayerTreeView() { + ServiceProviderPtr surfaces_service_provider; + shell_->ConnectToApplication("mojo:mojo_surfaces_service", + Get(&surfaces_service_provider)); + InterfacePtr<SurfacesService> surfaces_service; + ConnectToService(surfaces_service_provider.get(), &surfaces_service); + + ServiceProviderPtr gpu_service_provider; + // TODO(jamesr): Should be mojo:mojo_gpu_service + shell_->ConnectToApplication("mojo:mojo_native_viewport_service", + Get(&gpu_service_provider)); + InterfacePtr<Gpu> gpu_service; + ConnectToService(gpu_service_provider.get(), &gpu_service); + web_layer_tree_view_impl_.reset(new WebLayerTreeViewImpl( + compositor_thread_, surfaces_service.Pass(), gpu_service.Pass())); } -bool HTMLDocumentView::allowsBrokenNullLayerTreeView() const { - // TODO(darin): Switch to using compositor bindings. - // - // NOTE: Note to Blink maintainers, feel free to break this code if it is the - // last NOT using compositor bindings and you want to delete this code path. - // - return true; +blink::WebLayerTreeView* HTMLDocumentView::layerTreeView() { + return web_layer_tree_view_impl_.get(); } blink::WebFrame* HTMLDocumentView::createChildFrame( @@ -231,24 +239,4 @@ void HTMLDocumentView::OnViewInputEvent(View* view, const EventPtr& event) { web_view_->handleInputEvent(*web_event); } -void HTMLDocumentView::Repaint() { - repaint_pending_ = false; - - if (!root_) - return; - - web_view_->animate(0.0); - web_view_->layout(); - - int width = web_view_->size().width; - int height = web_view_->size().height; - - skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(SkCanvas::NewRaster( - SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType))); - - web_view_->paint(canvas.get(), gfx::Rect(0, 0, width, height)); - - root_->SetContents(canvas->getDevice()->accessBitmap(false)); -} - } // namespace mojo diff --git a/mojo/services/html_viewer/html_document_view.h b/mojo/services/html_viewer/html_document_view.h index 3efd707..d033368 100644 --- a/mojo/services/html_viewer/html_document_view.h +++ b/mojo/services/html_viewer/html_document_view.h @@ -17,10 +17,15 @@ #include "third_party/WebKit/public/web/WebFrameClient.h" #include "third_party/WebKit/public/web/WebViewClient.h" +namespace base { +class MessageLoopProxy; +} + namespace mojo { class ViewManager; class View; +class WebLayerTreeViewImpl; // A view for a single HTML document. class HTMLDocumentView : public blink::WebViewClient, @@ -38,7 +43,8 @@ class HTMLDocumentView : public blink::WebViewClient, // |shell| is the Shell connection for this mojo::Application. HTMLDocumentView(URLResponsePtr response, InterfaceRequest<ServiceProvider> service_provider_request, - Shell* shell); + Shell* shell, + scoped_refptr<base::MessageLoopProxy> compositor_thread); virtual ~HTMLDocumentView(); private: @@ -46,8 +52,8 @@ class HTMLDocumentView : public blink::WebViewClient, virtual blink::WebStorageNamespace* createSessionStorageNamespace(); // WebWidgetClient methods: - virtual void didInvalidateRect(const blink::WebRect& rect); - virtual bool allowsBrokenNullLayerTreeView() const; + virtual void initializeLayerTreeView(); + virtual blink::WebLayerTreeView* layerTreeView(); // WebFrameClient methods: virtual blink::WebFrame* createChildFrame(blink::WebLocalFrame* parent, @@ -84,7 +90,6 @@ class HTMLDocumentView : public blink::WebViewClient, virtual void OnViewInputEvent(View* view, const EventPtr& event) OVERRIDE; void Load(URLResponsePtr response); - void Repaint(); URLResponsePtr response_; scoped_ptr<ServiceProvider> embedder_service_provider_; @@ -93,7 +98,8 @@ class HTMLDocumentView : public blink::WebViewClient, blink::WebView* web_view_; View* root_; ViewManagerClientFactory view_manager_client_factory_; - bool repaint_pending_; + scoped_ptr<WebLayerTreeViewImpl> web_layer_tree_view_impl_; + scoped_refptr<base::MessageLoopProxy> compositor_thread_; base::WeakPtrFactory<HTMLDocumentView> weak_factory_; DISALLOW_COPY_AND_ASSIGN(HTMLDocumentView); diff --git a/mojo/services/html_viewer/html_viewer.cc b/mojo/services/html_viewer/html_viewer.cc index e8b5c76..2a8e766 100644 --- a/mojo/services/html_viewer/html_viewer.cc +++ b/mojo/services/html_viewer/html_viewer.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/message_loop/message_loop.h" +#include "base/threading/thread.h" #include "mojo/public/c/system/main.h" #include "mojo/public/cpp/application/application_connection.h" #include "mojo/public/cpp/application/application_delegate.h" @@ -20,7 +21,9 @@ class HTMLViewer; class ContentHandlerImpl : public InterfaceImpl<ContentHandler> { public: - explicit ContentHandlerImpl(Shell* shell) : shell_(shell) {} + ContentHandlerImpl(Shell* shell, + scoped_refptr<base::MessageLoopProxy> compositor_thread) + : shell_(shell), compositor_thread_(compositor_thread) {} virtual ~ContentHandlerImpl() {} private: @@ -29,40 +32,51 @@ class ContentHandlerImpl : public InterfaceImpl<ContentHandler> { const mojo::String& url, URLResponsePtr response, InterfaceRequest<ServiceProvider> service_provider_request) OVERRIDE { - new HTMLDocumentView( - response.Pass(), service_provider_request.Pass(), shell_); + new HTMLDocumentView(response.Pass(), + service_provider_request.Pass(), + shell_, + compositor_thread_); } Shell* shell_; + scoped_refptr<base::MessageLoopProxy> compositor_thread_; DISALLOW_COPY_AND_ASSIGN(ContentHandlerImpl); }; -class HTMLViewer : public ApplicationDelegate { +class HTMLViewer : public ApplicationDelegate, + public InterfaceFactory<ContentHandler> { public: - HTMLViewer() {} + HTMLViewer() : compositor_thread_("compositor thread") {} virtual ~HTMLViewer() { blink::shutdown(); } private: // Overridden from ApplicationDelegate: virtual void Initialize(ApplicationImpl* app) OVERRIDE { - content_handler_factory_.reset( - new InterfaceFactoryImplWithContext<ContentHandlerImpl, Shell>( - app->shell())); + shell_ = app->shell(); blink_platform_impl_.reset(new BlinkPlatformImpl(app)); blink::initialize(blink_platform_impl_.get()); + compositor_thread_.Start(); } virtual bool ConfigureIncomingConnection(ApplicationConnection* connection) OVERRIDE { - connection->AddService(content_handler_factory_.get()); + connection->AddService(this); return true; } + // Overridden from InterfaceFactory<ContentHandler> + virtual void Create(ApplicationConnection* connection, + InterfaceRequest<ContentHandler> request) OVERRIDE { + BindToRequest( + new ContentHandlerImpl(shell_, compositor_thread_.message_loop_proxy()), + &request); + } + scoped_ptr<BlinkPlatformImpl> blink_platform_impl_; - scoped_ptr<InterfaceFactoryImplWithContext<ContentHandlerImpl, Shell> > - content_handler_factory_; + Shell* shell_; + base::Thread compositor_thread_; DISALLOW_COPY_AND_ASSIGN(HTMLViewer); }; diff --git a/mojo/services/html_viewer/weblayertreeview_impl.cc b/mojo/services/html_viewer/weblayertreeview_impl.cc new file mode 100644 index 0000000..3f8ff80 --- /dev/null +++ b/mojo/services/html_viewer/weblayertreeview_impl.cc @@ -0,0 +1,232 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/services/html_viewer/weblayertreeview_impl.h" + +#include "base/message_loop/message_loop_proxy.h" +#include "cc/blink/web_layer_impl.h" +#include "cc/layers/layer.h" +#include "cc/output/begin_frame_args.h" +#include "cc/trees/layer_tree_host.h" +#include "mojo/cc/context_provider_mojo.h" +#include "mojo/cc/output_surface_mojo.h" +#include "mojo/services/public/cpp/surfaces/surfaces_type_converters.h" +#include "mojo/services/public/cpp/view_manager/view.h" +#include "third_party/WebKit/public/web/WebWidget.h" + +namespace mojo { + +WebLayerTreeViewImpl::WebLayerTreeViewImpl( + scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy, + SurfacesServicePtr surfaces_service, + GpuPtr gpu_service) + : widget_(NULL), + view_(NULL), + surfaces_service_(surfaces_service.Pass()), + gpu_service_(gpu_service.Pass()), + main_thread_compositor_task_runner_(base::MessageLoopProxy::current()), + weak_factory_(this) { + main_thread_bound_weak_ptr_ = weak_factory_.GetWeakPtr(); + surfaces_service_->CreateSurfaceConnection( + base::Bind(&WebLayerTreeViewImpl::OnSurfaceConnectionCreated, + main_thread_bound_weak_ptr_)); + + cc::LayerTreeSettings settings; + + // For web contents, layer transforms should scale up the contents of layers + // to keep content always crisp when possible. + settings.layer_transforms_should_scale_layer_contents = true; + + cc::SharedBitmapManager* shared_bitmap_manager = NULL; + + layer_tree_host_ = + cc::LayerTreeHost::CreateThreaded(this, + shared_bitmap_manager, + settings, + base::MessageLoopProxy::current(), + compositor_message_loop_proxy); + DCHECK(layer_tree_host_); +} + +WebLayerTreeViewImpl::~WebLayerTreeViewImpl() { +} + +void WebLayerTreeViewImpl::WillBeginMainFrame(int frame_id) { +} + +void WebLayerTreeViewImpl::DidBeginMainFrame() { +} + +void WebLayerTreeViewImpl::BeginMainFrame(const cc::BeginFrameArgs& args) { + VLOG(2) << "WebLayerTreeViewImpl::BeginMainFrame"; + double frame_time_sec = (args.frame_time - base::TimeTicks()).InSecondsF(); + double deadline_sec = (args.deadline - base::TimeTicks()).InSecondsF(); + double interval_sec = args.interval.InSecondsF(); + blink::WebBeginFrameArgs web_begin_frame_args( + frame_time_sec, deadline_sec, interval_sec); + widget_->beginFrame(web_begin_frame_args); +} + +void WebLayerTreeViewImpl::Layout() { + widget_->layout(); +} + +void WebLayerTreeViewImpl::ApplyViewportDeltas( + const gfx::Vector2d& scroll_delta, + float page_scale, + float top_controls_delta) { + widget_->applyViewportDeltas(scroll_delta, page_scale, top_controls_delta); +} + +scoped_ptr<cc::OutputSurface> WebLayerTreeViewImpl::CreateOutputSurface( + bool fallback) { + return output_surface_.Pass(); +} + +void WebLayerTreeViewImpl::DidInitializeOutputSurface() { +} + +void WebLayerTreeViewImpl::WillCommit() { +} + +void WebLayerTreeViewImpl::DidCommit() { + widget_->didCommitFrameToCompositor(); +} + +void WebLayerTreeViewImpl::DidCommitAndDrawFrame() { +} + +void WebLayerTreeViewImpl::DidCompleteSwapBuffers() { +} + +void WebLayerTreeViewImpl::setSurfaceReady() { +} + +void WebLayerTreeViewImpl::setRootLayer(const blink::WebLayer& layer) { + layer_tree_host_->SetRootLayer( + static_cast<const cc_blink::WebLayerImpl*>(&layer)->layer()); +} + +void WebLayerTreeViewImpl::clearRootLayer() { + layer_tree_host_->SetRootLayer(scoped_refptr<cc::Layer>()); +} + +void WebLayerTreeViewImpl::setViewportSize( + const blink::WebSize& device_viewport_size) { + layer_tree_host_->SetViewportSize(device_viewport_size); +} + +blink::WebSize WebLayerTreeViewImpl::deviceViewportSize() const { + return layer_tree_host_->device_viewport_size(); +} + +void WebLayerTreeViewImpl::setDeviceScaleFactor(float device_scale_factor) { + layer_tree_host_->SetDeviceScaleFactor(device_scale_factor); +} + +float WebLayerTreeViewImpl::deviceScaleFactor() const { + return layer_tree_host_->device_scale_factor(); +} + +void WebLayerTreeViewImpl::setBackgroundColor(blink::WebColor color) { + layer_tree_host_->set_background_color(color); +} + +void WebLayerTreeViewImpl::setHasTransparentBackground( + bool has_transparent_background) { + layer_tree_host_->set_has_transparent_background(has_transparent_background); +} + +void WebLayerTreeViewImpl::setOverhangBitmap(const SkBitmap& bitmap) { + layer_tree_host_->SetOverhangBitmap(bitmap); +} + +void WebLayerTreeViewImpl::setVisible(bool visible) { + layer_tree_host_->SetVisible(visible); +} + +void WebLayerTreeViewImpl::setPageScaleFactorAndLimits(float page_scale_factor, + float minimum, + float maximum) { + layer_tree_host_->SetPageScaleFactorAndLimits( + page_scale_factor, minimum, maximum); +} + +void WebLayerTreeViewImpl::registerForAnimations(blink::WebLayer* layer) { + cc::Layer* cc_layer = static_cast<cc_blink::WebLayerImpl*>(layer)->layer(); + cc_layer->layer_animation_controller()->SetAnimationRegistrar( + layer_tree_host_->animation_registrar()); +} + +void WebLayerTreeViewImpl::registerViewportLayers( + const blink::WebLayer* pageScaleLayer, + const blink::WebLayer* innerViewportScrollLayer, + const blink::WebLayer* outerViewportScrollLayer) { + layer_tree_host_->RegisterViewportLayers( + static_cast<const cc_blink::WebLayerImpl*>(pageScaleLayer)->layer(), + static_cast<const cc_blink::WebLayerImpl*>(innerViewportScrollLayer) + ->layer(), + // The outer viewport layer will only exist when using pinch virtual + // viewports. + outerViewportScrollLayer ? static_cast<const cc_blink::WebLayerImpl*>( + outerViewportScrollLayer)->layer() + : NULL); +} + +void WebLayerTreeViewImpl::clearViewportLayers() { + layer_tree_host_->RegisterViewportLayers(scoped_refptr<cc::Layer>(), + scoped_refptr<cc::Layer>(), + scoped_refptr<cc::Layer>()); +} + +void WebLayerTreeViewImpl::startPageScaleAnimation( + const blink::WebPoint& destination, + bool use_anchor, + float new_page_scale, + double duration_sec) { + base::TimeDelta duration = base::TimeDelta::FromMicroseconds( + duration_sec * base::Time::kMicrosecondsPerSecond); + layer_tree_host_->StartPageScaleAnimation( + gfx::Vector2d(destination.x, destination.y), + use_anchor, + new_page_scale, + duration); +} + +void WebLayerTreeViewImpl::setNeedsAnimate() { + layer_tree_host_->SetNeedsAnimate(); +} + +bool WebLayerTreeViewImpl::commitRequested() const { + return layer_tree_host_->CommitRequested(); +} + +void WebLayerTreeViewImpl::finishAllRendering() { + layer_tree_host_->FinishAllRendering(); +} + +void WebLayerTreeViewImpl::OnSurfaceConnectionCreated(SurfacePtr surface, + uint32_t id_namespace) { + CommandBufferPtr cb; + gpu_service_->CreateOffscreenGLES2Context(Get(&cb)); + scoped_refptr<cc::ContextProvider> context_provider( + new ContextProviderMojo(cb.PassMessagePipe())); + output_surface_.reset(new OutputSurfaceMojo( + this, context_provider, surface.Pass(), id_namespace)); + layer_tree_host_->SetLayerTreeHostClientReady(); +} + +void WebLayerTreeViewImpl::DidCreateSurface(cc::SurfaceId id) { + main_thread_compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&WebLayerTreeViewImpl::DidCreateSurfaceOnMainThread, + main_thread_bound_weak_ptr_, + id)); +} + +void WebLayerTreeViewImpl::DidCreateSurfaceOnMainThread(cc::SurfaceId id) { + view_->SetSurfaceId(SurfaceId::From(id)); +} + +} // namespace mojo diff --git a/mojo/services/html_viewer/weblayertreeview_impl.h b/mojo/services/html_viewer/weblayertreeview_impl.h new file mode 100644 index 0000000..a90ed2f --- /dev/null +++ b/mojo/services/html_viewer/weblayertreeview_impl.h @@ -0,0 +1,132 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_SERVICES_HTML_VIEWER_WEBLAYERTREEVIEW_IMPL_H_ +#define MOJO_SERVICES_HTML_VIEWER_WEBLAYERTREEVIEW_IMPL_H_ + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "cc/trees/layer_tree_host_client.h" +#include "mojo/cc/output_surface_mojo.h" +#include "mojo/services/public/interfaces/gpu/gpu.mojom.h" +#include "mojo/services/public/interfaces/surfaces/surfaces_service.mojom.h" +#include "third_party/WebKit/public/platform/WebLayerTreeView.h" + +namespace base { +class MessageLoopProxy; +} + +namespace blink { +class WebWidget; +} + +namespace cc { +class LayerTreeHost; +} + +namespace mojo { +class View; + +class WebLayerTreeViewImpl : public blink::WebLayerTreeView, + public cc::LayerTreeHostClient, + public OutputSurfaceMojoClient { + public: + WebLayerTreeViewImpl( + scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy, + SurfacesServicePtr surfaces_service, + GpuPtr gpu_service); + virtual ~WebLayerTreeViewImpl(); + + void set_widget(blink::WebWidget* widget) { widget_ = widget; } + void set_view(View* view) { view_ = view; } + + // cc::LayerTreeHostClient implementation. + virtual void WillBeginMainFrame(int frame_id) OVERRIDE; + virtual void DidBeginMainFrame() OVERRIDE; + virtual void BeginMainFrame(const cc::BeginFrameArgs& args) OVERRIDE; + virtual void Layout() OVERRIDE; + virtual void ApplyViewportDeltas(const gfx::Vector2d& scroll_delta, + float page_scale, + float top_controls_delta) OVERRIDE; + virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface( + bool fallback) OVERRIDE; + virtual void DidInitializeOutputSurface() OVERRIDE; + virtual void WillCommit() OVERRIDE; + virtual void DidCommit() OVERRIDE; + virtual void DidCommitAndDrawFrame() OVERRIDE; + virtual void DidCompleteSwapBuffers() OVERRIDE; + virtual void RateLimitSharedMainThreadContext() OVERRIDE {} + + // blink::WebLayerTreeView implementation. + virtual void setSurfaceReady() OVERRIDE; + virtual void setRootLayer(const blink::WebLayer& layer) OVERRIDE; + virtual void clearRootLayer() OVERRIDE; + virtual void setViewportSize( + const blink::WebSize& device_viewport_size) OVERRIDE; + virtual blink::WebSize deviceViewportSize() const OVERRIDE; + virtual void setDeviceScaleFactor(float) OVERRIDE; + virtual float deviceScaleFactor() const OVERRIDE; + virtual void setBackgroundColor(blink::WebColor color) OVERRIDE; + virtual void setHasTransparentBackground( + bool has_transparent_background) OVERRIDE; + virtual void setOverhangBitmap(const SkBitmap& bitmap) OVERRIDE; + virtual void setVisible(bool visible) OVERRIDE; + virtual void setPageScaleFactorAndLimits(float page_scale_factor, + float minimum, + float maximum) OVERRIDE; + virtual void startPageScaleAnimation(const blink::WebPoint& destination, + bool use_anchor, + float new_page_scale, + double duration_sec) OVERRIDE; + virtual void heuristicsForGpuRasterizationUpdated(bool matches_heuristic) {} + virtual void setTopControlsContentOffset(float offset) {} + virtual void setNeedsAnimate() OVERRIDE; + virtual bool commitRequested() const OVERRIDE; + virtual void didStopFlinging() {} + virtual void compositeAndReadbackAsync( + blink::WebCompositeAndReadbackAsyncCallback* callback) {} + virtual void finishAllRendering() OVERRIDE; + virtual void setDeferCommits(bool defer_commits) {} + virtual void registerForAnimations(blink::WebLayer* layer) OVERRIDE; + virtual void registerViewportLayers( + const blink::WebLayer* page_scale_layer, + const blink::WebLayer* inner_viewport_scroll_layer, + const blink::WebLayer* outer_viewport_scroll_layer) OVERRIDE; + virtual void clearViewportLayers() OVERRIDE; + virtual void registerSelection(const blink::WebSelectionBound& start, + const blink::WebSelectionBound& end) {} + virtual void clearSelection() {} + virtual void setShowFPSCounter(bool) {} + virtual void setShowPaintRects(bool) {} + virtual void setShowDebugBorders(bool) {} + virtual void setContinuousPaintingEnabled(bool) {} + virtual void setShowScrollBottleneckRects(bool) {} + + // OutputSurfaceMojoClient implementation. + virtual void DidCreateSurface(cc::SurfaceId id) OVERRIDE; + + private: + void OnSurfaceConnectionCreated(SurfacePtr surface, uint32_t id_namespace); + void DidCreateSurfaceOnMainThread(cc::SurfaceId id); + + // widget_ and view_ will outlive us. + blink::WebWidget* widget_; + View* view_; + scoped_ptr<cc::LayerTreeHost> layer_tree_host_; + SurfacesServicePtr surfaces_service_; + scoped_ptr<cc::OutputSurface> output_surface_; + GpuPtr gpu_service_; + scoped_refptr<base::SingleThreadTaskRunner> + main_thread_compositor_task_runner_; + base::WeakPtr<WebLayerTreeViewImpl> main_thread_bound_weak_ptr_; + + base::WeakPtrFactory<WebLayerTreeViewImpl> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(WebLayerTreeViewImpl); +}; + +} // namespace mojo + +#endif // MOJO_SERVICES_HTML_VIEWER_WEBLAYERTREEVIEW_IMPL_H_ diff --git a/mojo/services/public/cpp/geometry/geometry_type_converters.h b/mojo/services/public/cpp/geometry/geometry_type_converters.h index 876686e..2f2cc1b 100644 --- a/mojo/services/public/cpp/geometry/geometry_type_converters.h +++ b/mojo/services/public/cpp/geometry/geometry_type_converters.h @@ -52,6 +52,15 @@ struct MOJO_GEOMETRY_EXPORT TypeConverter<gfx::Rect, RectPtr> { }; template <> +struct MOJO_GEOMETRY_EXPORT TypeConverter<RectFPtr, gfx::RectF> { + static RectFPtr Convert(const gfx::RectF& input); +}; +template <> +struct MOJO_GEOMETRY_EXPORT TypeConverter<gfx::RectF, RectFPtr> { + static gfx::RectF Convert(const RectFPtr& input); +}; + +template <> struct MOJO_GEOMETRY_EXPORT TypeConverter<TransformPtr, gfx::Transform> { static TransformPtr Convert(const gfx::Transform& input); }; diff --git a/mojo/services/public/cpp/geometry/lib/geometry_type_converters.cc b/mojo/services/public/cpp/geometry/lib/geometry_type_converters.cc index 5a21f24..9a40c151 100644 --- a/mojo/services/public/cpp/geometry/lib/geometry_type_converters.cc +++ b/mojo/services/public/cpp/geometry/lib/geometry_type_converters.cc @@ -71,6 +71,23 @@ gfx::Rect TypeConverter<gfx::Rect, RectPtr>::Convert(const RectPtr& input) { } // static +RectFPtr TypeConverter<RectFPtr, gfx::RectF>::Convert(const gfx::RectF& input) { + RectFPtr rect(RectF::New()); + rect->x = input.x(); + rect->y = input.y(); + rect->width = input.width(); + rect->height = input.height(); + return rect.Pass(); +} + +// static +gfx::RectF TypeConverter<gfx::RectF, RectFPtr>::Convert(const RectFPtr& input) { + if (input.is_null()) + return gfx::RectF(); + return gfx::RectF(input->x, input->y, input->width, input->height); +} + +// static TransformPtr TypeConverter<TransformPtr, gfx::Transform>::Convert( const gfx::Transform& input) { std::vector<float> storage(16); diff --git a/mojo/services/public/cpp/surfaces/lib/surfaces_type_converters.cc b/mojo/services/public/cpp/surfaces/lib/surfaces_type_converters.cc index b6b348d..e86700e 100644 --- a/mojo/services/public/cpp/surfaces/lib/surfaces_type_converters.cc +++ b/mojo/services/public/cpp/surfaces/lib/surfaces_type_converters.cc @@ -9,10 +9,12 @@ #include "cc/output/delegated_frame_data.h" #include "cc/quads/draw_quad.h" #include "cc/quads/render_pass.h" +#include "cc/quads/render_pass_draw_quad.h" #include "cc/quads/shared_quad_state.h" #include "cc/quads/solid_color_draw_quad.h" #include "cc/quads/surface_draw_quad.h" #include "cc/quads/texture_draw_quad.h" +#include "cc/quads/tile_draw_quad.h" #include "mojo/services/public/cpp/geometry/geometry_type_converters.h" namespace mojo { @@ -54,6 +56,27 @@ bool ConvertDrawQuad(const QuadPtr& input, cc::SharedQuadState* sqs, cc::RenderPass* render_pass) { switch (input->material) { + case MATERIAL_RENDER_PASS: { + cc::RenderPassDrawQuad* render_pass_quad = + render_pass->CreateAndAppendDrawQuad<cc::RenderPassDrawQuad>(); + RenderPassQuadState* render_pass_quad_state = + input->render_pass_quad_state.get(); + gfx::PointF filter_scale_as_point = + render_pass_quad_state->filters_scale.To<gfx::PointF>(); + render_pass_quad->SetAll( + sqs, + input->rect.To<gfx::Rect>(), + input->opaque_rect.To<gfx::Rect>(), + input->visible_rect.To<gfx::Rect>(), + input->needs_blending, + render_pass_quad_state->render_pass_id.To<cc::RenderPassId>(), + render_pass_quad_state->mask_resource_id, + render_pass_quad_state->mask_uv_rect.To<gfx::RectF>(), + cc::FilterOperations(), // TODO(jamesr): filters + gfx::Vector2dF(filter_scale_as_point.x(), filter_scale_as_point.y()), + cc::FilterOperations()); // TODO(jamesr): background_filters + break; + } case MATERIAL_SOLID_COLOR: { if (input->solid_color_quad_state.is_null()) return false; @@ -107,6 +130,23 @@ bool ConvertDrawQuad(const QuadPtr& input, texture_quad_state->flipped); break; } + case MATERIAL_TILED_CONTENT: { + TileQuadStatePtr& tile_state = input->tile_quad_state; + if (tile_state.is_null()) + return false; + cc::TileDrawQuad* tile_quad = + render_pass->CreateAndAppendDrawQuad<cc::TileDrawQuad>(); + tile_quad->SetAll(sqs, + input->rect.To<gfx::Rect>(), + input->opaque_rect.To<gfx::Rect>(), + input->visible_rect.To<gfx::Rect>(), + input->needs_blending, + tile_state->resource_id, + tile_state->tex_coord_rect.To<gfx::RectF>(), + tile_state->texture_size.To<gfx::Size>(), + tile_state->swizzle_contents); + break; + } default: NOTREACHED() << "Unsupported material " << input->material; return false; @@ -143,6 +183,21 @@ SkColor TypeConverter<SkColor, ColorPtr>::Convert(const ColorPtr& input) { } // static +RenderPassIdPtr TypeConverter<RenderPassIdPtr, cc::RenderPassId>::Convert( + const cc::RenderPassId& input) { + RenderPassIdPtr pass_id(RenderPassId::New()); + pass_id->layer_id = input.layer_id; + pass_id->index = input.index; + return pass_id.Pass(); +} + +// static +cc::RenderPassId TypeConverter<cc::RenderPassId, RenderPassIdPtr>::Convert( + const RenderPassIdPtr& input) { + return cc::RenderPassId(input->layer_id, input->index); +} + +// static QuadPtr TypeConverter<QuadPtr, cc::DrawQuad>::Convert( const cc::DrawQuad& input) { QuadPtr quad = Quad::New(); @@ -156,6 +211,21 @@ QuadPtr TypeConverter<QuadPtr, cc::DrawQuad>::Convert( // state list. quad->shared_quad_state_index = -1; switch (input.material) { + case cc::DrawQuad::RENDER_PASS: { + const cc::RenderPassDrawQuad* render_pass_quad = + cc::RenderPassDrawQuad::MaterialCast(&input); + RenderPassQuadStatePtr pass_state = RenderPassQuadState::New(); + pass_state->render_pass_id = + RenderPassId::From(render_pass_quad->render_pass_id); + pass_state->mask_resource_id = render_pass_quad->mask_resource_id; + pass_state->mask_uv_rect = RectF::From(render_pass_quad->mask_uv_rect); + // TODO(jamesr): pass_state->filters + pass_state->filters_scale = PointF::From( + gfx::PointAtOffsetFromOrigin(render_pass_quad->filters_scale)); + // TODO(jamesr): pass_state->background_filters + quad->render_pass_quad_state = pass_state.Pass(); + break; + } case cc::DrawQuad::SOLID_COLOR: { const cc::SolidColorDrawQuad* color_quad = cc::SolidColorDrawQuad::MaterialCast(&input); @@ -179,7 +249,6 @@ QuadPtr TypeConverter<QuadPtr, cc::DrawQuad>::Convert( const cc::TextureDrawQuad* texture_quad = cc::TextureDrawQuad::MaterialCast(&input); TextureQuadStatePtr texture_state = TextureQuadState::New(); - texture_state = TextureQuadState::New(); texture_state->resource_id = texture_quad->resource_id; texture_state->premultiplied_alpha = texture_quad->premultiplied_alpha; texture_state->uv_top_left = PointF::From(texture_quad->uv_top_left); @@ -196,6 +265,17 @@ QuadPtr TypeConverter<QuadPtr, cc::DrawQuad>::Convert( quad->texture_quad_state = texture_state.Pass(); break; } + case cc::DrawQuad::TILED_CONTENT: { + const cc::TileDrawQuad* tile_quad = + cc::TileDrawQuad::MaterialCast(&input); + TileQuadStatePtr tile_state = TileQuadState::New(); + tile_state->tex_coord_rect = RectF::From(tile_quad->tex_coord_rect); + tile_state->texture_size = Size::From(tile_quad->texture_size); + tile_state->swizzle_contents = tile_quad->swizzle_contents; + tile_state->resource_id = tile_quad->resource_id; + quad->tile_quad_state = tile_state.Pass(); + break; + } default: NOTREACHED() << "Unsupported material " << input.material; } @@ -240,7 +320,7 @@ PassPtr TypeConverter<PassPtr, cc::RenderPass>::Convert( if (quad.shared_quad_state != last_sqs) { sqs_i++; shared_quad_state[sqs_i] = - SharedQuadState::From(*input.shared_quad_state_list[i]); + SharedQuadState::From(*input.shared_quad_state_list[sqs_i]); last_sqs = quad.shared_quad_state; } quads[i]->shared_quad_state_index = sqs_i; diff --git a/mojo/services/public/cpp/surfaces/surfaces_type_converters.h b/mojo/services/public/cpp/surfaces/surfaces_type_converters.h index 822c440..4ef0e2c 100644 --- a/mojo/services/public/cpp/surfaces/surfaces_type_converters.h +++ b/mojo/services/public/cpp/surfaces/surfaces_type_converters.h @@ -21,6 +21,7 @@ namespace cc { class CompositorFrame; class DrawQuad; class RenderPass; +class RenderPassId; class SharedQuadState; } // namespace cc @@ -47,6 +48,16 @@ struct MOJO_SURFACES_EXPORT TypeConverter<SkColor, ColorPtr> { }; template <> +struct MOJO_SURFACES_EXPORT TypeConverter<RenderPassIdPtr, cc::RenderPassId> { + static RenderPassIdPtr Convert(const cc::RenderPassId& input); +}; + +template <> +struct MOJO_SURFACES_EXPORT TypeConverter<cc::RenderPassId, RenderPassIdPtr> { + static cc::RenderPassId Convert(const RenderPassIdPtr& input); +}; + +template <> struct MOJO_SURFACES_EXPORT TypeConverter<QuadPtr, cc::DrawQuad> { static QuadPtr Convert(const cc::DrawQuad& input); }; diff --git a/mojo/services/public/interfaces/geometry/geometry.mojom b/mojo/services/public/interfaces/geometry/geometry.mojom index 56d10ef..f701fdf 100644 --- a/mojo/services/public/interfaces/geometry/geometry.mojom +++ b/mojo/services/public/interfaces/geometry/geometry.mojom @@ -26,6 +26,13 @@ struct Rect { int32 height; }; +struct RectF { + float x; + float y; + float width; + float height; +}; + struct Transform { // Row major order. float[16]? matrix; diff --git a/mojo/services/public/interfaces/surfaces/quads.mojom b/mojo/services/public/interfaces/surfaces/quads.mojom index be4a905..5b83d6a 100644 --- a/mojo/services/public/interfaces/surfaces/quads.mojom +++ b/mojo/services/public/interfaces/surfaces/quads.mojom @@ -18,7 +18,33 @@ struct DebugBorderQuadState {}; struct IoSurfaceContentQuadState {}; -struct RenderPassQuadState {}; +struct RenderPassId { + int32 layer_id; + int32 index; +}; + +struct RenderPassQuadState { + RenderPassId render_pass_id; + + // If nonzero, resource id of mask to use when drawing this pass. + uint32 mask_resource_id; + RectF mask_uv_rect; + + // Post-processing filters, applied to the pixels in the render pass' texture. + // TODO(jamesr): Support + // FilterOperations filters; + + // The scale from layer space of the root layer of the render pass to + // the render pass physical pixels. This scale is applied to the filter + // parameters for pixel-moving filters. This scale should include + // content-to-target-space scale, and device pixel ratio. + PointF filters_scale; + + // Post-processing filters, applied to the pixels showing through the + // background of the render pass, from behind it. + // TODO(jamesr): Support + // FilterOperations background_filters; +}; struct SolidColorQuadState { Color color; @@ -32,14 +58,19 @@ struct SurfaceQuadState { struct TextureQuadState { uint32 resource_id; bool premultiplied_alpha; - mojo.PointF uv_top_left; - mojo.PointF uv_bottom_right; + PointF uv_top_left; + PointF uv_bottom_right; Color background_color; float[4] vertex_opacity; bool flipped; }; -struct TiledContentQuadState {}; +struct TileQuadState { + RectF tex_coord_rect; + Size texture_size; + bool swizzle_contents; + uint32 resource_id; +}; struct StreamVideoQuadState {}; @@ -64,15 +95,15 @@ struct Quad { // This rect, after applying the quad_transform(), gives the geometry that // this quad should draw to. This rect lives in content space. - mojo.Rect rect; + Rect rect; // This specifies the region of the quad that is opaque. This rect lives in // content space. - mojo.Rect opaque_rect; + Rect opaque_rect; // Allows changing the rect that gets drawn to make it smaller. This value // should be clipped to |rect|. This rect lives in content space. - mojo.Rect visible_rect; + Rect visible_rect; // Allows changing the rect that gets drawn to make it smaller. This value // should be clipped to |rect|. This rect lives in content space. @@ -90,7 +121,7 @@ struct Quad { SolidColorQuadState? solid_color_quad_state; SurfaceQuadState? surface_quad_state; TextureQuadState? texture_quad_state; - TiledContentQuadState? tiled_content_quad_state; + TileQuadState? tile_quad_state; StreamVideoQuadState? stream_video_quad_state; YUVVideoQuadState? yuv_video_quad_state; }; @@ -137,16 +168,16 @@ enum SkXfermode { struct SharedQuadState { // Transforms from quad's original content space to its target content space. - mojo.Transform content_to_target_transform; + Transform content_to_target_transform; // This size lives in the content space for the quad's originating layer. - mojo.Size content_bounds; + Size content_bounds; // This rect lives in the content space for the quad's originating layer. - mojo.Rect visible_content_rect; + Rect visible_content_rect; // This rect lives in the target content space. - mojo.Rect clip_rect; + Rect clip_rect; bool is_clipped; float opacity; @@ -156,9 +187,9 @@ struct SharedQuadState { struct Pass { int32 id; - mojo.Rect output_rect; - mojo.Rect damage_rect; - mojo.Transform transform_to_root_target; + Rect output_rect; + Rect damage_rect; + Transform transform_to_root_target; bool has_transparent_background; Quad[] quads; SharedQuadState[] shared_quad_states; |