Home | History | Annotate | Download | only in cpp
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef PPAPI_CPP_ARRAY_OUTPUT_H_
      6 #define PPAPI_CPP_ARRAY_OUTPUT_H_
      7 
      8 #include <vector>
      9 
     10 #include "ppapi/c/pp_array_output.h"
     11 #include "ppapi/c/pp_resource.h"
     12 #include "ppapi/cpp/logging.h"
     13 #include "ppapi/cpp/pass_ref.h"
     14 #include "ppapi/cpp/var.h"
     15 
     16 namespace pp {
     17 
     18 // Converts the given array of PP_Resources into an array of the requested
     19 // C++ resource types, passing ownership of a reference in the process.
     20 //
     21 // This is used to convert output arrays of resources that the browser has
     22 // generated into the more convenient C++ wrappers for those resources. The
     23 // initial "PassRef" parameter is there to emphasize what happens to the
     24 // reference count of the input resource and to match the resource constructors
     25 // that look the same.
     26 template<typename ResourceObjectType>
     27 inline void ConvertPPResourceArrayToObjects(
     28     PassRef,
     29     const std::vector<PP_Resource>& input,
     30     std::vector<ResourceObjectType>* output) {
     31   output->resize(0);
     32   output->reserve(input.size());
     33   for (size_t i = 0; i < input.size(); i++)
     34     output->push_back(ResourceObjectType(PASS_REF, input[i]));
     35 }
     36 
     37 // Non-templatized base class for the array output conversion. It provides the
     38 // C implementation of a PP_ArrayOutput whose callback function is implemented
     39 // as a virtual call on a derived class. Do not use directly, use one of the
     40 // derived classes below.
     41 class ArrayOutputAdapterBase {
     42  public:
     43   ArrayOutputAdapterBase() {
     44     pp_array_output_.GetDataBuffer =
     45         &ArrayOutputAdapterBase::GetDataBufferThunk;
     46     pp_array_output_.user_data = this;
     47   }
     48   virtual ~ArrayOutputAdapterBase() {}
     49 
     50   const PP_ArrayOutput& pp_array_output() { return pp_array_output_; }
     51 
     52  protected:
     53   virtual void* GetDataBuffer(uint32_t element_count,
     54                               uint32_t element_size) = 0;
     55 
     56  private:
     57   static void* GetDataBufferThunk(void* user_data,
     58                                   uint32_t element_count,
     59                                   uint32_t element_size);
     60 
     61   PP_ArrayOutput pp_array_output_;
     62 
     63   // Disallow copying and assignment. This will do the wrong thing for most
     64   // subclasses.
     65   ArrayOutputAdapterBase(const ArrayOutputAdapterBase&);
     66   ArrayOutputAdapterBase& operator=(const ArrayOutputAdapterBase&);
     67 };
     68 
     69 // This adapter provides functionality for implementing a PP_ArrayOutput
     70 // structure as writing to a given vector object.
     71 //
     72 // This is generally used internally in the C++ wrapper objects to
     73 // write into an output parameter supplied by the plugin. If the element size
     74 // that the browser is writing does not match the size of the type we're using
     75 // this will assert and return NULL (which will cause the browser to fail the
     76 // call).
     77 //
     78 // Example that allows the browser to write into a given vector:
     79 //   void DoFoo(std::vector<int>* results) {
     80 //     ArrayOutputAdapter<int> adapter(results);
     81 //     ppb_foo->DoFoo(adapter.pp_array_output());
     82 //   }
     83 template<typename T>
     84 class ArrayOutputAdapter : public ArrayOutputAdapterBase {
     85  public:
     86   ArrayOutputAdapter(std::vector<T>* output) : output_(output) {}
     87 
     88  protected:
     89   // Two-step init for the "with storage" version below.
     90   ArrayOutputAdapter() : output_(NULL) {}
     91   void set_output(std::vector<T>* output) { output_ = output; }
     92 
     93   // ArrayOutputAdapterBase implementation.
     94   virtual void* GetDataBuffer(uint32_t element_count, uint32_t element_size) {
     95     if (element_count == 0)
     96       return NULL;
     97     PP_DCHECK(element_size == sizeof(T));
     98     if (element_size != sizeof(T))
     99       return NULL;
    100     output_->resize(element_count);
    101     return &(*output_)[0];
    102   }
    103 
    104  private:
    105   std::vector<T>* output_;
    106 };
    107 
    108 // This adapter provides functionality for implementing a PP_ArrayOutput
    109 // structure as writing resources to a given vector object.
    110 //
    111 // When returning an array of resources, the browser will write PP_Resources
    112 // via a PP_ArrayOutput. This code will automatically convert the PP_Resources
    113 // to the given wrapper type, (as long as that wrapper type supports the
    114 // correct constructor). The ownership of the resources that the browser passed
    115 // to us will be transferred to the C++ wrapper object.
    116 //
    117 // Conversion of the PP_Resources to the C++ wrapper object occurs in the
    118 // destructor. This object is intended to be used on the stack in a C++ wrapper
    119 // object for a call.
    120 //
    121 // Example:
    122 //   void GetFiles(std::vector<pp::FileRef>* results) {
    123 //     ResourceArrayOutputAdapter<pp::FileRef> adapter(results);
    124 //     ppb_foo->DoFoo(adapter.pp_array_output());
    125 //   }
    126 template<typename T>
    127 class ResourceArrayOutputAdapter : public ArrayOutputAdapterBase {
    128  public:
    129   explicit ResourceArrayOutputAdapter(std::vector<T>* output)
    130       : output_(output) {
    131     output_->resize(0);
    132   }
    133   virtual ~ResourceArrayOutputAdapter() {
    134     ConvertPPResourceArrayToObjects(PASS_REF, intermediate_output_, output_);
    135   }
    136 
    137  protected:
    138   // Two-step init for the "with storage" version below.
    139   ResourceArrayOutputAdapter() : output_(NULL) {}
    140   void set_output(T* output) { output_ = output; }
    141 
    142   // ArrayOutputAdapterBase implementation.
    143   virtual void* GetDataBuffer(uint32_t element_count,
    144                               uint32_t element_size) {
    145     if (element_count == 0)
    146       return NULL;
    147     PP_DCHECK(element_size == sizeof(PP_Resource));
    148     if (element_size != sizeof(PP_Resource))
    149       return NULL;
    150     intermediate_output_.resize(element_count);
    151     return &intermediate_output_[0];
    152   }
    153 
    154  private:
    155   std::vector<PP_Resource> intermediate_output_;
    156   std::vector<T>* output_;
    157 };
    158 
    159 // This adapter is like the ArrayOutputAdapter except that it also contains
    160 // the underlying std::vector that will be populated (rather than writing it to
    161 // an object passed into the constructor).
    162 //
    163 // This is used by the CompletionCallbackFactory system to collect the output
    164 // parameters from an async function call. The collected data is then passed to
    165 // the plugins callback function.
    166 //
    167 // You can also use it directly if you want to have an array output and aren't
    168 // using the CompletionCallbackFactory. For example, if you're calling a
    169 // PPAPI function DoFoo that takes a PP_OutputArray that is supposed to be
    170 // writing integers, do this:
    171 //
    172 //    ArrayOutputAdapterWithStorage<int> adapter;
    173 //    ppb_foo->DoFoo(adapter.pp_output_array());
    174 //    const std::vector<int>& result = adapter.output();
    175 template<typename T>
    176 class ArrayOutputAdapterWithStorage : public ArrayOutputAdapter<T> {
    177  public:
    178   ArrayOutputAdapterWithStorage() {
    179     this->set_output(&output_storage_);
    180   }
    181 
    182   std::vector<T>& output() { return output_storage_; }
    183 
    184  private:
    185   std::vector<T> output_storage_;
    186 };
    187 
    188 // This adapter is like the ArrayOutputAdapterWithStorage except this
    189 // additionally converts PP_Var structs to pp::Var objects.
    190 //
    191 // You can also use it directly if you want to have an array output and aren't
    192 // using the CompletionCallbackFactory. For example, if you're calling a
    193 // PPAPI function GetVars that takes a PP_OutputArray that is supposed to be
    194 // writing PP_Vars, do this:
    195 //
    196 //    VarArrayOutputAdapterWithStorage adapter;
    197 //    ppb_foo->GetVars(adapter.pp_output_array());
    198 //    const std::vector<pp::Var>& result = adapter.output().
    199 //
    200 // This one is non-inline since it's not templatized.
    201 class VarArrayOutputAdapterWithStorage : public ArrayOutputAdapter<PP_Var> {
    202  public:
    203   VarArrayOutputAdapterWithStorage();
    204   virtual ~VarArrayOutputAdapterWithStorage();
    205 
    206   // Returns the final array of resource objects, converting the PP_Vars
    207   // written by the browser to pp::Var objects.
    208   //
    209   // This function should only be called once or we would end up converting
    210   // the array more than once, which would mess up the refcounting.
    211   std::vector<Var>& output();
    212 
    213  private:
    214   // The browser will write the PP_Vars into this array.
    215   std::vector<PP_Var> temp_storage_;
    216 
    217   // When asked for the output, the resources above will be converted to the
    218   // C++ resource objects in this array for passing to the calling code.
    219   std::vector<Var> output_storage_;
    220 };
    221 
    222 // This adapter is like the ArrayOutputAdapterWithStorage except this
    223 // additionally converts PP_Resources to C++ wrapper objects of the given type.
    224 //
    225 // You can also use it directly if you want to have an array output and aren't
    226 // using the CompletionCallbackFactory. For example, if you're calling a
    227 // PPAPI function GetFiles that takes a PP_OutputArray that is supposed to be
    228 // writing PP_Resources cooresponding to FileRefs, do this:
    229 //
    230 //    ResourceArrayOutputAdapterWithStorage<FileRef> adapter;
    231 //    ppb_foo->GetFiles(adapter.pp_output_array());
    232 //    std::vector<FileRef> result = adapter.output().
    233 template<typename T>
    234 class ResourceArrayOutputAdapterWithStorage
    235     : public ArrayOutputAdapter<PP_Resource> {
    236  public:
    237   ResourceArrayOutputAdapterWithStorage() {
    238     set_output(&temp_storage_);
    239   }
    240 
    241   virtual ~ResourceArrayOutputAdapterWithStorage() {
    242     if (!temp_storage_.empty()) {
    243       // An easy way to release the resource references held by this object.
    244       output();
    245     }
    246   }
    247 
    248   // Returns the final array of resource objects, converting the PP_Resources
    249   // written by the browser to resource objects.
    250   //
    251   // This function should only be called once or we would end up converting
    252   // the array more than once, which would mess up the refcounting.
    253   std::vector<T>& output() {
    254     PP_DCHECK(output_storage_.empty());
    255 
    256     ConvertPPResourceArrayToObjects(PASS_REF, temp_storage_, &output_storage_);
    257     temp_storage_.clear();
    258     return output_storage_;
    259   }
    260 
    261  private:
    262   // The browser will write the PP_Resources into this array.
    263   std::vector<PP_Resource> temp_storage_;
    264 
    265   // When asked for the output, the resources above will be converted to the
    266   // C++ resource objects in this array for passing to the calling code.
    267   std::vector<T> output_storage_;
    268 };
    269 
    270 }  // namespace pp
    271 
    272 #endif  // PPAPI_CPP_ARRAY_OUTPUT_H_
    273