+++ /dev/null
-From c9f2fa16578bc20c83247e72608b5d6ca4dff6ba Mon Sep 17 00:00:00 2001
-From: "qing.zhang" <qing.zhang@intel.com>
-Date: Thu, 7 Nov 2013 08:59:38 -0500
-Subject: [PATCH] [Tizen] Enabling Hardware Acceleration with Libva and EGL in
- VDA for Tizen Mobile within chromium v31+.
-
-Why we need to maintain it in our side:
-===========================================
-1) Upstream confirm VAVDA will continue to be restricted to
- CrOS/X86 for dev & testing only and not for chromium road map.
-2) CrOS/X86 no plan to expend EGL backend which finalize in
- June 2012 and be addressed to the CrOS graphics team.
-
-So, the upstream no plan to lerage VAVDA with EGL graphic
- backend for any X86.
-
-3) The tizen-mobile's driver only support EGL as texture
- backend. The video hw acceleration of xwalk have to
- rely on EGL not GLX to bind decoded pixmap.
-===========================================
-That's why we enable specific EGL for VAVDA in tizen port.
----
- .../gpu/media/gpu_video_decode_accelerator.cc | 8 +
- .../media/vaapi_video_decode_accelerator_tizen.cc | 908 +++++++++++++++++++++
- .../media/vaapi_video_decode_accelerator_tizen.h | 273 +++++++
- content/content_common.gypi | 26 +
- 4 files changed, 1215 insertions(+)
- create mode 100644 content/common/gpu/media/vaapi_video_decode_accelerator_tizen.cc
- create mode 100644 content/common/gpu/media/vaapi_video_decode_accelerator_tizen.h
-
-diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc
-index bd1dc5f..c5a6df2 100644
---- a/content/common/gpu/media/gpu_video_decode_accelerator.cc
-+++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc
-@@ -32,6 +32,8 @@
- #include "content/common/gpu/media/vaapi_video_decode_accelerator.h"
- #include "ui/gl/gl_context_glx.h"
- #include "ui/gl/gl_implementation.h"
-+#elif defined(OS_TIZEN_MOBILE) && defined(ARCH_CPU_X86_FAMILY)
-+#include "content/common/gpu/media/vaapi_video_decode_accelerator_tizen.h"
- #elif defined(OS_ANDROID)
- #include "content/common/gpu/media/android_video_decode_accelerator.h"
- #endif
-@@ -296,6 +298,12 @@ void GpuVideoDecodeAccelerator::Initialize(
- static_cast<gfx::GLContextGLX*>(stub_->decoder()->GetGLContext());
- video_decode_accelerator_.reset(new VaapiVideoDecodeAccelerator(
- glx_context->display(), this, make_context_current_));
-+#elif defined(OS_TIZEN_MOBILE) && defined(ARCH_CPU_X86_FAMILY)
-+ video_decode_accelerator_.reset(new VaapiVideoDecodeAccelerator(
-+ gfx::GLSurfaceEGL::GetHardwareDisplay(),
-+ stub_->decoder()->GetGLContext()->GetHandle(),
-+ this,
-+ make_context_current_));
- #elif defined(OS_ANDROID)
- video_decode_accelerator_.reset(new AndroidVideoDecodeAccelerator(
- this,
-diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator_tizen.cc b/content/common/gpu/media/vaapi_video_decode_accelerator_tizen.cc
-new file mode 100644
-index 0000000..cfff457
---- /dev/null
-+++ b/content/common/gpu/media/vaapi_video_decode_accelerator_tizen.cc
-@@ -0,0 +1,908 @@
-+// Copyright (c) 2013 Intel Corporation. All rights reserved.
-+// Use of this source code is governed by a BSD-style license that can be
-+// found in the LICENSE file.
-+
-+#include "base/bind.h"
-+#include "base/debug/trace_event.h"
-+#include "base/logging.h"
-+#include "base/metrics/histogram.h"
-+#include "base/stl_util.h"
-+#include "base/strings/string_util.h"
-+#include "base/synchronization/waitable_event.h"
-+#include "content/child/child_thread.h"
-+#include "content/common/gpu/gpu_channel.h"
-+#include "content/common/gpu/media/vaapi_video_decode_accelerator_tizen.h"
-+#include "media/base/bind_to_current_loop.h"
-+#include "media/video/picture.h"
-+#include "ui/gl/gl_bindings.h"
-+#include "ui/gl/scoped_binders.h"
-+
-+static void ReportToUMA(
-+ content::VaapiH264Decoder::VAVDAH264DecoderFailure failure) {
-+ UMA_HISTOGRAM_ENUMERATION(
-+ "Media.VAVDAH264.DecoderFailure",
-+ failure,
-+ content::VaapiH264Decoder::VAVDA_H264_DECODER_FAILURES_MAX);
-+}
-+
-+namespace content {
-+
-+#define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \
-+ do { \
-+ if (!(result)) { \
-+ DVLOG(1) << log; \
-+ NotifyError(error_code); \
-+ return ret; \
-+ } \
-+ } while (0)
-+
-+VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) {
-+}
-+
-+VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() {
-+}
-+
-+void VaapiVideoDecodeAccelerator::NotifyError(Error error) {
-+ if (message_loop_ != base::MessageLoop::current()) {
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::NotifyError, weak_this_, error));
-+ return;
-+ }
-+
-+ // Post Cleanup() as a task so we don't recursively acquire lock_.
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::Cleanup, weak_this_));
-+
-+ DVLOG(1) << "Notifying of error " << error;
-+ if (client_) {
-+ client_->NotifyError(error);
-+ client_ptr_factory_.InvalidateWeakPtrs();
-+ }
-+}
-+
-+// TFPPicture allocates X Pixmaps and binds them to textures passed
-+// in PictureBuffers from clients to them. TFPPictures are created as
-+// a consequence of receiving a set of PictureBuffers from clients and released
-+// at the end of decode (or when a new set of PictureBuffers is required).
-+//
-+// TFPPictures are used for output, contents of VASurfaces passed from decoder
-+// are put into the associated pixmap memory and sent to client.
-+class VaapiVideoDecodeAccelerator::TFPPicture {
-+ public:
-+ ~TFPPicture();
-+
-+ static linked_ptr<TFPPicture> Create(
-+ const base::Callback<bool(void)>& make_context_current,
-+ EGLDisplay egl_display,
-+ Display* x_display,
-+ int32 picture_buffer_id,
-+ uint32 texture_id,
-+ gfx::Size size);
-+ int32 picture_buffer_id() {
-+ return picture_buffer_id_;
-+ }
-+
-+ uint32 texture_id() {
-+ return texture_id_;
-+ }
-+
-+ gfx::Size size() {
-+ return size_;
-+ }
-+
-+ int x_pixmap() {
-+ return x_pixmap_;
-+ }
-+
-+ // Bind texture to pixmap. Needs to be called every frame.
-+ bool Bind();
-+
-+ private:
-+ TFPPicture(const base::Callback<bool(void)>& make_context_current,
-+ Display* x_display,
-+ int32 picture_buffer_id,
-+ uint32 texture_id,
-+ gfx::Size size);
-+
-+ bool Initialize(EGLDisplay egl_display);
-+
-+ base::Callback<bool(void)> make_context_current_;
-+
-+ Display* x_display_;
-+
-+ // Output id for the client.
-+ int32 picture_buffer_id_;
-+ uint32 texture_id_;
-+
-+ gfx::Size size_;
-+
-+ // Pixmaps bound to this texture.
-+ Pixmap x_pixmap_;
-+ EGLDisplay egl_display_;
-+ EGLImageKHR egl_image_;
-+
-+ DISALLOW_COPY_AND_ASSIGN(TFPPicture);
-+};
-+
-+VaapiVideoDecodeAccelerator::TFPPicture::TFPPicture(
-+ const base::Callback<bool(void)>& make_context_current,
-+ Display* x_display,
-+ int32 picture_buffer_id,
-+ uint32 texture_id,
-+ gfx::Size size)
-+ : make_context_current_(make_context_current),
-+ x_display_(x_display),
-+ picture_buffer_id_(picture_buffer_id),
-+ texture_id_(texture_id),
-+ size_(size),
-+ x_pixmap_(0),
-+ egl_image_(0) {
-+ DCHECK(!make_context_current_.is_null());
-+};
-+
-+linked_ptr<VaapiVideoDecodeAccelerator::TFPPicture>
-+VaapiVideoDecodeAccelerator::TFPPicture::Create(
-+ const base::Callback<bool(void)>& make_context_current,
-+ EGLDisplay egl_display,
-+ Display* x_display,
-+ int32 picture_buffer_id,
-+ uint32 texture_id,
-+ gfx::Size size) {
-+
-+ linked_ptr<TFPPicture> tfp_picture(
-+ new TFPPicture(make_context_current, x_display,
-+ picture_buffer_id, texture_id, size));
-+
-+ if (!tfp_picture->Initialize(egl_display))
-+ tfp_picture.reset();
-+
-+ return tfp_picture;
-+}
-+
-+bool VaapiVideoDecodeAccelerator::TFPPicture::Initialize(
-+ EGLDisplay egl_display) {
-+ // Check for NULL prevents unittests from crashing on nonexistent ChildThread.
-+ DCHECK(ChildThread::current() == NULL ||
-+ ChildThread::current()->message_loop() == base::MessageLoop::current());
-+
-+ if (!make_context_current_.Run())
-+ return false;
-+
-+ XWindowAttributes win_attr;
-+ int screen = DefaultScreen(x_display_);
-+ XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr);
-+ //TODO(posciak): pass the depth required by libva, not the RootWindow's depth
-+ x_pixmap_ = XCreatePixmap(x_display_, RootWindow(x_display_, screen),
-+ size_.width(), size_.height(), win_attr.depth);
-+ if (!x_pixmap_) {
-+ DVLOG(1) << "Failed creating an X Pixmap for TFP";
-+ return false;
-+ }
-+
-+ egl_display_ = egl_display;
-+ EGLint image_attrs[] = { EGL_IMAGE_PRESERVED_KHR, 1 , EGL_NONE };
-+
-+ egl_image_ = eglCreateImageKHR(egl_display_,
-+ EGL_NO_CONTEXT,
-+ EGL_NATIVE_PIXMAP_KHR,
-+ (EGLClientBuffer)x_pixmap_,
-+ image_attrs);
-+ if (!egl_image_) {
-+ DVLOG(1) << "Failed creating a EGLImage from Pixmap for KHR";
-+ return false;
-+ }
-+
-+ return true;
-+}
-+VaapiVideoDecodeAccelerator::TFPPicture::~TFPPicture() {
-+ // Check for NULL prevents unittests from crashing on non-existing ChildThread.
-+ DCHECK(ChildThread::current() == NULL ||
-+ ChildThread::current()->message_loop() == base::MessageLoop::current());
-+
-+ // Unbind surface from texture and deallocate resources.
-+ if (make_context_current_.Run()) {
-+ eglDestroyImageKHR(egl_display_, egl_image_);
-+ }
-+
-+ if (x_pixmap_)
-+ XFreePixmap(x_display_, x_pixmap_);
-+ XSync(x_display_, False); // Needed to work around buggy vdpau-driver.
-+}
-+
-+bool VaapiVideoDecodeAccelerator::TFPPicture::Bind() {
-+ DCHECK(x_pixmap_);
-+ DCHECK(egl_image_);
-+
-+ // Check for NULL prevents unittests from crashing on nonexistent ChildThread.
-+ DCHECK(ChildThread::current() == NULL ||
-+ ChildThread::current()->message_loop() == base::MessageLoop::current());
-+
-+ if (!make_context_current_.Run())
-+ return false;
-+
-+ gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id_);
-+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
-+
-+ return true;
-+}
-+
-+VaapiVideoDecodeAccelerator::TFPPicture*
-+ VaapiVideoDecodeAccelerator::TFPPictureById(int32 picture_buffer_id) {
-+ TFPPictures::iterator it = tfp_pictures_.find(picture_buffer_id);
-+ if (it == tfp_pictures_.end()) {
-+ DVLOG(1) << "Picture id " << picture_buffer_id << " does not exist";
-+ return NULL;
-+ }
-+
-+ return it->second.get();
-+}
-+
-+VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator(
-+ EGLDisplay egl_display, EGLContext egl_context,
-+ Client* client,
-+ const base::Callback<bool(void)>& make_context_current)
-+ : x_display_(0),
-+ egl_display_(egl_display),
-+ egl_context_(egl_context),
-+ make_context_current_(make_context_current),
-+ state_(kUninitialized),
-+ input_ready_(&lock_),
-+ surfaces_available_(&lock_),
-+ message_loop_(base::MessageLoop::current()),
-+ weak_this_(base::AsWeakPtr(this)),
-+ client_ptr_factory_(client),
-+ client_(client_ptr_factory_.GetWeakPtr()),
-+ decoder_thread_("VaapiDecoderThread"),
-+ num_frames_at_client_(0),
-+ num_stream_bufs_at_decoder_(0),
-+ finish_flush_pending_(false),
-+ awaiting_va_surfaces_recycle_(false),
-+ requested_num_pics_(0) {
-+ DCHECK(client);
-+}
-+VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+}
-+
-+class ScopedPtrXFree {
-+ public:
-+ void operator()(void* x) const {
-+ ::XFree(x);
-+ }
-+};
-+
-+bool VaapiVideoDecodeAccelerator::Initialize(
-+ media::VideoCodecProfile profile) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ base::AutoLock auto_lock(lock_);
-+ DCHECK_EQ(state_, kUninitialized);
-+ DVLOG(2) << "Initializing VAVDA, profile: " << profile;
-+
-+ if (!make_context_current_.Run())
-+ return false;
-+
-+ x_display_ = base::MessagePumpForUI::GetDefaultXDisplay();
-+
-+ vaapi_wrapper_ = VaapiWrapper::Create(
-+ profile, x_display_,
-+ base::Bind(&ReportToUMA, content::VaapiH264Decoder::VAAPI_ERROR));
-+
-+ if (!vaapi_wrapper_.get()) {
-+ DVLOG(1) << "Failed initializing VAAPI";
-+ return false;
-+ }
-+
-+ decoder_.reset(
-+ new VaapiH264Decoder(
-+ vaapi_wrapper_.get(),
-+ media::BindToCurrentLoop(base::Bind(
-+ &VaapiVideoDecodeAccelerator::SurfaceReady, weak_this_)),
-+ base::Bind(&ReportToUMA)));
-+
-+ CHECK(decoder_thread_.Start());
-+
-+ state_ = kIdle;
-+
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &Client::NotifyInitializeDone, client_));
-+ return true;
-+}
-+
-+void VaapiVideoDecodeAccelerator::SurfaceReady(
-+ int32 input_id,
-+ const scoped_refptr<VASurface>& va_surface) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ DCHECK(!awaiting_va_surfaces_recycle_);
-+
-+ // Drop any requests to output if we are resetting or being destroyed.
-+ if (state_ == kResetting || state_ == kDestroying)
-+ return;
-+
-+ pending_output_cbs_.push(
-+ base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture,
-+ weak_this_, va_surface, input_id));
-+
-+ TryOutputSurface();
-+}
-+
-+void VaapiVideoDecodeAccelerator::OutputPicture(
-+ const scoped_refptr<VASurface>& va_surface,
-+ int32 input_id,
-+ TFPPicture* tfp_picture) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ int32 output_id = tfp_picture->picture_buffer_id();
-+
-+ TRACE_EVENT2("Video Decoder", "VAVDA::OutputSurface",
-+ "input_id", input_id,
-+ "output_id", output_id);
-+
-+ DVLOG(3) << "Outputting VASurface " << va_surface->id()
-+ << " into pixmap bound to picture buffer id " << output_id;
-+
-+ RETURN_AND_NOTIFY_ON_FAILURE(tfp_picture->Bind(),
-+ "Failed binding texture to pixmap",
-+ PLATFORM_FAILURE, );
-+
-+ RETURN_AND_NOTIFY_ON_FAILURE(
-+ vaapi_wrapper_->PutSurfaceIntoPixmap(va_surface->id(),
-+ tfp_picture->x_pixmap(),
-+ tfp_picture->size()),
-+ "Failed putting surface into pixmap", PLATFORM_FAILURE, );
-+
-+ // Notify the client a picture is ready to be displayed.
-+ ++num_frames_at_client_;
-+ TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_);
-+ DVLOG(4) << "Notifying output picture id " << output_id
-+ << " for input "<< input_id << " is ready";
-+ client_->PictureReady(media::Picture(output_id, input_id));
-+}
-+
-+void VaapiVideoDecodeAccelerator::TryOutputSurface() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ // Handle Destroy() arriving while pictures are queued for output.
-+ if (!client_)
-+ return;
-+
-+ if (pending_output_cbs_.empty() || output_buffers_.empty())
-+ return;
-+
-+ OutputCB output_cb = pending_output_cbs_.front();
-+ pending_output_cbs_.pop();
-+
-+ TFPPicture* tfp_picture = TFPPictureById(output_buffers_.front());
-+ DCHECK(tfp_picture);
-+ output_buffers_.pop();
-+
-+ output_cb.Run(tfp_picture);
-+
-+ if (finish_flush_pending_ && pending_output_cbs_.empty())
-+ FinishFlush();
-+}
-+
-+void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer(
-+ const media::BitstreamBuffer& bitstream_buffer) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ TRACE_EVENT1("Video Decoder", "MapAndQueueNewInputBuffer", "input_id",
-+ bitstream_buffer.id());
-+
-+ DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id()
-+ << " size: " << (int)bitstream_buffer.size();
-+
-+ scoped_ptr<base::SharedMemory> shm(
-+ new base::SharedMemory(bitstream_buffer.handle(), true));
-+ RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(bitstream_buffer.size()),
-+ "Failed to map input buffer", UNREADABLE_INPUT,);
-+
-+ base::AutoLock auto_lock(lock_);
-+
-+ // Set up a new input buffer and queue it for later.
-+ linked_ptr<InputBuffer> input_buffer(new InputBuffer());
-+ input_buffer->shm.reset(shm.release());
-+ input_buffer->id = bitstream_buffer.id();
-+ input_buffer->size = bitstream_buffer.size();
-+
-+ ++num_stream_bufs_at_decoder_;
-+ TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder",
-+ num_stream_bufs_at_decoder_);
-+
-+ input_buffers_.push(input_buffer);
-+ input_ready_.Signal();
-+}
-+
-+bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() {
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+ lock_.AssertAcquired();
-+
-+ if (curr_input_buffer_.get())
-+ return true;
-+
-+ // Will only wait if it is expected that in current state new buffers will
-+ // be queued from the client via Decode(). The state can change during wait.
-+ while (input_buffers_.empty() && (state_ == kDecoding || state_ == kIdle)) {
-+ input_ready_.Wait();
-+ }
-+
-+ // We could have got woken up in a different state or never got to sleep
-+ // due to current state; check for that.
-+ switch (state_) {
-+ case kFlushing:
-+ // Here we are only interested in finishing up decoding buffers that are
-+ // already queued up. Otherwise will stop decoding.
-+ if (input_buffers_.empty())
-+ return false;
-+ // else fallthrough
-+ case kDecoding:
-+ case kIdle:
-+ DCHECK(!input_buffers_.empty());
-+
-+ curr_input_buffer_ = input_buffers_.front();
-+ input_buffers_.pop();
-+
-+ DVLOG(4) << "New current bitstream buffer, id: "
-+ << curr_input_buffer_->id
-+ << " size: " << curr_input_buffer_->size;
-+
-+ decoder_->SetStream(
-+ static_cast<uint8*>(curr_input_buffer_->shm->memory()),
-+ curr_input_buffer_->size, curr_input_buffer_->id);
-+ return true;
-+
-+ default:
-+ // We got woken up due to being destroyed/reset, ignore any already
-+ // queued inputs.
-+ return false;
-+ }
-+}
-+
-+void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() {
-+ lock_.AssertAcquired();
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+ DCHECK(curr_input_buffer_.get());
-+
-+ int32 id = curr_input_buffer_->id;
-+ curr_input_buffer_.reset();
-+ DVLOG(4) << "End of input buffer " << id;
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &Client::NotifyEndOfBitstreamBuffer, client_, id));
-+
-+ --num_stream_bufs_at_decoder_;
-+ TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder",
-+ num_stream_bufs_at_decoder_);
-+}
-+
-+bool VaapiVideoDecodeAccelerator::FeedDecoderWithOutputSurfaces_Locked() {
-+ lock_.AssertAcquired();
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+
-+ while (available_va_surfaces_.empty() &&
-+ (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) {
-+ surfaces_available_.Wait();
-+ }
-+
-+ if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle)
-+ return false;
-+
-+ VASurface::ReleaseCB va_surface_release_cb =
-+ media::BindToCurrentLoop(base::Bind(
-+ &VaapiVideoDecodeAccelerator::RecycleVASurfaceID, weak_this_));
-+
-+ while (!available_va_surfaces_.empty()) {
-+ scoped_refptr<VASurface> va_surface(
-+ new VASurface(available_va_surfaces_.front(), va_surface_release_cb));
-+ available_va_surfaces_.pop_front();
-+ decoder_->ReuseSurface(va_surface);
-+ }
-+
-+ return true;
-+}
-+
-+void VaapiVideoDecodeAccelerator::DecodeTask() {
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+ TRACE_EVENT0("Video Decoder", "VAVDA::DecodeTask");
-+ base::AutoLock auto_lock(lock_);
-+
-+ if (state_ != kDecoding)
-+ return;
-+
-+ // Main decode task.
-+ DVLOG(4) << "Decode task";
-+
-+ // Try to decode what stream data is (still) in the decoder until we run out
-+ // of it.
-+ while (GetInputBuffer_Locked()) {
-+ DCHECK(curr_input_buffer_.get());
-+
-+ VaapiH264Decoder::DecResult res;
-+ {
-+ // We are OK releasing the lock here, as decoder never calls our methods
-+ // directly and we will reacquire the lock before looking at state again.
-+ // This is the main decode function of the decoder and while keeping
-+ // the lock for its duration would be fine, it would defeat the purpose
-+ // of having a separate decoder thread.
-+ base::AutoUnlock auto_unlock(lock_);
-+ res = decoder_->Decode();
-+ }
-+
-+ switch (res) {
-+ case VaapiH264Decoder::kAllocateNewSurfaces:
-+ DVLOG(1) << "Decoder requesting a new set of surfaces";
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange, weak_this_,
-+ decoder_->GetRequiredNumOfPictures(),
-+ decoder_->GetPicSize()));
-+ // We'll get rescheduled once ProvidePictureBuffers() finishes.
-+ return;
-+
-+ case VaapiH264Decoder::kRanOutOfStreamData:
-+ ReturnCurrInputBuffer_Locked();
-+ break;
-+
-+ case VaapiH264Decoder::kRanOutOfSurfaces:
-+ // No more output buffers in the decoder, try getting more or go to
-+ // sleep waiting for them.
-+ if (!FeedDecoderWithOutputSurfaces_Locked())
-+ return;
-+
-+ break;
-+
-+ case VaapiH264Decoder::kDecodeError:
-+ RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream",
-+ PLATFORM_FAILURE, );
-+ return;
-+ }
-+ }
-+}
-+
-+void VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange(size_t num_pics,
-+ gfx::Size size) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ DCHECK(!awaiting_va_surfaces_recycle_);
-+
-+ // At this point decoder has stopped running and has already posted onto our
-+ // loop any remaining output request callbacks, which executed before we got
-+ // here. Some of them might have been pended though, because we might not
-+ // have had enough TFPictures to output surfaces to. Initiate a wait cycle,
-+ // which will wait for client to return enough PictureBuffers to us, so that
-+ // we can finish all pending output callbacks, releasing associated surfaces.
-+ DVLOG(1) << "Initiating surface set change";
-+ awaiting_va_surfaces_recycle_ = true;
-+
-+ requested_num_pics_ = num_pics;
-+ requested_pic_size_ = size;
-+
-+ TryFinishSurfaceSetChange();
-+}
-+
-+void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ if (!awaiting_va_surfaces_recycle_)
-+ return;
-+
-+ if (!pending_output_cbs_.empty() ||
-+ tfp_pictures_.size() != available_va_surfaces_.size()) {
-+ // Either:
-+ // 1. Not all pending pending output callbacks have been executed yet.
-+ // Wait for the client to return enough pictures and retry later.
-+ // 2. The above happened and all surface release callbacks have been posted
-+ // as the result, but not all have executed yet. Post ourselves after them
-+ // to let them release surfaces.
-+ DVLOG(2) << "Awaiting pending output/surface release callbacks to finish";
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange, weak_this_));
-+ return;
-+ }
-+
-+ // All surfaces released, destroy them and dismiss all PictureBuffers.
-+ awaiting_va_surfaces_recycle_ = false;
-+ available_va_surfaces_.clear();
-+ vaapi_wrapper_->DestroySurfaces();
-+
-+ for (TFPPictures::iterator iter = tfp_pictures_.begin();
-+ iter != tfp_pictures_.end(); ++iter) {
-+ DVLOG(2) << "Dismissing picture id: " << iter->first;
-+ client_->DismissPictureBuffer(iter->first);
-+ }
-+ tfp_pictures_.clear();
-+
-+ // And ask for a new set as requested.
-+ DVLOG(1) << "Requesting " << requested_num_pics_ << " pictures of size: "
-+ << requested_pic_size_.ToString();
-+
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &Client::ProvidePictureBuffers, client_,
-+ requested_num_pics_, requested_pic_size_, GL_TEXTURE_2D));
-+}
-+
-+void VaapiVideoDecodeAccelerator::Decode(
-+ const media::BitstreamBuffer& bitstream_buffer) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "Buffer id",
-+ bitstream_buffer.id());
-+
-+ // We got a new input buffer from the client, map it and queue for later use.
-+ MapAndQueueNewInputBuffer(bitstream_buffer);
-+
-+ base::AutoLock auto_lock(lock_);
-+ switch (state_) {
-+ case kIdle:
-+ state_ = kDecoding;
-+ decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::DecodeTask,
-+ base::Unretained(this)));
-+ break;
-+
-+ case kDecoding:
-+ // Decoder already running.
-+ case kResetting:
-+ // When resetting, allow accumulating bitstream buffers, so that
-+ // the client can queue after-seek-buffers while we are finishing with
-+ // the before-seek one.
-+ break;
-+
-+ default:
-+ RETURN_AND_NOTIFY_ON_FAILURE(false,
-+ "Decode request from client in invalid state: " << state_,
-+ PLATFORM_FAILURE, );
-+ break;
-+ }
-+}
-+
-+void VaapiVideoDecodeAccelerator::RecycleVASurfaceID(
-+ VASurfaceID va_surface_id) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ base::AutoLock auto_lock(lock_);
-+
-+ available_va_surfaces_.push_back(va_surface_id);
-+ surfaces_available_.Signal();
-+}
-+
-+void VaapiVideoDecodeAccelerator::AssignPictureBuffers(
-+ const std::vector<media::PictureBuffer>& buffers) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ base::AutoLock auto_lock(lock_);
-+ DCHECK(tfp_pictures_.empty());
-+
-+ while (!output_buffers_.empty())
-+ output_buffers_.pop();
-+
-+ RETURN_AND_NOTIFY_ON_FAILURE(
-+ buffers.size() == requested_num_pics_,
-+ "Got an invalid number of picture buffers. (Got " << buffers.size()
-+ << ", requested " << requested_num_pics_ << ")", INVALID_ARGUMENT, );
-+ DCHECK(requested_pic_size_ == buffers[0].size());
-+
-+ std::vector<VASurfaceID> va_surface_ids;
-+ RETURN_AND_NOTIFY_ON_FAILURE(
-+ vaapi_wrapper_->CreateSurfaces(requested_pic_size_,
-+ buffers.size(),
-+ &va_surface_ids),
-+ "Failed creating VA Surfaces", PLATFORM_FAILURE, );
-+ DCHECK_EQ(va_surface_ids.size(), buffers.size());
-+
-+ for (size_t i = 0; i < buffers.size(); ++i) {
-+ DVLOG(2) << "Assigning picture id: " << buffers[i].id()
-+ << " to texture id: " << buffers[i].texture_id()
-+ << " VASurfaceID: " << va_surface_ids[i];
-+
-+ linked_ptr<TFPPicture> tfp_picture(
-+ TFPPicture::Create(make_context_current_, egl_display_, x_display_,
-+ buffers[i].id(), buffers[i].texture_id(),
-+ requested_pic_size_));
-+
-+ RETURN_AND_NOTIFY_ON_FAILURE(
-+ tfp_picture.get(), "Failed assigning picture buffer to a texture.",
-+ PLATFORM_FAILURE, );
-+
-+ bool inserted = tfp_pictures_.insert(std::make_pair(
-+ buffers[i].id(), tfp_picture)).second;
-+ DCHECK(inserted);
-+
-+ output_buffers_.push(buffers[i].id());
-+ available_va_surfaces_.push_back(va_surface_ids[i]);
-+ surfaces_available_.Signal();
-+ }
-+
-+ state_ = kDecoding;
-+ decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::DecodeTask, base::Unretained(this)));
-+}
-+
-+void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ TRACE_EVENT1("Video Decoder", "VAVDA::ReusePictureBuffer", "Picture id",
-+ picture_buffer_id);
-+
-+ --num_frames_at_client_;
-+ TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_);
-+
-+ output_buffers_.push(picture_buffer_id);
-+ TryOutputSurface();
-+}
-+
-+void VaapiVideoDecodeAccelerator::FlushTask() {
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+ DVLOG(1) << "Flush task";
-+
-+ // First flush all the pictures that haven't been outputted, notifying the
-+ // client to output them.
-+ bool res = decoder_->Flush();
-+ RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed flushing the decoder.",
-+ PLATFORM_FAILURE, );
-+
-+ // Put the decoder in idle state, ready to resume.
-+ decoder_->Reset();
-+
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::FinishFlush, weak_this_));
-+}
-+
-+void VaapiVideoDecodeAccelerator::Flush() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ DVLOG(1) << "Got flush request";
-+
-+ base::AutoLock auto_lock(lock_);
-+ state_ = kFlushing;
-+ // Queue a flush task after all existing decoding tasks to clean up.
-+ decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::FlushTask, base::Unretained(this)));
-+
-+ input_ready_.Signal();
-+ surfaces_available_.Signal();
-+}
-+
-+void VaapiVideoDecodeAccelerator::FinishFlush() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ finish_flush_pending_ = false;
-+
-+ base::AutoLock auto_lock(lock_);
-+ if (state_ != kFlushing) {
-+ DCHECK_EQ(state_, kDestroying);
-+ return; // We could've gotten destroyed already.
-+ }
-+
-+ // Still waiting for textures from client to finish outputting all pending
-+ // frames. Try again later.
-+ if (!pending_output_cbs_.empty()) {
-+ finish_flush_pending_ = true;
-+ return;
-+ }
-+
-+ state_ = kIdle;
-+
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &Client::NotifyFlushDone, client_));
-+
-+ DVLOG(1) << "Flush finished";
-+}
-+
-+void VaapiVideoDecodeAccelerator::ResetTask() {
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+ DVLOG(1) << "ResetTask";
-+
-+ // All the decoding tasks from before the reset request from client are done
-+ // by now, as this task was scheduled after them and client is expected not
-+ // to call Decode() after Reset() and before NotifyResetDone.
-+ decoder_->Reset();
-+
-+ base::AutoLock auto_lock(lock_);
-+
-+ // Return current input buffer, if present.
-+ if (curr_input_buffer_.get())
-+ ReturnCurrInputBuffer_Locked();
-+
-+ // And let client know that we are done with reset.
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::FinishReset, weak_this_));
-+}
-+
-+void VaapiVideoDecodeAccelerator::Reset() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ DVLOG(1) << "Got reset request";
-+
-+ // This will make any new decode tasks exit early.
-+ base::AutoLock auto_lock(lock_);
-+ state_ = kResetting;
-+ finish_flush_pending_ = false;
-+
-+ // Drop all remaining input buffers, if present.
-+ while (!input_buffers_.empty()) {
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &Client::NotifyEndOfBitstreamBuffer, client_,
-+ input_buffers_.front()->id));
-+ input_buffers_.pop();
-+ }
-+
-+ decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::ResetTask, base::Unretained(this)));
-+
-+ input_ready_.Signal();
-+ surfaces_available_.Signal();
-+}
-+
-+void VaapiVideoDecodeAccelerator::FinishReset() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ DVLOG(1) << "FinishReset";
-+ base::AutoLock auto_lock(lock_);
-+
-+ if (state_ != kResetting) {
-+ DCHECK(state_ == kDestroying || state_ == kUninitialized) << state_;
-+ return; // We could've gotten destroyed already.
-+ }
-+
-+ // Drop pending outputs.
-+ while (!pending_output_cbs_.empty())
-+ pending_output_cbs_.pop();
-+
-+ if (awaiting_va_surfaces_recycle_) {
-+ // Decoder requested a new surface set while we were waiting for it to
-+ // finish the last DecodeTask, running at the time of Reset().
-+ // Let the surface set change finish first before resetting.
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::FinishReset, weak_this_));
-+ return;
-+ }
-+
-+ num_stream_bufs_at_decoder_ = 0;
-+ state_ = kIdle;
-+
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &Client::NotifyResetDone, client_));
-+
-+ // The client might have given us new buffers via Decode() while we were
-+ // resetting and might be waiting for our move, and not call Decode() anymore
-+ // until we return something. Post a DecodeTask() so that we won't
-+ // sleep forever waiting for Decode() in that case. Having two of them
-+ // in the pipe is harmless, the additional one will return as soon as it sees
-+ // that we are back in kDecoding state.
-+ if (!input_buffers_.empty()) {
-+ state_ = kDecoding;
-+ decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::DecodeTask,
-+ base::Unretained(this)));
-+ }
-+
-+ DVLOG(1) << "Reset finished";
-+}
-+
-+void VaapiVideoDecodeAccelerator::Cleanup() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ if (state_ == kUninitialized || state_ == kDestroying)
-+ return;
-+
-+ DVLOG(1) << "Destroying VAVDA";
-+ base::AutoLock auto_lock(lock_);
-+ state_ = kDestroying;
-+
-+ client_ptr_factory_.InvalidateWeakPtrs();
-+
-+ {
-+ base::AutoUnlock auto_unlock(lock_);
-+ // Post a dummy task to the decoder_thread_ to ensure it is drained.
-+ base::WaitableEvent waiter(false, false);
-+ decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
-+ &base::WaitableEvent::Signal, base::Unretained(&waiter)));
-+ input_ready_.Signal();
-+ surfaces_available_.Signal();
-+ waiter.Wait();
-+ decoder_thread_.Stop();
-+ }
-+
-+ state_ = kUninitialized;
-+}
-+
-+void VaapiVideoDecodeAccelerator::Destroy() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ Cleanup();
-+ delete this;
-+}
-+
-+} // namespace content
-diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator_tizen.h b/content/common/gpu/media/vaapi_video_decode_accelerator_tizen.h
-new file mode 100644
-index 0000000..d41cf38
---- /dev/null
-+++ b/content/common/gpu/media/vaapi_video_decode_accelerator_tizen.h
-@@ -0,0 +1,273 @@
-+// Copyright (c) 2013 Intel Corporation. All rights reserved.
-+// Use of this source code is governed by a BSD-style license that can be
-+// found in the LICENSE file.
-+//
-+// This file contains an implementation of VideoDecoderAccelerator
-+// that utilizes hardware video decoder present on Intel CPUs for Tizen.
-+
-+#ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_VIDEO_DECODE_ACCELERATOR_H_
-+#define CONTENT_COMMON_GPU_MEDIA_VAAPI_VIDEO_DECODE_ACCELERATOR_H_
-+
-+#include <map>
-+#include <queue>
-+#include <utility>
-+#include <vector>
-+
-+#include "base/logging.h"
-+#include "base/memory/linked_ptr.h"
-+#include "base/memory/shared_memory.h"
-+#include "base/memory/weak_ptr.h"
-+#include "base/message_loop/message_loop.h"
-+#include "base/synchronization/condition_variable.h"
-+#include "base/synchronization/lock.h"
-+#include "base/threading/non_thread_safe.h"
-+#include "base/threading/thread.h"
-+#include "content/common/content_export.h"
-+#include "content/common/gpu/media/vaapi_h264_decoder.h"
-+#include "content/common/gpu/media/vaapi_wrapper.h"
-+#include "content/common/gpu/media/video_decode_accelerator_impl.h"
-+#include "media/base/bitstream_buffer.h"
-+#include "media/video/picture.h"
-+#include "media/video/video_decode_accelerator.h"
-+#include "ui/gl/gl_bindings.h"
-+
-+namespace content {
-+
-+// Class to provide video decode acceleration for Intel systems with hardware
-+// support for it, and on which libva is available.
-+// Decoding tasks are performed in a separate decoding thread.
-+//
-+// Threading/life-cycle: this object is created & destroyed on the GPU
-+// ChildThread. A few methods on it are called on the decoder thread which is
-+// stopped during |this->Destroy()|, so any tasks posted to the decoder thread
-+// can assume |*this| is still alive. See |weak_this_| below for more details.
-+class CONTENT_EXPORT VaapiVideoDecodeAccelerator
-+ : public VideoDecodeAcceleratorImpl {
-+ public:
-+ VaapiVideoDecodeAccelerator(
-+ EGLDisplay egl_display, EGLContext egl_context,
-+ Client* client,
-+ const base::Callback<bool(void)>& make_context_current);
-+ virtual ~VaapiVideoDecodeAccelerator();
-+
-+ // media::VideoDecodeAccelerator implementation.
-+ virtual bool Initialize(media::VideoCodecProfile profile) OVERRIDE;
-+ virtual void Decode(const media::BitstreamBuffer& bitstream_buffer) OVERRIDE;
-+ virtual void AssignPictureBuffers(
-+ const std::vector<media::PictureBuffer>& buffers) OVERRIDE;
-+ virtual void ReusePictureBuffer(int32 picture_buffer_id) OVERRIDE;
-+ virtual void Flush() OVERRIDE;
-+ virtual void Reset() OVERRIDE;
-+ virtual void Destroy() OVERRIDE;
-+
-+private:
-+ // Notify the client that |output_id| is ready for displaying.
-+ void NotifyPictureReady(int32 input_id, int32 output_id);
-+
-+ // Notify the client that an error has occurred and decoding cannot continue.
-+ void NotifyError(Error error);
-+
-+ // Map the received input buffer into this process' address space and
-+ // queue it for decode.
-+ void MapAndQueueNewInputBuffer(
-+ const media::BitstreamBuffer& bitstream_buffer);
-+
-+ // Get a new input buffer from the queue and set it up in decoder. This will
-+ // sleep if no input buffers are available. Return true if a new buffer has
-+ // been set up, false if an early exit has been requested (due to initiated
-+ // reset/flush/destroy).
-+ bool GetInputBuffer_Locked();
-+
-+ // Signal the client that the current buffer has been read and can be
-+ // returned. Will also release the mapping.
-+ void ReturnCurrInputBuffer_Locked();
-+
-+ // Pass one or more output buffers to the decoder. This will sleep
-+ // if no buffers are available. Return true if buffers have been set up or
-+ // false if an early exit has been requested (due to initiated
-+ // reset/flush/destroy).
-+ bool FeedDecoderWithOutputSurfaces_Locked();
-+
-+ // Continue decoding given input buffers and sleep waiting for input/output
-+ // as needed. Will exit if a new set of surfaces or reset/flush/destroy
-+ // is requested.
-+ void DecodeTask();
-+
-+ // Scheduled after receiving a flush request and executed after the current
-+ // decoding task finishes decoding pending inputs. Makes the decoder return
-+ // all remaining output pictures and puts it in an idle state, ready
-+ // to resume if needed and schedules a FinishFlush.
-+ void FlushTask();
-+
-+ // Scheduled by the FlushTask after decoder is flushed to put VAVDA into idle
-+ // state and notify the client that flushing has been finished.
-+ void FinishFlush();
-+
-+ // Scheduled after receiving a reset request and executed after the current
-+ // decoding task finishes decoding the current frame. Puts the decoder into
-+ // an idle state, ready to resume if needed, discarding decoded but not yet
-+ // outputted pictures (decoder keeps ownership of their associated picture
-+ // buffers). Schedules a FinishReset afterwards.
-+ void ResetTask();
-+
-+ // Scheduled by ResetTask after it's done putting VAVDA into an idle state.
-+ // Drops remaining input buffers and notifies the client that reset has been
-+ // finished.
-+ void FinishReset();
-+
-+ // Helper for Destroy(), doing all the actual work except for deleting self.
-+ void Cleanup();
-+
-+ // Get a usable framebuffer configuration for use in binding textures
-+ // or return false on failure.
-+ bool InitializeFBConfig();
-+
-+ // Callback for the decoder to execute when it wants us to output given
-+ // |va_surface|.
-+ void SurfaceReady(int32 input_id, const scoped_refptr<VASurface>& va_surface);
-+
-+ // Represents a texture bound to an X Pixmap for output purposes.
-+ class TFPPicture;
-+
-+ // Callback to be executed once we have a |va_surface| to be output and
-+ // an available |tfp_picture| to use for output.
-+ // Puts contents of |va_surface| into given |tfp_picture|, releases the
-+ // surface and passes the resulting picture to client for output.
-+ void OutputPicture(const scoped_refptr<VASurface>& va_surface,
-+ int32 input_id,
-+ TFPPicture* tfp_picture);
-+
-+ // Try to OutputPicture() if we have both a ready surface and picture.
-+ void TryOutputSurface();
-+
-+ // Called when a VASurface is no longer in use by the decoder or is not being
-+ // synced/waiting to be synced to a picture. Returns it to available surfaces
-+ // pool.
-+ void RecycleVASurfaceID(VASurfaceID va_surface_id);
-+
-+ // Initiate wait cycle for surfaces to be released before we release them
-+ // and allocate new ones, as requested by the decoder.
-+ void InitiateSurfaceSetChange(size_t num_pics, gfx::Size size);
-+ // Check if the surfaces have been released or post ourselves for later.
-+ void TryFinishSurfaceSetChange();
-+
-+ // Client-provided X/EGL state.
-+ Display* x_display_;
-+ EGLDisplay egl_display_;
-+ EGLContext egl_context_;
-+ base::Callback<bool(void)> make_context_current_;
-+
-+ // VAVDA state.
-+ enum State {
-+ // Initialize() not called yet or failed.
-+ kUninitialized,
-+ // DecodeTask running.
-+ kDecoding,
-+ // Resetting, waiting for decoder to finish current task and cleanup.
-+ kResetting,
-+ // Flushing, waiting for decoder to finish current task and cleanup.
-+ kFlushing,
-+ // Idle, decoder in state ready to start/resume decoding.
-+ kIdle,
-+ // Destroying, waiting for the decoder to finish current task.
-+ kDestroying,
-+ };
-+
-+ // Protects input buffer and surface queues and state_.
-+ base::Lock lock_;
-+ State state_;
-+
-+ // An input buffer awaiting consumption, provided by the client.
-+ struct InputBuffer {
-+ InputBuffer();
-+ ~InputBuffer();
-+
-+ int32 id;
-+ size_t size;
-+ scoped_ptr<base::SharedMemory> shm;
-+ };
-+
-+ // Queue for incoming input buffers.
-+ typedef std::queue<linked_ptr<InputBuffer> > InputBuffers;
-+ InputBuffers input_buffers_;
-+ // Signalled when input buffers are queued onto the input_buffers_ queue.
-+ base::ConditionVariable input_ready_;
-+
-+ // Current input buffer at decoder.
-+ linked_ptr<InputBuffer> curr_input_buffer_;
-+
-+ // Queue for incoming output buffers (texture ids).
-+ typedef std::queue<int32> OutputBuffers;
-+ OutputBuffers output_buffers_;
-+
-+ typedef std::map<int32, linked_ptr<TFPPicture> > TFPPictures;
-+ // All allocated TFPPictures, regardless of their current state. TFPPictures
-+ // are allocated once and destroyed at the end of decode.
-+ TFPPictures tfp_pictures_;
-+
-+ // Return a TFPPicture associated with given client-provided id.
-+ TFPPicture* TFPPictureById(int32 picture_buffer_id);
-+
-+ // VA Surfaces no longer in use that can be passed back to the decoder for
-+ // reuse, once it requests them.
-+ std::list<VASurfaceID> available_va_surfaces_;
-+ // Signalled when output surfaces are queued onto the available_va_surfaces_
-+ // queue.
-+ base::ConditionVariable surfaces_available_;
-+
-+ // Pending output requests from the decoder. When it indicates that we should
-+ // output a surface and we have an available TFPPicture (i.e. texture) ready
-+ // to use, we'll execute the callback passing the TFPPicture. The callback
-+ // will put the contents of the surface into the picture and return it to
-+ // the client, releasing the surface as well.
-+ // If we don't have any available TFPPictures at the time when the decoder
-+ // requests output, we'll store the request on pending_output_cbs_ queue for
-+ // later and run it once the client gives us more textures
-+ // via ReusePictureBuffer().
-+ typedef base::Callback<void(TFPPicture*)> OutputCB;
-+ std::queue<OutputCB> pending_output_cbs_;
-+
-+ // ChildThread's message loop
-+ base::MessageLoop* message_loop_;
-+
-+ // WeakPtr<> pointing to |this| for use in posting tasks from the decoder
-+ // thread back to the ChildThread. Because the decoder thread is a member of
-+ // this class, any task running on the decoder thread is guaranteed that this
-+ // object is still alive. As a result, tasks posted from ChildThread to
-+ // decoder thread should use base::Unretained(this), and tasks posted from the
-+ // decoder thread to the ChildThread should use |weak_this_|.
-+ base::WeakPtr<VaapiVideoDecodeAccelerator> weak_this_;
-+
-+ // To expose client callbacks from VideoDecodeAccelerator.
-+ // NOTE: all calls to these objects *MUST* be executed on message_loop_.
-+ base::WeakPtrFactory<Client> client_ptr_factory_;
-+ base::WeakPtr<Client> client_;
-+
-+ scoped_ptr<VaapiWrapper> vaapi_wrapper_;
-+
-+ // Comes after vaapi_wrapper_ to ensure its destructor is executed before
-+ // vaapi_wrapper_ is destroyed.
-+ scoped_ptr<VaapiH264Decoder> decoder_;
-+ base::Thread decoder_thread_;
-+
-+ int num_frames_at_client_;
-+ int num_stream_bufs_at_decoder_;
-+
-+ // Whether we are waiting for any pending_output_cbs_ to be run before
-+ // NotifyingFlushDone.
-+ bool finish_flush_pending_;
-+
-+ // Decoder requested a new surface set and we are waiting for all the surfaces
-+ // to be returned before we can free them.
-+ bool awaiting_va_surfaces_recycle_;
-+
-+ // Last requested number/resolution of output picture buffers.
-+ size_t requested_num_pics_;
-+ gfx::Size requested_pic_size_;
-+
-+ DISALLOW_COPY_AND_ASSIGN(VaapiVideoDecodeAccelerator);
-+};
-+
-+} // namespace content
-+
-+#endif // CONTENT_COMMON_GPU_MEDIA_VAAPI_VIDEO_DECODE_ACCELERATOR_H_
-diff --git a/content/content_common.gypi b/content/content_common.gypi
-index 9d6cb61..3f53dd5 100644
---- a/content/content_common.gypi
-+++ b/content/content_common.gypi
-@@ -583,6 +583,32 @@
- '<(DEPTH)/third_party/libva',
- ],
- }],
-+ ['target_arch != "arm" and tizen_mobile == 1 and use_x11 == 1', {
-+ 'dependencies': [
-+ '../media/media.gyp:media',
-+ ],
-+ 'sources': [
-+ 'common/gpu/media/h264_dpb.cc',
-+ 'common/gpu/media/h264_dpb.h',
-+ 'common/gpu/media/va_surface.h',
-+ 'common/gpu/media/vaapi_h264_decoder.cc',
-+ 'common/gpu/media/vaapi_h264_decoder.h',
-+ 'common/gpu/media/vaapi_video_decode_accelerator_tizen.cc',
-+ 'common/gpu/media/vaapi_video_decode_accelerator_tizen.h',
-+ 'common/gpu/media/vaapi_wrapper.cc',
-+ 'common/gpu/media/vaapi_wrapper.h',
-+ ],
-+ 'include_dirs': [
-+ '<(DEPTH)/third_party/libva',
-+ '<(DEPTH)/third_party/khronos',
-+ ],
-+ 'link_settings': {
-+ 'libraries': [
-+ '-lEGL',
-+ '-lGLESv2',
-+ ],
-+ },
-+ }],
- ['OS=="win"', {
- 'dependencies': [
- '../media/media.gyp:media',
-diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
-index 9e29e03..2c04d40 100644
---- a/content/gpu/gpu_main.cc
-+++ b/content/gpu/gpu_main.cc
-@@ -42,7 +42,8 @@
- #include "sandbox/win/src/sandbox.h"
- #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
- #include "content/common/gpu/media/exynos_video_decode_accelerator.h"
--#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
-+#elif (defined(OS_CHROMEOS) || defined(OS_TIZEN_MOBILE)) &&\
-+ defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
- #include "content/common/gpu/media/vaapi_wrapper.h"
- #endif
-
-@@ -360,7 +361,8 @@ bool WarmUpSandbox(const CommandLine& command_line) {
-
- #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
- ExynosVideoDecodeAccelerator::PreSandboxInitialization();
--#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
-+#elif (defined(OS_CHROMEOS) || defined(OS_TIZEN_MOBILE)) &&\
-+ defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
- VaapiWrapper::PreSandboxInitialization();
- #endif
-
---
-1.8.3.2
-
%bcond_with wayland
Name: crosswalk
-Version: 5.34.105.0
+Version: 6.34.113.0
Release: 0
Summary: Crosswalk is an app runtime based on Chromium
License: (BSD-3-Clause and LGPL-2.1+)
Source1002: %{name}.xml.in
Source1003: %{name}.png
Patch1: %{name}-do-not-look-for-gtk2-when-using-aura.patch
-Patch7: %{name}-tizen-audio-session-manager.patch
Patch8: %{name}-mesa-ozone-typedefs.patch
Patch9: Blink-Add-GCC-flag-Wno-narrowing-fix-64bits-build.patch
BuildRequires: flex
BuildRequires: gperf
BuildRequires: libcap-devel
+BuildRequires: ninja
BuildRequires: python
BuildRequires: python-xml
BuildRequires: perl
BuildRequires: which
BuildRequires: pkgconfig(alsa)
BuildRequires: pkgconfig(appcore-common)
-BuildRequires: pkgconfig(audio-session-mgr)
BuildRequires: pkgconfig(cairo)
BuildRequires: pkgconfig(capi-location-manager)
BuildRequires: pkgconfig(dbus-1)
cp -a src/xwalk/LICENSE LICENSE.xwalk
%patch1
-%patch7
%if "%{tizen}" < "3.0"
%patch2
# build root to the BUILDDIR_NAME definition, such as "/var/tmp/xwalk-build"
# (remember all paths are still inside the chroot):
# gbs build --define 'BUILDDIR_NAME /some/path'
-#
-# The --depth and --generator-output combo is used to put all the Makefiles
-# inside the build directory, and (this is the important part) keep file lists
-# (generatedwith <|() in gyp) in the build directory as well, otherwise they
-# will be in the source directory, erased every time and trigger an almost full
-# Blink rebuild (among other smaller targets).
-# We cannot always pass those flags, though, because gyp's make generator does
-# not work if the --generator-output is the top-level source directory.
BUILDDIR_NAME="%{?BUILDDIR_NAME}"
-if [ -z "${BUILDDIR_NAME}" ]; then
- BUILDDIR_NAME="."
-else
- GYP_EXTRA_FLAGS="--depth=. --generator-output=${BUILDDIR_NAME}"
+if [ -n "${BUILDDIR_NAME}" ]; then
+ mkdir -p "${BUILDDIR_NAME}"
+ ln -s "${BUILDDIR_NAME}" src/out
fi
%if %{with wayland}
-GYP_EXTRA_FLAGS="${GYP_EXTRA_FLAGS} -Duse_ash=1 -Duse_ozone=1"
+GYP_EXTRA_FLAGS="${GYP_EXTRA_FLAGS} -Duse_ozone=1"
%endif
-# Change src/ so that we can pass "." to --depth below, otherwise we would need
-# to pass "src" to it, but this confuses the gyp make generator, that expects
-# to be called from the root source directory.
-cd src
-
# --no-parallel is added because chroot does not mount a /dev/shm, this will
# cause python multiprocessing.SemLock error.
-export GYP_GENERATORS='make'
-./xwalk/gyp_xwalk xwalk/xwalk.gyp \
+export GYP_GENERATORS='ninja'
+./src/xwalk/gyp_xwalk src/xwalk/xwalk.gyp \
--no-parallel \
${GYP_EXTRA_FLAGS} \
-Dchromeos=0 \
-Duse_gconf=0 \
-Duse_kerberos=0 \
-Duse_system_bzip2=1 \
--Duse_system_icu=1 \
-Duse_system_libexif=1 \
-Duse_system_libxml=1 \
-Duse_system_nspr=1 \
--Denable_xi21_mt=1 \
--Duse_xi2_mt=0 \
-Denable_hidpi=1
-make %{?_smp_mflags} -C "${BUILDDIR_NAME}" BUILDTYPE=Release xwalk xwalkctl xwalk_launcher xwalk-pkg-helper
+ninja %{?_smp_mflags} -C src/out/Release xwalk xwalkctl xwalk_launcher xwalk-pkg-helper
%install
-# Support building in a non-standard directory, possibly outside %{_builddir}.
-# Since the build root is erased every time a new build is performed, one way
-# to avoid losing the build directory is to specify a location outside the
-# build root to the BUILDDIR_NAME definition, such as "/var/tmp/xwalk-build"
-# (remember all paths are still inside the chroot):
-# gbs build --define 'BUILDDIR_NAME /some/path'
-BUILDDIR_NAME="%{?BUILDDIR_NAME}"
-if [ -z "${BUILDDIR_NAME}" ]; then
- BUILDDIR_NAME="."
-fi
-
-# Since BUILDDIR_NAME can be either a relative path or an absolute one, we need
-# to cd into src/ so that it means the same thing in the build and install
-# stages: during the former, a relative location refers to a place inside src/,
-# whereas during the latter a relative location by default would refer to a
-# place one directory above src/. If BUILDDIR_NAME is an absolute path, this is
-# irrelevant anyway.
-cd src
-
# Binaries.
-install -p -D ../xwalk %{buildroot}%{_bindir}/xwalk
+install -p -D xwalk %{buildroot}%{_bindir}/xwalk
install -p -D %{SOURCE2} %{buildroot}%{_dbusservicedir}/org.crosswalkproject.Runtime1.service
-install -p -D ../xwalk.service %{buildroot}%{_systemduserservicedir}/xwalk.service
-install -p -D ${BUILDDIR_NAME}/out/Release/xwalk %{buildroot}%{_libdir}/xwalk/xwalk
-install -p -D ${BUILDDIR_NAME}/out/Release/xwalkctl %{buildroot}%{_bindir}/xwalkctl
-install -p -D ${BUILDDIR_NAME}/out/Release/xwalk-launcher %{buildroot}%{_bindir}/xwalk-launcher
+install -p -D xwalk.service %{buildroot}%{_systemduserservicedir}/xwalk.service
+install -p -D src/out/Release/xwalk %{buildroot}%{_libdir}/xwalk/xwalk
+install -p -D src/out/Release/xwalkctl %{buildroot}%{_bindir}/xwalkctl
+install -p -D src/out/Release/xwalk-launcher %{buildroot}%{_bindir}/xwalk-launcher
# xwalk-pkg-helper needs to be set-user-ID-root so it can finish the installation process.
-install -m 06755 -p -D ${BUILDDIR_NAME}/out/Release/xwalk-pkg-helper %{buildroot}%{_bindir}/xwalk-pkg-helper
+install -m 06755 -p -D src/out/Release/xwalk-pkg-helper %{buildroot}%{_bindir}/xwalk-pkg-helper
# Supporting libraries and resources.
-install -p -D ${BUILDDIR_NAME}/out/Release/icudtl.dat %{buildroot}%{_libdir}/xwalk/icudtl.dat
-install -p -D ${BUILDDIR_NAME}/out/Release/libffmpegsumo.so %{buildroot}%{_libdir}/xwalk/libffmpegsumo.so
-install -p -D ${BUILDDIR_NAME}/out/Release/xwalk.pak %{buildroot}%{_libdir}/xwalk/xwalk.pak
+install -p -D src/out/Release/icudtl.dat %{buildroot}%{_libdir}/xwalk/icudtl.dat
+install -p -D src/out/Release/libffmpegsumo.so %{buildroot}%{_libdir}/xwalk/libffmpegsumo.so
+install -p -D src/out/Release/xwalk.pak %{buildroot}%{_libdir}/xwalk/xwalk.pak
# Register xwalk to the package manager.
-install -p -D ../%{name}.xml %{buildroot}%{_manifestdir}/%{name}.xml
-install -p -D ../%{name}.png %{buildroot}%{_desktop_icondir}/%{name}.png
-
+install -p -D %{name}.xml %{buildroot}%{_manifestdir}/%{name}.xml
+install -p -D %{name}.png %{buildroot}%{_desktop_icondir}/%{name}.png
%post
mkdir -p %{_desktop_icondir_ro}
_VALID_OS_MACROS = (
# Please keep sorted.
'OS_ANDROID',
+ 'OS_ANDROID_HOST',
'OS_BSD',
'OS_CAT', # For testing.
'OS_CHROMEOS',
# hence the *_android.cc files are included but the actual code
# doesn't have OS_ANDROID / ANDROID defined.
'conditions': [
- # Host build on linux depends on system.gyp::gtk as
- # default linux build has TOOLKIT_GTK defined.
- ['host_os == "linux"', {
- 'sources/': [
- ['include', '^atomicops_internals_x86_gcc\\.cc$'],
- ],
- 'dependencies': [
- '../build/linux/system.gyp:gtk',
- ],
- 'export_dependent_settings': [
- '../build/linux/system.gyp:gtk',
- ],
- }],
['host_os == "mac"', {
'sources/': [
['exclude', '^native_library_linux\\.cc$'],
],
}],
['OS == "android" and _toolset == "host" and host_os == "linux"', {
+ 'defines': [
+ 'OS_ANDROID_HOST=Linux',
+ ],
'sources/': [
# Pull in specific files for host builds.
+ ['include', '^atomicops_internals_x86_gcc\\.cc$'],
['include', '^threading/platform_thread_linux\\.cc$'],
],
}],
#include "base/message_loop/message_pump_x11.h"
#elif defined(USE_OZONE) && !defined(OS_NACL)
#include "base/message_loop/message_pump_ozone.h"
-#else
+#elif !defined(OS_ANDROID_HOST)
#define USE_GTK_MESSAGE_PUMP
#include "base/message_loop/message_pump_gtk.h"
#if defined(TOOLKIT_GTK)
class ThreadTaskRunnerHandle;
#if defined(OS_ANDROID)
class MessagePumpForUI;
+#elif defined(OS_ANDROID_HOST)
+typedef MessagePumpLibevent MessagePumpForUI;
#endif
class WaitableEvent;
-LASTCHANGE=254894
+LASTCHANGE=257853
int pa_context_errno(pa_context *c);
const char* pa_strerror(int error);
pa_cvolume* pa_cvolume_set(pa_cvolume* a, unsigned channels, pa_volume_t v);
+# Functions from pulse used in TIZEN to tag the audio stream as "browser".
+pa_proplist* pa_proplist_new(void);
+void pa_proplist_free(pa_proplist* p);
+int pa_proplist_sets(pa_proplist *p, const char *key, const char *value);
+pa_stream* pa_stream_new_with_proplist(pa_context* c, const char* name, const pa_sample_spec* ss, const pa_channel_map* map, pa_proplist* proplist);
// than the default channel map (NULL).
map = &source_channel_map;
}
+#if defined(OS_TIZEN)
+ pa_proplist* proplist = pa_proplist_new();
+ pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "browser");
+ *stream = pa_stream_new_with_proplist(*context, "Playback",
+ &sample_specifications,
+ map, proplist);
+ pa_proplist_free(proplist);
+#else
*stream = pa_stream_new(*context, "Playback", &sample_specifications, map);
+#endif
RETURN_ON_FAILURE(*stream, "failed to create PA playback stream");
pa_stream_set_state_callback(*stream, stream_callback, user_data);
namespace ozonewayland {
OzoneDisplay* OzoneDisplay::instance_ = NULL;
-const int kMaxDisplaySize = 20;
OzoneDisplay* OzoneDisplay::GetInstance() {
return instance_;
display_(NULL),
channel_(NULL),
host_(NULL),
- event_converter_(NULL),
- spec_(NULL) {
+ event_converter_(NULL) {
instance_ = this;
}
instance_ = NULL;
}
-const char* OzoneDisplay::DefaultDisplaySpec() {
- if (!spec_) {
- spec_ = new char[kMaxDisplaySize];
- if (desktop_screen_ && !desktop_screen_->geometry().size().IsEmpty()) {
- gfx::Rect rect(desktop_screen_->geometry());
- base::snprintf(spec_,
- kMaxDisplaySize,
- "%dx%d*2",
- rect.width(),
- rect.height());
- } else {
- spec_[0] = '\0';
- }
- }
-
- if (spec_[0] == '\0')
- NOTREACHED() <<
- "OutputHandleMode should come from Wayland compositor first";
-
- return spec_;
-}
-
bool OzoneDisplay::InitializeHardware() {
display_ = new WaylandDisplay(WaylandDisplay::RegisterAsNeeded);
bool initialized_hardware = display_->display() ? true : false;
}
void OzoneDisplay::OnOutputSizeChanged(unsigned width, unsigned height) {
- if (spec_)
- base::snprintf(spec_, kMaxDisplaySize, "%dx%d*2", width, height);
if (desktop_screen_)
desktop_screen_->SetGeometry(gfx::Rect(0, 0, width, height));
}
if (!event_converter_ && !desktop_screen_)
return;
- if (spec_)
- delete[] spec_;
-
delete channel_;
if (desktop_screen_) {
delete desktop_screen_;
OzoneDisplay();
virtual ~OzoneDisplay();
- const char* DefaultDisplaySpec();
bool InitializeHardware();
void ShutdownHardware();
intptr_t GetNativeDisplay();
OzoneDisplayChannel* channel_;
OzoneDisplayChannelHost* host_;
EventConverterOzoneWayland* event_converter_;
- char* spec_;
static OzoneDisplay* instance_;
DISALLOW_COPY_AND_ASSIGN(OzoneDisplay);
};
SurfaceFactoryWayland::~SurfaceFactoryWayland() {
}
-const char* SurfaceFactoryWayland::DefaultDisplaySpec() {
- return OzoneDisplay::GetInstance()->DefaultDisplaySpec();
-}
-
gfx::Screen* SurfaceFactoryWayland::CreateDesktopScreen() {
return OzoneDisplay::GetInstance()->CreateDesktopScreen();
}
SurfaceFactoryWayland();
virtual ~SurfaceFactoryWayland();
- virtual const char* DefaultDisplaySpec() OVERRIDE;
virtual gfx::Screen* CreateDesktopScreen() OVERRIDE;
virtual SurfaceFactoryOzone::HardwareState InitializeHardware() OVERRIDE;
virtual intptr_t GetNativeDisplay() OVERRIDE;
aura_windows_ = NULL;
}
- if (!current_active_window_ || current_active_window_->window_ != handle ||
- !open_windows_) {
+ if (!current_active_window_ ||
+ GetWindowHandle(current_active_window_->window_) != handle ||
+ !open_windows_) {
return;
}
// Set first top level window in the list of open windows as dispatcher.
// This is just a guess of the window which would eventually be focussed.
// We should set the correct root window as dispatcher in OnWindowFocused.
- const std::list<gfx::AcceleratedWidget>& windows = open_windows();
+ const std::list<unsigned>& windows = open_windows();
DesktopWindowTreeHostWayland* rootWindow =
DesktopWindowTreeHostWayland::GetHostForAcceleratedWidget(
windows.front());
// Make sure the stacking order is correct. The activated window should be
// first one in list of open windows.
- std::list<gfx::AcceleratedWidget>& windows = open_windows();
+ std::list<unsigned>& windows = open_windows();
DCHECK(windows.size());
unsigned window_handle = current_active_window_->window_;
if (windows.front() != window_handle) {
const std::vector<aura::Window*>&
WindowTreeHostDelegateWayland::GetAllOpenWindows() {
if (!aura_windows_) {
- const std::list<gfx::AcceleratedWidget>& windows = open_windows();
+ const std::list<unsigned>& windows = open_windows();
DCHECK(windows.size());
aura_windows_ = new std::vector<aura::Window*>(windows.size());
std::transform(
event->StopPropagation();
}
-std::list<gfx::AcceleratedWidget>&
+std::list<unsigned>&
WindowTreeHostDelegateWayland::open_windows() {
if (!open_windows_)
- open_windows_ = new std::list<gfx::AcceleratedWidget>();
+ open_windows_ = new std::list<unsigned>();
return *open_windows_;
}
+unsigned
+WindowTreeHostDelegateWayland::GetWindowHandle(gfx::AcceleratedWidget widget) {
+ return static_cast<unsigned>(widget);
+}
+
ui::EventProcessor* WindowTreeHostDelegateWayland::GetEventProcessor() {
return current_dispatcher_->delegate_->GetEventProcessor();
}
// Don't dispatch events in case a window has installed itself as capture
// window but doesn't have the focus.
handle_event_ = current_capture_ ? current_focus_window_ ==
- current_capture_->GetAcceleratedWidget() : true;
- if (current_active_window_->window_ == handle)
+ GetWindowHandle(current_capture_->GetAcceleratedWidget()) : true;
+ if (GetWindowHandle(current_active_window_->window_) == handle)
return;
// A new window should not steal focus in case the current window has a open
// current_capture_ always be a valid pointer.
if (!handle || !current_capture_)
return;
- if (current_capture_->window_ != handle)
+ if (GetWindowHandle(current_capture_->window_) != handle)
return;
DesktopWindowTreeHostWayland* window = NULL;
window = DesktopWindowTreeHostWayland::GetHostForAcceleratedWidget(handle);
// Dispatches a mouse event.
void DispatchMouseEvent(ui::MouseEvent* event);
- std::list<gfx::AcceleratedWidget>& open_windows();
+ std::list<unsigned>& open_windows();
+ unsigned GetWindowHandle(gfx::AcceleratedWidget widget);
unsigned current_focus_window_;
bool handle_event_ :1;
DesktopWindowTreeHostWayland* current_capture_;
DesktopWindowTreeHostWayland* current_active_window_;
// List of all open windows.
- std::list<gfx::AcceleratedWidget>* open_windows_;
+ std::list<unsigned>* open_windows_;
// List of all open aura::Window.
std::vector<aura::Window*>* aura_windows_;
DISALLOW_COPY_AND_ASSIGN(WindowTreeHostDelegateWayland);
'host_forwarder_main.cc',
'pipe_notifier.cc',
'socket.cc',
- # TODO(pliard): Remove this. This is needed to avoid undefined
- # references at link time.
- '../../../base/message_loop/message_pump_glib.cc',
- '../../../base/message_loop/message_pump_gtk.cc',
],
},
],
{
'variables': {
'chromium_code': 1,
+ 'external_ozone_views_files': [],
},
'target_defaults': {
'conditions': [
],
}],
['use_ozone==1', {
+ 'sources': [
+ '<@(external_ozone_views_files)',
+ ],
'dependencies': [
'../ozone/ozone.gyp:ozone',
],
'v8_use_snapshot%': 'true',
+ # Enable XDK profiling support by default.
+ 'v8_enable_xdkprof': 1,
+
# With post mortem support enabled, metadata is embedded into libv8 that
# describes various parameters of the VM for use by debuggers. See
# tools/gen-postmortem-metadata.py for details.
EXTERNAL_##TYPE##_ELEMENTS); \
native_context()->set_##type##_array_fun(*fun); \
}
- TYPED_ARRAYS(INSTALL_TYPED_ARRAY)
+ BUILTIN_TYPED_ARRAY(INSTALL_TYPED_ARRAY)
#undef INSTALL_TYPED_ARRAY
Handle<JSFunction> data_view_fun =
#include "string-stream.h"
#include "vm-state-inl.h"
+// XDK support
+#include "third_party/xdk/xdk-v8.h"
+
namespace v8 {
namespace internal {
}
}
+ // XDK needs this function temporarily. It will be removed later.
+ void AppendAddress(Address address) {
+ Vector<char> buffer(utf8_buffer_ + utf8_pos_, kUtf8BufferSize - utf8_pos_);
+ int size = OS::SNPrintF(buffer, "0x%x", address);
+ if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
+ utf8_pos_ += size;
+ }
+ }
+
const char* get() { return utf8_buffer_; }
int size() const { return utf8_pos_; }
void* StartCodePosInfoEvent();
void EndCodePosInfoEvent(Code* code, void* jit_handler_data);
+
+ // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+ // XDK needs all this stuff below to generate the strings like
+ // "code-creation:..." in the same format as Logger generates.
+ // This string is sent to XDK by code_event_handler and then used for
+ // postprocessing. All these CodeCreateEvent(...) functions and helpers
+ // will be removed before commit.
+ void AppendCodeCreateHeader(NameBuffer* msg,
+ Logger::LogEventsAndTags tag,
+ Code* code) {
+ CHECK(msg);
+ msg->AppendBytes(kLogEventsNames[Logger::CODE_CREATION_EVENT]);
+ msg->AppendByte(',');
+ msg->AppendBytes(kLogEventsNames[tag]);
+ msg->AppendByte(',');
+ msg->AppendInt(code->kind());
+ msg->AppendByte(',');
+ msg->AppendAddress(code->instruction_start());
+ msg->AppendByte(',');
+ msg->AppendInt(code->instruction_size());
+ msg->AppendByte(',');
+ }
+
+
+ void AppendDetailed(NameBuffer* msg, String* str, bool show_impl_info) {
+ CHECK(msg);
+ if (str == NULL) return;
+ DisallowHeapAllocation no_gc; // Ensure string stay valid.
+ int len = str->length();
+ if (len > 0x1000)
+ len = 0x1000;
+ if (show_impl_info) {
+ msg->AppendByte(str->IsOneByteRepresentation() ? 'a' : '2');
+ if (StringShape(str).IsExternal())
+ msg->AppendByte('e');
+ if (StringShape(str).IsInternalized())
+ msg->AppendByte('#');
+ msg->AppendByte(':');
+ msg->AppendInt(str->length());
+ msg->AppendByte(':');
+ }
+ for (int i = 0; i < len; i++) {
+ uc32 c = str->Get(i);
+ if (c > 0xff) {
+ msg->AppendBytes("\\u");
+ msg->AppendHex(c);
+ } else if (c < 32 || c > 126) {
+ msg->AppendBytes("\\x");
+ msg->AppendHex(c);
+ } else if (c == ',') {
+ msg->AppendBytes("\\,");
+ } else if (c == '\\') {
+ msg->AppendBytes("\\\\");
+ } else if (c == '\"') {
+ msg->AppendBytes("\"\"");
+ } else {
+ msg->AppendByte(c);
+ }
+ }
+ }
+
+
+ void AppendDoubleQuotedString(NameBuffer* msg, const char* string) {
+ CHECK(msg);
+ msg->AppendByte('"');
+ for (const char* p = string; *p != '\0'; p++) {
+ if (*p == '"') {
+ msg->AppendByte('\\');
+ }
+ msg->AppendByte(*p);
+ }
+ msg->AppendByte('"');
+ }
+
+
+ void AppendSymbolName(NameBuffer* msg, Symbol* symbol) {
+ CHECK(msg);
+ ASSERT(symbol);
+ msg->AppendBytes("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ msg->AppendByte('"');
+ AppendDetailed(msg, String::cast(symbol->name()), false);
+ msg->AppendBytes("\" ");
+ }
+ msg->AppendBytes("hash ");
+ msg->AppendHex(symbol->Hash());
+ msg->AppendByte(')');
+ }
+
+
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code, const char* comment) {
+ if (!xdk::XDKIsAgentAlive()) {
+ CodeEventLogger::CodeCreateEvent(tag, code, comment);
+ return;
+ }
+
+ name_buffer_->Reset();
+ AppendCodeCreateHeader(name_buffer_, tag, code);
+ AppendDoubleQuotedString(name_buffer_, comment);
+ LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
+ }
+
+
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code, Name* name) {
+ if (!xdk::XDKIsAgentAlive()) {
+ CodeEventLogger::CodeCreateEvent(tag, code, name);
+ return;
+ }
+
+ name_buffer_->Reset();
+ AppendCodeCreateHeader(name_buffer_, tag, code);
+ if (name->IsString()) {
+ name_buffer_->AppendByte('"');
+ AppendDetailed(name_buffer_, String::cast(name), false);
+ name_buffer_->AppendByte('"');
+ } else {
+ AppendSymbolName(name_buffer_, Symbol::cast(name));
+ }
+ LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
+ }
+
+
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* name) {
+ if (!xdk::XDKIsAgentAlive()) {
+ CodeEventLogger::CodeCreateEvent(tag, code, shared, info, name);
+ return;
+ }
+
+ name_buffer_->Reset();
+ AppendCodeCreateHeader(name_buffer_, tag, code);
+ if (name->IsString()) {
+ SmartArrayPointer<char> str =
+ String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ name_buffer_->AppendByte('"');
+ name_buffer_->AppendBytes(str.get());
+ name_buffer_->AppendByte('"');
+ } else {
+ AppendSymbolName(name_buffer_, Symbol::cast(name));
+ }
+ name_buffer_->AppendByte(',');
+ name_buffer_->AppendAddress(shared->address());
+ name_buffer_->AppendByte(',');
+ name_buffer_->AppendBytes(ComputeMarker(code));
+ LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
+ }
+
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* source,
+ int line, int column) {
+ if (!xdk::XDKIsAgentAlive()) {
+ CodeEventLogger::CodeCreateEvent(tag, code, shared,
+ info, source, line, column);
+ return;
+ }
+
+ name_buffer_->Reset();
+ AppendCodeCreateHeader(name_buffer_, tag, code);
+ SmartArrayPointer<char> name =
+ shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ name_buffer_->AppendByte('"');
+ name_buffer_->AppendBytes(name.get());
+ name_buffer_->AppendByte(' ');
+ if (source->IsString()) {
+ SmartArrayPointer<char> sourcestr =
+ String::cast(source)->ToCString(DISALLOW_NULLS,
+ ROBUST_STRING_TRAVERSAL);
+ name_buffer_->AppendBytes(sourcestr.get());
+ } else {
+ AppendSymbolName(name_buffer_, Symbol::cast(source));
+ }
+ name_buffer_->AppendByte(':');
+ name_buffer_->AppendInt(line);
+ name_buffer_->AppendByte(':');
+ name_buffer_->AppendInt(column);
+ name_buffer_->AppendBytes("\",");
+ name_buffer_->AppendAddress(shared->address());
+ name_buffer_->AppendByte(',');
+ name_buffer_->AppendBytes(ComputeMarker(code));
+ LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
+ }
+
+
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ int args_count) {
+ if (!xdk::XDKIsAgentAlive()) {
+ CodeEventLogger::CodeCreateEvent(tag, code, args_count);
+ return;
+ }
+
+ name_buffer_->Reset();
+ AppendCodeCreateHeader(name_buffer_, tag, code);
+ name_buffer_->AppendBytes("\"args_count: ");
+ name_buffer_->AppendInt(args_count);
+ name_buffer_->AppendByte('"');
+ }
+
+
+ virtual void RegExpCodeCreateEvent(Code* code, String* source) {
+ if (!xdk::XDKIsAgentAlive()) {
+ CodeEventLogger::RegExpCodeCreateEvent(code, source);
+ return;
+ }
+
+ name_buffer_->Reset();
+ AppendCodeCreateHeader(name_buffer_, Logger::REG_EXP_TAG, code);
+ name_buffer_->AppendByte('"');
+ AppendDetailed(name_buffer_, source, false);
+ name_buffer_->AppendByte('"');
+ }
+
private:
virtual void LogRecordedBuffer(Code* code,
SharedFunctionInfo* shared,
kLogEventsNames[Logger::CODE_CREATION_EVENT],
kLogEventsNames[tag],
code->kind());
- msg->AppendAddress(code->address());
- msg->Append(",%d,", code->ExecutableSize());
+ if (xdk::XDKIsAgentAlive()) {
+ msg->AppendAddress(code->instruction_start());
+ msg->Append(",%d,", code->instruction_size());
+ } else {
+ msg->AppendAddress(code->address());
+ msg->Append(",%d,", code->ExecutableSize());
+ }
}
Address from,
Address to) {
if (!FLAG_log_code || !log_->IsEnabled()) return;
+
+ Code* from_code = NULL;
+ Address to_code = NULL;
+ if (xdk::XDKIsAgentAlive()) {
+ from_code = Code::cast(HeapObject::FromAddress(from));
+ const size_t header_size =
+ from_code->instruction_start() - reinterpret_cast<byte*>(from_code);
+ to_code =
+ reinterpret_cast<byte*>(HeapObject::FromAddress(to)) + header_size;
+ }
+
Log::MessageBuilder msg(log_);
msg.Append("%s,", kLogEventsNames[event]);
- msg.AppendAddress(from);
+ if (xdk::XDKIsAgentAlive()) {
+ msg.AppendAddress(from_code->instruction_start());
+ } else {
+ msg.AppendAddress(from);
+ }
msg.Append(',');
- msg.AppendAddress(to);
+ if (xdk::XDKIsAgentAlive()) {
+ msg.AppendAddress(to_code);
+ } else {
+ msg.AppendAddress(to);
+ }
msg.Append('\n');
msg.WriteToLogFile();
}
}
+void Logger::XDKResumeProfiler() {
+ if (!log_->IsEnabled()) return;
+ if (profiler_ != NULL) {
+ profiler_->resume();
+ is_logging_ = true;
+ }
+}
+
+
void Logger::StopProfiler() {
if (!log_->IsEnabled()) return;
if (profiler_ != NULL) {
void Logger::LogCodeObjects() {
+ // Starting from Chromium v34 this function is also called from
+ // V8::Initialize. This causes reading the heap to collect already
+ // compiled methods. For XDK that must be done because XDK profiler
+ // consumes CODE_ADDED events and mantains a map of compiled methods.
+ if (xdk::XDKIsAgentAlive()) return;
+
Heap* heap = isolate_->heap();
heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
"Logger::LogCodeObjects");
void Logger::LogCompiledFunctions() {
+ // Starting from Chromium v34 this function is also called from
+ // V8::Initialize. This causes reading the heap to collect already
+ // compiled methods. For XDK that must be done because XDK profiler
+ // consumes CODE_ADDED events and mantains a map of compiled methods.
+ if (xdk::XDKIsAgentAlive()) return;
+
Heap* heap = isolate_->heap();
heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
"Logger::LogCompiledFunctions");
is_logging_ = true;
}
+ xdk::XDKInitializeForV8(isolate);
+
if (FLAG_prof) {
profiler_ = new Profiler(isolate);
is_logging_ = true;
profiler_->Engage();
+
+ if (xdk::XDKIsAgentAlive()) {
+ // A way to to start profiler in pause mode was removed.
+ // To pause collection of the CPU ticks we need to emulate pause.
+ // This will be removed later once XDK agent will have own sampler.
+ profiler_->pause();
+ }
}
if (FLAG_log_internal_timer_events || FLAG_prof) timer_.Start();
// When data collection is paused, CPU Tick events are discarded.
void StopProfiler();
+ // Resumes collection of CPU Tick events.
+ void XDKResumeProfiler();
+
+ // XDK agent uses it log code map (list of CodeAdded event
+ // before resume CPU Tick events.
+ Log* XDKGetLog() { return log_; }
+
void LogExistingFunction(Handle<SharedFunctionInfo> shared,
Handle<Code> code);
// Logs all compiled functions found in the heap.
virtual void SharedFunctionInfoMoveEvent(Address from, Address to) { }
virtual void CodeMovingGCEvent() { }
- private:
+ protected:
class NameBuffer;
+ NameBuffer* name_buffer_;
+ private:
virtual void LogRecordedBuffer(Code* code,
SharedFunctionInfo* shared,
const char* name,
int length) = 0;
-
- NameBuffer* name_buffer_;
};
// V has parameters (Type, type, TYPE, C type, element_size)
-#define TYPED_ARRAYS(V) \
+#define BUILTIN_TYPED_ARRAY(V) \
V(Uint8, uint8, UINT8, uint8_t, 1) \
V(Int8, int8, INT8, int8_t, 1) \
V(Uint16, uint16, UINT16, uint16_t, 2) \
V(Int32, int32, INT32, int32_t, 4) \
V(Float32, float32, FLOAT32, float, 4) \
V(Float64, float64, FLOAT64, double, 8) \
- V(Float32x4, float32x4, FLOAT32x4, v8::internal::float32x4_value_t, 16) \
- V(Int32x4, int32x4, INT32x4, v8::internal::int32x4_value_t, 16) \
V(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t, 1)
+#define SIMD128_TYPED_ARRAY(V) \
+ V(Float32x4, float32x4, FLOAT32x4, v8::internal::float32x4_value_t, 16) \
+ V(Int32x4, int32x4, INT32x4, v8::internal::int32x4_value_t, 16)
+
+
+#define TYPED_ARRAYS(V) \
+ BUILTIN_TYPED_ARRAY(V) \
+ SIMD128_TYPED_ARRAY(V)
+
// An ExternalArray represents a fixed-size array of primitive values
// which live outside the JavaScript heap. Its subclasses are used to
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef __linux__
+#include <sys/stat.h>
+#endif // __linux__
+
+#include "xdk-agent.h"
+#include <vector>
+#include <string>
+#include <sstream>
+#include "platform.h"
+#include "log-utils.h"
+
+namespace xdk {
+namespace internal {
+
+static unsigned int XDK_COMMAND_LENGTH = 100; // It should be enough.
+
+static const char* XDK_TRACE_FILE =
+ "/data/data/com.intel.app_analyzer/files/result.xdk2v8";
+
+static const char* XDK_MARKER_FILE =
+ "/data/data/com.intel.app_analyzer/files/profiler.run";
+
+XDKAgent XDKAgent::instance_;
+
+// SetIdle has the same semantics as CpuProfiler::SetIdle has (v8/src/api.cc)
+// It is used to tell the sampler that XDK agent is idle (it is not busy with
+// some tasks). If the agent is idle that the sampler put a IDLE VM state into
+// the Tick record. The samples happen during IDLE will be attributed to (idle)
+// line in the XDK viewer.
+static void SetIdle(bool isIdle, v8engine::Isolate* isolate) {
+ CHECK(isolate);
+ v8engine::StateTag state = isolate->current_vm_state();
+ if (isolate->js_entry_sp() != NULL) return;
+ if (state == v8engine::EXTERNAL || state == v8engine::IDLE) {
+ if (isIdle) {
+ isolate->set_current_vm_state(v8engine::IDLE);
+ } else if (state == v8engine::IDLE) {
+ isolate->set_current_vm_state(v8engine::EXTERNAL);
+ }
+ }
+}
+
+
+bool XDKAgent::setUp(v8engine::Isolate* isolate) {
+ CHECK(isolate);
+
+ if (m_isolate) {
+ // The setUp method is called for the main thread first, then may be called
+ // again if the app uses Workers (each Worker object has own V8 instance).
+ // XDK agent does not support JavaScript Worker currently.
+ XDKLog("xdk: Agent is already initialized\n");
+ return false;
+ }
+
+ FILE* file = v8engine::OS::FOpen(XDK_MARKER_FILE, "r");
+ if (file == NULL) {
+ return false;
+ }
+
+ fclose(file);
+ m_alive = true;
+ m_isolate = isolate;
+
+ return m_alive;
+}
+
+
+void XDKAgent::resumeSampling() {
+ v8engine::LockGuard<v8engine::Mutex> l(m_agent_access);
+ CHECK(m_isolate);
+
+ v8engine::Log* log = m_isolate->logger()->XDKGetLog();
+ CHECK(log);
+
+ // Create a new log file for new profiling session
+ CHECK(!log->IsEnabled());
+ log->Initialize(XDK_TRACE_FILE);
+
+#ifdef __linux__
+ int mode = S_IRUSR|S_IROTH|S_IRGRP|S_IWUSR|S_IWOTH|S_IWGRP;
+ if (chmod(XDK_TRACE_FILE, mode) != 0) {
+ XDKLog("xdk: Couldn't change permissions for a trace file\n");
+ }
+#endif // __linux__
+
+ CHECK(log->IsEnabled());
+
+ logFunctionSnapshot();
+
+ // Write a marker line into the log for testing purpose
+ v8engine::Log::MessageBuilder msg(log);
+ msg.Append("Profiler started.\n");
+ msg.WriteToLogFile();
+
+ // Resume collection the CPU Tick events
+ m_isolate->logger()->XDKResumeProfiler();
+ XDKLog("xdk: Sampling is resumed\n");
+
+ SetIdle(true, m_isolate);
+}
+
+
+void XDKAgent::pauseSampling() {
+ // Pause collection the CPU Tick events
+ CHECK(m_isolate);
+ m_isolate->logger()->StopProfiler();
+
+ // Use v8 logger internals to close the trace file.
+ // Once XDK agent implements own sampler this will be removed.
+ v8engine::Log* log = m_isolate->logger()->XDKGetLog();
+ CHECK(log);
+ log->stop();
+ log->Close();
+
+ XDKLog("xdk: Sampling is stopped\n");
+}
+
+
+struct ObjectDeallocator {
+ template<typename T>
+ void operator()(const T& obj) const { delete obj.second; }
+};
+
+
+XDKAgent::~XDKAgent() {
+ CHECK(m_server != NULL);
+ CHECK(m_agent_access != NULL);
+
+ if (m_alive) {
+ CHECK(m_isolate != NULL);
+
+ m_terminate = true;
+
+ std::for_each(m_lineMaps.begin(), m_lineMaps.end(), ObjectDeallocator());
+ m_lineMaps.clear();
+
+ m_server->Shutdown();
+
+ Join();
+ }
+
+ delete m_server;
+ m_server = NULL;
+
+ delete m_agent_access;
+ m_agent_access = NULL;
+
+ m_isolate = NULL;
+}
+
+
+// The XDK listener thread.
+void XDKAgent::Run() {
+ v8engine::Isolate::EnsureDefaultIsolate();
+ v8engine::DisallowHeapAllocation no_allocation;
+ v8engine::DisallowHandleAllocation no_handles;
+ v8engine::DisallowHandleDereference no_deref;
+
+ XDKLog("xdk: Listener thread is running\n");
+ CHECK(m_server);
+
+ bool ok = m_server->Bind(m_port);
+ if (!ok) {
+ XDKLog("xdk: Unable to bind port=%d %d\n",
+ m_port, v8engine::Socket::GetLastError());
+ return;
+ }
+
+ std::vector<char> buf(XDK_COMMAND_LENGTH);
+
+ const std::string cmdStart = "start";
+ const std::string cmdStop = "stop";
+
+ while (!m_terminate) {
+ XDKLog("xdk: Listener thread is waiting for connection\n");
+
+ ok = m_server->Listen(1);
+ XDKLog("xdk: Listener thread got a connection request. Return value=%d\n",
+ v8engine::Socket::GetLastError());
+ if (ok) {
+ v8engine::Socket* client = m_server->Accept();
+ if (client == NULL) {
+ XDKLog("xdk: Accept failed %d\n", v8engine::Socket::GetLastError());
+ continue;
+ }
+
+ XDKLog("xdk: Connected\n");
+
+ int bytes_read = client->Receive(&buf[0], buf.size() - 1);
+ if (bytes_read == 0) {
+ XDKLog("xdk: Receive failed %d\n", v8engine::Socket::GetLastError());
+ break;
+ }
+ buf[bytes_read] = '\0';
+
+ #ifdef WIN32
+ if (bytes_read > 3) buf[bytes_read - 2] = '\0'; // remove CR+LF symbols
+ #else
+ if (bytes_read > 2) buf[bytes_read - 1] = '\0'; // remove LF symbol
+ #endif
+
+ std::string clientCommand(&buf[0]);
+ XDKLog("xdk: Got '%s' profiling command\n", clientCommand.c_str());
+
+ if (clientCommand == cmdStart) {
+ resumeSampling();
+ } else if (clientCommand == cmdStop) {
+ pauseSampling();
+ } else {
+ XDKLog("xdk: '%s' is not handled command\n", clientCommand.c_str());
+ break;
+ }
+ }
+ }
+
+ XDKLog("xdk: Listener thread is stopped\n");
+ return;
+}
+
+
+void XDKAgent::processCodeMovedEvent(const v8::JitCodeEvent* event) {
+ v8engine::LockGuard<v8engine::Mutex> l(m_agent_access);
+ v8engine::Address from = static_cast<v8engine::Address>(event->code_start);
+ v8engine::Address to = static_cast<v8engine::Address>(event->new_code_start);
+
+ if (!from || !to) return;
+ XDKLog("xdk: CODE_MOVED from=0x%x to=0x%x\n", from, to);
+ m_snapshot.move(from, to);
+}
+
+
+void XDKAgent::processCodeRemovedEvent(const v8::JitCodeEvent* event) {
+ v8engine::LockGuard<v8engine::Mutex> l(m_agent_access);
+ v8engine::Address addr = static_cast<v8engine::Address>(event->code_start);
+
+ if (!addr) return;
+ XDKLog("xdk: CODE_REMOVED for addr=0x%x\n", addr);
+ m_snapshot.remove(addr);
+}
+
+
+void XDKAgent::processCodeAddedEvent(const v8::JitCodeEvent* event) {
+ v8engine::LockGuard<v8engine::Mutex> l(m_agent_access);
+
+ v8engine::Address codeAddr =
+ static_cast<v8engine::Address>(event->code_start);
+ uint32_t codeLen = event->code_len;
+
+ if (!codeAddr || !codeLen) return;
+ XDKLog("xdk: CODE_ADDED for addr=0x%x len=0x%x\n", codeAddr, codeLen);
+
+ // Look for line number information
+ LineMap* lineMap = NULL;
+ LineMaps::iterator itr = m_lineMaps.find(codeAddr);
+ if (itr == m_lineMaps.end()) {
+ XDKLog("xdk: Unable to find line info for addr=0x%x\n", codeAddr);
+ } else {
+ lineMap = itr->second;
+
+ // Remove line map if no chance to get source lines for it
+ v8::Handle<v8::Script> script = event->script;
+ if (*script == NULL) {
+ XDKLog("xdk: Script is empty. No line info for addr=0x%x.\n", codeAddr);
+ delete lineMap;
+ lineMap = NULL;
+ m_lineMaps.erase(codeAddr);
+ } else {
+ // Convert V8 pos value into source line number.
+ LineMap::Entries* entries =
+ const_cast<LineMap::Entries*>(lineMap->getEntries());
+ CHECK(entries);
+ CHECK(entries->size());
+ XDKLog("xdk: Found line info (%d lines) for addr=0x%x\n",
+ entries->size(), codeAddr);
+ size_t srcLine = 0;
+ LineMap::Entries::iterator lineItr = entries->begin();
+ LineMap::Entries::iterator lineEnd = entries->end();
+ for (; lineItr != lineEnd; ++lineItr) {
+ srcLine = script->GetLineNumber(lineItr->line) + 1;
+ lineItr->line = srcLine;
+ XDKLog("xdk: offset=%p line=%d\n", lineItr->pcOffset, lineItr->line);
+ }
+ }
+ }
+
+ std::string funcType;
+ std::string name(event->name.str, event->name.len);
+ Function func(codeAddr, codeLen, name, funcType, lineMap);
+
+ if (lineMap) {
+ // Put the line number information for the given method into the trace file
+ // if profiling session is running.
+ logLineNumberInfo(codeAddr, *lineMap);
+
+ // Release memory allocated on CODE_START_LINE_INFO_RECORDING
+ delete lineMap;
+ lineMap = NULL;
+ m_lineMaps.erase(codeAddr);
+ }
+
+ m_snapshot.insert(func);
+}
+
+
+void XDKAgent::processLineMapAddedEvent(const v8::JitCodeEvent* event) {
+ v8engine::LockGuard<v8engine::Mutex> l(m_agent_access);
+ v8engine::Address codeAddr =
+ static_cast<v8engine::Address>(event->code_start);
+ void* userData = event->user_data;
+
+ if (!userData || !codeAddr) return;
+
+ LineMap* lineMap = reinterpret_cast<LineMap*>(userData);
+ if (lineMap->getSize() == 0) {
+ XDKLog("xdk: CODE_END_LINE no entries for user_data=%p addr=0x%x\n",
+ userData, codeAddr);
+ return;
+ }
+
+ std::pair<LineMaps::iterator, bool>
+ result = m_lineMaps.insert(std::make_pair(codeAddr, lineMap));
+ if (!result.second) {
+ m_lineMaps.erase(codeAddr);
+ XDKLog("xdk: removed unprocessed line info for addr=0x%x\n", codeAddr);
+ result = m_lineMaps.insert(std::make_pair(codeAddr, lineMap));
+ CHECK(result.second);
+ }
+
+ XDKLog("xdk: CODE_END_LINE added %d entries for user_data=%p addr=0x%x\n",
+ lineMap->getSize(), userData, codeAddr);
+}
+
+
+void EventHandler(const v8::JitCodeEvent* event) {
+ // This callback is called regardless of whether profiling is running.
+ //
+ // By default profiling is launched in paused mode, the agent is awaiting
+ // a command to resume profiling. At the same time, V8's JIT compiler is
+ // working. The functions which are JIT-compiled while sampling is paused
+ // are cached by V8's Logger and will be written in log (trace file) when
+ // XDK resumes the profiling. The line number info for such functions are not
+ // cached. We need to capture and cache the line number info and flush
+ // the cache on resume profiling.
+
+ if (event == NULL) return;
+
+ switch (event->type) {
+ case v8::JitCodeEvent::CODE_MOVED:
+ XDKAgent::instance().processCodeMovedEvent(event);
+ break;
+
+ case v8::JitCodeEvent::CODE_REMOVED:
+ XDKAgent::instance().processCodeRemovedEvent(event);
+ break;
+
+ case v8::JitCodeEvent::CODE_ADDED:
+ XDKAgent::instance().processCodeAddedEvent(event);
+
+ case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
+ void* userData = event->user_data;
+ if (!userData) return;
+ LineMap* lineMap = reinterpret_cast<LineMap*>(userData);
+ size_t offset = event->line_info.offset;
+ size_t pos = event->line_info.pos;
+ lineMap->setPosition(offset, pos);
+ XDKLog("xdk: CODE_ADD_LINE_POS for user_data=%p offset=0x%x pos=%d\n",
+ userData, offset, pos);
+ break;
+ }
+
+ case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
+ v8::JitCodeEvent* data = const_cast<v8::JitCodeEvent*>(event);
+ data->user_data = new LineMap();
+ XDKLog("xdk: CODE_START_LINE for user_data=%p\n", event->user_data);
+ break;
+ }
+
+ case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
+ XDKAgent::instance().processLineMapAddedEvent(event);
+ break;
+ }
+
+ default:
+ XDKLog("xdk: Unknown event\n");
+ break;
+ }
+
+ SetIdle(true, XDKAgent::instance().isolate());
+
+ return;
+}
+
+
+void XDKAgent::logLineNumberInfo(v8engine::Address addr,
+ const LineMap& lineInfo) {
+ CHECK(addr);
+ v8engine::Log* log = m_isolate->logger()->XDKGetLog();
+ CHECK(log);
+ if (!log->IsEnabled()) return;
+ if (lineInfo.getSize() == 0) return;
+ const LineMap::Entries* lines = lineInfo.getEntries();
+ CHECK(lines);
+ LineMap::Entries::const_iterator lineItr = lines->begin();
+ LineMap::Entries::const_iterator lineEnd = lines->end();
+
+ // Put 'src-pos' lines into the log in our own format
+ for (; lineItr != lineEnd; ++lineItr) {
+ v8engine::Log::MessageBuilder msg(m_isolate->logger()->XDKGetLog());
+ msg.Append("src-pos,");
+ msg.Append("0x%x,%d,%d\n", addr, lineItr->pcOffset, lineItr->line);
+ msg.WriteToLogFile();
+ }
+}
+
+
+void XDKAgent::logFunctionSnapshot() {
+ CHECK(m_isolate);
+
+ CodeMap::const_iterator funcItr = m_snapshot.entries().begin();
+ CodeMap::const_iterator funcEnd = m_snapshot.entries().end();
+
+ XDKLog("FunctionSnapshot: %d entries\n", m_snapshot.entries().size());
+ if (m_snapshot.entries().size() == 0) return;
+
+ unsigned int i = 1;
+
+ for (; funcItr != funcEnd; ++funcItr, i++) {
+ const Range& range = funcItr->first;
+ const Function& func = funcItr->second;
+
+ XDKLog("%d %s\n", i, func.getLogLine().c_str());
+
+ const LineMap& map = func.getLineMap();
+ if (map.getSize()) {
+ v8engine::Address codeAddr = range.start();
+ XDKLog(" Found %d lines for addr=%p\n", map.getSize(), codeAddr);
+ logLineNumberInfo(codeAddr, map);
+ }
+
+ // Write 'code-creation' line into the log
+ v8engine::Log::MessageBuilder msg(m_isolate->logger()->XDKGetLog());
+ msg.Append("%s\n", func.getLogLine().c_str());
+ msg.WriteToLogFile();
+ }
+}
+
+}} // namespace xdk::internal
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XDK_AGENT_H_
+#define XDK_AGENT_H_
+
+#include "v8.h"
+#include "sampler.h"
+#include "platform.h"
+#include "platform/socket.h"
+#include "platform/mutex.h"
+#include "xdk-types.h"
+#include "xdk-code-map.h"
+
+// ----------------------------------------------------------------------------
+//
+// This file declares XDKAgent class which does
+//
+// - Handles the code events to maintain the code map.
+// - Handles the line info events to assosiate the line info with code event.
+// - Accepts start / stop profiling commands from AppAnalyzer.
+//
+// ----------------------------------------------------------------------------
+
+namespace xdk {
+namespace internal {
+
+const int XDK_AGENT_PORT = 48899;
+
+// Callback called by V8 builtin logger.
+void EventHandler(const v8::JitCodeEvent* event);
+
+// XDK profiling agent. It starts a socket listener on the specific port and
+// handles commands to start and stop sampling.
+class XDKAgent : public v8engine::Thread {
+ public:
+ static XDKAgent& instance() {
+ return instance_;
+ }
+
+ void Run();
+
+ bool setUp(v8engine::Isolate* isolate);
+ bool isAlive() const { return m_alive; }
+
+ void processCodeMovedEvent(const v8::JitCodeEvent* event);
+ void processCodeRemovedEvent(const v8::JitCodeEvent* event);
+ void processCodeAddedEvent(const v8::JitCodeEvent* event);
+ void processLineMapAddedEvent(const v8::JitCodeEvent* event);
+
+ inline v8engine::Isolate* isolate() { return m_isolate; }
+
+ private:
+ virtual ~XDKAgent();
+ XDKAgent()
+ : v8engine::Thread("xdk:agent"),
+ m_alive(false),
+ m_port(XDK_AGENT_PORT),
+ m_server(new v8engine::Socket()),
+ m_agent_access(new v8engine::Mutex()),
+ m_isolate(NULL),
+ m_terminate(false) {
+ CHECK(m_server != NULL);
+ CHECK(m_agent_access != NULL);
+ }
+ XDKAgent(const XDKAgent&);
+ XDKAgent& operator=(const XDKAgent&);
+
+ void logFunctionSnapshot();
+ void logLineNumberInfo(v8engine::Address codeAddr, const LineMap& lineInfo);
+
+ void resumeSampling();
+ void pauseSampling();
+
+ bool m_alive;
+
+ const int m_port; // Port to use for the agent.
+ v8engine::Socket* m_server; // Server socket for listen/accept.
+ v8engine::Mutex* m_agent_access;
+ v8engine::Isolate* m_isolate;
+
+ // The snapshot of compiled methods at present moment.
+ FunctionSnapshot m_snapshot;
+
+ // The processLineMapAddedEvent function adds a new map for code starting
+ // address. Newly added map describes how ps offsets maps to internal pos,
+ // but not how ps offsets maps to line number within source file.
+ //
+ // On CodeAdd event, processCodeAddedEvent function looks for line map for
+ // a code address. If map is found that assign it to a object of Function type
+ // in FunctionSnapshot. Before assign the pc offset to pos map is converted
+ // to pc offset to source line.
+ //
+ // CodeMoved and CodeRemoved must not affect this map.
+ // Current understanding of V8 code generator: V8 first emits LineStart event,
+ // then bunch of LineAdd events, then LineEnd event, finally CodeAdded event.
+ // Based on above no need to add any 'smart' logic on CodeMoved and
+ // CodeRemoved for line map.
+ //
+ // Basically it should be always empty.
+ LineMaps m_lineMaps;
+
+ bool m_terminate; // Termination flag for listening thread.
+
+ static XDKAgent instance_;
+};
+
+} } // namespace xdk::internal
+
+#endif // XDK_AGENT_H_
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xdk-code-map.h"
+#include <sstream>
+
+namespace xdk {
+namespace internal {
+
+static std::string replaceAddress(const std::string& str,
+ v8engine::Address addr) {
+ // The input str: code-creation,LazyCompile,0,0x3851c4e0,200," native uri.js"
+ std::string first;
+ std::string end;
+
+ std::size_t found = str.find(',');
+ if (found != std::string::npos) {
+ found = str.find(',', found + 1);
+ if (found != std::string::npos) {
+ found = str.find(',', found + 1);
+ if (found != std::string::npos) {
+ first = str.substr(0, found);
+ found = str.find(',', found + 1);
+ if (found != std::string::npos) {
+ end = str.substr(found, str.size() - found);
+ }
+ }
+ }
+ }
+
+ if (!first.size() || !end.size()) return str;
+
+ std::stringstream ss;
+ ss << first << ','
+ << std::showbase << std::hex << static_cast<void*>(addr) << end;
+ return ss.str();
+}
+
+
+Function::Function(v8engine::Address codeAddr, uint32_t codeLen,
+ const std::string& name, const std::string& type,
+ const LineMap* lineMap)
+ : m_codeAddr(codeAddr), m_codeLen(codeLen), m_name(name), m_type(type) {
+ CHECK(codeAddr);
+ CHECK(codeLen);
+ // Can't be empty because it's came from CodeCreation(...) events
+ CHECK(!name.empty());
+ m_logLine = m_name;
+
+ if (lineMap && lineMap->getSize()) m_lineMap = *lineMap;
+}
+
+
+void FunctionSnapshot::removeAll(const Range& range) {
+ CodeMap::iterator low = m_impl.lower_bound(range);
+ CodeMap::iterator up = m_impl.upper_bound(range);
+ CodeMap::iterator::difference_type num = std::distance(low, up);
+
+ if (num) {
+ XDKLog("xdk: %d ranges were overlapped and removed\n", num);
+
+ CodeMap::iterator itr = low;
+ for (; itr != up; ++itr) {
+ XDKLog("xdk: ovrl&removed addr=0x%x len=0x%x name=%s\n",
+ itr->first.start(), itr->first.length(),
+ itr->second.getLogLine().c_str());
+ }
+ m_impl.erase(low, up);
+ }
+}
+
+
+void FunctionSnapshot::insert(const Function& func) {
+ v8engine::Address codeAddr = func.getCodeAddress();
+ uint32_t codeLen = func.getCodeLength();
+ CHECK(codeAddr);
+ CHECK(codeLen);
+
+ Range range(codeAddr, codeLen);
+
+ removeAll(range);
+
+ std::pair<CodeMap::iterator, bool> res =
+ m_impl.insert(std::make_pair(range, func));
+ CHECK(res.second);
+
+ XDKLog("xdk: size=%d added addr=0x%x name=%s\n",
+ m_impl.size(), range.start(), func.getLogLine().c_str());
+}
+
+
+void FunctionSnapshot::remove(v8engine::Address codeAddr) {
+ if (!codeAddr) return;
+ CodeMap::iterator itr = m_impl.find(Range(codeAddr, 1));
+ if (itr != m_impl.end()) {
+ std::string name = itr->second.getLogLine();
+ uint32_t len = itr->first.length();
+ m_impl.erase(itr);
+ XDKLog("xdk: size=%d removed addr=0x%x name=%s\n",
+ m_impl.size(), codeAddr, len, name.c_str());
+ }
+}
+
+
+void FunctionSnapshot::move(v8engine::Address from, v8engine::Address to) {
+ if (!from || !to) return;
+ if (from == to) return;
+
+ CodeMap::iterator itr = m_impl.find(Range(from, 1));
+ if (itr == m_impl.end()) {
+ XDKLog("xdk: couldn't find a code to move from=0x%x to=0x%x\n", from, to);
+ return;
+ }
+ if (itr->first.start() != from) {
+ XDKLog("xdk: discarded move from=0x%x to=0x%x\n", from, to);
+ return;
+ }
+
+ uint32_t codeLen = itr->second.getCodeLength();
+ const LineMap& lines = itr->second.getLineMap();
+
+ // In case of CodeMoved we have to check that name contains the same code
+ // addr and code length as the input params and replace if they are different.
+ const std::string& orig = itr->second.getName();
+ std::string name = replaceAddress(orig, to);
+
+ const std::string& type = itr->second.getType();
+ Function toEntry(to, codeLen, name, type, &lines);
+
+ m_impl.erase(itr);
+
+ Range range(to, codeLen);
+ removeAll(range);
+
+ // Now ready to move
+
+ bool ok = m_impl.insert(std::make_pair(range, toEntry)).second;
+ CHECK(ok);
+
+ XDKLog("xdk: size=%d moved from=0x%x to=0x%x name=%s\n",
+ m_impl.size(), from, to, toEntry.getLogLine().c_str());
+}
+
+} } // namespace xdk::internal
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XDK_CODE_MAP_H_
+#define XDK_CODE_MAP_H_
+
+// ----------------------------------------------------------------------------
+//
+// This file contains the FunctionSnapshot and related objects declarations
+//
+// The FunctionSnapshot object maintains a map of JIT compiled functions.
+// It is modified on code events(CodeAdded, CodeMoved and CodeDeleted) from
+// V8 built-in profiler.
+//
+// ----------------------------------------------------------------------------
+
+#include "xdk-types.h"
+#include <map>
+#include <list>
+#include <string>
+#include <algorithm>
+
+namespace xdk {
+namespace internal {
+
+class LineMap;
+typedef std::map<
+ v8engine::Address, // start address of code
+ LineMap*> LineMaps;
+
+// This class is used to record the JITted code position info for JIT
+// code profiling.
+class LineMap {
+ public:
+ struct LineEntry {
+ LineEntry(size_t offset, size_t line)
+ : pcOffset(offset), line(line) { }
+
+ size_t pcOffset; // PC offset from the begining of the code trace.
+ size_t line; // Can be either position returned from V8 assembler
+ // (which needs to be converted to src line) or src line
+ // number.
+ };
+
+ typedef std::list<LineEntry> Entries;
+
+ void setPosition(size_t offset, size_t line) {
+ addCodeLineEntry(LineEntry(offset, line));
+ }
+
+ inline size_t getSize() const { return m_lines.size(); }
+ const Entries* getEntries() const { return &m_lines; }
+
+ private:
+ void addCodeLineEntry(const LineEntry& entry) { m_lines.push_back(entry); }
+
+ Entries m_lines;
+};
+
+// This class describes the function reported with CodeAdded event.
+class Function {
+ public:
+ explicit Function(v8engine::Address codeAddr, uint32_t codeLen,
+ const std::string& name, const std::string& type,
+ const LineMap* lineMap);
+
+ inline v8engine::Address getCodeAddress() const { return m_codeAddr; }
+ inline uint32_t getCodeLength() const { return m_codeLen; }
+
+ inline const std::string& getType() const { return m_type; }
+ inline const std::string& getName() const { return m_name; }
+ inline const std::string& getLogLine() const { return m_logLine; }
+
+ const LineMap& getLineMap() const { return m_lineMap; }
+
+ private:
+ v8engine::Address m_codeAddr;
+ uint32_t m_codeLen;
+ std::string m_name;
+ std::string m_type;
+ std::string m_logLine;
+ LineMap m_lineMap;
+};
+
+// This class describes the code range related to object of Function type.
+// The start address and length are taken from CodeAdded event.
+class Range {
+ public:
+ class Comparator : public std::binary_function<Range&, Range&, bool> {
+ public:
+ bool operator()(const Range& l, const Range& r) const {
+ return (l.start() + l.length() <= r.start());
+ }
+ };
+
+ Range(v8engine::Address start, uint32_t length)
+ : m_start(start), m_length(length) { }
+
+ inline v8engine::Address start() const { return m_start; }
+ inline uint32_t length() const { return m_length; }
+
+ private:
+ v8engine::Address m_start;
+ uint32_t m_length;
+};
+
+// This class maintains a map of JIT compiled functions.
+// The content is changed on CodeAdded, CodeMoved and CodeDeleted events.
+typedef std::map<Range, const Function, Range::Comparator> CodeMap;
+
+class FunctionSnapshot {
+ public:
+ explicit FunctionSnapshot() {}
+ virtual ~FunctionSnapshot() { m_impl.clear(); }
+
+ void insert(const Function& func);
+ void move(v8engine::Address from, v8engine::Address to);
+ void remove(v8engine::Address addr);
+
+ inline const CodeMap& entries() { return m_impl; }
+
+ private:
+ FunctionSnapshot(const FunctionSnapshot&);
+ FunctionSnapshot& operator=(const FunctionSnapshot&);
+
+ void removeAll(const Range& range);
+
+ CodeMap m_impl;
+};
+
+} } // namespace xdk::internal
+
+#endif // XDK_CODE_MAP_H_
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XDK_TYPES_H_
+#define XDK_TYPES_H_
+
+#include "v8.h"
+#include "platform.h"
+
+namespace v8engine = v8::internal;
+
+static void XDKLog(const char* msg, ...) {
+#if DEBUG
+ va_list arguments;
+ va_start(arguments, msg);
+ v8engine::OS::VPrint(msg, arguments);
+ va_end(arguments);
+#endif
+}
+
+#endif // XDK_TYPES__H_
+
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "../../../include/v8.h"
+#include "xdk-v8.h"
+#include "xdk-agent.h"
+
+namespace xdk {
+
+void XDKInitializeForV8(v8::internal::Isolate* isolate) {
+ if (!internal::XDKAgent::instance().setUp(isolate)) return;
+
+ XDKLog("xdk: XDKInitializeForV8\n");
+
+ // The --prof flag is requred for now to enable the CPU ticks collection.
+ // This flag will be removed once xdk agent implements own sampler.
+ const char* flags = "--prof";
+ v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
+
+ v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+ xdk::internal::EventHandler);
+
+ internal::XDKAgent::instance().Start();
+}
+
+
+bool XDKIsAgentAlive() {
+ return internal::XDKAgent::instance().isAlive();
+}
+
+} // namespace xdk
--- /dev/null
+# Copyright (c) 2013 Intel Corporation. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'v8_code': 1,
+ },
+ 'includes': ['../../../build/toolchain.gypi', '../../../build/features.gypi'],
+ 'targets': [
+ {
+ 'target_name': 'v8_xdk',
+ 'type': 'static_library',
+ 'conditions': [
+ ['want_separate_host_toolset==1', {
+ 'toolsets': ['host', 'target'],
+ }, {
+ 'toolsets': ['target'],
+ }],
+ ],
+ 'include_dirs+': [
+ '../../',
+ ],
+ 'sources': [
+ 'xdk-v8.h',
+ 'xdk-v8.cc',
+ 'xdk-agent.h',
+ 'xdk-agent.cc',
+ 'xdk-code-map.h',
+ 'xdk-code-map.cc',
+ 'xdk-types.h',
+ ],
+ 'direct_dependent_settings': {
+ 'conditions': [
+ ['OS != "win"', {
+ 'libraries': ['-ldl',],
+ }],
+ ],
+ },
+ },
+ ]
+}
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_XDK_H_
+#define V8_XDK_H_
+
+// ----------------------------------------------------------------------------
+//
+// XDK profiling support for V8
+//
+// SOURCES:
+//
+// 1. XDK agent source files are located in v8/src/third_party/xdk folder.
+//
+// To integrate this stuff into V8 build system you need to modify
+// two v8 files:
+//
+// 1. v8/build/features.gypi
+// 'v8_enable_xdkprof': 1,
+// 2. v8/tools/gyp/v8.gyp
+// ['v8_enable_xdkprof==1', {
+// 'dependencies': ['../../src/third_party/xdk/xdk-v8.gyp:v8_xdk',],
+// }],
+//
+// 2. Two V8 files v8/src/log.cc and v8/src/log.h need to be modified
+//
+// The changes related to start CPU ticks collection using V8 built-in
+// profiler.
+// We are working on reduce these changes up to 2 lines:
+//
+// #include "third_party/xdk/xdk-v8.h"
+// bool Logger::SetUp(Isolate* isolate) {
+// ...
+// xdk::XDKInitializeForV8(isolate);
+// ...
+// }
+//
+// OVERVIEW:
+//
+// Start up
+//
+// XDK agent is initialized as a part of V8 built-in profiler on process
+// start up. V8 built-in profiler should be paused (CPU ticks are not
+// collected).
+//
+// v8/src/log.cc:
+// bool Logger::SetUp(Isolate* isolate) {
+// ...
+// xdk::XDKInitializeForV8(isolate);
+// ...
+// }
+//
+// XDKInitializeForV8() function
+// 1. Checks whether XDK agent can be initialized. If a marker file is not
+// found that initialization will be discarded.
+// 2. Starts a listener thread to accept start / stop profiling command
+// from AppAnalyzer (xdk/xdk-agent.cc).
+// 3. Registeres a callback to consume the CodeAdded, CodeMoved,
+// CodeDeleted events and events related to source line info by
+// the agent.
+//
+// Runtime
+//
+// XDK profiler consumes the code events (EventHandler() in xdk/xdk-agent.cc)
+// V8 emits these events even when CPU ticks collection is paused.
+// The profiler uses the code events to maintain a function snapshot (list of
+// code ranges assosiated with function name and source line info)
+// (xdk-code-map.cc).
+//
+// Start profiling
+//
+// When the profiler receives a command to start profiling that it calls
+// resumeSampling() (xdk/xdk-agent.cc) which
+// 1. Creates a new trace file to log the ticks and code events
+// 2. Puts the function snapshot into the trace file
+// 3. Resumes CPU ticks collection
+//
+// Stop profiling
+//
+// When the profiler receives a command to stop profiling that it calls
+// pauseSampling() (xdk/xdk-agent.cc) which stops the CPU ticks collection.
+// Note that the agent continues to consume the code events to maintain
+// the function snapshot.
+//
+// When collection is stopped that AppAnalyzer takes the trace file for
+// processing.
+//
+// ----------------------------------------------------------------------------
+
+namespace xdk {
+
+// This function
+// - Overrides the V8 flags to specify a new logfile for writting profiling data
+// (CPU ticks and Code* events).
+// - Registers callback to get line number info and code events from V8 built-in
+// profiler. These data are needed to mantain the code map.
+// - Starts the XDK agent listener thread which is awaiting for start and stop
+// profiling commands.
+void XDKInitializeForV8(v8::internal::Isolate* isolate);
+
+bool XDKIsAgentAlive();
+
+} // namespace XDK
+
+#endif // V8_XDK_H_
+
# - _GLOBAL__I__ZN2v810LineEditor6first_E
# - _GLOBAL__I__ZN2v88internal32AtomicOps_Internalx86CPUFeaturesE
# - _GLOBAL__I__ZN2v88internal8ThreadId18highest_thread_id_E
-expected_static_init_count=3
+
+# The XDK CPU profiler patch adds one more static initializer.
+# - _GLOBAL__sub_I__ZN3xdk8internal8XDKAgent9instance_E
+expected_static_init_count=4
v8_root=$(readlink -f $(dirname $BASH_SOURCE)/../)
}, {
'toolsets': ['target'],
}],
+ ['v8_enable_xdkprof==1', {
+ 'dependencies': ['../../src/third_party/xdk/xdk-v8.gyp:v8_xdk',],
+ }],
['v8_target_arch=="arm"', {
'sources': [ ### gcmole(arch:arm) ###
'../../src/arm/assembler-arm-inl.h',
# Use 'Trunk' for trunk.
# If using trunk, will use '.DEPS.git' for gclient.
chromium_version = '34.0.1847.45'
-chromium_crosswalk_point = 'cb7bc58aa1239e2fa92d692e81ccd06fa6c82722'
+chromium_crosswalk_point = 'b83e11e691378bba3b997c6c7667908c4cd33798'
blink_crosswalk_point = 'e8b6b995b38b422c2b4d58fa5201599f1e510537'
-v8_crosswalk_point = '702dcf9c6e58d90e85594fbe54579ade631fe3b5'
+v8_crosswalk_point = 'ffe72f9229923611866423ced472b1dff97abdfe'
deps_xwalk = {
'src': 'https://github.com/crosswalk-project/chromium-crosswalk.git@%s' % chromium_crosswalk_point,
'src/v8': 'https://github.com/crosswalk-project/v8-crosswalk.git@%s' % v8_crosswalk_point,
# Ozone-Wayland is required for Wayland support in Chromium.
- 'src/ozone': 'https://github.com/01org/ozone-wayland.git@39d93a66777395d5c9ca11da95c436b9192d9725',
+ 'src/ozone': 'https://github.com/01org/ozone-wayland.git@a4e3e96b1e1c51cecf5f7bc162b0d98064c95bc2',
}
vars_xwalk = {
}
-MAJOR=5
+MAJOR=6
MINOR=34
-BUILD=105
+BUILD=113
PATCH=0
package org.xwalk.app.template;
import android.graphics.Color;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import android.view.WindowManager;
import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;
setContentView(msgText);
}
}
+
+ private void enterFullscreen() {
+ if (VERSION.SDK_INT >= VERSION_CODES.KITKAT &&
+ ((getWindow().getAttributes().flags &
+ WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0)) {
+ View decorView = getWindow().getDecorView();
+ decorView.setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+ }
+ }
+
+ public void setIsFullscreen(boolean isFullscreen) {
+ if (isFullscreen) {
+ enterFullscreen();
+ }
+ }
+
}
def CustomizeXML(sanitized_name, package, app_versionCode, app_version,
- description, name, orientation, icon, fullscreen,
- launch_screen_img, permissions):
+ description, name, orientation, icon_dict, fullscreen,
+ launch_screen_img, permissions, app_root):
manifest_path = os.path.join(sanitized_name, 'AndroidManifest.xml')
if not os.path.isfile(manifest_path):
print ('Please make sure AndroidManifest.xml'
if orientation:
EditElementAttribute(xmldoc, 'activity', 'android:screenOrientation',
orientation)
- if icon and os.path.isfile(icon):
- drawable_path = os.path.join(sanitized_name, 'res', 'drawable')
- if not os.path.exists(drawable_path):
- os.makedirs(drawable_path)
- icon_file = os.path.basename(icon)
- icon_file = ReplaceInvalidChars(icon_file)
- shutil.copyfile(icon, os.path.join(drawable_path, icon_file))
- icon_name = os.path.splitext(icon_file)[0]
- EditElementAttribute(xmldoc, 'application',
- 'android:icon', '@drawable/%s' % icon_name)
- elif icon and (not os.path.isfile(icon)):
- print ('Please make sure the icon file does exist!')
- sys.exit(6)
+ if CustomizeIcon(sanitized_name, app_root, icon_dict):
+ EditElementAttribute(xmldoc, 'application', 'android:icon',
+ '@drawable/icon')
file_handle = open(os.path.join(sanitized_name, 'AndroidManifest.xml'), 'w')
xmldoc.writexml(file_handle, encoding='utf-8')
file_handle.close()
-def SetVariable(file_path, variable, value):
+def SetVariable(file_path, string_line, variable, value):
function_string = ('%sset%s(%s);\n' %
(' ', variable, value))
temp_file_path = file_path + '.backup'
file_handle = open(temp_file_path, 'w+')
for line in open(file_path):
file_handle.write(line)
- if (line.find('public void onCreate(Bundle savedInstanceState)') >= 0):
+ if (line.find(string_line) >= 0):
file_handle.write(function_string)
file_handle.close()
shutil.move(temp_file_path, file_path)
def CustomizeJava(sanitized_name, package, app_url, app_local_path,
- enable_remote_debugging):
+ enable_remote_debugging, display_as_fullscreen):
root_path = os.path.join(sanitized_name, 'src',
package.replace('.', os.path.sep))
dest_activity = os.path.join(root_path, sanitized_name + 'Activity.java')
sys.exit(8)
if enable_remote_debugging:
- SetVariable(dest_activity, 'RemoteDebugging', 'true')
+ SetVariable(dest_activity,
+ 'public void onCreate(Bundle savedInstanceState)',
+ 'RemoteDebugging', 'true')
+ if display_as_fullscreen:
+ SetVariable(dest_activity,
+ 'super.onCreate(savedInstanceState)',
+ 'IsFullscreen', 'true')
def CopyExtensionFile(extension_name, suffix, src_path, dest_path):
extension_json_file.close()
+def CustomizeIcon(sanitized_name, app_root, icon_dict):
+ icon_exist = False
+ drawable_dict = {'ldpi':[1, 37], 'mdpi':[37, 72], 'hdpi':[72, 96],
+ 'xhdpi':[96, 120], 'xxhdpi':[120, 144]}
+ if not icon_dict:
+ return icon_exist
+
+ try:
+ icon_dict = dict((int(k), v) for k, v in icon_dict.items())
+ except ValueError:
+ print('The key of icon in the manifest file should be a number.')
+
+ if len(icon_dict) > 0:
+ icon_list = sorted(icon_dict.iteritems(), key = lambda d:d[0])
+ for kd, vd in drawable_dict.iteritems():
+ for item in icon_list:
+ if item[0] >= vd[0] and item[0] < vd[1]:
+ drawable_path = os.path.join(sanitized_name, 'res', 'drawable-' + kd)
+ if not os.path.exists(drawable_path):
+ os.makedirs(drawable_path)
+ icon = os.path.join(app_root, item[1])
+ if icon and os.path.isfile(icon):
+ icon_name = os.path.basename(icon)
+ icon_suffix = icon_name.split('.')[-1]
+ shutil.copyfile(icon, os.path.join(drawable_path,
+ 'icon.' + icon_suffix))
+ icon_exist = True
+ elif icon and (not os.path.isfile(icon)):
+ print ('Error: Please make sure \"' + icon + '\" does exist!')
+ sys.exit(6)
+ break
+ return icon_exist
+
+
def CustomizeAll(app_versionCode, description, icon, permissions, app_url,
app_root, app_local_path, enable_remote_debugging,
- fullscreen_flag, extensions, launch_screen_img,
+ display_as_fullscreen, extensions, launch_screen_img,
package='org.xwalk.app.template', name='AppTemplate',
- app_version='1.0.0', orientation='unspecified'):
+ app_version='1.0.0', orientation='unspecified') :
sanitized_name = ReplaceInvalidChars(name, 'apkname')
try:
Prepare(sanitized_name, package, app_root)
CustomizeXML(sanitized_name, package, app_versionCode, app_version,
- description, name, orientation, icon, fullscreen_flag,
- launch_screen_img, permissions)
+ description, name, orientation, icon, display_as_fullscreen,
+ launch_screen_img, permissions, app_root)
CustomizeJava(sanitized_name, package, app_url, app_local_path,
- enable_remote_debugging)
+ enable_remote_debugging, display_as_fullscreen)
CustomizeExtensions(sanitized_name, name, extensions)
except SystemExit as ec:
print('Exiting with error code: %d' % ec.code)
info = ('The application description. Such as:'
'--description=YourApplicationdDescription')
parser.add_option('--description', help=info)
- info = ('The path of icon. Such as: --icon=/path/to/your/customized/icon')
- parser.add_option('--icon', help=info)
info = ('The permission list. Such as: --permissions="geolocation"'
'For more permissions, such as:'
'--permissions="geolocation:permission2"')
help='The fallback image for launch_screen')
options, _ = parser.parse_args()
try:
- CustomizeAll(options.app_versionCode, options.description, options.icon,
+ icon_dict = {144: 'icons/icon_144.png',
+ 72: 'icons/icon_72.png',
+ 96: 'icons/icon_96.png',
+ 48: 'icons/icon_48.png'}
+ if options.name == None:
+ options.name = 'Example'
+ if options.app_root == None:
+ options.app_root = os.path.join('test_data', 'manifest')
+ if options.package == None:
+ options.package = 'org.xwalk.app.template'
+ if options.orientation == None:
+ options.orientation = 'unspecified'
+ if options.app_version == None:
+ options.app_version = '1.0.0'
+ CustomizeAll(options.app_versionCode, options.description, icon_dict,
options.permissions, options.app_url, options.app_root,
options.app_local_path, options.enable_remote_debugging,
options.fullscreen, options.extensions,
sys.exit(9)
if parser.GetAppRoot():
options.app_root = parser.GetAppRoot()
- temp_dict = parser.GetIcons()
- try:
- icon_dict = dict((int(k), v) for k, v in temp_dict.items())
- except ValueError:
- print('The key of icon in the manifest file should be a number.')
- # TODO(junmin): add multiple icons support.
- if icon_dict:
- icon_file = max(iter(icon_dict.items()), key=operator.itemgetter(0))[1]
- options.icon = os.path.join(options.app_root, icon_file)
+ options.icon_dict = parser.GetIcons()
if parser.GetFullScreenFlag().lower() == 'true':
options.fullscreen = True
elif parser.GetFullScreenFlag().lower() == 'false':
name = 'AppTemplate'
if options.name:
name = options.name
- app_version = '1.0.0'
+ app_version = ''
if options.app_version:
app_version = options.app_version
app_versionCode = MakeVersionCode(options)
- icon = ''
- if options.icon:
- icon = os.path.expanduser(options.icon)
app_root = ''
if options.app_root:
app_root = os.path.expanduser(options.app_root)
orientation = 'unspecified'
if options.orientation:
orientation = options.orientation
- CustomizeAll(app_versionCode, options.description, icon,
+ CustomizeAll(app_versionCode, options.description, options.icon_dict,
options.permissions, options.app_url, app_root,
options.app_local_path, remote_debugging,
fullscreen_flag, options.extensions,
if options.permissions:
permission_list = options.permissions.split(':')
else:
- print ('Warning: all supported permissions on Android port are added. '
- 'Refer to https://github.com/crosswalk-project/'
- 'crosswalk-website/wiki/Crosswalk-manifest')
+ print('Warning: all supported permissions on Android port are added. '
+ 'Refer to https://github.com/crosswalk-project/'
+ 'crosswalk-website/wiki/Crosswalk-manifest')
permission_list = permission_mapping_table.keys()
options.permissions = HandlePermissionList(permission_list)
-
+ options.icon_dict = {}
else:
try:
ParseManifest(options)
except SystemExit as ec:
return ec.code
+ if (options.app_root and options.app_local_path and not
+ os.path.isfile(os.path.join(options.app_root, options.app_local_path))):
+ print('Please make sure that the local path file of launching app '
+ 'does exist.')
+ sys.exit(7)
+
options.name = ReplaceInvalidChars(options.name, 'apkname')
options.package = ReplaceInvalidChars(options.package)
sanitized_name = ReplaceInvalidChars(options.name, 'apkname')
self.checkApks('Example', '1.0.0')
Clean('Example', '1.0.0')
+ def testPermissionsWithError(self):
+ cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
+ '--package=org.xwalk.example', '--permissions=UndefinedPermission',
+ '--app-url=http://www.intel.com', self._mode]
+ out = RunCommand(cmd)
+ self.assertTrue(out.find('related API is not supported.') != -1)
+ cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
+ '--package=org.xwalk.example',
+ '--permissions=Contacts.Geolocation.Messaging',
+ '--app-url=http://www.intel.com', self._mode]
+ out = RunCommand(cmd)
+ self.assertTrue(out.find('related API is not supported.') != -1)
+
def testPackage(self):
cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
self._mode]
self.assertFalse(os.path.exists('Example.apk'))
Clean('Example', '1.0.0')
+ manifest_path = os.path.join('test_data', 'manifest',
+ 'manifest_app_launch_local_path.json')
+ cmd = ['python', 'make_apk.py', '--manifest=%s' % manifest_path, self._mode]
+ out = RunCommand(cmd)
+ self.assertTrue(out.find('Please make sure that the local path file') != -1)
+ self.assertFalse(os.path.exists('Example.apk'))
+ Clean('Example', '1.0.0')
+
def testIcon(self):
- icon_path = './app_src/res/drawable-xhdpi/crosswalk.png'
+ manifest_path = os.path.join('test_data', 'manifest', 'manifest_icon.json')
cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
'--package=org.xwalk.example', '--app-url=http://www.intel.com',
- '--icon=%s' % icon_path, self._mode]
+ '--manifest=%s' % manifest_path, self._mode]
RunCommand(cmd)
manifest = 'Example/AndroidManifest.xml'
with open(manifest, 'r') as content_file:
content = content_file.read()
- self.assertTrue(content.find('crosswalk') != -1)
- self.assertTrue(os.path.exists('Example/res/drawable'))
+ self.assertTrue(content.find('drawable/icon') != -1)
self.checkApks('Example', '1.0.0')
Clean('Example', '1.0.0')
icon_path = './app_src/res/drawable-xhdpi/crosswalk.png'
extension_path = 'test_data/extensions/myextension'
arch = ''
+ icon = ''
if exec_file.find("make_apk.py") != -1:
arch = '--arch=x86'
+ icon = '--icon=%s' % icon_path
cmd = ['python', '%s' % exec_file,
'--app-version=1.0.0',
'--app-url=http://www.intel.com',
'--enable-remote-debugging',
'--extensions=%s' % extension_path,
'--fullscreen',
- '--icon=%s' % icon_path,
+ '%s' % icon,
'--name=Example',
'--orientation=landscape',
'--package=org.xwalk.example',
self.assertTrue(content.find('versionName') != -1)
# Test orientation option.
self.assertTrue(content.find('landscape') != -1)
- # Test icon option.
- self.assertTrue(os.path.exists('Example/res/drawable'))
# Test fullscreen option
theme = 'Example/res/values/theme.xml'
with open(theme, 'r') as content_file:
test_suite.addTest(TestMakeApk('testOrientation'))
test_suite.addTest(TestMakeApk('testPackage'))
test_suite.addTest(TestMakeApk('testPermissions'))
+ test_suite.addTest(TestMakeApk('testPermissionsWithError'))
test_suite.addTest(TestMakeApk('testXPK'))
test_suite.addTest(TestMakeApk('testXPKWithError'))
test_suite.addTest(TestMakeApk('testTargetDir'))
ret_dict['plugin'] = ''
if 'plugin' in self.data_src:
ret_dict['plugin'] = self.data_src['plugin']
- if 'fullscreen' in self.data_src:
- ret_dict['fullscreen'] = self.data_src['fullscreen']
+ if 'display' in self.data_src and 'fullscreen' in self.data_src['display']:
+ ret_dict['fullscreen'] = 'true'
else:
- ret_dict['fullscreen'] = 'False'
+ ret_dict['fullscreen'] = ''
ret_dict['launch_screen_img'] = ''
if 'launch_screen' in self.data_src:
if 'default' not in self.data_src['launch_screen']:
"Messaging"],
"required_version": "1.28.1.0",
"plugin": [],
- "fullscreen":"true"
+ "display": ["fullscreen"]
}
"permissions": ["geolocation"],
"required_version": "1.28.1.0",
"plugin": [],
- "fullscreen":"true"
+ "display": ["fullscreen"]
}
--- /dev/null
+{
+ "name": "Example",
+ "version": "1.0.0",
+ "launch_path": "http://www.intel.com",
+ "app": {
+ "launch": {
+ "local_path": "index.html"
+ }
+ },
+ "description": "a sample description",
+ "origin": "app://app.id",
+ "icons": {
+ "144": "icons/icon_144.png",
+ "96": "icons/icon_96.png",
+ "72": "icons/icon_72.png",
+ "48": "icons/icon_48.png"
+ },
+ "default_locale": "en",
+ "fullscreen":"true"
+}
<include name="IDR_XWALK_APPLICATION_EVENT_API" file="extension/application_event_api.js" type="BINDATA" />
<include name="IDR_XWALK_APPLICATION_RUNTIME_API" file="extension/application_runtime_api.js" type="BINDATA" />
<include name="IDR_XWALK_APPLICATION_WIDGET_API" file="extension/application_widget_api.js" type="BINDATA" />
+ <include name="IDR_XWALK_APPLICATION_WIDGET_COMMON_API" file="extension/application_widget_common_api.js" type="BINDATA" />
<include name="IDR_XWALK_APPLICATION_TEST_API" file="test/application_testapi.js" type="BINDATA" />
</includes>
</release>
#include "xwalk/application/common/application_manifest_constants.h"
#include "xwalk/application/common/constants.h"
#include "xwalk/application/common/manifest_handlers/main_document_handler.h"
+#include "xwalk/application/common/manifest_handlers/warp_handler.h"
#include "xwalk/application/common/event_names.h"
#include "xwalk/runtime/browser/runtime.h"
#include "xwalk/runtime/browser/runtime_context.h"
#include "xwalk/runtime/browser/xwalk_runner.h"
+#include "xwalk/runtime/common/xwalk_common_messages.h"
namespace xwalk {
"index.svg",
"index.xhtml",
"index.xht"};
+
+content::RenderProcessHost* GetHost(Runtime* runtime) {
+ DCHECK(runtime);
+ return runtime->web_contents()->GetRenderProcessHost();
+}
} // namespace
namespace application {
return false;
main_runtime_ = Runtime::Create(runtime_context_, this);
+ InitSecurityPolicy();
main_runtime_->LoadURL(url);
if (entry_point_used_ != AppMainKey) {
NativeAppWindow::CreateParams params;
return false;
}
+void Application::InitSecurityPolicy() {
+ if (application_data_->GetPackageType() != Manifest::TYPE_WGT)
+ return;
+ const WARPInfo* info = static_cast<WARPInfo*>(
+ application_data_->GetManifestData(widget_keys::kAccessKey));
+ if (!info
+#if defined(OS_TIZEN)
+ // On Tizen, CSP mode has higher priority, and WARP will be disabled
+ // if the application is under CSP mode.
+ || application_data_->HasCSPDefined()
+#endif
+ )
+ return;
+ GURL app_url = application_data_->URL();
+ const base::ListValue* whitelist = info->GetWARP();
+ bool enable_warp_mode = true;
+ for (base::ListValue::const_iterator it = whitelist->begin();
+ it != whitelist->end(); ++it) {
+ base::DictionaryValue* value = NULL;
+ (*it)->GetAsDictionary(&value);
+ std::string dest;
+ if (!value || !value->GetString(widget_keys::kAccessOriginKey, &dest) ||
+ dest.empty())
+ continue;
+ if (dest == "*") {
+ enable_warp_mode = false;
+ break;
+ }
+
+ GURL dest_url(dest);
+ // The default subdomains attrubute should be "false".
+ std::string subdomains = "false";
+ value->GetString(widget_keys::kAccessSubdomainsKey, &subdomains);
+ GetHost(main_runtime_)->Send(
+ new ViewMsg_SetAccessWhiteList(
+ app_url, dest_url, (subdomains == "true")));
+ }
+ if (enable_warp_mode)
+ GetHost(main_runtime_)->Send(new ViewMsg_EnableWarpMode());
+}
+
} // namespace application
} // namespace xwalk
bool IsOnSuspendHandlerRegistered() const;
bool IsTerminating() const { return finish_observer_; }
+ void InitSecurityPolicy();
+
RuntimeContext* runtime_context_;
const scoped_refptr<ApplicationData> application_data_;
Runtime* main_runtime_;
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
#include "base/version.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "xwalk/runtime/browser/runtime_context.h"
#include "xwalk/runtime/browser/runtime.h"
#include "xwalk/runtime/browser/xwalk_runner.h"
+#include "xwalk/runtime/common/xwalk_paths.h"
#if defined(OS_TIZEN)
#include "xwalk/application/browser/installer/tizen/service_package_installer.h"
return true;
}
+void RemoveWidgetStorageFiles(const base::FilePath& storage_path,
+ const std::string& app_id) {
+ base::FileEnumerator iter(storage_path, true,
+ base::FileEnumerator::FILES);
+ for (base::FilePath file = iter.Next(); !file.empty(); file = iter.Next()) {
+ if (file.MaybeAsASCII().find(app_id) != std::string::npos)
+ base::DeleteFile(file, false);
+ }
+}
+
} // namespace
const base::FilePath::CharType kApplicationsDir[] =
application->URL(),
partition->GetURLRequestContext());
+ base::FilePath path;
+ PathService::Get(xwalk::DIR_WGT_STORAGE_PATH, &path);
+ RemoveWidgetStorageFiles(path, id);
+
FOR_EACH_OBSERVER(Observer, observers_, OnApplicationUninstalled(id));
return result;
Application* ApplicationService::Launch(
const std::string& id, const Application::LaunchParams& params) {
+ Application* application = NULL;
scoped_refptr<ApplicationData> application_data =
application_storage_->GetApplicationData(id);
if (!application_data) {
return NULL;
}
- return Launch(application_data, params);
+ if ((application = Launch(application_data, params))) {
+ scoped_refptr<Event> event = Event::CreateEvent(
+ kOnLaunched, scoped_ptr<base::ListValue>(new base::ListValue));
+ event_manager_->SendEvent(application->id(), event);
+ }
+ return application;
}
Application* ApplicationService::Launch(
const base::FilePath& path, const Application::LaunchParams& params) {
+ Application* application = NULL;
if (!base::DirectoryExists(path))
return NULL;
return NULL;
}
- return Launch(application_data, params);
+ if ((application = Launch(application_data, params))) {
+ scoped_refptr<Event> event = Event::CreateEvent(
+ kOnLaunched, scoped_ptr<base::ListValue>(new base::ListValue));
+ event_manager_->SendEvent(application->id(), event);
+ }
+ return application;
}
namespace {
if (cmd_line.HasSwitch(switches::kFullscreen))
launch_params.window_state = ui::SHOW_STATE_FULLSCREEN;
- if (Application* application =
- application_service_->Launch(param, launch_params)) {
- event_manager_->SendEvent(application->id(), event);
+ if (application_service_->Launch(param, launch_params)) {
return true;
}
if (!application_data) {
LOG(ERROR) << "Error occurred while trying to launch application: "
<< error;
- return NULL;
+ return false;
}
Application::LaunchParams launch_params;
Package::Package(const base::FilePath& source_path)
: source_path_(source_path),
- is_extracted_(false) {
+ is_extracted_(false),
+ is_valid_(false) {
}
Package::~Package() {
return true;
}
- if (!IsValid()) {
- LOG(ERROR) << "XPK/WGT file is not valid.";
- return false;
- }
-
if (!CreateTempDirectory()) {
LOG(ERROR) << "Can't create a temporary"
"directory for extracting the package content.";
static scoped_ptr<Package> Create(const base::FilePath& path);
// The function will unzip the XPK/WGT file and return the target path where
// to decompress by the parameter |target_path|.
- bool Extract(base::FilePath* target_path);
+ virtual bool Extract(base::FilePath* target_path);
protected:
explicit Package(const base::FilePath& source_path);
scoped_ptr<ScopedStdioHandle> file_;
if (!value.empty())
id_ = GenerateId(value);
+ is_valid_ = true;
+
scoped_ptr<ScopedStdioHandle> file(
new ScopedStdioHandle(base::OpenFile(path, "rb")));
} // namespace application
} // namespace xwalk
-
-
-
return true;
}
+bool XPKPackage::Extract(base::FilePath* target_path) {
+ if (is_extracted_) {
+ *target_path = temp_dir_.path();
+ return true;
+ }
+
+ if (!IsValid()) {
+ LOG(ERROR) << "The XPK file is not valid.";
+ return false;
+ }
+
+ return Package::Extract(target_path);
+}
+
} // namespace application
} // namespace xwalk
};
virtual ~XPKPackage();
explicit XPKPackage(const base::FilePath& path);
+ virtual bool Extract(base::FilePath* target_path);
private:
// verify the signature in the xpk package
}
const std::string ApplicationData::VersionString() const {
- return Version()->GetString();
+ if (!version_->components().empty())
+ return Version()->GetString();
+
+ return "";
}
bool ApplicationData::IsPlatformApp() const {
return permissions;
}
+#if defined(OS_TIZEN)
+bool ApplicationData::HasCSPDefined() const {
+ return (manifest_->HasPath(widget_keys::kCSPKey) ||
+ manifest_->HasPath(widget_keys::kCSPReportOnlyKey) ||
+ manifest_->HasPath(widget_keys::kAllowNavigationKey));
+}
+#endif
+
} // namespace application
} // namespace xwalk
bool HasMainDocument() const;
Manifest::PackageType GetPackageType() const;
+#if defined(OS_TIZEN)
+ bool HasCSPDefined() const;
+#endif
+
private:
friend class base::RefCountedThreadSafe<ApplicationData>;
friend class ApplicationStorageImpl;
const char kAppMainSourceKey[] = "app.main.source";
const char kCSPKey[] = "content_security_policy";
const char kDescriptionKey[] = "description";
+const char kDisplay[] = "display";
const char kLaunchLocalPathKey[] = "app.launch.local_path";
const char kLaunchScreen[] = "launch_screen";
const char kLaunchScreenReadyWhen[] = "launch_screen.ready_when";
// manifest keys for widget applications.
namespace application_widget_keys {
+const char kNamespaceKey[] = "@namespace";
const char kNameKey[] = "widget.name.#text";
const char kVersionKey[] = "widget.@version";
const char kWidgetKey[] = "widget";
#if defined(OS_TIZEN)
const char kIcon128Key[] = "widget.icon.@src";
+const char kTizenApplicationKey[] = "widget.application";
+// Child keys inside 'kTizenApplicationKey'
+const char kTizenApplicationIdKey[] = "@id";
+const char kTizenApplicationPackageKey[] = "@package";
+const char kTizenApplicationRequiredVersionKey[] = "@required_version";
+
const char kTizenAppIdKey[] = "widget.application.@package";
+const char kAllowNavigationKey[] = "widget.allow-navigation.#text";
+const char kCSPReportOnlyKey[] =
+ "widget.content-security-policy-report-only.#text";
#endif
} // namespace application_widget_keys
+#if defined(OS_TIZEN)
+const char kTizenNamespacePrefix[] = "http://tizen.org/ns/widgets";
+#endif
+
namespace application_manifest_errors {
const char kInvalidDescription[] =
"Invalid value for 'description'.";
extern const char kAppMainSourceKey[];
extern const char kCSPKey[];
extern const char kDescriptionKey[];
+ extern const char kDisplay[];
extern const char kLaunchLocalPathKey[];
extern const char kLaunchScreen[];
extern const char kLaunchScreenReadyWhen[];
} // namespace application_manifest_keys
namespace application_widget_keys {
+ extern const char kNamespaceKey[];
extern const char kNameKey[];
extern const char kLaunchLocalPathKey[];
extern const char kWebURLsKey[];
extern const char kPreferencesValueKey[];
extern const char kPreferencesReadonlyKey[];
#if defined(OS_TIZEN)
+ extern const char kTizenApplicationKey[];
+ extern const char kTizenApplicationIdKey[];
+ extern const char kTizenApplicationPackageKey[];
+ extern const char kTizenApplicationRequiredVersionKey[];
extern const char kTizenAppIdKey[];
extern const char kIcon128Key[];
+ extern const char kAllowNavigationKey[];
+ extern const char kCSPReportOnlyKey[];
#endif
} // namespace application_widget_keys
+#if defined(OS_TIZEN)
+extern const char kTizenNamespacePrefix[];
+#endif
+
namespace application_manifest_errors {
extern const char kInvalidDescription[];
extern const char kInvalidKey[];
#include "base/stl_util.h"
#include "xwalk/application/common/manifest_handlers/csp_handler.h"
#include "xwalk/application/common/manifest_handlers/main_document_handler.h"
+#if defined(OS_TIZEN)
+#include "xwalk/application/common/manifest_handlers/navigation_handler.h"
+#include "xwalk/application/common/manifest_handlers/tizen_application_handler.h"
+#endif
#include "xwalk/application/common/manifest_handlers/permissions_handler.h"
#include "xwalk/application/common/manifest_handlers/warp_handler.h"
#include "xwalk/application/common/manifest_handlers/widget_handler.h"
handlers.push_back(new WARPHandler);
#if defined(OS_TIZEN)
handlers.push_back(new CSPHandler(Manifest::TYPE_WGT));
+ handlers.push_back(new NavigationHandler);
+ handlers.push_back(new TizenApplicationHandler);
#endif
widget_registry_ = new ManifestHandlerRegistry(handlers);
return widget_registry_;
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/application/common/manifest_handlers/navigation_handler.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "xwalk/application/common/application_manifest_constants.h"
+
+namespace xwalk {
+
+namespace keys = application_widget_keys;
+
+namespace application {
+namespace {
+const char navigation_separator = ' ';
+}
+
+NavigationInfo::NavigationInfo(const std::string& allowed_domains) {
+ base::SplitString(allowed_domains, navigation_separator, &allowed_domains_);
+}
+
+NavigationInfo::~NavigationInfo() {
+}
+
+NavigationHandler::NavigationHandler() {
+}
+
+NavigationHandler::~NavigationHandler() {
+}
+
+bool NavigationHandler::Parse(scoped_refptr<ApplicationData> application_data,
+ base::string16* error) {
+ if (!application_data->GetManifest()->HasPath(keys::kAllowNavigationKey))
+ return true;
+ std::string allowed_domains;
+ if (!application_data->GetManifest()->GetString(keys::kAllowNavigationKey,
+ &allowed_domains)) {
+ *error = base::ASCIIToUTF16("Invalid value of allow-navigation.");
+ return false;
+ }
+ if (allowed_domains.empty())
+ return true;
+
+ application_data->SetManifestData(keys::kAllowNavigationKey,
+ new NavigationInfo(allowed_domains));
+
+ return true;
+}
+
+std::vector<std::string> NavigationHandler::Keys() const {
+ return std::vector<std::string>(1, keys::kAllowNavigationKey);
+}
+
+} // namespace application
+} // namespace xwalk
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef XWALK_APPLICATION_COMMON_MANIFEST_HANDLERS_NAVIGATION_HANDLER_H_
+#define XWALK_APPLICATION_COMMON_MANIFEST_HANDLERS_NAVIGATION_HANDLER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string_split.h"
+#include "xwalk/application/common/application_data.h"
+#include "xwalk/application/common/manifest_handler.h"
+
+namespace xwalk {
+namespace application {
+
+class NavigationInfo : public ApplicationData::ManifestData {
+ public:
+ explicit NavigationInfo(const std::string& allowed_domains);
+ virtual ~NavigationInfo();
+
+ const std::vector<std::string>& GetAllowedDomains() const {
+ return allowed_domains_; }
+
+ private:
+ std::vector<std::string> allowed_domains_;
+};
+
+class NavigationHandler : public ManifestHandler {
+ public:
+ NavigationHandler();
+ virtual ~NavigationHandler();
+
+ virtual bool Parse(scoped_refptr<ApplicationData> application_data,
+ base::string16* error) OVERRIDE;
+ virtual std::vector<std::string> Keys() const OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NavigationHandler);
+};
+
+} // namespace application
+} // namespace xwalk
+
+#endif // XWALK_APPLICATION_COMMON_MANIFEST_HANDLERS_NAVIGATION_HANDLER_H_
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/application/common/manifest_handlers/navigation_handler.h"
+
+#include <string>
+#include <vector>
+#include "xwalk/application/common/application_manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace xwalk {
+
+namespace keys = application_widget_keys;
+
+namespace application {
+
+class NavigationHandlerTest: public testing::Test {
+ public:
+ virtual void SetUp() OVERRIDE {
+ manifest.SetString(keys::kNameKey, "no name");
+ manifest.SetString(keys::kVersionKey, "0");
+ }
+
+ scoped_refptr<ApplicationData> CreateApplication() {
+ std::string error;
+ scoped_refptr<ApplicationData> application = ApplicationData::Create(
+ base::FilePath(), Manifest::INVALID_TYPE, manifest, "", &error);
+ return application;
+ }
+
+ const NavigationInfo* GetNavigationInfo(
+ scoped_refptr<ApplicationData> application) {
+ const NavigationInfo* info = static_cast<NavigationInfo*>(
+ application->GetManifestData(keys::kAllowNavigationKey));
+ return info;
+ }
+
+ base::DictionaryValue manifest;
+};
+
+TEST_F(NavigationHandlerTest, NoNavigation) {
+ scoped_refptr<ApplicationData> application = CreateApplication();
+ EXPECT_TRUE(application.get());
+ EXPECT_FALSE(GetNavigationInfo(application));
+}
+
+TEST_F(NavigationHandlerTest, OneNavigation) {
+ manifest.SetString(keys::kAllowNavigationKey, "http://www.sample.com");
+ scoped_refptr<ApplicationData> application = CreateApplication();
+ EXPECT_TRUE(application.get());
+ EXPECT_EQ(application->GetPackageType(), Manifest::TYPE_WGT);
+ const NavigationInfo* info = GetNavigationInfo(application);
+ EXPECT_TRUE(info);
+ const std::vector<std::string>& list = info->GetAllowedDomains();
+ EXPECT_TRUE(list.size() == 1 && list[0] == "http://www.sample.com");
+}
+
+TEST_F(NavigationHandlerTest, Navigations) {
+ manifest.SetString(keys::kAllowNavigationKey,
+ "http://www.sample1.com www.sample2.com");
+ scoped_refptr<ApplicationData> application = CreateApplication();
+ EXPECT_TRUE(application.get());
+ EXPECT_EQ(application->GetPackageType(), Manifest::TYPE_WGT);
+ const NavigationInfo* info = GetNavigationInfo(application);
+ EXPECT_TRUE(info);
+ const std::vector<std::string>& list = info->GetAllowedDomains();
+ EXPECT_TRUE(list.size() == 2 &&
+ list[0] == "http://www.sample1.com" &&
+ list[1] == "www.sample2.com");
+}
+
+} // namespace application
+} // namespace xwalk
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/application/common/manifest_handlers/tizen_application_handler.h"
+
+#include <map>
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/strings/string_split.h"
+#include "third_party/re2/re2/re2.h"
+#include "xwalk/application/common/application_manifest_constants.h"
+
+namespace xwalk {
+
+namespace keys = application_widget_keys;
+
+namespace application {
+
+TizenApplicationInfo::TizenApplicationInfo() {
+}
+
+TizenApplicationInfo::~TizenApplicationInfo() {
+}
+
+TizenApplicationHandler::TizenApplicationHandler() {}
+
+TizenApplicationHandler::~TizenApplicationHandler() {}
+
+bool TizenApplicationHandler::Parse(scoped_refptr<ApplicationData> application,
+ base::string16* error) {
+ scoped_ptr<TizenApplicationInfo> app_info(new TizenApplicationInfo);
+ const Manifest* manifest = application->GetManifest();
+ DCHECK(manifest);
+
+ base::Value* app_value = NULL;
+ manifest->Get(keys::kTizenApplicationKey, &app_value);
+ // Find an application element with tizen namespace
+ base::DictionaryValue* app_dict;
+ std::string value;
+ bool find = false;
+ if (app_value && app_value->IsType(base::Value::TYPE_DICTIONARY)) {
+ app_value->GetAsDictionary(&app_dict);
+ find = app_dict->GetString(keys::kNamespaceKey, &value);
+ find = find && (value == kTizenNamespacePrefix);
+ } else if (app_value && app_value->IsType(base::Value::TYPE_LIST)) {
+ base::ListValue* list;
+ app_value->GetAsList(&list);
+ for (base::ListValue::iterator it = list->begin();
+ it != list->end(); ++it) {
+ (*it)->GetAsDictionary(&app_dict);
+ find = app_dict->GetString(keys::kNamespaceKey, &value);
+ find = find && (value == kTizenNamespacePrefix);
+ if (find)
+ break;
+ }
+ }
+
+ if (!find) {
+ *error = base::ASCIIToUTF16(
+ "Cannot find application element with tizen namespace"
+ " or the tizen namespace prefix is incorrect.\n");
+ return false;
+ }
+ if (app_dict->GetString(keys::kTizenApplicationIdKey, &value))
+ app_info->set_id(value);
+ if (app_dict->GetString(keys::kTizenApplicationPackageKey, &value))
+ app_info->set_package(value);
+ if (app_dict->GetString(keys::kTizenApplicationRequiredVersionKey, &value))
+ app_info->set_required_version(value);
+
+ application->SetManifestData(keys::kTizenApplicationKey,
+ app_info.release());
+ return true;
+}
+
+bool TizenApplicationHandler::Validate(
+ scoped_refptr<const ApplicationData> application,
+ std::string* error,
+ std::vector<InstallWarning>* warnings) const {
+ const TizenApplicationInfo* app_info =
+ static_cast<const TizenApplicationInfo*>(
+ application->GetManifestData(keys::kTizenApplicationKey));
+
+ const char kIdPattern[] = "\\A[0-9a-zA-Z]{10}[.][0-9a-zA-Z]{1,52}\\z";
+ const char kPackagePattern[] = "\\A[0-9a-zA-Z]{10}\\z";
+ if (!RE2::PartialMatch(app_info->id(), kIdPattern)) {
+ *error = std::string("The id property of application element"
+ " does not match the format\n");
+ return false;
+ }
+ if (!RE2::PartialMatch(app_info->package(), kPackagePattern)) {
+ *error = std::string("The package property of application element"
+ " does not match the format\n");
+ return false;
+ }
+ if (app_info->id().find(app_info->package()) != 0) {
+ *error = std::string("The application element property id"
+ " does not start with package.\n");
+ return false;
+ }
+ // TODO(hongzhang): We need a version map (Tizen API version
+ // to Crosswalk API version) for checking required_version
+ if (app_info->required_version().empty()) {
+ *error = std::string("The required_version property of application"
+ " element does not exist.\n");
+ return false;
+ }
+
+ return true;
+}
+
+std::vector<std::string> TizenApplicationHandler::Keys() const {
+ return std::vector<std::string>(1, keys::kTizenApplicationKey);
+}
+
+} // namespace application
+} // namespace xwalk
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef XWALK_APPLICATION_COMMON_MANIFEST_HANDLERS_TIZEN_APPLICATION_HANDLER_H_
+#define XWALK_APPLICATION_COMMON_MANIFEST_HANDLERS_TIZEN_APPLICATION_HANDLER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/values.h"
+#include "xwalk/application/common/application_data.h"
+#include "xwalk/application/common/manifest_handler.h"
+
+namespace xwalk {
+namespace application {
+
+class TizenApplicationInfo : public ApplicationData::ManifestData {
+ public:
+ TizenApplicationInfo();
+ virtual ~TizenApplicationInfo();
+
+ void set_id(const std::string& id) {
+ id_ = id;
+ }
+ void set_package(const std::string& package) {
+ package_ = package;
+ }
+ void set_required_version(
+ const std::string& required_version) {
+ required_version_ = required_version;
+ }
+ const std::string& id() const {
+ return id_;
+ }
+ const std::string& package() const {
+ return package_;
+ }
+ const std::string& required_version() const {
+ return required_version_;
+ }
+
+ private:
+ std::string id_;
+ std::string package_;
+ std::string required_version_;
+};
+
+class TizenApplicationHandler : public ManifestHandler {
+ public:
+ TizenApplicationHandler();
+ virtual ~TizenApplicationHandler();
+
+ virtual bool Parse(scoped_refptr<ApplicationData> application,
+ base::string16* error) OVERRIDE;
+ virtual bool Validate(scoped_refptr<const ApplicationData> application,
+ std::string* error,
+ std::vector<InstallWarning>* warnings) const OVERRIDE;
+ virtual std::vector<std::string> Keys() const OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TizenApplicationHandler);
+};
+
+} // namespace application
+} // namespace xwalk
+
+#endif // XWALK_APPLICATION_COMMON_MANIFEST_HANDLERS_TIZEN_APPLICATION_HANDLER_H_
if (in_value->GetString(keys::kPreferencesValueKey, &pref_value))
out_value->SetString(kPreferencesValue, pref_value);
- if (in_value->GetString(keys::kPreferencesReadonlyKey, &pref_readonly))
- out_value->SetString(kPreferencesReadonly, pref_readonly);
+ if (in_value->GetString(keys::kPreferencesReadonlyKey, &pref_readonly)) {
+ out_value->SetBoolean(kPreferencesReadonly, pref_readonly == "true");
+ }
}
} // namespace
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/application/common/manifest_handlers/widget_handler.h"
+
+#include "xwalk/application/common/application_manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace xwalk {
+
+namespace keys = application_widget_keys;
+
+namespace application {
+
+namespace {
+// Below key names are readable from Javascript widget interface.
+const char kWidgetAuthor[] = "author";
+const char kWidgetDecription[] = "description";
+const char kWidgetName[] = "name";
+const char kWidgetShortName[] = "shortName";
+const char kWidgetVersion[] = "version";
+const char kWidgetID[] = "id";
+const char kWidgetAuthorEmail[] = "authorEmail";
+const char kWidgetAuthorHref[] = "authorHref";
+const char kWidgetHeight[] = "height";
+const char kWidgetWidth[] = "width";
+const char kWidgetPreferences[] = "preferences";
+
+// Child keys inside 'preferences' key.
+const char kWidgetPreferencesName[] = "name";
+const char kWidgetPreferencesValue[] = "value";
+const char kWidgetPreferencesReadonly[] = "readonly";
+
+// Value to test
+const char author[] = "Some one";
+const char decription[] = "This is a test";
+const char name[] = "widget handler unittest";
+const char shortName[] = "whu";
+const char version[] = "0.0.0.1";
+const char ID[] = "iiiiiiiiiid";
+const char authorEmail[] = "aaa@bbb.com";
+const char authorHref[] = "http://www.ssss.com";
+const char height[] = "800";
+const char width[] = "480";
+
+const char* preferencesName[] = {"pname0", "pname1", "pname2"};
+const char* preferencesValue[] = {"pvalue0", "pvalue1", "pvalue2"};
+const char* preferencesReadonly[] = {"true", "false", "false"};
+} // namespace
+
+class WidgetHandlerTest: public testing::Test {
+ public:
+ scoped_refptr<ApplicationData> CreateApplication(
+ base::DictionaryValue &manifest) {
+ std::string error;
+ scoped_refptr<ApplicationData> application = ApplicationData::Create(
+ base::FilePath(), Manifest::INVALID_TYPE, manifest, "", &error);
+ return application;
+ }
+
+ WidgetInfo* GetWidgetInfo(scoped_refptr<ApplicationData> application) {
+ WidgetInfo* info = static_cast<WidgetInfo*>(
+ application->GetManifestData(keys::kWidgetKey));
+ return info;
+ }
+
+ base::DictionaryValue* GetPreferencesItem(int id,
+ bool is_parsed_manifest_key) {
+ base::DictionaryValue* preferences = new base::DictionaryValue;
+ if (is_parsed_manifest_key) {
+ preferences->SetString(keys::kPreferencesNameKey,
+ preferencesName[id]);
+ preferences->SetString(keys::kPreferencesValueKey,
+ preferencesValue[id]);
+ // PreferencesReadonly is string on manifest and bool on widgetInfo
+ preferences->SetString(keys::kPreferencesReadonlyKey,
+ preferencesReadonly[id]);
+ } else {
+ preferences->SetString(kWidgetPreferencesName,
+ preferencesName[id]);
+ preferences->SetString(kWidgetPreferencesValue,
+ preferencesValue[id]);
+ preferences->SetBoolean(kWidgetPreferencesReadonly,
+ strncmp(preferencesReadonly[id], "true", 4) == 0);
+ }
+ return preferences;
+ }
+
+ // No Preferences and full other information
+ void SetAllInfoToManifest(base::DictionaryValue* manifest) {
+ // Insert some key-value pairs into manifest use full key
+ manifest->SetString(keys::kAuthorKey, author);
+ manifest->SetString(keys::kDescriptionKey, decription);
+ manifest->SetString(keys::kNameKey, name);
+ manifest->SetString(keys::kShortNameKey, shortName);
+ manifest->SetString(keys::kVersionKey, version);
+ manifest->SetString(keys::kIDKey, ID);
+ manifest->SetString(keys::kAuthorEmailKey, authorEmail);
+ manifest->SetString(keys::kAuthorHrefKey, authorHref);
+ manifest->SetString(keys::kHeightKey, height);
+ manifest->SetString(keys::kWidthKey, width);
+ }
+
+ // No Preferences and full other information
+ void SetAllInfoToWidget(base::DictionaryValue* widget) {
+ // Insert some key-value pairs into widget use widget key;
+ widget->SetString(kWidgetAuthor, author);
+ widget->SetString(kWidgetDecription, decription);
+ widget->SetString(kWidgetName, name);
+ widget->SetString(kWidgetShortName, shortName);
+ widget->SetString(kWidgetVersion, version);
+ widget->SetString(kWidgetID, ID);
+ widget->SetString(kWidgetAuthorEmail, authorEmail);
+ widget->SetString(kWidgetAuthorHref, authorHref);
+ widget->SetString(kWidgetHeight, height);
+ widget->SetString(kWidgetWidth, width);
+ }
+};
+
+TEST_F(WidgetHandlerTest, ParseManifestWithOnlyNameAndVersion) {
+ base::DictionaryValue manifest;
+ manifest.SetString(keys::kNameKey, "no name");
+ manifest.SetString(keys::kVersionKey, "0");
+
+ scoped_refptr<ApplicationData> application = CreateApplication(manifest);
+ EXPECT_TRUE(application);
+
+ WidgetInfo* info = GetWidgetInfo(application);
+ int size = info->GetWidgetInfo()->size();
+
+ // Only name and version ,others are empty string "",but exist.
+ // And widget have 10 items.
+ EXPECT_EQ(size, 10);
+
+ base::DictionaryValue* widget = info->GetWidgetInfo();
+ base::DictionaryValue::Iterator it(*widget);
+
+ std::string tmpStr;
+ // Check value
+ while (!it.IsAtEnd()) {
+ it.value().GetAsString(&tmpStr);
+ if (it.key() == kWidgetName) {
+ EXPECT_EQ(tmpStr, "no name");
+ } else if (it.key() == kWidgetVersion) {
+ EXPECT_EQ(tmpStr, "0");
+ } else {
+ EXPECT_EQ(tmpStr, "");
+ }
+ it.Advance();
+ }
+}
+
+TEST_F(WidgetHandlerTest,
+ ParseManifestWithAllOfOtherItemsAndOnePreferenceItem) {
+ // Create a manifest with one preference item.
+ scoped_ptr<base::DictionaryValue> manifest(new base::DictionaryValue);
+ SetAllInfoToManifest(manifest.get());
+ manifest->Set(keys::kPreferencesKey, GetPreferencesItem(0, true));
+ // Create an application use this manifest.
+ scoped_refptr<ApplicationData> application;
+ application = CreateApplication(*(manifest.get()));
+ EXPECT_TRUE(application);
+ EXPECT_EQ(application->GetPackageType(), Manifest::TYPE_WGT);
+ // Get widget info from this application.
+ WidgetInfo* info = GetWidgetInfo(application);
+ EXPECT_TRUE(info);
+ scoped_ptr<base::DictionaryValue> Copy(info->GetWidgetInfo()->DeepCopy());
+ base::DictionaryValue* widget_parsed_from_manifest;
+ Copy->GetAsDictionary(&widget_parsed_from_manifest);
+ EXPECT_TRUE(widget_parsed_from_manifest);
+
+ // Create a widget with one preference item manually.
+ scoped_ptr<base::DictionaryValue> widget(new base::DictionaryValue);
+ SetAllInfoToWidget(widget.get());
+ widget->Set(kWidgetPreferences, GetPreferencesItem(0, false));
+
+ // Compare the widget parsed from manifest with
+ // the widget create manually.
+ EXPECT_TRUE(widget->Equals(widget_parsed_from_manifest));
+}
+
+TEST_F(WidgetHandlerTest,
+ ParseManifestWithAllOfOtherItemsAndThreePreferenceItemsList) {
+ // Create a manifest with three preference items.
+ scoped_ptr<base::DictionaryValue> manifest(new base::DictionaryValue);
+ SetAllInfoToManifest(manifest.get());
+ base::ListValue* manifestPreferences = new base::ListValue;
+ for (int i = 0; i < 3; i++) {
+ manifestPreferences->Append(GetPreferencesItem(i, true));
+ }
+ // Create an application use this manifest,
+ scoped_refptr<ApplicationData> application;
+ application = CreateApplication(*(manifest.get()));
+ EXPECT_TRUE(application);
+ EXPECT_EQ(application->GetPackageType(), Manifest::TYPE_WGT);
+ // Get widget info from this application.
+ WidgetInfo* info = GetWidgetInfo(application);
+ EXPECT_TRUE(info);
+ scoped_ptr<base::DictionaryValue> Copy(info->GetWidgetInfo()->DeepCopy());
+ base::DictionaryValue* widget_parsed_from_manifest;
+ Copy->GetAsDictionary(&widget_parsed_from_manifest);
+ EXPECT_TRUE(widget_parsed_from_manifest);
+
+ // Create a widget with three preference items manually.
+ scoped_ptr<base::DictionaryValue> widget(new base::DictionaryValue);
+ SetAllInfoToWidget(widget.get());
+ base::ListValue* widgetPreferences = new base::ListValue;
+ for (int i = 0; i < 3; i++) {
+ widgetPreferences->Append(GetPreferencesItem(i, false));
+ }
+
+ // Compare the widget parsed from manifest with
+ // the widget create manually.
+ EXPECT_TRUE(widget->Equals(widget_parsed_from_manifest));
+}
+
+} // namespace application
+} // namespace xwalk
// found in the LICENSE file.
var application = requireNative('application');
+var common = requireNative('widget_common');
var empty = "";
var zero = 0;
+
var widgetStringInfo = {
"author" : empty,
"description" : empty,
} else if (key == "height") {
value = window.innerHeight;
} else if (value == empty) {
- value = extension.internal.sendSyncMessage(key);
+ value = extension.internal.sendSyncMessage(
+ { cmd: 'GetWidgetInfo', widgetKey: key });
}
return value;
defineReadOnlyProperty(exports, key, widgetStringInfo[key]);
}
+var WidgetStorage = function() {
+ var _keyList = new Array();
+
+ this.init = function() {
+ var result = extension.internal.sendSyncMessage(
+ { cmd: 'GetAllItems' });
+ for (var itemKey in result) {
+ var itemValue = result[itemKey];
+ this[itemKey] = itemValue;
+ _keyList.push(itemKey);
+ }
+ }
+
+ this.__defineGetter__('length', function() {
+ return _keyList.length;
+ });
+
+ this.key = function(index) {
+ return _keyList[index];
+ }
+
+ this.getItem = function(itemKey) {
+ return this[String(itemKey)];
+ }
+
+ this.setItem = function(itemKey, itemValue) {
+ var result = extension.internal.sendSyncMessage({
+ cmd: 'SetPreferencesItem',
+ preferencesItemKey: String(itemKey),
+ preferencesItemValue: String(itemValue) });
+
+ if (result) {
+ this[String(itemKey)] = String(itemValue);
+ _keyList.push(String(itemKey));
+ } else {
+ throw new common.CustomDOMException(
+ common.CustomDOMException.NO_MODIFICATION_ALLOWED_ERR,
+ 'The object can not be modified.');
+ }
+ };
+
+ this.removeItem = function(itemKey) {
+ var result = extension.internal.sendSyncMessage({
+ cmd: 'RemovePreferencesItem',
+ preferencesItemKey: String(itemKey) });
+
+ if (result) {
+ delete this[itemKey];
+ delete _keyList[_keyList.indexOf(String(itemKey))];
+ } else {
+ throw new common.CustomDOMException(
+ common.CustomDOMException.NO_MODIFICATION_ALLOWED_ERR,
+ 'The object can not be modified.');
+ }
+ }
+
+ this.clear = function() {
+ var itemKey;
+ var result = extension.internal.sendSyncMessage({
+ cmd: 'ClearAllItems' });
+
+ if (!result)
+ return;
+
+ for (var i = _keyList.length-1; i >= 0; --i) {
+ // if the itemKey is still in DB(e.g. readonly),
+ // we should keep it in JS side.
+ var exists = extension.internal.sendSyncMessage({
+ cmd: 'KeyExists',
+ preferencesItemKey: _keyList[i] });
+
+ if (!exists) {
+ delete this[_keyList[i]];
+ _keyList.splice(i, 1);
+ }
+ }
+ }
+
+ this.init();
+};
+
+var widgetStorage = new WidgetStorage();
+exports.preferences = widgetStorage;
+
+Object.defineProperty(exports, 'preferences', {
+ configurable: false,
+ enumerable: false,
+ get: function() {
+ return widgetStorage;
+ }
+});
--- /dev/null
+var errors = {
+ '1': { type: 'INDEX_SIZE_ERR', name: 'IndexSizeError', message: '' },
+ '2': { type: 'DOMSTRING_SIZE_ERR', name: 'DOMStringSizeError', message: '' },
+ '3': { type: 'HIERARCHY_REQUEST_ERR', name: 'HierarchyRequestError', message: '' },
+ '4': { type: 'WRONG_DOCUMENT_ERR', name: 'WrongDocumentError', message: '' },
+ '5': { type: 'INVALID_CHARACTER_ERR', name: 'InvalidCharacterError', message: '' },
+ '6': { type: 'NO_DATA_ALLOWED_ERR', name: 'NoDataAllowedError', message: '' },
+ '7': { type: 'NO_MODIFICATION_ALLOWED_ERR', name: 'NoModificationAllowedError', message: '' },
+ '8': { type: 'NOT_FOUND_ERR', name: 'NotFoundError', message: '' },
+ '9': { type: 'NOT_SUPPORTED_ERR', name: 'Not_supportedError', message: '' },
+ '10': { type: 'INUSE_ATTRIBUTE_ERR', name: 'InuseAttributeError', message: '' },
+ '11': { type: 'INVALID_STATE_ERR', name: 'InvalidStateError', message: '' },
+ '12': { type: 'SYNTAX_ERR', name: 'SyntaxError', message: '' },
+ '13': { type: 'INVALID_MODIFICATION_ERR', name: 'InvalidModificationError', message: '' },
+ '14': { type: 'NAMESPACE_ERR', name: 'NamespaceError', message: '' },
+ '15': { type: 'INVALID_ACCESS_ERR', name: 'InvalidAccessError', message: '' },
+ '16': { type: 'VALIDATION_ERR', name: 'ValidationError', message: '' },
+ '17': { type: 'TYPE_MISMATCH_ERR', name: 'TypeMismatchError', message: '' },
+ '18': { type: 'SECURITY_ERR', name: 'SecurityError', message: '' },
+ '19': { type: 'NETWORK_ERR', name: 'NetworkError', message: '' },
+ '20': { type: 'ABORT_ERR', name: 'AbortError', message: '' },
+ '21': { type: 'URL_MISMATCH_ERR', name: 'UrlMismatchError', message: '' },
+ '22': { type: 'QUOTA_EXCEEDED_ERR', name: 'QuotaExceededError', message: '' },
+ '23': { type: 'TIMEOUT_ERR', name: 'TimeoutError', message: '' },
+ '24': { type: 'INVALID_NODE_TYPE_ERR', name: 'InvalidNodeTypeError', message: '' },
+ '25': { type: 'DATA_CLONE_ERR', name: 'DataCloneError', message: '' },
+};
+
+var CustomDOMException = function(code, message) {
+ var _code, _message, _name;
+
+ if (typeof code !== 'number') {
+ throw TypeError('Wrong argument type for Exception.');
+ } else if ((code in errors) === false) {
+ throw TypeError('Unknown exception code: ' + code);
+ } else {
+ _code = code;
+ _name = errors[_code].name;
+ if (typeof message === 'string') {
+ _message = message;
+ } else {
+ _message = errors[_code].message;
+ }
+ }
+
+ var props = {};
+ var newException;
+
+ try {
+ document.removeChild({})
+ } catch (e) {
+ newException = Object.create(e)
+ }
+
+ var proto = newException.__proto__;
+
+ props = Object.getOwnPropertyDescriptor(proto, "name");
+ props.value = _name;
+ Object.defineProperty(newException, "name", props);
+
+ props = Object.getOwnPropertyDescriptor(proto, "code");
+ props.value = _code;
+ Object.defineProperty(newException, "code", props);
+
+ props = Object.getOwnPropertyDescriptor(proto, "message");
+ props.value = _message;
+ Object.defineProperty(newException, "message", props);
+
+ props.value = function() {
+ return _name + ": " + _message;
+ }
+ Object.defineProperty(newException, "toString", props);
+
+ return newException;
+}
+
+for (var value in errors) {
+ Object.defineProperty(CustomDOMException, errors[value].type,
+ { value: parseInt(value) });
+}
+
+exports.CustomDOMException = CustomDOMException;
#include "xwalk/application/extension/application_widget_extension.h"
#include "base/bind.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "ipc/ipc_message.h"
#include "xwalk/application/common/application_data.h"
#include "xwalk/application/common/application_manifest_constants.h"
#include "xwalk/application/common/manifest_handlers/widget_handler.h"
+#include "xwalk/application/extension/application_widget_storage.h"
#include "xwalk/runtime/browser/runtime.h"
+#include "xwalk/runtime/browser/runtime_context.h"
+#include "xwalk/runtime/browser/xwalk_runner.h"
+#include "xwalk/runtime/common/xwalk_paths.h"
using content::BrowserThread;
+namespace {
+const char kCommandKey[] = "cmd";
+const char kWidgetAttributeKey[] = "widgetKey";
+const char kPreferencesItemKey[] = "preferencesItemKey";
+const char kPreferencesItemValue[] = "preferencesItemValue";
+}
+
namespace xwalk {
namespace application {
AppWidgetExtensionInstance::AppWidgetExtensionInstance(
Application* application)
- : application_(application) {
+ : application_(application),
+ handler_(this) {
DCHECK(application_);
+ base::ThreadRestrictions::SetIOAllowed(true);
+
+ base::FilePath path;
+ xwalk::RegisterPathProvider();
+ PathService::Get(xwalk::DIR_WGT_STORAGE_PATH, &path);
+ widget_storage_.reset(new AppWidgetStorage(application_, path));
}
+AppWidgetExtensionInstance::~AppWidgetExtensionInstance() {}
+
void AppWidgetExtensionInstance::HandleMessage(scoped_ptr<base::Value> msg) {
+ handler_.HandleMessage(msg.Pass());
}
void AppWidgetExtensionInstance::HandleSyncMessage(
scoped_ptr<base::Value> msg) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- std::string key;
- base::Value* result;
- base::StringValue* ret_val = base::Value::CreateStringValue("");
+ base::DictionaryValue* dict;
+ std::string command;
+ msg->GetAsDictionary(&dict);
- if (!msg->GetAsString(&key)) {
- LOG(ERROR) << "Fail to get sync message as manifest widget key.";
- SendSyncReplyToJS(scoped_ptr<base::Value>(ret_val));
+ if (!msg->GetAsDictionary(&dict) || !dict->GetString(kCommandKey, &command)) {
+ LOG(ERROR) << "Fail to handle command sync message.";
+ SendSyncReplyToJS(scoped_ptr<base::Value>(
+ base::Value::CreateStringValue("")));
return;
}
+ scoped_ptr<base::Value> result(base::Value::CreateStringValue(""));
+ if (command == "GetWidgetInfo") {
+ result = GetWidgetInfo(msg.Pass());
+ } else if (command == "SetPreferencesItem") {
+ result = SetPreferencesItem(msg.Pass());
+ } else if (command == "RemovePreferencesItem") {
+ result = RemovePreferencesItem(msg.Pass());
+ } else if (command == "ClearAllItems") {
+ result = ClearAllItems(msg.Pass());
+ } else if (command == "GetAllItems") {
+ result = GetAllItems(msg.Pass());
+ } else if (command == "KeyExists") {
+ result = KeyExists(msg.Pass());
+ } else {
+ LOG(ERROR) << command << " ASSERT NOT REACHED.";
+ }
+
+ SendSyncReplyToJS(result.Pass());
+}
+
+scoped_ptr<base::StringValue> AppWidgetExtensionInstance::GetWidgetInfo(
+ scoped_ptr<base::Value> msg) {
+ scoped_ptr<base::StringValue> result(base::Value::CreateStringValue(""));
+ std::string key;
+ std::string value;
+ base::DictionaryValue* dict;
+
+ if (!msg->GetAsDictionary(&dict) ||
+ !dict->GetString(kWidgetAttributeKey, &key)) {
+ LOG(ERROR) << "Fail to get widget attribute key.";
+ return result.Pass();
+ }
+
WidgetInfo* info =
static_cast<WidgetInfo*>(
application_->data()->GetManifestData(widget_keys::kWidgetKey));
- base::DictionaryValue* value = info->GetWidgetInfo();
- if (!value->Get(key, &result)) {
- LOG(ERROR) << "Fail to get value for key: " << key;
- SendSyncReplyToJS(scoped_ptr<base::Value>(ret_val));
- } else {
- SendSyncReplyToJS(scoped_ptr<base::Value>(result));
+ base::DictionaryValue* widget_info = info->GetWidgetInfo();
+ widget_info->GetString(key, &value);
+ result.reset(base::Value::CreateStringValue(value));
+ return result.Pass();
+}
+
+scoped_ptr<base::FundamentalValue>
+AppWidgetExtensionInstance::SetPreferencesItem(scoped_ptr<base::Value> msg) {
+ scoped_ptr<base::FundamentalValue> result(
+ base::Value::CreateBooleanValue(false));
+ std::string key;
+ std::string value;
+ base::DictionaryValue* dict;
+
+ if (!msg->GetAsDictionary(&dict) ||
+ !dict->GetString(kPreferencesItemKey, &key) ||
+ !dict->GetString(kPreferencesItemValue, &value)) {
+ LOG(ERROR) << "Fail to set preferences item.";
+ return result.Pass();
+ }
+
+ if (widget_storage_->AddEntry(key, value, false))
+ result.reset(base::Value::CreateBooleanValue(true));
+
+ return result.Pass();
+}
+
+scoped_ptr<base::FundamentalValue>
+AppWidgetExtensionInstance::RemovePreferencesItem(scoped_ptr<base::Value> msg) {
+ scoped_ptr<base::FundamentalValue> result(
+ base::Value::CreateBooleanValue(false));
+ std::string key;
+ base::DictionaryValue* dict;
+
+ if (!msg->GetAsDictionary(&dict) ||
+ !dict->GetString(kPreferencesItemKey, &key)) {
+ LOG(ERROR) << "Fail to remove preferences item.";
+ return result.Pass();
}
+
+ if (widget_storage_->RemoveEntry(key))
+ result.reset(base::Value::CreateBooleanValue(true));
+
+ return result.Pass();
+}
+
+scoped_ptr<base::FundamentalValue> AppWidgetExtensionInstance::ClearAllItems(
+ scoped_ptr<base::Value> msg) {
+ scoped_ptr<base::FundamentalValue> result(
+ base::Value::CreateBooleanValue(false));
+
+ if (widget_storage_->Clear())
+ result.reset(base::Value::CreateBooleanValue(true));
+
+ return result.Pass();
+}
+
+scoped_ptr<base::DictionaryValue> AppWidgetExtensionInstance::GetAllItems(
+ scoped_ptr<base::Value> msg) {
+ scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
+ widget_storage_->GetAllEntries(result.get());
+
+ return result.Pass();
+}
+
+scoped_ptr<base::FundamentalValue> AppWidgetExtensionInstance::KeyExists(
+ scoped_ptr<base::Value> msg) const {
+ scoped_ptr<base::FundamentalValue> result(
+ base::Value::CreateBooleanValue(false));
+ std::string key;
+ base::DictionaryValue* dict;
+
+ if (!msg->GetAsDictionary(&dict) ||
+ !dict->GetString(kPreferencesItemKey, &key)) {
+ LOG(ERROR) << "Fail to remove preferences item.";
+ return result.Pass();
+ }
+
+ if (widget_storage_->EntryExists(key))
+ result.reset(base::Value::CreateBooleanValue(true));
+
+ return result.Pass();
}
} // namespace application
#include <string>
+#include "xwalk/extensions/browser/xwalk_extension_function_handler.h"
#include "xwalk/extensions/common/xwalk_extension.h"
namespace xwalk {
class Application;
using extensions::XWalkExtension;
+using extensions::XWalkExtensionFunctionHandler;
+using extensions::XWalkExtensionFunctionInfo;
using extensions::XWalkExtensionInstance;
class ApplicationWidgetExtension : public XWalkExtension {
class AppWidgetExtensionInstance : public XWalkExtensionInstance {
public:
explicit AppWidgetExtensionInstance(Application* application);
+ virtual ~AppWidgetExtensionInstance();
virtual void HandleMessage(scoped_ptr<base::Value> msg) OVERRIDE;
virtual void HandleSyncMessage(scoped_ptr<base::Value> msg) OVERRIDE;
private:
+ scoped_ptr<base::StringValue> GetWidgetInfo(scoped_ptr<base::Value> msg);
+ scoped_ptr<base::FundamentalValue> SetPreferencesItem(
+ scoped_ptr<base::Value> mgs);
+ scoped_ptr<base::FundamentalValue> RemovePreferencesItem(
+ scoped_ptr<base::Value> mgs);
+ scoped_ptr<base::FundamentalValue> ClearAllItems(scoped_ptr<base::Value> mgs);
+ scoped_ptr<base::DictionaryValue> GetAllItems(scoped_ptr<base::Value> mgs);
+ scoped_ptr<base::FundamentalValue> KeyExists(
+ scoped_ptr<base::Value> mgs) const;
+
Application* application_;
+ scoped_ptr<class AppWidgetStorage> widget_storage_;
+ XWalkExtensionFunctionHandler handler_;
};
} // namespace application
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/application/extension/application_widget_storage.h"
+
+#include <string>
+
+#include "base/file_util.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+#include "xwalk/application/common/application_manifest_constants.h"
+#include "xwalk/application/common/manifest_handlers/widget_handler.h"
+
+namespace {
+
+namespace widget_keys = xwalk::application_widget_keys;
+
+const char kPreferences[] = "preferences";
+const char kPreferencesName[] = "name";
+const char kPreferencesValue[] = "value";
+const char kPreferencesReadonly[] = "readonly";
+
+const base::FilePath::CharType kWidgetStorageExtension[] =
+ FILE_PATH_LITERAL(".widgetStorage");
+
+const char kStorageTableName[] = "widget_storage";
+
+const char kCreateStorageTableOp[] =
+ "CREATE TABLE widget_storage ("
+ "key TEXT NOT NULL UNIQUE PRIMARY KEY,"
+ "value TEXT NOT NULL,"
+ "read_only INTEGER )";
+
+const char kClearStorageTableWithBindOp[] =
+ "DELETE FROM widget_storage WHERE read_only = ? ";
+
+const char kInsertItemWithBindOp[] =
+ "INSERT INTO widget_storage (value, read_only, key) "
+ "VALUES(?,?,?)";
+
+const char kUpdateItemWithBindOp[] =
+ "UPDATE widget_storage SET value = ? , read_only = ? "
+ "WHERE key = ?";
+
+const char kRemoveItemWithBindOp[] =
+ "DELETE FROM widget_storage WHERE key = ?";
+
+const char kSelectTableLength[] =
+ "SELECT count(*) FROM widget_storage ";
+
+const char kSelectCountWithBindOp[] =
+ "SELECT count(*) FROM widget_storage "
+ "WHERE key = ?";
+
+const char kSelectAllItem[] =
+ "SELECT key, value FROM widget_storage ";
+
+const char kSelectReadOnlyWithBindOp[] =
+ "SELECT read_only FROM widget_storage "
+ "WHERE key = ?";
+} // namespace
+
+namespace xwalk {
+namespace application {
+
+AppWidgetStorage::AppWidgetStorage(Application* application,
+ const base::FilePath& data_dir)
+ : application_(application),
+ db_initialized_(false) {
+ sqlite_db_.reset(new sql::Connection);
+
+ base::FilePath name(application_->id());
+ base::FilePath::StringType storage_name =
+ name.value() + kWidgetStorageExtension;
+ data_path_ = data_dir.Append(storage_name);
+
+ if (!base::PathExists(data_dir) && !base::CreateDirectory(data_dir)) {
+ LOG(ERROR) << "Could not create widget storage path.";
+ return;
+ }
+
+ if (!Init()) {
+ LOG(ERROR) << "Initialize widget storage failed.";
+ return;
+ }
+}
+
+AppWidgetStorage::~AppWidgetStorage() {
+}
+
+bool AppWidgetStorage::Init() {
+ if (!sqlite_db_->Open(data_path_)) {
+ LOG(ERROR) << "Unable to open widget storage DB.";
+ return false;
+ }
+ sqlite_db_->Preload();
+
+ if (!InitStorageTable()) {
+ LOG(ERROR) << "Unable to init widget storage table.";
+ return false;
+ }
+ return db_initialized_;
+}
+
+bool AppWidgetStorage::SaveConfigInfoItem(base::DictionaryValue* dict) {
+ DCHECK(dict);
+ std::string key;
+ std::string value;
+ bool read_only = false;
+ dict->GetString(kPreferencesName, &key);
+ dict->GetString(kPreferencesValue, &value);
+ dict->GetBoolean(kPreferencesReadonly, &read_only);
+ return AddEntry(key, value, read_only);
+}
+
+bool AppWidgetStorage::SaveConfigInfoInDB() {
+ WidgetInfo* info =
+ static_cast<WidgetInfo*>(
+ application_->data()->GetManifestData(widget_keys::kWidgetKey));
+ base::DictionaryValue* widget_info = info->GetWidgetInfo();
+ if (!widget_info) {
+ LOG(ERROR) << "Fail to get parsed widget information.";
+ return false;
+ }
+
+ base::Value* pref_value;
+ widget_info->Get(kPreferences, &pref_value);
+
+ if (pref_value && pref_value->IsType(base::Value::TYPE_DICTIONARY)) {
+ base::DictionaryValue* dict;
+ pref_value->GetAsDictionary(&dict);
+ return SaveConfigInfoItem(dict);
+ } else if (pref_value && pref_value->IsType(base::Value::TYPE_LIST)) {
+ base::ListValue* list;
+ pref_value->GetAsList(&list);
+
+ for (base::ListValue::iterator it = list->begin();
+ it != list->end(); ++it) {
+ base::DictionaryValue* dict;
+ (*it)->GetAsDictionary(&dict);
+ if (!SaveConfigInfoItem(dict))
+ return false;
+ }
+ } else {
+ LOG(INFO) << "No widget preferences or preference type is not supported.";
+ }
+
+ return true;
+}
+
+bool AppWidgetStorage::InitStorageTable() {
+ if (sqlite_db_->DoesTableExist(kStorageTableName)) {
+ db_initialized_ = (sqlite_db_ && sqlite_db_->is_open());
+ return true;
+ }
+
+ sql::Transaction transaction(sqlite_db_.get());
+ transaction.Begin();
+ if (!sqlite_db_->Execute(kCreateStorageTableOp))
+ return false;
+ if (!transaction.Commit())
+ return false;
+
+ db_initialized_ = (sqlite_db_ && sqlite_db_->is_open());
+ SaveConfigInfoInDB();
+
+ return true;
+}
+
+bool AppWidgetStorage::EntryExists(const std::string& key) const {
+ sql::Transaction transaction(sqlite_db_.get());
+ if (!transaction.Begin())
+ return false;
+
+ sql::Statement stmt(sqlite_db_->GetUniqueStatement(
+ kSelectCountWithBindOp));
+ stmt.BindString(0, key);
+ if (!stmt.Step()) {
+ LOG(ERROR) << "An error occured when selecting count from DB.";
+ return false;
+ }
+
+ if (!transaction.Commit())
+ return false;
+
+ int exist = stmt.ColumnInt(0);
+ return exist > 0;
+}
+
+bool AppWidgetStorage::IsReadOnly(const std::string& key) {
+ sql::Transaction transaction(sqlite_db_.get());
+ if (!transaction.Begin())
+ return true;
+
+ sql::Statement stmt(sqlite_db_->GetUniqueStatement(
+ kSelectReadOnlyWithBindOp));
+ stmt.BindString(0, key);
+ if (!stmt.Step()) {
+ LOG(ERROR) << "An error occured when selecting count from DB.";
+ return true;
+ }
+
+ if (!transaction.Commit())
+ return true;
+
+ return stmt.ColumnBool(0);
+}
+
+bool AppWidgetStorage::AddEntry(const std::string& key,
+ const std::string& value,
+ bool read_only) {
+ if (!db_initialized_ && !Init())
+ return false;
+
+ std::string operation;
+ if (!EntryExists(key)) {
+ operation = kInsertItemWithBindOp;
+ } else if (!IsReadOnly(key)) {
+ operation = kUpdateItemWithBindOp;
+ } else {
+ LOG(ERROR) << "Could not set read only item " << key;
+ return false;
+ }
+
+ sql::Transaction transaction(sqlite_db_.get());
+ if (!transaction.Begin())
+ return false;
+
+ sql::Statement stmt(sqlite_db_->GetUniqueStatement(
+ operation.c_str()));
+ stmt.BindString(0, value);
+ stmt.BindBool(1, read_only);
+ stmt.BindString(2, key);
+ if (!stmt.Run()) {
+ LOG(ERROR) << "An error occured when set item into DB.";
+ return false;
+ }
+
+ return transaction.Commit();
+}
+
+bool AppWidgetStorage::RemoveEntry(const std::string& key) {
+ if (!db_initialized_ && !Init())
+ return false;
+
+ if (IsReadOnly(key)) {
+ LOG(ERROR) << "Could not remove read only item " << key;
+ return false;
+ }
+
+ sql::Transaction transaction(sqlite_db_.get());
+ if (!transaction.Begin())
+ return false;
+
+ sql::Statement stmt(sqlite_db_->GetUniqueStatement(
+ kRemoveItemWithBindOp));
+ stmt.BindString(0, key);
+
+ if (!stmt.Run()) {
+ LOG(ERROR) << "An error occured when removing item into DB.";
+ return false;
+ }
+
+ return transaction.Commit();
+}
+
+bool AppWidgetStorage::Clear() {
+ if (!db_initialized_ && !Init())
+ return false;
+
+ sql::Transaction transaction(sqlite_db_.get());
+ transaction.Begin();
+
+ sql::Statement stmt(sqlite_db_->GetUniqueStatement(
+ kClearStorageTableWithBindOp));
+ stmt.BindBool(0, false);
+
+ if (!stmt.Run()) {
+ LOG(ERROR) << "An error occured when removing item into DB.";
+ return false;
+ }
+
+ return transaction.Commit();
+}
+
+bool AppWidgetStorage::GetAllEntries(base::DictionaryValue* result) {
+ std::string key;
+ std::string value;
+ DCHECK(result);
+
+ if (!db_initialized_ && !Init())
+ return false;
+
+ sql::Statement stmt(sqlite_db_->GetUniqueStatement(kSelectAllItem));
+ while (stmt.Step()) {
+ key = stmt.ColumnString(0);
+ value = stmt.ColumnString(1);
+ result->SetString(key, value);
+ }
+
+ return true;
+}
+
+} // namespace application
+} // namespace xwalk
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XWALK_APPLICATION_EXTENSION_APPLICATION_WIDGET_STORAGE_H_
+#define XWALK_APPLICATION_EXTENSION_APPLICATION_WIDGET_STORAGE_H_
+
+#include <map>
+#include <string>
+
+#include "base/values.h"
+#include "base/files/file_path.h"
+#include "sql/connection.h"
+#include "xwalk/application/browser/application.h"
+
+namespace xwalk {
+namespace application {
+
+class AppWidgetStorage {
+ public:
+ AppWidgetStorage(Application* application,
+ const base::FilePath& data_dir);
+ ~AppWidgetStorage();
+
+ // Adds or replaces entry (if not readonly);
+ // returns true on success.
+ bool AddEntry(const std::string& key,
+ const std::string& value,
+ bool read_only);
+ bool RemoveEntry(const std::string& key);
+ bool Clear();
+ bool GetAllEntries(base::DictionaryValue* result);
+ bool EntryExists(const std::string& key) const;
+
+ private:
+ bool Init();
+ bool IsReadOnly(const std::string& key);
+ bool InitStorageTable();
+ bool SaveConfigInfoInDB();
+ bool SaveConfigInfoItem(base::DictionaryValue* dict);
+
+ Application* application_;
+ scoped_ptr<sql::Connection> sqlite_db_;
+ base::FilePath data_path_;
+ bool db_initialized_;
+};
+
+} // namespace application
+} // namespace xwalk
+#endif // XWALK_APPLICATION_EXTENSION_APPLICATION_WIDGET_STORAGE_H_
static const char* xwalk_running_app_iface =
"org.crosswalkproject.Running.Application1";
-static const char cmd_line_fullscreen_arg[] = "--fullscreen";
-
static char* application_object_path;
static GMainLoop* mainloop;
+static GDBusConnection* g_connection;
+
+static int g_argc;
+static char** g_argv;
+static gboolean query_running = FALSE;
+static gboolean fullscreen = FALSE;
+static gchar** cmd_appid;
+
+static GOptionEntry entries[] = {
+ { "running", 'r', 0, G_OPTION_ARG_NONE, &query_running,
+ "Check whether the application is running", NULL },
+ { "fullscreen", 'f', 0, G_OPTION_ARG_NONE, &fullscreen,
+ "Run the application as fullscreen", NULL },
+ { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &cmd_appid,
+ "ID of the application to be launched", NULL },
+ { NULL }
+};
static void object_removed(GDBusObjectManager* manager, GDBusObject* object,
gpointer user_data) {
}
}
-int main(int argc, char** argv) {
- GError* error = NULL;
- char* appid;
- gboolean fullscreen = FALSE;
-
-
-#if !GLIB_CHECK_VERSION(2, 36, 0)
- // g_type_init() is deprecated on GLib since 2.36, Tizen has 2.32.
- g_type_init();
-#endif
-
- if (xwalk_tizen_set_home_for_user_app())
- exit(1);
-
- if (!strcmp(basename(argv[0]), "xwalk-launcher")) {
- if (argc < 2) {
- fprintf(stderr, "No AppID informed, nothing to do\n");
- exit(1);
- }
-
- appid = argv[1];
+static void query_application_running(GDBusObjectManager* running_om,
+ const char* app_id) {
+ GList* objects = g_dbus_object_manager_get_objects(running_om);
+ GList* it;
+ bool is_running = FALSE;
+
+ for (it = objects; it; it = it->next) {
+ GDBusObject* object = reinterpret_cast<GDBusObject*>(it->data);
+ GDBusInterface* iface = g_dbus_object_get_interface(
+ object,
+ xwalk_running_app_iface);
+ if (!iface)
+ continue;
- if (argc > 2) {
- if (!strcmp(basename(argv[2]), cmd_line_fullscreen_arg))
- fullscreen = TRUE;
+ GDBusProxy* proxy = G_DBUS_PROXY(iface);
+ GVariant* id_variant;
+ id_variant = g_dbus_proxy_get_cached_property(proxy, "AppID");
+ if (!id_variant) {
+ g_object_unref(iface);
+ continue;
}
- } else {
- appid = strdup(basename(argv[0]));
-
- if (argc > 1) {
- if (!strcmp(basename(argv[1]), cmd_line_fullscreen_arg))
- fullscreen = TRUE;
+ const gchar* id;
+ g_variant_get(id_variant, "s", &id);
+ if (!strcmp(app_id, id)) {
+ is_running = TRUE;
+ break;
}
- }
- GDBusConnection* connection = get_session_bus_connection(&error);
- if (!connection) {
- fprintf(stderr, "Couldn't get the session bus connection: %s\n",
- error->message);
- exit(1);
+ g_object_unref(iface);
}
+ const char* str = is_running ? "running" : "not running";
+ g_print("Application %s is %s.\n", app_id, str);
- GDBusObjectManager* running_apps_om = g_dbus_object_manager_client_new_sync(
- connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
- xwalk_service_name, xwalk_running_path,
- NULL, NULL, NULL, NULL, &error);
- if (!running_apps_om) {
- fprintf(stderr, "Service '%s' does could not be reached: %s\n",
- xwalk_service_name, error->message);
- exit(1);
- }
+ g_list_free_full(objects, g_object_unref);
+}
- g_signal_connect(running_apps_om, "object-removed",
+static void launch_application(GDBusObjectManager* running_apps_manager,
+ const char* appid,
+ gboolean fullscreen) {
+ GError* error = NULL;
+ g_signal_connect(running_apps_manager, "object-removed",
G_CALLBACK(object_removed), NULL);
GDBusProxy* running_proxy = g_dbus_proxy_new_sync(
- connection,
+ g_connection,
G_DBUS_PROXY_FLAGS_NONE, NULL, xwalk_service_name,
xwalk_running_path, xwalk_running_manager_iface, NULL, &error);
if (!running_proxy) {
unsigned int launcher_pid = getpid();
- GVariant* result = g_dbus_proxy_call_sync(running_proxy, "Launch",
- g_variant_new("(sub)", appid,
- launcher_pid,
- fullscreen),
- G_DBUS_CALL_FLAGS_NONE,
- -1, NULL, &error);
+ GVariant* result = g_dbus_proxy_call_sync(running_proxy, "Launch",
+ g_variant_new("(sub)", appid, launcher_pid, fullscreen),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
if (!result) {
fprintf(stderr, "Couldn't call 'Launch' method: %s\n", error->message);
exit(1);
application_object_path);
GDBusProxy* app_proxy = g_dbus_proxy_new_sync(
- connection,
+ g_connection,
G_DBUS_PROXY_FLAGS_NONE, NULL, xwalk_service_name,
application_object_path, xwalk_running_app_iface, NULL, &error);
if (!app_proxy) {
char name[128];
snprintf(name, sizeof(name), "xwalk-%s", appid);
- if (xwalk_appcore_init(argc, argv, name)) {
+ if (xwalk_appcore_init(g_argc, g_argv, name)) {
fprintf(stderr, "Failed to initialize appcore");
exit(1);
}
#endif
g_main_loop_run(mainloop);
+}
+
+int main(int argc, char** argv) {
+ GError* error = NULL;
+ char* appid;
+
+ g_argc = argc;
+ g_argv = argv;
+
+#if !GLIB_CHECK_VERSION(2, 36, 0)
+ // g_type_init() is deprecated on GLib since 2.36.
+ g_type_init();
+#endif
+
+ if (xwalk_tizen_set_home_for_user_app())
+ exit(1);
+
+ GOptionContext* context =
+ g_option_context_new("- Crosswalk Application Launcher");
+ g_option_context_add_main_entries(context, entries, NULL);
+ if (!g_option_context_parse(context, &argc, &argv, &error)) {
+ fprintf(stderr, "Option parsing failed: %s\n", error->message);
+ exit(1);
+ }
+
+ if (!strcmp(basename(argv[0]), "xwalk-launcher")) {
+ if (cmd_appid == NULL) {
+ fprintf(stderr, "No AppID informed, nothing to do.\n");
+ return 0;
+ }
+ appid = cmd_appid[0];
+ } else {
+ appid = strdup(basename(argv[0]));
+ }
+
+ g_connection = get_session_bus_connection(&error);
+ if (!g_connection) {
+ fprintf(stderr, "Couldn't get the session bus connection: %s\n",
+ error->message);
+ exit(1);
+ }
+
+ GDBusObjectManager* running_apps_manager =
+ g_dbus_object_manager_client_new_sync(
+ g_connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+ xwalk_service_name, xwalk_running_path,
+ NULL, NULL, NULL, NULL, &error);
+ if (!running_apps_manager) {
+ fprintf(stderr, "Service '%s' does could not be reached: %s\n",
+ xwalk_service_name, error->message);
+ exit(1);
+ }
+
+ if (query_running) {
+ query_application_running(running_apps_manager, appid);
+ } else {
+ launch_application(running_apps_manager, appid, fullscreen);
+ }
return 0;
}
'extension/application_runtime_extension.h',
'extension/application_widget_extension.cc',
'extension/application_widget_extension.h',
+ 'extension/application_widget_storage.cc',
+ 'extension/application_widget_storage.h',
'renderer/application_native_module.cc',
'renderer/application_native_module.h',
'dependencies': [
'build/system.gyp:tizen',
'tizen/xwalk_tizen.gypi:xwalk_tizen_lib',
+ '../third_party/re2/re2.gyp:re2',
],
'sources': [
'browser/installer/tizen/packageinfo_constants.cc',
'browser/installer/tizen/packageinfo_constants.h',
'browser/installer/tizen/service_package_installer.cc',
'browser/installer/tizen/service_package_installer.h',
+ 'common/manifest_handlers/navigation_handler.cc',
+ 'common/manifest_handlers/navigation_handler.h',
+ 'common/manifest_handlers/tizen_application_handler.cc',
+ 'common/manifest_handlers/tizen_application_handler.h',
],
}],
],
{
'variables': {
- # Enable multitouch support with XInput2.1. When it is enabled, unlike
- # XInput2.2, there are no XI_TouchBegin, XI_TouchUpdate and XI_TouchEnd
- # raw touch events emitted from touch device. Instead, the touch event is
- # simulated by a normal mouse event, since X server maintains multiple
- # virtual touch screen devices as floating device, each of them can
- # simulate a touch event tracked by the device id of event source, as a
- # result, multi-touch support works with these simulated touch events
- # dispatched from floating device.
- 'enable_xi21_mt%': 0,
-
'tizen%': 0,
'tizen_mobile%': 0,
},
'tizen_mobile%': '<(tizen_mobile)',
},
'conditions': [
- ['enable_xi21_mt==1', {
- 'defines': ['ENABLE_XI21_MT=1'],
- }],
['tizen==1', {
'defines': ['OS_TIZEN=1'],
}],
sys.path.insert(1, os.path.join(chrome_src, 'third_party', 'WebKit',
'Source', 'build', 'scripts'))
-# FIXME(rakuco,joone): This is a workaround to allow the Tizen build to
-# proceed, as we use make there and GN isn't involved in this case (otherwise
-# we run into problems like GN always looking for GTK+ dependencies).
-if os.environ.get('GYP_GENERATORS') != 'make':
- import find_depot_tools
-
# On Windows, Psyco shortens warm runs of build/gyp_chromium by about
# 20 seconds on a z600 machine with 12 GB of RAM, from 90 down to 70
# seconds. Conversely, memory usage of build/gyp_chromium with Psyco
# TODO(bradnelson): take this out once this issue is fixed:
# http://code.google.com/p/gyp/issues/detail?id=177
if sys.platform == 'cygwin':
+ import find_depot_tools
depot_tools_path = find_depot_tools.add_depot_tools_to_path()
python_dir = sorted(glob.glob(os.path.join(depot_tools_path,
'python2*_bin')))[-1]
# by depot_tools, then use it.
if (sys.platform in ('win32', 'cygwin') and
os.environ.get('GYP_GENERATORS') == 'ninja'):
+ import find_depot_tools
depot_tools_path = find_depot_tools.add_depot_tools_to_path()
toolchain = os.path.normpath(os.path.join(
depot_tools_path, 'win_toolchain', 'vs2013_files'))
supplemental_includes = GetSupplementalFiles()
- # FIXME(rakuco,joone): This is a workaround to allow the Tizen build to
- # proceed, as we use make there and GN isn't involved in this case (otherwise
- # we run into problems like GN always looking for GTK+ dependencies).
- if os.environ.get('GYP_GENERATORS') != 'make':
- if not RunGN(supplemental_includes):
- sys.exit(1)
-
args.extend(
['-I' + i for i in additional_include_files(supplemental_includes, args)])
+++ /dev/null
-From c9f2fa16578bc20c83247e72608b5d6ca4dff6ba Mon Sep 17 00:00:00 2001
-From: "qing.zhang" <qing.zhang@intel.com>
-Date: Thu, 7 Nov 2013 08:59:38 -0500
-Subject: [PATCH] [Tizen] Enabling Hardware Acceleration with Libva and EGL in
- VDA for Tizen Mobile within chromium v31+.
-
-Why we need to maintain it in our side:
-===========================================
-1) Upstream confirm VAVDA will continue to be restricted to
- CrOS/X86 for dev & testing only and not for chromium road map.
-2) CrOS/X86 no plan to expend EGL backend which finalize in
- June 2012 and be addressed to the CrOS graphics team.
-
-So, the upstream no plan to lerage VAVDA with EGL graphic
- backend for any X86.
-
-3) The tizen-mobile's driver only support EGL as texture
- backend. The video hw acceleration of xwalk have to
- rely on EGL not GLX to bind decoded pixmap.
-===========================================
-That's why we enable specific EGL for VAVDA in tizen port.
----
- .../gpu/media/gpu_video_decode_accelerator.cc | 8 +
- .../media/vaapi_video_decode_accelerator_tizen.cc | 908 +++++++++++++++++++++
- .../media/vaapi_video_decode_accelerator_tizen.h | 273 +++++++
- content/content_common.gypi | 26 +
- 4 files changed, 1215 insertions(+)
- create mode 100644 content/common/gpu/media/vaapi_video_decode_accelerator_tizen.cc
- create mode 100644 content/common/gpu/media/vaapi_video_decode_accelerator_tizen.h
-
-diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc
-index bd1dc5f..c5a6df2 100644
---- a/content/common/gpu/media/gpu_video_decode_accelerator.cc
-+++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc
-@@ -32,6 +32,8 @@
- #include "content/common/gpu/media/vaapi_video_decode_accelerator.h"
- #include "ui/gl/gl_context_glx.h"
- #include "ui/gl/gl_implementation.h"
-+#elif defined(OS_TIZEN_MOBILE) && defined(ARCH_CPU_X86_FAMILY)
-+#include "content/common/gpu/media/vaapi_video_decode_accelerator_tizen.h"
- #elif defined(OS_ANDROID)
- #include "content/common/gpu/media/android_video_decode_accelerator.h"
- #endif
-@@ -296,6 +298,12 @@ void GpuVideoDecodeAccelerator::Initialize(
- static_cast<gfx::GLContextGLX*>(stub_->decoder()->GetGLContext());
- video_decode_accelerator_.reset(new VaapiVideoDecodeAccelerator(
- glx_context->display(), this, make_context_current_));
-+#elif defined(OS_TIZEN_MOBILE) && defined(ARCH_CPU_X86_FAMILY)
-+ video_decode_accelerator_.reset(new VaapiVideoDecodeAccelerator(
-+ gfx::GLSurfaceEGL::GetHardwareDisplay(),
-+ stub_->decoder()->GetGLContext()->GetHandle(),
-+ this,
-+ make_context_current_));
- #elif defined(OS_ANDROID)
- video_decode_accelerator_.reset(new AndroidVideoDecodeAccelerator(
- this,
-diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator_tizen.cc b/content/common/gpu/media/vaapi_video_decode_accelerator_tizen.cc
-new file mode 100644
-index 0000000..cfff457
---- /dev/null
-+++ b/content/common/gpu/media/vaapi_video_decode_accelerator_tizen.cc
-@@ -0,0 +1,908 @@
-+// Copyright (c) 2013 Intel Corporation. All rights reserved.
-+// Use of this source code is governed by a BSD-style license that can be
-+// found in the LICENSE file.
-+
-+#include "base/bind.h"
-+#include "base/debug/trace_event.h"
-+#include "base/logging.h"
-+#include "base/metrics/histogram.h"
-+#include "base/stl_util.h"
-+#include "base/strings/string_util.h"
-+#include "base/synchronization/waitable_event.h"
-+#include "content/child/child_thread.h"
-+#include "content/common/gpu/gpu_channel.h"
-+#include "content/common/gpu/media/vaapi_video_decode_accelerator_tizen.h"
-+#include "media/base/bind_to_current_loop.h"
-+#include "media/video/picture.h"
-+#include "ui/gl/gl_bindings.h"
-+#include "ui/gl/scoped_binders.h"
-+
-+static void ReportToUMA(
-+ content::VaapiH264Decoder::VAVDAH264DecoderFailure failure) {
-+ UMA_HISTOGRAM_ENUMERATION(
-+ "Media.VAVDAH264.DecoderFailure",
-+ failure,
-+ content::VaapiH264Decoder::VAVDA_H264_DECODER_FAILURES_MAX);
-+}
-+
-+namespace content {
-+
-+#define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \
-+ do { \
-+ if (!(result)) { \
-+ DVLOG(1) << log; \
-+ NotifyError(error_code); \
-+ return ret; \
-+ } \
-+ } while (0)
-+
-+VaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) {
-+}
-+
-+VaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() {
-+}
-+
-+void VaapiVideoDecodeAccelerator::NotifyError(Error error) {
-+ if (message_loop_ != base::MessageLoop::current()) {
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::NotifyError, weak_this_, error));
-+ return;
-+ }
-+
-+ // Post Cleanup() as a task so we don't recursively acquire lock_.
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::Cleanup, weak_this_));
-+
-+ DVLOG(1) << "Notifying of error " << error;
-+ if (client_) {
-+ client_->NotifyError(error);
-+ client_ptr_factory_.InvalidateWeakPtrs();
-+ }
-+}
-+
-+// TFPPicture allocates X Pixmaps and binds them to textures passed
-+// in PictureBuffers from clients to them. TFPPictures are created as
-+// a consequence of receiving a set of PictureBuffers from clients and released
-+// at the end of decode (or when a new set of PictureBuffers is required).
-+//
-+// TFPPictures are used for output, contents of VASurfaces passed from decoder
-+// are put into the associated pixmap memory and sent to client.
-+class VaapiVideoDecodeAccelerator::TFPPicture {
-+ public:
-+ ~TFPPicture();
-+
-+ static linked_ptr<TFPPicture> Create(
-+ const base::Callback<bool(void)>& make_context_current,
-+ EGLDisplay egl_display,
-+ Display* x_display,
-+ int32 picture_buffer_id,
-+ uint32 texture_id,
-+ gfx::Size size);
-+ int32 picture_buffer_id() {
-+ return picture_buffer_id_;
-+ }
-+
-+ uint32 texture_id() {
-+ return texture_id_;
-+ }
-+
-+ gfx::Size size() {
-+ return size_;
-+ }
-+
-+ int x_pixmap() {
-+ return x_pixmap_;
-+ }
-+
-+ // Bind texture to pixmap. Needs to be called every frame.
-+ bool Bind();
-+
-+ private:
-+ TFPPicture(const base::Callback<bool(void)>& make_context_current,
-+ Display* x_display,
-+ int32 picture_buffer_id,
-+ uint32 texture_id,
-+ gfx::Size size);
-+
-+ bool Initialize(EGLDisplay egl_display);
-+
-+ base::Callback<bool(void)> make_context_current_;
-+
-+ Display* x_display_;
-+
-+ // Output id for the client.
-+ int32 picture_buffer_id_;
-+ uint32 texture_id_;
-+
-+ gfx::Size size_;
-+
-+ // Pixmaps bound to this texture.
-+ Pixmap x_pixmap_;
-+ EGLDisplay egl_display_;
-+ EGLImageKHR egl_image_;
-+
-+ DISALLOW_COPY_AND_ASSIGN(TFPPicture);
-+};
-+
-+VaapiVideoDecodeAccelerator::TFPPicture::TFPPicture(
-+ const base::Callback<bool(void)>& make_context_current,
-+ Display* x_display,
-+ int32 picture_buffer_id,
-+ uint32 texture_id,
-+ gfx::Size size)
-+ : make_context_current_(make_context_current),
-+ x_display_(x_display),
-+ picture_buffer_id_(picture_buffer_id),
-+ texture_id_(texture_id),
-+ size_(size),
-+ x_pixmap_(0),
-+ egl_image_(0) {
-+ DCHECK(!make_context_current_.is_null());
-+};
-+
-+linked_ptr<VaapiVideoDecodeAccelerator::TFPPicture>
-+VaapiVideoDecodeAccelerator::TFPPicture::Create(
-+ const base::Callback<bool(void)>& make_context_current,
-+ EGLDisplay egl_display,
-+ Display* x_display,
-+ int32 picture_buffer_id,
-+ uint32 texture_id,
-+ gfx::Size size) {
-+
-+ linked_ptr<TFPPicture> tfp_picture(
-+ new TFPPicture(make_context_current, x_display,
-+ picture_buffer_id, texture_id, size));
-+
-+ if (!tfp_picture->Initialize(egl_display))
-+ tfp_picture.reset();
-+
-+ return tfp_picture;
-+}
-+
-+bool VaapiVideoDecodeAccelerator::TFPPicture::Initialize(
-+ EGLDisplay egl_display) {
-+ // Check for NULL prevents unittests from crashing on nonexistent ChildThread.
-+ DCHECK(ChildThread::current() == NULL ||
-+ ChildThread::current()->message_loop() == base::MessageLoop::current());
-+
-+ if (!make_context_current_.Run())
-+ return false;
-+
-+ XWindowAttributes win_attr;
-+ int screen = DefaultScreen(x_display_);
-+ XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr);
-+ //TODO(posciak): pass the depth required by libva, not the RootWindow's depth
-+ x_pixmap_ = XCreatePixmap(x_display_, RootWindow(x_display_, screen),
-+ size_.width(), size_.height(), win_attr.depth);
-+ if (!x_pixmap_) {
-+ DVLOG(1) << "Failed creating an X Pixmap for TFP";
-+ return false;
-+ }
-+
-+ egl_display_ = egl_display;
-+ EGLint image_attrs[] = { EGL_IMAGE_PRESERVED_KHR, 1 , EGL_NONE };
-+
-+ egl_image_ = eglCreateImageKHR(egl_display_,
-+ EGL_NO_CONTEXT,
-+ EGL_NATIVE_PIXMAP_KHR,
-+ (EGLClientBuffer)x_pixmap_,
-+ image_attrs);
-+ if (!egl_image_) {
-+ DVLOG(1) << "Failed creating a EGLImage from Pixmap for KHR";
-+ return false;
-+ }
-+
-+ return true;
-+}
-+VaapiVideoDecodeAccelerator::TFPPicture::~TFPPicture() {
-+ // Check for NULL prevents unittests from crashing on non-existing ChildThread.
-+ DCHECK(ChildThread::current() == NULL ||
-+ ChildThread::current()->message_loop() == base::MessageLoop::current());
-+
-+ // Unbind surface from texture and deallocate resources.
-+ if (make_context_current_.Run()) {
-+ eglDestroyImageKHR(egl_display_, egl_image_);
-+ }
-+
-+ if (x_pixmap_)
-+ XFreePixmap(x_display_, x_pixmap_);
-+ XSync(x_display_, False); // Needed to work around buggy vdpau-driver.
-+}
-+
-+bool VaapiVideoDecodeAccelerator::TFPPicture::Bind() {
-+ DCHECK(x_pixmap_);
-+ DCHECK(egl_image_);
-+
-+ // Check for NULL prevents unittests from crashing on nonexistent ChildThread.
-+ DCHECK(ChildThread::current() == NULL ||
-+ ChildThread::current()->message_loop() == base::MessageLoop::current());
-+
-+ if (!make_context_current_.Run())
-+ return false;
-+
-+ gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id_);
-+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
-+
-+ return true;
-+}
-+
-+VaapiVideoDecodeAccelerator::TFPPicture*
-+ VaapiVideoDecodeAccelerator::TFPPictureById(int32 picture_buffer_id) {
-+ TFPPictures::iterator it = tfp_pictures_.find(picture_buffer_id);
-+ if (it == tfp_pictures_.end()) {
-+ DVLOG(1) << "Picture id " << picture_buffer_id << " does not exist";
-+ return NULL;
-+ }
-+
-+ return it->second.get();
-+}
-+
-+VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator(
-+ EGLDisplay egl_display, EGLContext egl_context,
-+ Client* client,
-+ const base::Callback<bool(void)>& make_context_current)
-+ : x_display_(0),
-+ egl_display_(egl_display),
-+ egl_context_(egl_context),
-+ make_context_current_(make_context_current),
-+ state_(kUninitialized),
-+ input_ready_(&lock_),
-+ surfaces_available_(&lock_),
-+ message_loop_(base::MessageLoop::current()),
-+ weak_this_(base::AsWeakPtr(this)),
-+ client_ptr_factory_(client),
-+ client_(client_ptr_factory_.GetWeakPtr()),
-+ decoder_thread_("VaapiDecoderThread"),
-+ num_frames_at_client_(0),
-+ num_stream_bufs_at_decoder_(0),
-+ finish_flush_pending_(false),
-+ awaiting_va_surfaces_recycle_(false),
-+ requested_num_pics_(0) {
-+ DCHECK(client);
-+}
-+VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+}
-+
-+class ScopedPtrXFree {
-+ public:
-+ void operator()(void* x) const {
-+ ::XFree(x);
-+ }
-+};
-+
-+bool VaapiVideoDecodeAccelerator::Initialize(
-+ media::VideoCodecProfile profile) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ base::AutoLock auto_lock(lock_);
-+ DCHECK_EQ(state_, kUninitialized);
-+ DVLOG(2) << "Initializing VAVDA, profile: " << profile;
-+
-+ if (!make_context_current_.Run())
-+ return false;
-+
-+ x_display_ = base::MessagePumpForUI::GetDefaultXDisplay();
-+
-+ vaapi_wrapper_ = VaapiWrapper::Create(
-+ profile, x_display_,
-+ base::Bind(&ReportToUMA, content::VaapiH264Decoder::VAAPI_ERROR));
-+
-+ if (!vaapi_wrapper_.get()) {
-+ DVLOG(1) << "Failed initializing VAAPI";
-+ return false;
-+ }
-+
-+ decoder_.reset(
-+ new VaapiH264Decoder(
-+ vaapi_wrapper_.get(),
-+ media::BindToCurrentLoop(base::Bind(
-+ &VaapiVideoDecodeAccelerator::SurfaceReady, weak_this_)),
-+ base::Bind(&ReportToUMA)));
-+
-+ CHECK(decoder_thread_.Start());
-+
-+ state_ = kIdle;
-+
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &Client::NotifyInitializeDone, client_));
-+ return true;
-+}
-+
-+void VaapiVideoDecodeAccelerator::SurfaceReady(
-+ int32 input_id,
-+ const scoped_refptr<VASurface>& va_surface) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ DCHECK(!awaiting_va_surfaces_recycle_);
-+
-+ // Drop any requests to output if we are resetting or being destroyed.
-+ if (state_ == kResetting || state_ == kDestroying)
-+ return;
-+
-+ pending_output_cbs_.push(
-+ base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture,
-+ weak_this_, va_surface, input_id));
-+
-+ TryOutputSurface();
-+}
-+
-+void VaapiVideoDecodeAccelerator::OutputPicture(
-+ const scoped_refptr<VASurface>& va_surface,
-+ int32 input_id,
-+ TFPPicture* tfp_picture) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ int32 output_id = tfp_picture->picture_buffer_id();
-+
-+ TRACE_EVENT2("Video Decoder", "VAVDA::OutputSurface",
-+ "input_id", input_id,
-+ "output_id", output_id);
-+
-+ DVLOG(3) << "Outputting VASurface " << va_surface->id()
-+ << " into pixmap bound to picture buffer id " << output_id;
-+
-+ RETURN_AND_NOTIFY_ON_FAILURE(tfp_picture->Bind(),
-+ "Failed binding texture to pixmap",
-+ PLATFORM_FAILURE, );
-+
-+ RETURN_AND_NOTIFY_ON_FAILURE(
-+ vaapi_wrapper_->PutSurfaceIntoPixmap(va_surface->id(),
-+ tfp_picture->x_pixmap(),
-+ tfp_picture->size()),
-+ "Failed putting surface into pixmap", PLATFORM_FAILURE, );
-+
-+ // Notify the client a picture is ready to be displayed.
-+ ++num_frames_at_client_;
-+ TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_);
-+ DVLOG(4) << "Notifying output picture id " << output_id
-+ << " for input "<< input_id << " is ready";
-+ client_->PictureReady(media::Picture(output_id, input_id));
-+}
-+
-+void VaapiVideoDecodeAccelerator::TryOutputSurface() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ // Handle Destroy() arriving while pictures are queued for output.
-+ if (!client_)
-+ return;
-+
-+ if (pending_output_cbs_.empty() || output_buffers_.empty())
-+ return;
-+
-+ OutputCB output_cb = pending_output_cbs_.front();
-+ pending_output_cbs_.pop();
-+
-+ TFPPicture* tfp_picture = TFPPictureById(output_buffers_.front());
-+ DCHECK(tfp_picture);
-+ output_buffers_.pop();
-+
-+ output_cb.Run(tfp_picture);
-+
-+ if (finish_flush_pending_ && pending_output_cbs_.empty())
-+ FinishFlush();
-+}
-+
-+void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer(
-+ const media::BitstreamBuffer& bitstream_buffer) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ TRACE_EVENT1("Video Decoder", "MapAndQueueNewInputBuffer", "input_id",
-+ bitstream_buffer.id());
-+
-+ DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id()
-+ << " size: " << (int)bitstream_buffer.size();
-+
-+ scoped_ptr<base::SharedMemory> shm(
-+ new base::SharedMemory(bitstream_buffer.handle(), true));
-+ RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(bitstream_buffer.size()),
-+ "Failed to map input buffer", UNREADABLE_INPUT,);
-+
-+ base::AutoLock auto_lock(lock_);
-+
-+ // Set up a new input buffer and queue it for later.
-+ linked_ptr<InputBuffer> input_buffer(new InputBuffer());
-+ input_buffer->shm.reset(shm.release());
-+ input_buffer->id = bitstream_buffer.id();
-+ input_buffer->size = bitstream_buffer.size();
-+
-+ ++num_stream_bufs_at_decoder_;
-+ TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder",
-+ num_stream_bufs_at_decoder_);
-+
-+ input_buffers_.push(input_buffer);
-+ input_ready_.Signal();
-+}
-+
-+bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() {
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+ lock_.AssertAcquired();
-+
-+ if (curr_input_buffer_.get())
-+ return true;
-+
-+ // Will only wait if it is expected that in current state new buffers will
-+ // be queued from the client via Decode(). The state can change during wait.
-+ while (input_buffers_.empty() && (state_ == kDecoding || state_ == kIdle)) {
-+ input_ready_.Wait();
-+ }
-+
-+ // We could have got woken up in a different state or never got to sleep
-+ // due to current state; check for that.
-+ switch (state_) {
-+ case kFlushing:
-+ // Here we are only interested in finishing up decoding buffers that are
-+ // already queued up. Otherwise will stop decoding.
-+ if (input_buffers_.empty())
-+ return false;
-+ // else fallthrough
-+ case kDecoding:
-+ case kIdle:
-+ DCHECK(!input_buffers_.empty());
-+
-+ curr_input_buffer_ = input_buffers_.front();
-+ input_buffers_.pop();
-+
-+ DVLOG(4) << "New current bitstream buffer, id: "
-+ << curr_input_buffer_->id
-+ << " size: " << curr_input_buffer_->size;
-+
-+ decoder_->SetStream(
-+ static_cast<uint8*>(curr_input_buffer_->shm->memory()),
-+ curr_input_buffer_->size, curr_input_buffer_->id);
-+ return true;
-+
-+ default:
-+ // We got woken up due to being destroyed/reset, ignore any already
-+ // queued inputs.
-+ return false;
-+ }
-+}
-+
-+void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() {
-+ lock_.AssertAcquired();
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+ DCHECK(curr_input_buffer_.get());
-+
-+ int32 id = curr_input_buffer_->id;
-+ curr_input_buffer_.reset();
-+ DVLOG(4) << "End of input buffer " << id;
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &Client::NotifyEndOfBitstreamBuffer, client_, id));
-+
-+ --num_stream_bufs_at_decoder_;
-+ TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder",
-+ num_stream_bufs_at_decoder_);
-+}
-+
-+bool VaapiVideoDecodeAccelerator::FeedDecoderWithOutputSurfaces_Locked() {
-+ lock_.AssertAcquired();
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+
-+ while (available_va_surfaces_.empty() &&
-+ (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) {
-+ surfaces_available_.Wait();
-+ }
-+
-+ if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle)
-+ return false;
-+
-+ VASurface::ReleaseCB va_surface_release_cb =
-+ media::BindToCurrentLoop(base::Bind(
-+ &VaapiVideoDecodeAccelerator::RecycleVASurfaceID, weak_this_));
-+
-+ while (!available_va_surfaces_.empty()) {
-+ scoped_refptr<VASurface> va_surface(
-+ new VASurface(available_va_surfaces_.front(), va_surface_release_cb));
-+ available_va_surfaces_.pop_front();
-+ decoder_->ReuseSurface(va_surface);
-+ }
-+
-+ return true;
-+}
-+
-+void VaapiVideoDecodeAccelerator::DecodeTask() {
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+ TRACE_EVENT0("Video Decoder", "VAVDA::DecodeTask");
-+ base::AutoLock auto_lock(lock_);
-+
-+ if (state_ != kDecoding)
-+ return;
-+
-+ // Main decode task.
-+ DVLOG(4) << "Decode task";
-+
-+ // Try to decode what stream data is (still) in the decoder until we run out
-+ // of it.
-+ while (GetInputBuffer_Locked()) {
-+ DCHECK(curr_input_buffer_.get());
-+
-+ VaapiH264Decoder::DecResult res;
-+ {
-+ // We are OK releasing the lock here, as decoder never calls our methods
-+ // directly and we will reacquire the lock before looking at state again.
-+ // This is the main decode function of the decoder and while keeping
-+ // the lock for its duration would be fine, it would defeat the purpose
-+ // of having a separate decoder thread.
-+ base::AutoUnlock auto_unlock(lock_);
-+ res = decoder_->Decode();
-+ }
-+
-+ switch (res) {
-+ case VaapiH264Decoder::kAllocateNewSurfaces:
-+ DVLOG(1) << "Decoder requesting a new set of surfaces";
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange, weak_this_,
-+ decoder_->GetRequiredNumOfPictures(),
-+ decoder_->GetPicSize()));
-+ // We'll get rescheduled once ProvidePictureBuffers() finishes.
-+ return;
-+
-+ case VaapiH264Decoder::kRanOutOfStreamData:
-+ ReturnCurrInputBuffer_Locked();
-+ break;
-+
-+ case VaapiH264Decoder::kRanOutOfSurfaces:
-+ // No more output buffers in the decoder, try getting more or go to
-+ // sleep waiting for them.
-+ if (!FeedDecoderWithOutputSurfaces_Locked())
-+ return;
-+
-+ break;
-+
-+ case VaapiH264Decoder::kDecodeError:
-+ RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream",
-+ PLATFORM_FAILURE, );
-+ return;
-+ }
-+ }
-+}
-+
-+void VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange(size_t num_pics,
-+ gfx::Size size) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ DCHECK(!awaiting_va_surfaces_recycle_);
-+
-+ // At this point decoder has stopped running and has already posted onto our
-+ // loop any remaining output request callbacks, which executed before we got
-+ // here. Some of them might have been pended though, because we might not
-+ // have had enough TFPictures to output surfaces to. Initiate a wait cycle,
-+ // which will wait for client to return enough PictureBuffers to us, so that
-+ // we can finish all pending output callbacks, releasing associated surfaces.
-+ DVLOG(1) << "Initiating surface set change";
-+ awaiting_va_surfaces_recycle_ = true;
-+
-+ requested_num_pics_ = num_pics;
-+ requested_pic_size_ = size;
-+
-+ TryFinishSurfaceSetChange();
-+}
-+
-+void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ if (!awaiting_va_surfaces_recycle_)
-+ return;
-+
-+ if (!pending_output_cbs_.empty() ||
-+ tfp_pictures_.size() != available_va_surfaces_.size()) {
-+ // Either:
-+ // 1. Not all pending pending output callbacks have been executed yet.
-+ // Wait for the client to return enough pictures and retry later.
-+ // 2. The above happened and all surface release callbacks have been posted
-+ // as the result, but not all have executed yet. Post ourselves after them
-+ // to let them release surfaces.
-+ DVLOG(2) << "Awaiting pending output/surface release callbacks to finish";
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange, weak_this_));
-+ return;
-+ }
-+
-+ // All surfaces released, destroy them and dismiss all PictureBuffers.
-+ awaiting_va_surfaces_recycle_ = false;
-+ available_va_surfaces_.clear();
-+ vaapi_wrapper_->DestroySurfaces();
-+
-+ for (TFPPictures::iterator iter = tfp_pictures_.begin();
-+ iter != tfp_pictures_.end(); ++iter) {
-+ DVLOG(2) << "Dismissing picture id: " << iter->first;
-+ client_->DismissPictureBuffer(iter->first);
-+ }
-+ tfp_pictures_.clear();
-+
-+ // And ask for a new set as requested.
-+ DVLOG(1) << "Requesting " << requested_num_pics_ << " pictures of size: "
-+ << requested_pic_size_.ToString();
-+
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &Client::ProvidePictureBuffers, client_,
-+ requested_num_pics_, requested_pic_size_, GL_TEXTURE_2D));
-+}
-+
-+void VaapiVideoDecodeAccelerator::Decode(
-+ const media::BitstreamBuffer& bitstream_buffer) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "Buffer id",
-+ bitstream_buffer.id());
-+
-+ // We got a new input buffer from the client, map it and queue for later use.
-+ MapAndQueueNewInputBuffer(bitstream_buffer);
-+
-+ base::AutoLock auto_lock(lock_);
-+ switch (state_) {
-+ case kIdle:
-+ state_ = kDecoding;
-+ decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::DecodeTask,
-+ base::Unretained(this)));
-+ break;
-+
-+ case kDecoding:
-+ // Decoder already running.
-+ case kResetting:
-+ // When resetting, allow accumulating bitstream buffers, so that
-+ // the client can queue after-seek-buffers while we are finishing with
-+ // the before-seek one.
-+ break;
-+
-+ default:
-+ RETURN_AND_NOTIFY_ON_FAILURE(false,
-+ "Decode request from client in invalid state: " << state_,
-+ PLATFORM_FAILURE, );
-+ break;
-+ }
-+}
-+
-+void VaapiVideoDecodeAccelerator::RecycleVASurfaceID(
-+ VASurfaceID va_surface_id) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ base::AutoLock auto_lock(lock_);
-+
-+ available_va_surfaces_.push_back(va_surface_id);
-+ surfaces_available_.Signal();
-+}
-+
-+void VaapiVideoDecodeAccelerator::AssignPictureBuffers(
-+ const std::vector<media::PictureBuffer>& buffers) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ base::AutoLock auto_lock(lock_);
-+ DCHECK(tfp_pictures_.empty());
-+
-+ while (!output_buffers_.empty())
-+ output_buffers_.pop();
-+
-+ RETURN_AND_NOTIFY_ON_FAILURE(
-+ buffers.size() == requested_num_pics_,
-+ "Got an invalid number of picture buffers. (Got " << buffers.size()
-+ << ", requested " << requested_num_pics_ << ")", INVALID_ARGUMENT, );
-+ DCHECK(requested_pic_size_ == buffers[0].size());
-+
-+ std::vector<VASurfaceID> va_surface_ids;
-+ RETURN_AND_NOTIFY_ON_FAILURE(
-+ vaapi_wrapper_->CreateSurfaces(requested_pic_size_,
-+ buffers.size(),
-+ &va_surface_ids),
-+ "Failed creating VA Surfaces", PLATFORM_FAILURE, );
-+ DCHECK_EQ(va_surface_ids.size(), buffers.size());
-+
-+ for (size_t i = 0; i < buffers.size(); ++i) {
-+ DVLOG(2) << "Assigning picture id: " << buffers[i].id()
-+ << " to texture id: " << buffers[i].texture_id()
-+ << " VASurfaceID: " << va_surface_ids[i];
-+
-+ linked_ptr<TFPPicture> tfp_picture(
-+ TFPPicture::Create(make_context_current_, egl_display_, x_display_,
-+ buffers[i].id(), buffers[i].texture_id(),
-+ requested_pic_size_));
-+
-+ RETURN_AND_NOTIFY_ON_FAILURE(
-+ tfp_picture.get(), "Failed assigning picture buffer to a texture.",
-+ PLATFORM_FAILURE, );
-+
-+ bool inserted = tfp_pictures_.insert(std::make_pair(
-+ buffers[i].id(), tfp_picture)).second;
-+ DCHECK(inserted);
-+
-+ output_buffers_.push(buffers[i].id());
-+ available_va_surfaces_.push_back(va_surface_ids[i]);
-+ surfaces_available_.Signal();
-+ }
-+
-+ state_ = kDecoding;
-+ decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::DecodeTask, base::Unretained(this)));
-+}
-+
-+void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ TRACE_EVENT1("Video Decoder", "VAVDA::ReusePictureBuffer", "Picture id",
-+ picture_buffer_id);
-+
-+ --num_frames_at_client_;
-+ TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_);
-+
-+ output_buffers_.push(picture_buffer_id);
-+ TryOutputSurface();
-+}
-+
-+void VaapiVideoDecodeAccelerator::FlushTask() {
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+ DVLOG(1) << "Flush task";
-+
-+ // First flush all the pictures that haven't been outputted, notifying the
-+ // client to output them.
-+ bool res = decoder_->Flush();
-+ RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed flushing the decoder.",
-+ PLATFORM_FAILURE, );
-+
-+ // Put the decoder in idle state, ready to resume.
-+ decoder_->Reset();
-+
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::FinishFlush, weak_this_));
-+}
-+
-+void VaapiVideoDecodeAccelerator::Flush() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ DVLOG(1) << "Got flush request";
-+
-+ base::AutoLock auto_lock(lock_);
-+ state_ = kFlushing;
-+ // Queue a flush task after all existing decoding tasks to clean up.
-+ decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::FlushTask, base::Unretained(this)));
-+
-+ input_ready_.Signal();
-+ surfaces_available_.Signal();
-+}
-+
-+void VaapiVideoDecodeAccelerator::FinishFlush() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ finish_flush_pending_ = false;
-+
-+ base::AutoLock auto_lock(lock_);
-+ if (state_ != kFlushing) {
-+ DCHECK_EQ(state_, kDestroying);
-+ return; // We could've gotten destroyed already.
-+ }
-+
-+ // Still waiting for textures from client to finish outputting all pending
-+ // frames. Try again later.
-+ if (!pending_output_cbs_.empty()) {
-+ finish_flush_pending_ = true;
-+ return;
-+ }
-+
-+ state_ = kIdle;
-+
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &Client::NotifyFlushDone, client_));
-+
-+ DVLOG(1) << "Flush finished";
-+}
-+
-+void VaapiVideoDecodeAccelerator::ResetTask() {
-+ DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current());
-+ DVLOG(1) << "ResetTask";
-+
-+ // All the decoding tasks from before the reset request from client are done
-+ // by now, as this task was scheduled after them and client is expected not
-+ // to call Decode() after Reset() and before NotifyResetDone.
-+ decoder_->Reset();
-+
-+ base::AutoLock auto_lock(lock_);
-+
-+ // Return current input buffer, if present.
-+ if (curr_input_buffer_.get())
-+ ReturnCurrInputBuffer_Locked();
-+
-+ // And let client know that we are done with reset.
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::FinishReset, weak_this_));
-+}
-+
-+void VaapiVideoDecodeAccelerator::Reset() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ DVLOG(1) << "Got reset request";
-+
-+ // This will make any new decode tasks exit early.
-+ base::AutoLock auto_lock(lock_);
-+ state_ = kResetting;
-+ finish_flush_pending_ = false;
-+
-+ // Drop all remaining input buffers, if present.
-+ while (!input_buffers_.empty()) {
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &Client::NotifyEndOfBitstreamBuffer, client_,
-+ input_buffers_.front()->id));
-+ input_buffers_.pop();
-+ }
-+
-+ decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::ResetTask, base::Unretained(this)));
-+
-+ input_ready_.Signal();
-+ surfaces_available_.Signal();
-+}
-+
-+void VaapiVideoDecodeAccelerator::FinishReset() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ DVLOG(1) << "FinishReset";
-+ base::AutoLock auto_lock(lock_);
-+
-+ if (state_ != kResetting) {
-+ DCHECK(state_ == kDestroying || state_ == kUninitialized) << state_;
-+ return; // We could've gotten destroyed already.
-+ }
-+
-+ // Drop pending outputs.
-+ while (!pending_output_cbs_.empty())
-+ pending_output_cbs_.pop();
-+
-+ if (awaiting_va_surfaces_recycle_) {
-+ // Decoder requested a new surface set while we were waiting for it to
-+ // finish the last DecodeTask, running at the time of Reset().
-+ // Let the surface set change finish first before resetting.
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::FinishReset, weak_this_));
-+ return;
-+ }
-+
-+ num_stream_bufs_at_decoder_ = 0;
-+ state_ = kIdle;
-+
-+ message_loop_->PostTask(FROM_HERE, base::Bind(
-+ &Client::NotifyResetDone, client_));
-+
-+ // The client might have given us new buffers via Decode() while we were
-+ // resetting and might be waiting for our move, and not call Decode() anymore
-+ // until we return something. Post a DecodeTask() so that we won't
-+ // sleep forever waiting for Decode() in that case. Having two of them
-+ // in the pipe is harmless, the additional one will return as soon as it sees
-+ // that we are back in kDecoding state.
-+ if (!input_buffers_.empty()) {
-+ state_ = kDecoding;
-+ decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
-+ &VaapiVideoDecodeAccelerator::DecodeTask,
-+ base::Unretained(this)));
-+ }
-+
-+ DVLOG(1) << "Reset finished";
-+}
-+
-+void VaapiVideoDecodeAccelerator::Cleanup() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+
-+ if (state_ == kUninitialized || state_ == kDestroying)
-+ return;
-+
-+ DVLOG(1) << "Destroying VAVDA";
-+ base::AutoLock auto_lock(lock_);
-+ state_ = kDestroying;
-+
-+ client_ptr_factory_.InvalidateWeakPtrs();
-+
-+ {
-+ base::AutoUnlock auto_unlock(lock_);
-+ // Post a dummy task to the decoder_thread_ to ensure it is drained.
-+ base::WaitableEvent waiter(false, false);
-+ decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
-+ &base::WaitableEvent::Signal, base::Unretained(&waiter)));
-+ input_ready_.Signal();
-+ surfaces_available_.Signal();
-+ waiter.Wait();
-+ decoder_thread_.Stop();
-+ }
-+
-+ state_ = kUninitialized;
-+}
-+
-+void VaapiVideoDecodeAccelerator::Destroy() {
-+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
-+ Cleanup();
-+ delete this;
-+}
-+
-+} // namespace content
-diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator_tizen.h b/content/common/gpu/media/vaapi_video_decode_accelerator_tizen.h
-new file mode 100644
-index 0000000..d41cf38
---- /dev/null
-+++ b/content/common/gpu/media/vaapi_video_decode_accelerator_tizen.h
-@@ -0,0 +1,273 @@
-+// Copyright (c) 2013 Intel Corporation. All rights reserved.
-+// Use of this source code is governed by a BSD-style license that can be
-+// found in the LICENSE file.
-+//
-+// This file contains an implementation of VideoDecoderAccelerator
-+// that utilizes hardware video decoder present on Intel CPUs for Tizen.
-+
-+#ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_VIDEO_DECODE_ACCELERATOR_H_
-+#define CONTENT_COMMON_GPU_MEDIA_VAAPI_VIDEO_DECODE_ACCELERATOR_H_
-+
-+#include <map>
-+#include <queue>
-+#include <utility>
-+#include <vector>
-+
-+#include "base/logging.h"
-+#include "base/memory/linked_ptr.h"
-+#include "base/memory/shared_memory.h"
-+#include "base/memory/weak_ptr.h"
-+#include "base/message_loop/message_loop.h"
-+#include "base/synchronization/condition_variable.h"
-+#include "base/synchronization/lock.h"
-+#include "base/threading/non_thread_safe.h"
-+#include "base/threading/thread.h"
-+#include "content/common/content_export.h"
-+#include "content/common/gpu/media/vaapi_h264_decoder.h"
-+#include "content/common/gpu/media/vaapi_wrapper.h"
-+#include "content/common/gpu/media/video_decode_accelerator_impl.h"
-+#include "media/base/bitstream_buffer.h"
-+#include "media/video/picture.h"
-+#include "media/video/video_decode_accelerator.h"
-+#include "ui/gl/gl_bindings.h"
-+
-+namespace content {
-+
-+// Class to provide video decode acceleration for Intel systems with hardware
-+// support for it, and on which libva is available.
-+// Decoding tasks are performed in a separate decoding thread.
-+//
-+// Threading/life-cycle: this object is created & destroyed on the GPU
-+// ChildThread. A few methods on it are called on the decoder thread which is
-+// stopped during |this->Destroy()|, so any tasks posted to the decoder thread
-+// can assume |*this| is still alive. See |weak_this_| below for more details.
-+class CONTENT_EXPORT VaapiVideoDecodeAccelerator
-+ : public VideoDecodeAcceleratorImpl {
-+ public:
-+ VaapiVideoDecodeAccelerator(
-+ EGLDisplay egl_display, EGLContext egl_context,
-+ Client* client,
-+ const base::Callback<bool(void)>& make_context_current);
-+ virtual ~VaapiVideoDecodeAccelerator();
-+
-+ // media::VideoDecodeAccelerator implementation.
-+ virtual bool Initialize(media::VideoCodecProfile profile) OVERRIDE;
-+ virtual void Decode(const media::BitstreamBuffer& bitstream_buffer) OVERRIDE;
-+ virtual void AssignPictureBuffers(
-+ const std::vector<media::PictureBuffer>& buffers) OVERRIDE;
-+ virtual void ReusePictureBuffer(int32 picture_buffer_id) OVERRIDE;
-+ virtual void Flush() OVERRIDE;
-+ virtual void Reset() OVERRIDE;
-+ virtual void Destroy() OVERRIDE;
-+
-+private:
-+ // Notify the client that |output_id| is ready for displaying.
-+ void NotifyPictureReady(int32 input_id, int32 output_id);
-+
-+ // Notify the client that an error has occurred and decoding cannot continue.
-+ void NotifyError(Error error);
-+
-+ // Map the received input buffer into this process' address space and
-+ // queue it for decode.
-+ void MapAndQueueNewInputBuffer(
-+ const media::BitstreamBuffer& bitstream_buffer);
-+
-+ // Get a new input buffer from the queue and set it up in decoder. This will
-+ // sleep if no input buffers are available. Return true if a new buffer has
-+ // been set up, false if an early exit has been requested (due to initiated
-+ // reset/flush/destroy).
-+ bool GetInputBuffer_Locked();
-+
-+ // Signal the client that the current buffer has been read and can be
-+ // returned. Will also release the mapping.
-+ void ReturnCurrInputBuffer_Locked();
-+
-+ // Pass one or more output buffers to the decoder. This will sleep
-+ // if no buffers are available. Return true if buffers have been set up or
-+ // false if an early exit has been requested (due to initiated
-+ // reset/flush/destroy).
-+ bool FeedDecoderWithOutputSurfaces_Locked();
-+
-+ // Continue decoding given input buffers and sleep waiting for input/output
-+ // as needed. Will exit if a new set of surfaces or reset/flush/destroy
-+ // is requested.
-+ void DecodeTask();
-+
-+ // Scheduled after receiving a flush request and executed after the current
-+ // decoding task finishes decoding pending inputs. Makes the decoder return
-+ // all remaining output pictures and puts it in an idle state, ready
-+ // to resume if needed and schedules a FinishFlush.
-+ void FlushTask();
-+
-+ // Scheduled by the FlushTask after decoder is flushed to put VAVDA into idle
-+ // state and notify the client that flushing has been finished.
-+ void FinishFlush();
-+
-+ // Scheduled after receiving a reset request and executed after the current
-+ // decoding task finishes decoding the current frame. Puts the decoder into
-+ // an idle state, ready to resume if needed, discarding decoded but not yet
-+ // outputted pictures (decoder keeps ownership of their associated picture
-+ // buffers). Schedules a FinishReset afterwards.
-+ void ResetTask();
-+
-+ // Scheduled by ResetTask after it's done putting VAVDA into an idle state.
-+ // Drops remaining input buffers and notifies the client that reset has been
-+ // finished.
-+ void FinishReset();
-+
-+ // Helper for Destroy(), doing all the actual work except for deleting self.
-+ void Cleanup();
-+
-+ // Get a usable framebuffer configuration for use in binding textures
-+ // or return false on failure.
-+ bool InitializeFBConfig();
-+
-+ // Callback for the decoder to execute when it wants us to output given
-+ // |va_surface|.
-+ void SurfaceReady(int32 input_id, const scoped_refptr<VASurface>& va_surface);
-+
-+ // Represents a texture bound to an X Pixmap for output purposes.
-+ class TFPPicture;
-+
-+ // Callback to be executed once we have a |va_surface| to be output and
-+ // an available |tfp_picture| to use for output.
-+ // Puts contents of |va_surface| into given |tfp_picture|, releases the
-+ // surface and passes the resulting picture to client for output.
-+ void OutputPicture(const scoped_refptr<VASurface>& va_surface,
-+ int32 input_id,
-+ TFPPicture* tfp_picture);
-+
-+ // Try to OutputPicture() if we have both a ready surface and picture.
-+ void TryOutputSurface();
-+
-+ // Called when a VASurface is no longer in use by the decoder or is not being
-+ // synced/waiting to be synced to a picture. Returns it to available surfaces
-+ // pool.
-+ void RecycleVASurfaceID(VASurfaceID va_surface_id);
-+
-+ // Initiate wait cycle for surfaces to be released before we release them
-+ // and allocate new ones, as requested by the decoder.
-+ void InitiateSurfaceSetChange(size_t num_pics, gfx::Size size);
-+ // Check if the surfaces have been released or post ourselves for later.
-+ void TryFinishSurfaceSetChange();
-+
-+ // Client-provided X/EGL state.
-+ Display* x_display_;
-+ EGLDisplay egl_display_;
-+ EGLContext egl_context_;
-+ base::Callback<bool(void)> make_context_current_;
-+
-+ // VAVDA state.
-+ enum State {
-+ // Initialize() not called yet or failed.
-+ kUninitialized,
-+ // DecodeTask running.
-+ kDecoding,
-+ // Resetting, waiting for decoder to finish current task and cleanup.
-+ kResetting,
-+ // Flushing, waiting for decoder to finish current task and cleanup.
-+ kFlushing,
-+ // Idle, decoder in state ready to start/resume decoding.
-+ kIdle,
-+ // Destroying, waiting for the decoder to finish current task.
-+ kDestroying,
-+ };
-+
-+ // Protects input buffer and surface queues and state_.
-+ base::Lock lock_;
-+ State state_;
-+
-+ // An input buffer awaiting consumption, provided by the client.
-+ struct InputBuffer {
-+ InputBuffer();
-+ ~InputBuffer();
-+
-+ int32 id;
-+ size_t size;
-+ scoped_ptr<base::SharedMemory> shm;
-+ };
-+
-+ // Queue for incoming input buffers.
-+ typedef std::queue<linked_ptr<InputBuffer> > InputBuffers;
-+ InputBuffers input_buffers_;
-+ // Signalled when input buffers are queued onto the input_buffers_ queue.
-+ base::ConditionVariable input_ready_;
-+
-+ // Current input buffer at decoder.
-+ linked_ptr<InputBuffer> curr_input_buffer_;
-+
-+ // Queue for incoming output buffers (texture ids).
-+ typedef std::queue<int32> OutputBuffers;
-+ OutputBuffers output_buffers_;
-+
-+ typedef std::map<int32, linked_ptr<TFPPicture> > TFPPictures;
-+ // All allocated TFPPictures, regardless of their current state. TFPPictures
-+ // are allocated once and destroyed at the end of decode.
-+ TFPPictures tfp_pictures_;
-+
-+ // Return a TFPPicture associated with given client-provided id.
-+ TFPPicture* TFPPictureById(int32 picture_buffer_id);
-+
-+ // VA Surfaces no longer in use that can be passed back to the decoder for
-+ // reuse, once it requests them.
-+ std::list<VASurfaceID> available_va_surfaces_;
-+ // Signalled when output surfaces are queued onto the available_va_surfaces_
-+ // queue.
-+ base::ConditionVariable surfaces_available_;
-+
-+ // Pending output requests from the decoder. When it indicates that we should
-+ // output a surface and we have an available TFPPicture (i.e. texture) ready
-+ // to use, we'll execute the callback passing the TFPPicture. The callback
-+ // will put the contents of the surface into the picture and return it to
-+ // the client, releasing the surface as well.
-+ // If we don't have any available TFPPictures at the time when the decoder
-+ // requests output, we'll store the request on pending_output_cbs_ queue for
-+ // later and run it once the client gives us more textures
-+ // via ReusePictureBuffer().
-+ typedef base::Callback<void(TFPPicture*)> OutputCB;
-+ std::queue<OutputCB> pending_output_cbs_;
-+
-+ // ChildThread's message loop
-+ base::MessageLoop* message_loop_;
-+
-+ // WeakPtr<> pointing to |this| for use in posting tasks from the decoder
-+ // thread back to the ChildThread. Because the decoder thread is a member of
-+ // this class, any task running on the decoder thread is guaranteed that this
-+ // object is still alive. As a result, tasks posted from ChildThread to
-+ // decoder thread should use base::Unretained(this), and tasks posted from the
-+ // decoder thread to the ChildThread should use |weak_this_|.
-+ base::WeakPtr<VaapiVideoDecodeAccelerator> weak_this_;
-+
-+ // To expose client callbacks from VideoDecodeAccelerator.
-+ // NOTE: all calls to these objects *MUST* be executed on message_loop_.
-+ base::WeakPtrFactory<Client> client_ptr_factory_;
-+ base::WeakPtr<Client> client_;
-+
-+ scoped_ptr<VaapiWrapper> vaapi_wrapper_;
-+
-+ // Comes after vaapi_wrapper_ to ensure its destructor is executed before
-+ // vaapi_wrapper_ is destroyed.
-+ scoped_ptr<VaapiH264Decoder> decoder_;
-+ base::Thread decoder_thread_;
-+
-+ int num_frames_at_client_;
-+ int num_stream_bufs_at_decoder_;
-+
-+ // Whether we are waiting for any pending_output_cbs_ to be run before
-+ // NotifyingFlushDone.
-+ bool finish_flush_pending_;
-+
-+ // Decoder requested a new surface set and we are waiting for all the surfaces
-+ // to be returned before we can free them.
-+ bool awaiting_va_surfaces_recycle_;
-+
-+ // Last requested number/resolution of output picture buffers.
-+ size_t requested_num_pics_;
-+ gfx::Size requested_pic_size_;
-+
-+ DISALLOW_COPY_AND_ASSIGN(VaapiVideoDecodeAccelerator);
-+};
-+
-+} // namespace content
-+
-+#endif // CONTENT_COMMON_GPU_MEDIA_VAAPI_VIDEO_DECODE_ACCELERATOR_H_
-diff --git a/content/content_common.gypi b/content/content_common.gypi
-index 9d6cb61..3f53dd5 100644
---- a/content/content_common.gypi
-+++ b/content/content_common.gypi
-@@ -583,6 +583,32 @@
- '<(DEPTH)/third_party/libva',
- ],
- }],
-+ ['target_arch != "arm" and tizen_mobile == 1 and use_x11 == 1', {
-+ 'dependencies': [
-+ '../media/media.gyp:media',
-+ ],
-+ 'sources': [
-+ 'common/gpu/media/h264_dpb.cc',
-+ 'common/gpu/media/h264_dpb.h',
-+ 'common/gpu/media/va_surface.h',
-+ 'common/gpu/media/vaapi_h264_decoder.cc',
-+ 'common/gpu/media/vaapi_h264_decoder.h',
-+ 'common/gpu/media/vaapi_video_decode_accelerator_tizen.cc',
-+ 'common/gpu/media/vaapi_video_decode_accelerator_tizen.h',
-+ 'common/gpu/media/vaapi_wrapper.cc',
-+ 'common/gpu/media/vaapi_wrapper.h',
-+ ],
-+ 'include_dirs': [
-+ '<(DEPTH)/third_party/libva',
-+ '<(DEPTH)/third_party/khronos',
-+ ],
-+ 'link_settings': {
-+ 'libraries': [
-+ '-lEGL',
-+ '-lGLESv2',
-+ ],
-+ },
-+ }],
- ['OS=="win"', {
- 'dependencies': [
- '../media/media.gyp:media',
-diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
-index 9e29e03..2c04d40 100644
---- a/content/gpu/gpu_main.cc
-+++ b/content/gpu/gpu_main.cc
-@@ -42,7 +42,8 @@
- #include "sandbox/win/src/sandbox.h"
- #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
- #include "content/common/gpu/media/exynos_video_decode_accelerator.h"
--#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
-+#elif (defined(OS_CHROMEOS) || defined(OS_TIZEN_MOBILE)) &&\
-+ defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
- #include "content/common/gpu/media/vaapi_wrapper.h"
- #endif
-
-@@ -360,7 +361,8 @@ bool WarmUpSandbox(const CommandLine& command_line) {
-
- #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
- ExynosVideoDecodeAccelerator::PreSandboxInitialization();
--#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
-+#elif (defined(OS_CHROMEOS) || defined(OS_TIZEN_MOBILE)) &&\
-+ defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
- VaapiWrapper::PreSandboxInitialization();
- #endif
-
---
-1.8.3.2
-
%bcond_with wayland
Name: crosswalk
-Version: 5.34.105.0
+Version: 6.34.113.0
Release: 0
Summary: Crosswalk is an app runtime based on Chromium
License: (BSD-3-Clause and LGPL-2.1+)
Source1002: %{name}.xml.in
Source1003: %{name}.png
Patch1: %{name}-do-not-look-for-gtk2-when-using-aura.patch
-Patch7: %{name}-tizen-audio-session-manager.patch
Patch8: %{name}-mesa-ozone-typedefs.patch
Patch9: Blink-Add-GCC-flag-Wno-narrowing-fix-64bits-build.patch
BuildRequires: flex
BuildRequires: gperf
BuildRequires: libcap-devel
+BuildRequires: ninja
BuildRequires: python
BuildRequires: python-xml
BuildRequires: perl
BuildRequires: which
BuildRequires: pkgconfig(alsa)
BuildRequires: pkgconfig(appcore-common)
-BuildRequires: pkgconfig(audio-session-mgr)
BuildRequires: pkgconfig(cairo)
BuildRequires: pkgconfig(capi-location-manager)
BuildRequires: pkgconfig(dbus-1)
cp -a src/xwalk/LICENSE LICENSE.xwalk
%patch1
-%patch7
%if "%{tizen}" < "3.0"
%patch2
# build root to the BUILDDIR_NAME definition, such as "/var/tmp/xwalk-build"
# (remember all paths are still inside the chroot):
# gbs build --define 'BUILDDIR_NAME /some/path'
-#
-# The --depth and --generator-output combo is used to put all the Makefiles
-# inside the build directory, and (this is the important part) keep file lists
-# (generatedwith <|() in gyp) in the build directory as well, otherwise they
-# will be in the source directory, erased every time and trigger an almost full
-# Blink rebuild (among other smaller targets).
-# We cannot always pass those flags, though, because gyp's make generator does
-# not work if the --generator-output is the top-level source directory.
BUILDDIR_NAME="%{?BUILDDIR_NAME}"
-if [ -z "${BUILDDIR_NAME}" ]; then
- BUILDDIR_NAME="."
-else
- GYP_EXTRA_FLAGS="--depth=. --generator-output=${BUILDDIR_NAME}"
+if [ -n "${BUILDDIR_NAME}" ]; then
+ mkdir -p "${BUILDDIR_NAME}"
+ ln -s "${BUILDDIR_NAME}" src/out
fi
%if %{with wayland}
-GYP_EXTRA_FLAGS="${GYP_EXTRA_FLAGS} -Duse_ash=1 -Duse_ozone=1"
+GYP_EXTRA_FLAGS="${GYP_EXTRA_FLAGS} -Duse_ozone=1"
%endif
-# Change src/ so that we can pass "." to --depth below, otherwise we would need
-# to pass "src" to it, but this confuses the gyp make generator, that expects
-# to be called from the root source directory.
-cd src
-
# --no-parallel is added because chroot does not mount a /dev/shm, this will
# cause python multiprocessing.SemLock error.
-export GYP_GENERATORS='make'
-./xwalk/gyp_xwalk xwalk/xwalk.gyp \
+export GYP_GENERATORS='ninja'
+./src/xwalk/gyp_xwalk src/xwalk/xwalk.gyp \
--no-parallel \
${GYP_EXTRA_FLAGS} \
-Dchromeos=0 \
-Duse_gconf=0 \
-Duse_kerberos=0 \
-Duse_system_bzip2=1 \
--Duse_system_icu=1 \
-Duse_system_libexif=1 \
-Duse_system_libxml=1 \
-Duse_system_nspr=1 \
--Denable_xi21_mt=1 \
--Duse_xi2_mt=0 \
-Denable_hidpi=1
-make %{?_smp_mflags} -C "${BUILDDIR_NAME}" BUILDTYPE=Release xwalk xwalkctl xwalk_launcher xwalk-pkg-helper
+ninja %{?_smp_mflags} -C src/out/Release xwalk xwalkctl xwalk_launcher xwalk-pkg-helper
%install
-# Support building in a non-standard directory, possibly outside %{_builddir}.
-# Since the build root is erased every time a new build is performed, one way
-# to avoid losing the build directory is to specify a location outside the
-# build root to the BUILDDIR_NAME definition, such as "/var/tmp/xwalk-build"
-# (remember all paths are still inside the chroot):
-# gbs build --define 'BUILDDIR_NAME /some/path'
-BUILDDIR_NAME="%{?BUILDDIR_NAME}"
-if [ -z "${BUILDDIR_NAME}" ]; then
- BUILDDIR_NAME="."
-fi
-
-# Since BUILDDIR_NAME can be either a relative path or an absolute one, we need
-# to cd into src/ so that it means the same thing in the build and install
-# stages: during the former, a relative location refers to a place inside src/,
-# whereas during the latter a relative location by default would refer to a
-# place one directory above src/. If BUILDDIR_NAME is an absolute path, this is
-# irrelevant anyway.
-cd src
-
# Binaries.
-install -p -D ../xwalk %{buildroot}%{_bindir}/xwalk
+install -p -D xwalk %{buildroot}%{_bindir}/xwalk
install -p -D %{SOURCE2} %{buildroot}%{_dbusservicedir}/org.crosswalkproject.Runtime1.service
-install -p -D ../xwalk.service %{buildroot}%{_systemduserservicedir}/xwalk.service
-install -p -D ${BUILDDIR_NAME}/out/Release/xwalk %{buildroot}%{_libdir}/xwalk/xwalk
-install -p -D ${BUILDDIR_NAME}/out/Release/xwalkctl %{buildroot}%{_bindir}/xwalkctl
-install -p -D ${BUILDDIR_NAME}/out/Release/xwalk-launcher %{buildroot}%{_bindir}/xwalk-launcher
+install -p -D xwalk.service %{buildroot}%{_systemduserservicedir}/xwalk.service
+install -p -D src/out/Release/xwalk %{buildroot}%{_libdir}/xwalk/xwalk
+install -p -D src/out/Release/xwalkctl %{buildroot}%{_bindir}/xwalkctl
+install -p -D src/out/Release/xwalk-launcher %{buildroot}%{_bindir}/xwalk-launcher
# xwalk-pkg-helper needs to be set-user-ID-root so it can finish the installation process.
-install -m 06755 -p -D ${BUILDDIR_NAME}/out/Release/xwalk-pkg-helper %{buildroot}%{_bindir}/xwalk-pkg-helper
+install -m 06755 -p -D src/out/Release/xwalk-pkg-helper %{buildroot}%{_bindir}/xwalk-pkg-helper
# Supporting libraries and resources.
-install -p -D ${BUILDDIR_NAME}/out/Release/icudtl.dat %{buildroot}%{_libdir}/xwalk/icudtl.dat
-install -p -D ${BUILDDIR_NAME}/out/Release/libffmpegsumo.so %{buildroot}%{_libdir}/xwalk/libffmpegsumo.so
-install -p -D ${BUILDDIR_NAME}/out/Release/xwalk.pak %{buildroot}%{_libdir}/xwalk/xwalk.pak
+install -p -D src/out/Release/icudtl.dat %{buildroot}%{_libdir}/xwalk/icudtl.dat
+install -p -D src/out/Release/libffmpegsumo.so %{buildroot}%{_libdir}/xwalk/libffmpegsumo.so
+install -p -D src/out/Release/xwalk.pak %{buildroot}%{_libdir}/xwalk/xwalk.pak
# Register xwalk to the package manager.
-install -p -D ../%{name}.xml %{buildroot}%{_manifestdir}/%{name}.xml
-install -p -D ../%{name}.png %{buildroot}%{_desktop_icondir}/%{name}.png
-
+install -p -D %{name}.xml %{buildroot}%{_manifestdir}/%{name}.xml
+install -p -D %{name}.png %{buildroot}%{_desktop_icondir}/%{name}.png
%post
mkdir -p %{_desktop_icondir_ro}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.xwalk.core;
-
-import android.os.Handler;
-
-/**
- * SslErrorHandler: class responsible for handling SSL errors.
- * This class is passed as a parameter to BrowserCallback.displaySslErrorDialog
- * and is meant to receive the user's response.
- */
-public class SslErrorHandler extends Handler {
-
- /**
- * @hide Only for use by WebViewProvider implementations.
- */
- public SslErrorHandler() {}
-
- /**
- * Proceed with the SSL certificate.
- */
- public void proceed() {}
-
- /**
- * Cancel this request and all pending requests for the XWalkView that had
- * the error.
- */
- public void cancel() {}
-}
--- /dev/null
+// Copyright 2013 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.
+
+package org.xwalk.core;
+
+import android.net.http.SslCertificate;
+import android.net.http.SslError;
+import android.util.Log;
+
+import org.chromium.net.NetError;
+import org.chromium.net.X509Util;
+
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+class SslUtil {
+ private static final String TAG = "SslUtil";
+
+ /**
+ * Creates an SslError object from a chromium net error code.
+ */
+ public static SslError sslErrorFromNetErrorCode(int error, SslCertificate cert, String url) {
+ assert (error >= NetError.ERR_CERT_END && error <= NetError.ERR_CERT_COMMON_NAME_INVALID);
+ switch(error) {
+ case NetError.ERR_CERT_COMMON_NAME_INVALID:
+ return new SslError(SslError.SSL_IDMISMATCH, cert, url);
+ case NetError.ERR_CERT_DATE_INVALID:
+ return new SslError(SslError.SSL_DATE_INVALID, cert, url);
+ case NetError.ERR_CERT_AUTHORITY_INVALID:
+ return new SslError(SslError.SSL_UNTRUSTED, cert, url);
+ default:
+ break;
+ }
+ // Map all other codes to SSL_INVALID.
+ return new SslError(SslError.SSL_INVALID, cert, url);
+ }
+
+ public static SslCertificate getCertificateFromDerBytes(byte[] derBytes) {
+ if (derBytes == null) {
+ return null;
+ }
+
+ try {
+ X509Certificate x509Certificate =
+ X509Util.createCertificateFromBytes(derBytes);
+ return new SslCertificate(x509Certificate);
+ } catch (CertificateException e) {
+ // A SSL related exception must have occured. This shouldn't happen.
+ Log.w(TAG, "Could not read certificate: " + e);
+ } catch (KeyStoreException e) {
+ // A SSL related exception must have occured. This shouldn't happen.
+ Log.w(TAG, "Could not read certificate: " + e);
+ } catch (NoSuchAlgorithmException e) {
+ // A SSL related exception must have occured. This shouldn't happen.
+ Log.w(TAG, "Could not read certificate: " + e);
+ }
+ return null;
+ }
+}
import android.net.http.SslError;
import android.os.Message;
import android.view.KeyEvent;
+import android.webkit.ValueCallback;
import android.webkit.WebResourceResponse;
public class XWalkClient {
* load.
*
* @param view The XWalkView that is initiating the callback.
- * @param handler An SslErrorHandler object that will handle the user's
- * response.
+ * @param callback The callback class. Passing 'true' means accepting the
+ * ssl error and continue to load. Passing 'false' means
+ * forbidding to load the web page.
* @param error The SSL error object.
*/
- public void onReceivedSslError(XWalkView view, SslErrorHandler handler,
+ public void onReceivedSslError(XWalkView view, ValueCallback<Boolean> callback,
SslError error) {
- handler.cancel();
+ callback.onReceiveValue(true);
}
/**
loadUrl(url);
}
+ @CalledByNative
+ public void onGetFullscreenFlagFromManifest(boolean enterFullscreen) {
+ if (enterFullscreen) getXWalkWebChromeClient().onToggleFullscreen(true);
+ }
+
public void destroy() {
if (mXWalkContent == 0) return;
public abstract void onReceivedHttpAuthRequest(XWalkHttpAuthHandler handler,
String host, String realm);
- public abstract void onReceivedSslError(SslErrorHandler handler, SslError error);
+ public abstract void onReceivedSslError(ValueCallback<Boolean> callback, SslError error);
public abstract void onReceivedLoginRequest(String realm, String account, String args);
if (mXWalkClient != null && mXWalkView != null)
mXWalkClient.onReceivedHttpAuthRequest(mXWalkView, handler, host, realm);
}
+
@Override
- public void onReceivedSslError(SslErrorHandler handler, SslError error) {
- if (mXWalkClient != null && mXWalkView != null)
- mXWalkClient.onReceivedSslError(mXWalkView, handler, error);
+ public void onReceivedSslError(ValueCallback<Boolean> callback, SslError error) {
+ if (mXWalkClient != null && mXWalkView != null) {
+ mXWalkClient.onReceivedSslError(mXWalkView, callback, error);
+ }
}
@Override
@CalledByNative
private boolean allowCertificateError(int certError, byte[] derBytes, final String url,
final int id) {
- // TODO(yongsheng): Implement this.
- return false;
+ final SslCertificate cert = SslUtil.getCertificateFromDerBytes(derBytes);
+ if (cert == null) {
+ // if the certificate or the client is null, cancel the request
+ return false;
+ }
+ final SslError sslError = SslUtil.sslErrorFromNetErrorCode(certError, cert, url);
+ ValueCallback<Boolean> callback = new ValueCallback<Boolean>() {
+ @Override
+ public void onReceiveValue(Boolean value) {
+ proceedSslError(value.booleanValue(), id);
+ }
+ };
+ onReceivedSslError(callback, sslError);
+ return true;
}
private void proceedSslError(boolean proceed, int id) {
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.webkit.ValueCallback;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
-import org.xwalk.core.HttpAuthDatabase;
-import org.xwalk.core.XWalkHttpAuthHandler;
-import org.xwalk.core.R;
-import org.xwalk.core.SslErrorHandler;
-import org.xwalk.core.XWalkClient;
-import org.xwalk.core.XWalkView;
-
// TODO(yongsheng): remove public modifier.
public class XWalkDefaultClient extends XWalkClient {
}
@Override
- public void onReceivedSslError(XWalkView view, SslErrorHandler handler,
+ public void onReceivedSslError(XWalkView view, ValueCallback<Boolean> callback,
SslError error) {
- final SslErrorHandler sslHandler = handler;
+ final ValueCallback<Boolean> valueCallback = callback;
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+ // Don't use setOnDismissListener because it's supported since API level 17.
dialogBuilder.setTitle(R.string.ssl_alert_title)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- sslHandler.proceed();
+ valueCallback.onReceiveValue(true);
dialog.dismiss();
}
- })
- .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- sslHandler.cancel();
- dialog.cancel();
+ }).setNegativeButton(android.R.string.cancel, null)
+ .setOnCancelListener(new DialogInterface.OnCancelListener() {
+ public void onCancel(DialogInterface dialog) {
+ valueCallback.onReceiveValue(false);
}
});
mDialog = dialogBuilder.create();
import android.content.ContentResolver;
import android.database.Cursor;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Event;
long id = c.getLong(c.getColumnIndex(Data.CONTACT_ID));
if (!dataMap.containsKey(id)) dataMap.put(id, new ContactData());
ContactData d = dataMap.get(id);
+ if (d.lastUpdated == null && VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
+ d.lastUpdated = mUtils.getLastUpdated(id);
+ }
String mime = c.getString(c.getColumnIndex(Data.MIMETYPE));
- if (mime.equals(ContactConstants.CUSTOM_MIMETYPE_LASTUPDATED)) {
- d.lastUpdated = c.getString(c.getColumnIndex(Data.DATA1));
- } else if (mime.equals(StructuredName.CONTENT_ITEM_TYPE)) {
+ if (mime.equals(StructuredName.CONTENT_ITEM_TYPE)) {
d.oName = addString(d.oName, c, "displayName", StructuredName.DISPLAY_NAME);
d.oName = addArrayTop(d.oName, c, "honorificPrefixes", StructuredName.PREFIX);
d.oName = addArrayTop(d.oName, c, "givenNames", StructuredName.GIVEN_NAME);
}
}
- private void buildByDate(String name, String mimeType, String data) {
- buildByDate(name, mimeType, data, null, 0);
- }
-
private void buildByDate(String name, String mimeType, String data, String type, int dateType) {
if (!mContact.has(name)) return;
}
}
- private void PutToContact(String id) {
- if (id == null) return;
+ private void PutToContact(String name, String value) {
+ if (name == null) return;
try {
- mContact.put("id", id);
+ mContact.put(name, value);
} catch (JSONException e) {
- Log.e(TAG, "Failed to put id " + id + " into contact" + e.toString());
+ Log.e(TAG, "Failed to set " + name + " = " + value + " for contact" + e.toString());
}
}
}
}
- buildByDate("lastUpdated", ContactConstants.CUSTOM_MIMETYPE_LASTUPDATED, Data.DATA1);
buildByEvent("birthday", Event.TYPE_BIRTHDAY);
buildByEvent("anniversary", Event.TYPE_ANNIVERSARY);
+ "new raw ids are: " + newRawIds.toString());
return mContact;
}
- String id = mUtils.getId(newRawIds.iterator().next());
- PutToContact(id);
+ mId = mUtils.getId(newRawIds.iterator().next());
+ PutToContact("id", mId);
+ }
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2 ) {
+ PutToContact("lastUpdated", String.valueOf(mUtils.getLastUpdated(Long.valueOf(mId))));
}
return mContact;
}
}
}
+ /**
+ * Get lastUpdatedTimestamp and return as JS date format
+ * @param long e.g. 987654321012
+ * @return string e.g. "2001-04-19T04:25:21.012Z"
+ */
+ @android.annotation.TargetApi(android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
+ public String getLastUpdated(long contactId) {
+ String[] projection = new String[]{ContactsContract.Contacts.CONTACT_LAST_UPDATED_TIMESTAMP};
+
+ Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
+ Cursor cursor = mResolver.query(uri, projection, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return timeConvertToJS(cursor.getLong(0));
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return null;
+ }
+
public Set<String> getCurrentRawIds() {
Cursor c = null;
try {
}
return date;
}
+
+ /**
+ * Convert epoch seconds to JS date format
+ * @param long e.g. 61
+ * @return string e.g. "1969-12-31T00:01:01Z"
+ */
+ private String timeConvertToJS(long seconds) {
+ final SimpleDateFormat df =
+ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", java.util.Locale.getDefault());
+ return df.format(new java.util.Date(seconds));
+ }
}
window.Contact = function(init) {
this.id = null;
- this.lastUpdated = null;
+ this.lastUpdated = new Date();
this.name = init.name;
this.emails = init.emails;
this.photos = init.photos;
Finished to download file.
</message>
<message desc="Title for the Ssl Alert dialog [CHAR-LIMIT=32]" name="IDS_SSL_ALERT_TITLE">
- Ssl Alert
+ Ssl Certificate Error Alert
</message>
<message desc="Title for the http authentication dialog [CHAR-LIMIT=32]" name="IDS_HTTP_AUTH_TITLE">
Authentication Required
import android.content.Context;
import android.graphics.Bitmap;
import android.net.http.SslError;
+import android.webkit.ValueCallback;
import java.lang.reflect.Method;
import org.xwalk.core.XWalkDefaultClient;
-import org.xwalk.core.SslErrorHandler;
import org.xwalk.core.XWalkView;
class XWalkClientForTest extends XWalkDefaultClient {
}
@Override
- public void onReceivedSslError(XWalkView view, SslErrorHandler handler,
+ public void onReceivedSslError(XWalkView view, ValueCallback<Boolean> callback,
SslError error) {
if (mCallbackForTest != null) {
try {
Class<?> objectClass = mCallbackForTest.getClass();
Method onReceivedSslError = objectClass.getMethod(
- "onReceivedSslError", SslErrorHandler.class, SslError.class);
- onReceivedSslError.invoke(mCallbackForTest, handler, error);
+ "onReceivedSslError", ValueCallback.class, SslError.class);
+ onReceivedSslError.invoke(mCallbackForTest, callback, error);
} catch (Exception e) {
e.printStackTrace();
}
}
void XWalkMainDelegateAndroid::InitResourceBundle() {
- int pak_fd =
- base::GlobalDescriptors::GetInstance()->MaybeGet(kXWalkPakDescriptor);
- if (pak_fd != base::kInvalidPlatformFileValue) {
- ui::ResourceBundle::InitSharedInstanceWithPakFile(
- base::File(pak_fd), false);
- ResourceBundle::GetSharedInstance().AddDataPackFromFile(
- base::File(pak_fd), ui::SCALE_FACTOR_100P);
- return;
- }
base::FilePath pak_file;
base::FilePath pak_dir;
bool got_path = PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_dir);
const content::FrameNavigateParams& params) {
DCHECK(CalledOnValidThread());
- // TODO(Xingnan): Add the AddVisitedURLs method
- // in RuntimeContext.
-
- // RuntimeContext::FromWebContents(web_contents())
- // ->AddVisitedURLs(params.redirects);
+ RuntimeContext::FromWebContents(web_contents())
+ ->AddVisitedURLs(params.redirects);
}
bool XWalkRenderViewHostExt::OnMessageReceived(const IPC::Message& message) {
using content::BrowserThread;
using content::WebContents;
using navigation_interception::InterceptNavigationDelegate;
+using xwalk::application_manifest_keys::kDisplay;
namespace xwalk {
// According to original proposal for "app:launch:local_path", the "http"
// and "https" schemes are supported. So |url| should do nothing when it
// already has "http" or "https" scheme.
- std::string lower_url = url;
- std::transform(lower_url.begin(), lower_url.end(),
- lower_url.begin(), std::tolower);
- if (lower_url.find(content::kHttpScheme) == std::string::npos &&
- lower_url.find(content::kHttpsScheme) == std::string::npos) {
+ std::string scheme = GURL(url).scheme();
+ if (scheme != content::kHttpScheme && scheme != content::kHttpsScheme)
url = path_str + url;
- }
} else {
manifest.GetString(
xwalk::application_manifest_keys::kLaunchWebURLKey, &url);
ScopedJavaLocalRef<jstring> url_buffer =
base::android::ConvertUTF8ToJavaString(env, url);
+ if (manifest.HasPath(kDisplay)) {
+ std::string display_string;
+ manifest.GetString(kDisplay, &display_string);
+ // TODO(David): update the handling process of the display strings
+ // including fullscreen etc.
+ bool display_as_fullscreen = (
+ display_string.find("fullscreen") != std::string::npos);
+ Java_XWalkContent_onGetFullscreenFlagFromManifest(
+ env, obj, display_as_fullscreen ? JNI_TRUE : JNI_FALSE);
+ }
+
// Check whether need to display launch screen. (Read from manifest.json)
if (manifest.HasPath(
xwalk::application_manifest_keys::kLaunchScreen)) {
int route_id,
const SkBitmap& icon) {
XWalkContentsClientBridgeBase* bridge =
- XWalkContentsClientBridgeBase::FromID(process_id, route_id);
+ XWalkContentsClientBridgeBase::FromRenderViewID(process_id, route_id);
if (bridge)
bridge->UpdateNotificationIcon(notification_id, icon);
}
#include "xwalk/runtime/browser/android/xwalk_contents_client_bridge_base.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
}
// static
-XWalkContentsClientBridgeBase* XWalkContentsClientBridgeBase::FromID(
+XWalkContentsClientBridgeBase* XWalkContentsClientBridgeBase::FromRenderViewID(
int render_process_id,
int render_view_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return UserData::GetContents(web_contents);
}
+// static
+XWalkContentsClientBridgeBase* XWalkContentsClientBridgeBase::FromRenderFrameID(
+ int render_process_id,
+ int render_frame_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ content::RenderFrameHost* rfh =
+ content::RenderFrameHost::FromID(render_process_id, render_frame_id);
+ if (!rfh) return NULL;
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(rfh);
+ return UserData::GetContents(web_contents);
+}
+
XWalkContentsClientBridgeBase::~XWalkContentsClientBridgeBase() {
}
XWalkContentsClientBridgeBase* handler);
static XWalkContentsClientBridgeBase* FromWebContents(
content::WebContents* web_contents);
- static XWalkContentsClientBridgeBase* FromID(int render_process_id,
+ static XWalkContentsClientBridgeBase* FromRenderViewID(int render_process_id,
int render_view_id);
+ static XWalkContentsClientBridgeBase* FromRenderFrameID(int render_process_id,
+ int render_frame_id);
virtual ~XWalkContentsClientBridgeBase();
const net::CookieList& cookie_list,
content::ResourceContext* context,
int render_process_id,
- int render_view_id) {
+ int render_frame_id) {
return GetGlobalAllowAccess();
}
const std::string& cookie_line,
content::ResourceContext* context,
int render_process_id,
- int render_view_id,
+ int render_frame_id,
net::CookieOptions* options) {
return GetGlobalAllowAccess();
}
const net::CookieList& cookie_list,
content::ResourceContext* context,
int render_process_id,
- int render_view_id);
+ int render_frame_id);
bool AllowSetCookie(const GURL& url,
const GURL& first_party,
const std::string& cookie_line,
content::ResourceContext* context,
int render_process_id,
- int render_view_id,
+ int render_frame_id,
net::CookieOptions* options);
private:
const GURL& location,
net::URLRequest* request) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- int render_process_id, render_view_id;
+ int render_process_id, render_frame_id;
if (!ResourceRequestInfo::GetRenderFrameForRequest(
- request, &render_process_id, &render_view_id))
+ request, &render_process_id, &render_frame_id))
return scoped_ptr<InterceptedRequestData>();
scoped_ptr<XWalkContentsIoThreadClient> io_thread_client =
- XWalkContentsIoThreadClient::FromID(render_process_id, render_view_id);
+ XWalkContentsIoThreadClient::FromID(render_process_id, render_frame_id);
if (!io_thread_client.get())
return scoped_ptr<InterceptedRequestData>();
#include "base/command_line.h"
#include "base/logging.h"
#include "base/path_service.h"
+#include "components/visitedlink/browser/visitedlink_master.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/resource_context.h"
#include "content/public/browser/storage_partition.h"
RuntimeContext::RuntimeContext()
: resource_context_(new RuntimeResourceContext) {
InitWhileIOAllowed();
+#if defined(OS_ANDROID)
+ InitVisitedLinkMaster();
+#endif
}
RuntimeContext::~RuntimeContext() {
std::string RuntimeContext::GetCSPString() const {
return csp_;
}
+
+void RuntimeContext::InitVisitedLinkMaster() {
+ visitedlink_master_.reset(
+ new visitedlink::VisitedLinkMaster(this, this, false));
+ visitedlink_master_->Init();
+}
+
+void RuntimeContext::AddVisitedURLs(const std::vector<GURL>& urls) {
+ DCHECK(visitedlink_master_);
+ visitedlink_master_->AddURLs(urls);
+}
+
+void RuntimeContext::RebuildTable(
+ const scoped_refptr<URLEnumerator>& enumerator) {
+ // XWalkView rebuilds from XWalkWebChromeClient.getVisitedHistory. The client
+ // can change in the lifetime of this XWalkView and may not yet be set here.
+ // Therefore this initialization path is not used.
+ enumerator->OnComplete(true);
+}
#endif
} // namespace xwalk
#include <string>
#endif
+#include <vector>
+
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "components/visitedlink/browser/visitedlink_delegate.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/geolocation_permission_context.h"
class DownloadManagerDelegate;
}
+namespace visitedlink {
+class VisitedLinkMaster;
+}
+
namespace xwalk {
class RuntimeDownloadManagerDelegate;
class RuntimeURLRequestContextGetter;
-class RuntimeContext : public content::BrowserContext {
+class RuntimeContext
+ : public content::BrowserContext
+#if defined(OS_ANDROID)
+ , public visitedlink::VisitedLinkDelegate
+#endif
+{
public:
RuntimeContext();
virtual ~RuntimeContext();
#if defined(OS_ANDROID)
void SetCSPString(const std::string& csp);
std::string GetCSPString() const;
+ // These methods map to Add methods in visitedlink::VisitedLinkMaster.
+ void AddVisitedURLs(const std::vector<GURL>& urls);
+ // visitedlink::VisitedLinkDelegate implementation.
+ virtual void RebuildTable(
+ const scoped_refptr<URLEnumerator>& enumerator) OVERRIDE;
#endif
private:
// allowed on the current thread.
void InitWhileIOAllowed();
+#if defined(OS_ANDROID)
+ // Reset visitedlink master and initialize it.
+ void InitVisitedLinkMaster();
+#endif
+
scoped_ptr<RuntimeResourceContext> resource_context_;
scoped_refptr<RuntimeDownloadManagerDelegate> download_manager_delegate_;
scoped_refptr<RuntimeURLRequestContextGetter> url_request_getter_;
geolocation_permission_context_;
#if defined(OS_ANDROID)
std::string csp_;
+ scoped_ptr<visitedlink::VisitedLinkMaster> visitedlink_master_;
#endif
+
DISALLOW_COPY_AND_ASSIGN(RuntimeContext);
};
NativeAppWindowTizen::NativeAppWindowTizen(
const NativeAppWindow::CreateParams& create_params)
: NativeAppWindowViews(create_params),
+#if defined(OS_TIZEN_MOBILE)
indicator_widget_(new TizenSystemIndicatorWidget()),
+ indicator_container_(new WidgetContainerView(indicator_widget_)),
+#endif
allowed_orientations_(ANY) {
- indicator_container_.reset(new WidgetContainerView(indicator_widget_));
}
void NativeAppWindowTizen::Initialize() {
const ViewHierarchyChangedDetails& details) {
if (details.is_add && details.child == this) {
NativeAppWindowViews::ViewHierarchyChanged(details);
+#if defined(OS_TIZEN_MOBILE)
indicator_widget_->Initialize(GetNativeWindow());
top_view_layout()->set_top_view(indicator_container_.get());
AddChildView(indicator_container_.get());
+#endif
}
}
if (!root_window->IsVisible())
return;
UpdateTopViewOverlay();
+
+#if defined(OS_TIZEN_MOBILE)
indicator_widget_->SetDisplay(display_);
+#endif
root_window->SetTransform(GetRotationTransform());
}
gfx::Display::Rotation GetClosestAllowedRotation(
gfx::Display::Rotation) const;
+#if defined(OS_TIZEN_MOBILE)
// The system indicator is implemented as a widget because it needs to
// receive events and may also be an overlay on top of the rest of the
// content, regular views do not support this. We add it to the container,
// The |indicator_widget_| is owned by the WidgetContainerView.
TizenSystemIndicatorWidget* indicator_widget_;
scoped_ptr<WidgetContainerView> indicator_container_;
+#endif
+
gfx::Display display_;
OrientationMask allowed_orientations_;
#include "ui/views/window/native_frame_view.h"
#endif
-#if defined(OS_TIZEN_MOBILE)
+#if defined(OS_TIZEN)
#include "xwalk/runtime/browser/ui/native_app_window_tizen.h"
#endif
NativeAppWindow* NativeAppWindow::Create(
const NativeAppWindow::CreateParams& create_params) {
NativeAppWindowViews* window;
-#if defined(OS_TIZEN_MOBILE)
+#if defined(OS_TIZEN)
window = new NativeAppWindowTizen(create_params);
#else
window = new NativeAppWindowViews(create_params);
namespace xswitches {
// Redefine settings not exposed by content module.
-const char kEnableViewport[] = "enable-viewport";
const char kEnableOverlayScrollbars[] = "enable-overlay-scrollbars";
}
void XWalkBrowserMainParts::PreMainMessageLoopStart() {
CommandLine* command_line = CommandLine::ForCurrentProcess();
- command_line->AppendSwitch(xswitches::kEnableViewport);
+ command_line->AppendSwitch(switches::kEnableViewport);
+ command_line->AppendSwitch(switches::kEnableViewportMeta);
command_line->AppendSwitch(xswitches::kEnableOverlayScrollbars);
#include "content/public/browser/web_contents.h"
#include "content/public/common/main_function_params.h"
#include "content/public/common/show_desktop_notification_params.h"
+#include "net/ssl/ssl_info.h"
#include "net/url_request/url_request_context_getter.h"
#include "xwalk/extensions/common/xwalk_extension_switches.h"
#include "xwalk/runtime/browser/xwalk_browser_main_parts.h"
#endif
#if defined(OS_TIZEN)
+#include "xwalk/application/browser/application_system.h"
+#include "xwalk/application/browser/application_service.h"
+#include "xwalk/application/browser/application.h"
+#include "xwalk/application/common/application_manifest_constants.h"
+#include "xwalk/application/common/manifest_handlers/navigation_handler.h"
+#include "xwalk/application/common/constants.h"
+#include "xwalk/runtime/browser/runtime_platform_util.h"
#include "xwalk/runtime/browser/xwalk_browser_main_parts_tizen.h"
#endif
const net::CookieList& cookie_list,
content::ResourceContext* context,
int render_process_id,
- int render_view_id) {
+ int render_frame_id) {
#if defined(OS_ANDROID)
return XWalkCookieAccessPolicy::GetInstance()->AllowGetCookie(
url,
cookie_list,
context,
render_process_id,
- render_view_id);
+ render_frame_id);
#else
return true;
#endif
const std::string& cookie_line,
content::ResourceContext* context,
int render_process_id,
- int render_view_id,
+ int render_frame_id,
net::CookieOptions* options) {
#if defined(OS_ANDROID)
return XWalkCookieAccessPolicy::GetInstance()->AllowSetCookie(
cookie_line,
context,
render_process_id,
- render_view_id,
+ render_frame_id,
options);
#else
return true;
#endif
}
+void XWalkContentBrowserClient::AllowCertificateError(
+ int render_process_id,
+ int render_frame_id,
+ int cert_error,
+ const net::SSLInfo& ssl_info,
+ const GURL& request_url,
+ ResourceType::Type resource_type,
+ bool overridable,
+ bool strict_enforcement,
+ const base::Callback<void(bool)>& callback,
+ content::CertificateRequestResultType* result) {
+ // Currently only Android handles it.
+ // TODO(yongsheng): applies it for other platforms?
+#if defined(OS_ANDROID)
+ XWalkContentsClientBridgeBase* client =
+ XWalkContentsClientBridgeBase::FromRenderFrameID(render_process_id,
+ render_frame_id);
+ bool cancel_request = true;
+ if (client)
+ client->AllowCertificateError(cert_error,
+ ssl_info.cert.get(),
+ request_url,
+ callback,
+ &cancel_request);
+ if (cancel_request)
+ *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY;
+#endif
+}
+
void XWalkContentBrowserClient::RequestDesktopNotificationPermission(
const GURL& source_origin,
int callback_context,
bool worker) {
#if defined(OS_ANDROID)
XWalkContentsClientBridgeBase* bridge =
- XWalkContentsClientBridgeBase::FromID(render_process_id, render_view_id);
+ XWalkContentsClientBridgeBase::FromRenderViewID(render_process_id,
+ render_view_id);
bridge->ShowNotification(params, worker, render_process_id, render_view_id);
#endif
}
int notification_id) {
#if defined(OS_ANDROID)
XWalkContentsClientBridgeBase* bridge =
- XWalkContentsClientBridgeBase::FromID(render_process_id, render_view_id);
+ XWalkContentsClientBridgeBase::FromRenderViewID(render_process_id,
+ render_view_id);
bridge->CancelNotification(
notification_id, render_process_id, render_view_id);
#endif
}
#if defined(OS_ANDROID)
-void XWalkContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
- const CommandLine& command_line,
- int child_process_id,
- std::vector<content::FileDescriptorInfo>* mappings) {
- int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
- base::FilePath pak_file;
- bool r = PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_file);
- CHECK(r);
- pak_file = pak_file.Append(FILE_PATH_LITERAL("paks"));
- pak_file = pak_file.Append(FILE_PATH_LITERAL(kXWalkPakFilePath));
-
- base::PlatformFile f =
- base::CreatePlatformFile(pak_file, flags, NULL, NULL);
- if (f == base::kInvalidPlatformFileValue) {
- NOTREACHED() << "Failed to open file when creating renderer process: "
- << "xwalk.pak";
- }
- mappings->push_back(
- content::FileDescriptorInfo(kXWalkPakDescriptor,
- base::FileDescriptor(f, true)));
-}
-
void XWalkContentBrowserClient::ResourceDispatcherHostCreated() {
RuntimeResourceDispatcherHostDelegateAndroid::
ResourceDispatcherHostCreated();
return new xwalk::XWalkSpeechRecognitionManagerDelegate();
}
+#if defined(OS_TIZEN)
+bool XWalkContentBrowserClient::CanCommitURL(
+ content::RenderProcessHost* process_host, const GURL& url) {
+ application::Application* app = xwalk_runner_->app_system()->
+ application_service()->GetApplicationByRenderHostID(
+ process_host->GetID());
+ DCHECK(app);
+ const application::ApplicationData* app_data =app->data();
+ if (!app_data->HasCSPDefined() ||
+ (url.SchemeIs(application::kApplicationScheme) &&
+ url.host() == app_data->ID()))
+ return true;
+
+ application::NavigationInfo* info = static_cast<application::NavigationInfo*>(
+ app_data->GetManifestData(application_widget_keys::kAllowNavigationKey));
+ if (!info || !url.SchemeIsHTTPOrHTTPS()) {
+ LOG(INFO) << "[Block] Navigation link: " << url.spec();
+ // FIXME: Blocked navigation link should be opened in system web browser,
+ // add corresponding code like this:
+ // platform_util::OpenExternal(url);
+ return false;
+ }
+
+ // Check whether the navigation url domain is listed in WGT <allow-navigation>
+ // element, if yes, display it in web application, otherwise block the
+ // request.
+ const std::vector<std::string>& allowed_list = info->GetAllowedDomains();
+ for (std::vector<std::string>::const_iterator it = allowed_list.begin();
+ it != allowed_list.end(); ++it) {
+ if ((*it).find("*.") == 0 &&
+ url.DomainIs((*it).substr(2).c_str())) {
+ LOG(INFO) << "[Allow] Navigation link: " << url.spec();
+ return true;
+ }
+
+ if (url.host() == *it) {
+ LOG(INFO) << "[Allow] Navigation link: " << url.spec();
+ return true;
+ }
+ }
+ LOG(INFO) << "[Block] navigation link: " << url.spec();
+ // FIXME: Should open blocked link in system web browser, need to add:
+ // platform_util::OpenExternal(url);
+ return false;
+}
+#endif
+
} // namespace xwalk
const net::CookieList& cookie_list,
content::ResourceContext* context,
int render_process_id,
- int render_view_id) OVERRIDE;
+ int render_frame_id) OVERRIDE;
virtual bool AllowSetCookie(const GURL& url,
const GURL& first_party,
const std::string& cookie_line,
content::ResourceContext* context,
int render_process_id,
- int render_view_id,
+ int render_frame_id,
net::CookieOptions* options) OVERRIDE;
+ virtual void AllowCertificateError(
+ int render_process_id,
+ int render_frame_id,
+ int cert_error,
+ const net::SSLInfo& ssl_info,
+ const GURL& request_url,
+ ResourceType::Type resource_type,
+ bool overridable,
+ bool strict_enforcement,
+ const base::Callback<void(bool)>& callback,
+ content::CertificateRequestResultType* result) OVERRIDE;
+
virtual content::SpeechRecognitionManagerDelegate*
GetSpeechRecognitionManagerDelegate() OVERRIDE;
int render_process_id,
int render_view_id,
int notification_id) OVERRIDE;
+#if defined(OS_TIZEN)
+ virtual bool CanCommitURL(
+ content::RenderProcessHost* process_host, const GURL& url) OVERRIDE;
+#endif
#if defined(OS_ANDROID)
- virtual void GetAdditionalMappedFilesForChildProcess(
- const CommandLine& command_line,
- int child_process_id,
- std::vector<content::FileDescriptorInfo>* mappings) OVERRIDE;
virtual void ResourceDispatcherHostCreated();
#endif
XWalkBrowserMainParts* main_parts() { return main_parts_; }
--- /dev/null
+// Copyright (c) 2010 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.
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "xwalk/runtime/common/xwalk_common_message_generator.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#include "xwalk/runtime/common/xwalk_common_message_generator.h" // NOLINT
+
+// Generate destructors.
+#include "ipc/struct_destructor_macros.h"
+#include "xwalk/runtime/common/xwalk_common_message_generator.h" // NOLINT
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "xwalk/runtime/common/xwalk_common_message_generator.h" // NOLINT
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "xwalk/runtime/common/xwalk_common_message_generator.h" // NOLINT
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "xwalk/runtime/common/xwalk_common_message_generator.h" // NOLINT
+} // namespace IPC
--- /dev/null
+// Copyright (c) 2012 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.
+
+// Multiply-included file, hence no include guard.
+
+#include "xwalk/runtime/common/xwalk_common_messages.h"
--- /dev/null
+// Copyright (c) 2012 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 "xwalk/runtime/common/xwalk_common_messages.h"
+
+namespace IPC {
+
+// TODO(upstream): - add enums and custom IPC traits here when needed.
+
+} // namespace IPC
--- /dev/null
+// Copyright (c) 2012 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.
+
+// Multiply-included file, no traditional include guard.
+#include "content/public/common/common_param_traits.h"
+#include "ipc/ipc_channel_handle.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_platform_file.h"
+#include "url/gurl.h"
+
+// Singly-included section for enums and custom IPC traits.
+#ifndef XWALK_RUNTIME_COMMON_XWALK_COMMON_MESSAGES_H_
+#define XWALK_RUNTIME_COMMON_XWALK_COMMON_MESSAGES_H_
+
+namespace IPC {
+
+// TODO(upstream): - add enums and custom IPC traits here when needed.
+
+} // namespace IPC
+
+#endif // XWALK_RUNTIME_COMMON_XWALK_COMMON_MESSAGES_H_
+
+#define IPC_MESSAGE_START ViewMsgStart
+
+//-----------------------------------------------------------------------------
+// RenderView messages
+// These are messages sent from the browser to the renderer process.
+
+IPC_MESSAGE_CONTROL3(ViewMsg_SetAccessWhiteList, // NOLINT
+ GURL /* source */,
+ GURL /* dest */,
+ bool /* allow_subdomains */)
+
+IPC_MESSAGE_CONTROL0(ViewMsg_EnableWarpMode) // NOLINT
cur = cur.Append(FILE_PATH_LITERAL("test"));
cur = cur.Append(FILE_PATH_LITERAL("data"));
break;
+ case xwalk::DIR_WGT_STORAGE_PATH:
+ if (!GetXWalkDataPath(&cur))
+ return false;
+ cur = cur.Append(FILE_PATH_LITERAL("Widget Storage"));
+ break;
default:
return false;
}
DIR_DATA_PATH = PATH_START, // Directory where the cache and local storage
// data resides.
DIR_TEST_DATA, // Directory where unit test data resides.
+ DIR_WGT_STORAGE_PATH, // Directory where widget storage data resides.
PATH_END
};
#include "xwalk/runtime/renderer/xwalk_content_renderer_client.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/visitedlink/renderer/visitedlink_slave.h"
#include "content/public/renderer/render_thread.h"
+#include "grit/xwalk_application_resources.h"
#include "grit/xwalk_sysapps_resources.h"
#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
#include "xwalk/application/common/constants.h"
#include "xwalk/application/renderer/application_native_module.h"
#include "xwalk/runtime/renderer/android/xwalk_permission_client.h"
#include "xwalk/runtime/renderer/android/xwalk_render_process_observer.h"
#include "xwalk/runtime/renderer/android/xwalk_render_view_ext.h"
+#else
+#include "third_party/WebKit/public/web/WebFrame.h"
#endif
#if defined(OS_TIZEN_MOBILE)
blink::WebSecurityPolicy::registerURLSchemeAsSecure(application_scheme);
blink::WebSecurityPolicy::registerURLSchemeAsCORSEnabled(application_scheme);
-#if defined(OS_ANDROID)
content::RenderThread* thread = content::RenderThread::Get();
xwalk_render_process_observer_.reset(new XWalkRenderProcessObserver);
thread->AddObserver(xwalk_render_process_observer_.get());
+#if defined(OS_ANDROID)
+ visited_link_slave_.reset(new visitedlink::VisitedLinkSlave);
+ thread->AddObserver(visited_link_slave_.get());
#endif
}
blink::WebFrame* frame, v8::Handle<v8::Context> context,
int extension_group, int world_id) {
extension_controller_->DidCreateScriptContext(frame, context);
+#if !defined(OS_ANDROID)
+ xwalk_render_process_observer_->DidCreateScriptContext(
+ frame, context, extension_group, world_id);
+#endif
}
void XWalkContentRendererClient::WillReleaseScriptContext(
module_system->RegisterNativeModule("sysapps_promise",
extensions::CreateJSModuleFromResource(
IDR_XWALK_SYSAPPS_COMMON_PROMISE_API));
+ module_system->RegisterNativeModule("widget_common",
+ extensions::CreateJSModuleFromResource(
+ IDR_XWALK_APPLICATION_WIDGET_COMMON_API));
+}
+
+#if defined(OS_ANDROID)
+unsigned long long XWalkContentRendererClient::VisitedLinkHash(
+ const char* canonical_url, size_t length) {
+ return visited_link_slave_->ComputeURLFingerprint(canonical_url, length);
}
+bool XWalkContentRendererClient::IsLinkVisited(unsigned long long link_hash) {
+ return visited_link_slave_->IsVisited(link_hash);
+}
+#endif
+
+bool XWalkContentRendererClient::WillSendRequest(blink::WebFrame* frame,
+ content::PageTransition transition_type,
+ const GURL& url,
+ const GURL& first_party_for_cookies,
+ GURL* new_url) {
+#if defined(OS_ANDROID)
+ return false;
+#else
+ if (!xwalk_render_process_observer_->IsWarpMode())
+ return false;
+ GURL origin_url(frame->document().url());
+ if (origin_url.spec().empty() ||
+ frame->document().securityOrigin().canRequest(url)) {
+ LOG(INFO) << "[PASS] " << origin_url.spec() << " request " << url.spec();
+ return false;
+ }
+
+ LOG(INFO) << "[BLOCK] " << origin_url.spec() << " request " << url.spec();
+ *new_url = GURL();
+ return true;
+#endif
+}
} // namespace xwalk
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/platform_file.h"
+#include "content/public/common/page_transition_types.h"
#include "content/public/renderer/content_renderer_client.h"
#include "xwalk/extensions/renderer/xwalk_extension_renderer_controller.h"
+#if defined(OS_ANDROID)
+#include "xwalk/runtime/renderer/android/xwalk_render_process_observer.h"
+#else
+#include "xwalk/runtime/renderer/xwalk_render_process_observer_generic.h"
+#endif
+
+namespace visitedlink {
+class VisitedLinkSlave;
+}
namespace xwalk {
virtual void WillReleaseScriptContext(blink::WebFrame* frame,
v8::Handle<v8::Context>,
int world_id) OVERRIDE;
+#if defined(OS_ANDROID)
+ virtual unsigned long long VisitedLinkHash(const char* canonical_url,
+ size_t length) OVERRIDE;
+ virtual bool IsLinkVisited(unsigned long long link_hash) OVERRIDE;
+#endif
+
+ virtual bool WillSendRequest(blink::WebFrame* frame,
+ content::PageTransition transition_type,
+ const GURL& url,
+ const GURL& first_party_for_cookies,
+ GURL* new_url) OVERRIDE;
private:
// XWalkExtensionRendererController::Delegate implementation.
scoped_ptr<extensions::XWalkExtensionRendererController>
extension_controller_;
-#if defined(OS_ANDROID)
scoped_ptr<XWalkRenderProcessObserver> xwalk_render_process_observer_;
+#if defined(OS_ANDROID)
+ scoped_ptr<visitedlink::VisitedLinkSlave> visited_link_slave_;
#endif
DISALLOW_COPY_AND_ASSIGN(XWalkContentRendererClient);
--- /dev/null
+// Copyright (c) 2012 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 "xwalk/runtime/renderer/xwalk_render_process_observer_generic.h"
+
+#include <vector>
+
+#include "ipc/ipc_message_macros.h"
+#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "xwalk/runtime/common/xwalk_common_messages.h"
+
+
+namespace xwalk {
+namespace {
+struct AccessWhitelistItem {
+ AccessWhitelistItem(
+ const GURL& source, const GURL& dest, bool allow_subdomains);
+ GURL source_;
+ GURL dest_;
+ bool allow_subdomains_;
+};
+
+AccessWhitelistItem::AccessWhitelistItem(
+ const GURL& source, const GURL& dest, bool allow_subdomains)
+ : source_(source),
+ dest_(dest),
+ allow_subdomains_(allow_subdomains) {
+}
+
+std::vector<AccessWhitelistItem> access_whitelist;
+
+void AddAccessWhiteListEntry(
+ const GURL& source, const GURL& dest, bool allow_subdomains) {
+ blink::WebSecurityPolicy::addOriginAccessWhitelistEntry(
+ source.GetOrigin(),
+ blink::WebString::fromUTF8(dest.scheme()),
+ blink::WebString::fromUTF8(dest.HostNoBrackets()),
+ allow_subdomains);
+}
+} // namespace
+
+XWalkRenderProcessObserver::XWalkRenderProcessObserver()
+ : is_webkit_initialized_(false),
+ is_warp_mode_(false) {
+}
+
+XWalkRenderProcessObserver::~XWalkRenderProcessObserver() {
+}
+
+bool XWalkRenderProcessObserver::OnControlMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(XWalkRenderProcessObserver, message)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetAccessWhiteList, OnSetAccessWhiteList)
+ IPC_MESSAGE_HANDLER(ViewMsg_EnableWarpMode, OnEnableWarpMode)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void XWalkRenderProcessObserver::WebKitInitialized() {
+ is_webkit_initialized_ = true;
+}
+
+void XWalkRenderProcessObserver::OnRenderProcessShutdown() {
+ is_webkit_initialized_ = false;
+}
+
+void XWalkRenderProcessObserver::DidCreateScriptContext(
+ blink::WebFrame* frame, v8::Handle<v8::Context> context,
+ int extension_group, int world_id) {
+ for (std::vector<AccessWhitelistItem>::iterator it = access_whitelist.begin();
+ it != access_whitelist.end(); ++it)
+ AddAccessWhiteListEntry(it->source_, it->dest_, it->allow_subdomains_);
+
+ access_whitelist.clear();
+}
+
+void XWalkRenderProcessObserver::OnSetAccessWhiteList(const GURL& source,
+ const GURL& dest,
+ bool allow_subdomains) {
+ if (is_webkit_initialized_)
+ AddAccessWhiteListEntry(source, dest, allow_subdomains);
+ else
+ access_whitelist.push_back(
+ AccessWhitelistItem(source, dest, allow_subdomains));
+}
+
+void XWalkRenderProcessObserver::OnEnableWarpMode() {
+ is_warp_mode_ = true;
+}
+
+} // namespace xwalk
--- /dev/null
+// Copyright (c) 2012 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 XWALK_RUNTIME_RENDERER_XWALK_RENDER_PROCESS_OBSERVER_GENERIC_H_
+#define XWALK_RUNTIME_RENDERER_XWALK_RENDER_PROCESS_OBSERVER_GENERIC_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "content/public/renderer/render_process_observer.h"
+#include "url/gurl.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+class WebFrame;
+} // namespace blink
+
+namespace xwalk {
+
+// FIXME: Using filename "xwalk_render_process_observer_generic.cc(h)" temporary
+// , due to the conflict filename with Android port.
+// A RenderViewObserver implementation used for handling XWalkView
+// specific render-process wide IPC messages.
+class XWalkRenderProcessObserver : public content::RenderProcessObserver {
+ public:
+ XWalkRenderProcessObserver();
+ virtual ~XWalkRenderProcessObserver();
+
+ void DidCreateScriptContext(
+ blink::WebFrame* frame, v8::Handle<v8::Context> context,
+ int extension_group, int world_id);
+
+ // content::RenderProcessObserver implementation.
+ virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE;
+ virtual void WebKitInitialized() OVERRIDE;
+ virtual void OnRenderProcessShutdown() OVERRIDE;
+
+ bool IsWarpMode() const { return is_warp_mode_; }
+
+ private:
+ void OnSetAccessWhiteList(
+ const GURL& source, const GURL& dest, bool allow_subdomains);
+ void OnEnableWarpMode();
+
+ bool is_webkit_initialized_;
+ bool is_warp_mode_;
+};
+} // namespace xwalk
+
+#endif // XWALK_RUNTIME_RENDERER_XWALK_RENDER_PROCESS_OBSERVER_GENERIC_H_
dictionary DisplayUnit {
DOMString id;
DOMString name;
- boolean isPrimary;
- boolean isInternal;
- long dpiX;
- long dpiY;
+ boolean primary;
+ boolean external;
+ long deviceXDPI;
+ long deviceYDPI;
long width;
long height;
long availWidth;
long availHeight;
+ long colorDepth;
+ long pixelDepth;
};
dictionary SystemDisplay {
if (typeof info.displays[i].name != "string")
reportFail("Display name is not a string.");
- if (typeof info.displays[i].isPrimary != "boolean")
+ if (typeof info.displays[i].primary != "boolean")
reportFail("Display type is not a boolean.");
- if (typeof info.displays[i].isInternal != "boolean")
+ if (typeof info.displays[i].external != "boolean")
reportFail("Display type is not a boolean.");
- if (typeof info.displays[i].dpiX != "number")
- reportFail("Display dpiX must be a number.");
+ if (typeof info.displays[i].deviceXDPI != "number")
+ reportFail("Display deviceXDPI must be a number.");
- if (typeof info.displays[i].dpiY != "number")
- reportFail("Display dpiY must be a number.");
+ if (typeof info.displays[i].deviceYDPI != "number")
+ reportFail("Display deviceYDPI must be a number.");
if (typeof info.displays[i].width != "number")
reportFail("Display width must be a number.");
if (typeof info.displays[i].availHeight != "number")
reportFail("Display availHeight must be a number.");
+
+ if (typeof info.displays[i].colorDepth != "number")
+ reportFail("Display colorDepth must be a number.");
+
+ if (typeof info.displays[i].pixelDepth != "number")
+ reportFail("Display pixelDepth must be a number.");
}
if (document.title != "Fail")
// FIXME(YuZhiqiangX): find which field reflects 'name'.
display_unit->name = "unknown";
- display_unit->is_primary = (display.id() == primary_display_id);
- display_unit->is_internal = display.IsInternal();
+ display_unit->primary = (display.id() == primary_display_id);
+ display_unit->external = !display.IsInternal();
const float dpi = display.device_scale_factor() * kDpi96;
- display_unit->dpi_x = static_cast<unsigned int>(dpi);
- display_unit->dpi_y = static_cast<unsigned int>(dpi);
+ display_unit->device_xdpi = static_cast<unsigned int>(dpi);
+ display_unit->device_ydpi = static_cast<unsigned int>(dpi);
display_unit->width = display.bounds().width();
display_unit->height = display.bounds().height();
display_unit->avail_width = display.work_area_size().width();
display_unit->avail_height = display.work_area_size().height();
+ // colorDepth and pixelDepth are constantly set as 24 refer to
+ // http://www.w3.org/TR/cssom-view/#dom-screen-colordepth
+ display_unit->color_depth = 24;
+ display_unit->pixel_depth = 24;
+
return display_unit;
}
ReadyState readyState;
};
+ // Events and functions are defined at
+ // udp_socket.idl
+ dictionary UDPSocket {
+ DOMString localAddress;
+ long localPort;
+ DOMString remoteAddress;
+ long remotePort;
+ boolean addressReuse;
+ boolean loopback;
+ long bufferedAmount;
+ ReadyState readyState;
+ };
+
interface Functions {
[nodoc] static TCPSocket TCPSocketConstructor(DOMString objectId);
[nodoc] static TCPServerSocket TCPServerSocketConstructor(DOMString objectId);
+ [nodoc] static UDPSocket UDPSocketConstructor(DOMString objectId);
};
};
TCPServerSocket.prototype = new common.EventTargetPrototype();
TCPServerSocket.prototype.constructor = TCPServerSocket;
+// UDPSocket interface.
+//
+// TODO(tmpsantos): We are currently not throwing any exceptions
+// neither validating the input parameters.
+//
+var UDPSocket = function(options) {
+ common.BindingObject.call(this, common.getUniqueId());
+ common.EventTarget.call(this);
+
+ internal.postMessage("UDPSocketConstructor", [this._id]);
+
+ var options = options || {};
+
+ if (!options.localAddress)
+ options.localAddress = "";
+ if (!options.localPort)
+ options.localPort = 0;
+ if (!options.remoteAddress)
+ options.remoteAddress = "";
+ if (!options.remotePort)
+ options.remotePort = 0;
+ if (!options.addressReuse)
+ options.addressReuse = true;
+ if (!options.loopback)
+ options.loopback = false;
+
+ this._addMethod("_close");
+ this._addMethod("suspend");
+ this._addMethod("resume");
+ this._addMethod("joinMulticast");
+ this._addMethod("leaveMulticast");
+ this._addMethod("_sendString");
+
+ function MessageEvent(type, data) {
+ this.type = type;
+ this.data = data.data;
+ this.remotePort = data.remotePort;
+ this.remoteAddress = data.remoteAddress;
+ }
+
+ this._addEvent("open");
+ this._addEvent("drain");
+ this._addEvent("error");
+ this._addEvent("message", MessageEvent);
+
+ function sendWrapper(data, remoteAddress, remotePort) {
+ this._sendString(data, remoteAddress, remotePort);
+
+ // FIXME(tmpsantos): The spec says that send() should always
+ // return if you can keep sending data. This can only be
+ // verified in the native implementation, which makes this
+ // call sync. We are returning always true here to keep the
+ // implementation async.
+ return true;
+ };
+
+ function closeWrapper(data) {
+ if (this._readyStateObserver.readyState == "closed")
+ return;
+
+ this._readyStateObserver.readyState = "closing";
+ this._close();
+ };
+
+ Object.defineProperties(this, {
+ "_readyStateObserver": {
+ value: new ReadyStateObserver(this._id, "opening"),
+ },
+ "_readyStateObserverDeleter": {
+ value: v8tools.lifecycleTracker(),
+ },
+ "send": {
+ value: sendWrapper,
+ enumerable: true,
+ },
+ "close": {
+ value: closeWrapper,
+ enumerable: true,
+ },
+ "remoteAddress": {
+ value: options.remoteAddress,
+ enumerable: true,
+ },
+ "remotePort": {
+ value: options.remotePort,
+ enumerable: true,
+ },
+ "localAddress": {
+ value: options.localAddress,
+ enumerable: true,
+ },
+ "localPort": {
+ value: options.localPort,
+ enumerable: true,
+ },
+ "addressReuse": {
+ value: options.addressReuse,
+ enumerable: true,
+ },
+ "loopback": {
+ value: options.loopback,
+ enumerable: true,
+ },
+ "bufferedAmount": {
+ value: 0,
+ enumerable: true,
+ },
+ "readyState": {
+ get: function() { return this._readyStateObserver.readyState; },
+ enumerable: true,
+ },
+ });
+
+ var watcher = this._readyStateObserver;
+ this._readyStateObserverDeleter.destructor = function() {
+ watcher.destructor();
+ };
+
+ // This is needed, otherwise events like "error" can get fired before
+ // we give the user a chance to register a listener.
+ function delayedInitialization(obj) {
+ obj._postMessage("init", [options]);
+ };
+
+ this._registerLifecycleTracker();
+ setTimeout(delayedInitialization, 0, this);
+};
+
+UDPSocket.prototype = new common.EventTargetPrototype();
+UDPSocket.prototype.constructor = UDPSocket;
+
// Exported API.
exports.TCPSocket = TCPSocket;
exports.TCPServerSocket = TCPServerSocket;
+exports.UDPSocket = UDPSocket;
var current_test = 0;
var test_list = [
memoryManagement,
- pingPong,
- serverPortBusy,
+ pingPongTCP,
+ pingPongUDP,
+ serverPortBusyTCP,
+ serverPortBusyUDP,
endTest
];
// initialization is completed, the object will be collected if no
// variable is keeping a reference to it.
function runGCandCheck() {
+ // The GC is called here more than once to make sure
+ // all the dangling objects get collected. Calling the GC
+ // one time does not give a guarantee that everything that
+ // can be collected will be collected.
gc();
- if (garbageCollectionCount != 2)
- reportFail("TCPSocket or TCPServerSocket is leaking.");
+ gc();
+ gc();
+
+ if (garbageCollectionCount != 3)
+ reportFail("TCPSocket, TCPServerSocket or UDPSocket is leaking.");
else
runNextTest();
};
server.onopen = null;
server = null;
- if (++eventCount == 2)
+ if (++eventCount == 3)
setTimeout(runGCandCheck, 0);
};
client.onopen = null;
client = null;
- if (++eventCount == 2)
+ if (++eventCount == 3)
+ setTimeout(runGCandCheck, 0);
+ };
+
+ var udp = new api.UDPSocket({localAddress: "127.0.0.1", localPort: 7000});
+ udp.onerror = udp.onopen = nullifyUDP;
+ udp.tracker = v8tools.lifecycleTracker();
+ udp.tracker.destructor = function() {
+ garbageCollectionCount++;
+ };
+
+ function nullifyUDP() {
+ udp.onerror = null;
+ udp.onopen = null;
+ udp = null;
+
+ if (++eventCount == 3)
setTimeout(runGCandCheck, 0);
};
};
//
// This is not an API conformance test, it just verifies if the basic
// functionality works. W3C should provide the former.
- function pingPong(serverPort) {
+ function pingPongTCP(serverPort) {
serverPort = serverPort || 5000;
var serverPortMax = 5020;
var testData = "Hello World!";
// The default port might be busy, so we try different ports
// before reporting failure.
if (serverPort < serverPortMax)
- pingPong(++serverPort);
+ pingPongTCP(++serverPort);
else
reportFail("Not able to listen at port " + serverPort + ".");
};
};
};
- function serverPortBusy(serverPort) {
+ function pingPongUDP(serverPort) {
+ serverPort = serverPort || 6000;
+ var serverPortMax = 6020;
+ var testData = "Hello World!";
+
+ var server = new api.UDPSocket(
+ {"localAddress": "127.0.0.1", "localPort": serverPort});
+
+ server.onerror = function() {
+ // The default port might be busy, so we try different ports
+ // before reporting failure.
+ if (serverPort < serverPortMax)
+ pingPongUDP(++serverPort);
+ else
+ reportFail("Not able to listen at port " + serverPort + ".");
+ };
+
+ server.onopen = function() {
+ var client = new api.UDPSocket(
+ {remoteAddress: "127.0.0.1", remotePort: serverPort});
+ client.onopen = function() {
+ client.send(testData);
+ };
+
+ client.onerror = function() {
+ reportFail("Not able to connect to port " + serverPort + ".");
+ };
+
+ client.onmessage = function(event) {
+ var view = new Uint8Array(event.data);
+ var data = String.fromCharCode.apply(null, view);
+
+ if (data != testData)
+ reportFail("Invalid data received by the client socket.");
+ else
+ runNextTest();
+ };
+ };
+
+ server.onmessage = function(event) {
+ var view = new Uint8Array(event.data);
+ var data = String.fromCharCode.apply(null, view);
+
+ if (data != testData)
+ reportFail("Invalid data received by server socket.");
+ else
+ server.send(data, event.remoteAddress, event.remotePort);
+ };
+ };
+
+ function serverPortBusy(Socket, serverPort) {
serverPort = serverPort || 7000;
var serverPortMax = 7020;
- var server = new api.TCPServerSocket(
+ var server = new Socket(
{"localAddress": "127.0.0.1", "localPort": serverPort});
server.onerror = function() {
if (serverPort < serverPortMax)
- serverPortBusy(++serverPort);
+ serverPortBusy(Socket, ++serverPort);
else
reportFail("Not able to listen at port " + serverPort + ".");
};
server.onopen = function() {
- var serverShouldFail = new api.TCPServerSocket(
+ var serverShouldFail = new Socket(
{"localAddress": "127.0.0.1", "localPort": serverPort});
// Should fail, port already in use by another server.
};
};
+ function serverPortBusyTCP() {
+ serverPortBusy(api.TCPServerSocket);
+ };
+
+ function serverPortBusyUDP() {
+ serverPortBusy(api.UDPSocket);
+ };
+
runNextTest();
</script>
</body>
#include "xwalk/sysapps/raw_socket/raw_socket.h"
#include "xwalk/sysapps/raw_socket/tcp_server_socket_object.h"
#include "xwalk/sysapps/raw_socket/tcp_socket_object.h"
+#include "xwalk/sysapps/raw_socket/udp_socket_object.h"
using namespace xwalk::jsapi::raw_socket; // NOLINT
handler_.Register("TCPSocketConstructor",
base::Bind(&RawSocketInstance::OnTCPSocketConstructor,
base::Unretained(this)));
+ handler_.Register("UDPSocketConstructor",
+ base::Bind(&RawSocketInstance::OnUDPSocketConstructor,
+ base::Unretained(this)));
}
void RawSocketInstance::HandleMessage(scoped_ptr<base::Value> msg) {
store_.AddBindingObject(params->object_id, obj.Pass());
}
+void RawSocketInstance::OnUDPSocketConstructor(
+ scoped_ptr<XWalkExtensionFunctionInfo> info) {
+ scoped_ptr<UDPSocketConstructor::Params>
+ params(UDPSocketConstructor::Params::Create(*info->arguments()));
+
+ if (!params) {
+ LOG(WARNING) << "Malformed parameters passed to " << info->name();
+ return;
+ }
+
+ scoped_ptr<BindingObject> obj(new UDPSocketObject);
+ store_.AddBindingObject(params->object_id, obj.Pass());
+}
+
} // namespace sysapps
} // namespace xwalk
void OnTCPServerSocketConstructor(
scoped_ptr<XWalkExtensionFunctionInfo> info);
void OnTCPSocketConstructor(scoped_ptr<XWalkExtensionFunctionInfo> info);
+ void OnUDPSocketConstructor(scoped_ptr<XWalkExtensionFunctionInfo> info);
XWalkExtensionFunctionHandler handler_;
BindingObjectStore store_;
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// RawSocket API - UDPSocket
+namespace udp_socket {
+ dictionary UDPMessageEvent {
+ ArrayBuffer data;
+ DOMString remoteAddress;
+ long remotePort;
+ };
+
+ dictionary UDPOptions {
+ DOMString localAddress;
+ long localPort;
+ DOMString remoteAddress;
+ long remotePort;
+ boolean addressReuse;
+ boolean loopback;
+ };
+
+ interface Events {
+ static void ondrain();
+ static void onopen();
+ static void onerror();
+ static void onmessage();
+ };
+
+ interface Functions {
+ static void close();
+ static void suspend();
+ static void resume();
+ static void joinMulticast(DOMString multicastGroupAddress);
+ static void leaveMulticast(DOMString multicastGroupAddress);
+
+ [nocompile] static boolean send(object data, optional DOMString remoteAddress,
+ optional long remotePort);
+
+ // send() can take up to four different types of arguments. We try to
+ // detect what kind of argument we have and route to a more specialized
+ // handler.
+
+ [nodoc] static boolean sendDOMString(DOMString data,
+ optional DOMString remoteAddress, optional long remotePort);
+
+ [nodoc] static void init(optional UDPOptions options);
+ [nodoc] static void destroy();
+ };
+};
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/sysapps/raw_socket/udp_socket_object.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+#include "net/base/net_errors.h"
+#include "xwalk/sysapps/raw_socket/udp_socket.h"
+
+using namespace xwalk::jsapi::udp_socket; // NOLINT
+using namespace xwalk::jsapi::raw_socket; // NOLINT
+
+namespace {
+
+const unsigned kBufferSize = 4096;
+
+} // namespace
+
+namespace xwalk {
+namespace sysapps {
+
+UDPSocketObject::UDPSocketObject()
+ : has_write_pending_(false),
+ is_suspended_(false),
+ is_reading_(false),
+ resolver_(net::HostResolver::CreateDefaultResolver(NULL)),
+ read_buffer_(new net::IOBuffer(kBufferSize)),
+ write_buffer_(new net::IOBuffer(kBufferSize)),
+ single_resolver_(new net::SingleRequestHostResolver(resolver_.get())) {
+ handler_.Register("init",
+ base::Bind(&UDPSocketObject::OnInit, base::Unretained(this)));
+ handler_.Register("_close",
+ base::Bind(&UDPSocketObject::OnClose, base::Unretained(this)));
+ handler_.Register("suspend",
+ base::Bind(&UDPSocketObject::OnSuspend, base::Unretained(this)));
+ handler_.Register("resume",
+ base::Bind(&UDPSocketObject::OnResume, base::Unretained(this)));
+ handler_.Register("joinMulticast",
+ base::Bind(&UDPSocketObject::OnJoinMulticast, base::Unretained(this)));
+ handler_.Register("leaveMulticast",
+ base::Bind(&UDPSocketObject::OnLeaveMulticast, base::Unretained(this)));
+ handler_.Register("_sendString",
+ base::Bind(&UDPSocketObject::OnSendString, base::Unretained(this)));
+}
+
+UDPSocketObject::~UDPSocketObject() {}
+
+void UDPSocketObject::DoRead() {
+ if (!socket_->is_connected())
+ return;
+
+ is_reading_ = true;
+
+ int ret = socket_->RecvFrom(read_buffer_,
+ kBufferSize,
+ &from_,
+ base::Bind(&UDPSocketObject::OnRead,
+ base::Unretained(this)));
+
+ if (ret > 0)
+ OnRead(ret);
+}
+
+void UDPSocketObject::OnInit(scoped_ptr<XWalkExtensionFunctionInfo> info) {
+ scoped_ptr<Init::Params> params(Init::Params::Create(*info->arguments()));
+ if (!params) {
+ LOG(WARNING) << "Malformed parameters passed to " << info->name();
+ setReadyState(READY_STATE_CLOSED);
+ DispatchEvent("error");
+ return;
+ }
+
+ socket_.reset(new net::UDPSocket(net::DatagramSocket::DEFAULT_BIND,
+ net::RandIntCallback(),
+ NULL,
+ net::NetLog::Source()));
+
+ if (!params->options) {
+ OnConnectionOpen(net::OK);
+ return;
+ }
+
+ if (!params->options->local_address.empty()) {
+ net::IPAddressNumber ip_number;
+ if (!net::ParseIPLiteralToNumber(params->options->local_address,
+ &ip_number)) {
+ LOG(WARNING) << "Invalid IP address " << params->options->local_address;
+ setReadyState(READY_STATE_CLOSED);
+ DispatchEvent("error");
+ return;
+ }
+
+ if (params->options->address_reuse)
+ socket_->AllowAddressReuse();
+
+ net::IPEndPoint end_point(ip_number, params->options->local_port);
+ if (socket_->Bind(end_point) != net::OK) {
+ LOG(WARNING) << "Can't bind to " << end_point.ToString();
+ setReadyState(READY_STATE_CLOSED);
+ DispatchEvent("error");
+ return;
+ }
+
+ DoRead();
+ OnConnectionOpen(net::OK);
+ return;
+ }
+
+ if (params->options->remote_address.empty() ||
+ !params->options->remote_port) {
+ OnConnectionOpen(net::OK);
+ return;
+ }
+
+ net::HostResolver::RequestInfo request_info(net::HostPortPair(
+ params->options->remote_address, params->options->remote_port));
+
+ int ret = single_resolver_->Resolve(
+ request_info,
+ net::DEFAULT_PRIORITY,
+ &addresses_,
+ base::Bind(&UDPSocketObject::OnConnectionOpen,
+ base::Unretained(this)),
+ net::BoundNetLog());
+
+ if (ret != net::ERR_IO_PENDING)
+ OnConnectionOpen(ret);
+}
+
+void UDPSocketObject::OnClose(scoped_ptr<XWalkExtensionFunctionInfo> info) {
+ socket_.reset();
+}
+
+void UDPSocketObject::OnSuspend(scoped_ptr<XWalkExtensionFunctionInfo> info) {
+ is_suspended_ = true;
+}
+
+void UDPSocketObject::OnResume(scoped_ptr<XWalkExtensionFunctionInfo> info) {
+ is_suspended_ = false;
+}
+
+void UDPSocketObject::OnJoinMulticast(
+ scoped_ptr<XWalkExtensionFunctionInfo> info) {
+}
+
+void UDPSocketObject::OnLeaveMulticast(
+ scoped_ptr<XWalkExtensionFunctionInfo> info) {
+}
+
+void UDPSocketObject::OnSendString(
+ scoped_ptr<XWalkExtensionFunctionInfo> info) {
+ if (!socket_ || has_write_pending_)
+ return;
+
+ scoped_ptr<SendDOMString::Params>
+ params(SendDOMString::Params::Create(*info->arguments()));
+ if (!params) {
+ LOG(WARNING) << "Malformed parameters passed to " << info->name();
+ return;
+ }
+
+ if (params->data.size() > kBufferSize) {
+ LOG(WARNING) << "Write data bigger than the write buffer.";
+ return;
+ }
+
+ write_buffer_size_ = params->data.size();
+ memcpy(write_buffer_->data(), params->data.data(), write_buffer_size_);
+
+ if (!params->remote_address || !*params->remote_port) {
+ OnSend(net::OK);
+ return;
+ }
+
+ net::HostResolver::RequestInfo request_info(net::HostPortPair(
+ *params->remote_address, *params->remote_port));
+
+ int ret = single_resolver_->Resolve(
+ request_info,
+ net::DEFAULT_PRIORITY,
+ &addresses_,
+ base::Bind(&UDPSocketObject::OnSend,
+ base::Unretained(this)),
+ net::BoundNetLog());
+
+ if (ret != net::ERR_IO_PENDING)
+ OnSend(ret);
+ else
+ has_write_pending_ = true;
+}
+
+void UDPSocketObject::OnRead(int status) {
+ // No data means the other side has
+ // disconnected the socket.
+ if (status == 0) {
+ setReadyState(READY_STATE_CLOSED);
+ DispatchEvent("close");
+ return;
+ }
+
+ scoped_ptr<base::Value> data(base::BinaryValue::CreateWithCopiedBuffer(
+ static_cast<char*>(read_buffer_->data()), status));
+
+ UDPMessageEvent event;
+ event.data = std::string(read_buffer_->data(), status);
+ event.remote_port = from_.port();
+ event.remote_address = from_.ToStringWithoutPort();
+
+ scoped_ptr<base::ListValue> eventData(new base::ListValue);
+ eventData->Append(event.ToValue().release());
+
+ if (!is_suspended_)
+ DispatchEvent("message", eventData.Pass());
+
+ DoRead();
+}
+
+void UDPSocketObject::OnWrite(int status) {
+ has_write_pending_ = false;
+ DispatchEvent("drain");
+}
+
+void UDPSocketObject::OnConnectionOpen(int status) {
+ if (status != net::OK) {
+ setReadyState(READY_STATE_CLOSED);
+ DispatchEvent("error");
+ return;
+ }
+
+ setReadyState(READY_STATE_OPEN);
+ DispatchEvent("open");
+}
+
+void UDPSocketObject::OnSend(int status) {
+ if (status != net::OK || addresses_.empty()) {
+ setReadyState(READY_STATE_CLOSED);
+ DispatchEvent("error");
+ return;
+ }
+
+ if (!socket_->is_connected()) {
+ // If we are waiting for reads and the socket is not connect,
+ // it means the connection was closed.
+ if (is_reading_ || socket_->Connect(addresses_[0]) != net::OK) {
+ setReadyState(READY_STATE_CLOSED);
+ DispatchEvent("error");
+ return;
+ }
+ }
+
+ int ret = socket_->SendTo(
+ write_buffer_,
+ write_buffer_size_,
+ addresses_[0],
+ base::Bind(&UDPSocketObject::OnWrite, base::Unretained(this)));
+
+ if (ret == net::ERR_IO_PENDING) {
+ has_write_pending_ = true;
+ } else if (ret == write_buffer_size_) {
+ has_write_pending_ = false;
+ } else {
+ socket_->Close();
+ setReadyState(READY_STATE_CLOSED);
+ DispatchEvent("close");
+ return;
+ }
+
+ if (!is_reading_ && socket_->is_connected())
+ DoRead();
+}
+
+} // namespace sysapps
+} // namespace xwalk
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XWALK_SYSAPPS_RAW_SOCKET_UDP_SOCKET_OBJECT_H_
+#define XWALK_SYSAPPS_RAW_SOCKET_UDP_SOCKET_OBJECT_H_
+
+#include <string>
+
+#include "net/base/address_list.h"
+#include "net/base/io_buffer.h"
+#include "net/dns/single_request_host_resolver.h"
+#include "net/udp/udp_socket.h"
+#include "xwalk/sysapps/raw_socket/raw_socket_object.h"
+
+namespace xwalk {
+namespace sysapps {
+
+class UDPSocketObject : public RawSocketObject {
+ public:
+ UDPSocketObject();
+ virtual ~UDPSocketObject();
+
+ private:
+ void DoRead();
+
+ // JavaScript function handlers.
+ void OnInit(scoped_ptr<XWalkExtensionFunctionInfo> info);
+ void OnClose(scoped_ptr<XWalkExtensionFunctionInfo> info);
+ void OnSuspend(scoped_ptr<XWalkExtensionFunctionInfo> info);
+ void OnResume(scoped_ptr<XWalkExtensionFunctionInfo> info);
+ void OnJoinMulticast(scoped_ptr<XWalkExtensionFunctionInfo> info);
+ void OnLeaveMulticast(scoped_ptr<XWalkExtensionFunctionInfo> info);
+ void OnSendString(scoped_ptr<XWalkExtensionFunctionInfo> info);
+
+ // net::UDPSocket callbacks.
+ void OnRead(int status);
+ void OnWrite(int status);
+
+ // net::SingleRequestHostResolver callbacks.
+ void OnConnectionOpen(int status);
+ void OnSend(int status);
+
+ bool has_write_pending_;
+ bool is_suspended_;
+ bool is_reading_;
+
+ scoped_refptr<net::IOBuffer> read_buffer_;
+ scoped_refptr<net::IOBuffer> write_buffer_;
+ scoped_ptr<net::UDPSocket> socket_;
+
+ unsigned write_buffer_size_;
+
+ scoped_ptr<net::HostResolver> resolver_;
+ scoped_ptr<net::SingleRequestHostResolver> single_resolver_;
+ net::AddressList addresses_;
+ net::IPEndPoint from_;
+};
+
+} // namespace sysapps
+} // namespace xwalk
+
+#endif // XWALK_SYSAPPS_RAW_SOCKET_UDP_SOCKET_OBJECT_H_
'raw_socket/tcp_socket.idl',
'raw_socket/tcp_socket_object.cc',
'raw_socket/tcp_socket_object.h',
+ 'raw_socket/udp_socket.idl',
+ 'raw_socket/udp_socket_object.cc',
+ 'raw_socket/udp_socket_object.h',
],
'conditions': [
['OS!="android"', {
import org.xwalk.core.JsPromptResult;
import org.xwalk.core.JsResult;
-import org.xwalk.core.SslErrorHandler;
import org.xwalk.core.XWalkContentsClient;
import org.xwalk.core.XWalkGeolocationPermissions;
import org.xwalk.core.XWalkHttpAuthHandler;
}
@Override
- public void onReceivedSslError(SslErrorHandler handler, SslError error) {
+ public void onReceivedSslError(ValueCallback<Boolean> callback, SslError error) {
}
@Override
'../base/base.gyp:base',
'../base/base.gyp:base_i18n',
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../components/components.gyp:visitedlink_browser',
+ '../components/components.gyp:visitedlink_renderer',
'../content/content.gyp:content',
'../content/content.gyp:content_app_both',
'../content/content.gyp:content_browser',
'runtime/common/android/xwalk_render_view_messages.h',
'runtime/common/paths_mac.h',
'runtime/common/paths_mac.mm',
+ 'runtime/common/xwalk_common_messages.cc',
+ 'runtime/common/xwalk_common_messages.h',
+ 'runtime/common/xwalk_common_message_generator.cc',
+ 'runtime/common/xwalk_common_message_generator.h',
'runtime/common/xwalk_content_client.cc',
'runtime/common/xwalk_content_client.h',
'runtime/common/xwalk_paths.cc',
'runtime/renderer/tizen/xwalk_content_renderer_client_tizen.h',
'runtime/renderer/xwalk_content_renderer_client.cc',
'runtime/renderer/xwalk_content_renderer_client.h',
+ 'runtime/renderer/xwalk_render_process_observer_generic.cc',
+ 'runtime/renderer/xwalk_render_process_observer_generic.h',
],
'includes': [
'xwalk_jsapi.gypi',
'xwalk_core_jar_jni',
'xwalk_core_native_jni',
],
+ 'sources!':[
+ 'runtime/renderer/xwalk_render_process_observer_generic.cc',
+ 'runtime/renderer/xwalk_render_process_observer_generic.h',
+ ],
}],
['OS=="win" and win_use_allocator_shim==1', {
'dependencies': [
'application/common/manifest_handlers/main_document_handler_unittest.cc',
'application/common/manifest_handlers/permissions_handler_unittest.cc',
'application/common/manifest_handlers/warp_handler_unittest.cc',
+ 'application/common/manifest_handlers/widget_handler_unittest.cc',
'application/common/manifest_handler_unittest.cc',
'application/common/manifest_unittest.cc',
'runtime/common/xwalk_content_client_unittest.cc',
'../skia/skia.gyp:skia',
],
}],
+ ['tizen == 1 or tizen_mobile == 1', {
+ 'sources': [
+ 'application/common/manifest_handlers/navigation_handler_unittest.cc',
+ ],
+ }],
],
},
{