[CAIRO] Make GLContextGLX a subclass of GLContext
authormrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 11 Apr 2012 21:07:47 +0000 (21:07 +0000)
committermrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 11 Apr 2012 21:07:47 +0000 (21:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=81285

Reviewed by Gustavo Noronha Silva.

.:

* GNUmakefile.am: Add a configuration option for activating GLX.
This is selected automatically now, but in the future there will be
the choice to turn on EGL and turn off GLX at compilation time.
* configure.ac: Ditto.

Source/WebCore:

No new tests. This should not change behavior.

* GNUmakefile.list.am: Add new GLContextGLX files.
* platform/graphics/cairo/GLContext.cpp: Added. Composed of the
EGL/GLX independent portions of GLContext. Made the current context
a static variable so we can keep getting the current context platform-
-independent.
* platform/graphics/cairo/GLContext.h: Make this class an abstract
class. GLContextGLX is a concrete implementation.
* platform/graphics/cairo/GraphicsContext3DPrivate.cpp: Updated to reflect
slightly different calling conventions to create a sharing context.
* platform/graphics/glx/GLContextGLX.cpp: Updated to reflect
that this code is in a subclass now.
* platform/graphics/glx/GLContextGLX.h: Copied from Source/WebCore/platform/graphics/cairo/GLContext.h.
* platform/graphics/gtk/GLContextGtk.cpp:
(WebCore::GLContext::getContextForWidget): Updated to respect the new
USE(GLX) flag.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@113909 268f45cc-cd09-0410-ab3c-d52691b4dbfc

ChangeLog
GNUmakefile.am
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/platform/graphics/cairo/GLContext.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/cairo/GLContext.h
Source/WebCore/platform/graphics/cairo/GraphicsContext3DPrivate.cpp
Source/WebCore/platform/graphics/glx/GLContextGLX.cpp
Source/WebCore/platform/graphics/glx/GLContextGLX.h [new file with mode: 0644]
Source/WebCore/platform/graphics/gtk/GLContextGtk.cpp
configure.ac

index 7d4e6b4..a69f535 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2012-03-15  Martin Robinson  <mrobinson@igalia.com>
+
+        [CAIRO] Make GLContextGLX a subclass of GLContext
+        https://bugs.webkit.org/show_bug.cgi?id=81285
+
+        Reviewed by Gustavo Noronha Silva.
+
+        * GNUmakefile.am: Add a configuration option for activating GLX.
+        This is selected automatically now, but in the future there will be
+        the choice to turn on EGL and turn off GLX at compilation time.
+        * configure.ac: Ditto.
+
 2012-04-10  Jocelyn Turcotte  <jocelyn.turcotte@nokia.com>
 
         [Qt] InspectorServer: Add an API level auto test
index d8751ed..65e7c85 100644 (file)
@@ -204,6 +204,16 @@ global_cppflags += \
        -DWTF_USE_CLUTTER=1
 endif
 
+if USE_GLX
+global_cppflags += \
+       -DWTF_USE_GLX=1
+endif
+
+if USE_OPENGL
+global_cppflags += \
+       -DWTF_USE_OPENGL=1
+endif
+
 # ----
 # GTK+ 2.x/3.x support
 # ----
index cc22272..0009e0c 100644 (file)
@@ -1,3 +1,28 @@
+2012-03-15  Martin Robinson  <mrobinson@igalia.com>
+
+        [CAIRO] Make GLContextGLX a subclass of GLContext
+        https://bugs.webkit.org/show_bug.cgi?id=81285
+
+        Reviewed by Gustavo Noronha Silva.
+
+        No new tests. This should not change behavior.
+
+        * GNUmakefile.list.am: Add new GLContextGLX files.
+        * platform/graphics/cairo/GLContext.cpp: Added. Composed of the
+        EGL/GLX independent portions of GLContext. Made the current context
+        a static variable so we can keep getting the current context platform-
+        -independent.
+        * platform/graphics/cairo/GLContext.h: Make this class an abstract
+        class. GLContextGLX is a concrete implementation.
+        * platform/graphics/cairo/GraphicsContext3DPrivate.cpp: Updated to reflect
+        slightly different calling conventions to create a sharing context.
+        * platform/graphics/glx/GLContextGLX.cpp: Updated to reflect
+        that this code is in a subclass now.
+        * platform/graphics/glx/GLContextGLX.h: Copied from Source/WebCore/platform/graphics/cairo/GLContext.h.
+        * platform/graphics/gtk/GLContextGtk.cpp:
+        (WebCore::GLContext::getContextForWidget): Updated to respect the new
+        USE(GLX) flag.
+
 2012-04-11  Rob Buis  <rbuis@rim.com>
 
         [BlackBerry] Upstream BlackBerry change to PatternSkia.cpp
index 9d78218..ab0bdd0 100644 (file)
@@ -4726,7 +4726,9 @@ webcoregtk_sources += \
 if TARGET_X11
 webcoregtk_sources += \
        Source/WebCore/platform/graphics/glx/GLContextGLX.cpp \
+       Source/WebCore/platform/graphics/glx/GLContextGLX.h \
        Source/WebCore/platform/graphics/gtk/GLContextGtk.cpp \
+       Source/WebCore/platform/graphics/cairo/GLContext.cpp \
        Source/WebCore/platform/graphics/cairo/GLContext.h \
        Source/WebCore/platform/gtk/GtkWidgetBackingStoreX11.cpp \
        Source/WebCore/plugins/gtk/gtk2xtbin.c \
diff --git a/Source/WebCore/platform/graphics/cairo/GLContext.cpp b/Source/WebCore/platform/graphics/cairo/GLContext.cpp
new file mode 100644 (file)
index 0000000..c70307e
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011, 2012 Igalia, S.L.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+#include "GLContext.h"
+
+#if USE(OPENGL)
+
+#if USE(GLX)
+#include "GLContextGLX.h"
+#endif
+
+namespace WebCore {
+
+GLContext::GLContext()
+{
+}
+
+GLContext* GLContext::createOffscreenContext(GLContext* sharing)
+{
+    if (sharing)
+        return sharing->createOffscreenSharingContext();
+
+#if USE(GLX)
+    return GLContextGLX::createContext(0, 0);
+#endif
+}
+
+// FIXME: This should be a thread local eventually if we
+// want to support using GLContexts from multiple threads.
+static GLContext* gCurrentContext = 0;
+
+GLContext::~GLContext()
+{
+    if (this == gCurrentContext)
+        gCurrentContext = 0;
+}
+
+bool GLContext::makeContextCurrent()
+{
+    gCurrentContext = this;
+    return true;
+}
+
+GLContext* GLContext::getCurrent()
+{
+    return gCurrentContext;
+}
+
+} // namespace WebCore
+
+#endif // USE(OPENGL)
+
index 0a39cec..8b2eee7 100644 (file)
 #include <wtf/Noncopyable.h>
 #include <wtf/PassOwnPtr.h>
 
-#if defined(XP_UNIX)
-typedef struct __GLXcontextRec* GLXContext;
-typedef struct _XDisplay Display;
-typedef struct __GLXcontextRec *GLXContext;
-typedef unsigned long GLXPbuffer;
-typedef unsigned long GLXPixmap;
-typedef unsigned char GLubyte;
-typedef unsigned long Pixmap;
-typedef unsigned long XID;
-typedef void* ContextKeyType;
-#endif
-
 namespace WebCore {
 
 class GLContext {
     WTF_MAKE_NONCOPYABLE(GLContext);
 public:
-    static GLContext* createSharingContext(GLContext* shareContext);
     static GLContext* getContextForWidget(PlatformWidget);
+    static GLContext* createOffscreenContext(GLContext* sharing = 0);
     static GLContext* getCurrent();
-    static void removeActiveContext(GLContext*);
-    static void removeActiveContextForWidget(PlatformWidget);
 
+    GLContext();
     virtual ~GLContext();
-    bool makeContextCurrent();
-    void swapBuffers();
-    bool canRenderToDefaultFramebuffer();
+    virtual GLContext* createOffscreenSharingContext() = 0;
+    virtual bool makeContextCurrent();
+    virtual void swapBuffers() = 0;
+    virtual bool canRenderToDefaultFramebuffer() = 0;
 
 #if ENABLE(WEBGL)
-    PlatformGraphicsContext3D platformContext();
-#endif
-
-private:
-    static void addActiveContext(GLContext*);
-    static void cleanupActiveContextsAtExit();
-
-#if defined(XP_UNIX)
-    GLContext(GLXContext);
-    GLContext(GLXContext, Pixmap, GLXPixmap);
-    static GLContext* createContext(XID, GLXContext sharingContext = 0);
-    static GLContext* createWindowContext(XID window, GLXContext sharingContext);
-    static GLContext* createPbufferContext(GLXContext sharingContext);
-    static GLContext* createPixmapContext(GLXContext sharingContext);
-
-    GLXContext m_context;
-    Display* m_display;
-
-    XID m_window;
-    GLXPbuffer m_pbuffer;
-    Pixmap m_pixmap;
-    GLXPixmap m_glxPixmap;
+    virtual PlatformGraphicsContext3D platformContext() = 0;
 #endif
 };
 
-}
+} // namespace WebCore
 
 #endif // GLContext_h
index 7d9c44c..94d40ec 100644 (file)
@@ -40,16 +40,15 @@ GraphicsContext3DPrivate::GraphicsContext3DPrivate(GraphicsContext3D* context, H
     : m_context(context)
     , m_window(window)
 #if PLATFORM(GTK)
-    , m_glContext(GLContext::createSharingContext(GLContext::getContextForWidget(m_window->platformPageClient())))
+    , m_glContext(GLContext::createOffscreenContext(GLContext::getContextForWidget(m_window->platformPageClient())))
 #else
-    , m_glContext(GLContext::createContext(0, 0))
+    , m_glContext(GLContext::createOffscreenContext())
 #endif
 {
 }
 
 GraphicsContext3DPrivate::~GraphicsContext3DPrivate()
 {
-    GLContext::removeActiveContext(m_glContext);
 }
 
 bool GraphicsContext3DPrivate::makeContextCurrent()
index cdced68..6062e43 100644 (file)
@@ -17,9 +17,9 @@
  */
 
 #include "config.h"
-#include "GLContext.h"
+#include "GLContextGLX.h"
 
-#if ENABLE(WEBGL) || USE(TEXTURE_MAPPER_GL)
+#if USE(GLX)
 #include "GraphicsContext3D.h"
 #include "OpenGLShims.h"
 #include <GL/glx.h>
@@ -50,17 +50,17 @@ static ActiveContextList& activeContextList()
     return activeContexts;
 }
 
-void GLContext::addActiveContext(GLContext* context)
+void GLContextGLX::addActiveContext(GLContextGLX* context)
 {
     static bool addedAtExitHandler = false;
     if (!addedAtExitHandler) {
-        atexit(&GLContext::cleanupActiveContextsAtExit);
+        atexit(&GLContextGLX::cleanupActiveContextsAtExit);
         addedAtExitHandler = true;
     }
     activeContextList().append(context);
 }
 
-void GLContext::removeActiveContext(GLContext* context)
+void GLContextGLX::removeActiveContext(GLContext* context)
 {
     ActiveContextList& contextList = activeContextList();
     size_t i = contextList.find(context);
@@ -68,7 +68,7 @@ void GLContext::removeActiveContext(GLContext* context)
         contextList.remove(i);
 }
 
-void GLContext::cleanupActiveContextsAtExit()
+void GLContextGLX::cleanupActiveContextsAtExit()
 {
     ActiveContextList& contextList = activeContextList();
     for (size_t i = 0; i < contextList.size(); ++i)
@@ -80,23 +80,12 @@ void GLContext::cleanupActiveContextsAtExit()
     gSharedDisplay = 0;
 }
 
-GLContext* GLContext::getCurrent()
+GLContext* GLContextGLX::createOffscreenSharingContext()
 {
-    ActiveContextList& contextList = activeContextList();
-    GLXContext current = glXGetCurrentContext();
-    for (size_t i = 0; i < contextList.size(); ++i) {
-        if (current == contextList[i]->m_context)
-            return contextList[i];
-    }
-    return 0;
-}
-
-GLContext* GLContext::createSharingContext(GLContext* sharingContext)
-{
-    return createContext(0, sharingContext ? sharingContext->m_context : 0);
+    return createContext(0, m_context);
 }
 
-GLContext* GLContext::createWindowContext(XID window, GLXContext sharingContext)
+GLContextGLX* GLContextGLX::createWindowContext(XID window, GLXContext sharingContext)
 {
     Display* display = sharedDisplay();
     XWindowAttributes attributes;
@@ -116,12 +105,12 @@ GLContext* GLContext::createWindowContext(XID window, GLXContext sharingContext)
 
     // GLXPbuffer and XID are both the same types underneath, so we have to share
     // a constructor here with the window path.
-    GLContext* contextWrapper = new GLContext(context);
+    GLContextGLX* contextWrapper = new GLContextGLX(context);
     contextWrapper->m_window = window;
     return contextWrapper;
 }
 
-GLContext* GLContext::createPbufferContext(GLXContext sharingContext)
+GLContextGLX* GLContextGLX::createPbufferContext(GLXContext sharingContext)
 {
     int fbConfigAttributes[] = {
         GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
@@ -157,12 +146,12 @@ GLContext* GLContext::createPbufferContext(GLXContext sharingContext)
 
     // GLXPbuffer and XID are both the same types underneath, so we have to share
     // a constructor here with the window path.
-    GLContext* contextWrapper = new GLContext(context);
+    GLContextGLX* contextWrapper = new GLContextGLX(context);
     contextWrapper->m_pbuffer = pbuffer;
     return contextWrapper;
 }
 
-GLContext* GLContext::createPixmapContext(GLXContext sharingContext)
+GLContextGLX* GLContextGLX::createPixmapContext(GLXContext sharingContext)
 {
     static int visualAttributes[] = {
         GLX_RGBA,
@@ -197,10 +186,10 @@ GLContext* GLContext::createPixmapContext(GLXContext sharingContext)
         return 0;
     }
 
-    return new GLContext(context, pixmap, glxPixmap);
+    return new GLContextGLX(context, pixmap, glxPixmap);
 }
 
-GLContext* GLContext::createContext(XID window, GLXContext sharingContext)
+GLContextGLX* GLContextGLX::createContext(XID window, GLXContext sharingContext)
 {
     if (!sharedDisplay())
         return 0;
@@ -214,7 +203,7 @@ GLContext* GLContext::createContext(XID window, GLXContext sharingContext)
     if (!success)
         return 0;
 
-    GLContext* context = window ? createWindowContext(window, sharingContext) : 0;
+    GLContextGLX* context = window ? createWindowContext(window, sharingContext) : 0;
     if (!context)
         context = createPbufferContext(sharingContext);
     if (!context)
@@ -225,7 +214,7 @@ GLContext* GLContext::createContext(XID window, GLXContext sharingContext)
     return context;
 }
 
-GLContext::GLContext(GLXContext context)
+GLContextGLX::GLContextGLX(GLXContext context)
     : m_context(context)
     , m_window(0)
     , m_pbuffer(0)
@@ -235,7 +224,7 @@ GLContext::GLContext(GLXContext context)
     addActiveContext(this);
 }
 
-GLContext::GLContext(GLXContext context, Pixmap pixmap, GLXPixmap glxPixmap)
+GLContextGLX::GLContextGLX(GLXContext context, Pixmap pixmap, GLXPixmap glxPixmap)
     : m_context(context)
     , m_window(0)
     , m_pbuffer(0)
@@ -245,7 +234,7 @@ GLContext::GLContext(GLXContext context, Pixmap pixmap, GLXPixmap glxPixmap)
     addActiveContext(this);
 }
 
-GLContext::~GLContext()
+GLContextGLX::~GLContextGLX()
 {
     if (m_context) {
         // This may be necessary to prevent crashes with NVidia's closed source drivers. Originally
@@ -270,14 +259,16 @@ GLContext::~GLContext()
     removeActiveContext(this);
 }
 
-bool GLContext::canRenderToDefaultFramebuffer()
+bool GLContextGLX::canRenderToDefaultFramebuffer()
 {
     return m_window;
 }
 
-bool GLContext::makeContextCurrent()
+bool GLContextGLX::makeContextCurrent()
 {
     ASSERT(m_context && (m_window || m_pbuffer || m_glxPixmap));
+
+    GLContext::makeContextCurrent();
     if (glXGetCurrentContext() == m_context)
         return true;
 
@@ -290,14 +281,14 @@ bool GLContext::makeContextCurrent()
     return ::glXMakeCurrent(sharedDisplay(), m_glxPixmap, m_context);
 }
 
-void GLContext::swapBuffers()
+void GLContextGLX::swapBuffers()
 {
     if (m_window)
         glXSwapBuffers(sharedDisplay(), m_window);
 }
 
 #if ENABLE(WEBGL)
-PlatformGraphicsContext3D GLContext::platformContext()
+PlatformGraphicsContext3D GLContextGLX::platformContext()
 {
     return m_context;
 }
diff --git a/Source/WebCore/platform/graphics/glx/GLContextGLX.h b/Source/WebCore/platform/graphics/glx/GLContextGLX.h
new file mode 100644 (file)
index 0000000..0a7a924
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 Igalia S.L.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GLContextGLX_h
+#define GLContextGLX_h
+
+#if USE(GLX)
+
+#include "GLContext.h"
+
+typedef struct __GLXcontextRec* GLXContext;
+typedef struct _XDisplay Display;
+typedef struct __GLXcontextRec *GLXContext;
+typedef unsigned long GLXPbuffer;
+typedef unsigned long GLXPixmap;
+typedef unsigned char GLubyte;
+typedef unsigned long Pixmap;
+typedef unsigned long XID;
+typedef void* ContextKeyType;
+
+namespace WebCore {
+
+class GLContextGLX : public GLContext {
+    WTF_MAKE_NONCOPYABLE(GLContextGLX);
+public:
+    static GLContextGLX* createContext(XID, GLXContext sharingContext = 0);
+    static GLContextGLX* createWindowContext(XID window, GLXContext sharingContext);
+    static GLContextGLX* createPbufferContext(GLXContext sharingContext);
+    static GLContextGLX* createPixmapContext(GLXContext sharingContext);
+    static void removeActiveContext(GLContext*);
+
+    virtual ~GLContextGLX();
+    virtual GLContext* createOffscreenSharingContext();
+    virtual bool makeContextCurrent();
+    virtual void swapBuffers();
+    virtual bool canRenderToDefaultFramebuffer();
+
+#if ENABLE(WEBGL)
+    virtual PlatformGraphicsContext3D platformContext();
+#endif
+
+private:
+    static void addActiveContext(GLContextGLX*);
+    static void cleanupActiveContextsAtExit();
+
+    GLContextGLX(GLXContext);
+    GLContextGLX(GLXContext, Pixmap, GLXPixmap);
+
+    GLXContext m_context;
+    Display* m_display;
+    XID m_window;
+    GLXPbuffer m_pbuffer;
+    Pixmap m_pixmap;
+    GLXPixmap m_glxPixmap;
+};
+
+} // namespace WebCore
+
+#endif // USE(GLX)
+
+#endif // GLContextGLX_h
index 6b2461a..d460d12 100644 (file)
@@ -19,6 +19,7 @@
 #include "config.h"
 #include "GLContext.h"
 
+#include "GLContextGLX.h"
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 #include <gtk/gtk.h>
@@ -54,10 +55,14 @@ GLContext* GLContext::getContextForWidget(GtkWidget* widget)
     if (!g_signal_handler_find(widget, G_SIGNAL_MATCH_FUNC, 0, 0, 0, reinterpret_cast<void*>(shutdownGLContext), 0))
         g_signal_connect(widget, "unmap", G_CALLBACK(shutdownGLContext), 0);
 
+    GLContext* context = 0;
+
+#if USE(GLX)
     // If this GDK window doesn't have its own native window then, we don't want
     // to use it for rendering, since we'll be drawing over some other widget's area.
     GdkWindow* gdkWindow = gtk_widget_get_window(widget);
-    GLContext* context = gdkWindow && gdk_window_has_native(gdkWindow) ?  createContext(GDK_WINDOW_XID(gdkWindow)) : createContext(0);
+    context = gdkWindow && gdk_window_has_native(gdkWindow) ?  GLContextGLX::createContext(GDK_WINDOW_XID(gdkWindow)) : GLContextGLX::createContext(0);
+#endif
 
     if (!context)
         return 0;
index 6ae5d07..7b365f0 100644 (file)
@@ -547,11 +547,10 @@ AC_ARG_WITH(accelerated_compositing,
             [], [with_accelerated_compositing="no"])
 AC_MSG_RESULT([$with_accelerated_compositing])
 
-if test "$with_accelerated_compositing" = "opengl" && test "$with_target" != "x11" ; then
-    AC_MSG_ERROR([OpenGL accelerated compositing is only available on X11 currently.])
-fi
-
 if test "$enable_webgl" = "yes" ||  test "$with_accelerated_compositing" = "opengl" ; then
+    if test "$with_target" != "x11"; then
+        AC_MSG_ERROR([OpenGL support is only available on X11 currently.])
+    fi
     AC_CHECK_HEADERS([GL/gl.h], [], AC_MSG_ERROR([OpenGL header not found]))
     AC_CHECK_HEADERS([GL/glx.h], [], AC_MSG_ERROR([GLX header not found]))
     OPENGL_LIBS="-lGL -ldl"
@@ -1328,6 +1327,10 @@ AM_CONDITIONAL([USE_TEXTURE_MAPPER_CAIRO], [test "$with_accelerated_compositing"
 AM_CONDITIONAL([USE_TEXTURE_MAPPER_GL], [test "$with_accelerated_compositing" = "opengl"])
 AM_CONDITIONAL([USE_CLUTTER], [test "$with_accelerated_compositing" = "clutter"])
 
+# These are the same now, but they will soon be separate.
+AM_CONDITIONAL([USE_GLX], [test "$with_accelerated_compositing" = "opengl" || test "$enable_webgl" = "yes"])
+AM_CONDITIONAL([USE_OPENGL], [test "$with_accelerated_compositing" = "opengl" || test "$enable_webgl" = "yes"])
+
 # WebKit feature conditionals
 AM_CONDITIONAL([ENABLE_DEBUG],[test "$enable_debug_features" = "yes"])
 AM_CONDITIONAL([ENABLE_WEBGL],[test "$enable_webgl" = "yes"])