| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ppapi/proxy/ppb_font_proxy.h" | 5 #include "ppapi/proxy/ppb_font_proxy.h" |
| 6 | 6 |
| 7 #include "ppapi/c/dev/ppb_font_dev.h" | 7 #include "ppapi/c/dev/ppb_font_dev.h" |
| 8 #include "ppapi/proxy/image_data.h" |
| 8 #include "ppapi/proxy/plugin_dispatcher.h" | 9 #include "ppapi/proxy/plugin_dispatcher.h" |
| 9 #include "ppapi/proxy/plugin_resource.h" | 10 #include "ppapi/proxy/plugin_resource.h" |
| 10 #include "ppapi/proxy/ppapi_messages.h" | 11 #include "ppapi/proxy/ppapi_messages.h" |
| 11 | 12 |
| 12 namespace pp { | 13 namespace pp { |
| 13 namespace proxy { | 14 namespace proxy { |
| 14 | 15 |
| 15 class Font : public PluginResource { | 16 class Font : public PluginResource { |
| 16 public: | 17 public: |
| 17 Font(PP_Instance instance); | 18 Font(PP_Instance instance, SerializedResource resource); |
| 18 virtual ~Font(); | 19 virtual ~Font(); |
| 19 | 20 |
| 20 // PluginResource overrides. | 21 // PluginResource overrides. |
| 21 virtual Font* AsFont() { return this; } | 22 virtual Font* AsFont() { return this; } |
| 22 | 23 |
| 23 PP_FontDescription_Dev& desc() { return desc_; } | 24 PP_FontDescription_Dev& desc() { return desc_; } |
| 24 PP_FontDescription_Dev* desc_ptr() { return &desc_; } | 25 PP_FontDescription_Dev* desc_ptr() { return &desc_; } |
| 25 PP_FontMetrics_Dev& metrics() { return metrics_; } | 26 PP_FontMetrics_Dev& metrics() { return metrics_; } |
| 26 | 27 |
| 27 private: | 28 private: |
| 28 PP_FontDescription_Dev desc_; | 29 PP_FontDescription_Dev desc_; |
| 29 PP_FontMetrics_Dev metrics_; | 30 PP_FontMetrics_Dev metrics_; |
| 30 | 31 |
| 31 DISALLOW_COPY_AND_ASSIGN(Font); | 32 DISALLOW_COPY_AND_ASSIGN(Font); |
| 32 }; | 33 }; |
| 33 | 34 |
| 34 Font::Font(PP_Instance instance) : PluginResource(instance) { | 35 Font::Font(PP_Instance instance, SerializedResource resource) |
| 36 : PluginResource(instance, resource) { |
| 35 memset(&desc_, 0, sizeof(PP_FontDescription_Dev)); | 37 memset(&desc_, 0, sizeof(PP_FontDescription_Dev)); |
| 36 desc_.face.type = PP_VARTYPE_UNDEFINED; | 38 desc_.face.type = PP_VARTYPE_UNDEFINED; |
| 37 memset(&metrics_, 0, sizeof(PP_FontMetrics_Dev)); | 39 memset(&metrics_, 0, sizeof(PP_FontMetrics_Dev)); |
| 38 } | 40 } |
| 39 | 41 |
| 40 Font::~Font() { | 42 Font::~Font() { |
| 41 PluginVarTracker::GetInstance()->Release(desc_.face); | 43 PluginVarTracker::GetInstance()->Release(desc_.face); |
| 42 } | 44 } |
| 43 | 45 |
| 44 namespace { | 46 namespace { |
| 45 | 47 |
| 46 PP_Resource Create(PP_Instance instance, | 48 PP_Resource Create(PP_Instance instance, |
| 47 const PP_FontDescription_Dev* description) { | 49 const PP_FontDescription_Dev* description) { |
| 48 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); | 50 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); |
| 49 if (!dispatcher) | 51 if (!dispatcher) |
| 50 return 0; | 52 return 0; |
| 51 | 53 |
| 52 SerializedFontDescription in_description; | 54 SerializedFontDescription in_description; |
| 53 in_description.SetFromPPFontDescription(dispatcher, *description, true); | 55 in_description.SetFromPPFontDescription(dispatcher, *description, true); |
| 54 | 56 |
| 55 PP_Resource result; | 57 SerializedResource result; |
| 56 SerializedFontDescription out_description; | 58 SerializedFontDescription out_description; |
| 57 std::string out_metrics; | 59 std::string out_metrics; |
| 58 dispatcher->Send(new PpapiHostMsg_PPBFont_Create( | 60 dispatcher->Send(new PpapiHostMsg_PPBFont_Create( |
| 59 INTERFACE_ID_PPB_FONT, | 61 INTERFACE_ID_PPB_FONT, |
| 60 instance, in_description, &result, &out_description, &out_metrics)); | 62 instance, in_description, &result, &out_description, &out_metrics)); |
| 61 | 63 |
| 62 if (!result) | 64 if (result.is_null()) |
| 63 return 0; // Failure creating font. | 65 return 0; // Failure creating font. |
| 64 | 66 |
| 65 linked_ptr<Font> object(new Font(instance)); | 67 linked_ptr<Font> object(new Font(instance, result)); |
| 66 out_description.SetToPPFontDescription(dispatcher, object->desc_ptr(), true); | 68 out_description.SetToPPFontDescription(dispatcher, object->desc_ptr(), true); |
| 67 | 69 |
| 68 // Convert the metrics, this is just serialized as a string of bytes. | 70 // Convert the metrics, this is just serialized as a string of bytes. |
| 69 if (out_metrics.size() != sizeof(PP_FontMetrics_Dev)) | 71 if (out_metrics.size() != sizeof(PP_FontMetrics_Dev)) |
| 70 return 0; | 72 return 0; |
| 71 memcpy(&object->metrics(), out_metrics.data(), sizeof(PP_FontMetrics_Dev)); | 73 memcpy(&object->metrics(), out_metrics.data(), sizeof(PP_FontMetrics_Dev)); |
| 72 | 74 |
| 73 PluginResourceTracker::GetInstance()->AddResource(result, object); | 75 return PluginResourceTracker::GetInstance()->AddResource(object); |
| 74 return result; | |
| 75 } | 76 } |
| 76 | 77 |
| 77 PP_Bool IsFont(PP_Resource resource) { | 78 PP_Bool IsFont(PP_Resource resource) { |
| 78 Font* object = PluginResource::GetAs<Font>(resource); | 79 Font* object = PluginResource::GetAs<Font>(resource); |
| 79 return BoolToPPBool(!!object); | 80 return BoolToPPBool(!!object); |
| 80 } | 81 } |
| 81 | 82 |
| 82 PP_Bool Describe(PP_Resource font_id, | 83 PP_Bool Describe(PP_Resource font_id, |
| 83 PP_FontDescription_Dev* description, | 84 PP_FontDescription_Dev* description, |
| 84 PP_FontMetrics_Dev* metrics) { | 85 PP_FontMetrics_Dev* metrics) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 95 return PP_TRUE; | 96 return PP_TRUE; |
| 96 } | 97 } |
| 97 | 98 |
| 98 PP_Bool DrawTextAt(PP_Resource font_id, | 99 PP_Bool DrawTextAt(PP_Resource font_id, |
| 99 PP_Resource image_data, | 100 PP_Resource image_data, |
| 100 const PP_TextRun_Dev* text, | 101 const PP_TextRun_Dev* text, |
| 101 const PP_Point* position, | 102 const PP_Point* position, |
| 102 uint32_t color, | 103 uint32_t color, |
| 103 const PP_Rect* clip, | 104 const PP_Rect* clip, |
| 104 PP_Bool image_data_is_opaque) { | 105 PP_Bool image_data_is_opaque) { |
| 105 Font* object = PluginResource::GetAs<Font>(font_id); | 106 Font* font_object = PluginResource::GetAs<Font>(font_id); |
| 106 if (!object) | 107 if (!font_object) |
| 108 return PP_FALSE; |
| 109 ImageData* image_object = PluginResource::GetAs<ImageData>(image_data); |
| 110 if (!image_object) |
| 111 return PP_FALSE; |
| 112 if (font_object->instance() != image_object->instance()) |
| 107 return PP_FALSE; | 113 return PP_FALSE; |
| 108 | 114 |
| 109 PPBFont_DrawTextAt_Params params; | 115 PPBFont_DrawTextAt_Params params; |
| 110 params.font = font_id; | 116 params.font = font_object->host_resource(); |
| 111 params.image_data = image_data; | 117 params.image_data = image_object->host_resource(); |
| 112 params.text_is_rtl = text->rtl; | 118 params.text_is_rtl = text->rtl; |
| 113 params.override_direction = text->override_direction; | 119 params.override_direction = text->override_direction; |
| 114 params.position = *position; | 120 params.position = *position; |
| 115 params.color = color; | 121 params.color = color; |
| 116 if (clip) { | 122 if (clip) { |
| 117 params.clip = *clip; | 123 params.clip = *clip; |
| 118 params.clip_is_null = false; | 124 params.clip_is_null = false; |
| 119 } else { | 125 } else { |
| 120 params.clip = PP_MakeRectFromXYWH(0, 0, 0, 0); | 126 params.clip = PP_MakeRectFromXYWH(0, 0, 0, 0); |
| 121 params.clip_is_null = true; | 127 params.clip_is_null = true; |
| 122 } | 128 } |
| 123 params.image_data_is_opaque = image_data_is_opaque; | 129 params.image_data_is_opaque = image_data_is_opaque; |
| 124 | 130 |
| 125 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance()); | 131 Dispatcher* dispatcher = PluginDispatcher::GetForInstance( |
| 132 image_object->instance()); |
| 126 PP_Bool result = PP_FALSE; | 133 PP_Bool result = PP_FALSE; |
| 127 if (dispatcher) { | 134 if (dispatcher) { |
| 128 dispatcher->Send(new PpapiHostMsg_PPBFont_DrawTextAt( | 135 dispatcher->Send(new PpapiHostMsg_PPBFont_DrawTextAt( |
| 129 INTERFACE_ID_PPB_FONT, | 136 INTERFACE_ID_PPB_FONT, |
| 130 SerializedVarSendInput(dispatcher, text->text), | 137 SerializedVarSendInput(dispatcher, text->text), |
| 131 params, &result)); | 138 params, &result)); |
| 132 } | 139 } |
| 133 return result; | 140 return result; |
| 134 } | 141 } |
| 135 | 142 |
| 136 int32_t MeasureText(PP_Resource font_id, const PP_TextRun_Dev* text) { | 143 int32_t MeasureText(PP_Resource font_id, const PP_TextRun_Dev* text) { |
| 137 Font* object = PluginResource::GetAs<Font>(font_id); | 144 Font* object = PluginResource::GetAs<Font>(font_id); |
| 138 if (!object) | 145 if (!object) |
| 139 return -1; | 146 return -1; |
| 140 | 147 |
| 141 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance()); | 148 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance()); |
| 142 int32_t result = 0; | 149 int32_t result = 0; |
| 143 dispatcher->Send(new PpapiHostMsg_PPBFont_MeasureText( | 150 dispatcher->Send(new PpapiHostMsg_PPBFont_MeasureText( |
| 144 INTERFACE_ID_PPB_FONT, font_id, | 151 INTERFACE_ID_PPB_FONT, object->host_resource(), |
| 145 SerializedVarSendInput(dispatcher, text->text), | 152 SerializedVarSendInput(dispatcher, text->text), |
| 146 text->rtl, text->override_direction, &result)); | 153 text->rtl, text->override_direction, &result)); |
| 147 return result; | 154 return result; |
| 148 } | 155 } |
| 149 | 156 |
| 150 uint32_t CharacterOffsetForPixel(PP_Resource font_id, | 157 uint32_t CharacterOffsetForPixel(PP_Resource font_id, |
| 151 const PP_TextRun_Dev* text, | 158 const PP_TextRun_Dev* text, |
| 152 int32_t pixel_position) { | 159 int32_t pixel_position) { |
| 153 Font* object = PluginResource::GetAs<Font>(font_id); | 160 Font* object = PluginResource::GetAs<Font>(font_id); |
| 154 if (!object) | 161 if (!object) |
| 155 return -1; | 162 return -1; |
| 156 | 163 |
| 157 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance()); | 164 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance()); |
| 158 uint32_t result = 0; | 165 uint32_t result = 0; |
| 159 dispatcher->Send(new PpapiHostMsg_PPBFont_CharacterOffsetForPixel( | 166 dispatcher->Send(new PpapiHostMsg_PPBFont_CharacterOffsetForPixel( |
| 160 INTERFACE_ID_PPB_FONT, font_id, | 167 INTERFACE_ID_PPB_FONT, object->host_resource(), |
| 161 SerializedVarSendInput(dispatcher, text->text), | 168 SerializedVarSendInput(dispatcher, text->text), |
| 162 text->rtl, text->override_direction, pixel_position, &result)); | 169 text->rtl, text->override_direction, pixel_position, &result)); |
| 163 return result; | 170 return result; |
| 164 } | 171 } |
| 165 | 172 |
| 166 int32_t PixelOffsetForCharacter(PP_Resource font_id, | 173 int32_t PixelOffsetForCharacter(PP_Resource font_id, |
| 167 const PP_TextRun_Dev* text, | 174 const PP_TextRun_Dev* text, |
| 168 uint32_t char_offset) { | 175 uint32_t char_offset) { |
| 169 Font* object = PluginResource::GetAs<Font>(font_id); | 176 Font* object = PluginResource::GetAs<Font>(font_id); |
| 170 if (!object) | 177 if (!object) |
| 171 return -1; | 178 return -1; |
| 172 | 179 |
| 173 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance()); | 180 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance()); |
| 174 int32_t result = 0; | 181 int32_t result = 0; |
| 175 dispatcher->Send(new PpapiHostMsg_PPBFont_PixelOffsetForCharacter( | 182 dispatcher->Send(new PpapiHostMsg_PPBFont_PixelOffsetForCharacter( |
| 176 INTERFACE_ID_PPB_FONT, font_id, | 183 INTERFACE_ID_PPB_FONT, object->host_resource(), |
| 177 SerializedVarSendInput(dispatcher, text->text), | 184 SerializedVarSendInput(dispatcher, text->text), |
| 178 text->rtl, text->override_direction, char_offset, &result)); | 185 text->rtl, text->override_direction, char_offset, &result)); |
| 179 return result; | 186 return result; |
| 180 } | 187 } |
| 181 | 188 |
| 182 const PPB_Font_Dev ppb_font_interface = { | 189 const PPB_Font_Dev ppb_font_interface = { |
| 183 &Create, | 190 &Create, |
| 184 &IsFont, | 191 &IsFont, |
| 185 &Describe, | 192 &Describe, |
| 186 &DrawTextAt, | 193 &DrawTextAt, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFont_PixelOffsetForCharacter, | 228 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFont_PixelOffsetForCharacter, |
| 222 OnMsgPixelOffsetForCharacter) | 229 OnMsgPixelOffsetForCharacter) |
| 223 IPC_MESSAGE_UNHANDLED(handled = false) | 230 IPC_MESSAGE_UNHANDLED(handled = false) |
| 224 IPC_END_MESSAGE_MAP() | 231 IPC_END_MESSAGE_MAP() |
| 225 return handled; | 232 return handled; |
| 226 } | 233 } |
| 227 | 234 |
| 228 void PPB_Font_Proxy::OnMsgCreate( | 235 void PPB_Font_Proxy::OnMsgCreate( |
| 229 PP_Instance instance, | 236 PP_Instance instance, |
| 230 const SerializedFontDescription& in_description, | 237 const SerializedFontDescription& in_description, |
| 231 PP_Resource* result, | 238 SerializedResource* result, |
| 232 SerializedFontDescription* out_description, | 239 SerializedFontDescription* out_description, |
| 233 std::string* out_metrics) { | 240 std::string* out_metrics) { |
| 234 // Convert the face name in the input description. | 241 // Convert the face name in the input description. |
| 235 PP_FontDescription_Dev in_pp_desc; | 242 PP_FontDescription_Dev in_pp_desc; |
| 236 in_description.SetToPPFontDescription(dispatcher(), &in_pp_desc, false); | 243 in_description.SetToPPFontDescription(dispatcher(), &in_pp_desc, false); |
| 237 | 244 |
| 238 // Make sure the output is always defined so we can still serialize it back | 245 // Make sure the output is always defined so we can still serialize it back |
| 239 // to the plugin below. | 246 // to the plugin below. |
| 240 PP_FontDescription_Dev out_pp_desc; | 247 PP_FontDescription_Dev out_pp_desc; |
| 241 memset(&out_pp_desc, 0, sizeof(PP_FontDescription_Dev)); | 248 memset(&out_pp_desc, 0, sizeof(PP_FontDescription_Dev)); |
| 242 out_pp_desc.face = PP_MakeUndefined(); | 249 out_pp_desc.face = PP_MakeUndefined(); |
| 243 | 250 |
| 244 *result = ppb_font_target()->Create(instance, &in_pp_desc); | 251 result->set_host_resource(ppb_font_target()->Create(instance, &in_pp_desc)); |
| 245 if (*result) { | 252 if (result->is_null()) { |
| 246 // Get the metrics and resulting description to return to the browser. | 253 // Get the metrics and resulting description to return to the browser. |
| 247 PP_FontMetrics_Dev metrics; | 254 PP_FontMetrics_Dev metrics; |
| 248 if (ppb_font_target()->Describe(*result, &out_pp_desc, &metrics)) { | 255 if (ppb_font_target()->Describe(result->host_resource(), &out_pp_desc, |
| 256 &metrics)) { |
| 249 out_metrics->assign(reinterpret_cast<const char*>(&metrics), | 257 out_metrics->assign(reinterpret_cast<const char*>(&metrics), |
| 250 sizeof(PP_FontMetrics_Dev)); | 258 sizeof(PP_FontMetrics_Dev)); |
| 251 } | 259 } |
| 252 } | 260 } |
| 253 | 261 |
| 254 // This must always get called or it will assert when trying to serialize | 262 // This must always get called or it will assert when trying to serialize |
| 255 // the un-filled-in SerializedFontDescription as the return value. | 263 // the un-filled-in SerializedFontDescription as the return value. |
| 256 out_description->SetFromPPFontDescription(dispatcher(), out_pp_desc, false); | 264 out_description->SetFromPPFontDescription(dispatcher(), out_pp_desc, false); |
| 257 } | 265 } |
| 258 | 266 |
| 259 void PPB_Font_Proxy::OnMsgDrawTextAt(SerializedVarReceiveInput text, | 267 void PPB_Font_Proxy::OnMsgDrawTextAt(SerializedVarReceiveInput text, |
| 260 const PPBFont_DrawTextAt_Params& params, | 268 const PPBFont_DrawTextAt_Params& params, |
| 261 PP_Bool* result) { | 269 PP_Bool* result) { |
| 262 PP_TextRun_Dev run; | 270 PP_TextRun_Dev run; |
| 263 run.text = text.Get(dispatcher()); | 271 run.text = text.Get(dispatcher()); |
| 264 run.rtl = params.text_is_rtl; | 272 run.rtl = params.text_is_rtl; |
| 265 run.override_direction = params.override_direction; | 273 run.override_direction = params.override_direction; |
| 266 | 274 |
| 267 *result = ppb_font_target()->DrawTextAt(params.font, params.image_data, | 275 *result = ppb_font_target()->DrawTextAt(params.font.host_resource(), |
| 268 &run, ¶ms.position, params.color, | 276 params.image_data.host_resource(), &run, ¶ms.position, params.color, |
| 269 params.clip_is_null ? NULL : ¶ms.clip, params.image_data_is_opaque); | 277 params.clip_is_null ? NULL : ¶ms.clip, params.image_data_is_opaque); |
| 270 } | 278 } |
| 271 | 279 |
| 272 void PPB_Font_Proxy::OnMsgMeasureText(PP_Resource font, | 280 void PPB_Font_Proxy::OnMsgMeasureText(SerializedResource font, |
| 273 SerializedVarReceiveInput text, | 281 SerializedVarReceiveInput text, |
| 274 PP_Bool text_is_rtl, | 282 PP_Bool text_is_rtl, |
| 275 PP_Bool override_direction, | 283 PP_Bool override_direction, |
| 276 int32_t* result) { | 284 int32_t* result) { |
| 277 PP_TextRun_Dev run; | 285 PP_TextRun_Dev run; |
| 278 run.text = text.Get(dispatcher()); | 286 run.text = text.Get(dispatcher()); |
| 279 run.rtl = text_is_rtl; | 287 run.rtl = text_is_rtl; |
| 280 run.override_direction = override_direction; | 288 run.override_direction = override_direction; |
| 281 | 289 |
| 282 *result = ppb_font_target()->MeasureText(font, &run); | 290 *result = ppb_font_target()->MeasureText(font.host_resource(), &run); |
| 283 } | 291 } |
| 284 | 292 |
| 285 void PPB_Font_Proxy::OnMsgCharacterOffsetForPixel( | 293 void PPB_Font_Proxy::OnMsgCharacterOffsetForPixel( |
| 286 PP_Resource font, | 294 SerializedResource font, |
| 287 SerializedVarReceiveInput text, | 295 SerializedVarReceiveInput text, |
| 288 PP_Bool text_is_rtl, | 296 PP_Bool text_is_rtl, |
| 289 PP_Bool override_direction, | 297 PP_Bool override_direction, |
| 290 int32_t pixel_pos, | 298 int32_t pixel_pos, |
| 291 uint32_t* result) { | 299 uint32_t* result) { |
| 292 PP_TextRun_Dev run; | 300 PP_TextRun_Dev run; |
| 293 run.text = text.Get(dispatcher()); | 301 run.text = text.Get(dispatcher()); |
| 294 run.rtl = text_is_rtl; | 302 run.rtl = text_is_rtl; |
| 295 run.override_direction = override_direction; | 303 run.override_direction = override_direction; |
| 296 | 304 |
| 297 *result = ppb_font_target()->CharacterOffsetForPixel(font, &run, pixel_pos); | 305 *result = ppb_font_target()->CharacterOffsetForPixel(font.host_resource(), |
| 306 &run, pixel_pos); |
| 298 } | 307 } |
| 299 | 308 |
| 300 void PPB_Font_Proxy::OnMsgPixelOffsetForCharacter( | 309 void PPB_Font_Proxy::OnMsgPixelOffsetForCharacter( |
| 301 PP_Resource font, | 310 SerializedResource font, |
| 302 SerializedVarReceiveInput text, | 311 SerializedVarReceiveInput text, |
| 303 PP_Bool text_is_rtl, | 312 PP_Bool text_is_rtl, |
| 304 PP_Bool override_direction, | 313 PP_Bool override_direction, |
| 305 uint32_t char_offset, | 314 uint32_t char_offset, |
| 306 int32_t* result) { | 315 int32_t* result) { |
| 307 PP_TextRun_Dev run; | 316 PP_TextRun_Dev run; |
| 308 run.text = text.Get(dispatcher()); | 317 run.text = text.Get(dispatcher()); |
| 309 run.rtl = text_is_rtl; | 318 run.rtl = text_is_rtl; |
| 310 run.override_direction = override_direction; | 319 run.override_direction = override_direction; |
| 311 | 320 |
| 312 *result = ppb_font_target()->PixelOffsetForCharacter(font, &run, char_offset); | 321 *result = ppb_font_target()->PixelOffsetForCharacter(font.host_resource(), |
| 322 &run, char_offset); |
| 313 } | 323 } |
| 314 | 324 |
| 315 } // namespace proxy | 325 } // namespace proxy |
| 316 } // namespace pp | 326 } // namespace pp |
| OLD | NEW |