1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/string_tokenizer.h"
10 #include "mojo/application/application_runner_chromium.h"
11 #include "mojo/examples/media_viewer/media_viewer.mojom.h"
12 #include "mojo/public/c/system/main.h"
13 #include "mojo/public/cpp/application/application_connection.h"
14 #include "mojo/public/cpp/application/application_delegate.h"
15 #include "mojo/public/cpp/application/application_impl.h"
16 #include "mojo/public/cpp/application/interface_factory_impl.h"
17 #include "mojo/public/cpp/application/service_provider_impl.h"
18 #include "mojo/services/public/cpp/view_manager/types.h"
19 #include "mojo/services/public/cpp/view_manager/view.h"
20 #include "mojo/services/public/cpp/view_manager/view_manager.h"
21 #include "mojo/services/public/cpp/view_manager/view_manager_client_factory.h"
22 #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h"
23 #include "mojo/services/public/cpp/view_manager/view_observer.h"
24 #include "mojo/services/public/interfaces/content_handler/content_handler.mojom.h"
25 #include "skia/ext/platform_canvas.h"
26 #include "skia/ext/refptr.h"
27 #include "third_party/skia/include/core/SkBitmap.h"
28 #include "third_party/skia/include/core/SkCanvas.h"
29 #include "third_party/skia/include/core/SkPaint.h"
30 #include "third_party/skia/include/core/SkScalar.h"
31 #include "ui/gfx/codec/png_codec.h"
38 // TODO(aa): Hook up ZoomableMedia interface again.
39 class PNGView
: public ViewManagerDelegate
, public ViewObserver
{
41 static void Spawn(URLResponsePtr response
,
42 ServiceProviderImpl
* exported_services
,
43 scoped_ptr
<ServiceProvider
> imported_services
,
45 // PNGView deletes itself when its View is destroyed.
47 response
.Pass(), exported_services
, imported_services
.Pass(), shell
);
51 static const uint16_t kMaxZoomPercentage
= 400;
52 static const uint16_t kMinZoomPercentage
= 20;
53 static const uint16_t kDefaultZoomPercentage
= 100;
54 static const uint16_t kZoomStep
= 20;
56 PNGView(URLResponsePtr response
,
57 ServiceProviderImpl
* exported_services
,
58 scoped_ptr
<ServiceProvider
> imported_services
,
60 : imported_services_(imported_services
.Pass()),
62 view_manager_client_factory_(shell
, this),
63 zoom_percentage_(kDefaultZoomPercentage
) {
64 exported_services
->AddService(&view_manager_client_factory_
);
65 DecodePNG(response
.Pass());
70 root_
->RemoveObserver(this);
73 // Overridden from ViewManagerDelegate:
74 virtual void OnEmbed(ViewManager
* view_manager
,
76 ServiceProviderImpl
* exported_services
,
77 scoped_ptr
<ServiceProvider
> imported_services
) OVERRIDE
{
79 root_
->AddObserver(this);
80 root_
->SetColor(SK_ColorGRAY
);
81 if (!bitmap_
.isNull())
85 virtual void OnViewManagerDisconnected(ViewManager
* view_manager
) OVERRIDE
{
86 // TODO(aa): Need to figure out how shutdown works.
89 // Overridden from ViewObserver:
90 virtual void OnViewBoundsChanged(View
* view
,
91 const gfx::Rect
& old_bounds
,
92 const gfx::Rect
& new_bounds
) OVERRIDE
{
93 DCHECK_EQ(view
, root_
);
97 virtual void OnViewDestroyed(View
* view
) OVERRIDE
{
98 DCHECK_EQ(view
, root_
);
102 void DecodePNG(URLResponsePtr response
) {
103 int content_length
= GetContentLength(response
->headers
);
104 scoped_ptr
<unsigned char[]> data(new unsigned char[content_length
]);
105 unsigned char* buf
= data
.get();
106 uint32_t bytes_remaining
= content_length
;
107 uint32_t num_bytes
= bytes_remaining
;
108 while (bytes_remaining
> 0) {
109 MojoResult result
= ReadDataRaw(
110 response
->body
.get(), buf
, &num_bytes
, MOJO_READ_DATA_FLAG_NONE
);
111 if (result
== MOJO_RESULT_SHOULD_WAIT
) {
112 Wait(response
->body
.get(),
113 MOJO_HANDLE_SIGNAL_READABLE
,
114 MOJO_DEADLINE_INDEFINITE
);
115 } else if (result
== MOJO_RESULT_OK
) {
117 num_bytes
= bytes_remaining
-= num_bytes
;
123 gfx::PNGCodec::Decode(static_cast<const unsigned char*>(data
.get()),
132 skia::RefPtr
<SkCanvas
> canvas(skia::AdoptRef(skia::CreatePlatformCanvas(
133 root_
->bounds().width(), root_
->bounds().height(), true)));
134 canvas
->drawColor(SK_ColorGRAY
);
137 SkFloatToScalar(zoom_percentage_
* 1.0f
/ kDefaultZoomPercentage
);
138 canvas
->scale(scale
, scale
);
139 canvas
->drawBitmap(bitmap_
, 0, 0, &paint
);
140 root_
->SetContents(skia::GetTopDevice(*canvas
)->accessBitmap(true));
144 if (zoom_percentage_
>= kMaxZoomPercentage
)
146 zoom_percentage_
+= kZoomStep
;
151 if (zoom_percentage_
<= kMinZoomPercentage
)
153 zoom_percentage_
-= kZoomStep
;
157 void ZoomToActualSize() {
158 if (zoom_percentage_
== kDefaultZoomPercentage
)
160 zoom_percentage_
= kDefaultZoomPercentage
;
164 int GetContentLength(const Array
<String
>& headers
) {
165 for (size_t i
= 0; i
< headers
.size(); ++i
) {
166 base::StringTokenizer
t(headers
[i
], ": ;=");
167 while (t
.GetNext()) {
168 if (!t
.token_is_delim() && t
.token() == "Content-Length") {
169 while (t
.GetNext()) {
170 if (!t
.token_is_delim())
171 return atoi(t
.token().c_str());
180 scoped_ptr
<ServiceProvider
> imported_services_
;
182 ViewManagerClientFactory view_manager_client_factory_
;
183 uint16_t zoom_percentage_
;
185 DISALLOW_COPY_AND_ASSIGN(PNGView
);
188 class ContentHandlerImpl
: public InterfaceImpl
<ContentHandler
> {
190 explicit ContentHandlerImpl(Shell
* shell
) : shell_(shell
) {}
191 virtual ~ContentHandlerImpl() {}
194 // Overridden from ContentHandler:
195 virtual void OnConnect(
196 const mojo::String
& url
,
197 URLResponsePtr response
,
198 InterfaceRequest
<ServiceProvider
> service_provider
) OVERRIDE
{
199 ServiceProviderImpl
* exported_services
= new ServiceProviderImpl();
200 BindToRequest(exported_services
, &service_provider
);
201 scoped_ptr
<ServiceProvider
> remote(
202 exported_services
->CreateRemoteServiceProvider());
203 PNGView::Spawn(response
.Pass(), exported_services
, remote
.Pass(), shell_
);
208 DISALLOW_COPY_AND_ASSIGN(ContentHandlerImpl
);
211 class PNGViewer
: public ApplicationDelegate
{
215 // Overridden from ApplicationDelegate:
216 virtual void Initialize(ApplicationImpl
* app
) MOJO_OVERRIDE
{
217 content_handler_factory_
.reset(
218 new InterfaceFactoryImplWithContext
<ContentHandlerImpl
, Shell
>(
222 // Overridden from ApplicationDelegate:
223 virtual bool ConfigureIncomingConnection(ApplicationConnection
* connection
)
225 connection
->AddService(content_handler_factory_
.get());
229 scoped_ptr
<InterfaceFactoryImplWithContext
<ContentHandlerImpl
, Shell
> >
230 content_handler_factory_
;
232 DISALLOW_COPY_AND_ASSIGN(PNGViewer
);
235 } // namespace examples
238 MojoResult
MojoMain(MojoHandle shell_handle
) {
239 mojo::ApplicationRunnerChromium
runner(new mojo::examples::PNGViewer
);
240 return runner
.Run(shell_handle
);