Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(414)

Side by Side Diff: content/browser/devtools/protocol/input_handler.cc

Issue 2569273002: Add constructors to WebInputEvents and setters so we can work at cleaning up these public structs. (Closed)
Patch Set: Rebase Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "content/browser/devtools/protocol/input_handler.h" 5 #include "content/browser/devtools/protocol/input_handler.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include "base/strings/stringprintf.h" 9 #include "base/strings/stringprintf.h"
10 #include "base/strings/utf_string_conversions.h" 10 #include "base/strings/utf_string_conversions.h"
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 out = SyntheticGestureParams::GestureSourceType::TOUCH_INPUT; 48 out = SyntheticGestureParams::GestureSourceType::TOUCH_INPUT;
49 return true; 49 return true;
50 } 50 }
51 if (in.fromJust() == Input::GestureSourceTypeEnum::Mouse) { 51 if (in.fromJust() == Input::GestureSourceTypeEnum::Mouse) {
52 out = SyntheticGestureParams::GestureSourceType::MOUSE_INPUT; 52 out = SyntheticGestureParams::GestureSourceType::MOUSE_INPUT;
53 return true; 53 return true;
54 } 54 }
55 return false; 55 return false;
56 } 56 }
57 57
58 void SetEventModifiers(blink::WebInputEvent* event, int modifiers) { 58 int GetEventModifiers(int modifiers, bool auto_repeat, bool is_keypad) {
59 int result = 0;
60 if (auto_repeat)
61 result |= blink::WebInputEvent::IsAutoRepeat;
62 if (is_keypad)
63 result |= blink::WebInputEvent::IsKeyPad;
64
59 if (modifiers & 1) 65 if (modifiers & 1)
60 event->modifiers |= blink::WebInputEvent::AltKey; 66 result |= blink::WebInputEvent::AltKey;
61 if (modifiers & 2) 67 if (modifiers & 2)
62 event->modifiers |= blink::WebInputEvent::ControlKey; 68 result |= blink::WebInputEvent::ControlKey;
63 if (modifiers & 4) 69 if (modifiers & 4)
64 event->modifiers |= blink::WebInputEvent::MetaKey; 70 result |= blink::WebInputEvent::MetaKey;
65 if (modifiers & 8) 71 if (modifiers & 8)
66 event->modifiers |= blink::WebInputEvent::ShiftKey; 72 result |= blink::WebInputEvent::ShiftKey;
73 return result;
67 } 74 }
68 75
69 void SetEventTimestamp(blink::WebInputEvent* event, Maybe<double> timestamp) { 76 base::TimeTicks GetEventTimeTicks(Maybe<double> timestamp) {
70 // Convert timestamp, in seconds since unix epoch, to an event timestamp 77 // Convert timestamp, in seconds since unix epoch, to an event timestamp
71 // which is time ticks since platform start time. 78 // which is time ticks since platform start time.
72 base::TimeTicks ticks = timestamp.isJust() 79 return timestamp.isJust()
73 ? base::TimeDelta::FromSecondsD(timestamp.fromJust()) + 80 ? base::TimeDelta::FromSecondsD(timestamp.fromJust()) +
74 base::TimeTicks::UnixEpoch() 81 base::TimeTicks::UnixEpoch()
75 : base::TimeTicks::Now(); 82 : base::TimeTicks::Now();
76 event->timeStampSeconds = (ticks - base::TimeTicks()).InSecondsF(); 83 }
84
85 double GetEventTimestamp(Maybe<double> timestamp) {
86 return (GetEventTimeTicks(std::move(timestamp)) - base::TimeTicks())
87 .InSecondsF();
77 } 88 }
78 89
79 bool SetKeyboardEventText(blink::WebUChar* to, Maybe<std::string> from) { 90 bool SetKeyboardEventText(blink::WebUChar* to, Maybe<std::string> from) {
80 if (!from.isJust()) 91 if (!from.isJust())
81 return true; 92 return true;
82 93
83 base::string16 text16 = base::UTF8ToUTF16(from.fromJust()); 94 base::string16 text16 = base::UTF8ToUTF16(from.fromJust());
84 if (text16.size() > blink::WebKeyboardEvent::textLengthCap) 95 if (text16.size() > blink::WebKeyboardEvent::textLengthCap)
85 return false; 96 return false;
86 97
87 for (size_t i = 0; i < text16.size(); ++i) 98 for (size_t i = 0; i < text16.size(); ++i)
88 to[i] = text16[i]; 99 to[i] = text16[i];
89 return true; 100 return true;
90 } 101 }
91 102
92 bool SetMouseEventButton(blink::WebMouseEvent* event, 103 bool GetMouseEventButton(const std::string& button,
93 const std::string& button) { 104 blink::WebPointerProperties::Button* event_button,
105 int* event_modifiers) {
94 if (button.empty()) 106 if (button.empty())
95 return true; 107 return true;
96 108
97 if (button == Input::DispatchMouseEvent::ButtonEnum::None) { 109 if (button == Input::DispatchMouseEvent::ButtonEnum::None) {
98 event->button = blink::WebMouseEvent::Button::NoButton; 110 *event_button = blink::WebMouseEvent::Button::NoButton;
99 } else if (button == Input::DispatchMouseEvent::ButtonEnum::Left) { 111 } else if (button == Input::DispatchMouseEvent::ButtonEnum::Left) {
100 event->button = blink::WebMouseEvent::Button::Left; 112 *event_button = blink::WebMouseEvent::Button::Left;
101 event->modifiers |= blink::WebInputEvent::LeftButtonDown; 113 *event_modifiers = blink::WebInputEvent::LeftButtonDown;
102 } else if (button == Input::DispatchMouseEvent::ButtonEnum::Middle) { 114 } else if (button == Input::DispatchMouseEvent::ButtonEnum::Middle) {
103 event->button = blink::WebMouseEvent::Button::Middle; 115 *event_button = blink::WebMouseEvent::Button::Middle;
104 event->modifiers |= blink::WebInputEvent::MiddleButtonDown; 116 *event_modifiers = blink::WebInputEvent::MiddleButtonDown;
105 } else if (button == Input::DispatchMouseEvent::ButtonEnum::Right) { 117 } else if (button == Input::DispatchMouseEvent::ButtonEnum::Right) {
106 event->button = blink::WebMouseEvent::Button::Right; 118 *event_button = blink::WebMouseEvent::Button::Right;
107 event->modifiers |= blink::WebInputEvent::RightButtonDown; 119 *event_modifiers = blink::WebInputEvent::RightButtonDown;
108 } else { 120 } else {
109 return false; 121 return false;
110 } 122 }
111 return true; 123 return true;
112 } 124 }
113 125
114 bool SetMouseEventType(blink::WebMouseEvent* event, const std::string& type) { 126 blink::WebInputEvent::Type GetMouseEventType(const std::string& type) {
115 if (type == Input::DispatchMouseEvent::TypeEnum::MousePressed) { 127 if (type == Input::DispatchMouseEvent::TypeEnum::MousePressed)
116 event->type = blink::WebInputEvent::MouseDown; 128 return blink::WebInputEvent::MouseDown;
117 } else if (type == Input::DispatchMouseEvent::TypeEnum::MouseReleased) { 129 if (type == Input::DispatchMouseEvent::TypeEnum::MouseReleased)
118 event->type = blink::WebInputEvent::MouseUp; 130 return blink::WebInputEvent::MouseUp;
119 } else if (type == Input::DispatchMouseEvent::TypeEnum::MouseMoved) { 131 if (type == Input::DispatchMouseEvent::TypeEnum::MouseMoved)
120 event->type = blink::WebInputEvent::MouseMove; 132 return blink::WebInputEvent::MouseMove;
121 } else { 133 return blink::WebInputEvent::Undefined;
122 return false;
123 }
124 return true;
125 } 134 }
126 135
127 void SendSynthesizePinchGestureResponse( 136 void SendSynthesizePinchGestureResponse(
128 std::unique_ptr<Input::Backend::SynthesizePinchGestureCallback> callback, 137 std::unique_ptr<Input::Backend::SynthesizePinchGestureCallback> callback,
129 SyntheticGesture::Result result) { 138 SyntheticGesture::Result result) {
130 if (result == SyntheticGesture::Result::GESTURE_FINISHED) { 139 if (result == SyntheticGesture::Result::GESTURE_FINISHED) {
131 callback->sendSuccess(); 140 callback->sendSuccess();
132 } else { 141 } else {
133 callback->sendFailure(Response::Error( 142 callback->sendFailure(Response::Error(
134 base::StringPrintf("Synthetic pinch failed, result was %d", result))); 143 base::StringPrintf("Synthetic pinch failed, result was %d", result)));
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 Maybe<std::string> text, 231 Maybe<std::string> text,
223 Maybe<std::string> unmodified_text, 232 Maybe<std::string> unmodified_text,
224 Maybe<std::string> key_identifier, 233 Maybe<std::string> key_identifier,
225 Maybe<std::string> code, 234 Maybe<std::string> code,
226 Maybe<std::string> key, 235 Maybe<std::string> key,
227 Maybe<int> windows_virtual_key_code, 236 Maybe<int> windows_virtual_key_code,
228 Maybe<int> native_virtual_key_code, 237 Maybe<int> native_virtual_key_code,
229 Maybe<bool> auto_repeat, 238 Maybe<bool> auto_repeat,
230 Maybe<bool> is_keypad, 239 Maybe<bool> is_keypad,
231 Maybe<bool> is_system_key) { 240 Maybe<bool> is_system_key) {
232 NativeWebKeyboardEvent event; 241 blink::WebInputEvent::Type web_event_type;
233 event.skip_in_browser = true;
234 242
235 if (type == Input::DispatchKeyEvent::TypeEnum::KeyDown) { 243 if (type == Input::DispatchKeyEvent::TypeEnum::KeyDown) {
236 event.type = blink::WebInputEvent::KeyDown; 244 web_event_type = blink::WebInputEvent::KeyDown;
237 } else if (type == Input::DispatchKeyEvent::TypeEnum::KeyUp) { 245 } else if (type == Input::DispatchKeyEvent::TypeEnum::KeyUp) {
238 event.type = blink::WebInputEvent::KeyUp; 246 web_event_type = blink::WebInputEvent::KeyUp;
239 } else if (type == Input::DispatchKeyEvent::TypeEnum::Char) { 247 } else if (type == Input::DispatchKeyEvent::TypeEnum::Char) {
240 event.type = blink::WebInputEvent::Char; 248 web_event_type = blink::WebInputEvent::Char;
241 } else if (type == Input::DispatchKeyEvent::TypeEnum::RawKeyDown) { 249 } else if (type == Input::DispatchKeyEvent::TypeEnum::RawKeyDown) {
242 event.type = blink::WebInputEvent::RawKeyDown; 250 web_event_type = blink::WebInputEvent::RawKeyDown;
243 } else { 251 } else {
244 return Response::InvalidParams( 252 return Response::InvalidParams(
245 base::StringPrintf("Unexpected event type '%s'", type.c_str())); 253 base::StringPrintf("Unexpected event type '%s'", type.c_str()));
246 } 254 }
247 255
248 SetEventModifiers(&event, modifiers.fromMaybe(0)); 256 NativeWebKeyboardEvent event(
249 SetEventTimestamp(&event, std::move(timestamp)); 257 web_event_type,
258 GetEventModifiers(modifiers.fromMaybe(blink::WebInputEvent::NoModifiers),
259 auto_repeat.fromMaybe(false),
260 is_keypad.fromMaybe(false)),
261 GetEventTimeTicks(std::move(timestamp)));
262 event.skip_in_browser = true;
250 if (!SetKeyboardEventText(event.text, std::move(text))) 263 if (!SetKeyboardEventText(event.text, std::move(text)))
251 return Response::InvalidParams("Invalid 'text' parameter"); 264 return Response::InvalidParams("Invalid 'text' parameter");
252 if (!SetKeyboardEventText(event.unmodifiedText, std::move(unmodified_text))) 265 if (!SetKeyboardEventText(event.unmodifiedText, std::move(unmodified_text)))
253 return Response::InvalidParams("Invalid 'unmodifiedText' parameter"); 266 return Response::InvalidParams("Invalid 'unmodifiedText' parameter");
254 267
255 if (windows_virtual_key_code.isJust()) 268 if (windows_virtual_key_code.isJust())
256 event.windowsKeyCode = windows_virtual_key_code.fromJust(); 269 event.windowsKeyCode = windows_virtual_key_code.fromJust();
257 if (native_virtual_key_code.isJust()) 270 if (native_virtual_key_code.isJust())
258 event.nativeKeyCode = native_virtual_key_code.fromJust(); 271 event.nativeKeyCode = native_virtual_key_code.fromJust();
259 if (auto_repeat.fromMaybe(false))
260 event.modifiers |= blink::WebInputEvent::IsAutoRepeat;
261 if (is_keypad.fromMaybe(false))
262 event.modifiers |= blink::WebInputEvent::IsKeyPad;
263 if (is_system_key.isJust()) 272 if (is_system_key.isJust())
264 event.isSystemKey = is_system_key.fromJust(); 273 event.isSystemKey = is_system_key.fromJust();
265 274
266 if (code.isJust()) { 275 if (code.isJust()) {
267 event.domCode = static_cast<int>( 276 event.domCode = static_cast<int>(
268 ui::KeycodeConverter::CodeStringToDomCode(code.fromJust())); 277 ui::KeycodeConverter::CodeStringToDomCode(code.fromJust()));
269 } 278 }
270 279
271 if (key.isJust()) { 280 if (key.isJust()) {
272 event.domKey = static_cast<int>( 281 event.domKey = static_cast<int>(
273 ui::KeycodeConverter::KeyStringToDomKey(key.fromJust())); 282 ui::KeycodeConverter::KeyStringToDomKey(key.fromJust()));
274 } 283 }
275 284
276 if (!host_ || !host_->GetRenderWidgetHost()) 285 if (!host_ || !host_->GetRenderWidgetHost())
277 return Response::InternalError(); 286 return Response::InternalError();
278 287
279 host_->GetRenderWidgetHost()->Focus(); 288 host_->GetRenderWidgetHost()->Focus();
280 host_->GetRenderWidgetHost()->ForwardKeyboardEvent(event); 289 host_->GetRenderWidgetHost()->ForwardKeyboardEvent(event);
281 return Response::OK(); 290 return Response::OK();
282 } 291 }
283 292
284 Response InputHandler::DispatchMouseEvent( 293 Response InputHandler::DispatchMouseEvent(
285 const std::string& type, 294 const std::string& type,
286 int x, 295 int x,
287 int y, 296 int y,
288 Maybe<int> modifiers, 297 Maybe<int> modifiers,
289 Maybe<double> timestamp, 298 Maybe<double> timestamp,
290 Maybe<std::string> button, 299 Maybe<std::string> button,
291 Maybe<int> click_count) { 300 Maybe<int> click_count) {
292 blink::WebMouseEvent event; 301 blink::WebInputEvent::Type event_type = GetMouseEventType(type);
293 302 if (event_type == blink::WebInputEvent::Undefined) {
294 if (!SetMouseEventType(&event, type)) {
295 return Response::InvalidParams( 303 return Response::InvalidParams(
296 base::StringPrintf("Unexpected event type '%s'", type.c_str())); 304 base::StringPrintf("Unexpected event type '%s'", type.c_str()));
297 } 305 }
298 SetEventModifiers(&event, modifiers.fromMaybe(0)); 306 blink::WebPointerProperties::Button event_button =
299 SetEventTimestamp(&event, std::move(timestamp)); 307 blink::WebPointerProperties::Button::NoButton;
300 if (!SetMouseEventButton(&event, button.fromMaybe(""))) 308 int button_modifiers = 0;
309 if (!GetMouseEventButton(button.fromMaybe(""), &event_button,
310 &button_modifiers))
301 return Response::InvalidParams("Invalid mouse button"); 311 return Response::InvalidParams("Invalid mouse button");
302 312
313 blink::WebMouseEvent event(
314 event_type,
315 GetEventModifiers(modifiers.fromMaybe(blink::WebInputEvent::NoModifiers),
316 false, false) |
317 button_modifiers,
318 GetEventTimestamp(std::move(timestamp)));
319
320 event.button = event_button;
303 event.x = x * page_scale_factor_; 321 event.x = x * page_scale_factor_;
304 event.y = y * page_scale_factor_; 322 event.y = y * page_scale_factor_;
305 event.windowX = x * page_scale_factor_; 323 event.windowX = x * page_scale_factor_;
306 event.windowY = y * page_scale_factor_; 324 event.windowY = y * page_scale_factor_;
307 event.globalX = x * page_scale_factor_; 325 event.globalX = x * page_scale_factor_;
308 event.globalY = y * page_scale_factor_; 326 event.globalY = y * page_scale_factor_;
309 event.clickCount = click_count.fromMaybe(0); 327 event.clickCount = click_count.fromMaybe(0);
310 event.pointerType = blink::WebPointerProperties::PointerType::Mouse; 328 event.pointerType = blink::WebPointerProperties::PointerType::Mouse;
311 329
312 if (!host_ || !host_->GetRenderWidgetHost()) 330 if (!host_ || !host_->GetRenderWidgetHost())
313 return Response::InternalError(); 331 return Response::InternalError();
314 332
315 host_->GetRenderWidgetHost()->Focus(); 333 host_->GetRenderWidgetHost()->Focus();
316 host_->GetRenderWidgetHost()->ForwardMouseEvent(event); 334 host_->GetRenderWidgetHost()->ForwardMouseEvent(event);
317 return Response::OK(); 335 return Response::OK();
318 } 336 }
319 337
320 Response InputHandler::EmulateTouchFromMouseEvent(const std::string& type, 338 Response InputHandler::EmulateTouchFromMouseEvent(const std::string& type,
321 int x, 339 int x,
322 int y, 340 int y,
323 double timestamp, 341 double timestamp,
324 const std::string& button, 342 const std::string& button,
325 Maybe<double> delta_x, 343 Maybe<double> delta_x,
326 Maybe<double> delta_y, 344 Maybe<double> delta_y,
327 Maybe<int> modifiers, 345 Maybe<int> modifiers,
328 Maybe<int> click_count) { 346 Maybe<int> click_count) {
329 blink::WebMouseWheelEvent wheel_event; 347 blink::WebInputEvent::Type event_type;
330 blink::WebMouseEvent mouse_event;
331 blink::WebMouseEvent* event = &mouse_event;
332
333 if (type == Input::EmulateTouchFromMouseEvent::TypeEnum::MouseWheel) { 348 if (type == Input::EmulateTouchFromMouseEvent::TypeEnum::MouseWheel) {
349 event_type = blink::WebInputEvent::MouseWheel;
334 if (!delta_x.isJust() || !delta_y.isJust()) { 350 if (!delta_x.isJust() || !delta_y.isJust()) {
335 return Response::InvalidParams( 351 return Response::InvalidParams(
336 "'deltaX' and 'deltaY' are expected for mouseWheel event"); 352 "'deltaX' and 'deltaY' are expected for mouseWheel event");
337 } 353 }
338 wheel_event.deltaX = static_cast<float>(delta_x.fromJust()); 354 } else {
339 wheel_event.deltaY = static_cast<float>(delta_y.fromJust()); 355 event_type = GetMouseEventType(type);
340 event = &wheel_event; 356 if (event_type == blink::WebInputEvent::Undefined) {
341 event->type = blink::WebInputEvent::MouseWheel; 357 return Response::InvalidParams(
342 } else if (!SetMouseEventType(event, type)) { 358 base::StringPrintf("Unexpected event type '%s'", type.c_str()));
343 return Response::InvalidParams( 359 }
344 base::StringPrintf("Unexpected event type '%s'", type.c_str()));
345 } 360 }
346 361
347 SetEventModifiers(event, modifiers.fromMaybe(0)); 362 blink::WebPointerProperties::Button event_button =
348 SetEventTimestamp(event, Maybe<double>(timestamp)); 363 blink::WebPointerProperties::Button::NoButton;
349 if (!SetMouseEventButton(event, button)) 364 int button_modifiers = 0;
365 if (!GetMouseEventButton(button, &event_button, &button_modifiers))
350 return Response::InvalidParams("Invalid mouse button"); 366 return Response::InvalidParams("Invalid mouse button");
351 367
352 event->x = x; 368 ui::ScopedWebInputEvent event;
353 event->y = y; 369 blink::WebMouseWheelEvent* wheel_event = nullptr;
354 event->windowX = x; 370 blink::WebMouseEvent* mouse_event = nullptr;
355 event->windowY = y; 371 if (type == Input::EmulateTouchFromMouseEvent::TypeEnum::MouseWheel) {
356 event->globalX = x; 372 wheel_event = new blink::WebMouseWheelEvent(
357 event->globalY = y; 373 event_type, GetEventModifiers(
358 event->clickCount = click_count.fromMaybe(0); 374 modifiers.fromMaybe(blink::WebInputEvent::NoModifiers),
359 event->pointerType = blink::WebPointerProperties::PointerType::Touch; 375 false, false) |
376 button_modifiers,
377 GetEventTimestamp(timestamp));
378 mouse_event = wheel_event;
379 event.reset(wheel_event);
380 wheel_event->deltaX = static_cast<float>(delta_x.fromJust());
381 wheel_event->deltaY = static_cast<float>(delta_y.fromJust());
382 } else {
383 mouse_event = new blink::WebMouseEvent(
384 event_type, GetEventModifiers(
385 modifiers.fromMaybe(blink::WebInputEvent::NoModifiers),
386 false, false) |
387 button_modifiers,
388 GetEventTimestamp(timestamp));
389 event.reset(mouse_event);
390 }
391
392 mouse_event->x = x;
393 mouse_event->y = y;
394 mouse_event->button = event_button;
395 mouse_event->windowX = x;
396 mouse_event->windowY = y;
397 mouse_event->globalX = x;
398 mouse_event->globalY = y;
399 mouse_event->clickCount = click_count.fromMaybe(0);
400 mouse_event->pointerType = blink::WebPointerProperties::PointerType::Touch;
360 401
361 if (!host_ || !host_->GetRenderWidgetHost()) 402 if (!host_ || !host_->GetRenderWidgetHost())
362 return Response::InternalError(); 403 return Response::InternalError();
363 404
364 if (event->type == blink::WebInputEvent::MouseWheel) 405 if (wheel_event)
365 host_->GetRenderWidgetHost()->ForwardWheelEvent(wheel_event); 406 host_->GetRenderWidgetHost()->ForwardWheelEvent(*wheel_event);
366 else 407 else
367 host_->GetRenderWidgetHost()->ForwardMouseEvent(mouse_event); 408 host_->GetRenderWidgetHost()->ForwardMouseEvent(*mouse_event);
368 return Response::OK(); 409 return Response::OK();
369 } 410 }
370 411
371 void InputHandler::SynthesizePinchGesture( 412 void InputHandler::SynthesizePinchGesture(
372 int x, 413 int x,
373 int y, 414 int y,
374 double scale_factor, 415 double scale_factor,
375 Maybe<int> relative_speed, 416 Maybe<int> relative_speed,
376 Maybe<std::string> gesture_source_type, 417 Maybe<std::string> gesture_source_type,
377 std::unique_ptr<SynthesizePinchGestureCallback> callback) { 418 std::unique_ptr<SynthesizePinchGestureCallback> callback) {
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 for (int i = 0; i < count; i++) { 582 for (int i = 0; i < count; i++) {
542 host_->GetRenderWidgetHost()->QueueSyntheticGesture( 583 host_->GetRenderWidgetHost()->QueueSyntheticGesture(
543 SyntheticGesture::Create(gesture_params), 584 SyntheticGesture::Create(gesture_params),
544 base::Bind(&TapGestureResponse::OnGestureResult, 585 base::Bind(&TapGestureResponse::OnGestureResult,
545 base::Unretained(response))); 586 base::Unretained(response)));
546 } 587 }
547 } 588 }
548 589
549 } // namespace protocol 590 } // namespace protocol
550 } // namespace content 591 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698