Home | History | Annotate | Download | only in test_runner
      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 
     27 namespace content {
     28 
     29 namespace {
     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 
     61 void 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 
     70 const 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 
     85 void 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 
     96 void 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 
    115 blink::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 
    124 void DeferredDelete(void* context) {
    125   TestPlugin* plugin = static_cast<TestPlugin*>(context);
    126   delete plugin;
    127 }
    128 
    129 }  // namespace
    130 
    131 TestPlugin::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 
    200 TestPlugin::~TestPlugin() {
    201 }
    202 
    203 bool 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 
    226 void 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 
    244 NPObject* TestPlugin::scriptableObject() {
    245   return 0;
    246 }
    247 
    248 bool TestPlugin::canProcessDrag() const {
    249   return can_process_drag_;
    250 }
    251 
    252 void 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 
    310 bool TestPlugin::acceptsInputEvents() {
    311   return true;
    312 }
    313 
    314 bool TestPlugin::isPlaceholder() {
    315   return false;
    316 }
    317 
    318 static void IgnoreReleaseCallback(uint32 sync_point, bool lost) {
    319 }
    320 
    321 static void ReleaseSharedMemory(scoped_ptr<base::SharedMemory> bitmap,
    322                                 uint32 sync_point,
    323                                 bool lost) {
    324 }
    325 
    326 bool 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 
    344 TestPlugin::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.
    362 void 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 
    377 float TestPlugin::ParseOpacity(const blink::WebString& string) {
    378   return static_cast<float>(atof(string.utf8().data()));
    379 }
    380 
    381 bool TestPlugin::ParseBoolean(const blink::WebString& string) {
    382   const CR_DEFINE_STATIC_LOCAL(blink::WebString, kPrimitiveTrue, ("true"));
    383   return string == kPrimitiveTrue;
    384 }
    385 
    386 bool 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 
    409 void 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 
    417 void 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 
    451 void 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 
    472 bool 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 
    496 bool 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 
    511 void 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 
    532 unsigned 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 
    548 unsigned 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 
    573 bool 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 
    699 bool 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 
    727 TestPlugin* TestPlugin::create(blink::WebFrame* frame,
    728                                const blink::WebPluginParams& params,
    729                                WebTestDelegate* delegate) {
    730   return new TestPlugin(frame, params, delegate);
    731 }
    732 
    733 const blink::WebString& TestPlugin::MimeType() {
    734   const CR_DEFINE_STATIC_LOCAL(
    735       blink::WebString, kMimeType, ("application/x-webkit-test-webplugin"));
    736   return kMimeType;
    737 }
    738 
    739 const 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 
    747 const 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 
    755 bool 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