|  | // Copyright 2017 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 "ui/gl/gl_context_glx.h" | 
|  |  | 
|  | #include "base/memory/scoped_refptr.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "ui/gfx/x/x11.h" | 
|  | #include "ui/gfx/x/x11_error_tracker.h" | 
|  | #include "ui/gfx/x/x11_types.h" | 
|  | #include "ui/gl/gl_surface_glx_x11.h" | 
|  | #include "ui/gl/init/gl_factory.h" | 
|  | #include "ui/gl/test/gl_image_test_support.h" | 
|  |  | 
|  | namespace gl { | 
|  |  | 
|  | TEST(GLContextGLXTest, DoNotDestroyOnFailedMakeCurrent) { | 
|  | auto* xdisplay = gfx::GetXDisplay(); | 
|  | ASSERT_TRUE(xdisplay); | 
|  |  | 
|  | gfx::X11ErrorTracker error_tracker; | 
|  |  | 
|  | XSetWindowAttributes swa; | 
|  | memset(&swa, 0, sizeof(swa)); | 
|  | swa.background_pixmap = 0; | 
|  | swa.override_redirect = x11::True; | 
|  | auto xwindow = XCreateWindow(xdisplay, DefaultRootWindow(xdisplay), 0, 0, 10, | 
|  | 10,              // x, y, width, height | 
|  | 0,               // border width | 
|  | CopyFromParent,  // depth | 
|  | InputOutput, | 
|  | CopyFromParent,  // visual | 
|  | CWBackPixmap | CWOverrideRedirect, &swa); | 
|  | XSelectInput(xdisplay, xwindow, StructureNotifyMask); | 
|  |  | 
|  | XEvent xevent; | 
|  | XMapWindow(xdisplay, xwindow); | 
|  | // Wait until the window is mapped. | 
|  | while (XNextEvent(xdisplay, &xevent) && xevent.type != MapNotify && | 
|  | xevent.xmap.window != xwindow) { | 
|  | } | 
|  |  | 
|  | GLImageTestSupport::InitializeGL(base::nullopt); | 
|  | auto surface = | 
|  | gl::InitializeGLSurface(base::MakeRefCounted<GLSurfaceGLXX11>(xwindow)); | 
|  | scoped_refptr<GLContext> context = | 
|  | gl::init::CreateGLContext(nullptr, surface.get(), GLContextAttribs()); | 
|  |  | 
|  | // Verify that MakeCurrent() is successful. | 
|  | ASSERT_TRUE(context->GetHandle()); | 
|  | ASSERT_TRUE(context->MakeCurrent(surface.get())); | 
|  | EXPECT_TRUE(context->GetHandle()); | 
|  |  | 
|  | // Destroy the window, and wait until the window is unmapped. There should be | 
|  | // no x11 errors. | 
|  | context->ReleaseCurrent(surface.get()); | 
|  | XDestroyWindow(xdisplay, xwindow); | 
|  | while (XNextEvent(xdisplay, &xevent) && xevent.type != UnmapNotify) { | 
|  | } | 
|  | ASSERT_FALSE(error_tracker.FoundNewError()); | 
|  |  | 
|  | if (context->MakeCurrent(surface.get())) { | 
|  | // With some drivers, MakeCurrent() does not fail for an already-destroyed | 
|  | // window. In those cases, override the glx api to force MakeCurrent() to | 
|  | // fail. | 
|  | context->ReleaseCurrent(surface.get()); | 
|  | auto real_fn = g_driver_glx.fn.glXMakeContextCurrentFn; | 
|  | g_driver_glx.fn.glXMakeContextCurrentFn = | 
|  | [](Display* display, GLXDrawable drawable, GLXDrawable read, | 
|  | GLXContext context) -> int { return 0; }; | 
|  | EXPECT_FALSE(context->MakeCurrent(surface.get())); | 
|  | g_driver_glx.fn.glXMakeContextCurrentFn = real_fn; | 
|  | } | 
|  | // At this point, MakeCurrent() failed. Make sure the GLContextGLX still was | 
|  | // not destroyed. | 
|  | ASSERT_TRUE(context->GetHandle()); | 
|  | surface = nullptr; | 
|  | XSync(xdisplay, x11::True); | 
|  | } | 
|  |  | 
|  | }  // namespace gl |