diff options
26 files changed, 1322 insertions, 6 deletions
diff --git a/ppapi/api/dev/ppb_var_dictionary_dev.idl b/ppapi/api/dev/ppb_var_dictionary_dev.idl new file mode 100644 index 0000000..f3e7407 --- /dev/null +++ b/ppapi/api/dev/ppb_var_dictionary_dev.idl @@ -0,0 +1,89 @@ +/* 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. + */ + +/** + * This file defines the <code>PPB_VarDictionary_Dev</code> struct providing + * a way to interact with dictionary vars. + */ + +label Chrome { + M27 = 0.1 +}; + +/** + * A dictionary var contains key-value pairs with unique keys. The keys are + * strings while the values can be arbitrary vars. Key comparison is always + * done by value instead of by reference. + */ +[macro="PPB_VAR_DICTIONARY_DEV_INTERFACE"] +interface PPB_VarDictionary_Dev { + /** + * Creates a dictionary var, i.e., a <code>PP_Var</code> with type set to + * <code>PP_VARTYPE_DICTIONARY</code>. + * + * @return An empty dictionary var, whose reference count is set to 1 on + * behalf of the caller. + */ + PP_Var Create(); + + /** + * Gets the value associated with the specified key. + * + * @param[in] dict A dictionary var. + * @param[in] key A string var. + * + * @return The value that is associated with <code>key</code>. The reference + * count is incremented on behalf of the caller. If <code>key</code> is not a + * string var, or it doesn't exist in <code>dict</code>, an undefined var is + * returned. + */ + PP_Var Get([in] PP_Var dict, [in] PP_Var key); + + /** + * Sets the value associated with the specified key. The dictionary is + * responsible for holding references to its children to keep them alive. + * + * @param[in] dict A dictionary var. + * @param[in] key A string var. If this key hasn't existed in + * <code>dict</code>, it is added and associated with <code>value</code>; + * otherwise, the previous value is replaced with <code>value</code>. + * @param[in] value The value to set. + * + * @return A <code>PP_Bool</code> indicating whether the operation succeeds. + */ + PP_Bool Set([in] PP_Var dict, [in] PP_Var key, [in] PP_Var value); + + /** + * Deletes the specified key and its associated value, if the key exists. + * + * @param[in] dict A dictionary var. + * @param[in] key A string var. + */ + void Delete([in] PP_Var dict, [in] PP_Var key); + + /** + * Checks whether a key exists. + * + * @param[in] dict A dictionary var. + * @param[in] key A string var. + * + * @return A <code>PP_Bool</code> indicating whether the key exists. + */ + PP_Bool HasKey([in] PP_Var dict, [in] PP_Var key); + + /** + * Gets all the keys in a dictionary. Please note that for each key that you + * set into the dictionary, a string var with the same contents is returned; + * but it may not be the same string var (i.e., <code>value.as_id</code> may + * be different). + * + * @param[in] dict A dictionary var. + * + * @return An array var which contains all the keys of <code>dict</code>. Its + * reference count is incremented on behalf of the caller. The elements are + * string vars. Returns a null var if failed. + */ + PP_Var GetKeys([in] PP_Var dict); +}; diff --git a/ppapi/c/dev/ppb_var_dictionary_dev.h b/ppapi/c/dev/ppb_var_dictionary_dev.h new file mode 100644 index 0000000..d601071 --- /dev/null +++ b/ppapi/c/dev/ppb_var_dictionary_dev.h @@ -0,0 +1,106 @@ +/* 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. + */ + +/* From dev/ppb_var_dictionary_dev.idl modified Wed Mar 13 21:47:05 2013. */ + +#ifndef PPAPI_C_DEV_PPB_VAR_DICTIONARY_DEV_H_ +#define PPAPI_C_DEV_PPB_VAR_DICTIONARY_DEV_H_ + +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_macros.h" +#include "ppapi/c/pp_stdint.h" +#include "ppapi/c/pp_var.h" + +#define PPB_VAR_DICTIONARY_DEV_INTERFACE_0_1 "PPB_VarDictionary(Dev);0.1" +#define PPB_VAR_DICTIONARY_DEV_INTERFACE PPB_VAR_DICTIONARY_DEV_INTERFACE_0_1 + +/** + * @file + * This file defines the <code>PPB_VarDictionary_Dev</code> struct providing + * a way to interact with dictionary vars. + */ + + +/** + * @addtogroup Interfaces + * @{ + */ +/** + * A dictionary var contains key-value pairs with unique keys. The keys are + * strings while the values can be arbitrary vars. Key comparison is always + * done by value instead of by reference. + */ +struct PPB_VarDictionary_Dev_0_1 { + /** + * Creates a dictionary var, i.e., a <code>PP_Var</code> with type set to + * <code>PP_VARTYPE_DICTIONARY</code>. + * + * @return An empty dictionary var, whose reference count is set to 1 on + * behalf of the caller. + */ + struct PP_Var (*Create)(void); + /** + * Gets the value associated with the specified key. + * + * @param[in] dict A dictionary var. + * @param[in] key A string var. + * + * @return The value that is associated with <code>key</code>. The reference + * count is incremented on behalf of the caller. If <code>key</code> is not a + * string var, or it doesn't exist in <code>dict</code>, an undefined var is + * returned. + */ + struct PP_Var (*Get)(struct PP_Var dict, struct PP_Var key); + /** + * Sets the value associated with the specified key. The dictionary is + * responsible for holding references to its children to keep them alive. + * + * @param[in] dict A dictionary var. + * @param[in] key A string var. If this key hasn't existed in + * <code>dict</code>, it is added and associated with <code>value</code>; + * otherwise, the previous value is replaced with <code>value</code>. + * @param[in] value The value to set. + * + * @return A <code>PP_Bool</code> indicating whether the operation succeeds. + */ + PP_Bool (*Set)(struct PP_Var dict, struct PP_Var key, struct PP_Var value); + /** + * Deletes the specified key and its associated value, if the key exists. + * + * @param[in] dict A dictionary var. + * @param[in] key A string var. + */ + void (*Delete)(struct PP_Var dict, struct PP_Var key); + /** + * Checks whether a key exists. + * + * @param[in] dict A dictionary var. + * @param[in] key A string var. + * + * @return A <code>PP_Bool</code> indicating whether the key exists. + */ + PP_Bool (*HasKey)(struct PP_Var dict, struct PP_Var key); + /** + * Gets all the keys in a dictionary. Please note that for each key that you + * set into the dictionary, a string var with the same contents is returned; + * but it may not be the same string var (i.e., <code>value.as_id</code> may + * be different). + * + * @param[in] dict A dictionary var. + * + * @return An array var which contains all the keys of <code>dict</code>. Its + * reference count is incremented on behalf of the caller. The elements are + * string vars. Returns a null var if failed. + */ + struct PP_Var (*GetKeys)(struct PP_Var dict); +}; + +typedef struct PPB_VarDictionary_Dev_0_1 PPB_VarDictionary_Dev; +/** + * @} + */ + +#endif /* PPAPI_C_DEV_PPB_VAR_DICTIONARY_DEV_H_ */ + diff --git a/ppapi/cpp/dev/var_dictionary_dev.cc b/ppapi/cpp/dev/var_dictionary_dev.cc new file mode 100644 index 0000000..cb0ba5c --- /dev/null +++ b/ppapi/cpp/dev/var_dictionary_dev.cc @@ -0,0 +1,97 @@ +// 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. + +#include "ppapi/cpp/dev/var_dictionary_dev.h" + +#include "ppapi/c/dev/ppb_var_dictionary_dev.h" +#include "ppapi/cpp/logging.h" +#include "ppapi/cpp/module_impl.h" + +namespace pp { + +namespace { + +template <> const char* interface_name<PPB_VarDictionary_Dev_0_1>() { + return PPB_VAR_DICTIONARY_DEV_INTERFACE_0_1; +} + +} // namespace + +VarDictionary_Dev::VarDictionary_Dev() : Var(Null()) { + if (has_interface<PPB_VarDictionary_Dev_0_1>()) + var_ = get_interface<PPB_VarDictionary_Dev_0_1>()->Create(); + else + PP_NOTREACHED(); +} + +VarDictionary_Dev::VarDictionary_Dev(const Var& var) : Var(var) { + if (!var.is_dictionary()) { + PP_NOTREACHED(); + + // This takes care of releasing the reference that this object holds. + Var::operator=(Var(Null())); + } +} + +VarDictionary_Dev::VarDictionary_Dev(const VarDictionary_Dev& other) + : Var(other) { +} + +VarDictionary_Dev::~VarDictionary_Dev() { +} + +VarDictionary_Dev& VarDictionary_Dev::operator=( + const VarDictionary_Dev& other) { + Var::operator=(other); + return *this; +} + +Var& VarDictionary_Dev::operator=(const Var& other) { + if (other.is_dictionary()) { + Var::operator=(other); + } else { + PP_NOTREACHED(); + Var::operator=(Var(Null())); + } + return *this; +} + +Var VarDictionary_Dev::Get(const Var& key) const { + if (!has_interface<PPB_VarDictionary_Dev_0_1>()) + return Var(); + + return Var( + PASS_REF, + get_interface<PPB_VarDictionary_Dev_0_1>()->Get(var_, key.pp_var())); +} + +PP_Bool VarDictionary_Dev::Set(const Var& key, const Var& value) { + if (!has_interface<PPB_VarDictionary_Dev_0_1>()) + return PP_FALSE; + + return get_interface<PPB_VarDictionary_Dev_0_1>()->Set(var_, key.pp_var(), + value.pp_var()); +} + +void VarDictionary_Dev::Delete(const Var& key) { + if (has_interface<PPB_VarDictionary_Dev_0_1>()) + get_interface<PPB_VarDictionary_Dev_0_1>()->Delete(var_, key.pp_var()); +} + +PP_Bool VarDictionary_Dev::HasKey(const Var& key) const { + if (!has_interface<PPB_VarDictionary_Dev_0_1>()) + return PP_FALSE; + + return get_interface<PPB_VarDictionary_Dev_0_1>()->HasKey(var_, key.pp_var()); +} + +Var VarDictionary_Dev::GetKeys() const { + if (!has_interface<PPB_VarDictionary_Dev_0_1>()) + return Var(Null()); + + return Var(PASS_REF, + get_interface<PPB_VarDictionary_Dev_0_1>()->GetKeys(var_)); +} + +} // namespace pp diff --git a/ppapi/cpp/dev/var_dictionary_dev.h b/ppapi/cpp/dev/var_dictionary_dev.h new file mode 100644 index 0000000..a7f3abf --- /dev/null +++ b/ppapi/cpp/dev/var_dictionary_dev.h @@ -0,0 +1,87 @@ +// 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. + +#ifndef PPAPI_CPP_DEV_VAR_DICTIONARY_DEV_H_ +#define PPAPI_CPP_DEV_VAR_DICTIONARY_DEV_H_ + +#include "ppapi/c/pp_bool.h" +#include "ppapi/cpp/var.h" + +/// @file +/// This file defines the API for interacting with dictionary vars. + +namespace pp { + +class VarDictionary_Dev : public Var { + public: + /// Constructs a new dictionary var. + VarDictionary_Dev(); + + /// Contructs a <code>VarDictionary_Dev</code> given a var for which + /// is_dictionary() is true. This will refer to the same dictionary var, but + /// allow you to access methods specific to dictionary. + /// + /// @param[in] var A dictionary var. + explicit VarDictionary_Dev(const Var& var); + + /// Copy constructor. + VarDictionary_Dev(const VarDictionary_Dev& other); + + virtual ~VarDictionary_Dev(); + + /// Assignment operator. + VarDictionary_Dev& operator=(const VarDictionary_Dev& other); + + /// The <code>Var</code> assignment operator is overridden here so that we can + /// check for assigning a non-dictionary var to a + /// <code>VarDictionary_Dev</code>. + /// + /// @param[in] other The dictionary var to be assigned. + /// + /// @return The resulting <code>VarDictionary_Dev</code> (as a + /// <code>Var</code>&). + virtual Var& operator=(const Var& other); + + /// Gets the value associated with the specified key. + /// + /// @param[in] key A string var. + /// + /// @return The value that is associated with <code>key</code>. If + /// <code>key</code> is not a string var, or it doesn't exist in the + /// dictionary, an undefined var is returned. + Var Get(const Var& key) const; + + /// Sets the value associated with the specified key. + /// + /// @param[in] key A string var. If this key hasn't existed in the dictionary, + /// it is added and associated with <code>value</code>; otherwise, the + /// previous value is replaced with <code>value</code>. + /// @param[in] value The value to set. + /// + /// @return A <code>PP_Bool</code> indicating whether the operation succeeds. + PP_Bool Set(const Var& key, const Var& value); + + /// Deletes the specified key and its associated value, if the key exists. + /// + /// @param[in] key A string var. + void Delete(const Var& key); + + /// Checks whether a key exists. + /// + /// @param[in] key A string var. + /// + /// @return A <code>PP_Bool</code> indicating whether the key exists. + PP_Bool HasKey(const Var& key) const; + + /// Gets all the keys in the dictionary. + /// + /// @return An array var which contains all the keys of the dictionary. + /// The elements are string vars. Returns a null var if failed. + /// TODO(yzshen): Change Var to VarArray_Dev once it is supported. + Var GetKeys() const; +}; + +} // namespace pp + +#endif // PPAPI_CPP_DEV_VAR_DICTIONARY_DEV_H_ diff --git a/ppapi/cpp/var.cc b/ppapi/cpp/var.cc index 09a8fe3..1108e05 100644 --- a/ppapi/cpp/var.cc +++ b/ppapi/cpp/var.cc @@ -241,10 +241,16 @@ std::string Var::DebugString() const { str.append("..."); } snprintf(buf, sizeof(buf), format, str.c_str()); - } else if (is_array_buffer()) { - snprintf(buf, sizeof(buf), "Var(ARRAY_BUFFER)"); } else if (is_object()) { snprintf(buf, sizeof(buf), "Var(OBJECT)"); + } else if (is_array()) { + snprintf(buf, sizeof(buf), "Var(ARRAY)"); + } else if (is_dictionary()) { + snprintf(buf, sizeof(buf), "Var(DICTIONARY)"); + } else if (is_array_buffer()) { + snprintf(buf, sizeof(buf), "Var(ARRAY_BUFFER)"); + } else { + buf[0] = '\0'; } return buf; } diff --git a/ppapi/cpp/var.h b/ppapi/cpp/var.h index d114054..77bb5d8 100644 --- a/ppapi/cpp/var.h +++ b/ppapi/cpp/var.h @@ -122,9 +122,19 @@ class Var { /// This function determines if this <code>Var</code> is an object. /// - /// @return true if this <code>Var</code> is an object, otherwise false. + /// @return true if this <code>Var</code> is an object, otherwise false. bool is_object() const { return var_.type == PP_VARTYPE_OBJECT; } + /// This function determines if this <code>Var</code> is an array. + /// + /// @return true if this <code>Var</code> is an array, otherwise false. + bool is_array() const { return var_.type == PP_VARTYPE_ARRAY; } + + /// This function determines if this <code>Var</code> is a dictionary. + /// + /// @return true if this <code>Var</code> is a dictinoary, otherwise false. + bool is_dictionary() const { return var_.type == PP_VARTYPE_DICTIONARY; } + /// This function determines if this <code>Var</code> is an integer value. /// The <code>is_int</code> function returns the internal representation. /// The JavaScript runtime may convert between the two as needed, so the diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c index 310f946..1777207 100644 --- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c +++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c @@ -28,6 +28,7 @@ #include "ppapi/c/dev/ppb_trace_event_dev.h" #include "ppapi/c/dev/ppb_truetype_font_dev.h" #include "ppapi/c/dev/ppb_url_util_dev.h" +#include "ppapi/c/dev/ppb_var_dictionary_dev.h" #include "ppapi/c/dev/ppb_video_capture_dev.h" #include "ppapi/c/dev/ppb_video_decoder_dev.h" #include "ppapi/c/dev/ppb_view_dev.h" @@ -209,6 +210,7 @@ static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TextInput_Dev_0_2; static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Trace_Event_Dev_0_1; static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TrueTypeFont_Dev_0_1; static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_URLUtil_Dev_0_6; +static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_VarDictionary_Dev_0_1; static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_VideoCapture_Dev_0_2; static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_VideoCapture_Dev_0_3; static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_VideoDecoder_Dev_0_16; @@ -2085,6 +2087,46 @@ struct PP_Var Pnacl_M17_PPB_URLUtil_Dev_GetPluginInstanceURL(PP_Instance instanc /* End wrapper methods for PPB_URLUtil_Dev_0_6 */ +/* Begin wrapper methods for PPB_VarDictionary_Dev_0_1 */ + +static __attribute__((pnaclcall)) +struct PP_Var Pnacl_M27_PPB_VarDictionary_Dev_Create(void) { + const struct PPB_VarDictionary_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_VarDictionary_Dev_0_1.real_iface; + return iface->Create(); +} + +static __attribute__((pnaclcall)) +struct PP_Var Pnacl_M27_PPB_VarDictionary_Dev_Get(struct PP_Var dict, struct PP_Var key) { + const struct PPB_VarDictionary_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_VarDictionary_Dev_0_1.real_iface; + return iface->Get(dict, key); +} + +static __attribute__((pnaclcall)) +PP_Bool Pnacl_M27_PPB_VarDictionary_Dev_Set(struct PP_Var dict, struct PP_Var key, struct PP_Var value) { + const struct PPB_VarDictionary_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_VarDictionary_Dev_0_1.real_iface; + return iface->Set(dict, key, value); +} + +static __attribute__((pnaclcall)) +void Pnacl_M27_PPB_VarDictionary_Dev_Delete(struct PP_Var dict, struct PP_Var key) { + const struct PPB_VarDictionary_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_VarDictionary_Dev_0_1.real_iface; + iface->Delete(dict, key); +} + +static __attribute__((pnaclcall)) +PP_Bool Pnacl_M27_PPB_VarDictionary_Dev_HasKey(struct PP_Var dict, struct PP_Var key) { + const struct PPB_VarDictionary_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_VarDictionary_Dev_0_1.real_iface; + return iface->HasKey(dict, key); +} + +static __attribute__((pnaclcall)) +struct PP_Var Pnacl_M27_PPB_VarDictionary_Dev_GetKeys(struct PP_Var dict) { + const struct PPB_VarDictionary_Dev_0_1 *iface = Pnacl_WrapperInfo_PPB_VarDictionary_Dev_0_1.real_iface; + return iface->GetKeys(dict); +} + +/* End wrapper methods for PPB_VarDictionary_Dev_0_1 */ + /* Begin wrapper methods for PPB_VideoCapture_Dev_0_2 */ static __attribute__((pnaclcall)) @@ -4180,6 +4222,15 @@ struct PPB_URLUtil_Dev_0_6 Pnacl_Wrappers_PPB_URLUtil_Dev_0_6 = { .GetPluginInstanceURL = (struct PP_Var (*)(PP_Instance instance, struct PP_URLComponents_Dev* components))&Pnacl_M17_PPB_URLUtil_Dev_GetPluginInstanceURL }; +struct PPB_VarDictionary_Dev_0_1 Pnacl_Wrappers_PPB_VarDictionary_Dev_0_1 = { + .Create = (struct PP_Var (*)(void))&Pnacl_M27_PPB_VarDictionary_Dev_Create, + .Get = (struct PP_Var (*)(struct PP_Var dict, struct PP_Var key))&Pnacl_M27_PPB_VarDictionary_Dev_Get, + .Set = (PP_Bool (*)(struct PP_Var dict, struct PP_Var key, struct PP_Var value))&Pnacl_M27_PPB_VarDictionary_Dev_Set, + .Delete = (void (*)(struct PP_Var dict, struct PP_Var key))&Pnacl_M27_PPB_VarDictionary_Dev_Delete, + .HasKey = (PP_Bool (*)(struct PP_Var dict, struct PP_Var key))&Pnacl_M27_PPB_VarDictionary_Dev_HasKey, + .GetKeys = (struct PP_Var (*)(struct PP_Var dict))&Pnacl_M27_PPB_VarDictionary_Dev_GetKeys +}; + struct PPB_VideoCapture_Dev_0_2 Pnacl_Wrappers_PPB_VideoCapture_Dev_0_2 = { .Create = (PP_Resource (*)(PP_Instance instance))&Pnacl_M19_PPB_VideoCapture_Dev_Create, .IsVideoCapture = (PP_Bool (*)(PP_Resource video_capture))&Pnacl_M19_PPB_VideoCapture_Dev_IsVideoCapture, @@ -5054,6 +5105,12 @@ static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_URLUtil_Dev_0_6 = { .real_iface = NULL }; +static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_VarDictionary_Dev_0_1 = { + .iface_macro = PPB_VAR_DICTIONARY_DEV_INTERFACE_0_1, + .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_VarDictionary_Dev_0_1, + .real_iface = NULL +}; + static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_VideoCapture_Dev_0_2 = { .iface_macro = PPB_VIDEOCAPTURE_DEV_INTERFACE_0_2, .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_VideoCapture_Dev_0_2, @@ -5489,6 +5546,7 @@ static struct __PnaclWrapperInfo *s_ppb_wrappers[] = { &Pnacl_WrapperInfo_PPB_Trace_Event_Dev_0_1, &Pnacl_WrapperInfo_PPB_TrueTypeFont_Dev_0_1, &Pnacl_WrapperInfo_PPB_URLUtil_Dev_0_6, + &Pnacl_WrapperInfo_PPB_VarDictionary_Dev_0_1, &Pnacl_WrapperInfo_PPB_VideoCapture_Dev_0_2, &Pnacl_WrapperInfo_PPB_VideoCapture_Dev_0_3, &Pnacl_WrapperInfo_PPB_VideoDecoder_Dev_0_16, diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi index 6bfb2d9..699ef08 100644 --- a/ppapi/ppapi_shared.gypi +++ b/ppapi/ppapi_shared.gypi @@ -24,6 +24,8 @@ 'shared_impl/array_writer.h', 'shared_impl/callback_tracker.cc', 'shared_impl/callback_tracker.h', + 'shared_impl/dictionary_var.cc', + 'shared_impl/dictionary_var.h', 'shared_impl/file_io_state_manager.cc', 'shared_impl/file_io_state_manager.h', 'shared_impl/file_path.cc', @@ -111,6 +113,8 @@ 'shared_impl/var.h', 'shared_impl/var_tracker.cc', 'shared_impl/var_tracker.h', + 'shared_impl/var_value_conversions.cc', + 'shared_impl/var_value_conversions.h', # TODO(viettrungluu): Split these out; it won't be used in NaCl. 'shared_impl/private/net_address_private_impl.cc', 'shared_impl/private/net_address_private_impl.h', @@ -229,6 +233,7 @@ 'thunk/ppb_url_response_info_api.h', 'thunk/ppb_url_response_info_thunk.cc', 'thunk/ppb_url_util_thunk.cc', + 'thunk/ppb_var_dictionary_thunk.cc', 'thunk/ppb_video_capture_api.h', 'thunk/ppb_video_capture_thunk.cc', 'thunk/ppb_video_decoder_api.h', diff --git a/ppapi/ppapi_sources.gypi b/ppapi/ppapi_sources.gypi index 185cbb9..73e7a3f 100644 --- a/ppapi/ppapi_sources.gypi +++ b/ppapi/ppapi_sources.gypi @@ -77,6 +77,7 @@ 'c/dev/ppb_text_input_dev.h', 'c/dev/ppb_truetype_font_dev.h', 'c/dev/ppb_url_util_dev.h', + 'c/dev/ppb_var_dictionary_dev.h', 'c/dev/ppb_video_decoder_dev.h', 'c/dev/ppb_widget_dev.h', 'c/dev/ppb_zoom_dev.h', @@ -243,6 +244,8 @@ 'cpp/dev/truetype_font_dev.h', 'cpp/dev/url_util_dev.cc', 'cpp/dev/url_util_dev.h', + 'cpp/dev/var_dictionary_dev.cc', + 'cpp/dev/var_dictionary_dev.h', 'cpp/dev/video_capture_client_dev.cc', 'cpp/dev/video_capture_client_dev.h', 'cpp/dev/video_capture_dev.cc', diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi index c805ef6..a400e98 100644 --- a/ppapi/ppapi_tests.gypi +++ b/ppapi/ppapi_tests.gypi @@ -166,6 +166,7 @@ 'shared_impl/time_conversion_unittest.cc', 'shared_impl/tracked_callback_unittest.cc', 'shared_impl/var_tracker_unittest.cc', + 'shared_impl/var_value_conversions_unittest.cc', ], 'conditions': [ [ 'os_posix == 1 and OS != "mac" and OS != "android" and OS != "ios"', { diff --git a/ppapi/proxy/interface_list.cc b/ppapi/proxy/interface_list.cc index 4beeaab..9a4fd20 100644 --- a/ppapi/proxy/interface_list.cc +++ b/ppapi/proxy/interface_list.cc @@ -28,6 +28,7 @@ #include "ppapi/c/dev/ppb_truetype_font_dev.h" #include "ppapi/c/dev/ppb_url_util_dev.h" #include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/dev/ppb_var_dictionary_dev.h" #include "ppapi/c/dev/ppb_video_capture_dev.h" #include "ppapi/c/dev/ppb_view_dev.h" #include "ppapi/c/ppb_audio_config.h" diff --git a/ppapi/proxy/serialized_var.cc b/ppapi/proxy/serialized_var.cc index ad416db..5352e8f 100644 --- a/ppapi/proxy/serialized_var.cc +++ b/ppapi/proxy/serialized_var.cc @@ -140,7 +140,7 @@ void SerializedVar::Inner::WriteToMessage(IPC::Message* m) const { break; case PP_VARTYPE_ARRAY: case PP_VARTYPE_DICTIONARY: - // TODO(brettw) when these are supported, implement this. + // TODO(yzshen) when these are supported, implement this. NOTIMPLEMENTED(); break; } @@ -210,7 +210,7 @@ bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m, break; case PP_VARTYPE_ARRAY: case PP_VARTYPE_DICTIONARY: - // TODO(brettw) when these types are supported, implement this. + // TODO(yzshen) when these types are supported, implement this. NOTIMPLEMENTED(); break; default: diff --git a/ppapi/shared_impl/dictionary_var.cc b/ppapi/shared_impl/dictionary_var.cc new file mode 100644 index 0000000..9bfebb9 --- /dev/null +++ b/ppapi/shared_impl/dictionary_var.cc @@ -0,0 +1,101 @@ +// 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. + +#include "ppapi/shared_impl/dictionary_var.h" + +#include "base/memory/ref_counted.h" +#include "base/string_util.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/var_tracker.h" + +namespace ppapi { + +DictionaryVar::DictionaryVar() { +} + +DictionaryVar::~DictionaryVar() { +} + +// static +DictionaryVar* DictionaryVar::FromPPVar(const PP_Var& var) { + if (var.type != PP_VARTYPE_DICTIONARY) + return NULL; + + scoped_refptr<Var> var_object( + PpapiGlobals::Get()->GetVarTracker()->GetVar(var)); + if (!var_object.get()) + return NULL; + return var_object->AsDictionaryVar(); +} + +DictionaryVar* DictionaryVar::AsDictionaryVar() { + return this; +} + +PP_VarType DictionaryVar::GetType() const { + return PP_VARTYPE_DICTIONARY; +} + +PP_Var DictionaryVar::Get(const PP_Var& key) const { + StringVar* string_var = StringVar::FromPPVar(key); + if (!string_var) + return PP_MakeUndefined(); + + KeyValueMap::const_iterator iter = key_value_map_.find(string_var->value()); + if (iter != key_value_map_.end()) { + if (PpapiGlobals::Get()->GetVarTracker()->AddRefVar(iter->second.get())) + return iter->second.get(); + else + return PP_MakeUndefined(); + } else { + return PP_MakeUndefined(); + } +} + +PP_Bool DictionaryVar::Set(const PP_Var& key, const PP_Var& value) { + StringVar* string_var = StringVar::FromPPVar(key); + if (!string_var) + return PP_FALSE; + + key_value_map_[string_var->value()] = value; + return PP_TRUE; +} + +void DictionaryVar::Delete(const PP_Var& key) { + StringVar* string_var = StringVar::FromPPVar(key); + if (!string_var) + return; + + key_value_map_.erase(string_var->value()); +} + +PP_Bool DictionaryVar::HasKey(const PP_Var& key) const { + StringVar* string_var = StringVar::FromPPVar(key); + if (!string_var) + return PP_FALSE; + + bool result = + key_value_map_.find(string_var->value()) != key_value_map_.end(); + return PP_FromBool(result); +} + +PP_Var DictionaryVar::GetKeys() const { + // TODO(yzshen): Implement once array PP_Var is supported. + return PP_MakeNull(); +} + +bool DictionaryVar::SetWithStringKey(const std::string& utf8_key, + const PP_Var& value) { + if (!IsStringUTF8(utf8_key)) + return false; + + key_value_map_[utf8_key] = value; + return true; +} + +void DictionaryVar::DeleteWithStringKey(const std::string& utf8_key) { + key_value_map_.erase(utf8_key); +} + +} // namespace ppapi diff --git a/ppapi/shared_impl/dictionary_var.h b/ppapi/shared_impl/dictionary_var.h new file mode 100644 index 0000000..cdc63bd --- /dev/null +++ b/ppapi/shared_impl/dictionary_var.h @@ -0,0 +1,63 @@ +// 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. + +#ifndef PPAPI_SHARED_IMPL_DICTIONARY_VAR_H_ +#define PPAPI_SHARED_IMPL_DICTIONARY_VAR_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/shared_impl/ppapi_shared_export.h" +#include "ppapi/shared_impl/scoped_pp_var.h" +#include "ppapi/shared_impl/var.h" + +namespace ppapi { + +class PPAPI_SHARED_EXPORT DictionaryVar : public Var { + public: + typedef std::map<std::string, ScopedPPVar> KeyValueMap; + + DictionaryVar(); + + // Helper function that converts a PP_Var to a DictionaryVar. This will + // return NULL if the PP_Var is not of type PP_VARTYPE_DICTIONARY or the + // dictionary cannot be found from the var tracker. + static DictionaryVar* FromPPVar(const PP_Var& var); + + // Var overrides. + virtual DictionaryVar* AsDictionaryVar() OVERRIDE; + virtual PP_VarType GetType() const OVERRIDE; + + // The returned PP_Var has had a ref added on behalf of the caller. + PP_Var Get(const PP_Var& key) const; + PP_Bool Set(const PP_Var& key, const PP_Var& value); + void Delete(const PP_Var& key); + PP_Bool HasKey(const PP_Var& key) const; + // The returned PP_Var has had a ref added on behalf of the caller. + PP_Var GetKeys() const; + + // Returns false and keeps the dictionary unchanged if |key| is not a valid + // UTF-8 string. + bool SetWithStringKey(const std::string& utf8_key, const PP_Var& value); + void DeleteWithStringKey(const std::string& utf8_key); + + const KeyValueMap& key_value_map() const { + return key_value_map_; + } + + protected: + virtual ~DictionaryVar(); + + private: + KeyValueMap key_value_map_; + + DISALLOW_COPY_AND_ASSIGN(DictionaryVar); +}; + +} // namespace ppapi + +#endif // PPAPI_SHARED_IMPL_DICTIONARY_VAR_H_ diff --git a/ppapi/shared_impl/scoped_pp_var.cc b/ppapi/shared_impl/scoped_pp_var.cc index fcd6806..3ae13b0 100644 --- a/ppapi/shared_impl/scoped_pp_var.cc +++ b/ppapi/shared_impl/scoped_pp_var.cc @@ -47,4 +47,10 @@ ScopedPPVar& ScopedPPVar::operator=(const PP_Var& v) { return *this; } +PP_Var ScopedPPVar::Release() { + PP_Var result = var_; + var_ = PP_MakeUndefined(); + return result; +} + } // namespace ppapi diff --git a/ppapi/shared_impl/var.cc b/ppapi/shared_impl/var.cc index 2e63dbe..8870e3e 100644 --- a/ppapi/shared_impl/var.cc +++ b/ppapi/shared_impl/var.cc @@ -56,6 +56,12 @@ std::string Var::PPVarToLogString(PP_Var var) { } case PP_VARTYPE_OBJECT: return "[Object]"; + case PP_VARTYPE_ARRAY: + return "[Array]"; + case PP_VARTYPE_DICTIONARY: + return "[Dictionary]"; + case PP_VARTYPE_ARRAY_BUFFER: + return "[Array buffer]"; default: return "[Invalid var]"; } @@ -77,6 +83,10 @@ ProxyObjectVar* Var::AsProxyObjectVar() { return NULL; } +DictionaryVar* Var::AsDictionaryVar() { + return NULL; +} + PP_Var Var::GetPPVar() { int32 id = GetOrCreateVarID(); if (!id) diff --git a/ppapi/shared_impl/var.h b/ppapi/shared_impl/var.h index 77f707c..76654b4 100644 --- a/ppapi/shared_impl/var.h +++ b/ppapi/shared_impl/var.h @@ -15,6 +15,7 @@ namespace ppapi { class ArrayBufferVar; +class DictionaryVar; class NPObjectVar; class ProxyObjectVar; class StringVar; @@ -34,6 +35,7 @@ class PPAPI_SHARED_EXPORT Var : public base::RefCounted<Var> { virtual ArrayBufferVar* AsArrayBufferVar(); virtual NPObjectVar* AsNPObjectVar(); virtual ProxyObjectVar* AsProxyObjectVar(); + virtual DictionaryVar* AsDictionaryVar(); // Creates a PP_Var corresponding to this object. The return value will have // one reference addrefed on behalf of the caller. diff --git a/ppapi/shared_impl/var_tracker.cc b/ppapi/shared_impl/var_tracker.cc index 6bc0261..a704c3a 100644 --- a/ppapi/shared_impl/var_tracker.cc +++ b/ppapi/shared_impl/var_tracker.cc @@ -90,7 +90,7 @@ bool VarTracker::AddRefVar(const PP_Var& var) { ProxyLock::AssertAcquired(); if (!IsVarTypeRefcounted(var.type)) - return false; + return true; return AddRefVar(static_cast<int32>(var.value.as_id)); } diff --git a/ppapi/shared_impl/var_value_conversions.cc b/ppapi/shared_impl/var_value_conversions.cc new file mode 100644 index 0000000..a54c726 --- /dev/null +++ b/ppapi/shared_impl/var_value_conversions.cc @@ -0,0 +1,298 @@ +// 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. + +#include "ppapi/shared_impl/var_value_conversions.h" + +#include <limits> +#include <set> +#include <stack> + +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/stl_util.h" +#include "base/values.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_stdint.h" +#include "ppapi/shared_impl/dictionary_var.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/scoped_pp_var.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/shared_impl/var_tracker.h" + +namespace ppapi { + +namespace { + +// In CreateValueFromVar(), a stack is used to keep track of conversion progress +// of array and dictionary vars. VarNode represents elements of that stack. +struct VarNode { + VarNode(const PP_Var& in_var, base::Value* in_value) + : var(in_var), + value(in_value), + sentinel(false) { + } + + // This object doesn't hold a reference to it. + PP_Var var; + // It is not owned by this object. + base::Value* value; + // When this is set to true for a node in the stack, it means that we have + // finished processing the node itself. However, we keep it in the stack as + // a sentinel. When it becomes the top element of the stack again, we know + // that we have processed all the descendants of this node. + bool sentinel; +}; + +// In CreateVarFromValue(), a stack is used to keep track of conversion progress +// of list and dictionary values. ValueNode represents elements of that stack. +struct ValueNode { + ValueNode(const PP_Var& in_var, const base::Value* in_value) + : var(in_var), + value(in_value) { + } + + // This object doesn't hold a reference to it. + PP_Var var; + // It is not owned by this object. + const base::Value* value; +}; + +// Helper function for CreateValueFromVar(). It only looks at |var| but not its +// descendants. The conversion result is stored in |value|. If |var| is array or +// dictionary, a new node is pushed onto |state|. +// +// Returns false on failure. +bool CreateValueFromVarHelper(const std::set<int64_t>& parent_ids, + const PP_Var& var, + scoped_ptr<base::Value>* value, + std::stack<VarNode>* state) { + switch (var.type) { + case PP_VARTYPE_UNDEFINED: + case PP_VARTYPE_NULL: { + value->reset(base::Value::CreateNullValue()); + return true; + } + case PP_VARTYPE_BOOL: { + value->reset(new base::FundamentalValue(PP_ToBool(var.value.as_bool))); + return true; + } + case PP_VARTYPE_INT32: { + value->reset(new base::FundamentalValue(var.value.as_int)); + return true; + } + case PP_VARTYPE_DOUBLE: { + value->reset(new base::FundamentalValue(var.value.as_double)); + return true; + } + case PP_VARTYPE_STRING: { + StringVar* string_var = StringVar::FromPPVar(var); + if (!string_var) + return false; + + value->reset(new base::StringValue(string_var->value())); + return true; + } + case PP_VARTYPE_OBJECT: { + return false; + } + case PP_VARTYPE_ARRAY: { + // TODO(yzshen): Implement it once array var is supported. + return false; + } + case PP_VARTYPE_DICTIONARY: { + if (ContainsKey(parent_ids, var.value.as_id)) { + // A circular reference is found. + return false; + } + + value->reset(new base::DictionaryValue()); + state->push(VarNode(var, value->get())); + return true; + } + case PP_VARTYPE_ARRAY_BUFFER: { + ArrayBufferVar* array_buffer = ArrayBufferVar::FromPPVar(var); + if (!array_buffer) + return false; + + base::BinaryValue* binary_value = + base::BinaryValue::CreateWithCopiedBuffer( + static_cast<const char*>(array_buffer->Map()), + array_buffer->ByteLength()); + array_buffer->Unmap(); + value->reset(binary_value); + return true; + } + } + NOTREACHED(); + return false; +} + +// Helper function for CreateVarFromValue(). It only looks at |value| but not +// its descendants. The conversion result is stored in |var|. If |value| is list +// or dictionary, a new node is pushed onto |state|. +// +// Returns false on failure. +bool CreateVarFromValueHelper(const base::Value& value, + ScopedPPVar* var, + std::stack<ValueNode>* state) { + switch (value.GetType()) { + case base::Value::TYPE_NULL: { + *var = PP_MakeNull(); + return true; + } + case base::Value::TYPE_BOOLEAN: { + bool result = false; + if (value.GetAsBoolean(&result)) { + *var = PP_MakeBool(PP_FromBool(result)); + return true; + } + return false; + } + case base::Value::TYPE_INTEGER: { + int result = 0; + if (value.GetAsInteger(&result)) { + *var = PP_MakeInt32(result); + return true; + } + return false; + } + case base::Value::TYPE_DOUBLE: { + double result = 0; + if (value.GetAsDouble(&result)) { + *var = PP_MakeDouble(result); + return true; + } + return false; + } + case base::Value::TYPE_STRING: { + std::string result; + if (value.GetAsString(&result)) { + *var = ScopedPPVar(ScopedPPVar::PassRef(), + StringVar::StringToPPVar(result)); + return true; + } + return false; + } + case base::Value::TYPE_BINARY: { + const base::BinaryValue& binary_value = + static_cast<const base::BinaryValue&>(value); + + size_t size = binary_value.GetSize(); + if (size > std::numeric_limits<uint32>::max()) + return false; + + ScopedPPVar temp( + ScopedPPVar::PassRef(), + PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( + static_cast<uint32>(size), binary_value.GetBuffer())); + if (temp.get().type == PP_VARTYPE_ARRAY_BUFFER) { + *var = temp; + return true; + } + return false; + } + case base::Value::TYPE_DICTIONARY: { + scoped_refptr<DictionaryVar> dict_var(new DictionaryVar()); + *var = ScopedPPVar(ScopedPPVar::PassRef(), dict_var->GetPPVar()); + state->push(ValueNode(var->get(), &value)); + return true; + } + case base::Value::TYPE_LIST: { + // TODO(yzshen): Add support once array var is supported. + return false; + } + } + NOTREACHED(); + return false; +} + +} // namespace + +base::Value* CreateValueFromVar(const PP_Var& var) { + // Used to detect circular references. + std::set<int64_t> parent_ids; + std::stack<VarNode> state; + scoped_ptr<base::Value> root_value; + + if (!CreateValueFromVarHelper(parent_ids, var, &root_value, &state)) + return NULL; + + while (!state.empty()) { + VarNode& top = state.top(); + if (top.sentinel) { + parent_ids.erase(top.var.value.as_id); + state.pop(); + } else if (top.var.type == PP_VARTYPE_DICTIONARY) { + parent_ids.insert(top.var.value.as_id); + top.sentinel = true; + + DictionaryVar* dict_var = DictionaryVar::FromPPVar(top.var); + if (!dict_var) + return NULL; + + DCHECK(top.value->GetType() == base::Value::TYPE_DICTIONARY); + base::DictionaryValue* dict_value = + static_cast<base::DictionaryValue*>(top.value); + + for (DictionaryVar::KeyValueMap::const_iterator iter = + dict_var->key_value_map().begin(); + iter != dict_var->key_value_map().end(); + ++iter) { + // Skip the key-value pair if the value is undefined. + if (iter->second.get().type == PP_VARTYPE_UNDEFINED) + continue; + + scoped_ptr<base::Value> child_value; + if (!CreateValueFromVarHelper(parent_ids, iter->second.get(), + &child_value, &state)) { + return NULL; + } + + dict_value->SetWithoutPathExpansion(iter->first, child_value.release()); + } + } else { + NOTREACHED(); + return NULL; + } + } + DCHECK(parent_ids.empty()); + return root_value.release(); +} + +PP_Var CreateVarFromValue(const base::Value& value) { + std::stack<ValueNode> state; + ScopedPPVar root_var; + + if (!CreateVarFromValueHelper(value, &root_var, &state)) + return PP_MakeUndefined(); + + while (!state.empty()) { + ValueNode top = state.top(); + state.pop(); + + if (top.value->GetType() == base::Value::TYPE_DICTIONARY) { + const base::DictionaryValue* dict_value = + static_cast<const base::DictionaryValue*>(top.value); + DictionaryVar* dict_var = DictionaryVar::FromPPVar(top.var); + DCHECK(dict_var); + for (base::DictionaryValue::Iterator iter(*dict_value); + !iter.IsAtEnd(); + iter.Advance()) { + ScopedPPVar child_var; + if (!CreateVarFromValueHelper(iter.value(), &child_var, &state) || + !dict_var->SetWithStringKey(iter.key(), child_var.get())) { + return PP_MakeUndefined(); + } + } + } else { + NOTREACHED(); + return PP_MakeUndefined(); + } + } + + return root_var.Release(); +} +} // namespace ppapi + diff --git a/ppapi/shared_impl/var_value_conversions.h b/ppapi/shared_impl/var_value_conversions.h new file mode 100644 index 0000000..09145ce --- /dev/null +++ b/ppapi/shared_impl/var_value_conversions.h @@ -0,0 +1,41 @@ +// 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. + +#ifndef PPAPI_SHARED_IMPL_VAR_VALUE_CONVERSIONS_H_ +#define PPAPI_SHARED_IMPL_VAR_VALUE_CONVERSIONS_H_ + +#include "ppapi/c/pp_var.h" +#include "ppapi/shared_impl/ppapi_shared_export.h" + +namespace base { +class Value; +} + +namespace ppapi { + +// Converts a PP_Var to a base::Value object. The caller takes ownership of the +// returned object. +// +// Both PP_VARTYPE_UNDEFINED and PP_VARTYPE_NULL are converted to +// base::Value::TYPE_NULL. In dictionary vars, key-value pairs whose value is +// undefined (PP_VARTYPE_UNDEFINED) are ignored. If a node in |var| appears more +// than once, it is duplicated in the result. For example, if |var| is an array +// and it has two elements pointing to the same dictionary, the resulting list +// value will have two copies of the dictionary. +// +// The conversion fails and returns NULL if +// - |var| is object (PP_VARTYPE_OBJECT); or +// - |var| is an array or dictionary, and calling CreateValueFromVar() on any of +// the array elements or dictionary values fails; or +// - there exist circular references, i.e., an array or dictionary is its own +// ancestor/descendant. +PPAPI_SHARED_EXPORT base::Value* CreateValueFromVar(const PP_Var& var); + +// The returned var has been added ref on behalf of the caller. +// Returns an undefined var if the conversion fails. +PPAPI_SHARED_EXPORT PP_Var CreateVarFromValue(const base::Value& value); + +} // namespace ppapi + +#endif // PPAPI_SHARED_IMPL_VAR_VALUE_CONVERSIONS_H_ diff --git a/ppapi/shared_impl/var_value_conversions_unittest.cc b/ppapi/shared_impl/var_value_conversions_unittest.cc new file mode 100644 index 0000000..d9a2769 --- /dev/null +++ b/ppapi/shared_impl/var_value_conversions_unittest.cc @@ -0,0 +1,241 @@ +// 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. + +#include "ppapi/shared_impl/var_value_conversions.h" + +#include <cmath> +#include <cstring> + +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/shared_impl/dictionary_var.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/shared_impl/scoped_pp_var.h" +#include "ppapi/shared_impl/test_globals.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/shared_impl/var_tracker.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ppapi { +namespace { + +bool Equals(const base::Value& value, const PP_Var& var) { + switch (value.GetType()) { + case base::Value::TYPE_NULL: { + return var.type == PP_VARTYPE_NULL || var.type == PP_VARTYPE_UNDEFINED; + } + case base::Value::TYPE_BOOLEAN: { + bool result = false; + return var.type == PP_VARTYPE_BOOL && + value.GetAsBoolean(&result) && + result == PP_ToBool(var.value.as_bool); + } + case base::Value::TYPE_INTEGER: { + int result = 0; + return var.type == PP_VARTYPE_INT32 && + value.GetAsInteger(&result) && + result == var.value.as_int; + } + case base::Value::TYPE_DOUBLE: { + double result = 0; + return var.type == PP_VARTYPE_DOUBLE && + value.GetAsDouble(&result) && + fabs(result - var.value.as_double) < 1.0e-4; + } + case base::Value::TYPE_STRING: { + std::string result; + StringVar* string_var = StringVar::FromPPVar(var); + return string_var && + value.GetAsString(&result) && + result == string_var->value(); + } + case base::Value::TYPE_BINARY: { + const base::BinaryValue& binary_value = + static_cast<const base::BinaryValue&>(value); + ArrayBufferVar* array_buffer_var = ArrayBufferVar::FromPPVar(var); + if (!array_buffer_var || + binary_value.GetSize() != array_buffer_var->ByteLength()) { + return false; + } + + bool result = !memcmp(binary_value.GetBuffer(), array_buffer_var->Map(), + binary_value.GetSize()); + array_buffer_var->Unmap(); + return result; + } + case base::Value::TYPE_DICTIONARY: { + const base::DictionaryValue& dict_value = + static_cast<const base::DictionaryValue&>(value); + DictionaryVar* dict_var = DictionaryVar::FromPPVar(var); + if (!dict_var) + return false; + + size_t non_undefined_count = 0; + for (DictionaryVar::KeyValueMap::const_iterator iter = + dict_var->key_value_map().begin(); + iter != dict_var->key_value_map().end(); + ++iter) { + if (iter->second.get().type == PP_VARTYPE_UNDEFINED) + continue; + + ++non_undefined_count; + const base::Value* sub_value = NULL; + if (!dict_value.GetWithoutPathExpansion(iter->first, &sub_value) || + !Equals(*sub_value, iter->second.get())) { + return false; + } + } + return non_undefined_count == dict_value.size(); + } + case base::Value::TYPE_LIST: { + // TODO(yzshen): add support once array var is supported. + return false; + } + } + NOTREACHED(); + return false; +} + +class VarValueConversionsTest : public testing::Test { + public: + VarValueConversionsTest() { + } + virtual ~VarValueConversionsTest() { + } + + // testing::Test implementation. + virtual void SetUp() { + ProxyLock::Acquire(); + } + virtual void TearDown() { + ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty()); + ProxyLock::Release(); + } + + private: + TestGlobals globals_; +}; + +} // namespace + +TEST_F(VarValueConversionsTest, CreateValueFromVar) { + { + // Var holding a ref to itself is not a valid input. + scoped_refptr<DictionaryVar> dict_var_1(new DictionaryVar()); + ScopedPPVar var_1(ScopedPPVar::PassRef(), dict_var_1->GetPPVar()); + scoped_refptr<DictionaryVar> dict_var_2(new DictionaryVar()); + ScopedPPVar var_2(ScopedPPVar::PassRef(), dict_var_2->GetPPVar()); + + ASSERT_TRUE(dict_var_1->SetWithStringKey("key_1", var_2.get())); + scoped_ptr<base::Value> value(CreateValueFromVar(var_1.get())); + ASSERT_TRUE(value.get()); + + ASSERT_TRUE(dict_var_2->SetWithStringKey("key_2", var_1.get())); + value.reset(CreateValueFromVar(var_1.get())); + ASSERT_EQ(NULL, value.get()); + + // Make sure |var_1| doesn't indirectly hold a ref to itself, otherwise it + // is leaked. + dict_var_1->DeleteWithStringKey("key_1"); + } + + // Vars of null or undefined type are converted to null values. + { + scoped_ptr<base::Value> value(CreateValueFromVar(PP_MakeNull())); + ASSERT_TRUE(value.get()); + ASSERT_TRUE(Equals(*value, PP_MakeNull())); + + value.reset(CreateValueFromVar(PP_MakeUndefined())); + ASSERT_TRUE(value.get()); + ASSERT_TRUE(Equals(*value, PP_MakeUndefined())); + } + + { + // Key-value pairs whose value is undefined are ignored. + scoped_refptr<DictionaryVar> dict_var(new DictionaryVar()); + ASSERT_TRUE(dict_var->SetWithStringKey("key_1", PP_MakeUndefined())); + ASSERT_TRUE(dict_var->SetWithStringKey("key_2", PP_MakeInt32(1))); + ScopedPPVar var(ScopedPPVar::PassRef(), dict_var->GetPPVar()); + + scoped_ptr<base::Value> value(CreateValueFromVar(var.get())); + ASSERT_TRUE(value.get()); + ASSERT_TRUE(Equals(*value, var.get())); + } + + { + // The same PP_Var is allowed to appear multiple times. + scoped_refptr<DictionaryVar> dict_var_1(new DictionaryVar()); + ScopedPPVar dict_pp_var_1(ScopedPPVar::PassRef(), dict_var_1->GetPPVar()); + scoped_refptr<DictionaryVar> dict_var_2(new DictionaryVar()); + ScopedPPVar dict_pp_var_2(ScopedPPVar::PassRef(), dict_var_2->GetPPVar()); + scoped_refptr<StringVar> string_var(new StringVar("string_value")); + ScopedPPVar string_pp_var(ScopedPPVar::PassRef(), string_var->GetPPVar()); + + ASSERT_TRUE(dict_var_1->SetWithStringKey("key_1", dict_pp_var_2.get())); + ASSERT_TRUE(dict_var_1->SetWithStringKey("key_2", dict_pp_var_2.get())); + ASSERT_TRUE(dict_var_1->SetWithStringKey("key_3", string_pp_var.get())); + ASSERT_TRUE(dict_var_2->SetWithStringKey("key_4", string_pp_var.get())); + + scoped_ptr<base::Value> value(CreateValueFromVar(dict_pp_var_1.get())); + ASSERT_TRUE(value.get()); + ASSERT_TRUE(Equals(*value, dict_pp_var_1.get())); + } + + { + // Test more complex inputs. + scoped_refptr<DictionaryVar> dict_var_1(new DictionaryVar()); + ScopedPPVar dict_pp_var_1(ScopedPPVar::PassRef(), dict_var_1->GetPPVar()); + scoped_refptr<DictionaryVar> dict_var_2(new DictionaryVar()); + ScopedPPVar dict_pp_var_2(ScopedPPVar::PassRef(), dict_var_2->GetPPVar()); + scoped_refptr<StringVar> string_var(new StringVar("string_value")); + ScopedPPVar string_pp_var(ScopedPPVar::PassRef(), string_var->GetPPVar()); + + ASSERT_TRUE(dict_var_1->SetWithStringKey("null_key", PP_MakeNull())); + ASSERT_TRUE(dict_var_1->SetWithStringKey("string_key", + string_pp_var.get())); + ASSERT_TRUE(dict_var_1->SetWithStringKey("dict_key", dict_pp_var_2.get())); + + ASSERT_TRUE(dict_var_2->SetWithStringKey("undefined_key", + PP_MakeUndefined())); + ASSERT_TRUE(dict_var_2->SetWithStringKey("double_key", PP_MakeDouble(1))); + ASSERT_TRUE(dict_var_2->SetWithStringKey("int_key", PP_MakeInt32(2))); + ASSERT_TRUE(dict_var_2->SetWithStringKey("bool_key", PP_MakeBool(PP_TRUE))); + + scoped_ptr<base::Value> value(CreateValueFromVar(dict_pp_var_1.get())); + ASSERT_TRUE(value.get()); + ASSERT_TRUE(Equals(*value, dict_pp_var_1.get())); + } + + { + // Test that dictionary keys containing '.' are handled correctly. + scoped_refptr<DictionaryVar> dict_var(new DictionaryVar()); + ScopedPPVar dict_pp_var(ScopedPPVar::PassRef(), dict_var->GetPPVar()); + + ASSERT_TRUE(dict_var->SetWithStringKey("double.key", PP_MakeDouble(1))); + ASSERT_TRUE(dict_var->SetWithStringKey("int.key..name", PP_MakeInt32(2))); + + scoped_ptr<base::Value> value(CreateValueFromVar(dict_pp_var.get())); + ASSERT_TRUE(value.get()); + ASSERT_TRUE(Equals(*value, dict_pp_var.get())); + } +} + +TEST_F(VarValueConversionsTest, CreateVarFromValue) { + base::DictionaryValue dict_value; + dict_value.Set("null_key", base::Value::CreateNullValue()); + dict_value.SetString("string_key", "string_value"); + dict_value.SetDouble("dict_key.double_key", 1); + dict_value.SetInteger("dict_key.int_key", 2); + dict_value.SetBoolean("dict_key.bool_key", true); + + ScopedPPVar var(ScopedPPVar::PassRef(), CreateVarFromValue(dict_value)); + ASSERT_TRUE(Equals(dict_value, var.get())); +} + +} // namespace ppapi diff --git a/ppapi/tests/all_c_includes.h b/ppapi/tests/all_c_includes.h index 7d7a690..1f004d9 100644 --- a/ppapi/tests/all_c_includes.h +++ b/ppapi/tests/all_c_includes.h @@ -32,6 +32,7 @@ #include "ppapi/c/dev/ppb_truetype_font_dev.h" #include "ppapi/c/dev/ppb_url_util_dev.h" #include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/dev/ppb_var_dictionary_dev.h" #include "ppapi/c/dev/ppb_video_decoder_dev.h" #include "ppapi/c/dev/ppb_view_dev.h" #include "ppapi/c/dev/ppb_widget_dev.h" diff --git a/ppapi/tests/all_cpp_includes.h b/ppapi/tests/all_cpp_includes.h index e00e53a..6f643ad 100644 --- a/ppapi/tests/all_cpp_includes.h +++ b/ppapi/tests/all_cpp_includes.h @@ -29,6 +29,7 @@ #include "ppapi/cpp/dev/selection_dev.h" #include "ppapi/cpp/dev/text_input_dev.h" #include "ppapi/cpp/dev/url_util_dev.h" +#include "ppapi/cpp/dev/var_dictionary_dev.h" #include "ppapi/cpp/dev/video_decoder_dev.h" #include "ppapi/cpp/dev/view_dev.h" #include "ppapi/cpp/dev/widget_client_dev.h" diff --git a/ppapi/thunk/interfaces_ppb_public_dev.h b/ppapi/thunk/interfaces_ppb_public_dev.h index d0570d9..27f3b9c 100644 --- a/ppapi/thunk/interfaces_ppb_public_dev.h +++ b/ppapi/thunk/interfaces_ppb_public_dev.h @@ -30,6 +30,8 @@ PROXIED_IFACE(PPB_Instance, PPB_TEXTINPUT_DEV_INTERFACE_0_2, PPB_TextInput_Dev_0_2) PROXIED_IFACE(NoAPIName, PPB_TRUETYPEFONT_DEV_INTERFACE_0_1, PPB_TrueTypeFont_Dev_0_1) +PROXIED_IFACE(NoAPIName, PPB_VAR_DICTIONARY_DEV_INTERFACE_0_1, + PPB_VarDictionary_Dev_0_1) PROXIED_IFACE(NoAPIName, PPB_VIEW_DEV_INTERFACE_0_1, PPB_View_Dev_0_1) UNPROXIED_IFACE(PPB_Instance, PPB_ZOOM_DEV_INTERFACE_0_2, PPB_Zoom_Dev_0_2) diff --git a/ppapi/thunk/ppb_var_dictionary_thunk.cc b/ppapi/thunk/ppb_var_dictionary_thunk.cc new file mode 100644 index 0000000..25a8224 --- /dev/null +++ b/ppapi/thunk/ppb_var_dictionary_thunk.cc @@ -0,0 +1,86 @@ +// 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. + +#include "ppapi/c/dev/ppb_var_dictionary_dev.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/shared_impl/dictionary_var.h" +#include "ppapi/shared_impl/proxy_lock.h" +#include "ppapi/thunk/thunk.h" + +namespace ppapi { +namespace thunk { + +namespace { + +PP_Var Create() { + ProxyAutoLock lock; + + // Var tracker will hold a reference to this object. + DictionaryVar* var = new DictionaryVar(); + return var->GetPPVar(); +} + +PP_Var Get(PP_Var dict, PP_Var key) { + ProxyAutoLock lock; + + DictionaryVar* dict_var = DictionaryVar::FromPPVar(dict); + if (!dict_var) + return PP_MakeUndefined(); + return dict_var->Get(key); +} + +PP_Bool Set(PP_Var dict, PP_Var key, PP_Var value) { + ProxyAutoLock lock; + + DictionaryVar* dict_var = DictionaryVar::FromPPVar(dict); + if (!dict_var) + return PP_FALSE; + + return dict_var->Set(key, value); +} + +void Delete(PP_Var dict, PP_Var key) { + ProxyAutoLock lock; + + DictionaryVar* dict_var = DictionaryVar::FromPPVar(dict); + if (dict_var) + dict_var->Delete(key); +} + +PP_Bool HasKey(PP_Var dict, PP_Var key) { + ProxyAutoLock lock; + + DictionaryVar* dict_var = DictionaryVar::FromPPVar(dict); + if (!dict_var) + return PP_FALSE; + return dict_var->HasKey(key); +} + +PP_Var GetKeys(PP_Var dict) { + ProxyAutoLock lock; + + DictionaryVar* dict_var = DictionaryVar::FromPPVar(dict); + if (!dict_var) + return PP_MakeNull(); + return dict_var->GetKeys(); +} + +const PPB_VarDictionary_Dev_0_1 g_ppb_vardictionary_0_1_thunk = { + &Create, + &Get, + &Set, + &Delete, + &HasKey, + &GetKeys +}; + +} // namespace + +const PPB_VarDictionary_Dev_0_1* GetPPB_VarDictionary_Dev_0_1_Thunk() { + return &g_ppb_vardictionary_0_1_thunk; +} + +} // namespace thunk +} // namespace ppapi diff --git a/webkit/plugins/ppapi/plugin_module.cc b/webkit/plugins/ppapi/plugin_module.cc index 983c11d..4a9735c 100644 --- a/webkit/plugins/ppapi/plugin_module.cc +++ b/webkit/plugins/ppapi/plugin_module.cc @@ -36,6 +36,7 @@ #include "ppapi/c/dev/ppb_truetype_font_dev.h" #include "ppapi/c/dev/ppb_url_util_dev.h" #include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/dev/ppb_var_dictionary_dev.h" #include "ppapi/c/dev/ppb_video_capture_dev.h" #include "ppapi/c/dev/ppb_video_decoder_dev.h" #include "ppapi/c/dev/ppb_view_dev.h" |