1// Copyright 2013 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#include "content/shell/renderer/test_runner/test_plugin.h"
6
7#include "base/basictypes.h"
8#include "base/bind.h"
9#include "base/logging.h"
10#include "base/memory/shared_memory.h"
11#include "base/strings/stringprintf.h"
12#include "content/public/renderer/render_thread.h"
13#include "content/shell/renderer/test_runner/web_test_delegate.h"
14#include "third_party/skia/include/core/SkBitmap.h"
15#include "third_party/skia/include/core/SkCanvas.h"
16#include "third_party/skia/include/core/SkColor.h"
17#include "third_party/WebKit/public/platform/Platform.h"
18#include "third_party/WebKit/public/platform/WebCompositorSupport.h"
19#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
20#include "third_party/WebKit/public/web/WebFrame.h"
21#include "third_party/WebKit/public/web/WebInputEvent.h"
22#include "third_party/WebKit/public/web/WebKit.h"
23#include "third_party/WebKit/public/web/WebPluginParams.h"
24#include "third_party/WebKit/public/web/WebTouchPoint.h"
25#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
26
27namespace content {
28
29namespace {
30
31// GLenum values copied from gl2.h.
32#define GL_FALSE 0
33#define GL_TRUE 1
34#define GL_ONE 1
35#define GL_TRIANGLES 0x0004
36#define GL_ONE_MINUS_SRC_ALPHA 0x0303
37#define GL_DEPTH_TEST 0x0B71
38#define GL_BLEND 0x0BE2
39#define GL_SCISSOR_TEST 0x0B90
40#define GL_TEXTURE_2D 0x0DE1
41#define GL_FLOAT 0x1406
42#define GL_RGBA 0x1908
43#define GL_UNSIGNED_BYTE 0x1401
44#define GL_TEXTURE_MAG_FILTER 0x2800
45#define GL_TEXTURE_MIN_FILTER 0x2801
46#define GL_TEXTURE_WRAP_S 0x2802
47#define GL_TEXTURE_WRAP_T 0x2803
48#define GL_NEAREST 0x2600
49#define GL_COLOR_BUFFER_BIT 0x4000
50#define GL_CLAMP_TO_EDGE 0x812F
51#define GL_ARRAY_BUFFER 0x8892
52#define GL_STATIC_DRAW 0x88E4
53#define GL_FRAGMENT_SHADER 0x8B30
54#define GL_VERTEX_SHADER 0x8B31
55#define GL_COMPILE_STATUS 0x8B81
56#define GL_LINK_STATUS 0x8B82
57#define GL_COLOR_ATTACHMENT0 0x8CE0
58#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
59#define GL_FRAMEBUFFER 0x8D40
60
61void PremultiplyAlpha(const unsigned color_in[3],
62                      float alpha,
63                      float color_out[4]) {
64  for (int i = 0; i < 3; ++i)
65    color_out[i] = (color_in[i] / 255.0f) * alpha;
66
67  color_out[3] = alpha;
68}
69
70const char* PointState(blink::WebTouchPoint::State state) {
71  switch (state) {
72    case blink::WebTouchPoint::StateReleased:
73      return "Released";
74    case blink::WebTouchPoint::StatePressed:
75      return "Pressed";
76    case blink::WebTouchPoint::StateMoved:
77      return "Moved";
78    case blink::WebTouchPoint::StateCancelled:
79      return "Cancelled";
80    default:
81      return "Unknown";
82  }
83}
84
85void PrintTouchList(WebTestDelegate* delegate,
86                    const blink::WebTouchPoint* points,
87                    int length) {
88  for (int i = 0; i < length; ++i) {
89    delegate->PrintMessage(base::StringPrintf("* %.2f, %.2f: %s\n",
90                                              points[i].position.x,
91                                              points[i].position.y,
92                                              PointState(points[i].state)));
93  }
94}
95
96void PrintEventDetails(WebTestDelegate* delegate,
97                       const blink::WebInputEvent& event) {
98  if (blink::WebInputEvent::isTouchEventType(event.type)) {
99    const blink::WebTouchEvent& touch =
100        static_cast<const blink::WebTouchEvent&>(event);
101    PrintTouchList(delegate, touch.touches, touch.touchesLength);
102  } else if (blink::WebInputEvent::isMouseEventType(event.type) ||
103             event.type == blink::WebInputEvent::MouseWheel) {
104    const blink::WebMouseEvent& mouse =
105        static_cast<const blink::WebMouseEvent&>(event);
106    delegate->PrintMessage(base::StringPrintf("* %d, %d\n", mouse.x, mouse.y));
107  } else if (blink::WebInputEvent::isGestureEventType(event.type)) {
108    const blink::WebGestureEvent& gesture =
109        static_cast<const blink::WebGestureEvent&>(event);
110    delegate->PrintMessage(
111        base::StringPrintf("* %d, %d\n", gesture.x, gesture.y));
112  }
113}
114
115blink::WebPluginContainer::TouchEventRequestType ParseTouchEventRequestType(
116    const blink::WebString& string) {
117  if (string == blink::WebString::fromUTF8("raw"))
118    return blink::WebPluginContainer::TouchEventRequestTypeRaw;
119  if (string == blink::WebString::fromUTF8("synthetic"))
120    return blink::WebPluginContainer::TouchEventRequestTypeSynthesizedMouse;
121  return blink::WebPluginContainer::TouchEventRequestTypeNone;
122}
123
124void DeferredDelete(void* context) {
125  TestPlugin* plugin = static_cast<TestPlugin*>(context);
126  delete plugin;
127}
128
129}  // namespace
130
131TestPlugin::TestPlugin(blink::WebFrame* frame,
132                       const blink::WebPluginParams& params,
133                       WebTestDelegate* delegate)
134    : frame_(frame),
135      delegate_(delegate),
136      container_(0),
137      context_(0),
138      color_texture_(0),
139      mailbox_changed_(false),
140      framebuffer_(0),
141      touch_event_request_(
142          blink::WebPluginContainer::TouchEventRequestTypeNone),
143      re_request_touch_events_(false),
144      print_event_details_(false),
145      print_user_gesture_status_(false),
146      can_process_drag_(false),
147      is_persistent_(params.mimeType == PluginPersistsMimeType()),
148      can_create_without_renderer_(params.mimeType ==
149                                   CanCreateWithoutRendererMimeType()) {
150  const CR_DEFINE_STATIC_LOCAL(
151      blink::WebString, kAttributePrimitive, ("primitive"));
152  const CR_DEFINE_STATIC_LOCAL(
153      blink::WebString, kAttributeBackgroundColor, ("background-color"));
154  const CR_DEFINE_STATIC_LOCAL(
155      blink::WebString, kAttributePrimitiveColor, ("primitive-color"));
156  const CR_DEFINE_STATIC_LOCAL(
157      blink::WebString, kAttributeOpacity, ("opacity"));
158  const CR_DEFINE_STATIC_LOCAL(
159      blink::WebString, kAttributeAcceptsTouch, ("accepts-touch"));
160  const CR_DEFINE_STATIC_LOCAL(
161      blink::WebString, kAttributeReRequestTouchEvents, ("re-request-touch"));
162  const CR_DEFINE_STATIC_LOCAL(
163      blink::WebString, kAttributePrintEventDetails, ("print-event-details"));
164  const CR_DEFINE_STATIC_LOCAL(
165      blink::WebString, kAttributeCanProcessDrag, ("can-process-drag"));
166  const CR_DEFINE_STATIC_LOCAL(blink::WebString,
167                               kAttributePrintUserGestureStatus,
168                               ("print-user-gesture-status"));
169
170  DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size());
171  size_t size = params.attributeNames.size();
172  for (size_t i = 0; i < size; ++i) {
173    const blink::WebString& attribute_name = params.attributeNames[i];
174    const blink::WebString& attribute_value = params.attributeValues[i];
175
176    if (attribute_name == kAttributePrimitive)
177      scene_.primitive = ParsePrimitive(attribute_value);
178    else if (attribute_name == kAttributeBackgroundColor)
179      ParseColor(attribute_value, scene_.background_color);
180    else if (attribute_name == kAttributePrimitiveColor)
181      ParseColor(attribute_value, scene_.primitive_color);
182    else if (attribute_name == kAttributeOpacity)
183      scene_.opacity = ParseOpacity(attribute_value);
184    else if (attribute_name == kAttributeAcceptsTouch)
185      touch_event_request_ = ParseTouchEventRequestType(attribute_value);
186    else if (attribute_name == kAttributeReRequestTouchEvents)
187      re_request_touch_events_ = ParseBoolean(attribute_value);
188    else if (attribute_name == kAttributePrintEventDetails)
189      print_event_details_ = ParseBoolean(attribute_value);
190    else if (attribute_name == kAttributeCanProcessDrag)
191      can_process_drag_ = ParseBoolean(attribute_value);
192    else if (attribute_name == kAttributePrintUserGestureStatus)
193      print_user_gesture_status_ = ParseBoolean(attribute_value);
194  }
195  if (can_create_without_renderer_)
196    delegate_->PrintMessage(
197        std::string("TestPlugin: canCreateWithoutRenderer\n"));
198}
199
200TestPlugin::~TestPlugin() {
201}
202
203bool TestPlugin::initialize(blink::WebPluginContainer* container) {
204  blink::WebGraphicsContext3D::Attributes attrs;
205  context_ =
206      blink::Platform::current()->createOffscreenGraphicsContext3D(attrs);
207
208  if (!InitScene())
209    return false;
210
211  layer_ = cc::TextureLayer::CreateForMailbox(this);
212  web_layer_ = make_scoped_ptr(InstantiateWebLayer(layer_));
213  container_ = container;
214  container_->setWebLayer(web_layer_.get());
215  if (re_request_touch_events_) {
216    container_->requestTouchEventType(
217        blink::WebPluginContainer::TouchEventRequestTypeSynthesizedMouse);
218    container_->requestTouchEventType(
219        blink::WebPluginContainer::TouchEventRequestTypeRaw);
220  }
221  container_->requestTouchEventType(touch_event_request_);
222  container_->setWantsWheelEvents(true);
223  return true;
224}
225
226void TestPlugin::destroy() {
227  if (layer_.get())
228    layer_->ClearTexture();
229  if (container_)
230    container_->setWebLayer(0);
231  web_layer_.reset();
232  layer_ = NULL;
233  DestroyScene();
234
235  delete context_;
236  context_ = 0;
237
238  container_ = 0;
239  frame_ = 0;
240
241  blink::Platform::current()->callOnMainThread(DeferredDelete, this);
242}
243
244NPObject* TestPlugin::scriptableObject() {
245  return 0;
246}
247
248bool TestPlugin::canProcessDrag() const {
249  return can_process_drag_;
250}
251
252void TestPlugin::updateGeometry(
253    const blink::WebRect& frame_rect,
254    const blink::WebRect& clip_rect,
255    const blink::WebVector<blink::WebRect>& cut_outs_rects,
256    bool is_visible) {
257  if (clip_rect == rect_)
258    return;
259  rect_ = clip_rect;
260
261  if (rect_.isEmpty()) {
262    texture_mailbox_ = cc::TextureMailbox();
263  } else if (context_) {
264    context_->viewport(0, 0, rect_.width, rect_.height);
265
266    context_->bindTexture(GL_TEXTURE_2D, color_texture_);
267    context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
268    context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
269    context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
270    context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
271    context_->texImage2D(GL_TEXTURE_2D,
272                         0,
273                         GL_RGBA,
274                         rect_.width,
275                         rect_.height,
276                         0,
277                         GL_RGBA,
278                         GL_UNSIGNED_BYTE,
279                         0);
280    context_->bindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
281    context_->framebufferTexture2D(
282        GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_texture_, 0);
283
284    DrawSceneGL();
285
286    gpu::Mailbox mailbox;
287    context_->genMailboxCHROMIUM(mailbox.name);
288    context_->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
289    context_->flush();
290    uint32 sync_point = context_->insertSyncPoint();
291    texture_mailbox_ = cc::TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point);
292  } else {
293    size_t bytes = 4 * rect_.width * rect_.height;
294    scoped_ptr<base::SharedMemory> bitmap =
295        RenderThread::Get()->HostAllocateSharedMemoryBuffer(bytes);
296    if (!bitmap->Map(bytes)) {
297      texture_mailbox_ = cc::TextureMailbox();
298    } else {
299      DrawSceneSoftware(bitmap->memory(), bytes);
300      texture_mailbox_ = cc::TextureMailbox(
301          bitmap.get(), gfx::Size(rect_.width, rect_.height));
302      shared_bitmap_ = bitmap.Pass();
303    }
304  }
305
306  mailbox_changed_ = true;
307  layer_->SetNeedsDisplay();
308}
309
310bool TestPlugin::acceptsInputEvents() {
311  return true;
312}
313
314bool TestPlugin::isPlaceholder() {
315  return false;
316}
317
318static void IgnoreReleaseCallback(uint32 sync_point, bool lost) {
319}
320
321static void ReleaseSharedMemory(scoped_ptr<base::SharedMemory> bitmap,
322                                uint32 sync_point,
323                                bool lost) {
324}
325
326bool TestPlugin::PrepareTextureMailbox(
327    cc::TextureMailbox* mailbox,
328    scoped_ptr<cc::SingleReleaseCallback>* release_callback,
329    bool use_shared_memory) {
330  if (!mailbox_changed_)
331    return false;
332  *mailbox = texture_mailbox_;
333  if (texture_mailbox_.IsTexture()) {
334    *release_callback =
335        cc::SingleReleaseCallback::Create(base::Bind(&IgnoreReleaseCallback));
336  } else {
337    *release_callback = cc::SingleReleaseCallback::Create(
338        base::Bind(&ReleaseSharedMemory, base::Passed(&shared_bitmap_)));
339  }
340  mailbox_changed_ = false;
341  return true;
342}
343
344TestPlugin::Primitive TestPlugin::ParsePrimitive(
345    const blink::WebString& string) {
346  const CR_DEFINE_STATIC_LOCAL(blink::WebString, kPrimitiveNone, ("none"));
347  const CR_DEFINE_STATIC_LOCAL(
348      blink::WebString, kPrimitiveTriangle, ("triangle"));
349
350  Primitive primitive = PrimitiveNone;
351  if (string == kPrimitiveNone)
352    primitive = PrimitiveNone;
353  else if (string == kPrimitiveTriangle)
354    primitive = PrimitiveTriangle;
355  else
356    NOTREACHED();
357  return primitive;
358}
359
360// FIXME: This method should already exist. Use it.
361// For now just parse primary colors.
362void TestPlugin::ParseColor(const blink::WebString& string, unsigned color[3]) {
363  color[0] = color[1] = color[2] = 0;
364  if (string == "black")
365    return;
366
367  if (string == "red")
368    color[0] = 255;
369  else if (string == "green")
370    color[1] = 255;
371  else if (string == "blue")
372    color[2] = 255;
373  else
374    NOTREACHED();
375}
376
377float TestPlugin::ParseOpacity(const blink::WebString& string) {
378  return static_cast<float>(atof(string.utf8().data()));
379}
380
381bool TestPlugin::ParseBoolean(const blink::WebString& string) {
382  const CR_DEFINE_STATIC_LOCAL(blink::WebString, kPrimitiveTrue, ("true"));
383  return string == kPrimitiveTrue;
384}
385
386bool TestPlugin::InitScene() {
387  if (!context_)
388    return true;
389
390  float color[4];
391  PremultiplyAlpha(scene_.background_color, scene_.opacity, color);
392
393  color_texture_ = context_->createTexture();
394  framebuffer_ = context_->createFramebuffer();
395
396  context_->viewport(0, 0, rect_.width, rect_.height);
397  context_->disable(GL_DEPTH_TEST);
398  context_->disable(GL_SCISSOR_TEST);
399
400  context_->clearColor(color[0], color[1], color[2], color[3]);
401
402  context_->enable(GL_BLEND);
403  context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
404
405  return scene_.primitive != PrimitiveNone ? InitProgram() && InitPrimitive()
406                                           : true;
407}
408
409void TestPlugin::DrawSceneGL() {
410  context_->viewport(0, 0, rect_.width, rect_.height);
411  context_->clear(GL_COLOR_BUFFER_BIT);
412
413  if (scene_.primitive != PrimitiveNone)
414    DrawPrimitive();
415}
416
417void TestPlugin::DrawSceneSoftware(void* memory, size_t bytes) {
418  DCHECK_EQ(bytes, rect_.width * rect_.height * 4u);
419
420  SkColor background_color =
421      SkColorSetARGB(static_cast<uint8>(scene_.opacity * 255),
422                     scene_.background_color[0],
423                     scene_.background_color[1],
424                     scene_.background_color[2]);
425
426  const SkImageInfo info =
427      SkImageInfo::MakeN32Premul(rect_.width, rect_.height);
428  SkBitmap bitmap;
429  bitmap.installPixels(info, memory, info.minRowBytes());
430  SkCanvas canvas(bitmap);
431  canvas.clear(background_color);
432
433  if (scene_.primitive != PrimitiveNone) {
434    DCHECK_EQ(PrimitiveTriangle, scene_.primitive);
435    SkColor foreground_color =
436        SkColorSetARGB(static_cast<uint8>(scene_.opacity * 255),
437                       scene_.primitive_color[0],
438                       scene_.primitive_color[1],
439                       scene_.primitive_color[2]);
440    SkPath triangle_path;
441    triangle_path.moveTo(0.5f * rect_.width, 0.9f * rect_.height);
442    triangle_path.lineTo(0.1f * rect_.width, 0.1f * rect_.height);
443    triangle_path.lineTo(0.9f * rect_.width, 0.1f * rect_.height);
444    SkPaint paint;
445    paint.setColor(foreground_color);
446    paint.setStyle(SkPaint::kFill_Style);
447    canvas.drawPath(triangle_path, paint);
448  }
449}
450
451void TestPlugin::DestroyScene() {
452  if (scene_.program) {
453    context_->deleteProgram(scene_.program);
454    scene_.program = 0;
455  }
456  if (scene_.vbo) {
457    context_->deleteBuffer(scene_.vbo);
458    scene_.vbo = 0;
459  }
460
461  if (framebuffer_) {
462    context_->deleteFramebuffer(framebuffer_);
463    framebuffer_ = 0;
464  }
465
466  if (color_texture_) {
467    context_->deleteTexture(color_texture_);
468    color_texture_ = 0;
469  }
470}
471
472bool TestPlugin::InitProgram() {
473  const std::string vertex_source(
474      "attribute vec4 position;  \n"
475      "void main() {             \n"
476      "  gl_Position = position; \n"
477      "}                         \n");
478
479  const std::string fragment_source(
480      "precision mediump float; \n"
481      "uniform vec4 color;      \n"
482      "void main() {            \n"
483      "  gl_FragColor = color;  \n"
484      "}                        \n");
485
486  scene_.program = LoadProgram(vertex_source, fragment_source);
487  if (!scene_.program)
488    return false;
489
490  scene_.color_location = context_->getUniformLocation(scene_.program, "color");
491  scene_.position_location =
492      context_->getAttribLocation(scene_.program, "position");
493  return true;
494}
495
496bool TestPlugin::InitPrimitive() {
497  DCHECK_EQ(scene_.primitive, PrimitiveTriangle);
498
499  scene_.vbo = context_->createBuffer();
500  if (!scene_.vbo)
501    return false;
502
503  const float vertices[] = {0.0f, 0.8f, 0.0f,  -0.8f, -0.8f,
504                            0.0f, 0.8f, -0.8f, 0.0f};
505  context_->bindBuffer(GL_ARRAY_BUFFER, scene_.vbo);
506  context_->bufferData(GL_ARRAY_BUFFER, sizeof(vertices), 0, GL_STATIC_DRAW);
507  context_->bufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
508  return true;
509}
510
511void TestPlugin::DrawPrimitive() {
512  DCHECK_EQ(scene_.primitive, PrimitiveTriangle);
513  DCHECK(scene_.vbo);
514  DCHECK(scene_.program);
515
516  context_->useProgram(scene_.program);
517
518  // Bind primitive color.
519  float color[4];
520  PremultiplyAlpha(scene_.primitive_color, scene_.opacity, color);
521  context_->uniform4f(
522      scene_.color_location, color[0], color[1], color[2], color[3]);
523
524  // Bind primitive vertices.
525  context_->bindBuffer(GL_ARRAY_BUFFER, scene_.vbo);
526  context_->enableVertexAttribArray(scene_.position_location);
527  context_->vertexAttribPointer(
528      scene_.position_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
529  context_->drawArrays(GL_TRIANGLES, 0, 3);
530}
531
532unsigned TestPlugin::LoadShader(unsigned type, const std::string& source) {
533  unsigned shader = context_->createShader(type);
534  if (shader) {
535    context_->shaderSource(shader, source.data());
536    context_->compileShader(shader);
537
538    int compiled = 0;
539    context_->getShaderiv(shader, GL_COMPILE_STATUS, &compiled);
540    if (!compiled) {
541      context_->deleteShader(shader);
542      shader = 0;
543    }
544  }
545  return shader;
546}
547
548unsigned TestPlugin::LoadProgram(const std::string& vertex_source,
549                                 const std::string& fragment_source) {
550  unsigned vertex_shader = LoadShader(GL_VERTEX_SHADER, vertex_source);
551  unsigned fragment_shader = LoadShader(GL_FRAGMENT_SHADER, fragment_source);
552  unsigned program = context_->createProgram();
553  if (vertex_shader && fragment_shader && program) {
554    context_->attachShader(program, vertex_shader);
555    context_->attachShader(program, fragment_shader);
556    context_->linkProgram(program);
557
558    int linked = 0;
559    context_->getProgramiv(program, GL_LINK_STATUS, &linked);
560    if (!linked) {
561      context_->deleteProgram(program);
562      program = 0;
563    }
564  }
565  if (vertex_shader)
566    context_->deleteShader(vertex_shader);
567  if (fragment_shader)
568    context_->deleteShader(fragment_shader);
569
570  return program;
571}
572
573bool TestPlugin::handleInputEvent(const blink::WebInputEvent& event,
574                                  blink::WebCursorInfo& info) {
575  const char* event_name = 0;
576  switch (event.type) {
577    case blink::WebInputEvent::Undefined:
578      event_name = "unknown";
579      break;
580
581    case blink::WebInputEvent::MouseDown:
582      event_name = "MouseDown";
583      break;
584    case blink::WebInputEvent::MouseUp:
585      event_name = "MouseUp";
586      break;
587    case blink::WebInputEvent::MouseMove:
588      event_name = "MouseMove";
589      break;
590    case blink::WebInputEvent::MouseEnter:
591      event_name = "MouseEnter";
592      break;
593    case blink::WebInputEvent::MouseLeave:
594      event_name = "MouseLeave";
595      break;
596    case blink::WebInputEvent::ContextMenu:
597      event_name = "ContextMenu";
598      break;
599
600    case blink::WebInputEvent::MouseWheel:
601      event_name = "MouseWheel";
602      break;
603
604    case blink::WebInputEvent::RawKeyDown:
605      event_name = "RawKeyDown";
606      break;
607    case blink::WebInputEvent::KeyDown:
608      event_name = "KeyDown";
609      break;
610    case blink::WebInputEvent::KeyUp:
611      event_name = "KeyUp";
612      break;
613    case blink::WebInputEvent::Char:
614      event_name = "Char";
615      break;
616
617    case blink::WebInputEvent::GestureScrollBegin:
618      event_name = "GestureScrollBegin";
619      break;
620    case blink::WebInputEvent::GestureScrollEnd:
621      event_name = "GestureScrollEnd";
622      break;
623    case blink::WebInputEvent::GestureScrollUpdateWithoutPropagation:
624    case blink::WebInputEvent::GestureScrollUpdate:
625      event_name = "GestureScrollUpdate";
626      break;
627    case blink::WebInputEvent::GestureFlingStart:
628      event_name = "GestureFlingStart";
629      break;
630    case blink::WebInputEvent::GestureFlingCancel:
631      event_name = "GestureFlingCancel";
632      break;
633    case blink::WebInputEvent::GestureTap:
634      event_name = "GestureTap";
635      break;
636    case blink::WebInputEvent::GestureTapUnconfirmed:
637      event_name = "GestureTapUnconfirmed";
638      break;
639    case blink::WebInputEvent::GestureTapDown:
640      event_name = "GestureTapDown";
641      break;
642    case blink::WebInputEvent::GestureShowPress:
643      event_name = "GestureShowPress";
644      break;
645    case blink::WebInputEvent::GestureTapCancel:
646      event_name = "GestureTapCancel";
647      break;
648    case blink::WebInputEvent::GestureDoubleTap:
649      event_name = "GestureDoubleTap";
650      break;
651    case blink::WebInputEvent::GestureTwoFingerTap:
652      event_name = "GestureTwoFingerTap";
653      break;
654    case blink::WebInputEvent::GestureLongPress:
655      event_name = "GestureLongPress";
656      break;
657    case blink::WebInputEvent::GestureLongTap:
658      event_name = "GestureLongTap";
659      break;
660    case blink::WebInputEvent::GesturePinchBegin:
661      event_name = "GesturePinchBegin";
662      break;
663    case blink::WebInputEvent::GesturePinchEnd:
664      event_name = "GesturePinchEnd";
665      break;
666    case blink::WebInputEvent::GesturePinchUpdate:
667      event_name = "GesturePinchUpdate";
668      break;
669
670    case blink::WebInputEvent::TouchStart:
671      event_name = "TouchStart";
672      break;
673    case blink::WebInputEvent::TouchMove:
674      event_name = "TouchMove";
675      break;
676    case blink::WebInputEvent::TouchEnd:
677      event_name = "TouchEnd";
678      break;
679    case blink::WebInputEvent::TouchCancel:
680      event_name = "TouchCancel";
681      break;
682  }
683
684  delegate_->PrintMessage(std::string("Plugin received event: ") +
685                          (event_name ? event_name : "unknown") + "\n");
686  if (print_event_details_)
687    PrintEventDetails(delegate_, event);
688  if (print_user_gesture_status_)
689    delegate_->PrintMessage(
690        std::string("* ") +
691        (blink::WebUserGestureIndicator::isProcessingUserGesture() ? ""
692                                                                   : "not ") +
693        "handling user gesture\n");
694  if (is_persistent_)
695    delegate_->PrintMessage(std::string("TestPlugin: isPersistent\n"));
696  return false;
697}
698
699bool TestPlugin::handleDragStatusUpdate(
700    blink::WebDragStatus drag_status,
701    const blink::WebDragData& data,
702    blink::WebDragOperationsMask mask,
703    const blink::WebPoint& position,
704    const blink::WebPoint& screen_position) {
705  const char* drag_status_name = 0;
706  switch (drag_status) {
707    case blink::WebDragStatusEnter:
708      drag_status_name = "DragEnter";
709      break;
710    case blink::WebDragStatusOver:
711      drag_status_name = "DragOver";
712      break;
713    case blink::WebDragStatusLeave:
714      drag_status_name = "DragLeave";
715      break;
716    case blink::WebDragStatusDrop:
717      drag_status_name = "DragDrop";
718      break;
719    case blink::WebDragStatusUnknown:
720      NOTREACHED();
721  }
722  delegate_->PrintMessage(std::string("Plugin received event: ") +
723                          drag_status_name + "\n");
724  return false;
725}
726
727TestPlugin* TestPlugin::create(blink::WebFrame* frame,
728                               const blink::WebPluginParams& params,
729                               WebTestDelegate* delegate) {
730  return new TestPlugin(frame, params, delegate);
731}
732
733const blink::WebString& TestPlugin::MimeType() {
734  const CR_DEFINE_STATIC_LOCAL(
735      blink::WebString, kMimeType, ("application/x-webkit-test-webplugin"));
736  return kMimeType;
737}
738
739const blink::WebString& TestPlugin::CanCreateWithoutRendererMimeType() {
740  const CR_DEFINE_STATIC_LOCAL(
741      blink::WebString,
742      kCanCreateWithoutRendererMimeType,
743      ("application/x-webkit-test-webplugin-can-create-without-renderer"));
744  return kCanCreateWithoutRendererMimeType;
745}
746
747const blink::WebString& TestPlugin::PluginPersistsMimeType() {
748  const CR_DEFINE_STATIC_LOCAL(
749      blink::WebString,
750      kPluginPersistsMimeType,
751      ("application/x-webkit-test-webplugin-persistent"));
752  return kPluginPersistsMimeType;
753}
754
755bool TestPlugin::IsSupportedMimeType(const blink::WebString& mime_type) {
756  return mime_type == TestPlugin::MimeType() ||
757         mime_type == PluginPersistsMimeType() ||
758         mime_type == CanCreateWithoutRendererMimeType();
759}
760
761}  // namespace content
762