diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/mojo/public | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/mojo/public')
202 files changed, 16551 insertions, 82 deletions
diff --git a/chromium/mojo/public/DEPS b/chromium/mojo/public/DEPS new file mode 100644 index 00000000000..0c679b9fd0f --- /dev/null +++ b/chromium/mojo/public/DEPS @@ -0,0 +1,6 @@ +include_rules = [ + "-base", + "-build", + "-mojo", + "+mojo/public", +] diff --git a/chromium/mojo/public/README.md b/chromium/mojo/public/README.md new file mode 100644 index 00000000000..a31a8a8245e --- /dev/null +++ b/chromium/mojo/public/README.md @@ -0,0 +1,43 @@ +Mojo Public API +=============== + +The Mojo Public API is a binary stable API to the Mojo system. + +It consists of support for a number of programming languages (with a directory +for each support language), some "build" tools and build-time requirements, and +interface definitions for Mojo services (specified using an IDL). + +Note that there are various subdirectories named tests/. These contain tests of +the code in the enclosing directory, and are not meant for use by Mojo +applications. + +C/CPP/JS +-------- + +The c/, cpp/, js/ subdirectories define the API for C, C++, and JavaScript, +respectively. + +The basic principle for these directories is that they consist of the source +files that one needs at build/deployment/run time (as appropriate for the +language), organized in a natural way for the particular language. + +Interfaces +---------- + +The interfaces/ subdirectory contains Mojo IDL (a.k.a. .mojom) descriptions of +standard Mojo services. + +Platform +-------- + +The platform/ subdirectory contains any build-time requirements (e.g., static +libraries) that may be needed to produce a Mojo application for certain +platforms, such as a native shared library or as a NaCl binary. + +Tools +----- + +The tools/ subdirectory contains tools that are useful/necessary at +build/deployment time. These tools may be needed (as a practical necessity) to +use the API in any given language, e.g., to generate bindings from Mojo IDL +files. diff --git a/chromium/mojo/public/bindings/mojom_bindings_generator.gypi b/chromium/mojo/public/bindings/mojom_bindings_generator.gypi deleted file mode 100644 index 45efe768d1b..00000000000 --- a/chromium/mojo/public/bindings/mojom_bindings_generator.gypi +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (c) 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. - -{ - 'variables': { - 'output_dir': '<(SHARED_INTERMEDIATE_DIR)/mojom', - }, - 'rules': [ - { - 'rule_name': 'Generate C++ source files from mojom files', - 'extension': 'mojom', - 'variables': { - 'mojom_bindings_generator': - '<(DEPTH)/mojo/public/bindings/mojom_bindings_generator.py', - }, - 'inputs': [ - '<(mojom_bindings_generator)', - '<(DEPTH)/mojo/public/bindings/parse/mojo_parser.py', - '<(DEPTH)/mojo/public/bindings/parse/mojo_translate.py', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/interface_declaration', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/interface_definition', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/interface_proxy_declaration', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/interface_stub_case', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/interface_stub_declaration', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/interface_stub_definition', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/module.cc-template', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/module.h-template', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/module_internal.h-template', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/params_definition', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/params_serialization', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/proxy_implementation', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_builder_definition', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_declaration', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_destructor', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_definition', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_serialization', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_serialization_definition', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_serialization_traits', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/template_declaration', - '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/wrapper_class_declaration', - '<(DEPTH)/mojo/public/bindings/generators/js_templates/module.js.tmpl', - '<(DEPTH)/mojo/public/bindings/generators/mojom.py', - '<(DEPTH)/mojo/public/bindings/generators/mojom_cpp_generator.py', - '<(DEPTH)/mojo/public/bindings/generators/mojom_data.py', - '<(DEPTH)/mojo/public/bindings/generators/mojom_generator.py', - '<(DEPTH)/mojo/public/bindings/generators/mojom_js_generator.py', - '<(DEPTH)/mojo/public/bindings/generators/mojom_pack.py', - '<(DEPTH)/mojo/public/bindings/generators/template_expander.py', - ], - 'outputs': [ - '<(output_dir)/<(RULE_INPUT_ROOT).cc', - '<(output_dir)/<(RULE_INPUT_ROOT).h', - '<(output_dir)/<(RULE_INPUT_ROOT).js', - '<(output_dir)/<(RULE_INPUT_ROOT)_internal.h', - ], - 'action': [ - 'python', '<@(mojom_bindings_generator)', - '<(RULE_INPUT_PATH)', - '-i', 'mojom', - '-o', '<(output_dir)', - ], - 'message': 'Generating C++ from mojom <(RULE_INPUT_PATH)', - 'process_outputs_as_sources': 1, - } - ], - 'dependencies': [ - 'mojo_bindings', - 'mojo_system', - ], - 'include_dirs': [ - '<(DEPTH)', - '<(SHARED_INTERMEDIATE_DIR)', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '<(DEPTH)', - '<(SHARED_INTERMEDIATE_DIR)', - ], - }, - 'hard_dependency': 1, -} diff --git a/chromium/mojo/public/c/DEPS b/chromium/mojo/public/c/DEPS new file mode 100644 index 00000000000..52727706c38 --- /dev/null +++ b/chromium/mojo/public/c/DEPS @@ -0,0 +1,16 @@ +include_rules = [ + # Require explicit dependencies in each directory. + "-mojo/public", + # But everyone can depend on the C system headers. + "+mojo/public/c/system", +] + +specific_include_rules = { + r".*_(unit|perf)test\.cc": [ + "+testing", + # Our test harness is C++, so allow the use of C++: + "+mojo/public/cpp/system", + "+mojo/public/cpp/test_support", + "+mojo/public/cpp/utility", + ], +} diff --git a/chromium/mojo/public/c/README.md b/chromium/mojo/public/c/README.md new file mode 100644 index 00000000000..8e11545deb0 --- /dev/null +++ b/chromium/mojo/public/c/README.md @@ -0,0 +1,45 @@ +Mojo Public C API +================= + +This directory contains C language bindings for the Mojo Public API. + +Environment +----------- + +The environment/ subdirectory defines some common things that, while not part of +the system API, may be required for GLES2 (for example). These are things that a +Mojo application may be required to provide to the GLES2 (for example) library +in order to use it. (However, the Mojo application may implement these things as +it sees fit.) + +GLES2 +----- + +The gles2/ subdirectory defines the GLES2 C API that's available to Mojo +applications. To use GLES2, Mojo applications must link against a dynamic +library (the exact mechanism being platform-dependent) and use the header files +in this directory as well as the standard Khronos GLES2 header files. + +The reason for this, rather than providing GLES2 using the standard Mojo IPC +mechanism, is performance: The protocol (and transport mechanisms) used to +communicate with the Mojo GLES2 service is not stable nor "public" (mainly for +performance reasons), and using the dynamic library shields the application from +changes to the underlying system. + +System +------ + +The system/ subdirectory provides definitions of the basic low-level API used by +all Mojo applications (whether directly or indirectly). These consist primarily +of the IPC primitives used to communicate with Mojo services. + +Though the message protocol is stable, the implementation of the transport is +not, and access to the IPC mechanisms must be via the primitives defined in this +directory. + +Test Support +------------ + +This directory contains a C API for running tests. This API is only available +under special, specific test conditions. It is not meant for general use by Mojo +applications. diff --git a/chromium/mojo/public/c/environment/async_waiter.h b/chromium/mojo/public/c/environment/async_waiter.h new file mode 100644 index 00000000000..1eb06317d70 --- /dev/null +++ b/chromium/mojo/public/c/environment/async_waiter.h @@ -0,0 +1,30 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_C_ENVIRONMENT_ASYNC_WAITER_H_ +#define MOJO_PUBLIC_C_ENVIRONMENT_ASYNC_WAITER_H_ + +#include "mojo/public/c/system/types.h" + +typedef uintptr_t MojoAsyncWaitID; + +typedef void (*MojoAsyncWaitCallback)(void* closure, MojoResult result); + +struct MojoAsyncWaiter { + // Asynchronously call MojoWait on a background thread, and pass the result + // of MojoWait to the given MojoAsyncWaitCallback on the current thread. + // Returns a non-zero MojoAsyncWaitID that can be used with CancelWait to + // stop waiting. This identifier becomes invalid once the callback runs. + MojoAsyncWaitID (*AsyncWait)(MojoHandle handle, + MojoHandleSignals signals, + MojoDeadline deadline, + MojoAsyncWaitCallback callback, + void* closure); + + // Cancel an existing call to AsyncWait with the given MojoAsyncWaitID. The + // corresponding MojoAsyncWaitCallback will not be called in this case. + void (*CancelWait)(MojoAsyncWaitID wait_id); +}; + +#endif // MOJO_PUBLIC_C_ENVIRONMENT_ASYNC_WAITER_H_ diff --git a/chromium/mojo/public/c/environment/logger.h b/chromium/mojo/public/c/environment/logger.h new file mode 100644 index 00000000000..5e9067fb509 --- /dev/null +++ b/chromium/mojo/public/c/environment/logger.h @@ -0,0 +1,54 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_C_ENVIRONMENT_LOGGER_H_ +#define MOJO_PUBLIC_C_ENVIRONMENT_LOGGER_H_ + +#include <stdint.h> + +// |MojoLogLevel|: Used to specify the type of log message. Values are ordered +// by severity (i.e., higher numerical values are more severe). + +typedef int32_t MojoLogLevel; + +#ifdef __cplusplus +const MojoLogLevel MOJO_LOG_LEVEL_VERBOSE = -1; +const MojoLogLevel MOJO_LOG_LEVEL_INFO = 0; +const MojoLogLevel MOJO_LOG_LEVEL_WARNING = 1; +const MojoLogLevel MOJO_LOG_LEVEL_ERROR = 2; +const MojoLogLevel MOJO_LOG_LEVEL_FATAL = 3; +#else +#define MOJO_LOG_LEVEL_VERBOSE ((MojoLogLevel) -1) +#define MOJO_LOG_LEVEL_INFO ((MojoLogLevel) 0) +#define MOJO_LOG_LEVEL_WARNING ((MojoLogLevel) 1) +#define MOJO_LOG_LEVEL_ERROR ((MojoLogLevel) 2) +#define MOJO_LOG_LEVEL_FATAL ((MojoLogLevel) 3) +#endif + +// Structure with basic logging functions (on top of which more friendly logging +// macros may be built). The functions are thread-safe, except for +// |SetMinimumLogLevel()| (see below). +struct MojoLogger { + // Logs |message| at level |log_level| if |log_level| is at least the current + // minimum log level. If |log_level| is |MOJO_LOG_LEVEL_FATAL| (or greater), + // aborts the application/process. + void (*LogMessage)(MojoLogLevel log_level, const char* message); + + // Gets the minimum log level (see above), which will always be at most + // |MOJO_LOG_LEVEL_FATAL|. (Though |LogMessage()| will automatically avoid + // logging messages below the minimum log level, this may be used to avoid + // extra work.) + MojoLogLevel (*GetMinimumLogLevel)(void); + + // Sets the minimum log level (see above) to the lesser of |minimum_log_level| + // and |MOJO_LOG_LEVEL_FATAL|. + // + // Warning: This function may not be thread-safe, and should not be called + // concurrently with other |MojoLogger| functions. (In some environments -- + // such as Chromium -- that share a logger across applications, this may mean + // that it is almost never safe to call this.) + void (*SetMinimumLogLevel)(MojoLogLevel minimum_log_level); +}; + +#endif // MOJO_PUBLIC_C_ENVIRONMENT_LOGGER_H_ diff --git a/chromium/mojo/public/c/gles2/DEPS b/chromium/mojo/public/c/gles2/DEPS new file mode 100644 index 00000000000..38874579404 --- /dev/null +++ b/chromium/mojo/public/c/gles2/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+mojo/public/c/environment", +] diff --git a/chromium/mojo/public/c/gles2/gles2.h b/chromium/mojo/public/c/gles2/gles2.h new file mode 100644 index 00000000000..44880afc1ed --- /dev/null +++ b/chromium/mojo/public/c/gles2/gles2.h @@ -0,0 +1,51 @@ +// 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. + +#ifndef MOJO_PUBLIC_C_GLES2_GLES2_H_ +#define MOJO_PUBLIC_C_GLES2_GLES2_H_ + +// Note: This header should be compilable as C. + +#include <stdint.h> +#include <GLES2/gl2.h> + +#include "mojo/public/c/environment/async_waiter.h" +#include "mojo/public/c/gles2/gles2_export.h" +#include "mojo/public/c/gles2/gles2_types.h" +#include "mojo/public/c/system/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +MOJO_GLES2_EXPORT void MojoGLES2Initialize(const MojoAsyncWaiter* async_waiter); +MOJO_GLES2_EXPORT void MojoGLES2Terminate(void); +MOJO_GLES2_EXPORT MojoGLES2Context MojoGLES2CreateContext( + MojoHandle handle, + MojoGLES2ContextLost lost_callback, + MojoGLES2DrawAnimationFrame animation_callback, + void* closure); +MOJO_GLES2_EXPORT void MojoGLES2DestroyContext(MojoGLES2Context context); +MOJO_GLES2_EXPORT void MojoGLES2MakeCurrent(MojoGLES2Context context); +MOJO_GLES2_EXPORT void MojoGLES2SwapBuffers(void); +// TODO(piman): this doesn't belong here. +MOJO_GLES2_EXPORT void MojoGLES2RequestAnimationFrames( + MojoGLES2Context context); +MOJO_GLES2_EXPORT void MojoGLES2CancelAnimationFrames(MojoGLES2Context context); + +// TODO(piman): We shouldn't have to leak those 2 interfaces, especially in a +// type-unsafe way. +MOJO_GLES2_EXPORT void* MojoGLES2GetGLES2Interface(MojoGLES2Context context); +MOJO_GLES2_EXPORT void* MojoGLES2GetContextSupport(MojoGLES2Context context); + +#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \ + MOJO_GLES2_EXPORT ReturnType GL_APIENTRY gl##Function PARAMETERS; +#include "mojo/public/c/gles2/gles2_call_visitor_autogen.h" +#undef VISIT_GL_CALL + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // MOJO_PUBLIC_C_GLES2_GLES2_H_ diff --git a/chromium/mojo/public/c/gles2/gles2_call_visitor_autogen.h b/chromium/mojo/public/c/gles2/gles2_call_visitor_autogen.h new file mode 100644 index 00000000000..72494c5416c --- /dev/null +++ b/chromium/mojo/public/c/gles2/gles2_call_visitor_autogen.h @@ -0,0 +1,544 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is auto-generated from +// gpu/command_buffer/build_gles2_cmd_buffer.py +// It's formatted by clang-format using chromium coding style: +// clang-format -i -style=chromium filename +// DO NOT EDIT! + +VISIT_GL_CALL(ActiveTexture, void, (GLenum texture), (texture)) +VISIT_GL_CALL(AttachShader, + void, + (GLuint program, GLuint shader), + (program, shader)) +VISIT_GL_CALL(BindAttribLocation, + void, + (GLuint program, GLuint index, const char* name), + (program, index, name)) +VISIT_GL_CALL(BindBuffer, + void, + (GLenum target, GLuint buffer), + (target, buffer)) +VISIT_GL_CALL(BindFramebuffer, + void, + (GLenum target, GLuint framebuffer), + (target, framebuffer)) +VISIT_GL_CALL(BindRenderbuffer, + void, + (GLenum target, GLuint renderbuffer), + (target, renderbuffer)) +VISIT_GL_CALL(BindTexture, + void, + (GLenum target, GLuint texture), + (target, texture)) +VISIT_GL_CALL(BlendColor, + void, + (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha), + (red, green, blue, alpha)) +VISIT_GL_CALL(BlendEquation, void, (GLenum mode), (mode)) +VISIT_GL_CALL(BlendEquationSeparate, + void, + (GLenum modeRGB, GLenum modeAlpha), + (modeRGB, modeAlpha)) +VISIT_GL_CALL(BlendFunc, + void, + (GLenum sfactor, GLenum dfactor), + (sfactor, dfactor)) +VISIT_GL_CALL(BlendFuncSeparate, + void, + (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha), + (srcRGB, dstRGB, srcAlpha, dstAlpha)) +VISIT_GL_CALL(BufferData, + void, + (GLenum target, GLsizeiptr size, const void* data, GLenum usage), + (target, size, data, usage)) +VISIT_GL_CALL( + BufferSubData, + void, + (GLenum target, GLintptr offset, GLsizeiptr size, const void* data), + (target, offset, size, data)) +VISIT_GL_CALL(CheckFramebufferStatus, GLenum, (GLenum target), (target)) +VISIT_GL_CALL(Clear, void, (GLbitfield mask), (mask)) +VISIT_GL_CALL(ClearColor, + void, + (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha), + (red, green, blue, alpha)) +VISIT_GL_CALL(ClearDepthf, void, (GLclampf depth), (depth)) +VISIT_GL_CALL(ClearStencil, void, (GLint s), (s)) +VISIT_GL_CALL(ColorMask, + void, + (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha), + (red, green, blue, alpha)) +VISIT_GL_CALL(CompileShader, void, (GLuint shader), (shader)) +VISIT_GL_CALL( + CompressedTexImage2D, + void, + (GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const void* data), + (target, level, internalformat, width, height, border, imageSize, data)) +VISIT_GL_CALL( + CompressedTexSubImage2D, + void, + (GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const void* data), + (target, level, xoffset, yoffset, width, height, format, imageSize, data)) +VISIT_GL_CALL(CopyTexImage2D, + void, + (GLenum target, + GLint level, + GLenum internalformat, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLint border), + (target, level, internalformat, x, y, width, height, border)) +VISIT_GL_CALL(CopyTexSubImage2D, + void, + (GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height), + (target, level, xoffset, yoffset, x, y, width, height)) +VISIT_GL_CALL(CreateProgram, GLuint, (), ()) +VISIT_GL_CALL(CreateShader, GLuint, (GLenum type), (type)) +VISIT_GL_CALL(CullFace, void, (GLenum mode), (mode)) +VISIT_GL_CALL(DeleteBuffers, + void, + (GLsizei n, const GLuint* buffers), + (n, buffers)) +VISIT_GL_CALL(DeleteFramebuffers, + void, + (GLsizei n, const GLuint* framebuffers), + (n, framebuffers)) +VISIT_GL_CALL(DeleteProgram, void, (GLuint program), (program)) +VISIT_GL_CALL(DeleteRenderbuffers, + void, + (GLsizei n, const GLuint* renderbuffers), + (n, renderbuffers)) +VISIT_GL_CALL(DeleteShader, void, (GLuint shader), (shader)) +VISIT_GL_CALL(DeleteTextures, + void, + (GLsizei n, const GLuint* textures), + (n, textures)) +VISIT_GL_CALL(DepthFunc, void, (GLenum func), (func)) +VISIT_GL_CALL(DepthMask, void, (GLboolean flag), (flag)) +VISIT_GL_CALL(DepthRangef, void, (GLclampf zNear, GLclampf zFar), (zNear, zFar)) +VISIT_GL_CALL(DetachShader, + void, + (GLuint program, GLuint shader), + (program, shader)) +VISIT_GL_CALL(Disable, void, (GLenum cap), (cap)) +VISIT_GL_CALL(DisableVertexAttribArray, void, (GLuint index), (index)) +VISIT_GL_CALL(DrawArrays, + void, + (GLenum mode, GLint first, GLsizei count), + (mode, first, count)) +VISIT_GL_CALL(DrawElements, + void, + (GLenum mode, GLsizei count, GLenum type, const void* indices), + (mode, count, type, indices)) +VISIT_GL_CALL(Enable, void, (GLenum cap), (cap)) +VISIT_GL_CALL(EnableVertexAttribArray, void, (GLuint index), (index)) +VISIT_GL_CALL(Finish, void, (), ()) +VISIT_GL_CALL(Flush, void, (), ()) +VISIT_GL_CALL(FramebufferRenderbuffer, + void, + (GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer), + (target, attachment, renderbuffertarget, renderbuffer)) +VISIT_GL_CALL(FramebufferTexture2D, + void, + (GLenum target, + GLenum attachment, + GLenum textarget, + GLuint texture, + GLint level), + (target, attachment, textarget, texture, level)) +VISIT_GL_CALL(FrontFace, void, (GLenum mode), (mode)) +VISIT_GL_CALL(GenBuffers, void, (GLsizei n, GLuint * buffers), (n, buffers)) +VISIT_GL_CALL(GenerateMipmap, void, (GLenum target), (target)) +VISIT_GL_CALL(GenFramebuffers, + void, + (GLsizei n, GLuint * framebuffers), + (n, framebuffers)) +VISIT_GL_CALL(GenRenderbuffers, + void, + (GLsizei n, GLuint * renderbuffers), + (n, renderbuffers)) +VISIT_GL_CALL(GenTextures, void, (GLsizei n, GLuint * textures), (n, textures)) +VISIT_GL_CALL(GetActiveAttrib, + void, + (GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei * length, + GLint * size, + GLenum * type, + char* name), + (program, index, bufsize, length, size, type, name)) +VISIT_GL_CALL(GetActiveUniform, + void, + (GLuint program, + GLuint index, + GLsizei bufsize, + GLsizei * length, + GLint * size, + GLenum * type, + char* name), + (program, index, bufsize, length, size, type, name)) +VISIT_GL_CALL( + GetAttachedShaders, + void, + (GLuint program, GLsizei maxcount, GLsizei * count, GLuint * shaders), + (program, maxcount, count, shaders)) +VISIT_GL_CALL(GetAttribLocation, + GLint, + (GLuint program, const char* name), + (program, name)) +VISIT_GL_CALL(GetBooleanv, + void, + (GLenum pname, GLboolean * params), + (pname, params)) +VISIT_GL_CALL(GetBufferParameteriv, + void, + (GLenum target, GLenum pname, GLint * params), + (target, pname, params)) +VISIT_GL_CALL(GetError, GLenum, (), ()) +VISIT_GL_CALL(GetFloatv, + void, + (GLenum pname, GLfloat * params), + (pname, params)) +VISIT_GL_CALL(GetFramebufferAttachmentParameteriv, + void, + (GLenum target, GLenum attachment, GLenum pname, GLint * params), + (target, attachment, pname, params)) +VISIT_GL_CALL(GetIntegerv, + void, + (GLenum pname, GLint * params), + (pname, params)) +VISIT_GL_CALL(GetProgramiv, + void, + (GLuint program, GLenum pname, GLint * params), + (program, pname, params)) +VISIT_GL_CALL( + GetProgramInfoLog, + void, + (GLuint program, GLsizei bufsize, GLsizei * length, char* infolog), + (program, bufsize, length, infolog)) +VISIT_GL_CALL(GetRenderbufferParameteriv, + void, + (GLenum target, GLenum pname, GLint * params), + (target, pname, params)) +VISIT_GL_CALL(GetShaderiv, + void, + (GLuint shader, GLenum pname, GLint * params), + (shader, pname, params)) +VISIT_GL_CALL(GetShaderInfoLog, + void, + (GLuint shader, GLsizei bufsize, GLsizei * length, char* infolog), + (shader, bufsize, length, infolog)) +VISIT_GL_CALL( + GetShaderPrecisionFormat, + void, + (GLenum shadertype, GLenum precisiontype, GLint * range, GLint * precision), + (shadertype, precisiontype, range, precision)) +VISIT_GL_CALL(GetShaderSource, + void, + (GLuint shader, GLsizei bufsize, GLsizei * length, char* source), + (shader, bufsize, length, source)) +VISIT_GL_CALL(GetString, const GLubyte*, (GLenum name), (name)) +VISIT_GL_CALL(GetTexParameterfv, + void, + (GLenum target, GLenum pname, GLfloat * params), + (target, pname, params)) +VISIT_GL_CALL(GetTexParameteriv, + void, + (GLenum target, GLenum pname, GLint * params), + (target, pname, params)) +VISIT_GL_CALL(GetUniformfv, + void, + (GLuint program, GLint location, GLfloat * params), + (program, location, params)) +VISIT_GL_CALL(GetUniformiv, + void, + (GLuint program, GLint location, GLint * params), + (program, location, params)) +VISIT_GL_CALL(GetUniformLocation, + GLint, + (GLuint program, const char* name), + (program, name)) +VISIT_GL_CALL(GetVertexAttribfv, + void, + (GLuint index, GLenum pname, GLfloat * params), + (index, pname, params)) +VISIT_GL_CALL(GetVertexAttribiv, + void, + (GLuint index, GLenum pname, GLint * params), + (index, pname, params)) +VISIT_GL_CALL(GetVertexAttribPointerv, + void, + (GLuint index, GLenum pname, void** pointer), + (index, pname, pointer)) +VISIT_GL_CALL(Hint, void, (GLenum target, GLenum mode), (target, mode)) +VISIT_GL_CALL(IsBuffer, GLboolean, (GLuint buffer), (buffer)) +VISIT_GL_CALL(IsEnabled, GLboolean, (GLenum cap), (cap)) +VISIT_GL_CALL(IsFramebuffer, GLboolean, (GLuint framebuffer), (framebuffer)) +VISIT_GL_CALL(IsProgram, GLboolean, (GLuint program), (program)) +VISIT_GL_CALL(IsRenderbuffer, GLboolean, (GLuint renderbuffer), (renderbuffer)) +VISIT_GL_CALL(IsShader, GLboolean, (GLuint shader), (shader)) +VISIT_GL_CALL(IsTexture, GLboolean, (GLuint texture), (texture)) +VISIT_GL_CALL(LineWidth, void, (GLfloat width), (width)) +VISIT_GL_CALL(LinkProgram, void, (GLuint program), (program)) +VISIT_GL_CALL(PixelStorei, void, (GLenum pname, GLint param), (pname, param)) +VISIT_GL_CALL(PolygonOffset, + void, + (GLfloat factor, GLfloat units), + (factor, units)) +VISIT_GL_CALL(ReadPixels, + void, + (GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + void* pixels), + (x, y, width, height, format, type, pixels)) +VISIT_GL_CALL(ReleaseShaderCompiler, void, (), ()) +VISIT_GL_CALL( + RenderbufferStorage, + void, + (GLenum target, GLenum internalformat, GLsizei width, GLsizei height), + (target, internalformat, width, height)) +VISIT_GL_CALL(SampleCoverage, + void, + (GLclampf value, GLboolean invert), + (value, invert)) +VISIT_GL_CALL(Scissor, + void, + (GLint x, GLint y, GLsizei width, GLsizei height), + (x, y, width, height)) +VISIT_GL_CALL(ShaderBinary, + void, + (GLsizei n, + const GLuint* shaders, + GLenum binaryformat, + const void* binary, + GLsizei length), + (n, shaders, binaryformat, binary, length)) +VISIT_GL_CALL(ShaderSource, + void, + (GLuint shader, + GLsizei count, + const GLchar* const* str, + const GLint* length), + (shader, count, str, length)) +VISIT_GL_CALL(StencilFunc, + void, + (GLenum func, GLint ref, GLuint mask), + (func, ref, mask)) +VISIT_GL_CALL(StencilFuncSeparate, + void, + (GLenum face, GLenum func, GLint ref, GLuint mask), + (face, func, ref, mask)) +VISIT_GL_CALL(StencilMask, void, (GLuint mask), (mask)) +VISIT_GL_CALL(StencilMaskSeparate, + void, + (GLenum face, GLuint mask), + (face, mask)) +VISIT_GL_CALL(StencilOp, + void, + (GLenum fail, GLenum zfail, GLenum zpass), + (fail, zfail, zpass)) +VISIT_GL_CALL(StencilOpSeparate, + void, + (GLenum face, GLenum fail, GLenum zfail, GLenum zpass), + (face, fail, zfail, zpass)) +VISIT_GL_CALL(TexImage2D, + void, + (GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void* pixels), + (target, + level, + internalformat, + width, + height, + border, + format, + type, + pixels)) +VISIT_GL_CALL(TexParameterf, + void, + (GLenum target, GLenum pname, GLfloat param), + (target, pname, param)) +VISIT_GL_CALL(TexParameterfv, + void, + (GLenum target, GLenum pname, const GLfloat* params), + (target, pname, params)) +VISIT_GL_CALL(TexParameteri, + void, + (GLenum target, GLenum pname, GLint param), + (target, pname, param)) +VISIT_GL_CALL(TexParameteriv, + void, + (GLenum target, GLenum pname, const GLint* params), + (target, pname, params)) +VISIT_GL_CALL( + TexSubImage2D, + void, + (GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void* pixels), + (target, level, xoffset, yoffset, width, height, format, type, pixels)) +VISIT_GL_CALL(Uniform1f, void, (GLint location, GLfloat x), (location, x)) +VISIT_GL_CALL(Uniform1fv, + void, + (GLint location, GLsizei count, const GLfloat* v), + (location, count, v)) +VISIT_GL_CALL(Uniform1i, void, (GLint location, GLint x), (location, x)) +VISIT_GL_CALL(Uniform1iv, + void, + (GLint location, GLsizei count, const GLint* v), + (location, count, v)) +VISIT_GL_CALL(Uniform2f, + void, + (GLint location, GLfloat x, GLfloat y), + (location, x, y)) +VISIT_GL_CALL(Uniform2fv, + void, + (GLint location, GLsizei count, const GLfloat* v), + (location, count, v)) +VISIT_GL_CALL(Uniform2i, + void, + (GLint location, GLint x, GLint y), + (location, x, y)) +VISIT_GL_CALL(Uniform2iv, + void, + (GLint location, GLsizei count, const GLint* v), + (location, count, v)) +VISIT_GL_CALL(Uniform3f, + void, + (GLint location, GLfloat x, GLfloat y, GLfloat z), + (location, x, y, z)) +VISIT_GL_CALL(Uniform3fv, + void, + (GLint location, GLsizei count, const GLfloat* v), + (location, count, v)) +VISIT_GL_CALL(Uniform3i, + void, + (GLint location, GLint x, GLint y, GLint z), + (location, x, y, z)) +VISIT_GL_CALL(Uniform3iv, + void, + (GLint location, GLsizei count, const GLint* v), + (location, count, v)) +VISIT_GL_CALL(Uniform4f, + void, + (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w), + (location, x, y, z, w)) +VISIT_GL_CALL(Uniform4fv, + void, + (GLint location, GLsizei count, const GLfloat* v), + (location, count, v)) +VISIT_GL_CALL(Uniform4i, + void, + (GLint location, GLint x, GLint y, GLint z, GLint w), + (location, x, y, z, w)) +VISIT_GL_CALL(Uniform4iv, + void, + (GLint location, GLsizei count, const GLint* v), + (location, count, v)) +VISIT_GL_CALL( + UniformMatrix2fv, + void, + (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value), + (location, count, transpose, value)) +VISIT_GL_CALL( + UniformMatrix3fv, + void, + (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value), + (location, count, transpose, value)) +VISIT_GL_CALL( + UniformMatrix4fv, + void, + (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value), + (location, count, transpose, value)) +VISIT_GL_CALL(UseProgram, void, (GLuint program), (program)) +VISIT_GL_CALL(ValidateProgram, void, (GLuint program), (program)) +VISIT_GL_CALL(VertexAttrib1f, void, (GLuint indx, GLfloat x), (indx, x)) +VISIT_GL_CALL(VertexAttrib1fv, + void, + (GLuint indx, const GLfloat* values), + (indx, values)) +VISIT_GL_CALL(VertexAttrib2f, + void, + (GLuint indx, GLfloat x, GLfloat y), + (indx, x, y)) +VISIT_GL_CALL(VertexAttrib2fv, + void, + (GLuint indx, const GLfloat* values), + (indx, values)) +VISIT_GL_CALL(VertexAttrib3f, + void, + (GLuint indx, GLfloat x, GLfloat y, GLfloat z), + (indx, x, y, z)) +VISIT_GL_CALL(VertexAttrib3fv, + void, + (GLuint indx, const GLfloat* values), + (indx, values)) +VISIT_GL_CALL(VertexAttrib4f, + void, + (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w), + (indx, x, y, z, w)) +VISIT_GL_CALL(VertexAttrib4fv, + void, + (GLuint indx, const GLfloat* values), + (indx, values)) +VISIT_GL_CALL(VertexAttribPointer, + void, + (GLuint indx, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + const void* ptr), + (indx, size, type, normalized, stride, ptr)) +VISIT_GL_CALL(Viewport, + void, + (GLint x, GLint y, GLsizei width, GLsizei height), + (x, y, width, height)) diff --git a/chromium/mojo/public/c/gles2/gles2_export.h b/chromium/mojo/public/c/gles2/gles2_export.h new file mode 100644 index 00000000000..4f8796da069 --- /dev/null +++ b/chromium/mojo/public/c/gles2/gles2_export.h @@ -0,0 +1,26 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_C_GLES2_GLES2_EXPORT_H_ +#define MOJO_PUBLIC_C_GLES2_GLES2_EXPORT_H_ + +#if defined(WIN32) + +#if defined(MOJO_GLES2_IMPLEMENTATION) +#define MOJO_GLES2_EXPORT __declspec(dllexport) +#else +#define MOJO_GLES2_EXPORT __declspec(dllimport) +#endif + +#else // !defined(WIN32) + +#if defined(MOJO_GLES2_IMPLEMENTATION) +#define MOJO_GLES2_EXPORT __attribute__((visibility("default"))) +#else +#define MOJO_GLES2_EXPORT +#endif + +#endif // defined(WIN32) + +#endif // MOJO_PUBLIC_C_GLES2_GLES2_EXPORT_H_ diff --git a/chromium/mojo/public/c/gles2/gles2_types.h b/chromium/mojo/public/c/gles2/gles2_types.h new file mode 100644 index 00000000000..dd2a21314cc --- /dev/null +++ b/chromium/mojo/public/c/gles2/gles2_types.h @@ -0,0 +1,26 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_C_GLES2_GLES2_TYPES_H_ +#define MOJO_PUBLIC_C_GLES2_GLES2_TYPES_H_ + +// Note: This header should be compilable as C. + +#include <stdint.h> + +#include "mojo/public/c/gles2/gles2_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MojoGLES2ContextPrivate* MojoGLES2Context; +typedef void (*MojoGLES2ContextLost)(void* closure); +typedef void (*MojoGLES2DrawAnimationFrame)(void* closure); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // MOJO_PUBLIC_C_GLES2_GLES2_TYPES_H_ diff --git a/chromium/mojo/public/c/system/buffer.h b/chromium/mojo/public/c/system/buffer.h new file mode 100644 index 00000000000..86cf8223ee0 --- /dev/null +++ b/chromium/mojo/public/c/system/buffer.h @@ -0,0 +1,187 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains types/constants and functions specific to buffers (and in +// particular shared buffers). +// TODO(vtl): Reorganize this file (etc.) to separate general buffer functions +// from (shared) buffer creation. +// +// Note: This header should be compilable as C. + +#ifndef MOJO_PUBLIC_C_SYSTEM_BUFFER_H_ +#define MOJO_PUBLIC_C_SYSTEM_BUFFER_H_ + +#include "mojo/public/c/system/macros.h" +#include "mojo/public/c/system/system_export.h" +#include "mojo/public/c/system/types.h" + +// |MojoCreateSharedBufferOptions|: Used to specify creation parameters for a +// shared buffer to |MojoCreateSharedBuffer()|. +// |uint32_t struct_size|: Set to the size of the +// |MojoCreateSharedBufferOptions| struct. (Used to allow for future +// extensions.) +// |MojoCreateSharedBufferOptionsFlags flags|: Reserved for future use. +// |MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE|: No flags; default mode. +// +// TODO(vtl): Maybe add a flag to indicate whether the memory should be +// executable or not? +// TODO(vtl): Also a flag for discardable (ashmem-style) buffers. + +typedef uint32_t MojoCreateSharedBufferOptionsFlags; + +#ifdef __cplusplus +const MojoCreateSharedBufferOptionsFlags + MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE = 0; +#else +#define MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE \ + ((MojoCreateSharedBufferOptionsFlags) 0) +#endif + +MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int64_t) == 8, int64_t_has_weird_alignment); +struct MOJO_ALIGNAS(8) MojoCreateSharedBufferOptions { + uint32_t struct_size; + MojoCreateSharedBufferOptionsFlags flags; +}; +MOJO_COMPILE_ASSERT(sizeof(MojoCreateSharedBufferOptions) == 8, + MojoCreateSharedBufferOptions_has_wrong_size); + +// |MojoDuplicateBufferHandleOptions|: Used to specify parameters in duplicating +// access to a shared buffer to |MojoDuplicateBufferHandle()|. +// |uint32_t struct_size|: Set to the size of the +// |MojoDuplicateBufferHandleOptions| struct. (Used to allow for future +// extensions.) +// |MojoDuplicateBufferHandleOptionsFlags flags|: Reserved for future use. +// |MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE|: No flags; default +// mode. +// +// TODO(vtl): Add flags to remove writability (and executability)? Also, COW? + +typedef uint32_t MojoDuplicateBufferHandleOptionsFlags; + +#ifdef __cplusplus +const MojoDuplicateBufferHandleOptionsFlags + MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE = 0; +#else +#define MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE \ + ((MojoDuplicateBufferHandleOptionsFlags) 0) +#endif + +struct MojoDuplicateBufferHandleOptions { + uint32_t struct_size; + MojoDuplicateBufferHandleOptionsFlags flags; +}; +MOJO_COMPILE_ASSERT(sizeof(MojoDuplicateBufferHandleOptions) == 8, + MojoDuplicateBufferHandleOptions_has_wrong_size); + +// |MojoMapBufferFlags|: Used to specify different modes to |MojoMapBuffer()|. +// |MOJO_MAP_BUFFER_FLAG_NONE| - No flags; default mode. + +typedef uint32_t MojoMapBufferFlags; + +#ifdef __cplusplus +const MojoMapBufferFlags MOJO_MAP_BUFFER_FLAG_NONE = 0; +#else +#define MOJO_MAP_BUFFER_FLAG_NONE ((MojoMapBufferFlags) 0) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// Note: See the comment in functions.h about the meaning of the "optional" +// label for pointer parameters. + +// Creates a buffer of size |num_bytes| bytes that can be shared between +// applications (by duplicating the handle -- see |MojoDuplicateBufferHandle()| +// -- and passing it over a message pipe). To access the buffer, one must call +// |MojoMapBuffer()|. +// +// |options| may be set to null for a shared buffer with the default options. +// +// On success, |*shared_buffer_handle| will be set to the handle for the shared +// buffer. (On failure, it is not modified.) +// +// Note: While more than |num_bytes| bytes may apparently be +// available/visible/readable/writable, trying to use those extra bytes is +// undefined behavior. +// +// Returns: +// |MOJO_RESULT_OK| on success. +// |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g., if +// |*options| is invalid or |shared_buffer_handle| looks invalid). +// |MOJO_RESULT_RESOURCE_EXHAUSTED| if a process/system/quota/etc. limit has +// been reached (e.g., if the requested size was too large, or if the +// maximum number of handles was exceeded). +// |MOJO_RESULT_UNIMPLEMENTED| if an unsupported flag was set in |*options|. +MOJO_SYSTEM_EXPORT MojoResult MojoCreateSharedBuffer( + const struct MojoCreateSharedBufferOptions* options, // Optional. + uint64_t num_bytes, // In. + MojoHandle* shared_buffer_handle); // Out. + +// Duplicates the handle |buffer_handle| to a buffer. This creates another +// handle (returned in |*new_buffer_handle| on success), which can then be sent +// to another application over a message pipe, while retaining access to the +// |buffer_handle| (and any mappings that it may have). +// +// |options| may be set to null to duplicate the buffer handle with the default +// options. +// +// On success, |*shared_buffer_handle| will be set to the handle for the new +// buffer handle. (On failure, it is not modified.) +// +// Returns: +// |MOJO_RESULT_OK| on success. +// |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g., if +// |buffer_handle| is not a valid buffer handle, |*options| is invalid, or +// |new_buffer_handle| looks invalid). +// |MOJO_RESULT_UNIMPLEMENTED| if an unsupported flag was set in |*options|. +MOJO_SYSTEM_EXPORT MojoResult MojoDuplicateBufferHandle( + MojoHandle buffer_handle, + const struct MojoDuplicateBufferHandleOptions* options, // Optional. + MojoHandle* new_buffer_handle); // Out. + +// Maps the part (at offset |offset| of length |num_bytes|) of the buffer given +// by |buffer_handle| into memory, with options specified by |flags|. |offset + +// num_bytes| must be less than or equal to the size of the buffer. On success, +// |*buffer| points to memory with the requested part of the buffer. (On +// failure, it is not modified.) +// +// A single buffer handle may have multiple active mappings (possibly depending +// on the buffer type). The permissions (e.g., writable or executable) of the +// returned memory may depend on the properties of the buffer and properties +// attached to the buffer handle as well as |flags|. +// +// Note: Though data outside the specified range may apparently be +// available/visible/readable/writable, trying to use those extra bytes is +// undefined behavior. +// +// Returns: +// |MOJO_RESULT_OK| on success. +// |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g., if +// |buffer_handle| is not a valid buffer handle, the range specified by +// |offset| and |num_bytes| is not valid, or |buffer| looks invalid). +// |MOJO_RESULT_RESOURCE_EXHAUSTED| if the mapping operation itself failed +// (e.g., due to not having appropriate address space available). +MOJO_SYSTEM_EXPORT MojoResult MojoMapBuffer(MojoHandle buffer_handle, + uint64_t offset, + uint64_t num_bytes, + void** buffer, // Out. + MojoMapBufferFlags flags); + +// Unmaps a buffer pointer that was mapped by |MojoMapBuffer()|. |buffer| must +// have been the result of |MojoMapBuffer()| (not some pointer strictly inside +// the mapped memory), and the entire mapping will be removed (partial unmapping +// is not supported). A mapping may only be unmapped exactly once. +// +// Returns: +// |MOJO_RESULT_OK| on success. +// |MOJO_RESULT_INVALID_ARGUMENT| if |buffer| is invalid (e.g., if it is not +// the result of |MojoMapBuffer()| or it has already been unmapped). +MOJO_SYSTEM_EXPORT MojoResult MojoUnmapBuffer(void* buffer); // In. + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // MOJO_PUBLIC_C_SYSTEM_BUFFER_H_ diff --git a/chromium/mojo/public/c/system/core.h b/chromium/mojo/public/c/system/core.h new file mode 100644 index 00000000000..5ea03fc5a5e --- /dev/null +++ b/chromium/mojo/public/c/system/core.h @@ -0,0 +1,20 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This is a catch-all header that includes everything. +// +// Note: This header should be compilable as C. + +#ifndef MOJO_PUBLIC_C_SYSTEM_CORE_H_ +#define MOJO_PUBLIC_C_SYSTEM_CORE_H_ + +#include "mojo/public/c/system/buffer.h" +#include "mojo/public/c/system/data_pipe.h" +#include "mojo/public/c/system/functions.h" +#include "mojo/public/c/system/macros.h" +#include "mojo/public/c/system/message_pipe.h" +#include "mojo/public/c/system/system_export.h" +#include "mojo/public/c/system/types.h" + +#endif // MOJO_PUBLIC_C_SYSTEM_CORE_H_ diff --git a/chromium/mojo/public/c/system/data_pipe.h b/chromium/mojo/public/c/system/data_pipe.h new file mode 100644 index 00000000000..e28cf6eff11 --- /dev/null +++ b/chromium/mojo/public/c/system/data_pipe.h @@ -0,0 +1,367 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains types/constants and functions specific to data pipes. +// +// Note: This header should be compilable as C. + +#ifndef MOJO_PUBLIC_C_SYSTEM_DATA_PIPE_H_ +#define MOJO_PUBLIC_C_SYSTEM_DATA_PIPE_H_ + +#include "mojo/public/c/system/macros.h" +#include "mojo/public/c/system/system_export.h" +#include "mojo/public/c/system/types.h" + +// |MojoCreateDataPipeOptions|: Used to specify creation parameters for a data +// pipe to |MojoCreateDataPipe()|. +// |uint32_t struct_size|: Set to the size of the |MojoCreateDataPipeOptions| +// struct. (Used to allow for future extensions.) +// |MojoCreateDataPipeOptionsFlags flags|: Used to specify different modes of +// operation. +// |MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE|: No flags; default mode. +// |MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD|: May discard data for +// whatever reason; best-effort delivery. In particular, if the capacity +// is reached, old data may be discard to make room for new data. +// |uint32_t element_num_bytes|: The size of an element, in bytes. All +// transactions and buffers will consist of an integral number of +// elements. Must be nonzero. +// |uint32_t capacity_num_bytes|: The capacity of the data pipe, in number of +// bytes; must be a multiple of |element_num_bytes|. The data pipe will +// always be able to queue AT LEAST this much data. Set to zero to opt for +// a system-dependent automatically-calculated capacity (which will always +// be at least one element). + +typedef uint32_t MojoCreateDataPipeOptionsFlags; + +#ifdef __cplusplus +const MojoCreateDataPipeOptionsFlags + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE = 0; +const MojoCreateDataPipeOptionsFlags + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD = 1 << 0; +#else +#define MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE \ + ((MojoCreateDataPipeOptionsFlags) 0) +#define MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD \ + ((MojoCreateDataPipeOptionsFlags) 1 << 0) +#endif + +MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int64_t) == 8, int64_t_has_weird_alignment); +struct MOJO_ALIGNAS(8) MojoCreateDataPipeOptions { + uint32_t struct_size; + MojoCreateDataPipeOptionsFlags flags; + uint32_t element_num_bytes; + uint32_t capacity_num_bytes; +}; +MOJO_COMPILE_ASSERT(sizeof(MojoCreateDataPipeOptions) == 16, + MojoCreateDataPipeOptions_has_wrong_size); + +// |MojoWriteDataFlags|: Used to specify different modes to |MojoWriteData()| +// and |MojoBeginWriteData()|. +// |MOJO_WRITE_DATA_FLAG_NONE| - No flags; default mode. +// |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| - Write either all the elements +// requested or none of them. + +typedef uint32_t MojoWriteDataFlags; + +#ifdef __cplusplus +const MojoWriteDataFlags MOJO_WRITE_DATA_FLAG_NONE = 0; +const MojoWriteDataFlags MOJO_WRITE_DATA_FLAG_ALL_OR_NONE = 1 << 0; +#else +#define MOJO_WRITE_DATA_FLAG_NONE ((MojoWriteDataFlags) 0) +#define MOJO_WRITE_DATA_FLAG_ALL_OR_NONE ((MojoWriteDataFlags) 1 << 0) +#endif + +// |MojoReadDataFlags|: Used to specify different modes to |MojoReadData()| and +// |MojoBeginReadData()|. +// |MOJO_READ_DATA_FLAG_NONE| - No flags; default mode. +// |MOJO_READ_DATA_FLAG_ALL_OR_NONE| - Read (or discard) either the requested +// number of elements or none. +// |MOJO_READ_DATA_FLAG_DISCARD| - Discard (up to) the requested number of +// elements. +// |MOJO_READ_DATA_FLAG_QUERY| - Query the number of elements available to +// read. For use with |MojoReadData()| only. Mutually exclusive with +// |MOJO_READ_DATA_FLAG_DISCARD| and |MOJO_READ_DATA_FLAG_ALL_OR_NONE| is +// ignored if this flag is set. + +typedef uint32_t MojoReadDataFlags; + +#ifdef __cplusplus +const MojoReadDataFlags MOJO_READ_DATA_FLAG_NONE = 0; +const MojoReadDataFlags MOJO_READ_DATA_FLAG_ALL_OR_NONE = 1 << 0; +const MojoReadDataFlags MOJO_READ_DATA_FLAG_DISCARD = 1 << 1; +const MojoReadDataFlags MOJO_READ_DATA_FLAG_QUERY = 1 << 2; +#else +#define MOJO_READ_DATA_FLAG_NONE ((MojoReadDataFlags) 0) +#define MOJO_READ_DATA_FLAG_ALL_OR_NONE ((MojoReadDataFlags) 1 << 0) +#define MOJO_READ_DATA_FLAG_DISCARD ((MojoReadDataFlags) 1 << 1) +#define MOJO_READ_DATA_FLAG_QUERY ((MojoReadDataFlags) 1 << 2) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// Note: See the comment in functions.h about the meaning of the "optional" +// label for pointer parameters. + +// Creates a data pipe, which is a unidirectional communication channel for +// unframed data, with the given options. Data is unframed, but must come as +// (multiples of) discrete elements, of the size given in |options|. See +// |MojoCreateDataPipeOptions| for a description of the different options +// available for data pipes. +// +// |options| may be set to null for a data pipe with the default options (which +// will have an element size of one byte and have some system-dependent +// capacity). +// +// On success, |*data_pipe_producer_handle| will be set to the handle for the +// producer and |*data_pipe_consumer_handle| will be set to the handle for the +// consumer. (On failure, they are not modified.) +// +// Returns: +// |MOJO_RESULT_OK| on success. +// |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g., if +// |*options| is invalid or one of the handle pointers looks invalid). +// |MOJO_RESULT_RESOURCE_EXHAUSTED| if a process/system/quota/etc. limit has +// been reached (e.g., if the requested capacity was too large, or if the +// maximum number of handles was exceeded). +// |MOJO_RESULT_UNIMPLEMENTED| if an unsupported flag was set in |*options|. +MOJO_SYSTEM_EXPORT MojoResult MojoCreateDataPipe( + const struct MojoCreateDataPipeOptions* options, // Optional. + MojoHandle* data_pipe_producer_handle, // Out. + MojoHandle* data_pipe_consumer_handle); // Out. + +// Writes the given data to the data pipe producer given by +// |data_pipe_producer_handle|. |elements| points to data of size |*num_bytes|; +// |*num_bytes| should be a multiple of the data pipe's element size. If +// |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| is set in |flags|, either all the data +// will be written or none is. +// +// On success, |*num_bytes| is set to the amount of data that was actually +// written. +// +// Note: If the data pipe has the "may discard" option flag (specified on +// creation), this will discard as much data as required to write the given +// data, starting with the earliest written data that has not been consumed. +// However, even with "may discard", if |*num_bytes| is greater than the data +// pipe's capacity (and |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| is not set), this +// will write the maximum amount possible (namely, the data pipe's capacity) and +// set |*num_bytes| to that amount. It will *not* discard data from |elements|. +// +// Returns: +// |MOJO_RESULT_OK| on success. +// |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g., if +// |data_pipe_producer_dispatcher| is not a handle to a data pipe +// producer, |elements| does not look like a valid pointer, or +// |*num_bytes| is not a multiple of the data pipe's element size). +// |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe consumer handle has been +// closed. +// |MOJO_RESULT_OUT_OF_RANGE| if |flags| has +// |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set and the required amount of data +// (specified by |*num_bytes|) could not be written. +// |MOJO_RESULT_BUSY| if there is a two-phase write ongoing with +// |data_pipe_producer_handle| (i.e., |MojoBeginWriteData()| has been +// called, but not yet the matching |MojoEndWriteData()|). +// |MOJO_RESULT_SHOULD_WAIT| if no data can currently be written (and the +// consumer is still open) and |flags| does *not* have +// |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set. +// +// TODO(vtl): Should there be a way of querying how much data can be written? +MOJO_SYSTEM_EXPORT MojoResult MojoWriteData( + MojoHandle data_pipe_producer_handle, + const void* elements, + uint32_t* num_bytes, // In/out. + MojoWriteDataFlags flags); + +// Begins a two-phase write to the data pipe producer given by +// |data_pipe_producer_handle|. On success, |*buffer| will be a pointer to which +// the caller can write |*buffer_num_bytes| bytes of data. If flags has +// |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set, then the output value +// |*buffer_num_bytes| will be at least as large as its input value, which must +// also be a multiple of the element size (if |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| +// is not set, the input value of |*buffer_num_bytes| is ignored). +// +// During a two-phase write, |data_pipe_producer_handle| is *not* writable. +// E.g., if another thread tries to write to it, it will get |MOJO_RESULT_BUSY|; +// that thread can then wait for |data_pipe_producer_handle| to become writable +// again. +// +// Once the caller has finished writing data to |*buffer|, it should call +// |MojoEndWriteData()| to specify the amount written and to complete the +// two-phase write. +// +// Note: If the data pipe has the "may discard" option flag (specified on +// creation) and |flags| has |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set, this may +// discard some data. +// +// Returns: +// |MOJO_RESULT_OK| on success. +// |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g., if +// |data_pipe_producer_handle| is not a handle to a data pipe producer, +// |buffer| or |buffer_num_bytes| does not look like a valid pointer, or +// flags has |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set and +// |*buffer_num_bytes| is not a multiple of the element size). +// |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe consumer handle has been +// closed. +// |MOJO_RESULT_OUT_OF_RANGE| if |flags| has +// |MOJO_WRITE_DATA_FLAG_ALL_OR_NONE| set and the required amount of data +// (specified by |*buffer_num_bytes|) cannot be written contiguously at +// this time. (Note that there may be space available for the required +// amount of data, but the "next" write position may not be large enough.) +// |MOJO_RESULT_BUSY| if there is already a two-phase write ongoing with +// |data_pipe_producer_handle| (i.e., |MojoBeginWriteData()| has been +// called, but not yet the matching |MojoEndWriteData()|). +// |MOJO_RESULT_SHOULD_WAIT| if no data can currently be written (and the +// consumer is still open). +MOJO_SYSTEM_EXPORT MojoResult MojoBeginWriteData( + MojoHandle data_pipe_producer_handle, + void** buffer, // Out. + uint32_t* buffer_num_bytes, // In/out. + MojoWriteDataFlags flags); + +// Ends a two-phase write to the data pipe producer given by +// |data_pipe_producer_handle| that was begun by a call to +// |MojoBeginWriteData()| on the same handle. |num_bytes_written| should +// indicate the amount of data actually written; it must be less than or equal +// to the value of |*buffer_num_bytes| output by |MojoBeginWriteData()| and must +// be a multiple of the element size. The buffer given by |*buffer| from +// |MojoBeginWriteData()| must have been filled with exactly |num_bytes_written| +// bytes of data. +// +// On failure, the two-phase write (if any) is ended (so the handle may become +// writable again, if there's space available) but no data written to |*buffer| +// is "put into" the data pipe. +// +// Returns: +// |MOJO_RESULT_OK| on success. +// |MOJO_RESULT_INVALID_ARGUMENT| if |data_pipe_producer_handle| is not a +// handle to a data pipe producer or |num_bytes_written| is invalid +// (greater than the maximum value provided by |MojoBeginWriteData()| or +// not a multiple of the element size). +// |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe producer is not in a +// two-phase write (e.g., |MojoBeginWriteData()| was not called or +// |MojoEndWriteData()| has already been called). +MOJO_SYSTEM_EXPORT MojoResult MojoEndWriteData( + MojoHandle data_pipe_producer_handle, + uint32_t num_bytes_written); + +// Reads data from the data pipe consumer given by |data_pipe_consumer_handle|. +// May also be used to discard data or query the amount of data available. +// +// If |flags| has neither |MOJO_READ_DATA_FLAG_DISCARD| nor +// |MOJO_READ_DATA_FLAG_QUERY| set, this tries to read up to |*num_bytes| (which +// must be a multiple of the data pipe's element size) bytes of data to +// |elements| and set |*num_bytes| to the amount actually read. If flags has +// |MOJO_READ_DATA_FLAG_ALL_OR_NONE| set, it will either read exactly +// |*num_bytes| bytes of data or none. +// +// If flags has |MOJO_READ_DATA_FLAG_DISCARD| set, it discards up to +// |*num_bytes| (which again be a multiple of the element size) bytes of data, +// setting |*num_bytes| to the amount actually discarded. If flags has +// |MOJO_READ_DATA_FLAG_ALL_OR_NONE|, it will either discard exactly +// |*num_bytes| bytes of data or none. In this case, |MOJO_READ_DATA_FLAG_QUERY| +// must not be set, and |elements| is ignored (and should typically be set to +// null). +// +// If flags has |MOJO_READ_DATA_FLAG_QUERY| set, it queries the amount of data +// available, setting |*num_bytes| to the number of bytes available. In this +// case, |MOJO_READ_DATA_FLAG_DISCARD| must not be set, and +// |MOJO_READ_DATA_FLAG_ALL_OR_NONE| is ignored, as are |elements| and the input +// value of |*num_bytes|. +// +// Returns: +// |MOJO_RESULT_OK| on success (see above for a description of the different +// operations). +// |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g., +// |data_pipe_consumer_handle| is invalid, the combination of flags in +// |flags| is invalid, etc.). +// |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe producer handle has been +// closed and data (or the required amount of data) was not available to +// be read or discarded. +// |MOJO_RESULT_OUT_OF_RANGE| if |flags| has |MOJO_READ_DATA_FLAG_ALL_OR_NONE| +// set and the required amount of data is not available to be read or +// discarded (and the producer is still open). +// |MOJO_RESULT_BUSY| if there is a two-phase read ongoing with +// |data_pipe_consumer_handle| (i.e., |MojoBeginReadData()| has been +// called, but not yet the matching |MojoEndReadData()|). +// |MOJO_RESULT_SHOULD_WAIT| if there is no data to be read or discarded (and +// the producer is still open) and |flags| does *not* have +// |MOJO_READ_DATA_FLAG_ALL_OR_NONE| set. +MOJO_SYSTEM_EXPORT MojoResult MojoReadData( + MojoHandle data_pipe_consumer_handle, + void* elements, // Out. + uint32_t* num_bytes, // In/out. + MojoReadDataFlags flags); + +// Begins a two-phase read from the data pipe consumer given by +// |data_pipe_consumer_handle|. On success, |*buffer| will be a pointer from +// which the caller can read |*buffer_num_bytes| bytes of data. If flags has +// |MOJO_READ_DATA_FLAG_ALL_OR_NONE| set, then the output value +// |*buffer_num_bytes| will be at least as large as its input value, which must +// also be a multiple of the element size (if |MOJO_READ_DATA_FLAG_ALL_OR_NONE| +// is not set, the input value of |*buffer_num_bytes| is ignored). |flags| must +// not have |MOJO_READ_DATA_FLAG_DISCARD| or |MOJO_READ_DATA_FLAG_QUERY| set. +// +// During a two-phase read, |data_pipe_consumer_handle| is *not* readable. +// E.g., if another thread tries to read from it, it will get +// |MOJO_RESULT_BUSY|; that thread can then wait for |data_pipe_consumer_handle| +// to become readable again. +// +// Once the caller has finished reading data from |*buffer|, it should call +// |MojoEndReadData()| to specify the amount read and to complete the two-phase +// read. +// +// Returns: +// |MOJO_RESULT_OK| on success. +// |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g., if +// |data_pipe_consumer_handle| is not a handle to a data pipe consumer, +// |buffer| or |buffer_num_bytes| does not look like a valid pointer, +// |flags| has |MOJO_READ_DATA_FLAG_ALL_OR_NONE| set and +// |*buffer_num_bytes| is not a multiple of the element size, or |flags| +// has invalid flags set). +// |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe producer handle has been +// closed. +// |MOJO_RESULT_OUT_OF_RANGE| if |flags| has |MOJO_READ_DATA_FLAG_ALL_OR_NONE| +// set and the required amount of data (specified by |*buffer_num_bytes|) +// cannot be read from a contiguous buffer at this time. (Note that there +// may be the required amount of data, but it may not be contiguous.) +// |MOJO_RESULT_BUSY| if there is already a two-phase read ongoing with +// |data_pipe_consumer_handle| (i.e., |MojoBeginReadData()| has been +// called, but not yet the matching |MojoEndReadData()|). +// |MOJO_RESULT_SHOULD_WAIT| if no data can currently be read (and the +// producer is still open). +MOJO_SYSTEM_EXPORT MojoResult MojoBeginReadData( + MojoHandle data_pipe_consumer_handle, + const void** buffer, // Out. + uint32_t* buffer_num_bytes, // In/out. + MojoReadDataFlags flags); + +// Ends a two-phase read from the data pipe consumer given by +// |data_pipe_consumer_handle| that was begun by a call to |MojoBeginReadData()| +// on the same handle. |num_bytes_read| should indicate the amount of data +// actually read; it must be less than or equal to the value of +// |*buffer_num_bytes| output by |MojoBeginReadData()| and must be a multiple of +// the element size. +// +// On failure, the two-phase read (if any) is ended (so the handle may become +// readable again) but no data is "removed" from the data pipe. +// +// Returns: +// |MOJO_RESULT_OK| on success. +// |MOJO_RESULT_INVALID_ARGUMENT| if |data_pipe_consumer_handle| is not a +// handle to a data pipe consumer or |num_bytes_written| is invalid +// (greater than the maximum value provided by |MojoBeginReadData()| or +// not a multiple of the element size). +// |MOJO_RESULT_FAILED_PRECONDITION| if the data pipe consumer is not in a +// two-phase read (e.g., |MojoBeginReadData()| was not called or +// |MojoEndReadData()| has already been called). +MOJO_SYSTEM_EXPORT MojoResult MojoEndReadData( + MojoHandle data_pipe_consumer_handle, + uint32_t num_bytes_read); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // MOJO_PUBLIC_C_SYSTEM_DATA_PIPE_H_ diff --git a/chromium/mojo/public/c/system/functions.h b/chromium/mojo/public/c/system/functions.h new file mode 100644 index 00000000000..9d2ef6ca800 --- /dev/null +++ b/chromium/mojo/public/c/system/functions.h @@ -0,0 +1,87 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains basic functions common to different Mojo system APIs. +// +// Note: This header should be compilable as C. + +#ifndef MOJO_PUBLIC_C_SYSTEM_FUNCTIONS_H_ +#define MOJO_PUBLIC_C_SYSTEM_FUNCTIONS_H_ + +// Note: This header should be compilable as C. + +#include "mojo/public/c/system/system_export.h" +#include "mojo/public/c/system/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Note: Pointer parameters that are labelled "optional" may be null (at least +// under some circumstances). Non-const pointer parameters are also labeled +// "in", "out", or "in/out", to indicate how they are used. (Note that how/if +// such a parameter is used may depend on other parameters or the requested +// operation's success/failure. E.g., a separate |flags| parameter may control +// whether a given "in/out" parameter is used for input, output, or both.) + +// Platform-dependent monotonically increasing tick count representing "right +// now." The resolution of this clock is ~1-15ms. Resolution varies depending +// on hardware/operating system configuration. +MOJO_SYSTEM_EXPORT MojoTimeTicks MojoGetTimeTicksNow(void); + +// Closes the given |handle|. +// +// Returns: +// |MOJO_RESULT_OK| on success. +// |MOJO_RESULT_INVALID_ARGUMENT| if |handle| is not a valid handle. +// +// Concurrent operations on |handle| may succeed (or fail as usual) if they +// happen before the close, be cancelled with result |MOJO_RESULT_CANCELLED| if +// they properly overlap (this is likely the case with |MojoWait()|, etc.), or +// fail with |MOJO_RESULT_INVALID_ARGUMENT| if they happen after. +MOJO_SYSTEM_EXPORT MojoResult MojoClose(MojoHandle handle); + +// Waits on the given handle until a signal indicated by |signals| is satisfied +// or until |deadline| has passed. +// +// Returns: +// |MOJO_RESULT_OK| if some signal in |signals| was satisfied (or is already +// satisfied). +// |MOJO_RESULT_INVALID_ARGUMENT| if |handle| is not a valid handle (e.g., if +// it has already been closed). +// |MOJO_RESULT_DEADLINE_EXCEEDED| if the deadline has passed without any of +// the signals being satisfied. +// |MOJO_RESULT_FAILED_PRECONDITION| if it is or becomes impossible that any +// signal in |signals| will ever be satisfied. +// +// If there are multiple waiters (on different threads, obviously) waiting on +// the same handle and signal, and that signal becomes is satisfied, all waiters +// will be awoken. +MOJO_SYSTEM_EXPORT MojoResult MojoWait(MojoHandle handle, + MojoHandleSignals signals, + MojoDeadline deadline); + +// Waits on |handles[0]|, ..., |handles[num_handles-1]| for at least one of them +// to satisfy a signal indicated by |signals[0]|, ..., |signals[num_handles-1]|, +// respectively, or until |deadline| has passed. +// +// Returns: +// The index |i| (from 0 to |num_handles-1|) if |handle[i]| satisfies a signal +// from |signals[i]|. +// |MOJO_RESULT_INVALID_ARGUMENT| if some |handle[i]| is not a valid handle +// (e.g., if it has already been closed). +// |MOJO_RESULT_DEADLINE_EXCEEDED| if the deadline has passed without any of +// handles satisfying any of its signals. +// |MOJO_RESULT_FAILED_PRECONDITION| if it is or becomes impossible that SOME +// |handle[i]| will ever satisfy any of the signals in |signals[i]|. +MOJO_SYSTEM_EXPORT MojoResult MojoWaitMany(const MojoHandle* handles, + const MojoHandleSignals* signals, + uint32_t num_handles, + MojoDeadline deadline); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // MOJO_PUBLIC_C_SYSTEM_FUNCTIONS_H_ diff --git a/chromium/mojo/public/c/system/macros.h b/chromium/mojo/public/c/system/macros.h new file mode 100644 index 00000000000..f1e3c7d6831 --- /dev/null +++ b/chromium/mojo/public/c/system/macros.h @@ -0,0 +1,72 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_C_SYSTEM_MACROS_H_ +#define MOJO_PUBLIC_C_SYSTEM_MACROS_H_ + +#include <stddef.h> + +// Annotate a variable indicating it's okay if it's unused. +// Use like: +// int x MOJO_ALLOW_UNUSED = ...; +#if defined(__GNUC__) +#define MOJO_ALLOW_UNUSED __attribute__((unused)) +#else +#define MOJO_ALLOW_UNUSED +#endif + +// Annotate a function indicating that the caller must examine the return value. +// Use like: +// int foo() MOJO_WARN_UNUSED_RESULT; +// Note that it can only be used on the prototype, and not the definition. +#if defined(__GNUC__) +#define MOJO_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +#define MOJO_WARN_UNUSED_RESULT +#endif + +// Assert things at compile time. (|msg| should be a valid identifier name.) +// This macro is currently C++-only, but we want to use it in the C core.h. +// Use like: +// MOJO_COMPILE_ASSERT(sizeof(Foo) == 12, Foo_has_invalid_size); +#if __cplusplus >= 201103L +#define MOJO_COMPILE_ASSERT(expr, msg) static_assert(expr, #msg) +#elif defined(__cplusplus) +namespace mojo { template <bool> struct CompileAssert {}; } +#define MOJO_COMPILE_ASSERT(expr, msg) \ + typedef ::mojo::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] +#else +#define MOJO_COMPILE_ASSERT(expr, msg) +#endif + +// Like the C++11 |alignof| operator. +#if __cplusplus >= 201103L +#define MOJO_ALIGNOF(type) alignof(type) +#elif defined(__GNUC__) +#define MOJO_ALIGNOF(type) __alignof__(type) +#elif defined(_MSC_VER) +// The use of |sizeof| is to work around a bug in MSVC 2010 (see +// http://goo.gl/isH0C; supposedly fixed since then). +#define MOJO_ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type)) +#else +#error "Please define MOJO_ALIGNOF() for your compiler." +#endif + +// Specify the alignment of a |struct|, etc. +// Use like: +// struct MOJO_ALIGNAS(8) Foo { ... }; +// Unlike the C++11 |alignas()|, |alignment| must be an integer. It may not be a +// type, nor can it be an expression like |MOJO_ALIGNOF(type)| (due to the +// non-C++11 MSVS version). +#if __cplusplus >= 201103L +#define MOJO_ALIGNAS(alignment) alignas(alignment) +#elif defined(__GNUC__) +#define MOJO_ALIGNAS(alignment) __attribute__((aligned(alignment))) +#elif defined(_MSC_VER) +#define MOJO_ALIGNAS(alignment) __declspec(align(alignment)) +#else +#error "Please define MOJO_ALIGNAS() for your compiler." +#endif + +#endif // MOJO_PUBLIC_C_SYSTEM_MACROS_H_ diff --git a/chromium/mojo/public/c/system/message_pipe.h b/chromium/mojo/public/c/system/message_pipe.h new file mode 100644 index 00000000000..0d0b61b7c5b --- /dev/null +++ b/chromium/mojo/public/c/system/message_pipe.h @@ -0,0 +1,178 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains types/constants and functions specific to message pipes. +// +// Note: This header should be compilable as C. + +#ifndef MOJO_PUBLIC_C_SYSTEM_MESSAGE_PIPE_H_ +#define MOJO_PUBLIC_C_SYSTEM_MESSAGE_PIPE_H_ + +#include "mojo/public/c/system/macros.h" +#include "mojo/public/c/system/system_export.h" +#include "mojo/public/c/system/types.h" + +// |MojoCreateMessagePipeOptions|: Used to specify creation parameters for a +// message pipe to |MojoCreateMessagePipe()|. +// |uint32_t struct_size|: Set to the size of the +// |MojoCreateMessagePipeOptions| struct. (Used to allow for future +// extensions.) +// |MojoCreateMessagePipeOptionsFlags flags|: Reserved for future use. +// |MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE|: No flags; default mode. + +typedef uint32_t MojoCreateMessagePipeOptionsFlags; + +#ifdef __cplusplus +const MojoCreateMessagePipeOptionsFlags + MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE = 0; +#else +#define MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE \ + ((MojoCreateMessagePipeOptionsFlags) 0) +#endif + +MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int64_t) == 8, int64_t_has_weird_alignment); +struct MOJO_ALIGNAS(8) MojoCreateMessagePipeOptions { + uint32_t struct_size; + MojoCreateMessagePipeOptionsFlags flags; +}; +MOJO_COMPILE_ASSERT(sizeof(MojoCreateMessagePipeOptions) == 8, + MojoCreateMessagePipeOptions_has_wrong_size); + +// |MojoWriteMessageFlags|: Used to specify different modes to +// |MojoWriteMessage()|. +// |MOJO_WRITE_MESSAGE_FLAG_NONE| - No flags; default mode. + +typedef uint32_t MojoWriteMessageFlags; + +#ifdef __cplusplus +const MojoWriteMessageFlags MOJO_WRITE_MESSAGE_FLAG_NONE = 0; +#else +#define MOJO_WRITE_MESSAGE_FLAG_NONE ((MojoWriteMessageFlags) 0) +#endif + +// |MojoReadMessageFlags|: Used to specify different modes to +// |MojoReadMessage()|. +// |MOJO_READ_MESSAGE_FLAG_NONE| - No flags; default mode. +// |MOJO_READ_MESSAGE_FLAG_MAY_DISCARD| - If the message is unable to be read +// for whatever reason (e.g., the caller-supplied buffer is too small), +// discard the message (i.e., simply dequeue it). + +typedef uint32_t MojoReadMessageFlags; + +#ifdef __cplusplus +const MojoReadMessageFlags MOJO_READ_MESSAGE_FLAG_NONE = 0; +const MojoReadMessageFlags MOJO_READ_MESSAGE_FLAG_MAY_DISCARD = 1 << 0; +#else +#define MOJO_READ_MESSAGE_FLAG_NONE ((MojoReadMessageFlags) 0) +#define MOJO_READ_MESSAGE_FLAG_MAY_DISCARD ((MojoReadMessageFlags) 1 << 0) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// Note: See the comment in functions.h about the meaning of the "optional" +// label for pointer parameters. + +// Creates a message pipe, which is a bidirectional communication channel for +// framed data (i.e., messages). Messages can contain plain data and/or Mojo +// handles. +// +// |options| may be set to null for a message pipe with the default options. +// +// On success, |*message_pipe_handle0| and |*message_pipe_handle1| are set to +// handles for the two endpoints (ports) for the message pipe. +// +// Returns: +// |MOJO_RESULT_OK| on success. +// |MOJO_RESULT_INVALID_ARGUMENT| if |message_pipe_handle0| and/or +// |message_pipe_handle1| do not appear to be valid pointers. +// |MOJO_RESULT_RESOURCE_EXHAUSTED| if a process/system/quota/etc. limit has +// been reached. +// +// TODO(vtl): Add an options struct pointer argument. +MOJO_SYSTEM_EXPORT MojoResult MojoCreateMessagePipe( + const struct MojoCreateMessagePipeOptions* options, // Optional. + MojoHandle* message_pipe_handle0, // Out. + MojoHandle* message_pipe_handle1); // Out. + +// Writes a message to the message pipe endpoint given by |message_pipe_handle|, +// with message data specified by |bytes| of size |num_bytes| and attached +// handles specified by |handles| of count |num_handles|, and options specified +// by |flags|. If there is no message data, |bytes| may be null, in which case +// |num_bytes| must be zero. If there are no attached handles, |handles| may be +// null, in which case |num_handles| must be zero. +// +// If handles are attached, on success the handles will no longer be valid (the +// receiver will receive equivalent, but logically different, handles). Handles +// to be sent should not be in simultaneous use (e.g., on another thread). +// +// Returns: +// |MOJO_RESULT_OK| on success (i.e., the message was enqueued). +// |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g., if +// |message_pipe_handle| is not a valid handle, or some of the +// requirements above are not satisfied). +// |MOJO_RESULT_RESOURCE_EXHAUSTED| if some system limit has been reached, or +// the number of handles to send is too large (TODO(vtl): reconsider the +// latter case). +// |MOJO_RESULT_FAILED_PRECONDITION| if the other endpoint has been closed. +// Note that closing an endpoint is not necessarily synchronous (e.g., +// across processes), so this function may be succeed even if the other +// endpoint has been closed (in which case the message would be dropped). +// |MOJO_RESULT_BUSY| if some handle to be sent is currently in use. +// +// TODO(vtl): Add a notion of capacity for message pipes, and return +// |MOJO_RESULT_SHOULD_WAIT| if the message pipe is full. +MOJO_SYSTEM_EXPORT MojoResult MojoWriteMessage( + MojoHandle message_pipe_handle, + const void* bytes, // Optional. + uint32_t num_bytes, + const MojoHandle* handles, // Optional. + uint32_t num_handles, + MojoWriteMessageFlags flags); + +// Reads a message from the message pipe endpoint given by +// |message_pipe_handle|; also usable to query the size of the next message or +// discard the next message. |bytes|/|*num_bytes| indicate the buffer/buffer +// size to receive the message data (if any) and |handles|/|*num_handles| +// indicate the buffer/maximum handle count to receive the attached handles (if +// any). +// +// |num_bytes| and |num_handles| are optional "in-out" parameters. If non-null, +// on return |*num_bytes| and |*num_handles| will usually indicate the number +// of bytes and number of attached handles in the "next" message, respectively, +// whether that message was read or not. (If null, the number of bytes/handles +// is treated as zero.) +// +// If |bytes| is null, then |*num_bytes| must be zero, and similarly for +// |handles| and |*num_handles|. +// +// Partial reads are NEVER done. Either a full read is done and |MOJO_RESULT_OK| +// returned, or the read is NOT done and |MOJO_RESULT_RESOURCE_EXHAUSTED| is +// returned (if |MOJO_READ_MESSAGE_FLAG_MAY_DISCARD| was set, the message is +// also discarded in this case). +// +// Returns: +// |MOJO_RESULT_OK| on success (i.e., a message was actually read). +// |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid. +// |MOJO_RESULT_FAILED_PRECONDITION| if the other endpoint has been closed. +// |MOJO_RESULT_RESOURCE_EXHAUSTED| if one of the buffers to receive the +// message/attached handles (|bytes|/|*num_bytes| or +// |handles|/|*num_handles|) was too small. (TODO(vtl): Reconsider this +// error code; should distinguish this from the hitting-system-limits +// case.) +// |MOJO_RESULT_SHOULD_WAIT| if no message was available to be read. +MOJO_SYSTEM_EXPORT MojoResult MojoReadMessage( + MojoHandle message_pipe_handle, + void* bytes, // Optional out. + uint32_t* num_bytes, // Optional in/out. + MojoHandle* handles, // Optional out. + uint32_t* num_handles, // Optional in/out. + MojoReadMessageFlags flags); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // MOJO_PUBLIC_C_SYSTEM_MESSAGE_PIPE_H_ diff --git a/chromium/mojo/public/c/system/system_export.h b/chromium/mojo/public/c/system/system_export.h new file mode 100644 index 00000000000..bc3b459843f --- /dev/null +++ b/chromium/mojo/public/c/system/system_export.h @@ -0,0 +1,33 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_C_SYSTEM_SYSTEM_EXPORT_H_ +#define MOJO_PUBLIC_C_SYSTEM_SYSTEM_EXPORT_H_ + +#if defined(COMPONENT_BUILD) && defined(MOJO_USE_SYSTEM_IMPL) +#if defined(WIN32) + +#if defined(MOJO_SYSTEM_IMPLEMENTATION) +#define MOJO_SYSTEM_EXPORT __declspec(dllexport) +#else +#define MOJO_SYSTEM_EXPORT __declspec(dllimport) +#endif + +#else // !defined(WIN32) + +#if defined(MOJO_SYSTEM_IMPLEMENTATION) +#define MOJO_SYSTEM_EXPORT __attribute__((visibility("default"))) +#else +#define MOJO_SYSTEM_EXPORT +#endif + +#endif // defined(WIN32) + +#else // !defined(COMPONENT_BUILD) || !defined(MOJO_USE_SYSTEM_IMPL) + +#define MOJO_SYSTEM_EXPORT + +#endif // defined(COMPONENT_BUILD) && defined(MOJO_USE_SYSTEM_IMPL) + +#endif // MOJO_PUBLIC_C_SYSTEM_SYSTEM_EXPORT_H_ diff --git a/chromium/mojo/public/c/system/types.h b/chromium/mojo/public/c/system/types.h new file mode 100644 index 00000000000..e992d110e3a --- /dev/null +++ b/chromium/mojo/public/c/system/types.h @@ -0,0 +1,176 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains types and constants/macros common to different Mojo system +// APIs. +// +// Note: This header should be compilable as C. + +#ifndef MOJO_PUBLIC_C_SYSTEM_TYPES_H_ +#define MOJO_PUBLIC_C_SYSTEM_TYPES_H_ + +#include <stdint.h> + +#include "mojo/public/c/system/macros.h" + +// TODO(vtl): Notes: Use of undefined flags will lead to undefined behavior +// (typically they'll be ignored), not necessarily an error. + +// |MojoTimeTicks|: Used to specify time ticks. Value is in microseconds. + +typedef int64_t MojoTimeTicks; + +// |MojoHandle|: Handles to Mojo objects. +// |MOJO_HANDLE_INVALID| - A value that is never a valid handle. + +typedef uint32_t MojoHandle; + +#ifdef __cplusplus +const MojoHandle MOJO_HANDLE_INVALID = 0; +#else +#define MOJO_HANDLE_INVALID ((MojoHandle) 0) +#endif + +// |MojoResult|: Result codes for Mojo operations. Non-negative values are +// success codes; negative values are error/failure codes. +// |MOJO_RESULT_OK| - Not an error; returned on success. Note that positive +// |MojoResult|s may also be used to indicate success. +// |MOJO_RESULT_CANCELLED| - Operation was cancelled, typically by the caller. +// |MOJO_RESULT_UNKNOWN| - Unknown error (e.g., if not enough information is +// available for a more specific error). +// |MOJO_RESULT_INVALID_ARGUMENT| - Caller specified an invalid argument. This +// differs from |MOJO_RESULT_FAILED_PRECONDITION| in that the former +// indicates arguments that are invalid regardless of the state of the +// system. +// |MOJO_RESULT_DEADLINE_EXCEEDED| - Deadline expired before the operation +// could complete. +// |MOJO_RESULT_NOT_FOUND| - Some requested entity was not found (i.e., does +// not exist). +// |MOJO_RESULT_ALREADY_EXISTS| - Some entity or condition that we attempted +// to create already exists. +// |MOJO_RESULT_PERMISSION_DENIED| - The caller does not have permission to +// for the operation (use |MOJO_RESULT_RESOURCE_EXHAUSTED| for rejections +// caused by exhausting some resource instead). +// |MOJO_RESULT_RESOURCE_EXHAUSTED| - Some resource required for the call +// (possibly some quota) has been exhausted. +// |MOJO_RESULT_FAILED_PRECONDITION| - The system is not in a state required +// for the operation (use this if the caller must do something to rectify +// the state before retrying). +// |MOJO_RESULT_ABORTED| - The operation was aborted by the system, possibly +// due to a concurrency issue (use this if the caller may retry at a +// higher level). +// |MOJO_RESULT_OUT_OF_RANGE| - The operation was attempted past the valid +// range. Unlike |MOJO_RESULT_INVALID_ARGUMENT|, this indicates that the +// operation may be/become valid depending on the system state. (This +// error is similar to |MOJO_RESULT_FAILED_PRECONDITION|, but is more +// specific.) +// |MOJO_RESULT_UNIMPLEMENTED| - The operation is not implemented, supported, +// or enabled. +// |MOJO_RESULT_INTERNAL| - Internal error: this should never happen and +// indicates that some invariant expected by the system has been broken. +// |MOJO_RESULT_UNAVAILABLE| - The operation is (temporarily) currently +// unavailable. The caller may simply retry the operation (possibly with a +// backoff). +// |MOJO_RESULT_DATA_LOSS| - Unrecoverable data loss or corruption. +// |MOJO_RESULT_BUSY| - One of the resources involved is currently being used +// (possibly on another thread) in a way that prevents the current +// operation from proceeding, e.g., if the other operation may result in +// the resource being invalidated. +// |MOJO_RESULT_SHOULD_WAIT| - The request cannot currently be completed +// (e.g., if the data requested is not yet available). The caller should +// wait for it to be feasible using |MojoWait()| or |MojoWaitMany()|. +// +// Note that positive values are also available as success codes. +// +// The codes from |MOJO_RESULT_OK| to |MOJO_RESULT_DATA_LOSS| come from +// Google3's canonical error codes. +// +// TODO(vtl): Add a |MOJO_RESULT_UNSATISFIABLE|? + +typedef int32_t MojoResult; + +#ifdef __cplusplus +const MojoResult MOJO_RESULT_OK = 0; +const MojoResult MOJO_RESULT_CANCELLED = -1; +const MojoResult MOJO_RESULT_UNKNOWN = -2; +const MojoResult MOJO_RESULT_INVALID_ARGUMENT = -3; +const MojoResult MOJO_RESULT_DEADLINE_EXCEEDED = -4; +const MojoResult MOJO_RESULT_NOT_FOUND = -5; +const MojoResult MOJO_RESULT_ALREADY_EXISTS = -6; +const MojoResult MOJO_RESULT_PERMISSION_DENIED = -7; +const MojoResult MOJO_RESULT_RESOURCE_EXHAUSTED = -8; +const MojoResult MOJO_RESULT_FAILED_PRECONDITION = -9; +const MojoResult MOJO_RESULT_ABORTED = -10; +const MojoResult MOJO_RESULT_OUT_OF_RANGE = -11; +const MojoResult MOJO_RESULT_UNIMPLEMENTED = -12; +const MojoResult MOJO_RESULT_INTERNAL = -13; +const MojoResult MOJO_RESULT_UNAVAILABLE = -14; +const MojoResult MOJO_RESULT_DATA_LOSS = -15; +const MojoResult MOJO_RESULT_BUSY = -16; +const MojoResult MOJO_RESULT_SHOULD_WAIT = -17; +#else +#define MOJO_RESULT_OK ((MojoResult) 0) +#define MOJO_RESULT_CANCELLED ((MojoResult) -1) +#define MOJO_RESULT_UNKNOWN ((MojoResult) -2) +#define MOJO_RESULT_INVALID_ARGUMENT ((MojoResult) -3) +#define MOJO_RESULT_DEADLINE_EXCEEDED ((MojoResult) -4) +#define MOJO_RESULT_NOT_FOUND ((MojoResult) -5) +#define MOJO_RESULT_ALREADY_EXISTS ((MojoResult) -6) +#define MOJO_RESULT_PERMISSION_DENIED ((MojoResult) -7) +#define MOJO_RESULT_RESOURCE_EXHAUSTED ((MojoResult) -8) +#define MOJO_RESULT_FAILED_PRECONDITION ((MojoResult) -9) +#define MOJO_RESULT_ABORTED ((MojoResult) -10) +#define MOJO_RESULT_OUT_OF_RANGE ((MojoResult) -11) +#define MOJO_RESULT_UNIMPLEMENTED ((MojoResult) -12) +#define MOJO_RESULT_INTERNAL ((MojoResult) -13) +#define MOJO_RESULT_UNAVAILABLE ((MojoResult) -14) +#define MOJO_RESULT_DATA_LOSS ((MojoResult) -15) +#define MOJO_RESULT_BUSY ((MojoResult) -16) +#define MOJO_RESULT_SHOULD_WAIT ((MojoResult) -17) +#endif + +// |MojoDeadline|: Used to specify deadlines (timeouts), in microseconds (except +// for |MOJO_DEADLINE_INDEFINITE|). +// |MOJO_DEADLINE_INDEFINITE| - Used to indicate "forever". + +typedef uint64_t MojoDeadline; + +#ifdef __cplusplus +const MojoDeadline MOJO_DEADLINE_INDEFINITE = static_cast<MojoDeadline>(-1); +#else +#define MOJO_DEADLINE_INDEFINITE ((MojoDeadline) -1) +#endif + +// |MojoHandleSignals|: Used to specify signals that can be waited on for a +// handle (and which can be triggered), e.g., the ability to read or write to +// the handle. +// |MOJO_HANDLE_SIGNAL_NONE| - No flags. |MojoWait()|, etc. will return +// |MOJO_RESULT_FAILED_PRECONDITION| if you attempt to wait on this. +// |MOJO_HANDLE_SIGNAL_READABLE| - Can read (e.g., a message) from the handle. +// |MOJO_HANDLE_SIGNAL_WRITABLE| - Can write (e.g., a message) to the handle. + +typedef uint32_t MojoHandleSignals; + +#ifdef __cplusplus +const MojoHandleSignals MOJO_HANDLE_SIGNAL_NONE = 0; +const MojoHandleSignals MOJO_HANDLE_SIGNAL_READABLE = 1 << 0; +const MojoHandleSignals MOJO_HANDLE_SIGNAL_WRITABLE = 1 << 1; +#else +#define MOJO_HANDLE_SIGNAL_NONE ((MojoHandleSignals) 0) +#define MOJO_HANDLE_SIGNAL_READABLE ((MojoHandleSignals) 1 << 0) +#define MOJO_HANDLE_SIGNAL_WRITABLE ((MojoHandleSignals) 1 << 1) +#endif + +// TODO(vtl): Add out parameters with this to MojoWait/MojoWaitMany. +// Note: This struct is not extensible (and only has 32-bit quantities), so it's +// 32-bit-aligned. +MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int32_t) == 4, int32_t_has_weird_alignment); +struct MOJO_ALIGNAS(4) MojoHandleSignalsState { + MojoHandleSignals satisfied_signals; + MojoHandleSignals satisfiable_signals; +}; +MOJO_COMPILE_ASSERT(sizeof(MojoHandleSignalsState) == 8, + MojoHandleSignalsState_has_wrong_size); + +#endif // MOJO_PUBLIC_C_SYSTEM_TYPES_H_ diff --git a/chromium/mojo/public/c/test_support/test_support.h b/chromium/mojo/public/c/test_support/test_support.h new file mode 100644 index 00000000000..2b686b272eb --- /dev/null +++ b/chromium/mojo/public/c/test_support/test_support.h @@ -0,0 +1,48 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_C_TEST_SUPPORT_TEST_SUPPORT_H_ +#define MOJO_PUBLIC_C_TEST_SUPPORT_TEST_SUPPORT_H_ + +// Note: This header should be compilable as C. + +#include <stdio.h> + +#include "mojo/public/c/test_support/test_support_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +MOJO_TEST_SUPPORT_EXPORT void MojoTestSupportLogPerfResult( + const char* test_name, + double value, + const char* units); + +// Opens a "/"-delimited file path relative to the source root. +MOJO_TEST_SUPPORT_EXPORT FILE* MojoTestSupportOpenSourceRootRelativeFile( + const char* source_root_relative_path); + +// Enumerates a "/"-delimited directory path relative to the source root. +// Returns only regular files. The return value is a heap-allocated array of +// heap-allocated strings. Each must be free'd separately. +// +// The return value is built like so: +// +// char** rv = (char**) calloc(N + 1, sizeof(char*)); +// rv[0] = strdup("a"); +// rv[1] = strdup("b"); +// rv[2] = strdup("c"); +// ... +// rv[N] = NULL; +// +MOJO_TEST_SUPPORT_EXPORT +char** MojoTestSupportEnumerateSourceRootRelativeDirectory( + const char* source_root_relative_path); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // MOJO_PUBLIC_C_TEST_SUPPORT_TEST_SUPPORT_H_ diff --git a/chromium/mojo/public/c/test_support/test_support_export.h b/chromium/mojo/public/c/test_support/test_support_export.h new file mode 100644 index 00000000000..e22a9e30144 --- /dev/null +++ b/chromium/mojo/public/c/test_support/test_support_export.h @@ -0,0 +1,26 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_C_TEST_SUPPORT_TEST_SUPPORT_EXPORT_H_ +#define MOJO_PUBLIC_C_TEST_SUPPORT_TEST_SUPPORT_EXPORT_H_ + +#if defined(WIN32) + +#if defined(MOJO_TEST_SUPPORT_IMPLEMENTATION) +#define MOJO_TEST_SUPPORT_EXPORT __declspec(dllexport) +#else +#define MOJO_TEST_SUPPORT_EXPORT __declspec(dllimport) +#endif + +#else // !defined(WIN32) + +#if defined(MOJO_TEST_SUPPORT_IMPLEMENTATION) +#define MOJO_TEST_SUPPORT_EXPORT __attribute__((visibility("default"))) +#else +#define MOJO_TEST_SUPPORT_EXPORT +#endif + +#endif // defined(WIN32) + +#endif // MOJO_PUBLIC_C_TEST_SUPPORT_TEST_SUPPORT_EXPORT_H_ diff --git a/chromium/mojo/public/cpp/DEPS b/chromium/mojo/public/cpp/DEPS new file mode 100644 index 00000000000..74acd7c7ed3 --- /dev/null +++ b/chromium/mojo/public/cpp/DEPS @@ -0,0 +1,18 @@ +include_rules = [ + # Require explicit dependencies in each directory. + "-mojo/public", + # But everyone can depend on the C and C++ system headers. + "+mojo/public/c/system", + "+mojo/public/cpp/system", + # Ditto for the C environment headers (but not the C++ environment, since it + # has dependencies of its own). + "+mojo/public/c/environment", +] + +specific_include_rules = { + r".*_(unit|perf)test\.cc": [ + "+testing", + "+mojo/public/cpp/test_support", + "+mojo/public/cpp/utility", + ], +} diff --git a/chromium/mojo/public/cpp/README.md b/chromium/mojo/public/cpp/README.md new file mode 100644 index 00000000000..8f03d984b9a --- /dev/null +++ b/chromium/mojo/public/cpp/README.md @@ -0,0 +1,71 @@ +Mojo Public C++ API +=================== + +This directory contains C++ language bindings for the Mojo Public API. + +A number of subdirectories provide wrappers for the lower-level C APIs (in +subdirectories of the same name, under mojo/public/c/). Typically, these +wrappers provide increased convenience and/or type-safety. + +Other subdirectories provide support (static) libraries of various sorts. In +this case, the organization is to have the public interface for the library in +defined in header files in the subdirectory itself and the implementation of the +library at a lower level, under a lib (sub)subdirectory. A developer should be +able to substitute their own implementation of any such support library, and +expect other support libraries, which may depend on that library, to work +properly. + +Bindings +-------- + +The bindings/ subdirectory contains a support (static) library needed by the +code generated by the bindings generator tool (in mojo/public/tools/bindings/), +which translates Mojo IDL (.mojom) files into idiomatic C++ (among other +languages). + +This library depends on the Environment library. + +Environment +----------- + +The environment/ subdirectory contains a support (static) library that +represents shared state needed to support the Bindings and GLES2 libraries. + +This library depends on the Utility library. + + +GLES2 +----- + +The gles2/ subdirectory contains C++ wrappers (and some additional helpers) of +the API defined in mojo/public/c/gles2/ (which provides access to GLES2). + +These wrappers depend on the Environment library. + +Shell +----- + +The shell/ subdirectory contains a support (static) library that aids in writing +Mojo applications and interacting with the Shell service. + +System +------ + +The system/ subdirectory contains C++ wrappers (and some additional helpers) of +the API defined in mojo/public/c/system/, which defines the basic, "core" API, +especially used to communicate with Mojo services. + +Test Support +------------ + +The test_support/ subdirectory contains C++ wrappers of the test-only API +defined in mojo/public/c/test_support/. It is not meant for general use by Mojo +applications. + +Utility +------- + +The utility/ subdirectory contains a support (static) library that provides +various basic functionality. Most notably, it provides an implementation of a +RunLoop based on MojoWaitMany() that applications may use as the basis for +asynchronous message processing. diff --git a/chromium/mojo/public/cpp/application/DEPS b/chromium/mojo/public/cpp/application/DEPS new file mode 100644 index 00000000000..e808b79707e --- /dev/null +++ b/chromium/mojo/public/cpp/application/DEPS @@ -0,0 +1,14 @@ +include_rules = [ + "+mojo/public/cpp/bindings", + "+mojo/public/interfaces/service_provider", +] + +specific_include_rules = { + "mojo_main_chromium.cc": [ + "+base", + "+mojo/public/cpp" + ], + "mojo_main_standalone.cc": [ + "+mojo/public/cpp" + ], +} diff --git a/chromium/mojo/public/cpp/application/application.h b/chromium/mojo/public/cpp/application/application.h new file mode 100644 index 00000000000..da7a0ed7c61 --- /dev/null +++ b/chromium/mojo/public/cpp/application/application.h @@ -0,0 +1,121 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_APPLICATION_APPLICATION_H_ +#define MOJO_PUBLIC_APPLICATION_APPLICATION_H_ +#include <vector> + +#include "mojo/public/cpp/application/connect.h" +#include "mojo/public/cpp/application/lib/service_connector.h" +#include "mojo/public/cpp/system/core.h" +#include "mojo/public/interfaces/service_provider/service_provider.mojom.h" + +#if defined(WIN32) +#if !defined(CDECL) +#define CDECL __cdecl +#endif +#define APPLICATION_EXPORT __declspec(dllexport) +#else +#define CDECL +#define APPLICATION_EXPORT __attribute__((visibility("default"))) +#endif + +// DSOs can either implement MojoMain directly or include +// mojo_main_{standalone|chromium}.cc in their project and implement +// Application::Create(); +// TODO(davemoore): Establish this as part of our SDK for third party mojo +// application writers. +extern "C" APPLICATION_EXPORT MojoResult CDECL MojoMain( + MojoHandle service_provider_handle); + +namespace mojo { + +// Utility class for creating ServiceProviders that vend service instances. +// To use define a class that implements your specific server api, e.g. FooImpl +// to implement a service named Foo. +// That class must subclass an InterfaceImpl specialization. +// +// If there is context that is to be shared amongst all instances, define a +// constructor with that class as its only argument, otherwise define an empty +// constructor. +// +// class FooImpl : public InterfaceImpl<Foo> { +// public: +// FooImpl() {} +// }; +// +// or +// +// class BarImpl : public InterfaceImpl<Bar> { +// public: +// // context will remain valid for the lifetime of BarImpl. +// BarImpl(BarContext* context) : context_(context) {} +// private: +// BarContext* context; +// }; +// +// Create an Application instance that collects any service implementations. +// +// Application app(service_provider_handle); +// app.AddService<FooImpl>(); +// +// BarContext context; +// app.AddService<BarImpl>(&context); +// +// +class Application { + public: + Application(); + explicit Application(ScopedMessagePipeHandle service_provider_handle); + explicit Application(MojoHandle service_provider_handle); + virtual ~Application(); + + // Override this method to control what urls are allowed to connect to a + // service. + virtual bool AllowIncomingConnection(const mojo::String& service_name, + const mojo::String& requestor_url); + + template <typename Impl, typename Context> + void AddService(Context* context) { + service_registry_.AddServiceConnector( + new internal::ServiceConnector<Impl, Context>(Impl::Name_, context)); + } + + template <typename Impl> + void AddService() { + service_registry_.AddServiceConnector( + new internal::ServiceConnector<Impl, void>(Impl::Name_, NULL)); + } + + template <typename Interface> + void ConnectTo(const std::string& url, InterfacePtr<Interface>* ptr) { + mojo::ConnectToService(service_provider(), url, ptr); + } + + ServiceProvider* service_provider() { + return service_registry_.remote_service_provider(); + } + + void BindServiceProvider(ScopedMessagePipeHandle service_provider_handle); + + protected: + // Override this to do any necessary initialization. There's no need to call + // Application's implementation. + // The service_provider will be bound to its pipe before this is called. + virtual void Initialize(); + + private: + friend MojoResult (::MojoMain)(MojoHandle); + + // Implement this method to create the specific subclass of Application. + static Application* Create(); + + internal::ServiceRegistry service_registry_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Application); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_APPLICATION_APPLICATION_H_ diff --git a/chromium/mojo/public/cpp/application/connect.h b/chromium/mojo/public/cpp/application/connect.h new file mode 100644 index 00000000000..e4ba641e2ed --- /dev/null +++ b/chromium/mojo/public/cpp/application/connect.h @@ -0,0 +1,24 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_APPLICATION_CONNECT_H_ +#define MOJO_PUBLIC_CPP_APPLICATION_CONNECT_H_ + +#include "mojo/public/interfaces/service_provider/service_provider.mojom.h" + +namespace mojo { + +template <typename Interface> +inline void ConnectToService(ServiceProvider* service_provider, + const std::string& url, + InterfacePtr<Interface>* ptr) { + MessagePipe pipe; + ptr->Bind(pipe.handle0.Pass()); + service_provider->ConnectToService( + url, Interface::Name_, pipe.handle1.Pass(), std::string()); +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_APPLICATION_CONNECT_H_ diff --git a/chromium/mojo/public/cpp/application/lib/application.cc b/chromium/mojo/public/cpp/application/lib/application.cc new file mode 100644 index 00000000000..78f5a8bbd0e --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/application.cc @@ -0,0 +1,34 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/application/application.h" + +namespace mojo { + +Application::Application() : service_registry_(this) {} + +Application::Application(ScopedMessagePipeHandle service_provider_handle) + : service_registry_(this, service_provider_handle.Pass()) {} + +Application::Application(MojoHandle service_provider_handle) + : service_registry_( + this, + mojo::MakeScopedHandle( + MessagePipeHandle(service_provider_handle)).Pass()) {} + +Application::~Application() {} + +bool Application::AllowIncomingConnection(const mojo::String& service_name, + const mojo::String& requestor_url) { + return true; +} + +void Application::BindServiceProvider( + ScopedMessagePipeHandle service_provider_handle) { + service_registry_.BindRemoteServiceProvider(service_provider_handle.Pass()); +} + +void Application::Initialize() {} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/application/lib/mojo_main_chromium.cc b/chromium/mojo/public/cpp/application/lib/mojo_main_chromium.cc new file mode 100644 index 00000000000..cda7cd02d18 --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/mojo_main_chromium.cc @@ -0,0 +1,23 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/message_loop/message_loop.h" +#include "mojo/public/cpp/application/application.h" + +extern "C" APPLICATION_EXPORT MojoResult CDECL MojoMain( + MojoHandle service_provider_handle) { + base::CommandLine::Init(0, NULL); + base::AtExitManager at_exit; + base::MessageLoop loop; + + scoped_ptr<mojo::Application> app(mojo::Application::Create()); + app->BindServiceProvider( + mojo::MakeScopedHandle(mojo::MessagePipeHandle(service_provider_handle))); + app->Initialize(); + loop.Run(); + + return MOJO_RESULT_OK; +} diff --git a/chromium/mojo/public/cpp/application/lib/mojo_main_standalone.cc b/chromium/mojo/public/cpp/application/lib/mojo_main_standalone.cc new file mode 100644 index 00000000000..05825aa3319 --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/mojo_main_standalone.cc @@ -0,0 +1,22 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/application/application.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/utility/run_loop.h" + +extern "C" APPLICATION_EXPORT MojoResult CDECL MojoMain( + MojoHandle service_provider_handle) { + mojo::Environment env; + mojo::RunLoop loop; + + mojo::Application* app = mojo::Application::Create(); + app->BindServiceProvider( + mojo::MakeScopedHandle(mojo::MessagePipeHandle(service_provider_handle))); + app->Initialize(); + loop.Run(); + delete app; + + return MOJO_RESULT_OK; +} diff --git a/chromium/mojo/public/cpp/application/lib/service_connector.cc b/chromium/mojo/public/cpp/application/lib/service_connector.cc new file mode 100644 index 00000000000..5cc4421b7aa --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/service_connector.cc @@ -0,0 +1,18 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/application/lib/service_connector.h" + +namespace mojo { +namespace internal { + +ServiceConnectorBase::ServiceConnectorBase(const std::string& name) + : name_(name), + registry_(NULL) { +} + +ServiceConnectorBase::~ServiceConnectorBase() {} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/application/lib/service_connector.h b/chromium/mojo/public/cpp/application/lib/service_connector.h new file mode 100644 index 00000000000..30786adb55d --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/service_connector.h @@ -0,0 +1,133 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_CONNECTOR_H_ +#define MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_CONNECTOR_H_ + +#include <assert.h> + +#include <vector> + +#include "mojo/public/cpp/application/lib/service_registry.h" +#include "mojo/public/interfaces/service_provider/service_provider.mojom.h" + +namespace mojo { +namespace internal { + +template <class ServiceImpl, typename Context> +class ServiceConnector; + +// Specialization of ServiceConnection. +// ServiceImpl: Subclass of InterfaceImpl<...>. +// Context: Type of shared context. +template <class ServiceImpl, typename Context> +class ServiceConnection : public ServiceImpl { + public: + ServiceConnection() : ServiceImpl() {} + ServiceConnection(Context* context) : ServiceImpl(context) {} + + virtual void OnConnectionError() MOJO_OVERRIDE { + service_connector_->RemoveConnection(static_cast<ServiceImpl*>(this)); + ServiceImpl::OnConnectionError(); + } + +private: + friend class ServiceConnector<ServiceImpl, Context>; + + // Called shortly after this class is instantiated. + void set_service_connector( + ServiceConnector<ServiceImpl, Context>* connector) { + service_connector_ = connector; + } + + ServiceConnector<ServiceImpl, Context>* service_connector_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceConnection); +}; + +template <typename ServiceImpl, typename Context> +struct ServiceConstructor { + static ServiceConnection<ServiceImpl, Context>* New(Context* context) { + return new ServiceConnection<ServiceImpl, Context>(context); + } +}; + +template <typename ServiceImpl> +struct ServiceConstructor<ServiceImpl, void> { + public: + static ServiceConnection<ServiceImpl, void>* New(void* context) { + return new ServiceConnection<ServiceImpl, void>(); + } +}; + +class ServiceConnectorBase { + public: + ServiceConnectorBase(const std::string& name); + virtual ~ServiceConnectorBase(); + virtual void ConnectToService(const std::string& url, + const std::string& name, + ScopedMessagePipeHandle client_handle) = 0; + std::string name() const { return name_; } + void set_registry(ServiceRegistry* registry) { registry_ = registry; } + + protected: + std::string name_; + ServiceRegistry* registry_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceConnectorBase); +}; + +template <class ServiceImpl, typename Context=void> +class ServiceConnector : public internal::ServiceConnectorBase { + public: + ServiceConnector(const std::string& name, Context* context = NULL) + : ServiceConnectorBase(name), context_(context) {} + + virtual ~ServiceConnector() { + ConnectionList doomed; + doomed.swap(connections_); + for (typename ConnectionList::iterator it = doomed.begin(); + it != doomed.end(); ++it) { + delete *it; + } + assert(connections_.empty()); // No one should have added more! + } + + virtual void ConnectToService(const std::string& url, + const std::string& name, + ScopedMessagePipeHandle handle) MOJO_OVERRIDE { + ServiceConnection<ServiceImpl, Context>* impl = + ServiceConstructor<ServiceImpl, Context>::New(context_); + impl->set_service_connector(this); + BindToPipe(impl, handle.Pass()); + + connections_.push_back(impl); + } + + void RemoveConnection(ServiceImpl* impl) { + // Called from ~ServiceImpl, in response to a connection error. + for (typename ConnectionList::iterator it = connections_.begin(); + it != connections_.end(); ++it) { + if (*it == impl) { + delete impl; + connections_.erase(it); + return; + } + } + } + + Context* context() const { return context_; } + + private: + typedef std::vector<ServiceImpl*> ConnectionList; + ConnectionList connections_; + Context* context_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceConnector); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_CONNECTOR_H_ diff --git a/chromium/mojo/public/cpp/application/lib/service_registry.cc b/chromium/mojo/public/cpp/application/lib/service_registry.cc new file mode 100644 index 00000000000..bc901dfb924 --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/service_registry.cc @@ -0,0 +1,78 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/application/lib/service_registry.h" + +#include "mojo/public/cpp/application/application.h" +#include "mojo/public/cpp/application/lib/service_connector.h" + +namespace mojo { +namespace internal { + +ServiceRegistry::ServiceRegistry(Application* application) + : application_(application) { +} + +ServiceRegistry::ServiceRegistry( + Application* application, + ScopedMessagePipeHandle service_provider_handle) + : application_(application) { + remote_service_provider_.Bind(service_provider_handle.Pass()); + remote_service_provider_.set_client(this); +} + +ServiceRegistry::~ServiceRegistry() { + for (NameToServiceConnectorMap::iterator i = + name_to_service_connector_.begin(); + i != name_to_service_connector_.end(); ++i) { + delete i->second; + } + name_to_service_connector_.clear(); +} + +void ServiceRegistry::AddServiceConnector( + ServiceConnectorBase* service_connector) { + name_to_service_connector_[service_connector->name()] = service_connector; + service_connector->set_registry(this); +} + +void ServiceRegistry::RemoveServiceConnector( + ServiceConnectorBase* service_connector) { + NameToServiceConnectorMap::iterator it = + name_to_service_connector_.find(service_connector->name()); + assert(it != name_to_service_connector_.end()); + delete it->second; + name_to_service_connector_.erase(it); + if (name_to_service_connector_.empty()) + remote_service_provider_.reset(); +} + +void ServiceRegistry::BindRemoteServiceProvider( + ScopedMessagePipeHandle service_provider_handle) { + remote_service_provider_.Bind(service_provider_handle.Pass()); + remote_service_provider_.set_client(this); +} + +void ServiceRegistry::ConnectToService(const mojo::String& service_url, + const mojo::String& service_name, + ScopedMessagePipeHandle client_handle, + const mojo::String& requestor_url) { + if (name_to_service_connector_.find(service_name) == + name_to_service_connector_.end() || + !application_->AllowIncomingConnection(service_name, requestor_url)) { + client_handle.reset(); + return; + } + + internal::ServiceConnectorBase* service_connector = + name_to_service_connector_[service_name]; + assert(service_connector); + // requestor_url is ignored because the service_connector stores the url + // of the requestor safely. + return service_connector->ConnectToService( + service_url, service_name, client_handle.Pass()); +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/application/lib/service_registry.h b/chromium/mojo/public/cpp/application/lib/service_registry.h new file mode 100644 index 00000000000..478cd055ef2 --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/service_registry.h @@ -0,0 +1,55 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_REGISTRY_H_ +#define MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_REGISTRY_H_ + +#include "mojo/public/interfaces/service_provider/service_provider.mojom.h" + +namespace mojo { + +class Application; + +namespace internal { + +class ServiceConnectorBase; + +class ServiceRegistry : public ServiceProvider { + public: + ServiceRegistry(Application* application); + ServiceRegistry(Application* application, + ScopedMessagePipeHandle service_provider_handle); + virtual ~ServiceRegistry(); + + void AddServiceConnector(ServiceConnectorBase* service_connector); + void RemoveServiceConnector(ServiceConnectorBase* service_connector); + + ServiceProvider* remote_service_provider() { + return remote_service_provider_.get(); + } + + void BindRemoteServiceProvider( + ScopedMessagePipeHandle service_provider_handle); + + // ServiceProvider method. + virtual void ConnectToService(const mojo::String& service_url, + const mojo::String& service_name, + ScopedMessagePipeHandle client_handle, + const mojo::String& requestor_url) + MOJO_OVERRIDE; + + private: + Application* application_; + typedef std::map<std::string, ServiceConnectorBase*> + NameToServiceConnectorMap; + NameToServiceConnectorMap name_to_service_connector_; + ServiceProviderPtr remote_service_provider_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceRegistry); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_REGISTRY_H_ diff --git a/chromium/mojo/public/cpp/bindings/BUILD.gn b/chromium/mojo/public/cpp/bindings/BUILD.gn new file mode 100644 index 00000000000..2cc35aa52ff --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/BUILD.gn @@ -0,0 +1,53 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("bindings") { + sources = [ + "array.h", + "callback.h", + "error_handler.h", + "interface_ptr.h", + "message.h", + "message_filter.h", + "no_interface.h", + "string.h", + "struct_ptr.h", + "sync_dispatcher.h", + "type_converter.h", + "lib/array_internal.cc", + "lib/array_internal.h", + "lib/array_serialization.h", + "lib/bindings_internal.h", + "lib/bindings_serialization.cc", + "lib/bindings_serialization.h", + "lib/bounds_checker.cc", + "lib/bounds_checker.h", + "lib/buffer.h", + "lib/callback_internal.h", + "lib/connector.cc", + "lib/connector.h", + "lib/filter_chain.cc", + "lib/filter_chain.h", + "lib/fixed_buffer.cc", + "lib/fixed_buffer.h", + "lib/message.cc", + "lib/message_builder.cc", + "lib/message_builder.h", + "lib/message_filter.cc", + "lib/message_internal.h", + "lib/message_queue.cc", + "lib/message_queue.h", + "lib/no_interface.cc", + "lib/router.cc", + "lib/router.h", + "lib/shared_data.h", + "lib/shared_ptr.h", + "lib/string_serialization.cc", + "lib/string_serialization.h", + "lib/sync_dispatcher.cc", + "lib/template_util.h", + "lib/validation_errors.cc", + "lib/validation_errors.h", + ] +} diff --git a/chromium/mojo/public/cpp/bindings/DEPS b/chromium/mojo/public/cpp/bindings/DEPS new file mode 100644 index 00000000000..2a0496e9d9c --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+mojo/public/cpp/environment", +] diff --git a/chromium/mojo/public/cpp/bindings/array.h b/chromium/mojo/public/cpp/bindings/array.h new file mode 100644 index 00000000000..daf7125bb3c --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/array.h @@ -0,0 +1,143 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_ + +#include <string.h> + +#include <algorithm> +#include <string> +#include <vector> + +#include "mojo/public/cpp/bindings/lib/array_internal.h" +#include "mojo/public/cpp/bindings/lib/template_util.h" +#include "mojo/public/cpp/bindings/type_converter.h" + +namespace mojo { + +// Provides read-only access to array data. +template <typename T> +class Array { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(Array, RValue) + public: + typedef internal::ArrayTraits<T, internal::IsMoveOnlyType<T>::value> + Traits; + typedef typename Traits::ConstRefType ConstRefType; + typedef typename Traits::RefType RefType; + typedef typename Traits::StorageType StorageType; + typedef typename Traits::ForwardType ForwardType; + + typedef internal::Array_Data<typename internal::WrapperTraits<T>::DataType> + Data_; + + Array() : is_null_(true) {} + explicit Array(size_t size) : vec_(size), is_null_(false) { + Traits::Initialize(&vec_); + } + ~Array() { Traits::Finalize(&vec_); } + + Array(RValue other) : is_null_(true) { Take(other.object); } + Array& operator=(RValue other) { + Take(other.object); + return *this; + } + + static Array New(size_t size) { + return Array(size).Pass(); + } + + template <typename U> + static Array From(const U& other) { + return TypeConverter<Array, U>::ConvertFrom(other); + } + + template <typename U> + U To() const { + return TypeConverter<Array, U>::ConvertTo(*this); + } + + void reset() { + if (!vec_.empty()) { + Traits::Finalize(&vec_); + vec_.clear(); + } + is_null_ = true; + } + + bool is_null() const { return is_null_; } + + size_t size() const { return vec_.size(); } + + ConstRefType at(size_t offset) const { return Traits::at(&vec_, offset); } + ConstRefType operator[](size_t offset) const { return at(offset); } + + RefType at(size_t offset) { return Traits::at(&vec_, offset); } + RefType operator[](size_t offset) { return at(offset); } + + void push_back(ForwardType value) { + is_null_ = false; + Traits::PushBack(&vec_, value); + } + + void resize(size_t size) { + is_null_ = false; + Traits::Resize(&vec_, size); + } + + const std::vector<StorageType>& storage() const { + return vec_; + } + operator const std::vector<StorageType>&() const { + return vec_; + } + + void Swap(Array* other) { + std::swap(is_null_, other->is_null_); + vec_.swap(other->vec_); + } + void Swap(std::vector<StorageType>* other) { + is_null_ = false; + vec_.swap(*other); + } + + private: + typedef std::vector<StorageType> Array::*Testable; + + public: + operator Testable() const { return is_null_ ? 0 : &Array::vec_; } + + private: + void Take(Array* other) { + reset(); + Swap(other); + } + + std::vector<StorageType> vec_; + bool is_null_; +}; + +template <typename T, typename E> +class TypeConverter<Array<T>, std::vector<E> > { + public: + static Array<T> ConvertFrom(const std::vector<E>& input) { + Array<T> result(input.size()); + for (size_t i = 0; i < input.size(); ++i) + result[i] = TypeConverter<T, E>::ConvertFrom(input[i]); + return result.Pass(); + } + static std::vector<E> ConvertTo(const Array<T>& input) { + std::vector<E> result; + if (!input.is_null()) { + result.resize(input.size()); + for (size_t i = 0; i < input.size(); ++i) + result[i] = TypeConverter<T, E>::ConvertTo(input[i]); + } + return result; + } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_ diff --git a/chromium/mojo/public/cpp/bindings/callback.h b/chromium/mojo/public/cpp/bindings/callback.h new file mode 100644 index 00000000000..d8ff4718232 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/callback.h @@ -0,0 +1,462 @@ +// This file was GENERATED by command: +// pump.py callback.h.pump +// DO NOT EDIT BY HAND!!! + + + +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ + +#include "mojo/public/cpp/bindings/lib/callback_internal.h" +#include "mojo/public/cpp/bindings/lib/shared_ptr.h" +#include "mojo/public/cpp/bindings/lib/template_util.h" + +namespace mojo { + +template <typename Sig> +class Callback; + +template <> +class Callback<void()> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run() const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run() const { + if (sink_.get()) + sink_->Run(); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run() const MOJO_OVERRIDE { + sink.Run(); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1> +class Callback<void(A1)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1, typename A2> +class Callback<void(A1, A2)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1), + internal::Forward(a2)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1), + internal::Forward(a2)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1, typename A2, typename A3> +class Callback<void(A1, A2, A3)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1, typename A2, typename A3, typename A4> +class Callback<void(A1, A2, A3, A4)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1, typename A2, typename A3, typename A4, typename A5> +class Callback<void(A1, A2, A3, A4, A5)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4), + internal::Forward(a5)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4), + internal::Forward(a5)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1, typename A2, typename A3, typename A4, typename A5, + typename A6> +class Callback<void(A1, A2, A3, A4, A5, A6)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5, + typename internal::Callback_ParamTraits<A6>::ForwardType a6) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5, + typename internal::Callback_ParamTraits<A6>::ForwardType a6) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4), + internal::Forward(a5), + internal::Forward(a6)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5, + typename internal::Callback_ParamTraits<A6>::ForwardType a6) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4), + internal::Forward(a5), + internal::Forward(a6)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1, typename A2, typename A3, typename A4, typename A5, + typename A6, typename A7> +class Callback<void(A1, A2, A3, A4, A5, A6, A7)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5, + typename internal::Callback_ParamTraits<A6>::ForwardType a6, + typename internal::Callback_ParamTraits<A7>::ForwardType a7) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5, + typename internal::Callback_ParamTraits<A6>::ForwardType a6, + typename internal::Callback_ParamTraits<A7>::ForwardType a7) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4), + internal::Forward(a5), + internal::Forward(a6), + internal::Forward(a7)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5, + typename internal::Callback_ParamTraits<A6>::ForwardType a6, + typename internal::Callback_ParamTraits<A7>::ForwardType a7) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4), + internal::Forward(a5), + internal::Forward(a6), + internal::Forward(a7)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ diff --git a/chromium/mojo/public/cpp/bindings/callback.h.pump b/chromium/mojo/public/cpp/bindings/callback.h.pump new file mode 100644 index 00000000000..a0f23d5f77e --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/callback.h.pump @@ -0,0 +1,80 @@ +$$ This is a pump file for generating file templates. Pump is a python +$$ script that is part of the Google Test suite of utilities. Description +$$ can be found here: +$$ +$$ http://code.google.com/p/googletest/wiki/PumpManual +$$ + +$var MAX_ARITY = 7 + +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ + +#include "mojo/public/cpp/bindings/lib/callback_internal.h" +#include "mojo/public/cpp/bindings/lib/shared_ptr.h" +#include "mojo/public/cpp/bindings/lib/template_util.h" + +namespace mojo { + +template <typename Sig> +class Callback; + +$range ARITY 0..MAX_ARITY +$for ARITY [[ +$range ARG 1..ARITY + +template <$for ARG , [[typename A$(ARG)]]> +class Callback<void($for ARG , [[A$(ARG)]])> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + $for ARG , + [[typename internal::Callback_ParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + $for ARG , + [[typename internal::Callback_ParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const { + if (sink_.get()) + sink_->Run( + $for ARG , + [[internal::Forward(a$(ARG))]]); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + $for ARG , + [[typename internal::Callback_ParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const MOJO_OVERRIDE { + sink.Run( + $for ARG , + [[internal::Forward(a$(ARG))]]); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +]] $$ for ARITY + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ diff --git a/chromium/mojo/public/cpp/bindings/error_handler.h b/chromium/mojo/public/cpp/bindings/error_handler.h new file mode 100644 index 00000000000..8ce1af27264 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/error_handler.h @@ -0,0 +1,19 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_ERROR_HANDLER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_ERROR_HANDLER_H_ + +namespace mojo { + +// This interface is used to report connection errors. +class ErrorHandler { + public: + virtual ~ErrorHandler() {} + virtual void OnConnectionError() = 0; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_ERROR_HANDLER_H_ diff --git a/chromium/mojo/public/cpp/bindings/interface_impl.h b/chromium/mojo/public/cpp/bindings/interface_impl.h new file mode 100644 index 00000000000..8ba5e7ffa4a --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/interface_impl.h @@ -0,0 +1,109 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_IMPL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_IMPL_H_ + +#include "mojo/public/cpp/bindings/interface_request.h" +#include "mojo/public/cpp/bindings/lib/interface_impl_internal.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +// InterfaceImpl<..> is designed to be the base class of an interface +// implementation. It may be bound to a pipe or a proxy, see BindToPipe and +// BindToProxy. +template <typename Interface> +class InterfaceImpl : public internal::InterfaceImplBase<Interface> { + public: + typedef typename Interface::Client Client; + + InterfaceImpl() : internal_state_(this) {} + virtual ~InterfaceImpl() {} + + // Returns a proxy to the client interface. This is null upon construction, + // and becomes non-null after OnClientConnected. NOTE: It remains non-null + // until this instance is deleted. + Client* client() { return internal_state_.client(); } + + // Called when the client has connected to this instance. + virtual void OnConnectionEstablished() {} + + // Called when the client is no longer connected to this instance. NOTE: The + // client() method continues to return a non-null pointer after this method + // is called. After this method is called, any method calls made on client() + // will be silently ignored. + virtual void OnConnectionError() {} + + // DO NOT USE. Exposed only for internal use and for testing. + internal::InterfaceImplState<Interface>* internal_state() { + return &internal_state_; + } + + private: + internal::InterfaceImplState<Interface> internal_state_; + MOJO_DISALLOW_COPY_AND_ASSIGN(InterfaceImpl); +}; + +// Takes an instance of an InterfaceImpl<..> subclass and binds it to the given +// MessagePipe. The instance is returned for convenience in member initializer +// lists, etc. If the pipe is closed, the instance's OnConnectionError method +// will be called. +// +// The instance is also bound to the current thread. Its methods will only be +// called on the current thread, and if the current thread exits, then it will +// also be deleted, and along with it, its end point of the pipe will be closed. +// +// Before returning, the instance's OnConnectionEstablished method is called. +template <typename Impl> +Impl* BindToPipe( + Impl* instance, + ScopedMessagePipeHandle handle, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + instance->internal_state()->Bind(handle.Pass(), waiter); + return instance; +} + +// Takes an instance of an InterfaceImpl<..> subclass and binds it to the given +// InterfacePtr<..>. The instance is returned for convenience in member +// initializer lists, etc. If the pipe is closed, the instance's +// OnConnectionError method will be called. +// +// The instance is also bound to the current thread. Its methods will only be +// called on the current thread, and if the current thread exits, then it will +// also be deleted, and along with it, its end point of the pipe will be closed. +// +// Before returning, the instance's OnConnectionEstablished method is called. +template <typename Impl, typename Interface> +Impl* BindToProxy( + Impl* instance, + InterfacePtr<Interface>* ptr, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + instance->internal_state()->BindProxy(ptr, waiter); + return instance; +} + +// Takes an instance of an InterfaceImpl<..> subclass and binds it to the given +// InterfaceRequest<..>. The instance is returned for convenience in member +// initializer lists, etc. If the pipe is closed, the instance's +// OnConnectionError method will be called. +// +// The instance is also bound to the current thread. Its methods will only be +// called on the current thread, and if the current thread exits, then it will +// also be deleted, and along with it, its end point of the pipe will be closed. +// +// Before returning, the instance will receive a SetClient call, providing it +// with a proxy to the client on the other end of the pipe. +template <typename Impl, typename Interface> +Impl* BindToRequest( + Impl* instance, + InterfaceRequest<Interface>* request, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + return BindToPipe(instance, request->PassMessagePipe(), waiter); +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_IMPL_H_ diff --git a/chromium/mojo/public/cpp/bindings/interface_ptr.h b/chromium/mojo/public/cpp/bindings/interface_ptr.h new file mode 100644 index 00000000000..726896d9cce --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/interface_ptr.h @@ -0,0 +1,124 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_ + +#include <assert.h> + +#include <algorithm> + +#include "mojo/public/cpp/bindings/error_handler.h" +#include "mojo/public/cpp/bindings/lib/interface_ptr_internal.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +class ErrorHandler; + +// InterfacePtr represents a proxy to a remote instance of an interface. +template <typename Interface> +class InterfacePtr { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InterfacePtr, RValue) + public: + InterfacePtr() {} + + InterfacePtr(RValue other) { + internal_state_.Swap(&other.object->internal_state_); + } + InterfacePtr& operator=(RValue other) { + reset(); + internal_state_.Swap(&other.object->internal_state_); + return *this; + } + + ~InterfacePtr() {} + + Interface* get() const { + return internal_state_.instance(); + } + Interface* operator->() const { return get(); } + Interface& operator*() const { return *get(); } + + void reset() { + State doomed; + internal_state_.Swap(&doomed); + } + + // This method configures the InterfacePtr<..> to be a proxy to a remote + // object on the other end of the given pipe. + // + // The proxy is bound to the current thread, which means its methods may + // only be called on the current thread. + // + // To move a bound InterfacePtr<..> to another thread, call + // ResetAndReturnMessagePipe. Then create a new InterfacePtr<..> on another + // thread, and bind the new InterfacePtr<..> to the message pipe on that + // thread. + void Bind( + ScopedMessagePipeHandle handle, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + reset(); + internal_state_.ConfigureProxy(handle.Pass(), waiter); + } + + // The client interface may only be set after this InterfacePtr<..> is bound. + void set_client(typename Interface::Client* client) { + internal_state_.set_client(client); + } + + // This method may be called to query if the underlying pipe has encountered + // an error. If true, this means method calls made on this interface will be + // dropped (and may have already been dropped) on the floor. + bool encountered_error() const { + assert(internal_state_.router()); + return internal_state_.router()->encountered_error(); + } + + // This method may be called to register an ErrorHandler to observe a + // connection error on the underlying pipe. The callback runs asynchronously + // from the current message loop. + void set_error_handler(ErrorHandler* error_handler) { + assert(internal_state_.router()); + internal_state_.router()->set_error_handler(error_handler); + } + + // Returns the underlying message pipe handle (if any) and resets the + // InterfacePtr<..> to its uninitialized state. This method is helpful if you + // need to move a proxy to another thread. See related notes for Bind. + ScopedMessagePipeHandle PassMessagePipe() { + State state; + internal_state_.Swap(&state); + return state.router() ? + state.router()->PassMessagePipe() : ScopedMessagePipeHandle(); + } + + // DO NOT USE. Exposed only for internal use and for testing. + internal::InterfacePtrState<Interface>* internal_state() { + return &internal_state_; + } + + private: + typedef internal::InterfacePtrState<Interface> State; + State internal_state_; +}; + +// Takes a handle to the proxy end-point of a pipe. On the other end is +// presumed to be an interface implementation of type |Interface|. Returns a +// generated proxy to that interface, which may be used on the current thread. +// It is valid to call set_client on the returned InterfacePtr<..> to set an +// instance of Interface::Client. +template <typename Interface> +InterfacePtr<Interface> MakeProxy( + ScopedMessagePipeHandle handle, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + InterfacePtr<Interface> ptr; + if (handle.is_valid()) + ptr.Bind(handle.Pass(), waiter); + return ptr.Pass(); +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_ diff --git a/chromium/mojo/public/cpp/bindings/interface_request.h b/chromium/mojo/public/cpp/bindings/interface_request.h new file mode 100644 index 00000000000..6b7d3033c9d --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/interface_request.h @@ -0,0 +1,76 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_ + +#include "mojo/public/cpp/bindings/interface_ptr.h" + +namespace mojo { + +// Used in methods that return instances of remote objects. +template <typename Interface> +class InterfaceRequest { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InterfaceRequest, RValue) + public: + InterfaceRequest() {} + + InterfaceRequest(RValue other) { + handle_ = other.object->handle_.Pass(); + } + InterfaceRequest& operator=(RValue other) { + handle_ = other.object->handle_.Pass(); + return *this; + } + + // Returns true if the request has yet to be completed. + bool is_pending() const { return handle_.is_valid(); } + + void Bind(ScopedMessagePipeHandle handle) { + handle_ = handle.Pass(); + } + + ScopedMessagePipeHandle PassMessagePipe() { + return handle_.Pass(); + } + + private: + ScopedMessagePipeHandle handle_; +}; + +template <typename Interface> +InterfaceRequest<Interface> MakeRequest(ScopedMessagePipeHandle handle) { + InterfaceRequest<Interface> request; + request.Bind(handle.Pass()); + return request.Pass(); +} + +// Used to construct a request that synchronously binds an InterfacePtr<..>, +// making it immediately usable upon return. The resulting request object may +// then be later bound to an InterfaceImpl<..> via BindToRequest. +// +// Given the following interface: +// +// interface Foo { +// CreateBar(Bar& bar); +// } +// +// The caller of CreateBar would have code similar to the following: +// +// InterfacePtr<Foo> foo = ...; +// InterfacePtr<Bar> bar; +// foo->CreateBar(Get(&bar)); +// +// Upon return from CreateBar, |bar| is ready to have methods called on it. +// +template <typename Interface> +InterfaceRequest<Interface> Get(InterfacePtr<Interface>* ptr) { + MessagePipe pipe; + ptr->Bind(pipe.handle0.Pass()); + return MakeRequest<Interface>(pipe.handle1.Pass()); +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/DEPS b/chromium/mojo/public/cpp/bindings/lib/DEPS new file mode 100644 index 00000000000..b809b58d337 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/DEPS @@ -0,0 +1,5 @@ +include_rules = [ + "+mojo/public/cpp/bindings", + "+mojo/public/cpp/environment", + "+mojo/public/cpp/system", +] diff --git a/chromium/mojo/public/cpp/bindings/lib/TODO b/chromium/mojo/public/cpp/bindings/lib/TODO new file mode 100644 index 00000000000..21bcb6fe7a2 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/TODO @@ -0,0 +1,6 @@ +TODOs: + - Ensure validation checks are solid + - Add tests of validation logic + - Optimize Buffer classes? + - Add compile-time asserts to verify object packing and padding. + - Investigate making arrays of objects not be arrays of pointers. diff --git a/chromium/mojo/public/cpp/bindings/lib/array_internal.cc b/chromium/mojo/public/cpp/bindings/lib/array_internal.cc new file mode 100644 index 00000000000..3f7f1ce0b16 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/array_internal.cc @@ -0,0 +1,70 @@ +// 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. + +#include "mojo/public/cpp/bindings/lib/array_internal.h" + +namespace mojo { +namespace internal { + +ArrayDataTraits<bool>::BitRef::~BitRef() { +} + +ArrayDataTraits<bool>::BitRef::BitRef(uint8_t* storage, uint8_t mask) + : storage_(storage), + mask_(mask) { +} + +ArrayDataTraits<bool>::BitRef& +ArrayDataTraits<bool>::BitRef::operator=(bool value) { + if (value) { + *storage_ |= mask_; + } else { + *storage_ &= ~mask_; + } + return *this; +} + +ArrayDataTraits<bool>::BitRef& +ArrayDataTraits<bool>::BitRef::operator=(const BitRef& value) { + return (*this) = static_cast<bool>(value); +} + +ArrayDataTraits<bool>::BitRef::operator bool() const { + return (*storage_ & mask_) != 0; +} + +// static +void ArraySerializationHelper<Handle, true>::EncodePointersAndHandles( + const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + for (uint32_t i = 0; i < header->num_elements; ++i) + EncodeHandle(&elements[i], handles); +} + +// static +void ArraySerializationHelper<Handle, true>::DecodePointersAndHandles( + const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + for (uint32_t i = 0; i < header->num_elements; ++i) + DecodeHandle(&elements[i], handles); +} + +// static +bool ArraySerializationHelper<Handle, true>::ValidateElements( + const ArrayHeader* header, + const ElementType* elements, + BoundsChecker* bounds_checker) { + for (uint32_t i = 0; i < header->num_elements; ++i) { + if (!bounds_checker->ClaimHandle(elements[i])) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_HANDLE); + return false; + } + } + return true; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/array_internal.h b/chromium/mojo/public/cpp/bindings/lib/array_internal.h new file mode 100644 index 00000000000..8ea00991251 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/array_internal.h @@ -0,0 +1,384 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ + +#include <new> +#include <vector> + +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" +#include "mojo/public/cpp/bindings/lib/bounds_checker.h" +#include "mojo/public/cpp/bindings/lib/buffer.h" +#include "mojo/public/cpp/bindings/lib/validation_errors.h" + +namespace mojo { +template <typename T> class Array; +class String; + +namespace internal { + +template <typename T> +struct ArrayDataTraits { + typedef T StorageType; + typedef T& Ref; + typedef T const& ConstRef; + + static size_t GetStorageSize(size_t num_elements) { + return sizeof(StorageType) * num_elements; + } + static Ref ToRef(StorageType* storage, size_t offset) { + return storage[offset]; + } + static ConstRef ToConstRef(const StorageType* storage, size_t offset) { + return storage[offset]; + } +}; + +template <typename P> +struct ArrayDataTraits<P*> { + typedef StructPointer<P> StorageType; + typedef P*& Ref; + typedef P* const& ConstRef; + + static size_t GetStorageSize(size_t num_elements) { + return sizeof(StorageType) * num_elements; + } + static Ref ToRef(StorageType* storage, size_t offset) { + return storage[offset].ptr; + } + static ConstRef ToConstRef(const StorageType* storage, size_t offset) { + return storage[offset].ptr; + } +}; + +template <typename T> +struct ArrayDataTraits<Array_Data<T>*> { + typedef ArrayPointer<T> StorageType; + typedef Array_Data<T>*& Ref; + typedef Array_Data<T>* const& ConstRef; + + static size_t GetStorageSize(size_t num_elements) { + return sizeof(StorageType) * num_elements; + } + static Ref ToRef(StorageType* storage, size_t offset) { + return storage[offset].ptr; + } + static ConstRef ToConstRef(const StorageType* storage, size_t offset) { + return storage[offset].ptr; + } +}; + +// Specialization of Arrays for bools, optimized for space. It has the +// following differences from a generalized Array: +// * Each element takes up a single bit of memory. +// * Accessing a non-const single element uses a helper class |BitRef|, which +// emulates a reference to a bool. +template <> +struct ArrayDataTraits<bool> { + // Helper class to emulate a reference to a bool, used for direct element + // access. + class BitRef { + public: + ~BitRef(); + BitRef& operator=(bool value); + BitRef& operator=(const BitRef& value); + operator bool() const; + private: + friend struct ArrayDataTraits<bool>; + BitRef(uint8_t* storage, uint8_t mask); + BitRef(); + uint8_t* storage_; + uint8_t mask_; + }; + + typedef uint8_t StorageType; + typedef BitRef Ref; + typedef bool ConstRef; + + static size_t GetStorageSize(size_t num_elements) { + return ((num_elements + 7) / 8); + } + static BitRef ToRef(StorageType* storage, size_t offset) { + return BitRef(&storage[offset / 8], 1 << (offset % 8)); + } + static bool ToConstRef(const StorageType* storage, size_t offset) { + return (storage[offset / 8] & (1 << (offset % 8))) != 0; + } +}; + +// What follows is code to support the serialization of Array_Data<T>. There +// are two interesting cases: arrays of primitives and arrays of objects. +// Arrays of objects are represented as arrays of pointers to objects. + +template <typename T, bool kIsHandle> struct ArraySerializationHelper; + +template <typename T> +struct ArraySerializationHelper<T, false> { + typedef typename ArrayDataTraits<T>::StorageType ElementType; + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + } + + static void DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + } + + static bool ValidateElements(const ArrayHeader* header, + const ElementType* elements, + BoundsChecker* bounds_checker) { + return true; + } +}; + +template <> +struct ArraySerializationHelper<Handle, true> { + typedef ArrayDataTraits<Handle>::StorageType ElementType; + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles); + + static void DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles); + + static bool ValidateElements(const ArrayHeader* header, + const ElementType* elements, + BoundsChecker* bounds_checker); +}; + +template <typename H> +struct ArraySerializationHelper<H, true> { + typedef typename ArrayDataTraits<H>::StorageType ElementType; + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + ArraySerializationHelper<Handle, true>::EncodePointersAndHandles( + header, elements, handles); + } + + static void DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + ArraySerializationHelper<Handle, true>::DecodePointersAndHandles( + header, elements, handles); + } + + static bool ValidateElements(const ArrayHeader* header, + const ElementType* elements, + BoundsChecker* bounds_checker) { + return ArraySerializationHelper<Handle, true>::ValidateElements( + header, elements, bounds_checker); + } +}; + +template <typename P> +struct ArraySerializationHelper<P*, false> { + typedef typename ArrayDataTraits<P*>::StorageType ElementType; + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + for (uint32_t i = 0; i < header->num_elements; ++i) + Encode(&elements[i], handles); + } + + static void DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + for (uint32_t i = 0; i < header->num_elements; ++i) + Decode(&elements[i], handles); + } + + static bool ValidateElements(const ArrayHeader* header, + const ElementType* elements, + BoundsChecker* bounds_checker) { + for (uint32_t i = 0; i < header->num_elements; ++i) { + if (!ValidateEncodedPointer(&elements[i].offset)) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER); + return false; + } + if (!P::Validate(DecodePointerRaw(&elements[i].offset), bounds_checker)) + return false; + } + return true; + } +}; + +template <typename T> +class Array_Data { + public: + typedef ArrayDataTraits<T> Traits; + typedef typename Traits::StorageType StorageType; + typedef typename Traits::Ref Ref; + typedef typename Traits::ConstRef ConstRef; + typedef ArraySerializationHelper<T, IsHandle<T>::value> Helper; + + static Array_Data<T>* New(size_t num_elements, Buffer* buf) { + size_t num_bytes = sizeof(Array_Data<T>) + + Traits::GetStorageSize(num_elements); + return new (buf->Allocate(num_bytes)) Array_Data<T>(num_bytes, + num_elements); + } + + static bool Validate(const void* data, BoundsChecker* bounds_checker) { + if (!data) + return true; + if (!IsAligned(data)) { + ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT); + return false; + } + if (!bounds_checker->IsValidRange(data, sizeof(ArrayHeader))) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); + return false; + } + const ArrayHeader* header = static_cast<const ArrayHeader*>(data); + if (header->num_bytes < (sizeof(Array_Data<T>) + + Traits::GetStorageSize(header->num_elements))) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER); + return false; + } + if (!bounds_checker->ClaimMemory(data, header->num_bytes)) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); + return false; + } + + const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data); + return Helper::ValidateElements(&object->header_, object->storage(), + bounds_checker); + } + + size_t size() const { return header_.num_elements; } + + Ref at(size_t offset) { + assert(offset < static_cast<size_t>(header_.num_elements)); + return Traits::ToRef(storage(), offset); + } + + ConstRef at(size_t offset) const { + assert(offset < static_cast<size_t>(header_.num_elements)); + return Traits::ToConstRef(storage(), offset); + } + + StorageType* storage() { + return reinterpret_cast<StorageType*>( + reinterpret_cast<char*>(this) + sizeof(*this)); + } + + const StorageType* storage() const { + return reinterpret_cast<const StorageType*>( + reinterpret_cast<const char*>(this) + sizeof(*this)); + } + + void EncodePointersAndHandles(std::vector<Handle>* handles) { + Helper::EncodePointersAndHandles(&header_, storage(), handles); + } + + void DecodePointersAndHandles(std::vector<Handle>* handles) { + Helper::DecodePointersAndHandles(&header_, storage(), handles); + } + + private: + Array_Data(size_t num_bytes, size_t num_elements) { + header_.num_bytes = static_cast<uint32_t>(num_bytes); + header_.num_elements = static_cast<uint32_t>(num_elements); + } + ~Array_Data() {} + + internal::ArrayHeader header_; + + // Elements of type internal::ArrayDataTraits<T>::StorageType follow. +}; +MOJO_COMPILE_ASSERT(sizeof(Array_Data<char>) == 8, bad_sizeof_Array_Data); + +// UTF-8 encoded +typedef Array_Data<char> String_Data; + +template <typename T, bool kIsMoveOnlyType> struct ArrayTraits {}; + +template <typename T> struct ArrayTraits<T, false> { + typedef T StorageType; + typedef typename std::vector<T>::reference RefType; + typedef typename std::vector<T>::const_reference ConstRefType; + typedef ConstRefType ForwardType; + static inline void Initialize(std::vector<T>* vec) { + } + static inline void Finalize(std::vector<T>* vec) { + } + static inline ConstRefType at(const std::vector<T>* vec, size_t offset) { + return vec->at(offset); + } + static inline RefType at(std::vector<T>* vec, size_t offset) { + return vec->at(offset); + } + static inline void Resize(std::vector<T>* vec, size_t size) { + vec->resize(size); + } + static inline void PushBack(std::vector<T>* vec, ForwardType value) { + vec->push_back(value); + } +}; + +template <typename T> struct ArrayTraits<T, true> { + struct StorageType { + char buf[sizeof(T) + (8 - (sizeof(T) % 8)) % 8]; // Make 8-byte aligned. + }; + typedef T& RefType; + typedef const T& ConstRefType; + typedef T ForwardType; + static inline void Initialize(std::vector<StorageType>* vec) { + for (size_t i = 0; i < vec->size(); ++i) + new (vec->at(i).buf) T(); + } + static inline void Finalize(std::vector<StorageType>* vec) { + for (size_t i = 0; i < vec->size(); ++i) + reinterpret_cast<T*>(vec->at(i).buf)->~T(); + } + static inline ConstRefType at(const std::vector<StorageType>* vec, + size_t offset) { + return *reinterpret_cast<const T*>(vec->at(offset).buf); + } + static inline RefType at(std::vector<StorageType>* vec, size_t offset) { + return *reinterpret_cast<T*>(vec->at(offset).buf); + } + static inline void Resize(std::vector<StorageType>* vec, size_t size) { + size_t old_size = vec->size(); + for (size_t i = size; i < old_size; i++) + reinterpret_cast<T*>(vec->at(i).buf)->~T(); + ResizeStorage(vec, size); + for (size_t i = old_size; i < vec->size(); i++) + new (vec->at(i).buf) T(); + } + static inline void PushBack(std::vector<StorageType>* vec, RefType value) { + size_t old_size = vec->size(); + ResizeStorage(vec, old_size + 1); + new (vec->at(old_size).buf) T(value.Pass()); + } + static inline void ResizeStorage(std::vector<StorageType>* vec, size_t size) { + if (size <= vec->capacity()) { + vec->resize(size); + return; + } + std::vector<StorageType> new_storage(size); + for (size_t i = 0; i < vec->size(); i++) + new (new_storage.at(i).buf) T(at(vec, i).Pass()); + vec->swap(new_storage); + Finalize(&new_storage); + } +}; + +template <> struct WrapperTraits<String, false> { + typedef String_Data* DataType; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/array_serialization.h b/chromium/mojo/public/cpp/bindings/lib/array_serialization.h new file mode 100644 index 00000000000..83403d52502 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/array_serialization.h @@ -0,0 +1,179 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ + +#include <string> + +#include "mojo/public/cpp/bindings/lib/array_internal.h" +#include "mojo/public/cpp/bindings/lib/string_serialization.h" + +namespace mojo { + +template <typename E> +inline size_t GetSerializedSize_(const Array<E>& input); + +template <typename E, typename F> +inline void Serialize_(Array<E> input, internal::Buffer* buf, + internal::Array_Data<F>** output); +template <typename E, typename F> +inline void Deserialize_(internal::Array_Data<F>* data, Array<E>* output); + +namespace internal { + +template <typename E, typename F, bool move_only = IsMoveOnlyType<E>::value> +struct ArraySerializer; + +template <typename E, typename F> struct ArraySerializer<E, F, false> { + MOJO_COMPILE_ASSERT(sizeof(E) == sizeof(F), wrong_array_serializer); + static size_t GetSerializedSize(const Array<E>& input) { + return sizeof(Array_Data<F>) + Align(input.size() * sizeof(E)); + } + static void SerializeElements( + Array<E> input, Buffer* buf, Array_Data<F>* output) { + memcpy(output->storage(), &input.storage()[0], input.size() * sizeof(E)); + } + static void DeserializeElements( + Array_Data<F>* input, Array<E>* output) { + std::vector<E> result(input->size()); + memcpy(&result[0], input->storage(), input->size() * sizeof(E)); + output->Swap(&result); + } +}; + +template <> struct ArraySerializer<bool, bool, false> { + static size_t GetSerializedSize(const Array<bool>& input) { + return sizeof(Array_Data<bool>) + Align((input.size() + 7) / 8); + } + static void SerializeElements( + Array<bool> input, Buffer* buf, Array_Data<bool>* output) { + // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? + for (size_t i = 0; i < input.size(); ++i) + output->at(i) = input[i]; + } + static void DeserializeElements( + Array_Data<bool>* input, Array<bool>* output) { + Array<bool> result(input->size()); + // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? + for (size_t i = 0; i < input->size(); ++i) + result.at(i) = input->at(i); + output->Swap(&result); + } +}; + +template <typename H> struct ArraySerializer<ScopedHandleBase<H>, H, true> { + static size_t GetSerializedSize(const Array<ScopedHandleBase<H> >& input) { + return sizeof(Array_Data<H>) + Align(input.size() * sizeof(H)); + } + static void SerializeElements( + Array<ScopedHandleBase<H> > input, + Buffer* buf, + Array_Data<H>* output) { + for (size_t i = 0; i < input.size(); ++i) + output->at(i) = input[i].release(); // Transfer ownership of the handle. + } + static void DeserializeElements( + Array_Data<H>* input, Array<ScopedHandleBase<H> >* output) { + Array<ScopedHandleBase<H> > result(input->size()); + for (size_t i = 0; i < input->size(); ++i) + result.at(i) = MakeScopedHandle(FetchAndReset(&input->at(i))); + output->Swap(&result); + } +}; + +template <typename S> struct ArraySerializer<S, typename S::Data_*, true> { + static size_t GetSerializedSize(const Array<S>& input) { + size_t size = sizeof(Array_Data<typename S::Data_*>) + + input.size() * sizeof(internal::StructPointer<typename S::Data_>); + for (size_t i = 0; i < input.size(); ++i) + size += GetSerializedSize_(input[i]); + return size; + } + static void SerializeElements( + Array<S> input, + Buffer* buf, + Array_Data<typename S::Data_*>* output) { + for (size_t i = 0; i < input.size(); ++i) { + typename S::Data_* element; + Serialize_(input[i].Pass(), buf, &element); + output->at(i) = element; + } + } + static void DeserializeElements( + Array_Data<typename S::Data_*>* input, Array<S>* output) { + Array<S> result(input->size()); + for (size_t i = 0; i < input->size(); ++i) { + S element; + Deserialize_(input->at(i), &element); + result[i] = element.Pass(); + } + output->Swap(&result); + } +}; + +template <> struct ArraySerializer<String, String_Data*, false> { + static size_t GetSerializedSize(const Array<String>& input) { + size_t size = sizeof(Array_Data<String_Data*>) + + input.size() * sizeof(internal::StringPointer); + for (size_t i = 0; i < input.size(); ++i) + size += GetSerializedSize_(input[i]); + return size; + } + static void SerializeElements( + Array<String> input, + Buffer* buf, + Array_Data<String_Data*>* output) { + for (size_t i = 0; i < input.size(); ++i) { + String_Data* element; + Serialize_(input[i], buf, &element); + output->at(i) = element; + } + } + static void DeserializeElements( + Array_Data<String_Data*>* input, Array<String>* output) { + Array<String> result(input->size()); + for (size_t i = 0; i < input->size(); ++i) + Deserialize_(input->at(i), &result[i]); + output->Swap(&result); + } +}; + +} // namespace internal + +template <typename E> +inline size_t GetSerializedSize_(const Array<E>& input) { + if (!input) + return 0; + typedef typename internal::WrapperTraits<E>::DataType F; + return internal::ArraySerializer<E, F>::GetSerializedSize(input); +} + +template <typename E, typename F> +inline void Serialize_(Array<E> input, internal::Buffer* buf, + internal::Array_Data<F>** output) { + if (input) { + internal::Array_Data<F>* result = + internal::Array_Data<F>::New(input.size(), buf); + internal::ArraySerializer<E, F>::SerializeElements( + internal::Forward(input), buf, result); + *output = result; + } else { + *output = NULL; + } +} + +template <typename E, typename F> +inline void Deserialize_(internal::Array_Data<F>* input, + Array<E>* output) { + if (input) { + internal::ArraySerializer<E, F>::DeserializeElements(input, output); + } else { + output->reset(); + } +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h b/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h new file mode 100644 index 00000000000..6e87cbd1fb5 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h @@ -0,0 +1,86 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_ + +#include "mojo/public/cpp/bindings/lib/template_util.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +class String; + +namespace internal { +template <typename T> class Array_Data; + +#pragma pack(push, 1) + +struct StructHeader { + uint32_t num_bytes; + uint32_t num_fields; +}; +MOJO_COMPILE_ASSERT(sizeof(StructHeader) == 8, bad_sizeof_StructHeader); + +struct ArrayHeader { + uint32_t num_bytes; + uint32_t num_elements; +}; +MOJO_COMPILE_ASSERT(sizeof(ArrayHeader) == 8, bad_sizeof_ArrayHeader); + +template <typename T> +union StructPointer { + uint64_t offset; + T* ptr; +}; +MOJO_COMPILE_ASSERT(sizeof(StructPointer<char>) == 8, bad_sizeof_StructPointer); + +template <typename T> +union ArrayPointer { + uint64_t offset; + Array_Data<T>* ptr; +}; +MOJO_COMPILE_ASSERT(sizeof(ArrayPointer<char>) == 8, bad_sizeof_ArrayPointer); + +union StringPointer { + uint64_t offset; + Array_Data<char>* ptr; +}; +MOJO_COMPILE_ASSERT(sizeof(StringPointer) == 8, bad_sizeof_StringPointer); + +#pragma pack(pop) + +template <typename T> +void ResetIfNonNull(T* ptr) { + if (ptr) + *ptr = T(); +} + +template <typename T> +T FetchAndReset(T* ptr) { + T temp = *ptr; + *ptr = T(); + return temp; +} + +template <typename H> struct IsHandle { + static const bool value = IsBaseOf<Handle, H>::value; +}; + +template <typename T, bool move_only = IsMoveOnlyType<T>::value> +struct WrapperTraits; + +template <typename T> struct WrapperTraits<T, false> { + typedef T DataType; +}; +template <typename H> struct WrapperTraits<ScopedHandleBase<H>, true> { + typedef H DataType; +}; +template <typename S> struct WrapperTraits<S, true> { + typedef typename S::Data_* DataType; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.cc b/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.cc new file mode 100644 index 00000000000..d5f77853684 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.cc @@ -0,0 +1,118 @@ +// 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. + +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" + +#include <assert.h> + +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" +#include "mojo/public/cpp/bindings/lib/bounds_checker.h" +#include "mojo/public/cpp/bindings/lib/validation_errors.h" + +namespace mojo { +namespace internal { + +namespace { + +const size_t kAlignment = 8; + +template<typename T> +T AlignImpl(T t) { + return t + (kAlignment - (t % kAlignment)) % kAlignment; +} + +} // namespace + +size_t Align(size_t size) { + return AlignImpl(size); +} + +char* AlignPointer(char* ptr) { + return reinterpret_cast<char*>(AlignImpl(reinterpret_cast<uintptr_t>(ptr))); +} + +bool IsAligned(const void* ptr) { + return !(reinterpret_cast<uintptr_t>(ptr) % kAlignment); +} + +void EncodePointer(const void* ptr, uint64_t* offset) { + if (!ptr) { + *offset = 0; + return; + } + + const char* p_obj = reinterpret_cast<const char*>(ptr); + const char* p_slot = reinterpret_cast<const char*>(offset); + assert(p_obj > p_slot); + + *offset = static_cast<uint64_t>(p_obj - p_slot); +} + +const void* DecodePointerRaw(const uint64_t* offset) { + if (!*offset) + return NULL; + return reinterpret_cast<const char*>(offset) + *offset; +} + +bool ValidateEncodedPointer(const uint64_t* offset) { + // Cast to uintptr_t so overflow behavior is well defined. + return reinterpret_cast<uintptr_t>(offset) + *offset >= + reinterpret_cast<uintptr_t>(offset); +} + +void EncodeHandle(Handle* handle, std::vector<Handle>* handles) { + if (handle->is_valid()) { + handles->push_back(*handle); + handle->set_value(static_cast<MojoHandle>(handles->size() - 1)); + } else { + handle->set_value(kEncodedInvalidHandleValue); + } +} + +void DecodeHandle(Handle* handle, std::vector<Handle>* handles) { + if (handle->value() == kEncodedInvalidHandleValue) { + *handle = Handle(); + return; + } + assert(handle->value() < handles->size()); + // Just leave holes in the vector so we don't screw up other indices. + *handle = FetchAndReset(&handles->at(handle->value())); +} + +bool ValidateStructHeader(const void* data, + uint32_t min_num_bytes, + uint32_t min_num_fields, + BoundsChecker* bounds_checker) { + assert(min_num_bytes >= sizeof(StructHeader)); + + if (!IsAligned(data)) { + ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT); + return false; + } + if (!bounds_checker->IsValidRange(data, sizeof(StructHeader))) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); + return false; + } + + const StructHeader* header = static_cast<const StructHeader*>(data); + + // TODO(yzshen): Currently our binding code cannot handle structs of smaller + // size or with fewer fields than the version that it sees. That needs to be + // changed in order to provide backward compatibility. + if (header->num_bytes < min_num_bytes || + header->num_fields < min_num_fields) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + + if (!bounds_checker->ClaimMemory(data, header->num_bytes)) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); + return false; + } + + return true; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.h b/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.h new file mode 100644 index 00000000000..6bebf90bf95 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.h @@ -0,0 +1,83 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ + +#include <vector> + +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +namespace internal { + +class BoundsChecker; + +// Please note that this is a different value than |mojo::kInvalidHandleValue|, +// which is the "decoded" invalid handle. +const MojoHandle kEncodedInvalidHandleValue = static_cast<MojoHandle>(-1); + +size_t Align(size_t size); +char* AlignPointer(char* ptr); + +bool IsAligned(const void* ptr); + +// Pointers are encoded as relative offsets. The offsets are relative to the +// address of where the offset value is stored, such that the pointer may be +// recovered with the expression: +// +// ptr = reinterpret_cast<char*>(offset) + *offset +// +// A null pointer is encoded as an offset value of 0. +// +void EncodePointer(const void* ptr, uint64_t* offset); +// Note: This function doesn't validate the encoded pointer value. +const void* DecodePointerRaw(const uint64_t* offset); + +// Note: This function doesn't validate the encoded pointer value. +template <typename T> +inline void DecodePointer(const uint64_t* offset, T** ptr) { + *ptr = reinterpret_cast<T*>(const_cast<void*>(DecodePointerRaw(offset))); +} + +// Checks whether decoding the pointer will overflow and produce a pointer +// smaller than |offset|. +bool ValidateEncodedPointer(const uint64_t* offset); + +// Handles are encoded as indices into a vector of handles. These functions +// manipulate the value of |handle|, mapping it to and from an index. +void EncodeHandle(Handle* handle, std::vector<Handle>* handles); +// Note: This function doesn't validate the encoded handle value. +void DecodeHandle(Handle* handle, std::vector<Handle>* handles); + +// The following 2 functions are used to encode/decode all objects (structs and +// arrays) in a consistent manner. + +template <typename T> +inline void Encode(T* obj, std::vector<Handle>* handles) { + if (obj->ptr) + obj->ptr->EncodePointersAndHandles(handles); + EncodePointer(obj->ptr, &obj->offset); +} + +// Note: This function doesn't validate the encoded pointer and handle values. +template <typename T> +inline void Decode(T* obj, std::vector<Handle>* handles) { + DecodePointer(&obj->offset, &obj->ptr); + if (obj->ptr) + obj->ptr->DecodePointersAndHandles(handles); +} + +// If returns true, this function also claims the memory range of the size +// specified in the struct header, starting from |data|. +// Note: |min_num_bytes| must be no less than sizeof(StructHeader). +bool ValidateStructHeader(const void* data, + uint32_t min_num_bytes, + uint32_t min_num_fields, + BoundsChecker* bounds_checker); + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/bounds_checker.cc b/chromium/mojo/public/cpp/bindings/lib/bounds_checker.cc new file mode 100644 index 00000000000..cf1f3238e03 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/bounds_checker.cc @@ -0,0 +1,77 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/lib/bounds_checker.h" + +#include <assert.h> + +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +namespace internal { + +BoundsChecker::BoundsChecker(const void* data, uint32_t data_num_bytes, + size_t num_handles) + : data_begin_(reinterpret_cast<uintptr_t>(data)), + data_end_(data_begin_ + data_num_bytes), + handle_begin_(0), + handle_end_(static_cast<uint32_t>(num_handles)) { + if (data_end_ < data_begin_) { + // The calculation of |data_end_| overflowed. + // It shouldn't happen but if it does, set the range to empty so + // IsValidRange() and ClaimMemory() always fail. + assert(false); // Not reached. + data_end_ = data_begin_; + } + if (handle_end_ < num_handles) { + // Assigning |num_handles| to |handle_end_| overflowed. + // It shouldn't happen but if it does, set the handle index range to empty. + assert(false); // Not reached. + handle_end_ = 0; + } +} + +BoundsChecker::~BoundsChecker() { +} + +bool BoundsChecker::ClaimMemory(const void* position, uint32_t num_bytes) { + uintptr_t begin = reinterpret_cast<uintptr_t>(position); + uintptr_t end = begin + num_bytes; + + if (!InternalIsValidRange(begin, end)) + return false; + + data_begin_ = end; + return true; +} + +bool BoundsChecker::ClaimHandle(const Handle& encoded_handle) { + uint32_t index = encoded_handle.value(); + if (index == kEncodedInvalidHandleValue) + return true; + + if (index < handle_begin_ || index >= handle_end_) + return false; + + // |index| + 1 shouldn't overflow, because |index| is not the max value of + // uint32_t (it is less than |handle_end_|). + handle_begin_ = index + 1; + return true; +} + +bool BoundsChecker::IsValidRange(const void* position, + uint32_t num_bytes) const { + uintptr_t begin = reinterpret_cast<uintptr_t>(position); + uintptr_t end = begin + num_bytes; + + return InternalIsValidRange(begin, end); +} + +bool BoundsChecker::InternalIsValidRange(uintptr_t begin, uintptr_t end) const { + return end > begin && begin >= data_begin_ && end <= data_end_; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/bounds_checker.h b/chromium/mojo/public/cpp/bindings/lib/bounds_checker.h new file mode 100644 index 00000000000..6c472309dde --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/bounds_checker.h @@ -0,0 +1,64 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_BOUNDS_CHECKER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BOUNDS_CHECKER_H_ + +#include <stdint.h> + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +class Handle; + +namespace internal { + +// BoundsChecker is used to validate object sizes, pointers and handle indices +// for payload of incoming messages. +class BoundsChecker { + public: + // [data, data + data_num_bytes) specifies the initial valid memory range. + // [0, num_handles) specifies the initial valid range of handle indices. + BoundsChecker(const void* data, uint32_t data_num_bytes, + size_t num_handles); + + ~BoundsChecker(); + + // Claims the specified memory range. + // The method succeeds if the range is valid to claim. (Please see + // the comments for IsValidRange().) + // On success, the valid memory range is shrinked to begin right after the end + // of the claimed range. + bool ClaimMemory(const void* position, uint32_t num_bytes); + + // Claims the specified encoded handle (which is basically a handle index). + // The method succeeds if: + // - |encoded_handle|'s value is |kEncodedInvalidHandleValue|. + // - the handle is contained inside the valid range of handle indices. In this + // case, the valid range is shinked to begin right after the claimed handle. + bool ClaimHandle(const Handle& encoded_handle); + + // Returns true if the specified range is not empty, and the range is + // contained inside the valid memory range. + bool IsValidRange(const void* position, uint32_t num_bytes) const; + + private: + bool InternalIsValidRange(uintptr_t begin, uintptr_t end) const; + + // [data_begin_, data_end_) is the valid memory range. + uintptr_t data_begin_; + uintptr_t data_end_; + + // [handle_begin_, handle_end_) is the valid handle index range. + uint32_t handle_begin_; + uint32_t handle_end_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChecker); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BOUNDS_CHECKER_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/buffer.h b/chromium/mojo/public/cpp/bindings/lib/buffer.h new file mode 100644 index 00000000000..c3b570e7767 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/buffer.h @@ -0,0 +1,24 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_BUFFER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BUFFER_H_ + +#include <stddef.h> + +namespace mojo { +namespace internal { + +// Buffer provides a way to allocate memory. Allocations are 8-byte aligned and +// zero-initialized. Allocations remain valid for the lifetime of the Buffer. +class Buffer { + public: + virtual ~Buffer() {} + virtual void* Allocate(size_t num_bytes) = 0; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BUFFER_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/callback_internal.h b/chromium/mojo/public/cpp/bindings/lib/callback_internal.h new file mode 100644 index 00000000000..f76ebef59e6 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/callback_internal.h @@ -0,0 +1,26 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_CALLBACK_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_CALLBACK_INTERNAL_H_ + +namespace mojo { +class String; + +namespace internal { + +template <typename T> +struct Callback_ParamTraits { + typedef T ForwardType; +}; + +template <> +struct Callback_ParamTraits<String> { + typedef const String& ForwardType; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_CALLBACK_INTERNAL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/connector.cc b/chromium/mojo/public/cpp/bindings/lib/connector.cc new file mode 100644 index 00000000000..aa2c4d12334 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/connector.cc @@ -0,0 +1,157 @@ +// 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. + +#include "mojo/public/cpp/bindings/lib/connector.h" + +#include <assert.h> +#include <stdlib.h> + +#include "mojo/public/cpp/bindings/error_handler.h" + +namespace mojo { +namespace internal { + +// ---------------------------------------------------------------------------- + +Connector::Connector(ScopedMessagePipeHandle message_pipe, + const MojoAsyncWaiter* waiter) + : error_handler_(NULL), + waiter_(waiter), + message_pipe_(message_pipe.Pass()), + incoming_receiver_(NULL), + async_wait_id_(0), + error_(false), + drop_writes_(false), + enforce_errors_from_incoming_receiver_(true), + destroyed_flag_(NULL) { + // Even though we don't have an incoming receiver, we still want to monitor + // the message pipe to know if is closed or encounters an error. + WaitToReadMore(); +} + +Connector::~Connector() { + if (destroyed_flag_) + *destroyed_flag_ = true; + + if (async_wait_id_) + waiter_->CancelWait(async_wait_id_); +} + +void Connector::CloseMessagePipe() { + Close(message_pipe_.Pass()); +} + +ScopedMessagePipeHandle Connector::PassMessagePipe() { + if (async_wait_id_) { + waiter_->CancelWait(async_wait_id_); + async_wait_id_ = 0; + } + return message_pipe_.Pass(); +} + +bool Connector::Accept(Message* message) { + assert(message_pipe_.is_valid()); + + if (error_) + return false; + + if (drop_writes_) + return true; + + MojoResult rv = WriteMessageRaw( + message_pipe_.get(), + message->data(), + message->data_num_bytes(), + message->mutable_handles()->empty() ? NULL : + reinterpret_cast<const MojoHandle*>( + &message->mutable_handles()->front()), + static_cast<uint32_t>(message->mutable_handles()->size()), + MOJO_WRITE_MESSAGE_FLAG_NONE); + + switch (rv) { + case MOJO_RESULT_OK: + // The handles were successfully transferred, so we don't need the message + // to track their lifetime any longer. + message->mutable_handles()->clear(); + break; + case MOJO_RESULT_FAILED_PRECONDITION: + // There's no point in continuing to write to this pipe since the other + // end is gone. Avoid writing any future messages. Hide write failures + // from the caller since we'd like them to continue consuming any backlog + // of incoming messages before regarding the message pipe as closed. + drop_writes_ = true; + break; + default: + // This particular write was rejected, presumably because of bad input. + // The pipe is not necessarily in a bad state. + return false; + } + return true; +} + +// static +void Connector::CallOnHandleReady(void* closure, MojoResult result) { + Connector* self = static_cast<Connector*>(closure); + self->OnHandleReady(result); +} + +void Connector::OnHandleReady(MojoResult result) { + assert(async_wait_id_ != 0); + async_wait_id_ = 0; + + if (result == MOJO_RESULT_OK) { + // Return immediately if |this| was destroyed. Do not touch any members! + if (!ReadMore()) + return; + } else { + error_ = true; + } + + if (error_ && error_handler_) + error_handler_->OnConnectionError(); +} + +void Connector::WaitToReadMore() { + async_wait_id_ = waiter_->AsyncWait(message_pipe_.get().value(), + MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, + &Connector::CallOnHandleReady, + this); +} + +bool Connector::ReadMore() { + while (true) { + bool receiver_result = false; + + // Detect if |this| was destroyed during message dispatch. Allow for the + // possibility of re-entering ReadMore() through message dispatch. + bool was_destroyed_during_dispatch = false; + bool* previous_destroyed_flag = destroyed_flag_; + destroyed_flag_ = &was_destroyed_during_dispatch; + + MojoResult rv = ReadAndDispatchMessage( + message_pipe_.get(), incoming_receiver_, &receiver_result); + + if (was_destroyed_during_dispatch) { + if (previous_destroyed_flag) + *previous_destroyed_flag = true; // Propagate flag. + return false; + } + destroyed_flag_ = previous_destroyed_flag; + + if (rv == MOJO_RESULT_SHOULD_WAIT) { + WaitToReadMore(); + break; + } + if (rv != MOJO_RESULT_OK || + (enforce_errors_from_incoming_receiver_ && !receiver_result)) { + error_ = true; + break; + } + } + return true; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/connector.h b/chromium/mojo/public/cpp/bindings/lib/connector.h new file mode 100644 index 00000000000..30cd65f4c42 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/connector.h @@ -0,0 +1,100 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_CONNECTOR_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_CONNECTOR_H_ + +#include "mojo/public/c/environment/async_waiter.h" +#include "mojo/public/cpp/bindings/lib/message_queue.h" +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +class ErrorHandler; + +namespace internal { + +// The Connector class is responsible for performing read/write operations on a +// MessagePipe. It writes messages it receives through the MessageReceiver +// interface that it subclasses, and it forwards messages it reads through the +// MessageReceiver interface assigned as its incoming receiver. +// +// NOTE: MessagePipe I/O is non-blocking. +// +class Connector : public MessageReceiver { + public: + // The Connector takes ownership of |message_pipe|. + explicit Connector( + ScopedMessagePipeHandle message_pipe, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()); + virtual ~Connector(); + + // Sets the receiver to handle messages read from the message pipe. The + // Connector will read messages from the pipe regardless of whether or not an + // incoming receiver has been set. + void set_incoming_receiver(MessageReceiver* receiver) { + incoming_receiver_ = receiver; + } + + // Errors from incoming receivers will force the connector into an error + // state, where no more messages will be processed. This method is used + // during testing to prevent that from happening. + void set_enforce_errors_from_incoming_receiver(bool enforce) { + enforce_errors_from_incoming_receiver_ = enforce; + } + + // Sets the error handler to receive notifications when an error is + // encountered while reading from the pipe or waiting to read from the pipe. + void set_error_handler(ErrorHandler* error_handler) { + error_handler_ = error_handler; + } + + // Returns true if an error was encountered while reading from the pipe or + // waiting to read from the pipe. + bool encountered_error() const { return error_; } + + // Closes the pipe, triggering the error state. Connector is put into a + // quiescent state. + void CloseMessagePipe(); + + // Releases the pipe, not triggering the error state. Connector is put into + // a quiescent state. + ScopedMessagePipeHandle PassMessagePipe(); + + // MessageReceiver implementation: + virtual bool Accept(Message* message) MOJO_OVERRIDE; + + private: + static void CallOnHandleReady(void* closure, MojoResult result); + void OnHandleReady(MojoResult result); + + void WaitToReadMore(); + + // Returns false if |this| was destroyed during message dispatch. + MOJO_WARN_UNUSED_RESULT bool ReadMore(); + + ErrorHandler* error_handler_; + const MojoAsyncWaiter* waiter_; + + ScopedMessagePipeHandle message_pipe_; + MessageReceiver* incoming_receiver_; + + MojoAsyncWaitID async_wait_id_; + bool error_; + bool drop_writes_; + bool enforce_errors_from_incoming_receiver_; + + // If non-null, this will be set to true when the Connector is destroyed. We + // use this flag to allow for the Connector to be destroyed as a side-effect + // of dispatching an incoming message. + bool* destroyed_flag_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Connector); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_CONNECTOR_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/filter_chain.cc b/chromium/mojo/public/cpp/bindings/lib/filter_chain.cc new file mode 100644 index 00000000000..efd4ba19875 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/filter_chain.cc @@ -0,0 +1,49 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/lib/filter_chain.h" + +#include <assert.h> + +#include <algorithm> + +namespace mojo { +namespace internal { + +FilterChain::FilterChain(MessageReceiver* sink) : sink_(sink) { +} + +FilterChain::FilterChain(RValue other) : sink_(other.object->sink_) { + other.object->sink_ = NULL; + filters_.swap(other.object->filters_); +} + +FilterChain& FilterChain::operator=(RValue other) { + std::swap(sink_, other.object->sink_); + filters_.swap(other.object->filters_); + return *this; +} + +FilterChain::~FilterChain() { + for (std::vector<MessageFilter*>::iterator iter = filters_.begin(); + iter != filters_.end(); + ++iter) { + delete *iter; + } +} + +void FilterChain::SetSink(MessageReceiver* sink) { + assert(!sink_); + sink_ = sink; + if (!filters_.empty()) + filters_.back()->set_sink(sink); +} + +MessageReceiver* FilterChain::GetHead() { + assert(sink_); + return filters_.empty() ? sink_ : filters_.front(); +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/filter_chain.h b/chromium/mojo/public/cpp/bindings/lib/filter_chain.h new file mode 100644 index 00000000000..8680f41aaee --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/filter_chain.h @@ -0,0 +1,66 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_FILTER_CHAIN_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_FILTER_CHAIN_H_ + +#include <vector> + +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/bindings/message_filter.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +class FilterChain { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(FilterChain, RValue) + + public: + // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while + // this object is alive. + explicit FilterChain(MessageReceiver* sink = NULL); + + // Move-only constructor and operator=. + FilterChain(RValue other); + FilterChain& operator=(RValue other); + + ~FilterChain(); + + template <typename FilterType> + inline void Append(); + + // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while + // this object is alive. + void SetSink(MessageReceiver* sink); + + // Returns a receiver to accept messages. Messages flow through all filters in + // the same order as they were appended to the chain. If all filters allow a + // message to pass, it will be forwarded to |sink_|. + // The returned value is invalidated when this object goes away. + MessageReceiver* GetHead(); + + private: + // Owned by this object. + std::vector<MessageFilter*> filters_; + + MessageReceiver* sink_; +}; + +template <typename FilterType> +inline void FilterChain::Append() { + FilterType* filter = new FilterType(sink_); + if (!filters_.empty()) + filters_.back()->set_sink(filter); + filters_.push_back(filter); +} + +template <> +inline void FilterChain::Append<PassThroughFilter>() { +} + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_FILTER_CHAIN_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.cc b/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.cc new file mode 100644 index 00000000000..5226231725c --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.cc @@ -0,0 +1,53 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <algorithm> + +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" + +namespace mojo { +namespace internal { + +FixedBuffer::FixedBuffer(size_t size) + : ptr_(NULL), + cursor_(0), + size_(internal::Align(size)) { + // calloc() required to zero memory and thus avoid info leaks. + ptr_ = static_cast<char*>(calloc(size_, 1)); +} + +FixedBuffer::~FixedBuffer() { + free(ptr_); +} + +void* FixedBuffer::Allocate(size_t delta) { + delta = internal::Align(delta); + + if (delta == 0 || delta > size_ - cursor_) { + assert(false); + return NULL; + } + + char* result = ptr_ + cursor_; + cursor_ += delta; + + return result; +} + +void* FixedBuffer::Leak() { + char* ptr = ptr_; + ptr_ = NULL; + cursor_ = 0; + size_ = 0; + return ptr; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.h b/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.h new file mode 100644 index 00000000000..a3515a2ae86 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.h @@ -0,0 +1,67 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_FIXED_BUFFER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_FIXED_BUFFER_H_ + +#include "mojo/public/cpp/bindings/lib/buffer.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +// FixedBuffer provides a simple way to allocate objects within a fixed chunk +// of memory. Objects are allocated by calling the |Allocate| method, which +// extends the buffer accordingly. Objects allocated in this way are not freed +// explicitly. Instead, they remain valid so long as the FixedBuffer remains +// valid. The Leak method may be used to steal the underlying memory from the +// FixedBuffer. +// +// Typical usage: +// +// { +// FixedBuffer buf(8 + 8); +// +// int* a = static_cast<int*>(buf->Allocate(sizeof(int))); +// *a = 2; +// +// double* b = static_cast<double*>(buf->Allocate(sizeof(double))); +// *b = 3.14f; +// +// void* data = buf.Leak(); +// Process(data); +// +// free(data); +// } +// +class FixedBuffer : public Buffer { + public: + explicit FixedBuffer(size_t size); + virtual ~FixedBuffer(); + + // Grows the buffer by |num_bytes| and returns a pointer to the start of the + // addition. The resulting address is 8-byte aligned, and the content of the + // memory is zero-filled. + virtual void* Allocate(size_t num_bytes) MOJO_OVERRIDE; + + size_t size() const { return size_; } + + // Returns the internal memory owned by the Buffer to the caller. The Buffer + // relinquishes its pointer, effectively resetting the state of the Buffer + // and leaving the caller responsible for freeing the returned memory address + // when no longer needed. + void* Leak(); + + private: + char* ptr_; + size_t cursor_; + size_t size_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(FixedBuffer); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_FIXED_BUFFER_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_impl_internal.h b/chromium/mojo/public/cpp/bindings/lib/interface_impl_internal.h new file mode 100644 index 00000000000..f2cc4f0c5b6 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/interface_impl_internal.h @@ -0,0 +1,94 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_ + +#include "mojo/public/cpp/bindings/error_handler.h" +#include "mojo/public/cpp/bindings/interface_ptr.h" +#include "mojo/public/cpp/bindings/lib/filter_chain.h" +#include "mojo/public/cpp/bindings/lib/message_header_validator.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +template <typename Interface> +class InterfaceImplBase : public Interface { + public: + virtual ~InterfaceImplBase() {} + virtual void OnConnectionEstablished() = 0; + virtual void OnConnectionError() = 0; +}; + +template <typename Interface> +class InterfaceImplState : public ErrorHandler { + public: + typedef typename Interface::Client Client; + + explicit InterfaceImplState(InterfaceImplBase<Interface>* instance) + : router_(NULL), + proxy_(NULL) { + assert(instance); + stub_.set_sink(instance); + } + + virtual ~InterfaceImplState() { + delete proxy_; + if (router_) { + router_->set_error_handler(NULL); + delete router_; + } + } + + void BindProxy( + InterfacePtr<Interface>* ptr, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + MessagePipe pipe; + ptr->Bind(pipe.handle0.Pass(), waiter); + Bind(pipe.handle1.Pass(), waiter); + } + + void Bind(ScopedMessagePipeHandle handle, + const MojoAsyncWaiter* waiter) { + assert(!router_); + + FilterChain filters; + filters.Append<MessageHeaderValidator>(); + filters.Append<typename Interface::RequestValidator_>(); + filters.Append<typename Interface::Client::ResponseValidator_>(); + + router_ = new Router(handle.Pass(), filters.Pass(), waiter); + router_->set_incoming_receiver(&stub_); + router_->set_error_handler(this); + + proxy_ = new typename Client::Proxy_(router_); + + instance()->OnConnectionEstablished(); + } + + Router* router() { return router_; } + Client* client() { return proxy_; } + + private: + InterfaceImplBase<Interface>* instance() { + return static_cast<InterfaceImplBase<Interface>*>(stub_.sink()); + } + + virtual void OnConnectionError() MOJO_OVERRIDE { + instance()->OnConnectionError(); + } + + Router* router_; + typename Client::Proxy_* proxy_; + typename Interface::Stub_ stub_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(InterfaceImplState); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_ptr_internal.h b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_internal.h new file mode 100644 index 00000000000..a318d6185c5 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_internal.h @@ -0,0 +1,84 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_ + +#include <assert.h> +#include <stdio.h> + +#include "mojo/public/cpp/bindings/lib/filter_chain.h" +#include "mojo/public/cpp/bindings/lib/message_header_validator.h" +#include "mojo/public/cpp/bindings/lib/router.h" +#include "mojo/public/cpp/environment/environment.h" + +namespace mojo { +namespace internal { + +template <typename Interface> +class InterfacePtrState { + public: + InterfacePtrState() : proxy_(NULL), router_(NULL) {} + + ~InterfacePtrState() { + // Destruction order matters here. We delete |proxy_| first, even though + // |router_| may have a reference to it, so that |~Interface| may have a + // shot at generating new outbound messages (ie, invoking client methods). + delete proxy_; + delete router_; + } + + Interface* instance() const { return proxy_; } + + Router* router() const { return router_; } + + void Swap(InterfacePtrState* other) { + std::swap(other->proxy_, proxy_); + std::swap(other->router_, router_); + } + + void ConfigureProxy( + ScopedMessagePipeHandle handle, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + assert(!proxy_); + assert(!router_); + + FilterChain filters; + filters.Append<MessageHeaderValidator>(); + filters.Append<typename Interface::Client::RequestValidator_>(); + filters.Append<typename Interface::ResponseValidator_>(); + + router_ = new Router(handle.Pass(), filters.Pass(), waiter); + ProxyWithStub* proxy = new ProxyWithStub(router_); + router_->set_incoming_receiver(&proxy->stub); + + proxy_ = proxy; + } + + void set_client(typename Interface::Client* client) { + assert(proxy_); + proxy_->stub.set_sink(client); + } + + private: + class ProxyWithStub : public Interface::Proxy_ { + public: + explicit ProxyWithStub(MessageReceiverWithResponder* receiver) + : Interface::Proxy_(receiver) { + } + typename Interface::Client::Stub_ stub; + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(ProxyWithStub); + }; + + ProxyWithStub* proxy_; + Router* router_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(InterfacePtrState); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/message.cc b/chromium/mojo/public/cpp/bindings/lib/message.cc new file mode 100644 index 00000000000..78017c00793 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message.cc @@ -0,0 +1,81 @@ +// 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. + +#include "mojo/public/cpp/bindings/message.h" + +#include <assert.h> +#include <stdlib.h> + +#include <algorithm> + +namespace mojo { + +Message::Message() + : data_num_bytes_(0), + data_(NULL) { +} + +Message::~Message() { + free(data_); + + for (std::vector<Handle>::iterator it = handles_.begin(); + it != handles_.end(); ++it) { + if (it->is_valid()) + CloseRaw(*it); + } +} + +void Message::AllocUninitializedData(uint32_t num_bytes) { + assert(!data_); + data_num_bytes_ = num_bytes; + data_ = static_cast<internal::MessageData*>(malloc(num_bytes)); +} + +void Message::AdoptData(uint32_t num_bytes, internal::MessageData* data) { + assert(!data_); + data_num_bytes_ = num_bytes; + data_ = data; +} + +void Message::Swap(Message* other) { + std::swap(data_num_bytes_, other->data_num_bytes_); + std::swap(data_, other->data_); + std::swap(handles_, other->handles_); +} + +MojoResult ReadAndDispatchMessage(MessagePipeHandle handle, + MessageReceiver* receiver, + bool* receiver_result) { + MojoResult rv; + + uint32_t num_bytes = 0, num_handles = 0; + rv = ReadMessageRaw(handle, + NULL, + &num_bytes, + NULL, + &num_handles, + MOJO_READ_MESSAGE_FLAG_NONE); + if (rv != MOJO_RESULT_RESOURCE_EXHAUSTED) + return rv; + + Message message; + message.AllocUninitializedData(num_bytes); + message.mutable_handles()->resize(num_handles); + + rv = ReadMessageRaw(handle, + message.mutable_data(), + &num_bytes, + message.mutable_handles()->empty() + ? NULL + : reinterpret_cast<MojoHandle*>( + &message.mutable_handles()->front()), + &num_handles, + MOJO_READ_MESSAGE_FLAG_NONE); + if (receiver && rv == MOJO_RESULT_OK) + *receiver_result = receiver->Accept(&message); + + return rv; +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/message_builder.cc b/chromium/mojo/public/cpp/bindings/lib/message_builder.cc new file mode 100644 index 00000000000..c7466444d04 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_builder.cc @@ -0,0 +1,52 @@ +// 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. + +#include "mojo/public/cpp/bindings/lib/message_builder.h" + +#include "mojo/public/cpp/bindings/message.h" + +namespace mojo { +namespace internal { + +template <typename Header> +void Allocate(Buffer* buf, Header** header) { + *header = static_cast<Header*>(buf->Allocate(sizeof(Header))); + (*header)->num_bytes = sizeof(Header); +} + +MessageBuilder::MessageBuilder(uint32_t name, size_t payload_size) + : buf_(sizeof(MessageHeader) + payload_size) { + MessageHeader* header; + Allocate(&buf_, &header); + header->num_fields = 2; + header->name = name; +} + +MessageBuilder::~MessageBuilder() { +} + +void MessageBuilder::Finish(Message* message) { + uint32_t num_bytes = static_cast<uint32_t>(buf_.size()); + message->AdoptData(num_bytes, static_cast<MessageData*>(buf_.Leak())); +} + +MessageBuilder::MessageBuilder(size_t size) + : buf_(size) { +} + +MessageWithRequestIDBuilder::MessageWithRequestIDBuilder(uint32_t name, + size_t payload_size, + uint32_t flags, + uint64_t request_id) + : MessageBuilder(sizeof(MessageHeaderWithRequestID) + payload_size) { + MessageHeaderWithRequestID* header; + Allocate(&buf_, &header); + header->num_fields = 3; + header->name = name; + header->flags = flags; + header->request_id = request_id; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/message_builder.h b/chromium/mojo/public/cpp/bindings/lib/message_builder.h new file mode 100644 index 00000000000..b4988ff9cb9 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_builder.h @@ -0,0 +1,63 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_BUILDER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_BUILDER_H_ + +#include <stdint.h> + +#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" +#include "mojo/public/cpp/bindings/lib/message_internal.h" + +namespace mojo { +class Message; + +namespace internal { + +class MessageBuilder { + public: + MessageBuilder(uint32_t name, size_t payload_size); + ~MessageBuilder(); + + Buffer* buffer() { return &buf_; } + + // Call Finish when done making allocations in |buffer()|. Upon return, + // |message| will contain the message data, and |buffer()| will no longer be + // valid to reference. + void Finish(Message* message); + + protected: + explicit MessageBuilder(size_t size); + FixedBuffer buf_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(MessageBuilder); +}; + +class MessageWithRequestIDBuilder : public MessageBuilder { + public: + MessageWithRequestIDBuilder(uint32_t name, size_t payload_size, + uint32_t flags, uint64_t request_id); +}; + +class RequestMessageBuilder : public MessageWithRequestIDBuilder { + public: + RequestMessageBuilder(uint32_t name, size_t payload_size) + : MessageWithRequestIDBuilder(name, payload_size, kMessageExpectsResponse, + 0) { + } +}; + +class ResponseMessageBuilder : public MessageWithRequestIDBuilder { + public: + ResponseMessageBuilder(uint32_t name, size_t payload_size, + uint64_t request_id) + : MessageWithRequestIDBuilder(name, payload_size, kMessageIsResponse, + request_id) { + } +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_BUILDER_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/message_filter.cc b/chromium/mojo/public/cpp/bindings/lib/message_filter.cc new file mode 100644 index 00000000000..b09f40d8c5e --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_filter.cc @@ -0,0 +1,23 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/message_filter.h" + +namespace mojo { + +MessageFilter::MessageFilter(MessageReceiver* sink) : sink_(sink) { +} + +MessageFilter::~MessageFilter() { +} + +PassThroughFilter::PassThroughFilter(MessageReceiver* sink) + : MessageFilter(sink) { +} + +bool PassThroughFilter::Accept(Message* message) { + return sink_->Accept(message); +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/message_header_validator.cc b/chromium/mojo/public/cpp/bindings/lib/message_header_validator.cc new file mode 100644 index 00000000000..a55917afde5 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_header_validator.cc @@ -0,0 +1,81 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/lib/message_header_validator.h" + +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" +#include "mojo/public/cpp/bindings/lib/bounds_checker.h" +#include "mojo/public/cpp/bindings/lib/validation_errors.h" + +namespace mojo { +namespace internal { +namespace { + +bool IsValidMessageHeader(const MessageHeader* header) { + // NOTE: Our goal is to preserve support for future extension of the message + // header. If we encounter fields we do not understand, we must ignore them. + + // Extra validation of the struct header: + if (header->num_fields == 2) { + if (header->num_bytes != sizeof(MessageHeader)) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + } else if (header->num_fields == 3) { + if (header->num_bytes != sizeof(MessageHeaderWithRequestID)) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + } else if (header->num_fields > 3) { + if (header->num_bytes < sizeof(MessageHeaderWithRequestID)) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + } + + // Validate flags (allow unknown bits): + + // These flags require a RequestID. + if (header->num_fields < 3 && + ((header->flags & kMessageExpectsResponse) || + (header->flags & kMessageIsResponse))) { + ReportValidationError(VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID); + return false; + } + + // These flags are mutually exclusive. + if ((header->flags & kMessageExpectsResponse) && + (header->flags & kMessageIsResponse)) { + ReportValidationError( + VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION); + return false; + } + + return true; +} + +} // namespace + +MessageHeaderValidator::MessageHeaderValidator(MessageReceiver* sink) + : MessageFilter(sink) { +} + +bool MessageHeaderValidator::Accept(Message* message) { + // Pass 0 as number of handles because we don't expect any in the header, even + // if |message| contains handles. + BoundsChecker bounds_checker(message->data(), message->data_num_bytes(), 0); + + if (!ValidateStructHeader(message->data(), sizeof(MessageHeader), 2, + &bounds_checker)) { + return false; + } + + if (!IsValidMessageHeader(message->header())) + return false; + + return sink_->Accept(message); +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/message_header_validator.h b/chromium/mojo/public/cpp/bindings/lib/message_header_validator.h new file mode 100644 index 00000000000..c3f43a07fbc --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_header_validator.h @@ -0,0 +1,24 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_HEADER_VALIDATOR_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_HEADER_VALIDATOR_H_ + +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/bindings/message_filter.h" + +namespace mojo { +namespace internal { + +class MessageHeaderValidator : public MessageFilter { + public: + explicit MessageHeaderValidator(MessageReceiver* sink = NULL); + + virtual bool Accept(Message* message) MOJO_OVERRIDE; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_HEADER_VALIDATOR_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/message_internal.h b/chromium/mojo/public/cpp/bindings/lib/message_internal.h new file mode 100644 index 00000000000..3c67902b7a8 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_internal.h @@ -0,0 +1,44 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_INTERNAL_H_ + +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" + +namespace mojo { +namespace internal { + +#pragma pack(push, 1) + +enum { + kMessageExpectsResponse = 1 << 0, + kMessageIsResponse = 1 << 1 +}; + +struct MessageHeader : internal::StructHeader { + uint32_t name; + uint32_t flags; +}; +MOJO_COMPILE_ASSERT(sizeof(MessageHeader) == 16, bad_sizeof_MessageHeader); + +struct MessageHeaderWithRequestID : MessageHeader { + uint64_t request_id; +}; +MOJO_COMPILE_ASSERT(sizeof(MessageHeaderWithRequestID) == 24, + bad_sizeof_MessageHeaderWithRequestID); + +struct MessageData { + MessageHeader header; +}; + +MOJO_COMPILE_ASSERT(sizeof(MessageData) == sizeof(MessageHeader), + bad_sizeof_MessageData); + +#pragma pack(pop) + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_INTERNAL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/message_queue.cc b/chromium/mojo/public/cpp/bindings/lib/message_queue.cc new file mode 100644 index 00000000000..1982ccb14c2 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_queue.cc @@ -0,0 +1,50 @@ +// 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. + +#include "mojo/public/cpp/bindings/lib/message_queue.h" + +#include <assert.h> +#include <stddef.h> + +#include "mojo/public/cpp/bindings/message.h" + +namespace mojo { +namespace internal { + +MessageQueue::MessageQueue() { +} + +MessageQueue::~MessageQueue() { + while (!queue_.empty()) + Pop(); +} + +bool MessageQueue::IsEmpty() const { + return queue_.empty(); +} + +Message* MessageQueue::Peek() { + assert(!queue_.empty()); + return queue_.front(); +} + +void MessageQueue::Push(Message* message) { + queue_.push(new Message()); + queue_.back()->Swap(message); +} + +void MessageQueue::Pop(Message* message) { + assert(!queue_.empty()); + queue_.front()->Swap(message); + Pop(); +} + +void MessageQueue::Pop() { + assert(!queue_.empty()); + delete queue_.front(); + queue_.pop(); +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/message_queue.h b/chromium/mojo/public/cpp/bindings/lib/message_queue.h new file mode 100644 index 00000000000..4e46b54a250 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_queue.h @@ -0,0 +1,47 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_QUEUE_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_QUEUE_H_ + +#include <queue> + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +class Message; + +namespace internal { + +// A queue for Message objects. +class MessageQueue { + public: + MessageQueue(); + ~MessageQueue(); + + bool IsEmpty() const; + Message* Peek(); + + // This method transfers ownership of |message->data| and |message->handles| + // to the message queue, resetting |message| in the process. + void Push(Message* message); + + // Removes the next message from the queue, transferring ownership of its + // data and handles to the given |message|. + void Pop(Message* message); + + // Removes the next message from the queue, discarding its data and handles. + // This is meant to be used in conjunction with |Peek|. + void Pop(); + + private: + std::queue<Message*> queue_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(MessageQueue); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_QUEUE_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/no_interface.cc b/chromium/mojo/public/cpp/bindings/lib/no_interface.cc new file mode 100644 index 00000000000..9e0945c83b3 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/no_interface.cc @@ -0,0 +1,20 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/no_interface.h" + +namespace mojo { + +const char* NoInterface::Name_ = "mojo::NoInterface"; + +bool NoInterfaceStub::Accept(Message* message) { + return false; +} + +bool NoInterfaceStub::AcceptWithResponder(Message* message, + MessageReceiver* responder) { + return false; +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/router.cc b/chromium/mojo/public/cpp/bindings/lib/router.cc new file mode 100644 index 00000000000..a8222203c47 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/router.cc @@ -0,0 +1,140 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/lib/router.h" + +namespace mojo { +namespace internal { + +// ---------------------------------------------------------------------------- + +class ResponderThunk : public MessageReceiver { + public: + explicit ResponderThunk(const SharedData<Router*>& router) + : router_(router) { + } + virtual ~ResponderThunk() { + } + + // MessageReceiver implementation: + virtual bool Accept(Message* message) MOJO_OVERRIDE { + assert(message->has_flag(kMessageIsResponse)); + + bool result = false; + + Router* router = router_.value(); + if (router) + result = router->Accept(message); + + return result; + } + + private: + SharedData<Router*> router_; +}; + +// ---------------------------------------------------------------------------- + +Router::HandleIncomingMessageThunk::HandleIncomingMessageThunk(Router* router) + : router_(router) { +} + +Router::HandleIncomingMessageThunk::~HandleIncomingMessageThunk() { +} + +bool Router::HandleIncomingMessageThunk::Accept(Message* message) { + return router_->HandleIncomingMessage(message); +} + +// ---------------------------------------------------------------------------- + +Router::Router(ScopedMessagePipeHandle message_pipe, + FilterChain filters, + const MojoAsyncWaiter* waiter) + : thunk_(this), + filters_(filters.Pass()), + connector_(message_pipe.Pass(), waiter), + weak_self_(this), + incoming_receiver_(NULL), + next_request_id_(0), + testing_mode_(false) { + filters_.SetSink(&thunk_); + connector_.set_incoming_receiver(filters_.GetHead()); +} + +Router::~Router() { + weak_self_.set_value(NULL); + + for (ResponderMap::const_iterator i = responders_.begin(); + i != responders_.end(); ++i) { + delete i->second; + } +} + +bool Router::Accept(Message* message) { + assert(!message->has_flag(kMessageExpectsResponse)); + return connector_.Accept(message); +} + +bool Router::AcceptWithResponder(Message* message, + MessageReceiver* responder) { + assert(message->has_flag(kMessageExpectsResponse)); + + // Reserve 0 in case we want it to convey special meaning in the future. + uint64_t request_id = next_request_id_++; + if (request_id == 0) + request_id = next_request_id_++; + + message->set_request_id(request_id); + if (!connector_.Accept(message)) + return false; + + // We assume ownership of |responder|. + responders_[request_id] = responder; + return true; +} + +void Router::EnableTestingMode() { + testing_mode_ = true; + connector_.set_enforce_errors_from_incoming_receiver(false); +} + +bool Router::HandleIncomingMessage(Message* message) { + if (message->has_flag(kMessageExpectsResponse)) { + if (incoming_receiver_) { + MessageReceiver* responder = new ResponderThunk(weak_self_); + bool ok = incoming_receiver_->AcceptWithResponder(message, responder); + if (!ok) + delete responder; + return ok; + } + + // If we receive a request expecting a response when the client is not + // listening, then we have no choice but to tear down the pipe. + connector_.CloseMessagePipe(); + } else if (message->has_flag(kMessageIsResponse)) { + uint64_t request_id = message->request_id(); + ResponderMap::iterator it = responders_.find(request_id); + if (it == responders_.end()) { + assert(testing_mode_); + return false; + } + MessageReceiver* responder = it->second; + responders_.erase(it); + bool ok = responder->Accept(message); + delete responder; + return ok; + } else { + if (incoming_receiver_) + return incoming_receiver_->Accept(message); + // OK to drop message on the floor. + } + + return false; +} + +// ---------------------------------------------------------------------------- + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/router.h b/chromium/mojo/public/cpp/bindings/lib/router.h new file mode 100644 index 00000000000..76bf1471e2e --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/router.h @@ -0,0 +1,91 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_ + +#include <map> + +#include "mojo/public/cpp/bindings/lib/connector.h" +#include "mojo/public/cpp/bindings/lib/filter_chain.h" +#include "mojo/public/cpp/bindings/lib/shared_data.h" +#include "mojo/public/cpp/environment/environment.h" + +namespace mojo { +namespace internal { + +class Router : public MessageReceiverWithResponder { + public: + Router(ScopedMessagePipeHandle message_pipe, + FilterChain filters, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()); + virtual ~Router(); + + // Sets the receiver to handle messages read from the message pipe that do + // not have the kMessageIsResponse flag set. + void set_incoming_receiver(MessageReceiverWithResponder* receiver) { + incoming_receiver_ = receiver; + } + + // Sets the error handler to receive notifications when an error is + // encountered while reading from the pipe or waiting to read from the pipe. + void set_error_handler(ErrorHandler* error_handler) { + connector_.set_error_handler(error_handler); + } + + // Returns true if an error was encountered while reading from the pipe or + // waiting to read from the pipe. + bool encountered_error() const { return connector_.encountered_error(); } + + void CloseMessagePipe() { + connector_.CloseMessagePipe(); + } + + ScopedMessagePipeHandle PassMessagePipe() { + return connector_.PassMessagePipe(); + } + + // MessageReceiver implementation: + virtual bool Accept(Message* message) MOJO_OVERRIDE; + virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) + MOJO_OVERRIDE; + + // Sets this object to testing mode. + // In testing mode: + // - the object is more tolerant of unrecognized response messages; + // - the connector continues working after seeing errors from its incoming + // receiver. + void EnableTestingMode(); + + private: + typedef std::map<uint64_t, MessageReceiver*> ResponderMap; + + class HandleIncomingMessageThunk : public MessageReceiver { + public: + HandleIncomingMessageThunk(Router* router); + virtual ~HandleIncomingMessageThunk(); + + // MessageReceiver implementation: + virtual bool Accept(Message* message) MOJO_OVERRIDE; + + private: + Router* router_; + }; + + bool HandleIncomingMessage(Message* message); + + HandleIncomingMessageThunk thunk_; + FilterChain filters_; + Connector connector_; + SharedData<Router*> weak_self_; + MessageReceiverWithResponder* incoming_receiver_; + ResponderMap responders_; + uint64_t next_request_id_; + bool testing_mode_; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/shared_data.h b/chromium/mojo/public/cpp/bindings/lib/shared_data.h new file mode 100644 index 00000000000..c7bd54f8d7c --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/shared_data.h @@ -0,0 +1,84 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_ + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +// Used to allocate an instance of T that can be shared via reference counting. +template <typename T> +class SharedData { + public: + ~SharedData() { + holder_->Release(); + } + + SharedData() : holder_(new Holder()) { + } + + explicit SharedData(const T& value) : holder_(new Holder(value)) { + } + + SharedData(const SharedData<T>& other) : holder_(other.holder_) { + holder_->Retain(); + } + + SharedData<T>& operator=(const SharedData<T>& other) { + if (other.holder_ == holder_) + return *this; + holder_->Release(); + holder_ = other.holder_; + holder_->Retain(); + return *this; + } + + void reset() { + holder_->Release(); + holder_ = new Holder(); + } + + void reset(const T& value) { + holder_->Release(); + holder_ = new Holder(value); + } + + void set_value(const T& value) { + holder_->value = value; + } + T* mutable_value() { + return &holder_->value; + } + const T& value() const { + return holder_->value; + } + + private: + class Holder { + public: + Holder() : value(), ref_count_(1) { + } + Holder(const T& value) : value(value), ref_count_(1) { + } + + void Retain() { ++ref_count_; } + void Release() { if (--ref_count_ == 0) delete this; } + + T value; + + private: + int ref_count_; + MOJO_DISALLOW_COPY_AND_ASSIGN(Holder); + }; + + Holder* holder_; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/shared_ptr.h b/chromium/mojo/public/cpp/bindings/lib/shared_ptr.h new file mode 100644 index 00000000000..6ae53a5681a --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/shared_ptr.h @@ -0,0 +1,63 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_PTR_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_PTR_H_ + +#include "mojo/public/cpp/bindings/lib/shared_data.h" + +namespace mojo { +namespace internal { + +// Used to manage a heap-allocated instance of P that can be shared via +// reference counting. When the last reference is dropped, the instance is +// deleted. +template <typename P> +class SharedPtr { + public: + SharedPtr() {} + + explicit SharedPtr(P* ptr) { + impl_.mutable_value()->ptr = ptr; + } + + // Default copy-constructor and assignment operator are OK. + + P* get() { + return impl_.value().ptr; + } + const P* get() const { + return impl_.value().ptr; + } + + P* operator->() { return get(); } + const P* operator->() const { return get(); } + + private: + class Impl { + public: + ~Impl() { + if (ptr) + delete ptr; + } + + Impl() : ptr(NULL) { + } + + Impl(P* ptr) : ptr(ptr) { + } + + P* ptr; + + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(Impl); + }; + + SharedData<Impl> impl_; +}; + +} // namespace mojo +} // namespace internal + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_PTR_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/string_serialization.cc b/chromium/mojo/public/cpp/bindings/lib/string_serialization.cc new file mode 100644 index 00000000000..0044b1b9cff --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/string_serialization.cc @@ -0,0 +1,38 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/lib/string_serialization.h" + +#include <string.h> + +namespace mojo { + +size_t GetSerializedSize_(const String& input) { + if (!input) + return 0; + return internal::Align(sizeof(internal::String_Data) + input.size()); +} + +void Serialize_(const String& input, internal::Buffer* buf, + internal::String_Data** output) { + if (input) { + internal::String_Data* result = + internal::String_Data::New(input.size(), buf); + memcpy(result->storage(), input.data(), input.size()); + *output = result; + } else { + *output = NULL; + } +} + +void Deserialize_(internal::String_Data* input, String* output) { + if (input) { + String result(input->storage(), input->size()); + result.Swap(output); + } else { + output->reset(); + } +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/string_serialization.h b/chromium/mojo/public/cpp/bindings/lib/string_serialization.h new file mode 100644 index 00000000000..bad2a0c2766 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/string_serialization.h @@ -0,0 +1,20 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_STRING_SERIALIZATION_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_STRING_SERIALIZATION_H_ + +#include "mojo/public/cpp/bindings/lib/array_internal.h" +#include "mojo/public/cpp/bindings/string.h" + +namespace mojo { + +size_t GetSerializedSize_(const String& input); +void Serialize_(const String& input, internal::Buffer* buffer, + internal::String_Data** output); +void Deserialize_(internal::String_Data* input, String* output); + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_STRING_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/sync_dispatcher.cc b/chromium/mojo/public/cpp/bindings/lib/sync_dispatcher.cc new file mode 100644 index 00000000000..2cde97f6ee4 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/sync_dispatcher.cc @@ -0,0 +1,27 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/sync_dispatcher.h" + +#include <stdlib.h> + +#include "mojo/public/cpp/bindings/message.h" + +namespace mojo { + +bool WaitForMessageAndDispatch(MessagePipeHandle handle, + MessageReceiver* receiver) { + while (true) { + bool result; + MojoResult rv = ReadAndDispatchMessage(handle, receiver, &result); + if (rv == MOJO_RESULT_OK) + return result; + if (rv == MOJO_RESULT_SHOULD_WAIT) + rv = Wait(handle, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE); + if (rv != MOJO_RESULT_OK) + return false; + } +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/template_util.h b/chromium/mojo/public/cpp/bindings/lib/template_util.h new file mode 100644 index 00000000000..599126691ed --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/template_util.h @@ -0,0 +1,89 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_TEMPLATE_UTIL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_TEMPLATE_UTIL_H_ + +namespace mojo { +namespace internal { + +template<class T, T v> +struct IntegralConstant { + static const T value = v; +}; + +template <class T, T v> const T IntegralConstant<T, v>::value; + +typedef IntegralConstant<bool, true> TrueType; +typedef IntegralConstant<bool, false> FalseType; + +template <class T> struct IsConst : FalseType {}; +template <class T> struct IsConst<const T> : TrueType {}; + +template<bool B, typename T = void> +struct EnableIf {}; + +template<typename T> +struct EnableIf<true, T> { typedef T type; }; + +// Types YesType and NoType are guaranteed such that sizeof(YesType) < +// sizeof(NoType). +typedef char YesType; + +struct NoType { + YesType dummy[2]; +}; + +// A helper template to determine if given type is non-const move-only-type, +// i.e. if a value of the given type should be passed via .Pass() in a +// destructive way. +template <typename T> struct IsMoveOnlyType { + template <typename U> + static YesType Test(const typename U::MoveOnlyTypeForCPP03*); + + template <typename U> + static NoType Test(...); + + static const bool value = sizeof(Test<T>(0)) == sizeof(YesType) && + !IsConst<T>::value; +}; + +template <typename T> +typename EnableIf<!IsMoveOnlyType<T>::value, T>::type& Forward(T& t) { + return t; +} + +template <typename T> +typename EnableIf<IsMoveOnlyType<T>::value, T>::type Forward(T& t) { + return t.Pass(); +} + +// This goop is a trick used to implement a template that can be used to +// determine if a given class is the base class of another given class. +template<typename, typename> struct IsSame { + static bool const value = false; +}; +template<typename A> struct IsSame<A, A> { + static bool const value = true; +}; +template<typename Base, typename Derived> struct IsBaseOf { + private: + // This class doesn't work correctly with forward declarations. + // Because sizeof cannot be applied to incomplete types, this line prevents us + // from passing in forward declarations. + typedef char (*EnsureTypesAreComplete)[sizeof(Base) + sizeof(Derived)]; + + static Derived* CreateDerived(); + static char (&Check(Base*))[1]; + static char (&Check(...))[2]; + + public: + static bool const value = sizeof Check(CreateDerived()) == 1 && + !IsSame<Base const, void const>::value; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_TEMPLATE_UTIL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/validation_errors.cc b/chromium/mojo/public/cpp/bindings/lib/validation_errors.cc new file mode 100644 index 00000000000..ed5904d3963 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/validation_errors.cc @@ -0,0 +1,64 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/lib/validation_errors.h" + +#include <assert.h> +#include <stdio.h> + +namespace mojo { +namespace internal { +namespace { + +ValidationErrorObserverForTesting* g_validation_error_observer = NULL; + +} // namespace + +const char* ValidationErrorToString(ValidationError error) { + switch (error) { + case VALIDATION_ERROR_NONE: + return "VALIDATION_ERROR_NONE"; + case VALIDATION_ERROR_MISALIGNED_OBJECT: + return "VALIDATION_ERROR_MISALIGNED_OBJECT"; + case VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE: + return "VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE"; + case VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER: + return "VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER"; + case VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER: + return "VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER"; + case VALIDATION_ERROR_ILLEGAL_HANDLE: + return "VALIDATION_ERROR_ILLEGAL_HANDLE"; + case VALIDATION_ERROR_ILLEGAL_POINTER: + return "VALIDATION_ERROR_ILLEGAL_POINTER"; + case VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION: + return "VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION"; + case VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID: + return "VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID"; + } + + return "Unknown error"; +} + +void ReportValidationError(ValidationError error) { + if (g_validation_error_observer) { + g_validation_error_observer->set_last_error(error); + } else { + // TODO(yzshen): Consider adding better logging support. + fprintf(stderr, "Invalid message: %s\n", ValidationErrorToString(error)); + } +} + +ValidationErrorObserverForTesting::ValidationErrorObserverForTesting() + : last_error_(VALIDATION_ERROR_NONE) { + assert(!g_validation_error_observer); + g_validation_error_observer = this; +} + +ValidationErrorObserverForTesting::~ValidationErrorObserverForTesting() { + assert(g_validation_error_observer == this); + g_validation_error_observer = NULL; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/validation_errors.h b/chromium/mojo/public/cpp/bindings/lib/validation_errors.h new file mode 100644 index 00000000000..9b443c371e5 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/validation_errors.h @@ -0,0 +1,66 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_ + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +enum ValidationError { + // There is no validation error. + VALIDATION_ERROR_NONE, + // An object (struct or array) is not 8-byte aligned. + VALIDATION_ERROR_MISALIGNED_OBJECT, + // An object is not contained inside the message data, or it overlaps other + // objects. + VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE, + // A struct header doesn't make sense, for example: + // - |num_bytes| is smaller than the size of the oldest version that we + // support. + // - |num_fields| is smaller than the field number of the oldest version that + // we support. + // - |num_bytes| and |num_fields| don't match. + VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER, + // An array header doesn't make sense, for example: + // - |num_bytes| is smaller than the size of the header plus the size required + // to store |num_elements| elements. + VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, + // An encoded handle is illegal. + VALIDATION_ERROR_ILLEGAL_HANDLE, + // An encoded pointer is illegal. + VALIDATION_ERROR_ILLEGAL_POINTER, + // |flags| in the message header is an invalid flag combination. + VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION, + // |flags| in the message header indicates that a request ID is required but + // there isn't one. + VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID, +}; + +const char* ValidationErrorToString(ValidationError error); + +void ReportValidationError(ValidationError error); + +// Only used by validation tests and when there is only one thread doing message +// validation. +class ValidationErrorObserverForTesting { + public: + ValidationErrorObserverForTesting(); + ~ValidationErrorObserverForTesting(); + + ValidationError last_error() const { return last_error_; } + void set_last_error(ValidationError error) { last_error_ = error; } + + private: + ValidationError last_error_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ValidationErrorObserverForTesting); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_ diff --git a/chromium/mojo/public/cpp/bindings/message.h b/chromium/mojo/public/cpp/bindings/message.h new file mode 100644 index 00000000000..beb1cd9036f --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/message.h @@ -0,0 +1,123 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_H_ + +#include <assert.h> + +#include <vector> + +#include "mojo/public/cpp/bindings/lib/message_internal.h" + +namespace mojo { + +// Message is a holder for the data and handles to be sent over a MessagePipe. +// Message owns its data and handles, but a consumer of Message is free to +// mutate the data and handles. The message's data is comprised of a header +// followed by payload. +class Message { + public: + Message(); + ~Message(); + + // These may only be called on a newly created Message object. + void AllocUninitializedData(uint32_t num_bytes); + void AdoptData(uint32_t num_bytes, internal::MessageData* data); + + // Swaps data and handles between this Message and another. + void Swap(Message* other); + + uint32_t data_num_bytes() const { return data_num_bytes_; } + + // Access the raw bytes of the message. + const uint8_t* data() const { return + reinterpret_cast<const uint8_t*>(data_); + } + uint8_t* mutable_data() { return reinterpret_cast<uint8_t*>(data_); } + + // Access the header. + const internal::MessageHeader* header() const { return &data_->header; } + + uint32_t name() const { return data_->header.name; } + bool has_flag(uint32_t flag) const { return !!(data_->header.flags & flag); } + + // Access the request_id field (if present). + bool has_request_id() const { return data_->header.num_fields >= 3; } + uint64_t request_id() const { + assert(has_request_id()); + return static_cast<const internal::MessageHeaderWithRequestID*>( + &data_->header)->request_id; + } + void set_request_id(uint64_t request_id) { + assert(has_request_id()); + static_cast<internal::MessageHeaderWithRequestID*>(&data_->header)-> + request_id = request_id; + } + + // Access the payload. + const uint8_t* payload() const { + return reinterpret_cast<const uint8_t*>(data_) + data_->header.num_bytes; + } + uint8_t* mutable_payload() { + return reinterpret_cast<uint8_t*>(data_) + data_->header.num_bytes; + } + uint32_t payload_num_bytes() const { + assert(data_num_bytes_ >= data_->header.num_bytes); + return data_num_bytes_ - data_->header.num_bytes; + } + + // Access the handles. + const std::vector<Handle>* handles() const { return &handles_; } + std::vector<Handle>* mutable_handles() { return &handles_; } + + private: + uint32_t data_num_bytes_; + internal::MessageData* data_; // Heap-allocated using malloc. + std::vector<Handle> handles_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Message); +}; + +class MessageReceiver { + public: + virtual ~MessageReceiver() {} + + // The receiver may mutate the given message. Returns true if the message + // was accepted and false otherwise, indicating that the message was invalid + // or malformed. + virtual bool Accept(Message* message) MOJO_WARN_UNUSED_RESULT = 0; +}; + +class MessageReceiverWithResponder : public MessageReceiver { + public: + virtual ~MessageReceiverWithResponder() {} + + // A variant on Accept that registers a MessageReceiver (known as the + // responder) to handle the response message generated from the given + // message. The responder's Accept method may be called during + // AcceptWithResponder or some time after its return. + // + // NOTE: Upon returning true, AcceptWithResponder assumes ownership of + // |responder| and will delete it after calling |responder->Accept| or upon + // its own destruction. + // + virtual bool AcceptWithResponder( + Message* message, MessageReceiver* responder) MOJO_WARN_UNUSED_RESULT = 0; +}; + +// Read a single message from the pipe and dispatch to the given receiver. The +// receiver may be null, in which case the message is simply discarded. +// Returns MOJO_RESULT_SHOULD_WAIT if the caller should wait on the handle to +// become readable. Returns MOJO_RESULT_OK if a message was dispatched and +// otherwise returns an error code if something went wrong. +// +// NOTE: The message hasn't been validated and may be malformed! +MojoResult ReadAndDispatchMessage(MessagePipeHandle handle, + MessageReceiver* receiver, + bool* receiver_result); + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_H_ diff --git a/chromium/mojo/public/cpp/bindings/message_filter.h b/chromium/mojo/public/cpp/bindings/message_filter.h new file mode 100644 index 00000000000..6d716733ecc --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/message_filter.h @@ -0,0 +1,39 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_FILTER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_FILTER_H_ + +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +// This class is the base class for message filters. Subclasses should +// implement the pure virtual method Accept() inherited from MessageReceiver to +// process messages and/or forward them to |sink_|. +class MessageFilter : public MessageReceiver { + public: + // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while + // this object is alive. + explicit MessageFilter(MessageReceiver* sink = NULL); + virtual ~MessageFilter(); + + void set_sink(MessageReceiver* sink) { sink_ = sink; } + + protected: + MessageReceiver* sink_; +}; + +// A trivial filter that simply forwards every message it receives to |sink_|. +class PassThroughFilter : public MessageFilter { + public: + explicit PassThroughFilter(MessageReceiver* sink = NULL); + + virtual bool Accept(Message* message) MOJO_OVERRIDE; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_FILTER_H_ diff --git a/chromium/mojo/public/cpp/bindings/no_interface.h b/chromium/mojo/public/cpp/bindings/no_interface.h new file mode 100644 index 00000000000..83b0eff5000 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/no_interface.h @@ -0,0 +1,56 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_ + +#include <assert.h> + +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/bindings/message_filter.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { + +// NoInterface is for use in cases when a non-existent or empty interface is +// needed (e.g., when the Mojom "Peer" attribute is not present). + +class NoInterfaceProxy; +class NoInterfaceStub; + +class NoInterface { + public: + static const char* Name_; + typedef NoInterfaceProxy Proxy_; + typedef NoInterfaceStub Stub_; + typedef PassThroughFilter RequestValidator_; + typedef PassThroughFilter ResponseValidator_; + typedef NoInterface Client; + virtual ~NoInterface() {} +}; + +class NoInterfaceProxy : public NoInterface { + public: + explicit NoInterfaceProxy(MessageReceiver* receiver) {} +}; + +class NoInterfaceStub : public MessageReceiverWithResponder { + public: + NoInterfaceStub() {} + void set_sink(NoInterface* sink) {} + NoInterface* sink() { return NULL; } + virtual bool Accept(Message* message) MOJO_OVERRIDE; + virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) + MOJO_OVERRIDE; +}; + + +// AnyInterface is for use in cases where any interface would do (e.g., see the +// Shell::Connect method). + +typedef NoInterface AnyInterface; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_ diff --git a/chromium/mojo/public/cpp/bindings/string.h b/chromium/mojo/public/cpp/bindings/string.h new file mode 100644 index 00000000000..a2427844975 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/string.h @@ -0,0 +1,154 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRING_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_STRING_H_ + +#include <assert.h> + +#include <string> + +#include "mojo/public/cpp/bindings/lib/array_internal.h" +#include "mojo/public/cpp/bindings/type_converter.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +class String { + public: + typedef internal::String_Data Data_; + + String() : is_null_(true) {} + String(const std::string& str) : value_(str), is_null_(false) {} + String(const char* chars) : is_null_(!chars) { + if (chars) + value_ = chars; + } + String(const char* chars, size_t num_chars) + : value_(chars, num_chars), + is_null_(false) { + } + template <size_t N> + String(const char chars[N]) : value_(chars, N-1), is_null_(false) {} + + template <typename U> + static String From(const U& other) { + return TypeConverter<String, U>::ConvertFrom(other); + } + + template <typename U> + U To() const { + return TypeConverter<String, U>::ConvertTo(*this); + } + + String& operator=(const std::string& str) { + value_ = str; + is_null_ = false; + return *this; + } + String& operator=(const char* chars) { + is_null_ = !chars; + if (chars) { + value_ = chars; + } else { + value_.clear(); + } + return *this; + } + + void reset() { + value_.clear(); + is_null_ = true; + } + + bool is_null() const { return is_null_; } + + size_t size() const { return value_.size(); } + + const char* data() const { return value_.data(); } + + const char& at(size_t offset) const { return value_.at(offset); } + const char& operator[](size_t offset) const { return value_[offset]; } + + const std::string& get() const { return value_; } + operator const std::string&() const { return value_; } + + void Swap(String* other) { + std::swap(is_null_, other->is_null_); + value_.swap(other->value_); + } + + void Swap(std::string* other) { + is_null_ = false; + value_.swap(*other); + } + + private: + typedef std::string String::*Testable; + + public: + operator Testable() const { return is_null_ ? 0 : &String::value_; } + + private: + std::string value_; + bool is_null_; +}; + +inline bool operator==(const String& a, const String& b) { + return a.is_null() == b.is_null() && a.get() == b.get(); +} +inline bool operator==(const char* a, const String& b) { + return !b.is_null() && a == b.get(); +} +inline bool operator==(const String& a, const char* b) { + return !a.is_null() && a.get() == b; +} +inline bool operator!=(const String& a, const String& b) { return !(a == b); } +inline bool operator!=(const char* a, const String& b) { return !(a == b); } +inline bool operator!=(const String& a, const char* b) { return !(a == b); } + +// TODO(darin): Add similar variants of operator<,<=,>,>= + +template <> +class TypeConverter<String, std::string> { + public: + static String ConvertFrom(const std::string& input) { + return String(input); + } + static std::string ConvertTo(const String& input) { + return input; + } +}; + +template <size_t N> +class TypeConverter<String, char[N]> { + public: + static String ConvertFrom(const char input[N]) { + assert(input); + return String(input, N-1); + } +}; + +// Appease MSVC. +template <size_t N> +class TypeConverter<String, const char[N]> { + public: + static String ConvertFrom(const char input[N]) { + assert(input); + return String(input, N-1); + } +}; + +template <> +class TypeConverter<String, const char*> { + public: + // |input| may be null, in which case a null String will be returned. + static String ConvertFrom(const char* input) { + return String(input); + } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_STRING_H_ diff --git a/chromium/mojo/public/cpp/bindings/struct_ptr.h b/chromium/mojo/public/cpp/bindings/struct_ptr.h new file mode 100644 index 00000000000..a4e55e758f4 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/struct_ptr.h @@ -0,0 +1,154 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_ + +#include <assert.h> + +#include <new> + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +template <typename Struct> +class StructHelper { + public: + template <typename Ptr> + static void Initialize(Ptr* ptr) { ptr->Initialize(); } +}; + +} // namespace internal + +template <typename Struct> +class StructPtr { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(StructPtr, RValue); + public: + typedef typename Struct::Data_ Data_; + + StructPtr() : ptr_(NULL) {} + ~StructPtr() { + delete ptr_; + } + + StructPtr(RValue other) : ptr_(NULL) { Take(other.object); } + StructPtr& operator=(RValue other) { + Take(other.object); + return *this; + } + + template <typename U> + U To() const { + return TypeConverter<StructPtr, U>::ConvertTo(*this); + } + + void reset() { + if (ptr_) { + delete ptr_; + ptr_ = NULL; + } + } + + bool is_null() const { return ptr_ == NULL; } + + Struct& operator*() const { + assert(ptr_); + return *ptr_; + } + Struct* operator->() const { + assert(ptr_); + return ptr_; + } + Struct* get() const { return ptr_; } + + void Swap(StructPtr* other) { + std::swap(ptr_, other->ptr_); + } + + private: + typedef Struct* StructPtr::*Testable; + + public: + operator Testable() const { return ptr_ ? &StructPtr::ptr_ : 0; } + + private: + friend class internal::StructHelper<Struct>; + void Initialize() { assert(!ptr_); ptr_ = new Struct(); } + + void Take(StructPtr* other) { + reset(); + Swap(other); + } + + Struct* ptr_; +}; + +// Designed to be used when Struct is small and copyable. +template <typename Struct> +class InlinedStructPtr { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InlinedStructPtr, RValue); + public: + typedef typename Struct::Data_ Data_; + + InlinedStructPtr() : is_null_(true) {} + ~InlinedStructPtr() {} + + InlinedStructPtr(RValue other) : is_null_(true) { Take(other.object); } + InlinedStructPtr& operator=(RValue other) { + Take(other.object); + return *this; + } + + template <typename U> + U To() const { + return TypeConverter<InlinedStructPtr, U>::ConvertTo(*this); + } + + void reset() { + is_null_ = true; + value_.~Struct(); + new (&value_) Struct(); + } + + bool is_null() const { return is_null_; } + + Struct& operator*() const { + assert(!is_null_); + return value_; + } + Struct* operator->() const { + assert(!is_null_); + return &value_; + } + Struct* get() const { return &value_; } + + void Swap(InlinedStructPtr* other) { + std::swap(value_, other->value_); + std::swap(is_null_, other->is_null_); + } + + private: + typedef Struct InlinedStructPtr::*Testable; + + public: + operator Testable() const { return is_null_ ? 0 : &InlinedStructPtr::value_; } + + private: + friend class internal::StructHelper<Struct>; + void Initialize() { is_null_ = false; } + + void Take(InlinedStructPtr* other) { + reset(); + Swap(other); + } + + mutable Struct value_; + bool is_null_; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_ diff --git a/chromium/mojo/public/cpp/bindings/sync_dispatcher.h b/chromium/mojo/public/cpp/bindings/sync_dispatcher.h new file mode 100644 index 00000000000..9f825bf8a6a --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/sync_dispatcher.h @@ -0,0 +1,47 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_SYNC_DISPATCHER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_SYNC_DISPATCHER_H_ + +#include "mojo/public/cpp/bindings/lib/filter_chain.h" +#include "mojo/public/cpp/bindings/lib/message_header_validator.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { + +class MessageReceiver; + +// Waits for one message to arrive on the message pipe, and dispatch it to the +// receiver. Returns true on success, false on failure. +// +// NOTE: The message hasn't been validated and may be malformed! +bool WaitForMessageAndDispatch(MessagePipeHandle handle, + mojo::MessageReceiver* receiver); + +template<typename Interface> class SyncDispatcher { + public: + SyncDispatcher(ScopedMessagePipeHandle message_pipe, Interface* sink) + : message_pipe_(message_pipe.Pass()) { + stub_.set_sink(sink); + + filters_.Append<internal::MessageHeaderValidator>(); + filters_.Append<typename Interface::RequestValidator_>(); + filters_.SetSink(&stub_); + } + + bool WaitAndDispatchOneMessage() { + return WaitForMessageAndDispatch(message_pipe_.get(), + filters_.GetHead()); + } + + private: + ScopedMessagePipeHandle message_pipe_; + typename Interface::Stub_ stub_; + internal::FilterChain filters_; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_SYNC_DISPATCHER_H_ diff --git a/chromium/mojo/public/cpp/bindings/type_converter.h b/chromium/mojo/public/cpp/bindings/type_converter.h new file mode 100644 index 00000000000..0ac5f6d4760 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/type_converter.h @@ -0,0 +1,82 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_TYPE_CONVERTER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_TYPE_CONVERTER_H_ + +namespace mojo { + +// Specialize the following class: +// template <typename T, typename U> class TypeConverter; +// to perform type conversion for Mojom-defined structs and arrays. Here, T is +// the Mojom-defined struct or array, and U is some other non-Mojom +// struct or array type. +// +// Specializations should implement the following interface: +// namespace mojo { +// template <> +// class TypeConverter<T, U> { +// public: +// static T ConvertFrom(const U& input); +// static U ConvertTo(const T& input); +// }; +// } +// +// EXAMPLE: +// +// Suppose you have the following Mojom-defined struct: +// +// module geometry { +// struct Point { +// int32 x; +// int32 y; +// }; +// } +// +// Now, imagine you wanted to write a TypeConverter specialization for +// gfx::Point. It might look like this: +// +// namespace mojo { +// template <> +// class TypeConverter<geometry::PointPtr, gfx::Point> { +// public: +// static geometry::PointPtr ConvertFrom(const gfx::Point& input) { +// geometry::PointPtr result; +// result->x = input.x(); +// result->y = input.y(); +// return result.Pass(); +// } +// static gfx::Point ConvertTo(const geometry::PointPtr& input) { +// return input ? gfx::Point(input->x, input->y) : gfx::Point(); +// } +// }; +// } +// +// With the above TypeConverter defined, it is possible to write code like this: +// +// void AcceptPoint(const geometry::PointPtr& input) { +// // With an explicit cast using the .To<> method. +// gfx::Point pt = input.To<gfx::Point>(); +// +// // With an explicit cast using the static From() method. +// geometry::PointPtr output = geometry::Point::From(pt); +// } +// +template <typename T, typename U> class TypeConverter; + +// The following specialization is useful when you are converting between +// Array<POD> and std::vector<POD>. +template <typename T> class TypeConverter<T, T> { + public: + static T ConvertFrom(const T& obj) { + return obj; + } + static T ConvertTo(const T& obj) { + return obj; + } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_TYPE_CONVERTER_H_ diff --git a/chromium/mojo/public/cpp/environment/environment.h b/chromium/mojo/public/cpp/environment/environment.h new file mode 100644 index 00000000000..48f4c26eb72 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/environment.h @@ -0,0 +1,41 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_ENVIRONMENT_ENVIRONMENT_H_ +#define MOJO_PUBLIC_CPP_ENVIRONMENT_ENVIRONMENT_H_ + +#include "mojo/public/cpp/system/macros.h" + +struct MojoAsyncWaiter; +struct MojoLogger; + +namespace mojo { + +// Other parts of the Mojo C++ APIs use the *static* methods of this class. +// +// The "standalone" implementation of this class requires that this class (in +// the lib/ subdirectory) be instantiated (and remain so) while using the Mojo +// C++ APIs. I.e., the static methods depend on things set up by the constructor +// and torn down by the destructor. +// +// Other implementations may not have this requirement. +class Environment { + public: + Environment(); + // This constructor allows the standard implementations to be overridden (set + // a parameter to null to get the standard implementation). + Environment(const MojoAsyncWaiter* default_async_waiter, + const MojoLogger* default_logger); + ~Environment(); + + static const MojoAsyncWaiter* GetDefaultAsyncWaiter(); + static const MojoLogger* GetDefaultLogger(); + + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(Environment); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_ENVIRONMENT_ENVIRONMENT_H_ diff --git a/chromium/mojo/public/cpp/environment/lib/DEPS b/chromium/mojo/public/cpp/environment/lib/DEPS new file mode 100644 index 00000000000..1889e1fb75f --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+mojo/public/cpp/environment", + "+mojo/public/cpp/utility", +] diff --git a/chromium/mojo/public/cpp/environment/lib/default_async_waiter.cc b/chromium/mojo/public/cpp/environment/lib/default_async_waiter.cc new file mode 100644 index 00000000000..257f1c8d797 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/default_async_waiter.cc @@ -0,0 +1,94 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/environment/lib/default_async_waiter.h" + +#include <assert.h> + +#include "mojo/public/c/environment/async_waiter.h" +#include "mojo/public/cpp/utility/run_loop.h" +#include "mojo/public/cpp/utility/run_loop_handler.h" + +namespace mojo { + +namespace { + +// RunLoopHandler implementation used for a request to AsyncWait(). There are +// two ways RunLoopHandlerImpl is deleted: +// . when the handle is ready (or errored). +// . when CancelWait() is invoked. +class RunLoopHandlerImpl : public RunLoopHandler { + public: + RunLoopHandlerImpl(const Handle& handle, + MojoAsyncWaitCallback callback, + void* closure) + : handle_(handle), + callback_(callback), + closure_(closure) { + } + + virtual ~RunLoopHandlerImpl() { + RunLoop::current()->RemoveHandler(handle_); + } + + // RunLoopHandler: + virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE { + NotifyCallback(MOJO_RESULT_OK); + } + + virtual void OnHandleError(const Handle& handle, + MojoResult result) MOJO_OVERRIDE { + NotifyCallback(result); + } + + private: + void NotifyCallback(MojoResult result) { + // Delete this to unregister the handle. That way if the callback + // reregisters everything is ok. + MojoAsyncWaitCallback callback = callback_; + void* closure = closure_; + delete this; + + callback(closure, result); + } + + const Handle handle_; + MojoAsyncWaitCallback callback_; + void* closure_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoopHandlerImpl); +}; + +MojoAsyncWaitID AsyncWait(MojoHandle handle, + MojoHandleSignals signals, + MojoDeadline deadline, + MojoAsyncWaitCallback callback, + void* closure) { + RunLoop* run_loop = RunLoop::current(); + assert(run_loop); + + // |run_loop_handler| is destroyed either when the handle is ready or if + // CancelWait is invoked. + RunLoopHandlerImpl* run_loop_handler = + new RunLoopHandlerImpl(Handle(handle), callback, closure); + run_loop->AddHandler(run_loop_handler, Handle(handle), signals, deadline); + return reinterpret_cast<MojoAsyncWaitID>(run_loop_handler); +} + +void CancelWait(MojoAsyncWaitID wait_id) { + delete reinterpret_cast<RunLoopHandlerImpl*>(wait_id); +} + +} // namespace + +namespace internal { + +const MojoAsyncWaiter kDefaultAsyncWaiter = { + AsyncWait, + CancelWait +}; + +} // namespace internal + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/environment/lib/default_async_waiter.h b/chromium/mojo/public/cpp/environment/lib/default_async_waiter.h new file mode 100644 index 00000000000..49ce233490c --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/default_async_waiter.h @@ -0,0 +1,18 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_ASYNC_WAITER_H_ +#define MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_ASYNC_WAITER_H_ + +struct MojoAsyncWaiter; + +namespace mojo { +namespace internal { + +extern const MojoAsyncWaiter kDefaultAsyncWaiter; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_ASYNC_WAITER_H_ diff --git a/chromium/mojo/public/cpp/environment/lib/default_logger.cc b/chromium/mojo/public/cpp/environment/lib/default_logger.cc new file mode 100644 index 00000000000..af4a62866b0 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/default_logger.cc @@ -0,0 +1,71 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/environment/lib/default_logger.h" + +#include <stdio.h> +#include <stdlib.h> // For |abort()|. + +#include <algorithm> + +#include "mojo/public/c/environment/logger.h" + +namespace mojo { + +namespace { + +MojoLogLevel g_minimum_log_level = MOJO_LOG_LEVEL_INFO; + +const char* GetLogLevelString(MojoLogLevel log_level) { + if (log_level <= MOJO_LOG_LEVEL_VERBOSE-3) + return "VERBOSE4+"; + switch (log_level) { + case MOJO_LOG_LEVEL_VERBOSE-2: + return "VERBOSE3"; + case MOJO_LOG_LEVEL_VERBOSE-1: + return "VERBOSE2"; + case MOJO_LOG_LEVEL_VERBOSE: + return "VERBOSE1"; + case MOJO_LOG_LEVEL_INFO: + return "INFO"; + case MOJO_LOG_LEVEL_WARNING: + return "WARNING"; + case MOJO_LOG_LEVEL_ERROR: + return "ERROR"; + } + // Consider everything higher to be fatal. + return "FATAL"; +} + +void LogMessage(MojoLogLevel log_level, const char* message) { + if (log_level < g_minimum_log_level) + return; + + // TODO(vtl): Add timestamp also? + fprintf(stderr, "%s: %s\n", GetLogLevelString(log_level), message); + if (log_level >= MOJO_LOG_LEVEL_FATAL) + abort(); +} + +MojoLogLevel GetMinimumLogLevel() { + return g_minimum_log_level; +} + +void SetMinimumLogLevel(MojoLogLevel minimum_log_level) { + g_minimum_log_level = std::min(minimum_log_level, MOJO_LOG_LEVEL_FATAL); +} + +} // namespace + +namespace internal { + +const MojoLogger kDefaultLogger = { + LogMessage, + GetMinimumLogLevel, + SetMinimumLogLevel +}; + +} // namespace internal + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/environment/lib/default_logger.h b/chromium/mojo/public/cpp/environment/lib/default_logger.h new file mode 100644 index 00000000000..4db32336811 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/default_logger.h @@ -0,0 +1,18 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_LOGGER_H_ +#define MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_LOGGER_H_ + +struct MojoLogger; + +namespace mojo { +namespace internal { + +extern const MojoLogger kDefaultLogger; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_LOGGER_H_ diff --git a/chromium/mojo/public/cpp/environment/lib/environment.cc b/chromium/mojo/public/cpp/environment/lib/environment.cc new file mode 100644 index 00000000000..58e270e9ae4 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/environment.cc @@ -0,0 +1,60 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/environment/environment.h" + +#include <stddef.h> + +#include "mojo/public/c/environment/logger.h" +#include "mojo/public/cpp/environment/lib/default_async_waiter.h" +#include "mojo/public/cpp/environment/lib/default_logger.h" +#include "mojo/public/cpp/utility/run_loop.h" + +namespace mojo { + +namespace { + +const MojoAsyncWaiter* g_default_async_waiter = NULL; +const MojoLogger* g_default_logger = NULL; + +void Init(const MojoAsyncWaiter* default_async_waiter, + const MojoLogger* default_logger) { + g_default_async_waiter = + default_async_waiter ? default_async_waiter : + &internal::kDefaultAsyncWaiter; + g_default_logger = default_logger ? default_logger : + &internal::kDefaultLogger; + + RunLoop::SetUp(); +} + +} // namespace + +Environment::Environment() { + Init(NULL, NULL); +} + +Environment::Environment(const MojoAsyncWaiter* default_async_waiter, + const MojoLogger* default_logger) { + Init(default_async_waiter, default_logger); +} + +Environment::~Environment() { + RunLoop::TearDown(); + + // TODO(vtl): Maybe we should allow nesting, and restore previous default + // async waiters and loggers? +} + +// static +const MojoAsyncWaiter* Environment::GetDefaultAsyncWaiter() { + return g_default_async_waiter; +} + +// static +const MojoLogger* Environment::GetDefaultLogger() { + return g_default_logger; +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/environment/lib/logging.cc b/chromium/mojo/public/cpp/environment/lib/logging.cc new file mode 100644 index 00000000000..990626df736 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/logging.cc @@ -0,0 +1,45 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/environment/logging.h" + +#include "mojo/public/cpp/environment/environment.h" + +namespace mojo { +namespace internal { + +namespace { + +// Gets a pointer to the filename portion of |s|. Assumes that the filename +// follows the last slash or backslash in |s|, or is |s| if no slash or +// backslash is present. +// +// E.g., a pointer to "foo.cc" is returned for the following inputs: "foo.cc", +// "./foo.cc", ".\foo.cc", "/absolute/path/to/foo.cc", +// "relative/path/to/foo.cc", "C:\absolute\path\to\foo.cc", etc. +const char* GetFilename(const char* s) { + const char* rv = s; + while (*s) { + if (*s == '/' || *s == '\\') + rv = s + 1; + s++; + } + return rv; +} + +} // namespace + +LogMessage::LogMessage(const char* file, int line, MojoLogLevel log_level) + : log_level_(log_level) { + // Note: Don't include the log level in the message, since that's passed on. + stream_ << GetFilename(file) << '(' << line << "): "; +} + +LogMessage::~LogMessage() { + Environment::GetDefaultLogger()->LogMessage(log_level_, + stream_.str().c_str()); +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/environment/logging.h b/chromium/mojo/public/cpp/environment/logging.h new file mode 100644 index 00000000000..a3e2cef4293 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/logging.h @@ -0,0 +1,87 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Logging macros, similar to Chromium's base/logging.h, except with |MOJO_| +// prefixes and missing some features (notably |CHECK_EQ()|, etc.). + +// TODO(vtl): It's weird that this is in the environment directory, since its +// implementation (in environment/lib) is meant to be used by any implementation +// of the environment. + +#ifndef MOJO_PUBLIC_CPP_ENVIRONMENT_LOGGING_H_ +#define MOJO_PUBLIC_CPP_ENVIRONMENT_LOGGING_H_ + +#include <sstream> + +#include "mojo/public/c/environment/logger.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/macros.h" + +#define MOJO_LOG_STREAM(level) \ + ::mojo::internal::LogMessage(__FILE__, __LINE__, \ + MOJO_LOG_LEVEL_ ## level).stream() + +#define MOJO_LAZY_LOG_STREAM(level, condition) \ + !(condition) ? \ + (void) 0 : \ + ::mojo::internal::VoidifyOstream() & MOJO_LOG_STREAM(level) + +#define MOJO_SHOULD_LOG(level) \ + (MOJO_LOG_LEVEL_ ## level >= \ + ::mojo::Environment::GetDefaultLogger()->GetMinimumLogLevel()) + +#define MOJO_LOG(level) \ + MOJO_LAZY_LOG_STREAM(level, MOJO_SHOULD_LOG(level)) + +#define MOJO_LOG_IF(level, condition) \ + MOJO_LAZY_LOG_STREAM(level, MOJO_SHOULD_LOG(level) && (condition)) + +#define MOJO_CHECK(condition) \ + MOJO_LAZY_LOG_STREAM(FATAL, !(condition)) \ + << "Check failed: " #condition ". " + +// Note: For non-debug builds, |MOJO_DLOG_IF()| *eliminates* (i.e., doesn't +// compile) the condition, whereas |MOJO_DCHECK()| "neuters" the condition +// (i.e., compiles, but doesn't evaluate). +#ifdef NDEBUG + +#define MOJO_DLOG(level) MOJO_LAZY_LOG_STREAM(level, false) +#define MOJO_DLOG_IF(level, condition) MOJO_LAZY_LOG_STREAM(level, false) +#define MOJO_DCHECK(condition) MOJO_LAZY_LOG_STREAM(FATAL, false && (condition)) + +#else + +#define MOJO_DLOG(level) MOJO_LOG(level) +#define MOJO_DLOG_IF(level, condition) MOJO_LOG_IF(level, condition) +#define MOJO_DCHECK(condition) MOJO_CHECK(condition) + +#endif // NDEBUG + +namespace mojo { +namespace internal { + +class LogMessage { + public: + LogMessage(const char* file, int line, MojoLogLevel log_level); + ~LogMessage(); + + std::ostream& stream() { return stream_; } + + private: + const MojoLogLevel log_level_; + std::ostringstream stream_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(LogMessage); +}; + +// Used to ignore a stream. +struct VoidifyOstream { + // Use & since it has precedence lower than << but higher than ?:. + void operator&(std::ostream&) {} +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_ENVIRONMENT_LOGGING_H_ diff --git a/chromium/mojo/public/cpp/gles2/DEPS b/chromium/mojo/public/cpp/gles2/DEPS new file mode 100644 index 00000000000..3c48be99eb8 --- /dev/null +++ b/chromium/mojo/public/cpp/gles2/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+mojo/public/c/gles2", + "+mojo/public/cpp/environment", +] diff --git a/chromium/mojo/public/cpp/gles2/gles2.h b/chromium/mojo/public/cpp/gles2/gles2.h new file mode 100644 index 00000000000..a408fc701eb --- /dev/null +++ b/chromium/mojo/public/cpp/gles2/gles2.h @@ -0,0 +1,24 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_GLES2_GLES2_H_ +#define MOJO_PUBLIC_CPP_GLES2_GLES2_H_ + +#include "mojo/public/c/gles2/gles2.h" +#include "mojo/public/cpp/environment/environment.h" + +namespace mojo { + +class GLES2Initializer { + public: + explicit GLES2Initializer(const MojoAsyncWaiter* async_waiter = + Environment::GetDefaultAsyncWaiter()) { + MojoGLES2Initialize(async_waiter); + } + ~GLES2Initializer() { MojoGLES2Terminate(); } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_GLES2_GLES2_H_ diff --git a/chromium/mojo/public/cpp/system/core.h b/chromium/mojo/public/cpp/system/core.h new file mode 100644 index 00000000000..d73bb296514 --- /dev/null +++ b/chromium/mojo/public/cpp/system/core.h @@ -0,0 +1,555 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_SYSTEM_CORE_H_ +#define MOJO_PUBLIC_CPP_SYSTEM_CORE_H_ + +#include <assert.h> +#include <stddef.h> + +#include <limits> + +#include "mojo/public/c/system/core.h" +#include "mojo/public/c/system/system_export.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +// OVERVIEW +// +// |Handle| and |...Handle|: +// +// |Handle| is a simple, copyable wrapper for the C type |MojoHandle| (which is +// just an integer). Its purpose is to increase type-safety, not provide +// lifetime management. For the same purpose, we have trivial *subclasses* of +// |Handle|, e.g., |MessagePipeHandle| and |DataPipeProducerHandle|. |Handle| +// and its subclasses impose *no* extra overhead over using |MojoHandle|s +// directly. +// +// Note that though we provide constructors for |Handle|/|...Handle| from a +// |MojoHandle|, we do not provide, e.g., a constructor for |MessagePipeHandle| +// from a |Handle|. This is for type safety: If we did, you'd then be able to +// construct a |MessagePipeHandle| from, e.g., a |DataPipeProducerHandle| (since +// it's a |Handle|). +// +// |ScopedHandleBase| and |Scoped...Handle|: +// +// |ScopedHandleBase<HandleType>| is a templated scoped wrapper, for the handle +// types above (in the same sense that a C++11 |unique_ptr<T>| is a scoped +// wrapper for a |T*|). It provides lifetime management, closing its owned +// handle on destruction. It also provides (emulated) move semantics, again +// along the lines of C++11's |unique_ptr| (and exactly like Chromium's +// |scoped_ptr|). +// +// |ScopedHandle| is just (a typedef of) a |ScopedHandleBase<Handle>|. +// Similarly, |ScopedMessagePipeHandle| is just a +// |ScopedHandleBase<MessagePipeHandle>|. Etc. Note that a +// |ScopedMessagePipeHandle| is *not* a (subclass of) |ScopedHandle|. +// +// Wrapper functions: +// +// We provide simple wrappers for the |Mojo...()| functions (in +// mojo/public/c/system/core.h -- see that file for details on individual +// functions). +// +// The general guideline is functions that imply ownership transfer of a handle +// should take (or produce) an appropriate |Scoped...Handle|, while those that +// don't take a |...Handle|. For example, |CreateMessagePipe()| has two +// |ScopedMessagePipe| "out" parameters, whereas |Wait()| and |WaitMany()| take +// |Handle| parameters. Some, have both: e.g., |DuplicatedBuffer()| takes a +// suitable (unscoped) handle (e.g., |SharedBufferHandle|) "in" parameter and +// produces a suitable scoped handle (e.g., |ScopedSharedBufferHandle| a.k.a. +// |ScopedHandleBase<SharedBufferHandle>|) as an "out" parameter. +// +// An exception are some of the |...Raw()| functions. E.g., |CloseRaw()| takes a +// |Handle|, leaving the user to discard the handle. +// +// More significantly, |WriteMessageRaw()| exposes the full API complexity of +// |MojoWriteMessage()| (but doesn't require any extra overhead). It takes a raw +// array of |Handle|s as input, and takes ownership of them (i.e., invalidates +// them) on *success* (but not on failure). There are a number of reasons for +// this. First, C++03 |std::vector|s cannot contain the move-only +// |Scoped...Handle|s. Second, |std::vector|s impose extra overhead +// (necessitating heap-allocation of the buffer). Third, |std::vector|s wouldn't +// provide the desired level of flexibility/safety: a vector of handles would +// have to be all of the same type (probably |Handle|/|ScopedHandle|). Fourth, +// it's expected to not be used directly, but instead be used by generated +// bindings. +// +// Other |...Raw()| functions expose similar rough edges, e.g., dealing with raw +// pointers (and lengths) instead of taking |std::vector|s or similar. + +// Standalone functions -------------------------------------------------------- + +inline MojoTimeTicks GetTimeTicksNow() { + return MojoGetTimeTicksNow(); +} + +// ScopedHandleBase ------------------------------------------------------------ + +// Scoper for the actual handle types defined further below. It's move-only, +// like the C++11 |unique_ptr|. +template <class HandleType> +class ScopedHandleBase { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(ScopedHandleBase, RValue) + + public: + ScopedHandleBase() {} + explicit ScopedHandleBase(HandleType handle) : handle_(handle) {} + ~ScopedHandleBase() { CloseIfNecessary(); } + + template <class CompatibleHandleType> + explicit ScopedHandleBase(ScopedHandleBase<CompatibleHandleType> other) + : handle_(other.release()) { + } + + // Move-only constructor and operator=. + ScopedHandleBase(RValue other) : handle_(other.object->release()) {} + ScopedHandleBase& operator=(RValue other) { + if (other.object != this) { + CloseIfNecessary(); + handle_ = other.object->release(); + } + return *this; + } + + const HandleType& get() const { return handle_; } + + template <typename PassedHandleType> + static ScopedHandleBase<HandleType> From( + ScopedHandleBase<PassedHandleType> other) { + MOJO_COMPILE_ASSERT( + sizeof(static_cast<PassedHandleType*>(static_cast<HandleType*>(0))), + HandleType_is_not_a_subtype_of_PassedHandleType); + return ScopedHandleBase<HandleType>( + static_cast<HandleType>(other.release().value())); + } + + void swap(ScopedHandleBase& other) { + handle_.swap(other.handle_); + } + + HandleType release() MOJO_WARN_UNUSED_RESULT { + HandleType rv; + rv.swap(handle_); + return rv; + } + + void reset(HandleType handle = HandleType()) { + CloseIfNecessary(); + handle_ = handle; + } + + bool is_valid() const { + return handle_.is_valid(); + } + + private: + void CloseIfNecessary() { + if (!handle_.is_valid()) + return; + MojoResult result MOJO_ALLOW_UNUSED = MojoClose(handle_.value()); + assert(result == MOJO_RESULT_OK); + } + + HandleType handle_; +}; + +template <typename HandleType> +inline ScopedHandleBase<HandleType> MakeScopedHandle(HandleType handle) { + return ScopedHandleBase<HandleType>(handle); +} + +// Handle ---------------------------------------------------------------------- + +const MojoHandle kInvalidHandleValue = MOJO_HANDLE_INVALID; + +// Wrapper base class for |MojoHandle|. +class Handle { + public: + Handle() : value_(kInvalidHandleValue) {} + explicit Handle(MojoHandle value) : value_(value) {} + ~Handle() {} + + void swap(Handle& other) { + MojoHandle temp = value_; + value_ = other.value_; + other.value_ = temp; + } + + bool is_valid() const { + return value_ != kInvalidHandleValue; + } + + MojoHandle value() const { return value_; } + MojoHandle* mutable_value() { return &value_; } + void set_value(MojoHandle value) { value_ = value; } + + private: + MojoHandle value_; + + // Copying and assignment allowed. +}; + +// Should have zero overhead. +MOJO_COMPILE_ASSERT(sizeof(Handle) == sizeof(MojoHandle), + bad_size_for_cpp_Handle); + +// The scoper should also impose no more overhead. +typedef ScopedHandleBase<Handle> ScopedHandle; +MOJO_COMPILE_ASSERT(sizeof(ScopedHandle) == sizeof(Handle), + bad_size_for_cpp_ScopedHandle); + +inline MojoResult Wait(const Handle& handle, + MojoHandleSignals signals, + MojoDeadline deadline) { + return MojoWait(handle.value(), signals, deadline); +} + +// |HandleVectorType| and |FlagsVectorType| should be similar enough to +// |std::vector<Handle>| and |std::vector<MojoHandleSignals>|, respectively: +// - They should have a (const) |size()| method that returns an unsigned type. +// - They must provide contiguous storage, with access via (const) reference to +// that storage provided by a (const) |operator[]()| (by reference). +template <class HandleVectorType, class FlagsVectorType> +inline MojoResult WaitMany(const HandleVectorType& handles, + const FlagsVectorType& signals, + MojoDeadline deadline) { + if (signals.size() != handles.size()) + return MOJO_RESULT_INVALID_ARGUMENT; + if (handles.size() > std::numeric_limits<uint32_t>::max()) + return MOJO_RESULT_OUT_OF_RANGE; + + if (handles.size() == 0) + return MojoWaitMany(NULL, NULL, 0, deadline); + + const Handle& first_handle = handles[0]; + const MojoHandleSignals& first_signals = signals[0]; + return MojoWaitMany( + reinterpret_cast<const MojoHandle*>(&first_handle), + reinterpret_cast<const MojoHandleSignals*>(&first_signals), + static_cast<uint32_t>(handles.size()), + deadline); +} + +// |Close()| takes ownership of the handle, since it'll invalidate it. +// Note: There's nothing to do, since the argument will be destroyed when it +// goes out of scope. +template <class HandleType> +inline void Close(ScopedHandleBase<HandleType> /*handle*/) {} + +// Most users should typically use |Close()| (above) instead. +inline MojoResult CloseRaw(Handle handle) { + return MojoClose(handle.value()); +} + +// Strict weak ordering, so that |Handle|s can be used as keys in |std::map|s, +// etc. +inline bool operator<(const Handle& a, const Handle& b) { + return a.value() < b.value(); +} + +// MessagePipeHandle ----------------------------------------------------------- + +class MessagePipeHandle : public Handle { + public: + MessagePipeHandle() {} + explicit MessagePipeHandle(MojoHandle value) : Handle(value) {} + + // Copying and assignment allowed. +}; + +MOJO_COMPILE_ASSERT(sizeof(MessagePipeHandle) == sizeof(Handle), + bad_size_for_cpp_MessagePipeHandle); + +typedef ScopedHandleBase<MessagePipeHandle> ScopedMessagePipeHandle; +MOJO_COMPILE_ASSERT(sizeof(ScopedMessagePipeHandle) == + sizeof(MessagePipeHandle), + bad_size_for_cpp_ScopedMessagePipeHandle); + +inline MojoResult CreateMessagePipe(const MojoCreateMessagePipeOptions* options, + ScopedMessagePipeHandle* message_pipe0, + ScopedMessagePipeHandle* message_pipe1) { + assert(message_pipe0); + assert(message_pipe1); + MessagePipeHandle handle0; + MessagePipeHandle handle1; + MojoResult rv = MojoCreateMessagePipe(options, + handle0.mutable_value(), + handle1.mutable_value()); + // Reset even on failure (reduces the chances that a "stale"/incorrect handle + // will be used). + message_pipe0->reset(handle0); + message_pipe1->reset(handle1); + return rv; +} + +// These "raw" versions fully expose the underlying API, but don't help with +// ownership of handles (especially when writing messages). +// TODO(vtl): Write "baked" versions. +inline MojoResult WriteMessageRaw(MessagePipeHandle message_pipe, + const void* bytes, + uint32_t num_bytes, + const MojoHandle* handles, + uint32_t num_handles, + MojoWriteMessageFlags flags) { + return MojoWriteMessage(message_pipe.value(), bytes, num_bytes, handles, + num_handles, flags); +} + +inline MojoResult ReadMessageRaw(MessagePipeHandle message_pipe, + void* bytes, + uint32_t* num_bytes, + MojoHandle* handles, + uint32_t* num_handles, + MojoReadMessageFlags flags) { + return MojoReadMessage(message_pipe.value(), bytes, num_bytes, handles, + num_handles, flags); +} + +// A wrapper class that automatically creates a message pipe and owns both +// handles. +class MessagePipe { + public: + MessagePipe(); + explicit MessagePipe(const MojoCreateMessagePipeOptions& options); + ~MessagePipe(); + + ScopedMessagePipeHandle handle0; + ScopedMessagePipeHandle handle1; +}; + +inline MessagePipe::MessagePipe() { + MojoResult result MOJO_ALLOW_UNUSED = + CreateMessagePipe(NULL, &handle0, &handle1); + assert(result == MOJO_RESULT_OK); +} + +inline MessagePipe::MessagePipe(const MojoCreateMessagePipeOptions& options) { + MojoResult result MOJO_ALLOW_UNUSED = + CreateMessagePipe(&options, &handle0, &handle1); + assert(result == MOJO_RESULT_OK); +} + +inline MessagePipe::~MessagePipe() { +} + +// DataPipeProducerHandle and DataPipeConsumerHandle --------------------------- + +class DataPipeProducerHandle : public Handle { + public: + DataPipeProducerHandle() {} + explicit DataPipeProducerHandle(MojoHandle value) : Handle(value) {} + + // Copying and assignment allowed. +}; + +MOJO_COMPILE_ASSERT(sizeof(DataPipeProducerHandle) == sizeof(Handle), + bad_size_for_cpp_DataPipeProducerHandle); + +typedef ScopedHandleBase<DataPipeProducerHandle> ScopedDataPipeProducerHandle; +MOJO_COMPILE_ASSERT(sizeof(ScopedDataPipeProducerHandle) == + sizeof(DataPipeProducerHandle), + bad_size_for_cpp_ScopedDataPipeProducerHandle); + +class DataPipeConsumerHandle : public Handle { + public: + DataPipeConsumerHandle() {} + explicit DataPipeConsumerHandle(MojoHandle value) : Handle(value) {} + + // Copying and assignment allowed. +}; + +MOJO_COMPILE_ASSERT(sizeof(DataPipeConsumerHandle) == sizeof(Handle), + bad_size_for_cpp_DataPipeConsumerHandle); + +typedef ScopedHandleBase<DataPipeConsumerHandle> ScopedDataPipeConsumerHandle; +MOJO_COMPILE_ASSERT(sizeof(ScopedDataPipeConsumerHandle) == + sizeof(DataPipeConsumerHandle), + bad_size_for_cpp_ScopedDataPipeConsumerHandle); + +inline MojoResult CreateDataPipe( + const MojoCreateDataPipeOptions* options, + ScopedDataPipeProducerHandle* data_pipe_producer, + ScopedDataPipeConsumerHandle* data_pipe_consumer) { + assert(data_pipe_producer); + assert(data_pipe_consumer); + DataPipeProducerHandle producer_handle; + DataPipeConsumerHandle consumer_handle; + MojoResult rv = MojoCreateDataPipe(options, producer_handle.mutable_value(), + consumer_handle.mutable_value()); + // Reset even on failure (reduces the chances that a "stale"/incorrect handle + // will be used). + data_pipe_producer->reset(producer_handle); + data_pipe_consumer->reset(consumer_handle); + return rv; +} + +inline MojoResult WriteDataRaw(DataPipeProducerHandle data_pipe_producer, + const void* elements, + uint32_t* num_bytes, + MojoWriteDataFlags flags) { + return MojoWriteData(data_pipe_producer.value(), elements, num_bytes, flags); +} + +inline MojoResult BeginWriteDataRaw(DataPipeProducerHandle data_pipe_producer, + void** buffer, + uint32_t* buffer_num_bytes, + MojoWriteDataFlags flags) { + return MojoBeginWriteData(data_pipe_producer.value(), buffer, + buffer_num_bytes, flags); +} + +inline MojoResult EndWriteDataRaw(DataPipeProducerHandle data_pipe_producer, + uint32_t num_bytes_written) { + return MojoEndWriteData(data_pipe_producer.value(), num_bytes_written); +} + +inline MojoResult ReadDataRaw(DataPipeConsumerHandle data_pipe_consumer, + void* elements, + uint32_t* num_bytes, + MojoReadDataFlags flags) { + return MojoReadData(data_pipe_consumer.value(), elements, num_bytes, flags); +} + +inline MojoResult BeginReadDataRaw(DataPipeConsumerHandle data_pipe_consumer, + const void** buffer, + uint32_t* buffer_num_bytes, + MojoReadDataFlags flags) { + return MojoBeginReadData(data_pipe_consumer.value(), buffer, buffer_num_bytes, + flags); +} + +inline MojoResult EndReadDataRaw(DataPipeConsumerHandle data_pipe_consumer, + uint32_t num_bytes_read) { + return MojoEndReadData(data_pipe_consumer.value(), num_bytes_read); +} + +// A wrapper class that automatically creates a data pipe and owns both handles. +// TODO(vtl): Make an even more friendly version? (Maybe templatized for a +// particular type instead of some "element"? Maybe functions that take +// vectors?) +class DataPipe { + public: + DataPipe(); + explicit DataPipe(const MojoCreateDataPipeOptions& options); + ~DataPipe(); + + ScopedDataPipeProducerHandle producer_handle; + ScopedDataPipeConsumerHandle consumer_handle; +}; + +inline DataPipe::DataPipe() { + MojoResult result MOJO_ALLOW_UNUSED = + CreateDataPipe(NULL, &producer_handle, &consumer_handle); + assert(result == MOJO_RESULT_OK); +} + +inline DataPipe::DataPipe(const MojoCreateDataPipeOptions& options) { + MojoResult result MOJO_ALLOW_UNUSED = + CreateDataPipe(&options, &producer_handle, &consumer_handle); + assert(result == MOJO_RESULT_OK); +} + +inline DataPipe::~DataPipe() { +} + +// SharedBufferHandle ---------------------------------------------------------- + +class SharedBufferHandle : public Handle { + public: + SharedBufferHandle() {} + explicit SharedBufferHandle(MojoHandle value) : Handle(value) {} + + // Copying and assignment allowed. +}; + +MOJO_COMPILE_ASSERT(sizeof(SharedBufferHandle) == sizeof(Handle), + bad_size_for_cpp_SharedBufferHandle); + +typedef ScopedHandleBase<SharedBufferHandle> ScopedSharedBufferHandle; +MOJO_COMPILE_ASSERT(sizeof(ScopedSharedBufferHandle) == + sizeof(SharedBufferHandle), + bad_size_for_cpp_ScopedSharedBufferHandle); + +inline MojoResult CreateSharedBuffer( + const MojoCreateSharedBufferOptions* options, + uint64_t num_bytes, + ScopedSharedBufferHandle* shared_buffer) { + assert(shared_buffer); + SharedBufferHandle handle; + MojoResult rv = MojoCreateSharedBuffer(options, num_bytes, + handle.mutable_value()); + // Reset even on failure (reduces the chances that a "stale"/incorrect handle + // will be used). + shared_buffer->reset(handle); + return rv; +} + +// TODO(vtl): This (and also the functions below) are templatized to allow for +// future/other buffer types. A bit "safer" would be to overload this function +// manually. (The template enforces that the in and out handles to be of the +// same type.) +template <class BufferHandleType> +inline MojoResult DuplicateBuffer( + BufferHandleType buffer, + const MojoDuplicateBufferHandleOptions* options, + ScopedHandleBase<BufferHandleType>* new_buffer) { + assert(new_buffer); + BufferHandleType handle; + MojoResult rv = MojoDuplicateBufferHandle( + buffer.value(), options, handle.mutable_value()); + // Reset even on failure (reduces the chances that a "stale"/incorrect handle + // will be used). + new_buffer->reset(handle); + return rv; +} + +template <class BufferHandleType> +inline MojoResult MapBuffer(BufferHandleType buffer, + uint64_t offset, + uint64_t num_bytes, + void** pointer, + MojoMapBufferFlags flags) { + assert(buffer.is_valid()); + return MojoMapBuffer(buffer.value(), offset, num_bytes, pointer, flags); +} + +inline MojoResult UnmapBuffer(void* pointer) { + assert(pointer); + return MojoUnmapBuffer(pointer); +} + +// A wrapper class that automatically creates a shared buffer and owns the +// handle. +class SharedBuffer { + public: + explicit SharedBuffer(uint64_t num_bytes); + SharedBuffer(uint64_t num_bytes, + const MojoCreateSharedBufferOptions& options); + ~SharedBuffer(); + + ScopedSharedBufferHandle handle; +}; + +inline SharedBuffer::SharedBuffer(uint64_t num_bytes) { + MojoResult result MOJO_ALLOW_UNUSED = + CreateSharedBuffer(NULL, num_bytes, &handle); + assert(result == MOJO_RESULT_OK); +} + +inline SharedBuffer::SharedBuffer( + uint64_t num_bytes, + const MojoCreateSharedBufferOptions& options) { + MojoResult result MOJO_ALLOW_UNUSED = + CreateSharedBuffer(&options, num_bytes, &handle); + assert(result == MOJO_RESULT_OK); +} + +inline SharedBuffer::~SharedBuffer() { +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_SYSTEM_CORE_H_ diff --git a/chromium/mojo/public/cpp/system/macros.h b/chromium/mojo/public/cpp/system/macros.h new file mode 100644 index 00000000000..ac4f3dbc84c --- /dev/null +++ b/chromium/mojo/public/cpp/system/macros.h @@ -0,0 +1,53 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_SYSTEM_MACROS_H_ +#define MOJO_PUBLIC_CPP_SYSTEM_MACROS_H_ + +#include "mojo/public/c/system/macros.h" + +// Annotate a virtual method indicating it must be overriding a virtual method +// in the parent class. Use like: +// virtual void foo() OVERRIDE; +#if defined(_MSC_VER) || defined(__clang__) +#define MOJO_OVERRIDE override +#else +#define MOJO_OVERRIDE +#endif + +// A macro to disallow the copy constructor and operator= functions. +// This should be used in the private: declarations for a class. +#define MOJO_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +// Used to calculate the number of elements in an array. +// (See |arraysize()| in Chromium's base/basictypes.h for more details.) +namespace mojo { +template <typename T, size_t N> +char (&ArraySizeHelper(T (&array)[N]))[N]; +#if !defined(_MSC_VER) +template <typename T, size_t N> +char (&ArraySizeHelper(const T (&array)[N]))[N]; +#endif +} // namespace mojo +#define MOJO_ARRAYSIZE(array) (sizeof(::mojo::ArraySizeHelper(array))) + +// Used to make a type move-only in C++03. See Chromium's base/move.h for more +// details. +#define MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \ + private: \ + struct rvalue_type { \ + explicit rvalue_type(type* object) : object(object) {} \ + type* object; \ + }; \ + type(type&); \ + void operator=(type&); \ + public: \ + operator rvalue_type() { return rvalue_type(this); } \ + type Pass() { return type(rvalue_type(this)); } \ + typedef void MoveOnlyTypeForCPP03; \ + private: + +#endif // MOJO_PUBLIC_CPP_SYSTEM_MACROS_H_ diff --git a/chromium/mojo/public/cpp/test_support/DEPS b/chromium/mojo/public/cpp/test_support/DEPS new file mode 100644 index 00000000000..6dc53942e16 --- /dev/null +++ b/chromium/mojo/public/cpp/test_support/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+mojo/public/c/test_support", +] diff --git a/chromium/mojo/public/cpp/test_support/lib/test_support.cc b/chromium/mojo/public/cpp/test_support/lib/test_support.cc new file mode 100644 index 00000000000..55a3dcc7024 --- /dev/null +++ b/chromium/mojo/public/cpp/test_support/lib/test_support.cc @@ -0,0 +1,26 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/test_support/test_support.h" + +#include <stdlib.h> + +namespace mojo { +namespace test { + +std::vector<std::string> EnumerateSourceRootRelativeDirectory( + const std::string& relative_path) { + char** names = MojoTestSupportEnumerateSourceRootRelativeDirectory( + relative_path.c_str()); + std::vector<std::string> results; + for (char** ptr = names; *ptr != NULL; ++ptr) { + results.push_back(*ptr); + free(*ptr); + } + free(names); + return results; +} + +} // namespace test +} // namespace mojo diff --git a/chromium/mojo/public/cpp/test_support/lib/test_utils.cc b/chromium/mojo/public/cpp/test_support/lib/test_utils.cc new file mode 100644 index 00000000000..b47ea209020 --- /dev/null +++ b/chromium/mojo/public/cpp/test_support/lib/test_utils.cc @@ -0,0 +1,91 @@ +// 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. + +#include "mojo/public/cpp/test_support/test_utils.h" + +#include "mojo/public/cpp/system/core.h" +#include "mojo/public/cpp/test_support/test_support.h" + +namespace mojo { +namespace test { + +bool WriteTextMessage(const MessagePipeHandle& handle, + const std::string& text) { + MojoResult rv = WriteMessageRaw(handle, + text.data(), + static_cast<uint32_t>(text.size()), + NULL, + 0, + MOJO_WRITE_MESSAGE_FLAG_NONE); + return rv == MOJO_RESULT_OK; +} + +bool ReadTextMessage(const MessagePipeHandle& handle, std::string* text) { + MojoResult rv; + bool did_wait = false; + + uint32_t num_bytes = 0, num_handles = 0; + for (;;) { + rv = ReadMessageRaw(handle, + NULL, + &num_bytes, + NULL, + &num_handles, + MOJO_READ_MESSAGE_FLAG_NONE); + if (rv == MOJO_RESULT_SHOULD_WAIT) { + if (did_wait) { + assert(false); // Looping endlessly!? + return false; + } + rv = Wait(handle, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE); + if (rv != MOJO_RESULT_OK) + return false; + did_wait = true; + } else { + assert(!num_handles); + break; + } + } + + text->resize(num_bytes); + rv = ReadMessageRaw(handle, + &text->at(0), + &num_bytes, + NULL, + &num_handles, + MOJO_READ_MESSAGE_FLAG_NONE); + return rv == MOJO_RESULT_OK; +} + +bool DiscardMessage(const MessagePipeHandle& handle) { + MojoResult rv = ReadMessageRaw(handle, NULL, NULL, NULL, NULL, + MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); + return rv == MOJO_RESULT_OK; +} + +void IterateAndReportPerf(const char* test_name, + PerfTestSingleIteration single_iteration, + void* closure) { + // TODO(vtl): These should be specifiable using command-line flags. + static const size_t kGranularity = 100; + static const MojoTimeTicks kPerftestTimeMicroseconds = 3 * 1000000; + + const MojoTimeTicks start_time = GetTimeTicksNow(); + MojoTimeTicks end_time; + size_t iterations = 0; + do { + for (size_t i = 0; i < kGranularity; i++) + (*single_iteration)(closure); + iterations += kGranularity; + + end_time = GetTimeTicksNow(); + } while (end_time - start_time < kPerftestTimeMicroseconds); + + MojoTestSupportLogPerfResult(test_name, + 1000000.0 * iterations / (end_time - start_time), + "iterations/second"); +} + +} // namespace test +} // namespace mojo diff --git a/chromium/mojo/public/cpp/test_support/test_support.h b/chromium/mojo/public/cpp/test_support/test_support.h new file mode 100644 index 00000000000..eb4d4be7116 --- /dev/null +++ b/chromium/mojo/public/cpp/test_support/test_support.h @@ -0,0 +1,34 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_SUPPORT_H_ +#define MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_SUPPORT_H_ + +#include <string> +#include <vector> + +#include "mojo/public/c/test_support/test_support.h" + +namespace mojo { +namespace test { + +inline void LogPerfResult(const char* test_name, + double value, + const char* units) { + MojoTestSupportLogPerfResult(test_name, value, units); +} + +// Opens text file relative to the source root for reading. +inline FILE* OpenSourceRootRelativeFile(const std::string& relative_path) { + return MojoTestSupportOpenSourceRootRelativeFile(relative_path.c_str()); +} + +// Returns the list of regular files in a directory relative to the source root. +std::vector<std::string> EnumerateSourceRootRelativeDirectory( + const std::string& relative_path); + +} // namespace test +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_SUPPORT_H_ diff --git a/chromium/mojo/public/cpp/test_support/test_utils.h b/chromium/mojo/public/cpp/test_support/test_utils.h new file mode 100644 index 00000000000..43a3ea99821 --- /dev/null +++ b/chromium/mojo/public/cpp/test_support/test_utils.h @@ -0,0 +1,39 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_UTILS_H_ +#define MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_UTILS_H_ + +#include <string> + +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +namespace test { + +// Writes a message to |handle| with message data |text|. Returns true on +// success. +bool WriteTextMessage(const MessagePipeHandle& handle, const std::string& text); + +// Reads a message from |handle|, putting its contents into |*text|. Returns +// true on success. (This blocks if necessary and will call |MojoReadMessage()| +// multiple times, e.g., to query the size of the message.) +bool ReadTextMessage(const MessagePipeHandle& handle, std::string* text); + +// Discards a message from |handle|. Returns true on success. (This does not +// block. It will fail if no message is available to discard.) +bool DiscardMessage(const MessagePipeHandle& handle); + +// Run |single_iteration| an appropriate number of times and report its +// performance appropriately. (This actually runs |single_iteration| for a fixed +// amount of time and reports the number of iterations per unit time.) +typedef void (*PerfTestSingleIteration)(void* closure); +void IterateAndReportPerf(const char* test_name, + PerfTestSingleIteration single_iteration, + void* closure); + +} // namespace test +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_UTILS_H_ diff --git a/chromium/mojo/public/cpp/utility/lib/mutex.cc b/chromium/mojo/public/cpp/utility/lib/mutex.cc new file mode 100644 index 00000000000..23370e1c023 --- /dev/null +++ b/chromium/mojo/public/cpp/utility/lib/mutex.cc @@ -0,0 +1,52 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/utility/mutex.h" + +#include <assert.h> +#include <errno.h> + +namespace mojo { + +// Release builds have inlined (non-error-checking) definitions in the header. +#if !defined(NDEBUG) +Mutex::Mutex() { + pthread_mutexattr_t mutexattr; + int rv = pthread_mutexattr_init(&mutexattr); + assert(rv == 0); + rv = pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK); + assert(rv == 0); + rv = pthread_mutex_init(&mutex_, &mutexattr); + assert(rv == 0); + rv = pthread_mutexattr_destroy(&mutexattr); + assert(rv == 0); +} + +Mutex::~Mutex() { + int rv = pthread_mutex_destroy(&mutex_); + assert(rv == 0); +} + +void Mutex::Lock() { + int rv = pthread_mutex_lock(&mutex_); + assert(rv == 0); +} + +void Mutex::Unlock() { + int rv = pthread_mutex_unlock(&mutex_); + assert(rv == 0); +} + +bool Mutex::TryLock() { + int rv = pthread_mutex_trylock(&mutex_); + assert(rv == 0 || rv == EBUSY); + return rv == 0; +} + +void Mutex::AssertHeld() { + assert(pthread_mutex_lock(&mutex_) == EDEADLK); +} +#endif // !defined(NDEBUG) + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/utility/lib/run_loop.cc b/chromium/mojo/public/cpp/utility/lib/run_loop.cc new file mode 100644 index 00000000000..f523eaeaead --- /dev/null +++ b/chromium/mojo/public/cpp/utility/lib/run_loop.cc @@ -0,0 +1,221 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/utility/run_loop.h" + +#include <assert.h> + +#include <algorithm> +#include <vector> + +#include "mojo/public/cpp/utility/lib/thread_local.h" +#include "mojo/public/cpp/utility/run_loop_handler.h" + +namespace mojo { +namespace { + +internal::ThreadLocalPointer<RunLoop> current_run_loop; + +const MojoTimeTicks kInvalidTimeTicks = static_cast<MojoTimeTicks>(0); + +} // namespace + +// State needed for one iteration of WaitMany(). +struct RunLoop::WaitState { + WaitState() : deadline(MOJO_DEADLINE_INDEFINITE) {} + + std::vector<Handle> handles; + std::vector<MojoHandleSignals> handle_signals; + MojoDeadline deadline; +}; + +struct RunLoop::RunState { + RunState() : should_quit(false) {} + + bool should_quit; +}; + +RunLoop::RunLoop() : run_state_(NULL), next_handler_id_(0) { + assert(!current()); + current_run_loop.Set(this); +} + +RunLoop::~RunLoop() { + assert(current() == this); + current_run_loop.Set(NULL); +} + +// static +void RunLoop::SetUp() { + current_run_loop.Allocate(); +} + +// static +void RunLoop::TearDown() { + assert(!current()); + current_run_loop.Free(); +} + +// static +RunLoop* RunLoop::current() { + return current_run_loop.Get(); +} + +void RunLoop::AddHandler(RunLoopHandler* handler, + const Handle& handle, + MojoHandleSignals handle_signals, + MojoDeadline deadline) { + assert(current() == this); + assert(handler); + assert(handle.is_valid()); + // Assume it's an error if someone tries to reregister an existing handle. + assert(0u == handler_data_.count(handle)); + HandlerData handler_data; + handler_data.handler = handler; + handler_data.handle_signals = handle_signals; + handler_data.deadline = (deadline == MOJO_DEADLINE_INDEFINITE) ? + kInvalidTimeTicks : + GetTimeTicksNow() + static_cast<MojoTimeTicks>(deadline); + handler_data.id = next_handler_id_++; + handler_data_[handle] = handler_data; +} + +void RunLoop::RemoveHandler(const Handle& handle) { + assert(current() == this); + handler_data_.erase(handle); +} + +bool RunLoop::HasHandler(const Handle& handle) const { + return handler_data_.find(handle) != handler_data_.end(); +} + +void RunLoop::Run() { + assert(current() == this); + RunState* old_state = run_state_; + RunState run_state; + run_state_ = &run_state; + while (!run_state.should_quit) + Wait(false); + run_state_ = old_state; +} + +void RunLoop::RunUntilIdle() { + assert(current() == this); + RunState* old_state = run_state_; + RunState run_state; + run_state_ = &run_state; + while (!run_state.should_quit) { + if (!Wait(true)) + break; + } + run_state_ = old_state; +} + +void RunLoop::Quit() { + assert(current() == this); + if (run_state_) + run_state_->should_quit = true; +} + +bool RunLoop::Wait(bool non_blocking) { + const WaitState wait_state = GetWaitState(non_blocking); + if (wait_state.handles.empty()) { + Quit(); + return false; + } + + const MojoResult result = WaitMany(wait_state.handles, + wait_state.handle_signals, + wait_state.deadline); + if (result >= 0) { + const size_t index = static_cast<size_t>(result); + assert(handler_data_.find(wait_state.handles[index]) != + handler_data_.end()); + handler_data_[wait_state.handles[index]].handler->OnHandleReady( + wait_state.handles[index]); + return true; + } + + switch (result) { + case MOJO_RESULT_INVALID_ARGUMENT: + case MOJO_RESULT_FAILED_PRECONDITION: + return RemoveFirstInvalidHandle(wait_state); + case MOJO_RESULT_DEADLINE_EXCEEDED: + return NotifyDeadlineExceeded(); + } + + assert(false); + return false; +} + +bool RunLoop::NotifyDeadlineExceeded() { + bool notified = false; + + // Make a copy in case someone tries to add/remove new handlers as part of + // notifying. + const HandleToHandlerData cloned_handlers(handler_data_); + const MojoTimeTicks now(GetTimeTicksNow()); + for (HandleToHandlerData::const_iterator i = cloned_handlers.begin(); + i != cloned_handlers.end(); ++i) { + // Since we're iterating over a clone of the handlers, verify the handler is + // still valid before notifying. + if (i->second.deadline != kInvalidTimeTicks && + i->second.deadline < now && + handler_data_.find(i->first) != handler_data_.end() && + handler_data_[i->first].id == i->second.id) { + handler_data_.erase(i->first); + i->second.handler->OnHandleError(i->first, MOJO_RESULT_DEADLINE_EXCEEDED); + notified = true; + } + } + + return notified; +} + +bool RunLoop::RemoveFirstInvalidHandle(const WaitState& wait_state) { + for (size_t i = 0; i < wait_state.handles.size(); ++i) { + const MojoResult result = + mojo::Wait(wait_state.handles[i], wait_state.handle_signals[i], + static_cast<MojoDeadline>(0)); + if (result == MOJO_RESULT_INVALID_ARGUMENT || + result == MOJO_RESULT_FAILED_PRECONDITION) { + // Remove the handle first, this way if OnHandleError() tries to remove + // the handle our iterator isn't invalidated. + assert(handler_data_.find(wait_state.handles[i]) != handler_data_.end()); + RunLoopHandler* handler = + handler_data_[wait_state.handles[i]].handler; + handler_data_.erase(wait_state.handles[i]); + handler->OnHandleError(wait_state.handles[i], result); + return true; + } + assert(MOJO_RESULT_DEADLINE_EXCEEDED == result); + } + return false; +} + +RunLoop::WaitState RunLoop::GetWaitState(bool non_blocking) const { + WaitState wait_state; + MojoTimeTicks min_time = kInvalidTimeTicks; + for (HandleToHandlerData::const_iterator i = handler_data_.begin(); + i != handler_data_.end(); ++i) { + wait_state.handles.push_back(i->first); + wait_state.handle_signals.push_back(i->second.handle_signals); + if (!non_blocking && i->second.deadline != kInvalidTimeTicks && + (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) { + min_time = i->second.deadline; + } + } + if (non_blocking) { + wait_state.deadline = static_cast<MojoDeadline>(0); + } else if (min_time != kInvalidTimeTicks) { + const MojoTimeTicks now = GetTimeTicksNow(); + if (min_time < now) + wait_state.deadline = static_cast<MojoDeadline>(0); + else + wait_state.deadline = static_cast<MojoDeadline>(min_time - now); + } + return wait_state; +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/utility/lib/thread.cc b/chromium/mojo/public/cpp/utility/lib/thread.cc new file mode 100644 index 00000000000..da33497df42 --- /dev/null +++ b/chromium/mojo/public/cpp/utility/lib/thread.cc @@ -0,0 +1,69 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/utility/thread.h" + +#include <assert.h> + +namespace mojo { + +Thread::Thread() + : options_(), + thread_(), + started_(false), + joined_(false) { +} + +Thread::Thread(const Options& options) + : options_(options), + thread_(), + started_(false), + joined_(false) { +} + +Thread::~Thread() { + // If it was started, it must have been joined. + assert(!started_ || joined_); +} + +void Thread::Start() { + assert(!started_); + assert(!joined_); + + pthread_attr_t attr; + int rv MOJO_ALLOW_UNUSED = pthread_attr_init(&attr); + assert(rv == 0); + + // Non-default stack size? + if (options_.stack_size() != 0) { + rv = pthread_attr_setstacksize(&attr, options_.stack_size()); + assert(rv == 0); + } + + started_ = true; + rv = pthread_create(&thread_, &attr, &ThreadRunTrampoline, this); + assert(rv == 0); + + rv = pthread_attr_destroy(&attr); + assert(rv == 0); +} + +void Thread::Join() { + // Must have been started but not yet joined. + assert(started_); + assert(!joined_); + + joined_ = true; + int rv MOJO_ALLOW_UNUSED = pthread_join(thread_, NULL); + assert(rv == 0); +} + +// static +void* Thread::ThreadRunTrampoline(void* arg) { + Thread* self = static_cast<Thread*>(arg); + self->Run(); + return NULL; +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/utility/lib/thread_local.h b/chromium/mojo/public/cpp/utility/lib/thread_local.h new file mode 100644 index 00000000000..4c3625d00d8 --- /dev/null +++ b/chromium/mojo/public/cpp/utility/lib/thread_local.h @@ -0,0 +1,61 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_UTILITY_LIB_THREAD_LOCAL_H_ +#define MOJO_PUBLIC_CPP_UTILITY_LIB_THREAD_LOCAL_H_ + +#ifndef _WIN32 +#include <pthread.h> +#endif + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +// Helper functions that abstract the cross-platform APIs. +struct ThreadLocalPlatform { +#ifdef _WIN32 + typedef unsigned long SlotType; +#else + typedef pthread_key_t SlotType; +#endif + + static void AllocateSlot(SlotType* slot); + static void FreeSlot(SlotType slot); + static void* GetValueFromSlot(SlotType slot); + static void SetValueInSlot(SlotType slot, void* value); +}; + +// This class is intended to be statically allocated. +template <typename P> +class ThreadLocalPointer { + public: + ThreadLocalPointer() : slot_() { + } + + void Allocate() { + ThreadLocalPlatform::AllocateSlot(&slot_); + } + + void Free() { + ThreadLocalPlatform::FreeSlot(slot_); + } + + P* Get() { + return static_cast<P*>(ThreadLocalPlatform::GetValueFromSlot(slot_)); + } + + void Set(P* value) { + ThreadLocalPlatform::SetValueInSlot(slot_, value); + } + + private: + ThreadLocalPlatform::SlotType slot_; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_UTILITY_LIB_THREAD_LOCAL_H_ diff --git a/chromium/mojo/public/cpp/utility/lib/thread_local_posix.cc b/chromium/mojo/public/cpp/utility/lib/thread_local_posix.cc new file mode 100644 index 00000000000..b33dfc61297 --- /dev/null +++ b/chromium/mojo/public/cpp/utility/lib/thread_local_posix.cc @@ -0,0 +1,39 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/utility/lib/thread_local.h" + +#include <assert.h> + +namespace mojo { +namespace internal { + +// static +void ThreadLocalPlatform::AllocateSlot(SlotType* slot) { + if (pthread_key_create(slot, NULL) != 0) { + assert(false); + } +} + +// static +void ThreadLocalPlatform::FreeSlot(SlotType slot) { + if (pthread_key_delete(slot) != 0) { + assert(false); + } +} + +// static +void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) { + return pthread_getspecific(slot); +} + +// static +void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) { + if (pthread_setspecific(slot, value) != 0) { + assert(false); + } +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/utility/lib/thread_local_win.cc b/chromium/mojo/public/cpp/utility/lib/thread_local_win.cc new file mode 100644 index 00000000000..98841f7273a --- /dev/null +++ b/chromium/mojo/public/cpp/utility/lib/thread_local_win.cc @@ -0,0 +1,39 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/utility/lib/thread_local.h" + +#include <assert.h> +#include <windows.h> + +namespace mojo { +namespace internal { + +// static +void ThreadLocalPlatform::AllocateSlot(SlotType* slot) { + *slot = TlsAlloc(); + assert(*slot != TLS_OUT_OF_INDEXES); +} + +// static +void ThreadLocalPlatform::FreeSlot(SlotType slot) { + if (!TlsFree(slot)) { + assert(false); + } +} + +// static +void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) { + return TlsGetValue(slot); +} + +// static +void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) { + if (!TlsSetValue(slot, value)) { + assert(false); + } +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/utility/mutex.h b/chromium/mojo/public/cpp/utility/mutex.h new file mode 100644 index 00000000000..35611c2ba9a --- /dev/null +++ b/chromium/mojo/public/cpp/utility/mutex.h @@ -0,0 +1,70 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_UTILITY_MUTEX_H_ +#define MOJO_PUBLIC_CPP_UTILITY_MUTEX_H_ + +#ifdef _WIN32 +#error "Not implemented: See crbug.com/342893." +#endif + +#include <pthread.h> + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +#ifdef NDEBUG +// Note: Make a C++ constant for |PTHREAD_MUTEX_INITIALIZER|. (We can't directly +// use the C macro in an initializer list, since it might expand to |{ ... }|.) +namespace internal { +const pthread_mutex_t kPthreadMutexInitializer = PTHREAD_MUTEX_INITIALIZER; +} +#endif + +class Mutex { + public: +#ifdef NDEBUG + Mutex() : mutex_(internal::kPthreadMutexInitializer) {} + ~Mutex() { pthread_mutex_destroy(&mutex_); } + + void Lock() { pthread_mutex_lock(&mutex_); } + void Unlock() { pthread_mutex_unlock(&mutex_); } + bool TryLock() { return pthread_mutex_trylock(&mutex_) == 0; } + + void AssertHeld() {} +#else + Mutex(); + ~Mutex(); + + void Lock(); + void Unlock(); + bool TryLock(); + + void AssertHeld(); +#endif + + private: + pthread_mutex_t mutex_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Mutex); +}; + +class MutexLock { + public: + explicit MutexLock(Mutex* mutex) : mutex_(mutex) { mutex_->Lock(); } + ~MutexLock() { mutex_->Unlock(); } + + private: + Mutex* const mutex_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(MutexLock); +}; + +// Catch bug where variable name is omitted (e.g., |MutexLock (&mu)|). +#define MutexLock(x) MOJO_COMPILE_ASSERT(0, mutex_lock_missing_variable_name); + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_UTILITY_MUTEX_H_ diff --git a/chromium/mojo/public/cpp/utility/run_loop.h b/chromium/mojo/public/cpp/utility/run_loop.h new file mode 100644 index 00000000000..74f870abc57 --- /dev/null +++ b/chromium/mojo/public/cpp/utility/run_loop.h @@ -0,0 +1,108 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_ +#define MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_ + +#include <map> + +#include "mojo/public/cpp/system/core.h" + +namespace mojo { + +class RunLoopHandler; + +class RunLoop { + public: + RunLoop(); + ~RunLoop(); + + // Sets up state needed for RunLoop. This must be invoked before creating a + // RunLoop. + static void SetUp(); + + // Cleans state created by Setup(). + static void TearDown(); + + // Returns the RunLoop for the current thread. Returns NULL if not yet + // created. + static RunLoop* current(); + + // Registers a RunLoopHandler for the specified handle. Only one handler can + // be registered for a specified handle. + void AddHandler(RunLoopHandler* handler, + const Handle& handle, + MojoHandleSignals handle_signals, + MojoDeadline deadline); + void RemoveHandler(const Handle& handle); + bool HasHandler(const Handle& handle) const; + + // Runs the loop servicing handles as they are ready. This returns when Quit() + // is invoked, or there no more handles. + void Run(); + + // Runs the loop servicing any handles that are ready. Does not wait for + // handles to become ready before returning. Returns early if Quit() is + // invoked. + void RunUntilIdle(); + + void Quit(); + + private: + struct RunState; + struct WaitState; + + // Contains the data needed to track a request to AddHandler(). + struct HandlerData { + HandlerData() + : handler(NULL), + handle_signals(MOJO_HANDLE_SIGNAL_NONE), + deadline(0), + id(0) {} + + RunLoopHandler* handler; + MojoHandleSignals handle_signals; + MojoTimeTicks deadline; + // See description of |RunLoop::next_handler_id_| for details. + int id; + }; + + typedef std::map<Handle, HandlerData> HandleToHandlerData; + + // Waits for a handle to be ready. Returns after servicing at least one + // handle (or there are no more handles) unless |non_blocking| is true, + // in which case it will also return if servicing at least one handle + // would require blocking. Returns true if a RunLoopHandler was notified. + bool Wait(bool non_blocking); + + // Notifies any handlers whose deadline has expired. Returns true if a + // RunLoopHandler was notified. + bool NotifyDeadlineExceeded(); + + // Removes the first invalid handle. This is called if MojoWaitMany() finds an + // invalid handle. Returns true if a RunLoopHandler was notified. + bool RemoveFirstInvalidHandle(const WaitState& wait_state); + + // Returns the state needed to pass to WaitMany(). + WaitState GetWaitState(bool non_blocking) const; + + HandleToHandlerData handler_data_; + + // If non-NULL we're running (inside Run()). Member references a value on the + // stack. + RunState* run_state_; + + // An ever increasing value assigned to each HandlerData::id. Used to detect + // uniqueness while notifying. That is, while notifying expired timers we copy + // |handler_data_| and only notify handlers whose id match. If the id does not + // match it means the handler was removed then added so that we shouldn't + // notify it. + int next_handler_id_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoop); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_ diff --git a/chromium/mojo/public/cpp/utility/run_loop_handler.h b/chromium/mojo/public/cpp/utility/run_loop_handler.h new file mode 100644 index 00000000000..69838d5e57c --- /dev/null +++ b/chromium/mojo/public/cpp/utility/run_loop_handler.h @@ -0,0 +1,25 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_HANDLER_H_ +#define MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_HANDLER_H_ + +#include "mojo/public/cpp/system/core.h" + +namespace mojo { + +// Used by RunLoop to notify when a handle is either ready or has become +// invalid. +class RunLoopHandler { + public: + virtual void OnHandleReady(const Handle& handle) = 0; + virtual void OnHandleError(const Handle& handle, MojoResult result) = 0; + + protected: + virtual ~RunLoopHandler() {} +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_HANDLER_H_ diff --git a/chromium/mojo/public/cpp/utility/thread.h b/chromium/mojo/public/cpp/utility/thread.h new file mode 100644 index 00000000000..b7d10ee7037 --- /dev/null +++ b/chromium/mojo/public/cpp/utility/thread.h @@ -0,0 +1,62 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_CPP_UTILITY_THREAD_H_ +#define MOJO_PUBLIC_CPP_UTILITY_THREAD_H_ + +#ifdef _WIN32 +#error "Not implemented: See crbug.com/342893." +#endif + +#include <pthread.h> +#include <stddef.h> + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +// This class is thread-friendly, not thread-safe (e.g., you mustn't call +// |Join()| from multiple threads and/or simultaneously try to destroy the +// object). +class Thread { + public: + // TODO(vtl): Support non-joinable? priority? + class Options { + public: + Options() : stack_size_(0) {} + + // A stack size of 0 means the default. + size_t stack_size() const { return stack_size_; } + void set_stack_size(size_t stack_size) { stack_size_ = stack_size; } + + private: + size_t stack_size_; + + // Copy and assign allowed. + }; + + // TODO(vtl): Add name or name prefix? + Thread(); + explicit Thread(const Options& options); + virtual ~Thread(); + + void Start(); + void Join(); + + virtual void Run() = 0; + + private: + static void* ThreadRunTrampoline(void* arg); + + const Options options_; + pthread_t thread_; + bool started_; + bool joined_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Thread); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_UTILITY_THREAD_H_ diff --git a/chromium/mojo/public/gles2/gles2_interface.h b/chromium/mojo/public/gles2/gles2_interface.h new file mode 100644 index 00000000000..19b958ec112 --- /dev/null +++ b/chromium/mojo/public/gles2/gles2_interface.h @@ -0,0 +1,23 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_GLES2_GLES2_INTERFACE_H_ +#define MOJO_PUBLIC_GLES2_GLES2_INTERFACE_H_ + +#include <GLES2/gl2.h> + +namespace mojo { + +class GLES2Interface { + public: + virtual ~GLES2Interface() {} +#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \ + virtual ReturnType Function PARAMETERS = 0; +#include "mojo/public/c/gles2/gles2_call_visitor_autogen.h" +#undef VISIT_GL_CALL +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_GLES2_GLES2_INTERFACE_H_ diff --git a/chromium/mojo/public/gles2/gles2_private.cc b/chromium/mojo/public/gles2/gles2_private.cc new file mode 100644 index 00000000000..52b47d36c3f --- /dev/null +++ b/chromium/mojo/public/gles2/gles2_private.cc @@ -0,0 +1,92 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/gles2/gles2_private.h" + +#include <assert.h> +#include <stddef.h> + +#include "mojo/public/c/gles2/gles2.h" +#include "mojo/public/gles2/gles2_interface.h" + +static mojo::GLES2Support* g_gles2_support = NULL; +static mojo::GLES2Interface* g_gles2_interface = NULL; + +extern "C" { + +void MojoGLES2Initialize(const MojoAsyncWaiter* async_waiter) { + assert(g_gles2_support); + return g_gles2_support->Initialize(async_waiter); +} + +void MojoGLES2Terminate() { + assert(g_gles2_support); + return g_gles2_support->Terminate(); +} + +MojoGLES2Context MojoGLES2CreateContext( + MojoHandle handle, + MojoGLES2ContextLost lost_callback, + MojoGLES2DrawAnimationFrame animation_callback, + void* closure) { + return g_gles2_support->CreateContext(mojo::MessagePipeHandle(handle), + lost_callback, + animation_callback, + closure); +} + +void MojoGLES2DestroyContext(MojoGLES2Context context) { + return g_gles2_support->DestroyContext(context); +} + +void MojoGLES2MakeCurrent(MojoGLES2Context context) { + assert(g_gles2_support); + g_gles2_support->MakeCurrent(context); + g_gles2_interface = g_gles2_support->GetGLES2InterfaceForCurrentContext(); +} + +void MojoGLES2SwapBuffers() { + assert(g_gles2_support); + return g_gles2_support->SwapBuffers(); +} + +void MojoGLES2RequestAnimationFrames(MojoGLES2Context context) { + assert(g_gles2_support); + return g_gles2_support->RequestAnimationFrames(context); +} + +void MojoGLES2CancelAnimationFrames(MojoGLES2Context context) { + assert(g_gles2_support); + return g_gles2_support->CancelAnimationFrames(context); +} + +void* MojoGLES2GetGLES2Interface(MojoGLES2Context context) { + assert(g_gles2_support); + return g_gles2_support->GetGLES2Interface(context); +} + +void* MojoGLES2GetContextSupport(MojoGLES2Context context) { + assert(g_gles2_support); + return g_gles2_support->GetContextSupport(context); +} + +#define VISIT_GL_CALL(Function, ReturnType, PARAMETERS, ARGUMENTS) \ + ReturnType gl##Function PARAMETERS { \ + return g_gles2_interface->Function ARGUMENTS; \ + } +#include "mojo/public/c/gles2/gles2_call_visitor_autogen.h" +#undef VISIT_GL_CALL + +} // extern "C" + +namespace mojo { + +GLES2Support::~GLES2Support() {} + +void GLES2Support::Init(GLES2Support* gles2_support) { + assert(!g_gles2_support); + g_gles2_support = gles2_support; +} + +} // namespace mojo diff --git a/chromium/mojo/public/gles2/gles2_private.h b/chromium/mojo/public/gles2/gles2_private.h new file mode 100644 index 00000000000..f0a336d60e6 --- /dev/null +++ b/chromium/mojo/public/gles2/gles2_private.h @@ -0,0 +1,46 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_GLES2_GLES2_PRIVATE_H_ +#define MOJO_PUBLIC_GLES2_GLES2_PRIVATE_H_ + +#include <stdint.h> + +#include "mojo/public/c/environment/async_waiter.h" +#include "mojo/public/c/gles2/gles2_export.h" +#include "mojo/public/c/gles2/gles2_types.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +class GLES2Interface; + +// Implementors of the GLES2 APIs can use this interface to install their +// implementation into the mojo_gles2 dynamic library. Mojo clients should not +// call these functions directly. +class MOJO_GLES2_EXPORT GLES2Support { + public: + virtual ~GLES2Support(); + + static void Init(GLES2Support* gles2_support); + + virtual void Initialize(const MojoAsyncWaiter* async_waiter) = 0; + virtual void Terminate() = 0; + virtual MojoGLES2Context CreateContext( + MessagePipeHandle handle, + MojoGLES2ContextLost lost_callback, + MojoGLES2DrawAnimationFrame animation_callback, + void* closure) = 0; + virtual void DestroyContext(MojoGLES2Context context) = 0; + virtual void MakeCurrent(MojoGLES2Context context) = 0; + virtual void SwapBuffers() = 0; + virtual void RequestAnimationFrames(MojoGLES2Context context) = 0; + virtual void CancelAnimationFrames(MojoGLES2Context context) = 0; + virtual void* GetGLES2Interface(MojoGLES2Context context) = 0; + virtual void* GetContextSupport(MojoGLES2Context context) = 0; + virtual GLES2Interface* GetGLES2InterfaceForCurrentContext() = 0; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_GLES2_GLES2_PRIVATE_H_ diff --git a/chromium/mojo/public/interfaces/interface_provider/BUILD.gn b/chromium/mojo/public/interfaces/interface_provider/BUILD.gn new file mode 100644 index 00000000000..55d5b0a37da --- /dev/null +++ b/chromium/mojo/public/interfaces/interface_provider/BUILD.gn @@ -0,0 +1,11 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("interface_provider") { + sources = [ + "interface_provider.mojom", + ] +} diff --git a/chromium/mojo/public/interfaces/interface_provider/interface_provider.mojom b/chromium/mojo/public/interfaces/interface_provider/interface_provider.mojom new file mode 100644 index 00000000000..91e32813da6 --- /dev/null +++ b/chromium/mojo/public/interfaces/interface_provider/interface_provider.mojom @@ -0,0 +1,12 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module mojo { + +[Client=IInterfaceProvider] +interface IInterfaceProvider { + GetInterface(string name, handle<message_pipe> client_handle); +}; + +} diff --git a/chromium/mojo/public/interfaces/service_provider/BUILD.gn b/chromium/mojo/public/interfaces/service_provider/BUILD.gn new file mode 100644 index 00000000000..990d3e9b626 --- /dev/null +++ b/chromium/mojo/public/interfaces/service_provider/BUILD.gn @@ -0,0 +1,11 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("service_provider") { + sources = [ + "service_provider.mojom", + ] +} diff --git a/chromium/mojo/public/interfaces/service_provider/service_provider.mojom b/chromium/mojo/public/interfaces/service_provider/service_provider.mojom new file mode 100644 index 00000000000..190c85c2d78 --- /dev/null +++ b/chromium/mojo/public/interfaces/service_provider/service_provider.mojom @@ -0,0 +1,19 @@ +// 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. + +module mojo { + +[Client=ServiceProvider] +interface ServiceProvider { + // Loads url. mojo:{service} will result in the user of the value of the + // --origin flag to the shell being used. + ConnectToService(string service_url, + string service_name, + handle<message_pipe> client_handle, + // ignored for client making request, filled in by system for + // implementor. + string requestor_url); +}; + +} diff --git a/chromium/mojo/public/interfaces/shell/BUILD.gn b/chromium/mojo/public/interfaces/shell/BUILD.gn new file mode 100644 index 00000000000..c11ae70a311 --- /dev/null +++ b/chromium/mojo/public/interfaces/shell/BUILD.gn @@ -0,0 +1,11 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("shell") { + sources = [ + "shell.mojom", + ] +} diff --git a/chromium/mojo/public/js/bindings/BUILD.gn b/chromium/mojo/public/js/bindings/BUILD.gn new file mode 100644 index 00000000000..0f305e924ec --- /dev/null +++ b/chromium/mojo/public/js/bindings/BUILD.gn @@ -0,0 +1,10 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("bindings") { + sources = [ + "constants.cc", + "constants.h", + ] +} diff --git a/chromium/mojo/public/js/bindings/codec.js b/chromium/mojo/public/js/bindings/codec.js new file mode 100644 index 00000000000..84c86c12991 --- /dev/null +++ b/chromium/mojo/public/js/bindings/codec.js @@ -0,0 +1,739 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +define("mojo/public/js/bindings/codec", [ + "mojo/public/js/bindings/unicode" +], function(unicode) { + + var kErrorUnsigned = "Passing negative value to unsigned"; + + // Memory ------------------------------------------------------------------- + + var kAlignment = 8; + var kHighWordMultiplier = 0x100000000; + var kHostIsLittleEndian = (function () { + var endianArrayBuffer = new ArrayBuffer(2); + var endianUint8Array = new Uint8Array(endianArrayBuffer); + var endianUint16Array = new Uint16Array(endianArrayBuffer); + endianUint16Array[0] = 1; + return endianUint8Array[0] == 1; + })(); + + function align(size) { + return size + (kAlignment - (size % kAlignment)) % kAlignment; + } + + function getInt64(dataView, byteOffset, value) { + var lo, hi; + if (kHostIsLittleEndian) { + lo = dataView.getUint32(byteOffset, kHostIsLittleEndian); + hi = dataView.getInt32(byteOffset + 4, kHostIsLittleEndian); + } else { + hi = dataView.getInt32(byteOffset, kHostIsLittleEndian); + lo = dataView.getUint32(byteOffset + 4, kHostIsLittleEndian); + } + return lo + hi * kHighWordMultiplier; + } + + function getUint64(dataView, byteOffset, value) { + var lo, hi; + if (kHostIsLittleEndian) { + lo = dataView.getUint32(byteOffset, kHostIsLittleEndian); + hi = dataView.getUint32(byteOffset + 4, kHostIsLittleEndian); + } else { + hi = dataView.getUint32(byteOffset, kHostIsLittleEndian); + lo = dataView.getUint32(byteOffset + 4, kHostIsLittleEndian); + } + return lo + hi * kHighWordMultiplier; + } + + function setInt64(dataView, byteOffset, value) { + var hi = Math.floor(value / kHighWordMultiplier); + if (kHostIsLittleEndian) { + dataView.setInt32(byteOffset, value, kHostIsLittleEndian); + dataView.setInt32(byteOffset + 4, hi, kHostIsLittleEndian); + } else { + dataView.setInt32(byteOffset, hi, kHostIsLittleEndian); + dataView.setInt32(byteOffset + 4, value, kHostIsLittleEndian); + } + } + + function setUint64(dataView, byteOffset, value) { + var hi = (value / kHighWordMultiplier) | 0; + if (kHostIsLittleEndian) { + dataView.setInt32(byteOffset, value, kHostIsLittleEndian); + dataView.setInt32(byteOffset + 4, hi, kHostIsLittleEndian); + } else { + dataView.setInt32(byteOffset, hi, kHostIsLittleEndian); + dataView.setInt32(byteOffset + 4, value, kHostIsLittleEndian); + } + } + + function copyArrayBuffer(dstArrayBuffer, srcArrayBuffer) { + (new Uint8Array(dstArrayBuffer)).set(new Uint8Array(srcArrayBuffer)); + } + + // Buffer ------------------------------------------------------------------- + + function Buffer(sizeOrArrayBuffer) { + if (sizeOrArrayBuffer instanceof ArrayBuffer) { + this.arrayBuffer = sizeOrArrayBuffer; + } else { + this.arrayBuffer = new ArrayBuffer(sizeOrArrayBuffer); + }; + + this.dataView = new DataView(this.arrayBuffer); + this.next = 0; + } + + Buffer.prototype.alloc = function(size) { + var pointer = this.next; + this.next += size; + if (this.next > this.arrayBuffer.byteLength) { + var newSize = (1.5 * (this.arrayBuffer.byteLength + size)) | 0; + this.grow(newSize); + } + return pointer; + }; + + Buffer.prototype.grow = function(size) { + var newArrayBuffer = new ArrayBuffer(size); + copyArrayBuffer(newArrayBuffer, this.arrayBuffer); + this.arrayBuffer = newArrayBuffer; + this.dataView = new DataView(this.arrayBuffer); + }; + + Buffer.prototype.trim = function() { + this.arrayBuffer = this.arrayBuffer.slice(0, this.next); + this.dataView = new DataView(this.arrayBuffer); + }; + + // Constants ---------------------------------------------------------------- + + var kArrayHeaderSize = 8; + var kStructHeaderSize = 8; + var kMessageHeaderSize = 16; + var kMessageWithRequestIDHeaderSize = 24; + + // Decoder ------------------------------------------------------------------ + + function Decoder(buffer, handles, base) { + this.buffer = buffer; + this.handles = handles; + this.base = base; + this.next = base; + } + + Decoder.prototype.skip = function(offset) { + this.next += offset; + }; + + Decoder.prototype.readInt8 = function() { + var result = this.buffer.dataView.getInt8(this.next, kHostIsLittleEndian); + this.next += 1; + return result; + }; + + Decoder.prototype.readUint8 = function() { + var result = this.buffer.dataView.getUint8(this.next, kHostIsLittleEndian); + this.next += 1; + return result; + }; + + Decoder.prototype.readInt16 = function() { + var result = this.buffer.dataView.getInt16(this.next, kHostIsLittleEndian); + this.next += 2; + return result; + }; + + Decoder.prototype.readUint16 = function() { + var result = this.buffer.dataView.getUint16(this.next, kHostIsLittleEndian); + this.next += 2; + return result; + }; + + Decoder.prototype.readInt32 = function() { + var result = this.buffer.dataView.getInt32(this.next, kHostIsLittleEndian); + this.next += 4; + return result; + }; + + Decoder.prototype.readUint32 = function() { + var result = this.buffer.dataView.getUint32(this.next, kHostIsLittleEndian); + this.next += 4; + return result; + }; + + Decoder.prototype.readInt64 = function() { + var result = getInt64(this.buffer.dataView, this.next, kHostIsLittleEndian); + this.next += 8; + return result; + }; + + Decoder.prototype.readUint64 = function() { + var result = getUint64( + this.buffer.dataView, this.next, kHostIsLittleEndian); + this.next += 8; + return result; + }; + + Decoder.prototype.readFloat = function() { + var result = this.buffer.dataView.getFloat32( + this.next, kHostIsLittleEndian); + this.next += 4; + return result; + }; + + Decoder.prototype.readDouble = function() { + var result = this.buffer.dataView.getFloat64( + this.next, kHostIsLittleEndian); + this.next += 8; + return result; + }; + + Decoder.prototype.decodePointer = function() { + // TODO(abarth): To correctly decode a pointer, we need to know the real + // base address of the array buffer. + var offsetPointer = this.next; + var offset = this.readUint64(); + if (!offset) + return 0; + return offsetPointer + offset; + }; + + Decoder.prototype.decodeAndCreateDecoder = function(pointer) { + return new Decoder(this.buffer, this.handles, pointer); + }; + + Decoder.prototype.decodeHandle = function() { + return this.handles[this.readUint32()]; + }; + + Decoder.prototype.decodeString = function() { + var numberOfBytes = this.readUint32(); + var numberOfElements = this.readUint32(); + var base = this.next; + this.next += numberOfElements; + return unicode.decodeUtf8String( + new Uint8Array(this.buffer.arrayBuffer, base, numberOfElements)); + }; + + Decoder.prototype.decodeArray = function(cls) { + var numberOfBytes = this.readUint32(); + var numberOfElements = this.readUint32(); + var val = new Array(numberOfElements); + for (var i = 0; i < numberOfElements; ++i) { + val[i] = cls.decode(this); + } + return val; + }; + + Decoder.prototype.decodeStruct = function(cls) { + return cls.decode(this); + }; + + Decoder.prototype.decodeStructPointer = function(cls) { + var pointer = this.decodePointer(); + if (!pointer) { + return null; + } + return cls.decode(this.decodeAndCreateDecoder(pointer)); + }; + + Decoder.prototype.decodeArrayPointer = function(cls) { + var pointer = this.decodePointer(); + if (!pointer) { + return null; + } + return this.decodeAndCreateDecoder(pointer).decodeArray(cls); + }; + + Decoder.prototype.decodeStringPointer = function() { + var pointer = this.decodePointer(); + if (!pointer) { + return null; + } + return this.decodeAndCreateDecoder(pointer).decodeString(); + }; + + // Encoder ------------------------------------------------------------------ + + function Encoder(buffer, handles, base) { + this.buffer = buffer; + this.handles = handles; + this.base = base; + this.next = base; + } + + Encoder.prototype.skip = function(offset) { + this.next += offset; + }; + + Encoder.prototype.writeInt8 = function(val) { + // NOTE: Endianness doesn't come into play for single bytes. + this.buffer.dataView.setInt8(this.next, val); + this.next += 1; + }; + + Encoder.prototype.writeUint8 = function(val) { + if (val < 0) { + throw new Error(kErrorUnsigned); + } + // NOTE: Endianness doesn't come into play for single bytes. + this.buffer.dataView.setUint8(this.next, val); + this.next += 1; + }; + + Encoder.prototype.writeInt16 = function(val) { + this.buffer.dataView.setInt16(this.next, val, kHostIsLittleEndian); + this.next += 2; + }; + + Encoder.prototype.writeUint16 = function(val) { + if (val < 0) { + throw new Error(kErrorUnsigned); + } + this.buffer.dataView.setUint16(this.next, val, kHostIsLittleEndian); + this.next += 2; + }; + + Encoder.prototype.writeInt32 = function(val) { + this.buffer.dataView.setInt32(this.next, val, kHostIsLittleEndian); + this.next += 4; + }; + + Encoder.prototype.writeUint32 = function(val) { + if (val < 0) { + throw new Error(kErrorUnsigned); + } + this.buffer.dataView.setUint32(this.next, val, kHostIsLittleEndian); + this.next += 4; + }; + + Encoder.prototype.writeInt64 = function(val) { + setInt64(this.buffer.dataView, this.next, val); + this.next += 8; + }; + + Encoder.prototype.writeUint64 = function(val) { + if (val < 0) { + throw new Error(kErrorUnsigned); + } + setUint64(this.buffer.dataView, this.next, val); + this.next += 8; + }; + + Encoder.prototype.writeFloat = function(val) { + this.buffer.dataView.setFloat32(this.next, val, kHostIsLittleEndian); + this.next += 4; + }; + + Encoder.prototype.writeDouble = function(val) { + this.buffer.dataView.setFloat64(this.next, val, kHostIsLittleEndian); + this.next += 8; + }; + + Encoder.prototype.encodePointer = function(pointer) { + if (!pointer) + return this.writeUint64(0); + // TODO(abarth): To correctly encode a pointer, we need to know the real + // base address of the array buffer. + var offset = pointer - this.next; + this.writeUint64(offset); + }; + + Encoder.prototype.createAndEncodeEncoder = function(size) { + var pointer = this.buffer.alloc(align(size)); + this.encodePointer(pointer); + return new Encoder(this.buffer, this.handles, pointer); + }; + + Encoder.prototype.encodeHandle = function(handle) { + this.handles.push(handle); + this.writeUint32(this.handles.length - 1); + }; + + Encoder.prototype.encodeString = function(val) { + var base = this.next + kArrayHeaderSize; + var numberOfElements = unicode.encodeUtf8String( + val, new Uint8Array(this.buffer.arrayBuffer, base)); + var numberOfBytes = kArrayHeaderSize + numberOfElements; + this.writeUint32(numberOfBytes); + this.writeUint32(numberOfElements); + this.next += numberOfElements; + }; + + Encoder.prototype.encodeArray = function(cls, val) { + var numberOfElements = val.length; + var numberOfBytes = kArrayHeaderSize + cls.encodedSize * numberOfElements; + this.writeUint32(numberOfBytes); + this.writeUint32(numberOfElements); + for (var i = 0; i < numberOfElements; ++i) { + cls.encode(this, val[i]); + } + }; + + Encoder.prototype.encodeStruct = function(cls, val) { + return cls.encode(this, val); + }; + + Encoder.prototype.encodeStructPointer = function(cls, val) { + if (!val) { + this.encodePointer(val); + return; + } + var encoder = this.createAndEncodeEncoder(cls.encodedSize); + cls.encode(encoder, val); + }; + + Encoder.prototype.encodeArrayPointer = function(cls, val) { + if (!val) { + this.encodePointer(val); + return; + } + var encodedSize = kArrayHeaderSize + cls.encodedSize * val.length; + var encoder = this.createAndEncodeEncoder(encodedSize); + encoder.encodeArray(cls, val); + }; + + Encoder.prototype.encodeStringPointer = function(val) { + if (!val) { + this.encodePointer(val); + return; + } + var encodedSize = kArrayHeaderSize + unicode.utf8Length(val); + var encoder = this.createAndEncodeEncoder(encodedSize); + encoder.encodeString(val); + }; + + // Message ------------------------------------------------------------------ + + var kMessageExpectsResponse = 1 << 0; + var kMessageIsResponse = 1 << 1; + + // Skip over num_bytes, num_fields, and message_name. + var kFlagsOffset = 4 + 4 + 4; + + // Skip over num_bytes, num_fields, message_name, and flags. + var kRequestIDOffset = 4 + 4 + 4 + 4; + + function Message(buffer, handles) { + this.buffer = buffer; + this.handles = handles; + } + + Message.prototype.setRequestID = function(requestID) { + // TODO(darin): Verify that space was reserved for this field! + setUint64(this.buffer.dataView, kRequestIDOffset, requestID); + }; + + Message.prototype.getFlags = function() { + return this.buffer.dataView.getUint32(kFlagsOffset, kHostIsLittleEndian); + }; + + // MessageBuilder ----------------------------------------------------------- + + function MessageBuilder(messageName, payloadSize) { + // Currently, we don't compute the payload size correctly ahead of time. + // Instead, we resize the buffer at the end. + var numberOfBytes = kMessageHeaderSize + payloadSize; + this.buffer = new Buffer(numberOfBytes); + this.handles = []; + var encoder = this.createEncoder(kMessageHeaderSize); + encoder.writeUint32(kMessageHeaderSize); + encoder.writeUint32(2); // num_fields. + encoder.writeUint32(messageName); + encoder.writeUint32(0); // flags. + } + + MessageBuilder.prototype.createEncoder = function(size) { + var pointer = this.buffer.alloc(size); + return new Encoder(this.buffer, this.handles, pointer); + }; + + MessageBuilder.prototype.encodeStruct = function(cls, val) { + cls.encode(this.createEncoder(cls.encodedSize), val); + }; + + MessageBuilder.prototype.finish = function() { + // TODO(abarth): Rather than resizing the buffer at the end, we could + // compute the size we need ahead of time, like we do in C++. + this.buffer.trim(); + var message = new Message(this.buffer, this.handles); + this.buffer = null; + this.handles = null; + this.encoder = null; + return message; + }; + + // MessageWithRequestIDBuilder ----------------------------------------------- + + function MessageWithRequestIDBuilder(messageName, payloadSize, flags, + requestID) { + // Currently, we don't compute the payload size correctly ahead of time. + // Instead, we resize the buffer at the end. + var numberOfBytes = kMessageWithRequestIDHeaderSize + payloadSize; + this.buffer = new Buffer(numberOfBytes); + this.handles = []; + var encoder = this.createEncoder(kMessageWithRequestIDHeaderSize); + encoder.writeUint32(kMessageWithRequestIDHeaderSize); + encoder.writeUint32(3); // num_fields. + encoder.writeUint32(messageName); + encoder.writeUint32(flags); + encoder.writeUint64(requestID); + } + + MessageWithRequestIDBuilder.prototype = + Object.create(MessageBuilder.prototype); + + MessageWithRequestIDBuilder.prototype.constructor = + MessageWithRequestIDBuilder; + + // MessageReader ------------------------------------------------------------ + + function MessageReader(message) { + this.decoder = new Decoder(message.buffer, message.handles, 0); + var messageHeaderSize = this.decoder.readUint32(); + this.payloadSize = + message.buffer.arrayBuffer.byteLength - messageHeaderSize; + var numFields = this.decoder.readUint32(); + this.messageName = this.decoder.readUint32(); + this.flags = this.decoder.readUint32(); + if (numFields >= 3) + this.requestID = this.decoder.readUint64(); + this.decoder.skip(messageHeaderSize - this.decoder.next); + } + + MessageReader.prototype.decodeStruct = function(cls) { + return cls.decode(this.decoder); + }; + + // Built-in types ----------------------------------------------------------- + + function Int8() { + } + + Int8.encodedSize = 1; + + Int8.decode = function(decoder) { + return decoder.readInt8(); + }; + + Int8.encode = function(encoder, val) { + encoder.writeInt8(val); + }; + + Uint8.encode = function(encoder, val) { + encoder.writeUint8(val); + }; + + function Uint8() { + } + + Uint8.encodedSize = 1; + + Uint8.decode = function(decoder) { + return decoder.readUint8(); + }; + + Uint8.encode = function(encoder, val) { + encoder.writeUint8(val); + }; + + function Int16() { + } + + Int16.encodedSize = 2; + + Int16.decode = function(decoder) { + return decoder.readInt16(); + }; + + Int16.encode = function(encoder, val) { + encoder.writeInt16(val); + }; + + function Uint16() { + } + + Uint16.encodedSize = 2; + + Uint16.decode = function(decoder) { + return decoder.readUint16(); + }; + + Uint16.encode = function(encoder, val) { + encoder.writeUint16(val); + }; + + function Int32() { + } + + Int32.encodedSize = 4; + + Int32.decode = function(decoder) { + return decoder.readInt32(); + }; + + Int32.encode = function(encoder, val) { + encoder.writeInt32(val); + }; + + function Uint32() { + } + + Uint32.encodedSize = 4; + + Uint32.decode = function(decoder) { + return decoder.readUint32(); + }; + + Uint32.encode = function(encoder, val) { + encoder.writeUint32(val); + }; + + function Int64() { + } + + Int64.encodedSize = 8; + + Int64.decode = function(decoder) { + return decoder.readInt64(); + }; + + Int64.encode = function(encoder, val) { + encoder.writeInt64(val); + }; + + function Uint64() { + } + + Uint64.encodedSize = 8; + + Uint64.decode = function(decoder) { + return decoder.readUint64(); + }; + + Uint64.encode = function(encoder, val) { + encoder.writeUint64(val); + }; + + function String() { + }; + + String.encodedSize = 8; + + String.decode = function(decoder) { + return decoder.decodeStringPointer(); + }; + + String.encode = function(encoder, val) { + encoder.encodeStringPointer(val); + }; + + + function Float() { + } + + Float.encodedSize = 4; + + Float.decode = function(decoder) { + return decoder.readFloat(); + }; + + Float.encode = function(encoder, val) { + encoder.writeFloat(val); + }; + + function Double() { + } + + Double.encodedSize = 8; + + Double.decode = function(decoder) { + return decoder.readDouble(); + }; + + Double.encode = function(encoder, val) { + encoder.writeDouble(val); + }; + + function PointerTo(cls) { + this.cls = cls; + } + + PointerTo.prototype.encodedSize = 8; + + PointerTo.prototype.decode = function(decoder) { + var pointer = decoder.decodePointer(); + if (!pointer) { + return null; + } + return this.cls.decode(decoder.decodeAndCreateDecoder(pointer)); + }; + + PointerTo.prototype.encode = function(encoder, val) { + if (!val) { + encoder.encodePointer(val); + return; + } + var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize); + this.cls.encode(objectEncoder, val); + }; + + function ArrayOf(cls) { + this.cls = cls; + } + + ArrayOf.prototype.encodedSize = 8; + + ArrayOf.prototype.decode = function(decoder) { + return decoder.decodeArrayPointer(this.cls); + }; + + ArrayOf.prototype.encode = function(encoder, val) { + encoder.encodeArrayPointer(this.cls, val); + }; + + function Handle() { + } + + Handle.encodedSize = 4; + + Handle.decode = function(decoder) { + return decoder.decodeHandle(); + }; + + Handle.encode = function(encoder, val) { + encoder.encodeHandle(val); + }; + + var exports = {}; + exports.align = align; + exports.Buffer = Buffer; + exports.Message = Message; + exports.MessageBuilder = MessageBuilder; + exports.MessageWithRequestIDBuilder = MessageWithRequestIDBuilder; + exports.MessageReader = MessageReader; + exports.kArrayHeaderSize = kArrayHeaderSize; + exports.kStructHeaderSize = kStructHeaderSize; + exports.kMessageHeaderSize = kMessageHeaderSize; + exports.kMessageExpectsResponse = kMessageExpectsResponse; + exports.kMessageIsResponse = kMessageIsResponse; + exports.Int8 = Int8; + exports.Uint8 = Uint8; + exports.Int16 = Int16; + exports.Uint16 = Uint16; + exports.Int32 = Int32; + exports.Uint32 = Uint32; + exports.Int64 = Int64; + exports.Uint64 = Uint64; + exports.Float = Float; + exports.Double = Double; + exports.String = String; + exports.PointerTo = PointerTo; + exports.ArrayOf = ArrayOf; + exports.Handle = Handle; + return exports; +}); diff --git a/chromium/mojo/public/js/bindings/connection.js b/chromium/mojo/public/js/bindings/connection.js new file mode 100644 index 00000000000..ebf60adb7f8 --- /dev/null +++ b/chromium/mojo/public/js/bindings/connection.js @@ -0,0 +1,30 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +define("mojo/public/js/bindings/connection", [ + "mojo/public/js/bindings/router", +], function(router) { + + function Connection(handle, localFactory, remoteFactory) { + this.router_ = new router.Router(handle); + this.remote = new remoteFactory(this.router_); + this.local = new localFactory(this.remote); + this.router_.setIncomingReceiver(this.local); + } + + Connection.prototype.close = function() { + this.router_.close(); + this.router_ = null; + this.local = null; + this.remote = null; + }; + + Connection.prototype.encounteredError = function() { + return this.router_.encounteredError(); + }; + + var exports = {}; + exports.Connection = Connection; + return exports; +}); diff --git a/chromium/mojo/public/js/bindings/connector.js b/chromium/mojo/public/js/bindings/connector.js new file mode 100644 index 00000000000..51022b0e45f --- /dev/null +++ b/chromium/mojo/public/js/bindings/connector.js @@ -0,0 +1,109 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +define("mojo/public/js/bindings/connector", [ + "mojo/public/js/bindings/codec", + "mojo/public/js/bindings/core", + "mojo/public/js/bindings/support", +], function(codec, core, support) { + + function Connector(handle) { + this.handle_ = handle; + this.dropWrites_ = false; + this.error_ = false; + this.incomingReceiver_ = null; + this.readWaitCookie_ = null; + this.errorHandler_ = null; + + this.waitToReadMore_(); + } + + Connector.prototype.close = function() { + if (this.readWaitCookie_) { + support.cancelWait(this.readWaitCookie_); + this.readWaitCookie_ = null; + } + if (this.handle_ != null) { + core.close(this.handle_); + this.handle_ = null; + } + }; + + Connector.prototype.accept = function(message) { + if (this.error_) + return false; + + if (this.dropWrites_) + return true; + + var result = core.writeMessage(this.handle_, + new Uint8Array(message.buffer.arrayBuffer), + message.handles, + core.WRITE_MESSAGE_FLAG_NONE); + switch (result) { + case core.RESULT_OK: + // The handles were successfully transferred, so we don't own them + // anymore. + message.handles = []; + break; + case core.RESULT_FAILED_PRECONDITION: + // There's no point in continuing to write to this pipe since the other + // end is gone. Avoid writing any future messages. Hide write failures + // from the caller since we'd like them to continue consuming any + // backlog of incoming messages before regarding the message pipe as + // closed. + this.dropWrites_ = true; + break; + default: + // This particular write was rejected, presumably because of bad input. + // The pipe is not necessarily in a bad state. + return false; + } + return true; + }; + + Connector.prototype.setIncomingReceiver = function(receiver) { + this.incomingReceiver_ = receiver; + }; + + Connector.prototype.setErrorHandler = function(handler) { + this.errorHandler_ = handler; + }; + + Connector.prototype.encounteredError = function() { + return this.error_; + }; + + Connector.prototype.waitToReadMore_ = function() { + this.readWaitCookie_ = support.asyncWait(this.handle_, + core.HANDLE_SIGNAL_READABLE, + this.readMore_.bind(this)); + }; + + Connector.prototype.readMore_ = function(result) { + for (;;) { + var read = core.readMessage(this.handle_, + core.READ_MESSAGE_FLAG_NONE); + if (read.result == core.RESULT_SHOULD_WAIT) { + this.waitToReadMore_(); + return; + } + if (read.result != core.RESULT_OK) { + this.error_ = true; + if (this.errorHandler_) + this.errorHandler_.onError(read.result); + return; + } + var buffer = new codec.Buffer(read.buffer); + var message = new codec.Message(buffer, read.handles); + if (this.incomingReceiver_) { + this.incomingReceiver_.accept(message); + } + } + }; + + var exports = {}; + exports.Connector = Connector; + return exports; +}); diff --git a/chromium/mojo/public/js/bindings/constants.cc b/chromium/mojo/public/js/bindings/constants.cc new file mode 100644 index 00000000000..239b67d4139 --- /dev/null +++ b/chromium/mojo/public/js/bindings/constants.cc @@ -0,0 +1,15 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/js/bindings/constants.h" + +namespace mojo { + +const char kCodecModuleName[] = "mojo/public/js/bindings/codec"; +const char kConnectionModuleName[] = "mojo/public/js/bindings/connection"; +const char kConnectorModuleName[] = "mojo/public/js/bindings/connector"; +const char kUnicodeModuleName[] = "mojo/public/js/bindings/unicode"; +const char kRouterModuleName[] = "mojo/public/js/bindings/router"; + +} // namespace mojo diff --git a/chromium/mojo/public/js/bindings/constants.h b/chromium/mojo/public/js/bindings/constants.h new file mode 100644 index 00000000000..50e5d7c0248 --- /dev/null +++ b/chromium/mojo/public/js/bindings/constants.h @@ -0,0 +1,19 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_JS_BINDINGS_CONSTANTS_H_ +#define MOJO_PUBLIC_JS_BINDINGS_CONSTANTS_H_ + +namespace mojo { + +// JavaScript module names: +extern const char kCodecModuleName[]; +extern const char kConnectionModuleName[]; +extern const char kConnectorModuleName[]; +extern const char kUnicodeModuleName[]; +extern const char kRouterModuleName[]; + +} // namespace mojo + +#endif // MOJO_PUBLIC_JS_BINDINGS_CONSTANTS_H_ diff --git a/chromium/mojo/public/js/bindings/core.js b/chromium/mojo/public/js/bindings/core.js new file mode 100644 index 00000000000..0aff5310833 --- /dev/null +++ b/chromium/mojo/public/js/bindings/core.js @@ -0,0 +1,215 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Module "mojo/public/js/bindings/core" +// +// Note: This file is for documentation purposes only. The code here is not +// actually executed. The real module is implemented natively in Mojo. +// +// This module provides the JavaScript bindings for mojo/public/c/system/core.h. +// Refer to that file for more detailed documentation for equivalent methods. + +while (1); + +/** + * MojoHandle: An opaque handles to a Mojo object (e.g. a message pipe). + */ +var kInvalidHandle; + +/** + * MojoResult {number}: Result codes for Mojo operations. + * See core.h for more information. + */ +var RESULT_OK; +var RESULT_CANCELLED; +var RESULT_UNKNOWN; +var RESULT_INVALID_ARGUMENT; +var RESULT_DEADLINE_EXCEEDED; +var RESULT_NOT_FOUND; +var RESULT_ALREADY_EXISTS; +var RESULT_PERMISSION_DENIED; +var RESULT_RESOURCE_EXHAUSTED; +var RESULT_FAILED_PRECONDITION; +var RESULT_ABORTED; +var RESULT_OUT_OF_RANGE; +var RESULT_UNIMPLEMENTED; +var RESULT_INTERNAL; +var RESULT_UNAVAILABLE; +var RESULT_DATA_LOSS; +var RESULT_BUSY; +var RESULT_SHOULD_WAIT; + +/** + * MojoDeadline {number}: Used to specify deadlines (timeouts), in microseconds. + * See core.h for more information. + */ +var DEADLINE_INDEFINITE; + +/** + * MojoHandleSignals: Used to specify signals that can be waited on for a handle + *(and which can be triggered), e.g., the ability to read or write to + * the handle. + * See core.h for more information. + */ +var HANDLE_SIGNAL_NONE; +var HANDLE_SIGNAL_READABLE; +var HANDLE_SIGNAL_WRITABLE; + +/* + * MojoWriteMessageFlags: Used to specify different modes to |writeMessage()|. + * See core.h for more information. + */ +var WRITE_MESSAGE_FLAG_NONE; + +/** + * MojoReadMessageFlags: Used to specify different modes to |readMessage()|. + * See core.h for more information. + */ +var READ_MESSAGE_FLAG_NONE; +var READ_MESSAGE_FLAG_MAY_DISCARD; + +/** + * MojoCreateDataPipeOptions: Used to specify creation parameters for a data + * pipe to |createDataPipe()|. + * See core.h for more information. + */ +dictionary MojoCreateDataPipeOptions { + MojoCreateDataPipeOptionsFlags flags; // See below. + int32 elementNumBytes; // The size of an element, in bytes. + int32 capacityNumBytes; // The capacity of the data pipe, in bytes. +}; + +// MojoCreateDataPipeOptionsFlags +var CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; +var CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD; + +/* + * MojoWriteDataFlags: Used to specify different modes to |writeData()|. + * See core.h for more information. + */ +var WRITE_DATA_FLAG_NONE; +var WRITE_DATA_FLAG_ALL_OR_NONE; + +/** + * MojoReadDataFlags: Used to specify different modes to |readData()|. + * See core.h for more information. + */ +var READ_DATA_FLAG_NONE; +var READ_DATA_FLAG_ALL_OR_NONE; +var READ_DATA_FLAG_DISCARD; +var READ_DATA_FLAG_QUERY; + +/** + * Closes the given |handle|. See MojoClose for more info. + * @param {MojoHandle} Handle to close. + * @return {MojoResult} Result code. + */ +function close(handle) { [native code] } + +/** + * Waits on the given handle until a signal indicated by |signals| is + * satisfied or until |deadline| is passed. See MojoWait for more information. + * + * @param {MojoHandle} handle Handle to wait on. + * @param {MojoHandleSignals} signals Specifies the condition to wait for. + * @param {MojoDeadline} deadline Stops waiting if this is reached. + * @return {MojoResult} Result code. + */ +function wait(handle, signals, deadline) { [native code] } + +/** + * Waits on |handles[0]|, ..., |handles[handles.length-1]| for at least one of + * them to satisfy the state indicated by |flags[0]|, ..., + * |flags[handles.length-1]|, respectively, or until |deadline| has passed. + * See MojoWaitMany for more information. + * + * @param {Array.MojoHandle} handles Handles to wait on. + * @param {Array.MojoHandleSignals} signals Specifies the condition to wait for, + * for each corresponding handle. Must be the same length as |handles|. + * @param {MojoDeadline} deadline Stops waiting if this is reached. + * @return {MojoResult} Result code. + */ +function waitMany(handles, signals, deadline) { [native code] } + +/** + * Creates a message pipe. This function always succeeds. + * See MojoCreateMessagePipe for more information on message pipes. + * + * @return {MessagePipe} An object of the form { + * handle0, + * handle1, + * } + * where |handle0| and |handle1| are MojoHandles to each end of the channel. + */ +function createMessagePipe() { [native code] } + +/** + * Writes a message to the message pipe endpoint given by |handle|. See + * MojoWriteMessage for more information, including return codes. + * + * @param {MojoHandle} handle The endpoint to write to. + * @param {ArrayBufferView} buffer The message data. May be empty. + * @param {Array.MojoHandle} handlesArray Any handles to attach. Handles are + * transferred on success and will no longer be valid. May be empty. + * @param {MojoWriteMessageFlags} flags Flags. + * @return {MojoResult} Result code. + */ +function writeMessage(handle, buffer, handlesArray, flags) { [native code] } + +/** + * Reads a message from the message pipe endpoint given by |handle|. See + * MojoReadMessage for more information, including return codes. + * + * @param {MojoHandle} handle The endpoint to read from. + * @param {MojoReadMessageFlags} flags Flags. + * @return {object} An object of the form { + * result, // |RESULT_OK| on success, error code otherwise. + * buffer, // An ArrayBufferView of the message data (only on success). + * handles // An array of MojoHandles transferred, if any. + * } + */ +function readMessage(handle, flags) { [native code] } + +/** + * Creates a data pipe, which is a unidirectional communication channel for + * unframed data, with the given options. See MojoCreateDataPipe for more + * more information, including return codes. + * + * @param {MojoCreateDataPipeOptions} optionsDict Options to control the data + * pipe parameters. May be null. + * @return {object} An object of the form { + * result, // |RESULT_OK| on success, error code otherwise. + * producerHandle, // MojoHandle to use with writeData (only on success). + * consumerHandle, // MojoHandle to use with readData (only on success). + * } + */ +function createDataPipe(optionsDict) { [native code] } + +/** + * Writes the given data to the data pipe producer given by |handle|. See + * MojoWriteData for more information, including return codes. + * + * @param {MojoHandle} handle A producerHandle returned by createDataPipe. + * @param {ArrayBufferView} buffer The data to write. + * @param {MojoWriteDataFlags} flags Flags. + * @return {object} An object of the form { + * result, // |RESULT_OK| on success, error code otherwise. + * numBytes, // The number of bytes written. + * } + */ +function writeData(handle, buffer, flags) { [native code] } + +/** + * Reads data from the data pipe consumer given by |handle|. May also + * be used to discard data. See MojoReadData for more information, including + * return codes. + * + * @param {MojoHandle} handle A consumerHandle returned by createDataPipe. + * @param {MojoReadDataFlags} flags Flags. + * @return {object} An object of the form { + * result, // |RESULT_OK| on success, error code otherwise. + * buffer, // An ArrayBufferView of the data read (only on success). + * } + */ +function readData(handle, flags) { [native code] } diff --git a/chromium/mojo/public/js/bindings/router.js b/chromium/mojo/public/js/bindings/router.js new file mode 100644 index 00000000000..2718e8b0b78 --- /dev/null +++ b/chromium/mojo/public/js/bindings/router.js @@ -0,0 +1,93 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +define("mojo/public/js/bindings/router", [ + "mojo/public/js/bindings/codec", + "mojo/public/js/bindings/connector", +], function(codec, connector) { + + function Router(handle) { + this.connector_ = new connector.Connector(handle); + this.incomingReceiver_ = null; + this.nextRequestID_ = 0; + this.responders_ = {}; + + this.connector_.setIncomingReceiver({ + accept: this.handleIncomingMessage_.bind(this), + }); + this.connector_.setErrorHandler({ + onError: this.handleConnectionError_.bind(this), + }); + } + + Router.prototype.close = function() { + this.responders_ = {}; // Drop any responders. + this.connector_.close(); + }; + + Router.prototype.accept = function(message) { + this.connector_.accept(message); + }; + + Router.prototype.reject = function(message) { + // TODO(mpcomplete): no way to trasmit errors over a Connection. + }; + + Router.prototype.acceptWithResponder = function(message, responder) { + // Reserve 0 in case we want it to convey special meaning in the future. + var requestID = this.nextRequestID_++; + if (requestID == 0) + requestID = this.nextRequestID_++; + + message.setRequestID(requestID); + var result = this.connector_.accept(message); + + this.responders_[requestID] = responder; + + // TODO(mpcomplete): accept should return a Promise too, maybe? + if (result) + return Promise.resolve(); + return Promise.reject(Error("Connection error")); + }; + + Router.prototype.setIncomingReceiver = function(receiver) { + this.incomingReceiver_ = receiver; + }; + + Router.prototype.encounteredError = function() { + return this.connector_.encounteredError(); + }; + + Router.prototype.handleIncomingMessage_ = function(message) { + var flags = message.getFlags(); + if (flags & codec.kMessageExpectsResponse) { + if (this.incomingReceiver_) { + this.incomingReceiver_.acceptWithResponder(message, this); + } else { + // If we receive a request expecting a response when the client is not + // listening, then we have no choice but to tear down the pipe. + this.close(); + } + } else if (flags & codec.kMessageIsResponse) { + var reader = new codec.MessageReader(message); + var requestID = reader.requestID; + var responder = this.responders_[requestID]; + delete this.responders_[requestID]; + responder.accept(message); + } else { + if (this.incomingReceiver_) + this.incomingReceiver_.accept(message); + } + }; + + Router.prototype.handleConnectionError_ = function(result) { + for (var each in this.responders_) + this.responders_[each].reject(result); + this.close(); + }; + + var exports = {}; + exports.Router = Router; + return exports; +}); diff --git a/chromium/mojo/public/js/bindings/support.js b/chromium/mojo/public/js/bindings/support.js new file mode 100644 index 00000000000..58df6bd4d02 --- /dev/null +++ b/chromium/mojo/public/js/bindings/support.js @@ -0,0 +1,30 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Module "mojo/public/js/bindings/support" +// +// Note: This file is for documentation purposes only. The code here is not +// actually executed. The real module is implemented natively in Mojo. + +while (1); + +/* + * Waits on the given handle until the state indicated by |signals| is + * satisfied. + * + * @param {MojoHandle} handle The handle to wait on. + * @param {MojoHandleSignals} signals Specifies the condition to wait for. + * @param {function (mojoResult)} callback Called with the result the wait is + * complete. See MojoWait for possible result codes. + * + * @return {MojoWaitId} A waitId that can be passed to cancelWait to cancel the + * wait. + */ +function asyncWait(handle, signals, callback) { [native code] } + +/* + * Cancels the asyncWait operation specified by the given |waitId|. + * @param {MojoWaitId} waitId The waitId returned by asyncWait. + */ +function cancelWait(waitId) { [native code] } diff --git a/chromium/mojo/public/js/bindings/unicode.js b/chromium/mojo/public/js/bindings/unicode.js new file mode 100644 index 00000000000..ba0f00f95ba --- /dev/null +++ b/chromium/mojo/public/js/bindings/unicode.js @@ -0,0 +1,51 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * Defines functions for translating between JavaScript strings and UTF8 strings + * stored in ArrayBuffers. There is much room for optimization in this code if + * it proves necessary. + */ +define("mojo/public/js/bindings/unicode", function() { + /** + * Decodes the UTF8 string from the given buffer. + * @param {ArrayBufferView} buffer The buffer containing UTF8 string data. + * @return {string} The corresponding JavaScript string. + */ + function decodeUtf8String(buffer) { + return decodeURIComponent(escape(String.fromCharCode.apply(null, buffer))); + } + + /** + * Encodes the given JavaScript string into UTF8. + * @param {string} str The string to encode. + * @param {ArrayBufferView} outputBuffer The buffer to contain the result. + * Should be pre-allocated to hold enough space. Use |utf8Length| to determine + * how much space is required. + * @return {number} The number of bytes written to |outputBuffer|. + */ + function encodeUtf8String(str, outputBuffer) { + var utf8String = unescape(encodeURIComponent(str)); + if (outputBuffer.length < utf8String.length) + throw new Error("Buffer too small for encodeUtf8String"); + for (var i = 0; i < outputBuffer.length && i < utf8String.length; i++) + outputBuffer[i] = utf8String.charCodeAt(i); + return i; + } + + /** + * Returns the number of bytes that a UTF8 encoding of the JavaScript string + * |str| would occupy. + */ + function utf8Length(str) { + var utf8String = unescape(encodeURIComponent(str)); + return utf8String.length; + } + + var exports = {}; + exports.decodeUtf8String = decodeUtf8String; + exports.encodeUtf8String = encodeUtf8String; + exports.utf8Length = utf8Length; + return exports; +}); diff --git a/chromium/mojo/public/platform/native/system_thunks.cc b/chromium/mojo/public/platform/native/system_thunks.cc new file mode 100644 index 00000000000..6fdc4f4530f --- /dev/null +++ b/chromium/mojo/public/platform/native/system_thunks.cc @@ -0,0 +1,170 @@ +// 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. + +#include "mojo/public/platform/native/system_thunks.h" + +#include <assert.h> + +extern "C" { + +static MojoSystemThunks g_thunks = {0}; + +MojoTimeTicks MojoGetTimeTicksNow() { + assert(g_thunks.GetTimeTicksNow); + return g_thunks.GetTimeTicksNow(); +} + +MojoResult MojoClose(MojoHandle handle) { + assert(g_thunks.Close); + return g_thunks.Close(handle); +} + +MojoResult MojoWait(MojoHandle handle, + MojoHandleSignals signals, + MojoDeadline deadline) { + assert(g_thunks.Wait); + return g_thunks.Wait(handle, signals, deadline); +} + +MojoResult MojoWaitMany(const MojoHandle* handles, + const MojoHandleSignals* signals, + uint32_t num_handles, + MojoDeadline deadline) { + assert(g_thunks.WaitMany); + return g_thunks.WaitMany(handles, signals, num_handles, deadline); +} + +MojoResult MojoCreateMessagePipe(const MojoCreateMessagePipeOptions* options, + MojoHandle* message_pipe_handle0, + MojoHandle* message_pipe_handle1) { + assert(g_thunks.CreateMessagePipe); + return g_thunks.CreateMessagePipe(options, message_pipe_handle0, + message_pipe_handle1); +} + +MojoResult MojoWriteMessage(MojoHandle message_pipe_handle, + const void* bytes, + uint32_t num_bytes, + const MojoHandle* handles, + uint32_t num_handles, + MojoWriteMessageFlags flags) { + assert(g_thunks.WriteMessage); + return g_thunks.WriteMessage(message_pipe_handle, bytes, num_bytes, handles, + num_handles, flags); +} + +MojoResult MojoReadMessage(MojoHandle message_pipe_handle, + void* bytes, + uint32_t* num_bytes, + MojoHandle* handles, + uint32_t* num_handles, + MojoReadMessageFlags flags) { + assert(g_thunks.ReadMessage); + return g_thunks.ReadMessage(message_pipe_handle, bytes, num_bytes, handles, + num_handles, flags); +} + +MojoResult MojoCreateDataPipe(const MojoCreateDataPipeOptions* options, + MojoHandle* data_pipe_producer_handle, + MojoHandle* data_pipe_consumer_handle) { + assert(g_thunks.CreateDataPipe); + return g_thunks.CreateDataPipe(options, data_pipe_producer_handle, + data_pipe_consumer_handle); +} + +MojoResult MojoWriteData(MojoHandle data_pipe_producer_handle, + const void* elements, + uint32_t* num_elements, + MojoWriteDataFlags flags) { + assert(g_thunks.WriteData); + return g_thunks.WriteData(data_pipe_producer_handle, elements, num_elements, + flags); +} + +MojoResult MojoBeginWriteData(MojoHandle data_pipe_producer_handle, + void** buffer, + uint32_t* buffer_num_elements, + MojoWriteDataFlags flags) { + assert(g_thunks.BeginWriteData); + return g_thunks.BeginWriteData(data_pipe_producer_handle, buffer, + buffer_num_elements, flags); +} + +MojoResult MojoEndWriteData(MojoHandle data_pipe_producer_handle, + uint32_t num_elements_written) { + assert(g_thunks.EndWriteData); + return g_thunks.EndWriteData(data_pipe_producer_handle, num_elements_written); +} + +MojoResult MojoReadData(MojoHandle data_pipe_consumer_handle, + void* elements, + uint32_t* num_elements, + MojoReadDataFlags flags) { + assert(g_thunks.ReadData); + return g_thunks.ReadData(data_pipe_consumer_handle, elements, num_elements, + flags); +} + +MojoResult MojoBeginReadData(MojoHandle data_pipe_consumer_handle, + const void** buffer, + uint32_t* buffer_num_elements, + MojoReadDataFlags flags) { + assert(g_thunks.BeginReadData); + return g_thunks.BeginReadData(data_pipe_consumer_handle, buffer, + buffer_num_elements, flags); +} + +MojoResult MojoEndReadData(MojoHandle data_pipe_consumer_handle, + uint32_t num_elements_read) { + assert(g_thunks.EndReadData); + return g_thunks.EndReadData(data_pipe_consumer_handle, num_elements_read); +} + +MojoResult MojoCreateSharedBuffer( + const struct MojoCreateSharedBufferOptions* options, + uint64_t num_bytes, + MojoHandle* shared_buffer_handle) { + assert(g_thunks.CreateSharedBuffer); + return g_thunks.CreateSharedBuffer(options, num_bytes, shared_buffer_handle); +} + +MojoResult MojoDuplicateBufferHandle( + MojoHandle buffer_handle, + const struct MojoDuplicateBufferHandleOptions* options, + MojoHandle* new_buffer_handle) { + assert(g_thunks.DuplicateBufferHandle); + return g_thunks.DuplicateBufferHandle(buffer_handle, options, + new_buffer_handle); +} + +MojoResult MojoMapBuffer(MojoHandle buffer_handle, + uint64_t offset, + uint64_t num_bytes, + void** buffer, + MojoMapBufferFlags flags) { + assert(g_thunks.MapBuffer); + return g_thunks.MapBuffer(buffer_handle, offset, num_bytes, buffer, flags); +} + +MojoResult MojoUnmapBuffer(void* buffer) { + assert(g_thunks.UnmapBuffer); + return g_thunks.UnmapBuffer(buffer); +} + +// Call this function by looking +// Always export this api. +#if defined(WIN32) +#define THUNK_EXPORT __declspec(dllexport) +#else +#define THUNK_EXPORT __attribute__((visibility("default"))) +#endif + +extern "C" THUNK_EXPORT size_t MojoSetSystemThunks( + const MojoSystemThunks* system_thunks) { + if (system_thunks->size >= sizeof(g_thunks)) + g_thunks = *system_thunks; + return sizeof(g_thunks); +} + +} // extern "C" diff --git a/chromium/mojo/public/platform/native/system_thunks.h b/chromium/mojo/public/platform/native/system_thunks.h new file mode 100644 index 00000000000..de82eba1bfc --- /dev/null +++ b/chromium/mojo/public/platform/native/system_thunks.h @@ -0,0 +1,137 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_PUBLIC_PLATFORM_NATIVE_SYSTEM_THUNKS_H_ +#define MOJO_PUBLIC_PLATFORM_NATIVE_SYSTEM_THUNKS_H_ + +#include <stddef.h> + +#include "mojo/public/c/system/core.h" + +// The embedder needs to bind the basic Mojo Core functions of a DSO to those of +// the embedder when loading a DSO that is dependent on mojo_system. +// The typical usage would look like: +// base::ScopedNativeLibrary app_library( +// base::LoadNativeLibrary(app_path_, &error)); +// typedef MojoResult (*MojoSetSystemThunksFn)(MojoSystemThunks*); +// MojoSetSystemThunksFn mojo_set_system_thunks_fn = +// reinterpret_cast<MojoSetSystemThunksFn>(app_library.GetFunctionPointer( +// "MojoSetSystemThunks")); +// MojoSystemThunks system_thunks = MojoMakeSystemThunks(); +// size_t expected_size = mojo_set_system_thunks_fn(&system_thunks); +// if (expected_size > sizeof(MojoSystemThunks)) { +// LOG(ERROR) +// << "Invalid DSO. Expected MojoSystemThunks size: " +// << expected_size; +// break; +// } + +// Structure used to bind the basic Mojo Core functions of a DSO to those of +// the embedder. +// This is the ABI between the embedder and the DSO. It can only have new +// functions added to the end. No other changes are supported. +#pragma pack(push, 8) +struct MojoSystemThunks { + size_t size; // Should be set to sizeof(MojoSystemThunks). + MojoTimeTicks (*GetTimeTicksNow)(); + MojoResult (*Close)(MojoHandle handle); + MojoResult (*Wait)(MojoHandle handle, + MojoHandleSignals signals, + MojoDeadline deadline); + MojoResult (*WaitMany)(const MojoHandle* handles, + const MojoHandleSignals* signals, + uint32_t num_handles, + MojoDeadline deadline); + MojoResult (*CreateMessagePipe)(const MojoCreateMessagePipeOptions* options, + MojoHandle* message_pipe_handle0, + MojoHandle* message_pipe_handle1); + MojoResult (*WriteMessage)(MojoHandle message_pipe_handle, + const void* bytes, + uint32_t num_bytes, + const MojoHandle* handles, + uint32_t num_handles, + MojoWriteMessageFlags flags); + MojoResult (*ReadMessage)(MojoHandle message_pipe_handle, + void* bytes, + uint32_t* num_bytes, + MojoHandle* handles, + uint32_t* num_handles, + MojoReadMessageFlags flags); + MojoResult (*CreateDataPipe)(const MojoCreateDataPipeOptions* options, + MojoHandle* data_pipe_producer_handle, + MojoHandle* data_pipe_consumer_handle); + MojoResult (*WriteData)(MojoHandle data_pipe_producer_handle, + const void* elements, + uint32_t* num_elements, + MojoWriteDataFlags flags); + MojoResult (*BeginWriteData)(MojoHandle data_pipe_producer_handle, + void** buffer, + uint32_t* buffer_num_elements, + MojoWriteDataFlags flags); + MojoResult (*EndWriteData)(MojoHandle data_pipe_producer_handle, + uint32_t num_elements_written); + MojoResult (*ReadData)(MojoHandle data_pipe_consumer_handle, + void* elements, + uint32_t* num_elements, + MojoReadDataFlags flags); + MojoResult (*BeginReadData)(MojoHandle data_pipe_consumer_handle, + const void** buffer, + uint32_t* buffer_num_elements, + MojoReadDataFlags flags); + MojoResult (*EndReadData)(MojoHandle data_pipe_consumer_handle, + uint32_t num_elements_read); + MojoResult (*CreateSharedBuffer)( + const MojoCreateSharedBufferOptions* options, + uint64_t num_bytes, + MojoHandle* shared_buffer_handle); + MojoResult (*DuplicateBufferHandle)( + MojoHandle buffer_handle, + const MojoDuplicateBufferHandleOptions* options, + MojoHandle* new_buffer_handle); + MojoResult (*MapBuffer)(MojoHandle buffer_handle, + uint64_t offset, + uint64_t num_bytes, + void** buffer, + MojoMapBufferFlags flags); + MojoResult (*UnmapBuffer)(void* buffer); +}; +#pragma pack(pop) + +// Intended to be called from the embedder. Returns a |MojoCore| initialized +// to contain pointers to each of the embedder's MojoCore functions. +inline MojoSystemThunks MojoMakeSystemThunks() { + MojoSystemThunks system_thunks = { + sizeof(MojoSystemThunks), + MojoGetTimeTicksNow, + MojoClose, + MojoWait, + MojoWaitMany, + MojoCreateMessagePipe, + MojoWriteMessage, + MojoReadMessage, + MojoCreateDataPipe, + MojoWriteData, + MojoBeginWriteData, + MojoEndWriteData, + MojoReadData, + MojoBeginReadData, + MojoEndReadData, + MojoCreateSharedBuffer, + MojoDuplicateBufferHandle, + MojoMapBuffer, + MojoUnmapBuffer + }; + return system_thunks; +} + +// Use this type for the function found by dynamically discovering it in +// a DSO linked with mojo_system. For example: +// MojoSetSystemThunksFn mojo_set_system_thunks_fn = +// reinterpret_cast<MojoSetSystemThunksFn>(app_library.GetFunctionPointer( +// "MojoSetSystemThunks")); +// The expected size of |system_thunks} is returned. +// The contents of |system_thunks| are copied. +typedef size_t (*MojoSetSystemThunksFn)(const MojoSystemThunks* system_thunks); + +#endif // MOJO_PUBLIC_PLATFORM_NATIVE_SYSTEM_THUNKS_H_ diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/enum_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/enum_declaration.tmpl new file mode 100644 index 00000000000..bc2a097b098 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/enum_declaration.tmpl @@ -0,0 +1,9 @@ +enum {{enum.name}} { +{%- for field in enum.fields %} +{%- if field.value %} + {{field.name}} = {{field.value|expression_to_text}}, +{%- else %} + {{field.name}}, +{%- endif %} +{%- endfor %} +}; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl new file mode 100644 index 00000000000..30d20d8993e --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl @@ -0,0 +1,49 @@ +{%- import "interface_macros.tmpl" as interface_macros %} +class {{interface.name}}Proxy; +class {{interface.name}}Stub; + +class {{interface.name}}RequestValidator; +{%- if interface|has_callbacks %} +class {{interface.name}}ResponseValidator; +{%- endif %} +{% if interface.client %} +class {{interface.client}}; +{% endif %} + +class {{interface.name}} { + public: + static const char* Name_; + + typedef {{interface.name}}Proxy Proxy_; + typedef {{interface.name}}Stub Stub_; + + typedef {{interface.name}}RequestValidator RequestValidator_; +{%- if interface|has_callbacks %} + typedef {{interface.name}}ResponseValidator ResponseValidator_; +{%- else %} + typedef mojo::PassThroughFilter ResponseValidator_; +{%- endif %} +{% if interface.client %} + typedef {{interface.client}} Client; +{% else %} + typedef mojo::NoInterface Client; +{% endif %} + +{#--- Constants #} +{%- for constant in interface.constants %} + static const {{constant.kind|cpp_pod_type}} {{constant.name}}; +{%- endfor %} + +{#--- Enums #} +{%- for enum in interface.enums %} +{% macro enum_def() %}{% include "enum_declaration.tmpl" %}{% endmacro %} + {{enum_def()|indent(2)}} +{%- endfor %} + +{#--- Methods #} + virtual ~{{interface.name}}() {} + +{%- for method in interface.methods %} + virtual void {{method.name}}({{interface_macros.declare_request_params("", method)}}) = 0; +{%- endfor %} +}; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl new file mode 100644 index 00000000000..9b6a3249e55 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl @@ -0,0 +1,315 @@ +{%- import "interface_macros.tmpl" as interface_macros %} +{%- set class_name = interface.name %} +{%- set proxy_name = interface.name ~ "Proxy" %} +{%- set namespace_as_string = "%s"|format(namespace|replace(".","::")) %} + +{%- macro alloc_params(parameters) %} +{%- for param in parameters %} +{%- if param.kind|is_object_kind %} +{{param.kind|cpp_result_type}} p{{loop.index}}; +Deserialize_(params->{{param.name}}.ptr, &p{{loop.index}}); +{% endif -%} +{%- endfor %} +{%- endmacro %} + +{%- macro pass_params(parameters) %} +{%- for param in parameters %} +{%- if param.kind|is_string_kind -%} +p{{loop.index}} +{%- elif param.kind|is_object_kind -%} +p{{loop.index}}.Pass() +{%- elif param.kind|is_interface_kind -%} +mojo::MakeProxy<{{param.kind|get_name_for_kind}}>(mojo::MakeScopedHandle(mojo::internal::FetchAndReset(¶ms->{{param.name}}))) +{%- elif param.kind|is_interface_request_kind -%} +mojo::MakeRequest<{{param.kind.kind|get_name_for_kind}}>(mojo::MakeScopedHandle(mojo::internal::FetchAndReset(¶ms->{{param.name}}))) +{%- elif param.kind|is_handle_kind -%} +mojo::MakeScopedHandle(mojo::internal::FetchAndReset(¶ms->{{param.name}})) +{%- elif param.kind|is_enum_kind -%} +static_cast<{{param.kind|cpp_wrapper_type}}>(params->{{param.name}}) +{%- else -%} +params->{{param.name}} +{%- endif -%} +{%- if not loop.last %}, {% endif %} +{%- endfor %} +{%- endmacro %} + +{%- macro compute_payload_size(params_name, parameters) -%} + size_t payload_size = + mojo::internal::Align(sizeof({{params_name}})); +{#--- Computes #} +{%- for param in parameters %} +{%- if param.kind|is_object_kind %} + payload_size += GetSerializedSize_(in_{{param.name}}); +{%- endif %} +{%- endfor %} +{%- endmacro %} + +{%- macro build_message(params_name, parameters) -%} + {{params_name}}* params = + {{params_name}}::New(builder.buffer()); +{#--- Sets #} +{% for param in parameters %} +{%- if param.kind|is_object_kind %} + Serialize_(mojo::internal::Forward(in_{{param.name}}), builder.buffer(), ¶ms->{{param.name}}.ptr); +{%- elif param.kind|is_interface_kind %} + if (!in_{{param.name}}.get()) { + params->{{param.name}} = mojo::MessagePipeHandle(); + } else { + // Delegate handle. + params->{{param.name}} = in_{{param.name}}.PassMessagePipe().release(); + } +{%- elif param.kind|is_interface_request_kind %} + // Delegate handle. + params->{{param.name}} = in_{{param.name}}.PassMessagePipe().release(); +{%- elif param.kind|is_handle_kind %} + params->{{param.name}} = in_{{param.name}}.release(); +{%- else %} + params->{{param.name}} = in_{{param.name}}; +{%- endif %} +{%- endfor %} + mojo::Message message; + params->EncodePointersAndHandles(message.mutable_handles()); + builder.Finish(&message); +{%- endmacro %} + +{#--- Begin #} +const char* {{class_name}}::Name_ = "{{namespace_as_string}}::{{class_name}}"; +{#--- Constants #} +{% for constant in interface.constants %} +const {{constant.kind|cpp_pod_type}} {{interface.name}}::{{constant.name}} = {{constant.value|expression_to_text}}; +{%- endfor %} + +{#--- ForwardToCallback definition #} +{%- for method in interface.methods -%} +{%- if method.response_parameters != None %} +class {{class_name}}_{{method.name}}_ForwardToCallback + : public mojo::MessageReceiver { + public: + {{class_name}}_{{method.name}}_ForwardToCallback( + const {{interface_macros.declare_callback(method)}}& callback) + : callback_(callback) { + } + virtual bool Accept(mojo::Message* message) MOJO_OVERRIDE; + private: + {{interface_macros.declare_callback(method)}} callback_; + MOJO_DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ForwardToCallback); +}; +bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept( + mojo::Message* message) { + internal::{{class_name}}_{{method.name}}_ResponseParams_Data* params = + reinterpret_cast<internal::{{class_name}}_{{method.name}}_ResponseParams_Data*>( + message->mutable_payload()); + + params->DecodePointersAndHandles(message->mutable_handles()); + {{alloc_params(method.response_parameters)|indent(2)}} + callback_.Run({{pass_params(method.response_parameters)}}); + return true; +} +{%- endif %} +{%- endfor %} + +{{proxy_name}}::{{proxy_name}}(mojo::MessageReceiverWithResponder* receiver) + : receiver_(receiver) { +} + +{#--- Proxy definitions #} + +{%- for method in interface.methods %} +{%- set message_name = + "internal::k%s_%s_Name"|format(interface.name, method.name) %} +{%- set params_name = + "internal::%s_%s_Params_Data"|format(interface.name, method.name) %} +void {{proxy_name}}::{{method.name}}( + {{interface_macros.declare_request_params("in_", method)}}) { + {{compute_payload_size(params_name, method.parameters)}} + +{%- if method.response_parameters != None %} + mojo::internal::RequestMessageBuilder builder({{message_name}}, payload_size); +{%- else %} + mojo::internal::MessageBuilder builder({{message_name}}, payload_size); +{%- endif %} + + {{build_message(params_name, method.parameters)}} + +{%- if method.response_parameters != None %} + mojo::MessageReceiver* responder = + new {{class_name}}_{{method.name}}_ForwardToCallback(callback); + if (!receiver_->AcceptWithResponder(&message, responder)) + delete responder; +{%- else %} + bool ok MOJO_ALLOW_UNUSED = receiver_->Accept(&message); + // This return value may be ignored as !ok implies the Connector has + // encountered an error, which will be visible through other means. +{%- endif %} +} +{%- endfor %} + +{#--- ProxyToResponder definition #} +{%- for method in interface.methods -%} +{%- if method.response_parameters != None %} +{%- set message_name = + "internal::k%s_%s_Name"|format(interface.name, method.name) %} +{%- set params_name = + "internal::%s_%s_ResponseParams_Data"|format(interface.name, method.name) %} +class {{class_name}}_{{method.name}}_ProxyToResponder + : public {{interface_macros.declare_callback(method)}}::Runnable { + public: + virtual ~{{class_name}}_{{method.name}}_ProxyToResponder() { + delete responder_; + } + + {{class_name}}_{{method.name}}_ProxyToResponder( + uint64_t request_id, + mojo::MessageReceiver* responder) + : request_id_(request_id), + responder_(responder) { + } + + virtual void Run({{interface_macros.declare_params("in_", method.response_parameters)}}) const; + + private: + uint64_t request_id_; + mutable mojo::MessageReceiver* responder_; + MOJO_DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ProxyToResponder); +}; +void {{class_name}}_{{method.name}}_ProxyToResponder::Run( + {{interface_macros.declare_params("in_", method.response_parameters)}}) const { + {{compute_payload_size(params_name, method.response_parameters)}} + mojo::internal::ResponseMessageBuilder builder( + {{message_name}}, payload_size, request_id_); + {{build_message(params_name, method.response_parameters)}} + bool ok MOJO_ALLOW_UNUSED = responder_->Accept(&message); + // TODO(darin): !ok returned here indicates a malformed message, and that may + // be good reason to close the connection. However, we don't have a way to do + // that from here. We should add a way. + delete responder_; + responder_ = NULL; +} +{%- endif -%} +{%- endfor %} + +{{class_name}}Stub::{{class_name}}Stub() + : sink_(NULL) { +} + +{#--- Stub definition #} + +bool {{class_name}}Stub::Accept(mojo::Message* message) { +{%- if interface.methods %} + switch (message->header()->name) { +{%- for method in interface.methods %} + case internal::k{{class_name}}_{{method.name}}_Name: { +{%- if method.response_parameters == None %} + internal::{{class_name}}_{{method.name}}_Params_Data* params = + reinterpret_cast<internal::{{class_name}}_{{method.name}}_Params_Data*>( + message->mutable_payload()); + + params->DecodePointersAndHandles(message->mutable_handles()); + {{alloc_params(method.parameters)|indent(6)}} + sink_->{{method.name}}({{pass_params(method.parameters)}}); + return true; +{%- else %} + break; +{%- endif %} + } +{%- endfor %} + } +{%- endif %} + return false; +} + +bool {{class_name}}Stub::AcceptWithResponder( + mojo::Message* message, mojo::MessageReceiver* responder) { +{%- if interface.methods %} + switch (message->header()->name) { +{%- for method in interface.methods %} + case internal::k{{class_name}}_{{method.name}}_Name: { +{%- if method.response_parameters != None %} + internal::{{class_name}}_{{method.name}}_Params_Data* params = + reinterpret_cast<internal::{{class_name}}_{{method.name}}_Params_Data*>( + message->mutable_payload()); + + params->DecodePointersAndHandles(message->mutable_handles()); + {{interface_macros.declare_callback(method)}}::Runnable* runnable = + new {{class_name}}_{{method.name}}_ProxyToResponder( + message->request_id(), responder); + {{interface_macros.declare_callback(method)}} callback(runnable); + {{alloc_params(method.parameters)|indent(6)}} + sink_->{{method.name}}( +{%- if method.parameters -%}{{pass_params(method.parameters)}}, {% endif -%}callback); + return true; +{%- else %} + break; +{%- endif %} + } +{%- endfor %} + } +{%- endif %} + return false; +} + +{#--- Request validator definitions #} + +{{class_name}}RequestValidator::{{class_name}}RequestValidator( + mojo::MessageReceiver* sink) : MessageFilter(sink) { +} + +bool {{class_name}}RequestValidator::Accept(mojo::Message* message) { +{%- if interface.methods %} + switch (message->header()->name) { +{%- for method in interface.methods %} + case internal::k{{class_name}}_{{method.name}}_Name: { +{%- if method.response_parameters != None %} + if (!message->has_flag(mojo::internal::kMessageExpectsResponse)) + break; +{%- else %} + if (message->has_flag(mojo::internal::kMessageExpectsResponse) || + message->has_flag(mojo::internal::kMessageIsResponse)) { + break; + } +{%- endif %} + mojo::internal::BoundsChecker bounds_checker( + message->payload(), message->payload_num_bytes(), + message->handles()->size()); + if (!internal::{{class_name}}_{{method.name}}_Params_Data::Validate( + message->payload(), &bounds_checker)) { + return false; + } + break; + } +{%- endfor %} + } +{%- endif %} + + return sink_->Accept(message); +} + +{#--- Response validator definitions #} +{% if interface|has_callbacks %} +{{class_name}}ResponseValidator::{{class_name}}ResponseValidator( + mojo::MessageReceiver* sink) : MessageFilter(sink) { +} + +bool {{class_name}}ResponseValidator::Accept(mojo::Message* message) { +{%- if interface.methods %} + switch (message->header()->name) { +{%- for method in interface.methods if method.response_parameters != None %} + case internal::k{{class_name}}_{{method.name}}_Name: { + if (!message->has_flag(mojo::internal::kMessageIsResponse)) + break; + mojo::internal::BoundsChecker bounds_checker( + message->payload(), message->payload_num_bytes(), + message->handles()->size()); + if (!internal::{{class_name}}_{{method.name}}_ResponseParams_Data::Validate( + message->payload(), &bounds_checker)) { + return false; + } + break; + } +{%- endfor %} + } +{%- endif %} + + return sink_->Accept(message); +} +{%- endif -%} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl new file mode 100644 index 00000000000..fbefce2d397 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl @@ -0,0 +1,23 @@ +{%- macro declare_params(prefix, parameters) %} +{%- for param in parameters -%} +{{param.kind|cpp_const_wrapper_type}} {{prefix}}{{param.name}} +{%- if not loop.last %}, {% endif %} +{%- endfor %} +{%- endmacro %} + +{%- macro declare_callback(method) -%} +mojo::Callback<void( +{%- for param in method.response_parameters -%} +{{param.kind|cpp_result_type}} +{%- if not loop.last %}, {% endif %} +{%- endfor -%} +)> +{%- endmacro -%} + +{%- macro declare_request_params(prefix, method) -%} +{{declare_params(prefix, method.parameters)}} +{%- if method.response_parameters != None -%} +{%- if method.parameters %}, {% endif %} +const {{declare_callback(method)}}& callback +{%- endif -%} +{%- endmacro -%} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl new file mode 100644 index 00000000000..9451118a438 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl @@ -0,0 +1,14 @@ +{%- import "interface_macros.tmpl" as interface_macros %} +class {{interface.name}}Proxy : public {{interface.name}} { + public: + explicit {{interface.name}}Proxy(mojo::MessageReceiverWithResponder* receiver); + +{%- for method in interface.methods %} + virtual void {{method.name}}( + {{interface_macros.declare_request_params("", method)}} + ) MOJO_OVERRIDE; +{%- endfor %} + + private: + mojo::MessageReceiverWithResponder* receiver_; +}; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl new file mode 100644 index 00000000000..63c60ee2db8 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl @@ -0,0 +1,6 @@ +class {{interface.name}}RequestValidator : public mojo::MessageFilter { + public: + explicit {{interface.name}}RequestValidator(mojo::MessageReceiver* sink = NULL); + + virtual bool Accept(mojo::Message* message) MOJO_OVERRIDE; +}; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl new file mode 100644 index 00000000000..0719060c155 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl @@ -0,0 +1,6 @@ +class {{interface.name}}ResponseValidator : public mojo::MessageFilter { + public: + explicit {{interface.name}}ResponseValidator(mojo::MessageReceiver* sink = NULL); + + virtual bool Accept(mojo::Message* message) MOJO_OVERRIDE; +}; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl new file mode 100644 index 00000000000..25b28ec777a --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl @@ -0,0 +1,14 @@ +class {{interface.name}}Stub : public mojo::MessageReceiverWithResponder { + public: + {{interface.name}}Stub(); + void set_sink({{interface.name}}* sink) { sink_ = sink; } + {{interface.name}}* sink() { return sink_; } + + virtual bool Accept(mojo::Message* message) MOJO_OVERRIDE; + virtual bool AcceptWithResponder(mojo::Message* message, + mojo::MessageReceiver* responder) + MOJO_OVERRIDE; + + private: + {{interface.name}}* sink_; +}; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl new file mode 100644 index 00000000000..f0cf33b560b --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl @@ -0,0 +1,49 @@ +// 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. + +{%- set header_guard = "%s_INTERNAL_H_"| + format(module.path|upper|replace("/","_")|replace(".","_")) %} + +#ifndef {{header_guard}} +#define {{header_guard}} + +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" +#include "mojo/public/cpp/bindings/lib/buffer.h" + +{%- for import in imports %} +#include "{{import.module.path}}-internal.h" +{%- endfor %} + +namespace mojo { +namespace internal { +class BoundsChecker; +} +} + +{%- for namespace in namespaces_as_array %} +namespace {{namespace}} { +{%- endfor %} + +{#--- Wrapper forward declarations #} +{% for struct in structs %} +class {{struct.name}}; +{%- endfor %} + +namespace internal { + +#pragma pack(push, 1) + +{#--- Class declarations #} +{% for struct in structs %} +{% include "struct_declaration.tmpl" %} +{%- endfor %} + +#pragma pack(pop) + +} // namespace internal +{%- for namespace in namespaces_as_array|reverse %} +} // namespace {{namespace}} +{%- endfor %} + +#endif // {{header_guard}} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl new file mode 100644 index 00000000000..8cf8e99713c --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl @@ -0,0 +1,86 @@ +// 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. + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif + +#include "{{module.path}}.h" + +#include "mojo/public/cpp/bindings/lib/array_serialization.h" +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" +#include "mojo/public/cpp/bindings/lib/bounds_checker.h" +#include "mojo/public/cpp/bindings/lib/message_builder.h" +#include "mojo/public/cpp/bindings/lib/string_serialization.h" +#include "mojo/public/cpp/bindings/lib/validation_errors.h" + +{%- for namespace in namespaces_as_array %} +namespace {{namespace}} { +{%- endfor %} + +{#--- Constants #} +{% for constant in module.constants %} +const {{constant.kind|cpp_pod_type}} {{constant.name}} = {{constant.value|expression_to_text}}; +{%- endfor %} + +namespace internal { +namespace { + +#pragma pack(push, 1) + +{#--- Interface parameter definitions #} +{%- for interface in interfaces %} +{%- for method in interface.methods %} +{%- set method_name = "k%s_%s_Name"|format(interface.name, method.name) %} +const uint32_t {{method_name}} = {{method.ordinal}}; +{% set struct = method|struct_from_method %} +{%- include "params_definition.tmpl" %} +{%- if method.response_parameters != None %} +{%- set struct = method|response_struct_from_method %} +{%- include "params_definition.tmpl" %} +{%- endif %} +{%- endfor %} +{%- endfor %} + +#pragma pack(pop) + +} // namespace + +{#--- Struct definitions #} +{% for struct in structs %} +{%- include "struct_definition.tmpl" %} +{%- endfor %} + +} // namespace internal + +{#--- Struct Constants #} +{%- for struct in structs %} +{% for constant in struct.constants %} +const {{constant.kind|cpp_pod_type}} {{struct.name}}::{{constant.name}} = {{constant.value|expression_to_text}}; +{%- endfor %} +{%- endfor %} + +{#--- Struct builder definitions #} +{%- for struct in structs %} +{%- include "wrapper_class_definition.tmpl" %} +{%- endfor %} + +{#--- Interface definitions #} +{%- for interface in interfaces %} +{%- include "interface_definition.tmpl" %} +{%- endfor %} + +{#--- Struct Serialization Helpers #} +{%- for struct in structs %} +{%- include "struct_serialization_definition.tmpl" %} +{%- endfor %} + +{%- for namespace in namespaces_as_array|reverse %} +} // namespace {{namespace}} +{%- endfor %} + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl new file mode 100644 index 00000000000..4e21d4774bd --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl @@ -0,0 +1,108 @@ +// 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. + +{%- set header_guard = "%s_H_"| + format(module.path|upper|replace("/","_")|replace(".","_")) %} + +#ifndef {{header_guard}} +#define {{header_guard}} + +#include "mojo/public/cpp/bindings/array.h" +#include "mojo/public/cpp/bindings/callback.h" +#include "mojo/public/cpp/bindings/interface_impl.h" +#include "mojo/public/cpp/bindings/interface_ptr.h" +#include "mojo/public/cpp/bindings/interface_request.h" +#include "mojo/public/cpp/bindings/message_filter.h" +#include "mojo/public/cpp/bindings/no_interface.h" +#include "mojo/public/cpp/bindings/string.h" +#include "mojo/public/cpp/bindings/struct_ptr.h" +#include "{{module.path}}-internal.h" +{%- for import in imports %} +#include "{{import.module.path}}.h" +{%- endfor %} + +{%- for namespace in namespaces_as_array %} +namespace {{namespace}} { +{%- endfor %} + +{#--- Constants #} +{% for constant in module.constants %} +extern const {{constant.kind|cpp_pod_type}} {{constant.name}}; +{%- endfor %} + +{#--- Enums #} +{% for enum in enums %} +{% include "enum_declaration.tmpl" %} +{%- endfor %} + +{#--- Interface Forward Declarations -#} +{% for interface in interfaces %} +class {{interface.name}}; +typedef mojo::InterfacePtr<{{interface.name}}> {{interface.name}}Ptr; +{% endfor %} + +{#--- Struct Forward Declarations -#} +{% for struct in structs %} +class {{struct.name}}; +{% if struct|should_inline %} +typedef mojo::InlinedStructPtr<{{struct.name}}> {{struct.name}}Ptr; +{% else %} +typedef mojo::StructPtr<{{struct.name}}> {{struct.name}}Ptr; +{% endif %} +{% endfor %} + +{#--- NOTE: Non-inlined structs may have pointers to inlined structs, so we #} +{#--- need to fully define inlined structs ahead of the others. #} + +{#--- Inlined structs #} +{% for struct in structs %} +{% if struct|should_inline %} +{% include "wrapper_class_declaration.tmpl" %} +{% endif %} +{%- endfor %} + +{#--- Non-inlined structs #} +{% for struct in structs %} +{% if not struct|should_inline %} +{% include "wrapper_class_declaration.tmpl" %} +{% endif %} +{%- endfor %} + +{#--- Interfaces -#} +{% for interface in interfaces %} +{% include "interface_declaration.tmpl" %} +{%- endfor %} + +{#--- Interface Proxies -#} +{% for interface in interfaces %} +{% include "interface_proxy_declaration.tmpl" %} +{%- endfor %} + +{#--- Interface Stubs -#} +{% for interface in interfaces %} +{% include "interface_stub_declaration.tmpl" %} +{%- endfor %} + +{#--- Interface Request Validators -#} +{% for interface in interfaces %} +{% include "interface_request_validator_declaration.tmpl" %} +{%- endfor %} + +{#--- Interface Response Validators -#} +{% for interface in interfaces if interface|has_callbacks %} +{% include "interface_response_validator_declaration.tmpl" %} +{%- endfor %} + +{#--- Struct Serialization Helpers -#} +{% if structs %} +{% for struct in structs %} +{% include "struct_serialization_declaration.tmpl" %} +{%- endfor %} +{%- endif %} + +{%- for namespace in namespaces_as_array|reverse %} +} // namespace {{namespace}} +{%- endfor %} + +#endif // {{header_guard}} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl new file mode 100644 index 00000000000..0b1104719bb --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl @@ -0,0 +1,33 @@ +{%- import "struct_macros.tmpl" as struct_macros %} +{%- set class_name = struct.name ~ "_Data" %} +class {{class_name}} { + public: + static {{class_name}}* New(mojo::internal::Buffer* buf) { + return new (buf->Allocate(sizeof({{class_name}}))) + {{class_name}}(); + } + + static bool Validate(const void* data, + mojo::internal::BoundsChecker* bounds_checker) { + {{ struct_macros.validate(struct, class_name)|indent(4) }} + } + + mojo::internal::StructHeader header_; +{{struct_macros.fields(struct)}} + + void EncodePointersAndHandles(std::vector<mojo::Handle>* handles) { + {{ struct_macros.encodes(struct)|indent(4) }} + } + + void DecodePointersAndHandles(std::vector<mojo::Handle>* handles) { + {{ struct_macros.decodes(struct)|indent(4) }} + } + + private: + {{class_name}}() { + header_.num_bytes = sizeof(*this); + header_.num_fields = {{struct.packed.packed_fields|length}}; + } +}; +MOJO_COMPILE_ASSERT(sizeof({{class_name}}) == {{struct.packed|struct_size}}, + bad_sizeof_{{class_name}}); diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl new file mode 100644 index 00000000000..60a6a9e6d3e --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl @@ -0,0 +1,22 @@ +{%- import "struct_macros.tmpl" as struct_macros %} +{%- set class_name = struct.name ~ "_Data" -%} + +class {{class_name}} { + public: + static {{class_name}}* New(mojo::internal::Buffer* buf); + + static bool Validate(const void* data, + mojo::internal::BoundsChecker* bounds_checker); + + mojo::internal::StructHeader header_; +{{struct_macros.fields(struct)}} + + void EncodePointersAndHandles(std::vector<mojo::Handle>* handles); + void DecodePointersAndHandles(std::vector<mojo::Handle>* handles); + + private: + {{class_name}}(); + ~{{class_name}}(); // NOT IMPLEMENTED +}; +MOJO_COMPILE_ASSERT(sizeof({{class_name}}) == {{struct.packed|struct_size}}, + bad_sizeof_{{class_name}}); diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl new file mode 100644 index 00000000000..461f158602b --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl @@ -0,0 +1,28 @@ +{%- import "struct_macros.tmpl" as struct_macros %} +{%- set class_name = struct.name ~ "_Data" %} + +// static +{{class_name}}* {{class_name}}::New(mojo::internal::Buffer* buf) { + return new (buf->Allocate(sizeof({{class_name}}))) {{class_name}}(); +} + +// static +bool {{class_name}}::Validate(const void* data, + mojo::internal::BoundsChecker* bounds_checker) { + {{ struct_macros.validate(struct, class_name)|indent(2) }} +} + +{{class_name}}::{{class_name}}() { + header_.num_bytes = sizeof(*this); + header_.num_fields = {{struct.packed.packed_fields|length}}; +} + +void {{class_name}}::EncodePointersAndHandles( + std::vector<mojo::Handle>* handles) { + {{ struct_macros.encodes(struct)|indent(2) }} +} + +void {{class_name}}::DecodePointersAndHandles( + std::vector<mojo::Handle>* handles) { + {{ struct_macros.decodes(struct)|indent(2) }} +} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl new file mode 100644 index 00000000000..bd05a06de72 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl @@ -0,0 +1,91 @@ +{%- macro validate(struct, class_name) %} + if (!data) + return true; + + if (!ValidateStructHeader( + data, sizeof({{class_name}}), + {{struct.packed.packed_fields|length}}, bounds_checker)) { + return false; + } + + const {{class_name}}* MOJO_ALLOW_UNUSED object = + static_cast<const {{class_name}}*>(data); + +{%- for packed_field in struct.packed.packed_fields %} +{%- set name = packed_field.field.name %} +{%- if packed_field.field.kind|is_object_kind %} +{%- set wrapper_type = packed_field.field.kind|cpp_wrapper_type %} + if (!mojo::internal::ValidateEncodedPointer(&object->{{name}}.offset)) { + ReportValidationError(mojo::internal::VALIDATION_ERROR_ILLEGAL_POINTER); + return false; + } + if (!{{wrapper_type}}::Data_::Validate( + mojo::internal::DecodePointerRaw(&object->{{name}}.offset), + bounds_checker)) { + return false; + } +{%- elif packed_field.field.kind|is_handle_kind %} + if (!bounds_checker->ClaimHandle(object->{{name}})) { + ReportValidationError(mojo::internal::VALIDATION_ERROR_ILLEGAL_HANDLE); + return false; + } +{%- endif %} +{%- endfor %} + + return true; +{%- endmacro %} + +{%- macro field_line(field) %} +{%- set type = field.kind|cpp_field_type %} +{%- set name = field.name -%} +{%- if field.kind.spec == 'b' -%} + uint8_t {{name}} : 1; +{%- elif field.kind|is_enum_kind -%} + int32_t {{name}}; +{%- else -%} + {{type}} {{name}}; +{%- endif %} +{%- endmacro %} + +{%- macro fields(struct) %} +{%- for packed_field in struct.packed.packed_fields %} + {{field_line(packed_field.field)}} +{%- if not loop.last %} +{%- set next_pf = struct.packed.packed_fields[loop.index0 + 1] %} +{%- set pad = next_pf.offset - (packed_field.offset + packed_field.size) %} +{%- if pad > 0 %} + uint8_t pad{{loop.index0}}_[{{pad}}]; +{%- endif %} +{%- endif %} +{%- endfor -%} + +{%- set num_fields = struct.packed.packed_fields|length %} +{%- if num_fields > 0 %} +{%- set last_field = struct.packed.packed_fields[num_fields - 1] %} +{%- set offset = last_field.offset + last_field.size %} +{%- set pad = offset|get_pad(8) -%} +{%- if pad > 0 %} + uint8_t padfinal_[{{pad}}]; +{%- endif %} +{%- endif %} +{%- endmacro %} + +{%- macro encodes(struct) -%} +{%- for pf in struct.packed.packed_fields %} +{%- if pf.field.kind|is_object_kind %} +mojo::internal::Encode(&{{pf.field.name}}, handles); +{%- elif pf.field.kind|is_handle_kind %} +mojo::internal::EncodeHandle(&{{pf.field.name}}, handles); +{%- endif %} +{%- endfor %} +{%- endmacro -%} + +{%- macro decodes(struct) -%} +{%- for pf in struct.packed.packed_fields %} +{%- if pf.field.kind|is_object_kind %} +mojo::internal::Decode(&{{pf.field.name}}, handles); +{%- elif pf.field.kind|is_handle_kind %} +mojo::internal::DecodeHandle(&{{pf.field.name}}, handles); +{%- endif %} +{%- endfor %} +{%- endmacro -%} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl new file mode 100644 index 00000000000..604be86c7e2 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl @@ -0,0 +1,5 @@ +size_t GetSerializedSize_(const {{struct.name}}Ptr& input); +void Serialize_({{struct.name}}Ptr input, mojo::internal::Buffer* buffer, + internal::{{struct.name}}_Data** output); +void Deserialize_(internal::{{struct.name}}_Data* input, + {{struct.name}}Ptr* output); diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl new file mode 100644 index 00000000000..aec2afa93e5 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl @@ -0,0 +1,51 @@ +size_t GetSerializedSize_(const {{struct.name}}Ptr& input) { + if (!input) + return 0; + size_t size = sizeof(internal::{{struct.name}}_Data); +{%- for pf in struct.packed.packed_fields if pf.field.kind|is_object_kind %} + size += GetSerializedSize_(input->{{pf.field.name}}); +{%- endfor %} + return size; +} + +void Serialize_({{struct.name}}Ptr input, mojo::internal::Buffer* buf, + internal::{{struct.name}}_Data** output) { + if (input) { + internal::{{struct.name}}_Data* result = + internal::{{struct.name}}_Data::New(buf); +{%- for pf in struct.packed.packed_fields %} +{%- if pf.field.kind|is_object_kind %} + Serialize_(mojo::internal::Forward(input->{{pf.field.name}}), buf, &result->{{pf.field.name}}.ptr); +{%- elif pf.field.kind|is_handle_kind %} + result->{{pf.field.name}} = input->{{pf.field.name}}.release(); +{%- else %} + result->{{pf.field.name}} = input->{{pf.field.name}}; +{%- endif %} +{%- endfor %} + *output = result; + } else { + *output = NULL; + } +} + +void Deserialize_(internal::{{struct.name}}_Data* input, + {{struct.name}}Ptr* output) { + if (input) { + {{struct.name}}Ptr result({{struct.name}}::New()); +{%- for pf in struct.packed.packed_fields %} +{%- if pf.field.kind|is_object_kind %} + Deserialize_(input->{{pf.field.name}}.ptr, &result->{{pf.field.name}}); +{%- elif pf.field.kind|is_handle_kind %} + result->{{pf.field.name}}.reset(mojo::internal::FetchAndReset(&input->{{pf.field.name}})); +{%- elif pf.field.kind|is_enum_kind %} + result->{{pf.field.name}} = static_cast<{{pf.field.kind|cpp_wrapper_type}}>( + input->{{pf.field.name}}); +{%- else %} + result->{{pf.field.name}} = input->{{pf.field.name}}; +{%- endif %} +{%- endfor %} + *output = result.Pass(); + } else { + output->reset(); + } +} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl new file mode 100644 index 00000000000..0e01976ce61 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl @@ -0,0 +1,31 @@ + +class {{struct.name}} { + public: + typedef internal::{{struct.name}}_Data Data_; + +{#--- Constants #} +{%- for constant in struct.constants %} + static const {{constant.kind|cpp_pod_type}} {{constant.name}}; +{%- endfor %} +{#--- Enums #} +{%- for enum in struct.enums -%} +{% macro enum_def() %}{% include "enum_declaration.tmpl" %}{% endmacro %} + {{enum_def()|indent(2)}} +{%- endfor %} + static {{struct.name}}Ptr New(); + + template <typename U> + static {{struct.name}}Ptr From(const U& u) { + return mojo::TypeConverter<{{struct.name}}Ptr, U>::ConvertFrom(u); + } + + {{struct.name}}(); + ~{{struct.name}}(); + +{#--- Getters #} +{% for field in struct.fields %} +{%- set type = field.kind|cpp_wrapper_type %} +{%- set name = field.name %} + {{type}} {{name}}; +{%- endfor %} +}; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl new file mode 100644 index 00000000000..29bdd8eeb95 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl @@ -0,0 +1,15 @@ +// static +{{struct.name}}Ptr {{struct.name}}::New() { + {{struct.name}}Ptr rv; + mojo::internal::StructHelper<{{struct.name}}>::Initialize(&rv); + return rv.Pass(); +} + +{{struct.name}}::{{struct.name}}() +{%-for field in struct.fields %} + {% if loop.first %}:{% else %} {% endif %} {{field.name}}({{field|default_value}}){% if not loop.last %},{% endif %} +{%- endfor %} { +} + +{{struct.name}}::~{{struct.name}}() { +} diff --git a/chromium/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl new file mode 100644 index 00000000000..f69f657d314 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl @@ -0,0 +1,5 @@ +{% from "java_macros.tmpl" import build_default %} + +{% macro constant_def(constant) %} +public static final {{constant.kind|java_type}} {{constant|name}} = {{build_default(module, constant.kind, constant.value)|indent(4)}}; +{% endmacro %} diff --git a/chromium/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl b/chromium/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl new file mode 100644 index 00000000000..0a4e29956b6 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl @@ -0,0 +1,12 @@ +{% from "constant_definition.tmpl" import constant_def %} +{% include "header.java.tmpl" %} + +public final class {{main_entity}} { +{% for constant in constants %} + + {{constant_def(constant)|indent(4)}} +{% endfor %} + + private {{main_entity}}() {} + +} diff --git a/chromium/mojo/public/tools/bindings/generators/java_templates/enum.java.tmpl b/chromium/mojo/public/tools/bindings/generators/java_templates/enum.java.tmpl new file mode 100644 index 00000000000..7096a18747f --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/java_templates/enum.java.tmpl @@ -0,0 +1,4 @@ +{% from "enum_definition.tmpl" import enum_def %} +{% include "header.java.tmpl" %} + +{{enum_def(enum, true)}} diff --git a/chromium/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl new file mode 100644 index 00000000000..d72bd7ff4a7 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl @@ -0,0 +1,21 @@ +{%- macro enum_value(enum, field, index) -%} +{%- if field.value -%} +(int) ({{field.value|expression_to_text}}) +{%- elif index == 0 -%} +0 +{%- else -%} +{{enum.fields[index - 1].name}} + 1 +{%- endif -%} +{%- endmacro -%} + +{%- macro enum_def(enum, top_level) -%} +public {{ 'static ' if not top_level }}final class {{enum|name}} { + +{% for field in enum.fields %} + public static final int {{field.name}} = {{enum_value(enum, field, loop.index0)}}; +{% endfor %} + + private {{enum|name}}() {} + +} +{%- endmacro -%} diff --git a/chromium/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl b/chromium/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl new file mode 100644 index 00000000000..ec6a88b1474 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl @@ -0,0 +1,11 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is autogenerated by: +// mojo/public/tools/bindings/mojom_bindings_generator.py +// For: +// {{module.path}} +// + +package {{package}}; diff --git a/chromium/mojo/public/tools/bindings/generators/java_templates/java_macros.tmpl b/chromium/mojo/public/tools/bindings/generators/java_templates/java_macros.tmpl new file mode 100644 index 00000000000..d7339f5a420 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/java_templates/java_macros.tmpl @@ -0,0 +1,3 @@ +{% macro build_default(module, kind, value) %} +({{kind|java_type}}) {{value|expression_to_text}} +{% endmacro %} diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl new file mode 100644 index 00000000000..795116d8dd9 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl @@ -0,0 +1,14 @@ +{%- macro enum_def(enum_name, enum, module) -%} + {{enum_name}} = {}; + +{%- set prev_enum = 0 %} +{%- for field in enum.fields %} +{%- if field.value %} + {{enum_name}}.{{field.name}} = {{field.value|expression_to_text}}; +{%- elif loop.first %} + {{enum_name}}.{{field.name}} = 0; +{%- else %} + {{enum_name}}.{{field.name}} = {{enum_name}}.{{enum.fields[loop.index0 - 1].name}} + 1; +{%- endif %} +{%- endfor %} +{%- endmacro %} diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl new file mode 100644 index 00000000000..d46f8eeac9c --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl @@ -0,0 +1,122 @@ +{%- set namespace_as_string = namespace|replace(".","::") %} +{%- for method in interface.methods %} + var k{{interface.name}}_{{method.name}}_Name = {{method.ordinal}}; +{%- endfor %} + + function {{interface.name}}Proxy(receiver) { + this.receiver_ = receiver; + } + + {{interface.name}}Proxy.NAME_ = '{{namespace_as_string}}::{{interface.name}}'; + +{%- for method in interface.methods %} + {{interface.name}}Proxy.prototype.{{method.name|stylize_method}} = function( +{%- for parameter in method.parameters -%} +{{parameter.name}}{% if not loop.last %}, {% endif %} +{%- endfor -%} +) { + var params = new {{interface.name}}_{{method.name}}_Params(); +{%- for parameter in method.parameters %} + params.{{parameter.name}} = {{parameter.name}}; +{%- endfor %} + +{%- if method.response_parameters == None %} + var builder = new codec.MessageBuilder( + k{{interface.name}}_{{method.name}}_Name, + codec.align({{interface.name}}_{{method.name}}_Params.encodedSize)); + builder.encodeStruct({{interface.name}}_{{method.name}}_Params, params); + var message = builder.finish(); + this.receiver_.accept(message); +{%- else %} + return new Promise(function(resolve, reject) { + var builder = new codec.MessageWithRequestIDBuilder( + k{{interface.name}}_{{method.name}}_Name, + codec.align({{interface.name}}_{{method.name}}_Params.encodedSize), + codec.kMessageExpectsResponse, 0); + builder.encodeStruct({{interface.name}}_{{method.name}}_Params, params); + var message = builder.finish(); + this.receiver_.acceptWithResponder(message, { + accept: function(message) { + var reader = new codec.MessageReader(message); + var responseParams = + reader.decodeStruct({{interface.name}}_{{method.name}}_ResponseParams); + resolve(responseParams); + }, + reject: function(result) { + reject(Error("Connection error: " + result)); + }, + }).catch(reject); + }.bind(this)); +{%- endif %} + }; +{%- endfor %} + + function {{interface.name}}Stub() { + } + + {{interface.name}}Stub.NAME_ = '{{namespace_as_string}}::{{interface.name}}'; + + {{interface.name}}Stub.prototype.accept = function(message) { + var reader = new codec.MessageReader(message); + switch (reader.messageName) { +{%- for method in interface.methods %} +{%- if method.response_parameters == None %} + case k{{interface.name}}_{{method.name}}_Name: + var params = reader.decodeStruct({{interface.name}}_{{method.name}}_Params); + this.{{method.name|stylize_method}}( +{%- for parameter in method.parameters -%} +params.{{parameter.name}}{% if not loop.last %}, {% endif %} +{%- endfor %}); + return true; +{%- endif %} +{%- endfor %} + default: + return false; + } + }; + + {{interface.name}}Stub.prototype.acceptWithResponder = + function(message, responder) { + var reader = new codec.MessageReader(message); + switch (reader.messageName) { +{%- for method in interface.methods %} +{%- if method.response_parameters != None %} + case k{{interface.name}}_{{method.name}}_Name: + var params = reader.decodeStruct({{interface.name}}_{{method.name}}_Params); + return this.{{method.name|stylize_method}}( +{%- for parameter in method.parameters -%} +params.{{parameter.name}}{% if not loop.last %}, {% endif -%} +{%- endfor %}).then(function(response) { + var responseParams = + new {{interface.name}}_{{method.name}}_ResponseParams(); +{%- for parameter in method.response_parameters %} + responseParams.{{parameter.name}} = response.{{parameter.name}}; +{%- endfor %} + var builder = new codec.MessageWithRequestIDBuilder( + k{{interface.name}}_{{method.name}}_Name, + codec.align({{interface.name}}_{{method.name}}_ResponseParams.encodedSize), + codec.kMessageIsResponse, reader.requestID); + builder.encodeStruct({{interface.name}}_{{method.name}}_ResponseParams, + responseParams); + var message = builder.finish(); + responder.accept(message); + }); +{%- endif %} +{%- endfor %} + default: + return Promise.reject(Error("Unhandled message: " + reader.messageName)); + } + }; + +{#--- Enums #} +{% from "enum_definition.tmpl" import enum_def -%} +{% for enum in interface.enums %} + {{enum_def("%sProxy.%s"|format(interface.name, enum.name), enum, module)}} + {{interface.name}}Stub.{{enum.name}} = {{interface.name}}Proxy.{{enum.name}}; +{%- endfor %} + +{#--- Constants. #} +{% for constant in interface.constants %} + {{interface.name}}Proxy.{{constant.name}} = {{constant.value|expression_to_text}}; + {{interface.name}}Stub.{{constant.name}} = {{interface.name}}Proxy.{{constant.name}}; +{% endfor %} diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/module.js.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/module.js.tmpl new file mode 100644 index 00000000000..db570cd79df --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/js_templates/module.js.tmpl @@ -0,0 +1,52 @@ +// 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. + +define("{{module.path}}", [ + "mojo/public/js/bindings/codec", +{%- for import in imports %} + "{{import.module.path}}", +{%- endfor %} + ], function(codec +{%- for import in imports -%} + , {{import.unique_name}} +{%- endfor -%} +) { + +{#--- Constants #} +{% for constant in module.constants %} + var {{constant.name}} = {{constant.value|expression_to_text}}; +{%- endfor %} + +{#--- Enums #} +{%- from "enum_definition.tmpl" import enum_def %} +{%- for enum in enums %} + var {{ enum_def(enum.name, enum, module) }} +{%- endfor %} + +{#--- Struct definitions #} +{% for struct in structs %} +{%- include "struct_definition.tmpl" %} +{%- endfor %} + +{#--- Interface definitions #} +{%- for interface in interfaces %} +{%- include "interface_definition.tmpl" %} +{%- endfor %} + + var exports = {}; +{% for constant in module.constants %} + exports.{{constant.name}} = {{constant.name}}; +{%- endfor %} +{%- for enum in enums %} + exports.{{enum.name}} = {{enum.name}}; +{%- endfor %} +{%- for struct in structs if struct.exported %} + exports.{{struct.name}} = {{struct.name}}; +{%- endfor %} +{%- for interface in interfaces %} + exports.{{interface.name}}Proxy = {{interface.name}}Proxy; + exports.{{interface.name}}Stub = {{interface.name}}Stub; +{%- endfor %} + return exports; +}); diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl new file mode 100644 index 00000000000..ae1ccb079af --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl @@ -0,0 +1,72 @@ +{#--- Begin #} + function {{struct.name}}() { + this.initDefaults_(); + } + +{#--- Enums #} +{%- from "enum_definition.tmpl" import enum_def %} +{% for enum in struct.enums %} + {{enum_def("%s.%s"|format(struct.name, enum.name), enum, module)}} +{% endfor %} + +{#--- Constants #} +{% for constant in struct.constants %} + {{struct.name}}.{{constant.name}} = {{constant.value|expression_to_text}}; +{% endfor %} + +{#--- Set up defaults #} + {{struct.name}}.prototype.initDefaults_ = function() { +{%- for packed_field in struct.packed.packed_fields %} + this.{{packed_field.field.name}} = {{packed_field.field|default_value}}; +{%- endfor %} + }; + +{#--- Encoding and decoding #} + + {{struct.name}}.encodedSize = codec.kStructHeaderSize + {{struct.packed|payload_size}}; + + {{struct.name}}.decode = function(decoder) { + var packed; + var val = new {{struct.name}}(); + var numberOfBytes = decoder.readUint32(); + var numberOfFields = decoder.readUint32(); +{%- for byte in struct.bytes %} +{%- if byte.packed_fields|length > 1 %} + packed = decoder.readUint8(); +{%- for packed_field in byte.packed_fields %} + val.{{packed_field.field.name}} = (packed >> {{packed_field.bit}}) & 1 ? true : false; +{%- endfor %} +{%- else %} +{%- for packed_field in byte.packed_fields %} + val.{{packed_field.field.name}} = decoder.{{packed_field.field.kind|decode_snippet}}; +{%- endfor %} +{%- endif %} +{%- if byte.is_padding %} + decoder.skip(1); +{%- endif %} +{%- endfor %} + return val; + }; + + {{struct.name}}.encode = function(encoder, val) { + var packed; + encoder.writeUint32({{struct.name}}.encodedSize); + encoder.writeUint32({{struct.packed.packed_fields|length}}); + +{%- for byte in struct.bytes %} +{%- if byte.packed_fields|length > 1 %} + packed = 0; +{%- for packed_field in byte.packed_fields %} + packed |= (val.{{packed_field.field.name}} & 1) << {{packed_field.bit}} +{%- endfor %} + encoder.writeUint8(packed); +{%- else %} +{%- for packed_field in byte.packed_fields %} + encoder.{{packed_field.field.kind|encode_snippet}}val.{{packed_field.field.name}}); +{%- endfor %} +{%- endif %} +{%- if byte.is_padding %} + encoder.skip(1); +{%- endif %} +{%- endfor %} + }; diff --git a/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py new file mode 100644 index 00000000000..812dd47c609 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py @@ -0,0 +1,286 @@ +# 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. + +"""Generates C++ source files from a mojom.Module.""" + +import mojom.generate.generator as generator +import mojom.generate.module as mojom +import mojom.generate.pack as pack +from mojom.generate.template_expander import UseJinja + + +_kind_to_cpp_type = { + mojom.BOOL: "bool", + mojom.INT8: "int8_t", + mojom.UINT8: "uint8_t", + mojom.INT16: "int16_t", + mojom.UINT16: "uint16_t", + mojom.INT32: "int32_t", + mojom.UINT32: "uint32_t", + mojom.FLOAT: "float", + mojom.HANDLE: "mojo::Handle", + mojom.DCPIPE: "mojo::DataPipeConsumerHandle", + mojom.DPPIPE: "mojo::DataPipeProducerHandle", + mojom.MSGPIPE: "mojo::MessagePipeHandle", + mojom.SHAREDBUFFER: "mojo::SharedBufferHandle", + mojom.INT64: "int64_t", + mojom.UINT64: "uint64_t", + mojom.DOUBLE: "double", +} + +def DefaultValue(field): + if field.default: + if isinstance(field.kind, mojom.Struct): + assert field.default == "default" + return "%s::New()" % GetNameForKind(field.kind) + return ExpressionToText(field.default) + return "" + +def NamespaceToArray(namespace): + return namespace.split('.') if namespace else [] + +def GetNameForKind(kind, internal = False): + parts = [] + if kind.imported_from: + parts.extend(NamespaceToArray(kind.imported_from["namespace"])) + if internal: + parts.append("internal") + if kind.parent_kind: + parts.append(kind.parent_kind.name) + parts.append(kind.name) + return "::".join(parts) + +def GetCppType(kind): + if isinstance(kind, mojom.Struct): + return "%s_Data*" % GetNameForKind(kind, internal=True) + if isinstance(kind, mojom.Array): + return "mojo::internal::Array_Data<%s>*" % GetCppType(kind.kind) + if isinstance(kind, mojom.Interface) or \ + isinstance(kind, mojom.InterfaceRequest): + return "mojo::MessagePipeHandle" + if isinstance(kind, mojom.Enum): + return "int32_t" + if kind.spec == 's': + return "mojo::internal::String_Data*" + return _kind_to_cpp_type[kind] + +def GetCppPodType(kind): + if kind.spec == 's': + return "char*" + return _kind_to_cpp_type[kind] + +def GetCppArrayArgWrapperType(kind): + if isinstance(kind, mojom.Enum): + return GetNameForKind(kind) + if isinstance(kind, mojom.Struct): + return "%sPtr" % GetNameForKind(kind) + if isinstance(kind, mojom.Array): + return "mojo::Array<%s> " % GetCppArrayArgWrapperType(kind.kind) + if isinstance(kind, mojom.Interface): + raise Exception("Arrays of interfaces not yet supported!") + if isinstance(kind, mojom.InterfaceRequest): + raise Exception("Arrays of interface requests not yet supported!") + if kind.spec == 's': + return "mojo::String" + if kind.spec == 'h': + return "mojo::ScopedHandle" + if kind.spec == 'h:d:c': + return "mojo::ScopedDataPipeConsumerHandle" + if kind.spec == 'h:d:p': + return "mojo::ScopedDataPipeProducerHandle" + if kind.spec == 'h:m': + return "mojo::ScopedMessagePipeHandle" + if kind.spec == 'h:s': + return "mojo::ScopedSharedBufferHandle" + return _kind_to_cpp_type[kind] + +def GetCppResultWrapperType(kind): + if isinstance(kind, mojom.Enum): + return GetNameForKind(kind) + if isinstance(kind, mojom.Struct): + return "%sPtr" % GetNameForKind(kind) + if isinstance(kind, mojom.Array): + return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind) + if isinstance(kind, mojom.Interface): + return "%sPtr" % GetNameForKind(kind) + if isinstance(kind, mojom.InterfaceRequest): + return "mojo::InterfaceRequest<%s>" % GetNameForKind(kind.kind) + if kind.spec == 's': + return "mojo::String" + if kind.spec == 'h': + return "mojo::ScopedHandle" + if kind.spec == 'h:d:c': + return "mojo::ScopedDataPipeConsumerHandle" + if kind.spec == 'h:d:p': + return "mojo::ScopedDataPipeProducerHandle" + if kind.spec == 'h:m': + return "mojo::ScopedMessagePipeHandle" + if kind.spec == 'h:s': + return "mojo::ScopedSharedBufferHandle" + return _kind_to_cpp_type[kind] + +def GetCppWrapperType(kind): + if isinstance(kind, mojom.Enum): + return GetNameForKind(kind) + if isinstance(kind, mojom.Struct): + return "%sPtr" % GetNameForKind(kind) + if isinstance(kind, mojom.Array): + return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind) + if isinstance(kind, mojom.Interface): + return "mojo::ScopedMessagePipeHandle" + if isinstance(kind, mojom.InterfaceRequest): + raise Exception("InterfaceRequest fields not supported!") + if kind.spec == 's': + return "mojo::String" + if kind.spec == 'h': + return "mojo::ScopedHandle" + if kind.spec == 'h:d:c': + return "mojo::ScopedDataPipeConsumerHandle" + if kind.spec == 'h:d:p': + return "mojo::ScopedDataPipeProducerHandle" + if kind.spec == 'h:m': + return "mojo::ScopedMessagePipeHandle" + if kind.spec == 'h:s': + return "mojo::ScopedSharedBufferHandle" + return _kind_to_cpp_type[kind] + +def GetCppConstWrapperType(kind): + if isinstance(kind, mojom.Struct): + return "%sPtr" % GetNameForKind(kind) + if isinstance(kind, mojom.Array): + return "mojo::Array<%s>" % GetCppArrayArgWrapperType(kind.kind) + if isinstance(kind, mojom.Interface): + return "%sPtr" % GetNameForKind(kind) + if isinstance(kind, mojom.InterfaceRequest): + return "mojo::InterfaceRequest<%s>" % GetNameForKind(kind.kind) + if isinstance(kind, mojom.Enum): + return GetNameForKind(kind) + if kind.spec == 's': + return "const mojo::String&" + if kind.spec == 'h': + return "mojo::ScopedHandle" + if kind.spec == 'h:d:c': + return "mojo::ScopedDataPipeConsumerHandle" + if kind.spec == 'h:d:p': + return "mojo::ScopedDataPipeProducerHandle" + if kind.spec == 'h:m': + return "mojo::ScopedMessagePipeHandle" + if kind.spec == 'h:s': + return "mojo::ScopedSharedBufferHandle" + if not kind in _kind_to_cpp_type: + print "missing:", kind.spec + return _kind_to_cpp_type[kind] + +def GetCppFieldType(kind): + if isinstance(kind, mojom.Struct): + return ("mojo::internal::StructPointer<%s_Data>" % + GetNameForKind(kind, internal=True)) + if isinstance(kind, mojom.Array): + return "mojo::internal::ArrayPointer<%s>" % GetCppType(kind.kind) + if isinstance(kind, mojom.Interface) or \ + isinstance(kind, mojom.InterfaceRequest): + return "mojo::MessagePipeHandle" + if isinstance(kind, mojom.Enum): + return GetNameForKind(kind) + if kind.spec == 's': + return "mojo::internal::StringPointer" + return _kind_to_cpp_type[kind] + +def IsStructWithHandles(struct): + for pf in struct.packed.packed_fields: + if generator.IsHandleKind(pf.field.kind): + return True + return False + +def TranslateConstants(token): + if isinstance(token, (mojom.NamedValue, mojom.EnumValue)): + # Both variable and enum constants are constructed like: + # Namespace::Struct::CONSTANT_NAME + name = [] + if token.imported_from: + name.extend(NamespaceToArray(token.namespace)) + if token.parent_kind: + name.append(token.parent_kind.name) + name.append(token.name) + return "::".join(name) + return token + +def ExpressionToText(value): + return TranslateConstants(value) + +def HasCallbacks(interface): + for method in interface.methods: + if method.response_parameters != None: + return True + return False + +def ShouldInlineStruct(struct): + # TODO(darin): Base this on the size of the wrapper class. + if len(struct.fields) > 4: + return False + for field in struct.fields: + if generator.IsHandleKind(field.kind) or generator.IsObjectKind(field.kind): + return False + return True + +_HEADER_SIZE = 8 + +class Generator(generator.Generator): + + cpp_filters = { + "cpp_const_wrapper_type": GetCppConstWrapperType, + "cpp_field_type": GetCppFieldType, + "cpp_pod_type": GetCppPodType, + "cpp_result_type": GetCppResultWrapperType, + "cpp_type": GetCppType, + "cpp_wrapper_type": GetCppWrapperType, + "default_value": DefaultValue, + "expression_to_text": ExpressionToText, + "get_name_for_kind": GetNameForKind, + "get_pad": pack.GetPad, + "has_callbacks": HasCallbacks, + "should_inline": ShouldInlineStruct, + "is_enum_kind": generator.IsEnumKind, + "is_move_only_kind": generator.IsMoveOnlyKind, + "is_handle_kind": generator.IsHandleKind, + "is_interface_kind": generator.IsInterfaceKind, + "is_interface_request_kind": generator.IsInterfaceRequestKind, + "is_object_kind": generator.IsObjectKind, + "is_string_kind": generator.IsStringKind, + "is_struct_with_handles": IsStructWithHandles, + "struct_size": lambda ps: ps.GetTotalSize() + _HEADER_SIZE, + "struct_from_method": generator.GetStructFromMethod, + "response_struct_from_method": generator.GetResponseStructFromMethod, + "stylize_method": generator.StudlyCapsToCamel, + } + + def GetJinjaExports(self): + return { + "module": self.module, + "namespace": self.module.namespace, + "namespaces_as_array": NamespaceToArray(self.module.namespace), + "imports": self.module.imports, + "kinds": self.module.kinds, + "enums": self.module.enums, + "structs": self.GetStructs(), + "interfaces": self.module.interfaces, + } + + @UseJinja("cpp_templates/module.h.tmpl", filters=cpp_filters) + def GenerateModuleHeader(self): + return self.GetJinjaExports() + + @UseJinja("cpp_templates/module-internal.h.tmpl", filters=cpp_filters) + def GenerateModuleInternalHeader(self): + return self.GetJinjaExports() + + @UseJinja("cpp_templates/module.cc.tmpl", filters=cpp_filters) + def GenerateModuleSource(self): + return self.GetJinjaExports() + + def GenerateFiles(self, args): + self.Write(self.GenerateModuleHeader(), "%s.h" % self.module.name) + self.Write(self.GenerateModuleInternalHeader(), + "%s-internal.h" % self.module.name) + self.Write(self.GenerateModuleSource(), "%s.cc" % self.module.name) diff --git a/chromium/mojo/public/tools/bindings/generators/mojom_java_generator.py b/chromium/mojo/public/tools/bindings/generators/mojom_java_generator.py new file mode 100644 index 00000000000..ca43b845630 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/mojom_java_generator.py @@ -0,0 +1,187 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Generates java source files from a mojom.Module.""" + +import argparse +import os +import re + +import mojom.generate.generator as generator +import mojom.generate.module as mojom +from mojom.generate.template_expander import UseJinja + + +GENERATOR_PREFIX = 'java' + +_spec_to_java_type = { + 'b': 'boolean', + 'd': 'double', + 'f': 'float', + 'h:d:c': 'org.chromium.mojo.system.DataPipe.ConsumerHandle', + 'h:d:p': 'org.chromium.mojo.system.DataPipe.ProducerHandle', + 'h:m': 'org.chromium.mojo.system.MessagePipeHandle', + 'h': 'org.chromium.mojo.system.UntypedHandle', + 'h:s': 'org.chromium.mojo.system.SharedBufferHandle', + 'i16': 'short', + 'i32': 'int', + 'i64': 'long', + 'i8': 'byte', + 's': 'String', + 'u16': 'short', + 'u32': 'int', + 'u64': 'long', + 'u8': 'byte', +} + + +def NameToComponent(name): + # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar -> + # HTTP_Entry2_FooBar) + name = re.sub('([^_])([A-Z][^A-Z_]+)', r'\1_\2', name) + # insert '_' between non upper and start of upper blocks (e.g., + # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar) + name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name) + return [x.lower() for x in name.split('_')] + +def CapitalizeFirst(string): + return string[0].upper() + string[1:] + +def UpperCamelCase(name): + return ''.join([CapitalizeFirst(x) for x in NameToComponent(name)]) + +def CamelCase(name): + uccc = UpperCamelCase(name) + return uccc[0].lower() + uccc[1:] + +def ConstantStyle(name): + components = NameToComponent(name) + if components[0] == 'k': + components = components[1:] + return '_'.join([x.upper() for x in components]) + +def GetNameForElement(element): + if (isinstance(element, mojom.Enum) or + isinstance(element, mojom.Interface) or + isinstance(element, mojom.Struct)): + return UpperCamelCase(element.name) + if (isinstance(element, mojom.Method) or + isinstance(element, mojom.Parameter) or + isinstance(element, mojom.Field)): + return CamelCase(element.name) + if isinstance(element, mojom.EnumValue): + return (UpperCamelCase(element.enum_name) + '.' + + ConstantStyle(element.name)) + if (isinstance(element, mojom.NamedValue) or + isinstance(element, mojom.Constant)): + return ConstantStyle(element.name) + raise Exception("Unexpected element: " % element) + +def ParseStringAttribute(attribute): + assert isinstance(attribute, basestring) + return attribute + +def GetPackage(module): + if 'JavaPackage' in module.attributes: + return ParseStringAttribute(module.attributes['JavaPackage']) + # Default package. + return "org.chromium.mojom." + module.namespace + +def GetNameForKind(kind): + def _GetNameHierachy(kind): + hierachy = [] + if kind.parent_kind: + hierachy = _GetNameHierachy(kind.parent_kind) + hierachy.append(kind.name) + return hierachy + + elements = [GetPackage(kind.module)] + elements += _GetNameHierachy(kind) + return '.'.join(elements) + +def GetJavaType(kind): + if isinstance(kind, (mojom.Struct, mojom.Interface)): + return GetNameForKind(kind) + if isinstance(kind, mojom.Array): + return "%s[]" % GetJavaType(kind.kind) + if isinstance(kind, mojom.Enum): + return "int" + return _spec_to_java_type[kind.spec] + +def ExpressionToText(token): + def _TranslateNamedValue(named_value): + entity_name = GetNameForElement(named_value) + if named_value.parent_kind: + return GetJavaType(named_value.parent_kind) + '.' + entity_name + # Handle the case where named_value is a module level constant: + if not isinstance(named_value, mojom.EnumValue): + entity_name = (GetConstantsMainEntityName(named_value.module) + '.' + + entity_name) + return GetPackage(named_value.module) + '.' + entity_name + + if isinstance(token, mojom.NamedValue): + return _TranslateNamedValue(token) + # Add Long suffix to all number literals. + if re.match('^[0-9]+$', token): + return token + 'L' + return token + +def GetConstantsMainEntityName(module): + if 'JavaConstantsClassName' in module.attributes: + return ParseStringAttribute(module.attributes['JavaConstantsClassName']) + # This constructs the name of the embedding classes for module level constants + # by extracting the mojom's filename and prepending it to Constants. + return (UpperCamelCase(module.path.split('/')[-1].rsplit('.', 1)[0]) + + 'Constants') + +class Generator(generator.Generator): + + java_filters = { + "expression_to_text": ExpressionToText, + "java_type": GetJavaType, + "name": GetNameForElement, + } + + def GetJinjaExports(self): + return { + "module": self.module, + "package": GetPackage(self.module), + } + + @UseJinja("java_templates/enum.java.tmpl", filters=java_filters, + lstrip_blocks=True, trim_blocks=True) + def GenerateEnumSource(self, enum): + exports = self.GetJinjaExports() + exports.update({"enum": enum}) + return exports + + @UseJinja("java_templates/constants.java.tmpl", filters=java_filters, + lstrip_blocks=True, trim_blocks=True) + def GenerateConstantsSource(self, module): + exports = self.GetJinjaExports() + exports.update({"main_entity": GetConstantsMainEntityName(module), + "constants": module.constants}) + return exports + + def GenerateFiles(self, unparsed_args): + parser = argparse.ArgumentParser() + parser.add_argument("--java_output_directory", dest="java_output_directory") + args = parser.parse_args(unparsed_args) + if self.output_dir and args.java_output_directory: + self.output_dir = os.path.join(args.java_output_directory, + GetPackage(self.module).replace('.', '/')) + if not os.path.exists(self.output_dir): + try: + os.makedirs(self.output_dir) + except: + # Ignore errors on directory creation. + pass + + for enum in self.module.enums: + self.Write(self.GenerateEnumSource(enum), + "%s.java" % GetNameForElement(enum)) + + if self.module.constants: + self.Write(self.GenerateConstantsSource(self.module), + "%s.java" % GetConstantsMainEntityName(self.module)) diff --git a/chromium/mojo/public/tools/bindings/generators/mojom_js_generator.py b/chromium/mojo/public/tools/bindings/generators/mojom_js_generator.py new file mode 100644 index 00000000000..1fa351037c6 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/mojom_js_generator.py @@ -0,0 +1,186 @@ +# 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. + +"""Generates JavaScript source files from a mojom.Module.""" + +import mojom.generate.generator as generator +import mojom.generate.module as mojom +import mojom.generate.pack as pack +from mojom.generate.template_expander import UseJinja + +_kind_to_javascript_default_value = { + mojom.BOOL: "false", + mojom.INT8: "0", + mojom.UINT8: "0", + mojom.INT16: "0", + mojom.UINT16: "0", + mojom.INT32: "0", + mojom.UINT32: "0", + mojom.FLOAT: "0", + mojom.HANDLE: "null", + mojom.DCPIPE: "null", + mojom.DPPIPE: "null", + mojom.MSGPIPE: "null", + mojom.SHAREDBUFFER: "null", + mojom.INT64: "0", + mojom.UINT64: "0", + mojom.DOUBLE: "0", + mojom.STRING: '""', +} + + +def JavaScriptDefaultValue(field): + if field.default: + if isinstance(field.kind, mojom.Struct): + assert field.default == "default" + return "new %s()" % JavascriptType(field.kind) + return ExpressionToText(field.default) + if field.kind in mojom.PRIMITIVES: + return _kind_to_javascript_default_value[field.kind] + if isinstance(field.kind, mojom.Struct): + return "null" + if isinstance(field.kind, mojom.Array): + return "[]" + if isinstance(field.kind, mojom.Interface) or \ + isinstance(field.kind, mojom.InterfaceRequest): + return _kind_to_javascript_default_value[mojom.MSGPIPE] + if isinstance(field.kind, mojom.Enum): + return "0" + + +def JavaScriptPayloadSize(packed): + packed_fields = packed.packed_fields + if not packed_fields: + return 0 + last_field = packed_fields[-1] + offset = last_field.offset + last_field.size + pad = pack.GetPad(offset, 8) + return offset + pad + + +_kind_to_codec_type = { + mojom.BOOL: "codec.Uint8", + mojom.INT8: "codec.Int8", + mojom.UINT8: "codec.Uint8", + mojom.INT16: "codec.Int16", + mojom.UINT16: "codec.Uint16", + mojom.INT32: "codec.Int32", + mojom.UINT32: "codec.Uint32", + mojom.FLOAT: "codec.Float", + mojom.HANDLE: "codec.Handle", + mojom.DCPIPE: "codec.Handle", + mojom.DPPIPE: "codec.Handle", + mojom.MSGPIPE: "codec.Handle", + mojom.SHAREDBUFFER: "codec.Handle", + mojom.INT64: "codec.Int64", + mojom.UINT64: "codec.Uint64", + mojom.DOUBLE: "codec.Double", + mojom.STRING: "codec.String", +} + + +def CodecType(kind): + if kind in mojom.PRIMITIVES: + return _kind_to_codec_type[kind] + if isinstance(kind, mojom.Struct): + return "new codec.PointerTo(%s)" % CodecType(kind.name) + if isinstance(kind, mojom.Array): + return "new codec.ArrayOf(%s)" % CodecType(kind.kind) + if isinstance(kind, mojom.Interface) or \ + isinstance(kind, mojom.InterfaceRequest): + return CodecType(mojom.MSGPIPE) + if isinstance(kind, mojom.Enum): + return _kind_to_codec_type[mojom.INT32] + return kind + + +def JavaScriptDecodeSnippet(kind): + if kind in mojom.PRIMITIVES: + return "decodeStruct(%s)" % CodecType(kind) + if isinstance(kind, mojom.Struct): + return "decodeStructPointer(%s)" % CodecType(kind.name) + if isinstance(kind, mojom.Array): + return "decodeArrayPointer(%s)" % CodecType(kind.kind) + if isinstance(kind, mojom.Interface) or \ + isinstance(kind, mojom.InterfaceRequest): + return JavaScriptDecodeSnippet(mojom.MSGPIPE) + if isinstance(kind, mojom.Enum): + return JavaScriptDecodeSnippet(mojom.INT32) + + +def JavaScriptEncodeSnippet(kind): + if kind in mojom.PRIMITIVES: + return "encodeStruct(%s, " % CodecType(kind) + if isinstance(kind, mojom.Struct): + return "encodeStructPointer(%s, " % CodecType(kind.name) + if isinstance(kind, mojom.Array): + return "encodeArrayPointer(%s, " % CodecType(kind.kind) + if isinstance(kind, mojom.Interface) or \ + isinstance(kind, mojom.InterfaceRequest): + return JavaScriptEncodeSnippet(mojom.MSGPIPE) + if isinstance(kind, mojom.Enum): + return JavaScriptEncodeSnippet(mojom.INT32) + + +def TranslateConstants(token): + if isinstance(token, (mojom.EnumValue, mojom.NamedValue)): + # Both variable and enum constants are constructed like: + # NamespaceUid.Struct[.Enum].CONSTANT_NAME + name = [] + if token.imported_from: + name.append(token.imported_from["unique_name"]) + if token.parent_kind: + name.append(token.parent_kind.name) + if isinstance(token, mojom.EnumValue): + name.append(token.enum_name) + name.append(token.name) + return ".".join(name) + return token + + +def ExpressionToText(value): + return TranslateConstants(value) + + +def JavascriptType(kind): + if kind.imported_from: + return kind.imported_from["unique_name"] + "." + kind.name + return kind.name + + +class Generator(generator.Generator): + + js_filters = { + "default_value": JavaScriptDefaultValue, + "payload_size": JavaScriptPayloadSize, + "decode_snippet": JavaScriptDecodeSnippet, + "encode_snippet": JavaScriptEncodeSnippet, + "expression_to_text": ExpressionToText, + "js_type": JavascriptType, + "stylize_method": generator.StudlyCapsToCamel, + } + + @UseJinja("js_templates/module.js.tmpl", filters=js_filters) + def GenerateJsModule(self): + return { + "namespace": self.module.namespace, + "imports": self.GetImports(), + "kinds": self.module.kinds, + "enums": self.module.enums, + "module": self.module, + "structs": self.GetStructs() + self.GetStructsFromMethods(), + "interfaces": self.module.interfaces, + } + + def GenerateFiles(self, args): + self.Write(self.GenerateJsModule(), "%s.js" % self.module.name) + + def GetImports(self): + # Since each import is assigned a variable in JS, they need to have unique + # names. + counter = 1 + for each in self.module.imports: + each["unique_name"] = "import" + str(counter) + counter += 1 + return self.module.imports diff --git a/chromium/mojo/public/tools/bindings/generators/run_cpp_generator.py b/chromium/mojo/public/tools/bindings/generators/run_cpp_generator.py new file mode 100755 index 00000000000..4c6f5974069 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/generators/run_cpp_generator.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# 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. + +import ast +import os +import sys + +script_dir = os.path.dirname(os.path.realpath(__file__)) +sys.path.insert(0, os.path.join(script_dir, os.pardir, "pylib")) + +from mojom.generate.data +import mojom_cpp_generator + +def ReadDict(file): + with open(file, 'r') as f: + s = f.read() + dict = ast.literal_eval(s) + return dict + +dict = ReadDict(sys.argv[1]) +module = mojom.generate.data.ModuleFromData(dict) +dir = None +if len(sys.argv) > 2: + dir = sys.argv[2] +cpp = mojom_cpp_generator.Generator(module, ".", dir) +cpp.GenerateFiles([]) diff --git a/chromium/mojo/public/tools/bindings/mojom.gni b/chromium/mojo/public/tools/bindings/mojom.gni new file mode 100644 index 00000000000..3376abfb6d0 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/mojom.gni @@ -0,0 +1,90 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Generate C++ and JavaScript source files from mojom files. +template("mojom") { + assert(defined(invoker.sources), + "\"sources\" must be defined for the $target_name template.") + + generator_root = "//mojo/public/tools/bindings" + generator_script = "$generator_root/mojom_bindings_generator.py" + generator_sources = [ + generator_script, + "$generator_root/generators/cpp_templates/enum_declaration.tmpl", + "$generator_root/generators/cpp_templates/interface_declaration.tmpl", + "$generator_root/generators/cpp_templates/interface_definition.tmpl", + "$generator_root/generators/cpp_templates/interface_macros.tmpl", + "$generator_root/generators/cpp_templates/interface_proxy_declaration.tmpl", + "$generator_root/generators/cpp_templates/interface_request_validator_declaration.tmpl", + "$generator_root/generators/cpp_templates/interface_response_validator_declaration.tmpl", + "$generator_root/generators/cpp_templates/interface_stub_declaration.tmpl", + "$generator_root/generators/cpp_templates/module.cc.tmpl", + "$generator_root/generators/cpp_templates/module.h.tmpl", + "$generator_root/generators/cpp_templates/module-internal.h.tmpl", + "$generator_root/generators/cpp_templates/params_definition.tmpl", + "$generator_root/generators/cpp_templates/struct_declaration.tmpl", + "$generator_root/generators/cpp_templates/struct_definition.tmpl", + "$generator_root/generators/cpp_templates/struct_serialization_declaration.tmpl", + "$generator_root/generators/cpp_templates/struct_serialization_definition.tmpl", + "$generator_root/generators/cpp_templates/struct_macros.tmpl", + "$generator_root/generators/cpp_templates/wrapper_class_declaration.tmpl", + "$generator_root/generators/cpp_templates/wrapper_class_definition.tmpl", + "$generator_root/generators/js_templates/enum_definition.tmpl", + "$generator_root/generators/js_templates/interface_definition.tmpl", + "$generator_root/generators/js_templates/module.js.tmpl", + "$generator_root/generators/js_templates/struct_definition.tmpl", + "$generator_root/generators/mojom_cpp_generator.py", + "$generator_root/generators/mojom_js_generator.py", + "$generator_root/pylib/mojom/__init__.py", + "$generator_root/pylib/mojom/error.py", + "$generator_root/pylib/mojom/generate/__init__.py", + "$generator_root/pylib/mojom/generate/data.py", + "$generator_root/pylib/mojom/generate/generator.py", + "$generator_root/pylib/mojom/generate/module.py", + "$generator_root/pylib/mojom/generate/pack.py", + "$generator_root/pylib/mojom/generate/template_expander.py", + "$generator_root/pylib/mojom/parse/__init__.py", + "$generator_root/pylib/mojom/parse/ast.py", + "$generator_root/pylib/mojom/parse/lexer.py", + "$generator_root/pylib/mojom/parse/parser.py", + "$generator_root/pylib/mojom/parse/translate.py", + ] + generator_cpp_outputs = [ + "$target_gen_dir/{{source_name_part}}.mojom.cc", + "$target_gen_dir/{{source_name_part}}.mojom.h", + "$target_gen_dir/{{source_name_part}}.mojom-internal.h", + ] + generator_js_outputs = [ + "$target_gen_dir/{{source_name_part}}.mojom.js", + ] + + target_visibility = ":$target_name" + + generator_target_name = target_name + "_generator" + action_foreach(generator_target_name) { + visibility = target_visibility + script = generator_script + source_prereqs = generator_sources + sources = invoker.sources + outputs = generator_cpp_outputs + generator_js_outputs + args = [ + "{{source}}", + "--use_chromium_bundled_pylibs", + "-d", rebase_path("//", root_build_dir), + "-o", rebase_path(target_gen_dir, root_build_dir), + ] + } + + source_set(target_name) { + if (defined(invoker.visibility)) { + visibility = invoker.visibility + } + sources = process_file_template(invoker.sources, generator_cpp_outputs) + data = process_file_template(invoker.sources, generator_js_outputs) + deps = [ + ":$generator_target_name", + "//mojo/public/cpp/bindings", + ] + } +} diff --git a/chromium/mojo/public/tools/bindings/mojom_bindings_generator.gypi b/chromium/mojo/public/tools/bindings/mojom_bindings_generator.gypi new file mode 100644 index 00000000000..1341685a2ee --- /dev/null +++ b/chromium/mojo/public/tools/bindings/mojom_bindings_generator.gypi @@ -0,0 +1,99 @@ +# 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. + +{ + 'rules': [ + { + 'rule_name': 'Generate C++, JS and Java source files from mojom files', + 'extension': 'mojom', + 'variables': { + 'mojom_base_output_dir': + '<!(python <(DEPTH)/build/inverse_depth.py <(DEPTH))', + 'mojom_bindings_generator': + '<(DEPTH)/mojo/public/tools/bindings/mojom_bindings_generator.py', + 'java_out_dir': '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src', + }, + 'inputs': [ + '<(mojom_bindings_generator)', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/enum_declaration.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_request_validator_declaration.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_response_validator_declaration.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/module-internal.h.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/params_definition.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/enum.java.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/java_macros.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/module.js.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_cpp_generator.py', + '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_java_generator.py', + '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_js_generator.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/__init__.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/error.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/__init__.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/data.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/generator.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/module.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/pack.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/__init__.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/ast.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/lexer.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/parser.py', + '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/parse/translate.py', + ], + 'outputs': [ + '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom.cc', + '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom.h', + '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom.js', + '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom-internal.h', + ], + 'action': [ + 'python', '<@(mojom_bindings_generator)', + './<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom', + '--use_chromium_bundled_pylibs', + '-d', '<(DEPTH)', + '-o', '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)', + '--java_output_directory=<(java_out_dir)', + ], + 'message': 'Generating Mojo bindings from <(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom', + 'process_outputs_as_sources': 1, + } + ], + 'include_dirs': [ + '<(DEPTH)', + '<(SHARED_INTERMEDIATE_DIR)', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(DEPTH)', + '<(SHARED_INTERMEDIATE_DIR)', + ], + 'variables': { + 'generated_src_dirs': [ + '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src', + ], + }, + }, + 'hard_dependency': 1, +} diff --git a/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py b/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py new file mode 100755 index 00000000000..93325767b2a --- /dev/null +++ b/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python +# 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. + +"""The frontend for the Mojo bindings system.""" + + +import argparse +import imp +import os +import pprint +import sys + +# Disable lint check for finding modules: +# pylint: disable=F0401 + +def _GetDirAbove(dirname): + """Returns the directory "above" this file containing |dirname| (which must + also be "above" this file).""" + path = os.path.abspath(__file__) + while True: + path, tail = os.path.split(path) + assert tail + if tail == dirname: + return path + +# Manually check for the command-line flag. (This isn't quite right, since it +# ignores, e.g., "--", but it's close enough.) +if "--use_chromium_bundled_pylibs" in sys.argv[1:]: + sys.path.insert(0, os.path.join(_GetDirAbove("mojo"), "third_party")) + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), + "pylib")) + +from mojom.error import Error +from mojom.generate.data import OrderedModuleFromData +from mojom.parse.parser import Parse +from mojom.parse.translate import Translate + + +def LoadGenerators(generators_string): + if not generators_string: + return [] # No generators. + + script_dir = os.path.dirname(os.path.abspath(__file__)) + generators = [] + for generator_name in [s.strip() for s in generators_string.split(",")]: + # "Built-in" generators: + if generator_name.lower() == "c++": + generator_name = os.path.join(script_dir, "generators", + "mojom_cpp_generator.py") + elif generator_name.lower() == "javascript": + generator_name = os.path.join(script_dir, "generators", + "mojom_js_generator.py") + elif generator_name.lower() == "java": + generator_name = os.path.join(script_dir, "generators", + "mojom_java_generator.py") + # Specified generator python module: + elif generator_name.endswith(".py"): + pass + else: + print "Unknown generator name %s" % generator_name + sys.exit(1) + generator_module = imp.load_source(os.path.basename(generator_name)[:-3], + generator_name) + generators.append(generator_module) + return generators + + +def MakeImportStackMessage(imported_filename_stack): + """Make a (human-readable) message listing a chain of imports. (Returned + string begins with a newline (if nonempty) and does not end with one.)""" + return ''.join( + reversed(["\n %s was imported by %s" % (a, b) for (a, b) in \ + zip(imported_filename_stack[1:], imported_filename_stack)])) + + +# Disable check for dangerous default arguments (they're "private" keyword +# arguments; note that we want |_processed_files| to memoize across invocations +# of |ProcessFile()|): +# pylint: disable=W0102 +def ProcessFile(args, remaining_args, generator_modules, filename, + _processed_files={}, _imported_filename_stack=None): + # Memoized results. + if filename in _processed_files: + return _processed_files[filename] + + if _imported_filename_stack is None: + _imported_filename_stack = [] + + # Ensure we only visit each file once. + if filename in _imported_filename_stack: + print "%s: Error: Circular dependency" % filename + \ + MakeImportStackMessage(_imported_filename_stack + [filename]) + sys.exit(1) + + try: + with open(filename) as f: + source = f.read() + except IOError as e: + print "%s: Error: %s" % (e.filename, e.strerror) + \ + MakeImportStackMessage(_imported_filename_stack + [filename]) + sys.exit(1) + + try: + tree = Parse(source, filename) + except Error as e: + print str(e) + MakeImportStackMessage(_imported_filename_stack + [filename]) + sys.exit(1) + + dirname, name = os.path.split(filename) + mojom = Translate(tree, name) + if args.debug_print_intermediate: + pprint.PrettyPrinter().pprint(mojom) + + # Process all our imports first and collect the module object for each. + # We use these to generate proper type info. + for import_data in mojom['imports']: + import_filename = os.path.join(dirname, import_data['filename']) + import_data['module'] = ProcessFile( + args, remaining_args, generator_modules, import_filename, + _processed_files=_processed_files, + _imported_filename_stack=_imported_filename_stack + [filename]) + + module = OrderedModuleFromData(mojom) + + # Set the path as relative to the source root. + module.path = os.path.relpath(os.path.abspath(filename), + os.path.abspath(args.depth)) + + # Normalize to unix-style path here to keep the generators simpler. + module.path = module.path.replace('\\', '/') + + for generator_module in generator_modules: + generator = generator_module.Generator(module, args.output_dir) + filtered_args = [] + if hasattr(generator_module, 'GENERATOR_PREFIX'): + prefix = '--' + generator_module.GENERATOR_PREFIX + '_' + filtered_args = [arg for arg in remaining_args if arg.startswith(prefix)] + generator.GenerateFiles(filtered_args) + + # Save result. + _processed_files[filename] = module + return module +# pylint: enable=W0102 + + +def main(): + parser = argparse.ArgumentParser( + description="Generate bindings from mojom files.") + parser.add_argument("filename", nargs="+", + help="mojom input file") + parser.add_argument("-d", "--depth", dest="depth", default=".", + help="depth from source root") + parser.add_argument("-o", "--output_dir", dest="output_dir", default=".", + help="output directory for generated files") + parser.add_argument("-g", "--generators", dest="generators_string", + metavar="GENERATORS", default="c++,javascript,java", + help="comma-separated list of generators") + parser.add_argument("--debug_print_intermediate", action="store_true", + help="print the intermediate representation") + parser.add_argument("--use_chromium_bundled_pylibs", action="store_true", + help="use Python modules bundled in the Chromium source") + (args, remaining_args) = parser.parse_known_args() + + generator_modules = LoadGenerators(args.generators_string) + + if not os.path.exists(args.output_dir): + os.makedirs(args.output_dir) + + for filename in args.filename: + ProcessFile(args, remaining_args, generator_modules, filename) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/chromium/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py b/chromium/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py new file mode 100644 index 00000000000..de388561cb5 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py @@ -0,0 +1,23 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest + +from mojom_bindings_generator import MakeImportStackMessage + + +class MojoBindingsGeneratorTest(unittest.TestCase): + """Tests mojo_bindings_generator.""" + + def testMakeImportStackMessage(self): + """Tests MakeImportStackMessage().""" + self.assertEquals(MakeImportStackMessage(["x"]), "") + self.assertEquals(MakeImportStackMessage(["x", "y"]), + "\n y was imported by x") + self.assertEquals(MakeImportStackMessage(["x", "y", "z"]), + "\n z was imported by y\n y was imported by x") + + +if __name__ == "__main__": + unittest.main() diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/__init__.py b/chromium/mojo/public/tools/bindings/pylib/mojom/__init__.py new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/__init__.py diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/error.py b/chromium/mojo/public/tools/bindings/pylib/mojom/error.py new file mode 100644 index 00000000000..99522b9507f --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/error.py @@ -0,0 +1,27 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +class Error(Exception): + """Base class for Mojo IDL bindings parser/generator errors.""" + + def __init__(self, filename, message, lineno=None, addenda=None, **kwargs): + """|filename| is the (primary) file which caused the error, |message| is the + error message, |lineno| is the 1-based line number (or |None| if not + applicable/available), and |addenda| is a list of additional lines to append + to the final error message.""" + Exception.__init__(self, **kwargs) + self.filename = filename + self.message = message + self.lineno = lineno + self.addenda = addenda + + def __str__(self): + if self.lineno: + s = "%s:%d: Error: %s" % (self.filename, self.lineno, self.message) + else: + s = "%s: Error: %s" % (self.filename, self.message) + return "\n".join([s] + self.addenda) if self.addenda else s + + def __repr__(self): + return str(self) diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/__init__.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/__init__.py new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/__init__.py diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/data.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/data.py new file mode 100644 index 00000000000..608603b8584 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/data.py @@ -0,0 +1,348 @@ +# 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. + +# TODO(vtl): "data" is a pretty vague name. Rename it? + +import copy + +import module as mojom + +# This module provides a mechanism to turn mojom Modules to dictionaries and +# back again. This can be used to persist a mojom Module created progromatically +# or to read a dictionary from code or a file. +# Example: +# test_dict = { +# 'name': 'test', +# 'namespace': 'testspace', +# 'structs': [{ +# 'name': 'teststruct', +# 'fields': [ +# {'name': 'testfield1', 'kind': 'i32'}, +# {'name': 'testfield2', 'kind': 'a:i32', 'ordinal': 42}]}], +# 'interfaces': [{ +# 'name': 'Server', +# 'methods': [{ +# 'name': 'Foo', +# 'parameters': [{ +# 'name': 'foo', 'kind': 'i32'}, +# {'name': 'bar', 'kind': 'a:x:teststruct'}], +# 'ordinal': 42}]}] +# } +# test_module = data.ModuleFromData(test_dict) + +# Used to create a subclass of str that supports sorting by index, to make +# pretty printing maintain the order. +def istr(index, string): + class IndexedString(str): + def __lt__(self, other): + return self.__index__ < other.__index__ + + istr = IndexedString(string) + istr.__index__ = index + return istr + +def LookupKind(kinds, spec, scope): + """Tries to find which Kind a spec refers to, given the scope in which its + referenced. Starts checking from the narrowest scope to most general. For + example, given a struct field like + Foo.Bar x; + Foo.Bar could refer to the type 'Bar' in the 'Foo' namespace, or an inner + type 'Bar' in the struct 'Foo' in the current namespace. + + |scope| is a tuple that looks like (namespace, struct/interface), referring + to the location where the type is referenced.""" + if spec.startswith('x:'): + name = spec[2:] + for i in xrange(len(scope), -1, -1): + test_spec = 'x:' + if i > 0: + test_spec += '.'.join(scope[:i]) + '.' + test_spec += name + kind = kinds.get(test_spec) + if kind: + return kind + + return kinds.get(spec) + +def LookupValue(values, name, scope): + """Like LookupKind, but for constant values.""" + for i in xrange(len(scope), -1, -1): + if i > 0: + test_spec = '.'.join(scope[:i]) + '.' + test_spec += name + value = values.get(test_spec) + if value: + return value + + return values.get(name) + +def FixupExpression(module, value, scope): + """Translates an IDENTIFIER into a structured Value object.""" + if isinstance(value, tuple) and value[0] == 'IDENTIFIER': + result = LookupValue(module.values, value[1], scope) + if result: + return result + return value + +def KindToData(kind): + return kind.spec + +def KindFromData(kinds, data, scope): + kind = LookupKind(kinds, data, scope) + if kind: + return kind + if data.startswith('a:'): + kind = mojom.Array() + kind.kind = KindFromData(kinds, data[2:], scope) + elif data.startswith('r:'): + kind = mojom.InterfaceRequest() + kind.kind = KindFromData(kinds, data[2:], scope) + else: + kind = mojom.Kind() + kind.spec = data + kinds[data] = kind + return kind + +def KindFromImport(original_kind, imported_from): + """Used with 'import module' - clones the kind imported from the given + module's namespace. Only used with Structs, Interfaces and Enums.""" + kind = copy.deepcopy(original_kind) + kind.imported_from = imported_from + return kind + +def ImportFromData(module, data): + import_module = data['module'] + + import_item = {} + import_item['module_name'] = import_module.name + import_item['namespace'] = import_module.namespace + import_item['module'] = import_module + + # Copy the struct kinds from our imports into the current module. + for kind in import_module.kinds.itervalues(): + if (isinstance(kind, (mojom.Struct, mojom.Enum, mojom.Interface)) and + kind.imported_from is None): + kind = KindFromImport(kind, import_item) + module.kinds[kind.spec] = kind + # Ditto for values. + for value in import_module.values.itervalues(): + if value.imported_from is None: + value = copy.deepcopy(value) + value.imported_from = import_item + module.values[value.GetSpec()] = value + + return import_item + +def StructToData(struct): + return { + istr(0, 'name'): struct.name, + istr(1, 'fields'): map(FieldToData, struct.fields) + } + +def StructFromData(module, data): + struct = mojom.Struct(module=module) + struct.name = data['name'] + struct.attributes = data['attributes'] + struct.spec = 'x:' + module.namespace + '.' + struct.name + module.kinds[struct.spec] = struct + struct.enums = map(lambda enum: + EnumFromData(module, enum, struct), data['enums']) + struct.constants = map(lambda constant: + ConstantFromData(module, constant, struct), data['constants']) + # Stash fields data here temporarily. + struct.fields_data = data['fields'] + return struct + +def FieldToData(field): + data = { + istr(0, 'name'): field.name, + istr(1, 'kind'): KindToData(field.kind) + } + if field.ordinal != None: + data[istr(2, 'ordinal')] = field.ordinal + if field.default != None: + data[istr(3, 'default')] = field.default + return data + +def FieldFromData(module, data, struct): + field = mojom.Field() + field.name = data['name'] + field.kind = KindFromData( + module.kinds, data['kind'], (module.namespace, struct.name)) + field.ordinal = data.get('ordinal') + field.default = FixupExpression( + module, data.get('default'), (module.namespace, struct.name)) + return field + +def ParameterToData(parameter): + data = { + istr(0, 'name'): parameter.name, + istr(1, 'kind'): parameter.kind.spec + } + if parameter.ordinal != None: + data[istr(2, 'ordinal')] = parameter.ordinal + if parameter.default != None: + data[istr(3, 'default')] = parameter.default + return data + +def ParameterFromData(module, data, interface): + parameter = mojom.Parameter() + parameter.name = data['name'] + parameter.kind = KindFromData( + module.kinds, data['kind'], (module.namespace, interface.name)) + parameter.ordinal = data.get('ordinal') + parameter.default = data.get('default') + return parameter + +def MethodToData(method): + data = { + istr(0, 'name'): method.name, + istr(1, 'parameters'): map(ParameterToData, method.parameters) + } + if method.ordinal != None: + data[istr(2, 'ordinal')] = method.ordinal + if method.response_parameters != None: + data[istr(3, 'response_parameters')] = map( + ParameterToData, method.response_parameters) + return data + +def MethodFromData(module, data, interface): + method = mojom.Method(interface, data['name'], ordinal=data.get('ordinal')) + method.default = data.get('default') + method.parameters = map(lambda parameter: + ParameterFromData(module, parameter, interface), data['parameters']) + if data.has_key('response_parameters'): + method.response_parameters = map( + lambda parameter: ParameterFromData(module, parameter, interface), + data['response_parameters']) + return method + +def InterfaceToData(interface): + return { + istr(0, 'name'): interface.name, + istr(1, 'client'): interface.client, + istr(2, 'methods'): map(MethodToData, interface.methods) + } + +def InterfaceFromData(module, data): + interface = mojom.Interface(module=module) + interface.name = data['name'] + interface.spec = 'x:' + module.namespace + '.' + interface.name + interface.client = data['client'] if data.has_key('client') else None + module.kinds[interface.spec] = interface + interface.enums = map(lambda enum: + EnumFromData(module, enum, interface), data['enums']) + interface.constants = map(lambda constant: + ConstantFromData(module, constant, interface), data['constants']) + # Stash methods data here temporarily. + interface.methods_data = data['methods'] + return interface + +def EnumFieldFromData(module, enum, data, parent_kind): + field = mojom.EnumField() + field.name = data['name'] + # TODO(mpcomplete): FixupExpression should be done in the second pass, + # so constants and enums can refer to each other. + # TODO(mpcomplete): But then, what if constants are initialized to an enum? Or + # vice versa? + if parent_kind: + field.value = FixupExpression( + module, data['value'], (module.namespace, parent_kind.name)) + else: + field.value = FixupExpression( + module, data['value'], (module.namespace, )) + value = mojom.EnumValue(module, enum, field) + module.values[value.GetSpec()] = value + return field + +def EnumFromData(module, data, parent_kind): + enum = mojom.Enum(module=module) + enum.name = data['name'] + name = enum.name + if parent_kind: + name = parent_kind.name + '.' + name + enum.spec = 'x:%s.%s' % (module.namespace, name) + enum.parent_kind = parent_kind + + enum.fields = map( + lambda field: EnumFieldFromData(module, enum, field, parent_kind), + data['fields']) + module.kinds[enum.spec] = enum + return enum + +def ConstantFromData(module, data, parent_kind): + constant = mojom.Constant() + constant.name = data['name'] + if parent_kind: + scope = (module.namespace, parent_kind.name) + else: + scope = (module.namespace, ) + # TODO(mpcomplete): maybe we should only support POD kinds. + constant.kind = KindFromData(module.kinds, data['kind'], scope) + constant.value = FixupExpression(module, data.get('value'), scope) + + value = mojom.NamedValue(module, parent_kind, constant.name) + module.values[value.GetSpec()] = value + return constant + +def ModuleToData(module): + return { + istr(0, 'name'): module.name, + istr(1, 'namespace'): module.namespace, + istr(2, 'structs'): map(StructToData, module.structs), + istr(3, 'interfaces'): map(InterfaceToData, module.interfaces) + } + +def ModuleFromData(data): + module = mojom.Module() + module.kinds = {} + for kind in mojom.PRIMITIVES: + module.kinds[kind.spec] = kind + + module.values = {} + + module.name = data['name'] + module.namespace = data['namespace'] + module.attributes = data['attributes'] + # Imports must come first, because they add to module.kinds which is used + # by by the others. + module.imports = map( + lambda import_data: ImportFromData(module, import_data), + data['imports']) + + # First pass collects kinds. + module.enums = map( + lambda enum: EnumFromData(module, enum, None), data['enums']) + module.structs = map( + lambda struct: StructFromData(module, struct), data['structs']) + module.interfaces = map( + lambda interface: InterfaceFromData(module, interface), + data['interfaces']) + module.constants = map( + lambda constant: ConstantFromData(module, constant, None), + data['constants']) + + # Second pass expands fields and methods. This allows fields and parameters + # to refer to kinds defined anywhere in the mojom. + for struct in module.structs: + struct.fields = map(lambda field: + FieldFromData(module, field, struct), struct.fields_data) + del struct.fields_data + for interface in module.interfaces: + interface.methods = map(lambda method: + MethodFromData(module, method, interface), interface.methods_data) + del interface.methods_data + + return module + +def OrderedModuleFromData(data): + module = ModuleFromData(data) + next_interface_ordinal = 0 + for interface in module.interfaces: + next_ordinal = 0 + for method in interface.methods: + if method.ordinal is None: + method.ordinal = next_ordinal + next_ordinal = method.ordinal + 1 + return module diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py new file mode 100644 index 00000000000..096554c61a9 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py @@ -0,0 +1,86 @@ +# 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. + +import sys + +import data +import test_support + +EXPECT_EQ = test_support.EXPECT_EQ +EXPECT_TRUE = test_support.EXPECT_TRUE +RunTest = test_support.RunTest + + +def DeepEquals(d1, d2): + if d1 == d2: + return True + if d2.__class__ != d2.__class__: + return False + if isinstance(d1, dict): + if set(d1.keys()) != set(d2.keys()): + return False + for key in d1.keys(): + if not DeepEquals(d1[key], d2[key]): + return False + return True + if isinstance(d1, (list, tuple)): + if len(d1) != len(d2): + return False + for i in range(len(d1)): + if not DeepEquals(d1[i], d2[i]): + return False + return True + return False + + +test_dict = { + 'name': 'test', + 'namespace': 'testspace', + 'structs': [{ + 'name': 'teststruct', + 'fields': [ + {'name': 'testfield1', 'kind': 'i32'}, + {'name': 'testfield2', 'kind': 'a:i32', 'ordinal': 42}]}], + 'interfaces': [{ + 'name': 'Server', + 'client': None, + 'methods': [{ + 'name': 'Foo', + 'parameters': [ + {'name': 'foo', 'kind': 'i32'}, + {'name': 'bar', 'kind': 'a:x:teststruct'}], + 'ordinal': 42}]}] +} + + +def TestRead(): + module = data.ModuleFromData(test_dict) + return test_support.TestTestModule(module) + + +def TestWrite(): + module = test_support.BuildTestModule() + d = data.ModuleToData(module) + return EXPECT_TRUE(DeepEquals(test_dict, d)) + + +def TestWriteRead(): + module1 = test_support.BuildTestModule() + + dict1 = data.ModuleToData(module1) + module2 = data.ModuleFromData(dict1) + return EXPECT_TRUE(test_support.ModulesAreEqual(module1, module2)) + + +def Main(args): + errors = 0 + errors += RunTest(TestWriteRead) + errors += RunTest(TestRead) + errors += RunTest(TestWrite) + + return errors + + +if __name__ == '__main__': + sys.exit(Main(sys.argv[1:])) diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py new file mode 100644 index 00000000000..707028568c3 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py @@ -0,0 +1,90 @@ +# 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. + +"""Code shared by the various language-specific code generators.""" + +from functools import partial +import os.path + +import module as mojom +import pack + +def GetStructFromMethod(method): + """Converts a method's parameters into the fields of a struct.""" + params_class = "%s_%s_Params" % (method.interface.name, method.name) + struct = mojom.Struct(params_class, module=method.interface.module) + for param in method.parameters: + struct.AddField(param.name, param.kind, param.ordinal) + struct.packed = pack.PackedStruct(struct) + return struct + +def GetResponseStructFromMethod(method): + """Converts a method's response_parameters into the fields of a struct.""" + params_class = "%s_%s_ResponseParams" % (method.interface.name, method.name) + struct = mojom.Struct(params_class, module=method.interface.module) + for param in method.response_parameters: + struct.AddField(param.name, param.kind, param.ordinal) + struct.packed = pack.PackedStruct(struct) + return struct + +def GetDataHeader(exported, struct): + struct.packed = pack.PackedStruct(struct) + struct.bytes = pack.GetByteLayout(struct.packed) + struct.exported = exported + return struct + +def IsStringKind(kind): + return kind.spec == 's' + +def IsEnumKind(kind): + return isinstance(kind, mojom.Enum) + +def IsObjectKind(kind): + return isinstance(kind, (mojom.Struct, mojom.Array)) or IsStringKind(kind) + +def IsHandleKind(kind): + return kind.spec.startswith('h') or \ + isinstance(kind, mojom.Interface) or \ + isinstance(kind, mojom.InterfaceRequest) + +def IsInterfaceKind(kind): + return isinstance(kind, mojom.Interface) + +def IsInterfaceRequestKind(kind): + return isinstance(kind, mojom.InterfaceRequest) + +def IsMoveOnlyKind(kind): + return IsObjectKind(kind) or IsHandleKind(kind) + +def StudlyCapsToCamel(studly): + return studly[0].lower() + studly[1:] + +class Generator(object): + # Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all + # files to stdout. + def __init__(self, module, output_dir=None): + self.module = module + self.output_dir = output_dir + + def GetStructsFromMethods(self): + result = [] + for interface in self.module.interfaces: + for method in interface.methods: + result.append(GetStructFromMethod(method)) + if method.response_parameters != None: + result.append(GetResponseStructFromMethod(method)) + return map(partial(GetDataHeader, False), result) + + def GetStructs(self): + return map(partial(GetDataHeader, True), self.module.structs) + + def Write(self, contents, filename): + if self.output_dir is None: + print contents + return + with open(os.path.join(self.output_dir, filename), "w+") as f: + f.write(contents) + + def GenerateFiles(self, args): + raise NotImplementedError("Subclasses must override/implement this method") diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module.py new file mode 100644 index 00000000000..345f432030f --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module.py @@ -0,0 +1,217 @@ +# 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. + +# This module's classes provide an interface to mojo modules. Modules are +# collections of interfaces and structs to be used by mojo ipc clients and +# servers. +# +# A simple interface would be created this way: +# module = mojom.generate.module.Module('Foo') +# interface = module.AddInterface('Bar') +# method = interface.AddMethod('Tat', 0) +# method.AddParameter('baz', 0, mojom.INT32) +# + +class Kind(object): + def __init__(self, spec=None): + self.spec = spec + self.parent_kind = None + +# Initialize the set of primitive types. These can be accessed by clients. +BOOL = Kind('b') +INT8 = Kind('i8') +INT16 = Kind('i16') +INT32 = Kind('i32') +INT64 = Kind('i64') +UINT8 = Kind('u8') +UINT16 = Kind('u16') +UINT32 = Kind('u32') +UINT64 = Kind('u64') +FLOAT = Kind('f') +DOUBLE = Kind('d') +STRING = Kind('s') +HANDLE = Kind('h') +DCPIPE = Kind('h:d:c') +DPPIPE = Kind('h:d:p') +MSGPIPE = Kind('h:m') +SHAREDBUFFER = Kind('h:s') + + +# Collection of all Primitive types +PRIMITIVES = ( + BOOL, + INT8, + INT16, + INT32, + INT64, + UINT8, + UINT16, + UINT32, + UINT64, + FLOAT, + DOUBLE, + STRING, + HANDLE, + DCPIPE, + DPPIPE, + MSGPIPE, + SHAREDBUFFER +) + + +class NamedValue(object): + def __init__(self, module, parent_kind, name): + self.module = module + self.namespace = module.namespace + self.parent_kind = parent_kind + self.name = name + self.imported_from = None + + def GetSpec(self): + return (self.namespace + '.' + + (self.parent_kind and (self.parent_kind.name + '.') or "") + + self.name) + + +class EnumValue(NamedValue): + def __init__(self, module, enum, field): + NamedValue.__init__(self, module, enum.parent_kind, field.name) + self.enum_name = enum.name + + +class Constant(object): + def __init__(self, name=None, kind=None, value=None): + self.name = name + self.kind = kind + self.value = value + + +class Field(object): + def __init__(self, name=None, kind=None, ordinal=None, default=None): + self.name = name + self.kind = kind + self.ordinal = ordinal + self.default = default + + +class Struct(Kind): + def __init__(self, name=None, module=None): + self.name = name + self.module = module + self.imported_from = None + if name != None: + spec = 'x:' + name + else: + spec = None + Kind.__init__(self, spec) + self.fields = [] + + def AddField(self, name, kind, ordinal=None, default=None): + field = Field(name, kind, ordinal, default) + self.fields.append(field) + return field + + +class Array(Kind): + def __init__(self, kind=None): + self.kind = kind + if kind != None: + Kind.__init__(self, 'a:' + kind.spec) + else: + Kind.__init__(self) + + +class InterfaceRequest(Kind): + def __init__(self, kind=None): + self.kind = kind + if kind != None: + Kind.__init__(self, 'r:' + kind.spec) + else: + Kind.__init__(self) + + +class Parameter(object): + def __init__(self, name=None, kind=None, ordinal=None, default=None): + self.name = name + self.ordinal = ordinal + self.kind = kind + self.default = default + + +class Method(object): + def __init__(self, interface, name, ordinal=None): + self.interface = interface + self.name = name + self.ordinal = ordinal + self.parameters = [] + self.response_parameters = None + + def AddParameter(self, name, kind, ordinal=None, default=None): + parameter = Parameter(name, kind, ordinal, default) + self.parameters.append(parameter) + return parameter + + def AddResponseParameter(self, name, kind, ordinal=None, default=None): + if self.response_parameters == None: + self.response_parameters = [] + parameter = Parameter(name, kind, ordinal, default) + self.response_parameters.append(parameter) + return parameter + + +class Interface(Kind): + def __init__(self, name=None, client=None, module=None): + self.module = module + self.name = name + self.imported_from = None + if name != None: + spec = 'x:' + name + else: + spec = None + Kind.__init__(self, spec) + self.client = client + self.methods = [] + + def AddMethod(self, name, ordinal=None): + method = Method(self, name, ordinal=ordinal) + self.methods.append(method) + return method + + +class EnumField(object): + def __init__(self, name=None, value=None): + self.name = name + self.value = value + + +class Enum(Kind): + def __init__(self, name=None, module=None): + self.module = module + self.name = name + self.imported_from = None + if name != None: + spec = 'x:' + name + else: + spec = None + Kind.__init__(self, spec) + self.fields = [] + + +class Module(object): + def __init__(self, name=None, namespace=None): + self.name = name + self.path = name + self.namespace = namespace + self.structs = [] + self.interfaces = [] + + def AddInterface(self, name): + interface=Interface(name, module=self); + self.interfaces.append(interface) + return interface + + def AddStruct(self, name): + struct=Struct(name, module=self) + self.structs.append(struct) + return struct diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module_tests.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module_tests.py new file mode 100644 index 00000000000..a887686e1b5 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module_tests.py @@ -0,0 +1,34 @@ +# 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. + +import sys + +import test_support + +EXPECT_EQ = test_support.EXPECT_EQ +EXPECT_TRUE = test_support.EXPECT_TRUE +RunTest = test_support.RunTest +ModulesAreEqual = test_support.ModulesAreEqual +BuildTestModule = test_support.BuildTestModule +TestTestModule = test_support.TestTestModule + + +def BuildAndTestModule(): + return TestTestModule(BuildTestModule()) + + +def TestModulesEqual(): + return EXPECT_TRUE(ModulesAreEqual(BuildTestModule(), BuildTestModule())) + + +def Main(args): + errors = 0 + errors += RunTest(BuildAndTestModule) + errors += RunTest(TestModulesEqual) + + return errors + + +if __name__ == '__main__': + sys.exit(Main(sys.argv[1:])) diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/pack.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/pack.py new file mode 100644 index 00000000000..21d2c184180 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/pack.py @@ -0,0 +1,150 @@ +# 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. + +import module as mojom + +# This module provides a mechanism for determining the packed order and offsets +# of a mojom.Struct. +# +# ps = pack.PackedStruct(struct) +# ps.packed_fields will access a list of PackedField objects, each of which +# will have an offset, a size and a bit (for mojom.BOOLs). + +class PackedField(object): + kind_to_size = { + mojom.BOOL: 1, + mojom.INT8: 1, + mojom.UINT8: 1, + mojom.INT16: 2, + mojom.UINT16: 2, + mojom.INT32: 4, + mojom.UINT32: 4, + mojom.FLOAT: 4, + mojom.HANDLE: 4, + mojom.MSGPIPE: 4, + mojom.SHAREDBUFFER: 4, + mojom.DCPIPE: 4, + mojom.DPPIPE: 4, + mojom.INT64: 8, + mojom.UINT64: 8, + mojom.DOUBLE: 8, + mojom.STRING: 8 + } + + @classmethod + def GetSizeForKind(cls, kind): + if isinstance(kind, mojom.Array) or isinstance(kind, mojom.Struct): + return 8 + if isinstance(kind, mojom.Interface) or \ + isinstance(kind, mojom.InterfaceRequest): + kind = mojom.MSGPIPE + if isinstance(kind, mojom.Enum): + # TODO(mpcomplete): what about big enums? + return cls.kind_to_size[mojom.INT32] + if not kind in cls.kind_to_size: + raise Exception("Invalid kind: %s" % kind.spec) + return cls.kind_to_size[kind] + + def __init__(self, field, ordinal): + self.field = field + self.ordinal = ordinal + self.size = self.GetSizeForKind(field.kind) + self.offset = None + self.bit = None + + +# Returns the pad necessary to reserve space for alignment of |size|. +def GetPad(offset, size): + return (size - (offset % size)) % size + + +# Returns a 2-tuple of the field offset and bit (for BOOLs) +def GetFieldOffset(field, last_field): + if field.field.kind == mojom.BOOL and \ + last_field.field.kind == mojom.BOOL and \ + last_field.bit < 7: + return (last_field.offset, last_field.bit + 1) + + offset = last_field.offset + last_field.size + pad = GetPad(offset, field.size) + return (offset + pad, 0) + + +class PackedStruct(object): + def __init__(self, struct): + self.struct = struct + self.packed_fields = [] + + # No fields. + if (len(struct.fields) == 0): + return + + # Start by sorting by ordinal. + src_fields = [] + ordinal = 0 + for field in struct.fields: + if field.ordinal is not None: + ordinal = field.ordinal + src_fields.append(PackedField(field, ordinal)) + ordinal += 1 + src_fields.sort(key=lambda field: field.ordinal) + + src_field = src_fields[0] + src_field.offset = 0 + src_field.bit = 0 + # dst_fields will contain each of the fields, in increasing offset order. + dst_fields = self.packed_fields + dst_fields.append(src_field) + + # Then find first slot that each field will fit. + for src_field in src_fields[1:]: + last_field = dst_fields[0] + for i in xrange(1, len(dst_fields)): + next_field = dst_fields[i] + offset, bit = GetFieldOffset(src_field, last_field) + if offset + src_field.size <= next_field.offset: + # Found hole. + src_field.offset = offset + src_field.bit = bit + dst_fields.insert(i, src_field) + break + last_field = next_field + if src_field.offset is None: + # Add to end + src_field.offset, src_field.bit = GetFieldOffset(src_field, last_field) + dst_fields.append(src_field) + + def GetTotalSize(self): + if not self.packed_fields: + return 0 + last_field = self.packed_fields[-1] + offset = last_field.offset + last_field.size + pad = GetPad(offset, 8) + return offset + pad + + +class ByteInfo(object): + def __init__(self): + self.is_padding = False + self.packed_fields = [] + + +def GetByteLayout(packed_struct): + bytes = [ByteInfo() for i in xrange(packed_struct.GetTotalSize())] + + limit_of_previous_field = 0 + for packed_field in packed_struct.packed_fields: + for i in xrange(limit_of_previous_field, packed_field.offset): + bytes[i].is_padding = True + bytes[packed_field.offset].packed_fields.append(packed_field) + limit_of_previous_field = packed_field.offset + packed_field.size + + for i in xrange(limit_of_previous_field, len(bytes)): + bytes[i].is_padding = True + + for byte in bytes: + # A given byte cannot both be padding and have a fields packed into it. + assert not (byte.is_padding and byte.packed_fields) + + return bytes diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/pack_tests.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/pack_tests.py new file mode 100644 index 00000000000..4e61004e5f4 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/pack_tests.py @@ -0,0 +1,176 @@ +# 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. + +import sys + +import module as mojom +import pack +import test_support + + +EXPECT_EQ = test_support.EXPECT_EQ +EXPECT_TRUE = test_support.EXPECT_TRUE +RunTest = test_support.RunTest + + +def TestOrdinalOrder(): + errors = 0 + struct = mojom.Struct('test') + struct.AddField('testfield1', mojom.INT32, 2) + struct.AddField('testfield2', mojom.INT32, 1) + ps = pack.PackedStruct(struct) + + errors += EXPECT_EQ(2, len(ps.packed_fields)) + errors += EXPECT_EQ('testfield2', ps.packed_fields[0].field.name) + errors += EXPECT_EQ('testfield1', ps.packed_fields[1].field.name) + + return errors + +def TestZeroFields(): + errors = 0 + struct = mojom.Struct('test') + ps = pack.PackedStruct(struct) + errors += EXPECT_EQ(0, len(ps.packed_fields)) + return errors + + +def TestOneField(): + errors = 0 + struct = mojom.Struct('test') + struct.AddField('testfield1', mojom.INT8) + ps = pack.PackedStruct(struct) + errors += EXPECT_EQ(1, len(ps.packed_fields)) + return errors + +# Pass three tuples. +# |kinds| is a sequence of mojom.Kinds that specify the fields that are to +# be created. +# |fields| is the expected order of the resulting fields, with the integer +# "1" first. +# |offsets| is the expected order of offsets, with the integer "0" first. +def TestSequence(kinds, fields, offsets): + errors = 0 + struct = mojom.Struct('test') + index = 1 + for kind in kinds: + struct.AddField("%d" % index, kind) + index += 1 + ps = pack.PackedStruct(struct) + num_fields = len(ps.packed_fields) + errors += EXPECT_EQ(len(kinds), num_fields) + for i in xrange(num_fields): + EXPECT_EQ("%d" % fields[i], ps.packed_fields[i].field.name) + EXPECT_EQ(offsets[i], ps.packed_fields[i].offset) + + return errors + + +def TestPaddingPackedInOrder(): + return TestSequence( + (mojom.INT8, mojom.UINT8, mojom.INT32), + (1, 2, 3), + (0, 1, 4)) + + +def TestPaddingPackedOutOfOrder(): + return TestSequence( + (mojom.INT8, mojom.INT32, mojom.UINT8), + (1, 3, 2), + (0, 1, 4)) + + +def TestPaddingPackedOverflow(): + kinds = (mojom.INT8, mojom.INT32, mojom.INT16, mojom.INT8, mojom.INT8) + # 2 bytes should be packed together first, followed by short, then by int. + fields = (1, 4, 3, 2, 5) + offsets = (0, 1, 2, 4, 8) + return TestSequence(kinds, fields, offsets) + + +def TestAllTypes(): + struct = mojom.Struct('test') + array = mojom.Array() + return TestSequence( + (mojom.BOOL, mojom.INT8, mojom.STRING, mojom.UINT8, + mojom.INT16, mojom.DOUBLE, mojom.UINT16, + mojom.INT32, mojom.UINT32, mojom.INT64, + mojom.FLOAT, mojom.STRING, mojom.HANDLE, + mojom.UINT64, mojom.Struct('test'), mojom.Array()), + (1, 2, 4, 5, 7, 3, 6, 8, 9, 10, 11, 13, 12, 14, 15, 16, 17), + (0, 1, 2, 4, 6, 8, 16, 24, 28, 32, 40, 44, 48, 56, 64, 72, 80)) + + +def TestPaddingPackedOutOfOrderByOrdinal(): + errors = 0 + struct = mojom.Struct('test') + struct.AddField('testfield1', mojom.INT8) + struct.AddField('testfield3', mojom.UINT8, 3) + struct.AddField('testfield2', mojom.INT32, 2) + ps = pack.PackedStruct(struct) + errors += EXPECT_EQ(3, len(ps.packed_fields)) + + # Second byte should be packed in behind first, altering order. + errors += EXPECT_EQ('testfield1', ps.packed_fields[0].field.name) + errors += EXPECT_EQ('testfield3', ps.packed_fields[1].field.name) + errors += EXPECT_EQ('testfield2', ps.packed_fields[2].field.name) + + # Second byte should be packed with first. + errors += EXPECT_EQ(0, ps.packed_fields[0].offset) + errors += EXPECT_EQ(1, ps.packed_fields[1].offset) + errors += EXPECT_EQ(4, ps.packed_fields[2].offset) + + return errors + + +def TestBools(): + errors = 0 + struct = mojom.Struct('test') + struct.AddField('bit0', mojom.BOOL) + struct.AddField('bit1', mojom.BOOL) + struct.AddField('int', mojom.INT32) + struct.AddField('bit2', mojom.BOOL) + struct.AddField('bit3', mojom.BOOL) + struct.AddField('bit4', mojom.BOOL) + struct.AddField('bit5', mojom.BOOL) + struct.AddField('bit6', mojom.BOOL) + struct.AddField('bit7', mojom.BOOL) + struct.AddField('bit8', mojom.BOOL) + ps = pack.PackedStruct(struct) + errors += EXPECT_EQ(10, len(ps.packed_fields)) + + # First 8 bits packed together. + for i in xrange(8): + pf = ps.packed_fields[i] + errors += EXPECT_EQ(0, pf.offset) + errors += EXPECT_EQ("bit%d" % i, pf.field.name) + errors += EXPECT_EQ(i, pf.bit) + + # Ninth bit goes into second byte. + errors += EXPECT_EQ("bit8", ps.packed_fields[8].field.name) + errors += EXPECT_EQ(1, ps.packed_fields[8].offset) + errors += EXPECT_EQ(0, ps.packed_fields[8].bit) + + # int comes last. + errors += EXPECT_EQ("int", ps.packed_fields[9].field.name) + errors += EXPECT_EQ(4, ps.packed_fields[9].offset) + + return errors + + +def Main(args): + errors = 0 + errors += RunTest(TestZeroFields) + errors += RunTest(TestOneField) + errors += RunTest(TestPaddingPackedInOrder) + errors += RunTest(TestPaddingPackedOutOfOrder) + errors += RunTest(TestPaddingPackedOverflow) + errors += RunTest(TestAllTypes) + errors += RunTest(TestPaddingPackedOutOfOrderByOrdinal) + errors += RunTest(TestBools) + + return errors + + +if __name__ == '__main__': + sys.exit(Main(sys.argv[1:])) diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/run_tests.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/run_tests.py new file mode 100755 index 00000000000..41f11a2b71e --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/run_tests.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# 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. + +""" Test runner for Mojom """ + +import subprocess +import sys + +def TestMojom(testname, args): + print '\nRunning unit tests for %s.' % testname + try: + args = [sys.executable, testname] + args + subprocess.check_call(args, stdout=sys.stdout) + print 'Succeeded' + return 0 + except subprocess.CalledProcessError as err: + print 'Failed with %s.' % str(err) + return 1 + + +def main(args): + errors = 0 + errors += TestMojom('data_tests.py', ['--test']) + errors += TestMojom('module_tests.py', ['--test']) + errors += TestMojom('pack_tests.py', ['--test']) + + if errors: + print '\nFailed tests.' + return min(errors, 127) # Make sure the return value doesn't "wrap". + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py new file mode 100644 index 00000000000..86ea0eac0b4 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py @@ -0,0 +1,54 @@ +# 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. + +# Based on: +# http://src.chromium.org/viewvc/blink/trunk/Source/build/scripts/template_expander.py + +import imp +import inspect +import os.path +import sys + +# Disable lint check for finding modules: +# pylint: disable=F0401 + +def _GetDirAbove(dirname): + """Returns the directory "above" this file containing |dirname| (which must + also be "above" this file).""" + path = os.path.abspath(__file__) + while True: + path, tail = os.path.split(path) + assert tail + if tail == dirname: + return path + +try: + imp.find_module("jinja2") +except ImportError: + sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party")) +import jinja2 + + +def ApplyTemplate(base_dir, path_to_template, params, filters=None, **kwargs): + template_directory, template_name = os.path.split(path_to_template) + path_to_templates = os.path.join(base_dir, template_directory) + loader = jinja2.FileSystemLoader([path_to_templates]) + jinja_env = jinja2.Environment(loader=loader, keep_trailing_newline=True, + **kwargs) + if filters: + jinja_env.filters.update(filters) + template = jinja_env.get_template(template_name) + return template.render(params) + + +def UseJinja(path_to_template, **kwargs): + # Get the directory of our caller's file. + base_dir = os.path.dirname(inspect.getfile(sys._getframe(1))) + def RealDecorator(generator): + def GeneratorInternal(*args, **kwargs2): + parameters = generator(*args, **kwargs2) + return ApplyTemplate(base_dir, path_to_template, parameters, **kwargs) + GeneratorInternal.func_name = generator.func_name + return GeneratorInternal + return RealDecorator diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/test_support.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/test_support.py new file mode 100644 index 00000000000..eb394619d2b --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/test_support.py @@ -0,0 +1,193 @@ +# 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. + +import sys +import traceback + +import module as mojom + +# Support for writing mojom test cases. +# RunTest(fn) will execute fn, catching any exceptions. fn should return +# the number of errors that are encountered. +# +# EXPECT_EQ(a, b) and EXPECT_TRUE(b) will print error information if the +# expectations are not true and return a non zero value. This allows test cases +# to be written like this +# +# def Foo(): +# errors = 0 +# errors += EXPECT_EQ('test', test()) +# ... +# return errors +# +# RunTest(foo) + +def FieldsAreEqual(field1, field2): + if field1 == field2: + return True + return field1.name == field2.name and \ + KindsAreEqual(field1.kind, field2.kind) and \ + field1.ordinal == field2.ordinal and \ + field1.default == field2.default + + +def KindsAreEqual(kind1, kind2): + if kind1 == kind2: + return True + if kind1.__class__ != kind2.__class__ or kind1.spec != kind2.spec: + return False + if kind1.__class__ == mojom.Kind: + return kind1.spec == kind2.spec + if kind1.__class__ == mojom.Struct: + if kind1.name != kind2.name or \ + kind1.spec != kind2.spec or \ + len(kind1.fields) != len(kind2.fields): + return False + for i in range(len(kind1.fields)): + if not FieldsAreEqual(kind1.fields[i], kind2.fields[i]): + return False + return True + if kind1.__class__ == mojom.Array: + return KindsAreEqual(kind1.kind, kind2.kind) + print 'Unknown Kind class: ', kind1.__class__.__name__ + return False + + +def ParametersAreEqual(parameter1, parameter2): + if parameter1 == parameter2: + return True + return parameter1.name == parameter2.name and \ + parameter1.ordinal == parameter2.ordinal and \ + parameter1.default == parameter2.default and \ + KindsAreEqual(parameter1.kind, parameter2.kind) + + +def MethodsAreEqual(method1, method2): + if method1 == method2: + return True + if method1.name != method2.name or \ + method1.ordinal != method2.ordinal or \ + len(method1.parameters) != len(method2.parameters): + return False + for i in range(len(method1.parameters)): + if not ParametersAreEqual(method1.parameters[i], method2.parameters[i]): + return False + return True + + +def InterfacesAreEqual(interface1, interface2): + if interface1 == interface2: + return True + if interface1.name != interface2.name or \ + len(interface1.methods) != len(interface2.methods): + return False + for i in range(len(interface1.methods)): + if not MethodsAreEqual(interface1.methods[i], interface2.methods[i]): + return False + return True + + +def ModulesAreEqual(module1, module2): + if module1 == module2: + return True + if module1.name != module2.name or \ + module1.namespace != module2.namespace or \ + len(module1.structs) != len(module2.structs) or \ + len(module1.interfaces) != len(module2.interfaces): + return False + for i in range(len(module1.structs)): + if not KindsAreEqual(module1.structs[i], module2.structs[i]): + return False + for i in range(len(module1.interfaces)): + if not InterfacesAreEqual(module1.interfaces[i], module2.interfaces[i]): + return False + return True + + +# Builds and returns a Module suitable for testing/ +def BuildTestModule(): + module = mojom.Module('test', 'testspace') + struct = module.AddStruct('teststruct') + struct.AddField('testfield1', mojom.INT32) + struct.AddField('testfield2', mojom.Array(mojom.INT32), 42) + + interface = module.AddInterface('Server') + method = interface.AddMethod('Foo', 42) + method.AddParameter('foo', mojom.INT32) + method.AddParameter('bar', mojom.Array(struct)) + + return module + + +# Tests if |module| is as built by BuildTestModule(). Returns the number of +# errors +def TestTestModule(module): + errors = 0 + + errors += EXPECT_EQ('test', module.name) + errors += EXPECT_EQ('testspace', module.namespace) + errors += EXPECT_EQ(1, len(module.structs)) + errors += EXPECT_EQ('teststruct', module.structs[0].name) + errors += EXPECT_EQ(2, len(module.structs[0].fields)) + errors += EXPECT_EQ('testfield1', module.structs[0].fields[0].name) + errors += EXPECT_EQ(mojom.INT32, module.structs[0].fields[0].kind) + errors += EXPECT_EQ('testfield2', module.structs[0].fields[1].name) + errors += EXPECT_EQ(mojom.Array, module.structs[0].fields[1].kind.__class__) + errors += EXPECT_EQ(mojom.INT32, module.structs[0].fields[1].kind.kind) + + errors += EXPECT_EQ(1, len(module.interfaces)) + errors += EXPECT_EQ('Server', module.interfaces[0].name) + errors += EXPECT_EQ(1, len(module.interfaces[0].methods)) + errors += EXPECT_EQ('Foo', module.interfaces[0].methods[0].name) + errors += EXPECT_EQ(2, len(module.interfaces[0].methods[0].parameters)) + errors += EXPECT_EQ('foo', module.interfaces[0].methods[0].parameters[0].name) + errors += EXPECT_EQ(mojom.INT32, + module.interfaces[0].methods[0].parameters[0].kind) + errors += EXPECT_EQ('bar', module.interfaces[0].methods[0].parameters[1].name) + errors += EXPECT_EQ( + mojom.Array, + module.interfaces[0].methods[0].parameters[1].kind.__class__) + errors += EXPECT_EQ( + module.structs[0], + module.interfaces[0].methods[0].parameters[1].kind.kind) + return errors + + +def PrintFailure(string): + stack = traceback.extract_stack() + frame = stack[len(stack)-3] + sys.stderr.write("ERROR at %s:%d, %s\n" % (frame[0], frame[1], string)) + print "Traceback:" + for line in traceback.format_list(stack[:len(stack)-2]): + sys.stderr.write(line) + + +def EXPECT_EQ(a, b): + if a != b: + PrintFailure("%s != %s" % (a, b)) + return 1 + return 0 + + +def EXPECT_TRUE(a): + if not a: + PrintFailure('Expecting True') + return 1 + return 0 + + +def RunTest(fn): + sys.stdout.write('Running %s...' % fn.__name__) + try: + errors = fn() + except: + traceback.print_exc(sys.stderr) + errors = 1 + if errors == 0: + sys.stdout.write('OK\n') + elif errors == 1: + sys.stdout.write('1 ERROR\n') + else: + sys.stdout.write('%d ERRORS\n' % errors) + return errors diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/parse/__init__.py b/chromium/mojo/public/tools/bindings/pylib/mojom/parse/__init__.py new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/parse/__init__.py diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/parse/ast.py b/chromium/mojo/public/tools/bindings/pylib/mojom/parse/ast.py new file mode 100644 index 00000000000..bd398c18ecb --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/parse/ast.py @@ -0,0 +1,25 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Node objects for the AST for a Mojo IDL file.""" + +# Note: For convenience of testing, you probably want to define __eq__() methods +# for all node types; it's okay to be slightly lax (e.g., not compare filename +# and lineno). + + +class BaseNode(object): + def __init__(self, filename=None, lineno=None): + self.filename = filename + self.lineno = lineno + + +class Ordinal(BaseNode): + """Represents an ordinal value labeling, e.g., a struct field.""" + def __init__(self, value, **kwargs): + BaseNode.__init__(self, **kwargs) + self.value = value + + def __eq__(self, other): + return self.value == other.value diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/parse/lexer.py b/chromium/mojo/public/tools/bindings/pylib/mojom/parse/lexer.py new file mode 100644 index 00000000000..34419acd53c --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/parse/lexer.py @@ -0,0 +1,277 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import imp +import os.path +import sys + +# Disable lint check for finding modules: +# pylint: disable=F0401 + +def _GetDirAbove(dirname): + """Returns the directory "above" this file containing |dirname| (which must + also be "above" this file).""" + path = os.path.abspath(__file__) + while True: + path, tail = os.path.split(path) + assert tail + if tail == dirname: + return path + +try: + imp.find_module("ply") +except ImportError: + sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party")) +from ply.lex import TOKEN + +from ..error import Error + + +# Disable lint check for exceptions deriving from Exception: +# pylint: disable=W0710 +class LexError(Error): + """Class for errors from the lexer.""" + + def __init__(self, filename, message, lineno): + Error.__init__(self, filename, message, lineno=lineno) + + +# We have methods which look like they could be functions: +# pylint: disable=R0201 +class Lexer(object): + + def __init__(self, filename): + self.filename = filename + + ######################-- PRIVATE --###################### + + ## + ## Internal auxiliary methods + ## + def _error(self, msg, token): + raise LexError(self.filename, msg, token.lineno) + + ## + ## Reserved keywords + ## + keywords = ( + 'HANDLE', + + 'IMPORT', + 'MODULE', + 'STRUCT', + 'INTERFACE', + 'ENUM', + 'CONST', + 'TRUE', + 'FALSE', + 'DEFAULT', + ) + + keyword_map = {} + for keyword in keywords: + keyword_map[keyword.lower()] = keyword + + ## + ## All the tokens recognized by the lexer + ## + tokens = keywords + ( + # Identifiers + 'NAME', + + # Constants + 'ORDINAL', + 'INT_CONST_DEC', 'INT_CONST_HEX', + 'FLOAT_CONST', + 'CHAR_CONST', + + # String literals + 'STRING_LITERAL', + + # Operators + 'MINUS', + 'PLUS', + 'AMP', + + # Assignment + 'EQUALS', + + # Request / response + 'RESPONSE', + + # Delimiters + 'LPAREN', 'RPAREN', # ( ) + 'LBRACKET', 'RBRACKET', # [ ] + 'LBRACE', 'RBRACE', # { } + 'LANGLE', 'RANGLE', # < > + 'SEMI', # ; + 'COMMA', 'DOT' # , . + ) + + ## + ## Regexes for use in tokens + ## + + # valid C identifiers (K&R2: A.2.3) + identifier = r'[a-zA-Z_][0-9a-zA-Z_]*' + + hex_prefix = '0[xX]' + hex_digits = '[0-9a-fA-F]+' + + # integer constants (K&R2: A.2.5.1) + decimal_constant = '0|([1-9][0-9]*)' + hex_constant = hex_prefix+hex_digits + # Don't allow octal constants (even invalid octal). + octal_constant_disallowed = '0[0-9]+' + + # character constants (K&R2: A.2.5.2) + # Note: a-zA-Z and '.-~^_!=&;,' are allowed as escape chars to support #line + # directives with Windows paths as filenames (..\..\dir\file) + # For the same reason, decimal_escape allows all digit sequences. We want to + # parse all correct code, even if it means to sometimes parse incorrect + # code. + # + simple_escape = r"""([a-zA-Z._~!=&\^\-\\?'"])""" + decimal_escape = r"""(\d+)""" + hex_escape = r"""(x[0-9a-fA-F]+)""" + bad_escape = r"""([\\][^a-zA-Z._~^!=&\^\-\\?'"x0-7])""" + + escape_sequence = \ + r"""(\\("""+simple_escape+'|'+decimal_escape+'|'+hex_escape+'))' + cconst_char = r"""([^'\\\n]|"""+escape_sequence+')' + char_const = "'"+cconst_char+"'" + unmatched_quote = "('"+cconst_char+"*\\n)|('"+cconst_char+"*$)" + bad_char_const = \ + r"""('"""+cconst_char+"""[^'\n]+')|('')|('"""+ \ + bad_escape+r"""[^'\n]*')""" + + # string literals (K&R2: A.2.6) + string_char = r"""([^"\\\n]|"""+escape_sequence+')' + string_literal = '"'+string_char+'*"' + bad_string_literal = '"'+string_char+'*'+bad_escape+string_char+'*"' + + # floating constants (K&R2: A.2.5.3) + exponent_part = r"""([eE][-+]?[0-9]+)""" + fractional_constant = r"""([0-9]*\.[0-9]+)|([0-9]+\.)""" + floating_constant = \ + '(((('+fractional_constant+')'+ \ + exponent_part+'?)|([0-9]+'+exponent_part+')))' + + # Ordinals + ordinal = r'@[0-9]+' + missing_ordinal_value = r'@' + # Don't allow ordinal values in octal (even invalid octal, like 09) or + # hexadecimal. + octal_or_hex_ordinal_disallowed = r'@((0[0-9]+)|('+hex_prefix+hex_digits+'))' + + ## + ## Rules for the normal state + ## + t_ignore = ' \t\r' + + # Newlines + def t_NEWLINE(self, t): + r'\n+' + t.lexer.lineno += len(t.value) + + # Operators + t_MINUS = r'-' + t_PLUS = r'\+' + t_AMP = r'&' + + # = + t_EQUALS = r'=' + + # => + t_RESPONSE = r'=>' + + # Delimiters + t_LPAREN = r'\(' + t_RPAREN = r'\)' + t_LBRACKET = r'\[' + t_RBRACKET = r'\]' + t_LBRACE = r'\{' + t_RBRACE = r'\}' + t_LANGLE = r'<' + t_RANGLE = r'>' + t_COMMA = r',' + t_DOT = r'\.' + t_SEMI = r';' + + t_STRING_LITERAL = string_literal + + # The following floating and integer constants are defined as + # functions to impose a strict order (otherwise, decimal + # is placed before the others because its regex is longer, + # and this is bad) + # + @TOKEN(floating_constant) + def t_FLOAT_CONST(self, t): + return t + + @TOKEN(hex_constant) + def t_INT_CONST_HEX(self, t): + return t + + @TOKEN(octal_constant_disallowed) + def t_OCTAL_CONSTANT_DISALLOWED(self, t): + msg = "Octal values not allowed" + self._error(msg, t) + + @TOKEN(decimal_constant) + def t_INT_CONST_DEC(self, t): + return t + + # Must come before bad_char_const, to prevent it from + # catching valid char constants as invalid + # + @TOKEN(char_const) + def t_CHAR_CONST(self, t): + return t + + @TOKEN(unmatched_quote) + def t_UNMATCHED_QUOTE(self, t): + msg = "Unmatched '" + self._error(msg, t) + + @TOKEN(bad_char_const) + def t_BAD_CHAR_CONST(self, t): + msg = "Invalid char constant %s" % t.value + self._error(msg, t) + + # unmatched string literals are caught by the preprocessor + + @TOKEN(bad_string_literal) + def t_BAD_STRING_LITERAL(self, t): + msg = "String contains invalid escape code" + self._error(msg, t) + + # Handle ordinal-related tokens in the right order: + @TOKEN(octal_or_hex_ordinal_disallowed) + def t_OCTAL_OR_HEX_ORDINAL_DISALLOWED(self, t): + msg = "Octal and hexadecimal ordinal values not allowed" + self._error(msg, t) + + @TOKEN(ordinal) + def t_ORDINAL(self, t): + return t + + @TOKEN(missing_ordinal_value) + def t_BAD_ORDINAL(self, t): + msg = "Missing ordinal value" + self._error(msg, t) + + @TOKEN(identifier) + def t_NAME(self, t): + t.type = self.keyword_map.get(t.value, "NAME") + return t + + # Ignore C and C++ style comments + def t_COMMENT(self, t): + r'(/\*(.|\n)*?\*/)|(//.*(\n[ \t]*//.*)*)' + t.lexer.lineno += t.value.count("\n") + + def t_error(self, t): + msg = "Illegal character %s" % repr(t.value[0]) + self._error(msg, t) diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/parse/parser.py b/chromium/mojo/public/tools/bindings/pylib/mojom/parse/parser.py new file mode 100644 index 00000000000..da441e3806c --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/parse/parser.py @@ -0,0 +1,323 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Generates a syntax tree from a Mojo IDL file.""" + +import imp +import os.path +import sys + +# Disable lint check for finding modules: +# pylint: disable=F0401 + +def _GetDirAbove(dirname): + """Returns the directory "above" this file containing |dirname| (which must + also be "above" this file).""" + path = os.path.abspath(__file__) + while True: + path, tail = os.path.split(path) + assert tail + if tail == dirname: + return path + +try: + imp.find_module("ply") +except ImportError: + sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party")) +from ply import lex +from ply import yacc + +from ..error import Error +import ast +from lexer import Lexer + + +_MAX_ORDINAL_VALUE = 0xffffffff + + +def _ListFromConcat(*items): + """Generate list by concatenating inputs (note: only concatenates lists, not + tuples or other iterables).""" + itemsout = [] + for item in items: + if item is None: + continue + if type(item) is not type([]): + itemsout.append(item) + else: + itemsout.extend(item) + return itemsout + + +# Disable lint check for exceptions deriving from Exception: +# pylint: disable=W0710 +class ParseError(Error): + """Class for errors from the parser.""" + + def __init__(self, filename, message, lineno=None, snippet=None): + Error.__init__(self, filename, message, lineno=lineno, + addenda=([snippet] if snippet else None)) + + +# We have methods which look like they could be functions: +# pylint: disable=R0201 +class Parser(object): + + def __init__(self, lexer, source, filename): + self.tokens = lexer.tokens + self.source = source + self.filename = filename + + def p_root(self, p): + """root : import root + | module + | definitions""" + if len(p) > 2: + p[0] = _ListFromConcat(p[1], p[2]) + else: + # Generator expects a module. If one wasn't specified insert one with an + # empty name. + if p[1][0] != 'MODULE': + p[0] = [('MODULE', '', None, p[1])] + else: + p[0] = [p[1]] + + def p_import(self, p): + """import : IMPORT STRING_LITERAL""" + # 'eval' the literal to strip the quotes. + p[0] = ('IMPORT', eval(p[2])) + + def p_module(self, p): + """module : attribute_section MODULE identifier LBRACE definitions RBRACE""" + p[0] = ('MODULE', p[3], p[1], p[5]) + + def p_definitions(self, p): + """definitions : definition definitions + | """ + if len(p) > 1: + p[0] = _ListFromConcat(p[1], p[2]) + + def p_definition(self, p): + """definition : struct + | interface + | enum + | const""" + p[0] = p[1] + + def p_attribute_section(self, p): + """attribute_section : LBRACKET attributes RBRACKET + | """ + if len(p) > 3: + p[0] = p[2] + + def p_attributes(self, p): + """attributes : attribute + | attribute COMMA attributes + | """ + if len(p) == 2: + p[0] = _ListFromConcat(p[1]) + elif len(p) > 3: + p[0] = _ListFromConcat(p[1], p[3]) + + def p_attribute(self, p): + """attribute : NAME EQUALS evaled_literal + | NAME EQUALS NAME""" + p[0] = ('ATTRIBUTE', p[1], p[3]) + + def p_evaled_literal(self, p): + """evaled_literal : literal""" + # 'eval' the literal to strip the quotes. + p[0] = eval(p[1]) + + def p_struct(self, p): + """struct : attribute_section STRUCT NAME LBRACE struct_body RBRACE SEMI""" + p[0] = ('STRUCT', p[3], p[1], p[5]) + + def p_struct_body(self, p): + """struct_body : field struct_body + | enum struct_body + | const struct_body + | """ + if len(p) > 1: + p[0] = _ListFromConcat(p[1], p[2]) + + def p_field(self, p): + """field : typename NAME ordinal default SEMI""" + p[0] = ('FIELD', p[1], p[2], p[3], p[4]) + + def p_default(self, p): + """default : EQUALS constant + | """ + if len(p) > 2: + p[0] = p[2] + + def p_interface(self, p): + """interface : attribute_section INTERFACE NAME LBRACE interface_body \ + RBRACE SEMI""" + p[0] = ('INTERFACE', p[3], p[1], p[5]) + + def p_interface_body(self, p): + """interface_body : method interface_body + | enum interface_body + | const interface_body + | """ + if len(p) > 1: + p[0] = _ListFromConcat(p[1], p[2]) + + def p_response(self, p): + """response : RESPONSE LPAREN parameters RPAREN + | """ + if len(p) > 3: + p[0] = p[3] + + def p_method(self, p): + """method : NAME ordinal LPAREN parameters RPAREN response SEMI""" + p[0] = ('METHOD', p[1], p[4], p[2], p[6]) + + def p_parameters(self, p): + """parameters : parameter + | parameter COMMA parameters + | """ + if len(p) == 1: + p[0] = [] + elif len(p) == 2: + p[0] = _ListFromConcat(p[1]) + elif len(p) > 3: + p[0] = _ListFromConcat(p[1], p[3]) + + def p_parameter(self, p): + """parameter : typename NAME ordinal""" + p[0] = ('PARAM', p[1], p[2], p[3]) + + def p_typename(self, p): + """typename : basictypename + | array + | interfacerequest""" + p[0] = p[1] + + def p_basictypename(self, p): + """basictypename : identifier + | handletype""" + p[0] = p[1] + + def p_handletype(self, p): + """handletype : HANDLE + | HANDLE LANGLE NAME RANGLE""" + if len(p) == 2: + p[0] = p[1] + else: + if p[3] not in ('data_pipe_consumer', + 'data_pipe_producer', + 'message_pipe', + 'shared_buffer'): + # Note: We don't enable tracking of line numbers for everything, so we + # can't use |p.lineno(3)|. + raise ParseError(self.filename, "Invalid handle type %r:" % p[3], + lineno=p.lineno(1), + snippet=self._GetSnippet(p.lineno(1))) + p[0] = "handle<" + p[3] + ">" + + def p_array(self, p): + """array : typename LBRACKET RBRACKET""" + p[0] = p[1] + "[]" + + def p_interfacerequest(self, p): + """interfacerequest : identifier AMP""" + p[0] = p[1] + "&" + + def p_ordinal(self, p): + """ordinal : ORDINAL + | """ + if len(p) > 1: + value = int(p[1][1:]) + if value > _MAX_ORDINAL_VALUE: + raise ParseError(self.filename, "Ordinal value %d too large:" % value, + lineno=p.lineno(1), + snippet=self._GetSnippet(p.lineno(1))) + p[0] = ast.Ordinal(value, filename=self.filename, lineno=p.lineno(1)) + else: + p[0] = ast.Ordinal(None) + + def p_enum(self, p): + """enum : ENUM NAME LBRACE enum_fields RBRACE SEMI""" + p[0] = ('ENUM', p[2], p[4]) + + def p_enum_fields(self, p): + """enum_fields : enum_field + | enum_field COMMA enum_fields + | """ + if len(p) == 2: + p[0] = _ListFromConcat(p[1]) + elif len(p) > 3: + p[0] = _ListFromConcat(p[1], p[3]) + + def p_enum_field(self, p): + """enum_field : NAME + | NAME EQUALS constant""" + if len(p) == 2: + p[0] = ('ENUM_FIELD', p[1], None) + else: + p[0] = ('ENUM_FIELD', p[1], p[3]) + + def p_const(self, p): + """const : CONST typename NAME EQUALS constant SEMI""" + p[0] = ('CONST', p[2], p[3], p[5]) + + def p_constant(self, p): + """constant : literal + | identifier_wrapped""" + p[0] = p[1] + + def p_identifier_wrapped(self, p): + """identifier_wrapped : identifier""" + p[0] = ('IDENTIFIER', p[1]) + + def p_identifier(self, p): + """identifier : NAME + | NAME DOT identifier""" + p[0] = ''.join(p[1:]) + + def p_literal(self, p): + """literal : number + | CHAR_CONST + | TRUE + | FALSE + | DEFAULT + | STRING_LITERAL""" + p[0] = p[1] + + def p_number(self, p): + """number : digits + | PLUS digits + | MINUS digits""" + p[0] = ''.join(p[1:]) + + def p_digits(self, p): + """digits : INT_CONST_DEC + | INT_CONST_HEX + | FLOAT_CONST""" + p[0] = p[1] + + def p_error(self, e): + if e is None: + # Unexpected EOF. + # TODO(vtl): Can we figure out what's missing? + raise ParseError(self.filename, "Unexpected end of file") + + raise ParseError(self.filename, "Unexpected %r:" % e.value, lineno=e.lineno, + snippet=self._GetSnippet(e.lineno)) + + def _GetSnippet(self, lineno): + return self.source.split('\n')[lineno - 1] + + +def Parse(source, filename): + lexer = Lexer(filename) + parser = Parser(lexer, source, filename) + + lex.lex(object=lexer) + yacc.yacc(module=parser, debug=0, write_tables=0) + + tree = yacc.parse(source) + return tree diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/parse/translate.py b/chromium/mojo/public/tools/bindings/pylib/mojom/parse/translate.py new file mode 100644 index 00000000000..8407a088c6b --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/parse/translate.py @@ -0,0 +1,144 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Translates parse tree to Mojom IR.""" + + +import ast + + +def _MapTree(func, tree, name): + if not tree: + return [] + return [func(subtree) for subtree in tree if subtree[0] == name] + +def _MapKind(kind): + map_to_kind = { 'bool': 'b', + 'int8': 'i8', + 'int16': 'i16', + 'int32': 'i32', + 'int64': 'i64', + 'uint8': 'u8', + 'uint16': 'u16', + 'uint32': 'u32', + 'uint64': 'u64', + 'float': 'f', + 'double': 'd', + 'string': 's', + 'handle': 'h', + 'handle<data_pipe_consumer>': 'h:d:c', + 'handle<data_pipe_producer>': 'h:d:p', + 'handle<message_pipe>': 'h:m', + 'handle<shared_buffer>': 'h:s'} + if kind.endswith('[]'): + return 'a:' + _MapKind(kind[0:len(kind)-2]) + if kind.endswith('&'): + return 'r:' + _MapKind(kind[0:len(kind)-1]) + if kind in map_to_kind: + return map_to_kind[kind] + return 'x:' + kind + +def _MapAttributes(attributes): + if not attributes: + return {} + return dict([(attribute[1], attribute[2]) + for attribute in attributes if attribute[0] == 'ATTRIBUTE']) + +def _GetAttribute(attributes, name): + out = None + if attributes: + for attribute in attributes: + if attribute[0] == 'ATTRIBUTE' and attribute[1] == name: + out = attribute[2] + return out + +def _MapField(tree): + assert type(tree[3]) is ast.Ordinal + return {'name': tree[2], + 'kind': _MapKind(tree[1]), + 'ordinal': tree[3].value, + 'default': tree[4]} + +def _MapParameter(tree): + assert type(tree[3]) is ast.Ordinal + return {'name': tree[2], + 'kind': _MapKind(tree[1]), + 'ordinal': tree[3].value} + +def _MapMethod(tree): + assert type(tree[3]) is ast.Ordinal + method = {'name': tree[1], + 'parameters': _MapTree(_MapParameter, tree[2], 'PARAM'), + 'ordinal': tree[3].value} + if tree[4] != None: + method['response_parameters'] = _MapTree(_MapParameter, tree[4], 'PARAM') + return method + +def _MapEnumField(tree): + return {'name': tree[1], + 'value': tree[2]} + +def _MapStruct(tree): + struct = {} + struct['name'] = tree[1] + struct['attributes'] = _MapAttributes(tree[2]) + struct['fields'] = _MapTree(_MapField, tree[3], 'FIELD') + struct['enums'] = _MapTree(_MapEnum, tree[3], 'ENUM') + struct['constants'] = _MapTree(_MapConstant, tree[3], 'CONST') + return struct + +def _MapInterface(tree): + interface = {} + interface['name'] = tree[1] + interface['client'] = _GetAttribute(tree[2], 'Client') + interface['methods'] = _MapTree(_MapMethod, tree[3], 'METHOD') + interface['enums'] = _MapTree(_MapEnum, tree[3], 'ENUM') + interface['constants'] = _MapTree(_MapConstant, tree[3], 'CONST') + return interface + +def _MapEnum(tree): + enum = {} + enum['name'] = tree[1] + enum['fields'] = _MapTree(_MapEnumField, tree[2], 'ENUM_FIELD') + return enum + +def _MapConstant(tree): + constant = {} + constant['name'] = tree[2] + constant['kind'] = _MapKind(tree[1]) + constant['value'] = tree[3] + return constant + +def _MapModule(tree, name): + mojom = {} + mojom['name'] = name + mojom['namespace'] = tree[1] + mojom['attributes'] = _MapAttributes(tree[2]) + mojom['structs'] = _MapTree(_MapStruct, tree[3], 'STRUCT') + mojom['interfaces'] = _MapTree(_MapInterface, tree[3], 'INTERFACE') + mojom['enums'] = _MapTree(_MapEnum, tree[3], 'ENUM') + mojom['constants'] = _MapTree(_MapConstant, tree[3], 'CONST') + return mojom + +def _MapImport(tree): + import_item = {} + import_item['filename'] = tree[1] + return import_item + + +class _MojomBuilder(object): + def __init__(self): + self.mojom = {} + + def Build(self, tree, name): + modules = [_MapModule(item, name) for item in tree if item[0] == 'MODULE'] + if len(modules) != 1: + raise Exception('A mojom file must contain exactly 1 module.') + self.mojom = modules[0] + self.mojom['imports'] = _MapTree(_MapImport, tree, 'IMPORT') + return self.mojom + + +def Translate(tree, name): + return _MojomBuilder().Build(tree, name) diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom_tests/__init__.py b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/__init__.py new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/__init__.py diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/__init__.py b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/__init__.py new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/__init__.py diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/lexer_unittest.py b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/lexer_unittest.py new file mode 100644 index 00000000000..28c936d20b8 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/lexer_unittest.py @@ -0,0 +1,187 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import imp +import os.path +import sys +import unittest + +# Disable lint check for finding modules: +# pylint: disable=F0401 + +def _GetDirAbove(dirname): + """Returns the directory "above" this file containing |dirname| (which must + also be "above" this file).""" + path = os.path.abspath(__file__) + while True: + path, tail = os.path.split(path) + assert tail + if tail == dirname: + return path + +try: + imp.find_module("ply") +except ImportError: + sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party")) +from ply import lex + +try: + imp.find_module("mojom") +except ImportError: + sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib")) +import mojom.parse.lexer + + +# This (monkey-patching LexToken to make comparison value-based) is evil, but +# we'll do it anyway. (I'm pretty sure ply's lexer never cares about comparing +# for object identity.) +def _LexTokenEq(self, other): + return self.type == other.type and self.value == other.value and \ + self.lineno == other.lineno and self.lexpos == other.lexpos +setattr(lex.LexToken, '__eq__', _LexTokenEq) + + +def _MakeLexToken(token_type, value, lineno=1, lexpos=0): + """Makes a LexToken with the given parameters. (Note that lineno is 1-based, + but lexpos is 0-based.)""" + rv = lex.LexToken() + rv.type, rv.value, rv.lineno, rv.lexpos = token_type, value, lineno, lexpos + return rv + + +def _MakeLexTokenForKeyword(keyword, **kwargs): + """Makes a LexToken for the given keyword.""" + return _MakeLexToken(keyword.upper(), keyword.lower(), **kwargs) + + +class LexerTest(unittest.TestCase): + """Tests |mojom.parse.lexer.Lexer|.""" + + def __init__(self, *args, **kwargs): + unittest.TestCase.__init__(self, *args, **kwargs) + # Clone all lexer instances from this one, since making a lexer is slow. + self._zygote_lexer = lex.lex(mojom.parse.lexer.Lexer("my_file.mojom")) + + def testValidKeywords(self): + """Tests valid keywords.""" + self.assertEquals(self._SingleTokenForInput("handle"), + _MakeLexTokenForKeyword("handle")) + self.assertEquals(self._SingleTokenForInput("import"), + _MakeLexTokenForKeyword("import")) + self.assertEquals(self._SingleTokenForInput("module"), + _MakeLexTokenForKeyword("module")) + self.assertEquals(self._SingleTokenForInput("struct"), + _MakeLexTokenForKeyword("struct")) + self.assertEquals(self._SingleTokenForInput("interface"), + _MakeLexTokenForKeyword("interface")) + self.assertEquals(self._SingleTokenForInput("enum"), + _MakeLexTokenForKeyword("enum")) + self.assertEquals(self._SingleTokenForInput("const"), + _MakeLexTokenForKeyword("const")) + self.assertEquals(self._SingleTokenForInput("true"), + _MakeLexTokenForKeyword("true")) + self.assertEquals(self._SingleTokenForInput("false"), + _MakeLexTokenForKeyword("false")) + self.assertEquals(self._SingleTokenForInput("default"), + _MakeLexTokenForKeyword("default")) + + def testValidIdentifiers(self): + """Tests identifiers.""" + self.assertEquals(self._SingleTokenForInput("abcd"), + _MakeLexToken("NAME", "abcd")) + self.assertEquals(self._SingleTokenForInput("AbC_d012_"), + _MakeLexToken("NAME", "AbC_d012_")) + self.assertEquals(self._SingleTokenForInput("_0123"), + _MakeLexToken("NAME", "_0123")) + + def testInvalidIdentifiers(self): + with self.assertRaisesRegexp( + mojom.parse.lexer.LexError, + r"^my_file\.mojom:1: Error: Illegal character '\$'$"): + self._TokensForInput("$abc") + with self.assertRaisesRegexp( + mojom.parse.lexer.LexError, + r"^my_file\.mojom:1: Error: Illegal character '\$'$"): + self._TokensForInput("a$bc") + + def testDecimalIntegerConstants(self): + self.assertEquals(self._SingleTokenForInput("0"), + _MakeLexToken("INT_CONST_DEC", "0")) + self.assertEquals(self._SingleTokenForInput("1"), + _MakeLexToken("INT_CONST_DEC", "1")) + self.assertEquals(self._SingleTokenForInput("123"), + _MakeLexToken("INT_CONST_DEC", "123")) + self.assertEquals(self._SingleTokenForInput("10"), + _MakeLexToken("INT_CONST_DEC", "10")) + + def testValidTokens(self): + """Tests valid tokens (which aren't tested elsewhere).""" + # Keywords tested in |testValidKeywords|. + # NAME tested in |testValidIdentifiers|. + self.assertEquals(self._SingleTokenForInput("@123"), + _MakeLexToken("ORDINAL", "@123")) + self.assertEquals(self._SingleTokenForInput("456"), + _MakeLexToken("INT_CONST_DEC", "456")) + self.assertEquals(self._SingleTokenForInput("0x01aB2eF3"), + _MakeLexToken("INT_CONST_HEX", "0x01aB2eF3")) + self.assertEquals(self._SingleTokenForInput("123.456"), + _MakeLexToken("FLOAT_CONST", "123.456")) + self.assertEquals(self._SingleTokenForInput("'x'"), + _MakeLexToken("CHAR_CONST", "'x'")) + self.assertEquals(self._SingleTokenForInput("\"hello\""), + _MakeLexToken("STRING_LITERAL", "\"hello\"")) + self.assertEquals(self._SingleTokenForInput("+"), + _MakeLexToken("PLUS", "+")) + self.assertEquals(self._SingleTokenForInput("-"), + _MakeLexToken("MINUS", "-")) + self.assertEquals(self._SingleTokenForInput("&"), + _MakeLexToken("AMP", "&")) + self.assertEquals(self._SingleTokenForInput("="), + _MakeLexToken("EQUALS", "=")) + self.assertEquals(self._SingleTokenForInput("=>"), + _MakeLexToken("RESPONSE", "=>")) + self.assertEquals(self._SingleTokenForInput("("), + _MakeLexToken("LPAREN", "(")) + self.assertEquals(self._SingleTokenForInput(")"), + _MakeLexToken("RPAREN", ")")) + self.assertEquals(self._SingleTokenForInput("["), + _MakeLexToken("LBRACKET", "[")) + self.assertEquals(self._SingleTokenForInput("]"), + _MakeLexToken("RBRACKET", "]")) + self.assertEquals(self._SingleTokenForInput("{"), + _MakeLexToken("LBRACE", "{")) + self.assertEquals(self._SingleTokenForInput("}"), + _MakeLexToken("RBRACE", "}")) + self.assertEquals(self._SingleTokenForInput("<"), + _MakeLexToken("LANGLE", "<")) + self.assertEquals(self._SingleTokenForInput(">"), + _MakeLexToken("RANGLE", ">")) + self.assertEquals(self._SingleTokenForInput(";"), + _MakeLexToken("SEMI", ";")) + self.assertEquals(self._SingleTokenForInput(","), + _MakeLexToken("COMMA", ",")) + self.assertEquals(self._SingleTokenForInput("."), + _MakeLexToken("DOT", ".")) + + def _TokensForInput(self, input_string): + """Gets a list of tokens for the given input string.""" + lexer = self._zygote_lexer.clone() + lexer.input(input_string) + rv = [] + while True: + tok = lexer.token() + if not tok: + return rv + rv.append(tok) + + def _SingleTokenForInput(self, input_string): + """Gets the single token for the given input string. (Raises an exception if + the input string does not result in exactly one token.)""" + toks = self._TokensForInput(input_string) + assert len(toks) == 1 + return toks[0] + + +if __name__ == "__main__": + unittest.main() diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py new file mode 100644 index 00000000000..024b433410b --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/parser_unittest.py @@ -0,0 +1,493 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import imp +import os.path +import sys +import unittest + +# Disable lint check for finding modules: +# pylint: disable=F0401 + +def _GetDirAbove(dirname): + """Returns the directory "above" this file containing |dirname| (which must + also be "above" this file).""" + path = os.path.abspath(__file__) + while True: + path, tail = os.path.split(path) + assert tail + if tail == dirname: + return path + +try: + imp.find_module("mojom") +except ImportError: + sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib")) +import mojom.parse.ast as ast +import mojom.parse.lexer as lexer +import mojom.parse.parser as parser + + +class ParserTest(unittest.TestCase): + """Tests |parser.Parse()|.""" + + def testTrivialValidSource(self): + """Tests a trivial, but valid, .mojom source.""" + source = """\ +// This is a comment. + +module my_module { +} +""" + self.assertEquals(parser.Parse(source, "my_file.mojom"), + [("MODULE", "my_module", None, None)]) + + def testSourceWithCrLfs(self): + """Tests a .mojom source with CR-LFs instead of LFs.""" + source = "// This is a comment.\r\n\r\nmodule my_module {\r\n}\r\n" + self.assertEquals(parser.Parse(source, "my_file.mojom"), + [("MODULE", "my_module", None, None)]) + + def testUnexpectedEOF(self): + """Tests a "truncated" .mojom source.""" + source = """\ +// This is a comment. + +module my_module { +""" + with self.assertRaisesRegexp( + parser.ParseError, + r"^my_file\.mojom: Error: Unexpected end of file$"): + parser.Parse(source, "my_file.mojom") + + def testCommentLineNumbers(self): + """Tests that line numbers are correctly tracked when comments are + present.""" + source1 = """\ +// Isolated C++-style comments. + +// Foo. +asdf1 +""" + with self.assertRaisesRegexp( + parser.ParseError, + r"^my_file\.mojom:4: Error: Unexpected 'asdf1':\nasdf1$"): + parser.Parse(source1, "my_file.mojom") + + source2 = """\ +// Consecutive C++-style comments. +// Foo. + // Bar. + +struct Yada { // Baz. +// Quux. + int32 x; +}; + +asdf2 +""" + with self.assertRaisesRegexp( + parser.ParseError, + r"^my_file\.mojom:10: Error: Unexpected 'asdf2':\nasdf2$"): + parser.Parse(source2, "my_file.mojom") + + source3 = """\ +/* Single-line C-style comments. */ +/* Foobar. */ + +/* Baz. */ +asdf3 +""" + with self.assertRaisesRegexp( + parser.ParseError, + r"^my_file\.mojom:5: Error: Unexpected 'asdf3':\nasdf3$"): + parser.Parse(source3, "my_file.mojom") + + source4 = """\ +/* Multi-line C-style comments. +*/ +/* +Foo. +Bar. +*/ + +/* Baz + Quux. */ +asdf4 +""" + with self.assertRaisesRegexp( + parser.ParseError, + r"^my_file\.mojom:10: Error: Unexpected 'asdf4':\nasdf4$"): + parser.Parse(source4, "my_file.mojom") + + + def testSimpleStruct(self): + """Tests a simple .mojom source that just defines a struct.""" + source = """\ +module my_module { + +struct MyStruct { + int32 a; + double b; +}; + +} // module my_module +""" + expected = \ +[('MODULE', + 'my_module', + None, + [('STRUCT', + 'MyStruct', + None, + [('FIELD', 'int32', 'a', ast.Ordinal(None), None), + ('FIELD', 'double', 'b', ast.Ordinal(None), None)])])] + self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) + + def testSimpleStructWithoutModule(self): + """Tests a simple struct without an enclosing module.""" + source = """\ +struct MyStruct { + int32 a; + double b; +}; +""" + expected = \ +[('MODULE', + '', + None, + [('STRUCT', + 'MyStruct', + None, + [('FIELD', 'int32', 'a', ast.Ordinal(None), None), + ('FIELD', 'double', 'b', ast.Ordinal(None), None)])])] + self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) + + def testMissingModuleName(self): + """Tests an (invalid) .mojom with a missing module name.""" + source1 = """\ +// Missing module name. +module { +struct MyStruct { + int32 a; +}; +} +""" + with self.assertRaisesRegexp( + parser.ParseError, + r"^my_file\.mojom:2: Error: Unexpected '{':\nmodule {$"): + parser.Parse(source1, "my_file.mojom") + + # Another similar case, but make sure that line-number tracking/reporting + # is correct. + source2 = """\ +module +// This line intentionally left unblank. + +{ +} +""" + with self.assertRaisesRegexp( + parser.ParseError, + r"^my_file\.mojom:4: Error: Unexpected '{':\n{$"): + parser.Parse(source2, "my_file.mojom") + + def testEnumInitializers(self): + """Tests an enum with simple initialized values.""" + source = """\ +module my_module { + +enum MyEnum { + MY_ENUM_NEG1 = -1, + MY_ENUM_ZERO = 0, + MY_ENUM_1 = +1, + MY_ENUM_2, +}; + +} // my_module +""" + expected = \ +[('MODULE', + 'my_module', + None, + [('ENUM', + 'MyEnum', + [('ENUM_FIELD', 'MY_ENUM_NEG1', '-1'), + ('ENUM_FIELD', 'MY_ENUM_ZERO', '0'), + ('ENUM_FIELD', 'MY_ENUM_1', '+1'), + ('ENUM_FIELD', 'MY_ENUM_2', None)])])] + self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) + + def testConst(self): + """Tests some constants and struct memebers initialized with them.""" + source = """\ +module my_module { + +struct MyStruct { + const int8 kNumber = -1; + int8 number@0 = kNumber; +}; + +} // my_module +""" + expected = \ +[('MODULE', + 'my_module', + None, + [('STRUCT', + 'MyStruct', None, + [('CONST', 'int8', 'kNumber', '-1'), + ('FIELD', 'int8', 'number', + ast.Ordinal(0), ('IDENTIFIER', 'kNumber'))])])] + self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) + + def testNoConditionals(self): + """Tests that ?: is not allowed.""" + source = """\ +module my_module { + +enum MyEnum { + MY_ENUM_1 = 1 ? 2 : 3 +}; + +} // my_module +""" + with self.assertRaisesRegexp( + lexer.LexError, + r"^my_file\.mojom:4: Error: Illegal character '\?'$"): + parser.Parse(source, "my_file.mojom") + + def testSimpleOrdinals(self): + """Tests that (valid) ordinal values are scanned correctly.""" + source = """\ +module my_module { + +// This isn't actually valid .mojom, but the problem (missing ordinals) should +// be handled at a different level. +struct MyStruct { + int32 a0@0; + int32 a1@1; + int32 a2@2; + int32 a9@9; + int32 a10 @10; + int32 a11 @11; + int32 a29 @29; + int32 a1234567890 @1234567890; +}; + +} // module my_module +""" + expected = \ +[('MODULE', + 'my_module', + None, + [('STRUCT', + 'MyStruct', + None, + [('FIELD', 'int32', 'a0', ast.Ordinal(0), None), + ('FIELD', 'int32', 'a1', ast.Ordinal(1), None), + ('FIELD', 'int32', 'a2', ast.Ordinal(2), None), + ('FIELD', 'int32', 'a9', ast.Ordinal(9), None), + ('FIELD', 'int32', 'a10', ast.Ordinal(10), None), + ('FIELD', 'int32', 'a11', ast.Ordinal(11), None), + ('FIELD', 'int32', 'a29', ast.Ordinal(29), None), + ('FIELD', 'int32', 'a1234567890', ast.Ordinal(1234567890), None)])])] + self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) + + def testInvalidOrdinals(self): + """Tests that (lexically) invalid ordinals are correctly detected.""" + source1 = """\ +module my_module { + +struct MyStruct { + int32 a_missing@; +}; + +} // module my_module +""" + with self.assertRaisesRegexp( + lexer.LexError, + r"^my_file\.mojom:4: Error: Missing ordinal value$"): + parser.Parse(source1, "my_file.mojom") + + source2 = """\ +module my_module { + +struct MyStruct { + int32 a_octal@01; +}; + +} // module my_module +""" + with self.assertRaisesRegexp( + lexer.LexError, + r"^my_file\.mojom:4: Error: " + r"Octal and hexadecimal ordinal values not allowed$"): + parser.Parse(source2, "my_file.mojom") + + source3 = """\ +module my_module { struct MyStruct { int32 a_invalid_octal@08; }; } +""" + with self.assertRaisesRegexp( + lexer.LexError, + r"^my_file\.mojom:1: Error: " + r"Octal and hexadecimal ordinal values not allowed$"): + parser.Parse(source3, "my_file.mojom") + + source4 = """\ +module my_module { struct MyStruct { int32 a_hex@0x1aB9; }; } +""" + with self.assertRaisesRegexp( + lexer.LexError, + r"^my_file\.mojom:1: Error: " + r"Octal and hexadecimal ordinal values not allowed$"): + parser.Parse(source4, "my_file.mojom") + + source5 = """\ +module my_module { struct MyStruct { int32 a_hex@0X0; }; } +""" + with self.assertRaisesRegexp( + lexer.LexError, + r"^my_file\.mojom:1: Error: " + r"Octal and hexadecimal ordinal values not allowed$"): + parser.Parse(source5, "my_file.mojom") + + source6 = """\ +struct MyStruct { + int32 a_too_big@999999999999; +}; +""" + with self.assertRaisesRegexp( + parser.ParseError, + r"^my_file\.mojom:2: Error: " + r"Ordinal value 999999999999 too large:\n" + r" int32 a_too_big@999999999999;$"): + parser.Parse(source6, "my_file.mojom") + + def testNestedNamespace(self): + """Tests that "nested" namespaces work.""" + source = """\ +module my.mod { + +struct MyStruct { + int32 a; +}; + +} // module my.mod +""" + expected = \ +[('MODULE', + 'my.mod', + None, + [('STRUCT', + 'MyStruct', + None, + [('FIELD', 'int32', 'a', ast.Ordinal(None), None)])])] + self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) + + def testValidHandleTypes(self): + """Tests (valid) handle types.""" + source = """\ +struct MyStruct { + handle a; + handle<data_pipe_consumer> b; + handle <data_pipe_producer> c; + handle < message_pipe > d; + handle + < shared_buffer + > e; +}; +""" + expected = \ +[('MODULE', + '', + None, + [('STRUCT', + 'MyStruct', + None, + [('FIELD', 'handle', 'a', ast.Ordinal(None), None), + ('FIELD', 'handle<data_pipe_consumer>', 'b', ast.Ordinal(None), None), + ('FIELD', 'handle<data_pipe_producer>', 'c', ast.Ordinal(None), None), + ('FIELD', 'handle<message_pipe>', 'd', ast.Ordinal(None), None), + ('FIELD', 'handle<shared_buffer>', 'e', ast.Ordinal(None), None)])])] + self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) + + def testInvalidHandleType(self): + """Tests an invalid (unknown) handle type.""" + source = """\ +struct MyStruct { + handle<wtf_is_this> foo; +}; +""" + with self.assertRaisesRegexp( + parser.ParseError, + r"^my_file\.mojom:2: Error: " + r"Invalid handle type 'wtf_is_this':\n" + r" handle<wtf_is_this> foo;$"): + parser.Parse(source, "my_file.mojom") + + def testValidDefaultValues(self): + """Tests default values that are valid (to the parser).""" + source = """\ +struct MyStruct { + int16 a0 = 0; + uint16 a1 = 0x0; + uint16 a2 = 0x00; + uint16 a3 = 0x01; + uint16 a4 = 0xcd; + int32 a5 = 12345; + int64 a6 = -12345; + int64 a7 = +12345; + uint32 a8 = 0x12cd3; + uint32 a9 = -0x12cD3; + uint32 a10 = +0x12CD3; + bool a11 = true; + bool a12 = false; + float a13 = 1.2345; + float a14 = -1.2345; + float a15 = +1.2345; + float a16 = 123.; + float a17 = .123; + double a18 = 1.23E10; + double a19 = 1.E-10; + double a20 = .5E+10; + double a21 = -1.23E10; + double a22 = +.123E10; +}; +""" + expected = \ +[('MODULE', + '', + None, + [('STRUCT', + 'MyStruct', + None, + [('FIELD', 'int16', 'a0', ast.Ordinal(None), '0'), + ('FIELD', 'uint16', 'a1', ast.Ordinal(None), '0x0'), + ('FIELD', 'uint16', 'a2', ast.Ordinal(None), '0x00'), + ('FIELD', 'uint16', 'a3', ast.Ordinal(None), '0x01'), + ('FIELD', 'uint16', 'a4', ast.Ordinal(None), '0xcd'), + ('FIELD', 'int32', 'a5' , ast.Ordinal(None), '12345'), + ('FIELD', 'int64', 'a6', ast.Ordinal(None), '-12345'), + ('FIELD', 'int64', 'a7', ast.Ordinal(None), '+12345'), + ('FIELD', 'uint32', 'a8', ast.Ordinal(None), '0x12cd3'), + ('FIELD', 'uint32', 'a9', ast.Ordinal(None), '-0x12cD3'), + ('FIELD', 'uint32', 'a10', ast.Ordinal(None), '+0x12CD3'), + ('FIELD', 'bool', 'a11', ast.Ordinal(None), 'true'), + ('FIELD', 'bool', 'a12', ast.Ordinal(None), 'false'), + ('FIELD', 'float', 'a13', ast.Ordinal(None), '1.2345'), + ('FIELD', 'float', 'a14', ast.Ordinal(None), '-1.2345'), + ('FIELD', 'float', 'a15', ast.Ordinal(None), '+1.2345'), + ('FIELD', 'float', 'a16', ast.Ordinal(None), '123.'), + ('FIELD', 'float', 'a17', ast.Ordinal(None), '.123'), + ('FIELD', 'double', 'a18', ast.Ordinal(None), '1.23E10'), + ('FIELD', 'double', 'a19', ast.Ordinal(None), '1.E-10'), + ('FIELD', 'double', 'a20', ast.Ordinal(None), '.5E+10'), + ('FIELD', 'double', 'a21', ast.Ordinal(None), '-1.23E10'), + ('FIELD', 'double', 'a22', ast.Ordinal(None), '+.123E10')])])] + self.assertEquals(parser.Parse(source, "my_file.mojom"), expected) + + +if __name__ == "__main__": + unittest.main() diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/run_parser.py b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/run_parser.py new file mode 100755 index 00000000000..edca7e11ff1 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/run_parser.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Simple testing utility to just run the mojom parser.""" + + +import os.path +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), + os.path.pardir, os.path.pardir)) + +# Disable lint check for finding modules: +# pylint: disable=F0401 + +from mojom.parse.parser import Parse, ParseError + + +def main(argv): + if len(argv) < 2: + print "usage: %s filename" % argv[0] + return 0 + + for filename in argv[1:]: + with open(filename) as f: + print "%s:" % filename + try: + print Parse(f.read(), filename) + except ParseError, e: + print e + return 1 + + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/run_translate.py b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/run_translate.py new file mode 100755 index 00000000000..833af6292a7 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/parse/run_translate.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Simple testing utility to just run the mojom translate stage.""" + + +import os.path +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), + os.path.pardir, os.path.pardir)) + +# Disable lint check for finding modules: +# pylint: disable=F0401 + +from mojom.parse.parser import Parse +from mojom.parse.translate import Translate + + +def main(argv): + if len(argv) < 2: + print "usage: %s filename" % sys.argv[0] + return 1 + + for filename in argv[1:]: + with open(filename) as f: + print "%s:" % filename + print Translate(Parse(f.read(), filename), + os.path.splitext(os.path.basename(filename))[0]) + + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom_tests/support/__init__.py b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/support/__init__.py new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/support/__init__.py diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom_tests/support/find_files.py b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/support/find_files.py new file mode 100644 index 00000000000..00524a2413a --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/support/find_files.py @@ -0,0 +1,32 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from fnmatch import filter +from os import walk +from os.path import join +import sys + + +def FindFiles(top, pattern, **kwargs): + """Finds files under |top| matching the glob pattern |pattern|, returning a + list of paths.""" + matches = [] + for dirpath, _, filenames in walk(top, **kwargs): + for filename in filter(filenames, pattern): + matches.append(join(dirpath, filename)) + return matches + + +def main(argv): + if len(argv) != 3: + print "usage: %s path pattern" % argv[0] + return 1 + + for filename in FindFiles(argv[1], argv[2]): + print filename + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom_tests/support/run_bindings_generator.py b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/support/run_bindings_generator.py new file mode 100644 index 00000000000..20ef4619699 --- /dev/null +++ b/chromium/mojo/public/tools/bindings/pylib/mojom_tests/support/run_bindings_generator.py @@ -0,0 +1,47 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os.path +from subprocess import check_call +import sys + + +def RunBindingsGenerator(out_dir, root_dir, mojom_file, extra_flags=None): + out_dir = os.path.abspath(out_dir) + root_dir = os.path.abspath(root_dir) + mojom_file = os.path.abspath(mojom_file) + + # The mojom file should be under the root directory somewhere. + assert mojom_file.startswith(root_dir) + mojom_reldir = os.path.dirname(os.path.relpath(mojom_file, root_dir)) + + # TODO(vtl): Abstract out the "main" functions, so that we can just import + # the bindings generator (which would be more portable and easier to use in + # tests). + this_dir = os.path.dirname(os.path.abspath(__file__)) + # We're in src/mojo/public/tools/bindings/pylib/mojom_tests/support; + # mojom_bindings_generator.py is in .../bindings. + bindings_generator = os.path.join(this_dir, os.pardir, os.pardir, os.pardir, + "mojom_bindings_generator.py") + + args = ["python", bindings_generator, + "-o", os.path.join(out_dir, mojom_reldir)] + if extra_flags: + args.extend(extra_flags) + args.append(mojom_file) + + check_call(args) + + +def main(argv): + if len(argv) < 4: + print "usage: %s out_dir root_dir mojom_file [extra_flags]" % argv[0] + return 1 + + RunBindingsGenerator(argv[1], argv[2], argv[3], extra_flags=argv[4:]) + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) |