| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/shell/test_runner/test_plugin.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/shared_memory.h" |
| #include "base/no_destructor.h" |
| #include "base/strings/stringprintf.h" |
| #include "cc/layers/texture_layer.h" |
| #include "cc/resources/cross_thread_shared_bitmap.h" |
| #include "components/viz/common/resources/bitmap_allocation.h" |
| #include "content/shell/test_runner/web_test_delegate.h" |
| #include "gpu/command_buffer/client/gles2_interface.h" |
| #include "third_party/blink/public/platform/platform.h" |
| #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" |
| #include "third_party/blink/public/platform/web_coalesced_input_event.h" |
| #include "third_party/blink/public/platform/web_gesture_event.h" |
| #include "third_party/blink/public/platform/web_graphics_context_3d_provider.h" |
| #include "third_party/blink/public/platform/web_input_event.h" |
| #include "third_party/blink/public/platform/web_mouse_event.h" |
| #include "third_party/blink/public/platform/web_touch_event.h" |
| #include "third_party/blink/public/platform/web_touch_point.h" |
| #include "third_party/blink/public/platform/web_url.h" |
| #include "third_party/blink/public/web/blink.h" |
| #include "third_party/blink/public/web/web_plugin_params.h" |
| #include "third_party/blink/public/web/web_user_gesture_indicator.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "third_party/skia/include/core/SkCanvas.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "third_party/skia/include/core/SkPaint.h" |
| #include "third_party/skia/include/core/SkPath.h" |
| |
| namespace test_runner { |
| |
| namespace { |
| |
| void PremultiplyAlpha(const uint8_t color_in[3], |
| float alpha, |
| float color_out[4]) { |
| for (int i = 0; i < 3; ++i) |
| color_out[i] = (color_in[i] / 255.0f) * alpha; |
| |
| color_out[3] = alpha; |
| } |
| |
| const char* PointState(blink::WebTouchPoint::State state) { |
| switch (state) { |
| case blink::WebTouchPoint::kStateReleased: |
| return "Released"; |
| case blink::WebTouchPoint::kStatePressed: |
| return "Pressed"; |
| case blink::WebTouchPoint::kStateMoved: |
| return "Moved"; |
| case blink::WebTouchPoint::kStateCancelled: |
| return "Cancelled"; |
| default: |
| return "Unknown"; |
| } |
| } |
| |
| void PrintTouchList(WebTestDelegate* delegate, |
| const blink::WebTouchPoint* points, |
| int length) { |
| for (int i = 0; i < length; ++i) { |
| delegate->PrintMessage(base::StringPrintf( |
| "* %.2f, %.2f: %s\n", points[i].PositionInWidget().x, |
| points[i].PositionInWidget().y, PointState(points[i].state))); |
| } |
| } |
| |
| void PrintEventDetails(WebTestDelegate* delegate, |
| const blink::WebInputEvent& event) { |
| if (blink::WebInputEvent::IsTouchEventType(event.GetType())) { |
| const blink::WebTouchEvent& touch = |
| static_cast<const blink::WebTouchEvent&>(event); |
| PrintTouchList(delegate, touch.touches, touch.touches_length); |
| } else if (blink::WebInputEvent::IsMouseEventType(event.GetType()) || |
| event.GetType() == blink::WebInputEvent::kMouseWheel) { |
| const blink::WebMouseEvent& mouse = |
| static_cast<const blink::WebMouseEvent&>(event); |
| delegate->PrintMessage(base::StringPrintf("* %.2f, %.2f\n", |
| mouse.PositionInWidget().x, |
| mouse.PositionInWidget().y)); |
| } else if (blink::WebInputEvent::IsGestureEventType(event.GetType())) { |
| const blink::WebGestureEvent& gesture = |
| static_cast<const blink::WebGestureEvent&>(event); |
| delegate->PrintMessage(base::StringPrintf("* %.2f, %.2f\n", |
| gesture.PositionInWidget().x, |
| gesture.PositionInWidget().y)); |
| } |
| } |
| |
| blink::WebPluginContainer::TouchEventRequestType ParseTouchEventRequestType( |
| const blink::WebString& string) { |
| if (string == blink::WebString::FromUTF8("raw")) |
| return blink::WebPluginContainer::kTouchEventRequestTypeRaw; |
| if (string == blink::WebString::FromUTF8("raw-lowlatency")) |
| return blink::WebPluginContainer::kTouchEventRequestTypeRawLowLatency; |
| if (string == blink::WebString::FromUTF8("synthetic")) |
| return blink::WebPluginContainer::kTouchEventRequestTypeSynthesizedMouse; |
| return blink::WebPluginContainer::kTouchEventRequestTypeNone; |
| } |
| |
| } // namespace |
| |
| TestPlugin::TestPlugin(const blink::WebPluginParams& params, |
| WebTestDelegate* delegate, |
| blink::WebLocalFrame* frame) |
| : delegate_(delegate), |
| container_(nullptr), |
| web_local_frame_(frame), |
| gl_(nullptr), |
| color_texture_(0), |
| content_changed_(false), |
| framebuffer_(0), |
| touch_event_request_( |
| blink::WebPluginContainer::kTouchEventRequestTypeNone), |
| re_request_touch_events_(false), |
| print_event_details_(false), |
| print_user_gesture_status_(false), |
| can_process_drag_(false), |
| supports_keyboard_focus_(false), |
| is_persistent_(params.mime_type == PluginPersistsMimeType()) { |
| DCHECK_EQ(params.attribute_names.size(), params.attribute_values.size()); |
| size_t size = params.attribute_names.size(); |
| for (size_t i = 0; i < size; ++i) { |
| const blink::WebString& attribute_name = params.attribute_names[i]; |
| const blink::WebString& attribute_value = params.attribute_values[i]; |
| |
| if (attribute_name == "primitive") |
| scene_.primitive = ParsePrimitive(attribute_value); |
| else if (attribute_name == "background-color") |
| ParseColor(attribute_value, scene_.background_color); |
| else if (attribute_name == "primitive-color") |
| ParseColor(attribute_value, scene_.primitive_color); |
| else if (attribute_name == "opacity") |
| scene_.opacity = ParseOpacity(attribute_value); |
| else if (attribute_name == "accepts-touch") |
| touch_event_request_ = ParseTouchEventRequestType(attribute_value); |
| else if (attribute_name == "re-request-touch") |
| re_request_touch_events_ = ParseBoolean(attribute_value); |
| else if (attribute_name == "print-event-details") |
| print_event_details_ = ParseBoolean(attribute_value); |
| else if (attribute_name == "can-process-drag") |
| can_process_drag_ = ParseBoolean(attribute_value); |
| else if (attribute_name == "supports-keyboard-focus") |
| supports_keyboard_focus_ = ParseBoolean(attribute_value); |
| else if (attribute_name == "print-user-gesture-status") |
| print_user_gesture_status_ = ParseBoolean(attribute_value); |
| } |
| } |
| |
| TestPlugin::~TestPlugin() {} |
| |
| bool TestPlugin::Initialize(blink::WebPluginContainer* container) { |
| DCHECK(container); |
| DCHECK_EQ(this, container->Plugin()); |
| |
| container_ = container; |
| |
| blink::Platform::ContextAttributes attrs; |
| blink::WebURL url = container->GetDocument().Url(); |
| blink::Platform::GraphicsInfo gl_info; |
| context_provider_ = |
| blink::Platform::Current()->CreateOffscreenGraphicsContext3DProvider( |
| attrs, url, &gl_info); |
| if (context_provider_ && !context_provider_->BindToCurrentThread()) |
| context_provider_ = nullptr; |
| gl_ = context_provider_ ? context_provider_->ContextGL() : nullptr; |
| |
| if (!InitScene()) |
| return false; |
| |
| layer_ = cc::TextureLayer::CreateForMailbox(this); |
| bool prevent_contents_opaque_changes = false; |
| container_->SetCcLayer(layer_.get(), prevent_contents_opaque_changes); |
| if (re_request_touch_events_) { |
| container_->RequestTouchEventType( |
| blink::WebPluginContainer::kTouchEventRequestTypeSynthesizedMouse); |
| container_->RequestTouchEventType( |
| blink::WebPluginContainer::kTouchEventRequestTypeRaw); |
| } |
| container_->RequestTouchEventType(touch_event_request_); |
| container_->SetWantsWheelEvents(true); |
| return true; |
| } |
| |
| void TestPlugin::Destroy() { |
| if (layer_.get()) |
| layer_->ClearTexture(); |
| if (container_) |
| container_->SetCcLayer(nullptr, false); |
| layer_ = nullptr; |
| DestroyScene(); |
| |
| gl_ = nullptr; |
| context_provider_.reset(); |
| |
| container_ = nullptr; |
| |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()->DeleteSoon(FROM_HERE, |
| this); |
| } |
| |
| blink::WebPluginContainer* TestPlugin::Container() const { |
| return container_; |
| } |
| |
| bool TestPlugin::CanProcessDrag() const { |
| return can_process_drag_; |
| } |
| |
| bool TestPlugin::SupportsKeyboardFocus() const { |
| return supports_keyboard_focus_; |
| } |
| |
| void TestPlugin::UpdateGeometry( |
| const blink::WebRect& window_rect, |
| const blink::WebRect& clip_rect, |
| const blink::WebRect& unobscured_rect, |
| bool is_visible) { |
| if (clip_rect == rect_) |
| return; |
| rect_ = clip_rect; |
| |
| if (rect_.IsEmpty()) { |
| mailbox_ = gpu::Mailbox(); |
| sync_token_ = gpu::SyncToken(); |
| shared_bitmap_ = nullptr; |
| } else if (gl_) { |
| gl_->Viewport(0, 0, rect_.width, rect_.height); |
| |
| gl_->BindTexture(GL_TEXTURE_2D, color_texture_); |
| gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rect_.width, rect_.height, 0, |
| GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| gl_->BindFramebuffer(GL_FRAMEBUFFER, framebuffer_); |
| gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| GL_TEXTURE_2D, color_texture_, 0); |
| |
| DrawSceneGL(); |
| |
| gl_->ProduceTextureDirectCHROMIUM(color_texture_, mailbox_.name); |
| gl_->Flush(); |
| gl_->GenSyncTokenCHROMIUM(sync_token_.GetData()); |
| |
| shared_bitmap_ = nullptr; |
| } else { |
| mailbox_ = gpu::Mailbox(); |
| sync_token_ = gpu::SyncToken(); |
| |
| viz::SharedBitmapId id = viz::SharedBitmap::GenerateId(); |
| std::unique_ptr<base::SharedMemory> shm = |
| viz::bitmap_allocation::AllocateMappedBitmap(gfx::Rect(rect_).size(), |
| viz::RGBA_8888); |
| shared_bitmap_ = base::MakeRefCounted<cc::CrossThreadSharedBitmap>( |
| id, std::move(shm), gfx::Rect(rect_).size(), viz::RGBA_8888); |
| // The |shared_bitmap_|'s id will be registered when being given to the |
| // compositor. |
| |
| DrawSceneSoftware(shared_bitmap_->shared_memory()->memory()); |
| } |
| |
| content_changed_ = true; |
| layer_->SetNeedsDisplay(); |
| } |
| |
| bool TestPlugin::IsPlaceholder() { |
| return false; |
| } |
| |
| static void IgnoreReleaseCallback(const gpu::SyncToken& sync_token, bool lost) { |
| } |
| |
| // static |
| void TestPlugin::ReleaseSharedMemory( |
| scoped_refptr<cc::CrossThreadSharedBitmap> shared_bitmap, |
| cc::SharedBitmapIdRegistration registration, |
| const gpu::SyncToken& sync_token, |
| bool lost) {} |
| |
| bool TestPlugin::PrepareTransferableResource( |
| cc::SharedBitmapIdRegistrar* bitmap_registrar, |
| viz::TransferableResource* resource, |
| std::unique_ptr<viz::SingleReleaseCallback>* release_callback) { |
| if (!content_changed_) |
| return false; |
| if (!mailbox_.IsZero()) { |
| *resource = viz::TransferableResource::MakeGL(mailbox_, GL_LINEAR, |
| GL_TEXTURE_2D, sync_token_); |
| *release_callback = viz::SingleReleaseCallback::Create( |
| base::BindOnce(&IgnoreReleaseCallback)); |
| } else if (shared_bitmap_) { |
| // The |bitmap_data_| is only used for a single compositor frame, so we know |
| // the SharedBitmapId in it was not registered yet. |
| cc::SharedBitmapIdRegistration registration = |
| bitmap_registrar->RegisterSharedBitmapId(shared_bitmap_->id(), |
| shared_bitmap_); |
| |
| *resource = viz::TransferableResource::MakeSoftware( |
| shared_bitmap_->id(), shared_bitmap_->size(), viz::RGBA_8888); |
| *release_callback = viz::SingleReleaseCallback::Create( |
| base::BindOnce(&ReleaseSharedMemory, std::move(shared_bitmap_), |
| std::move(registration))); |
| } |
| content_changed_ = false; |
| return true; |
| } |
| |
| TestPlugin::Primitive TestPlugin::ParsePrimitive( |
| const blink::WebString& string) { |
| static const base::NoDestructor<blink::WebString> kPrimitiveNone("none"); |
| static const base::NoDestructor<blink::WebString> kPrimitiveTriangle( |
| "triangle"); |
| |
| Primitive primitive = PrimitiveNone; |
| if (string == *kPrimitiveNone) |
| primitive = PrimitiveNone; |
| else if (string == *kPrimitiveTriangle) |
| primitive = PrimitiveTriangle; |
| else |
| NOTREACHED(); |
| return primitive; |
| } |
| |
| // FIXME: This method should already exist. Use it. |
| // For now just parse primary colors. |
| void TestPlugin::ParseColor(const blink::WebString& string, uint8_t color[3]) { |
| color[0] = color[1] = color[2] = 0; |
| if (string == "black") |
| return; |
| |
| if (string == "red") |
| color[0] = 255; |
| else if (string == "green") |
| color[1] = 255; |
| else if (string == "blue") |
| color[2] = 255; |
| else |
| NOTREACHED(); |
| } |
| |
| float TestPlugin::ParseOpacity(const blink::WebString& string) { |
| return static_cast<float>(atof(string.Utf8().data())); |
| } |
| |
| bool TestPlugin::ParseBoolean(const blink::WebString& string) { |
| static const base::NoDestructor<blink::WebString> kPrimitiveTrue("true"); |
| return string == *kPrimitiveTrue; |
| } |
| |
| bool TestPlugin::InitScene() { |
| if (!gl_) |
| return true; |
| |
| float color[4]; |
| PremultiplyAlpha(scene_.background_color, scene_.opacity, color); |
| |
| gl_->GenTextures(1, &color_texture_); |
| gl_->GenFramebuffers(1, &framebuffer_); |
| |
| gl_->Viewport(0, 0, rect_.width, rect_.height); |
| gl_->Disable(GL_DEPTH_TEST); |
| gl_->Disable(GL_SCISSOR_TEST); |
| |
| gl_->ClearColor(color[0], color[1], color[2], color[3]); |
| |
| gl_->Enable(GL_BLEND); |
| gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); |
| |
| return scene_.primitive != PrimitiveNone ? InitProgram() && InitPrimitive() |
| : true; |
| } |
| |
| void TestPlugin::DrawSceneGL() { |
| gl_->Viewport(0, 0, rect_.width, rect_.height); |
| gl_->Clear(GL_COLOR_BUFFER_BIT); |
| |
| if (scene_.primitive != PrimitiveNone) |
| DrawPrimitive(); |
| } |
| |
| void TestPlugin::DrawSceneSoftware(void* memory) { |
| SkColor background_color = SkColorSetARGB( |
| static_cast<uint8_t>(scene_.opacity * 255), scene_.background_color[0], |
| scene_.background_color[1], scene_.background_color[2]); |
| |
| const SkImageInfo info = |
| SkImageInfo::MakeN32Premul(rect_.width, rect_.height); |
| SkBitmap bitmap; |
| bitmap.installPixels(info, memory, info.minRowBytes()); |
| SkCanvas canvas(bitmap); |
| canvas.clear(background_color); |
| |
| if (scene_.primitive != PrimitiveNone) { |
| DCHECK_EQ(PrimitiveTriangle, scene_.primitive); |
| SkColor foreground_color = SkColorSetARGB( |
| static_cast<uint8_t>(scene_.opacity * 255), scene_.primitive_color[0], |
| scene_.primitive_color[1], scene_.primitive_color[2]); |
| SkPath triangle_path; |
| triangle_path.moveTo(0.5f * rect_.width, 0.9f * rect_.height); |
| triangle_path.lineTo(0.1f * rect_.width, 0.1f * rect_.height); |
| triangle_path.lineTo(0.9f * rect_.width, 0.1f * rect_.height); |
| SkPaint paint; |
| paint.setColor(foreground_color); |
| paint.setStyle(SkPaint::kFill_Style); |
| canvas.drawPath(triangle_path, paint); |
| } |
| } |
| |
| void TestPlugin::DestroyScene() { |
| if (scene_.program) { |
| gl_->DeleteProgram(scene_.program); |
| scene_.program = 0; |
| } |
| if (scene_.vbo) { |
| gl_->DeleteBuffers(1, &scene_.vbo); |
| scene_.vbo = 0; |
| } |
| |
| if (framebuffer_) { |
| gl_->DeleteFramebuffers(1, &framebuffer_); |
| framebuffer_ = 0; |
| } |
| |
| if (color_texture_) { |
| gl_->DeleteTextures(1, &color_texture_); |
| color_texture_ = 0; |
| } |
| } |
| |
| bool TestPlugin::InitProgram() { |
| const std::string vertex_source( |
| "attribute vec4 position; \n" |
| "void main() { \n" |
| " gl_Position = position; \n" |
| "} \n"); |
| |
| const std::string fragment_source( |
| "precision mediump float; \n" |
| "uniform vec4 color; \n" |
| "void main() { \n" |
| " gl_FragColor = color; \n" |
| "} \n"); |
| |
| scene_.program = LoadProgram(vertex_source, fragment_source); |
| if (!scene_.program) |
| return false; |
| |
| scene_.color_location = gl_->GetUniformLocation(scene_.program, "color"); |
| scene_.position_location = gl_->GetAttribLocation(scene_.program, "position"); |
| return true; |
| } |
| |
| bool TestPlugin::InitPrimitive() { |
| DCHECK_EQ(scene_.primitive, PrimitiveTriangle); |
| |
| gl_->GenBuffers(1, &scene_.vbo); |
| if (!scene_.vbo) |
| return false; |
| |
| const float vertices[] = {0.0f, 0.8f, 0.0f, -0.8f, -0.8f, |
| 0.0f, 0.8f, -0.8f, 0.0f}; |
| gl_->BindBuffer(GL_ARRAY_BUFFER, scene_.vbo); |
| gl_->BufferData(GL_ARRAY_BUFFER, sizeof(vertices), nullptr, GL_STATIC_DRAW); |
| gl_->BufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); |
| return true; |
| } |
| |
| void TestPlugin::DrawPrimitive() { |
| DCHECK_EQ(scene_.primitive, PrimitiveTriangle); |
| DCHECK(scene_.vbo); |
| DCHECK(scene_.program); |
| |
| gl_->UseProgram(scene_.program); |
| |
| // Bind primitive color. |
| float color[4]; |
| PremultiplyAlpha(scene_.primitive_color, scene_.opacity, color); |
| gl_->Uniform4f(scene_.color_location, color[0], color[1], color[2], color[3]); |
| |
| // Bind primitive vertices. |
| gl_->BindBuffer(GL_ARRAY_BUFFER, scene_.vbo); |
| gl_->EnableVertexAttribArray(scene_.position_location); |
| gl_->VertexAttribPointer(scene_.position_location, 3, GL_FLOAT, GL_FALSE, 0, |
| nullptr); |
| gl_->DrawArrays(GL_TRIANGLES, 0, 3); |
| } |
| |
| GLuint TestPlugin::LoadShader(GLenum type, const std::string& source) { |
| GLuint shader = gl_->CreateShader(type); |
| if (shader) { |
| const GLchar* shader_data = source.data(); |
| GLint shader_length = strlen(shader_data); // source.length(); |
| gl_->ShaderSource(shader, 1, &shader_data, &shader_length); |
| gl_->CompileShader(shader); |
| |
| int compiled = 0; |
| gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compiled); |
| if (!compiled) { |
| gl_->DeleteShader(shader); |
| shader = 0; |
| } |
| } |
| return shader; |
| } |
| |
| GLuint TestPlugin::LoadProgram(const std::string& vertex_source, |
| const std::string& fragment_source) { |
| GLuint vertex_shader = LoadShader(GL_VERTEX_SHADER, vertex_source); |
| GLuint fragment_shader = LoadShader(GL_FRAGMENT_SHADER, fragment_source); |
| GLuint program = gl_->CreateProgram(); |
| if (vertex_shader && fragment_shader && program) { |
| gl_->AttachShader(program, vertex_shader); |
| gl_->AttachShader(program, fragment_shader); |
| gl_->LinkProgram(program); |
| |
| int linked = 0; |
| gl_->GetProgramiv(program, GL_LINK_STATUS, &linked); |
| if (!linked) { |
| gl_->DeleteProgram(program); |
| program = 0; |
| } |
| } |
| if (vertex_shader) |
| gl_->DeleteShader(vertex_shader); |
| if (fragment_shader) |
| gl_->DeleteShader(fragment_shader); |
| |
| return program; |
| } |
| |
| blink::WebInputEventResult TestPlugin::HandleInputEvent( |
| const blink::WebCoalescedInputEvent& coalesced_event, |
| blink::WebCursorInfo& info) { |
| const blink::WebInputEvent& event = coalesced_event.Event(); |
| const char* event_name = blink::WebInputEvent::GetName(event.GetType()); |
| if (!strcmp(event_name, "") || !strcmp(event_name, "Undefined")) |
| event_name = "unknown"; |
| delegate_->PrintMessage(std::string("Plugin received event: ") + event_name + |
| "\n"); |
| if (print_event_details_) |
| PrintEventDetails(delegate_, event); |
| |
| if (print_user_gesture_status_) { |
| bool has_user_gesture = |
| blink::WebUserGestureIndicator::IsProcessingUserGesture( |
| web_local_frame_); |
| delegate_->PrintMessage(std::string("* ") + |
| (has_user_gesture ? "" : "not ") + |
| "handling user gesture\n"); |
| } |
| |
| if (is_persistent_) |
| delegate_->PrintMessage(std::string("TestPlugin: isPersistent\n")); |
| return blink::WebInputEventResult::kNotHandled; |
| } |
| |
| bool TestPlugin::HandleDragStatusUpdate( |
| blink::WebDragStatus drag_status, |
| const blink::WebDragData& data, |
| blink::WebDragOperationsMask mask, |
| const blink::WebFloatPoint& position, |
| const blink::WebFloatPoint& screen_position) { |
| const char* drag_status_name = nullptr; |
| switch (drag_status) { |
| case blink::kWebDragStatusEnter: |
| drag_status_name = "DragEnter"; |
| break; |
| case blink::kWebDragStatusOver: |
| drag_status_name = "DragOver"; |
| break; |
| case blink::kWebDragStatusLeave: |
| drag_status_name = "DragLeave"; |
| break; |
| case blink::kWebDragStatusDrop: |
| drag_status_name = "DragDrop"; |
| break; |
| case blink::kWebDragStatusUnknown: |
| NOTREACHED(); |
| } |
| delegate_->PrintMessage(std::string("Plugin received event: ") + |
| drag_status_name + "\n"); |
| return false; |
| } |
| |
| TestPlugin* TestPlugin::Create(const blink::WebPluginParams& params, |
| WebTestDelegate* delegate, |
| blink::WebLocalFrame* frame) { |
| return new TestPlugin(params, delegate, frame); |
| } |
| |
| const blink::WebString& TestPlugin::MimeType() { |
| static const base::NoDestructor<blink::WebString> kMimeType( |
| "application/x-webkit-test-webplugin"); |
| return *kMimeType; |
| } |
| |
| const blink::WebString& TestPlugin::PluginPersistsMimeType() { |
| static const base::NoDestructor<blink::WebString> kPluginPersistsMimeType( |
| "application/x-webkit-test-webplugin-persistent"); |
| return *kPluginPersistsMimeType; |
| } |
| |
| bool TestPlugin::IsSupportedMimeType(const blink::WebString& mime_type) { |
| return mime_type == TestPlugin::MimeType() || |
| mime_type == PluginPersistsMimeType(); |
| } |
| |
| } // namespace test_runner |